summaryrefslogtreecommitdiffstats
path: root/fluent-bit/lib/monkey
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-03-09 13:19:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-03-09 13:19:22 +0000
commitc21c3b0befeb46a51b6bf3758ffa30813bea0ff0 (patch)
tree9754ff1ca740f6346cf8483ec915d4054bc5da2d /fluent-bit/lib/monkey
parentAdding upstream version 1.43.2. (diff)
downloadnetdata-c21c3b0befeb46a51b6bf3758ffa30813bea0ff0.tar.xz
netdata-c21c3b0befeb46a51b6bf3758ffa30813bea0ff0.zip
Adding upstream version 1.44.3.upstream/1.44.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'fluent-bit/lib/monkey')
-rw-r--r--fluent-bit/lib/monkey/.gitignore30
-rw-r--r--fluent-bit/lib/monkey/CMakeLists.txt331
-rw-r--r--fluent-bit/lib/monkey/CONTRIBUTING.md60
-rw-r--r--fluent-bit/lib/monkey/ChangeLog24225
-rw-r--r--fluent-bit/lib/monkey/ChangeLog.old233
-rw-r--r--fluent-bit/lib/monkey/FUZZ.md33
-rw-r--r--fluent-bit/lib/monkey/INSTALL52
-rw-r--r--fluent-bit/lib/monkey/LICENSE177
-rw-r--r--fluent-bit/lib/monkey/NOTICE12
-rw-r--r--fluent-bit/lib/monkey/README.md59
-rw-r--r--fluent-bit/lib/monkey/api/CMakeLists.txt18
-rw-r--r--fluent-bit/lib/monkey/api/errors.c103
-rw-r--r--fluent-bit/lib/monkey/api/test.c186
-rw-r--r--fluent-bit/lib/monkey/cmake/FindLibkqueue.cmake18
-rw-r--r--fluent-bit/lib/monkey/conf/CMakeLists.txt17
-rw-r--r--fluent-bit/lib/monkey/conf/monkey.conf.in166
-rw-r--r--fluent-bit/lib/monkey/conf/monkey.mime.in145
-rw-r--r--fluent-bit/lib/monkey/conf/plugins.load.in10
-rw-r--r--fluent-bit/lib/monkey/conf/sites/default.in57
-rwxr-xr-xfluent-bit/lib/monkey/configure220
-rwxr-xr-xfluent-bit/lib/monkey/debian.sh6
-rw-r--r--fluent-bit/lib/monkey/debian/changelog89
-rw-r--r--fluent-bit/lib/monkey/debian/compat1
-rw-r--r--fluent-bit/lib/monkey/debian/control38
-rw-r--r--fluent-bit/lib/monkey/debian/copyright34
-rw-r--r--fluent-bit/lib/monkey/debian/docs1
-rw-r--r--fluent-bit/lib/monkey/debian/monkey-dev.install37
-rw-r--r--fluent-bit/lib/monkey/debian/monkey-doc.docs1
-rw-r--r--fluent-bit/lib/monkey/debian/monkey-doc.install1
-rw-r--r--fluent-bit/lib/monkey/debian/monkey-polarssl.install6
-rwxr-xr-xfluent-bit/lib/monkey/debian/monkey.init101
-rw-r--r--fluent-bit/lib/monkey/debian/monkey.install51
-rw-r--r--fluent-bit/lib/monkey/debian/monkey.postinst14
-rwxr-xr-xfluent-bit/lib/monkey/debian/rules20
-rw-r--r--fluent-bit/lib/monkey/debian/source/format1
-rw-r--r--fluent-bit/lib/monkey/debian/watch2
-rw-r--r--fluent-bit/lib/monkey/deps/deps.txt3
-rw-r--r--fluent-bit/lib/monkey/deps/flb_libco/CMakeLists.txt28
-rw-r--r--fluent-bit/lib/monkey/deps/flb_libco/README.md14
-rw-r--r--fluent-bit/lib/monkey/deps/flb_libco/aarch64.c138
-rw-r--r--fluent-bit/lib/monkey/deps/flb_libco/amd64.c163
-rw-r--r--fluent-bit/lib/monkey/deps/flb_libco/arm.c81
-rwxr-xr-xfluent-bit/lib/monkey/deps/flb_libco/doc/style.css8
-rwxr-xr-xfluent-bit/lib/monkey/deps/flb_libco/doc/targets.html89
-rwxr-xr-xfluent-bit/lib/monkey/deps/flb_libco/doc/usage.html107
-rw-r--r--fluent-bit/lib/monkey/deps/flb_libco/fiber.c54
-rw-r--r--fluent-bit/lib/monkey/deps/flb_libco/libco.c37
-rw-r--r--fluent-bit/lib/monkey/deps/flb_libco/libco.h28
-rw-r--r--fluent-bit/lib/monkey/deps/flb_libco/ppc.c369
-rw-r--r--fluent-bit/lib/monkey/deps/flb_libco/settings.h52
-rw-r--r--fluent-bit/lib/monkey/deps/flb_libco/sjlj.c105
-rw-r--r--fluent-bit/lib/monkey/deps/flb_libco/ucontext.c72
-rw-r--r--fluent-bit/lib/monkey/deps/flb_libco/x86.c116
-rw-r--r--fluent-bit/lib/monkey/deps/rbtree/CMakeLists.txt5
-rw-r--r--fluent-bit/lib/monkey/deps/rbtree/README.md7
-rw-r--r--fluent-bit/lib/monkey/deps/rbtree/rbtree.c811
-rw-r--r--fluent-bit/lib/monkey/deps/rbtree/rbtree.h459
-rw-r--r--fluent-bit/lib/monkey/deps/regex/CMakeLists.txt5
-rw-r--r--fluent-bit/lib/monkey/deps/regex/re.c515
-rw-r--r--fluent-bit/lib/monkey/deps/regex/re.h87
-rw-r--r--fluent-bit/lib/monkey/examples/README1
-rw-r--r--fluent-bit/lib/monkey/examples/hello.c68
-rw-r--r--fluent-bit/lib/monkey/examples/hello.py12
-rw-r--r--fluent-bit/lib/monkey/examples/image.h256
-rw-r--r--fluent-bit/lib/monkey/examples/list.c91
-rw-r--r--fluent-bit/lib/monkey/examples/list.py24
-rw-r--r--fluent-bit/lib/monkey/examples/quiz.c124
-rw-r--r--fluent-bit/lib/monkey/examples/quiz.py298
-rw-r--r--fluent-bit/lib/monkey/fuzz/CMakeLists.txt11
-rw-r--r--fluent-bit/lib/monkey/fuzz/mk_check.c113
-rw-r--r--fluent-bit/lib/monkey/fuzz/mk_fuzz_me.c143
-rw-r--r--fluent-bit/lib/monkey/htdocs/CMakeLists.txt1
-rw-r--r--fluent-bit/lib/monkey/htdocs/css/bootstrap.min.css7
-rw-r--r--fluent-bit/lib/monkey/htdocs/css/freelancer.css459
-rw-r--r--fluent-bit/lib/monkey/htdocs/css/monkey.css59
-rw-r--r--fluent-bit/lib/monkey/htdocs/favicon.icobin0 -> 133982 bytes
-rw-r--r--fluent-bit/lib/monkey/htdocs/font-awesome/css/font-awesome.min.css4
-rw-r--r--fluent-bit/lib/monkey/htdocs/font-awesome/fonts/FontAwesome.otfbin0 -> 85908 bytes
-rw-r--r--fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.eotbin0 -> 56006 bytes
-rw-r--r--fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.svg520
-rw-r--r--fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.ttfbin0 -> 112160 bytes
-rw-r--r--fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.woffbin0 -> 65452 bytes
-rw-r--r--fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.eotbin0 -> 20127 bytes
-rw-r--r--fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.svg288
-rw-r--r--fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.ttfbin0 -> 45404 bytes
-rw-r--r--fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.woffbin0 -> 23424 bytes
-rw-r--r--fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.woff2bin0 -> 18028 bytes
-rw-r--r--fluent-bit/lib/monkey/htdocs/img/mk_banner.pngbin0 -> 4281 bytes
-rw-r--r--fluent-bit/lib/monkey/htdocs/img/mk_logo.pngbin0 -> 28765 bytes
-rw-r--r--fluent-bit/lib/monkey/htdocs/img/mk_signature.pngbin0 -> 14707 bytes
-rw-r--r--fluent-bit/lib/monkey/htdocs/index.html207
-rw-r--r--fluent-bit/lib/monkey/htdocs/js/bootstrap.min.js7
-rw-r--r--fluent-bit/lib/monkey/htdocs/js/cbpAnimatedHeader.js44
-rw-r--r--fluent-bit/lib/monkey/htdocs/js/cbpAnimatedHeader.min.js11
-rw-r--r--fluent-bit/lib/monkey/htdocs/js/classie.js80
-rw-r--r--fluent-bit/lib/monkey/htdocs/js/freelancer.js37
-rw-r--r--fluent-bit/lib/monkey/htdocs/js/jqBootstrapValidation.js912
-rw-r--r--fluent-bit/lib/monkey/htdocs/js/jquery.js4
-rw-r--r--fluent-bit/lib/monkey/include/CMakeLists.txt11
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_api.h102
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_cache.h26
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_cache_tls.h40
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_clock.h59
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_config.h227
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core.h69
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/external/dirent.h1027
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/external/wingetopt.h282
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/external/winpthreads.h340
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/external/winuio.h54
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_core_info.h.in26
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_dep_unistd.h56
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_dirent.h31
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_event.h156
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_epoll.h44
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_kqueue.h72
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_libevent.h45
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_select.h59
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_file.h48
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_getopt.h31
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_iov.h127
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_limits.h32
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_list.h244
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_macros.h184
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_memory.h125
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_pipe.h32
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_pthread.h31
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_rconf.h92
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_sleep.h59
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_string.h97
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_thread.h47
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_thread_channel.h127
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_uio.h13
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_unistd.h31
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_core/mk_utils.h115
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_env.h.in26
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_fifo.h97
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_header.h113
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_http.h225
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_http2.h182
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_http2_settings.h71
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_http_internal.h197
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_http_parser.h348
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_http_status.h84
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_http_thread.h61
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_info.h.in45
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_kernel.h35
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_lib.h76
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_linuxtrace.h80
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_mimetype.h45
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_net.h40
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_plugin.h384
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_plugin_net.h40
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_plugin_stage.h99
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_scheduler.h353
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_scheduler_tls.h39
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_server.h75
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_server_tls.h34
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_socket.h85
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_static_plugins.h.in69
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_stream.h398
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_thread.h25
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_thread_libco.h123
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_thread_ucontext.h129
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_tls.h110
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_user.h35
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_utils.h54
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_vhost.h123
-rw-r--r--fluent-bit/lib/monkey/include/monkey/mk_vhost_tls.h38
-rw-r--r--fluent-bit/lib/monkey/include/monkey/monkey.h72
-rw-r--r--fluent-bit/lib/monkey/man/CMakeLists.txt3
-rw-r--r--fluent-bit/lib/monkey/man/monkey.1127
-rw-r--r--fluent-bit/lib/monkey/mk_bin/CMakeLists.txt21
-rw-r--r--fluent-bit/lib/monkey/mk_bin/mk_signals.c103
-rw-r--r--fluent-bit/lib/monkey/mk_bin/mk_signals.h27
-rw-r--r--fluent-bit/lib/monkey/mk_bin/monkey.c328
-rw-r--r--fluent-bit/lib/monkey/mk_bin/systemd.in13
-rw-r--r--fluent-bit/lib/monkey/mk_core/CMakeLists.txt156
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/CMakeLists.txt13
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/.clang-format63
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/.gitignore149
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/.travis.yml88
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/.uncrustify55
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/CMakeLists.txt1458
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/CONTRIBUTING.md35
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/ChangeLog1811
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/ChangeLog-1.4231
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/ChangeLog-2.01280
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/Doxyfile257
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/LICENSE99
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/Makefile.am305
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/Makefile.nmake82
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/README.md427
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/VERSION5
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/Vagrantfile400
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/getopt.c149
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/getopt.h33
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/getopt_long.c233
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/nmake/evconfig-private.h6
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/nmake/event2/event-config.h360
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/tree.h677
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/appveyor.yml59
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/arc4random.c556
-rwxr-xr-xfluent-bit/lib/monkey/mk_core/deps/libevent/autogen.sh22
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/buffer.c3447
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/buffer_iocp.c326
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent-internal.h482
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent.c1015
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_async.c686
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_filter.c623
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_openssl.c1486
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_pair.c365
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_ratelim.c1092
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_sock.c720
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/changelist-internal.h102
-rwxr-xr-xfluent-bit/lib/monkey/mk_core/deps/libevent/checkpatch.sh299
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/AddCompilerFlags.cmake13
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/COPYING-CMAKE-SCRIPTS22
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFileOffsetBits.c14
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFileOffsetBits.cmake43
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFunctionExistsEx.c30
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFunctionExistsEx.cmake69
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFunctionKeywords.cmake14
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckPrototypeDefinition.c.in29
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckPrototypeDefinition.cmake82
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckWaitpidSupportWNOWAIT.cmake18
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckWorkingKqueue.cmake52
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CodeCoverage.cmake165
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/Copyright.txt57
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/FindGit.cmake45
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/LibeventConfig.cmake.in17
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/LibeventConfigBuildTree.cmake.in17
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/LibeventConfigVersion.cmake.in11
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/VersionViaGit.cmake66
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/compat/sys/queue.h488
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/configure.ac958
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/defer-internal.h70
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/devpoll.c311
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/epoll.c540
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/epoll_sub.c66
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/epolltable-internal.h1166
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evbuffer-internal.h351
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evconfig-private.h.cmake35
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evconfig-private.h.in48
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evdns.3322
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evdns.c4767
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/event-config.h.cmake532
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/event-internal.h479
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/event.3624
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/event.c3940
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/event_iocp.c294
-rwxr-xr-xfluent-bit/lib/monkey/mk_core/deps/libevent/event_rpcgen.py1728
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/event_tagging.c605
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evmap-internal.h117
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evmap.c1055
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evport.c451
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evrpc-internal.h205
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evrpc.c1171
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evsignal-internal.h65
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evthread-internal.h392
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evthread.c509
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evthread_pthread.c191
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evthread_win32.c341
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evutil.c2693
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evutil_rand.c206
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/evutil_time.c573
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/ht-internal.h487
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/http-internal.h205
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/http.c5024
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/evdns.h45
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event.h83
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/buffer.h1076
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/buffer_compat.h115
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent.h1021
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent_compat.h100
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent_ssl.h134
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent_struct.h116
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/dns.h717
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/dns_compat.h336
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/dns_struct.h80
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/event.h1675
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/event_compat.h230
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/event_struct.h180
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/http.h1189
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/http_compat.h90
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/http_struct.h152
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/keyvalq_struct.h80
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/listener.h180
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/rpc.h596
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/rpc_compat.h61
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/rpc_struct.h100
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/tag.h146
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/tag_compat.h49
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/thread.h253
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/util.h866
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/visibility.h50
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/evhttp.h45
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/evrpc.h45
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/evutil.h39
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/include/include.am46
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/iocp-internal.h201
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/ipv6-internal.h83
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/kqueue-internal.h39
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/kqueue.c567
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/libevent.pc.in16
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_core.pc.in16
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_extra.pc.in16
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_openssl.pc.in16
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_pthreads.pc.in16
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/listener.c890
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/log-internal.h83
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/log.c253
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/m4/ac_backport_259_ssizet.m43
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/m4/acx_pthread.m4279
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/m4/libevent_openssl.m452
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/m4/ntp_pkg_config.m427
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/make-event-config.sed23
-rwxr-xr-xfluent-bit/lib/monkey/mk_core/deps/libevent/make_epoll_table.py63
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/minheap-internal.h188
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/mm-internal.h87
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/openssl-compat.h35
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/poll.c341
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/ratelim-internal.h105
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/dns-example.c257
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/event-read-fifo.c162
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/hello-world.c141
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/hostcheck.c217
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/hostcheck.h30
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/http-connect.c117
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/http-server.c418
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/https-client.c502
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/include.am53
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/le-proxy.c291
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/openssl_hostname_validation.c177
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/openssl_hostname_validation.h56
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/signal-test.c72
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/sample/time-test.c107
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/select.c346
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/signal.c479
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/strlcpy-internal.h22
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/strlcpy.c75
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/Makefile.nmake79
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench.c207
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench_cascade.c188
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench_http.c197
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench_httpclient.c240
-rwxr-xr-xfluent-bit/lib/monkey/mk_core/deps/libevent/test/check-dumpevents.py54
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/include.am148
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/print-winsock-errors.c86
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress.c3473
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress.h144
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress.rpc25
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_buffer.c2563
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_bufferevent.c1443
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_dns.c2172
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_et.c204
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_finalize.c347
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_http.c4640
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_iocp.c352
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_listener.c258
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_main.c464
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_minheap.c99
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_rpc.c905
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_ssl.c802
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_testutils.c233
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_testutils.h67
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_thread.c590
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_thread.h48
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_util.c1478
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_zlib.c348
-rwxr-xr-xfluent-bit/lib/monkey/mk_core/deps/libevent/test/rpcgen_wrapper.sh52
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-changelist.c224
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-closed.c110
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-dumpevents.c179
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-eof.c117
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-fdleak.c249
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-init.c65
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-ratelim.c603
-rwxr-xr-xfluent-bit/lib/monkey/mk_core/deps/libevent/test/test-ratelim.sh88
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-time.c116
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-weof.c114
-rwxr-xr-xfluent-bit/lib/monkey/mk_core/deps/libevent/test/test.sh160
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest.c493
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest.h100
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest_demo.c262
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest_local.h12
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest_macros.h205
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/time-internal.h98
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/util-internal.h483
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/whatsnew-2.0.txt609
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/whatsnew-2.1.txt690
-rw-r--r--fluent-bit/lib/monkey/mk_core/deps/libevent/win32select.c388
-rw-r--r--fluent-bit/lib/monkey/mk_core/external/README.md3
-rw-r--r--fluent-bit/lib/monkey/mk_core/external/winpthreads.c1261
-rw-r--r--fluent-bit/lib/monkey/mk_core/include/CMakeLists.txt16
-rw-r--r--fluent-bit/lib/monkey/mk_core/mk_event.c211
-rw-r--r--fluent-bit/lib/monkey/mk_core/mk_event_epoll.c461
-rw-r--r--fluent-bit/lib/monkey/mk_core/mk_event_kqueue.c373
-rw-r--r--fluent-bit/lib/monkey/mk_core/mk_event_libevent.c514
-rw-r--r--fluent-bit/lib/monkey/mk_core/mk_event_select.c439
-rw-r--r--fluent-bit/lib/monkey/mk_core/mk_file.c153
-rw-r--r--fluent-bit/lib/monkey/mk_core/mk_iov.c209
-rw-r--r--fluent-bit/lib/monkey/mk_core/mk_memory.c80
-rw-r--r--fluent-bit/lib/monkey/mk_core/mk_rconf.c779
-rw-r--r--fluent-bit/lib/monkey/mk_core/mk_string.c615
-rw-r--r--fluent-bit/lib/monkey/mk_core/mk_thread.c347
-rw-r--r--fluent-bit/lib/monkey/mk_core/mk_thread_channel.c150
-rw-r--r--fluent-bit/lib/monkey/mk_core/mk_utils.c393
-rw-r--r--fluent-bit/lib/monkey/mk_server/CMakeLists.txt57
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_cache.c81
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_clock.c171
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_config.c636
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_fifo.c463
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_header.c451
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_http.c1638
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_http2.c384
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_http_parser.c744
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_http_thread.c290
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_kernel.c165
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_lib.c796
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_mimetype.c227
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_net.c284
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_plugin.c804
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_scheduler.c866
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_server.c679
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_socket.c402
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_stream.c338
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_user.c175
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_utils.c589
-rw-r--r--fluent-bit/lib/monkey/mk_server/mk_vhost.c821
-rw-r--r--fluent-bit/lib/monkey/mk_server/monkey.c241
-rw-r--r--fluent-bit/lib/monkey/monkey.pc.in10
-rw-r--r--fluent-bit/lib/monkey/monkey.spec145
-rw-r--r--fluent-bit/lib/monkey/plugins/CMakeLists.txt111
-rw-r--r--fluent-bit/lib/monkey/plugins/README61
-rw-r--r--fluent-bit/lib/monkey/plugins/auth/ABOUT2
-rw-r--r--fluent-bit/lib/monkey/plugins/auth/CMakeLists.txt10
-rw-r--r--fluent-bit/lib/monkey/plugins/auth/OPTIONAL0
-rw-r--r--fluent-bit/lib/monkey/plugins/auth/auth.c254
-rw-r--r--fluent-bit/lib/monkey/plugins/auth/auth.h106
-rw-r--r--fluent-bit/lib/monkey/plugins/auth/base64.c172
-rw-r--r--fluent-bit/lib/monkey/plugins/auth/base64.h11
-rw-r--r--fluent-bit/lib/monkey/plugins/auth/conf.c244
-rw-r--r--fluent-bit/lib/monkey/plugins/auth/conf.h25
-rw-r--r--fluent-bit/lib/monkey/plugins/auth/sha1.c288
-rw-r--r--fluent-bit/lib/monkey/plugins/auth/sha1.h22
-rw-r--r--fluent-bit/lib/monkey/plugins/auth/tools/CMakeLists.txt15
-rw-r--r--fluent-bit/lib/monkey/plugins/auth/tools/mk_passwd.c209
-rw-r--r--fluent-bit/lib/monkey/plugins/cgi/CMakeLists.txt7
-rw-r--r--fluent-bit/lib/monkey/plugins/cgi/cgi.c501
-rw-r--r--fluent-bit/lib/monkey/plugins/cgi/cgi.h133
-rw-r--r--fluent-bit/lib/monkey/plugins/cgi/event.c170
-rw-r--r--fluent-bit/lib/monkey/plugins/cgi/request.c72
-rw-r--r--fluent-bit/lib/monkey/plugins/cheetah/ABOUT4
-rw-r--r--fluent-bit/lib/monkey/plugins/cheetah/CMakeLists.txt9
-rw-r--r--fluent-bit/lib/monkey/plugins/cheetah/OPTIONAL0
-rw-r--r--fluent-bit/lib/monkey/plugins/cheetah/cheetah.c162
-rw-r--r--fluent-bit/lib/monkey/plugins/cheetah/cheetah.h79
-rw-r--r--fluent-bit/lib/monkey/plugins/cheetah/cmd.c472
-rw-r--r--fluent-bit/lib/monkey/plugins/cheetah/cmd.h41
-rw-r--r--fluent-bit/lib/monkey/plugins/cheetah/conf/CMakeLists.txt9
-rw-r--r--fluent-bit/lib/monkey/plugins/cheetah/conf/cheetah.conf17
-rw-r--r--fluent-bit/lib/monkey/plugins/cheetah/cutils.c117
-rw-r--r--fluent-bit/lib/monkey/plugins/cheetah/cutils.h32
-rw-r--r--fluent-bit/lib/monkey/plugins/cheetah/loop.c149
-rw-r--r--fluent-bit/lib/monkey/plugins/cheetah/loop.h26
-rw-r--r--fluent-bit/lib/monkey/plugins/dirlisting/ABOUT4
-rw-r--r--fluent-bit/lib/monkey/plugins/dirlisting/CMakeLists.txt7
-rw-r--r--fluent-bit/lib/monkey/plugins/dirlisting/OPTIONAL0
-rw-r--r--fluent-bit/lib/monkey/plugins/dirlisting/conf/CMakeLists.txt11
-rw-r--r--fluent-bit/lib/monkey/plugins/dirlisting/conf/dirhtml.conf2
-rw-r--r--fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/entry.theme5
-rw-r--r--fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/footer.theme8
-rw-r--r--fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/header.theme27
-rw-r--r--fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/entry.theme14
-rw-r--r--fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/footer.theme7
-rw-r--r--fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/header.theme58
-rw-r--r--fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.c949
-rw-r--r--fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.h181
-rw-r--r--fluent-bit/lib/monkey/plugins/fastcgi/CMakeLists.txt7
-rw-r--r--fluent-bit/lib/monkey/plugins/fastcgi/conf/CMakeLists.txt9
-rw-r--r--fluent-bit/lib/monkey/plugins/fastcgi/conf/fastcgi.conf16
-rw-r--r--fluent-bit/lib/monkey/plugins/fastcgi/fastcgi.c233
-rw-r--r--fluent-bit/lib/monkey/plugins/fastcgi/fastcgi.h36
-rw-r--r--fluent-bit/lib/monkey/plugins/fastcgi/fcgi_handler.c967
-rw-r--r--fluent-bit/lib/monkey/plugins/fastcgi/fcgi_handler.h128
-rw-r--r--fluent-bit/lib/monkey/plugins/liana/ABOUT4
-rw-r--r--fluent-bit/lib/monkey/plugins/liana/CMakeLists.txt5
-rw-r--r--fluent-bit/lib/monkey/plugins/liana/MANDATORY0
-rw-r--r--fluent-bit/lib/monkey/plugins/liana/Makefile.in18
-rw-r--r--fluent-bit/lib/monkey/plugins/liana/README7
-rw-r--r--fluent-bit/lib/monkey/plugins/liana/STATIC0
-rw-r--r--fluent-bit/lib/monkey/plugins/liana/liana.c221
-rw-r--r--fluent-bit/lib/monkey/plugins/logger/CMakeLists.txt21
-rw-r--r--fluent-bit/lib/monkey/plugins/logger/conf/CMakeLists.txt11
-rw-r--r--fluent-bit/lib/monkey/plugins/logger/conf/logger.conf.in22
-rw-r--r--fluent-bit/lib/monkey/plugins/logger/logger.c852
-rw-r--r--fluent-bit/lib/monkey/plugins/logger/logger.h58
-rw-r--r--fluent-bit/lib/monkey/plugins/logger/pointers.c43
-rw-r--r--fluent-bit/lib/monkey/plugins/logger/pointers.h59
-rw-r--r--fluent-bit/lib/monkey/plugins/mandril/CMakeLists.txt6
-rw-r--r--fluent-bit/lib/monkey/plugins/mandril/conf/CMakeLists.txt9
-rw-r--r--fluent-bit/lib/monkey/plugins/mandril/conf/mandril.conf57
-rw-r--r--fluent-bit/lib/monkey/plugins/mandril/mandril.c403
-rw-r--r--fluent-bit/lib/monkey/plugins/mandril/mandril.h57
-rw-r--r--fluent-bit/lib/monkey/plugins/tls/CMakeLists.txt17
-rw-r--r--fluent-bit/lib/monkey/plugins/tls/conf/CMakeLists.txt9
-rw-r--r--fluent-bit/lib/monkey/plugins/tls/conf/tls.conf25
-rw-r--r--fluent-bit/lib/monkey/plugins/tls/tls.c862
-rw-r--r--fluent-bit/lib/monkey/qa/README.txt20
-rw-r--r--fluent-bit/lib/monkey/qa/TEMPLATE26
-rw-r--r--fluent-bit/lib/monkey/qa/__CONFIG10
-rw-r--r--fluent-bit/lib/monkey/qa/__MACROS51
-rwxr-xr-xfluent-bit/lib/monkey/qa/checklog239
-rw-r--r--fluent-bit/lib/monkey/qa/connection_http10_01.htt26
-rw-r--r--fluent-bit/lib/monkey/qa/connection_http10_02.htt28
-rw-r--r--fluent-bit/lib/monkey/qa/connection_http10_03.htt27
-rw-r--r--fluent-bit/lib/monkey/qa/connection_http11_01.htt27
-rw-r--r--fluent-bit/lib/monkey/qa/connection_http11_02.htt28
-rw-r--r--fluent-bit/lib/monkey/qa/connection_http11_03.htt30
-rw-r--r--fluent-bit/lib/monkey/qa/directory_redirect_01.htt33
-rw-r--r--fluent-bit/lib/monkey/qa/directory_redirect_02.htt33
-rw-r--r--fluent-bit/lib/monkey/qa/directory_redirect_03.htt33
-rw-r--r--fluent-bit/lib/monkey/qa/docs_httest.txt181
-rw-r--r--fluent-bit/lib/monkey/qa/error_400_test01.htt26
-rw-r--r--fluent-bit/lib/monkey/qa/error_404.htt26
-rw-r--r--fluent-bit/lib/monkey/qa/error_411.htt26
-rw-r--r--fluent-bit/lib/monkey/qa/error_413_01.htt28
-rw-r--r--fluent-bit/lib/monkey/qa/error_413_02.htt297
-rw-r--r--fluent-bit/lib/monkey/qa/error_501.htt26
-rw-r--r--fluent-bit/lib/monkey/qa/error_505.htt27
-rw-r--r--fluent-bit/lib/monkey/qa/head_01.htt23
-rw-r--r--fluent-bit/lib/monkey/qa/head_02.htt29
-rw-r--r--fluent-bit/lib/monkey/qa/headers_case_insensitive.htt36
-rw-r--r--fluent-bit/lib/monkey/qa/hexa.htt26
-rw-r--r--fluent-bit/lib/monkey/qa/host_port_01.htt27
-rw-r--r--fluent-bit/lib/monkey/qa/host_port_02.htt25
-rw-r--r--fluent-bit/lib/monkey/qa/host_port_03.htt25
-rw-r--r--fluent-bit/lib/monkey/qa/http_parse_01.htt23
-rw-r--r--fluent-bit/lib/monkey/qa/if_modified_since_test01.htt32
-rw-r--r--fluent-bit/lib/monkey/qa/if_modified_since_test02.htt38
-rw-r--r--fluent-bit/lib/monkey/qa/if_modified_since_test03.htt50
-rw-r--r--fluent-bit/lib/monkey/qa/if_modified_since_test04.htt38
-rw-r--r--fluent-bit/lib/monkey/qa/keepalive_01.htt30
-rw-r--r--fluent-bit/lib/monkey/qa/keepalive_02.htt32
-rw-r--r--fluent-bit/lib/monkey/qa/last_modified_01.htt30
-rw-r--r--fluent-bit/lib/monkey/qa/path_traversal01.htt27
-rw-r--r--fluent-bit/lib/monkey/qa/path_traversal02.htt27
-rw-r--r--fluent-bit/lib/monkey/qa/path_traversal03.htt27
-rw-r--r--fluent-bit/lib/monkey/qa/post_test01.htt26
-rw-r--r--fluent-bit/lib/monkey/qa/post_test02.htt33
-rw-r--r--fluent-bit/lib/monkey/qa/post_test03.htt28
-rw-r--r--fluent-bit/lib/monkey/qa/protocol_01.htt26
-rw-r--r--fluent-bit/lib/monkey/qa/protocol_02.htt25
-rw-r--r--fluent-bit/lib/monkey/qa/protocol_03.htt25
-rw-r--r--fluent-bit/lib/monkey/qa/protocol_04.htt25
-rw-r--r--fluent-bit/lib/monkey/qa/protocol_05.htt25
-rw-r--r--fluent-bit/lib/monkey/qa/query.htt25
-rw-r--r--fluent-bit/lib/monkey/qa/ranges_test01.htt37
-rw-r--r--fluent-bit/lib/monkey/qa/ranges_test02.htt37
-rw-r--r--fluent-bit/lib/monkey/qa/ranges_test03.htt45
-rw-r--r--fluent-bit/lib/monkey/qa/ranges_test04.htt45
-rw-r--r--fluent-bit/lib/monkey/qa/ranges_test05.htt46
-rwxr-xr-xfluent-bit/lib/monkey/qa/run_tests.sh119
-rw-r--r--fluent-bit/lib/monkey/qa/simple.htt26
-rw-r--r--fluent-bit/lib/monkey/qa/uri_01.htt26
-rw-r--r--fluent-bit/lib/monkey/qa/uri_02.htt27
566 files changed, 166859 insertions, 0 deletions
diff --git a/fluent-bit/lib/monkey/.gitignore b/fluent-bit/lib/monkey/.gitignore
new file mode 100644
index 000000000..6708c67e1
--- /dev/null
+++ b/fluent-bit/lib/monkey/.gitignore
@@ -0,0 +1,30 @@
+*.[aod]
+*~
+*.so*
+*.pyc
+bin/*
+Makefile
+mk_env.h
+mk_info.h
+*.dpkg
+*.pc
+*.lo
+tags
+*.log
+logs/*
+callgrind.out.*
+tests/lib/bin/*
+plugins.conf
+plugins.list
+plugins/Make.common
+plugins/auth/mk_passwd
+lib/python/monkey.c
+lib/python/bin/*
+lib/python/conf/*
+lib/python/jemalloc.config
+src/include/
+build/
+include/monkey/mk_static_plugins.h
+include/monkey/mk_core/mk_core_info.h
+.vscode
+monkey.service
diff --git a/fluent-bit/lib/monkey/CMakeLists.txt b/fluent-bit/lib/monkey/CMakeLists.txt
new file mode 100644
index 000000000..2d43835b7
--- /dev/null
+++ b/fluent-bit/lib/monkey/CMakeLists.txt
@@ -0,0 +1,331 @@
+# Let's have fun!
+cmake_minimum_required(VERSION 3.0)
+project(monkey C)
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
+set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
+
+# CMake includes
+include(CheckSymbolExists)
+include(CheckLibraryExists)
+include(CheckIncludeFile)
+include(CheckCSourceCompiles)
+include(ExternalProject)
+include(GNUInstallDirs)
+
+# Set default compiler options
+if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__FILENAME__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath \$<))\"'")
+else()
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__FILENAME__=__FILE__")
+endif()
+
+# Monkey Version
+set(MK_VERSION_MAJOR 1)
+set(MK_VERSION_MINOR 7)
+set(MK_VERSION_PATCH 2)
+set(MK_VERSION_STR "${MK_VERSION_MAJOR}.${MK_VERSION_MINOR}.${MK_VERSION_PATCH}")
+
+# Output paths
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/library")
+
+# ============================================
+# ============= BUILD OPTIONS ================
+# ============================================
+
+# Monkey Core
+option(MK_DEBUG "Build with debug symbols" No)
+option(MK_ACCEPT "Use accept(2) system call" No)
+option(MK_ACCEPT4 "Use accept4(2) system call" Yes)
+option(MK_LINUX_KQUEUE "Use Linux kqueue emulator" No)
+option(MK_TRACE "Enable Trace mode" No)
+option(MK_UCLIB "Enable uClib libc support" No)
+option(MK_MUSL "Enable Musl libc support" No)
+option(MK_BACKTRACE "Enable Backtrace feature" Yes)
+option(MK_LINUX_TRACE "Enable Lttng support" No)
+option(MK_PTHREAD_TLS "Use old Pthread TLS mode" No)
+option(MK_MBEDTLS_SHARED "Use mbedtls shared lib" No)
+option(MK_VALGRIND "Enable Valgrind support" No)
+option(MK_FUZZ_MODE "Enable HonggFuzz mode" No)
+option(MK_HTTP2 "Enable HTTP Support (dev)" No)
+option(MK_TESTS "Enable Tests" No)
+
+# Plugins: what should be build ?, these options
+# will be processed later on the plugins/CMakeLists.txt file
+option(MK_PLUGIN_AUTH "Basic authentication" No)
+option(MK_PLUGIN_CGI "CGI support" No)
+option(MK_PLUGIN_CHEETAH "Cheetah Shell Interface" No)
+option(MK_PLUGIN_DIRLISTING "Directory Listing" Yes)
+option(MK_PLUGIN_FASTCGI "FastCGI" No)
+option(MK_PLUGIN_LIANA "Basic network layer" Yes)
+option(MK_PLUGIN_LOGGER "Log Writer" No)
+option(MK_PLUGIN_MANDRIL "Security" Yes)
+option(MK_PLUGIN_TLS "TLS/SSL support" No)
+
+# Options to build Monkey with/without binary and
+# static/dynamic library modes (default is always just
+# one target binary).
+option(MK_WITHOUT_BIN "Do not build binary" No)
+option(MK_WITHOUT_CONF "Skip configuration files" No)
+option(MK_STATIC_LIB_MODE "Static library mode" No)
+
+# If building just for a "library" mode, disable plugins
+if(MK_LIB_ONLY)
+ set(MK_PLUGIN_AUTH No)
+ set(MK_PLUGIN_CGI No)
+ set(MK_PLUGIN_CHEETAH No)
+ set(MK_PLUGIN_DIRLISTING No)
+ set(MK_PLUGIN_FASTCGI No)
+ set(MK_PLUGIN_LOGGER No)
+ set(MK_PLUGIN_MANDRIL No)
+endif()
+
+if(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ set(MK_ACCEPT 1)
+ set(MK_ACCEPT4 0)
+ set(MK_SYSTEM_MALLOC 1)
+endif()
+
+if(MK_STATIC_PLUGINS)
+ set(MK_STATIC_PLUGINS "${MK_STATIC_PLUGINS},liana")
+else()
+ set(MK_STATIC_PLUGINS "liana")
+endif()
+
+# Variable to be populated by plugins/CMakeLists.txt. It will contain the
+# code required to initialize any static plugin.
+set(STATIC_PLUGINS_INIT "")
+set(STATIC_PLUGINS_LIBS "")
+
+# ===========================================
+# ============== DEPENDENCIES ===============
+# ===========================================
+
+# Find pthreads
+find_package(Threads)
+
+if(MK_DEBUG)
+ set(CMAKE_BUILD_TYPE "Debug")
+endif()
+
+# It set's a definition and register into the mk_info.h file */
+macro(MK_DEFINITION var)
+ add_definitions(-D${var})
+ set(MK_BUILD_FLAGS "${MK_BUILD_FLAGS}#ifndef ${var}\n#define ${var}\n#endif\n")
+endmacro()
+
+if (CMAKE_SYSTEM_NAME MATCHES "Windows")
+ MK_DEFINITION(_CRT_SECURE_NO_WARNINGS)
+endif()
+
+# Enable experimental (dev) HTTP/2 support
+if (MK_HTTP2)
+ MK_DEFINITION(MK_HAVE_HTTP2)
+endif()
+
+# Check for accept(2) v/s accept(4)
+list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
+check_symbol_exists(accept4 "sys/socket.h" HAVE_ACCEPT4)
+list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
+if(HAVE_ACCEPT4)
+ MK_DEFINITION(MK_HAVE_ACCEPT4)
+endif()
+
+# Check for Linux Kqueue library emulator
+if(MK_LINUX_KQUEUE)
+ find_package(Libkqueue REQUIRED)
+ if(NOT LIBKQUEUE_FOUND)
+ message(FATAL_ERROR "Linux libkqueue was not found." )
+ else()
+ MK_DEFINITION(MK_LINUX_KQUEUE)
+ endif()
+endif()
+
+# Check Trace
+if(MK_TRACE)
+ MK_DEFINITION(MK_HAVE_TRACE)
+endif()
+
+# Check Uclib library
+if(MK_UCLIB)
+ MK_DEFINITION(MK_HAVE_UCLIB)
+endif()
+
+# Check Musl library
+if(MK_MUSL)
+ MK_DEFINITION(MK_HAVE_MUSL)
+endif()
+
+# Check Backtrace support
+check_include_file("execinfo.h" HAVE_BACKTRACE)
+if (NOT HAVE_BACKTRACE)
+ set(MK_BACKTRACE No)
+else()
+ MK_DEFINITION(MK_HAVE_BACKTRACE)
+endif()
+
+# Check for LTTng-UST
+if(MK_LINUX_TRACE)
+ check_include_file("lttng/tracepoint.h" HAVE_LTTNG)
+ if (NOT HAVE_LTTNG)
+ message(FATAL_ERROR "LTTng-UST is not installed in your system." )
+ else()
+ MK_DEFINITION(MK_HAVE_LINUX_TRACE)
+ endif()
+endif()
+
+# Use old Pthread TLS
+if(NOT MK_PTHREAD_TLS)
+ check_c_source_compiles("
+ __thread int a;
+ int main() {
+ __tls_get_addr(0);
+ return 0;
+ }" HAVE_C_TLS)
+
+ if(HAVE_C_TLS)
+ MK_DEFINITION(MK_HAVE_C_TLS)
+ endif()
+endif()
+
+# Valgrind support
+check_c_source_compiles("
+ #include <valgrind/valgrind.h>
+ int main() {
+ return 0;
+ }" MK_HAVE_VALGRIND)
+
+if(MK_VALGRIND OR MK_HAVE_VALGRIND)
+ MK_DEFINITION(MK_HAVE_VALGRIND)
+endif()
+
+# Regex support
+check_c_source_compiles("
+ #include <regex.h>
+ int main() {
+ regex_t reg;
+ const char str[] = \"[a-zA-Z0-9]*\";
+ ret = regcomp(&reg, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+ return 0;
+ }" HAVE_REGEX)
+
+if(HAVE_REGEX)
+ MK_DEFINITION(MK_HAVE_REGEX)
+endif()
+
+
+# ============================================
+# =========== CONFIGURATION FILES=============
+# ============================================
+
+# Default values for conf/monkey.conf
+set(MK_CONF_LISTEN "2001")
+set(MK_CONF_WORKERS "0")
+set(MK_CONF_TIMEOUT "15")
+set(MK_CONF_PIDFILE "monkey.pid")
+set(MK_CONF_USERDIR "public_html")
+set(MK_CONF_INDEXFILE "index.html index.htm index.php")
+set(MK_CONF_HIDEVERSION "Off")
+set(MK_CONF_RESUME "On")
+set(MK_CONF_USER "www-data")
+set(MK_CONF_KA "On")
+set(MK_CONF_KA_TIMEOUT "5")
+set(MK_CONF_KA_MAXREQ "1000")
+set(MK_CONF_REQ_SIZE "32")
+set(MK_CONF_SYMLINK "Off")
+set(MK_CONF_DEFAULT_MIME "text/plain")
+set(MK_CONF_FDT "On")
+set(MK_CONF_OVERCAPACITY "Resist")
+
+# Default values for conf/sites/default
+set(MK_VH_SERVERNAME "127.0.0.1")
+set(MK_VH_DOCUMENT_ROOT MK_DATADIR)
+set(MK_VH_LOG_ACCESS MK_LOGDIR)
+set(MK_VH_LOG_ERROR MK_LOGDIR)
+
+# Paths
+if(APPLE)
+ set(CMAKE_MACOSX_RPATH ${CMAKE_MACOSX_RPATH};${CMAKE_INSTALL_FULL_LIBDIR}/monkey)
+endif()
+
+if(DEFAULT_PORT)
+ set(MK_CONF_LISTEN ${DEFAULT_PORT})
+endif()
+
+if(DEFAULT_USER)
+ set(MK_CONF_USER ${DEFAULT_USER})
+endif()
+
+configure_file(
+ "${PROJECT_SOURCE_DIR}/include/monkey/mk_info.h.in"
+ "${PROJECT_BINARY_DIR}/include/monkey/mk_info.h"
+ )
+
+configure_file(
+ "${PROJECT_SOURCE_DIR}/include/monkey/mk_env.h.in"
+ "${PROJECT_BINARY_DIR}/include/monkey/mk_env.h"
+ )
+
+
+# General Headers
+include_directories(./)
+include_directories(deps/rbtree)
+include_directories(deps/flb_libco)
+include_directories(deps/regex)
+include_directories(include)
+include_directories(include/monkey/)
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/include/)
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/include/monkey/)
+
+if (CMAKE_SYSTEM_NAME MATCHES "Windows")
+ include_directories(mk_core/deps/libevent/include)
+ include_directories("${PROJECT_BINARY_DIR}/mk_core/deps/libevent/include/")
+endif()
+
+# Instruct CMake to build the the code base
+# =========================================
+# mk_core : generic utilities
+# plugins : plugins for mk_server
+# mk_server: server code base: plugins, protocols, scheduler.. (no executable)
+# mk_bin : server executable
+
+add_subdirectory(man)
+add_subdirectory(deps/rbtree)
+add_subdirectory(deps/regex)
+add_subdirectory(deps/flb_libco)
+add_subdirectory(mk_core)
+add_subdirectory(plugins)
+add_subdirectory(mk_server)
+
+if(NOT MK_WITHOUT_BIN)
+ add_subdirectory(mk_bin)
+endif()
+
+# Configuration, headers generation and others
+if(NOT MK_WITHOUT_CONF)
+ add_subdirectory(conf)
+endif()
+add_subdirectory(htdocs)
+add_subdirectory(include)
+
+# Install (missings ?) paths
+install(DIRECTORY DESTINATION ${MK_PATH_LOG})
+install(DIRECTORY DESTINATION ${MK_PATH_PIDPATH})
+install(DIRECTORY DESTINATION ${MK_PATH_WWW})
+
+if(NOT SKIP_EMPTY_DIRS)
+ install(DIRECTORY DESTINATION ${MK_PATH_PIDPATH})
+ install(DIRECTORY DESTINATION ${MK_PATH_LOG})
+endif()
+
+add_subdirectory(api)
+
+if(MK_FUZZ_MODE)
+ add_subdirectory(fuzz)
+endif()
+
+if(MK_TESTS)
+ add_subdirectory(test)
+endif()
diff --git a/fluent-bit/lib/monkey/CONTRIBUTING.md b/fluent-bit/lib/monkey/CONTRIBUTING.md
new file mode 100644
index 000000000..e82a8af73
--- /dev/null
+++ b/fluent-bit/lib/monkey/CONTRIBUTING.md
@@ -0,0 +1,60 @@
+# Contributing to Monkey Project
+
+We build Open Source software and we invite everyone to join us and contribute. So if you are interested into participate, please refer to the guidelines below.
+
+## GIT Repositories
+
+All code changes and submissions happens on [Github](http://github.com), that means that to start contributing you should clone the target repository, perform local changes and then do a Pull Request. For more details about the workflow we suggest you check the following documents:
+
+ - https://help.github.com/articles/using-pull-requests
+ - https://help.github.com/articles/creating-a-pull-request
+
+## Coding Style
+
+Our development coding style for C is based on the Apache C style guidelines, we use the same rules, to get more details about it please check the following URL:
+
+ - https://httpd.apache.org/dev/styleguide.html
+
+You have to pay attention to the code indentation, tabs are 4 spaces, spaces on conditionals, etc. If your code submission is not aligned, it will be rejected.
+
+## Commit Changes
+
+When you commit your local changes in your repository (before to push to Github), we need you take care of the following:
+
+ - Your principal commit message (one line subject) must be prefixed with the core section name, e.g: If you are adding a new but missing protocol feature it could be __HTTP: add new XYZ method__.
+ - The Subject of the commit must not be longer than 80 characters.
+ - On the commit body, each line should not be longer than 80 characters.
+ - On most of cases we want full description about what your patch is doing, the patch description should be self descriptive.. like for dummies. Do not assume everybody knows what you are doing and on each like do not exceed 80 characters.
+ - When running the __git commit__ command, make sure you are using the __-s__ flag, that will add a Signed-off comment in the patch description.
+
+Expanding a bit the example feature message we could use the following command:
+
+> $ git commit -a -s
+>
+> HTTP: add new XYZ method
+>
+> This patch adds the missing XYZ method described in RCF2616 in the
+> section 12.4.x.a, it do not alter the core behavior but if the new
+> method is requested it will take care of the proper handling.
+>
+> the patch have been tested using tools A & B.
+>
+> Signed-off-by: Your Name <your@email.com>
+
+If you want to see a real example, run the following command:
+
+> $ git log 4efbc11bafeb56fbe2b4f0f6925671630ce84125
+
+Your path/patches should be fully documented, that will make the review process faster for us, and a faster merge for you.
+
+## Code review, no feelings
+
+When we review your code submission, they must follow our coding style, the code should be clear enough, documented if required and the patch Subject and Description well formed (within others).
+
+If your code needs some improvement, someone of the reviewers or core developers, will write a comment in your Pull Request, so please take in count the suggestion there, otherwise your request will never be merged.
+
+Despite the effort that took for you to create the contribution, that is not an inditacion that the code have to be merged into upstream, everything will be reviewed and must be aligned as the code base.
+
+## Community and respect
+
+Beside code, we are a community. Respect between all of us is mandatory, so we encourage to keep a good vocabulary on all our communication channels, as well we don't accept any discrimination by gender, sexual orientation, religion or other. Make sure you also contribute to keep a good environment.
diff --git a/fluent-bit/lib/monkey/ChangeLog b/fluent-bit/lib/monkey/ChangeLog
new file mode 100644
index 000000000..819a0e4d2
--- /dev/null
+++ b/fluent-bit/lib/monkey/ChangeLog
@@ -0,0 +1,24225 @@
+commit 2ec7636630df1ed405179e66fe7c5dad4b533496
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Aug 7 16:48:18 2015 -0600
+
+ server: HTTP: restrict pipeline request as keepalive requests
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4723dac02f6d0dc62c5985833b286c2ed3817e3b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Aug 7 12:14:57 2015 -0600
+
+ server: HTTP parser: make parser_more() check static inline
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 49760cddbc41c5c8147fb3e0201943a296c5df71
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Aug 7 12:14:23 2015 -0600
+
+ server: scheduler: let protocol handlers decide if they want to process more data upon channel_done
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2e2fdb5117f7a33a2b872fa9805b49e53d54c7e9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Aug 7 12:13:41 2015 -0600
+
+ server: HTTP: reset errno for connection problems and re-enable pipeline support
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5a64dff41dd030864e4c2c03b0da43e9e69e1c8a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Aug 7 11:29:11 2015 -0600
+
+ server: HTTP parser: general improvements
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 04c32ed5753a1c4b43308e7e379d19f26e44500c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Aug 6 14:32:39 2015 -0600
+
+ server: HTTP: remove unused code
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 697dd3ac80ea56b60c7b3d8d5a8f4566d1878935
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Aug 5 13:27:09 2015 -0600
+
+ HTML: intro update
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8ff57ef1308cfc07a3babdc8bcb9c57d8e9b1d85
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Aug 5 13:11:59 2015 -0600
+
+ QA: update scripts to new htdocs content
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 08ebcfe0e9fe10cd6165bdde7f16216ab4d806cf
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Aug 5 11:05:44 2015 -0600
+
+ server: scheduler: invalidate scheduler mode when initializing
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 03a79f05027adda286bc4d51cdfc7c560ff07f0b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Aug 5 10:53:50 2015 -0600
+
+ Doc: remove draft doc
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 90641dd3ab239f0e80d633a1f106955d4aecb3a1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Aug 5 10:27:24 2015 -0600
+
+ Build: new option to use mbedtls shared lib (installed somewhere)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 57eb2f6363db95f07b1e5c3179e525bd642d8b76
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Aug 5 09:53:21 2015 -0600
+
+ Build: configure: fix banner
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 125709c0a104fa1c17a31d7f41e63e8f0071afd7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Aug 5 09:18:32 2015 -0600
+
+ server: scheduler: validate if channel is busy on event_write
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5517c83c4089eca84b7051fd7f24c391ac7dc584
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Aug 5 09:14:02 2015 -0600
+
+ server: stream: fix trace message when consuming bytes
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0e5b14e0a20428e7555156e8ef201223ebca410c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Aug 5 07:22:15 2015 -0600
+
+ server: validate listner list head when exiting
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 71579c4e83488a20d8afc3bb4e529f2f76917127
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Aug 5 06:40:23 2015 -0600
+
+ Build: make sure to generate 'modules' for OSX instead of shared lib
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2d4fd2d01338f2b933d010f5c12a6bd223b84c9e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Aug 5 06:14:09 2015 -0600
+
+ Deps: add mbedtls sources as a dependency for TLS plugin
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 012f1abccad3128b000d8c1b150376e1ddff9778
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Aug 4 14:21:53 2015 -0600
+
+ bin: signals: restore uid/guid upon exit
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 338e595c7b9281172fa71c7acba0099a1873b561
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Aug 4 14:06:57 2015 -0600
+
+ server: scheduler: abort on listener problem
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c0932895310200aa637cd0c6ecbec1a0e4097d64
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Aug 4 14:06:40 2015 -0600
+
+ server: scheduler: if listener fails, return NULL
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e68ccfd99590d873e95d8c639d964ee3486fee82
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Aug 4 14:06:14 2015 -0600
+
+ server: socket: return error value if cannot bind
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8100ed24a1b22c2da29ead8d84abdecb71e8773e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Aug 4 12:36:54 2015 -0600
+
+ Build: restore 'bash' for configure script
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4b052a302101e81547f5f29d93ab5ee6f57dfd71
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Aug 4 12:03:14 2015 -0600
+
+ server: stream: fix trace message for 32 bits platforms
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f93cb2d173dbace2c21a5ed888fa903e9094fbe9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Aug 2 20:57:00 2015 -0600
+
+ HTML: add CMakeLists.txt file for content installation
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 69276b66028e2c31cffa91419846ed4f83dc34d7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Aug 2 20:33:40 2015 -0600
+
+ HTML: update homepage with new template and branding
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8bfffd1f511d49083c658203809f33ead6a6763d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Aug 2 05:53:55 2015 -0600
+
+ Plugins: logger: do not use mk_libc_error from plugins
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 35169f869f46bd30ccc04533f0dd6c702fd17245
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Aug 2 05:50:09 2015 -0600
+
+ server: plugin: remove unused function
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e9982e355014f21c50a5712b83b841543f6a3d02
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Aug 2 05:48:43 2015 -0600
+
+ mk_core: file: change data type for size field
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 467471fcf80a28d27c78a3c66655bb3443946e09
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 1 18:41:35 2015 -0600
+
+ Plugins: fastcgi: fix reference to channel_write
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7c0242a3aeed802fdeac6b626b6775700d689fb5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 1 18:38:41 2015 -0600
+
+ Plugins: cgi: fix reference to TLS
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 55ac31218959d57fc3fdf3906595df6b97bcf26b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jul 31 15:27:50 2015 -0600
+
+ Plugins: tls: functional with mbedtls-2.0
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 07b811096b795ff87cc905be0bb113190c2a69ab
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jul 31 11:14:02 2015 -0600
+
+ server: scheduler: on read error, validate EAGAIN case
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2f5639ef94cb106fbdd714644448c09b5d9e41ac
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jul 30 15:37:45 2015 -0600
+
+ server: HTTP: fix LF catch limit
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d254c61e209aaaf9e1d10a175053e2be3a23cc80
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 23:43:21 2015 -0600
+
+ Plugins: auth: mk_passwd: validate when dumping info (CID 1245666)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2f0b50123c16885f91f72b1737792fa170e87a43
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 23:40:55 2015 -0600
+
+ server: http: fix error page leak with HEAD method (CID 1299283)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d258adcbee6011ad9ba13382a6313587c0d85376
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 23:30:28 2015 -0600
+
+ server: http: validate return value of resource check (CID 1245652)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 49b5e03de046e4105932d43be026b81d5cdbbcca
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 23:28:31 2015 -0600
+
+ server: vhost: do not leak file descriptor (CID 1245664)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 97f5f9a5adaae23ce8275028f24cefaec39e2f5d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 23:27:27 2015 -0600
+
+ server: http: on status error, validate content length against method
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6d81d929643092ece4a53562a1070b503c4f9676
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 23:22:40 2015 -0600
+
+ server: config: do not override list of values (CID 1299286)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 737d3b1b9cd9ccad715b83457694481153797177
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 23:09:19 2015 -0600
+
+ server: make sure timeout_fd is valid before close it
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 311db001a3087ac20f2e9df0761a5c71678d7dc6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 23:08:22 2015 -0600
+
+ Plugins: logger: fix unitialized value (CID 1313320)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 91b4107f6986cec1fa1bf6da60db2556e322c9dd
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 23:01:23 2015 -0600
+
+ Plugins: TLS: move API for mbedtls 2.0 (not functional yet)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 37bb5e1919073b0f44953105cfa2497419e81e9e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 19:47:47 2015 -0600
+
+ Plugins: mandril: adapt callbacks to new API
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6b77fbd253ee4e76512a9eb1b7623bd0c60a2a4d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 19:47:25 2015 -0600
+
+ server: scheduler: do not print out msg if connection was block by a plugin
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit eb632b4240876a534a35f7e8bfa3465cc4a934c2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 18:46:51 2015 -0600
+
+ server: on exit remove listeners
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6365f40ff244c4bbce5dac5b6c8e2af46d2df892
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 17:51:49 2015 -0600
+
+ Plugins: logger: fix pthread_cache initialization and get rid of the evil _mkp_data
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 55eb5a63ce21a0e9802ab2a91d161426422b140b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 15:59:39 2015 -0600
+
+ Plugins: logger: adapt to new API
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0a9e696d9882042de07cc4752c9a4533ccf598e2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 15:58:40 2015 -0600
+
+ server: http_parser: fix pointer protocol length
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 264c6f488d8d237e24b8f4bf7e8f2299d184238a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 15:58:14 2015 -0600
+
+ server: HTTP: invoke stage 40 upon request end
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3570ba2861dd0c13afe6d0bfa95872b1b360ac7b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 14:02:12 2015 -0600
+
+ server: streams: do not release stream with pending bytes
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 85e492d766599b89a0d9a148df9a13fe26d1706f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 11:51:21 2015 -0600
+
+ Plugins: dirlisting: general improvements and cleanup
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7d31f9764a962c62ddf340fcf8b4d1223fb996e4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 27 11:51:00 2015 -0600
+
+ server: streams & http: cleanup channel on exit
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 86aa7ee843a3b609bad921ddc5db8be14c21b1ca
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 26 12:43:04 2015 -0600
+
+ mk_server: HTTP: do not walk around all stage30
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 870ff952ef530de5911ea4bf56d1233c6642534b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 26 12:27:26 2015 -0600
+
+ Plugins: cheetah: fix format parameters
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 268072bd72ab6f7eb888d3b8afc0e381f917df91
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 26 12:15:52 2015 -0600
+
+ server: vhost: fix missing plugin msg
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 801352f0550e7574b3b61d935e86fb68d33ea565
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 26 12:14:34 2015 -0600
+
+ Plugins: cgi: fix unitialized vars and use proper URI address
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3a10263b7007320df59a10bf001bf6ee7cd69d52
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 26 12:07:48 2015 -0600
+
+ Plugins: auth: fix number of parameters
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0e293b071cb608a47a8b0d393544a0238ebaa2c5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 26 12:07:35 2015 -0600
+
+ server: HTTP: remove silly msg
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit eb0dbf936e70d64e4438c64a49ae7486d80aa990
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 26 11:53:47 2015 -0600
+
+ Plugins: fastcgi: fix callback parameters
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f26f2108e760411b460aee0b277c695db05213cc
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 26 11:49:40 2015 -0600
+
+ Plugins: cgi: handle parameters from handler setup
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit aa986169ebf4ba648fded97fec95626599dee16f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 26 11:47:22 2015 -0600
+
+ server: plugin: handlers now support parameters
+
+ The handlers definitions on virtual host now can specify parameters, e.g:
+
+ [HANDLERS]
+ Match /.*\.cgi param_1 param_2 param_3
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 98481f6f2755f49e74aa88c30ee1587aa809324b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 26 06:55:49 2015 -0600
+
+ server: HTTP: do not handle missing files with a handler (temporal)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d164a051bf053babe30742277dee8acb0a15f230
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 15:04:05 2015 -0600
+
+ mk_server: add handlers support
+
+ this patch enable a new Handlers support for plugins, so now is
+ possible to define custom handlers for specific URI matches based
+ on regular expressions, a virtual host may enable FastCGI through
+ the following setup:
+
+ [HANDLERS]
+ Match /.*\.php fastcgi
+
+ The 'Match' rule indicate that it's about a regular expression, the
+ second argument is the regexec and the third argument is the plugin
+ handler name (known as short name).
+
+ Handlers are processed in order, if no handler own the request the
+ server will dispatch the file content.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit dd2e7bee7e990cc3111522e997a20e2459ef41b9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 12:49:14 2015 -0600
+
+ Plugins: fastcgi: make query string conditional
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0a9a2237ac6e90630c28e650cbdc04aeeef208f7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 11:42:22 2015 -0600
+
+ Plugins: fastcgi: handle unix socket mode
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 097fbc702f70320a8e53f916ac181582904a5469
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 11:41:57 2015 -0600
+
+ mk_server: plugin: new api to open unix sockets
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 28c4683c7a667bdec8b47cad49ff567a01cd6d1d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 11:40:56 2015 -0600
+
+ mk_server: HTTP: flush error page on error
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 763d032e4044ae705e84c321cd6694c2bdb218ba
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 10:36:29 2015 -0600
+
+ plugins: fastcgi: general improvements and cleanups on broken connections
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e9cee1f7fa37a5daaff71bb985bf918b1db84c7e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 10:35:48 2015 -0600
+
+ mk_server: server: do not process idle connections
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit dbea72780a8e9880db44bdb9b011e23a32a6a838
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 10:35:17 2015 -0600
+
+ mk_server: scheduler: initialize event and defer event free
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 858491d1b074ecbd16504c2a0be0e7c0c569f2e7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 10:34:31 2015 -0600
+
+ mk_server: plugin: on request end, set the connection as incomplete
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit aa0fac20feb1e14f3581d2bf767a0108e5f68100
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 10:33:56 2015 -0600
+
+ mk_server: HTTP: set handler data and perform channel cleanup on broken connection
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d685645426848e5917c2e4f34a73c3740594730a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 10:27:46 2015 -0600
+
+ mk_core: event: add new status field
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 76d557a916a2040eee8bc00d80e11725e2b176c3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 10:26:00 2015 -0600
+
+ mk_core: iov: fix buf_to_free reference
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit af9f867c44bfed3fea54d57488247aba2d13a1d2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 10:24:58 2015 -0600
+
+ mk_server: stream: new clean interface to remove channel data
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8c53246ee66249d054a87a80da9fa9818fffe7ac
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 10:23:36 2015 -0600
+
+ mk_server: HTTP: session request now have a new handler_data reference (used by plugins)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5a2eca4e4b3b411b1da49efce9da56ed713c044f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 10:22:55 2015 -0600
+
+ mk_server: HTTP: do not mk_bug() when status is already completed
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6cd33fc88cd8596d7540e7187b80aa0401f5804f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 25 10:21:24 2015 -0600
+
+ API: fix MK_TRACE position declaration
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5051e1a7117020cbb96f36341ba0f24b53fab409
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jul 24 09:35:39 2015 -0600
+
+ Trace: shrink component name
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4d1e398b1acb747227734af9166e820713849e08
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jul 24 09:13:45 2015 -0600
+
+ Trace: shrink file path, do not include absolute path
+
+ This patch makes CMAKE to define a new macro called __FILENAME__ which
+ allows to set the relative path of the target file instead of the absolute
+ path, e.g:
+
+ before: /home/edsiper/coding/monkey/mk_server/mk_server.c
+ after : mk_server/mk_server.c
+
+ Now the trace mode use this new __FILENAME__ macro making the output
+ a bit friendly.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a680478232959070ae4cfe7e02216badd1ff2070
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 22 22:32:14 2015 -0600
+
+ Plugins: FastCGI: fix unitialized variable on on_read callback (CID 1312111)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f05a8c4d0b833c8239026ee4a7cd5d1827bc7ead
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 22 22:28:47 2015 -0600
+
+ Plugins: FastCGI: do not assume 'buf' can be null (CID 1312110)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 856858980ca0a6d0dcf0f0ba237a31b2033fca3a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 22 22:19:45 2015 -0600
+
+ mk_server: streams: fix dereference after null check (CID 1312109)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit df43e8bd93980c6977d07eb3a1af3164623dd28d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 22 21:59:28 2015 -0600
+
+ Plugins: CGI: devnull cannot be negative (CID 1124125)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 232b036cc2d7a95abef27681cb9d47f7fc20bf7c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 22 17:58:06 2015 -0600
+
+ Plugins: FastCGI: add missing return value
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 72b3b52ee9daf1d1444613c97550d6f5968c2262
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 22 17:57:28 2015 -0600
+
+ mk_server: plugin: re-map socket inteface
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d9bf3ffaabddbee11a3709d6c20d1ef837e95a26
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 22 17:55:49 2015 -0600
+
+ mk_server: socket: improved connect interface
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1f9eb5c84426e036c5baf7611e82f2c27a646dd1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 22 17:55:17 2015 -0600
+
+ mk_server: http: add header counters
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ad043900b9bf8d4e0536b24198d3967869510cf4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 22 17:54:18 2015 -0600
+
+ mk_core: event: new initializator
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ace406df30d6e627345916f857e458314c3360f6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 22 17:51:50 2015 -0600
+
+ Build: enable fastcgi plugin by default
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 989bae1d501f9c010283f24698294e4111f4aa7a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 22 17:49:59 2015 -0600
+
+ Plugins: FastCGI: new FastCGI plugin
+
+ This new implementation of the fastcgi interface use the new Monkey
+ architecture and reduce the code complexity due to the new features
+ available on the server core.
+
+ It drops some neat features from the old version as KeepAlive and
+ the ability of multiple connections, all that will be restored in the
+ new version of Monkey which will support server pools natively.
+
+ Note: old plugin required like 3000 lines of code, the new one only
+ around 650.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d380488a14f9b914a49b8de5d75b90f9c0b4e19b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 22 17:45:57 2015 -0600
+
+ Plugins: FastCGI: deprecate old FastCGI plugin
+
+ This patch removes the old fastcgi plugins due to the following reasons:
+
+ - New Monkey architecture requires plugins to hook and work in a different way.
+ - New Monkey features abstract many interfaces that were required by the old plugin
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ceafd30127c7c22a6612534521b72c2576f9239f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 19 19:17:52 2015 -0600
+
+ mk_server: http_parser: map body content
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e34a971e17b737b099e3c130cc1a27741d88a76e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 19 18:23:06 2015 -0600
+
+ Build: use absolute path on --local mode when setting up the document root
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 42caa74b228a77c21470385eec1a190fe1e92937
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 19 17:05:01 2015 -0600
+
+ mk_server: scheduler: new macro to get connection layer capabilities
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 89781b5963af38289d9f42c4f6502637ddc51b1e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 19 14:47:07 2015 -0600
+
+ mk_core: iov: fix iov reference pointer
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2c459b61fc69c85eed10d6a853ecd625d713b207
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jul 7 17:53:53 2015 -0600
+
+ mk_core: iov: new implementation for mk_iov re-alloc
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 79630e6945e4e106f87480b2c67514e214143fcc
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jul 7 17:39:12 2015 -0600
+
+ mk_server: header: now each response context have it own iov buffer
+
+ This patch get rid of the cached (TLS) iov buffer for the response headers. It
+ now implements a struct mk_iov inside the struct response_header.
+
+ No extra memory allocations are required, we keep the pattern of one memory
+ allocation per request for HTTP/1.1.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5eb89be5bd4980030f8581c03432374045054fa4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jul 7 17:37:21 2015 -0600
+
+ mk_core: iov: improve implementation, use just one memory buffer
+
+ This patch makes the iov handler to use just one memory buffer instead
+ of multiple allocations. It also defines a new allocator and initializator
+ function.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6e749e93bc78a43e03b18a7ced442345a9dfb5f7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jul 7 07:52:57 2015 -0600
+
+ Plugins: cgi: defer event free when a hangup is faced
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0773a305c299e73a5d51b7fa3d48d88ac9989a61
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jul 7 07:52:30 2015 -0600
+
+ mk_core: event: add new field for generic purpose of a linked list
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit bb079fe1197e005e1d311af7950025d48d8ff1b7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jul 7 07:37:17 2015 -0600
+
+ mk_server: scheduler: new interface to enqueue defer events object free
+
+ This patch implements a new scheduler interface that allows the plugins to
+ defer the release of some object, the context and requirement of implementation
+ is based on the following behavior:
+
+ 1. A connection is being handled by a plugin (e.g: CGI), the CGI plugin also
+ registered it own 'event' into the Event Loop to read incoming data from the
+ child process.
+
+ 2. Before to receive the response, the client for some reason closes
+ the TCP connection.
+
+ 3. The Scheduler will trap the 'close event' on the connection and start
+ notifying the protocol handler and the plugin associated about this.
+
+ 4. The plugin will catch the notification on it stage30_hangup() callback so it
+ will release it resources (CGI context, child process,
+ close file desriptors, etc).
+
+ 5. At this point in the same Event Loop round, it may contain many events notified
+ in the array, e.g:
+
+ [0] TCP connection closed
+ [N] others...
+ [16] Read data from CGI child
+
+ So when we reach the the 'TCP connection closed'[0], we perform a release procedure as
+ stated on #3 and #4, but then we reach 'Read data from CGI child'[16] but our event
+ context was already released due to 'TCP connection closed'[0]. For hence we face a
+ memory corruption.
+
+ In order to avoid this kind of situations, the Scheduler and the plugins interface now
+ provides a new interface to request the Server to perform a 'memory release' of a linked
+ list of 'struct mk_event' after processing all the events in the round returned by mk_event_wait().
+
+ A plugin only requires to be aware of the broken connection stage30_hangup() and register it
+ event object mk_api->sched_event_free(struct mk_event *x).
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c9c44785e354efd6c776509c48cb600464b56589
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 5 21:45:47 2015 -0600
+
+ Doc: update draft announcement
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9b3e6f055972d774876d3af6ba337955f8f09ca5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 5 21:17:01 2015 -0600
+
+ Plugins: cgi: better handling for exceptions
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ced05634e7b79fb03c5d44f01a851d6ca6da6f02
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 5 21:15:25 2015 -0600
+
+ mk_server: stream: more debug message when TRACE is enabled
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1e1c5082221e4f52cdbf3fbf8dbf1dff78e3687c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 5 21:13:44 2015 -0600
+
+ mk_server: scheduler: improve drop connection routine with new socket flags
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 22b565337b7f3270abbefb7d993222a6fb628c00
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 5 21:13:01 2015 -0600
+
+ mk_server: plugin: on http request end, handle event close with a DONE_SOCKET flag
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d88cf83f0179f940e6704c49a40a655db15b3246
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 5 21:10:57 2015 -0600
+
+ mk_core: event: new SOCKET_DONE status
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a20fd2be48461ac20f73a191faefeafb79037b65
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jul 3 09:32:53 2015 -0600
+
+ Plugins: cgi: remove breakline
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 57b448421c258b3ad777ffe1beca5e04afd71b34
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jul 3 09:32:35 2015 -0600
+
+ mk_server: plugin: fix validation of list of http requests
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b9c27a55fdf5f59ac173bc0380a5278dea0d8e72
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jul 3 07:16:20 2015 -0600
+
+ mk_core: utils: rename backend of mk_libc_warn()
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d3fc419519a6c3d32f5f4b5065d1cf7bd7f1a263
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jul 2 12:59:53 2015 -0600
+
+ mk_core: implement a static buffer for libc error messages (fix #195)
+
+ Monkey utils implements a buffer per thread to format libc errors, but
+ when the mk_utils_libc_error() is invoked from the parent process, it
+ may crash as the pthread key do not exists.
+
+ This patch implements a static buffer for those cases when the call is
+ invoked from a parent process.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e5407e2c547c60a44b76db1c7215ce730a4c69e0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 30 17:08:46 2015 -0600
+
+ mk_server: plugin, http: session handling improvements
+
+ This patch add some improvements over the Plugin interface to provide
+ more reliable handling of connection at the plugins levels (e.g: CGI),
+ it also adds a new callback to the stage30 based plugins to be triggered
+ when a hangup is faced (very common).
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9f46b81ab442b90befe7880f4e251fd58d31660f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 30 17:04:01 2015 -0600
+
+ Plugins: cgi: improved session hangup and cleanup
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit fa5adce7128fcd91d62da968f21c7aa108b23ac6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 29 11:34:24 2015 -0600
+
+ Plugins: cgi: keepalive only allowed for HTTP/1.1 connections
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 12428e6658ae846762af08f9fa5c8b34ca32a3dc
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 29 10:50:05 2015 -0600
+
+ Plugins: cgi: restore session hangup
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0ef0dee8d8155eb116ae035836be411540e204ba
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 29 10:48:25 2015 -0600
+
+ mk_server: http: fix api to handle request_ends
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8c73d44c269c822e5b9bc2320260a3b0bb179094
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jun 27 06:56:57 2015 -0600
+
+ Plugins: cgi: close CGI pipe read end
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 87a188c212beb9d453845297217ab0205f198467
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jun 26 23:28:53 2015 -0600
+
+ mk_server: http: add support for ETag header (fix #139)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 239af215c7ed9b529ad24687aff5382d8805fad8
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jun 26 17:08:05 2015 -0600
+
+ Plugin: fix trace message (fix #181)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3e5025e51865979fc6fff73b6ebcbc2ccd7a596c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jun 26 17:04:04 2015 -0600
+
+ Doc: update man page (fix #196)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0319ce1ef112ded31f6eef854f2e2867aee7a21c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jun 26 15:39:03 2015 -0600
+
+ Plugins: cgi: workaround for separate breaklines (#202)
+
+ This patch makes to read the whole data in the buffer until the
+ breaklines are found, if the buffer becomes full it will abort
+ the CGI program.
+
+ This implementation needs more testing.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 94cfa12080d3a4be979e8d5da27992d862d3855c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jun 25 16:46:25 2015 -0600
+
+ mk_server: http: fix trace messages (socket number)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9b11ec43623a703ad05e67678f45f8d446906054
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jun 25 16:28:53 2015 -0600
+
+ Plugins: cgi: use Monkey streams to dispatch data to the client
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3f9b90ce3d9052ec218ee280c51c8e2bd1327c8b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jun 25 16:27:12 2015 -0600
+
+ mk_server: streams: new interfaces to 'intent' to flush data
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f294a7d4480c992e3a1d17d4574c55755e3f523f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 24 23:08:45 2015 -0600
+
+ mk_server: stream: add copybuf handling to stream_set
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 027706c4adc4e11be013732fd70a14c112264a71
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 24 18:01:26 2015 -0600
+
+ mk_server: stream: handle MK_STREAM_COPYBUF
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5e4ae0f504555a91373f34ea6a67c02b839426f9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 24 14:24:20 2015 -0600
+
+ mk_server: scheduler: initialize variable
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4de656146e10fa775f6ae3b1c1e53de6c15fb7fd
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 24 12:22:44 2015 -0600
+
+ Plugins: cgi: little API changes and add CMake rules for configuration (#184)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1be4f4500f2b845fc972a0ab4a7f157fd7f34f2f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 23 22:50:00 2015 -0600
+
+ mk_server: re-implement timeout handler
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4583d128d283f4a851f60b049a1053dc683f2863
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jun 19 20:39:44 2015 -0600
+
+ Plugins: build plugins with position independent code (PIC)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a0e5c7334d7dfc74e312059f2a8ca5291844285a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jun 18 11:23:50 2015 -0600
+
+ mk_core: event: workaround for old Linux Kernels without EPOLL_CLOEXEC
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ac8be28bc69c2e024d969df91f35493b92fd542f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 17 09:48:57 2015 -0600
+
+ mk_core: event: fix leak if loop events mem creation fails
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7186e87f8fb80a1a34228710dde0cb5cfcf49e4e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 17 09:48:22 2015 -0600
+
+ mk_core: event: fix leak if loop creation fails
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 32e69eecbe7e483267012c110ad9bb1379485eb7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 17 09:45:00 2015 -0600
+
+ mk_core: utils: fix leak on PID file after locking
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 62e73837abf39ab1cd7b7aab9253fa763631fcb9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 17 09:37:20 2015 -0600
+
+ mk_core: utils: improve validation check when registering PID
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4f6d84cf616e68d8fb1ac293a89f14c44c7b56f5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 17 09:33:07 2015 -0600
+
+ mk_core: iov: make iov_print work again
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7bac859c623c112b565862e00e1be2333bf4bc2f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 15 16:46:10 2015 -0600
+
+ mk_server: server: fix unitialized variable reuse port
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ab7bbf5307177830621639e22c6e0cd15b46b090
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 15 16:45:09 2015 -0600
+
+ mk_core: config: fix leak on split list
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e219aeca6840a114e71d3128e81bbd196666d92a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 15 16:40:14 2015 -0600
+
+ mk_server: http_parser: fix method table index
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 172ef76e626b68c678b745bdf6d243cc7b736218
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 15 16:34:13 2015 -0600
+
+ mk_server: http_parser: remove unnecessary continue() after parse_next()
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2be215b216172a0295ff44edc7f64c23bc942faf
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 15 16:32:56 2015 -0600
+
+ mk_core: rconf: do not over validate configuration context
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4521934825c1ecc58df82b34a8ae5542c7189c45
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 15 16:31:41 2015 -0600
+
+ mk_server: plugin: validate plugin instance
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4bd3a9bb903740031f5af2a58b45bfd6810e7539
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 15 16:30:47 2015 -0600
+
+ mk_server: plugin: close handler on exception
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f0c80f93024347d7030644fdeb646ddb5436b00f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 15 16:26:16 2015 -0600
+
+ mk_server: plugin: fix stage40 call assignation
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 41f890e01f5a595c79a2c2918f50c42e16802dab
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 15 16:25:19 2015 -0600
+
+ plugins: logger: validate return value of fcntl() calls
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3fb870f276ba6b75bd75370941d288ced34fb6ac
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 15 16:20:47 2015 -0600
+
+ mk_server: socket: validate tcp_nodelay return value
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4445249a91db4b2057730685e55a330a7646fd1e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 15 16:19:50 2015 -0600
+
+ mk_server: http: validate return value of cork_flag func
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1771d759e3d7c16f03c2bb43cc125017d0fe78ba
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 15 16:03:27 2015 -0600
+
+ mk_server: rework connections timeout handling
+
+ This patch re-enable the timeout handling into the scheduler, it now works
+ as follows:
+
+ - Scheduler implements a new timeout_queue linked list (similar than before)
+ - Scheduler register all new connections into the timeout_queue
+ - Connections that have not send any data upon a timeout check, will be
+ dropped.
+ - If a connection sent some data, the protocol handler is in charge to
+ unregister the connection from the timeout_queue.
+ - For HTTP KeepAlive case, the session is registered on the timeout_queue
+ everytime a response was sent.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 79294d2bda10c31c35a7f86690cc295579edc992
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jun 14 21:03:38 2015 -0600
+
+ mk_server: move server_info func
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit daf22a2a13ac7eddfd1645c1f5b7eb649f46ef4c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jun 12 16:38:37 2015 -0600
+
+ mk_core: rconf: validate NULL path before create configuration context
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2e4d82a3558b79f2836991cdfdf78f7ca6a2c11f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jun 12 16:37:07 2015 -0600
+
+ mk_server: do not abort when no mimetypes are registered
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit afcdf28455b5755136d527e861fe6562819481f0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jun 12 12:16:36 2015 -0600
+
+ Build: new WITHOUT_CONF CMake option to skip configuration files
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 889cd613bc8b19c20c56009adee3478af1a557ba
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jun 12 12:05:38 2015 -0600
+
+ mk_server: plugin: check if a plugins config file was set
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 71e79106e550afab974ca03d52380e115764a92b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jun 12 11:33:56 2015 -0600
+
+ mk_server: plugin: do not abort if there is no dynamic plugins
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit af1ffbb13e2838a8b23ed7daf6b2bb3d4352bddf
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jun 11 11:23:11 2015 -0600
+
+ mk_server: set -fPIC to C_FLAGS
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f2ca8ab23d47c0ebe01a8664b8018202a488d5c4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jun 11 11:03:06 2015 -0600
+
+ mk_server: build: link to -dl using CMAKE_DL_LIBS variable
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d024fdee05a6379138f818ecf5ccffb67d517d5a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 10 19:44:15 2015 -0600
+
+ CI: add OSX as build system
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit aa04d958ed18472b9eed2fae78f2baf8a43e8ae4
+Author: Chris Johns <chrisj@rtems.org>
+Date: Thu Jun 11 11:14:52 2015 +1000
+
+ mk_server: build: fix library lists rules for FreeBSD.
+
+commit 87f3012d3bcd70ee696bba554f5312facbbaa2ab
+Author: Chris Johns <chrisj@rtems.org>
+Date: Thu Jun 11 11:14:24 2015 +1000
+
+ mk_server: socket: platform neutral sockopt setting
+
+commit 3593904c35c0f102d919ee5d83b0f41f9f893b60
+Author: Chris Johns <chrisj@rtems.org>
+Date: Thu Jun 11 10:55:57 2015 +1000
+
+ mk_server: Liana: add FreeBSD support for sending a file.
+
+commit 8e88d356c86afd8d6be02bc845b000dd4a24344f
+Author: Chris Johns <chrisj@rtems.org>
+Date: Thu Jun 11 10:43:15 2015 +1000
+
+ Configure: add support for FreeBSD
+
+ Switch the shell to /bin/sh as this should work on all systems.
+
+ Make the colour support specific to Linux.
+
+ Show Monkey is more than just Linux these days.
+
+commit ffe2625d75639d0a48daa26f8651b8a7f23ec53f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 10 15:39:13 2015 -0600
+
+ mk_bin: mk_server: move signals interfaces and cleanup executable calls
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d7b4f703bb4295888c6dbd37e69c930813580bd7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 9 11:21:45 2015 -0600
+
+ mk_server: scheduler: fix variables on trace mode
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 090462eb5302654394e87fad74c77079998f4101
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 9 11:13:56 2015 -0600
+
+ mk_core: event: epoll: fix parameter when trace is enabled
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit eed81571a50a58c997c1458147ed8253b414783a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 9 11:12:29 2015 -0600
+
+ mk_core: adopt mk_file interface
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 42225b674517d89eb87b9ffa0230e6c987118b92
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 9 11:02:57 2015 -0600
+
+ mk_core: event: epoll: align API change for event_del()
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5a2d722e08f7783ff7d6200871a6a529495a485a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 9 10:58:39 2015 -0600
+
+ mk_core: event (mk_server): use event context when deleting a connection
+
+ this patch makes the event handler to use the connection context mk_event as
+ a reference to obtain the connection file descriptor and event bitmask.
+
+ The main reason for this change is the requirement to get the existent bitmask for
+ the kqueue interface, when deleting an event it needs the 'filter' associated and this
+ is translated to the event mask: EVFILT_READ ; EVFILT_WRITE.
+
+ For epoll(2) backend is not required but there is no performance penalty associated,
+ epoll backend patch already coming.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8ba5c4fbc56f76a6a97da21a1ce6c22258af90e7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 9 08:51:54 2015 -0600
+
+ mk_core: kqueue: fix mask when adding a new fd
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2cdeec3cd1e0fbf02afd8d7818e3a98de948414b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 9 08:47:18 2015 -0600
+
+ mk_core: add missing declaration of memrchr for OSX
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c80b114349b70a19657e332adc404cf05ecc4c9d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 9 08:39:49 2015 -0600
+
+ mk_core: kqueue: remove unused variable
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4b92fe6cb528ec6bdfcb8edf61fd70641e7f56c4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 9 08:35:23 2015 -0600
+
+ File: add time header
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit bc286b7995ca518c186e3c64c2aa4dbd2f729388
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 8 22:43:59 2015 -0600
+
+ Build: fix linking to jemalloc when is enabled
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 303cb4c56695c4ce7609ab2150eb389de9ec6e26
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 8 16:31:46 2015 -0600
+
+ mk_server: fix compiler warnings
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit fffffe67cc64517e6a3c8e45f38647d5f19af8d2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 8 16:22:29 2015 -0600
+
+ mk_server: add initializator
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit da39c4e9ad7c67545bdecb59288965fe9cda4827
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 8 16:17:10 2015 -0600
+
+ mk_core: mk_server: general fixes for building
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5aad2c798b80bc47516cc4e372fe518c8784e1d2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jun 7 09:57:42 2015 -0600
+
+ mk_core: adopt some mk_server utilities
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b135a82caa17ea3324590d2037714ae74345b260
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jun 7 09:43:47 2015 -0600
+
+ mk_bin: add build system
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2d09462fc4891988b846d1edb7cb481112f7dce7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jun 7 09:43:12 2015 -0600
+
+ Source: split code into new directories: mk_bin, mk_server & mk_core
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 67278ace622986ad7d12ff903e90c4406b0b0fff
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jun 7 08:51:10 2015 -0600
+
+ Core: fix some compiler warnings
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit aef09631c107649a1b32afe924e487120718dba0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jun 7 08:25:26 2015 -0600
+
+ Build: add rules to build static lib
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 69f8762ab3707d61aa2870b25c867e5b13f29fe5
+Author: pandax381 <pandax381@gmail.com>
+Date: Sat Jun 6 16:59:57 2015 -0600
+
+ Build: porting Mac OS X (and other BSD systems)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 542a9dfd66069eebbd0b2619bed51f81e96a42cb
+Author: nkaneko <nkaneko@iij.ad.jp>
+Date: Thu Jun 4 17:25:58 2015 +0900
+
+ mk_core: fix timeout given to EVFILT_TIMER in some BSD
+
+ This patch fix timeout parameter given to EV_SET(EVFILT_TIMER) in BSD system
+ other than FreeBSD. Only FreeBSD(or LINUX_SECOND) has NOTE_SECONDS defined and
+ specify seconds in EV_SET(EVFILT_TIMER). Other BSD expects milliseconds.
+
+ Tested in NetBSD environment.
+
+ Signed-off-by: enukane <enukane@glenda9.org>
+
+commit dfc6fd602b2ca06849967cbed711202d119787fb
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 3 17:29:52 2015 -0600
+
+ Stream: remove mk_bug() check on copybuf
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 16cd3c6dc41fc985548da7b54e2641355d6db975
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 3 17:25:55 2015 -0600
+
+ Mimetype: fix header inclusion (core)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e5d7a1f235927ed1b48a62ecd74255baaab446ec
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 3 17:23:14 2015 -0600
+
+ mk_core: move getenv routine inside TRACE conditional
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3640f6ff14bdac110c8192bd92585c809b6f7f7f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 3 17:18:59 2015 -0600
+
+ HTTP: fix header inclusion (core)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f7c46f7548e7371fb05c363904570fdb3a781255
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 3 17:13:04 2015 -0600
+
+ Dirlisting: do not try to flush the channel, just enqueue data
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5a5a4f262a75a4720db47790c8e3014540ad8b32
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 3 17:12:08 2015 -0600
+
+ Auth: fix headers and API calls
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit cc8258f9d296185845259ec0261a8b69f43c5373
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 3 03:01:28 2015 -0600
+
+ mk_core: add missing mk_rbtree.c
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4fd1504c3bb7ef00c2be9f882ca4bf35ce3f19d6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 3 02:51:35 2015 -0600
+
+ mk_core: add missing mk_memory.c
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9cf7ec5c43fa6f99b5767df1c1e3c9daf3cb5008
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 3 02:47:54 2015 -0600
+
+ mk_core: add missing mk_limits
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 520d8c7f1401f345046a50f136b71c90e91b7916
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jun 3 01:46:20 2015 -0600
+
+ mk_core: adopt some mk_utils functions
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 99aeba18807637dbcc2a91d434ab71467622f7b9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 2 23:53:04 2015 -0600
+
+ mk_core: move core files of generic features to a kind of 'lib'
+
+ this patch moves several Monkey source code files to a mk_core
+ sub-directory:
+
+ - moved only generic interfaces for memory, string handling, configuration,
+ polling, etc.
+ - useful for other projects that use some Monkey core files (e.g: fluent/fluent-bit)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 69ba3fd02a2442544ee50e732504e14882632f9b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jun 2 20:52:36 2015 -0600
+
+ Scheduler: write buffering and I/O abstraction.
+
+ this patch makes the Monkey scheduler aware about buffering and
+ protocol handling. From now Monkey core protocol handlers are plugins
+ requires to enqueue outgoing data and the Scheduler take care of dispatch
+ the information out.
+
+ Note: It still need to be tweak for high performance.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7e2a4075719ca8b06be406edfaa7a0d1e27f56a4
+Merge: 890c16f 47baec9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun May 31 18:45:51 2015 -0600
+
+ Merge pull request #209 from neeraj9/dev-use-sigsuspend
+
+ Server: Use sigsuspend instead of sleep
+
+commit 47baec966af07fd919c6e7fe36f1f42748a6df9e
+Author: Neeraj Sharma <neeraj.sharma@alumni.iitg.ernet.in>
+Date: Fri May 29 14:45:43 2015 +0530
+
+ Use sigsuspend instead of sleep
+
+ The usage of sigsuspend is both portable and cleaner than sleep to
+ indefinitely do nothing. This approach is useful in the master
+ loop (mk_server).
+
+ This commit closes #203
+
+ Signed-off-by: Neeraj Sharma <neeraj.sharma@alumni.iitg.ernet.in>
+
+commit 890c16f1cc73609ffd203c0dc2b74f3d08104748
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon May 18 21:42:15 2015 -0600
+
+ Plugin: deprecate old 'events' interface
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 240c2ab4accb5550ae06dd071a83462f640b3106
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon May 18 11:51:20 2015 -0600
+
+ Plugin: remove dead events code
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7e900b99dfae6934b51d7f6e5757f0d8ef2d88ea
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon May 18 11:43:53 2015 -0600
+
+ Server: banner now print the list of loaded plugins (Fix #185)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e426544df9513c29dbd48fee8f480883b84513a4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon May 18 11:36:11 2015 -0600
+
+ Server: -b option now lists the built-in plugins (ref #185)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b4d7ea69bb6d8baa8b1dcbe349408929e18cff86
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 16 21:41:26 2015 -0600
+
+ Core: buffer: use network layer buffer size
+
+ this patch makes the protocol handlers to respect the buffer sizes
+ suggested by the network plugin.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 22a4435fdf21c2cc2ad95e2f293f148fcdab6f05
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 16 20:24:33 2015 -0600
+
+ Scheduler: remove 'capacity' feature
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6b419d1fd22030b4f71e20d59884872ed618a9ae
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 16 20:11:34 2015 -0600
+
+ Headers: some header inclusion cleanups
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit def1f351d2e8344ac73c35df3125c4a69c66bf2b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 16 18:31:09 2015 -0600
+
+ Socket: fix variable name
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0b82d7f7e6632a1e785850ea08a1bd705de0365c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 16 18:25:58 2015 -0600
+
+ Build: CMake: rename mbedtls option to tls
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 04290bc6fd5580ebb9190df711b575531ab55508
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 16 18:23:04 2015 -0600
+
+ TLS: polarssl plugin fixes and rebranded as 'tls'.
+
+ This patch makes some changes on the old polarssl plugin and is rebranded as
+ 'tls'. It now depends on mbedtls library.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5267220b44b65a5a8e41aafb280ae173e3d0ea13
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri May 15 17:06:24 2015 -0600
+
+ Core: new network layer abstraction
+
+ This patch implement the following changes/features:
+
+ - Listeners configuration allows extra parameters or flags, the options are:
+ - http
+ - http2 (not implemented yet)
+ - ssl
+ these options are handled as 'capabilities' by the plugins and the core
+ interfaces.
+ - Each scheduler connection is linked to a protocol handler and a network layer
+ plugin.
+ - Due to previous changes, now multiple TCP ports can have different capabilities
+ and use multiple transports layer.
+ - Global configuration is not longer aware about networking stuff.
+ - Socket interface cleanup: moved network features like server, bind & connect
+ to it.
+ - Channels are now linked to the network layer interface.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3da7a940212e7e3fe70af8de0d63f74a1fe3ceea
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu May 14 14:10:52 2015 -0600
+
+ Config: Listen key now support flags: http, http2 & ssl (not yet functional)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit dc9f68cb24eaa116edcc9b566ca95709f621c672
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon May 11 14:47:52 2015 -0600
+
+ Server: remove silly printf msg
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 40e72221a9e6ff12adcba32fad75b601f17b8d9a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun May 10 21:24:28 2015 -0600
+
+ Build: CMake: when using jemalloc, link pthreads explicity
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3c4770c2aae04c927d2a5faeed387c0b983f5409
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun May 10 21:05:32 2015 -0600
+
+ Build: CMake: do not repeat parameters when adding libraries to the monkey target
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 45da3b13301c152f5f4a6e644e27a5a5763f6aa0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun May 10 20:57:49 2015 -0600
+
+ Event: Kqueue: fix backend to align to new Event core interface
+
+ This patch modify the kqueue backend to align to the new Events mechanism,
+ at the moment it 'compiles', but it's not 100% functional.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 43290a4dee0220beed77069271c8394392d89d5b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun May 10 20:30:22 2015 -0600
+
+ Event: remove old references to event file descriptor table (EFDT)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f46e84626162684db700d7ffa10130e46acb57b4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon May 4 11:11:42 2015 -0600
+
+ Event: epoll: do not zero events struct
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 44348ebe228511892371b3b15da9c49a214743a2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon May 4 09:36:08 2015 -0600
+
+ HTTP: improve how to check keepalive and session closing
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c45dfe03289336520108e35e1c89167e246a1924
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun May 3 21:03:56 2015 -0600
+
+ HTTP: deprecate support of old Keep-Alive response header
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 05cc0e704fc9eabc3abeb14f1e39dc2b537a0e31
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun May 3 13:45:16 2015 -0600
+
+ IOV: do not print out an error if array is outside of size
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8bc7294801f1e0bdf8b92c45b327a2b362cc6032
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun May 3 13:37:37 2015 -0600
+
+ IOV: on consume, check best of case where all bytes where consume (avoid walk around the array)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f1d284238bf8212ee3765cc3310cf7b088739324
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun May 3 13:29:30 2015 -0600
+
+ HTTP: store session in extended Scheduler connection memory area
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4c8d6d9b2cec996c2589b37e24924919bb9b17e5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 2 15:46:40 2015 -0600
+
+ Doc: draft of v1.6 Announcement
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit aaa8977a5cdc45e9b53e7e005371b75001a697c0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 2 15:42:56 2015 -0600
+
+ Scheduler: support protocols handler.
+
+ This first patch makes the Scheduler aware about protocol handlers
+ per connection.
+
+ One the next set of patches the following will be implemented:
+
+ - Configure Listeners handlers per configuration
+ - Let CMake define protocols/handlers available and auto register
+ - Improve Scheduler memory allocation for protocol/handlers that
+ will own the session (e.g: HTTP).
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 94cb66c178c2b69f30080b1c0fce348f59ca7d07
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 2 14:47:05 2015 -0600
+
+ Mandril: use new rconf api
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e7326959203b248281f9338852f8f9019121b8e7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 2 14:45:06 2015 -0600
+
+ Logger: use new rconf api
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6a917c5928140642314d8ffc260711c3f19a144d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 2 14:43:49 2015 -0600
+
+ Dirlisting: use new rconf api
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a1a6461f91c90a54a6c25adbe0586e5ebc3cf4a1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 2 14:43:08 2015 -0600
+
+ Cheetah: use new rconf api
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit fa9c420a7c4bd3c1c1472341cb7577c82ab5384d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 2 14:42:02 2015 -0600
+
+ Auth: use new rconf api
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit dd534ad6a2ebc7282b44646521b55ccf7053247d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 2 14:39:01 2015 -0600
+
+ RConf: new interface to handle configuration files.
+
+ This patch creates rconf which is a new interface to read configuration
+ files, it basically take the routines to read configuration files from
+ the mk_config.c and place it in a new mk_rconf.c, functions got renamed
+ and some macros changed.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1ebbb35d3f78af749c3451a6468a12ca51233fee
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 2 10:44:37 2015 -0600
+
+ Scheduler: rename sched_list_node to mk_sched_worker
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit cf8a4f4dc56e5b92b45ef09bb3b1841a304080a6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 2 09:23:39 2015 -0600
+
+ Connection: deprecate interface and move routines into the Scheduler
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2e95030a0435147c54ef6b979329ffaa72c23160
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Apr 30 23:51:53 2015 -0600
+
+ HTTP: on error handling, set content-length=0 when no body exists
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 21c27fcbf1d372dc91d8cc660db9e273bdd1fa68
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Apr 30 23:45:22 2015 -0600
+
+ Core: fix GMT_DATEFORMAT macro for clock and HTTP
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9d40873869dceb2da17177dbf886426a254bc82e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Apr 29 22:30:07 2015 -0600
+
+ Scheduler: free mk_sched_conn on closing connection
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 86a3550cd06714cbb3b5116be2fb56cef0b8c3e1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Apr 29 15:15:02 2015 -0600
+
+ HTTP: on '400 Bad Request' do not compose error page
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 73a8f9cd4abfbed86f5087e1bc7bca6638042e91
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Apr 29 14:14:38 2015 -0600
+
+ HTTP: compose error page stream with stream API directly
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 355b208cdc3204ff0caade7fe293df91efcb7db9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 28 18:37:23 2015 -0600
+
+ Scheduler: remove unused field
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8ee889bf5b59c9af0a6865cca4d9f3d18c22dab5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 28 17:06:33 2015 -0600
+
+ HTTP Parser: pack http_parser structure
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e781b99328fcda31e56a45731aff65c6a2cd318b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 28 15:58:17 2015 -0600
+
+ Virtual Host FDT: do not try to close(2) a non-open file descriptor
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 807b7de732a5215996cd57d7dece569169ce6a51
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 28 15:24:32 2015 -0600
+
+ Virtual Host FDT: fix uninitialized values and context flags
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6a2a0f13fc0d8224d7ea9a1cd33181d86237e8ae
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 28 11:01:29 2015 -0600
+
+ Connection: Server: pass sched context across callbacks
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 24eebd4342a016384f03f7d30dd540a9af595ec0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 27 10:55:36 2015 -0600
+
+ Connection: fix handling for keep-alive connection
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e92f46764d959c2e014e1d43ab06d593ae2d078c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 27 10:47:01 2015 -0600
+
+ Server: fix trace mode on loop_balancer()
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 996a877e2a63439b553d507d0352430befc6e112
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 27 10:44:04 2015 -0600
+
+ Server: make old-balancer mode work again
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 271ce08ed7361e70db88fcbccfa256d087aff044
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Apr 26 20:43:42 2015 -0600
+
+ Server: fix worker_loop() declaration
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a2af71bf8e2f8660ed1e0c7928f2ecbf1f06f52a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Apr 26 20:40:30 2015 -0600
+
+ Plugin: remove deprecated reference of mk_stats.h
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6021603736bb3952967a20362e538a917f37015a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Apr 26 20:37:25 2015 -0600
+
+ Mandril: adapt to new stage10 declaration
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit abc4cfdd6231b45ad69e918ecd572c940a9c66f6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Apr 26 20:36:32 2015 -0600
+
+ Logger: adapt to new polling API
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e4de5346782d85b3dea5598917e6124020045516
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Apr 26 20:18:04 2015 -0600
+
+ Core: Scheduler: Polling: new architecture (work in process)
+
+ This patch is a major change on Monkey architecture. This is the
+ summary of the changes:
+
+ - Polling: the polling mechanism do not longer works with a file
+ descriptor, instead, it store a 'struct mk_event' as void * that
+ can be used by the callers to set their own data and retrieve it
+ once an event is triggered on the monitored fd.
+
+ The way to use it by the callers is that callers create their own
+ structure but the first field of that structure is a static
+ reference of 'struct mk_event', e.g:
+
+ struct mk_sched_conn {
+ struct mk_event event;
+ ...
+ };
+
+ On that way we allow callers to set their own data and also let the
+ polling core to handle what they need.
+
+ - Scheduler: major cleanup and reduced code, some functionalities are
+ still pending waiting for migration of code. For each accepted connection
+ a 'struct mk_sched_conn' exists.
+
+ The scheduler do not longer holds a static array with the maximum number of
+ allowed connection. They are allocated on fly now. We reduced memory usage
+ and speed up the handling.
+
+ - Event File Descriptor Table (EFDT): droped. Initially conceived to maintain
+ a global status of each file descriptor, this now is deprecated and handled
+ by the 'struct mk_event' and the structure in use by the caller. We reduced
+ memory usage and speed up the handling.
+
+ This is still work in process, more updates on the next series of commits.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 22d336ef7798e476822df637d0aa61bd37cbf8f4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 14 23:33:59 2015 -0600
+
+ Liana: do not print broken pipe errors to stdout on sendfile()
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b9f86ede3f8924359fe2faccc1ed981a71f11d95
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 14 23:30:21 2015 -0600
+
+ Stream: fix data type to handle streams operations results (fix #200)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a93a37553c920732f4708ba4f04f8a3e5255fe8b
+Merge: 5e4c4d2 6faee5f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 14 23:15:33 2015 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit 5e4c4d2899d5b7efd8fcf82e2973f0ac9774adef
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 14 23:13:53 2015 -0600
+
+ Core: rename common return values and do not perform channel writes from protocol handling routines
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6faee5ffd3c25892ee6d073bb8e067048c1eedad
+Merge: 23b1dfe 04899a1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 14 22:58:07 2015 -0600
+
+ Merge pull request #199 from leowzukw/patch-1
+
+ Configuration: typo in template (/~user)
+
+commit 23b1dfe526b04abead092f18e36545d0761894ca
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Apr 12 20:13:01 2015 -0600
+
+ HTTP: on http_prepare, return right return proper channel value
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4de62255d716c21c5178f908ef31618dc785ee1f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Apr 12 18:51:56 2015 -0600
+
+ Request: initialize file stream 'preserve' field
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit fb621bd8ffbdeece94cd97b756d76af799e9268e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Apr 12 18:45:22 2015 -0600
+
+ HTTP Parser: send 413 HTTP error when cannot store extra headers
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit cda7a3d35865880240f536655c59867a57d3fe79
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Apr 12 17:37:55 2015 -0600
+
+ Stream: fix unitialized 'preserve' stream field
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0560ee853a6e1f2fd3441753f69201fcdac40217
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Apr 12 17:33:22 2015 -0600
+
+ Connection: on premature close, check if the channel have some data to send
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit cf5d2eeed9f97314ab1bc62a8e526656d41950d7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Apr 11 19:53:26 2015 -0600
+
+ HTTP: on error, do not append stream after stream_set
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 04899a1ccb03a97c49b4a7ec89fc89821c97b5d2
+Author: leowzukw <leowzukw@users.noreply.github.com>
+Date: Sat Apr 11 09:15:55 2015 +0200
+
+ Typo?
+
+commit 58aa859de248e74e2bb196c02bbeeed172c9fabb
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 10 21:14:36 2015 -0600
+
+ Build: CMake: fix variable scope when linking static plugins
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4e70b74e6202196534df3fcdf70c5c713901560d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 10 09:31:04 2015 -0600
+
+ Server: remove unnecessary remove_client call
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 27a7a4302a415f545ecb72727e429ed396b802e7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 10 09:10:18 2015 -0600
+
+ Core: remove old/unused stats interface
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit eec21cd5e47f6a2f6167d74324a25f8590a5fd4e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 10 09:07:25 2015 -0600
+
+ HTTP: Fix memory corruption when handling a protocol error (Fix #194)
+
+ When the HTTP parser catch an error, the HTTP core will try to close(2) an
+ unitialized file descriptor from the session, generating a memory corruption.
+
+ This patch make sure to initialize the value and only try to close it if
+ it have some valid number.
+
+ note: this problem is only faced on v1.6.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c77183d9d11e2a1378ac27508a745f805c51448b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Apr 8 15:16:45 2015 -0600
+
+ Files: remove unused text documents
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2438d67233b5849cfb537b01f16b9ca65c09e833
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 7 11:43:46 2015 -0600
+
+ Build: CMake: auto-turn off Linux options on non-Linux systems
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 87e3f0ac229dd718297ce1919284946377bc20cc
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 7 10:27:38 2015 -0600
+
+ Doc: update README
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 04bded2cf38615821adfda51706834284b65636d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 7 10:25:38 2015 -0600
+
+ Configure: remove old references to systemd init scripts
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 10be8467f510b2e357ea6f6473407e90a83dabb4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 7 10:24:01 2015 -0600
+
+ Mandril: CMake: support configuration files
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit be90b12f4c6e45569c5bdf54703c56f9540b09db
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 7 10:18:05 2015 -0600
+
+ Build: CMake: create log path for local mode
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c29ffbf5bb96b97e979b8c9da4b8e2c495dea57f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 7 10:14:33 2015 -0600
+
+ Logger: CMake: support configuration files
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e2e156ba0494f00c6035eb35aed4092186d47495
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 7 10:04:03 2015 -0600
+
+ Cheetah: CMake: support configuration files
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 362921535e04ec2c552f4948a8e86c019e841579
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 7 10:01:56 2015 -0600
+
+ Dirlisting: CMake: fix conf path
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit fdf1f1948cdad3f7b2af55318363faa52e2cc41e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 7 09:57:12 2015 -0600
+
+ Dirlisting: CMake: support configuration files
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 927b1a8c502c3d9d670ffa540fb00439275a6c44
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Apr 7 08:52:47 2015 -0600
+
+ Auth: avoid jemalloc stuff on mk_passwd
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit efaaf4bc5b7fcf626739890975f1a665b5e8acc8
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 22:47:18 2015 -0600
+
+ Build: CMake: do not load all plugins by default on plugins.load
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f1931b869a763cd02dba3abb303a4ee895e93a86
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 22:46:18 2015 -0600
+
+ Build: CMake: fix webroot for local mode
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3a515c3c56ccddce4b367755549676924efc7d63
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 22:44:06 2015 -0600
+
+ Build: CMake: add missing path for PIDFILE on local mode
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3691c6e7aa0d29722dec85b7d611964c3dc1d689
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 22:40:15 2015 -0600
+
+ Logger: do not double print-error on configuration problem
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e7ecaff35172a3a51b3455e7a6c832917197dd70
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 22:39:12 2015 -0600
+
+ Mandril: validate configuration file
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5cbdb271cd13856abc40f4640c38a83b32ffabe2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 22:37:50 2015 -0600
+
+ Logger: validate configuration file
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c61be3be4f83a605c568e5c9560823f248a775e2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 22:36:56 2015 -0600
+
+ Dirlisting: validate configuration path, unload plugin if it fails
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1368045797ce61df56f9f1c640343d243d03fbe5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 22:35:47 2015 -0600
+
+ Cheetah: unload plugin if configuration fails
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e32bb45a3f0e9a189b50804c6e3b1b77c1ebfd95
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 17:16:24 2015 -0600
+
+ Auth: remove unused configuration example
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 77a61dbdd5b2db3e7356e129aa9bc4d7a578f47f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 17:14:48 2015 -0600
+
+ Auth: build mk_passwd in tools (add CMake rules)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f5988a4d8a81fcdd5cb66c4b729066c8a31c1979
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 17:09:33 2015 -0600
+
+ Build: CMake: add support for --includedir/-DINSTALL_INCLUDEDIR
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b6ffe187675f028a1d6d0b6688155e247855fb55
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 16:52:10 2015 -0600
+
+ Build: CMake: fix mimetypes installation
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 31c7db4f327773fec8ee76c5ad81187c31e3097c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 16:48:46 2015 -0600
+
+ Build: CMake: add support for --webroot/-DINSTALL_WEBROOTDIR
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 29599e4beb508996bbb889ba1151f90440988f39
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 16:27:41 2015 -0600
+
+ Build: CMake: add support for --pidfile/-DPID_FILE
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f9d7c6e2e8d5a090c26c86dc737682f87967fa3f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 16:17:23 2015 -0600
+
+ Build: CMake: add support for --logdir/-DINSTALL_LOGDIR
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 690e68ad3589c6d34e0c98f417481d8599ffad15
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 16:06:12 2015 -0600
+
+ Man: drop unused man pages
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit cfb1cbb847dfa692f7a0bbd75290a614006954f5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 16:03:56 2015 -0600
+
+ Build: CMake: extend support for install libs and others
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3d17830ca7a18d4dda34be183e7d7e897730a347
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Apr 6 10:27:44 2015 -0600
+
+ Build: CMake: generate plugins.load on plugins/CMakeLists.txt rules
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4ccab82c3d38c27b995ab031768d428e3142f17c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Apr 5 22:55:49 2015 -0600
+
+ Build: CMake: improve config files decls and fix static linking
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit fbdf82de06459fe8b6d3bc6fc464a278ee3614c9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Apr 4 19:29:56 2015 -0600
+
+ CI: fix script line
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 733acfe88a05b23851a920738b497410396ce44b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Apr 4 19:26:35 2015 -0600
+
+ Build: Memory: fixes on CMake for Jemalloc
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit fe4a2d48c564b0066036ae6d00730cf5b90f6c66
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Apr 4 18:47:42 2015 -0600
+
+ Liana: add missing CMakeLists.txt file
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2bf4ab6a26dd402d8a9f60aa013d083683f8dcba
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Apr 4 18:45:51 2015 -0600
+
+ Build: add root Makefile helper
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 09c6b2ab6fc31ed1d8c2f476e7a735cdb90a5ce0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Apr 4 18:43:35 2015 -0600
+
+ Cheetah: add missing CMakeLists.txt file
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2d2d0a9c27e8fdfe8ef9fe8f350eed886c986891
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Apr 4 18:40:07 2015 -0600
+
+ Build: CMake: fixes on MK_BUILD_PLUGIN macro
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6f994da1c8d0712d3518df3e2d07bd89d22e7da0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Apr 4 18:18:29 2015 -0600
+
+ Build: CMake: fixes on data to stdout
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 206e1d0a6ba148abeb1c1e40f061ee40e078208a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 3 22:40:10 2015 -0600
+
+ Build: CMake: support enable,disable and static plugins. Configure script stripped!
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1e4d9432fae2e9b6b0d5dae44846985c4d0ed353
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 3 16:04:23 2015 -0600
+
+ Build: CMake: add definitions and support for Jemalloc as external dependency
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 775c187e07750a91831fb9c646a1f04120b2990e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 3 14:28:48 2015 -0600
+
+ Plugin: remove old proxy_reverse plugin
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 79c046f854c96fd030a344c5a137d867a8231fc0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 3 14:28:22 2015 -0600
+
+ CMake: remove old reference to unused plugin
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 52b8ca8f6a77c9f7f1b589fbdfe749290cebf48d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 3 14:23:56 2015 -0600
+
+ Mandril: add build/cmake support
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a3e21879c97f0b8f4d1b91ab25a7b7c45110dc7a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 3 14:22:15 2015 -0600
+
+ Log Writer: add build/cmake support
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5b23faef2dfa9a463f328e79eed5451043e3eab2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 3 14:18:13 2015 -0600
+
+ Directory Listing: add build/cmake support
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a6dcfe002a15b6cb434d9c5ea608d5c6636f1861
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 3 14:15:33 2015 -0600
+
+ Cheetah: add build/cmake support
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 17c41f42e548c3233c9b577ff66bf64dab4d7b29
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 3 14:10:41 2015 -0600
+
+ CGI: add build/cmake support
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0610a5355103e1bb1d70bf321fd36cbc15b428e1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 3 14:04:32 2015 -0600
+
+ Build: CMake: Plugins: drop library prefix 'lib' from shared targets
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 70228379c2bee857bc12a6d576e7ee0b83b42d31
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 3 13:00:43 2015 -0600
+
+ Liana: add build/cmake support
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ad2d252fcf1efd1412fe40ad480e91564152d6d6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 3 12:58:22 2015 -0600
+
+ Build: CMake: support to build plugins
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 93bc2b199b2e8e1c06e09ae0dc224e6f0fbb9e38
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Apr 3 11:10:30 2015 -0600
+
+ Build: CMake: generate mk_env.h using a template
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a6534a25d0f0907ebdeea5b55efb97d3f5248632
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Apr 2 14:25:22 2015 -0600
+
+ Core: use new definitions from CMake
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 33349e41c421dcf8cc8886f9fd0cd509855f77e7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Apr 2 13:50:44 2015 -0600
+
+ Build: CMake: generate conf/sites/default using a template
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4abab291cd9fb6b2ad734e170d15dbb792a1bfd6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Apr 2 13:40:36 2015 -0600
+
+ Build: CMake: generate monkey.conf using a template
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0b8d21efee1ff13b9e4e09cf284503e76b3f415c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Apr 2 13:22:43 2015 -0600
+
+ Build: CMake: generate mk_info.h
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit eb7a77215a866e8ea7b12260938397cb4ac102b2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Apr 2 12:56:03 2015 -0600
+
+ Build: start migration to CMake (yes, I changed my mind)
+
+ This patch adds the first changes of the migration from the old
+ bash build system to a compatible CMake.
+
+ This is still work in process and it aims to keep a generic 'configure'
+ script with the same options than before but it uses CMake in the
+ backend to validate dependencies and generate the Makefiles.
+
+ I will explain later why I changed my mind about this in blog post, for
+ now there is a lot of work to do. :)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 251e33194263ab22b9cf67c632007f484a9e1ae5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Mar 25 17:46:58 2015 -0700
+
+ File: new 'mode' flag for file_get_info()
+
+ this patch adds a new flag to the file_get_info() function to determinate
+ which kind of permission the caller want to check.
+
+ It also modify all callers in the core and plugins.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 007f681c1d6b87e3221afb1a51297087f0d6bc5d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Mar 9 09:30:26 2015 -0600
+
+ Stream: fix debug function for OSX
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 405ca7483bf6ba436c93c86b8d99533bcb54c39b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Mar 9 09:15:11 2015 -0600
+
+ Header: fix CORK usage on OSX
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7e08773fe192ab083e23b15b78e86fed3669b641
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Mar 9 09:13:04 2015 -0600
+
+ Socket: move socket_accept at the end to avoid func declaration problems
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e0d713a4679b8b78b948f8090e1d547889dec3be
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Mar 9 08:53:30 2015 -0600
+
+ Build: move -rdynamic to linker LDFLAGS variable
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3f7d9be01d8941d5aa8dae34d2c46664c1e43950
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 22:13:01 2015 -0600
+
+ Stream: set fmt default for trace mode
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit bfaddc73e70e11b9e5a0142bc86377d669aa1cb1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 22:07:32 2015 -0600
+
+ CI: disable CGI and FastCGI on Travis
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 72babe73941ca87d4eb6678842d710f8dbfc3442
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 21:38:00 2015 -0600
+
+ Socket: remove unused tcp_autocorking() function
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 05538a448de1c1a17f97f07576b9882d3e04ebda
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Mar 2 14:49:22 2015 -0600
+
+ Scheduler: fix wrong handling of incoming queue.
+
+ Under high load with many invalid (not finished) connections, the
+ scheduler incoming queue may generate invalid references.
+
+ This patch solves the problem validating the sched node status.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0db2a4be943a04b0f1a238af9c5a79bfce9b7d79
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 19:51:58 2015 -0600
+
+ Debian: remove old references of libmonkey
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f2d96fbd630817606a66f895894fc560d8acd49c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 19:49:41 2015 -0600
+
+ Lib: more cleanup from headers
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2b5d00774b539fb87123359f85658677d263c6f1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 19:44:42 2015 -0600
+
+ Lib: remove old SHAREDLIB macros and perform some headers cleanup
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 66949bc6f43cb0c79cf9ff66b44c4bcefd45d2e8
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 19:26:51 2015 -0600
+
+ Plugin: silence some compiler warnings
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f60bc7302539b17670c82712795244ee7777dbd1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 19:19:03 2015 -0600
+
+ Mandril: fix headers
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3fa454adb8ecd9c42945545f27b2f52ef93c446e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 19:17:52 2015 -0600
+
+ Logger: fix headers
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2dda685cecd01674f431eedd30d23bfd7e5bffe2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 19:16:48 2015 -0600
+
+ FastCGI: fix headers and disable until check it works with new API
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f5317ee11ecf79840e6cbb6e1276b50fc5ea08dc
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 19:09:17 2015 -0600
+
+ Cheetah: fix headers
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 115039f61b2fd584b0bf11c283eacc1cabbf2a48
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 19:07:38 2015 -0600
+
+ CGI: fix headers and disable plugin until new API takes place
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 271811e7c3ec0ae6618c52fe2cc5d6561f2b019d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 19:05:34 2015 -0600
+
+ Auth: fix headers
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 69511b932f1120e867dea14b519681d06ded99d1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 19:00:44 2015 -0600
+
+ Lib: deprecate library implementation.
+
+ This patch removes the library mode as in the next changes Monkey
+ will become a library it self.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8fc94330ed321b8d5c503e7e714a78907674672d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 18:57:00 2015 -0600
+
+ Headers: fix server name
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 86b3e938f55f1d012aa913bfa3f07fa886b91b66
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 18:51:19 2015 -0600
+
+ Core: Network: move accept callback to the core.
+
+ This patch deprecate the accept() callback from networking plugins
+ and place the functionality directly on the mk_server.c code through
+ an inclusion of mk_socket.h (static inline).
+
+ It also perform some headers declaration fixes to align to the change
+ described.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ffd5f5eae81723b7015b2c3ff3157592ff8ae148
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 17:39:26 2015 -0600
+
+ Directory Listing: align streams structs declarations
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b480ec3e32bb9fb24297fbc25cda5e261504660b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 17:38:02 2015 -0600
+
+ Core: Stream: use structs instead of typedef
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f8b8d5781a07cc322e1b9a2e3e9c8410dba90967
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 17:34:37 2015 -0600
+
+ Directory Listing: enable chunked encoding (not functional yet)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f38c68f8c9c8ada20bb29508d849caa8f810bce5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Mar 8 16:02:53 2015 -0600
+
+ Directory Listing: update API to use new Monkey streams.
+
+ this patch modify the directory listing plugin to use the new streams
+ mechanism, it works in async mode but it still requires the following
+ improvements:
+
+ - Enable Chunked-Transfer encoding once the core start supporting it.
+ - Improve entries handling and enqueue N instead of 1 per write event.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 00482feeee753e396ae7664675e2b3a93be87110
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Mar 7 14:19:02 2015 -0600
+
+ Stream: fix initialization and streams linking
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4ac4bcc60010f96893cedff3327b03bc9e119854
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jan 26 20:59:27 2015 -0600
+
+ Stream: accept custom 'data' by reference in functions
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0c5d113bce0cb3b4396e6dfc4f5734a8a691bd66
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jan 26 20:54:00 2015 -0600
+
+ Stream: new 'data' field for custom references
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0e37bc34d825acf9a9265d90f7e83331d4027f8b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jan 26 20:52:43 2015 -0600
+
+ Stream: rename data field as 'buffer'
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4f330264ba340a8d3ffc8c0241624cca1a3d5ddb
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jan 26 18:09:35 2015 -0600
+
+ Plugin: fix exit_all handler
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b252648ddd1e7382fa55ababa33abdf21839e641
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jan 26 08:53:44 2015 -0600
+
+ HTTP: fix redirection for missing ending slash on directory request
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0ce6955f31e354a384d0ec3fc852ed1f713ec874
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jan 26 08:14:57 2015 -0600
+
+ IOV: deprecate MK_IOV_ macros, use Monkey MK_TRUE/MK_FALSE
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 00f15d2950bfd95bf9668dccb2d461efb0d4d738
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jan 26 03:49:08 2015 -0600
+
+ Stream: on HTTP static file, set the Stream Channel.
+
+ This patch fixes a problem when disabling the TCP_CORK. The Stream
+ did not contain the channel reference.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit bb0719c67fe76a3d93df866314002e90a3c6df73
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 23 12:50:36 2015 -0600
+
+ Auth: use new Streams API to send headers response
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit edc0d1a7825ee91924aa35182ee08f43810e6374
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 23 12:48:03 2015 -0600
+
+ Plugin/API: export Channel/Stream API
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1f5a90489c51e7a2cfd48bbea80c3e5e290c3fbd
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 23 12:18:40 2015 -0600
+
+ Auth: fix server signature usage
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 512fd58c9c0435d7433a4649286ae11acf0e1aec
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 23 12:14:42 2015 -0600
+
+ Plugin: disable shortname plugin on trace
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit dfdc4d5f323c6485c5009f0c317560ef579078a5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 23 12:07:21 2015 -0600
+
+ HTTP: mark two variables as unused
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6e4e916851d61630ed72c7cbd8aa435f94fb3df3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 23 10:56:34 2015 -0600
+
+ Core: on server exit, fix some minor leaks.
+
+ - Mimetype headers
+ - MK Event loops (epoll/kqueue)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 00a64181f4987139ac2e5df23ce6abfa6c5cb0cb
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 23 08:50:01 2015 -0600
+
+ Core: new option -I, --pid-file to override PID file path set by configuration (Ref #173)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2ba417f2ee344f4981b819b6a2cfde05b65597f3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 23 08:31:25 2015 -0600
+
+ Core: Check Listeners at start (Fix #173).
+
+ This patch implements a new mechanism to test if a Listener interface and
+ TCP port are already in use through a basic TCP connection. This check
+ is required as the sockets can be in shared mode (SO_REUSEPORT) we need
+ to be aware if other Monkey instance is already running.
+
+ If the test claims there is an interface busy, it will abort. But we give
+ the user a new option '-T' to override this failure and proceed anyways.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f4b57a5016a19a1cdc8bcff65599bea69cfda4c5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jan 22 18:09:01 2015 -0600
+
+ Server: scheduler mode is now optional and other improvements.
+
+ - scheduler mode is optional using new -B argument.
+ - balancer use monkey event API to handle connections.
+ - code cleanup.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d308add756c75bf9b081f81d5af4cbd8b95a1c66
+Merge: 7549514 1fa31d3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 16 23:28:32 2015 -0600
+
+ Merge branch 'streams2'
+
+commit 1fa31d3b97714923cb63f9a8abfb4279acbf9664
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 16 23:18:10 2015 -0600
+
+ Core: improve stream handling and Cork options (KeepAlive slow)
+
+ this patch makes improvements when using the streams to dispatch responses. As
+ well it take care of the right usage pf TCP_CORK (Linux) and TCP_NOPUSH (OSX).
+
+ KeepAlive mode is running with a delay between each request, still work in
+ process.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 754951414210e3496ebcb725637c2bb56ebc12bd
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jan 10 09:28:29 2015 -0600
+
+ HTTP: Parser: optimize performance, try to catch protocol version by chars check
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit cfd4bcf1d5d040f9d4a4eebe32a54ec74d5f1f1e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 9 10:00:14 2015 -0600
+
+ Clock: Header: pre-set Server and Date headers, reduce one mk_iov
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit bc653cadc2ffaf8dd657b6c6960e23e6f4bc6cfc
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 9 09:22:49 2015 -0600
+
+ Core: move server signature to global config struct
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1ba2aa963d906d71bf44952f611a98aeb836a90c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jan 8 16:06:53 2015 -0600
+
+ HTTP: Parser: pack structure and remove alignment
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 481cd277a6a46c974e3412121b0cf5e038095520
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jan 8 15:52:21 2015 -0600
+
+ HTTP: Parser: do pre-rolling check on header comparisson, performance improvement
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ae6711912995c0f2fe0d4991ecc4f109b674830f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jan 8 13:23:47 2015 -0600
+
+ API: remove old plugin (MK_EXPORT) declarations
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3397d97cfddcfc829511416e7095e295ebe192b0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jan 6 23:04:21 2015 -0600
+
+ Core: dispatch headers and static files using Streams
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5cfaf8967d535cea95d3d4f540e9ee2cd1003816
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jan 5 21:21:52 2015 -0600
+
+ Streams: initial implementation of Streams and Channels.
+
+ This patch implement the Streams concept which will be the interface
+ to enqueue and dispatch data.
+
+ Taken from a conversation with Sonny over email, here is the description:
+
+ "I think this is the point where the Channel concept joins, a socket is
+ represented at high level by a Channel, which contains the references
+ to the callbacks for each event and also the transport layer to be used,
+ and who handle Channel events is the Scheduler.
+
+ A Channel have two directions IN/OUT and each one managed by a list of
+ Streams: socket, iov, raw buffer, etc."
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8a8abb2f36a62381f7f55147e174178bf809c715
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jan 4 20:55:42 2015 -0600
+
+ Plugin: deprecate old stage_run routines
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f615e9625e7976c1ba20b4bfa5edeb1b7f07cc66
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jan 4 17:17:03 2015 -0600
+
+ Core: support new PTHREAD_TLS mode
+
+ Monkey support threads, and when sharing global data on each worker it does
+ it by using the Compiler TLS (Thread Local Storage) feature.
+
+ TLS is a compiler specific feature, it works on GCC and CLANG. As it can be
+ considered a *new* feature on compilers, some legacy compiler versions or
+ custom toolchains for Embedded do not come with that feature.
+
+ This patch adds a new option called PTHREAD_TLS that can be enabled on the
+ configure script through the --pthread-tls option. When enabled, instead
+ of TLS, Monkey will use Pthread Keys for the same purpose.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0ecc932cb877831c539a01e3a57c3673b3333d62
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jan 4 20:33:48 2015 -0600
+
+ Liana: remove unused header reference
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4db8df50271207b06dedb6f1a09a3e4e57d654c5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jan 4 17:26:07 2015 -0600
+
+ Build: use environment variable to set AR
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d59d7db6ae8d1f89e120464938ad61415bd58722
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jan 4 13:40:56 2015 -0600
+
+ Logger: use new mk_iov API
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 03989f4bdb91cca890cf42098907de1b2dda1790
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jan 4 12:32:25 2015 -0600
+
+ Configure: detect STATIC Plugins by default
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e99756f3253542566ddc3e9219c978852576cbfe
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jan 3 10:45:15 2015 -0600
+
+ HTTP: Parser: improve method lookup for known methods
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3c463a34eee1223fb7b3b8d0d220cdbefb82b998
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jan 3 09:30:46 2015 -0600
+
+ IOV: remove separators implementation
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d262dace63e389ddeb468ca1540cb1abf0849b57
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jan 3 08:53:04 2015 -0600
+
+ Core: Plugin: separate stage_run routines
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 348f972ba4117c0213c78ccc8a2cea52dfafe470
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jan 3 00:25:58 2015 -0600
+
+ HTTP: restore performance on Linux for small static files.
+
+ Later on 2014 Monkey performance got decreased when serving few bytes
+ of data on Linux. A fix for OSX generated a performance issue on Linux
+ that is only faced when mixing sendfile(2) and TCP_CORK.
+
+ This patch implements the fix for Linux, now it increased performance
+ up to ~24% when serving small static files. Monkey is rocking again :)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d796c9ca2081368bdd2bb9c4a83c74098402175d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 2 23:32:26 2015 -0600
+
+ Headers: optimize composer of response headers
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 66bff035168d835ff87ee8bb6fe771effd3d11ec
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 2 22:58:32 2015 -0600
+
+ HTTP: Parser: after first header key character check, do a continue
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit bced74cb1b81bdd4823825ccc9e4e53dd207da6a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 2 22:42:57 2015 -0600
+
+ HTTP: Parser: on CR, try to catch LF if there are some remaining bytes to check
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ecf23216d71005e930aa980de738961bb4dbb267
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 2 22:20:34 2015 -0600
+
+ Configure: fix static plugins code generator
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c71d9fcf03a35de5d4e0acc7a3c7bc0b0e64c625
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jan 2 21:22:47 2015 -0600
+
+ Core: global confix context rename from 'config' to 'mk_config'
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9fa29382bb73e4c5bec2e8bdf7b46ee1cdd9c255
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jan 1 10:18:49 2015 -0600
+
+ Copyright: welcome 2015!
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d5ba99de550c7385d65afe23e16b412ede2d2cea
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 31 17:22:45 2014 -0600
+
+ Logger: fix callbacks for local worker
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit da599328f589ad681da90a2f84b7d1c73ddf3db8
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 31 17:18:38 2014 -0600
+
+ FastCGI: fix declarations
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5a16b1882821032d8f2622eed8c8f243235fe6f6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 31 17:16:02 2014 -0600
+
+ Plugin: allow plugins without direct hook type
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 21bd9a16408ca21ea92e5353819dee7c8d0eaab8
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 31 17:05:15 2014 -0600
+
+ Logger: fix pointer initialization
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ef95e85a72beeac780fb66795e62d9f53a411cba
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 31 17:02:01 2014 -0600
+
+ Mandril: migrate plugin schema to new model (support static linking)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit dfd9994cc60e5ff498b0cbf7198749d9499fe2d3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 31 16:54:25 2014 -0600
+
+ Logger: migrate plugin schema to new model (support static linking)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d658b432cfaa70c8991f04915b42a2244bedb405
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 31 16:42:33 2014 -0600
+
+ FastCGI: migrate plugin schema to new model (support static linking)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d5553e62da6c634b6e5ff505f3f087bddc8b1471
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 31 15:05:47 2014 -0600
+
+ CI: Disable library mode on Travis
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1aefdc9430e46ef573c2f0a34e1f658442059f5e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 31 15:05:00 2014 -0600
+
+ Dirlisting: migrate plugin schema to new model (support static linking)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2abfc62e7d24f67b191d1d893a98daaf04def470
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 31 14:56:45 2014 -0600
+
+ Plugin: restore stage macros
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 701cefe16c89490b961c003d0636751b48fb81de
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 31 14:55:39 2014 -0600
+
+ Cheetah: migrate plugin schema to new model (support static linking)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6dd04787f72fe1ec3830813e4b9acc65240afd71
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 31 13:46:59 2014 -0600
+
+ CGI: migrate plugin schema to new model (support static linking)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4523f0b3a3486095797af51984ada700ac64ebd1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 31 13:34:10 2014 -0600
+
+ Core: Plugin: re-implement stages setup and callbacks
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d1ee9d2836336cfbe13aa4f9ac6bf8765bb1e3c3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Dec 30 14:47:04 2014 -0600
+
+ Core: Plugin: remove old structures for plugins
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit de6102471a27ab5cff5ceb583aa562c05e89d79a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Dec 30 11:43:53 2014 -0600
+
+ Auth: migrate plugin schema to new model (support static linking)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f345bd2b48846a962da66d4a6448d5c995b1cefe
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Dec 30 11:19:03 2014 -0600
+
+ Plugins: remove old API.txt doc file
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 59fbe838e53b68673a9fbbf5de66dad6e445c144
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Dec 30 11:14:49 2014 -0600
+
+ PolarSSL: migrate plugin schema to new model (support static linking)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 79a8a90137e316152a3ad312a56bfcdab046a04d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 29 23:43:55 2014 -0600
+
+ Config: do not warn on Sections without keys
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9e64323f73c9785e51c509187eaf68fb8a21dc7b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 29 23:39:43 2014 -0600
+
+ Core: Plugin: load dynamic and static plugins
+
+ This patch makes able to load plugins in static or dynamic mode
+ for those who provides a NETWORK_LAYER (Liana on this case).
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0c37330d7bc03d9910c1295f1945346be18fc72c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Dec 28 20:25:33 2014 -0600
+
+ Core: Plugin: Let build system hook static plugins
+
+ This patch implements a new option on the configure script called 'static_plugins='
+ where is possible to define which plugins will be build in static mode. Also the
+ core is able to detect the statics and link them in the global configuration.
+
+ More work is required, but this is a good progress. Just tested on Liana plugin.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 241964ca3180606fe6f1ca3762c115841020ba97
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Dec 28 09:41:10 2014 -0600
+
+ Liana: Build: add static build support
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ea4e2c1d51438aaab839fe943c3c668734dfb74a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Dec 27 16:37:20 2014 -0600
+
+ Core: Plugin: Network layer functional in workaround mode
+
+ This patch makes Liana work with the new plugin mechanism. More
+ work is required to re-enable stages and hooks for other plugins.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 36efede314d2d66c6876bdb76070e943be63108b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Dec 25 22:53:28 2014 -0600
+
+ Core: Plugin: new draft of plugin mechanism (wip)
+
+ This patch adds a new mechanism to load plugins, at the moment it only
+ do some partial replacements over the Liana plugin adding a new structure
+ to define callbacks for certain I/O network operations.
+
+ note: work in process.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e8100255efb586abe26978e41be69950b99859d9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Dec 25 17:18:01 2014 -0600
+
+ Mandril: use new Monkey structures to handle sessions and requests
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f085ed3e75f815366385f53f81e901d56047dc89
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 24 15:20:18 2014 -0600
+
+ Logger: use new Monkey structures to handle sessions and requests
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2f66a51dcc3ad6b5d1dfde440f5266583f480f9c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 24 15:19:11 2014 -0600
+
+ FastCGI: iterate headers using new Parser Headers list
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit cbb361e6af331ea169106beae80162eb67617355
+Merge: 16be561 307a10f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 24 14:59:11 2014 -0600
+
+ Merge branch 'fastcgi_upgrade'
+
+commit 16be561926ce5b1406c228b1c76b8c87533a8b4e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 24 14:56:32 2014 -0600
+
+ HTTP: Parser: register headers in a parser linked list
+
+ This patch implements a linked list in the parser so when a known header
+ or extra headers are found, they are linked to the list so any plugin
+ can iterate them without problems.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 307a10f31f8425fd6a0c00de6145f0d0c328ee56
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 24 14:47:32 2014 -0600
+
+ FastCGI: use new Monkey structures to handle sessions and requests
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ca3273b5ca3617f378f4c71f66eb4f6a4108b22b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 24 13:36:22 2014 -0600
+
+ Dirlisting: use new Monkey structures to handle sessions and requests
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f10d6eaeb91fff4b854dcab133829516cd2262a0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 24 13:33:51 2014 -0600
+
+ CGI: use new Monkey structures to handle sessions and requests
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b4b0202dfc9a022b99f33ae9dbd26eee42fb8e1f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 24 13:30:49 2014 -0600
+
+ Auth: use new HTTP Parser API to manage Authorization header
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e3c59ac5b8702e74286ce17f8efa2c87e233046a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 24 11:59:37 2014 -0600
+
+ HTTP: Fix Content-Length array index
+
+ This patch fix a static workaround implemented to by pass a double
+ definitions of headers strings, it basically did two things:
+
+ 1. Use the MK_HEADER_CONTENT_LENGTH macro
+ 2. On header.h move some definitions to the .c file
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ee783ad26b9bb97602e66d4c5ac4c78cc7210861
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 22 00:23:35 2014 -0600
+
+ HTTP: Parser: add lookup support for 'Cache-Control' header
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b0ed0172fc6b1cc27b7cae387b53e388fd182d29
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Dec 21 23:52:38 2014 -0600
+
+ Core: make header_get() usable with new parser internals
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4aba21b6db2213150c945e5af467a000e5980d10
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Dec 20 23:06:35 2014 -0600
+
+ HTTP: Parser: initialize headers_extra_count field with zero
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0d3575fa7bf63c5777c30e4270fcc77c4b883447
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Dec 20 23:05:10 2014 -0600
+
+ HTTP: Parser: parser now supports 'Upgrade' value on Connection header
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b93946c1638587e79029670ed0d2a407207da4e1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Dec 20 23:02:50 2014 -0600
+
+ HTTP: Parser: add support for 'Upgrade' Header
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6c075d7acfd4a55aa3a4bbbadd2a6f015268def9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Dec 20 22:58:43 2014 -0600
+
+ HTTP: Parser: new parser->headers_extra array
+
+ The purpose of the new array, is to register unknown/custom headers
+ set by the client.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2f21ff44819a943239257cf31b7c153a7a6e5933
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 15 13:58:42 2014 -0600
+
+ QA: improved Keep-Alive tests
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 737895140d541b71f9276364a9ad7563f1eefd45
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 15 13:48:47 2014 -0600
+
+ HTTP: Parser: don't validate EOF on Content-Length header
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c396ee073bf6d616d9003881230f3fdef2c17510
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 15 13:37:27 2014 -0600
+
+ HTTP: Parser: fix host string length in mk_ptr
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0ae9da888eb9b87bb25d80e6910f94bfa1be8985
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 15 13:31:35 2014 -0600
+
+ HTTP: Parser: handle Host header TCP port
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f0e49c171eb08f9c5959787287e5dc38c3ca7df7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 15 10:25:35 2014 -0600
+
+ HTTP: Parser: validate protocol when query string is set (add QA script)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3b0454cee3a68ceca09d763faed1243f58da9956
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 15 10:20:00 2014 -0600
+
+ HTTP: Initialize request->port field
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7d2f51fff68439962d0a53537235fbb1e07a72eb
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 15 10:18:19 2014 -0600
+
+ QA: Fix error_413_02 test, send a very long request
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit bdfbcd8c437101430de8cc28393077c63be086d6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 15 09:45:26 2014 -0600
+
+ HTTP: Parser: support insensitive headers RFC2616 s4.2
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2551ee37f8a3793e1ca423e862d6961a6f05dbde
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 15 09:03:26 2014 -0600
+
+ HTTP: fix code indentation
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d5f2d97aa8a05b0c4aa656ffdc099961c5ee2094
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 15 09:02:27 2014 -0600
+
+ HTTP: Parser: extra checks on protocol and error page fixes
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 94a8ab5934276c84040f0831efd623f7d82eb0b4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Dec 14 23:11:16 2014 -0600
+
+ HTTP: Parser: return BAD_REQUEST error on bad-formed protocol
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c3207c9bf502c23970ceb1704dbe063e01241b27
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Dec 14 22:58:36 2014 -0600
+
+ HTTP: Parser: validate protocol version
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9c3cf34a773c226058bf6a277921ff6f8fe1af46
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Dec 14 22:44:11 2014 -0600
+
+ HTTP: Core: initialize request and headers flags
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 72be121d33d45e8baa939dd0f4624b03d880e949
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Dec 14 22:39:28 2014 -0600
+
+ HTTP: Parser: handle MK_CLIENT_REQUEST_ENTITY_TOO_LARGE
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d25172c6d2805bfe7e94e86f3e51f1d693c49589
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Dec 14 20:56:52 2014 -0600
+
+ HTTP: Parser: validate Content-Length is set on POST/PUT requests
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f8a173e7047b682c5c8b862c953860c6a88974ab
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Dec 14 02:20:04 2014 -0600
+
+ HTTP: Parser: fix iterator limit
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7ae62fc1d5ceb25c71f1c830af0f621782dc0755
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 10 17:58:30 2014 -0600
+
+ HTTP: Parser: fix handling of KA connections
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4ca7fff7acc7834e0907c80c3c8f7710a364b625
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 10 13:28:09 2014 -0600
+
+ Connection: fix body length passed to HTTP parser
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ef515294a28c6b5c06663c9c9d589f3b7b58fb46
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Dec 10 13:08:36 2014 -0600
+
+ Server: improve behavior when accepting a new connection
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7bc851668797f2f06c594f392353f1609444cd9e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Dec 9 14:44:50 2014 -0600
+
+ HTTP: re-enable support for Keep-Alive check.
+
+ This patch re-introduce the detection of the Connection header value
+ and do some logic steps to determinate if the connection should be
+ keep open as in a keep-alive state or be closed.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d1c7cc8005fd58ce78489440f9b178ead838f3b5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Dec 8 21:33:37 2014 -0600
+
+ HTTP: little improvement when initializing parser.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b99037eccba56c008481d4442593d66faacaa81b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Nov 20 17:28:56 2014 -0600
+
+ Connection: link fixed http_request from http_session
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9f1595d0cf9d3d4957a8b7741e9b5d07a1a9bafd
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Nov 7 22:34:30 2014 -0600
+
+ HTTP: more code cleanup (wip)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 27a6e9e359adf76519c46c0bc2b5230f13f091d7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Nov 7 13:34:19 2014 -0600
+
+ HTTP: merge parser results on http_request
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7fbca6e347c4bef7b1c31620b59259b2cb9cf4b5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Nov 7 10:38:11 2014 -0600
+
+ Core: refactoring structures and HTTP parser
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5dde82f851c1e13ef14360c8b92f0dae05378e2c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Nov 4 21:58:51 2014 -0600
+
+ Core: small fixes when building in TRACE mode
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 690eb05d57d9c8f1c1941285926fb3ea0192ad54
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Nov 4 21:57:23 2014 -0600
+
+ HTTP: do not include old mk_method header file
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6dfb5b744a52401c2c117b9011be35216d4c17e7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Nov 4 21:40:35 2014 -0600
+
+ HTTP: new parser and main structures refactoring
+
+ This is the first patch of a big change that is coming, it does:
+
+ - deprecate mk_request.[ch]
+ - deprecate mk_method.[ch]
+ - replace struct client_session by struct mk_http_session
+ - replace struct session_request by struct mk_http_request
+ - new HTTP parser mk_http_parser.c
+
+ At this moment the server 'compiles'. It now needs to be aware about
+ the new parser and also needs some cleanup on headers interfaces.
+
+ the fun begins..
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d3b498a11a8b535eae5be8d17bf290e110aa09f1
+Merge: a79c038 7815bb3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Nov 4 11:11:01 2014 -0600
+
+ Merge branch 'master' of https://github.com/monkey/monkey
+
+commit a79c038f5e8bbe94a2f4fbbe442aeb677488334a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Nov 4 11:10:45 2014 -0600
+
+ Kernel: disable TCP_AUTOCORKING (#175)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7815bb3932a38fb4746663eb4f66479a33426a04
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Oct 27 09:45:36 2014 -0600
+
+ Auth: if no global config exists, just skip stage 30
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c61969059ee58ef73492bf3fb3abb4dea87ea509
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Oct 27 09:41:48 2014 -0600
+
+ Auth: validate that config have been loaded
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit fe65020113a4411dcf3a0446aacff8460f761e86
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Oct 27 02:04:55 2014 -0600
+
+ Configure: enable -rdynamic
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit fb297b42b0ce66901425b5d08644432ee3155ae9
+Merge: f1a5e96 b6ddb6d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Oct 24 00:03:10 2014 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit f1a5e96ae40d79530b2e9eb4339642ac4784c4c4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Oct 23 14:44:07 2014 -0600
+
+ Scheduler: proper handling when dropping connections
+
+ This patch implements a new function at scheduler level that is
+ used to cleanup a complete connection.
+
+ It helps to fix an issue when connections are dropped from different
+ sources such as: timeouts, I/O errors, incomplete requests, etc.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+ Conflicts:
+ src/mk_http.c
+ src/mk_request.c
+ src/mk_scheduler.c
+
+commit b6ddb6d2324a4106b7c1548ef73f015c242af865
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Wed Oct 22 13:07:51 2014 -0700
+
+ utils: Fixes Mac Os X macro in mk_utils_worker_rename().
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 7bb177644652667021c3c89dc64a2f5a961bf5b3
+Merge: 1c76aaa 01bf1af
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 21 20:17:03 2014 -0600
+
+ Merge pull request #172 from ksonny/master
+
+ OSX fixes
+
+commit 01bf1af68a817a7b3fd7d4828b8b3d1fa6bf6f3d
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Oct 21 17:04:45 2014 -0700
+
+ liana: Fixes for *bsd sendfile().
+
+ Always update file_offset variable.
+ Return -1 if errno == EAGAIN and no bytes sent.
+ Use error log instead of trace for Linux sendfile().
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 81e8b869d70f9da93ddfbfb17ec7f12ce3c28fc6
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sat Oct 18 12:11:49 2014 +0200
+
+ http: Remove cork before first call to sendfile().
+
+ This removes a large delay on Mac OS X when headers and file content
+ does not fill a single frame.
+ Deactivating TCP_NOPUSH does not cause pending frames to be sent until
+ the next write operation.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 389e84766bece353fdb681e618691aceca38e41d
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sat Oct 18 11:41:17 2014 +0200
+
+ logger: Uses stack buffer in splice() fallback.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 774859a98271668f4a51b33e7b8c017d8864a7d5
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Oct 21 18:09:27 2014 -0700
+
+ socket: Set SOL_TCP to IPPROTO_TCP for Mac Os X.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit af513bbac2d4ac56e356edb11ebe5e6be52afd4e
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sat Oct 18 11:36:11 2014 +0200
+
+ util: Set thread name on Mac OS X.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 1c76aaaaf510101c07376d3c9b05f0ed01fd61f7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Oct 19 13:45:02 2014 -0600
+
+ Configure: improve src/Makefile output
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9ead720f52f12d60fa0e87c6c6d091fed9919b48
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Oct 19 11:21:14 2014 -0600
+
+ Utils: on worker_rename, fix warning on OSX
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 67973ab53e0c2a5dd44d758dc297615471c68dbe
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 18 22:59:07 2014 -0600
+
+ Cheetah: fix address length for unix socket
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 71ecbdcc2e4872ec0283ab6fd8398e6d21d3e889
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 18 22:32:00 2014 -0600
+
+ HTML: update Monkey to 'Black Macaque'
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5176e48f879c873c9da0cb5d04ea660818a3ada2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 18 22:30:17 2014 -0600
+
+ HTML: update info for v1.6
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 424c7d40aa0f1dba383427687ecbf19449fb9b2c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 18 21:49:39 2014 -0600
+
+ Socket: fix warnings on OSX
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 835fb4630e93ca4a84e01caa9ea59947eefb327e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 18 21:48:58 2014 -0600
+
+ Liana: fix sendfile() call for OSX
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 731d41ae12727090ca0a3d7903f96f74ad2c487c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 18 21:28:35 2014 -0600
+
+ Server: do not warn TCP_DEFER_ACCEPT problem on OSX
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b89953faf7034cf42a10b103f069498011568268
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 18 21:26:13 2014 -0600
+
+ Socket: fixes for OSX
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 92725ce811204282815a493631425fac1380c0b0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 18 21:23:44 2014 -0600
+
+ Configure: drop -rdynamic from Makefiles
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 27992a0daabea32f0b2a149b6689505175852576
+Merge: ad133f8 b841ec2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 18 20:47:39 2014 -0600
+
+ Merge branch 'logger-event'
+
+commit b841ec20299b33930b213ebbc25a98800c7d2a4f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 18 20:47:03 2014 -0600
+
+ Logger: add support for Linux and OSX, use Events translator to iterate events
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b6492096df03dd702cd977168d18a4c9e2ef400b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 18 20:46:13 2014 -0600
+
+ Events: export fdt() api and add extra validation on backend iterators
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ad133f85851c33e9680cb5df8965f13460591b99
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Oct 16 10:45:06 2014 -0600
+
+ Scheduler: trigger exception when registering a client that already exists
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e0d86fd358946e35bab5f916b8580684c5c67a9a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Oct 16 10:37:42 2014 -0600
+
+ Request: trigger an exception when an entry already exists on the rbtree
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 80815f28b0ee26fef2332cd7635aea3450c5ff64
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Oct 16 10:32:31 2014 -0600
+
+ Macros: new mk_exception(), similar to mk_bug() but without conditional
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c997b057edaeb8512f264a58e365c338482c4952
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Oct 12 17:35:22 2014 -0600
+
+ Liana: add support for OSX sendfile()
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 31b767bbe75c034d0d2918a8ebb853720fd05741
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Oct 12 17:23:09 2014 -0600
+
+ Utils: support worker rename just on Linux
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 03dbbf8ea4ab9ceaf6d38611939723098a2b4ff0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Oct 12 17:18:05 2014 -0600
+
+ String: add memrchr() function as OSX lacks of it
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit cc1919843389b39a4a961ad574b3ef125afdfe76
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Oct 12 17:15:19 2014 -0600
+
+ Socket: fixes to support Linux and OSX
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 62b266905f4e7025f3a135b0bd8a226333a7d856
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Oct 12 17:04:57 2014 -0600
+
+ Signal: remove dependency of features.h
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 30ac42fd066d5a5dbf2cf854268ed0004070f0c1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Oct 12 17:04:19 2014 -0600
+
+ Scheduler: support thread id for OSX
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7f4d2aefc0ec9cdd1c5ad43957d4afb6d27ce4e8
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Oct 12 17:01:51 2014 -0600
+
+ Scheduler: remove old direct dependency of epoll and eventfd
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ef016abe806b97998fab59bd251f69dc66c410d2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Oct 12 17:01:10 2014 -0600
+
+ File: use O_NOATIME just on Linux
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 669c9330122d3687f3965bd0c4447f611b56db26
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Oct 12 16:56:03 2014 -0600
+
+ Configure: check_generic() now accepts new parameter for defines
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 55e2a683383c246c3d3d09359e86eaf37ba65d8d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Oct 12 16:46:20 2014 -0600
+
+ Configure: find: use -type instead of -xtype (OSX friendly)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4af9151e1521c4cdc2fd224aede9e8a1c2ddab23
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Oct 12 16:45:03 2014 -0600
+
+ Configure: support 'sed' options for Linux and OSX
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5d8e70421b6074edc5f6ddf16b7d0e24c491adb2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 11 23:46:51 2014 -0600
+
+ Config: reset address of listener on setup
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 64e032b66d5f840f58d24e04875df8ddd9ef7c9b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 11 23:09:01 2014 -0600
+
+ Config: on listener read, do not continue on loop
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 98be899bb28214486c35fa6ab52419515131f4bd
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 11 22:33:52 2014 -0600
+
+ Event: on initialization error, release memory
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 94676f37dfdc002007b6e3683236ed79c6816489
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 11 22:32:51 2014 -0600
+
+ Config: fix mem leak on 'address' when using multiple listeners
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0e741727b13e6c83daa3a32592d101a65ce628d2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 11 22:26:22 2014 -0600
+
+ Vhost: when find a docerror exception (config), do not leak host
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit fa0ea796f4c069b605234fcadc5aa81c3b78f908
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 11 22:23:52 2014 -0600
+
+ Config: on config create, do not leak indent var
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 23bf3f2c6f20b8a0958ddea03a0ff4816cc1decb
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 11 22:22:51 2014 -0600
+
+ Config: on config create, do not leak file handler
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f95d28ea02d34ce83e5f3e6f02550d807cbff839
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 11 22:21:44 2014 -0600
+
+ Config: abort if SECTION config is not found
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 91f58ae6c4b5f1134d972515f5ccb9d15e74d362
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 11 22:20:08 2014 -0600
+
+ Request: check status of cork_flag set
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 08b7a135b673deb02150e401bc04c116bd7d55a7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 11 22:17:35 2014 -0600
+
+ HTTP: validate return when sending headers on redirection
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3095600949656fe76d102251be6bb64d89612152
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Oct 11 22:15:28 2014 -0600
+
+ Mimetype: fix leak if initialization fails
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f330be3527e9cfe04049f4e4147a7847865eadd7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Oct 3 11:35:40 2014 -0600
+
+ HTTP: do not allow GET with body data
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 96a82376061935ccc06d7610998e0b49f4bf47af
+Merge: 92fcaa1 1f840f0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 24 23:28:35 2014 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit 92fcaa1963b2ac7c0e021ec80f8ce7dbea8966ee
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 24 23:28:24 2014 -0600
+
+ Conf: validate sections
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1f840f0674b3e94c2db1303b759973b2fc7fd1fa
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 24 16:04:03 2014 -0600
+
+ User: use memcpy() instead of strncpy()
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f29a133cb92fac74e6642c41d45eeb78c9d6e580
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 24 16:02:04 2014 -0600
+
+ Utils: use memcpy() on URL decode
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 322b011c4f6c0e80167f80955c43f513f196dc74
+Merge: 24f03ef ff95472
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 23 21:52:28 2014 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit ff954726382476e5f7766c53860d64a5dc4bd03b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 23 10:40:35 2014 -0600
+
+ Configure: fix override of DEFS environment variable
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0091d4dcb91d1f00de27dc80fa0d20cad7a2da1e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 22 10:58:26 2014 -0600
+
+ Configure: new get_realpath() to resolve script path
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 24f03ef309e9592a478701568b68cdab25f622d6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Sep 19 19:08:51 2014 -0600
+
+ Banner: print Linux Features just if __linux__ is defined
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d2c4058a685a2a93d54a08ff7e03caea0ea23ab5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Sep 18 09:00:59 2014 -0600
+
+ Cheetah: print error if bind fails
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit cc764b459736ccca11f8f9a36c9393ff23857590
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 17 22:25:50 2014 -0600
+
+ Scheduler: on Fair Balancing, adapt worker capacity
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5834427d031e726c92b6caf83c7582a94dfe18b2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 17 11:44:32 2014 -0600
+
+ Cheetah: on server info expose events backend
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0cf60e6b8d9895742c2f6033a8bc4047ac7beca0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 17 11:42:48 2014 -0600
+
+ Plugin: export event_backend()
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit af4ae08fc118bf55f7952619dd6ca887596d5ab7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 17 11:26:59 2014 -0600
+
+ User: on switch user, do not alter NOFILE limits
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit bf106fefab74448de22f60d0978b16c389870fa9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 17 10:34:04 2014 -0600
+
+ Events: new event_backend() to identify polling mechanism
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2c61531b8aa36477e84c8f03c8d3c3039fc4c925
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 22:23:00 2014 -0600
+
+ HTTP: Disable TCP_CORK on send_file on first round of data
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0b283275cf691e120fd4a4471676569c69e7aaff
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 22:11:16 2014 -0600
+
+ Header: improve performance on buffers cache
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit fc577af77858db10403d8913067edb339eda4907
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 21:45:27 2014 -0600
+
+ Plugin: improve performance when accessing thread global event list
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 496770a6291246e39f7d45e036acd8ed3a0cf8df
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 19:18:22 2014 -0600
+
+ Cache: remove unused pthread keys
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 93d2f5730cb380c3dd85762a333013b25c8a8e71
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 19:16:17 2014 -0600
+
+ Utils: improve performance when accessing thread global gmt caches
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1c2d028cedba355753cb67cd978f1e012ef09fcc
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 17:10:31 2014 -0600
+
+ Scheduler: improve performance when accessing thread sched node
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5e2d95b2f8075f6db72d2731a9f205e1e2d217f4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 16:01:01 2014 -0600
+
+ Plugin: expose ev_translate() on API
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7c36db6f6f500b8d29304abc4398b5c2e884a3ca
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 15:57:21 2014 -0600
+
+ Events: kqueue: new mk_event_translate() and mk_event_foreach() interfaces
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3ae46a119e5f80b3099a5053d8672768e686df8c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 15:35:43 2014 -0600
+
+ Events: new mk_event_translate() and mk_event_foreach() interfaces
+
+ Previous mechanism required to perform two walks through the events
+ result array, the first one for the native backend and the second
+ to export the results to a new interface.
+
+ This patch implements two new interface to improve performance over
+ the past scenario plus a minor change:
+
+ 1. mk_event_wait(): just invoke the backend poll interface, nothing else.
+ 2. mk_event_foreach() macros that allows to walk arround over the backend
+ interface results avoiding double copy.
+ 3. mk_event_translate(): do a explicit copy from backend resutls to the
+ public interface.
+
+ This patch only apply the interfaces to the epoll backend.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1c8ba8561adca6d099faea1a1cb2f33d9f9826c4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 14:44:56 2014 -0600
+
+ Events: remove old events data structure approach
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e6e518457528ce5f58f17f7e531090c00f7cc01d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 14:38:38 2014 -0600
+
+ Scheduler: remove unused events mask on sched_connection
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e0ea056c00f575019554b0dbca1cb510f473dfb7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 11:51:03 2014 -0600
+
+ CI: disable proxy_reverse plugin
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 009ef9ee06f59e8294bc44c61f8aceeccd250704
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 11:47:30 2014 -0600
+
+ Logger: replace old epoll calls by new Events mechanism
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 28bbd325d410f2bb2e86d5e4adce627625684123
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 11:42:00 2014 -0600
+
+ CGI: use new Events mechanism
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b8c18ae15a052ae43a055be187b4875da44c3ad9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 11:39:52 2014 -0600
+
+ Lib: adjust to new Server capacity logic
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit dcf3020ec45a6d403946130417b9354c8ca93a9a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 11:26:47 2014 -0600
+
+ CI: re-enable Travis
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit dd40abe3f1fe7b58ac1b5c5fdadefe94bd5f3858
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 11:19:48 2014 -0600
+
+ Events: kqueue: implement timeout_create
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8145451314e626fcb599dbe26993897cb839ebe4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 10:58:54 2014 -0600
+
+ Events: epoll: on timeout_create, use event_add() call
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b8c632c5457b869d17bfb828414c41ba0b9451d0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 10:46:50 2014 -0600
+
+ Events: kqueue: implement channels_create() handler
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 73baa60d613a335784dc45dceb53556b082afd3b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 10:37:50 2014 -0600
+
+ Events: Scheduler / Epoll: set read and write file descriptors
+
+ This patchs makes the Events channel creation to use two file descriptors
+ for read and write operations. Mostly because kqueue based interface
+ will use old-fashion pipe(2) as eventfd() is not available.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6ccbfc050058e78a9223a52b2c8f19b78e4b5687
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 16 10:05:36 2014 -0600
+
+ Events: kqueue: disable debug messages
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0dde3beb69e595cc8e6a4c2b9dbcf47a2915db1a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 15 22:55:41 2014 -0600
+
+ Events: change flags value and found a libkqueue bug
+
+ I found a bug running libkqueue (GIT version), not sure if it
+ can be replicated on older versions. It only happens when the
+ following sequence of kqueue calls are done:
+
+ 1. Register FD as EVFILT_READ
+ 2. Delete EVFILT_READ for FD
+ 3. Register FD as EVFILT_WRITE
+ 4. Register FD as EVFILT_READ
+
+ On step #4 kevent() fails with EFAULT (Bad Address). I was able
+ to reproduce the problem with a standalone test case, I contacted
+ the library author about this problem. I need this to get resolved
+ to continue.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 281183ca6fafb2790c7ed554efd6bb2dafda0546
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 15 14:53:39 2014 -0600
+
+ Events: kqueue: on delete, do not validate errors
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b9a081ea766d1485827463b141a5bc3b7c1f4b7c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 15 14:15:52 2014 -0600
+
+ Events: kqueue: fix event deletion
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 271a33c390af5b7f1934e1fdc4c06396ba82f028
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 15 12:37:10 2014 -0600
+
+ Events: add kqueue poll events handler
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4fc2cd53dde74ef170fb33f5562d7f3465245bde
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 15 12:25:29 2014 -0600
+
+ Events: add kevent 'event delete' handler
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 39ed833f715a9bcd1231f0f8a04cae4fdf865f54
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 15 12:22:56 2014 -0600
+
+ Events: kqueue event add callback
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3df8d431789a75e702f492f92693692d1a3e8363
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 15 11:41:25 2014 -0600
+
+ Events: kqueue loop create plus configure script fixes for libkqemu
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a0abb6fc2d56e2f9a4799cd16a47664dcc465796
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 15 11:31:03 2014 -0600
+
+ Events: add kqueue handler Skeleton
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 10b58cec2301df36bf4001bb8afc8e472b2c08da
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 15 11:25:48 2014 -0600
+
+ Events: use epoll only on Linux and when linux-kqueue not defined
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d1f303d2f855224f5c2322ad00e6a94032474cd3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 15 10:50:48 2014 -0600
+
+ Config: move port override to global conf
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit dbabdc09b16a1cee49222255eb40615b4fbce943
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Sep 12 11:15:53 2014 -0600
+
+ Events: set custom 'data' field on results array
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a6d101e3db41e9cbcf1f9a98370f37200fde8163
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Sep 12 10:43:18 2014 -0600
+
+ Plugin: make events behavior param void
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ce18be91117be85132289e0357075afc2aaf3151
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Sep 12 10:40:09 2014 -0600
+
+ Server: remove deprecated reference to mk_epoll.h
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f1a8928ab405cfd793d678ad79893556edbd8900
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Sep 11 16:46:17 2014 -0600
+
+ Events: set array size using getrlimit
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7da674a44ce21dbedc9534681f0b26d56c9b1108
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Sep 11 16:13:51 2014 -0600
+
+ Events: align EFDT size with server capacity
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7a75941f318464d35093e5fc11b1027b7f0172a4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Sep 11 16:07:57 2014 -0600
+
+ Config: update FDLimit description
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8dc36979a08e2b6c56f8dae6cb81d36d97d62fbf
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Sep 11 11:26:06 2014 -0600
+
+ Config: support new FDLimit (fix #143)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c1b2228db588c21724fb3c838990b4d20c09e242
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Sep 11 10:02:27 2014 -0600
+
+ Doc: new Branch TODO for this new architecture
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2c9bbe7c73a7d67811f42256727d3f3110f5fc6b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Sep 11 09:19:31 2014 -0600
+
+ FastCGI: fix API flags
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a5b40f0584f7f0f96fcb7f3f5ff2ba53f9f8fa97
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 10 22:17:01 2014 -0600
+
+ Scheduler: change server capacity
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c3358d8785f5f0e45cad53480c3e3f8b2d874dbf
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 10 21:42:23 2014 -0600
+
+ Event: separate logic between main loop and backend
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit bd6866c7cdad267d2cc067ce1689bf43fe8dc969
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 10 21:29:28 2014 -0600
+
+ Event: small fixes, partially working (serving requests)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0944212c0a4c76940797abc294ad18dac7418ebb
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 10 19:56:43 2014 -0600
+
+ Scheduler: mark thread loop as initialized
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1d05d26c43e92c2004f900d7ecdd559699bc3d38
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 10 19:42:11 2014 -0600
+
+ Plugin: export new Event core API to plugins
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 66b21a904631a839e4f4b20b8a8cd07eda7c8030
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 10 16:40:57 2014 -0600
+
+ Core: remove deprecated calls based on old epoll_ API
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c876a79f547c8cd0c95ea2d9f432f8b9c98a5078
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 10 13:38:37 2014 -0600
+
+ Scheduler: use new Event interface
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit cd0366cffcf98bac1d123cc559dbf42c3a80e62a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 10 13:26:18 2014 -0600
+
+ CI: disable Travis CI for this branch
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d6566f741b3e6ed29e5130105667d6d85f8f343b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 10 13:17:36 2014 -0600
+
+ Epoll: it was a pleasure, but you have been deprecated.
+
+ This patch removes mk_epoll.[ch] from sources as the new mk_event.c
+ handler with mk_event_epoll.c backend is in place.
+
+ Now the core is totally broken as all other interfaces needs to be
+ adjusted to the new Events mechanism.
+
+ Now the fun begins :)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit fc6c4231a069425f953938f343f6b90ef6fc33d3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 10 13:13:00 2014 -0600
+
+ Scheduler: use new event loop interface
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8107a13f3899c30d8d27d950829576f4c2d79b48
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Sep 10 12:44:10 2014 -0600
+
+ Event: add signal channel support
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit adc206c604717e32787f866a3e2fbce0dae7d568
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 9 22:34:48 2014 -0600
+
+ Server: worker loop handle events
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8f6a135dec17f111129bf8b66e0d2b0e9a1e6cd0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 9 12:09:34 2014 -0600
+
+ Server: prepare worker loop
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e9a4ab97be444a47595bb1c0d3fd47eac485279b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 9 12:05:17 2014 -0600
+
+ Event: wrap backend context on a 'loop_t' data type
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ffb68fede1c5d96ea2a297c4fbe5c82ed008c827
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 9 11:17:08 2014 -0600
+
+ Config: remove unused param when calling listeners free
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d4788c69da0f65c51cb1d76bd6183e33c9b9a1f9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 9 11:10:47 2014 -0600
+
+ Event: fix compiler warnings
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8074056d5a4ac0d22bd553f060d5991b410e658b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Sep 9 11:03:26 2014 -0600
+
+ Event: fix builder
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5243abd1073deecdec279904b179824808808256
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 8 23:14:01 2014 -0600
+
+ Event: header fixes
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 034a53a9746b0917f9fbdc955da9915d41bb5ffe
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 8 22:29:59 2014 -0600
+
+ Event: workaround for events abstraction
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ab9ac8be1e85fe09f62133fa91a2c5aafa096386
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 8 20:10:25 2014 -0600
+
+ Event: rename calls and add timeout handler
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d7c980c31eaa9a8b05347c5cea22a91c720e4f62
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 8 17:32:00 2014 -0600
+
+ Event: wrappers for event_add and event_dell
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8060d44ca35eb4224754f6b4dc2cf969515659bf
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Sep 8 12:31:11 2014 -0600
+
+ Event: initialize global event states table
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a972d061e8761e78edf83a591cf09415ebb16d78
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Sep 7 23:11:04 2014 -0600
+
+ Event: preparing event handlers & basic epoll
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4171e4dda9057bbcba17fdf027699180e75df818
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Sep 7 12:10:41 2014 -0600
+
+ Configure: enable check for libkqueue (linux emulation)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8f20986ec316fd560a53bf7ec0b3feab1f69691a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Sep 4 16:55:38 2014 -0600
+
+ API: export str_char_search()
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 987c2e2455fbed7fa9d07325778589e8dd1efd94
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 30 23:07:02 2014 -0600
+
+ Config: export listener_add so the lib can use it
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8e41fe656e925c49bde9f58e846689b2d7f21370
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 30 21:05:07 2014 -0600
+
+ Cheetah: print mem allocator and little tweaks
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5e39bd80c78e5253d25646059cd2d27f0912c1d9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 30 20:44:49 2014 -0600
+
+ Config: duplicate Listener value buffers for safe free
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit abcea6e6c42179ecb4bdaf1eaef9a98c94a19208
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 30 20:42:53 2014 -0600
+
+ Epoll: make listener set EPOLLRDHUP
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9bd6b9edfef8e271f7989c10b9be0ec8e6fc5c8f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 30 20:41:59 2014 -0600
+
+ Epoll: initialize event struct for listener
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 77e7f3a7c4e255082a89f1f9b2b50ccfdd84a97a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 30 20:40:54 2014 -0600
+
+ Config: skip duplicated listeners
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 11f4b1cb307ca08f366ffff51445b4dedf36d3eb
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 30 20:26:09 2014 -0600
+
+ Config: do not free resources after load a Listener
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1c1a173ac7462ca20ec9f211364fbe24e23aa35c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 30 17:53:19 2014 -0600
+
+ Logger: fix API usage for new Listeners
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6e78b9daf89964f50090c84e42e2b8e5df20c858
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 30 17:50:13 2014 -0600
+
+ PolarSSL: fix data type
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b0c7f25886fa2138f103eb6ce7dab00973d3968a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 30 17:48:06 2014 -0600
+
+ Cheetah: fix API usage on Listeners
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d2bf008233de3f25811b15943022881afab0365b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 30 17:42:34 2014 -0600
+
+ Lib: fix API for new Listener stuff
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d1af5833ef6eda83e8942c362afa7c99c0cce3bd
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 30 17:27:30 2014 -0600
+
+ Core: fix API usage on new Listeners mode and small changes
+
+ A new feature for multiple listeners was added but it did not follow
+ the Monkey pattern internals, this patch perform the following changes:
+
+ - Listeners are not longer a linked list, instead a mk_list.
+ - Memory allocations/deallocations now use mk_mem_*() family.
+ - Renamed concepts of 'listen' to 'listener' and 'listeners'.
+ - Small function to register a new listener.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f07ec2d17088922bcfd47cb8f0500d5d12d5f25d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Aug 26 11:05:14 2014 -0600
+
+ README: updates
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 506a7a18564be6bea8d61952384970088a20c7ac
+Merge: 6dd20b3 ae3bffe
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Aug 26 10:35:50 2014 -0600
+
+ Merge pull request #168 from ksonny/master
+
+ Multiple listen sockets support
+
+commit 6dd20b3da0d5d120a60d7c751d7ecfbb068e1a66
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 23 11:28:36 2014 -0600
+
+ Header: when using Chunked encoding, do not set Content-Length
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 51aed72efb590622de33071a555ebed94eb10ac3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Aug 19 22:51:24 2014 -0600
+
+ API: export je_mallctl when JEMALLOC_STATS is set
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+ Conflicts:
+ include/monkey/mk_plugin.h
+
+commit df7aca1ae80d6ed5e856f944d4318b0ef8848711
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Aug 18 19:38:46 2014 -0600
+
+ Kernel: support Debian version format
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ae3bffeb93bfd75380b88ff32ab8c2f6f00f0a36
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 18 18:13:56 2014 +0200
+
+ mk_lib: Adds multi listening socket support.
+
+commit f364dbc90f81570ec289d1171e52c22fdbe51e65
+Merge: 491f7e8 7ad943c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Aug 18 09:51:20 2014 -0600
+
+ Merge pull request #167 from kaspersky/ldpreload
+
+ Libmonkey: Stats and python bindings
+
+commit 491f7e8026da1f1f9dcaf82a3f27e8f459e726a9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Aug 18 09:48:38 2014 -0600
+
+ CI: Make Travis to build the shared library version
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9e764c5dd509bfeda929437eb450e1aabdd0a0ea
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 18 17:45:04 2014 +0200
+
+ mk_lib: Fixes errors from changes made to server_config.
+
+ Use config->listen.address and config->listen.port instead of
+ config->listen_addr and config->serverport.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 7ad943cf04aeb8cc15f0dc3f9e9b23e283fda441
+Merge: 3c8cddc 6125f57
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Mon Aug 18 17:59:53 2014 +0300
+
+ Merge branch 'master' of https://github.com/monkey/monkey into ldpreload
+
+commit 6125f57da0fca4c8be93ec745ab4243577733ccc
+Merge: 7cf0dab e260a6c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Aug 18 08:47:52 2014 -0600
+
+ Merge pull request #166 from Denisss025/plugin_buff_size_export
+
+ Plugin: add export to buffer_size function.
+
+commit a22d33668aeb3ab5f0006fe2f9f38df5476580d9
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 18 15:47:44 2014 +0200
+
+ plugins/logger: Fixes printing of listen addresses.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 4e8f93630bc4a9bc52f1fbf53f001559c998689e
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 18 15:46:09 2014 +0200
+
+ plugins/cheetah: Fixes printing of listen addresses.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit ce470b9ab428e60ad2f62f3c9777f32e023781d4
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 18 15:44:08 2014 +0200
+
+ mk_scheduler: Initialize mk_server_listen struct.
+
+ Binds listening sockets when thread is launched.
+ Use stack-allocated mk_server_listen to start mk_epoll_loop().
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 3c5827e9e7079f3988711af3d130491241d3edd5
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 18 15:39:10 2014 +0200
+
+ mk_scheduler: Removes mk_scheduler_add_client*() methods.
+
+ mk_scheduler_add_client_reuseport() and mk_scheduler_add_client() are
+ superseded by mk_server_listen_handler().
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 9dc8c01eeb9899c4e500c1b2029360b1dcb82512
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 18 15:34:17 2014 +0200
+
+ mk_scheduler: Adds mk_sched_next_target().
+
+ Used in mk_server to balance new connections.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 1a89da348e36997c0c3820c3248014b40554f031
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 18 15:30:48 2014 +0200
+
+ mk_epoll: Adds multisocket support to epoll loop.
+
+ Changes arguments of mk_epoll_init() to accept a mk_server_listen
+ struct instead of a filedescriptor.
+ Adds code to register listening sockets from mk_server_listen to
+ epoll().
+ Adds call to mk_server_listen_handler() when a new connection arrives.
+ Changes type of mk_api->epoll_init().
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 7961903fadc6dd198d63865eee824c0bf0d77690
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 18 15:21:11 2014 +0200
+
+ mk_server: Adds multisocket support for server loop.
+
+ Adds support for multiple listening sockets when SO_REUSEADRESS is
+ unavailable. Uses poll() for event notification.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit afb20cb1492328a8ebe30830d38327b11b4092c4
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sat Aug 16 17:23:20 2014 +0200
+
+ monkey: Adopts port override for multiple listen sockets.
+
+ Set port in first listen structure on configuration and removes other
+ listen directives when port specified on commandline.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 8b40ef64ea68e237461d7758e4212e61bcdcadd3
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sat Aug 16 17:18:44 2014 +0200
+
+ plugin: Changes port argument type on mk_socket_server().
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 2c70a37dd00924095ceac6e30c675bdeef09edf5
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sat Aug 16 17:12:06 2014 +0200
+
+ utils: Use first listen port on pid file name.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 9a76bc0ee8c7053bccb932728f35c91f5ce8428e
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 18 16:26:35 2014 +0200
+
+ en/mconf: Removes Port and changes Listen directives.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit d9fc68fb50dbe9c340748a527d5b0ee887f04f8c
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sat Aug 16 16:58:18 2014 +0200
+
+ mk_config: Parse multiple Listen configuration options.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit e260a6ce1c1f404d195a44bfa4b35462804118f8
+Author: Denis <denisnovikov@garant.ru>
+Date: Mon Aug 18 11:51:28 2014 +0400
+
+ Plugin: add export to buffer_size function.
+
+ This patch fixes a problem where `mk_plugin_load_symbol` returns 0
+ for `_mkp_network_io_buffer_size` function.
+
+commit 3c8cddcf996da4f3311c0e217148d611f8d11e7f
+Merge: 55f2a7b 7cf0dab
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Sun Aug 17 17:56:12 2014 +0300
+
+ Merge branch 'master' of https://github.com/monkey/monkey into ldpreload
+
+commit 7cf0dabd31878b58bd190e85fc87e3901265ea0b
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 16 20:30:02 2014 -0600
+
+ Epoll: validate when registering connection with the Scheduler
+
+ In the epoll event loop, when registering a new connection with
+ the Scheduler, there were not check if this was successfull or not,
+ a common example may be a security plugin dropping a connection
+ at STAGE_10.
+
+ This patch adds a validation on the return value when trying to register
+ a connection with the Scheduler. If it fails, the socket will be closed
+ right away.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 869eb02be55dbe94729a2d76444122bbe62ed299
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 16 20:16:40 2014 -0600
+
+ Mandril: remove trace msg
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit d13e8d9d6a6764aad845f83dfb45ce4a274b9ac7
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 16 17:34:15 2014 -0600
+
+ Macros: document NET macros parameters
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8424837a4840473a478df333949fae303df36248
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 16 17:27:27 2014 -0600
+
+ Mandril: fix network address reference
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b2d0e6f92310bb14a15aa2f8e96e1fb5379776dd
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Aug 16 11:55:28 2014 -0600
+
+ Request: new request session flag to mark those files opened by FDT
+
+ This patch aims to fix a potential DDoS problem that can be caused
+ in the server quering repetitive non-existent resources.
+
+ When serving a static file, the core use Vhost FDT mechanism, but if
+ it sends a static error page it does a direct open(2). When closing
+ the resources for the same request it was just calling mk_vhost_close()
+ which did not clear properly the file descriptor.
+
+ This patch adds a new field on the struct session_request called 'fd_is_fdt',
+ which contains MK_TRUE or MK_FALSE depending of how fd_file was opened.
+
+ Thanks to Matthew Daley <mattd@bugfuzz.com> for report and troubleshoot this
+ problem.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f9d0f8d4cbf7a799a9af2a1e70e6ed622a95b399
+Author: Matthew Daley <mattd@bugfuzz.com>
+Date: Fri Aug 8 00:23:48 2014 +1200
+
+ Utils: allocate enough space to include the null terminator when URL-decoding URLs
+
+ Signed-off-by: Matthew Daley <mattd@bugfuzz.com>
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1b5d6cc3fd03b513f6793bf56af0c8b02a3a69ff
+Author: Matthew Daley <mattd@bugfuzz.com>
+Date: Fri Aug 8 00:20:52 2014 +1200
+
+ Request: don't search off the end of the body buffer for query strings
+
+ mk_string_char_search takes a length, not an end position.
+
+ Signed-off-by: Matthew Daley <mattd@bugfuzz.com>
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e2b2d78d62b524eb3c6245289ed9fc1362fdb054
+Author: Matthew Daley <mattd@bugfuzz.com>
+Date: Fri Aug 8 00:11:02 2014 +1200
+
+ Method: correctly extract content length value from body buffer when pre-parsing
+
+ The buffer offset and the end position passed to mk_string_copy_substr
+ is incorrect.
+
+ Signed-off-by: Matthew Daley <mattd@bugfuzz.com>
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9ba97fa0029ab332110cd45ac123f129646fe822
+Author: Matthew Daley <mattd@bugfuzz.com>
+Date: Fri Aug 8 00:06:08 2014 +1200
+
+ Mimetype: don't iterate off the start of the filename when looking for an extension
+
+ Check the iterator position before checking for an extension.
+
+ Signed-off-by: Matthew Daley <mattd@bugfuzz.com>
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 115c4edd02a8b5aaa2d5aecdf8d8cfa8aa168d53
+Author: Matthew Daley <mattd@bugfuzz.com>
+Date: Fri Aug 8 00:05:38 2014 +1200
+
+ Request: set correct path size when truncated
+
+ If snprintf can't write the entire string out to the buffer, it will
+ still null-terminate it. Hence, the length of the string is one less
+ than the maximum passed in, not the maximum itself.
+
+ Signed-off-by: Matthew Daley <mattd@bugfuzz.com>
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3f7fa6f73de8dea848443690774792690e61d41b
+Author: Matthew Daley <mattd@bugfuzz.com>
+Date: Sat Aug 16 07:38:14 2014 -0600
+
+ Request: unlink request node from cs->request_lists
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 58473846c364a4d4f160bd4d7955d97937c55462
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Aug 15 19:08:00 2014 -0600
+
+ Scheduler: on timeout, validate incomplete linked list (#163)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 55f2a7be51ab0f0cc269d3cfb553591dc34e4bf5
+Merge: 9748d1e 295512e
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Fri Aug 15 23:19:00 2014 +0300
+
+ Merge branch 'master' of https://github.com/monkey/monkey into ldpreload
+
+commit 9748d1e181706647e09f4293d53e41be10109573
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Fri Aug 15 23:18:10 2014 +0300
+
+ Libmonkey: Fix clock_gettime undefined
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 295512e5ad2e5f857777381be5179f72d7af7054
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Aug 14 23:40:49 2014 -0600
+
+ PolarSSL: new get_bytes_avail() call
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c74f062cbfd25ca7c29dd35f5ffd56cca413ffda
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Aug 14 23:38:20 2014 -0600
+
+ PolarSSL: let io_read return more bytes than consumed
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8c9c5d61fade510bb90107ec173cb42cdc06ed01
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Aug 14 23:28:54 2014 -0600
+
+ Request: initialize max_read
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 00954f84880d642f592886015a944e58066df6d1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Aug 14 23:12:35 2014 -0600
+
+ Core: adaptive network buffer size (Fix #163)
+
+ Monkey stack allows to a plugin to handle the network operations
+ in a low level layer, at that area the plugins Liana and PolarSSL
+ are the main ones in charge to add support for plain communication
+ and further SSL.
+
+ When working over plain sockets, the Networking plugin (liana) just
+ perform direct read from the system call to the clien_session buffer,
+ so it will read as of buffer capacity and then continue after each
+ event triggered by the Kernel. In the opposite side, when the plugin
+ requires some data processing after read(2) and before to return the
+ control to Monkey core, we may face a double-buffering and that is
+ the case of the PolarSSL plugin, where by obvious reasons it needs
+ it own buffer.
+
+ By RFC defition, SSL/TLS defines a maximum transaction of 2^14 bytes,
+ which is 16KB, so if we get an Event notification from the Kernel and the
+ plugin processed a number of bytes grater that the available on the caller
+ buffer (client_session), we may ended up with some un-read bytes in the
+ SSL layer.
+
+ This patch implements a few mechanisms to avoid the situation described:
+
+ 1. The Plugin API at Networking level now implements a new callback
+ called 'buffer_size', so from now all Networking plugins requires
+ to implement it. Monkey core will call it with the purpose to ask if
+ the plugin is implementing it own buffering and the size of it.
+
+ 2. When initializing plugins and check the Networking plugin buffer size,
+ If it returns something >= MK_REQUEST_CHUNK, the Configuration will be
+ set to that value. Note that from that moment every request will require
+ two memory allocations (a workaround for custom systems will in the next
+ patch).
+
+ 3. When invoking a Network read, now a plugin may be able to return a greater
+ number of bytes requested by the caller. If this is faced, it means the
+ Network plugin have some pending data to be read, so now the Request handler
+ will consume that amount of data before to return to process other events.
+
+ note: as said a new patch will come to fix the need of double-memory allocation
+ per request.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+ Conflicts:
+ src/mk_http.c
+ src/mk_request.c
+
+commit 05024797ba95ba737a8cd6b647f20d8ebe8493e2
+Merge: fd2ac8f 1025daf
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Aug 14 09:51:03 2014 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit fd2ac8ffa428c54ef4b4909d8292174ee4f9c347
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Aug 14 09:49:23 2014 -0600
+
+ Core: new '-t' option to override TransportLayer from command line
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3abb35c3d89b5dcaf66ec050781828532d403343
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Aug 12 19:22:38 2014 -0600
+
+ Epoll: move READ message after signal condition
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 775ca46644ffbae7317f49e5e9eeff188d61caa3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Aug 8 20:00:03 2014 -0600
+
+ Scheduler: on TRACE mode when closing connection, validate cs.
+
+ When trace mode is enabled through --trace, when the Scheduler will
+ close a connection, verify that no client_session associated exists
+ to the Scheduler entry, this condition may happen on bad API usage
+ by plugins.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2d43b5e8aa1d05755ac169b93fb075b448ef8514
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Wed Aug 13 19:29:54 2014 +0300
+
+ Libmonkey: Add usage instructions for stats
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit ee178e150ea80261f2538904fa1d76c476707b7a
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Wed Aug 13 19:29:31 2014 +0300
+
+ Libmonkey: Improve documentation in python API.
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 4e96b2fd7c34987738d5dea1abddaaf6ee1a28a6
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Sun Aug 10 23:15:08 2014 +0300
+
+ Libmonkey: Convert integer return value to boolean in monkey.configure()
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 7c55d140c3b0cb7b946110e671135575afecfe68
+Merge: 36cac75 1025daf
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Sun Aug 10 22:21:29 2014 +0300
+
+ Merge branch 'master' of https://github.com/monkey/monkey into ldpreload
+
+commit 36cac7523d1a102fcdfd63181e832121dddefc2f
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Sun Aug 10 22:20:45 2014 +0300
+
+ Libmonkey: Update manpages
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 1025daf4e36e29bd22a108fed08e7384569d863d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Aug 8 20:00:03 2014 -0600
+
+ Scheduler: on TRACE mode when closing connection, validate cs.
+
+ When trace mode is enabled through --trace, when the Scheduler will
+ close a connection, verify that no client_session associated exists
+ to the Scheduler entry, this condition may happen on bad API usage
+ by plugins.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 44beac406efaf89073fd10b25b140332a9691aa2
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Fri Aug 8 02:00:32 2014 +0300
+
+ Libmonkey: Fix 'content_len' field in python examples
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 04516e3fc08e3cdc402aa20e7b7f807778e58a45
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Fri Aug 8 01:37:47 2014 +0300
+
+ Libmonkey: Fix a bizarre segmentation fault at libstats unload
+
+ Apparently, an application with multiple threads or child processes
+ can cause a call to libstats destructor many times. Avoid closing
+ multiple times the same library handler.
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 6324c2b06702c6c81b23ebfd1951d817bfbee0c1
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Fri Aug 8 00:53:35 2014 +0300
+
+ Libmonkey: Move liana plugin to right location for running tests
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 0412b23ec12f7138f30992c98711120278c55df2
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Thu Aug 7 22:35:43 2014 +0300
+
+ Libmonkey: Fix equality test to mk_stats variable
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 5a23be68e103e06526b248a8df89896e57a4d186
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Thu Aug 7 22:34:53 2014 +0300
+
+ Libmonkey: Remove hardcoded value in run-tests.sh
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit f412eb5d8e156b52dfe9d7aa96e583b3158ea401
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Thu Aug 7 22:34:30 2014 +0300
+
+ Libmonkey: Add stop server message in python examples
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit e3223cc6ea5147e6e872b04d29530cdd4e3c6426
+Merge: 9d569f1 7fc6a5f
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Thu Aug 7 20:49:18 2014 +0300
+
+ Merge branch 'master' of https://github.com/monkey/monkey into ldpreload
+
+commit 9d569f1ec3a32bf1406f24109ca6704fd3d5aa2a
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Thu Aug 7 20:09:00 2014 +0300
+
+ Libmonkey: Prettier print format for worker stats
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 212da6ae5ed413f5dcc2de023802bc3fbe6f5151
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Thu Aug 7 20:08:17 2014 +0300
+
+ Libmonkey: Fix -DSTATS flag for stats Makefile
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit ceeb8e7e2f826bc592da8c5a53c585b6a0beef97
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Thu Aug 7 19:22:32 2014 +0300
+
+ Libmonkey: Add compile option for libstats in Makefile
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 3e91987a70c756a2ef7413427d8044097d61f3c6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Aug 7 09:55:32 2014 -0600
+
+ WIP: status completed crash
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c45d68f78371e00d115254e480909322e7fd490e
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Wed Aug 6 22:13:43 2014 +0300
+
+ Libmonkey: Minor stats fix
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 07d213126c9f0fe1fc4d30108a49e5e59486f957
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Wed Aug 6 22:06:15 2014 +0300
+
+ gitignore: more stuff to gitignore
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 7fc6a5fbcee8b148ad389cbef22461f56882b6e0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Aug 4 21:50:01 2014 -0600
+
+ Epoll: initialize unitilialized static epoll event
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2b6326c97f3cb1a6117e738729820b6d0d27fade
+Merge: 4b6145c 53e0ace
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 3 14:25:00 2014 -0600
+
+ Merge pull request #161 from txt-file/patch-1
+
+ identi.ca
+
+commit 53e0ace55e247cab7b4ebd99f63cb527a7d7f1fd
+Author: txt.file <txt.file@txtfile.eu>
+Date: Sun Aug 3 21:51:55 2014 +0200
+
+ README.md: removed identi.ca link
+
+ The link gives only an error message.
+
+commit 3c2c1fa4edf5860e03a5c606d4cce75319783e9f
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Sun Aug 3 22:32:13 2014 +0300
+
+ Libmonkey: Move python extension module to appropriate location.
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 5f6f56d6cdc3993bedc0e426b71e83d292f90118
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Sun Aug 3 21:27:23 2014 +0300
+
+ Libmonkey: Check for python dependencies when building the python extension
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit a74b20803d8c5a8f780add67450b319ee832ca61
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Sun Aug 3 21:04:30 2014 +0300
+
+ Libmonkey: Remove inappropriate test
+
+ Currently, monkey doesn't support multiple contexts at once,
+ so keeping a test which always fails isn't useful.
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 7a72619218e4b0debb04b97b89d46265ad1fa47f
+Merge: 06d5ccc 4b6145c
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Sun Aug 3 20:56:17 2014 +0300
+
+ Merge branch 'master' of https://github.com/monkey/monkey into ldpreload
+
+commit 06d5cccc0129f01118cdffd4f1d9c0e7a0b84aef
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Sun Aug 3 20:55:05 2014 +0300
+
+ Libmonkey: Add python docstrings to monkey module
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 4b6145cc9b68e0a210db88d79b5d01f1207060d3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Aug 1 20:14:14 2014 -0600
+
+ String: performance improvement converting uint64_t to string (4x)
+
+ Based on the trick given by A. Alexandrescu on Facebook Engineering
+ blog, this patch replace the old mk_str_itop() with the faster
+ algorithm proposed.
+
+ More details about the implementation here:
+
+ https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8f86e733e09427fa52e9e8258dca32431a845ac6
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Fri Aug 1 20:36:26 2014 +0300
+
+ Libmonkey: Fix configuration free crash in library after recent upstream changes
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 4197d76aeba2d33a89c7df229005c22d66c73cbf
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Fri Aug 1 20:34:05 2014 +0300
+
+ Libmonkey: Fix libmonkey.h path in run-tests.sh
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 82c5b0d5144ab3acd522da5a01db0cb55e0098a6
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Fri Aug 1 17:14:34 2014 +0300
+
+ Libmonkey: Update run-tests.sh script for new include location
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit e5d0d3dcd8c010820bde691df1e9cee4307adf65
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Fri Aug 1 00:57:49 2014 +0300
+
+ Libmonkey: Fix mk_info new include location
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit ddbe93feb59beabfa418d2a7dcb3052747e09913
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Fri Aug 1 00:51:42 2014 +0300
+
+ Libmonkey: Move mk_stats.h to right location
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit d0b2ffe0219cd40ff26a93d0f48e8f47f4b71bc1
+Merge: ca3dbc7 41d018e
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Fri Aug 1 00:47:05 2014 +0300
+
+ Merge with upstream
+
+commit ca3dbc7979ea62392a5a99d13a76ded49c9f8240
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Thu Jul 31 20:41:43 2014 +0300
+
+ Libmonkey: Trigger python bindings generation from configure
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 41d018e45f10d12c708968e3f7038eb765ff46f1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jul 31 10:59:05 2014 -0600
+
+ Signal: if write fails, print error
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 793a38f16c9afd5c19ed6364dc77e9ac13a78a27
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jul 31 10:57:29 2014 -0600
+
+ Request: fix debug messages when TRACE is enabled
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 80e722b242f8033a80310f5414a85fa7b2a5aec9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 30 21:58:09 2014 -0600
+
+ Dirlisting: make bootstrap theme the default one
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7abe5d435172343282154266a59fd81d161d5d83
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 30 21:57:50 2014 -0600
+
+ Dirlisting: new Bootstrap theme
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c1e0a2b90f4ebe6d99a1ed7cff1562883714eab3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed Jul 30 21:13:41 2014 -0600
+
+ Core: new 'one-shot' option to serve a directory without setup.
+
+ This patch implements a new optional argument when start Monkey to
+ start serving a directory as a specific virtual host. This is only
+ useful when doing fast things locally mostly for testing.
+
+ $ monkey -o /var/www/
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1e0d7224ac26b4b36bc4db127719887b8d096fa6
+Author: kaspersky <gg.kaspersky@gmail.com>
+Date: Thu Jul 31 02:02:48 2014 +0300
+
+ Libmonkey: Implement worker-info bindings and test
+
+ Signed-off-by: kaspersky <gg.kaspersky@gmail.com>
+
+commit 0f7bd7bd08b7f57482a2179594d34a7d4739df01
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jul 29 09:06:00 2014 -0600
+
+ Help: fix text formatting
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f5b17aa60c57de1bc2fa75e614fe7e8ab521d79e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 28 23:13:06 2014 -0600
+
+ Scheduler: optimization when timing out connections
+
+ This patch adds a good improvement on performance when the event poll
+ system start checking for candidates to timed out connections. It adds
+ two main lists:
+
+ - sched->status_queue: Open socket connections list that have not sent any data
+ - cs_incomplete: Client requests list that still have some pending data
+
+ When the timer triggers the timeout check, now the Scheduler will look
+ over those two global lists at thread level, avoiding to check connections
+ that are in a good state.
+
+ This performance improvement is faced when having several active connections
+ in the server.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3f8fa573563d3d15aad7fbc19224bb07087ed338
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 28 20:44:41 2014 -0600
+
+ Epoll: use TimerFD interface to perform scheduler timeouts checks
+
+ This patchs makes the scheduler and it epoll event loop to check
+ for timeout connections through the timerfd Linux interface.
+
+ It improve performance of the polling event loop as the previous
+ version did a check after every epoll_wait().
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 06ce79936423c34ef472e7d21bafaec99a7946b9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 28 15:30:55 2014 -0600
+
+ Virtual Host: validate dummy files (Fix #155)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9a1b8c354b170bab41466f04b8e6e77b98438a67
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Mon Jul 28 01:18:43 2014 +0300
+
+ Libmonkey: Port library test suite to python
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 806bd166ebeaf8488a98d995cb7b4f502d5a3c11
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Mon Jul 28 01:17:53 2014 +0300
+
+ Libmonkey: Minor bugfixes to monkey.pyx
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit c2268adfed6f781b389715bbb205dc23ad10ffaa
+Author: Nithin Saji <nithin111@gmail.com>
+Date: Sun Jul 27 23:56:42 2014 +0530
+
+ LTT: update new header path
+
+commit e031e5d17851ba1f75be79b656066566d7596460
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 26 20:52:44 2014 -0600
+
+ Plugin: remove dummy trace msg
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c67696609c3a73287a93f4a3480aae6eb4e6fc0a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 26 20:08:17 2014 -0600
+
+ HTTP: Pipelining fix #145 and improvements.
+
+ This patch fix a problem where Pipelining requests were not being
+ processed correctly and also do some improvements about how they are
+ handled internally.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2675f1a53299be72c03594cc498b295f14b69367
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jul 27 04:58:18 2014 +0300
+
+ Libmonkey: Implement examples for python also
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 9f15f444f5ee25eeeffc34aa063ec0f2825f8fa9
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jul 27 04:55:24 2014 +0300
+
+ Libmonkey: Fixed segmentation fault in python bindings
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 292c8f6dd3fb97ded34b1241ea97c2cd7b71c8aa
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jul 22 11:36:22 2014 -0600
+
+ Core: on exit, wait for threads.
+
+ This path makes Monkey workers Joinable, upon exit it joins the
+ threads before to exit. Safe exit.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 644f1b48740dcb6db55cd79af1191643dbf197b6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jul 22 10:26:00 2014 -0600
+
+ Core: zero leaks on exit without load
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6296f0aadc172c67db7cdeb2be74ea1fb63ab96c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jul 22 08:44:25 2014 -0600
+
+ Plugin: start releasing worker resources on exit
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 85265408ad5251b8a43052f6c9994f1570915dbf
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue Jul 22 08:25:56 2014 -0600
+
+ Proxy Reverse: fix mk_ptr usage
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 31b82584f9adfa6173a70b9581448ee3c683d3a2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 21 23:20:52 2014 -0600
+
+ Plugins: fix mk_ptr_XYZ() calls
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 11d9e17d707fcdf1a20fbb94edb0dcb127c53fbf
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 21 23:13:45 2014 -0600
+
+ Mimetype: remove old SAFE_FREE macro
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6ddc5dbaac55a19469e2ab6ec78915e9f0fdcaf0
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 21 23:11:44 2014 -0600
+
+ Memory: rename mk_ptr_XYZ() functions
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 32877c2bfbf615e0d0d1486f47d017abbb450222
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 21 23:08:03 2014 -0600
+
+ Configure: cleanup
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 33ac7891f7e309c24f769d4e7bd0c22834fd92bb
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 21 22:58:49 2014 -0600
+
+ Mimetype: release default entry on exit
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 82fe17e1821f6931cb641ac6e65cdfc4284026c9
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 21 22:27:22 2014 -0600
+
+ Core: release resources on exit, the saga continue
+
+ this patch makes to release many resources from the core subsystems
+ such as epoll_states, vhost fdt, clock, buffers cache, etc.
+
+ This is still work in process and the pending areas are:
+
+ - Global scheduler
+ - Plugins -> per worker exit
+ - Plugin Events
+ - Plugins shared libraries
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0f38f5e3ac52e172a87822e9151933d6d6823474
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 21 20:40:26 2014 -0600
+
+ Core: minor memory releases on server exit
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c48ca4eb6e6c535e2c0061fea0ef70135e03ed69
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 21 20:32:02 2014 -0600
+
+ Core: SAFE_FREE is now the default and not longer optional
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit bac02a04f8e84f2fd282b33be7ab996bfbf12d33
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 21 19:36:43 2014 -0600
+
+ Core: on SAFE_FREE, release list of mime types
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 56a67aa3cfe7e059c40a9a424ff3abbee111a016
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 21 10:37:51 2014 -0600
+
+ Debian: adjust rules for packaging
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 4c5037cc43f30bf9b6d8ab958043410b4d6a0773
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 21 10:27:47 2014 -0600
+
+ Configure: install headers to new path
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e92f318066ad5e69834b0e4b241ac81f03b7a947
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 20 23:32:55 2014 -0600
+
+ Debian: prepare for v1.6.0
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e10ca4560c07cc6f6efb1a919bcfbd0ed21f1c0f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jul 18 15:35:58 2014 -0600
+
+ Debian: bump to 1.5.2
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+ Conflicts:
+ debian/changelog
+
+commit 4d6bf1e10a5b65a73ec96fdf790c8d16d8ca7ff1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 20 23:01:59 2014 -0600
+
+ README: tweaks
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 10465318965aab16527fae5933568f72887b2887
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 20 22:58:05 2014 -0600
+
+ README: move to Markdown mode
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7de944bc3cb145200645fa73b0008b5bfdbcee24
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Mon Jul 21 07:46:48 2014 +0300
+
+ Libmonkey: Implement library callbacks in cython
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit b62a54a08376ebac22210c2a07f610913cf0d859
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 20 21:42:26 2014 -0600
+
+ Configure: adjust main Makefile
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 67b66c8a6aa388fa43e746a7fe4e282b670322ca
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 20 21:22:48 2014 -0600
+
+ Header: add missing monkey.h
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 72551048ceb109bcb3407864a5257736d19457f4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 20 21:21:55 2014 -0600
+
+ Structure: add missing headers
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8f41cb714ced0679f99b7b5d5e2ff8d2ffcb689a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 20 20:55:25 2014 -0600
+
+ API: fix included headers
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 8da3e0570d07962952c4a63ad7ec352f8111e789
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 20 20:48:08 2014 -0600
+
+ Proxy Reverse: fix API header
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 075795ac0747ff2f97f4bb75bcbb35a4efb49460
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 20 20:37:46 2014 -0600
+
+ Configure: build path fixes
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 6a045c7eff74ef6b132fd51ad5f51afb95ae9c80
+Merge: 3cb9c1c ec7f216
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 20 15:49:01 2014 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit 3cb9c1cf7da3f98423e9d568b738a2a49b16d087
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 19 10:37:35 2014 -0600
+
+ HTTP: on using API sendfile, check EAGAIN
+
+ Some plugins may not be too efficient to buffer outgoing data
+ and when implementing the sendfile callback on some cases it will
+ need to re-call the routine until the Kernel enqueue the data.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f28b6255ab6410df02b8cde5c51de1e20c896bf6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jul 18 16:46:55 2014 -0600
+
+ HTTP: If-Modified-Since now allow clients from the future.
+
+ Before this patch the server did not respect a conditional
+ If-Modified-Since if the value was higher than the system server
+ date. This patch makes this pass, not a bug but make it more
+ friendly with Checker tools.
+
+ This patch also fix a QA script involved.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit db6949f5c43e420f5c38cad72fd6f8d42a8b483a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jul 18 15:24:21 2014 -0600
+
+ Signal: restore handler for SIGPIPE.
+
+ This problem was introduced on commit 84fa79eb. Without the SIGPIPE handler
+ the server will stop working when the Kernel trigger a SIGPIPE because of a
+ remote socket disconnection.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 460df48d8abbecf02c17f192f298ec8fd910db23
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jul 17 23:22:23 2014 -0600
+
+ Core: change name in banner
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f410faadae298fa53994d0e42cb19d4e9165c61e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 13 11:53:49 2014 -0600
+
+ Mimetype: add SVG types (fix #153)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 23dc017c67e8b09e2ca6a512e783f040bf118310
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 20 15:48:02 2014 -0600
+
+ Structure: adjust configure script and mklib
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit ec7f216dd2e03c974152f0e009b05b152c4f3bd2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat Jul 19 10:37:35 2014 -0600
+
+ HTTP: on using API sendfile, check EAGAIN
+
+ Some plugins may not be too efficient to buffer outgoing data
+ and when implementing the sendfile callback on some cases it will
+ need to re-call the routine until the Kernel enqueue the data.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c24e8a7344dd63375f55be4902c61fd3879f614f
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jul 18 16:46:55 2014 -0600
+
+ HTTP: If-Modified-Since now allow clients from the future.
+
+ Before this patch the server did not respect a conditional
+ If-Modified-Since if the value was higher than the system server
+ date. This patch makes this pass, not a bug but make it more
+ friendly with Checker tools.
+
+ This patch also fix a QA script involved.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 67fe5023e7364106258816987c918108b8bac979
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jul 18 15:24:21 2014 -0600
+
+ Signal: restore handler for SIGPIPE.
+
+ This problem was introduced on commit 84fa79eb. Without the SIGPIPE handler
+ the server will stop working when the Kernel trigger a SIGPIPE because of a
+ remote socket disconnection.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f23158d22398bffb0c7961312ca8225c84ee46d2
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jul 17 23:22:23 2014 -0600
+
+ Core: change name in banner
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit e5d9a21c5460df45e6d22e6eb8084623602f9b8e
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Mon Jul 14 20:46:41 2014 +0300
+
+ Libmonkey: Implement python bindings for configuration
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit ed9f1f600702949bd68f992a2a658de82204da32
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 13 11:53:49 2014 -0600
+
+ Mimetype: add SVG types (fix #153)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9d1ed470588d1ace4098c8b68d8059feea39a594
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jul 13 11:47:24 2014 -0600
+
+ Structure: move headers to different location
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0b80fd51f89ed7664297e6a45d9eafcf6280181d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jul 7 12:12:41 2014 -0600
+
+ Configure: options to set PolarSSL specifics.
+
+ This patch add 3 options to the configure script:
+
+ --polarssl-headers Path to PolarSSL headers
+ --polarssl-library Path to PolarSSL library
+ --polarssl-debug-level Set PolarSSL debug level (not implemented)
+
+ the first two aims to make things easier when using a custom or
+ compiled from scratch version of PolarSSL library.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 0d22025603d23e15c9a6422d00b7b343bd2ddd90
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Mon Jul 7 01:03:08 2014 +0300
+
+ Libmonkey: Implement start and stop server python bindings
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 5df26f337df3ad9f6378eb0a1c2188c05b1bb845
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Mon Jul 7 00:59:24 2014 +0300
+
+ Libmonkey: Fix stats configure for ldpreload
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 53290a9464bcaebbbfcbf7426194d6ebef5e4d25
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jun 29 22:34:32 2014 +0300
+
+ Libmonkey: Add selectively compiling support for stats
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit ca5f6306807d7aabddd31576c9ec46e9beb15f20
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jun 29 20:49:17 2014 +0300
+
+ Libmonkey: Remove commented lines in mk_lib.c
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit b6a7ac0d254ef7be451dd037d47920a3585887f8
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jun 29 02:43:01 2014 +0300
+
+ Libmonkey: rework stats using LD_PRELOAD mechanism
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit e1b9177e1797a2de0185b125b28425869e10199b
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Wed Jun 25 20:41:19 2014 +0300
+
+ Libmonkey: Reduce number of fields in stats data structure
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit a3205fefcc59a3ec06217d81d50c1721bf769642
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Wed Jun 25 20:32:30 2014 +0300
+
+ Libmonkey: enable kernel features in mklib_init
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit b245a7b7bea66ce84204137f5fff3e74aa0b582a
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sat Jun 21 16:19:57 2014 +0300
+
+ Libmonkey: Add configure option for enabling worker statistics
+
+ Use ./configure --stats
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 91566a7bb954ccbb384b2027e649cc86a41480d4
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Fri Jun 20 15:15:23 2014 +0300
+
+ gitignore: Add more stuff to gitignore
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 6e6374f0eb8296ee42377c5c7358aa41d2521861
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Fri Jun 20 15:12:53 2014 +0300
+
+ Libmonkey: Compile and run library test suite from a bin/ directory
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 989526d72e2044337935327c09bdb584f14502c8
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Fri Jun 20 14:57:34 2014 +0300
+
+ Libmonkey: Add library configuration retrieving functionality
+
+ Also write a test for it.
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 9c3b83de4c92e17f13c7fc51111748e6f6a63dfd
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Fri Jun 20 02:42:49 2014 +0300
+
+ Libmonkey: Cosmetic fix to mimetype test
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit afbf12c7f3d2ab02eda15d64506f619c80412395
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Mon Jun 16 00:04:29 2014 +0300
+
+ Libmonkey: Trace mk_conn_read and mk_conn_write
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 7aa33a64faef50c2f34dff47377a5be868fd336b
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jun 15 20:32:10 2014 +0300
+
+ Libmonkey: Add counters to more functions
+
+ mk_http_init, mk_plugin_event_read,
+ mk_plugin_event_write, mk_header_send
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 95f483a874a1746500faa16ffdbefd22f16bdc61
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jun 15 19:54:35 2014 +0300
+
+ Libmonkey: Trace mk_plugin_stage_run, mk_http_range_parse and mk_sched_remove_client
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 8df48c3a3e90bd59f2b83d101c9156d265ba4bde
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jun 15 19:21:31 2014 +0300
+
+ Libmonkey: Add routing for printing worker stats
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit c4c70c1466a8bb4a272dc890a6f9f7d5e0036ab9
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jun 15 18:32:22 2014 +0300
+
+ Libmonkey: Add STATS_COUNTER_INIT_NO_SCHED
+
+ Avoid redundant calls to pthread_getspecific
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit b383962ffc2d8905552657c1fd1856ee4d20da17
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jun 15 15:26:28 2014 +0300
+
+ Libmonkey: Add mk_sched_get_connection to stats
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit eb5235601a719ecccea9165780936259e1b25d27
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jun 8 18:13:26 2014 +0300
+
+ Libmonkey: Implement simple stat counters
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 1a57d6a2d1dd8002acfe511f12deef97cdd6f897
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jun 8 00:00:38 2014 +0300
+
+ Libmonkey: Add option to select tests to run-tests.sh
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 43da338886ccc8cbe2fbc7415de8b3a0f6493804
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sat Jun 7 23:51:11 2014 +0300
+
+ Libmonkey: Add new test for worker info
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 24b4c7eb8f30adcab0181787765caeffa30ad710
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sat Jun 7 23:18:55 2014 +0300
+
+ Libmonkey: Fix warning in md5_check.h
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 928cfc6e4c418528dcf0258a796eebe3ec2582d6
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sat Jun 7 23:16:57 2014 +0300
+
+ Libmonkey: Add accepted_connections to mklib_worker_info
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 8060135ec5507d1d2a2d998d301ce06c9333d0a3
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jun 1 20:45:17 2014 +0300
+
+ Scheduler: Close connection after MK_PLUGIN_STAGE_10
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit cf078f7ab53f0fdce55562b91f7f651df8301b8b
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sat May 31 01:20:28 2014 +0300
+
+ Libmonkey: fix run-tests.sh
+
+commit 77c4b30bdb36550e7e7bf7d3eb9fe01f940e5f89
+Author: Felipe Reyes <freyes@tty.cl>
+Date: Tue Jun 24 22:34:43 2014 +0200
+
+ Update FSF address in a couple of headers
+
+ The headers were using the old FSF address.
+
+commit 53504ed659b58b20f97de5286f6627039452fc01
+Merge: 57d2cda 4f3bd16
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jun 22 23:45:18 2014 -0600
+
+ Merge branch 'fixwarning' of https://github.com/kaspersky/monkey
+
+commit 57d2cdad0b3acc9036dc39edad27a01bc10bcefd
+Merge: 4df84b8 dbcaf87
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun Jun 22 23:44:59 2014 -0600
+
+ Merge branch 'fixconfigure' of https://github.com/kaspersky/monkey
+
+commit 4df84b84f6000b436df042c808b3530e260d2e21
+Author: Felipe Reyes <freyes@tty.cl>
+Date: Sun Jun 22 23:32:14 2014 +0200
+
+ Fix date in changelog of spec file
+
+ The day of the week was Thursday when it should be Tuesday, also the
+ email's domain of the author of that same changelog entry was fixed.
+
+commit 4f3bd16e92916bfece41173d3efd8b00968398e2
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jun 22 23:38:29 2014 +0300
+
+ Scheduler: Fix warning for implicit declaration
+
+ Add declaration of mk_sched_check_capacity in mk_scheduler.h
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit dbcaf87889c8941dfe4bb8caf5e20bb5eb849a3b
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sun Jun 22 23:32:49 2014 +0300
+
+ configure: Fix compilation (".lo" objects)
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 53af4faac9859a4c860b377ce1933c13fc7316a2
+Merge: 33334a6 b3a41d6
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri Jun 20 11:04:30 2014 -0600
+
+ Merge branch 'lineindentfix' of https://github.com/kaspersky/monkey
+
+commit b3a41d60c7694c87586d75a3cbaf5ce9ab6d76c0
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Fri Jun 20 15:34:05 2014 +0300
+
+ Plugins: fix indentation of 2 lines in mk_plugin.c
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 33334a6bdeed850ca412eb3f53bf80ddd80c5329
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu Jun 12 20:20:55 2014 -0600
+
+ wip configure
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c7646b792d270401b82eac67c6c46d456de8ec18
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 9 23:26:22 2014 -0600
+
+ WIP: overcapacity
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit acad4a9d60bb552b25be6d5b00e817795fbebd8b
+Merge: 93368c4 46a2552
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 9 21:56:52 2014 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit 93368c4f6245eab247a8e7558ec9943772a15afe
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 9 16:24:08 2014 -0600
+
+ Core: fix user switch when running as root
+
+ Previous this patch the core was using real user id as reference
+ to perform user switch but when restoring back this is not allowed
+ by the Kernel, the right way to do it is through the effective user ID.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 7cf4d7f26ece9030179d3761931e625313e5f26a
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 9 15:53:41 2014 -0600
+
+ Core: switch user after Bind port.
+
+ When running in newer systems with Kernel >= 3.9 and the SO_REUSEPORT
+ option is used, the server was switching to the unpriviledge user before
+ to bind the TCP port, this was generating problems when the port was <= 1024.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 46a2552ddfaf9f7a4f77cc97e7df57cdf0b25abd
+Merge: 06c02a4 dad05cd
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 9 10:01:44 2014 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit 06c02a4efd3f939008acbbdcfd91840851f85cf1
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon Jun 9 10:01:31 2014 -0600
+
+ Configure: update banner
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit dad05cd82200d92e81c134c6e1ffd11e2eb75786
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Sat May 31 00:31:43 2014 +0300
+
+ Libmonkey: fix mimes configuration file name
+
+commit b30bfcb8ee0e151443d93483cfbcf3d70535077f
+Merge: 6bde0ec 5014aae
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu May 29 09:10:57 2014 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit 6bde0ec0f322614c685a66693e8a713a3d071126
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu May 29 09:03:26 2014 -0600
+
+ Debian: bump version to 1.5.0-2
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 29e93616d8ad05121af843fbdba5fe699cd98426
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu May 29 08:54:01 2014 -0600
+
+ Debian: fix PidFile path
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5014aaebe48c4a1ca1151f22bbaae0e46126b9c5
+Merge: b2e0eda 5e43e08
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed May 28 21:54:46 2014 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit b2e0eda8459ae99a3f2409add2dd95fb1acd1659
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed May 28 21:54:37 2014 -0600
+
+ Config: allow empty sections, just warn them
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5e43e08fde033ca62d1a79d6261985e6c69801f5
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon May 26 15:52:18 2014 -0600
+
+ Development of v1.6 begins :)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit dd861f49dce2c78f13a45b82cb15f7ac5935a8cd
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun May 25 17:12:44 2014 -0600
+
+ Update ChangeLog for v1.5.0
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2b0f84634272a3b695587dfb9b21a2ba792b98eb
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun May 25 17:12:28 2014 -0600
+
+ Debian: drop dependency of old packages
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 9bf5eaf420f80bd130bc47168926d5bb48f0acee
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sun May 25 15:31:32 2014 -0600
+
+ Configure: new argument to set PidFile in default monkey.conf
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1bd7c17e0ec88b9bd20c29f68759952f5cf02446
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 24 21:48:19 2014 -0600
+
+ Configure: bypass OpenEmbedded/Yocto arguments
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit b3f21be68bca3f91857a49ceba4ed03245103462
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 24 21:09:52 2014 -0600
+
+ HTML: set release date
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit a479b9cb852ee686d3ef2ecae8fe1d6d9a9f2fba
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 24 16:39:49 2014 -0600
+
+ HTML: codename 'Emperor Tamarin'
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit c9314b429091cec6b25c726cb209b9554d02a8a3
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Sat May 24 15:58:38 2014 -0600
+
+ Proxy Reverse: do not remove FD from event pool on hangup
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5aed3d31417d5b0efdd190570720647a679fcd85
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu May 22 11:59:57 2014 -0600
+
+ HTML: prepare home page for next version
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5f2c9addc7a3e3e9bf40a78b6558eaf7ea950ce4
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu May 22 11:40:57 2014 -0600
+
+ FastCGI: do not remove the FD event on hangup (Monkey already did)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 96b03a487b6731331f0092a98704f2c686b02241
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Thu May 22 11:28:50 2014 -0600
+
+ Connection: on close, remove FD from Scheduler first
+
+ when a hangup or connection close event is raised, the core
+ was invoking plugins callback directly and at the end the Scheduler
+ for removal procedure.
+
+ This behavior ended up in a problem as the core is not aware about
+ what a plugin is doing after a callback, the plugin may "open" a
+ new connection (new FD) and the Kernel "may" assign the previous FD
+ closed number again, ending in a new close from the caller, e.g:
+
+ - Plugin request to hangup a connection.
+ - Core receive the event and invoke callbacks for closing stuff.
+ - Plugin after cleanup decides to create a new FD.
+ - The Kernel assign the same FD number than the recently closed.
+ - Core retakes the control and let the Scheduler close everything
+ related to the original FD.
+ - The Core is closing "the NEW FD" messing up everything.
+
+ After this patch the behavior is:
+
+ - Plugin request to hangup a connection.
+ - Core receive the close event, invoke the Scheduler.
+ - The Scheduler cleanup all references for this FD, also it make
+ sure to remove event notifications from the epoll(7) loop.
+ - The Core invoke callbacks for closing stuff.
+ - Everything gets clean properly.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 5ab55cb77e27a0159a8323822897dc3910959cc8
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed May 21 21:59:11 2014 -0600
+
+ Plugin: do not re-set event list
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 83bf013de38df051bbdf20de6cfc604cca20411d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Wed May 21 21:15:54 2014 -0600
+
+ Utils: fix return value check on libc_error() stuff
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 15f72c1ee5e0afad20232bdf0fcecab8d62a5d89
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue May 20 11:22:19 2014 -0600
+
+ Mandril: check decoded URI (fix #92)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit f929f3e6dca9a0ff2e08dcd286346ef7e436c139
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon May 19 11:00:16 2014 -0600
+
+ Doc: update Contributing file (lines length)
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 1c9538ed901643a03af601115f88c37f98bbf066
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon May 19 10:55:50 2014 -0600
+
+ Debian: structure changes
+
+ From now all plugins that do not depends on external dependencies are
+ distributed from the principal Monkey package. The only plugin that remains
+ as a separate package is monkey-polarssl.
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 2635bbb3d2b3dfb36835aee01a0b04b1c686ecb3
+Merge: 5f998e1 547b701
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue May 13 08:56:27 2014 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit 5f998e189e293ab854e892012bd91b7710591734
+Author: Savita TS <savita.seetaraman5@gmail.com>
+Date: Tue May 13 18:58:25 2014 +0530
+
+ Signals: Removed unused variable 'old' in mk_signal_thread_sigpipe_safe()
+
+ Removed the variable 'sigset_t old' in line 71 from function, 'void mk_signal_thread_sigpipe_safe()'. This patch removes the following warning caused during 'make':
+
+ ------------------ WARNING ---------------------
+ mk_signals.c: In function ‘mk_signal_thread_sigpipe_safe’:
+ mk_signals.c:71:19: warning: unused variable ‘old’ [-Wunused-variable]
+ ------------------ WARNING ---------------------
+
+ Signed-off-by: Savita TS <savita.seetaraman5@gmail.com>
+
+commit 58fe3faf2fb919a5a2ac7fd68b3770a3c781b149
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon May 12 00:17:43 2014 -0600
+
+ Virtual Host: add Redirect support (Fix #132).
+
+ This patch implements a basic HTTP redirect functionality at
+ Virtual Host level, when the Redirect key is set on the Virtual
+ Host configuration file, for every incoming request the server
+ will perform a HTTP redirect. e.g:
+
+ [SERVER]
+ Redirect http://monkey-project.com
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 547b701b2f69a6c6a89ff2887488dd8c6a73ee88
+Merge: 868d751 38f823e
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Tue May 13 08:54:08 2014 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit 868d751d2cdfa2a00ad386b0085efd69f498c87c
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon May 12 00:17:43 2014 -0600
+
+ Virtual Host: add Redirect support (Fix #132).
+
+ This patch implements a basic HTTP redirect functionality at
+ Virtual Host level, when the Redirect key is set on the Virtual
+ Host configuration file, for every incoming request the server
+ will perform a HTTP redirect. e.g:
+
+ [SERVER]
+ Redirect http://monkey-project.com
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 3df0f7ebc6fce3976edd7fc6fbabb8f7619748c7
+Author: Savita TS <savita.seetaraman5@gmail.com>
+Date: Tue May 13 19:05:17 2014 +0530
+
+ Socket: Added a variable to accept return value of read() in 'mk_socket_tcp_autocorking()'
+
+ Added a variable to accept the return value of read() in line 266 in function 'mk_socket_tcp_autocorking()'. This patch removes the following warning that arises during 'make' :
+
+ --------------- WARNING --------------------
+ mk_socket.c: In function ‘mk_socket_tcp_autocorking’:
+ mk_socket.c:265:9: warning: ignoring return value of ‘read’, declared with attribute warn_unused_result [-Wunused-result]
+ --------------- WARNING --------------------
+
+ Signed-off-by: Savita TS <savita.seetaraman5@gmail.com>
+
+commit b08cdddb2e4383ac96689a4a3739713c570e3bb2
+Author: Savita TS <savita.seetaraman5@gmail.com>
+Date: Tue May 13 18:58:25 2014 +0530
+
+ Signals: Removed unused variable 'old' in mk_signal_thread_sigpipe_safe()
+
+ Removed the variable 'sigset_t old' in line 71 from function, 'void mk_signal_thread_sigpipe_safe()'. This patch removes the following warning caused during 'make':
+
+ ------------------ WARNING ---------------------
+ mk_signals.c: In function ‘mk_signal_thread_sigpipe_safe’:
+ mk_signals.c:71:19: warning: unused variable ‘old’ [-Wunused-variable]
+ ------------------ WARNING ---------------------
+
+ Signed-off-by: Savita TS <savita.seetaraman5@gmail.com>
+
+commit 38f823e329a6a757a255f981a073edda7bad53c8
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Mon May 12 00:17:43 2014 -0600
+
+ Virtual Host: add Redirect support (Fix #132).
+
+ This patch implements a basic HTTP redirect functionality at
+ Virtual Host level, when the Redirect key is set on the Virtual
+ Host configuration file, for every incoming request the server
+ will perform a HTTP redirect. e.g:
+
+ [SERVER]
+ Redirect http://monkey-project.com
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 133c62d5635bd3c4181b3cf1fa8fc11640d3f684
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri May 9 14:50:54 2014 -0600
+
+ Doc: update INSTALL
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 84fa79eb42617d57207bba784157f5b48ce6c25d
+Author: Eduardo Silva <eduardo@monkey.io>
+Date: Fri May 9 10:40:49 2014 -0600
+
+ License: core and plugins are now under the Apache License v2.0
+
+ Signed-off-by: Eduardo Silva <eduardo@monkey.io>
+
+commit 50d34fca7dc3ff6af4e2de492ab06c5e6d136b83
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun May 4 19:58:35 2014 -0600
+
+ CGI: make sure the Interpreter can be used, otherwise use status 500
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d63286e36abce81f1e6aca261e1534d4e96edeb7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 3 17:18:33 2014 -0600
+
+ CI: enable IRC notifications
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0698068328e660270fc3d419bb8fc0142f398893
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 3 17:00:41 2014 -0600
+
+ CI: disable PolarSSL due to test box problem
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7882a48badc0fd22fc425d84deb673cfcda5744a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 3 16:54:43 2014 -0600
+
+ CI: add PolarSSL dependency and compile SSL Plugin
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 60296a159ab9f805d25daf8736b880b790503428
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 3 16:43:54 2014 -0600
+
+ CI: add Travis integration
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit df6f67ceff090c5202107060aba87212ff99ce0e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 2 21:29:31 2014 -0600
+
+ Auth: move mk_passwd code into tools/ for clean build
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a4225df6ff7e065ce9ee1a76846fef939106eb8b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 2 14:33:17 2014 -0600
+
+ Auth: make mk_passwd work without Monkey internals.
+
+ This patch adds a few workarounds to make mk_passwd avoid Monkey
+ internals about memory allocations and string lines dependencies.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4a4ae564079574fcf7ed81ac07808d9025f33c7b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 30 22:18:59 2014 -0600
+
+ Request: optimize initialization of session_request
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2371f385c9b89208a8724821d8988142599c1a79
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 29 16:42:12 2014 -0600
+
+ Lib: fix parameters for mk_socket_server() call
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f1876018eb32cf3c1cf7cdf77e34fea203fdbad0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 29 16:35:30 2014 -0600
+
+ Debian: minor updates
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 409c5fb0e9636052acd4a41013694372739a1ba0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 28 21:12:28 2014 -0600
+
+ Doc: CONTRIBUTING.md: specify number of chars per line
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8b97b01ef591186929b6d59dffef2988b4808526
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Tue Apr 29 00:00:36 2014 +0300
+
+ Auth: Rewrite mk_passwd in C (close #131).
+
+ This patch drops the mk_passwd python script from auth plugin, by adding an
+ equivalent C implementation.
+
+ The C implementation makes use of Monkey functions, whenever possible, so it
+ links with Monkey objects.
+
+ In order to make the linking possible, some minor modifications had to be made
+ to the configure script, monkey.c and mk_config.c source files.
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 9e8444445daa2a2ad12d774250ec1bbe924e8362
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 28 10:12:43 2014 -0600
+
+ Socket: fix array index.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b4ef860e3f2edd1de6d0626c19a56730e7104428
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 28 10:05:48 2014 -0600
+
+ PolarSSL: Enable REUSEPORT feature
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e2ede773d0341f65e7be99887c699f8af206d6ee
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Apr 25 04:29:44 2014 +0200
+
+ PolarSSL: Enable session cache.
+
+ Sets session cache on ssl context.
+ Moves pk_context to local thread context to allow use of polarssl
+ compiled without threading support.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit c51124d1ab2e1900b4eee4a9ef8adab58c59295b
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Apr 25 04:28:26 2014 +0200
+
+ PolarSSL: Fixes error where connection isn't terminated on error.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 3b22521b6fed4d1f13a62f898a8b379168bde97e
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Apr 25 04:00:40 2014 +0200
+
+ PolarSSL: Drops polarssl v1.1 support.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit c8dba9b191784af72c82e4884520e4919b706661
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 26 23:21:52 2014 -0600
+
+ Scheduler: enable TCP_DEFER_ACCEPT on REUSEPORT mode
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0da162a6cae7c7c5616afda06b18973c9fcb643d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 26 23:06:54 2014 -0600
+
+ Cheetah: on status command, print new Kernel features
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a94fa2e04f8b4508e62f4c92950c951986c1b430
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 26 23:05:09 2014 -0600
+
+ Plugin API: export mk_kernel_features_print
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9a6ad8a67a09e72d96ca7b2d740569f39a1494dd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 26 22:40:37 2014 -0600
+
+ HTTP/Server: use new server_cork_flag() interface
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7aed9dd5f4685a5481209e898a905918e1fb7759
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 26 22:36:11 2014 -0600
+
+ Config: check kernel_features flag for REUSEPORT
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit de083846ecece14949b66575851b66b411efd54f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 26 22:31:49 2014 -0600
+
+ Kernel: remove unused variable
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9d7a8cda6b967abd24e34b0369dfcae1ded7885a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 26 22:24:05 2014 -0600
+
+ Kernel: new features interfaces and core flags
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fcfba4903f61b33e01124bbc8a60ea47f4d94b0a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 26 10:19:11 2014 -0600
+
+ Scheduler: Little improvements over REUSEPORT implementation.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d1da249a0b5e8f5765ea8031919fb32e93c57cb8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 24 22:57:43 2014 -0600
+
+ Scheduler: new REUSEPORT balancing method/architecture.
+
+ Starting from Linux Kernel 3.9, there is a new TCP/UDP socket option which allows
+ to bind same port and address from multiples threads (or any instance under the
+ same process context).
+
+ This patch implements the SO_REUSEPORT TCP Flag if the running Kernel is >= 3.9,
+ so on that mode each working thread create it own socket that bind the same address,
+ with this implementation we reduce the number of system calls involved when a new
+ connection arrives, avoid lookup the lowest loaded thread and also we allow the
+ Kernel to perform a better Scheduling on SMP systems that requires to scale.
+
+ If the detected Kernel is lower than 3.9, it will use the old Fair Balancing
+ mechanism.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 27878547891bdac7456fbae2c60942434d40e065
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 24 19:51:57 2014 -0600
+
+ Config: fix typo in mk_kernel_runver
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 17df1070b417cca6d13ee3e863c3680830d27960
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 24 09:24:44 2014 -0600
+
+ Socket: TCP Auto Corking only on Linux >= 3.14.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 697341887751ac74f0e477754b18229e7c05d952
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 23 23:51:30 2014 -0600
+
+ Socket: enable TCP_FASTOPEN only on Kernel >= 3.7.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2c38ddb3178aefbe9122702309d2bfa183a11ac4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 23 23:36:22 2014 -0600
+
+ Kernel: new interface to query Linux Kernel version.
+
+ This patch implements two things:
+
+ 1. Macro MK_KERNEL_VERSION() to return an unique representative integer
+ of the Linux Kernel version given the 3 common values.
+ 2. Function mk_kernel_version() that returns the Kernel version from
+ the running system.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9b6f016df7d68f7a8fbd67b7f0b1aaf4eb597248
+Merge: ccd9d24 30c050b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 15 09:27:33 2014 -0600
+
+ Merge pull request #128 from tssavita/patch1_epoll
+
+ Epoll: Reporting when event EPOLLRDHUP occurs for an fd
+
+commit 30c050b50f9940d9743c7b711fd10310764e3d04
+Author: Savita TS <savita.seetaraman5@gmail.com>
+Date: Tue Apr 15 17:21:56 2014 +0530
+
+ Reporting when event EPOLLRDHUP occurs in a file descriptor registered in an epoll instance
+
+commit ccd9d24e94e8cc5a0ca4053c1e9983edfe27dbfa
+Merge: 06fb6c9 d253f45
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 8 10:42:57 2014 -0600
+
+ Merge pull request #127 from tssavita/http-conditionals
+
+ HTTP: Removing unnecessary conditionals from src/mk_http.c
+
+commit d253f454ef2e0f313ebbcdd40bd45b36b6253516
+Author: Savita TS <savita.seetaraman5@gmail.com>
+Date: Tue Apr 8 17:54:38 2014 +0530
+
+ Removing unnecessary conditionals from src/mk_http.c
+
+commit 06fb6c9f8968fbc358551f571febc20a57a4f336
+Merge: ba0fb33 635c130
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 6 08:05:48 2014 -0600
+
+ Merge pull request #125 from TamerTas/master
+
+ HTTP: Fix comments' grammar and punctuation in mk_http.c
+
+commit 635c1304dd803e611e673521f6b3f389de6438e9
+Author: TamerTas <tamertas@outlook.com>
+Date: Sun Apr 6 14:25:29 2014 +0300
+
+ HTTP: Fix comments' grammar and punctuation in mk_http.c
+
+commit ba0fb3326560c2d8ba0af7fabfe6bcdf4c0d60ca
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 2 23:31:17 2014 -0600
+
+ Socket: handle new Kernel 3.14 tcp_autocorking feature.
+
+ the server use the TCP_CORK feature to instruct the Kernel to
+ wait for some data before dispatch it on the socket buffer. This
+ is a common approach when sending HTTP response headers and then
+ a content body (file data).
+
+ The Linux Kernel 3.14 introduce a new feature called 'tcp autocorking',
+ it basically do TCP_CORK by default based on specific conditions of
+ each socket status. This is a good approach to let the Kernel to decide
+ when it can be used and also it avoid user space to invoke two system
+ calls to enable/disable the TCP_CORK.
+
+ This patch makes the Server to validate if the new feature exists on the
+ running Kernel and if is enabled, it will disable all manual corking done,
+ for more details about how it works at Kernel level refer to the following
+ patch:
+
+ http://goo.gl/AMFIuI
+
+ Note: on an older Kernel it will continue working as usual.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1b486a5d0930d13b042d2e4128455a3e8bd9f022
+Merge: 698f2a5 3946861
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 2 13:32:47 2014 -0600
+
+ Merge pull request #115 from kaspersky/master
+
+ Monkey configuration: add program options for configuration paths
+
+commit 698f2a554845659645835f6b978004f98ec7c708
+Merge: 1b16611 7ddf7f9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 2 13:32:10 2014 -0600
+
+ Merge pull request #123 from kaspersky/systemd
+
+ Systemd: add unit file monkey.service
+
+commit 7ddf7f99126487a94064e559edfd570c7e92b745
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Mon Mar 31 23:40:46 2014 +0300
+
+ Systemd: add unit file monkey.service
+
+ This patch adds a unit file for systemd init system, as described in issue #39.
+ The installation of the unit file is triggered by the "--systemddir" passed to configure script, in the following way:
+ $ ./configure # no systemd unit file deployed
+ $ ./configure --systemddir # Unit file systemd.service is created with default installation path "/lib/systemd/system"
+ $ ./configure --systemddir=CUSTOM_PATH # Unit file systemd.service is created with installation path "CUSTOM_PATH"
+
+ The unit file is deployed is deployed using "make install" command, so you should also specify "--prefix" option for configure.
+
+ I tested the patch on archlinux and fedora (systemd init system) deploying the unit file in different system paths. The following commands were successful:
+ $ service monkey start
+ $ systemctl start monkey.service
+
+ I also tested on ubuntu (upstart init system), ensuring nothing is broken.
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 1b16611c40d763160a41646cabd0173a08d5ca00
+Merge: d289b9d e74ff9f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 1 10:41:45 2014 -0600
+
+ Merge pull request #122 from tssavita/sched_plugin
+
+ Scheduler-Plugin: Moving and renaming function mk_sched_worker_info()
+
+commit e74ff9f8f96726a4ef4db63032680fb2ca3cbf90
+Author: Savita TS <savita.seetaraman5@gmail.com>
+Date: Tue Apr 1 21:53:47 2014 +0530
+
+ Scheduler: Moving and renaming function mk_sched_worker_info() to mk_plugin_sched_get_thread_conf
+
+commit d289b9d1e307e7ec8b865cfd2cb8d2cb6fd4b520
+Merge: adc4ccc c253b36
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 31 11:03:14 2014 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit adc4ccc42780ff96e03257cb625d7441f556d7b0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 31 11:00:58 2014 -0600
+
+ Memory: upgrade Jemalloc to 3.6.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c253b3675fe90361fef91139127db7c76f55f32d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 29 11:22:53 2014 -0600
+
+ Epoll: when adding a new FD, return status value
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3400e110bc3c5f6e24fce0ef1f3c0e77cd9d745f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 27 22:28:36 2014 -0600
+
+ Vhost: skip files ending in '~' (editor backups)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 11d7459f9c719433244d0a5d7fd2bd7b61c77b0d
+Merge: f5ce9bf 0f51130
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 27 21:14:20 2014 -0600
+
+ Merge pull request #120 from tssavita/iov_patch2
+
+ IOV: store buffer type from char changed to void in function 'void _mk_iov_set_free'
+
+commit 0f511308bd443f72b5bc7b451870a4e363ac8029
+Author: Savita TS <savita.seetaraman5@gmail.com>
+Date: Fri Mar 28 04:33:51 2014 +0530
+
+ IOV: store buffer type changed to void in function '_mk_iov_set_free'
+
+commit f5ce9bfcb83e53ee6d043b52c918bc33272d00b9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 24 22:38:35 2014 -0600
+
+ IOV: store buffer using void data type instead of char
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3946861b5b5b4e0755b47c39d0f1fbcc87995542
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Wed Mar 19 23:50:27 2014 +0200
+
+ Monkey configuration: add program options for configuration paths
+
+ This patch solves the issue #36.
+
+ 4 additional program arguments were added for specifying different
+ configuration files and directories:
+
+ -m, --mimes-conf-file # path to monkey.mime
+ -P, --plugins-conf-dir # path to plugins configuration directory
+ -l, --plugin-load-conf-file # path to plugins.load file
+ -S, --sites-conf-dir # path to sites directory
+
+ Each option has a default value.
+
+ Monkey will try to interpret the options by prepending their values
+ to default configuration directory. If the obtained path does not
+ exist, the options will be treated as absolute paths.
+
+ I tested using ./configure --prefix=path --plugdir=--path2 and
+ default build. I was able to load different configuration files
+ from custom locations with custom names, overriding the default
+ names which were hardcoded in Monkey.
+
+ The patch also contains an unrelated fix to:
+
+ bin/monkey --confdir # was not working, while provided by --help
+
+ Signed-off-by: Vladimir Cernov <gg.kaspersky@gmail.com>
+
+commit 2d5e48d7697dd6b1ea3aaed48406d74e5d3ab097
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 17 23:13:14 2014 -0600
+
+ Epoll: Fix not catched peer close after events modifications (EPOLLRDHUP)
+
+ If a socket created on the event loop did some events modifications and
+ the peer closed the connection, the core did not trap this event. This
+ patch re-enable the EPOLLRDHUP flag.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 102b45e247b4b46d7499f34d8e160f2a22d33eee
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 15 15:51:55 2014 -0600
+
+ Configure: fix broken plugins path on previous contributor patch
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 42a3a8e95d02c14e5f2396e0932ec6b51e634b05
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 10 13:22:05 2014 -0600
+
+ Doc: update CONTRIBUTING with 'Commit Changes' info
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cffdbc9ed802025a4f2b7a0894388f5ccb517b36
+Merge: f0e78d7 5458096
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 10 13:00:20 2014 -0600
+
+ Merge pull request #109 from kaspersky/master
+
+ Libmonkey: fix build and add test for mimetype
+
+commit 545809698864309c9c49dc4874f7cdae4596082a
+Author: Vladimir Cernov <gg.kaspersky@gmail.com>
+Date: Mon Mar 10 20:08:50 2014 +0200
+
+ Libmonkey: fix build and add test for mimetype
+
+commit f0e78d7f1e8e482035ded9e3199f2d575791c2f3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 9 21:31:48 2014 -0600
+
+ Doc: Add CONTRIBUTING.md file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c17f98155104412e01e455874f63c81b04269944
+Merge: b11236b 2eb580c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 8 16:02:29 2014 -0600
+
+ Merge pull request #103 from matematik7/master
+
+ Linux Trace: fix compile issue
+
+commit 2eb580ce3ba890540461d9afc25e28204e5588f2
+Author: matematik7 <domen.ipavec@z-v.si>
+Date: Sat Mar 8 22:29:35 2014 +0100
+
+ Linux Trace: Fix compile issue
+
+commit b11236bedd56672b56fc3aa235428455e6041071
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 5 13:34:59 2014 -0600
+
+ Debian: bump to v1.5.o (development)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fab1e41130f6ca76add03df8ed3f51b1325fcd24
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 5 11:46:26 2014 -0600
+
+ Lib: upgrade test lib version
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a3a99b141d0508ef33593e10e4df52a3abdcf04d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 2 23:22:07 2014 -0600
+
+ Epoll: testing new MK_EPOLL_HANGUP mode
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a123d949d03906cfc9f27a5489dc3baa96b5338d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 6 11:31:41 2014 -0600
+
+ Plugins: use new mk_ptr_t data type
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b79465eeaf8ed06727b01fc8359edd9850a5b115
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 6 11:30:01 2014 -0600
+
+ Core: use new mk_ptr_t data type
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b353825456fb522bf335ac831570e543e9e2dcf6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 6 11:26:49 2014 -0600
+
+ Memory: rename datatype mk_pointer to mk_ptr_t
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d77504ab34a4e8633bf643497c75cab2ae7c5843
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 6 11:24:20 2014 -0600
+
+ Development of v1.5 begins :)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 726b3e8bcb7b14b2adc9ea6e3b2e67c7de25c032
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 4 08:04:22 2014 -0600
+
+ Update ChangeLog for v1.4.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f3638d9d6b7f781d0ad5dd87e04ee03c84271d90
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 4 08:04:22 2014 -0600
+
+ Monkey v1.4.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 90e358af00312cce155c0bd5039522fc9739a1e4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 4 08:04:16 2014 -0600
+
+ HTML: update home page
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f35e15c8b7e153fe71db51f29643a0016c427984
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 4 08:02:04 2014 -0600
+
+ Proxy Reverse: fix config file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 35b00ab23b081b363c840b4457b3eee3a34373e0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 3 22:51:57 2014 -0600
+
+ Debian: update rules for v1.4.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a8ac7e28cb2aaea6da2086632e383835777b80fb
+Merge: a31d354 dc4bc59
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 29 08:09:22 2014 -0600
+
+ Merge branch 'master' of github.com:monkey/monkey
+
+commit a31d354f0bc22f4801a7927953c393ae2eb93bf5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 29 08:03:12 2014 -0600
+
+ Lib: fix missing vhost header and API usage (#99)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit dc4bc593202d008ec6e7531005be167211fc8ff0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 29 01:18:51 2014 -0600
+
+ Jemalloc: upgrade commit to fix compiler warnings
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c28781f3874325a0d3d54f054461804ae81af46b
+Merge: 9b43aa6 9304105
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 28 10:49:47 2014 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit 9b43aa61e36a465409317f1759816695a00f019c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 28 10:49:22 2014 -0600
+
+ HTML: update index page for v1.4, codename Spider Monkey
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 930410506d352377017b3465a75af62e503ae382
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 27 20:45:31 2014 -0600
+
+ Macro: rename MAX_PATH to MK_MAX_PATH
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4c5ad82cd04cbc9bfdcdd97bbdc491ab1ca8a61c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 27 15:30:03 2014 -0600
+
+ Doc: Update kernel requirements
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7268167c2a022495d0395108480802adb33ece74
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 27 15:26:13 2014 -0600
+
+ Configure: update copyright
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2522c5fd50f387ea83b79e0a35f69b74d9daf63a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 27 12:50:04 2014 -0600
+
+ Conf: make FDT configurable
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a365d457d3fe6026b25aeb0524d8a34852994bd0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 27 11:10:12 2014 -0600
+
+ Jemalloc: back to original 3.5.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 80942638c24e837c33e43dffde28364d910ed2f2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 24 10:10:30 2014 -0600
+
+ Scheduler: optimize access to thread specific data with __thread
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit aeb004b31b5b710561acd5782372d805aeba84c0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 23 22:32:20 2014 -0600
+
+ Virtual Host: reduce hashed string on FDT.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4efbc11bafeb56fbe2b4f0f6925671630ce84125
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 23 21:53:37 2014 -0600
+
+ Virtual Host: File Descriptor Table (FDT).
+
+ The File Descriptor Table (FDT) aims to provide a mechanism to share
+ open file descriptors at Virtual Host level with the goal of to reduce the
+ number of open file descriptors and reduce the calls to open(2) and close(2).
+
+ The FDT is implemented in the following way:
+
+ - For each worker thread, maintain a list matching the global Virtual Host
+ list and for each entry create a Hash Table (HT) of 64 entries, and each
+ HT entry maintain a sub-array of 8 chains.
+
+ - When a request for a static file arrives, use the new Virtual Host open/close
+ wrappers, from the given parsed and processed URI generate a hash value and
+ try to see if it exists in the HT, if it don't exist, just open the file
+ directly and register the data into the chain for a possible future reuse.
+
+ If the hash exists in some HT/Chain, obtain the opened file descriptor and
+ increment the readers counter.
+
+ - When the Monkey core do not longer needs the file descriptor, instruct the
+ Virtual Host 'close' wrapper to perform the cleanup. If the resource/hash
+ exists in the HT/Chain, decrement the readers counter, if counter reach
+ zero, just perform an explicit close(2) as nobody is using it, if readers
+ is greater than zero just return as the file descriptor is in use.
+
+ If the resource do not exists in the HT, do a direct close(2).
+
+ The good thing of this implementation is that exists at worker level, so there
+ is no race conditions and is lock-free. Also collisions are reduced to zero
+ using HashTable Chaining. The hashing algorithm in use MurmurHash 2.
+
+ This implementation reduce the overhead under high concurrency sharing the file
+ descriptor resources and making it more scalable.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6d666da1a8c1d91a67348c935a657080731fdc18
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 23 00:22:52 2014 -0600
+
+ Core: fix compiler warnings
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3d70f08ee3c7c2a34207512a88d67c568f136635
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 23 00:11:34 2014 -0600
+
+ Deps: update Jemalloc commit
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 732226720b26b4b534dec8db466f44523760d51a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 23 00:05:11 2014 -0600
+
+ Memory: upgrade Jemalloc to 3.5.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 10ce73fb71e0b711b87234498af0f363c706374c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 22 14:09:36 2014 -0600
+
+ Core: move vhost structs to new mk_vhost.h
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit af0b80de1568bf2977f971827756c29296dcbf63
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 22 14:04:09 2014 -0600
+
+ Core: separate virtual host logic from config: new mk_vhost.c
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4564a587c5c00c9259567d043d74cde1226c6e95
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 22 11:18:31 2014 -0600
+
+ Core: deprecate perror(), use mk_libc_xxx() wrappers
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e47643e347714e14a08babc667db92df7505e052
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 22 11:13:13 2014 -0600
+
+ Error Handling: add caller name
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b2aacccc4fcb8ea465543c4a16ffd1ab22f49069
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 22 11:04:11 2014 -0600
+
+ Error Handling: new macros mk_libc_error() and mk_libc_warning()
+
+ This patch adds two new functions and proper macros to handle common
+ 'errno' errors and format them to stdout.
+
+ The new static inline functions are located in src/include/utils.h:
+
+ mk_utils_libc_error(char *file, int line);
+ mk_utils_libc_warning(char *file, int line);
+
+ the wrappers (based on macros) to be use are:
+
+ mk_libc_error();
+ mk_libc_warning();
+
+ when used the following information is formatted to stdout: errno number,
+ errno message, file and line.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2c52f3dc2adfdfe0c619b9122143563b6101f867
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jan 18 10:22:13 2014 -0600
+
+ Events: remove unnecessary handlers
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c9c4f0c681732c304db2779b4357a9432d40507f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 17 08:45:33 2014 -0600
+
+ Plugin API: export epoll_state calls
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0340926daccf555acf44f94a8ec1c5d62970ea7c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 16 12:01:11 2014 -0600
+
+ Trace: color tweaks and reduce va_args arguments
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 23c2d87a9ac82fa9ede3a8b49a62dbf72b796880
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 7 11:21:29 2014 -0600
+
+ Mimetypes: add debian package entry
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 102f65a9a6baafbd480d100e6007186d044523fd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 2 09:19:22 2014 -0600
+
+ Cheetah: use memory wrapper instead of direct malloc/free calls
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 91d0e5484f0bf852c8b2330ef726a0b62df87cca
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 2 09:17:52 2014 -0600
+
+ CGI: use memory wrapper on requests handler
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0fb9c91056ae5c9162f7a88fb46f46ebd8344959
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 2 09:16:43 2014 -0600
+
+ CGI: use API memory wrapper instead of direct free()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c22b71489455e3a6bfbcaf4b0d430de89354fcd6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 2 09:14:07 2014 -0600
+
+ Config: fail on zero keys just if a section exists
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 56574e396cc86a883129b0054fc65d5f9c128b3c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 2 09:11:29 2014 -0600
+
+ Config: add empty file on plugins dir
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b3cfab8134615ba2bce82cad99d398eceff04ed0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 2 09:10:20 2014 -0600
+
+ Core: minor config checks and CGI api fix
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2d2cd856584ec4dc73a58e9424f7168ea3f53f34
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Dec 31 16:13:14 2013 -0600
+
+ Mimetype: if cannot read config file, abort properly
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c8d2a558997294014f9a20ad5dca8f152a843aae
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Dec 29 15:20:44 2013 -0600
+
+ License: moves from GPLv2 to LGPLv2.1
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7719a5b7447f83eb53fd06a7f5881cd0d764eb81
+Merge: fee4cb0 624ce82
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 26 11:54:47 2013 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit fee4cb0282d9db9419837a3112f9cd4480a3389d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 26 11:54:08 2013 -0600
+
+ Logger: plugin moves from MANDATORY to OPTIONAL
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 624ce82fb08788c49be99926156886879d4a64fa
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 23 21:43:17 2013 -0600
+
+ Background: print server info to STDOUT before to close it
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 77adad4e3fbe7dd821f80a44186f25c2f9d9ccd9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Dec 22 21:04:47 2013 -0600
+
+ RPM: update SPEC file for incoming v1.4.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e21dfccb22f517592fa2fedc11b746c6211e540f
+Merge: ed0d928 fd8c3d9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Dec 18 22:27:30 2013 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit ed0d928ffc665f131ddd66d1fbbde7d47baac26d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Dec 18 22:22:13 2013 -0600
+
+ Scheduler: Workaround for ULONG_MAX bug.
+
+ This is a workaround for a specific Bug that we still not find the
+ root cause for it. The conditions are:
+
+ - for some reason closed_connections > active_connections
+ - when performing (active_connections - closed_connections it will
+ return UMAX_LONG, which is OK but *not* for our case
+
+ - if cur (current connections) is greater than worker capacity it will
+ fail all new incoming connections, and as it may have ULONG_MAX that
+ would case a very very bad behavior
+
+ The temporal workaround is to when facing that we are over capacity,
+ check if we have a ULONG_MAX value in 'cur', on that moment signal
+ our workers so they can start performing a synchronization of their
+ counters.
+
+ The patch adds a signal channel for each worker so every epoll loop
+ will monitor that channel, on receive the 0xDEADBEEF value, it will
+ perform a synchronization of counters based on scheduler busy queue.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fd8c3d9ad368658f02c31d8d468e10a5e850a533
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Dec 14 10:27:47 2013 -0600
+
+ Core: pack and optimize structures
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c3835e9aa40fc61f7a51e1f86a1fb9f051cc6967
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Dec 7 10:09:56 2013 -0600
+
+ Logger: fix HTTP macros name
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 350a0022cf2237d5aeded680f5462eb2fc020711
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Dec 7 10:09:21 2013 -0600
+
+ Dirlisting: fix HTTP macros name
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c4f122c1027e02b71584e09926daaa97b9092102
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Dec 7 10:08:13 2013 -0600
+
+ CGI: rename HTTP macros
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c76789b7f6d8419a5df1fbb743de797b12126a85
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Dec 7 10:06:40 2013 -0600
+
+ HTTP: prefix HTTP macros with MK_
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit abcc45eeb757b85a3ef4a354c7557db37e0ee660
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Dec 7 01:21:26 2013 -0600
+
+ Memory: improvements to avoid third party components crash when using direct malloc
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 893d8329d792c94f81c36761d374be3c7227c045
+Merge: 3fd2271 53ec2cc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Dec 7 00:09:26 2013 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit 3fd227144d1ec421826a7a80a7fc57ca4218ed85
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Dec 7 00:08:56 2013 -0600
+
+ Plugin: do not register event if worker scheduler context is NULL
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 53ec2cca2dee6f6ee4735c3ba781d2268e551e9f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 2 10:51:20 2013 -0600
+
+ Auth: use Monkey memory allocator API
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f94f3986e01ec23404ec67025ed981573b142735
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 30 22:04:02 2013 -0600
+
+ FastCGI: change memory allocators
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 70bce6abfed4793fa0c45192ce657c8cf9be74d9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 30 16:48:27 2013 -0600
+
+ Configure: to enable libc memory allocator use --malloc-libc
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3234b8237fd509268110c7bb6dac3487f53aab12
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Nov 29 10:48:56 2013 -0600
+
+ SSL: use Monkey memory handling calls
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 400891bfca3cf813431c7344e3083475f9b16249
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Nov 28 23:56:15 2013 -0600
+
+ Configuration: add support to change the main configuration file.
+
+ This patch adds a new option '-s' to specify an alternative configuration
+ file to the default monkey.conf. This is useful in case someone wanted
+ to run multiple instances of the server without copying the whole
+ configuration directory.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 54c58c37c5fda4afe379831decf1cec930bd6435
+Merge: d9ad8bd dddf9f0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Nov 28 11:37:19 2013 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit d9ad8bdbc36f3847005ea56d801c3b0c5cd3e680
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Nov 28 11:25:33 2013 -0600
+
+ Epoll: replace Epoll state TLS implementation with direct __thread
+
+ the epoll estate interface aims to hold information about every
+ socket that resides in an event loop, mostly to track events status.
+
+ The list per worker is implemented through Thread Local Storage (TLS),
+ this patch makes some performance improvements deprecating the usage
+ of pthread_setspecific() and pthread_getspecific() functions by using
+ the compiler aware TLS __thread feature.
+
+ With this patch each worker event loop optimize as follows:
+
+ +--------------------------+
+ | average costs |
+ +----------------------+------------+-------------+--------+
+ | function | pre-patch | post-patch | gain |
+ +----------------------+------------+-------------+--------+
+ | mk_epoll_state_set() | 4.15 | 3.45 | 0.70 |
+ +----------------------+------------+-------------+--------+
+ | mk_epoll_state_get() | 2.82 | 1.90 | 0.91 |
+ +----------------------+------------+-------------+--------+
+ | 1.60 |
+ +--------+
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit dddf9f0228f05cc5e088f16b668976897f8b2e06
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 26 10:02:36 2013 -0600
+
+ Linux Trace: rename provider header file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6b89900c2576ab787d5fb69dedcc6bd63a38fc93
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 26 09:57:09 2013 -0600
+
+ Linux Trace: register events for the Scheduler
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e6ddbeb1f94744ddac389d0036a28be38eb6f02e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 26 09:03:18 2013 -0600
+
+ Proxy Reverse: format C code according to Monkey programming style
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2001f52571115c62f39b200301ffdd6a915b0c98
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 26 08:51:48 2013 -0600
+
+ Proxy Reverse: tweak conf and documentation
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a22b0640da93a5698aab0e2c88d64545de481704
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 26 08:42:54 2013 -0600
+
+ Proxy Reverse: move OPTIONAL to EXPERIMENTAL
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 944a82db1d6943f63ed10de23b9464b84d5a83a2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 26 08:42:21 2013 -0600
+
+ Proxy Reverse: set plugin as experimental
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6649f2b7718ce893aa95dcf2bb161f643fb0d7eb
+Author: Nikola Nikov <nikola.h.nikov@gmail.com>
+Date: Tue Nov 26 08:41:33 2013 -0600
+
+ Proxy Reverse: initial merge of plugin
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d90cb4420976a0d2341ce72c2d011720d25c967f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 26 08:39:05 2013 -0600
+
+ API: expose mk_string_split_free in the API
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1a24bf587410b51ada45c578ef19441ead50543d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 25 22:43:35 2013 -0600
+
+ Jemalloc: do not run autoconf, configure script added
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 75e6b213a8574ec7c0818e71a8f362c17fc1a8f0
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Nov 25 20:42:18 2013 +0200
+
+ lib: Fix a bug introduced in 2a281ae932b30e0f40a925429437ca4304b6b954
+
+ The jemalloc commit changed a wrong line, this wouldn't even compile.
+
+commit 77a6683acfc7fa4601527dc4f2dc0bb836d5abce
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 25 10:46:17 2013 -0600
+
+ Linux Trace: fix conditional macro
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e2eddd1e7eff2a36d62cdb5ab673aa01720e4cb3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 25 01:37:29 2013 -0600
+
+ Jemalloc: add support for JEMALLOC_OPTS and fix libmath linker
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 41a1dd4cc370b2951ac80c9dda4c10f88720a00c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 25 00:25:31 2013 -0600
+
+ Doc: Remove TODO file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9028a390e09ebc46c7beb5559bf09c449426820b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 25 00:19:06 2013 -0600
+
+ Jemalloc: run autoconf before configure script
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 84105d4b48821bd414d7a9b887bb471a47e8641e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 25 00:18:28 2013 -0600
+
+ Jemalloc: add missing test header file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 462e2bc98ca984d54b19c7e16109d25712d61912
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 25 00:10:33 2013 -0600
+
+ Jemalloc: upgrade to v3.4.1-d6df91438a1cf25ea248c3897da463c51709c580
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e750ea0768181766332c8d1df66bcc47e610871b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Nov 24 23:41:46 2013 -0600
+
+ CGI: replace strdup() by API str_dup
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2a281ae932b30e0f40a925429437ca4304b6b954
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Nov 24 23:39:26 2013 -0600
+
+ Memory: new default (optional) jemalloc memory allocator
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e8d06ea1492b3fda90754db49f9a906cd4e0e7c9
+Merge: 98a9864 5bcef00
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 23 14:50:35 2013 -0600
+
+ Merge branch 'lttng'
+
+commit 5bcef00dab6e7001ec157320fd06b0eb2e413c52
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 23 14:49:35 2013 -0600
+
+ Linux Trace: banner to stdout
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9c4097f3e549fff8d0e1674fcb76a75c4081bb82
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 23 14:36:45 2013 -0600
+
+ Linux Trace: Initial traces for epoll and epoll_state interfaces
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6eb3555ce7e2e669cb9411a74e78e99c889a401a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 23 11:36:54 2013 -0600
+
+ Linux Trace: initial test
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 98a986419a0856f4464644d8c9f293e43962b581
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Nov 20 18:19:14 2013 +0200
+
+ Another go at fixing the ghost issue
+
+commit c5a859c667d3a29951a132cb42dee79882ad0d34
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Nov 20 17:18:30 2013 +0200
+
+ dirlisting: handle dirhtml_init failure
+
+commit eb6425b869a0f0058872d32f8ac1fd9d2625f78e
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Oct 21 23:13:13 2013 +0200
+
+ polarssl: Add support for polarssl-1.3.*.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b03bf69168414f911980a67aa6364f87b4eff519
+Merge: 1acfbbe 801e6b7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 29 22:14:06 2013 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit 1acfbbedd705433d144bc499e5122981fba2907b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 29 22:13:36 2013 -0600
+
+ Plugin: on finish request, validate existent session
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 801e6b7e39f0489d00ab7c81aa3eb94f26072200
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Oct 20 18:21:30 2013 +0300
+
+ conn: Handle ghost connections from interrupted benchmarks, etc
+
+commit a47352dcce9429c9d3b59348d988fca42a4b763f
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Oct 20 16:12:44 2013 +0300
+
+ utils: Constify the un-changing colors in mk_print
+
+commit f96547689bce3bf7c3cf3f498ed70559b7391aae
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Oct 20 16:09:42 2013 +0300
+
+ logger: Remove unused var
+
+commit dd096fdb71cf35f240d7d85ef782c0c2b898138e
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Oct 20 15:48:07 2013 +0300
+
+ logger: Print the reason for log file failure
+
+commit 95779ab605f3482edde2b9547b4e542317a72bf4
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Oct 20 15:43:05 2013 +0300
+
+ cgi: Must return close_conx on error without sent data
+
+commit 7de62a5d03ce1fcfcac37ab86ca52a61b902206b
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sat Oct 19 12:20:19 2013 +0300
+
+ logger: tm_mon is from 0 to 11
+
+commit 379f2f9f9bc71cfaa119606eef6b14bc3077845b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Oct 17 17:38:22 2013 -0600
+
+ Development of Monkey v1.4 begins
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a3a3b44eabba6ea9741d5db7521246daf6f3337b
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu Oct 17 17:58:19 2013 +0300
+
+ logger: Include the URL in unknown errors
+
+commit 65f01c0433bb3cc6e2b09c1237c374ba2949827e
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu Oct 17 15:29:32 2013 +0300
+
+ logger: Move err_str to the above block so it stays available
+
+commit f07989e94160d6f591e262f72099017da1f64520
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu Oct 17 14:19:49 2013 +0300
+
+ Logger: handle unexpected errors too.
+
+ Otherwise, the error log will have double lines, like these:
+ 1.2.3.4 - [14/Oct/2013 23:59:40 +0200] 2.3.4.5 - [14/Oct/2013 23:59:40 +0200] 5.4.3.2
+
+commit 8c79733cfe3b5a903ad339d7274dc9bd8682ed86
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu Oct 17 14:02:33 2013 +0300
+
+ signal: strsignal requires GNU_SOURCE
+
+commit 07fec9e26a9130a3a45da96df2c2e1888eb0ab62
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 15 10:25:17 2013 -0600
+
+ Monkey 1.3.0
+
+commit 33b9fdbea4ac6d8ef7e4eecd263d96af7b024227
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 15 10:24:50 2013 -0600
+
+ HTML: update index page
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8d29d5b9712de8fad67fb489c39dd41e84308354
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 15 08:58:45 2013 -0600
+
+ Debian: update changelog
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5d65b57499f8022be6f026a04d316c73f62cccb9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Oct 3 19:30:04 2013 -0600
+
+ API: Expose mimetype_lookup()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 846e4423a3df7cba25923d4086faf274ddb02518
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Oct 3 08:43:36 2013 -0600
+
+ Red-Black-Tree: remove unused augmented function
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3fdcce481927307245b0cfe440a2609faba3a724
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Oct 3 08:37:08 2013 -0600
+
+ Socket: on IP format error, use errno code number
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9f854866d923df6042f859c167538f4e4b3a4acf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Oct 3 08:33:31 2013 -0600
+
+ Mimetype: fix linking to global linked list head
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit edbcc31f4c894a1a2cc726457d77730cd1317b4a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Oct 3 08:20:16 2013 -0600
+
+ Move roadmap to v1.4
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6bb72aa98f7933b423b71a55cb37e576d1514cb9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 2 14:55:40 2013 -0600
+
+ Configure: add new htdocs/ files
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 117f2c5025830f2a98a9ccf0b51acc85a7b94b84
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 2 14:49:01 2013 -0600
+
+ Mimetype: use also linked list and adapt mk_lib
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 67f638c49910e1636121df93f867ad2ed58395ee
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 2 14:06:51 2013 -0600
+
+ Debian: update changelog
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 96b5d8ac4c00a481fadf53dedf34cb86eb353e70
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 2 00:28:33 2013 -0600
+
+ HTML: little style changes
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 89c92d3b62ab3579fe2cff7efbc0ac11ccef2d03
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 1 14:59:08 2013 -0600
+
+ HTML: image logo scaled
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 04eb1c876bac3a405b7fea20f8eb0ae61cd1c692
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 1 14:31:19 2013 -0600
+
+ Core: upgrade red-black-tree implementation to the latest on Linux Kernel
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9ae25f5d5576c6e5cb1f068057b4ad6fb302908c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Sep 30 23:20:23 2013 -0600
+
+ HTML: refactor index page with Bootstrap 3
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5410b8fd6c8feb2a799bfec0117fff6010538650
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Sep 30 09:32:27 2013 -0600
+
+ Mimetype: replace bsearch by red-black-tree (50% improvement)
+
+ The mime types lookup algorithm was using a qsort()ed array plus a
+ binary search with two main arrays: a top ten list (common) and another
+ one for the rest.
+
+ Even the solution was optimal for some cases, it have a huge dependency
+ of a righ configuration of the top ten list, and considering the support
+ of virtual host and different types of content we need a more generic
+ solution that scale and optimize for all cases.
+
+ This patch deprecate the top-ten list and replace the binary search by a
+ red-black-tree solution, looking at the results after a benchmark we can
+ see the following:
+
+ +-----------+-----------------+--------+
+ | bsearch | red-black-tree | gain |
+ +---------------------+-----------+-----------------+--------+
+ | mk_mimetype_find | 11.54 | 5.82 | ~50% |
+ +---------------------+-----------+-----------------+--------+
+
+ More graphical details here:
+
+ http://edsiper.linuxchile.cl/mimetype_performance_improvement_001.png
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit defb83d92ec9da697c532ec23c06323476975c78
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Sep 22 10:14:42 2013 -0600
+
+ Core: initialize clock before load plugins.
+
+ Some plugins could use the core clock API or buffer cache to perform
+ some timing operations (or format strings), before this patch the plugin
+ would crash as the clock was not initialized before spawn it.
+
+ This patch moves the sequential initialization before to load the plugins.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 58d0806619fdc16e96fd1accba8b9f06d0ec8656
+Author: Nil Croustillac <nilcroustillac@gmail.com>
+Date: Thu Aug 1 11:00:39 2013 +0200
+
+ HTTP: add support for OPTIONS method
+
+ Signed-off-by: Nil Croustillac <nilcroustillac@gmail.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 216b8c8682b6ef31b5ef47cf0ecb7a295a61922b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 31 20:57:14 2013 -0600
+
+ Core: on segfault... abort
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 12ac9fa3207c5f635e0f463c6d10a6ae7f53667e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Aug 26 23:08:44 2013 -0600
+
+ Event: verbose message on error when waking up connection
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7ff71743097c04e2af7c95bcb8ef85a65dce79c8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Aug 26 22:10:30 2013 -0600
+
+ Event: move event check to plugin logic
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f0085c4e177905c8f5338e4c819cab84481fd5e5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Aug 26 21:52:29 2013 -0600
+
+ Event: check that socket is alive before trigger hooks.
+
+ When the events take place in the worker epoll queue, the timeout
+ routine can remove and inactivate a client session, but sometimes
+ a write event reporeted by the same epoll_wait() loop can be queued
+ and can cause some inconsistences.
+
+ For safety this patch makes the read and write event connection hooks
+ to validate the epoll state before to proceed.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 98baeef078bfcd266c7c76f973bc4e0acbfe2a19
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 24 18:57:25 2013 -0600
+
+ Event: if wakeup fails, do not stop the server, just warn and return -1
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 303ef6d3470c006bd2a64f1387d454e9bd780bdf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 24 10:45:01 2013 -0600
+
+ Core: new argument '-b' to print build information to stdout
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 765a16452d67971acfe76810212ba35519f7ec7f
+Author: Valentin Ochs <a-monkey@0au.de>
+Date: Sun Jul 21 19:06:43 2013 +0200
+
+ configure: check_generic returns false on warnings, links against needed libraries, gets documentation.
+
+ configure: pthread test runs one function from pthread.h
+
+ Signed-off-by: Valentin Ochs <a-monkey@0au.de>
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 5cdd50d72ed45291d8e980fe34b84cbaaeb50297
+Author: Valentin Ochs <a-monkey@0au.de>
+Date: Sun Jul 21 19:06:42 2013 +0200
+
+ configure: Use tab for indentation consistently
+
+ Signed-off-by: Valentin Ochs <a-monkey@0au.de>
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 9aa8693670e1a81bb6ccbf442144fe3d488cc349
+Author: Valentin Ochs <a-monkey@0au.de>
+Date: Sun Jul 21 19:06:41 2013 +0200
+
+ configure: Use generic function to check for headers and functions
+
+ Signed-off-by: Valentin Ochs <a-monkey@0au.de>
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 2eefc13c6c3c8c330e7dd2ffc0484c07e1675a72
+Author: Valentin Ochs <a-monkey@0au.de>
+Date: Fri Jul 19 20:18:36 2013 -0600
+
+ configure: auto-check for backtrace support
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 88ca15385f0058f1e0dd77bc8064eca69c95ed79
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 19 19:16:19 2013 -0600
+
+ signal: do not use sys_siglist array anymore
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 49a46c4fd6fa2963adf93b0ea2785a1b517d33df
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 19 19:05:25 2013 -0600
+
+ core: add support for 'musl' C library, use --musl-mode
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4b3b67c492ab304179becf6ba748f309b9afcba9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 19 18:50:03 2013 -0600
+
+ FastCGI: use IOV_MAX instead of UIO_MAXIOV
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 45e34971c64fd4865cede108d62cacf1c6df3451
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Wed Jul 10 17:36:52 2013 +0200
+
+ mk_utils: Use timegm() instead of mktime().
+
+ Fix if_modified_since_test01.htt failure in GMT+ zones and
+ if_modified_since_test04.htt failure in GMT- zones.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 6d09cfb29399a04d6dd39ccf7de219e64b5a1e05
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Wed Jul 10 17:40:19 2013 +0200
+
+ Revert "mk_utils: Properly convert GMT to time_t."
+
+ This reverts commit 63b90609f1863eefb5ab17d6effb69e0efef3b99.
+
+commit 63b90609f1863eefb5ab17d6effb69e0efef3b99
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Wed Jul 10 14:11:56 2013 +0200
+
+ mk_utils: Properly convert GMT to time_t.
+
+ Fix if_modified_since_test01.htt failure in GMT+ zones and
+ if_modified_since_test04.htt failure in GMT- zones.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 43cc52f08f237dfda363903e21095b4a0e1a175c
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Wed Jul 10 14:09:47 2013 +0200
+
+ qa: Add if_modified_since_test04.htt.
+
+ This test together with test01 should guarantee will guarantee that time
+ conversion is properly performed both on negative and positive GMT
+ offsets.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit ca073bbd339d0fb4340674451989ac7fc0d9e616
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Jul 9 22:53:15 2013 +0200
+
+ fastcgi: Remove unnecessary chunk debug messages.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 198891679b946193fbd408839b273ed3ea4c1b36
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Jul 9 16:21:22 2013 +0200
+
+ mk_connection: Remove unused conn_switch declarations.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 40d7771c352f3902d8e68c1a5c75b7be0ebe9d67
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Jul 2 16:27:21 2013 +0200
+
+ mandril: Add deny_hotlink /path directive.
+
+ Deny any access to /path if referer is another domain.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 64c4e13c0f61bd007cd7d31d710231230719010d
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Jul 2 16:26:03 2013 +0200
+
+ mandril: Check URL in stage_30 instead of stage_20.
+
+ Assures that check is done on all pipelined requests.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 49f5ec670287ec3876b9990accf30d9fde725cf7
+Merge: 4a6cf53 e169b4c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 26 19:39:08 2013 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit 4a6cf53c01459f167de6dc027549cfbd9da3e003
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 26 19:38:19 2013 -0600
+
+ HTTP/Post: do not force content-type (RFC2616 - 7.2.1)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e169b4c08a241c3c3f678bf2d49b4aea18ee698d
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Jun 24 12:06:17 2013 +0200
+
+ auth: Fix bug 188, add extra space for '\0' termination.
+
+ The buffer was too small to fit a terminator when there were no padding
+ on the base64 encoded string.
+ This patch makes base64_decode() terminate the decoded string by
+ default.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 1e8944293f9125fce0e802cb1b48d2f3a085b7fd
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sun Jun 23 13:52:25 2013 +0200
+
+ auth: Fix missing PLUGIN_TRACE argument.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 74eff649f0a2b6bf833d39c0ed5e96a11a002814
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sun Jun 23 13:42:51 2013 +0200
+
+ fastcgi: Fix of request error log and signed compare warning.
+
+ Report request errors using PLUGIN_TRACE() instead of mk_info().
+ Fix signed compare in fcgi_config.c.
+ Use PLUGIN_TRACE() for "No chunks to free".
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit f13791a0472b5578b397ebdf11184f7d9ed29827
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sat Jun 22 16:02:32 2013 +0300
+
+ Fix a few fcntl mismatches
+
+commit ec97e15a0bdbc3a2a59dc42e854f3ae79933d440
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sat Jun 22 15:54:47 2013 +0300
+
+ Logger: set the log pipes to close-on-exec
+
+ Likewise no race here, as connections aren't accepted yet.
+
+commit a94b557dc182524a6c052f844dd1964eb3a3d601
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sat Jun 22 15:50:43 2013 +0300
+
+ liana: Set close-on-exec on new sockets
+
+commit b2f03a35313c0ea0826e9cd2a4f9b44c77b44a1a
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sat Jun 22 15:33:54 2013 +0300
+
+ epoll: Set close-on-exec on the epoll FDs.
+
+ Note that there is no race here, as connections are not accepted until everything is up.
+
+commit 06fc2bb462241ee1e45e0026ee01cb0fc46831c5
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sat Jun 22 15:27:06 2013 +0300
+
+ utils: Open the PID file with close-on-exec
+
+commit 945bdca2531a4125b23b44ee75f9dd0632cfea20
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sat Jun 22 15:22:46 2013 +0300
+
+ Logger: open the logs with the close-on-exec flag
+
+commit eaf79f62c48138fff08f0d1d8cc3bd75517bd76b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 19 19:35:13 2013 -0600
+
+ QA: add HTTP range tests 04 and 05
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 91628ec15925878f21a4bf0db7e4a7eaabb45ee1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 19 19:30:28 2013 -0600
+
+ HTTP: ranges fixes and implement 416 status code (fix #184)
+
+ The ranges parser did not validate properly the maximum offset
+ allowed, so if a requester set limit offset equal to file size it
+ continue processing, internally the sendfile(2) did not failed
+ returning always zero, this condition was not handled and for hence
+ that connections keeps running without ending, it could lead to a
+ DoS.
+
+ This patch improves the range headers validation, fix the validation
+ of mk_http_send_file() routine and when the range is not satisfied, it
+ will return the status code 416:
+
+ HTTP/1.1 416 Requested Range Not Satisfiable
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 493609cbe3d19325f2dbe9d64dfc3d9d27d82764
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 19 15:33:10 2013 -0600
+
+ mandril: fix rule names
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fcb7727b8130673f01adb3bf8c55967c3e100c5e
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Wed Jun 19 15:11:41 2013 +0200
+
+ auth: Ignore too large user entries.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 5d5c5fb6d2a8439f44f963924318cef3144e83ae
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Wed Jun 19 15:01:32 2013 +0200
+
+ auth: Fix buffer overflow when loading user file.
+
+ The third parameter of strncpy(3) was badly calculated.
+ For each entry in the users file the parameter was the length from start
+ of file until end of username, when it should be calculated from current
+ buffer position.
+ This causes writes outside buffer when the user file is larger than 2 *
+ sizeof(struct user).
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit fffc0f51ce49441a690ff841265017d4cac106a1
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Wed Jun 19 14:29:16 2013 +0200
+
+ auth: Fix bug where failed base64_decode() cause segfault.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 009b2cedb9e9c03a3fcfeef25079427b155ad9c2
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Wed Jun 19 13:25:16 2013 +0200
+
+ request: Remove unused session_request member virtual_user.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 9a68d97358be416376f53d8c6a401258b7c32f76
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 17 21:35:43 2013 -0600
+
+ Liana/PolarSSL: add listen address to error message
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1c5d24707a3194aa5681b42f7bbce69f011c40b8
+Merge: 37c90d6 4128b9a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 17 17:50:05 2013 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit 37c90d66a890ba97d906a777373220a75a9cb85d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 17 17:49:11 2013 -0600
+
+ monkey.conf: keys description ends with ':'
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c14ab3825e73d91becf085e0ca4ec51ff5ba82a7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 17 17:47:58 2013 -0600
+
+ PolarSSL: TransportLayer config must exists
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4128b9a19120ae74e7f7621ac29abf0ce1d222fe
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Jun 7 10:27:59 2013 +0200
+
+ auth: Reject usernames if length does not match.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit e3e7c57796e43512252b36af5cfcc651ef74ff36
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 6 11:38:54 2013 -0600
+
+ Fix #182: DoS bug on headers parser.
+
+ This patch fix the root cause for a problem described in Ticket #182,
+ actually if a header is malformed like a Header Key without a value, the
+ ToC parser used to continue processing the next header line.
+
+ The solution applied is to improve the ToC generator where it adds extra
+ validations for at least one colon and forcing each header line to contain
+ a value or empty space, otherwise the server will trigger a Bad Request
+ response to the client and close the connection.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f073796eb48f55637c96c2f37029b54d9a5892c4
+Merge: 6933315 ae6817d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 6 11:40:23 2013 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit ae6817d2b3a0eb473c5ef2b98ce55a8abf8d4e88
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu Jun 6 17:49:57 2013 +0300
+
+ utils: Fix a valgrind warning about uninitialized data
+
+commit fd2ffd31a29c6d63d3de7a09c84a9184f853317b
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu Jun 6 17:42:46 2013 +0300
+
+ Sched: Fix a segfault when iterating timeouts
+
+commit 9b835d04f1f02872d4e19063fcfca57e9c502526
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 3 19:47:54 2013 -0600
+
+ auth: add trace messages
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ca93a333398ebf05ee235d324484824026ae7ee4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 31 23:09:39 2013 -0600
+
+ Add a roadmap draft for v1.3
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6933315a67aae991d2a87a4eee736cec042e2225
+Merge: 8b182d3 84eada9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 27 08:33:26 2013 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit 84eada9f0991929c67798695c5561127aa0b6745
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun May 26 21:17:27 2013 -0600
+
+ Debian: update Monkey version to v1.3
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit eb014709ff2c5d6c5156f321e38ac850ce6bbdfa
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun May 26 21:05:27 2013 -0600
+
+ Development of Monkey v1.3 begins
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 894b9ae667b7a54e22392501f1572c84d89737bd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun May 26 20:59:57 2013 -0600
+
+ Update ChangeLog for v1.2.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0176bede95ebcb8930e45c5a4fac40f0cd8b17cd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun May 26 20:59:57 2013 -0600
+
+ Monkey v1.2.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d5369c55e1351cfeec7accf9a01823fffaaf70c6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun May 26 20:59:45 2013 -0600
+
+ configure: set new macro __MONKEY_GIT__ (devel/release)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9f32a0c56ab185651dc91a858ac5259f07ed9ad1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun May 26 18:24:08 2013 -0600
+
+ request: improve security over first HTTP request line.
+
+ The HTTP parser did not evaluate probable invalid return values
+ for the index() glibc function. This patch force to verify the
+ value before to move forward with the next parsing instructions.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2fb4023627071cfbacd0ac7d3774191bb4fe742f
+Author: Zeying Xie <swpdtz@gmail.com>
+Date: Sat May 25 13:53:04 2013 +0800
+
+ Config: Fix substring length for copy
+
+ Signed-off-by: Zeying Xie <swpdtz@gmail.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f9b2c35fa4cfaceb4f6dbb149a0d5da16c2240a8
+Author: Zeying Xie <swpdtz@gmail.com>
+Date: Sat May 25 13:50:23 2013 +0800
+
+ String: validate length of substring first.
+
+ This patch makes to validate the substring string length
+ to avoid extra memory allocation and release.
+
+ Signed-off-by: Zeying Xie <swpdtz@gmail.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8ea90d941448212398603e2a29c9dedd024e6686
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 24 20:13:21 2013 -0600
+
+ Scheduler: protect from zombie connections
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8b182d3d8cb29ae4eb2085db381898ec5643fcb1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 20 12:45:57 2013 -0600
+
+ Config: fix trace message for error pages
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 94e3366912cc2bd8fb278c3fa8a8963041b25c42
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 20 12:39:17 2013 -0600
+
+ Debian: add missing 404.html file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 40bd68e22fec0ef075fe9a13a2095ce1a132d121
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 20 15:02:07 2013 +0300
+
+ cgi: Should return NEXT here
+
+commit 2e1b665ec4ee71d743b3ba53038a510e2aae8417
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 20 14:55:45 2013 +0300
+
+ cgi: Don't call close on self
+
+commit c0d904b3c666788cd39229cf50e24b0d9758ada8
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 20 14:20:43 2013 +0300
+
+ cgi: Don't access freed memory
+
+commit c64107ab88ee8446d45485398d5d22b2d2234c39
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 20 14:03:30 2013 +0300
+
+ Set close-on-exec flag on new connections
+
+commit de122063f92cbc0bfde72ad41fffb978b66ba2d4
+Merge: dac562a 7fa5419
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 20 15:23:02 2013 +0300
+
+ Merge branch 'master' of monkey.io:/srv/git/monkey
+
+commit 7fa54197d6b3cd470170e5a9fd606e9d1a277236
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon May 20 14:05:47 2013 +0200
+
+ fastcgi: Remove use of strndup().
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit dac562ad1385e2cc5dda833a13e9be1fa07bcf88
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 20 13:53:22 2013 +0300
+
+ cgi: Make sure stderr is handled
+
+commit f7347aecdd0c35e99825f0826e08c636d04dfd12
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 20 13:46:31 2013 +0300
+
+ Fix some remaining places from the monkey.h > libmonkey.h rename
+
+ Configure, man pages, and examples were not updated in
+ fd9c07d6ccc2fe8d37093bb213d375fbbd77cd29
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+
+commit 5c77a262bf69380b80937ab15bad4a974ffa74d1
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon May 20 10:27:20 2013 +0200
+
+ fastcgi: Change event mode of fcgi_fd correctly.
+
+ Prevent fcgi_fd from causing error when write event occur when
+ receiving.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit cf95a901e99dd80fc174cdd8300b5d14be08953e
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sun Apr 7 20:07:41 2013 +0200
+
+ plugin: Invoke stage_40 in http_request_end().
+
+ Fix a bug where stage_40 is never invoked if plugin ends request outside
+ of stage_* callbacks.
+
+ Bug discovered by mchubby
+ (github.com/ksonny/fastcgi-monkey-plugin/issues/1).
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 20853846056a327c47cbf6693f3580b198593882
+Author: Zeying Xie <swpdtz@gmail.com>
+Date: Sun May 19 22:25:47 2013 +0800
+
+ Cheetah: Add a funtion to strip leading and trailing whitespace of input command line
+
+ Signed-off-by: Zeying Xie <swpdtz@gmail.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit df51b9ee3a4aab57abc01716cdcd82cb72c0d834
+Author: Zeying Xie <swpdtz@gmail.com>
+Date: Thu Apr 25 14:34:13 2013 +0800
+
+ Config: remove unnecessary semicolon(;)
+
+ Signed-off-by: Zeying Xie <swpdtz@gmail.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6dfecb2c6bc1577d5cd121ab711d338bef2c4fd3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 17 18:02:26 2013 -0600
+
+ Debian: dropped libmonkey-dev and fixes in monkey-dev
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fd9c07d6ccc2fe8d37093bb213d375fbbd77cd29
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed May 15 21:45:21 2013 -0600
+
+ Debian: new libmonkey-dev and library naming improvements
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ebec48b762776d951953eeaf8bf95f3dfac25514
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed May 15 16:48:51 2013 -0600
+
+ Debian: libmonkey now distributes libmonkey.so symbolic link
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a8ff795e6d068858ca237f7b0a629a49e6d184d3
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Dec 16 17:10:11 2012 +0200
+
+ cgi: Fix behavior with high-performance CGI
+
+ cgit is too fast for epoll, causing epoll to send a hangup event
+ even though there are still several kilobytes left to read.
+
+ With this change, cgit can correctly send huge files on monkey.
+
+commit 0ca081c82d6e3c8a4b498c338dcb7ae0d199160d
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 15 17:59:26 2013 +0300
+
+ cgi: Fix a crash due to uninitialized list
+
+commit be7bc69fd5c92f24a1cab5cd14125bf4361d05eb
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue May 14 12:15:34 2013 +0300
+
+ cgi: Make sure all mk_pointers are handled with length
+
+commit c91eb32fbb59a8376f49dcf088bb646e9b2e5724
+Author: Denis Mone <monedenis@gmail.com>
+Date: Wed Apr 10 16:08:32 2013 +0300
+
+ Follow on Bug #172: content_type fixes.
+
+ There is a problem with the sr data structure the
+ sr->content_type.data field contains the content_type
+ value as well as the content_length value.This in combination
+ with the SHORTLEN value(64) leads wrong characters being copied
+ to the content_type ENV variable.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c6f86d70cc02277aa73335a5d72a847478b3968a
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Dec 17 18:14:15 2012 +0200
+
+ cgi: More swrite error checks
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f2433e07d695bdb81b4724a7aaafd93e75965deb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 10 21:18:12 2013 -0600
+
+ Debian: new libmonkey package (still require some fixes)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 126a172f2428ae4a63003304aa143b1d2d62204d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 3 21:56:24 2013 -0600
+
+ Debian: monkey-dev now distribute Monkey headers
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8abf65df12ad9d4b810a68dfbdd346b46d7c0fad
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 30 20:27:42 2013 -0600
+
+ Debian: few Lintian cleanups
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ed229dc7333162328bc3d5ee61b3fed4a3e3ba3e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 30 20:15:58 2013 -0600
+
+ Debian: add monkey-mandril package
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 968879437194bb51d6fc15538dcd72dfbc1d5683
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 30 20:06:26 2013 -0600
+
+ Debian: add monkey-dirlisting plugin
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fb071fe12611de2a5440346e340d746e26a1bb93
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 30 20:01:45 2013 -0600
+
+ Debian: add monkey-auth package
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d8cc0fe51c715c23a6fcf3c0b9240d15a0c0887f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 29 21:29:07 2013 -0600
+
+ Debian: new monkey-cheetah plugin
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 40f3f462a30f20a063116cc14261b7f6987ff61c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 29 20:48:09 2013 -0600
+
+ Debian: new monkey-logger plugin
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 84221c7ed8205a862df9c730b222605119a77913
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 29 20:37:16 2013 -0600
+
+ Logger: exit properly if config file cannot be found
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b6b08ae2217e777c53bb28a62c60a7779b27d981
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 29 20:23:03 2013 -0600
+
+ Debian: cleanup most of Lintian errors and warnings
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 32afbfe931094ea450af8b55ebcee4e3a9a9eae7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 29 18:44:45 2013 -0600
+
+ Debian: new monkey-liana
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit aeb58c3dc18bf4c3a1d696e36b6768e7e1adff3d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 29 18:41:28 2013 -0600
+
+ Debian: new monkey-cgi and monkey-fastcgi packages
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit de3533d990eb7412715651570967059a374db950
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 29 18:37:04 2013 -0600
+
+ Debian: make monkey-polarssl depends on monkey
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fd1e3276bc04e2f611373eec9ee6c88b19fc0037
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 29 18:33:40 2013 -0600
+
+ FastCGI: plugin is now OPTIONAL
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7ab566607c0e01d199ba931916d51fa59c3912a7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 29 18:33:20 2013 -0600
+
+ Debian: new monkey-polarssl and enable fastcgi
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 253a247f74204ac7f0e5c771b4e37d60bfb7336f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 29 16:47:48 2013 -0600
+
+ Debian: update package version to v1.2.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0a4a9d98db477bf70154cb9dbeae60a2b1ba1200
+Author: Vincent Cheng <Vincentc1208@gmail.com>
+Date: Sat Apr 20 01:29:33 2013 -0700
+
+ Debian: install all plugins made available in the debian/tmp/ build tree
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ce89b5d81bf6ac305bece9021884c9b7f5a7910d
+Merge: b354b03 d857e52
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 19 07:40:23 2013 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit b354b03baea8b0bb0237609d43888c4dedd140ad
+Author: Vincent Cheng <Vincentc1208@gmail.com>
+Date: Wed Apr 17 01:18:35 2013 -0700
+
+ Debian: include polarssl plugin, remove reference to matrixssl in d/control
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 14ba00892735c44742519e5e6b15ff3b846dad58
+Author: Vincent Cheng <Vincentc1208@gmail.com>
+Date: Mon Apr 15 02:21:17 2013 -0700
+
+ Debian: add watch file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f173c8a78bdd4ef8f6d1f25eb03ea2d0d887eb99
+Author: Vincent Cheng <Vincentc1208@gmail.com>
+Date: Mon Apr 15 02:11:26 2013 -0700
+
+ Debian: update Format: field in d/copyright with DEP-5's successor
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c0b801dc98db2165f73278a9ebb5cf6ed6b9f2a6
+Author: Vincent Cheng <Vincentc1208@gmail.com>
+Date: Mon Apr 15 02:09:02 2013 -0700
+
+ Debian: set -e is generally preferred (IIRC it's mentioned somewhere in Policy)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 30c797ecae404006a3a4505995eaad69dc0c33c7
+Author: Vincent Cheng <Vincentc1208@gmail.com>
+Date: Mon Apr 15 02:08:30 2013 -0700
+
+ Debian: clean up rules file and take advantage of override targets provided by dh >= 7
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 525131518d4228fb62c5e9bb03ed80cc39419bb7
+Author: Vincent Cheng <Vincentc1208@gmail.com>
+Date: Mon Apr 15 02:06:52 2013 -0700
+
+ Debian: remove redundant README file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d857e52237c82173e47584b98efa46d87cea61cc
+Author: swpd <swpdtz@gmail.com>
+Date: Tue Apr 16 01:10:31 2013 +0800
+
+ Logger: fix type mismatch
+
+ Signed-off-by: swpd <swpdtz@gmail.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1a4d0880bd8ad4d86571c38966b94718b218e5e3
+Author: swpd <swpdtz@gmail.com>
+Date: Sat Apr 13 00:37:51 2013 +0800
+
+ Macro: remove semicolon(;) behind the MK_NET_HOSTMAX macro
+
+ Signed-off-by: swpd <swpdtz@gmail.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1053f3be5c28f536537ca008579ed65284a8e745
+Author: swpd <swpdtz@gmail.com>
+Date: Wed Apr 10 23:27:16 2013 +0800
+
+ HTTP: remove double inclusion in mk_http.h
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d1413bbfec6a2ede6de97bfb369c9369cbd98f89
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Apr 9 10:18:22 2013 +0300
+
+ dirlisting: Fix off-by-one
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ec0f09ba3b4c5264c64b91664a24f90833f3ff46
+Author: Bjorn Lindgren <nr@c64.org>
+Date: Mon Apr 8 09:31:30 2013 +0200
+
+ Lib: fix minor memory leak
+
+ Signed-off-by: Bjorn Lindgren <nr@c64.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e400659ccdcbd884f893f95e8a53e6a6bb887e67
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 6 14:35:09 2013 -0600
+
+ Dirlisting: file name entry is a static buffer now
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f9c7f9a36787fc0e3e817750b454a8d755a06856
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 5 14:17:33 2013 -0600
+
+ Core: fix minor data type mismatch
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6b94536861568359a23da5b23740ada4df621104
+Merge: c22fd25 3724f56
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 5 14:04:58 2013 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit c22fd25c0c33ebfb8a23d12b97c85244524428e5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 5 14:02:28 2013 -0600
+
+ HTTP/API: Fix #161: restrict and validate return of MK_PLUGIN_RET_END.
+
+ This patch fix issue #161 where a plugin on stage_30 returns
+ MK_PLUGIN_RET_END without do nothing.
+
+ From now a STAGE_30 plugin when sending MK_PLUGIN_RET_END requires
+ that response HTTP headers have been sent, otherwise it will fail
+ with a mk_bug() from the plugin caller.
+
+ If the intention is to close the connection, use MK_PLUGIN_RET_CLOSE_CONX
+ instead.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3724f56a1f5d4cd52970738f6766f4ea426c80b0
+Merge: 927b887 e26011f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 1 09:45:10 2013 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit 927b8870ebef817d25a8e0c6909c5cad4c386980
+Author: Denis Mone <monedenis@gmail.com>
+Date: Thu Mar 28 20:34:37 2013 +0200
+
+ Fixed bug #172. The problem was that the CONTENT_TYPE enviromental variable had to be set to application/x-www-form-urlencoded for the POST array to be accesed.Because the SHORTLEN value was not big enough the value copied on CONTENT_TYPE was application/x-www-form.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b2a18cd9a5aea7f04d52009768a5f5848bbb01e6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 27 04:20:44 2013 -0600
+
+ PolarSSL: align configuration file indentation level
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e26011f4449ff534b2c21bd2d9ca35ecb5de66a8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 25 22:30:21 2013 -0600
+
+ PolarSSL: Fix makefile to link polarssl library properly
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ee5c1dbe656d93c031a584e2c38663a501e3ba6c
+Merge: 1aa1a71 844b042
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 16 12:10:54 2013 -0600
+
+ Merge fix for #174
+
+commit 844b0429ce3e64535a10b5cd7f144ff39bae4b7b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 16 12:07:05 2013 -0600
+
+ CGI: Fix #174 / unhandled global rules
+
+ This patch Trac #174 problem, where the global rules for CGI
+ were not handled by the plugin. Now the plugin is able to run CGI
+ based scripts using rules from plugins/conf/cgi/cgi.conf.
+
+ Tested with simple Perl and PHP scripts.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1aa1a711da6bc36a901514474ad9e24e803132c5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Mar 15 15:45:42 2013 -0600
+
+ Configure: Fix #117: remove strip instructions
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 90363a114804d38330091977e15478b134e83543
+Merge: 0dd4dfb 3a14258
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Mar 15 07:27:28 2013 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit 3a14258510e016b15b2c28c1ce434a9c91a3d8e7
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Mar 12 22:32:27 2013 +0100
+
+ mconf: List polarssl as https transport layer.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit c9ce51ea18da423d1fee026ef16fa78226da3b5d
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Mar 8 18:48:03 2013 +0100
+
+ polarssl: Add support for TCP_FASTOPEN.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 76211481835ca0e5e2a01bd9b49f53a32cef694b
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Mar 8 17:41:40 2013 +0100
+
+ polarssl: Fix assert failure on exit.
+
+ Return NULL if local contexts is requested outside worker threads.
+ Allows close calls from main process on exit.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 7d137885ee9611f3e2a5a0ce8b4741320835845b
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Mar 8 17:14:46 2013 +0100
+
+ polarssl: Use DHM parameters from RFC5114 if available.
+
+ Uses built-in parameters and removes warnings if polarssl version >
+ 1.2.0.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 4573786c2f704385ae02f833c5c4a7a4faecb34e
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Mar 8 17:07:39 2013 +0100
+
+ polarssl: Use dummy error_strerror() if not available.
+
+ Includes a dummy version of error_strerror() if POLARSSL_ERROR_C is
+ undefined and version <1.2.5.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 364f63a107be7d298ea8ead1fc12c29b87c4c2a1
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Mar 8 16:57:12 2013 +0100
+
+ polarssl: Use global entropy context.
+
+ Move entropy from thread context to global context.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit d7147c3ee56e6d83760c1b0f6167f2bf21916ebf
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Feb 5 15:08:48 2013 +0100
+
+ polarssl: Reset session in context_unset.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit df144491b6cae55b4a906d57dea62cf0b39a7dbb
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Feb 5 15:08:26 2013 +0100
+
+ polarssl: Rename polar_context_unset to context_unset.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 594120113bfaf432acbed4bef02b828a0e4c73b7
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Mar 8 21:22:53 2013 +0100
+
+ polarssl: Don't return -1 from sendfile on EAGAIN.
+
+ If no data is sent, but EAGAIN is set, return 0 instead of the usual -1.
+ This is a workaround as EAGAIN isn't checked when sendfile is used in
+ core.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+
+commit 0dd4dfb6baeceb62e317bd4813773657f8e3b8e0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 11 20:20:37 2013 -0600
+
+ Mimetype: remove lower case lookup
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2bb5178ed74300a9b4e95b2cc1f960dde5b01dc9
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Mar 11 20:31:45 2013 +0200
+
+ lib: Move the workers check to the right place, fixes crash
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 73a011168e8c2c13e45dad0a4a705e6fa89d345b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 11 12:56:39 2013 -0600
+
+ Configure: add #LIBDIR# parser
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 82ab60f4f3ad1d23230c680a330ba62507eca48f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 7 08:23:23 2013 -0600
+
+ Lib: if config->workers is zero, set value based on number of CPU cores
+
+ If the config->workers is zero, the number of worker threads is
+ determinated based on the number of CPU cores.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0198689376cad221b15129808196f2c2d21d08b4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 18 07:11:03 2013 -0600
+
+ Lib: add missing errno.h header and fix a mimetype point type
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 62a9f2a08bb788f664402ffaf4cf2d4cff8f929a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 18 07:04:42 2013 -0600
+
+ CGI: implement global CGI match rules
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5a6696bf90a9b563c1a7c22752ac171102b13462
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 16 16:54:11 2013 -0600
+
+ TCP: Add support for Linux TCP_FASTOPEN (aka TFO)
+
+ Recent Linux Kernels implements a new TCP feature
+ called TCP_FASTOPEN. This feature reduces the TCP
+ handshake roundtrip improving performance for new
+ connections. For more details refer to the following
+ articles:
+
+ - http://lwn.net/Articles/508865/
+ - http://kernelnewbies.org/Linux_3.7#head-cd32b65674184083465d349ad6d772c828fbbd8b
+
+ Requirements:
+
+ - the client side must be running Kernel >= 3.6.
+ - the server side must be running Kernel >= 3.7.
+ - Besides the Kernel version, the client and the server
+ must request to use TCP_FASTOPEN/MSG_FASTOPEN in their
+ respective calls.
+ - the tcp_fastopen flag must be enabled:
+
+ # echo 1 > /proc/sys/net/ipv4/tcp_fastopen
+
+ The good thing of this feature is that no matters if
+ the client implements TFO or not, the server will work
+ anyways.
+
+ This patch enable TCP_FASTOPEN by default in Liana plugin
+ and also export a new function mk_socket_set_tcp_fastopen()
+ for generic purposes.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fbc2a6b2c8828e6bbc1ae5a5c099905abc1c4263
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 16 13:50:47 2013 -0600
+
+ Liana_SSL: deprecate plugin based on MatrixSSL
+
+ According to:
+
+ http://lists.monkey-project.com/pipermail/monkey/2013-February/001785.html
+
+ Liana provides the networking layer to Monkey and its _SSL version the
+ networking layer with SSL encryption capabilities. The first version of
+ this plugin was built on top of MatrixSSL library but this last one is not
+ well maintained and there is no community involved on that product, what
+ that means ? that nobody cares about it and integrate in a Linux
+ distribution is a pain so we cannot be stuck on that anymore. Jonathan
+ (zeus) from our community was doing a good job packaging the latest version
+ in our repository, but MatrixSSL continue be a problem.
+
+ After review some open sourced SSL options, I found that PolarSSL is the
+ best one that fit our needs. Because of:
+
+ - open source
+ - well maintained in Linux distributions
+ - lightweight so it fill well in embedded Linux environments
+ - years of work supported by a community
+
+ Besides that, there is a concern about how that library can impact Duda I/O
+ (web services framework that runs on top of Monkey). Because the web
+ services created by people can be closed... what happen if the service
+ links to PolarSSL through Duda LGPL code ? answer: nothing. As PolarSSL
+ works under Monkey and Monkey under Duda, there is no problem in linking
+ or licensing issues, this have been confirmed by PolarSSL team after talk
+ to their lawyer, so we are pretty good.
+
+ Sonny Karlsson have provided yesterday a new plugin named PolarSSL (good
+ job!), so everything is ok for the next step.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 056b7fc2ebd889fa9e4d41db427301d31b57d34c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 16 13:45:20 2013 -0600
+
+ Palm: deprecate plugin. Its not you, its me.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e5f9bc8a4576c2e6870c5143cf2aaf958ae00bac
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 15 21:18:16 2013 -0600
+
+ Plugin: export red-black tree interfaces
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d6b00238a1c68a1428c4da370978f7a7ed5e5bdf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 15 16:48:44 2013 -0600
+
+ Scheduler: use red-black tree algorithm to handle connection nodes
+
+ This patch replace the linear query over the busy queue to lookup
+ connection nodes by a red-black tree algorithm. This represents
+ a huge improvement in performance under a high load.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0665af623c3f6b74e268566bce81b9fcc16500d5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 14 23:33:46 2013 -0600
+
+ Epoll: remove instance field from epoll state nodes and code cleanups
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f64be99085b28f425ca81f7429396b967a244108
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 14 12:02:50 2013 -0600
+
+ Configure: link to mk_rbtree.o object
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d4460fd3c810e017292a27b42b9f9e95c4b6cd0b
+Merge: ca69bc6 fed3d42
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 14 12:02:06 2013 -0600
+
+ Merge commit 'fed3d4224cdbf2fed51c272dde6138df14916aad' into red-black-tree
+
+commit fed3d4224cdbf2fed51c272dde6138df14916aad
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 14 11:53:46 2013 -0600
+
+ Epoll: define behavior mask as unsigned int
+
+ previous this patch the behavior mask for each file descriptor
+ state was defined as signed int, but EPOLLET value can take the
+ highest value available and this can lead to some problems when
+ mapping inside a signed value.
+
+ This patch makes the behavior mask be defined as unsigned int.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 73f14a893bc1c1844f0afce1b53029cfc4f1b43c
+Author: Curtis Hall <curt@bluecherry.net>
+Date: Mon Feb 11 14:18:54 2013 -0600
+
+ Added CONFIGURATION title to INSTALL
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ca69bc66ecba9827efbee88fd9fc1fe9e8cf140c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 10 16:31:22 2013 -0600
+
+ Core: add mk_rbtree.c and mk_rbtree.h
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e6bb1fb52f00ce7180a992a462da99a7abf0a906
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 10 16:30:55 2013 -0600
+
+ Core: initial implementation of red-black tree
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 831645824fc48ab97e59da06f63e94090a07c758
+Author: Neil Haran <neil.haran@inrom.co.uk>
+Date: Wed Feb 6 14:20:06 2013 -0600
+
+ Plugin: fix offset of data content when sending out data
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b402b91f20f55570625e0fe0651bf481bd95ddd4
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Wed Feb 6 19:34:52 2013 +0100
+
+ fastcgi: Update plugin to v0.2.
+
+ commit 03aec5b6d3a364625aa31c3bfef8605d0bdd44f9
+ Author: Sonny Karlsson <ksonny@lotrax.org>
+ Date: Wed Feb 6 19:23:06 2013 +0100
+
+ fastcgi: Set version.
+
+ commit 064822ac4a913cf067db34c374492243e9079981
+ Author: Sonny Karlsson <ksonny@lotrax.org>
+ Date: Wed Feb 6 19:21:24 2013 +0100
+
+ fastcgi: Set HTTPS in cgi environment.
+
+ commit 58585d06c37a5a1f1ca008b5bbba0bb1b64f877a
+ Author: Sonny Karlsson <ksonny@lotrax.org>
+ Date: Wed Feb 6 19:13:28 2013 +0100
+
+ fastcgi: Compatibility with SSL transport.
+
+ Use mk_api->socket* on client socket and unistd functions on fastcgi
+ socket.
+
+ commit e8549387c228c45bc128844deaa27d97fc64cc3d
+ Author: Sonny Karlsson <ksonny@lotrax.org>
+ Date: Mon Jan 28 13:20:12 2013 +0100
+
+ fastcgi: Fix conditional close of fastcgi connection.
+
+ commit f5ebf5edc5062446313b99f6886cad8620df5b06
+ Author: Sonny Karlsson <ksonny@lotrax.org>
+ Date: Sun Jan 27 16:54:43 2013 +0100
+
+ fastcgi: Update minimal libfcgi config example.
+
+ commit ce56895c132c8b9769e9fd365b6662a2d8b47596
+ Author: Sonny Karlsson <ksonny@lotrax.org>
+ Date: Sun Jan 27 17:10:16 2013 +0100
+
+ fastcgi: Indicate which variables are required in config.
+
+ commit 46875aafb63897d75fc2398db381679d28d27ffb
+ Author: Sonny Karlsson <ksonny@lotrax.org>
+ Date: Sun Jan 27 17:08:57 2013 +0100
+
+ fastcgi: Auto-generate LocationName if none given.
+
+ commit 427a513223fc7fe5b70cc8657b147f6e86c5f48b
+ Author: Sonny Karlsson <ksonny@lotrax.org>
+ Date: Fri Jan 11 11:57:03 2013 +0100
+
+ fastcgi: Let default for MaxConnections be 1.
+
+ commit 6738f4baff43f4f8455b4606dc1f811e729d2802
+ Author: Sonny Karlsson <ksonny@lotrax.org>
+ Date: Fri Jan 11 11:52:57 2013 +0100
+
+ fastcgi: Fixup of trace and debug messages.
+
+ Fix format warning in printf.
+
+ Check return from event_add.
+
+ Check return of fcgi_fd state change.
+
+ Remove some redundant trace messages.
+
+ commit 3f5015ad04c60f286fa1bc998bb13bb334b9e841
+ Author: Sonny Karlsson <ksonny@lotrax.org>
+ Date: Mon Jan 7 12:23:25 2013 +0100
+
+ fastcgi: Add inet_ntop include in fcgi_env.
+
+ commit f3caaa99dee45405a3e4c993fd987287d6505971
+ Author: Sonny Karlsson <ksonny@lotrax.org>
+ Date: Fri Jan 11 11:41:46 2013 +0100
+
+ fastcgi: Don't set CONTENT_LENGTH unless needed.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cd07b9cd073e915f632929f6f4b5a9d0ff967a16
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Jan 18 08:50:13 2013 +0100
+
+ polarssl: Add HTTPS plugin.
+
+ Adds HTTPS support using PolarSSL v1.*.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2942ec90beb9353cb45eff1ed26c0b67d74b3ac5
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sun Feb 3 12:48:02 2013 +0100
+
+ configure: Fix replacement of variables in Makefiles.
+
+ Handle CFLAGS/LDFLAGS/DEFS containing '/' characters.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f6f18f4665c12a00e98923770bf9a4f9c6034ec1
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Feb 1 10:06:11 2013 +0100
+
+ iov: Reset total_len in mk_iov_free_marked.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4edf9a89ffbdc75e25fe424cf1f301ebb7986ae7
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Thu Jan 31 20:34:34 2013 +0100
+
+ socket: Use close from transport plugin.
+
+ sched: Replace close call with mk_socket_close.
+
+ server: Replace close call with mk_socket_close.
+
+ lib: Replace close with mk_socket_close.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit eb250bf432bf9654e56380ef3c56dbf327b23e7f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 3 20:55:05 2013 -0600
+
+ Plugin: fix return value for http_request_end() on mk_conn_close() call
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a08cf6b4bc9eb1be6b4767dc917cf68fc09279eb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 2 23:24:50 2013 -0600
+
+ Epoll: epoll states array size now its equal to worker capacity
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3ee55869f6ab1c27f28a191716ec170606324180
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 1 07:19:23 2013 -0600
+
+ Configure: use --strip-program argument for install command
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c8b8e3ae1ae0c84ae513e06e1f7ec9dd3f386e18
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 31 21:45:21 2013 -0600
+
+ README: update
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 573c43eeabff347a566a6d57bf7648ce9b941e5e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 31 21:31:08 2013 -0600
+
+ HTTP: fix protocol version
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit abf99c6a96c5111d269657681d25f3fc41686a3f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 31 21:27:49 2013 -0600
+
+ Core: new -w flag to specify number of workers from command line
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 601f9be93184ba3f74e3293122e95706b192a8ad
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 31 13:10:00 2013 -0600
+
+ Utils: check that gmt cache is being used properly
+
+ If the gmtcache is invoked from a process context, this will end
+ in a segfault. This patch adds an mk_unlikely() validation to the
+ value returned by pthread_getspecific(). So if it was called from
+ an unexpected process context it will end up in a mk_bug().
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c35886f58c7f2a0d8af42e4b467bd3f0c3267dd7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 29 15:31:21 2013 -0600
+
+ Mimetype: do all extension cmp in lower case mode
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2754611600726f7baaa130d2c57578becfc22e1b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 28 23:08:21 2013 -0600
+
+ Memory: do not reset pointer when is setting data. not required
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6bf0f0c95f435e66aef06043b086dc570eeeb1aa
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 28 18:53:10 2013 -0600
+
+ List: comment code for entry_first() and entry_last() (Fixed)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4f2f9445249eb0572df33b007c55e02a5a3a485a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 28 18:51:41 2013 -0600
+
+ Revert "List: comment code for entry_first() and entry_last()"
+
+ This reverts commit 5e9971d539b80d87f00c3a41f45cd6fb1b3fea22.
+
+commit 5e9971d539b80d87f00c3a41f45cd6fb1b3fea22
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 28 18:38:25 2013 -0600
+
+ List: comment code for entry_first() and entry_last()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 83003497f1794c955a5d522e824deff541044400
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 28 08:05:38 2013 -0600
+
+ utils: stacktrace add padding zeros to pointer addr
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9b8380de08fdf0f5d4c11972d2ec8049b017b4bf
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Jan 18 09:24:54 2013 +0100
+
+ utils: Stacktrace fixup.
+
+ Fix loop condition in stacktrace.
+
+ Use %p for printing pointers in stacktrace.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ff6ca37841b5747ba80dc7ddf3e6bf255082211e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jan 26 09:44:25 2013 -0600
+
+ Help: update banner
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b733d39c87b5ca5dbcce170167d5edb18177bf8c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jan 26 09:42:46 2013 -0600
+
+ Core: new -p flag to specity TCP port
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fcd1c6f9d4183cac4b61cf3f281b964c05211725
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Dec 16 16:41:01 2012 +0200
+
+ cgi: Document the request getters
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7ff63bb2feb3ce519125e23a7049e05bfa7e2ed2
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Dec 16 14:08:28 2012 +0200
+
+ dirlisting: Don't allocate unneeded memory, save 104 bytes per entry
+
+ We need pointers, not full structs in toc.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5d74678e3de2f14dd995e1c2b81c5d3d5b8dd3bd
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jan 20 19:20:13 2013 +0200
+
+ configure: Fix a typo (CLFLAGS) and make sure the -O logic always sets the visibility
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5c688e274c8445c135b5db903a589136d59130c6
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Jan 22 21:49:13 2013 +0100
+
+ request: Remove handled_by member from session_request.
+
+ Unused relic from old commit.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a6bdc1225fd34fac0da4f3af1e39e5b1ee07a1f3
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Jan 21 17:33:51 2013 +0100
+
+ config: If Workers is 0, launch one thread per processor.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1a1d04483290fcf1fc4463366d91e54b96978f1d
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Dec 16 15:11:58 2012 +0200
+
+ dirlisting/guineo: Compact the theme
+
+ This saves about 270kb (29%) in a dir of about 3k entries, while looking the same.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9d9faba9e78eab1f7fc71b9e75353c450b4899d2
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Dec 16 14:55:27 2012 +0200
+
+ dirlisting: Fix failure in big directories
+
+ Dirlisting is not designed to support event-based working, it is one-shot.
+
+ So in a big directory, writev would return EAGAIN (EWOULDBLOCK) after
+ having written a partial entry.
+
+ This would then confuse the client in chunked mode (you promise X bytes but
+ only send less), which closes the connection, leaving you with a partial listing.
+
+ With this patch, dirlisting succeeds in a dir with 23k entries.
+ Without, it fails in a dir with little over 1k entries.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cbb879b5c54182744807d2eaed014c7e359e1a2b
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Dec 16 14:20:59 2012 +0200
+
+ dirlisting: Use case-insensitive sort
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 712d22cf72893e03cea6de9efbc9148c58d8ff9d
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Dec 16 14:19:10 2012 +0200
+
+ dirlisting: Remove unnecessary variable
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9e938fee821167daf6ef03bd8ee8d74644b09431
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Dec 16 14:16:07 2012 +0200
+
+ dirlisting: Mem-optimize mk_f_list, 112 -> 88 bytes
+
+ The theoretical maximum of the strftime string is somewhere around 18 bytes.
+ Make it 24 to have some extra, and to be a nicely cacheable multiple.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3a06c0e85f9bb4e1594a35de4db2645ae214d223
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Dec 16 13:33:21 2012 +0200
+
+ request: If mk_file_get_info returns -1, size is not set. Found by valgrind
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 622dcd384f998c666d6fc0dc5779436d1127b9f1
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jan 20 10:44:35 2013 -0600
+
+ configure: Conditionally set -O2
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f80af9e2a62bb666c5d21b04eae17dddd2e7f7c3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 15 21:10:05 2013 -0600
+
+ lib: do not left stage30 until all content is sent
+
+ If for some reason the send() call returns -1 because the socket
+ is not yet ready to receive more data (due to non-blocking mode),
+ the routine should not stop working and should try to send the
+ information over and over until is fully served.
+
+ This is not an expected behavior in a non-blocking server, but is
+ a temporal fix until the 'pending buffers' interface is implemented.
+
+ This problem was found due to #170.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 473ba999caf7d87cd815d0f4abe1efc89a994b0d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 15 21:00:40 2013 -0600
+
+ Headers: Fix #170: sr->headers._extra_rows keeps invalid reference
+
+ Found a specific condition in Monkey core where after send
+ the headers, if the field sr->headers._extra_rows is set and
+ then freed, its not marked as NULL. If sub sequent calls
+ from the Plugin API takes place and this field is validated,
+ it fails in a segmentation fault.
+
+ This patch set the structure field to NULL after is freed.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 97ba007c7ad14db2863a367c579eac44a9e32aca
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 11 16:40:09 2013 -0600
+
+ Plugin: do not print out error messages if a symbol is not found
+
+ The plugins interface try to load every known symbol from a loaded
+ plugin, not all plugins implements all of them so when dlerror()
+ returns NULL, it should not print errors to stdout.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f01ab1d29d7f31a5799194395afb191ac00b091f
+Merge: bbcd308 b89c7db
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 11 15:38:15 2013 -0600
+
+ Liana: fix merge
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b89c7dbb493da00d27327860f1ddedeb51baea33
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 11 15:34:31 2013 -0600
+
+ Liana: fix merge problem from coverity branch
+
+commit 7fc2395bd7e596978e4163c6be39d893017a718c
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:41:49 2012 +0200
+
+ palm: getpeername may fail, found by coverity
+
+commit 0054fc538aa0145b335f22277460b854db9903e7
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:39:07 2012 +0200
+
+ dirlisting: Remove dead code, found by coverity
+
+commit 804b2dbc067c01e61aec70883aef2aed116f2a5e
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:29:58 2012 +0200
+
+ liana, cheetah: Fix fd leaks on error path, found by coverity
+
+commit d2f6e0b1ebf81773f93d31f88db9cb949cb379e5
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:24:27 2012 +0200
+
+ plugin, iov, auth, request: Remove mem leaks, found by coverity
+
+commit 5096a2332433b6c4141306711496e22575b9ac33
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:16:46 2012 +0200
+
+ liana: Fix non-looping loops, found by coverity
+
+commit 51161ddea1669f9412627ef319eaefb166078bb8
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:13:21 2012 +0200
+
+ plugin: Make use of the err variable, found by coverity
+
+commit 81761182e46d916608d985a7bb7b542de6cee57c
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:11:41 2012 +0200
+
+ sched: Remove double close, found by coverity
+
+commit 42e966e729f2e369df199c4c3d20c325f262b516
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sat Dec 15 21:51:03 2012 +0200
+
+ cgi: Support some non-compliant CGI programs (cgit uses LFLF after headers)
+
+commit bbcd3082b9bc36678296fd7377fca5d38838c93e
+Merge: 652fbf3 9fcc2e8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 11 15:29:44 2013 -0600
+
+ Merge branch 'coverity' of https://github.com/clbr/monkey
+
+commit 652fbf3c0232258263922b036f389948490bb65a
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:41:49 2012 +0200
+
+ palm: getpeername may fail, found by coverity
+
+commit 1b41f2eaa67b9f228062c82be6288b8150ce5d38
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:39:07 2012 +0200
+
+ dirlisting: Remove dead code, found by coverity
+
+commit 2512bb30c1ea8d55780aad39db8cc6661cdaae27
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:29:58 2012 +0200
+
+ liana, cheetah: Fix fd leaks on error path, found by coverity
+
+commit 5f8efc9d465fd455c825693dae547ce077b80a51
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:24:27 2012 +0200
+
+ plugin, iov, auth, request: Remove mem leaks, found by coverity
+
+commit bbe12cbbe3dc98fd3ad45e8b4c79c5e42eaa26da
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:16:46 2012 +0200
+
+ liana: Fix non-looping loops, found by coverity
+
+commit 71db62aaecbae223d159def4608597ac5278c378
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:13:21 2012 +0200
+
+ plugin: Make use of the err variable, found by coverity
+
+commit 3b419e749e51311e3efd48d8c6942df46a58d973
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:11:41 2012 +0200
+
+ sched: Remove double close, found by coverity
+
+commit 62029e2df99c9bc349412b081bedf1a2f0b94e3a
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sat Dec 15 21:51:03 2012 +0200
+
+ cgi: Support some non-compliant CGI programs (cgit uses LFLF after headers)
+
+commit ae4eb56a56bebac82806bfcd2255878d5ddb84cd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 11 14:16:06 2013 -0600
+
+ Configure: new uClib mode through --uclib-mode
+
+ This patch introduce the new parameter to enable uclib compatibility,
+ once is set it disable some specific GLIBC features.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3ff524cfbb5cc1eb5e2c3e83ea686d05cbad0cb7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 11 13:51:17 2013 -0600
+
+ Configure: new option --no-backtrace
+
+ This patch introduce a new 'configure' script option --no-backtrace.
+ The backtrace(3) function is part of GNU extensions, mostly available
+ in glibc, on other C libraries like uClib is not implemented, for hence
+ we need a mechanism to disable the backtrace feature on demand.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4d01c9c4b564ef12c396f1b48f0a36690a205e45
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 11 13:33:10 2013 -0600
+
+ Signals: implement sys_siglist if symbol is not found
+
+ When compiling with old toolchains for some ARM devices and
+ mostly related to old versions of uClib, the symbol sys_siglist
+ is not found and make the compilation process to fail.
+
+ This patch introduce a header with the sys_siglist array defined
+ in the following file:
+
+ src/contrib/uclib/sys_siglist.h
+
+ If the symbol is not found, it includes the header.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 94b3e10b22e6956abc01322ac2bf12fea7db2d11
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 11 13:15:42 2013 -0600
+
+ Utils: improve stacktrace
+
+ This patch adds a few useful features to the mk_utils_stacktrace()
+ function.
+
+ - It adds the function name resolution and binary file associated
+ - The stacktrace is print on any compilation mode
+ - Function resolution names are only available on --debug mode
+ - If Monkey compiles with --debug mode, the compiler parameter
+ -fvisibility=hidden is turned off.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1da85f5567caa0d2f8e8d46249283bb1659e7912
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sat Jan 5 15:33:22 2013 +0100
+
+ fastcgi: Use pthread_key_t for thread local vars.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ac57d90a13025e510e12476d8e72c56b675bd6d6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Dec 23 07:28:56 2012 -0600
+
+ CGI: Allow to define interpreter and mimetypes for each match
+
+ This patch expand the CGI plugin so now is possible to define
+ multiple Match rules plus define an optional interpreter and
+ mime type to assist scripting such as PHP, Python, Lua, etc.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9fcc2e8a32e26dbc7c2c89aa28d23cfffae6cbbe
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:41:49 2012 +0200
+
+ palm: getpeername may fail, found by coverity
+
+commit e0a39a6d058de6f8572713146d04df8a3c4685e1
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:39:07 2012 +0200
+
+ dirlisting: Remove dead code, found by coverity
+
+commit e4a73c3c12de66a7940f717742a69d72abf1b0b9
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:29:58 2012 +0200
+
+ liana, cheetah: Fix fd leaks on error path, found by coverity
+
+commit 72cb7769c9ce12a9b307daf16b95819bab13701f
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:24:27 2012 +0200
+
+ plugin, iov, auth, request: Remove mem leaks, found by coverity
+
+commit e61aedbad8722294eb669eff2a7a26050d7187ca
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:16:46 2012 +0200
+
+ liana: Fix non-looping loops, found by coverity
+
+commit 1d5e904579ccc41bcfaa4e39a2cc66b422cea155
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:13:21 2012 +0200
+
+ plugin: Make use of the err variable, found by coverity
+
+commit b9dba8467dd9c26fbadde4234116251c2da15c83
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Dec 18 14:11:41 2012 +0200
+
+ sched: Remove double close, found by coverity
+
+commit 79a86b16fe593d6d7e597e54c74861ee9661a9f2
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sat Dec 15 21:51:03 2012 +0200
+
+ cgi: Support some non-compliant CGI programs (cgit uses LFLF after headers)
+
+commit a44d623f7ef22769b1441ab95701851afd7682d6
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Fri Nov 30 20:11:44 2012 +0100
+
+ lib: Add get_request_header.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c11795dd2946ca8162925bafb20d52d145fb144f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Nov 30 12:42:06 2012 -0600
+
+ Palm: fix unused variables with void type
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b7eb06ec76060a63157431f8db4c007c8ac99493
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Nov 30 12:38:09 2012 -0600
+
+ Mandril: fix unused variables with void type
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 28b0aaa3ac8bc2c0b8876599d3726e9d81b0818a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Nov 30 12:37:08 2012 -0600
+
+ Logger: fix unused variables with void type
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 40f57bb7cd2ae0b1a2bf2ba2306dbf86612a6c51
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Nov 30 12:35:53 2012 -0600
+
+ Dirlisting: fix unused variables with void type
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8a46a856a1128f3efb584318c9c18fce178f8489
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Nov 30 12:34:44 2012 -0600
+
+ Auth: fix unused variables with void type
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9100a131a80251c8a2fa91d1386335af6c47c15c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 6 20:27:48 2012 -0600
+
+ Liana: set confdir variable as unused
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d46f2223e0e6ffbd0acac380877aea80eedd6943
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 30 07:49:17 2012 -0600
+
+ Plugins: Fix license headers from GPL to LGPL
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9e7b283a26b3e5505b647eff4259a9d29cc606f8
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Thu Aug 30 19:44:35 2012 +0200
+
+ liana_ssl: Handle multiple SSL records and false start.
+
+ In io_read, handle as many records as possible. Use non-blocking sockets
+ for IO. Most of the handshake is done in events, may cause troubles.
+ Tested with Safari, Chrome and Firefox.
+
+ Known problems:
+ * First request by Chrome browsers fail, one byte is missing every
+ time, may be a bug in matrixssl.
+ * Generates occasional socket errors in event_read, may fail
+ requests.
+ * SSL closure notifications are sometimes ignored.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5f6087e3d69f076bb3d4a98d628e18b672f1ce13
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Sep 15 09:50:01 2012 -0600
+
+ Request: new stage30_blocked flag
+
+ This patch introduces a new flag in the session_request struct
+ named 'stage30_blocked'. In mk_http_init() when the file is not found,
+ it triggers the plugin STAGE_30 to look for a plugin handler. In some
+ cases the plugin would overwrite the real path of the requested file
+ and make Monkey handle the new path for the static file. At this point
+ we need to block the extra STAGE_30 calls from mk_http_init().
+
+ For short.. if a plugin overwrites the real_path, let Monkey handle that
+ and do not trigger more STAGE_30's.
+
+ int stage30_blocked;
+
+ The default value is MK_FALSE.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d7dd615bf51b0e3c3943fcb76fadfae9dc2c9fe2
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Sep 10 15:12:25 2012 +0200
+
+ util: Remove mk_request.h include from header.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit db5f3a06f14a311c934b9153e1bd091be2b051dd
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Sep 3 13:28:03 2012 +0200
+
+ socket: Remove mk_socket_timeout prototype.
+
+ The associated definition does not exist.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 657423bcfe7f04afc93ced37a178d28fbf602b46
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Sep 6 07:51:08 2012 -0600
+
+ Logger: Fix #163 - fake consuming when the log file is not accessible
+
+ If the log file cannot be open for writting, we should perform a
+ 'fake consuming' of the pipe data, otherwise we will get consecutive
+ epoll notifications as the data is still there.
+
+ This patchs forces to consume the data if the log file cannot be
+ updated.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2cc2dc269858f2e2534f6b7cfb023ac6a493e7e9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Sep 4 13:05:58 2012 -0600
+
+ API: new sched_worker_info() call
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 35cafeb4f2adcf2191c8645b511be4ede756160c
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Aug 24 13:38:02 2012 +0300
+
+ cgi: Mention PHP in the README
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c4ad986ab9fc529dae90ed1dc2788bfb215b5921
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Aug 24 13:34:15 2012 +0300
+
+ cgi: Don't check for vhosts if none are configured
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 75af537c2c7cf3c6343bc65b9fa0197690737c35
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu Aug 23 16:46:14 2012 +0300
+
+ examples: Add a Makefile
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 43f59ced23f8d53980eca3682b2ba5848eb452ee
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu Aug 23 16:38:23 2012 +0300
+
+ examples: Remove unused variables, fix two warnings
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0ae38aeb6ebb3c607d09e8667e6c648a022aeb09
+Merge: 6bb6b94 d509c17
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 18 21:16:38 2012 -0600
+
+ Merge commit 'd509c17687f99f93b1fba67e48055a73995efd81'
+
+commit 6bb6b94bd2df4fcc7d5cb659e19cd19e8e57b326
+Merge: a496e6e f3eefe1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 18 21:16:10 2012 -0600
+
+ debian: merge
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a496e6e5beb58eb4ff588ee22a5808d22f05286d
+Merge: be05a00 16c324d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 18 21:15:18 2012 -0600
+
+ Merge commit '16c324ddec7a33ac92de0a6a4a497b73a30b4d6b'
+
+commit be05a00b6e7b46ce3dbd61abebbb99e33c8898ed
+Merge: f3088d8 8bbb309
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 18 21:15:07 2012 -0600
+
+ Merge commit '8bbb30982845e7f1e5cb5c999a5256d752056ac8'
+
+commit f3088d8b3f342a4b51532afcf9e2e3c288282bdb
+Merge: e0102ba 3ddbf16
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 18 21:14:44 2012 -0600
+
+ Configure: merge
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d509c17687f99f93b1fba67e48055a73995efd81
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 18 16:43:22 2012 -0600
+
+ Configure: fix installer on plugins Makefile
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b4d950df3c1518d4b979c86136657addd6e0c7a3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 18 09:20:23 2012 -0600
+
+ Configure: remove merge comment
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f3eefe14ab129397e09928f5ac2ef89360999379
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 18 09:18:20 2012 -0600
+
+ debian: update rules for v1.1.1
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 16c324ddec7a33ac92de0a6a4a497b73a30b4d6b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 18 08:39:46 2012 -0600
+
+ Dirlisting: add OPTIONAL file to the repository
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8bbb30982845e7f1e5cb5c999a5256d752056ac8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 18 08:36:16 2012 -0600
+
+ Logger: add MANDATORY file to the repository
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3ddbf16925619679b7c019bbf43b762c79a5ea3c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 18 09:16:08 2012 -0600
+
+ Configure: fix broken builder
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e0102badb6201794ae240ad2378fba8fd33d0026
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 13 20:30:39 2012 +0200
+
+ configure: Use gnu99 as default C dialect.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 323e1fa8766366b8ece812bafddd7ae9df6358de
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 13 20:07:56 2012 +0200
+
+ epoll: Remove inline from mk_epoll_state_set declaration.
+
+ Allows calls to function from outside translation unit under C99
+ inlining rules.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c0be18929778c456b38b59854e10e967d1568042
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 13 20:02:04 2012 +0200
+
+ scheduler: Remove inline from mk_scheduler_add_client declaration.
+
+ Fixes incompatibilities with C99 inlining rules.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0ff3e5a20fbe909dc4a0c51f5e8b34c09043c83a
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Aug 13 19:57:17 2012 +0200
+
+ mk_memory: Make mem_ functions static inline.
+
+ Use static inline for mem_malloc, mem_malloc_z, mem_realloc and
+ mem_free. This will assure that calls to these functions from monkey
+ core is inlined. Fixes incompatibilities with C99 inlining rules.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9cb8335a8f6c50b345800e9842cb64b686cf8d67
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Aug 14 14:45:36 2012 +0200
+
+ mimetype: Remove inline from mk_mimetype_lookup declaration.
+
+ Allows calls to function from outside translation unit under C99
+ inlining rules.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 416a323905df9b347b20eaea6ef0b15e70c1785e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 17 15:42:32 2012 -0600
+
+ IOV: iov_add_entry: mk_bug() is back
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5097c86433d4125e3827710bf84200b0525abfbe
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Aug 13 12:50:57 2012 +0300
+
+ iov, utils: Fix build with trace
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8da883be5bc80e7510920700a5b02ffedd50849b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 17 15:37:04 2012 -0600
+
+ IOV: on add_entry, validate with mk_unlikely() directly instead of mk_bug
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5dacea2f8c0f796a7d268beda97541c7c729eec5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 17 15:05:04 2012 -0600
+
+ Configure: remove merge comments
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 828cdfe961c903d9a23f00601314852659f95cc1
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sun Aug 12 15:50:50 2012 +0200
+
+ configure: Fix accept4() check.
+
+ Builds check.c with -Wimplitic to detect when accept4 is absent. Also
+ adds _GNU_SOURCE define so accept4 is actually declared.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7b677516d904780b0dca483a7817076d3e543b62
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 17 15:01:55 2012 -0600
+
+ Debian: fix cgi stuff 1.1.0-2
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a8210cd4ecf6bc24900d1af3078fda1b2b7803d8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 17 11:09:34 2012 -0600
+
+ Monkey v1.2.0 dev
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7a4a3bbf2314df09f21c6be891474f0c7d9c4fad
+Merge: fd01402 b827b96
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 17 11:01:53 2012 -0600
+
+ Merge tag 'v1.1.0'
+
+ Conflicts:
+ configure
+
+commit b827b96ff9dcf739004a0e87f72b985132b7061a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 17 10:58:57 2012 -0600
+
+ Monkey v1.1.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c04cd225ca81977d80566e05087f86ea2f876dec
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 17 10:16:03 2012 -0600
+
+ Configure: remove trace message
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit af7cea3dc41d0bb278aaa6c2eaedbd64e8d209c3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 17 10:12:37 2012 -0600
+
+ Configure: fix plugins configuration files path
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f45169a8ab9874df74bc6701d6b97cdb240b07f7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 17 09:59:59 2012 -0600
+
+ Debian: update changelog to v1.1.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d72e0cf49253d30daa70811ae768b189fb089f98
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 17 09:51:26 2012 -0600
+
+ Configure: improve plugin detection
+
+ The configure script now have a new function called skip_plugin()
+ which determinate if a plugin must be compiled/included or not
+ in the build stage, as well the same is used for the Makefile
+ generation.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit bdbe14c4c9dea086d094f67e3143cda02717d7cc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 12 09:52:28 2012 -0600
+
+ Plugins: Fix usage of INC_EXTRA in Make.comm
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9dd7a634294735da3536e4e8fac50372c26222bd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 12 09:16:15 2012 -0600
+
+ Auth: enable -fPIC flag in Makefile to fix relocation error
+
+ If -fPIC is not used, the following error is raised by the compiler:
+
+ "relocation R_X86_64_32 against `a local symbol' can not be
+ used when making a shared object"
+
+ Adding that flag to Makefile.in fixes the issue
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ed49c1dc112da8ba2c2839f2d1ad27a7796582fa
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 12 09:11:48 2012 -0600
+
+ Liana_SSL: Use proper prototype for _mkp_init()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 14dd9e004f784e1618e0cb46f939785b4828bd6f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 12 09:10:52 2012 -0600
+
+ Liana_SSL: define INC_EXTRA for MatrixSSL headers
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 789f1a3015cc71a32c8043a5f095728462536ec2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 12 09:09:22 2012 -0600
+
+ Plugins: update Make.commons to allow add extra headers through INC_EXTRA var
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fd0140287fad32d1ea53d9797a9f08bb815cb2f4
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sun Aug 12 13:16:35 2012 +0200
+
+ fastcgi: Add experimental FastCGI proxy plugin.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 028a523859da450476042a2ee2beacd6620077da
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Aug 8 22:27:59 2012 +0300
+
+ build: Make sure the lib-objs also get header deps
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1aa037b55758a661b60477662939483ad3f5f681
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Aug 8 16:54:42 2012 +0300
+
+ clock, epoll: Fix gcc warning "no return statement in function returning non-void"
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4917a2491b0a1aa313830f9ffb41f630ddb4e37b
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Aug 8 16:54:42 2012 +0300
+
+ clock, epoll: Fix gcc warning "no return statement in function returning non-void"
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 95f374c1346832c28ac9739d2290c0ba960fb7d0
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Aug 8 17:20:30 2012 +0300
+
+ mem: Inline pointer_reset, called ~3 times per request
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3901ff6e77ae442b2d0d47dc7941b896501f57cb
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Aug 8 17:18:23 2012 +0300
+
+ sched: Inline get_request_list, called 4-5 times per request
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3e08ef527a96c11a9ef70eb7a80e3ccc7b55a728
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Aug 8 17:13:52 2012 +0300
+
+ cache: Inline cache_get, called ~4 times per request
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 61920a7da546024ec72017fab6531a03b6c747b8
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Aug 8 17:11:58 2012 +0300
+
+ sched: Inline sched_get_thread_conf, it's called 4-5 times per request
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6fb56fd85c8005b79b7faaf897f1791fd0b99047
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Aug 8 17:03:44 2012 +0300
+
+ iov: Make iov_add_entry inline
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2f8313fb5d99446937f3f74b1fdf99cd938da9c7
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Aug 8 17:20:30 2012 +0300
+
+ mem: Inline pointer_reset, called ~3 times per request
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5179c23cd0ace9914306ff31a260cbe86add9baa
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Aug 8 17:18:23 2012 +0300
+
+ sched: Inline get_request_list, called 4-5 times per request
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a6ee405e9c0421782d610fc6b8d9a13173b498de
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Aug 8 17:13:52 2012 +0300
+
+ cache: Inline cache_get, called ~4 times per request
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e2416acd1321bb74814c50f5f09eeaf2d13ae73a
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Aug 8 17:11:58 2012 +0300
+
+ sched: Inline sched_get_thread_conf, it's called 4-5 times per request
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d6472cdb785e9ad9a8b22cb6b26ddc20ace0d24d
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Aug 8 17:03:44 2012 +0300
+
+ iov: Make iov_add_entry inline
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ba959a090bec37547a6f7a3feb0dd2e0848fec85
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Aug 7 16:35:09 2012 +0300
+
+ lib: Bring the bulk of lib over
+
+ Some mime functions get exported, config init & reading is separated, and some functions are
+ moved around so that they can be ifdef'd out, to create a smaller library.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 633598061bd5a65d5758254d7091efe1a4b7f6e2
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Aug 7 12:05:47 2012 +0300
+
+ cheetah: Remove some duplicated code by using worker_spawn
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ea1e5a5d246f1870a3d43814d48fb03e4f288298
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Jun 12 16:54:41 2012 +0300
+
+ utils: Fix a small oops from the signed warning removal
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d2363c8fefe33249ae24536cb3233870f871e191
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jun 13 18:32:03 2012 +0300
+
+ auth: Remove one signed-unsigned warning, we know sep is positive at that point
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4191cf5de6fe0c8304aca24163e0124d21078f79
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 15:25:01 2012 +0300
+
+ http: Remove one signed-unsigned warning
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7b169703ecf36fc527874da0e547191518d0c404
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jun 17 17:18:46 2012 +0300
+
+ sched: Mark mk_sched_register_thread as static
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a5d91c050db3533ad0cb18d207198c3523e152ad
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Aug 5 12:52:28 2012 +0300
+
+ cgi: Make sure chdir succeeds
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 188d96017789f82b9fe8aaa73579719c085b7367
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Aug 3 18:29:28 2012 +0300
+
+ epoll: Make mk_epoll_state_k properly extern
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a5e86fea65e7538f981839d8997082cdcffa667f
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Aug 3 18:27:28 2012 +0300
+
+ plugin: Remove unneeded typedef
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 21931ff0a4aeb611f4c342c0a33a8c64ddeb0b6f
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 15:04:38 2012 +0300
+
+ request: body_size and body_length can't be negative
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7b2cb07f040e365b30ed978ea39c18a4123b943f
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 15:10:37 2012 +0300
+
+ utils: Remove one signed-unsigned warning
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e5575ef707e14830d31c675688605a9d4649b215
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 15:14:08 2012 +0300
+
+ user: Remove one signed-unsigned warning
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c701ded506effbe4f5a9aaa3b6eeb20de0800641
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Aug 3 16:24:30 2012 +0300
+
+ mime: Mimetype names are const
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 95c3e62558787f8b6f8318c5c999dc8db4cc79c7
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 15:12:38 2012 +0300
+
+ utils: Remove two signed-unsigned warnings
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+
+commit f5367ae1c6aacb5cdc0b95c12b5510c5b089cf10
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Aug 6 11:16:35 2012 -0600
+
+ Core: usage of GCC built-ins: prefetch/[un]likely
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 65264d6ced93bbc9de34b2a189a8ae66ed89c252
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Jun 11 22:10:49 2012 +0300
+
+ plugin: Remove two unused functions
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7829f0c442ec0e80ba68c9415243091900676174
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jun 6 18:12:21 2012 +0300
+
+ plugin: The path passed in is const
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a745d25152896a80889112236ed175e121e82091
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Jul 31 13:32:08 2012 +0300
+
+ plugin: Mark plg_stagemap as static
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ec923083f1a13eaaf38a27933e2370d94e7c9a12
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Jun 12 18:45:03 2012 +0300
+
+ MKPlugin.h: no need to export mk_api
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 44b887d06ed3f24896043a6712e62bb53e79dff7
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 15:08:52 2012 +0300
+
+ config: host_alias, worker_capacity and max_load are never negative
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1cfe4c3dba41420430d8e5f88846bb7ec9a889d2
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Jul 31 21:04:18 2012 +0200
+
+ liano: Plug leak of struct addrinfo.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3996a5495b5916705791ab56275f2c81129d0e44
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Wed Aug 1 11:54:26 2012 +0200
+
+ plugin_api: Add http_request_error.
+
+ Allow serving errors outside of _stage_* callbacks.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 515ef47f67e9052d452e464eb99044149df295ef
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jun 6 18:50:01 2012 +0300
+
+ utils: Make sure the date_yd date_wd arrays are read-only
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b0819286dd8a44588dd97f445879b2fed5d17ba9
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Jul 30 11:44:03 2012 +0200
+
+ connection: Don't enable TCP_NODELAY in mk_conn_read.
+
+ The option is overridden by TCP_CORK.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f08a347f6a906f46f084e2c095ebd7c1e061dac8
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Mon Jul 30 11:40:23 2012 +0200
+
+ http: Unset cork flag when mk_http_send_file is done.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0a7056e452c1d9c408631099cc22b83d6188bf69
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 15:24:25 2012 +0300
+
+ connection: Remove one signed-unsigned warning
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0fc969d4e1bbb4af16a964c6476ad8f3101b3889
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jun 17 17:11:14 2012 +0300
+
+ clock: Mark mk_clock_header_set_time as static
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a7d6ceb1e6520e2cc5b7ef1b154ce768293f3a93
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jun 17 17:15:51 2012 +0300
+
+ signals: Mark signal_handler and signal_exit as static
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 70e97e83e8e5031d966624ac9325299468cb8fd9
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Jun 11 22:06:20 2012 +0300
+
+ header: Remove unused function chunked_line
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3b6f307108adbdd44a4f1e658f48c0315bf1e510
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 14:55:44 2012 +0300
+
+ user: Constify some read-only variables
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0774534137dd45df0b69e6dba33d9ba0ce14000b
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Jul 30 19:35:50 2012 +0300
+
+ string: Fix some signed-unsigned warnings, plus one wrongly declared variable (static > const)
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a4a0f44441955dd7e82ad1470e5cc48e7de7a1ab
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 15:21:04 2012 +0300
+
+ server: Use more appropriate types for mk_server_worker_capacity
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0dbac768aaf4f9e639e6b9211bc7e3fd53b1454f
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jun 6 18:08:13 2012 +0300
+
+ config: Use int8_t, not int, for tri-state options (true, false, error)
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 41265d96e9cffc255c463d1151f84eb6a09113f7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 29 08:03:15 2012 -0600
+
+ Header: merge lines in status entries
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a204f12bc27f990ad2cd04d37a0de7193f43bdf5
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jul 27 17:35:22 2012 +0300
+
+ dirlisting, palm, logger: Use const mk_pointers where possible
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4f59c55225a5522dc3ceeed6c4539cf7558f6cdc
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Jun 19 13:26:34 2012 +0300
+
+ memory, header, request, monkey, http, iov: Add mk_pointer_init macro, mark global mk_pinters const
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit bafb88732a4fa57dcf2e35853e9716721117d510
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jun 17 16:51:34 2012 +0300
+
+ header: Remove unused code
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c1f0af7bd1d57df4c1bb4739921f6f2bc12897cc
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sat Jul 28 17:38:28 2012 +0200
+
+ plugin: Remove sr and cs members from plugin_event struct.
+
+ Remove unused members and change the event_add api function.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f586a31c85c53185b3fb41dabd7b2bb438f46397
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jun 13 18:33:22 2012 +0300
+
+ cheetah: sysconf returns a long, not size_t; removes one signed-unsigned warning
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 35c4be79bb001831c94690eb7ceda03c6d70ddda
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jun 13 18:21:27 2012 +0300
+
+ macros: Add a macro to skip warnings about possibly unused parameters
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit adbb2f08dead908e86de600cef7e4bbfbdfd9b6a
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jun 17 17:14:48 2012 +0300
+
+ http: Mark range_set, range_parse as static
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit bbfe79eeb5f6a7a390340e99fb94c9a6711d0902
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jun 17 17:18:27 2012 +0300
+
+ config: Mark mk_config_entry_add as static
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7704bc1f41d9e7238b2d7bec2cf7371279203266
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jun 17 17:12:35 2012 +0300
+
+ http: Mark mk_http_directory_redirect_check as static
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c1d7d922f04d10ef9fbef32abe75ade7e9bfd0af
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Jun 19 13:10:36 2012 +0300
+
+ cache: Remove unused function prototype, struct
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a5c80bc8f782ce6d79f054844bcf9e6efb1aadb8
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu Jul 26 18:26:32 2012 +0300
+
+ monkey: Update README and add a pkg-config file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8ad6ebae873705beb928ec32c017d82c1dfa6656
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu Jul 26 23:53:49 2012 +0300
+
+ plugins: Consolidate common build system parts, remove 63 lines of copy-paste
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 75e49628bfbfeb8116f6c6378329a97150f96142
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jun 17 16:57:43 2012 +0300
+
+ request: Remove unused code
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 12a4a6d7696ac5aa978d718cf83ecd20ee2f195a
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jun 6 18:44:51 2012 +0300
+
+ header: Simplify the status_response array init, reorder the struct
+
+ This saves 4 bytes per struct on x64. The size of the library drops 300 bytes due to
+ the big static array taking less space now.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c9effedfd11484678775631b878ae2ae849cc136
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jun 17 17:09:46 2012 +0300
+
+ iov: Mark _mk_iov_set_free as static (unused externally, and the _ prefix suggests it's meant to be private)
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3c84846b0501953c322be926bf42200f96f9961a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 26 10:28:32 2012 -0600
+
+ Palm: initialize missing mk_pointer
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ff5eb559922cbbc26cd07a653506fec131dbb27f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 26 10:26:04 2012 -0600
+
+ Dirlisting: initialize missing mk_pointers
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2184262ec740510ce54cf042254ba248f17b8442
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 26 10:20:01 2012 -0600
+
+ Logger: fix warnings and missing mk_pointer
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4469aff433d9964238bb61165804fb2c173db052
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Jun 18 19:23:08 2012 +0300
+
+ monkey: Properly use extern for the globals
+
+ This drops the size of each plugin by about 2kb (they were getting the global variables
+ too!), and makes it easier to find unused global variables.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d39662dc100664065dafe78d1522b7dcb2908219
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Jun 18 19:31:53 2012 +0300
+
+ mem: Remove unused struct
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0b3319649f59d7334834192b1c08d9fc23458cb9
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Jun 18 19:21:45 2012 +0300
+
+ cache: Remove unused define
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5acf61cd0343c71a059a0f22e97222f085c2cab3
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jun 17 17:20:31 2012 +0300
+
+ plugin: Mark register_stagemap* as static
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a5fd3ec44995f5148b2e5ddad109f3af94e4882d
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Jun 11 22:09:24 2012 +0300
+
+ sched: Remove one unused thread key and its handling functions
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a4889ef726087deed9733911d8fef4d22f4679f0
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 14:26:54 2012 +0300
+
+ gitignore: Add lib-objs
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fae49241eb13fda7b514ffbb043bfa03699801c5
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 28 18:19:32 2012 +0300
+
+ plugin: API must be global (bug)
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 259eb25b96f2f851fe4adc6127e615c0897abf4d
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 14:30:42 2012 +0300
+
+ plugins: LDFLAGS only belongs in the linker command
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit efda62cc2802b7a28de89387c89f855aa5b86f2f
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jul 18 19:36:16 2012 +0300
+
+ lib: Add some examples on how to use the library
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e15778ca68456f3ad159026d5ffc0f405dbf9cc9
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jul 18 19:35:32 2012 +0300
+
+ lib: Add the test suite
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 646222a4a77e9ce4ae86cb3aff9d8776acddf3be
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jul 18 19:33:53 2012 +0300
+
+ lib: Add the generated man pages, plus the asciidoc sources
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a796e535776fc662a62b40db45ad6171c5d167a0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 26 05:52:27 2012 -0600
+
+ Epoll: remove unused variable
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c080d3d6ecf9c4da5e344ef51bc0451092f48dd5
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Jul 17 21:29:48 2012 +0200
+
+ http: Check if plugin set status in http_init.
+
+ Checks if header status is set when MK_PLUGIN_RET_CLOSE_CONX is
+ returned in stage_30 and uses it instead of MK_CLIENT_FORBIDDEN.
+
+ Signed-off-by: Sonny Karlsson <ksonny@lotrax.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit dc464102ccafd5a8367e526908dcaa8bafd08ace
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jul 11 19:03:42 2012 +0300
+
+ configure: Mark CGI as disabled on android
+
+ Android does not support regex. Using plain string matches is slower,
+ less flexible, and opens up a security hole. So rather than do that,
+ just disable cgi on android.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a6c0fd174a202e604bced7a9510c645d5b7c3b41
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 12 15:24:25 2012 -0600
+
+ epoll: epoll_states are linked in common linked list
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 762239e0bf284d7dde8e4fa59646255128e31732
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jul 6 14:49:25 2012 +0300
+
+ cgi: Pass headers through monkey, support chunked encoding
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ddbc9569dc5e54c9f7b4d4fd05d329a02b7b2633
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Jul 3 18:31:32 2012 +0200
+
+ configure: Ignore plugins without Makefile.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 954f28b8333e621f5da8698c0f0c48e35f084cb8
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Tue Jul 3 16:41:40 2012 +0200
+
+ list: Add parenthesis around macro arguments.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 676d3a2d3491f482937f126c2166599992dd4be3
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jul 4 13:21:50 2012 +0300
+
+ Fully comment the CGI section
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1f5fb3a2533b433d6768dae24f510034b9b25728
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Jul 2 16:59:03 2012 +0300
+
+ cgi: Add support for per-vhost configuration
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9f1ae9f124f9a7b7c06ec024cc01ce1f0f653ef5
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Jul 2 16:53:58 2012 +0300
+
+ cgi: Correct the config example
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6b3b03373a1752098c2cfcd8d14c2a57e6a1c730
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 30 14:29:58 2012 -0600
+
+ epoll: event state declarations cleanup
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5d5f8736224cb5f526016af4fd2b50332c025e05
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 30 13:03:35 2012 -0600
+
+ epoll: New epoll states
+
+ The Monkey API allows third party components to hook file descriptors
+ into the main worker epoll loop and base on the events it triggers the
+ proper callbacks through the plugins interface, but Monkey did not
+ track the epoll mode flags as this was just known by the Kernel.
+
+ This patch introduces the 'epoll states' mechanism which keeps track
+ of every file descriptor in the epoll loop into a user-space linked
+ list per worker using thread keys. In addition, this feature is the
+ base for new epoll modes implemented in the core: MK_EPOLL_SLEEP and
+ MK_EPOLL_WAKEUP.
+
+ From now the core and plugins can set an epoll file descriptor in
+ sleep mode (do not trigger events) and wakeup mode to restore events
+ to the state before the sleep mode.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 36356c55450b4dc78e7d76e716ce1db284b34973
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jun 29 12:21:12 2012 -0600
+
+ Plugin: deprecate unused plugin_network_ip struct
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 79c098842a175491ed351e3032192e1c3dc5a4dd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 28 22:39:06 2012 -0600
+
+ epoll: new mode MK_EPOLL_DISABLE
+
+ This new mode instruct the kernel to disable the events in the
+ file descriptor until the the events are set again.
+
+ This is *not* a remove, just a sleep mode.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 61d04b5eb6fb5666eda60c42433815e211d6b8e8
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Jun 19 18:58:52 2012 +0300
+
+ conn: if there is no cs, return 0: otherwise it tries to close a closed FD
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d3acc00c3de1226d3495ede9965747ce7d51eefb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 28 19:58:07 2012 -0600
+
+ epoll: print errors just in trace mode
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 03926427b3fcafaf5d5cba7eb683841e834df1e5
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jun 24 11:40:51 2012 +0300
+
+ cgi: Some cleanups
+
+ Removes unused variable, unneeded argument to do_cgi, some memory leaks,
+ and one malloc is replaced with a static array.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6b03a29e2fbab19b19998237031fd7c02395c516
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Jun 18 12:08:11 2012 +0300
+
+ cgi: Update to an event model
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 528735a810fae6440f3c2ef4c2c67408a80286af
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon Jun 18 14:20:52 2012 +0300
+
+ plugin: epoll_del is needed here too for stability
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f08531e48606827f5c30eb6340ec2cff559c463f
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 24 15:04:48 2012 +0300
+
+ plugins: Properly control visibility, v2
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1b6300a0bca41b415f1fb055a2d9652c07fb8766
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 21 19:29:36 2012 +0300
+
+ includes: Guard global variables with hidden visibility, v3
+
+ This makes every plugin load faster. Each plugin is also 3-4kb smaller.
+
+ v2: Fix one goof
+ v3: Change to attributes.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b29d7301706d5b2172e452244a073a539827714f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 19 07:10:13 2012 -0600
+
+ Palm: remove bad code in the read routine
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5de725002103bb84ccb00fb9556c04c5f237228c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 18 10:26:00 2012 -0600
+
+ Mimetype: add JSON mimetype
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 605877fb845871d665469a59085fd86d0b63192d
+Author: Sonny Karlsson <ksonny@lotrax.org>
+Date: Sun Jun 17 17:27:21 2012 +0200
+
+ iov: Fix initial zeroing of offset entries.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b5f057d9072ee29bc97e430198e6967a4c86617e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jun 15 16:40:01 2012 -0600
+
+ QA: new host_port_XX.htt scripts
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit bd4dd78cb5ac28f8651617d556b661534f7d36d6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jun 15 15:46:58 2012 -0600
+
+ Request: fix possible buffer overflow in Host header
+
+ The Host header allow the input of the hostname plus the TCP
+ port used, e.g:
+
+ GET / HTTP/1.1
+ Host: localhost:2001
+
+ If the port length was higher than 6 bytes, it make monkey crash
+ due an overflow in the port buffer.
+
+ This patch restrict the port length and also add a validation
+ to the port value so it just can hold numeric values.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 824ed68cad14f6b2ad72bf46e62d93babebc4770
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 14 14:17:01 2012 -0600
+
+ cgi: make the plugin OPTIONAL and README updated
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cdf94da5cc886b09b1eec7a5b43c3327f58febd0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 14 14:13:53 2012 -0600
+
+ cgi: set plugin disabled by default
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit af633500a3cac9659052c3c344d00baca8bf6a9c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 14 13:35:47 2012 -0600
+
+ Logger: adapt usage of worker_spawn()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ba96e4aca15685c48b7a5a10d6328c8518f6c0ec
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu Jun 14 17:46:04 2012 +0300
+
+ cgi: Use worker_spawn to conserve thread resources (detached)
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4ff00e6c16c5848200e3db0a1df731fcec2bcb08
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu Jun 14 17:45:25 2012 +0300
+
+ utils: Make worker_spawn take the void *argument
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 87f98cec322967afb8f564ae1e172cb203e87507
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Jun 12 23:41:14 2012 +0300
+
+ sched: We must call epoll_del here to work around kernel behavior
+
+ If the fd is not removed from the epoll set, it keeps getting notified and then monkey tries
+ to close it - and since it now refers to some other file, errors ensue.
+
+ This sounds exactly like http://osdir.com/ml/linux-kernel/2009-02/msg10362.html
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 229e717d0d1b9ae52cd50bf4bdb780baea7b4549
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jun 13 19:59:15 2012 +0300
+
+ plugins: New plugin: CGI, v2
+
+ Updated file check, plus variables http_host, server_software, server_protocol
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e94e33367c32b70fb5ab89ad2ac9cd936ab936a7
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue Jun 12 12:27:13 2012 +0300
+
+ README: Say GCC 3.2 is needed.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 64fd21542d6cfbf9e3f723e432cecfdb8c3a7c44
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 21 19:58:48 2012 +0300
+
+ dirlisting: Remove some gcc warnings (signed-unsigned, always true if)
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 90f2925523fe77f23ae1aa11279b0963a85d36b9
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 21 19:17:52 2012 +0300
+
+ plugins: General cleanup, make possible functions static
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3e8a8de131f428ced59bea91fe1b26c2d37a2765
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 12 00:01:18 2012 -0600
+
+ Utils: add missing mk_macros.h header
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2265b7ca8b4a9d2b146f0d798a48b2c95923c960
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 14:48:22 2012 +0300
+
+ dirlisting: Use correct printf formatter
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3c24fac36f7a09fd08b712c6cb6f5119e42af192
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 14:44:55 2012 +0300
+
+ logger: Use correct printf formatter
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0a8a90bb723808df87c650a7ae47c165d52f109b
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 8 14:42:34 2012 +0300
+
+ header: Use the correct printf formatters
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6fcdf2372c2cd7cbf41ca8e22a26187598b81dd8
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu Jun 7 22:33:33 2012 +0300
+
+ headers: Enable printf warnings for the wrapped printf functions
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fb9b3e9bb41e1ac37e5eb76210ddb720a3ed4a70
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jun 6 19:10:51 2012 +0300
+
+ utils: If the passed date is current, we know it's not in cache
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 813c28d308840b8f9e06241478a64a959b259bdd
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed Jun 6 16:30:10 2012 +0300
+
+ .gitignore: Add versioned libs and pkgconfig files
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8c716cc47444174de16b0de456854b3d41dd82ea
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 1 16:37:05 2012 +0300
+
+ plugin: Check that the would-be-removed handler matches
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d5f5824fdde582392d39c904ed48ca917f2d8eb6
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue May 29 12:17:43 2012 +0300
+
+ request: Add a check for no index files
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6d585d7b6a103f166dc4f47e06bfbb9c9049c4cf
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue May 29 16:33:00 2012 +0300
+
+ config: Make use of the tolower function
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c2a48089b74edc5b23be15944d109e04de90c37f
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue May 29 16:31:04 2012 +0300
+
+ string: Add a function to turn a string to lowercase
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ea01c897e88832fcf740e388ec47ea23f22f28ba
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 28 18:46:52 2012 +0300
+
+ sched: Return the worker thread id
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3ac3852528375cc5b56ed8a12040c4baeb15a959
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 28 17:25:39 2012 +0300
+
+ Export the thread_key init for the lib
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9c3658ec1b4df9bb54fad5148700294144fe1cdf
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 28 18:36:54 2012 +0300
+
+ config: Move default workers to config_init
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ace60526275964d1c44a4c72ed774a52d00ba4ef
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 11 12:09:00 2012 -0600
+
+ Scheduler: register new incoming sockets with MK_EPOLL_READ
+
+ Previous this patch, the Scheduler used to register each new incoming
+ socket with the MK_EPOLL_WRITE flag, so when the connection was established
+ epoll_wait(2) triggered the write event, meaning 'the socket is ready to
+ write'. On that moment the Connection handler realised that no Scheduler
+ information exists for that socket and run the mk_sched_register_client()
+ function, then invoke epoll_ctl(2) to change the socket mode to
+ MK_EPOLL_READ, so it start to wait for the incoming request string.
+
+ In HTTP the client always begins the communication sending the request, so
+ having a socket on MK_EPOLL_WRITE and then change it to MK_EPOLL_READ adds
+ a little overhead.
+
+ This patch makes the initial socket be registered with MK_EPOLL_READ and
+ make the Connection handler identify this new connection in the
+ mk_conn_read() function, avoiding the extra system call described in the
+ previous behavior.
+
+ Here is a little benchmark done with Valgrind/Callgrind:
+
+ +------------------------+----------------+-----------------+--------+
+ | function() | before patch | after patch | gain |
+ +------------------------+------+---------+-----------------+--------+
+ | | self | called | self | called | |
+ +------------------------+------+---------+-------+---------+--------+
+ | epoll_ctl(2) | 0.15 | 15000 | 0.10 | 10000 | 44% |
+ +------------------------+------+---------+-------+---------+--------+
+ | mk_epoll_change_mode() | 0.57 | 10000 | 0.27 | 5000 | 63% |
+ +------------------------+------+---------+-------+---------+--------+
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8a3890b241f2692acfd5ffba328aa84905b66f4c
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Jun 10 19:27:28 2012 +0300
+
+ utils: speed up mk_utils_utime2gmt non-cache path by 25%
+
+ Unsigned division is nicely faster than signed division.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d50dc1b4984d9d473e7886b833d9b8af7829195a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 10 15:20:44 2012 -0600
+
+ Configure: find: user -xtype instead of -type
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cd22c840e76d84b032c75f2e80ae07b982780844
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 10 15:18:03 2012 -0600
+
+ Development of v1.1 begins
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit dbd0f65089f1696f2395dbc178b3de8c3215815a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 5 16:38:37 2012 -0600
+
+ Monkey v1.0.0
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 87146aa7535061ff5e45ded5cd969a1eeb619de2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 5 16:37:21 2012 -0600
+
+ Deprecate websockets and patas plugins
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 28640341187a1c2e64d4c00663c96a12557ccb6b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 5 16:34:26 2012 -0600
+
+ Monkey 1.0.0
+
+commit 976340d08576e36e06d45a9f55cb119efe0210ca
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 31 20:17:42 2012 +0300
+
+ monkey: wait until all workers are ready
+
+ Otherwise the manager thread may cause a client to be added to an epoll fd
+ that has not been initialized yet.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5659e4ac6c2dd805e74670411231d2b63fee03c1
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 1 17:01:15 2012 +0300
+
+ headers: Remove unused header file
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 32324994d0d3a2d6edbfec2f92db668b90e5851d
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 1 17:03:34 2012 +0300
+
+ configure, headers: Make sure every header has include guards
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f84cf355886b7d4e2646f7c1dc43e55c3c0ec764
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Jun 1 17:08:42 2012 +0300
+
+ memory: Correct the header to have the same definition as the source
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 55e736dc846c5f711347bdcdc8d827e5972e5258
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 31 19:54:49 2012 +0300
+
+ sched: Protect the wid init with a mutex
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 46a029b86042d6ec024068a5250048d779a495cc
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Mar 23 20:50:32 2012 +0200
+
+ Clock: move sequential clock init to its own function
+
+ If the memory were allocated in a thread, it may happen too late.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 28ee0b84fb73f83893e324293104c7cdf34447c6
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 30 07:46:59 2012 -0600
+
+ Scheduler: fix return value when registering a new client
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b5cf6793490ac2ee96a87e05c69c71db1830ca1e
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue May 29 17:04:49 2012 +0300
+
+ configure: Use wildcards for the man page installs
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit bb436da99383077109819b2c458fd0db28e312f0
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue May 29 13:59:27 2012 +0300
+
+ config: Add some checks in SAFE_FREE for things that aren't alloced with the lib
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a98f2b874ada4e2a6353cb3f85601208aabd6aeb
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 28 15:01:11 2012 +0300
+
+ configure: Don't overwrite other defs with TRACE
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4d2ccdf2bf362b206876bbea19892991ae49e030
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 29 09:09:22 2012 -0600
+
+ Connection: validate mk_sched_register_client() return value
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0b93ac03b38c791f5103a912114f25422dbe7536
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 28 19:24:23 2012 -0600
+
+ Cheetah: variables cleanup
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0cf0f38428669a060ff5a84119d9ea317d5324eb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun May 27 18:08:27 2012 -0600
+
+ Mandril: re-write configuration file and examples
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8e8f6cc6a220b2e7e720b879aa5d9e44db394670
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sat May 26 20:10:52 2012 -0600
+
+ mandril: Remove unused function argument
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d1edaed10ea987933aad85a5886cba78136b949b
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sat May 26 20:07:51 2012 -0600
+
+ palm: Constify some read-only variables
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f716104d38a3ee1f7e2ff42ac78e8d7f284e262b
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 21 20:00:47 2012 +0300
+
+ liana: Remove unused variable
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 267f9a6d89618f76ecde102194ccc16dc893d6f6
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 23 18:10:51 2012 +0300
+
+ dirlisting: Prevent possible crash
+
+ Fixes a Clang warning.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 89d918ad3096a1a096ba8c3a7ada2bcb9473a210
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 23 18:00:33 2012 +0300
+
+ cheetah: Comment out some dead code
+
+ Fixes two Clang warnings (dead writes to init and last).
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 77ba5b5b4ced1b218df0177ce686b7ab0c859387
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 23 17:40:01 2012 +0300
+
+ mimetype: If the file is invalid, we would crash. Exit instead. v2
+
+ Fixes a Clang warning. v2: exit instead of abort
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7e1cd84da7fc8e2da4f2ceead4ae4987f478289d
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri May 25 13:41:06 2012 +0300
+
+ config: Don't pass NULL to readdir, v2
+
+ Exit instead of return.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8aa2fc246dab61808db4e5f28599639ddc32143a
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 23 18:03:11 2012 +0300
+
+ palm: Prevent possible crash
+
+ Fixes a Clang warning. If pr is NULL, the final return would crash.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f53867d9dd9d0bc179b322d36152e9806fb7f8bd
+Author: mahesh gondi <mashf13@gmail.com>
+Date: Sun May 27 01:06:44 2012 +0530
+
+ monkey : adds thread key initialization
+
+ added missing thread key initialization for mk_cache_utils_gmt_text
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e3131ef6eea71820059636d714e39a5d81ab347a
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 23 18:04:37 2012 +0300
+
+ mandril: Correct in_addr usage
+
+ Fixes a Clang warning. The file had used only a pointer to in_addr, when
+ it should have used a struct!
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 041cb9843211a05e997f4d4742e0754abcd34770
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 23 17:58:56 2012 +0300
+
+ palm: Remove two dead writes
+
+ Fixes two Clang warnings.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 72912a6d113ba6fe78f326f04b073b0baa87209b
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 23 17:58:35 2012 +0300
+
+ config: Prevent possible crash
+
+ Fixes a Clang warning.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e9961d6fd5ff92a6a787788a5acaa8098f276073
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 23 17:28:25 2012 +0300
+
+ user: Check the return value of sete[ug]id
+
+ Fixes a Clang warning.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8a83a2645b51897b1cea99f1b73ee0b4f94f1a6f
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 23 17:21:43 2012 +0300
+
+ user: Fix possible crash
+
+ Fixes a Clang warning. If getpwnam returns NULL, accessing usr->something
+ would segfault.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6fc0f92b09e2d76f6bb4574ea62708584c7bb886
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 23 17:18:43 2012 +0300
+
+ request: Remove dead assignment
+
+ Fixes a Clang warning. This write is pointless, since it is never read.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 70f9a5063921bfc967a161e8a86fb10503b9d7a0
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 23 17:17:30 2012 +0300
+
+ plugin: Remove dead assignment
+
+ Fixes a Clang warning.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 11859b9416ab0fa9cd3866d2882458dfc4602863
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 23 17:15:54 2012 +0300
+
+ memory: Prevent a possible crash in mk_pointer_to_buf
+
+ Fixes a Clang warning. If *dest is NULL, memcpy would crash.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9bb06a3cb31d5164588b67e466c4ee53984d7aae
+Author: Anthony G. Basile <blueness@gentoo.org>
+Date: Wed May 23 10:53:10 2012 -0400
+
+ configure: fix #156, install man pages to the correct sections
+
+ The current configure script installs the man pages banana.1, monkey.1
+ and monkey-api.3 at the top level man dir, /usr/share/man, and not in
+ the appropriate categories by FHS standards. This fixes the issue.
+
+ Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e57c12e63555141cfd4cc23c8850994dfcac2364
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 22 07:48:02 2012 -0600
+
+ Auth: rename mkpasswd utlity to mk_passwd
+
+ Monkey's "mkpasswd" clashes with the /usr/bin/mkpasswd
+ utility of the standard Whois tools package.
+
+ Thanks to Fiorella Santini for catching this.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6b6595bd4c9aa97fb2557ee6d0bea2964df02973
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 21 20:31:06 2012 +0300
+
+ file: Reorder struct file_info, drop 8 bytes, v2
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 92fa0e1c195561981de9fd0cc05916cc933255cc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 22 07:12:44 2012 -0600
+
+ Configure: fix #155 new accept() mode in configure flags
+
+ This patch add two new flags to the configure script:
+
+ --only-accept
+ --only-accept4
+
+ These flags let specify the builder system which accept mode
+ must be used in the server socket: accept() or accept4(). If
+ no one is specified the builder will auto-test accept4(), if
+ it fails, it will go for accept().
+
+ This is useful when doing cross compiling and want to specify a
+ specific operation mode.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e7cea98fb67ba94b4bc2a3fbd2f35511e9c8ec97
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 21 14:33:47 2012 -0600
+
+ http: do not perror() when sendfile() fails
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 28d844073108cdc3786024b4487059ad8b1b430c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 21 11:34:30 2012 -0600
+
+ Config: fix unitilialized variable
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ee151fc730b8ea7057bbec4a63f80dbfff1a3436
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 21 11:29:46 2012 -0600
+
+ Liana: use monkey api to set a socket non-blocking
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d3db12dee2a384bd0d298428535bc4c5281512cb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun May 20 20:45:32 2012 -0600
+
+ Config: fix minor validation bug and add extra checks
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c7392542711fb00819d877378b674847a1183b53
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 19 14:56:07 2012 -0600
+
+ file: add new field 'exists' to the struct file_info
+
+ The new field added is used to mark if the file exists or not,
+ because lstat(2)/stat(2) can fail due to multiple reasons.
+
+ If the HTTP core get a -1 from mk_file_get_info(), it now will
+ validate the 'exists' field to send a 404 or 403 error
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 508d413cca627b9ba5ee206dc7654e782b4b1185
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 19 13:33:30 2012 -0600
+
+ QA: remove old redir_301.htt test
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit be62ea4f9d1074a970fc114348dfa5583fb38b2c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 19 13:32:20 2012 -0600
+
+ file: set the proper O_NOATIME when applies
+
+ if the user is the owner of the file or the user is root, it
+ can set the O_NOATIME flag for open(2) operations to avoid
+ inode updates about last accessed time.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9d3b09bb976fe28d0f88bf0e1e476480895bfef6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 19 08:37:16 2012 -0600
+
+ http: fix directory redirect when Host header specify a TCP port
+
+ This patch makes the server to respect the port sent in the Host
+ header, so if a redirect is performed it must use the port sent in
+ the request headers.
+
+ This patch also add two QA scripts to verify the right behavior:
+
+ - directory_redirect_02.htt
+ - directory_redirect_03.htt
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c807c1894c6817bd1c11c3118a64e8890d874a3e
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue May 8 20:53:05 2012 +0300
+
+ http/request: Remove malloc from request_index with short paths
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 851590893a992728d24d607b93c8b49e9c8ff04b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 18 11:07:35 2012 -0600
+
+ auth: adapt base64.c to monkey
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9f5633473aa49413a9288b0fa38a639cb52f53ab
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 18 11:04:38 2012 -0600
+
+ auth: use new base64.c version from Jouni Malinen
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 37ecbbdf577148be7a47b8ef940d1506cc41f6a0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 18 11:02:28 2012 -0600
+
+ socket: fix mk_socket_ip_str() for IPv6
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 43784c313a7cbc249408a1897213b619853f219a
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 3 15:19:00 2012 +0300
+
+ socket: Fix possible overflow, v2
+
+ mk_socket_ip_str passed the wrong size to inet_ntop.
+
+ v2: Output a nice error message
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d16e0530615c9dc5b924fa206dcc353ecbb34a13
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 18 08:17:44 2012 -0600
+
+ auth: temporal fix for GCC warning over olen in decode function
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 368be9249051cfe4917d515ad4f6438d822477ec
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 18 07:15:59 2012 -0600
+
+ Cheetah: validate return of fgets()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0dbeaa6e42701417e10d40f53b524d2cc9f0b462
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu May 17 21:27:36 2012 -0600
+
+ Builder: compile output like Linux Kernel style
+
+ Makefiles has been modified to print out messages like the Linux
+ Kernel at compile time:
+
+ edsiper@monotop:~/coding/monkey$ make
+ CC src/monkey.o
+ CC src/mk_method.o
+ CC src/mk_mimetype.o
+ CC src/mk_request.o
+ CC src/mk_header.o
+ CC src/mk_config.o
+ CC src/mk_signals.o
+ CC src/mk_user.o
+ CC src/mk_utils.o
+ CC src/mk_epoll.o
+ CC src/mk_scheduler.o
+ ...
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cbcdb2d8fdac5284b4248504b75cd490b42ea591
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 17 22:20:04 2012 +0300
+
+ Build system: Automatic dependencies for the header files
+
+ This removes the need to "make clean" after editing a header file.
+ All C files that need recompiling are automatically rebuilt.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit bf0b20cb4b6b63585aac51525870bd9ee5ddb754
+Author: Ankit Kumar <ankitkumar.itbhu@gmail.com>
+Date: Thu May 17 12:13:41 2012 -0600
+
+ utils: add MK_TRACE_BACKGROUND env var for trace mode
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 41863a08de9c55b3fd039fb4e53440ee3dd30db7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu May 17 12:00:22 2012 -0600
+
+ http: fix a validation over if-modified-since
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 82e95aba7b3208e589434a1fc8bcea7908fe6e13
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu May 17 11:47:02 2012 -0600
+
+ QA: fix and add missing error_413_02.htt file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4e7379d64ebf9d57983f701d709394df56c9ff41
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 2 19:18:36 2012 +0300
+
+ request: Optimize mk_request_init, v2
+
+ This both simplifies the code, and moves the function from 1.6% to 0.4% of
+ Monkey CPU time.
+
+ Changelog:
+ v2 - Removed one forgotten zero set
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8138e4044b0a0c1fe058df7cab99b676c055dd70
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu May 17 11:28:33 2012 -0600
+
+ request: on premature close, make sure a default vhost details exists
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 036cc1d30dd9ff49577233700c23ed99bb3af95f
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 2 18:03:33 2012 +0300
+
+ main: Use malloc_z for the config struct
+
+ Valgrind found an uninitialized use. Initializing to zero fixes that.
+
+ Conditional jump or move depends on uninitialised value(s)
+ at 0x406D28: mk_utils_register_pid (mk_utils.c:411)
+ by 0x402CD5: main (monkey.c:168)
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+
+commit d0b38247d6ba44efbdaabcc769eab5dc7c752c01
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 17 10:13:45 2012 -0600
+
+ http: Remove unused arg from mk_http_keepalive_check
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 16d10675e2e6dd09914111bcab64b64b43f20a68
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed May 16 20:53:35 2012 -0600
+
+ Logger: if content length is not set in headers, use zero
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9e67f09f907667b522856303831f0a686351b058
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed May 16 09:39:52 2012 -0600
+
+ Config: add new DefaultMimeType configuration key
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0541d1ea9ca602a59437ee842b378f72bfbe4ce9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 15 12:59:31 2012 -0600
+
+ Readme: add requirements section
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 862f46c4837b46ebc1ca54237ae5e4707db60a92
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 15 12:33:55 2012 -0600
+
+ Duda: drop plugin (new repo has been created)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 563cb7516dba2c2411abd2927858422500cd880c
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 10 19:14:13 2012 +0300
+
+ memory: realloc had wrong size hint
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 28936ef50c37b1e5c2b24c78b169f787617c8a91
+Author: Sourabh Chandak <sourabh3934@gmail.com>
+Date: Tue May 15 16:05:37 2012 +0530
+
+ htdocs: corrected image path
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f54d9fa4e24907af1d08f4e204862bc807cdede3
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 9 16:33:46 2012 +0300
+
+ http: use memmem for the ".." check
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 517634c2cee744acb58cdbcff356df3337d30d80
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue May 8 19:26:05 2012 +0300
+
+ http: Remove the _status_ functions and list, all unused
+
+ Besides cleaner code, runtime RAM use drops by 1.3kb.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 347265e1327e59414795268bcadae0ccaa46195c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 15 08:56:34 2012 -0600
+
+ utils: optimize utime2gmt when the entry does not hit the cache
+
+ This patch reduce the number of char assignation to the target buffer
+ replacing a few of them with the memcpy() call.
+
+ Using valgrind is possible to see that the optimization helps to reduce
+ the computing time from 2.73 to 2.34.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0ffe16fb144bc1d6a00d5acc1a72aa4d4a783f8e
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Tue May 15 14:49:15 2012 +0300
+
+ utils: Add a gmt text cache for utime2gmt
+
+ In the worst case (no cache hit ever), the overhead for utime2gmt is little less than 1%.
+ In the best case (cache hits always), drops utime2gmt cpu usage from 9.6% to 1.2%.
+
+ Helps in mixed usage, since often accessed pages like the index page stay in the
+ cache.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f2e96ab21f32063b0d01bb96a05a3af0f8169e0f
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 10 19:13:43 2012 +0300
+
+ memory: Calloc is much faster than malloc+memset.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3362d3c6437c25934df8ae5452cf493ecb666d5b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 14 23:22:49 2012 -0600
+
+ Config: add support for customized error pages
+
+ This patch allow to add customized error pages per virtual host,
+ it adds a new section under the virtual host file called [ERROR_PAGES].
+
+ You can define multiple error pages depending of the error status, check
+ the following example:
+
+ [ERROR_PAGES]
+ 404 404.html
+ 500 500.html
+
+ Everytime a an error is raised, it looks for the defined error pages, if
+ it match, it will try to send the file in question, if even the configured
+ file is not found, it will send the built-in error page.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3b57324c8527e5e100fdcf841510be4acbbfdac4
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri May 11 17:39:54 2012 +0300
+
+ Request: Remove one unused struct member from session_request
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+
+commit 607ad623ad365c8be9e8f5cfe360680c5f876ab0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 14 11:50:31 2012 -0600
+
+ Trace: rename filter variable from MK_TRACE to MK_TRACE_FILTER
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fec973e48356aa588105c34b070bf2f23ffe7503
+Merge: 44a0dda 9b3bb92
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 14 11:46:17 2012 -0600
+
+ Merge branch 'patches'
+
+commit 9b3bb925816285f487b94e0db2933057c56f0cbd
+Author: Ankit Kumar <ankitkumar.iitbhu@gmail.com>
+Date: Mon May 14 11:42:10 2012 -0600
+
+ Scheduler: Fix #151: changing %i to %llu and connections counter
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8b7cc73867c7c00be9404e9ce627075508b1e39b
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 10 12:26:28 2012 +0300
+
+ Update the configure script
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+
+commit 855fc67178d334ee26856a2b3e9278fdbd336103
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 7 17:45:45 2012 +0300
+
+ request: Make use of the socket arg
+
+ GCC said that socket was unused. Another option would be to remove it
+ as an argument and keep the access as cs->socket.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e28880d7a858699dfdb569195ae216192919f7bf
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 7 19:07:38 2012 +0300
+
+ plugin: close memory leak (~5kb)
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+
+commit 44a0dda51fbf2c1c8ea7e1d351bb3f0a3e1f243f
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Wed May 9 18:01:30 2012 +0300
+
+ header: Make mk_header_iov_* static
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+
+commit c160cd9848c0e13996bb0a3bd644dcc891776014
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 7 16:46:35 2012 +0300
+
+ sched: Allocate the connections at once
+
+ This saves some 4kb of memory, and improves cache usage.
+
+ Signed-off-by: Lauri Kasanen <cand@gmx.com>
+
+commit 2939842f743fb4b7fc9cbb91f245994c7591a48d
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Mon May 7 10:50:12 2012 -0600
+
+ Scheduler: remove unneeded active_connections check
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8fd10d02ce169a7d863202f0dabc72ab95a00b7e
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri May 4 14:24:33 2012 -0600
+
+ epoll: fix unitialized variable
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a25e0593fb2a57a1cec588a567cb711dbabfd969
+Author: Ivo Brunnbauer <ivobrunnbauer@gmail.com>
+Date: Fri May 4 13:10:04 2012 -0600
+
+ GCC: Make monkey compile on gcc 4.7
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8dc3b186efe1b4d1209a3d6919c196166c55eb50
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri May 4 12:24:59 2012 -0600
+
+ String: fast path / pending part
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 32f764a155788ac9956c1ab2adbf01e772b87e14
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri May 4 12:00:12 2012 -0600
+
+ monkey: Remove two unused global variables
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5bb1a5b22f941fc149833f12c71989938bd53470
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 4 11:48:39 2012 -0600
+
+ Cheetah: use new accepted/closed connection from the scheduler
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 34bf2db21deaa9d1b7877463fd96427d8d42c093
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri May 4 11:36:44 2012 -0600
+
+ Scheduler: Fix #144: Make active_connections lock free
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ea83cb6860f9555011a4959294bd7d765b1fe533
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 3 16:53:01 2012 -0600
+
+ iov: Remove one gcc warning (unsigned-signed)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fd97b0a4652b9046e34bd3f718661bed61f26867
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 3 16:50:11 2012 -0600
+
+ string: Remove one gcc warning (unsigned-signed)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 64321e79e9e6ae14344b7d484fbaa65c566570f7
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 3 16:48:45 2012 -0600
+
+ request: Remove always-true if
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3f77bf3d9809005daf686e13761d82a44f9d054b
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 3 16:43:12 2012 -0600
+
+ memory: fix one gcc warning
+
+ Comparison between signed and unsigned.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c3b43cb2550fbd77253b5e53d3bf0618137b65b7
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 3 16:41:27 2012 -0600
+
+ string: Add string fast path
+
+ This dropped _mk_string_search from 4.5% to 3.5% of Monkey CPU time.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c65ddde770dda43b2940f2bc6049c3088ce06152
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Thu May 3 16:35:36 2012 -0600
+
+ request: no-op cleanups
+
+ Remove always true else if check, and move one common if check one level above.
+
+ No functional changes.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 03e2a6a1e3638018897bee44d2c034aa5f91ced9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 30 14:56:45 2012 -0600
+
+ Duda: rename hook duda_init() to duda_main()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit dc2d07d8ac991392aaf8de8ea82cc60257a15670
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 30 11:57:25 2012 -0600
+
+ Monkey v1.0 is coming. Woohooo
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4e25739b9369f9bee278140280e04db8e00a324d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 30 11:55:35 2012 -0600
+
+ Duda: example: use new API
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0d9ad9a07bdbd32a28145bc4145a9d2f2b0520fb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 30 10:23:17 2012 -0600
+
+ Clock: remove atomic operations
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ac962a24a8be46e5a989363d8e5e258197073a5f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 30 10:13:26 2012 -0600
+
+ Scheduler: remove atomic lock mechanism provided by GCC:
+
+ This patch drops the atomic calls set by the compiler from patch:
+
+ http://goo.gl/Ff0u0
+
+ It now uses the common pthread mutex in place.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit dada1cf543d5c1842d6b6553df46eaebeb513fcc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 30 09:34:25 2012 -0600
+
+ Config: allocate a new memory space when assigning MK_DEFAULT_LISTEN_ADDR
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 37cb86881d9ac9367233328d7b30384a3df41706
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 30 06:46:35 2012 -0600
+
+ Config: #fix 139 Invalid value for config->listen_addr
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d06d004638380368137b82362a98b4aebefcc7ca
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Sun Apr 29 20:14:39 2012 -0600
+
+ iov: Remove unused variable
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 484f819cf5a65d8f26add14243c8ffcee6293cc1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 27 22:03:09 2012 -0600
+
+ Header: fix HTTP header length
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c5e31d2e6f89d957eae281988de6ff9d466f4176
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 27 21:56:34 2012 -0600
+
+ Duda: API changes and new 'map' console interface
+
+ - New response->body_print() method. Implemented to send static
+ buffers, this one deprecates the old body_write().
+ - New response->body_printf() method. Similar to its 'print' version
+ but it allows to format a string as printf(3) does.
+ - When creating a dynamic buffer, the memory is freed automatically
+ by Duda when the flush process is done.
+ - New web interface 'map' under console interface, it prints the
+ interfaces and methods available.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9ece261ac94053020951d8954c694d8575e02de8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 25 10:53:29 2012 -0600
+
+ Duda: cookie: fix path location when expiring a cookie
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b8cc1a7ff6a5751c8286851c9affe16c02735ae6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 25 09:22:40 2012 -0600
+
+ Duda: session: on destroy, make the cookie expire
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 56429614cdd2da82fded3040117515726f5c3b2d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 25 08:51:34 2012 -0600
+
+ Duda: session: destroy sessions by name (internal lookup for UUID)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 70d6fdb1b6a4e82587933a11c4947e7d890401c3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 24 20:56:41 2012 -0600
+
+ Duda: base64: do not add breaklines to encoded string
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8d1b5ebe321c6ae2303d6a7530b3fb8208b6a5a6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 23 23:08:01 2012 -0600
+
+ Duda: SQLite: fix return value on sql_dump()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 592347065cd028b1fe79f4c993087d30678b4f06
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 23 22:54:03 2012 -0600
+
+ Duda: cookie: add path field specifying the webservice path
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f84b3b21b8953ce1ca10e206bd40a24ac881eb0a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 22 09:54:05 2012 -0600
+
+ Duda: fix xtime object name
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2d640f48841b43c03f18f0869145af1bc630e356
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 22 09:52:09 2012 -0600
+
+ Duda: rename utime object to xtime, no more conflicts.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8182ba0ede256493d0680e2dc907cc6eaeabebdc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 15:57:41 2012 -0600
+
+ Duda: add missing headers to webservice.h
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e211b9778d046b214b2e0529014a4464b9f75727
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 15:54:49 2012 -0600
+
+ Duda: minor fixes on webservice.h
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 26cea04fd15a81e2ae1bdcdd27f1582628c258ca
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 15:38:21 2012 -0600
+
+ Duda: adjust utime object
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ef9c2d02abc8e85eadca87f2858680b3a385e625
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 15:33:36 2012 -0600
+
+ Duda: adjust param object name #2
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1bc05e0785ca78af6ba774f1c415a7591669f8b4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 15:31:08 2012 -0600
+
+ Duda: adjust param object name
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 79823d071c4a951c88b378374702953999b87531
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 15:27:50 2012 -0600
+
+ Duda: rename time object to utime to avoid time.h conflict
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3dd489d90d1508090360a68fc930526ec18e5a79
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 12:20:05 2012 -0600
+
+ Duda: expose 'time' object in the web services
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3751045757a60d9b928d286bef9741c010664ebe
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 12:19:12 2012 -0600
+
+ Duda: update README file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f699c3e7cb232ea8293423c211d5464b968aa937
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 12:13:00 2012 -0600
+
+ Duda: new directory and files structure
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5d266b76e6516da1e2d307b5844716e9b6d4d922
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 11:34:24 2012 -0600
+
+ Duda: console: move object logic to the same file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fa6489bdfa3893ac612c34d08b0a56b66cf28f53
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 11:27:06 2012 -0600
+
+ Duda: cookie: move object logic to the same file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3b8978f92b56e599215d173f723cd553010a072b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 11:22:28 2012 -0600
+
+ Duda: session: move object logic to same file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8e6f3149ec64e03c1c7c28449ce5fcbdf254ccc8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 11:16:36 2012 -0600
+
+ Duda: param: move object logic to same file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3706dd5750ddc24c72fca9b36fd7a20a8d913b30
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 10:56:34 2012 -0600
+
+ Duda: plugin now is disabled by default
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 50254308131b6c89d2009f52cfe0c3ec81a09682
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 10:55:27 2012 -0600
+
+ Duda: new 'time' object
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c333eac18e3eb071fb41d0dfd53364c45e106c7b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 21 09:03:12 2012 -0600
+
+ Duda: object names are singular
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 16133773decb6acbc9cb4601c760ce1fe199cce0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 20 22:13:09 2012 -0600
+
+ Duda: cookie: fix iov_create() call
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 02ab4621c153c18d92c426ace4414de033303690
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 15 12:56:16 2012 -0600
+
+ Duda: params: new get_number() method
+
+ This new method add the capability to get a converted parameter
+ from it string origin to a long data type, the work is done without
+ extra memory allocations and it take cares of long overflows. The
+ implementation its almost equal to strtol() but it uses a fixed
+ base 10 and accept an offset for the string length.
+
+ The patch also add a new file duda_utils.c and duda_utils.h where
+ the duda_utils_strtol() function lives.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d2047a2ff79e1a437655938eeeb6b1a3cdacc796
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 13 15:44:19 2012 -0600
+
+ Duda: fix some data types
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5ac91e40e1e5b4203f19d3fecb201ad14972dccc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 12 23:26:56 2012 -0600
+
+ Duda: SQLite: sqlite->step now can return SQLITE_ROW
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5641eb9ad3146e8a8b8f51527d19378cb579ee16
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 12 22:32:50 2012 -0600
+
+ Duda: SQLite: sql_step is a wrapper now of sqlite3_step
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8e68b748e44706f6fc99b8a84ae1b7a36ebd160f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 12 22:21:40 2012 -0600
+
+ Duda: console: include duda_request_t address in the log
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2b53185f872a74870bb6ca3bbf00053c8f27fec5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 12 21:05:35 2012 -0600
+
+ Duda: param: write params error to the debug console
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 724d28c1ae300b77ce1bd6abefc4d4740042377f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 12 21:00:46 2012 -0600
+
+ Duda: param: if max_len=0, skip validation
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 101d602cc9c6d3f08f7a844bfe88b719ba1c2a29
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 12 11:59:16 2012 -0600
+
+ Duda: map console_debug() to console->debug()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f6b95269857bddf135166a88df1f02d736915a1d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 12 11:12:00 2012 -0600
+
+ Duda: console: rename method 'write' to 'debug' and add __FILE__ and __LINE__
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fe7fb973ad2cd14a9a2dd7cf593b1b53f1936d44
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 11 23:52:31 2012 -0600
+
+ Duda: new 'console' object
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit af30f7c7da2863997c971d027419a1dcd9367685
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 11 08:56:19 2012 -0600
+
+ Duda: validate that the method was set
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2b6b45b749c2bb666dfb58b1860916611a053415
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 11 08:50:47 2012 -0600
+
+ Duda: session: new isset() method
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d45b98021233fc3b8d1c717550405aba6781e1ec
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 11 08:12:38 2012 -0600
+
+ Duda: api: add a message for invalid macros
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a8c27389cf9b06a2819c9efd42190174e8d96301
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 11 08:00:13 2012 -0600
+
+ Duda: session: session->get() is working now
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ba906cdeac72578dd5e67f691c32bbd0e0e10fbb
+Author: Felipe Astroza Araya <felipe@astroza.cl>
+Date: Tue Apr 10 13:00:04 2012 -0600
+
+ Server: unused global variable removed
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8bb6a3e35ee5640de9c57e237db7d7ae103dfdaa
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 10 12:42:59 2012 -0600
+
+ Duda: cookie: minor fix in get() method
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 73e31e091c55007556be8a87e65355c355110f7e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 10 12:34:39 2012 -0600
+
+ Duda: cookie: new cmp() method
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b4291f20441a6b5e15f82876011a985f1f98f3ad
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 10 12:06:54 2012 -0600
+
+ Duda: cookie: new get() method
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f11eef1e920687503652f2e787fb51c872a0c26f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 6 23:45:30 2012 -0600
+
+ Duda: Session support completed (create/destroy/get)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit dc8019a4edafaa0fd9b555cf8cf21b00885af01b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 5 23:01:39 2012 -0600
+
+ Duda: new Cookies support
+
+ This patch do the following changes:
+
+ - Duda : add a new 'cookie' object, allows to set and destroy a cookie
+ - IOV : add a mk_bug() to check if the iov is being used over capacity
+ - API : export a new function time_to_gmt()
+ - Utils: mk_utils_utime2gmt() now accepts a buffer instead a mk_pointer
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 260064836b7aae1fc38039cfc8f331281e6e66e6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 4 23:33:21 2012 -0600
+
+ Duda: session: more entropy
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 91575a40ccfc989ba08d4f70de923dbc8f0897a5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 4 23:26:53 2012 -0600
+
+ Duda: session: generate UUID
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 245540a0d1fd01965b9a64aa4d5bab1c86b05f17
+Author: Nicolas Pépin Perreault <n.pepinpe@gmail.com>
+Date: Wed Apr 4 12:04:42 2012 -0600
+
+ Duda: new SHA1 package
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b77e32b428bea3622246469c2debecc6f2c5c17d
+Author: Kay <kay21s@gmail.com>
+Date: Wed Apr 4 11:18:43 2012 -0600
+
+ Websocket: implement 'echo' subprotocol
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 01be8a3bab1fc66fbd90e8bca2fe9ee9c36d4297
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 4 09:10:45 2012 -0600
+
+ QA: add check for HTTP parsing
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8ab993fbe960a2138a351c4a81083a63994afc22
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 4 09:10:20 2012 -0600
+
+ HTTP: assign default host before HTTP parsing
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 126e383a45bd810a12be2aad9f21c6b92e86ebe1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 4 08:58:57 2012 -0600
+
+ HTTP: validate port value after numeric conversion
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ba8fd7dbf5aa5ee774341ba333a48727b0326d7c
+Author: Jean-Paul Bonnet <bonnet.jp@gmail.com>
+Date: Wed Apr 4 08:55:15 2012 -0600
+
+ HTTP: fix Host header parser
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2c05d6ee3f128282180ff3f951f24be91180e77c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 4 08:40:00 2012 -0600
+
+ Duda: initial session support
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2a971e5b7aa1b594988994ab40ff5ef54db5c808
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 2 13:25:44 2012 -0600
+
+ Core: new SAFE_FREE macro (./configure --safe-free)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3d05fa9238b13c85f13a934f974bddb564f94779
+Author: Felipe Astroza <felipe@astroza.cl>
+Date: Sun Apr 1 15:10:12 2012 -0600
+
+ Scheduler: improve algorithm to get the lowest load worker
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1cd7bc0e639bc56a81773371b416bc3f1ece89d1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 1 15:02:52 2012 -0600
+
+ Plugin: free resources on exit
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4b5a409f5c36d1a323921a80d5e45fa072096f9f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 1 14:49:52 2012 -0600
+
+ Config: free 'file' buffer
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6a4644d618a7f40134f343760e9db6aa31dd1c97
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 1 14:46:01 2012 -0600
+
+ Logger: free resources on exit
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7f692265986643b97ded3f49becc754777e3f225
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 1 13:48:16 2012 -0600
+
+ String: new mk_string_split_free call and other changes
+
+ A new function called mk_string_split_free() has been added, this
+ function free any resources allocated by a mk_string_split_line()
+ function.
+
+ This patch also free some resources used by the main configuration
+ structure of Monkey
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit be5a8455d49c8913c2aafb6d36340342387e1862
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 1 11:55:50 2012 -0600
+
+ Signal: free main configuration on exit
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b600b7cf7e08b08a12795b2f648eb7f0dfe51889
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 1 11:55:14 2012 -0600
+
+ String: split_line now returns a mk_list
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8b841ccf79a975f36584158ce1743acf225dfe5e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 21:37:20 2012 -0600
+
+ Patas: use mk_list method when reading config sections
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8e7c6cb4f9d1a3402aee1e6ff6d3c5145d4fea8e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 18:21:48 2012 -0600
+
+ Palm: use mk_list method when reading config sections
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 822ebe18f3844e4f75c2dae30e087b55da90a909
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 18:20:36 2012 -0600
+
+ Mandril: use mk_list method when reading config sections
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a2ecf6a410af102ee75349a69432c5dc9a1112da
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 18:18:54 2012 -0600
+
+ Liana_SSL: use mk_list method when reading config sections
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8b285ed3af3ba7adf72dbfcfd92debfeb7845bec
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 18:17:08 2012 -0600
+
+ Duda: use mk_list method when reading config sections
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6290c20886bfb5aabfddd5a4697192b887381936
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 18:12:43 2012 -0600
+
+ Cheetah: use mk_list method when reading config sections
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 977acfd620662459bac39f23e5aac64b886858eb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 18:05:32 2012 -0600
+
+ Auth: use mk_list method when reading config sections
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 94fd69b66f018cab0cdc0bc2d1b1bb7716820092
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 18:00:41 2012 -0600
+
+ Config: struct mk_config now uses mk_list
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 71c8f051dc4030a63b949a68397da4f0d3979aef
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 17:32:55 2012 -0600
+
+ Config: free hosts information when exiting
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9bfbdbbd6a77f5aea1b3e97b597295c5bfc9d841
+Merge: f26230e b30bd47
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 16:00:43 2012 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit f26230e314699331e2094b67e2badbbf79800101
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 15:55:04 2012 -0600
+
+ Logger: use new vhost structure based on mk_list
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5ecb697f8516d57a7ef53a87d3229c98412852d8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 15:51:38 2012 -0600
+
+ Duda: use new vhost structure based on mk_list
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a80fe821b1cfa9964bbca01f70a36d932036c48a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 15:48:38 2012 -0600
+
+ Cheetah: use new vhost structure based on mk_list
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5c6ea12e93c83a6ed611a48f7ff392938d546aef
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 14:52:01 2012 -0600
+
+ Auth: use new vhost structure based on mk_list
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 985329d65e8b242572cd23c5b8c5213d378e56d2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 31 14:44:27 2012 -0600
+
+ Config: vhosts are now handled by a mk_list
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e1e1d0c0d3c160c0a44dd8c62db71fc86d72fea5
+Author: Kay <kay21s@gmail.com>
+Date: Fri Mar 30 13:41:56 2012 -0600
+
+ websockets: fix variable payload length
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b30bd47f6422b363a9b8ca94a1c145737dc93d0f
+Author: Kay <kay21s@gmail.com>
+Date: Fri Mar 30 13:41:56 2012 -0600
+
+ websockets: fix variable payload length
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fe7bd889834e00b7aa050509e68ac97332f8b9a9
+Author: Sourabh Chandak <sourabh3934@gmail.com>
+Date: Fri Mar 30 08:49:18 2012 -0600
+
+ Duda: apply restriction for number of method parameters
+
+ This patch looks after the restriction on the max permissible length
+ of every parameter.If a parameter value exceeds the max length it
+ duda_request_parse returns -1 and an appropriate message is shown
+ on the terminal when in the TRACE mode.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit bc530876e840ece9316010e386b3169c5d4d0949
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 27 23:23:24 2012 -0600
+
+ Scheduler: optimize connection queues
+
+ This patch does a great improvement in terms of performance. When
+ a write event is triggered the scheduler is invoked to verify if the
+ connection already exist or if it refers to a new one.
+
+ The past scheduler implementation had a fixed array per thread with
+ slots for a number of (sched_connection struct * worker_capacity). The
+ main problem was that when many connections were active, do a sequencial
+ search was very expensive due to the fragmentation originated by the
+ 'status' field of the the sched_connection entries in the whole array.
+
+ In the mailing list, developers were discussing a better approach to
+ register a new connection and Max mentioned that having two queues of
+ connection could improve something and be more clean.
+
+ This patch applies the "two queues" idea proposed to the scheduler but
+ improving not only the connection register, also improving the hard lookup
+ when the write event is triggered, the new mechanism is as follows:
+
+ struct sched_connection {
+ ...
+ mk_list busy_queue; /* active sched connections */
+ mk_list av_queue; /* available sched connections */
+ ...
+ };
+
+ Comparing and profiling with valgrind/callgrind we get the following
+ performance results:
+
+ Function name Inclusive Cost Self Cost
+ -------------------------------------------------------
+ old -> mk_sched_get_connection() 10.63 10.63
+ new -> mk_sched_get_connection() 0.86 0.86
+
+ The new mechanism optimize the scheduler connections lookup in a 90%!,
+ conclusion?, good public discussions get great ideas :)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 58fe4349b558159c356fc9a3b0b4a023dd5ed085
+Author: Torsten Pfüller <torsten.pfueller@message-people.de>
+Date: Mon Mar 26 11:57:39 2012 -0600
+
+ config: fix some memory leaks
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6bb902569b3080f9d41aa83b6fa812e66d58d56c
+Author: Sourabh Chandak <sourabh3934@gmail.com>
+Date: Sun Mar 25 21:14:07 2012 -0600
+
+ Duda: modifed sample webservice for better string handling
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ed0ffeda9e5a8e6469013620753dfbbef1ffd169
+Author: Sourabh Chandak <sourabh3934@gmail.com>
+Date: Sun Mar 25 20:57:14 2012 -0600
+
+ Duda: added duda_structure type variable to duda_request and related methods
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b3bab756c41549de4fa9d12878a0d41a714567f1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 25 13:33:41 2012 -0600
+
+ Duda: move params interface to a duda_param.c file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e265d90acb21f9bb1acca9cf2c0564cc23f29783
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Mar 23 17:42:38 2012 -0600
+
+ scheduler: Use atomic writes in register_thread
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 437786e4d04eba98e8b2d8c73decee852a5400f7
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Mar 23 17:38:44 2012 -0600
+
+ clock: Initialize the _current_time variables
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d1cf22e74a0794e464a5e62ace20ac6cb9d56597
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Mar 23 17:23:45 2012 -0600
+
+ scheduler: Do atomic writes for active_connections
+
+ This fixes the bug under extremely high load.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c5eebd8b4da2924f1ddda86ecd33cddb693c37e6
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Mar 23 16:49:39 2012 -0600
+
+ threading: Use thread-safe time functions
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 290717de95dc276e4108d6f9bbe5e1d546593d79
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Mar 23 16:48:14 2012 -0600
+
+ threading: Do atomic writes in the clock thread (gcc-specific)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9a2b826e119513835ed65b63dbdf0bc78ab536fe
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Mar 23 16:42:52 2012 -0600
+
+ messages: only print colors to terminal
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 512c6c898dd1778a0aa7819231e8f42bcb9751c9
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Mar 23 13:09:27 2012 -0600
+
+ header: move mk_bug() check before iov_*() call
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit dd092f94a0083dbbf6d423ccbeec750f8f544825
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Mar 23 13:06:57 2012 -0600
+
+ config: enable GNU extensions to get isblank()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 614dbdde7c988bdffd163769ff6b67d821e6aeb2
+Author: Lauri Kasanen <cand@gmx.com>
+Date: Fri Mar 23 13:05:36 2012 -0600
+
+ git: Update .gitignore to match all generated files
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0cbbc480e66bc52a794d8cdf2963fdb68e1b331c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Mar 23 13:03:49 2012 -0600
+
+ Duda: SQLite: update API, new methods to retrieve column values
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0c9cad07f5a2cce4905a27d52c1b425766ad44e4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 22 20:14:22 2012 -0600
+
+ Duda: SQLite: new sqlite_handle_t data type
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 35fbe01f79d132305343ee360f3eedac2239d082
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 22 19:08:27 2012 -0600
+
+ Duda: SQLite: rename method step() to fetch()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8bdad89a66e5529aedf558b1438b1c7d1c87fa86
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 22 14:50:50 2012 -0600
+
+ Request: fix memory leak when invoking premature close
+
+ When premature close was invoked, it requested memory for a temporal
+ session_request. On this condition that memory block was never freed.
+
+ The patch drops the mk_mem_alloc() call and just link the temporal
+ session_request pointer to the sr_fixed field from the client_session
+ struct.
+
+ Thanks to Felipe Astroza for report this issue!
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7c75f3547d114bed39b52edc63f1791cad681c7e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 22 13:39:41 2012 -0600
+
+ HTTP: fix keep_alive initial value on session_request
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 53650ac48a163f95eefb10abee9680be9b7a087b
+Author: Sourabh Chandak <sourabh3934@gmail.com>
+Date: Wed Mar 21 23:16:20 2012 -0600
+
+ Duda: add new 'params' object to handle parameters
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 841c6607eec2db8084043df5d8fb54129bd5c269
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 20 22:01:40 2012 -0600
+
+ Duda: SQLite: new dump() and done() methods
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 697ab06e2f28597a475a8db212bffc8b73c268ae
+Author: Mahesh Gondi <mashf13@gmail.com>
+Date: Tue Mar 20 12:49:44 2012 -0600
+
+ [PATCH] utils: deprecate err(), use mk_err() as it should
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit afb82edd01846e3f65d9f60110bc556ed70d006c
+Author: Sourabh Chandak <sourabh3934@gmail.com>
+Date: Tue Mar 20 08:23:14 2012 -0600
+
+ [PATCH] Duda: examples: improved json example
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a6f4f43673e3ed98d4c337d3f07d37cfb3792354
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 19 16:28:45 2012 -0600
+
+ Duda: SQLite: callback now gets 'struct sqlite_cb_data' as data
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3fb9eee764c98e803038e509302d8558c383d203
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 19 09:25:38 2012 -0600
+
+ Duda: examples: fix Makefile paths
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 08e3e0be5e8318640a085d556793931ed42fc681
+Author: Felipe Astroza <felipe@astroza.cl>
+Date: Mon Mar 19 09:22:15 2012 -0600
+
+ clock: Comments added and indentation fixes
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ff8fd67dd32976e156b55c55bf9ca7ffbf1e8354
+Author: Felipe Astroza <felipe@astroza.cl>
+Date: Mon Mar 19 09:20:57 2012 -0600
+
+ clock: improve time strings concurrent access
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2a60a7ba8e6f358e0485c89cae7306ba14214a20
+Merge: a5e22aa d2696fe
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 19 09:15:16 2012 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit a5e22aa45db79eec35c85739de75ddd0efccb4b4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 19 09:14:45 2012 -0600
+
+ Duda: examples: add json loader
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d2696fe56f8347f324cd5057634c0172785e685b
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Mon Mar 19 14:29:33 2012 +0100
+
+ iov: remove bogus variable initialization
+
+ There's no point setting up an initial variable value when it is replaced right away, it wastes cycles.
+
+commit 93e9510343395a9ff24407cdcd8b01131099c1a5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 18 23:51:21 2012 -0600
+
+ Duda: fix Makefile.in in packages
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a58f49525992526a4f20afdbcf8a4ced0c521719
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 18 18:02:26 2012 -0600
+
+ Duda: SQLite: add callback support to sqlite->exec()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 730354399b181815d04e0b715150b04a3612672c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 18 15:45:13 2012 -0600
+
+ Duda: SQLITE: deprecate content of sql_init() routine
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit acce61d8fae4c15a5cc86a80a2640711f4b0eb89
+Merge: 76c5d4a cb1b1ee
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 18 15:15:50 2012 -0600
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit 76c5d4a142e74d8fe942f2c5d5af697c058ec6ee
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 18 15:15:23 2012 -0600
+
+ Duda: SQLITE / delete hidden file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a4979060b2226afce6331da2b38dca141c45e225
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 18 15:14:52 2012 -0600
+
+ Duda: new SQLITE package
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cb1b1eea50060808320ce68c2870d14979214755
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sun Mar 18 17:38:49 2012 +0100
+
+ overwrite pidfile upon SIGKILL
+
+ With the pidfile as a write-lock, SIGKILL does not remove the file
+ and causes the next execution of monkey to abort as it cannot open
+ the existing file. Solve this by unlinking it before opening it if
+ the file is already there (from the previous run).
+
+commit 60b6303aedceeafd12867fa5bc2bfe73a8bb4ce8
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sun Mar 18 14:54:05 2012 +0100
+
+ monkey: core: lockup pidfile
+
+ The pidfile that is created when monkey is started should, as its exclusive nature requires,
+ be locked against other processes's that might attempt to write over it. Create a POSIX write-lock
+ for this, as shown by lslocks(8):
+
+ $> lslocks -p 15676
+ COMMAND PID SIZE ACCESS M START END PATH
+ monkey: server 15676 5B WRITE 0 0 0 /home/dave/projects/monkey-dev/logs/monkey.pid.2001
+
+commit fcd3b9a26f0b45c6b748384d3058f9270a763102
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 17 23:51:10 2012 -0600
+
+ Duda: deprecate crypto routines
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 92ddb8d358f7ff4f06256eae788e428d4ca3f88c
+Author: Felipe Astroza <felipe@astroza.cl>
+Date: Sat Mar 17 20:15:38 2012 -0600
+
+ core:time string sizes constant replaced by macro definition
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 25c43e80ef70a5be53cefd2aa53450b18055b63f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 17 18:12:05 2012 -0600
+
+ Duda: new base64 package
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 74a2e71006a6c5fa1555bcb3914fe52b5eba54e5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Mar 16 10:21:07 2012 -0600
+
+ Duda: new packages support!
+
+ This patch adds a new packages mechanism, so web services can
+ request to Duda to load specific packages/objects.
+
+ The first package available with Duda is JSON, so to add JSON
+ support to a web service, it will take two steps:
+
+ #include "packages/json/json.h"
+
+ int duda_init(struct duda_api_objects *api)
+ {
+ ...
+ duda_service_init();
+ duda_load_package(json, "json");
+ ...
+ }
+
+ The duda_load_package() call takes two arguments, the first one
+ is the package object which expose the API calls, the second is
+ the name of the package.
+
+ The packages lookup takes place in duda.conf file under the configuration
+ key 'PackagesRoot'.
+
+ Now the fun begins :)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit da5cecae409761582207c07f115f4d1ed15ae3e7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 14 23:05:04 2012 -0600
+
+ Duda: link to libmath '-lm', required by cJSON
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4f0b80c677818ed54a18fae7c3931477b928c5dd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 14 16:59:55 2012 -0600
+
+ Header: fix memory leak when extra_rows are set by the API
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7857513b51d0c021d650189fe82d116f18679ef7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 10 23:01:36 2012 -0600
+
+ Duda: check interfaces and methods string length
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6ce9948ae08c6a4499d8a5ab8246f447a791ee31
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 10 20:37:09 2012 -0600
+
+ Duda: validate wrong services path
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b9ab3c926f5e65a0ef8054cb97184daeab53eb5f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 10 13:19:28 2012 -0600
+
+ Configure: do not install not compiled plugins
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4ac2b2a2cbf8422a550a8d24594f4bc376fa1d9f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Mar 9 22:04:55 2012 -0600
+
+ Configure: tweak compiler message
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3d024c987071bb35e60878000b1c7297c50bb622
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Mar 9 17:04:58 2012 -0600
+
+ Duda: update Makefile.in
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 106de2c80f62b04c1f305fe6a6a5389f429a519f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Mar 9 16:56:58 2012 -0600
+
+ Duda: new global variables support
+
+ In order to create a global variable in your service:
+
+ 1) Define a global variable as any C global var:
+
+ /* define variable */
+ duda_global_t my_variable;
+
+ 2) Declare the variable as global for Duda, you need to do this
+ inside the duda_init() call and after duda_service_init():
+
+ /* initialize variable */
+ duda_global_init(my_variable, NULL);
+
+ 3) Optionally, you can initialize the variable with a defined value,
+ this is done using a callback function, so you could do:
+
+ /* define variable callback */
+ void *cb_global_myvar()
+ {
+ void *mem = malloc(16);
+ return mem;
+ }
+
+ /* initialize the variable with the callback */
+ duda_global_init(my_variable, cb_global_myvar);
+
+ 4) Inside the services callback for each method you can retrieve or
+ set a new value for each one using the global object:
+
+ global->set(my_variable, some_value);
+ global->get(my_variable);
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8f37d029001b157ef47be5ad7cd4209ea258cd42
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 8 08:51:24 2012 -0600
+
+ Duda: fix bad object name in Makefile.in
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d38824c7b6e33ea3aca3c291c05b5496ce8d89cc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 7 22:48:13 2012 -0600
+
+ Duda: add JSON support
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 80de9a781787a04ff5d8b5bac69cf67a3f304464
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 6 22:56:43 2012 -0600
+
+ Duda: new crypto object with base64_[en|de]code support
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 266a9b3469bc707c90b37dc08c16af1acf077e4a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 6 22:07:11 2012 -0600
+
+ Configure: recursive search for Makefile.in in plugins directory
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 605a3690b533cf82bf7a0b6279a008b31dbf41a8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Mar 2 10:47:08 2012 -0600
+
+ Duda: add Makefile.in to examples/
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2bfd63c43a54a274a36f6200e513a1123952d832
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 1 21:58:47 2012 -0600
+
+ Duda: new response->sendfile() method
+
+ the sendfile() method send a complete file in asyncronous mode using
+ the Monkey socket_sendfile() api.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ef1dac2dabd2c8fc74fbc1d88babbdfdc028bdfe
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 1 19:51:46 2012 -0600
+
+ Duda: prefix filenames
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6bbbf5672c78bdf9d97b06bc8dcbb24071ac5818
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 1 19:02:14 2012 -0600
+
+ Duda: on response end, use service_end() properly
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f7fbad6848c8f40a576ba8d86b629b967ba77170
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 29 22:26:26 2012 -0600
+
+ Duda: complete queue_flush() and free resources
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 680c9771abe513ea620d3413838e0ebb276a2184
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 29 20:08:16 2012 -0600
+
+ Jump to v0.99
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 87cc2365e3c87ccf7317176069656d24291bf434
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 29 19:39:27 2012 -0600
+
+ Macros: fix mk_bug() w/stacktrace
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c7ba6efd915c1d52cf2d4ff245f8340ab4466650
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 29 19:38:34 2012 -0600
+
+ Duda: queue_flush
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f41f22c500fda4161f98586865b95f4315fee8e3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 28 23:48:30 2012 -0600
+
+ Duda: initial implementation of output queue
+
+ This patch add a new way to handle the output data. All new output
+ request are linked to dr->queue_out and handle in async mode in order.
+
+ New files have been added: queue.c & body_buffer.c (and it headers)
+
+ The queue.c file represent the queue management routines, the body_buffer
+ stuff represents the the strings output: response->body_write().
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit caf6e49f0a6f6955398136b2f5cd588d7ba1184d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 27 21:38:11 2012 -0600
+
+ Request: on trace mode do not use cs->socket
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9bd31cbb12fe0d42b96bc752360bd8357abfca57
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 26 23:31:18 2012 -0600
+
+ Duda: events_write management
+
+ The framework now supports handlers for the write events, so it
+ can send multiple data buffer and close session properly.
+
+ Other improvements:
+
+ - Added a callback to response->end(..., callback_func)
+ - Content length is sent on every response
+ - Free allocated resources when the Duda request ends
+ - Events write: register / unregister
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e12777ce010909b792465b2ff258b9c6b3053904
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 26 11:15:06 2012 -0600
+
+ Duda: body_buffer adjust to asynchronous mode (event oriented)
+
+ When writting the body_buffer, due to the asynchronous sockets mode,
+ less data than the expected can be written, so Duda must catch up this
+ behavior.
+
+ This patch makes to adjust an offset in the body_buffer, as well it
+ register a callback with the write events triggered by the core of
+ Monkey, so in the next event calls it sends the pending data.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 65a4c25dffdc55efd86816a4628c5b61e25149e3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 25 21:27:54 2012 -0600
+
+ Macros: print stacktrace when mk_bug() is called
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4b4efc5011f84ce31211a869cc9c857cb41daf94
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 25 21:12:45 2012 -0600
+
+ Duda: body_flush set offset when data sent is less than total
+
+ If the socket_sendv() function wrote less data than the total instructed,
+ it reset the iovec struct and perform an offset operation for the available
+ iovec entries setting length=0 and adjusting iov_base if required.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5e60aaff9a6eeef5222befca2a68e873ef11f714
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sat Feb 25 23:37:48 2012 +0100
+
+ add stacktrace output
+
+ Add a stacktrace output for debugging purposes in both the plugins API and
+ the SIGSEGV handler.
+
+commit cfa10482915871a696e4bbbac1d6eaeca14f18e9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 24 16:06:11 2012 -0600
+
+ Duda: body_buffer now uses Monkey iov struct to store buffers
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit be74d947e7aba560171dc0c22f4e38eddf2c5b24
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 24 15:58:32 2012 -0600
+
+ iov: fix realloc new pointers
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e98e97afbc830e521fff3294e38625aea9e25cf8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 24 15:50:50 2012 -0600
+
+ iov: new mk_iov_realloc() call
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 283c7df870c6c1b7eec3b0d61a9bb071281cb2f1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 24 15:32:41 2012 -0600
+
+ Duda: new response API object
+
+ the response API object expose methods to configure and perform
+ a response of data to the client, this patch implements the following
+ methods:
+
+ - http_status: set the response HTTP status
+ - http_header: add a new HTTP response header
+ - body_write : write content in the body part of the response
+ - end : finalize the work flushing data as required
+
+ This patch also implements the body_buffer concept. Each duda_request_t
+ have associated a 'struct iovec *' array which is used by body_write()
+ to perform socket writes. These writes are asynchronous and done when
+ the callback is ending, leaving Duda and Monkey Core to handle the
+ output data.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cd91d10faa7ef3a0d680968a2d97d2b010885fa6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 23 23:57:02 2012 -0600
+
+ Duda: hello service rename callbacks
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7d3c2c477be9bc8da8e29bf5e2dc3336a3573661
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 23 23:53:33 2012 -0600
+
+ Duda: callbacks working
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 41bf469a405a7beab1c92a443685b24ea91c26e0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 22 23:39:47 2012 -0600
+
+ Duda: parse request routine
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cceb21fd529dd9432b4b13ba7230664e20563896
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 21 21:59:22 2012 -0600
+
+ Duda: match web service app with request URI
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fd95b4897f1c96bba3248f44522a5634529c67e0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 20 23:31:00 2012 -0600
+
+ Duda: new API objects
+
+ Duda framework now export four pseudo-objects for the webservice usage:
+
+ - monkey: core monkey API methods
+ - map : methods to define the webservice URI map
+ - msg : messaging object (info/warn/err/bug)
+ - debug : debugging methods (not yet implemented)
+
+ Each object contains N methods which can be invoked like:
+
+ msg->info("some message");
+
+ The API is still in a early state and it will implement more features
+ in the next commits.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 07b0435cbc22d2d3eba5bdb54c3aeba7f2e7576f
+Merge: 48882ee 6f4a9b9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 20 11:54:08 2012 -0600
+
+ Merge commit 'v0.33.0'
+
+commit 6f4a9b9534d624a27fa848719383b7c5cc759e77
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 20 11:49:26 2012 -0600
+
+ Monkey 0.33.0
+
+commit 6eeba30564bf31e17e180c4fe23de267bbc74501
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 20 11:49:20 2012 -0600
+
+ Config: fix mk_bug() alert when reading a vhost file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 48882eef8b690e76091ee83b850113cc2006d27a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 20 11:47:13 2012 -0600
+
+ Duda: checking hooks references
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0db7753218ed1f8a39b6aa7ad78e3094faae9eeb
+Merge: 6287750 85b9ac2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 17 22:59:09 2012 -0600
+
+ Merge conflicts
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 85b9ac2e267448960ee11ec5c2849f8d1031c194
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 17 22:55:28 2012 -0600
+
+ Duda: initial API object
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 78cec1ffe2c1d3ef7f3533ac979945f78fcc309f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 17 21:27:59 2012 -0600
+
+ Duda: load service libraries
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 79a8edd9ed782d8ef38f69999948f45116f273e7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 16 19:55:39 2012 -0600
+
+ Duda: add example service
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6287750ae1fe4c801c83fbc4175a61f0f6fbf557
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 16 19:52:06 2012 -0600
+
+ Duda: add example service
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e83477dccaa5d080a7aaa9737e92d15bc7c633cc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 16 19:51:42 2012 -0600
+
+ Duda: add webservice API files
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a451185ef30de2c68649d92f18e57fb7dfb14e23
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 14 10:12:41 2012 -0600
+
+ README: update project basic info
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fc3f4c71f02bdd16fd20db7bcb1847f2d28fb315
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 14 10:02:21 2012 -0600
+
+ Duda: plugin is licensed under LGPL v2.1
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8ca25f97ffbaefabde23e58a7b938045d62f8f87
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 13 21:55:00 2012 -0600
+
+ Duda: web services framework
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6ef849fde878164c90d09111d8807e56dd7bb625
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 13 21:13:50 2012 -0600
+
+ Liana_SSL: count number of Bazingas
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 62a778c302e18df0fe4dd10daa515fc2d2a72e39
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 13 21:01:55 2012 -0600
+
+ Macros: fix return value for mk_is_bool()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 307261c25e1857591d7faa49f04be56e7937064a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 13 20:27:38 2012 -0600
+
+ Macros: new mk_is_bool() macro to evaluate booleans
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7e07cc54b6536af38ae9b7255cb3c82d1aada392
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 9 16:08:46 2012 -0600
+
+ Monkey 0.32.0
+
+commit 7b941b3f22e4dc39a0fab564eda5f86002a6f837
+Merge: a2ff857 041f314
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 9 16:08:31 2012 -0600
+
+ Merge conflict
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a2ff857f891e8f7cfdea5c3418962da957744664
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 9 16:06:50 2012 -0600
+
+ Monkey 0.32.0
+
+commit e55d571e11bc333fa6e5e6ee3de8cb95e1947fa6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 9 16:05:30 2012 -0600
+
+ Debian: update rules and install data files
+
+ the debian package now install the htdocs files under:
+
+ /var/www/monkey
+
+ The version also has been updated to 0.32 in the changelog
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 041f3146c6a2db4cd2a1cbf0899cbfc6bc355d63
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 9 15:38:53 2012 -0600
+
+ Monkey 0.32.0
+
+commit 898d00f874831ca1887570441552fbf19db4ad88
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 9 13:06:15 2012 -0600
+
+ Distribute binary script added by plugins
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 07bb5f297ddd6eb0844a01a09e2da39e6d163084
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 9 12:58:22 2012 -0600
+
+ Update Copyright year
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1148ee03422d3c04da70227e358eb7a971497e83
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 26 23:51:04 2012 -0300
+
+ Cheetah: default to Server mode
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e1106921235795817c84b16807e3768d58ac8003
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 26 23:11:09 2012 -0300
+
+ Cheetah: adjust worker ID
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 896127b0928027bca4ca2597cd983c6a7ab611ca
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 19 12:57:11 2012 -0300
+
+ Workers have names
+
+ Since now all monkey threads (Linux tasks) have set a human readable name,
+ this has been done using the prctl(PR_SET_NAME,...) syscall.
+
+ You can use 'ps' utility to check the tasks in question, eg:
+
+ edsiper@monotop:~$ ps -L -p 16058
+ PID LWP TTY TIME CMD
+ 16058 16058 pts/2 00:00:00 monkey: server
+ 16058 16059 pts/2 00:00:00 monkey: clock
+ 16058 16060 pts/2 00:00:00 monkey: cheetah
+ 16058 16061 pts/2 00:00:00 monkey: logger
+ 16058 16062 pts/2 00:00:00 monkey: wrk/0
+ 16058 16063 pts/2 00:00:00 monkey: wrk/1
+ 16058 16064 pts/2 00:00:00 monkey: wrk/3
+ 16058 16065 pts/2 00:00:00 monkey: wrk/2
+ 16058 16066 pts/2 00:00:00 monkey: wrk/4
+
+ If you use 'ps' with common arguments you will not realize this change
+ as 'ps' primary looks for the command line in procfs for each task, you
+ have to use the '-L' argument to get details of the process tasks.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 424217adc5555c0e54acfeffdef264d4d7448870
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 17 10:38:21 2012 -0300
+
+ API: drop ip_str plugin struct field
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit dfc6ce449c32281e09dacab38c44526ce844c681
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 17 10:14:26 2012 -0300
+
+ Config: do not cast to size_t
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8eb0a3489013acb73d34da240903d071b8771844
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 16 15:39:48 2012 -0300
+
+ Plugin: drop deprecated ip_str function hook validation
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c63148843a62e747d9d52a01a0bcdc76ba4445b7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 16 15:39:14 2012 -0300
+
+ API: drop (void *) casts
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 592389eabd99a7eb0429ab1944ec153c6a4db0b6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 12 10:25:24 2012 -0300
+
+ Monkey 0.31.0
+
+commit b43b743905349d226a3eeaff34178e3d42dc7938
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 12 10:25:09 2012 -0300
+
+ Update MONKEY_MINOR version to 31
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0b7d5c5ab20b2ffb5fb40f23801a2e03b8cbe328
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 11 18:10:13 2012 -0300
+
+ Palm: use new socket_ip_str() API call
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 69d630cbb649cfa74e4a81c7b0e6c38784d4dbe1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 11 16:21:16 2012 -0300
+
+ Socket: mk_socket_ip_str() accepts input buffer
+
+ The function which format IP strings was allocating memory buffer
+ for the string, this patch makes the function to accept an input
+ buffer so the caller must care about it.
+
+ Also this patch modifies the logger plugin to use the new API of
+ the function in question. Now it uses a thread key to hold the
+ buffer in memory used to format the IP string, it should be
+ a little bit faster now.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e8f33a8ecfdcb71336afd0cc54bb4c65eab982f6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 10 15:57:57 2012 -0300
+
+ Logger: fix memory leak on ip_str buffer
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 901ca276f3b64e42882e00b30a2ff3d41a27c422
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 10 15:43:30 2012 -0300
+
+ Liana_SSL: deprecate _mkp_network_io_ip_str()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 34572c8ae18199611ceaf3919631e80f452e4714
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 10 15:43:10 2012 -0300
+
+ Liana: deprecate _mkp_network_io_ip_str()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit daffacfa85039688965a9dd9f47cd196ebfb4a30
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 10 15:40:54 2012 -0300
+
+ Socket: move socket_ip_str to core interface
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2d608e5c9556cd201fe72b6db1c416f74452d6c4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jan 7 22:15:55 2012 -0300
+
+ Config: add details for IPv6
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 95ef0f616c4b25ce4fde895aab33eb4670de6585
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jan 7 12:12:53 2012 -0300
+
+ Logger: fix fake consuming, perform when the buffer is full
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4f00640fd82912f5560cbe13a75eee873df8bfc6
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Jan 6 13:28:52 2012 -0300
+
+ Liana_ssl: Replicated the fix of Liana because it was happening here too
+
+commit 72a9a427bf5a8e646a8c630def85f3c94aed2db5
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Jan 6 13:28:25 2012 -0300
+
+ Liana: Fix bug #111 reported on the bug tracker of monkey
+
+commit c59682e46d6831ceec219103d37578ad71dee8e4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jan 1 10:21:25 2012 -0300
+
+ Monkey 0.30.0
+
+commit d8035ebcbf071c8e59d87ff4857d163888239f12
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Dec 23 11:27:22 2011 -0300
+
+ Liana_ipv6: Plugin deprecated since we have the IPv6 support integrated in liana plugin
+
+commit 291356eb23d8db491b85b69dc7aafaaefa55bba7
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Dec 22 10:18:32 2011 -0300
+
+ Core: Fix mk_string_trim() it doesn't segfault when we pass a string with lenght 0
+
+commit 4b5327dd99e431803bfd522d9d2889a06a98536a
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Dec 22 10:18:03 2011 -0300
+
+ Liana: Fix some warnings
+
+commit 2cc17fdba1c174fa50f22f6b4d8d6200b8736437
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Dec 14 20:04:54 2011 -0300
+
+ Palm: Fix it to fit the new network layer
+
+commit f97f0932e84f0933898f9f4320b4f64ac6eb6896
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Dec 14 20:03:51 2011 -0300
+
+ Liana_ipv6: We don't need it anymore for the moment
+
+commit 6227a44a8b36ebfff81f8b256543f8aa710334cf
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Dec 14 20:03:04 2011 -0300
+
+ Liana_ssl: Use the same way as liana to connect using ipv4 or ipv6
+
+commit 5d38843cd1abecda7ad1a86f8deb6f870730791a
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Dec 14 20:02:07 2011 -0300
+
+ Liana: Fix network layer to use ipv4 or ipv6 according to configuration values in monkey.c
+
+commit c9b217fa0e9f1c8b178c6d792759ca1fbaa6ef79
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 15 14:36:47 2011 -0300
+
+ Fix double-free() on client_session when keep-alive is off
+
+ When KeepAlive feature is set to off, Monkey was doubling free
+ the client_session struct, this was done in mk_http_request_end()
+ and also in mk_conn_write().
+
+ The patch removes the explicit free in mk_conn_write() and let
+ return mk_http_request_end() the final status.
+
+ This issue was discovered and initially fixed with a patch
+ provided by "hio_ <trustthesky@gmail.com>". This new patch
+ handles the conditionals in a different way.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0cdb0e6a3513af5b1817031bf467e174a2d5e49d
+Author: hio_ <trustthesky@gmail.com>
+Date: Tue Nov 15 13:22:58 2011 -0300
+
+ Fix session_request buffer size when using dynamic memory
+
+ If the request is greater than the initial 4KB allocated, Monkey
+ allocate/reallocate space in the main buffer to continue reading
+ the incoming request, but when the buffer is full it was writing
+ a NULL byte outside of the buffer size, issue detected with
+ valgrind:
+
+ ==25232== Invalid write of size 1
+ ==25232== at 0x4045AE: mk_handler_read (mk_request.c:602)
+ ==25232== by 0x40A3AC: mk_conn_read (mk_connection.c:64)
+ ==25232== by 0x40886E: mk_epoll_init (mk_epoll.c:98)
+ ==25232== by 0x408E4E: mk_sched_launch_worker_loop (mk_scheduler.c:196)
+ ==25232== by 0x503AEFB: start_thread (pthread_create.c:304)
+ ==25232== by 0x533189C: clone (clone.S:112)
+
+ This patch add one extra byte to the buffer size.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8b04e9377769835ee96a09cf8d027ac0b75b0d96
+Author: hio_ <trustthesky@gmail.com>
+Date: Tue Nov 8 17:20:47 2011 -0300
+
+ Fix unitialized mk_pointer passed to string builder
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9dddd9b5c31ad34828fac1d2061daf204b1f4c96
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 8 11:49:26 2011 -0300
+
+ Fix trace messages
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0b1eb127830ac5ae90e14c3a839b2a93f93c8e55
+Merge: 8b55d76 c83ee4d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 8 11:23:22 2011 -0300
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+ Conflicts:
+ plugins/liana/liana.c
+
+commit 8b55d769beba5dafd29f2a7bb002fe80d5b94182
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 8 11:19:29 2011 -0300
+
+ Server: check server load versus capacity
+
+ Now monkey checks the server load when a new connection arrives,
+ if this connection reach the limit of the current capacity, the
+ socket will be closed.
+
+ This patch also fix a trace messages.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2a80e9f245a71a22bc08fa7e71b859df9951fc17
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 8 10:40:17 2011 -0300
+
+ Liana: do not print error when socket is unavailable
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit be830e0f8a4c5a53ba29abf1792247f81335b8ed
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 8 10:31:00 2011 -0300
+
+ Scheduler: do not print warning message on error handler
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c83ee4d9bbe9bcc4bebac37eb8c72595fbbd5496
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Sat Nov 5 11:54:24 2011 -0300
+
+ Liana_ipv6: Fix typo
+
+commit afb799408661ccb68a89157c84edb7a0ee4c559d
+Merge: bab5f54 c990a23
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Sat Nov 5 10:42:23 2011 -0300
+
+ Merge branch 'master' of ssh://monkey-project.com/srv/git/monkey
+
+commit bab5f5455b782fb3f2f1c453ee68b68fee499a66
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Sat Nov 5 10:42:02 2011 -0300
+
+ Liana_ssl: set ip buffer to zero
+
+commit c990a239aff0b90852554d5a24e6017ceba5311f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Nov 4 22:52:06 2011 -0300
+
+ Liana: set IP buffer to zero
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit bae55109d52fc3aa4c28eeb587b4e731d7518bfa
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Nov 4 22:51:48 2011 -0300
+
+ Websockets: force payload size
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 11fc3723601ebc0fcada915440d436925829e8b3
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Nov 4 18:45:21 2011 -0300
+
+ Liana, Liana_ssl, Liana_ipv6: free the memory for the ip text from if it returns null
+
+commit bec53b2586f621fc937b957c080e8d0f33edc2f9
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Nov 4 10:16:44 2011 -0300
+
+ Liana_ssl Fix plugin to match the new network layer model
+
+commit b4dd7ce18a1d73fd74f77aa9a974bc6ba0f2f515
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Nov 4 10:15:48 2011 -0300
+
+ Liana: Fix some arguments problem in _mkp_network_io_accept()
+
+commit 744bbd269cd4a0f288b5721a8cba2d2e00108fdc
+Merge: 3fcd8d3 801f773
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Nov 4 09:50:01 2011 -0300
+
+ Merge branch 'master' of ssh://monkey-project.com/srv/git/monkey
+
+commit 3fcd8d30bd498a2d3cf7d0a5bab507f4655e2fb4
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Nov 4 09:46:43 2011 -0300
+
+ Liana: Fix bug remained of the latest network layer fixes
+
+commit 801f7737dbf823b56896a3245144d8d0821b2fda
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Nov 3 23:36:44 2011 -0300
+
+ WebSockets: Initial plugin import
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 138f68e2aeb622a7c3a55f16ac593e3c08b30349
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Nov 3 22:44:21 2011 -0300
+
+ v0.30 begins
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 629602272f8b8efd5f216d0cc8932e1bb0644a27
+Merge: e7f3036 ad2f90a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Nov 3 22:43:31 2011 -0300
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit e7f303637bed20f33d66e9898755c3182cd42870
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Nov 3 22:43:04 2011 -0300
+
+ Session Request: add new connection field to the response header
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ad2f90a2bdc0b175398ff5ddb327973e4dd69e0a
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Nov 2 22:07:44 2011 -0300
+
+ Logger: Use of the new function socket_ip_str() provided by the API to obtain the text form of the IP address.
+ Mandril: Obtain the in_addr from the socket to use it. This propose some new issues like, should our network layer provide more info necessary for plugins like Mandril?
+ Palm: Use of the new function socket_ip_str() provided by the API to obtain the text from of the IP address.
+
+commit 3aab2cd6fc82c33bbf4a18cd06d308f308fa1790
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Nov 2 22:02:51 2011 -0300
+
+ Removed ipv4 element from struct sched_connections.
+ Removed ipv4 element from struct client_session.
+
+commit 53ab1b86e5e9a8ddcc74d922325943480dcc8c3a
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Nov 2 21:54:30 2011 -0300
+
+ Added new function to the network layer: mk_socket_ip_str(), for now this function will replace mk_socket_get_ip() but in the future it may be renamed to mk_socket_get_ip_str().
+ Removed the old mk_socket_get_ip() to prove that no one use it.
+ Removed the argument of type sockaddr and sockaddr_in in a few functions because they were unnecessary.
+ Match new arguments in mk_server.c
+ Liana: Added new function _mkp_network_io_ip_str() to provide the new required function.
+ Liana: Clean all the functions that use arguments of type sockaddr and sockaddr_in to match new arguments.
+ Liana_ipv6: Clean up of the code and removed some comment lines.
+ Liana_ipv6: Added new function _mkp_newtwork_io_ip_str() to provide the new required function.
+ Liana_ipv6: Clean all the funtions that use arguments of type sockaddr and sockaddr_in to match new arguments.
+
+commit d97ff6ab7fddc0cae88dd26c318365735e07c948
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Nov 2 21:46:27 2011 -0300
+
+ Liana_ipv6: Fixed name of the so object
+
+commit aa57e510f28e695ac6a6d045ea49f65a4f93ce6f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 31 18:30:12 2011 -0300
+
+ Monkey API Manpage (draft)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ecdd29f441d6fec9ccc957cf1ef1173695770fb2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 31 18:17:41 2011 -0300
+
+ mk_header_get() now use different parameters
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e05ff7883af0b57e33e7c3af23f913b0e29cbea5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 31 13:02:57 2011 -0300
+
+ Core/API: now support custom response status
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8752906e72caf9c73472fe59a341cd00e8106263
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 30 14:52:20 2011 -0300
+
+ STAGE_30 plugins now can handle requests with unknown HTTP methods
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 33e546f4d5bed08279bf3aa2bafa9b2f8b9ed44a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 30 13:54:34 2011 -0300
+
+ Listen for PUT and DELETE methods
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 98ffb705b7489d7fbd158ed01914496e7082294b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 26 14:13:32 2011 -0300
+
+ Lists: fix mk_list_entry_next() macro
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 00fd080e47bd817a072311fdc946e951dedfba18
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 21 13:31:40 2011 -0300
+
+ Monkey 0.21.0
+
+commit 78b750df798539a31ef36685857d3f44c68e8744
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Oct 20 20:26:06 2011 -0300
+
+ Liana_ipv6: Removed DISABLED since we don't need it but we want to aim users to use it
+
+commit 58d23d4ad3cc68fa613edd6eabf27b8ada41696e
+Merge: 667fc70 9a0289d
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Oct 20 20:18:55 2011 -0300
+
+ Merge branch 'master' of ssh://monkey-project.com/srv/git/monkey
+
+commit 667fc70afcb8791db3876dda79a65903c7d1a4a2
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Oct 20 20:17:55 2011 -0300
+
+ Liana_ipv6: New plugin to support IPv6, very experimental but it can be used!
+
+commit 9a0289d86d33a9684e871ca7f5b1ce84f2a3df5f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 14 08:37:38 2011 -0300
+
+ Fix compiling issues
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a72cea2c143de4fdb4c6d97e2676f0fa96104abf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 12 17:39:32 2011 -0300
+
+ Monkey 0.20.3
+
+commit 8014c83141c5cb9e6091b78571ab934473123bdc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 12 17:15:06 2011 -0300
+
+ Debian: Add manpage
+ Debian: Fix changelog
+ Debian: Fix copyright
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1862e52d967ceb173fa1915dac994836981da3c4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 12 14:52:52 2011 -0300
+
+ update to v0.20.3
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2026084af05646f8ffbad0795a6b354dc7395c75
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 12 14:47:32 2011 -0300
+
+ Debian: add monkey init script
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit bc3831ae4bfa5f3157ef6d1f398a4d60ebff704f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 12 14:40:19 2011 -0300
+
+ Liana_SSL: auto-unload if the plugin is not being used as transport layer
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d92ff319d01da216db2ad477d8370cc351166de0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 12 12:33:23 2011 -0300
+
+ Debian: add liana_ssl
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f938511e822140ee3887ba96e1edf99737bf7721
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 11 23:27:27 2011 -0300
+
+ Debian: cleanup
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 94b3ddaab676ae8092295b24a1464863b8ccc606
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 11 23:26:14 2011 -0300
+
+ Debian: add debian build script
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7cb548202932581834a7ba1710652d30ae537e63
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 11 23:21:10 2011 -0300
+
+ Add Debian rules
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 511b95b91bb9ea65c9edb18972bf59d9e64adbf5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 10 20:48:26 2011 -0300
+
+ Monkey 0.20.2
+
+commit 5d4d8f87ba456706aeb9b2bf3f801f84bd979299
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Oct 8 21:56:43 2011 -0300
+
+ Dirlisting: reduce one malloc and validate headers return
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9950abe71bce2750c41cb9e829b18a81a1e34f90
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Oct 6 10:02:22 2011 -0300
+
+ Logger: Redirect stderr to master log when going into background mode
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6ac8ca050490f2f427ae9ee5a4fcff452228cf3c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Oct 6 01:20:11 2011 -0300
+
+ Logger: improve fake consumer
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ff70e0ce84f9b5add3bb7e4bcd961357bc027e1d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 5 21:25:44 2011 -0300
+
+ Logger: consume pipe end if cannot write to log file when the buffer is full
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 590725131767ff0160ec937c7a2d1df053379910
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 5 19:52:56 2011 -0300
+
+ Fix #80: Detect non-writable logfiles for logger plugin
+
+ This patch does the following:
+
+ - If master log file was defined and Monkey goes into background
+ mode, the target file *must* be writable. Otherwise Monkey will
+ exit.
+ - Master log now is enabled by default.
+ - Fix mk_print(), now it flush() the stdout.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f4b290f856eebfc27a6085504c9f5b7b3c559e6d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 5 19:10:37 2011 -0300
+
+ Update configure to v0.20.2
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0dfdf9d5605cdd76ba7783413c97e165f912fb84
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 5 19:09:34 2011 -0300
+
+ Fi #78: Error in the balancing between workers
+
+ This patch makes the scheduler to increment the sched node counter
+ after the socket is added to the thread worker through mk_epoll_add().
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8e283a0a6616866c503c4654327a45c320fc319c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 3 09:55:57 2011 -0300
+
+ Monkey 0.20.1
+
+commit e7822845c0eb2f4bb7276d21f95ad5bafc30c795
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 3 09:49:06 2011 -0300
+
+ Fix #75: Handle DT_UNKNOWN in struct dirent *ent->d_type. by Gatling
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit bb0bf026cc2aecf99309fef0b25b8d1e440b7a05
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 2 23:49:10 2011 -0300
+
+ Fix #74: chunked encoding in dirlisting is broken
+
+ When HTTP/1.1 was used, dirlisting was counting the ending CRLF as
+ part of the chunk length. This patch set's the proper chunk length
+ and add the ending CRLF after set the chunk data.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7a86a147021523d9c867c77f15b0467d93c8e699
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 2 15:16:32 2011 -0300
+
+ Dirlisting: use API mem_free instead of mk_mem_free()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5396125684ec6381ac53e2625b004e01d19867d8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 2 12:08:37 2011 -0300
+
+ Fix #76: dirlisting returns nothing for HTTP/1.0 request
+
+ When creating an 'iov' with mk_iov_create() and using an offset,
+ the entries before the offset index were not set to len=0 and
+ buf=NULL. This patch fix that issue and makes the dirlisting
+ plugin work as expected.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c265bb057482e39eab74646c8259615430efd0ca
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 2 09:42:23 2011 -0300
+
+ Fix ticket #77: 100% CPU usage after having broken connection
+
+ When sending a static file content fails due to a broken
+ connection, mk_http_send_file() now returns EXIT_ABORT to finalize
+ the client session.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5a3a09aa1660f0c34418ccba828c9199418f09b0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Oct 1 01:38:19 2011 -0300
+
+ Monkey 0.20.0
+
+commit 05e5cb8fa4f1719d694c50c5f0af5c1bab954588
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Oct 1 01:32:39 2011 -0300
+
+ Palm: improve buffer proxy handler
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit bbb2646a87db8356f26dd57406c40a795ea20c33
+Merge: c0a4669 6fc7ae1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Sep 15 23:04:04 2011 -0300
+
+ Liana_ssl: fix merge conflict
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c0a466945b0601675b0eddf416a8563155166bed
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Sep 15 23:00:34 2011 -0300
+
+ Update favicon
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 10c3eb27f4f9719c030419fa7cef0b0d09815c0f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Sep 15 22:59:04 2011 -0300
+
+ Epoll: use level triggered mode
+ Palm : use epoll level triggered mode
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6fc7ae1e80a11417b3c8cf3c20578907113126b6
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sun Sep 11 16:40:26 2011 -0300
+
+ introduce ARRAY_SIZE macro
+
+ Compute the amount of elements in an array with this.
+
+commit 08d915cdc61e44713ff4f0ccfbfe967632414d13
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Wed Sep 7 12:10:12 2011 -0300
+
+ unlink: check syscall return status
+
+ This allows to unmask bugs.
+
+commit d63e174440d4a0252979c8addf373ab4909bec46
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Tue Sep 6 12:29:12 2011 -0300
+
+ fix use before init
+
+ When changing the process' user, we are setting resource limits with unitialized values, thus producing an error when calling setrlimit(2).
+ We need to first get the limits, then reset them with the current = max value changes. This patch also does some trivial function refactoring.
+
+commit abe748dd12da0475c760ecf30c9208339af5186f
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sat Sep 3 13:02:41 2011 -0300
+
+ remove file boolean values
+
+ There's absolutely no reason to have specific true/false values for file specific operations. Simply use those defined in mk_macros.
+
+commit 0e04224b855b24c5508d7378c174be1c195c5eff
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sat Sep 3 12:57:19 2011 -0300
+
+ correct time
+
+ The month member of the tm structure (broken down by localtime()) uses the [0, 11] range. We need to add
+ one to this variable, otherwise incorrect dates will appear:
+
+ dave@offbook:~/projects/monkey-dev$ date
+ Wed Aug 31 02:40:01 CLST 2011
+ dave@offbook:~/projects/monkey-dev$ bin/monkey
+ Monkey HTTP Daemon 0.20.0
+ Built : Aug 31 2011 00:05:39 (gcc 4.5.2)
+ Home : http://www.monkey-project.com
+ * Process ID is 9900
+ * Server socket listening on Port 2001
+ * 5 threads, 101 client connections per thread, total 505
+ * Transport layer by liana in http mode
+ [2011/07/31 02:40:10] [ Info] HTTP Server started
+ ^^
+
+commit bbfe65f3e0fa6fdfda96d06b21963bb6910405ff
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Mon Aug 22 16:00:29 2011 -0300
+
+ Liana_ssl: Added MATRIX_HEADERS to the Makefile.in file, and removed MATRIX_LIBS from the objects line
+
+commit fb8e8b153fac54fca73dbcdfafc367354cf29ac0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 20 17:15:03 2011 -0400
+
+ Add missing headers: mk_socket, mk_signals, mk_server
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6759f328634c1eb20bcd619524798f0e1baa82ca
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 20 17:12:46 2011 -0400
+
+ Add missing mk_string.h
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8f03c0b52cc2aa9394b5fdd72997db56c3584af9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 20 17:12:17 2011 -0400
+
+ Fix chunk size
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 805aff2c3dc19f3f5b571bfb0e405ac1d214e655
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 20 15:50:05 2011 -0400
+
+ Palm: do not use chunked transfer encoding on redirection status
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0a73bb565e5861a3d16e590955c4c62ed849eff6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 20 15:27:01 2011 -0400
+
+ Epoll: always process EPOLLIN or EPOLLOUT before EPOLLERR/EPOLLHUP
+ Scheduler: on remove client, always close remote file descriptor
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1f3ae21ddecd675cd16c330d6e032781692e22e1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 19 21:46:52 2011 -0400
+
+ Fix inclusion header in mk_utils.h
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit df265fc456905e9dae15366307db60053863dcd5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 19 21:44:21 2011 -0400
+
+ Prefix source code files and headers with 'mk_'
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cd8fad5a5eeabf0f51894f2ab498eee12e638955
+Merge: 0db9f4e 3a7a69b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 19 20:29:42 2011 -0400
+
+ Merge branch 'sched_add_event'
+
+commit 3a7a69bd940fd4432e0214edcb77e6a3205deaf6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 19 20:29:30 2011 -0400
+
+ rename limits.h to mk_limits.h
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 202e2077b4861deac779a9631f4f0778f3480ee0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 19 20:28:48 2011 -0400
+
+ New sched add event core
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0db9f4e6417ac2b0cdad307b21bc6c374b5a24ff
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jul 23 13:00:18 2011 -0400
+
+ Rename limits.h to mk_limits.h
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 49e73b5fc5406dc19ae3be3e16ad9bbb6f9a36b7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 30 16:11:21 2011 -0400
+
+ New cycle: v0.20.0 - Maduro frito con queso
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a72f658121900f75fc8e948e6d57903a1dff0392
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 30 13:58:51 2011 -0400
+
+ mconf: add index.php to Indexfile by default
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit bb23d5f67b2c6da2f214287b319260fb9d35e015
+Author: Christian Stankowic <info@stankowic-development.net>
+Date: Thu Jun 30 08:56:24 2011 -0400
+
+ Banana: add missing 'status' command in help output
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8bdbcc5009c4ecda0ae60089943a5a233a83f6be
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 29 08:51:12 2011 -0400
+
+ Banana: add missing status command
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8042b2a807fec6771e1209b78c64a5ca832ea150
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 29 08:46:49 2011 -0400
+
+ Configure: add missing changes for banana script
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 34806c72b0e9a1ac310a0edd66e31829516b3714
+Author: Christian Stankowic <info@stankowic-development.net>
+Date: Wed Jun 29 08:42:15 2011 -0400
+
+ Configure: deprecate old cgi-bin stuff
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit af6230e1c64b5250eb7a00211b6cd75b1e85f789
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 29 08:33:39 2011 -0400
+
+ Palm: use new IP mechanism
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d6fce0889a3158dc4ba412b642a25738d7dfd1d9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 27 12:15:48 2011 -0400
+
+ Core: use epoll LEVEL_TRIGGERED mode
+
+ Monkey events handler was using the EDGE_TRIGGERED (EPOLLET) for the
+ sockets file descriptors, also doing an unnecessary ioctl() to FIONREAD,
+ this was causing an extra load which can be avoided with LEVEL_TRIGGERED
+ and doing some better handling of buffers to read() incoming data.
+
+ This patch also fix an unset new_size counter when reallocating the read
+ buffer.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3dcf0ed8c84d0c4e2bc26ce01188d84b1f9498cf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 26 23:09:48 2011 -0400
+
+ Auth/mkpasswd: fix password store when adding new users
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 60bff1488422cfe843213f74c4c3afa2cdb249f3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 26 13:10:18 2011 -0400
+
+ Exit properly when TransportLayer is not defined
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5f63717867ab301f47421492da575bf4aa2ba530
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 26 12:46:37 2011 -0400
+
+ Liana_SSL: memory copy of confdir parameter
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 177ff1a29afb90b234e9d5950b328167a7bf78ea
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 26 12:43:03 2011 -0400
+
+ Liana_SSL: fix liana_conf() parameter
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 297b2a7050e09aa0f7261d6f9b17ec74efc6d867
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 26 12:41:26 2011 -0400
+
+ Liana_SSL: main setup now is done in _mkp_core_prctx() hook
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 473b1db4542d351b6ed6af14c25230d9770ab57d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 26 12:03:07 2011 -0400
+
+ New TransportLayer directive in monkey.conf
+
+ This new directive provides to each [SERVER] section the capability to
+ define which transport layer the core server will use. The value of the
+ key is the shortname of one of the network I/O plugin defined in the
+ configuration file plugins.load.
+
+ Please check the following example for the file monkey.conf:
+
+ To provide just HTTP use:
+
+ TransportLayer liana
+
+ To provide SSL over HTTP (https):
+
+ TransportLayer liana_ssl
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 304e89e44c3a3505445ede1447cc56defd686bc5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 25 11:47:51 2011 -0400
+
+ Cheetah: add active connections to worker command
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fbdc9edf1cbeaa1a004001117a71eb57f620b031
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 25 09:28:43 2011 -0400
+
+ Logger: format IP address from network address in_addr
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 196e77cf51c8a05deefd65e6d822527700b997b4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 25 09:16:02 2011 -0400
+
+ Scheduler: do not bug_on when sched_node is NULL (premature close)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 204e503dec5928b748e2c75184d7300b9b65d847
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 25 09:14:40 2011 -0400
+
+ Mandril: validate IP with new Monkey scheduler info 'in_addr' data
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f191d6502d1ea91fc9f08a1cb8e0f874069d5f32
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jun 24 23:44:20 2011 -0400
+
+ Scheduler: store in_addr info instead of IPv4 string
+
+ When a connection arrives, the scheduler assign the new connection
+ to a sched node which hold information about the connection. Previous
+ this patch, it used to store the IP address in a common string, now
+ we just store the data in 'struct in_addr' format.
+
+ This also reduce the memory used by Monkey as the previous model holds
+ in memory buffers for each possible incomming network address. The
+ memory usage is reduced in about 20KB.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 37d91ae6b85a8f37d94f6c08fca3215f2ac2363a
+Author: Felipe Astroza <felipe@astroza.cl>
+Date: Fri Jun 24 22:29:06 2011 -0400
+
+ [PATCH] mk_sched_add_client() does not increment active_connections. Issue solved
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4dc835695c2afc587082f7df24e14d958172b9de
+Author: Felipe Astroza <felipe@astroza.cl>
+Date: Fri Jun 24 21:36:00 2011 -0400
+
+ [PATCH] Useless mutex in mk_sched_launch_thread() deleted.
+
+ A more convenient use for mk_sched_register_thread() to avoid search the thinfo structure in sched_list.
+ Memory leak in mk_sched_launch_thread() fixed.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 46b0505de7de3ecd2d873529f4af5c31675bc6c3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jun 24 12:26:51 2011 -0400
+
+ Mandril: new rules model
+
+ Now mandril plugin restrict IP address by specific ip or through
+ a defined subnet, the new configuration model looks like:
+
+ [RULES]
+ Deny_IP 10.20.1.27
+ Deny_IP 192.168.1.0/24
+ Deny_URL /imgs
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 133d40a60ab0368daff5213113d3c7c4b29f3ca4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 22 08:24:41 2011 -0400
+
+ Update TODO List
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 348ec85e1e0b027e8423957902962b66685c232f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 20 16:31:54 2011 -0400
+
+ Liana_SSL: New version 0.2, view full log for details
+ Liana_SSL: New Makefile macros MATRIX_LIBS and MATRIX_HEADERS
+ Liana_SSL: Validate MatrixSSL version, requires >= 3.2.0
+ Liana_SSL: Extra validation messages for certificate
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a59dd35394d168897f3456da1534fd4c2c6b6422
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 20 12:40:43 2011 -0400
+
+ Rename macro unlikely to mk_unlikely
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f72b9bda71acb7e3fa2e75e6200eecc15eddf76d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 20 10:42:16 2011 -0400
+
+ Liana_SSL: Fix Makefile.in to avoid recompile if objects have not changed
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d003ab6784bf455f1ab3a51a82ff05776c38120d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jun 17 14:46:54 2011 -0400
+
+ Palm: Fix Makefile.in to avoid recompile if objects have not changed
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f71044a942b560ff8665f68ce304cb9f86476f70
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jun 17 14:44:19 2011 -0400
+
+ Auth: Fix Makefile.in to avoid recompile if objects have not changed
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0aba529d1ec25a2d4d1d875625c400e0bd029125
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jun 17 09:51:10 2011 -0400
+
+ Config: deprecate strtok_*()
+ Config: EXIT_FAILURE on error
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 724a3215439fcc51d7a1fa005ed4fab97acc3cce
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 16 23:22:00 2011 -0400
+
+ Plugin: just validate network plugin in TRACE mode
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1696e4afa7b676a576ac088b70219182347424f2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 16 17:50:40 2011 -0400
+
+ Configure: fix patch level grr
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7b2d28c4ca9140894767d0349b5650ba3f32a359
+Author: Jacques-D. Piguet <Jacques.Piguet@bluewin.ch>
+Date: Thu Jun 16 17:48:03 2011 -0400
+
+ Banana: get port and pid file from the config file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f0a324df97edcc4ae78910a8b0ff2f8040ea5b09
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 15 22:41:50 2011 -0400
+
+ Daemon/Setuid: fix umask for files and seteuid undo routine
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 777624a0a9dedba70cbf9f80b10d425a52b86f4a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 15 17:27:21 2011 -0400
+
+ Configure: just 'install' command strip binaries
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 39a2a5763f381abb4b992725ec8f1c6803e27cd3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 15 08:27:23 2011 -0400
+
+ Fix Background mode: parent exit with EXIT_SUCCESS
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cacc5bf3b272dfbbcb1293d321b373c0fbd70250
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 14 22:31:25 2011 -0400
+
+ file_info: add boolean field is_file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0871673bfdf36ff0c68af786f004c5298c4eb020
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 14 22:27:14 2011 -0400
+
+ Auth: read users credentials and validate on-fly
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d46a7a41c18c53f5887a42a550249b5003f3ba98
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 13 22:50:57 2011 -0400
+
+ Auth: associate locations and users with virtual hosts
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2d8429351d019d8606dd6a0a0ae51cea62f03b8c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 12 22:39:55 2011 -0400
+
+ Auth: initial import
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1a714b5e99fdcad949ae4e9179b9aa3f1b21b84e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 12 13:01:05 2011 -0400
+
+ Palm: move plugin from EXPERIMENTAL to DISABLED
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 10f7def8eb52d80816d441daa24fd313310449b9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 8 23:45:06 2011 -0400
+
+ Palm: Fix CGI headers and better event management
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 35cebc67fe19d5436d5c03c0fa70f23989cb0604
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 16 14:14:02 2011 -0400
+
+ Palm: add ending CRLFCRLF to palm request
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5e53b7014cff6d5c1d023b2c3bf1d4dae57d4acb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 14 08:51:55 2011 -0400
+
+ Liana_SSL: fix usage of api->file_get_info()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3b29ce2ffa807041c56e4eb3511f3e977d781649
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 14 08:31:03 2011 -0400
+
+ Minor messages
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d41967a0e5abba26a95cb790bccae3bbbf608192
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed May 11 17:21:14 2011 -0400
+
+ Palm: add REMOTE_PORT CGI variable
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4b80c14f89dba7f2fd5f5befdd0e8c41c0a6c62d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed May 11 16:44:35 2011 -0400
+
+ Config: export server socket in config struct
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5a7589a8171e548e65c73370048e2f5ecd0b7082
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed May 11 16:43:38 2011 -0400
+
+ Palm: complete CGI headers for palm request
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 284caee49b977dd932b1a63e2926728a29c9d5e8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed May 11 12:51:24 2011 -0400
+
+ Fix host_alias setup
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a651b6b2aa519570bebef426feed2e4d6a1fc850
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 9 23:01:12 2011 -0400
+
+ Palm: new template request
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2c071b07768ed75c53525e9a55d88c54f8e34c10
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 9 11:13:02 2011 -0400
+
+ Fix headers_toc size in session_request struct
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 35074388b8358119e0d565e2bbd18ecfd375161c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 18 14:13:20 2011 -0400
+
+ Do iov_add_entry() inline function
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a877cd3396e1298b80c2b864c77e1ef6c6432b58
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 15 14:11:53 2011 -0400
+
+ Fix some trace messages
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e12a7f8f7951602bd36b1c38b2567ef77ccff9c3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 15 11:43:27 2011 -0400
+
+ Cheetah: fix workers command
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2707c427162cfe651c48490583dd62b2856b66e2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 15 11:33:46 2011 -0400
+
+ Request: reuse session_request on non-keepalive request
+
+ A new static field has been added to client_session struct called
+ sr_fixed, which aims to provide an already allocated space for
+ normal and keep alive request. If the request is NOT pipelined,
+ we are not allocating new memory anymore under the same
+ client_session.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0f11f5b157ad8e0f8abe1ca43456d15ef87e928e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 15 09:18:13 2011 -0400
+
+ Little cleanup
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4452b7bb44f492b8fead0a63ed821c2128f9e2f7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 14 08:12:07 2011 -0400
+
+ Scheduler: export sched node to worker scope through thread_key
+
+ Inside a worker, they are multiple calls to the function
+ mk_sched_get_thread_conf() which returns the sched node associated
+ to the worker in question. Previously this function was matching
+ each scheduler node information with the thread ID, now the
+ function knows the sched node through a thread_key avoiding
+ 'for' cycles and multiple comparissons.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5ddd71421893b317512fad69fe5af2904f95d183
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 13 11:14:05 2011 -0400
+
+ Fix mk_sched_update_conn_status(): search in the whole queue
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 674ff58696c101e9028867b1cee62a0a5e386b9a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 12 19:49:54 2011 -0400
+
+ Optimize headers TOC parser
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit dc05977f9c1c766fd480c2ab0f0ba167a805b22a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 12 10:03:55 2011 -0400
+
+ mk_socket_get_ip() now returns ip string length
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e574070645d9206b942a022989fa232abc7aef57
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 11 06:43:12 2011 -0400
+
+ Scheduler optimization
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a1938b427dad13b90a432924d840349946edc73e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 9 23:55:52 2011 -0400
+
+ Validate return of setsockopt()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit bddacdf81b5b36835e325594c07d4e6af8bf62aa
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 9 23:38:22 2011 -0400
+
+ Server socket now use TCP_DEFER_ACCEPT socket option
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9fd8b15d41cdf1ed3db27c9d670ecae5cb34c45d
+Merge: fb01bca d64c8b7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 7 16:23:19 2011 -0400
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit fb01bca5fe5384827a9b36276d46dc9af76dd7d2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 7 16:21:26 2011 -0400
+
+ Palm: remove unused headers by Monkey
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d64c8b7ccd3c22906e3d3f257c01a57e00e5f044
+Merge: 73b7302 2d408ca
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Apr 7 15:47:52 2011 -0300
+
+ Merge branch 'master' of ssh://monkey-project.com/srv/git/monkey
+
+commit 73b73026cbf380066063c079cc7d1900383fe135
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Apr 7 15:47:45 2011 -0300
+
+ Added macros to calculate sub-net,broadcast and network using the ip address on sock_addr
+
+commit 2d408ca9d59484661975be9aa332cafacd3fc139
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 7 11:54:14 2011 -0400
+
+ Limit hostname aliases length to 64 bytes
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f09a72dd06a031c5faf7e836ea843c582fe0276d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 7 11:46:30 2011 -0400
+
+ Force config hostnames to lowercase
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2fd9dfbfd7a9389d488da02b7a4df9151346e102
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 7 10:31:23 2011 -0400
+
+ Reponse headers now are static allocated inside session_request
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 40bcb02f6dc5acc1abe8e261459e84bc7dc1fd4f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 7 09:04:02 2011 -0400
+
+ New client_session->body_fixed for common small requests
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ad8624255ed1696bab49c2b29d85701bf8705b2d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 7 08:51:37 2011 -0400
+
+ Pass sched node on mk_session_create
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 20c016d61defab73e049fbe520e0fa0f462fe5b4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 7 08:05:19 2011 -0400
+
+ Fix recently introduced overflow when parsing Host header
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6cdca627e934ecb8e3e3b7643b2cf118f3b14be2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 7 07:37:36 2011 -0400
+
+ Just invoke mk_socket_safe_event_write when it has been specified by config
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b5f52730dc9b4b5a9dc539d4d412e72626e0d36d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 7 07:00:32 2011 -0400
+
+ Drop parsing for unused request headers, just keep TOC
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b2fd300fd27f26f0a0bf3ed5788b238f44c92d33
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 6 22:10:03 2011 -0400
+
+ Remove unnecessary calls to mk_pointer_reset
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8963afbaeac4dd10b297ff91e54f45b0d8e26464
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 6 21:52:04 2011 -0400
+
+ When parsing Host header, do not malloc on port field
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7b008db1dab120d0011f652a70bcbeab286047ea
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 6 16:50:38 2011 -0400
+
+ Rewrite of _mk_string_search(): 57% performance gained
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 73550a8535dad2fd9c621939b314ab56b41630af
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 6 11:57:37 2011 -0400
+
+ update debug request blocks
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9979882526b792c6b593bfa2264401ec9750738b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 6 09:51:16 2011 -0400
+
+ QA: Improve keepalive test
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b44e74fc4e5b289b711142a0e9769b0081ad9dda
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 5 12:11:43 2011 -0400
+
+ Do not allow pipelining requets in non-keepalive connections
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 54823ff0c76b060126d2bdc620bf8fd4bff259e1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 5 08:20:47 2011 -0400
+
+ Fix MK_PATH_BASE
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d648dc88b960c3453e36dace0ebf5fb5a1665a75
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 5 08:17:44 2011 -0400
+
+ real_path_static now uses MK_PATH_BASE
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 137abdd187ed82b452c5c1c3bef436e572401f66
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 5 08:01:14 2011 -0400
+
+ session_request: new real_path_static field and new macro MAX_PATH_BASE
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ec9b5a0cb1e04851da1d81ea78e1b8ec9fed5b9a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 5 06:03:23 2011 -0400
+
+ mk_file_get_info() now accept two parameters and return int value.
+
+ the new definition is as follow:
+
+ int mk_file_get_into(const char *path, struct file_info *f_info);
+
+ so the called needs to pass by reference an allocated struct for
+ f_info where the file information will be stored.
+
+ At Monkey core level, this new method reduce one malloc/free in the
+ session_request structure, as the new file_info node is allocated
+ as static and not dynamic as it used to.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4f2fc9f8879bc3721875e78814ecee63bfa2c255
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 4 21:05:34 2011 -0400
+
+ Deprecate mk_string_remove_space()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5fcf77ecaa00ba4e3315d52f3c981cd82962eebe
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 4 14:56:59 2011 -0400
+
+ Liana_SSL: use MK_SOMAXCONN
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1993a7405eba5d44c137dfc9add8ac2cb8f44100
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 4 14:53:34 2011 -0400
+
+ Deprecate mk_utils_get_somaxconn, new macro MK_SOMAXCONN
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 001b55f596cd64957f434e3c96868a6299c5d2f3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 3 21:21:58 2011 -0400
+
+ Re-enable return value MK_PLUGIN_RET_CONTINUE for STAGE_30
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d482f0d4b4cb75aeac24fbdcc97b1240dff5f318
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 31 04:47:56 2011 -0400
+
+ Monkey 0.13.2
+
+commit a1b29ab0129b41d9e53772bcd26d0009a30c3e04
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 30 17:22:38 2011 -0400
+
+ Fix #51: Can't set to non-blocking the socket when compiled with ACCEPT_GENERIC
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d75580bccce6a401d76994532b1ead52524b3473
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 27 14:51:08 2011 -0400
+
+ Mandril: fix bad usage of str_build()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cc0d64f7b6f646c88b9a6fe56eb2fb246d47d68a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 27 14:19:40 2011 -0400
+
+ Cheetah: fix broken Makefile.in
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f3a8aef0da43d53382c39bef4a72bca72052e96b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 27 12:42:31 2011 -0400
+
+ Palm: pass NULL pointer to str_build()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 23d5aa1ba011dba8ee3ba48442664d81a2cc5a0d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 27 12:39:43 2011 -0400
+
+ Palm: deprecate old macros and adapt to new structs
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fc83d7eb7b09cd8b08a02845003bd22faf0c22e2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 19 12:13:51 2011 -0400
+
+ New host_alias field in session_request
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a2ec116fca488fc289052e22754d5b7adf99424f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 12 14:24:48 2011 -0300
+
+ Config: fix minor leak when composing vhost path
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 33085320c8c681271a4e840bd35d51fdda1fc3a7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 12 14:17:07 2011 -0300
+
+ Mimetype: safe configuration free
+
+commit afe26a2fe8bd6c9ed4e54595e423dda85dd662aa
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Mar 10 12:52:58 2011 -0300
+
+ Replace some repetitive code
+
+commit daee575882cbe5f05fdca9597d2804ff8b999ea0
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Mar 9 14:43:07 2011 -0300
+
+ Fix configure script and Makefile.in in all the plugins direcotory to not re-compile every time that we run make command
+
+commit 5058f2355358944db455254c556c618f4ac9f3e1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 9 11:40:24 2011 -0300
+
+ Dirlisting: free finfo check
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit dd15d6df77a29811fe4e033301176736abe01a05
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 9 11:17:53 2011 -0300
+
+ Configure: bold some text
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e0b02a2b7b59b5771a0cc9ce5ad8dc58712e323d
+Merge: 421bbe8 6cb1b54
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 9 11:10:02 2011 -0300
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit 421bbe8ff00fd328d7ce9dab3353e949ad58984a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 9 11:09:11 2011 -0300
+
+ Dirlisting: validate theme path and print error if required
+
+commit d57cf54fc559601239661f4ab3cf718fe171dbde
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 9 10:46:50 2011 -0300
+
+ Plugin: if the plugin fails by it own rules, free configuration memory
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a0823c3b9033b5161eb7719a35547db089c6be51
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 9 10:38:09 2011 -0300
+
+ Dirlisting: fix return values when loading plugin
+
+commit 6cb1b5447a131be54eb16adebff33e23d0951bc0
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Mon Mar 7 15:47:22 2011 -0300
+
+ Added more colors to the configure script. Deleted trailling whitespaces
+
+commit 2d6b5244e6a639a30d7d0233ed01b6524df21b2b
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Mon Mar 7 11:39:39 2011 -0300
+
+ Added a /certs/ directory to the conf directory so it will store the cert in a "secure" place
+
+commit 152cf1139b77f25266b7e67488d5ec88d98b07cb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 7 10:52:17 2011 -0300
+
+ 0.13.2 begins
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 606a99d93b90a359f904cbdaafb880f7ca0a55a5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 7 10:04:44 2011 -0300
+
+ Monkey 0.13.1
+
+commit 5fa744d3e6302465b8b741b15dd3f9effd38d11c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 6 21:43:18 2011 -0300
+
+ Improve some string search with memchr family
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 991d192c72a3669eb3497dcac78af5ee119354a8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 6 19:41:14 2011 -0300
+
+ Query string parser: better performance, restrict lookup to first header
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e249fe85d975c95c1b8ed90d92b1cd1bcd22dd82
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 6 19:28:30 2011 -0300
+
+ Keepalive: split buffer and add to iov
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 19bc524081a4712fc3ffe607df1c79fafb51e61e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 6 15:23:25 2011 -0300
+
+ Faster string_itop(), code based in stringencoders-3.10.3
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d9c22249f77bc2f02743cbee2df85c6ad4167de8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 5 23:47:12 2011 -0300
+
+ Ticket #33: add conf directory to plugins, it also supports all configuration keys
+
+commit 9e4e9da11fe8955fe950d4dd3e7037ecb714fbad
+Merge: 04b0798 64c946e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 5 21:39:25 2011 -0300
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit 64c946ea5c0c32ce9c6c0a471fdaca77631b7b46
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sat Mar 5 01:17:14 2011 -0300
+
+ Exit the program if cannot find (invalid) the server configuration entry
+
+ Signed-off-by: Davidlohr Bueso <dave@gnu.org>
+
+commit 04b07981db9c95cac29f49e1b8109ab581b2d782
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 3 10:55:37 2011 -0300
+
+ KeepAlive improve
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 33d307efc7a62f8a7ac88adb4a114f09c8dda2ca
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Thu Mar 3 01:39:18 2011 -0300
+
+ Use mk_mem_malloc() when allocating memory in mk_string_copy_substr
+
+ Signed-off-by: Davidlohr Bueso <dave@gnu.org>
+
+commit 17563671709103f7917491db40e767bd22ee8dd4
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Thu Mar 3 01:33:43 2011 -0300
+
+ Remove unused MIME constants: MAX_MIMETYPES_NOMBRE, MAX_MIMETYPES_TIPO, MAX_SCRIPT_BIN_PATH
+
+ Signed-off-by: Davidlohr Bueso <dave@gnu.org>
+
+commit 0d086eaddf62c49372fd0d7a899906d3b10cca77
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 3 00:36:42 2011 -0300
+
+ Reduce number of calls to iov_add_entry when sending response headers
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ff99a92eb161231b59c1b42f99be76e3d2fce3c0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 2 23:55:51 2011 -0300
+
+ Change default MaxKeepAliveRequest to 120 and KeepAliveTimeout to 5
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 038834fc7f309ae64472d7100ed3f709e076360c
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Tue Mar 1 01:14:17 2011 -0300
+
+ Get rid of unused mk_string_array_count
+
+ Signed-off-by: Davidlohr Bueso <dave@gnu.org>
+
+commit e7b9bc2484b1d3f0d0a656b0bc8804ff9fee70f0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 28 23:15:37 2011 -0300
+
+ Cheetah: minor fix in config command
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3b1d75b22997c6fb3a9a2bde68187bf6e7476b5d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 28 15:04:57 2011 -0300
+
+ Configure: generate banana script to use right pidfile
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c66ff0c78b12682d261a1001473f507cae0555cd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 28 15:01:50 2011 -0300
+
+ Monkey v0.13.1 begins
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 05895a3c92214450a040fcb594e8e5154db4251b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 27 20:15:16 2011 -0300
+
+ Monkey 0.13.0
+
+commit d70563a95e641964b8692cac241a46620b98c741
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 27 17:34:49 2011 -0300
+
+ New macros for versioning: __MONKEY__, __MONKEY_MINOR__ and __MONKEY_PATCHLEVEL__
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 52cc10c2ff7579f27c9c0365b9bb35ca8b1fd7ab
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 27 13:13:58 2011 -0300
+
+ User directory: new parser and code cleanup
+
+ The user's directory feature has been improved with a new parser,
+ also some unnecesary session request fields has been dropped.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5277ae186f80c695f4b0ebd227a25037fa6b609c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 27 11:20:23 2011 -0300
+
+ Core: sr->uri_processed to mk_pointer
+
+ The session request field 'uri_processed' now is converted to a
+ mk_pointer. Monkey used to calc the string length multiple times
+ along every request cycle, with this little change we avoid that
+ and gain better performance.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit be02800bc2afc8a4179eedc2d70dd8907f05f689
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 27 02:32:06 2011 -0300
+
+ Logger: Improve performance
+
+ Do not use str_itop() to convert integer HTTP status codes,
+ instead use the new static map table for that.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 79bf0282df4d210d00d7214c696e9a615a71668d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 27 01:44:22 2011 -0300
+
+ Configure: improve help command output
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 87441011f08ba0e1287c6ecba227f21699f8b8f3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 27 01:28:54 2011 -0300
+
+ Configure: new option --default-user to override default web user
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d61422efae9a866e9b20ced4fff82ba515526ccb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 26 20:20:49 2011 -0300
+
+ Configure: new option --default-port to override default TCP port
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8e6d45f69f1339505e9e21110a42a228c3b1385a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 26 18:19:57 2011 -0300
+
+ Print message when Monkey goes into background mode
+
+commit f8e688073bace892d03f94a4c5c65fdd9aefb0bb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 26 17:09:43 2011 -0300
+
+ QA: Add keepalive header checker
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c3a2dbbf6e24ca3ec52b475837a96bafd64df477
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 26 16:28:31 2011 -0300
+
+ QA: head_02 test, expect Content-Type
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4c76f0b46d794932240b8b682063467f379fea42
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 26 16:27:04 2011 -0300
+
+ Fix HTTP Method conditional
+
+commit 16cb3fc16306e37ad0ed9332525cca3864cff220
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sat Feb 26 15:28:52 2011 -0300
+
+ Fix the GCC version for which the alloc_size attribute was introduced.
+
+ Reference: http://gcc.gnu.org/gcc-4.3/changes.html
+
+ Signed-off-by: Davidlohr Bueso <dave@gnu.org>
+
+commit fc51aec45ab286f3d029e516265c4b592812f4a5
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sat Feb 26 14:48:59 2011 -0300
+
+ Remove the 'to' parameter from the mk_socket_sendv function, it is
+ not needed, so we can simplify this.
+
+ Signed-off-by: Davidlohr Bueso <dave@gnu.org>
+
+commit 9c6c74a38ec33e2d875fb821835437a6ccd0f5f8
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sat Feb 26 14:05:20 2011 -0300
+
+ Remove MK_SEND_IOV_TO_PIPE constant, no longer used.
+
+ Signed-off-by: Davidlohr Bueso <dave@gnu.org>
+
+commit 3deb3d26990167728374bae05f09dcd9a4dd8249
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sat Feb 26 13:44:21 2011 -0300
+
+ Simplify the mk_iov_send function.
+
+ This patch removes the socket or pipe differentiation that existed
+ in order to use writev(2) or vmsplice(2), which is not implementable
+ because of buffer alignment.
+
+ Signed-off-by: Davidlohr Bueso <dave@gnu.org>
+
+commit 28db1c3aafd4cd0d1f6606e119afb8439fe938ca
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sat Feb 26 13:43:40 2011 -0300
+
+ Update Plugins iov_send API function to reflect changes.
+
+ Signed-off-by: Davidlohr Bueso <dave@gnu.org>
+
+commit d3ea2425a4c9e8a7b75f720dc26ecf7ea04be48f
+Merge: 2f352f3 deac1d9
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Thu Feb 24 16:56:49 2011 -0300
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+commit 2f352f382b46a2f2c28d5095cc3dd4609d927d24
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Thu Feb 24 16:46:14 2011 -0300
+
+ Improve MIME performance lookup
+
+ Currently when searching for MIME types to service, a sequencial search is made, wasting time and calls,
+ specially for the most commonly used types.
+
+ This patch introduces a heuristic which allows two mime lists to exist, one with the most commonly used
+ types (like HTML, CSS, images, etc.), and another with the rest. When servicing a type that is very used, it
+ will continue to do a sequencial search, otherwise we do a binary one.
+
+ Signed-off-by: Davidlohr Bueso <dave@gnu.org>
+
+commit bb17de3fbd73511239741fe9466405bfbaee7795
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Thu Feb 24 16:44:42 2011 -0300
+
+ monkey.mime: Change entry order
+
+ This list is read when the application is started, and there is an immediate performance improvement
+ when leaving the most used MIMEs on top. This patch also removes a duplicate entry.
+
+ Signed-off-by: Davidlohr Bueso <dave@gnu.org>
+
+commit deac1d969592c4f365a836d1195e7748635dbc72
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 24 15:02:27 2011 -0300
+
+ Plugin: continue on error
+
+commit c5ea58289641b09c33650e33b17f5efa6abe7bac
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 21 17:23:45 2011 -0300
+
+ API: deprecate MK_PLUGIN_RET_CONTINUE for STAGE_30
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 55223c532a1644c6e54e4cff240e741c8146b43f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 21 16:55:54 2011 -0300
+
+ API: export header_get()
+
+commit 6774a28f84ddaa8f0d2af4f35a9dcd66ee266826
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 20 18:01:31 2011 -0300
+
+ Add some CSS to error pages
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6df397e7c4d1d92a703e96b47dc8e6b4fd3d7e73
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 20 17:08:05 2011 -0300
+
+ Liana_SSL: Update docs
+
+commit 1bd1f58fb8816a4f8f29fa50b0a056f9d3bb2683
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 20 16:33:32 2011 -0300
+
+ Liana_SSL: Set transport type to MK_TRANSPORT_HTTPS
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 73296caf0ffff8b87414a374c7ae95f72736c158
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 20 16:30:36 2011 -0300
+
+ Add 'transport' field to configuratrion struct.
+
+ This new field defines if the server is working in http or
+ https mode, on that way we can send safe full redirection
+ headers. Values added to macros are:
+
+ MK_TRANSPORT HTTP
+ MK_TRANSPORT HTTPS
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6cb7e8bf6eeeae4ff6b9fc8616ecc85861c3d31c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 20 14:28:23 2011 -0300
+
+ Liana_SSL: Exit with failure when cannot bind the port
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d45b9c1c7e3d187e03b309a1c96bcdda815ef5ad
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 20 14:19:23 2011 -0300
+
+ Exit when networking plugin fails
+
+commit 46c24d65d41be1208dd2a1d2a674b919fc9b35c7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 20 14:17:16 2011 -0300
+
+ Liana_SSL: Fix memory leak
+ Liana_SSL: Exit with failure on error
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit aec4f06fa994484a3f299b6c76d07d46e019e52a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 20 13:45:21 2011 -0300
+
+ Sort headers
+ API: Testing new header_find() function
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 3c7d3bd7420a8cca04a440573e756894258eed69
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 19 15:21:18 2011 -0300
+
+ API: new interface to add extra response header rows api->header_add_row
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0e5e7894a3200e3b239184b2a5afb60cebf70631
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 19 09:33:05 2011 -0300
+
+ Add some validations to response status set
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 93565e73564066ddf581a0dadd09e0b370cd2a20
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 19 08:49:58 2011 -0300
+
+ Fix CRLF for 401 response
+
+commit 57c18be8adc6ebd0973f25498a832bbc1754e140
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 19 08:20:28 2011 -0300
+
+ Add support for all HTTP response headers
+
+ Monkey used to support just the common HTTP response
+ headers, in order to provide a more flexible mechanism for
+ the plugins interface, all HTTP possible responses has been
+ added.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7a9e1151a87b877e51a25448c95bde78ee82ee05
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 18 10:49:38 2011 -0300
+
+ Update JCI email address
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1352faecd7cbcdc1199cc02547fd200a710aba52
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 18 10:46:09 2011 -0300
+
+ Rename HTTP status macros names
+ Rename MK_INF to MK_INFO
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8f5c55071495fcf0e0f2aaeb0b4997153a23eb9d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 17 23:53:18 2011 -0300
+
+ API: do api->error private = api->_error
+
+commit 004c20fb80206643db2c03d714abc30eb10f8a4a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 17 23:48:09 2011 -0300
+
+ Adapt plugins to new message macros
+
+commit c9db5ac9793ccab2b202fe5bc24a00cab81bef53
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 17 17:35:39 2011 -0300
+
+ API: Export direct message macros to plugins
+
+commit 55d5758653395aab195c35e79088e0d89e47da33
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 17 17:06:57 2011 -0300
+
+ Deprecate VAR_ON and VAR_OFF, unify MK_TRUE and MK_FALSE
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ed026d083d1e3e716b108cc9ce3f45813fbe002c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 17 14:35:45 2011 -0300
+
+ Improve performance of mk_pointer_to_buf()
+
+commit bd9a6964fda9130c21de2db34ceb7f054bca9291
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 17 14:17:45 2011 -0300
+
+ Exit when cannot log PID of Monkey
+
+commit 8935b95279c46930d3ebc87db2e360a1a7db81ec
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 17 14:08:13 2011 -0300
+
+ Improve setrlimit() messages
+
+commit 6872eaa7ebcf24edc8e98345c78f253b4d79091f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 17 09:44:43 2011 -0300
+
+ Replace gmtime() by reentrant version gmtime_r() and use thread key for cache
+
+commit 9260c8fe69310e9c46ee667912f7d4ac83901174
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 17 09:14:00 2011 -0300
+
+ Fix: send Content-Length header for HEAD method requests
+ QA: Add script to check that content-length header is sent when the HEAD
+ method is used
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4170b0e4ead37b020fb993d9740be5e92ff1fd4c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 16 17:36:11 2011 -0300
+
+ Dirlisting: pass NULL pointers when creating string buffers
+
+commit 365426b678902bc969d18591405892a1a43fbfdb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 16 16:49:01 2011 -0300
+
+ Exit with error if monkey.conf cannot be loaded
+
+commit eaab8459086ee2c2f9b383f1e380b6d1fef3ba4e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 16 16:45:02 2011 -0300
+
+ Exit with error if plugins.load cannot be loaded
+
+commit a40cbe8280567d7c49903e747fbc8ecc34033516
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 16 16:40:24 2011 -0300
+
+ Plugin core: more error checks
+
+commit ea3f0a6c7035a24c205168ada4e7e7c736d64337
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 16 16:04:47 2011 -0300
+
+ Reset mk_pointer variable for mk_string_build()
+
+commit c6fa207751639d9b20c3b9f7dfc22ad37b84b087
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 16 15:41:17 2011 -0300
+
+ mk_sched_get_connection: do not accept sched = NULL
+
+commit ab3bb3d826bb65ebf6b9838152fe71e86d7354ca
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 16 14:56:30 2011 -0300
+
+ Validate mk_string_build() with mk_bug() and fix some guilties
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8da2050e6d21cb8937d9933e56a3ec86efdf4132
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 16 14:10:44 2011 -0300
+
+ New mk_bug() macro (Kernel BUG_ON macro style)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b89bb6ae6fcc1aabd1ce518436d4e4e38cad09a0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 15 13:56:15 2011 -0300
+
+ Patas: replace wrong call to MK_ERROR_WARNING
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 629983194c8c20a17137842017990c02b2e782cc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 15 13:54:59 2011 -0300
+
+ Patas: remove #ifdef TRACE conditionals
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit dd009a1605eca149eac7860fb56892f50f8eda6c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 15 13:53:01 2011 -0300
+
+ Palm: remove #ifdef TRACE conditionals
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ade3e8a34b05a2a41bc433be0228b7e61904380d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 15 13:49:21 2011 -0300
+
+ Mandril: remove #ifdef TRACE conditionals
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e29132d10a7f1d6e7f3294ae820c811357e28d9e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 15 13:48:38 2011 -0300
+
+ Logger: remove #ifdef TRACE conditionals
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e65bb91cebe33b22d733de60f548c82e36861158
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 15 13:47:26 2011 -0300
+
+ Dirlisting: remove #ifdef TRACE conditionals
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 77b56b599d761af15d7f4cfb31bf5af154ae171e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 15 13:46:12 2011 -0300
+
+ Liana_SSL: remove #ifdef TRACE conditionals
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cca07d5c1d46fc0c65f79684beb4df59e015e372
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 15 13:32:08 2011 -0300
+
+ Create empty MK_TRACE macro when TRACE is not defined in configure
+
+ If TRACE is not defined, now MK_TRACE is set to do {} while(0) , on
+ that way all core code can invoke MK_TRACE() no matters if really
+ exists or not.
+
+ Most of the #ifdef TRACE conditional statements have been removed.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 818f58973349edba7a834cbf5d6460f8902da12b
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Thu Feb 10 17:01:08 2011 -0300
+
+ [PATCH] Update the mconf to reflect pidfile changes, and the TODO file as well
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b2186d54a8c7507e7124531a695bc306e4e16ee6
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Thu Feb 10 11:18:41 2011 -0300
+
+ [PATCH] Remove duplicate headers
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0e5d4f6357b93906e68480734a14e1283be9d8b8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 10 07:51:37 2011 -0300
+
+ Make up signal errors
+
+commit 31e16255147fdb9024f60a06144ee76b09d9d945
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 10 01:47:24 2011 -0300
+
+ Print 'started' info message when running in console
+
+commit 3d47933fee07b15547f3e5888dca9d3703729cea
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 10 01:36:37 2011 -0300
+
+ New macros.h
+
+commit ae20fb91ebf003e854e2e346fd1240daf07a7c8f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 10 01:30:10 2011 -0300
+
+ New macros for messages: mk_err(), mk_warn() and mk_info()
+
+ The new macros works over new mk_print() function (old mk_error).
+
+commit dce25c403ccb56b8862324af3a1cc6383062be57
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 9 16:42:37 2011 -0300
+
+ Little fix in help text
+
+commit 66037324e3fb12439e30a8f0016be7a83fe10ef2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 9 16:04:34 2011 -0300
+
+ Add date and time to error messages
+
+commit a7cfb8f6952aa1373d257fc49806e2d546c65d6c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 9 13:00:14 2011 -0300
+
+ Dirlisting: replace fprintf by mk_error
+
+commit 3b7e05c78ea0d0a552fd9103619fce4a6708c8c0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 9 12:58:34 2011 -0300
+
+ Remove fprintf() calls, replaced by mk_error()
+
+commit 1c7ac52c3c0293d7d44a66648ce798718f81da30
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Wed Feb 9 11:13:45 2011 -0300
+
+ [PATCH 2/2] Fix English for better reading
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 26a816c84c5428c1acb84c7bf0fcf83959f3b774
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Wed Feb 9 11:12:31 2011 -0300
+
+ [PATCH 1/2] Fix English better reading
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 1717a363e125fab1f5251a88cc47a5040fff22e7
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Wed Feb 9 11:10:32 2011 -0300
+
+ [PATCH] Add banana manual page
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 2eaa47df83c387483ad6a8aa27209599ad22645d
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Wed Feb 9 11:06:28 2011 -0300
+
+ [PATCH] This patch does a few things:
+
+ - Adds static (and void argument) to the definition of locally used functions, like mk_details()
+ - Allocates the config global structure after parsing the command line arguments, this avoids an unnecesary mem leak
+ and overall makes things a bit cleaner and more UNIX-style standard.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 15bcbb43e8ec76eb935a4fc023aefbaab816c482
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 9 11:04:24 2011 -0300
+
+ Logger: Comment masterlog conf
+
+commit 60ac2357a70324f820a058830f4faed4d507f688
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 9 10:29:36 2011 -0300
+
+ Logger Plugin: Add new support for MasterLog file
+
+ Now when Monkey runs in daemon mode and per configuration in file
+ logger.conf the key 'MasterLog' is defined, all Monkey STDOUT will
+ be redirected to that file.
+
+commit 143a083101856a797b54ce015204a9f823dbb0f6
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Tue Feb 8 11:13:00 2011 -0300
+
+ [PATCH] When passing an invalid option to monkey we should be returning an EXIT_FAILURE code indicating the wrong status
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 5e42facb3d88c0429c751644b4d538d955606d2b
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Tue Feb 8 11:02:41 2011 -0300
+
+ [PATCH] There is currently a race condition with Monkey's pidfile.
+
+ If two instances of the webserver are started, the pidfile of the
+ first instance will be replaced by the second one.
+
+ This presents an issue, can be avoided having a pidfile for each instance
+ differenciating by port.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d1d8ea61a8463bfdcdaf57cd217e55631932c07e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 8 09:41:25 2011 -0300
+
+ Remove unused config->port
+
+commit 0707bdc15b10fb0440ea145fc204d75742f1b0b1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 7 19:33:07 2011 -0300
+
+ Logger: use mk_list implementation
+
+commit bac9183d6decf4efff701718352334531b038f5d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 7 14:38:50 2011 -0300
+
+ Base plugins now uses VERSION macro when registering
+
+commit b86892c82a2a268ab10a45733ccf77529200f55e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 7 14:27:43 2011 -0300
+
+ Logger: fix default configuration flushtime
+
+commit a9a45f3391d82fc5d106bf5258c8bcc84c2ec85e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 7 12:51:58 2011 -0300
+
+ Configure: add --mandir option
+
+commit 7de7c25c8ee6272e10e264d4b9913fcf567ee57a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 5 14:20:14 2011 -0300
+
+ Update man page and move it to man/ directory
+
+commit 71ee362fc6b3e04ce83be8689dabb639686f477b
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sat Feb 5 14:12:58 2011 -0300
+
+ [PATCH] Add manual page
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4fcf7f84ffa1315e75c6b17c3cc21ba0026c150f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 5 13:59:37 2011 -0300
+
+ Add new options to help list and add documentation url
+
+commit 37372df32ab3e44578f909378961998744ba113f
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sat Feb 5 13:50:42 2011 -0300
+
+ [PATCH] Add support for long options
+ With this patch we can now use --version, --configdir, etc (you get the idea).
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 481129e76dbcab7f325f4ac8fb8a58b03afbf440
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Wed Feb 2 13:52:01 2011 -0300
+
+ [PATCH] make the deaminization function more robust
+
+ Good deamon processes follow certain basic coding rules when being created.
+ This patch attempts to make mk_utils_set_daemon() more robust, making this chimp a bit more evil >:)
+
+ * Call umask: If the deamon process wants to create files it might want to set specific permissions, otherwise
+ the file creation mode (mask) might deny certain permissions.
+
+ * Change the current working directory to "/" (root), which allows the previous working directory to be unmounted.
+
+ All syscalls are exit-error validated, since there is absolutely no point in going on with the program if the deamonization is not well done.
+ This patch also removes some duplicate included headers.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d044f4ead262e22c6345dcbe0e195b3555dfd42c
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Tue Feb 1 14:25:20 2011 -0300
+
+ Declare non-argument functions with void
+
+ It is best practises to declare functions that do not accept parameters with void:
+
+ "int foo(void);" instead of "int foo();"
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit c695177d39cf5ee461a52a776cad33805a38bca7
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Tue Feb 1 14:23:51 2011 -0300
+
+ [PATCH 4/6] TODO: add manpage creation
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7f74e4493b12c22af8bebbac1db05930c6817853
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Tue Feb 1 14:20:50 2011 -0300
+
+ The atoi(3) function is deprecated: The ahttp://www.gnu.org/software/libc/manual/html_mono/libc.html#index-atoi-2567
+ It is recommended to replace it with strtol(3), which detects errors, as opposed to the former. Since strtol returns long,
+ this also modifies the data types of some variables. This however is not a problem, because a long integer fits anywhere an int does.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 711b0e81a258245537f611dbaec76b072fbe7483
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Tue Feb 1 14:17:55 2011 -0300
+
+ The mutex_wait_register mutex is being locked and immediatelly afterwards unlocked, without protecting any code, it can be removed.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 0e9022db6ea698f13c93ee1aad5f009769376735
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Mon Jan 31 16:44:31 2011 -0300
+
+ When using an older version of GCC (3.0), the alloc_size attribute,
+ used in memory, does not exist, producing multiple warnings:
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 8db1a7b59d615a7c123f5bf8b97d403314b71c35
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 31 16:43:51 2011 -0300
+
+ 0.12.3-dev begins
+
+commit c2f58c1c8d89a452ccf20c60005873cc09ffcbac
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jan 29 15:08:51 2011 -0300
+
+ Monkey 0.12.2
+
+commit a1140e918c6f5346cf34ef41550dcdec0a0bbfc6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jan 29 14:14:26 2011 -0300
+
+ Configure: when creating Makefile install rutine, do not install
+ or copy content of plugins which have not been selected
+
+commit a412c1e2799677fd849dde72225d1c341e4eefb3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 27 19:03:30 2011 -0300
+
+ Scheduler: validate memory allocation for IP cache queue
+
+commit c713caa0e8b19d9b9189582768af80fb4742507e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 27 18:51:26 2011 -0300
+
+ Scheduler: validate first list node allocation
+
+commit d70642846f7c3939422e0fdd9cdb3c875844be54
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Jan 27 15:18:51 2011 -0300
+
+ liana_ssl: Moved _mkp_network_io_close before any other function so we don't need to declare anything
+
+commit a3dedd64c1f42527fa45d6426083611fa7302a08
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 27 14:42:54 2011 -0300
+
+ Configure: pass LDFLAGS value to plugins Makefile
+
+commit de363659be3922075afe87ee6b21719b825228d3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 27 14:19:19 2011 -0300
+
+ Add LDFLAGS to plugins Makefile.in files
+
+commit 1b92c08bf11079ea29f6c403ccd67958ff632379
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 27 14:04:25 2011 -0300
+
+ Configure: fix LDFLAGS
+
+commit 9c0bb27d68799fa15fdf328ad4c757f14e49c66b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 26 11:09:18 2011 -0300
+
+ cleanup
+
+commit 8f024a32f56d5062bf4d3bb2755ed44a813755ff
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 21 14:08:55 2011 -0300
+
+ API: deprecate unused NETIP plugin type
+
+commit 48234c1e323ba546f0fd2aa5b7658aade2564890
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 21 13:59:30 2011 -0300
+
+ API: Fix PLUGIN_TRACE() issue
+
+commit e42da8d756f051fc77b582327a295e7ab5a702cd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 20 15:15:28 2011 -0300
+
+ API: revert change
+
+commit dfee6484d5312543bdd2fb027f2a75958220aba0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 20 13:35:55 2011 -0300
+
+ Patas Plugin: include MKPlugin.h instead of old plugin.h
+
+commit 58328f25a07535184ce45bc098aefa66514826ff
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 20 13:32:18 2011 -0300
+
+ API: Fix problem with bad reference in plugin context when some
+ non-principal .c file invokes PLUGIN_TRACE macro.
+
+commit 9a13bcab886b0832ad8279fba27421683e4d496d
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Thu Jan 20 12:43:08 2011 -0300
+
+ [PATCH 2/2] Update the README file to reflect a more general plugin subsystem instead of naming specific ones.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 87d2df94be8d90b6bd2340fd39ff562bc5f68b8a
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Thu Jan 20 12:42:25 2011 -0300
+
+ [PATCH 1/2] update TODO file
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 50b0f09f1e7a54d497db514be3235a4cf5798a80
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 20 12:23:24 2011 -0300
+
+ Add TODO file
+
+commit 8c88f8619bee05339146259dab2db5a932670c66
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 17 13:45:41 2011 -0300
+
+ Remove old chars.h
+
+commit d33369751ac67c709cb5875d2d1ce680eb6b4ff7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 17 13:45:04 2011 -0300
+
+ Monkey 0.12.2-dev begins
+
+commit 8665ac9882df36e91fbcb25e6ce8b7b78eed8714
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 17 13:44:34 2011 -0300
+
+ Rename PutDateUnix to mk_utils_gmt2utime
+
+commit 4f104cf525720684c52870d7aa64be0628ed28ac
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 17 00:57:59 2011 -0300
+
+ Monkey 0.12.1
+
+commit 7f677ddf425ad9e1820725ab35371853d71d0938
+Merge: 6c94b17 7e64c73
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 17 00:55:01 2011 -0300
+
+ Merge branch 'master' of ssh://git.monkey-project.com/srv/git/monkey
+
+ Conflicts:
+ configure
+
+commit 6c94b1723349252929f4291d9cd0e6327657ae18
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 17 00:50:16 2011 -0300
+
+ Upgrade Copyrights to 2011
+
+commit e54d82e0dc952990a8e2ac5df061f7ccf0c7bdcf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 17 00:35:48 2011 -0300
+
+ Rename mk_utils_hexuri_to_ascii to mk_utils_url_decode
+
+commit 6bb7d1c384015bc161ef700722e8981173bb4475
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 17 00:30:22 2011 -0300
+
+ Deprecate silly chars.c
+
+commit 55970889521653578ce654406dafbd839bee5acb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 17 00:27:56 2011 -0300
+
+ Full UTF-8 support
+
+commit 2941363dea23c177f5003fa373ee4990d4c3dcb1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jan 16 23:37:35 2011 -0300
+
+ Dirlisting: Set charset to UTF-8 in Guineo theme
+
+commit 081092a4ce4f7e1dd2ec173e9bb42aca56d5a226
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jan 16 23:31:13 2011 -0300
+
+ Dirlisting: skip broken file entries
+
+commit c482e753a6a8376b3bb1eb089673741833cce516
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jan 16 23:26:38 2011 -0300
+
+ Rewrite hex2int: mk_utils_hex2int()
+
+commit e2f5347024a3deac20cc93ac2d223857eb84421b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 6 19:53:13 2011 -0300
+
+ 0.12.1-dev begins
+
+commit 2aad66df741aee2e88981dc080f7e38f6d4a2f89
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Dec 31 17:44:31 2010 -0300
+
+ Monkey 0.12.0
+
+commit 7e64c73db27368778778f3918abe0bcc7fcb2e50
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Dec 31 17:41:18 2010 -0300
+
+ Monkey 0.12.0
+
+commit 62156adb40ec8853b61d3b40a263dc737d36033e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Dec 31 11:21:59 2010 -0300
+
+ Fix error message for M_SERVER_INTERNAL_ERROR
+
+commit 445d4d6b1b92d7fc58396302810178fd5815ed62
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Dec 31 10:29:15 2010 -0300
+
+ Fix plugin interface for returned values, now plugins can specify
+ some error exception and Monkey will handle it properly
+
+commit 8fbd19a7fe9e16d17d1a05af10321b4f6fea0899
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Dec 31 09:54:26 2010 -0300
+
+ Palm: comment old validation for iov array
+ Core: fix typo messages
+
+commit 65d00f052e8e8c236f61cf8fda237c40cc455f7c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Dec 29 09:14:07 2010 -0300
+
+ Mandril: comment security rules
+
+commit e69245043e9e7d6222a74b4ae91212477caf2e0e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Dec 29 01:28:58 2010 -0300
+
+ Do not crash when mk_plugin_event_get() is invoked from process
+ context due to a STAGE_10 running plugin.
+
+commit c82e65e2789b44a0fffca6cd35dff033f9e90137
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Dec 28 20:59:27 2010 -0300
+
+ Mandril plugin: rename configuration file
+
+commit fba91d428686729d1acbb9df23694a34add93a48
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Dec 28 20:41:10 2010 -0300
+
+ QA: add log rules for error_413_01 and error_413_02
+
+commit 3e1b75a7562809cc04833932eed7327254d32f48
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Dec 18 13:41:45 2010 -0300
+
+ When an experimental plugin is enabled using --enable-plugins in
+ configure script, the plugin entry now is commented in plugins.load.
+
+commit 2f5c892403c36cbb98a7f25548f65c7e4451b51a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Dec 18 13:27:27 2010 -0300
+
+ Patas plugin to EXPERIMENTAL
+
+commit 986bb06101a607ab45d4145e5fb16f0ba1c72f50
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Dec 18 13:27:05 2010 -0300
+
+ Plugins now can be in EXPERIMENTAL stage
+
+commit c65da1f09e1c640bfe4cb224de44c1b7b889376d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 2 18:53:35 2010 -0300
+
+ Liana_SSL: enable safe_event_write flag
+
+commit 36090436a0f67ca541f031a6c21ddd913b078805
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 2 18:52:35 2010 -0300
+
+ New internal safe_event_write flag
+
+commit de68d358cb089a3b03c1ad215bd5af821cf07cae
+Merge: 9140e66 8f0a963
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Dec 2 16:04:56 2010 -0300
+
+ Merge branch 'v0.12.0-dev' of ssh://monkey-project.com/srv/git/monkey into v0.12.0-dev
+
+commit 9140e667ca5639d35b69f3e0236642d84e0a15d4
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Dec 2 16:04:12 2010 -0300
+
+ liana_ssl: Let monkey decide how many times call _mkp_network_io_send_file() to send a file
+
+commit 8f0a9634e723f0283e66b79e7d817e1372468d7b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Dec 1 10:14:37 2010 -0300
+
+ Add new mk_utils_errno_print() for tracing context/API
+ Patas: refactoring stage plugin
+
+commit a80c456fea4fc1c16f722fc6da5dcd05904c7a78
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Thu Nov 25 10:39:52 2010 -0300
+
+ [PATCH] Move mk_worker_spawn() to utils
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f1f3bec9c0f8bd251cb8f9ab0e5515c62b80a0f2
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Tue Nov 23 10:24:11 2010 -0300
+
+ [PATCH] Use static identifier for functions and variables which have local file scope.
+ This optmization reduces the size of the binary file.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 080b696d4f5280b17678240295a390b736067d27
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Mon Nov 22 16:59:57 2010 -0300
+
+ * Use sigaction(2) instead of non trustworthy signal(2)
+
+ * Currently monkey's signal handling mechanism is very open to race conditions because the handler is does not guarantee reentrancy.
+ - Change remove(2) to unlink(2) in mk_utils_remove() to use reentrant functions.
+
+ * Layout basics to implement the configuration reload in SIGHUP, this is the most common scenario for deamonized procs.
+
+ * Avoid until needed handling SIGUSR[N]
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 87f7741020018aa2f9f77b4dd59fe6860f26132f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Nov 18 18:35:23 2010 -0300
+
+ On connection error, pass missing sched node
+
+commit 160fbafdcb76df626d466e950109af95ce4d88e8
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Thu Nov 18 18:15:54 2010 -0300
+
+ We can apply a few optimizations to mk_mem_malloc, mk_mem_malloc_z and mk_mem_realloc:
+ * Since they are called frequently they are good candidates to inline
+ * Use GCC's alloc_size function attribute[1]
+ * When we pass a zero value for the size to a memory allocation function (ie: malloc)
+ it is not an error and should return NULL gracefully [2]
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit fcfb3e7c5cbb0a7ea75af2907b8424d10e20f90e
+Author: Felipe Ortega <felipe@tezeract.org>
+Date: Tue Nov 16 23:58:21 2010 -0300
+
+ Fix #28: Back one directory level
+
+commit 60c85fddf0d31c2d332c8fe95019a3c76a7c82fd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 16 09:36:16 2010 -0300
+
+ Patas Plugin: pre-resolve node/socket details
+ When the plugin read the nodes configuration, now it performs the
+ socket sockaddr allocation on that place, avoiding to do the same
+ process every time when connecting to a node server.
+
+commit 0e8f0b46ffa84c3dc99176e17bb7f595426d716c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 16 09:00:48 2010 -0300
+
+ Replace bzero w/memset
+
+commit 8f2e425c3a88f2ac3d0b6d27d0d233e8cf81a69e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 16 08:58:03 2010 -0300
+
+ Init old http field headers
+
+commit cf943f87e8578777d9815c9e49b233928ed68f44
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 16 08:50:56 2010 -0300
+
+ Ticket #24: Improve TOC headers
+ Now Monkey handles all request HTTP headers in persistent table of content or
+ ToC, this can be accessed from session_request->headers_toc
+
+commit ab9d982b6ef43e9305d9f1ee062ff1290d656154
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 15 15:29:47 2010 -0300
+
+ clean up
+
+commit c35d2eaece4fb4f89a9b666e92c13ac0c9366582
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 15 14:54:02 2010 -0300
+
+ Ticket #22: Load Balancing
+ Now the scheduler determinate the less overhead thread worker and
+ assign the new incoming connection to it.
+
+commit b3c9899f6582aa300a02df4ca8f4bc5ab38b554a
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Mon Nov 15 10:09:58 2010 -0300
+
+ Use _exit(2) instead of exit(2) for signal handlers. The former is a guaranteed-reentrant function.
+ Also replace exit status with proper glibc constant.
+
+commit a43c7054436ac1f4b9bab31369c11d7bd2ae35ad
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 15 09:28:18 2010 -0300
+
+ Patas Plugin: fix doc
+
+commit 67f2c388315efb02959980042845704b446a84f8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 15 07:56:23 2010 -0300
+
+ Patas Plugin: fix head for next target node
+
+commit f37ed8edd744ad5385885ad8a57cfc1416a0acb6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 15 01:30:20 2010 -0300
+
+ Patas Plugin: validate node:port != localhost:port
+
+commit ef6eda30d45d822889e3be737ffdd821716da14a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 15 00:39:03 2010 -0300
+
+ Patas: change nodes default port in configuration
+
+commit 5673d22d6a0955e5691f5c107841bb3aef42c295
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Nov 14 21:57:32 2010 -0300
+
+ New Patas Plugin (proxy reverse)
+
+commit d53f3df27c97c717e5f85ca590b3e4550edf23a2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Nov 14 20:19:21 2010 -0300
+
+ Logger: remove unnecessary trace
+
+commit ca385ec02d4dcc1ccfc64f242ce54cb76c076bc2
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sun Nov 14 02:02:34 2010 -0300
+
+ plugins: Use glibc EXIT_{FAILURE,SUCCESS} constants instead of 0 or 1 values
+ This applies to the monkey plugins.
+
+commit 1fca7bc7c5b8c4a67abfd2d940e2e32b722443ad
+Author: Davidlohr Bueso <dave@gnu.org>
+Date: Sun Nov 14 02:01:27 2010 -0300
+
+ Use glibc EXIT_{FAILURE,SUCCESS} constants instead of 0 or 1 values.
+ This applies to the monkey core (not plugins)
+
+commit a32c2614e64d5e77ddb21a1caaccb412e65f7c88
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Nov 14 02:00:45 2010 -0300
+
+ Remove script_filename var
+
+commit 4540f6b31423a52f2d7a261cae5c955517e96eb9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 8 17:25:23 2010 -0300
+
+ Cheetah: print vhost aliases
+
+commit 7163f64ed4b757d5bdc43e87c4815ea90e5f0d0c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 8 16:28:48 2010 -0300
+
+ Support virtual host aliases
+
+commit 886c6fc6ea7291b242ecafd024d47d569ef8880b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 29 20:24:25 2010 -0300
+
+ liana_ssl: add friendly message when certificate/key cannot be opened
+
+commit 40eb2ed2a843d10e7e6c5cb21e85ae495bf9c0d3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 29 20:15:40 2010 -0300
+
+ fix SOCK_NONBLOCK value
+
+commit 690a795471f122cbbd6c14e96dd6863917d2bd40
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 29 20:11:31 2010 -0300
+
+ liana: fix macro check for accept4()
+
+commit 87670e1468ede6b04bb5e75edf7095b33293bd39
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 29 20:08:05 2010 -0300
+
+ Configure: check for accept4() function, if it does not exists,
+ use the generic accept().
+
+commit bceb8844c7f30063f27eb15674831104d1d2d59c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Oct 28 16:35:01 2010 -0300
+
+ Fix: set non-block to right socket
+
+commit 61e087db4f6e5969134cf455a2396d11ba71e680
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue Oct 26 16:55:15 2010 -0300
+
+ liana_ssl: Added liana_ssl_close() to properly send the alert close to the client
+
+commit ac4377588a26da9bdc40d580b78a523af2476cc2
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue Oct 26 16:16:34 2010 -0300
+
+ liana_ssl: Fix typo
+
+commit 00ccdcb1b9d4ee309d81d17c75824f4e0c6e2399
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue Oct 26 13:31:34 2010 -0300
+
+ If function accept4 isn't defined we use accept and set the socket to O_NONBLOCK using fcntl
+
+commit 484f5ed099bf683e414b96bad2cdd3ab57dbbf9d
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue Oct 26 13:30:37 2010 -0300
+
+ If SOCK_NONBLOCK isn't defined we defined as 00004000
+
+commit dca54fd7164e2327086ea3eb933c7ce9adc03371
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue Oct 26 13:10:19 2010 -0300
+
+ If the user selected android as target platform we disable by default the plugins cheetah, palm and logger
+
+commit 177490bb9e7e0acb8d8dd02ed0aba99d030702ca
+Merge: 0bc2c79 76bf7c5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 26 11:50:21 2010 -0300
+
+ Merge branch 'v0.12.0-dev' of ssh://git.monkey-project.com/srv/git/monkey into v0.12.0-dev
+
+commit 0bc2c79153593489c4fa65a860ee450ff9087b99
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 26 11:49:52 2010 -0300
+
+ Support platform in configuration: generic and android
+
+commit 76bf7c5041c24126ada9ef5993b91354edc00d8c
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue Oct 26 10:34:09 2010 -0300
+
+ If theres' noe EPOLLRDHUP defined we defined. Added pthread.h to scheduler.h and memory.h to clock.h
+
+commit 8db02c6e94a9285f4bd281367d24b0c7fba0bf66
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue Oct 26 10:28:30 2010 -0300
+
+ Use the definition of offsetof in stddef.h if it's not there we define our own
+
+commit 401798351fd73b094aa659b6ef565b5312566868
+Author: Felipe Ortega <felipe@tezeract.org>
+Date: Tue Oct 26 08:12:23 2010 -0300
+
+ [PATCH] Small typo correction in the configure script
+
+commit 87e1a2eecb4846c4a5250b1a3df4960b4778ffd0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 25 15:20:56 2010 -0300
+
+ Fix mandril plugin
+
+commit a32057fea602d7c0040604f90ea87ed1e1f7584b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 25 14:51:36 2010 -0300
+
+ Add validation to epoll_create
+
+commit 30dcd40b90b499c9bc266fe723b0989ff8afb8e2
+Merge: 3de27b6 f092a61
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 25 12:51:06 2010 -0300
+
+ Merge branch 'v0.12.0-dev' of ssh://git.monkey-project.com/srv/git/monkey into v0.12.0-dev
+
+commit 3de27b641628a21e177469753a9c2a98d1f4bf71
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 25 12:49:36 2010 -0300
+
+ Remove unnecessary sysctl.h
+
+commit f092a617f29c47d4c9decc7cbff2649f72e0f1fa
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Mon Oct 25 00:08:57 2010 -0300
+
+ liana_ssl: many changes to the way to handle and store data in buffers. We need work to pass the ab test
+
+commit 91a17b9f1699fb62ba5038566adbc07e001dec67
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 24 23:39:19 2010 -0300
+
+ Fix rules for Cheetah and Liana_ssl
+
+commit 3e7a8c498696d0ff8076d37802fb5c040bcc8309
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Oct 21 16:45:48 2010 -0300
+
+ Dirlisting: use socket api instead of direct calls
+
+commit 801cb1a239ad5785d7d2922712715bcc154123df
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 20 21:16:43 2010 -0300
+
+ Move Security plugin to Mandril
+
+commit f01a287741a8001e13cfd3117bcff976ff0c6b3b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 18 12:56:13 2010 -0300
+
+ Fix help space
+
+commit e4a20da91e96db0b2415b42713d462596acbcf9e
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Mon Oct 18 12:53:32 2010 -0300
+
+ Changed the way to separate the enabled/disable plugins list in the configure command
+
+commit 78e6426e5f484eacb405c7757ebcda0b0feb30be
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 18 12:33:29 2010 -0300
+
+ Improve configure script printing detailed messages
+
+commit 48943420222466391255937a9690c5aa12271c09
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Oct 16 23:40:59 2010 -0300
+
+ Improve KeepAlive checker
+ Palm plugin: rewrite hook _mkp_event_read
+
+commit 231ed4d077526128754f7550dd9f7b141ff0d577
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 15 06:52:48 2010 -0300
+
+ Move plugin event list to mk_list
+
+commit 7dfae55e5c3bfcab4c4840f31aa7bf77d47d19f3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 15 06:26:54 2010 -0300
+
+ Code cleanup and extra validations for plugins
+
+commit 906a658bb64cab30095f6342deb8ca22d07a98b4
+Merge: 548fdc0 025b9d3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 15 05:33:46 2010 -0300
+
+ Merge branch 'v0.12.0-dev' of ssh://git.monkey-project.com/srv/git/monkey into v0.12.0-dev
+
+commit 548fdc06f2444cacb13527a6d49e7fee873c6afc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Oct 14 22:16:44 2010 -0300
+
+ Palm plugin improvements
+
+commit 025b9d3fdb3a3a2ebde31238f0a189e5b94bb6e5
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Oct 14 16:33:34 2010 -0300
+
+ Replaced the use of mk_list_foreach for mk_list_foreach_safe
+
+commit 0d2e7512aa0174a9fc707e9ec32f2a171024f234
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Oct 13 17:25:15 2010 -0300
+
+ Plugin and palm fixes
+
+commit 4b9c99d2a1e5412297e301e05af8d5fc49382bbf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 12 19:37:12 2010 -0300
+
+ Re-enable event_read by plugins in protocol layer
+
+commit 23d180b1953b6c79f5ff105f2bbca1338ddcf43b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 11 14:01:32 2010 -0300
+
+ Remove palm server from monkey sources
+
+commit d41319bb65b6b6e6f48ac303d2ec5a612556446a
+Merge: 612cb2a a7d7dc9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 10 14:37:55 2010 -0300
+
+ Merge branch 'v0.12.0-dev' of ssh://git.monkey-project.com/srv/git/monkey into v0.12.0-dev
+
+commit 612cb2a0bc67a07681980d473819aad9498ba7d6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 10 14:37:11 2010 -0300
+
+ Rename main program
+
+commit ff47bded862c070e8580a5559468880534264672
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 10 14:36:40 2010 -0300
+
+ Palm server: add license
+
+commit 20cb347f3f40b95536c16ebbabea9c31684d5738
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 10 14:34:52 2010 -0300
+
+ new API sched_remove_client()
+
+commit a7d7dc93656f1ff69a260728dcbc293df28a6d9a
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Oct 7 12:23:33 2010 -0400
+
+ liana_ssl: Fixed the return values for _mkp_event_read() to proper follow the new event api
+
+commit ec92758635e0b756e7f6c62bbf402797f9194de1
+Merge: 01c2ec2 388be7c
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Oct 7 12:02:48 2010 -0400
+
+ Merge branch 'v0.12.0-dev' of git://git.monkey-project.com/monkey into v0.12.0-dev
+
+commit 01c2ec2f7da8478977dcbcf74e00d009130ca55b
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Oct 7 12:00:34 2010 -0400
+
+ liana_ssl: Fix _mkp_network_io_writev() to put all the strings inside mk_iov struct and just do one write to the peer
+
+commit 4f2f59b9c78182ea1cd21e4c40ae73ff6388d546
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Oct 6 21:42:43 2010 -0400
+
+ liana_ssl: Fixed _mkp_network_io_send_file() and _mkp_network_io_write() to properly send a binary file
+
+commit 388be7c3f1bef91b4b4ee15cc249f7a674eedc10
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 4 17:16:58 2010 -0400
+
+ Move core errors to mk_error()
+
+commit e2693b182f6610c181fa078c2c54e7613fd4e91e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 4 16:58:32 2010 -0400
+
+ Config error to mk_error()
+
+commit 83a171882f3d4f9484ad2f8c2511cc0823b1182a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 4 16:52:04 2010 -0400
+
+ New error function mk_error()
+
+commit 4503b8c5f52c4f73ca0c4858d68ca5738b9123cd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 1 19:56:02 2010 -0400
+
+ Complete API events/hook interface
+
+commit a150fe18f23fa45ca0f9384f3434aa4081d867b5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 1 18:03:12 2010 -0400
+
+ Read events: fix cascade return values
+
+commit 793199a6cc1c8e5d64809382e54ac3dec50c4a85
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 1 16:57:45 2010 -0400
+
+ New plugin event return types
+
+commit 02319e815dfb980cd2cebabac29f6ce935b2ee58
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 1 15:03:27 2010 -0400
+
+ Fix configure help to 80cols
+
+commit 5c711413f63f7b77b7d0ec255b248605f069c9c2
+Merge: b5a9fd7 81d20ec
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 1 14:56:59 2010 -0400
+
+ Merge branch 'v0.12.0-dev' of ssh://git.monkey-project.com/srv/git/monkey into v0.12.0-dev
+
+commit 81d20ec7654ddbfc5faecbcf9b0c97c815d3d601
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Oct 1 14:56:39 2010 -0400
+
+ Added the options --enable-plugins and --disable-plugins to the help of configure. Indent description string to be in the same column in the help of configure
+
+commit b5a9fd725b6a73cc66f35128709c72436b34ddb4
+Merge: 2786619 b179acf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 1 14:47:22 2010 -0400
+
+ Merge branch 'v0.12.0-dev' of ssh://git.monkey-project.com/srv/git/monkey into v0.12.0-dev
+
+commit b179acfe173fddddfa65de87b0f8e3c1c52ad03f
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Oct 1 13:47:49 2010 -0400
+
+ Added options --enable-plugins and --disable-plugins to the configure script
+
+commit 277fe8f72277230cbac91c9b096a84c8ef39c788
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Oct 1 13:19:10 2010 -0400
+
+ liana_ssl: Added info on how to enable the liana_ssl plugin and test it
+
+commit 3e9b351c331a5646323bbb34464f0970de6cbc68
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Oct 1 12:22:23 2010 -0400
+
+ liana_ssl: Added a check to the cert and key files to know if they exists
+
+commit 278661975f024193309af4ac04a8ce1243428afe
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 1 11:00:25 2010 -0400
+
+ Remove STAGE_15
+
+commit adb65d1381b0b086cf7d3918f1826ec64ca56b8c
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Sep 30 12:14:46 2010 -0400
+
+ Run indent comment to indent the code as it should be
+
+commit 4058507822b23dde09f989a060de0d82bcd95cf8
+Merge: 454daeb 4892adb
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Sep 30 11:12:27 2010 -0400
+
+ Merge of liana_ssl plugin to the main dev branch
+
+commit 4892adb00ff82d33808f51e316511622b131c3bc
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Sep 30 11:08:43 2010 -0400
+
+ Added some error checks and a better way to send files for _mkp_network_io_send_file()
+
+commit 27b0a613b499617adc4009f8aa30e5b391b441d1
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Sep 29 15:39:09 2010 -0400
+
+ Fixed the way to send the mk_iov, now it use _idx to send all the content inside the mk_iov. It should build just one string in the future
+
+commit 454daebb195bbd171466c81f3cc345f6fd8f99d1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Sep 29 15:25:55 2010 -0400
+
+ Safe node removal
+
+commit 9ca1f7eee796458840d1d306cd7c93a4c311deca
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Sep 29 15:21:43 2010 -0400
+
+ [PATCH] Added mk_list_foreach_safe to list.h and used it at request.c
+
+commit b702e19e90e2b2298a96f54179802a0c7f1fe5a1
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Sep 29 15:10:54 2010 -0400
+
+ Added mk_list_foreach_safe to list.h and used it at request.c
+
+commit 896f3cb0c5211ae79cba71561af000a3603437ee
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Sep 29 14:20:12 2010 -0400
+
+ Latest fixed to work with ssl
+
+commit 8304c2535d0d0d8860bf6d66f41ddfb47f62b296
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Sep 29 11:47:06 2010 -0400
+
+ Move the handshake to the _mkp_event_read() if the socket it's already in our ssl list we presume that there were a handhskae before
+
+commit 35ddb964699571a4a79f85896548713b3c7cecc6
+Merge: 9945151 f51207b
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Sep 29 10:48:21 2010 -0400
+
+ Merge branch 'v0.12.0-dev' into liana_ssl
+
+commit 9945151bb204976fc0326ebad9dedc007c675a29
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Sep 29 10:46:01 2010 -0400
+
+ Move the pthread_setspecific to the thread context and create a function to handle the read event
+
+commit f51207b8537a0bf3dad74056d16029801636e6d2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Sep 28 22:55:36 2010 -0400
+
+ Experiment new event hooks model
+
+commit 1c030b3becba91ace8c7a85cd7a19c2c9f8772a9
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue Sep 28 14:20:17 2010 -0400
+
+ Added a pre-capability to send files
+
+commit 3e876511a542c8496eb4f188fd417d186d274c82
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Sep 28 12:49:11 2010 -0400
+
+ Fix SIGTERM and remove unnecessary check
+
+commit 0b5f326747d4f65e3f9db98c022d409891b2e872
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Sep 27 23:27:13 2010 -0400
+
+ Palm Server: fix POST length limitation
+
+commit be3e00af962d22d411a3ae918a57eacdc8235568
+Merge: 6bb7846 db55bae
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Sun Sep 26 11:23:20 2010 -0400
+
+ Merge branch 'v0.12.0-dev' into liana_ssl
+
+commit 6bb7846fc4c6dadcbb62d513fc9053b913f1c955
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Sun Sep 26 11:04:50 2010 -0400
+
+ Changed send for write at handshake process added some trace functions
+
+commit 6049fc715188683ddcf23f6a2e825c6121a7d1f2
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Sun Sep 26 11:03:32 2010 -0400
+
+ Fix local path of liana_ssl certificates
+
+commit db55baee41673afca9f1d2027cc6bf2a5b626a3e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Sep 25 13:59:21 2010 -0400
+
+ Fix palm plugin request list init
+
+commit 47326fdde53d88c4e542238d07b9bdf2c54164aa
+Merge: 8243f09 2a79c12
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Sep 25 13:31:41 2010 -0400
+
+ fix merge
+
+commit 8243f09f55406185dfeff6e1f27c99eb9fcd46ab
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Sep 25 13:30:34 2010 -0400
+
+ fix cheetah conf
+
+commit 5f4120cc6583a2d80c1cce2f52f2a66c4cc671b6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Sep 25 13:18:34 2010 -0400
+
+ Use network plugin when writting response headers
+
+commit 29a17dfa94a64537d0fce46dabdc5c3d75e27981
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Sep 25 13:08:21 2010 -0400
+
+ New STAGE_15
+
+commit c56c76c6bb498ca9133d89ee7e0e370cf596c60b
+Merge: ab674dd 2a79c12
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Sep 23 23:18:24 2010 -0400
+
+ Merge branch 'v0.12.0-dev' into liana_ssl
+
+commit ab674dde6ef93176cb0b18659715f3d720e166bf
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Sep 23 23:17:51 2010 -0400
+
+ Added liana_conf() to read from the configuration file of the plugin the proper path for Cert and Key file
+
+commit 2a79c12f182f2d1bb435b8f562556d4b50aff410
+Author: Eduardo Silva <Eduardo Silva>
+Date: Thu Sep 23 23:03:27 2010 -0400
+
+ Add cheetah conf
+
+commit 3d3b711d3c3dda0f262394dd3784d2e4ceb2f290
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue Sep 21 16:50:52 2010 -0400
+
+ Added disabled file to start this plugin disabled and liana_ssl.h
+
+commit 0e5eda9cfc93a6d66faacff0d5442ab3651e9fb9
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Mon Sep 20 18:45:47 2010 -0400
+
+ Fixed the handshake process
+
+commit b474a1c415ed3fffd1ebf0b12a31e05657dd0cd1
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Mon Sep 20 18:44:26 2010 -0400
+
+ Fixed Makefile.in to properly compile with matrixssl 3.1
+
+commit e7c91da1d6e50a42a0476ef391e6a152469f7900
+Merge: 76ed8bc 7207773
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Sat Sep 18 11:00:13 2010 -0400
+
+ Merge with v0.12.0-dev to get latest changes related to sessions and new manage of request
+
+commit 76ed8bc4ccf020b3cff692b9e1025c38d208fa50
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Sat Sep 18 10:52:38 2010 -0400
+
+ Removed innecesary data from mk_liana_ssl. Start the work to support the new API for matrixssl 3.1
+
+commit 1a1acc3a008f98288e21636166b6777ce475196e
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Sat Sep 18 10:51:33 2010 -0400
+
+ Fix makefile.in to fit with the current matrixssl 3.1 package
+
+commit bdbe5f8f541dcadff9c0082d0aa709996640cbc3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Sep 14 14:50:31 2010 -0400
+
+ Update RPM spec to 0.12.0
+
+commit 720777369255538b674344104afdc80fba1180f8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Sep 4 10:00:38 2010 -0400
+
+ Adapt plugins to new string calls
+
+commit 61b5f28a50bbc1159d2f0b676a47122382ff325a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Sep 4 09:52:17 2010 -0400
+
+ Refactor string functions
+
+commit 7377249a28a084a0ebe170fe37966a6321953b53
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Sep 3 19:33:43 2010 -0400
+
+ Adapt cheetah to new list implementation
+
+commit 379a79cb864fede7a08bf1c15d3d55448c6d60c9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Sep 3 19:20:53 2010 -0400
+
+ Plugin: use new monkey list interface
+
+commit 659b1509aea487f7b6614c0e970fe2bfb4c5868b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 29 20:33:24 2010 -0400
+
+ Palm Plugin: use new list implementation
+
+commit 4d4c98e05c640e53c8f319286c1764e82f9dcdd0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 29 16:19:51 2010 -0400
+
+ QA: fix post_test2.htt wait time
+
+commit e47aee64c80309e658b0795bcc7f2ed8065a0c7b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 29 16:15:13 2010 -0400
+
+ QA: new post_test03.htt - check post timeout/incomplete data
+
+commit 9250551a9b7552b6168f9c0672448d2768174409
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 29 11:18:21 2010 -0400
+
+ Alloc node for premature close
+
+commit 6795a43a53201a9bfd07f0a877a0dbad5e9259d4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 29 10:58:21 2010 -0400
+
+ Minor fixes
+
+commit ab9157ab5b087ab97f8a1faabd2881f25d8a465f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 29 10:47:38 2010 -0400
+
+ Remove validation message
+
+commit 48c1dda1d790479f745780bb038c527643306d08
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 29 10:45:50 2010 -0400
+
+ Security: use new CLIENT_SESSION and SESSION_REQUEST model
+
+commit 99cbb5daf09a903b5b0863930edb94de880ff3e7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 29 10:44:24 2010 -0400
+
+ Palm: use new CLIENT_SESSION and SESSION_REQUEST model
+
+commit 659aa55b801503c9597ced82df62d0efc1fd8111
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 29 10:37:14 2010 -0400
+
+ Logger: use new CLIENT_SESSION and SESSION_REQUEST model
+
+commit 258c1b20089c307f3f1fddda7e8c393e746faf33
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 29 10:36:08 2010 -0400
+
+ Dirlisting: use new CLIENT_SESSION and SESSION_REQUEST model
+
+commit c187696da6ff9e326f02fe6403463493f564cec2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 29 10:31:56 2010 -0400
+
+ Core: new CLIENT_SESSION and SESSION_REQUEST architecture
+
+commit e3c7b98a874b06b3bdf465141683754e46ac32df
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 28 09:19:09 2010 -0400
+
+ request.c: move to new list implementation
+
+commit 65f8675bb4e5fb8895ebfc4a517358f36dda8d66
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 27 20:22:26 2010 -0400
+
+ List: add list_entry_next call
+
+commit 5ae164cfb9b2a72ac2c2f37a4d09d8c757e37d54
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 27 19:42:04 2010 -0400
+
+ List: implement list_entry_first and list_entry_last
+
+commit eeb2a5df3a6589ead6def010efc7a335c7fa83c6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 27 19:35:04 2010 -0400
+
+ scheduler.c: move to new list implementation
+
+commit f0aee1b82ffecba256f178757475269fd3d5b652
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 27 17:12:34 2010 -0400
+
+ mimetype.c: move to new list implementation
+
+commit 0b54dbbf96c640880ef410f437bd47aca3c30581
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 27 16:18:37 2010 -0400
+
+ Cheetah: for server mode if monkey runs in background
+
+commit eb99074ea30525de97377639bf17504615cc3ed3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 27 16:11:41 2010 -0400
+
+ Define mk_plugin_exit_all func
+
+commit c20d8aefec8d96ffce03314d4bf37eb8a6088e2b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 27 16:09:38 2010 -0400
+
+ Add is_daemon variable to config struct
+
+commit 7bf032e9e5ec82e91400f87f95fac510d3b5ef5e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 27 16:05:21 2010 -0400
+
+ Cheetah: status command - print listen mode
+
+commit 2e1c526e240f5326db5ddc91a3a20558caf90633
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Aug 27 15:44:17 2010 -0400
+
+ Cheetah: print all configuration in a vhost
+
+commit 3aeb58f78f6e901dcf3ae4b59702eb0143b5fb1c
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Aug 27 12:45:13 2010 -0400
+
+ gg
+
+commit 3194181081e9586f67ee8e7384b06effbec6e076
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Aug 25 11:58:23 2010 -0400
+
+ Deprecate AccessLog and Error log in vhost conf
+
+commit 2068e5b7d23b0e2f391d70753fc6c047b6d0c13a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Aug 25 11:22:35 2010 -0400
+
+ Cheetah: code cleanup
+
+commit 371e5de10a34090c4f3a7be8e0a09724a123bbb7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Aug 25 11:04:15 2010 -0400
+
+ Cheetah: fix fprintf() compiler warning
+
+commit 306317ef8dd435aa300c72cc01fccc771fdaf58e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Aug 25 10:58:44 2010 -0400
+
+ Cheetah: remove socket server when exit
+
+commit 78c98b44eaaa57a34f27278a7fe633f006a75598
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Aug 25 10:52:17 2010 -0400
+
+ Cheetah: New server mode through unix domain socket
+
+commit cc028143185a16300c11b774f41348763665fa5e
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue Aug 24 10:31:10 2010 -0400
+
+ Added some trace and fix the compilation at the Makefile.in file
+
+commit a4f6726282bf9e3524c2f37f18524809310016ac
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue Aug 3 14:36:40 2010 -0400
+
+ First work on liana_ssl
+
+commit b130094bf7401d3d3cf3fee082405724cbe784c8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jul 31 14:54:18 2010 -0400
+
+ Cheetah Plugin: remove pipe when monkey exit
+
+commit 5c24b997703d85629da850dd4b41cb1c905ea213
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jul 31 12:05:07 2010 -0400
+
+ Plugins: invoke _mkp_exit() on SIGINT
+
+commit b9f4e1f51a51eeb87bec7546cd5bef46069bc756
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jul 31 11:45:15 2010 -0400
+
+ Cheetah Plugin: new conf and new PIPE communication support
+
+commit 9918ccce027eaaad5c88eb2dddd871cfa4b62fc5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 30 20:59:29 2010 -0400
+
+ Cheetah Plugin: new cutils.c file
+
+commit 5f4bd527e5e401085c93323aaa9a258024594f83
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 30 14:31:42 2010 -0400
+
+ Cheetah: move registration to top
+
+commit 102c6832589303c84b556dc51a1f5028221074a8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 30 14:30:41 2010 -0400
+
+ Liana: move registration to top
+
+commit 293e0b51b7d1de195c41f9cfe5bd1ac63d9fbf81
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 30 14:30:14 2010 -0400
+
+ Fix MK_TRACE and move registration to top on each plugin
+
+commit c70bd21509a637eb2a7f5b4ff3d4ea6a20dc4397
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 30 13:23:30 2010 -0400
+
+ Temporal fix for PLUGIN_TRACE
+
+commit 8a76bdc444b6ad33b97701363b2384fc16782d15
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 30 13:14:57 2010 -0400
+
+ Plugin struct cleanup
+
+commit d2884679f8ebc79ef745f942f1c606f42490b8be
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 30 13:11:18 2010 -0400
+
+ Update version to 0.12.0-dev
+
+commit 30f21c8efed492e65800ecc9d94a303895c7886e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 30 13:10:56 2010 -0400
+
+ Security Plugin: Use new registration method
+
+commit 3eabae477e992dcbda6b43e90e9c07bd9887d3fc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 30 13:07:36 2010 -0400
+
+ Palm Plugin: Use new registration method
+
+commit 463fe33207670f2d969e5ad9dd0e18d7761c391e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 30 13:04:19 2010 -0400
+
+ Dirlisting: Use new registration method
+
+commit cc77514b0d91a7cb205ec1a75f7f2e71b0db9f04
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 30 12:43:43 2010 -0400
+
+ Liana: Use new registration method
+
+commit 2c92b058fd04d60045ad9f5ecf0f5c59f684afc3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 30 12:36:37 2010 -0400
+
+ New Plugin registration macro: MONKEY_PLUGIN()
+
+commit 6a70333667ae2a57652e0d10f060876e24348c97
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 29 19:56:06 2010 -0400
+
+ New plugin header file for plugins: MKPlugin.h
+
+commit 9c4738722e470e29b1be56d0d693bb7aaf3fa03d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 29 19:16:52 2010 -0400
+
+ Cheetah: refactoring code
+
+commit 62a441e8bddcd239ed9c3546b6c2cd8130fec6ff
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 29 18:29:33 2010 -0400
+
+ Cheetah: move constants to header file
+
+commit b97c56be2a6f57c04f376955cc1a9d20a517a022
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 29 17:59:50 2010 -0400
+
+ Monkey 0.11.1
+
+commit 5beb18fd6d45f3ff739f69dad62b9abb6b2ad096
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 29 17:38:17 2010 -0400
+
+ Limit POST DATA length to 65536 bytes
+
+commit 51a7e58736ec510dcfa12ec781a16b59e68f61e7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 29 10:02:31 2010 -0400
+
+ move thread init keys to new func
+
+commit ee2e8a08182094d4a21f3a46b32d08bdd12bb593
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jul 28 18:48:41 2010 -0400
+
+ Move logger global configuration to conf/plugins/logger/logger.conf
+
+commit 4e8904d569afabf0baffb8a705a36c09e3bc65cf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 26 12:36:14 2010 -0400
+
+ Fix data type in mk_mem_malloc_z()
+
+commit ba9bc9b0382ae6c996d339ebe8a8664de219e3ab
+Author: Davidlohr Bueso <dave.bueso@gmail.com>
+Date: Mon Jul 26 11:10:28 2010 -0400
+
+ [PATCH] Grammar and typo fixes
+
+commit 9de8f26ce29358d04bc31af98cfea5c6158f251f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 26 11:01:54 2010 -0400
+
+ Fix space
+
+commit cd5d99614961182d6ad1dbf9b36a885d6e08c21e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 26 10:35:42 2010 -0400
+
+ Add Content-Encoding header support
+
+commit 1125d0a2a21b3a8ebc0e5430a68fb3149f9322a2
+Author: Davidlohr Bueso <dave.bueso@gmail.com>
+Date: Mon Jul 26 10:17:24 2010 -0400
+
+ [PATCH] Makefile changes
+
+commit 595cd5c336bf7e0caf9238433c223138b0162b97
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 25 20:11:02 2010 -0400
+
+ QA: update post_test02.htt comments
+
+commit d3b0873baf6132c07f46549ff3d36c9c3025f814
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 25 19:54:33 2010 -0400
+
+ Validate content-length in http pending
+
+commit 1200abd552e02ab1937f4ae9ab94bff156fd603a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 25 19:51:03 2010 -0400
+
+ Do not process request if post data is still pending
+
+commit 9057accef008661f4e4978912f13b661a21d6ac1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 25 18:58:03 2010 -0400
+
+ Implement mk_request_premature_close
+
+commit 4173c8ed7211baa2259c5c73d571a04d7eece398
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 25 18:09:26 2010 -0400
+
+ Add missed list.h
+
+commit 75fc5f98ea307cea8b64a9cec24f2d52fe17c1fb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 25 18:08:12 2010 -0400
+
+ HTTP: Improve POST data receiver
+ Palm: Safe POST data sender
+
+commit a0c75be90c8e57eeff576bbac15a72c01ddaab07
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jul 24 01:57:27 2010 -0400
+
+ Little Palm fixes
+
+commit 073733b953e8980f11bb5d0a9f4aa0272a534b32
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jul 24 01:41:50 2010 -0400
+
+ Palm Server: Fix POST data support
+
+commit 0b706441321e08cb6a8163b29ab1951f4276b0d9
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Jul 23 21:10:03 2010 -0400
+
+ [PATCH] Added list.h with the needed definitions to manage double linked list. Added list.h to plugin.h and utils.h
+
+commit 3d1c5ef131ade47652459b6ba27ee76254b26a5d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 23 21:02:33 2010 -0400
+
+ Palm Plugin: Enable REMOTE_ADDR cgi header to palm request
+
+commit ae02e21a017b80e55cdc77270ef642b05a86b304
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 23 20:58:12 2010 -0400
+
+ Add host_port mk_pointer to request struct
+ Palm Plugin: add HOST_PORT header in palm request
+
+commit 0e6273e1c20c6f9437e9d09f9dc11a725761b010
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 23 19:55:05 2010 -0400
+
+ Set mk_pointer config->port and add server port to Palm plugin
+
+commit 62686138c50dc3888dd53a7bc2baa68ac53f969e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 23 18:22:06 2010 -0400
+
+ Validate header response status on send
+ Palm Plugin: check Status CGI field
+
+commit 81ba0f36a7aa173fbbcfaa04728d3a1b73f5d632
+Author: Horst H. von Brand <vonbrand@inf.utfsm.cl>
+Date: Thu Jul 22 14:33:30 2010 -0400
+
+ [PATCH 6/6] Fix file/directory names
+
+commit 9d5e869d701be53b650fa9f1378b137ce5ffaff0
+Author: Horst H. von Brand <vonbrand@inf.utfsm.cl>
+Date: Thu Jul 22 14:32:52 2010 -0400
+
+ [PATCH 5/6] Bump release in specfile
+
+commit 1c63c46f0f075bfb77a945b3a93ad8ca35e1989a
+Author: Horst H. von Brand <vonbrand@inf.utfsm.cl>
+Date: Thu Jul 22 14:32:02 2010 -0400
+
+ [PATCH 4/6] Package correct monkey.conf in specfile
+
+commit 67a824425ada06058a43ccb5c9af357e6b62ef65
+Author: Horst H. von Brand <vonbrand@inf.utfsm.cl>
+Date: Thu Jul 22 14:31:28 2010 -0400
+
+ [PATCH 3/6] Add locale handling to specfile
+
+commit cba7391985ec410c2efc49c5651699f37f4a995c
+Author: Horst H. von Brand <vonbrand@inf.utfsm.cl>
+Date: Thu Jul 22 14:30:45 2010 -0400
+
+ [PATCH 2/6] Reorder tags in specfile according to Fedora guidelines
+
+commit f97e6010f9480097842bbc5d729e4c89ab4b62e8
+Author: Horst H. von Brand <vonbrand@inf.utfsm.cl>
+Date: Thu Jul 22 14:29:18 2010 -0400
+
+ [PATCH 1/6] Minor cleanup of the spec file
+
+commit 0dfa317d1c5b33aeebdc21bb15d18f16a7e3cbc4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 22 11:25:39 2010 -0400
+
+ Update version to 0.11.1-git
+
+commit d2d8a3384f40a5ccbf2ae12841e052f63f0ce28b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 22 11:03:24 2010 -0400
+
+ Security Plugin: set http status for URL rule match
+
+commit 9ccb145c6c2ba71aece45697a6c87dedd1382911
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 22 10:20:47 2010 -0400
+
+ Strip plugins on make install
+
+commit 4c5e441895fbe30e32907d326c145799c67901b4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 22 09:57:19 2010 -0400
+
+ Drop status_p from headers and fix Logger plugin
+
+commit 76ce40169c0311aa940edfce59b1c1c26ef71e2c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jul 20 15:04:18 2010 -0400
+
+ Fix thread_key plugin connector
+
+commit bc8f78bc072ba5ef163aa33bfa00d77ff81d0e98
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 19 12:33:55 2010 -0400
+
+ Safe use of va_start()/vsnprintf()/va_end()
+
+commit a34265f1e00e4af717d335ab48c49a268a10c945
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 19 12:13:51 2010 -0400
+
+ Dirty hack to fix vsnprintf() problem in 32 and 64 bits
+
+commit 573f51412b628a4f643b0227fdedeb104305007b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 19 11:12:12 2010 -0400
+
+ Fix 64 bits warnings and issues
+
+commit 792f05a50ee763a9b9e80867a86b521c1f67607b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jul 17 10:30:31 2010 -0400
+
+ Configure script: replace make by $(MAKE)
+
+commit 12c8cd5d413e1820481af7dd5a102a9b692d9924
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jul 17 10:20:02 2010 -0400
+
+ Fix pointers warning
+
+commit d4b84332f2a54f1030957eb3e0d834bb4546cfdc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 16 08:53:43 2010 -0400
+
+ Monkey 0.11.0
+
+commit 924ac75d9ba4f5efd8163ef3c53522cccc2bcf47
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jul 14 10:55:40 2010 -0400
+
+ Plugins: use compiler defined in environment
+
+commit fd4a7a35469ebfc6e6622816c8199621a5e0be3d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 12 13:35:08 2010 -0400
+
+ Fix config.c merge
+
+commit 52eddac688373c6f0e46860e7324fd5a801df9df
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 12 13:25:06 2010 -0400
+
+ Update configure script to v0.11.0-git
+
+commit 51c34c1a2a13a230557584f92b4a90b761e58216
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 12 13:24:38 2010 -0400
+
+ Fix merge
+
+commit f57f5485a1aa3c6cf92513a3c414c9803172bc72
+Merge: dff448d 30fc792
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 12 13:20:41 2010 -0400
+
+ Merge v0.11.0-dev branch
+
+commit 30fc792384a1e564fdf707c5dab38bf8d4029ba8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 12 10:48:51 2010 -0400
+
+ Read somaxconn from procfs
+
+commit 28931dee0f8723d06e1ad31675945ca4ed9f4776
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 12 10:13:13 2010 -0400
+
+ Palm Plugin: Set status 500 on palm server connection problem
+
+commit 6c88d399921bedb862c8eab11192dac46ea2faa4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 12 10:04:56 2010 -0400
+
+ Missed realloc()
+
+commit df8493659092a84c69f6c0a6ba68fdfae4e31ab6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 12 00:34:27 2010 -0400
+
+ Ser worker capacity inside configuration
+
+commit bd38084c55f7caadc9664ad1c3af3a27b79ab4f3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 12 00:30:06 2010 -0400
+
+ Cheetah! Plugin: Add new 'config' command
+ Remove indexfile struct
+
+commit 6462cf76e62e97faa3936666dd9509d30811e7da
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 11 23:52:14 2010 -0400
+
+ Print Monkey details before invoke process context
+
+commit c852ebed7aff6bcdd894d47c1451c832a1958370
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 11 23:47:19 2010 -0400
+
+ Default request chunk size set to 4096 bytes
+
+commit 5f702e42d3b541a06772a4ace443ba2f590f5b94
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 11 23:38:53 2010 -0400
+
+ New MaxRequestSize configuration directive
+
+commit f8f2a7f4eb175b08fc9819284d6bf030626c7e08
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 11 23:05:34 2010 -0400
+
+ Request buffer size now is dynamic :)
+
+commit 02c92f0fec10c86eaf18a82fe2eb126a809942b3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 11 18:44:04 2010 -0400
+
+ Request error: just validate page pointer
+
+commit 1435fb94b021225e35fbd6ba5d7e5903f584fb3f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 11 18:38:28 2010 -0400
+
+ Logger Plugin: Add 413 status 'Request Entity Too Large'
+
+commit 4df6376fcb2d2bc847332363d590c01535dabb3c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 11 18:21:32 2010 -0400
+
+ QA: Add test and checker for 413 error
+
+commit 0ed8022c6981c3b2c3ec5fc3ac0c6ce639c6b902
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 11 18:16:23 2010 -0400
+
+ Refactoring mk_request_error()
+ Do not send content-length header if HEAD method is used
+
+commit 370d661b54af1f0c88bf0f4a030ec55745e165dc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 11 18:03:01 2010 -0400
+
+ Add status code 413: Request Entity Too Large
+
+commit bf291c1c46a94087b5d6a33aea2672704b43731a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 11 11:48:18 2010 -0400
+
+ Fix plugin thread key API
+ Plugin: Fix thread event list
+ Plugin API: new event_del() interface
+ Palm Plugin: Fix
+ Palm Server: remove unnecessary pipe()s
+ More descriptive TRACE messages
+
+commit 72bb731716fb1d0c07b957471c5ffed45216cf7d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 9 19:07:06 2010 -0400
+
+ update a line
+
+commit b8e50e13f1bd5e139949def5ca32cc0e08b7781e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 9 14:50:37 2010 -0400
+
+ Palm Plugin: Fix request_free
+
+commit 8396ea6d5e99e74a30b3405d56012de540bb0494
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 9 11:40:15 2010 -0400
+
+ Do not close STDIN in daemon mode
+
+commit a7268886df2aeb5b008902ea44f5a4d89d1bbbaf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 9 11:12:24 2010 -0400
+
+ RPM SPEC: Add 'monkey' user to the system
+ RPM SPEC: Fix log directory permission
+
+commit 074e76d262d971266cc2930fa2aa92800ee04c5d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 9 10:33:09 2010 -0400
+
+ RPM Spec: add logdir
+
+commit df6273eaa8bf5bcaaff13ecaf194230cf86703b7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 9 10:19:21 2010 -0400
+
+ Fix configuration text template line lengths
+
+commit 356a27c7221724f49c0ffffd3c2885c09cde1bd6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 9 09:53:48 2010 -0400
+
+ New RPM builder spec file
+
+commit 273ed1d3f5097e00cf475ba70ed121cb67e7ef73
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 8 14:28:44 2010 -0400
+
+ Palm Plugin: little changes
+
+commit e0a4f72493f0bd287906417fdeb12a883fbf3e46
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 5 16:03:26 2010 -0400
+
+ Palm Plugin: fix thread key var name
+
+commit be159a359954e9a2d1a2f23cca200d95b840f2b3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 2 08:37:16 2010 -0400
+
+ Palm: Launch each palm in a new process context
+ Palm: Fix auto create new child on die
+ Palm: Kill palm pids when the server exit
+
+commit bc5de8033ba88761edddd7202a97d46343f95b76
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 1 11:12:01 2010 -0400
+
+ Palm: Fix POST method
+
+commit 9cba0a0a7ca5494f58ea2c6252ccdf402421d14c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 30 22:55:09 2010 -0400
+
+ QA: remove files
+
+commit fdc7934d57f1196c57c4290a68e33918c219b4a4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 30 22:53:55 2010 -0400
+
+ Add missed QA log scripts
+
+commit 48c0af36778977475dc0e5d2800b678204d5d543
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 30 22:40:01 2010 -0400
+
+ QA: Fix headers case insensitive log check
+
+commit d58a0a61b4de2f70c19b106ecf81515a7f2b350f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 30 21:47:14 2010 -0400
+
+ Set content length inside http_range_parse() if ranges are set
+
+commit 83e6716334dee76368722a69036fbae0b02f4435
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 29 20:08:56 2010 -0400
+
+ Add mk_string_itop() to plugin API
+ Logger: use new str_itop() API
+ Remove mk_utils_int2mkp() function
+
+commit 355150aa5640d261bf3c08771b4a8f1af261c8ca
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 29 15:23:36 2010 -0400
+
+ Faster mk_utils_int2mkp()
+ Add mk_string_itop()
+
+commit f38ab6217b55eb8c5725c61911e39eae3b38adb0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 28 17:21:16 2010 -0400
+
+ Trim each key/value configuration string
+
+commit 8e4dad88cd26ce75a6699aaebf5281769ff66f59
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 28 17:17:50 2010 -0400
+
+ Add internal mk_string_trim()
+
+commit 88edd1d0397f315ffb188e15c60200f18566777f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 28 11:26:32 2010 -0400
+
+ Remove deprecated maxclients and maxip from configuration struct
+
+commit dc1a3f090af1225e15b751fefc05f1a253914f59
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 28 11:25:15 2010 -0400
+
+ Fix workers configuration value
+
+commit 3229fc1c8fe051fc4fba20ca063c80806611789b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 27 12:11:14 2010 -0400
+
+ Good bye strftime(), it's not you, it's me :P
+
+commit ccec86920bfee90d5c610ad412ba39a3c609fab6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 26 21:48:31 2010 -0400
+
+ Send bad request response headers on bad request
+
+commit ff220b1782bb875506c32f75e931e8ec8c845a8a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 26 16:11:55 2010 -0400
+
+ Replace some pthread_getspecific() calls for the new mk_cache_get()
+
+commit eabdee01173e11be445d0b0aa19b6c73627206ce
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 26 16:09:09 2010 -0400
+
+ QA: Add last_modified qa script
+
+commit 8fd4815879245979b191627767c1dd765a6b1ee0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 26 16:07:37 2010 -0400
+
+ Fix 'Last-Modified' response header
+
+commit 9ce7b4d9cf99db3191592352593bccab6fec4747
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 18:49:47 2010 -0400
+
+ Add uri_01 log checker
+
+commit 07377274e993e9098182cecfba1f5c9e541c8852
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 18:49:23 2010 -0400
+
+ QA: Add protocol test files
+
+commit 296c5135d00f0432254df4ffcc8da5d9220051c9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 18:49:01 2010 -0400
+
+ Forward Port: Validate empty protocol
+
+commit 11605af53081fa701f2d20ef0c8dbf9908829f1b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 18:46:11 2010 -0400
+
+ Forward Port: Fix data type for uri_len in http.c
+
+commit 762a439eb2af9dc0b6cf1cee5de8c3694623f542
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 18:44:08 2010 -0400
+
+ Forward Port: Protect mk_buffer_cat() from invalid length
+
+commit 4117c2b010d8982594ac7e64a8da11a699c5a0d5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 18:42:43 2010 -0400
+
+ QA: Add uri test files
+
+commit 7f1a723d158aac6ad35446e7c492260c35837241
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 18:40:20 2010 -0400
+
+ Forward Port: Force validation of initial slash in request URI
+
+commit dff448d17fab961ee7947e6e630296a9a16f87f4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 17:55:36 2010 -0400
+
+ Monkey 0.10.3
+
+commit ece8dbc85051f2ce7da69ae8b8338ab302cb6b15
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 17:24:05 2010 -0400
+
+ QA: Add protocol_02 test
+
+commit a1bcc16e8cd69f0360b4b6d20367b4097b4ef08e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 17:04:04 2010 -0400
+
+ QA: Add protocol_01 test
+
+commit 8b2d9447cd2d4c41d963c7b62e199cdc640ab2e3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 17:03:40 2010 -0400
+
+ Validate empty protocol
+
+commit 361d701d4fdd61eeeeee66b9f90ce0be9e2a1545
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 16:33:50 2010 -0400
+
+ Monkey 0.10.3
+
+commit fc7f1dddc75f6ef8d732ec4b1d97760f8f9b0271
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 16:31:19 2010 -0400
+
+ Fix data type for uri_len in http.c
+ Check return value from mk_buffer_cat()
+
+commit 96e35bf0f120546af82784f456a3437b28a474b2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 15:53:55 2010 -0400
+
+ Protect mk_buffer_cat() from invalid length
+
+commit 49bd4d0ca104faca6c8fd34f0db07a76b7a279bb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 15:29:12 2010 -0400
+
+ Monkey 0.10.3
+
+commit 9edfe0c9ccc34064bb9045120025591ebe23b139
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 15:21:17 2010 -0400
+
+ QA: Add uri_01.htt test (check first slash)
+
+commit bc5dd0267abb8f32c409d3475b934795bd137ad3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 15:20:44 2010 -0400
+
+ Merge header and log info for file size when ranges are used
+
+commit fc56e6a1382eb0335fcd16fdef0858302ac9e981
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 08:26:06 2010 -0400
+
+ Force validation of initial slash in request URI
+
+commit 001f9d6788a4bdb6c44b5f4dad2d046bce6ea958
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 23 08:02:07 2010 -0400
+
+ Missing semicolon
+
+commit f86008fd2deeec9fab7a43c47b9ba024e3a4c8e9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 22 09:20:00 2010 -0400
+
+ Logger Plugin: Add FORBIDDEN error message
+
+commit f210e376562c1cd3c87f7f787ac7f7a86594a0f6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 22 09:19:39 2010 -0400
+
+ Logger Plugin: Use unix breakline code
+
+commit d485ad50ba910a1061d1c27bd33507666c21c0ff
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 21 13:16:31 2010 -0400
+
+ Plugin API: Add header_set_http_status() call
+ DirListing Plugin: support new configuration mode
+ DirListing Plugin: Fix theme and man configuration
+
+commit 721a688db4e16bf623a4c5751c6ac01aafc91bb5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 21 12:38:28 2010 -0400
+
+ Logger Plugin: fix entries
+
+commit bbacdcb12f5db1c019c7c16634d50bb32f55ecea
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 20 12:22:51 2010 -0400
+
+ Logger plugin: add files
+
+commit b9faf647bfd0464b6ce5f8265de28c72963198bf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 20 12:22:31 2010 -0400
+
+ Logger plugin: add error log support
+
+commit a9ced288e9e13de61e96c94d84b38e5543d2ed60
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 19 19:35:36 2010 -0400
+
+ Fix 'FIXME' code
+
+commit 1603fdeea80376391df445a6edfe25bc906eb047
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 19 19:32:59 2010 -0400
+
+ Do not free CR before check KeepAlive
+
+commit c76e77660c913c8b3ab151e76c085a5862cc5289
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 19 19:10:12 2010 -0400
+
+ Logger Plugin: add Global configuration section
+
+commit a8dd3baeabaafa75c290e5eb1cc86e7af535c005
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 19 18:44:04 2010 -0400
+
+ Fix configuration reader, do not override global section names
+
+commit 155e22d26a5ca0afc2face09c331f3c6a06b1d58
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 19 17:54:42 2010 -0400
+
+ Plugin API: Export time functions
+ Plugin API: Set plugin thread keys before invoke prctx()
+ Plugin API:
+ Core: add mk_header_set_http_status()
+ Core: remove old log cache
+ Core: add mk_pointer protocol_p to struct request
+ Do not free content_length_p when sending headers
+ Logger Plugin: Access log working
+
+commit 92e1144332495c0c0fb3b89f657f4cc9d68891c5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jun 18 18:06:52 2010 -0400
+
+ Enable STAGE_40
+
+commit b5043a203f5a7467321918fd1720de77a37c70a8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jun 18 18:04:14 2010 -0400
+
+ Drop logfile.c dependency
+
+commit 6ab9a2bc6840f49ebb5652cdf54c91eb196b0e14
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 17 21:46:18 2010 -0400
+
+ Add Logger Plugin (under development)
+
+commit 19730b062f752401b89b9ee9f7e52638b024c1c5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 17 21:45:35 2010 -0400
+
+ Deprecate core logger
+
+commit 4300e297b1e74e1998ff0be05b9434a3e5ba684b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 17 17:08:55 2010 -0400
+
+ Plugin API: Export mk_epoll_ calls
+
+commit 93bc69fb47edc63d669968b5c55cb285676b1b49
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 15 17:38:03 2010 -0400
+
+ API: export mk_worker_spawn()
+
+commit 95a8b1867a0dcc6d4437fd9253f20a68531f2a13
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 15 17:25:26 2010 -0400
+
+ Fix plugin hooks declaration
+
+commit b35c51d4f5c3912100cc79b079b40c9adb902969
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 14 17:16:47 2010 -0400
+
+ Fix un-freed cr nodes
+
+commit 2109750a7af2d2888748f9df223fe750ab12943d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 12 15:28:33 2010 -0400
+
+ Changelog update
+
+commit 07abe05218db6f412aea151019921f5cc9739afb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 12 14:35:13 2010 -0400
+
+ Monkey 0.10.2
+
+commit 2f3ce8bd01ffd39c4fc042690978350a52055fd6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 12 14:24:52 2010 -0400
+
+ Rename Logo image file
+
+commit 134a226f9da58de0f550415dcecf9474c535c5dd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 12 14:06:47 2010 -0400
+
+ Close connection in handler write if process returns ABORT
+
+commit 8109a7409ec52aaab22e003cdaeec656123d5ca0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 12 13:50:26 2010 -0400
+
+ Load plugin trace message before load
+
+commit 2d76a292985125a66284b37371176f8af345fe59
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 12 12:34:55 2010 -0400
+
+ Security Plugin: add trace rules
+
+commit 40e673d32c4e8261abb97fef0714741cb3cfc202
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 12 12:16:29 2010 -0400
+
+ Adapt security plugin to new configuration model
+
+commit f4c72ed3b55a1100ae3bd2660530ddd777b8d7c5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 12 12:07:32 2010 -0400
+
+ Adapt palm plugin to new configuration model
+
+commit df7a1ce79bd4e7348163a323ec6c2066f5700d57
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 12 11:56:24 2010 -0400
+
+ Adapt palm configuration file
+
+commit 1e570d29f48ceb2c8280577cea76f677630a646c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 12 11:53:50 2010 -0400
+
+ Adapt server config to new configuration model
+
+commit 3b297b5767b34d8f8d99ebd0962f3df7c1b22671
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 12 11:42:15 2010 -0400
+
+ Adapt mime types reader to new configuration model
+
+commit a870e2522902d7d4611477680bd68fc8a231ad7a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 12 11:40:55 2010 -0400
+
+ Restructure configuration 'structs'
+
+commit b63883dc56f1d46a09b6e7fbe891225ef7310e74
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jun 11 20:06:57 2010 -0400
+
+ Read from indented configuration
+
+commit 0dddda3162e5ec33742f4b8befd469290f988847
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jun 11 08:32:36 2010 -0400
+
+ Indent configuration template
+
+commit 2d7f7fd0951d00b9be356fe99c68e04a1f3a894d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 10 00:08:22 2010 -0400
+
+ New configuration reader: indented mode
+
+commit cdf629003f5f9ecdbede745212e8a0f039cf37da
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 8 15:31:45 2010 -0400
+
+ Update configure message
+
+commit a103adf31f9bfb3341a59518f47b098693c56bcd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 8 14:40:55 2010 -0400
+
+ Config: skip 'value' empty left spaces
+
+commit 61ad3e7cd2d71fdcb1455369b33b08b9c8fb0178
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 8 14:39:08 2010 -0400
+
+ Fix #6: Monkey as daemon, logger do not write log files
+
+commit 9215903eda3bfba69345875631fbe728b9bb5567
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 7 14:49:01 2010 -0400
+
+ Colorize headers sent in MK_TRACE
+
+commit 28e197ba2249922f2b5efc45b2f6bfc100ef08b8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 7 14:36:29 2010 -0400
+
+ Fix: set right content length for headers
+
+commit 981be84767361782ebc79e93c304b9aee16e5963
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 7 14:34:43 2010 -0400
+
+ Print headers sent to STDOUT as MK_TRACE message
+
+commit 48ae46b3a8f5faa87749274409ed6639e8a441d1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 7 14:31:31 2010 -0400
+
+ Set content-length pointer inside header_send()
+
+commit dd3f39e1c5ce68fab353c96c0091f9c0deea0a6d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 7 14:04:03 2010 -0400
+
+ Check STAGE_30 return value for not found file request
+
+commit d451bf65e7cc23cb2430aae4accf9aa58a0d04b1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 7 13:18:03 2010 -0400
+
+ Return right data type for API->header_send()
+
+commit 0f843c580d0cf3eb7bd24f11b4f356ca152d8fc7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 7 10:45:58 2010 -0400
+
+ Remove unnecessary trace
+
+commit 8501f3f2099fa2a9c96274f3abe77302eae15b01
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 7 10:29:33 2010 -0400
+
+ Remove security rule in security.conf
+
+commit 3f1f05c99ac24f9d3e827d6a58064ba4179b8007
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 7 10:29:07 2010 -0400
+
+ Remove double STAGE_30 call
+
+commit 87bceea3be32c04ffe1648036ecf39b5558a1fd4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 2 14:10:32 2010 -0400
+
+ Set values for content_length and content_length_p in one function
+
+commit 1f04d77872cb7fcb9051302b3e8f1e9860e5d7bf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 2 13:21:26 2010 -0400
+
+ Return FORBIDDEN error if open() fails
+
+commit 3f37443e79ce331b4fba108ee7500d7a6c948e94
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 2 12:56:47 2010 -0400
+
+ Fix file permission check
+
+commit f7e11d100147a712fc4c7494453a204bee4475cb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 2 12:09:50 2010 -0400
+
+ Remove trace message
+
+commit 5acdd396a2cb2e6a6078e129405bf6fcb146ec3f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 2 11:29:57 2010 -0400
+
+ QA: Add log rule for directory redirect check
+
+commit d39e2e635983afac2436a8686ffc151e90918cb2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 2 11:22:25 2010 -0400
+
+ QA: Add directory redirect checker
+
+commit d5f007fba75c8539a4bcd3829554001fe9d50258
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 2 11:16:21 2010 -0400
+
+ Fix plugin return values for STAGE_30
+ Fix directory redirect
+
+commit 601344a416bf3bcebba035ee4d4ce3cc9c1c4237
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 2 08:12:29 2010 -0400
+
+ Update plugins version to Monkey version
+
+commit b6f8bdceead8751592d5111d93138e1ac5e03860
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 1 11:41:21 2010 -0400
+
+ Read env CFLAGS and fix some plugins variables declaration
+
+commit 09c24d197f25dfb700ccd83c121832e782225e28
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 1 09:54:46 2010 -0400
+
+ Fix #6: Monkey as daemon, logger do not write log files
+ For some unknown reason, when monkey goes into daemon mode after launch
+ the logger worker, this last one does not write to the log files.
+ Issue fixed moving the daemon routine before launch workers.
+
+commit 7cb8abf92576bc28e3435cf8798b32a651e2296b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon May 31 23:11:40 2010 -0400
+
+ Fix #7: QA script if_modified_since_test03.htt failed
+ Core was resetting requests nodes from client request struct
+ before check the KeepAlive. Also when the request client were
+ removed from thread index, the index was not updated.
+
+commit c710d7488760e1c620cf4ded083c79621b2f1353
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 29 08:47:43 2010 -0400
+
+ Plugin: Enable STAGE 50
+
+commit 16e728d524ed12c18c81b51cf6cb366c52b84fe4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 28 09:33:14 2010 -0400
+
+ Palm Plugin: remove dummy trace
+
+commit 71e7aab5b5a2edd407fd1744c96814d01adb69b5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu May 27 15:23:50 2010 -0400
+
+ Palm Server: fix debug message
+
+commit 1b52d13df15e91ff762359db541187ed76673005
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed May 26 16:43:08 2010 -0400
+
+ Improve plugins loader
+ Now plugins can return -1 when the init hook is called to avoid be registered
+
+commit b65c1859fa7c9066f91580caadd550fa20d17de5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed May 26 11:51:26 2010 -0400
+
+ Add _mkp_exit() missed hook to plugins
+
+commit 3d502bd2f960f76ec31a6e72e3cc868be34eb949
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed May 26 11:25:05 2010 -0400
+
+ Plugin: validate init and exit hooks
+
+commit 5ed3cbb26c764ea65e12879658bbee2bb83e2724
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed May 26 10:16:34 2010 -0400
+
+ Fix and implement new API spec
+ Dirlisting: fix stages for new API
+ Cheetah: fix stages for new API
+ Security: fix stages for new API
+
+commit 8099c9d51aede8dfc571658f00adea1f8646d25d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 21 09:44:39 2010 -0400
+
+ Palm Plugin: update plugin data when deleting request node
+
+commit 505d98b75ee10b66e7b1852d0f7b901ac2ac3651
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu May 20 16:41:42 2010 -0400
+
+ Palm Server: add debug.py
+
+commit 88a1f3dcde4be3fd157c6cbaaf31a48d1a4ea1b2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu May 20 16:39:48 2010 -0400
+
+ Palm Server: Improve debug messages through env variable PALM_DEBUG
+
+commit cca96b62b5884425253bca94977dc5a024909f16
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 18 22:57:11 2010 -0400
+
+ Palm: handle errors when executing in child
+
+commit 741a988013d7ce78ca439b5b5c21ad8ee4f994a4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 18 22:27:30 2010 -0400
+
+ Palm Plugin: do not own request if file does not exists
+
+commit 4a746dfa79a8593f8709754209d9dfb17da347cc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 18 22:22:03 2010 -0400
+
+ Palm: change ports (again)
+
+commit f572af89a787838c9dd8b3fd321e8d0e81ce6746
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 18 21:49:16 2010 -0400
+
+ TRACE: load plugin message
+
+commit 3c3c74fded312e591c622de9e0c2a0b04f6c265f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 18 11:39:41 2010 -0400
+
+ TRACE: Fix init time for first message
+
+commit 990e0aea2d01512bf2259cb7f374c40225c695e6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 18 11:34:46 2010 -0400
+
+ Move first monkey trace message to the begin
+
+commit 7a315dd952bee93cb1a2d64ece7b08f73d8f9233
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 18 11:29:48 2010 -0400
+
+ Palm Plugin: add trace for registered palms
+
+commit 9cab84ad6b316ee68c39356872bfebc7795f4123
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue May 18 11:22:17 2010 -0400
+
+ Palm: change configuration ports
+
+commit 8441f6be49c06e95ac4fd62474dc6aaeb799d065
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun May 16 22:32:05 2010 -0400
+
+ Palm Plugin: Add request method to environment request
+
+commit 5a1c793ef8775305e26457cb49b29256dac1e7b1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun May 16 22:04:29 2010 -0400
+
+ Palm: add hangup() function
+
+commit 0b0c433c61e4dd2d17fb903d8be11792da6eb350
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri May 14 21:09:04 2010 -0400
+
+ Added CC option to all plugins Makefile.in
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 7b1a544688d658de9d5c252d30c5c3dc43e20369
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri May 14 21:01:39 2010 -0400
+
+ Added a check to configure to verify that there's a compiler installed
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 6b1c9d2be01306dc46b653b4168a70daf8eb6f6a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 14 18:17:02 2010 -0400
+
+ Optional Palm Plugin
+
+commit 4c2d64920177f074f1fc15483f3321e3f766959a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 14 18:06:43 2010 -0400
+
+ Plugins: improve plugins.load details and add plugins ABOUT doc
+
+commit 88bfd0f098bcd94611e76900cd9fea1658930e82
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri May 14 15:30:26 2010 -0400
+
+ Fix bug in configure, it wasn't looking the correct plugin dir. Added ABOUT option to added a proper comment line to plugins.load
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 09c34af7767557a9af9032af903ac63cababf036
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri May 14 15:11:33 2010 -0400
+
+ Fix configure to do sed work in-line to both expressionan create Makefile directly. Replaced ENABLED for OPTIONAL and added MANDATORY for plugins compile options
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e4b7cec9f8e5dd6a2099a9bf1ec85c57ea2c0e47
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri May 14 14:43:39 2010 -0400
+
+ Configure add proper cflags an defs to Makefiles at plugin dirs. Added proper #ifdef #endif to palm.c
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e010e9767db4f768ed7a2e4ef7c0517c4cd8e6fd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 14 13:25:38 2010 -0400
+
+ Config: skip 'value' empty left spaces
+
+commit 905c4bc9553200b9173eb707504e14db0c644119
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 14 10:55:59 2010 -0400
+
+ Plugin: new API call http_request_end()
+
+commit 343270c585eb69f6ebd86c233e61954b92f48622
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 8 13:51:24 2010 -0400
+
+ Palm Plugin: enable content length
+
+commit e556adc5533c86cb6b84544e5a50b5ce9a8f8b33
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 8 13:26:58 2010 -0400
+
+ Palm Plugin: do not use chunked transfer encoding for HTTP/1.0
+
+commit 46fcc7525d207a579a39530249bb13a4bb79db14
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 8 10:40:07 2010 -0400
+
+ Palm Plugin: Use real path instead of request uri
+
+commit c07531bd851afffe27f485b0a3c1720f0b296849
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat May 8 09:43:56 2010 -0400
+
+ Palm Plugin: Fix sockets and send final zero chunk
+
+commit 0cd799e85831d1e51bf61b13184b8939b2e2ce4f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 7 15:05:35 2010 -0400
+
+ Remove silly palm server code and remove tcp no delay in palm client
+
+commit 03ae7eb204862161312c7ddd63ecc8fcae0a5a0e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri May 7 14:12:54 2010 -0400
+
+ epoll: check error event after EPOLLIN & EPOLLOUT
+
+commit b22ded92a67ab3e4af435230634795c948a0b9d7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed May 5 09:54:35 2010 -0400
+
+ Do not start if socket server have failed
+
+commit 6a6f810d3d143748d111655c619cc0df5d9274a0
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue May 4 13:43:19 2010 -0400
+
+ Added declratino of mk_palm_request_get_by_http() to request.h of palm
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b4c7a78a7c8d3ac85f3bc0c5ab8f76ad11d25194
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 30 13:40:08 2010 -0400
+
+ Change plugin events and palm plugin hooks
+
+commit a2100cf1e23a62813ec3fcfc1d17bc170e49f840
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 29 16:54:57 2010 -0400
+
+ Plugin API: rename get_somaxconn() to sys_get_somaxconn()
+
+commit 60e1742bd255588d6ca3f65c1cf10efae352ef07
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Apr 29 16:45:51 2010 -0400
+
+ Added bind, listen, create_socket and server to liana and replace
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e1bf6e52f944c594bbe43ff484b2d895072fd0bd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 29 16:12:33 2010 -0400
+
+ Palm Plugin: free resources
+
+commit d29250f4b09649b6d3d7a6d296cd8788211506ff
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 29 15:53:01 2010 -0400
+
+ Palm Plugin: fix missed epoll notification
+
+commit 5d0c533a76b0f9fc045dfaac243ec4e60978c574
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 29 14:17:59 2010 -0400
+
+ Palm Plugin: change some trace messages
+
+commit 3b070c50155c31adc945d239b3d5d1ea1b59a1e8
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Apr 29 13:25:11 2010 -0400
+
+ Moved mk_socket_connect to the proper function inside of liana plugin
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 77b7d7bb2425e163ab0f9a04a00327dd56653fb1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 29 13:24:44 2010 -0400
+
+ Palm Plugin: set socket TCP_CORK to OFF after send headers
+
+commit 71ac4e0bea6cb03f4764f19a2fc76be90c511e87
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 29 13:17:56 2010 -0400
+
+ Palm Plugin: remove deprecated function
+
+commit 8478bd0035e79bf2c6513b10f112aa23c71e3309
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 29 13:05:19 2010 -0400
+
+ Palm Plugin: set socket status
+
+commit 5150567186bf2b5322512fa11ed06bf5f0227193
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 29 12:49:57 2010 -0400
+
+ Connection: use right plugin read returned value
+
+commit 4f8ba77d40f130c085bbd0a3e91ea06ed19591b5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 29 12:45:55 2010 -0400
+
+ Palm Plugin: fix return value for read()
+
+commit 18ed002a9584a76e92907ace72913f53a3c07735
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 29 12:42:39 2010 -0400
+
+ Remove silly message 'Aqui va'
+
+commit 8ab028f8491da993626bce4cd975ca7cc82aca8d
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Apr 29 12:14:39 2010 -0400
+
+ Replaced write() and read() for mk_api->socket_(send|read)
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit eed08188a0cf441d27bab0fc5fa0cc2cc4ea3504
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Wed Apr 28 16:48:02 2010 -0400
+
+ Added some missing .h at the top of request.c, fix Makefile to link request.o.
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 9b45505cadf6c86d62fe30b1caec1961408d1eb5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 27 16:41:11 2010 -0400
+
+ Palm: split request code
+
+commit a6ff7c0c65f34eb012ca9ab487451fdc71918c15
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue Apr 27 15:46:37 2010 -0400
+
+ Some order in plugin.c. Added more callbacks realted to sockets in the plugin api. Proposed .gitignore
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b5fb90872ca66cbe86c12b71e53cfbb652cc92f8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 27 14:55:00 2010 -0400
+
+ Plugin event: return hook return values
+
+commit 6082f8400fab686c8f3b61cc0a372709d48d2cfd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 27 14:52:19 2010 -0400
+
+ Epoll: set ret to -1 in every cycle
+
+commit db34b2f0bf87c5d9afc8dd9c705fc9be315319b7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 27 11:53:47 2010 -0400
+
+ Fix epoll interface events
+
+commit a5dab47ef17bbd250244c6dd23cab495dc25a2d3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 26 17:46:04 2010 -0400
+
+ Palm Server: os.wait() on child die
+
+commit 9dc53e21d4c5f992238d7098918963f45e716302
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 26 16:49:44 2010 -0400
+
+ Scheduler: remove incomplete client_request from list
+
+commit 1b7cc37a52ee11c14ae6be4b35dcf0d6076a115e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 26 15:58:14 2010 -0400
+
+ Epoll: add mk_epoll_del() interface
+
+commit 9f3be00c19541b776a62d7e8b27bdd638db7ad84
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 26 15:12:59 2010 -0400
+
+ Plugin: event add now requires EPOLL modes
+
+commit 78e8e4a9f38ca5a7abade8e3b5d0d616cd93dd32
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 26 14:18:47 2010 -0400
+
+ Add plugin handlers for events
+
+commit 0e3fc059a6765a90ced3eb9b73c159d1d9168857
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Mon Apr 26 13:01:56 2010 -0400
+
+ Deleted some trailing whitespaces. Added a method to Request on palm server. Fixed palm plugin to work with the new api
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 4805774da7cf47af18674b325c231f77150cc38b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 26 12:52:18 2010 -0400
+
+ Plugin API: Document event_* hook calls
+
+commit 141a4e631ad0254a702df57891353767b5ee6ced
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 26 12:43:55 2010 -0400
+
+ Plugin: remove old STAGE_60
+
+commit 53a5e4c2456b7d71713d308a1fded91b4cb13165
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 26 12:41:14 2010 -0400
+
+ Plugin: Add new event plugin hooks
+
+commit 1b2c755bf94f00896b934b4a0de05d845444d6e6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 26 12:03:17 2010 -0400
+
+ Liana Plugin: remove cast
+
+commit b995809ab33dc78c5f21e2f93711a5d7a683bce5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 26 11:56:47 2010 -0400
+
+ Plugin: use right return data type for exported functions
+
+commit e2119ef7817799b68216a80e4e236b00ea87bd74
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 26 11:41:11 2010 -0400
+
+ Rename m_build_buffer() to mk_string_build() and move it to str.c
+
+commit a2769ecd9ec34ef4cc1ba99d62f5c464393a655e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 25 11:56:32 2010 -0400
+
+ Plugin API: Add API definition
+
+commit a8f8963d2303b8290f307d96a2a4d61b82c8dbc7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 25 01:13:17 2010 -0400
+
+ Plugin API: Add function definitions
+
+commit 2f65eba33206de81902cae94aa2f92e1d47fe411
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 22 17:01:51 2010 -0400
+
+ Cheetah: colorize plugin category tags
+
+commit 27c028e68f9c64870da9d75dbbd0bbda6a43bbd4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 22 16:51:21 2010 -0400
+
+ Enable DirListing plugin
+ Core: fix directory http restriction
+
+commit 72b1ec2932fa8fc855d26b7a0ef22d77702748ba
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 22 14:23:02 2010 -0400
+
+ Rename api.txt to API.txt
+
+commit 55892b050fb3148d38d540454904ab33cab69626
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 21 20:49:10 2010 -0400
+
+ Liana: Accept socket and set non-block inmediately
+
+commit bbcd028276780c3611f6149188d0a6fcc381c99e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 21 20:47:10 2010 -0400
+
+ Plugin: change type for neti* map
+
+commit d9fa53c3d0a54e62a86a2134197d3adbdd990bdb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 21 13:07:23 2010 -0400
+
+ Liana: code cleanup
+
+commit c45e302e4cffa3fcd66b859bd30185f933a83f5b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 21 13:03:53 2010 -0400
+
+ New Liana Network Plugin
+
+commit 1945e06be0a9bba0b69331ff21371415c4decea1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 21 13:03:17 2010 -0400
+
+ Plugin: validate NETWORK IO
+
+commit c71471b1a434bee6d84d651170e5ac835cfbf8bb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 21 12:58:25 2010 -0400
+
+ Configure: optional ENABLED file under mandatory plugins directory
+
+commit 8ea12e29118da08294ae6dc25da0d40abeff301b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 21 12:44:47 2010 -0400
+
+ Core: add wrappers for network io calls
+
+commit 4b57e6fd888daf9d783d1c86ca61e731f45c961d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 21 11:50:20 2010 -0400
+
+ Plugin: add TRACE detailed message when NETWORK IO/IP plugin are cincomplete
+
+commit 359fdcadb0cae86924cb0e81e9600b2324632e70
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 21 11:37:35 2010 -0400
+
+ Plugin: restrict to one I/O and IP network plugin
+
+commit 284b3eba5cc211fc298984e66c8991a68356725e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 21 11:22:38 2010 -0400
+
+ Plugin: add net_io.sendfile hook
+
+commit 16feb3d280f1eb1f1c7f113977d5d18887eaff11
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 21 11:17:48 2010 -0400
+
+ Plugin API: add _mkp_network_io_send_file
+
+commit bb18a3cf9de4abae15e2adda572364cb8b4b7adb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Apr 21 09:57:01 2010 -0400
+
+ Plugin: Fix reference under trace context
+
+commit b3d267a8685dbbd420bf7d2538f3d68ea5ff7519
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 20 23:14:15 2010 -0400
+
+ Plugin: free plugin struct if it fails
+
+commit 85ef77ad48e34939308b9aa65843ee0a5d0d5add
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 20 23:11:07 2010 -0400
+
+ Plugin: fix NETWORK_* validation
+
+commit e1c46f1f8f86b218640fa7519533d7da225ce5a8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 20 23:09:34 2010 -0400
+
+ Plugin: Validate calls for NETWORK_IO and NETWORK_IP
+
+commit fbac72567e0d716f5581061bb573a1e507113277
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 20 23:01:45 2010 -0400
+
+ Cheetah Plugin: Add NETWORK IO/IP
+
+commit 67d02bbe5a7ec3874efc7f75505f1d7dd3bcbf98
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 20 21:08:35 2010 -0400
+
+ Cheetah API: add CORE THREAD CONTEXT
+
+commit 151b76d31c73d7b6753b23a430a50f470252c584
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 20 21:05:37 2010 -0400
+
+ Cheetah Plugin: adapt code to new API
+
+commit 7bd98e2b42b340f0581c86f2dc1845d3247d5993
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 20 19:59:01 2010 -0400
+
+ Security Plugin: adapt code to new API
+
+commit 5b5187b75a529891eabc33ac8326d911434c6c2e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 20 19:50:13 2010 -0400
+
+ Plugin: Add stages 50 and 60 to run command
+
+commit d5ea021bbf50a8b87dcd0c134eff00a4ba43503b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 20 19:44:12 2010 -0400
+
+ Plugin: set global stage map
+
+commit c958e5f1a7923e334d69b773e9bb94b88af40b0e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 20 17:58:58 2010 -0400
+
+ Fix data type
+
+commit 7aaf23da52c68fab31beb9dad4f3ca8b1acc9be9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 20 17:45:36 2010 -0400
+
+ Plugin: New internal structure
+
+commit 214d0d820734ba23a54bbf8d082225984dc639d1
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Tue Apr 20 12:27:40 2010 -0400
+
+ Repalce __uint32_t for int, we don't need to use __uint32_t
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit a1cecf6364aa9d814be656be09a0b60de3479ad1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Apr 20 12:09:16 2010 -0400
+
+ Plugin API: description fixes
+
+commit 55919adde457f7cae9816b0ad3315452e4810fd4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 19 22:57:40 2010 -0400
+
+ Disable plugins
+
+commit a05898d496ca31c9e948eda126236a46cf7a2006
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 19 22:57:17 2010 -0400
+
+ Plugin API: use spec definitions
+
+commit 82957c6dc5669f9d5e0f133b055a73bc7bfd0368
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 19 17:20:18 2010 -0400
+
+ Cleanup utils.h
+
+commit 79887c974b2ca79d85fc7e23c4fc3050286bf971
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 19 17:17:05 2010 -0400
+
+ Deprecate SendFile()
+
+commit 817dc521016ea33e8d5c71048b588707535d68cc
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Mon Apr 19 16:59:28 2010 -0400
+
+ Create layer to handler the send of data using a socket
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit b446620f0632a0cada30c9df7940f91f3a9a1529
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 19 14:34:34 2010 -0400
+
+ Plugin API: little style change
+
+commit b44a645ab4a13d1986e64f0d3320152c95bc0351
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 16 17:28:42 2010 -0400
+
+ Plugin API: Change data type names and minor fixes
+
+commit ac924b118dcd6e588cfeb977e96d028252669220
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 16 14:33:32 2010 -0400
+
+ Plugin API: Add a list of Monkey functions exported to each plugin
+
+commit 7760b28036d893be26e00f39017de0526156dad6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 16 13:37:36 2010 -0400
+
+ Plugin API: Add mandatory hooks
+
+commit 354680601f978469898f302f46b0f92238e04764
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 16 13:16:03 2010 -0400
+
+ Plugin API: Add function hook names
+
+commit 5473daaf2674fdc374b3de53387c86324e9a246a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 16 12:57:38 2010 -0400
+
+ Add Plugin API spec
+
+commit 13a23ecbda005e21537aee68bf07d5d7654d3928
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 10 19:00:50 2010 -0400
+
+ Update branch version
+
+commit 6151a552c7b263afd3dd1dbe1d5cb65a36f9f595
+Merge: 5df493b 88db354
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 10 18:59:24 2010 -0400
+
+ Update configure script
+
+commit 88db3540cd7fcd22eaba8f2f4a225996960acf39
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 9 20:24:30 2010 -0400
+
+ Update ChangeLog
+
+commit 456fa7adae97f9a2a5e2b9358f1c7229662f5d29
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 9 20:22:37 2010 -0400
+
+ Monkey 0.10.1
+
+commit 9c0b03f7b2175df327ffe5f8734f827284be64f4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 9 16:43:12 2010 -0400
+
+ Makefile: remove 'Running Monkey' message
+
+commit 07ba1cc1d225c373f9ea2a930d6933b57be2e46a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 9 16:39:50 2010 -0400
+
+ Configure: add DESTDIR support to Makefile
+
+commit 31bf65ca0a0fe2ab070292f1f4f1f9821da432ab
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 8 10:53:21 2010 -0400
+
+ Config: fix reader for line with multiple values
+
+commit 9006e228ae771ea70483f29f14eb37fbccf895c7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Apr 8 09:52:34 2010 -0400
+
+ Configure: move env vars to global context
+
+commit d4cbe4cebf3215a9137ff447cd539dd638d45e50
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 5 02:37:50 2010 -0400
+
+ Update changelog
+
+commit f8873bf50e6a5dc3333189c73cf9ad52ac105ffd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 5 02:31:25 2010 -0400
+
+ Monkey 0.10.0
+
+commit d5e41dab115fcda61e89d3de6998a1aa53e3832f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Apr 4 00:13:34 2010 -0400
+
+ Configure: fix test validation
+
+commit aaae7cba11f4d87f339cc6b3f66561c2087b447a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 3 12:35:29 2010 -0400
+
+ Configure: fix test
+
+commit 566fff86e2b19bb4b78cd9603d86a0d8cad6cd3f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 3 11:41:31 2010 -0400
+
+ Do not read SOMAXCONN using deprecated sysctl()
+
+commit 7e11eb5d2000d574340a919c8c33a006384faa52
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 3 11:40:21 2010 -0400
+
+ Configure: get DEFS from environment
+
+commit 454a52b0ec8aa54edfe70db9a5fd1ef3b909dc1e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 3 11:31:16 2010 -0400
+
+ New Macro DEPRECATE_SYSCTL
+
+commit 96659604becde82325beb0e4ea6c64fd42e1edbf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Apr 3 09:48:14 2010 -0400
+
+ Configure: read STRIP enviroment var for binary stripping
+
+commit 689982d72cc273c0dfcb47b1fe92148ef77f7baf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Apr 2 21:05:43 2010 -0400
+
+ Cheetah. remove dummy .c file
+
+commit ca56f2d3b948de35a02dd94207d37a34bf583841
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 29 14:14:28 2010 -0400
+
+ Cheetah: change some breaklines
+
+commit 0e8323b723db0c605fcc400ffc1e4eff67f0fe44
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 29 12:34:43 2010 -0400
+
+ Cheetah: New 'clear' and '?' commands
+
+commit 4347b4d42c05a7914602b1c6c93965b21c83ffb6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 24 15:03:23 2010 -0400
+
+ More code cleanups
+
+commit bc12a003630e471dcefaa1c9abfd9b10f629f321
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 24 14:56:51 2010 -0400
+
+ Remove old getdir configuration variable and code cleanup
+
+commit f3c8491671eeef106c2272f4d504174080074499
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 24 14:43:00 2010 -0400
+
+ Cheetah: Add plugin version to status command
+
+commit 2f5a60f18b4b23a7c38b9cdaa6a7e444f63ccee1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 24 14:35:07 2010 -0400
+
+ Cheetah: colorize the shell
+
+commit 6e61c3783dd1c0383634d06bc5c0546adc1f92a4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 24 10:14:41 2010 -0400
+
+ Configure: default shell to bash / fix install permissions
+
+commit 3384597042e1488464bc277f75c6e1b5b32ebb4e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 22 14:06:24 2010 -0400
+
+ QA: Checklog, add rule for query.htt
+
+commit 13af8147a9a5f7fd849425502d7460f2547e2684
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 22 13:36:17 2010 -0400
+
+ Monkey 0.10.0-rc5
+
+commit 5ee340cc98cb2401c1cab07df50981a302509618
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 22 13:32:14 2010 -0400
+
+ QA: Checklog, add rule for simple.htt
+
+commit fc47daab1e7f37f4da448828eaf674d41cf4d11e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 22 13:32:03 2010 -0400
+
+ QA: Checklog, add rule for redit_301.htt
+
+commit 242dec902ccc52fc22e8d2c40c65c7a249b3365d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 22 13:31:20 2010 -0400
+
+ Logger: register 301 and 302 status in acccess log
+
+commit 58bc216d3845bcc20500a1e5db603ab821ac0cae
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 22 12:58:06 2010 -0400
+
+ QA: Checklog, add rules for ranges_*
+
+commit d0bedd1488ffd5731f934161ba3c20a617123b93
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 22 12:38:51 2010 -0400
+
+ Core: Register partial content status in access logfile
+ Logger: Register length of partial content instead of file size
+
+commit 68a93e9c89205f58b9ebaddf99f6b69f14958652
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 22 11:22:07 2010 -0400
+
+ Logger: write size 0 for HEAD method request
+
+commit 552f879cfc09abec99a30340a1daa80dbf57d056
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 22 10:25:46 2010 -0400
+
+ QA: Checklog, add rules for post_*
+
+commit 85d824e81432f9aec59686f503cda6fb50a59638
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 22 10:25:26 2010 -0400
+
+ QA: Checklog, add rules for path_transversal*
+
+commit 80b1c63c1345268332b69db3470113047dc6508b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 22 08:46:06 2010 -0400
+
+ QA: Why post_test02.htt sometimes fail?
+
+commit f591349d633dc387d7bfec32c1bc94ec86c0f90a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 21 20:02:12 2010 -0400
+
+ QA: Checklog, two new script for if_modified_since
+
+commit cc4f43007f79b252a2d9ddd77eb8cd10d68b2f17
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 21 19:55:49 2010 -0400
+
+ Enable log register for '304 Not Modified status'
+
+commit 90ffabde40a48010f4a079db060b6e1bb73bbe66
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 21 19:29:52 2010 -0400
+
+ QA: Add new rules scripts for checklog tool
+
+commit 78d47394c886595420c6e8b969860d5d87ac411d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 21 19:28:26 2010 -0400
+
+ Little fixes for checklog tool
+
+commit cf308dc26e03c32d8859ad245f43533c3955ee63
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 20 20:23:14 2010 -0400
+
+ Improve checklog messages
+
+commit 8af3091a19845652202b208fd05e1e547c09834f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 20 17:47:10 2010 -0400
+
+ QA: New checklog program, check access and error logs based on rules
+
+commit 0d9fed0966f49b9fb133f8bb01996a22e655eb3d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 20 17:46:27 2010 -0400
+
+ QA: Add new option to run_tests.sh: -l, check logfiles after each check
+
+commit 3ae5a2f1969140c2b5e8edea908708a581542398
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Sat Mar 20 16:28:30 2010 -0300
+
+ Add mk_utils_get_somaxconn() function
+
+commit 5272a1ca131d382b6b1dae9b9e7eee517b6e0b25
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Sat Mar 20 16:25:55 2010 -0300
+
+ Revert "Add mk_utils_get_somaxconn function"
+
+ This reverts commit eca13bdb3e2e2896fe8cd586b6fd4799747983f9.
+
+commit eca13bdb3e2e2896fe8cd586b6fd4799747983f9
+Author: android <android@box.(none)>
+Date: Sat Mar 20 16:02:00 2010 -0300
+
+ Add mk_utils_get_somaxconn function
+
+commit 378858f7f1c4ede46a24534799e40f7e0f310a91
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 18 18:39:43 2010 -0400
+
+ Fix error log, add EXIT_ERROR macro
+
+commit f6073febf9fbbe565accac24066f5da9f7480180
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 18 11:41:40 2010 -0400
+
+ Configure: Do not copy README and INSTALL from lang directory
+
+commit 4dcaeb433029b41851e173b54adb41281a2fa5f7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 18 07:39:36 2010 -0400
+
+ Monkey 0.10.0-rc4
+
+commit 19ab24c589910a991fd147e9d6a14111c0cc9467
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 18 07:36:46 2010 -0400
+
+ Update ChangeLogs
+
+commit 41c5814e1806507e68e795232495032e38ec9527
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 18 07:31:12 2010 -0400
+
+ Update README information
+
+commit 8c0d05ab919779d05dd364e76fa9cd66c6662759
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 18 07:20:30 2010 -0400
+
+ Configure: remove old 'lang' and 'cgibin' options
+
+commit 9a034287cc60536e66a832bfd07cd02195ba21c9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 18 07:18:34 2010 -0400
+
+ Fix configure script for make install
+
+commit 585ea1b61686f562eeb61dfcacdcebd72eb9dbd1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 18 07:01:52 2010 -0400
+
+ Change configure script email address
+
+commit 9e3297ce72b4b560bc27989ae6132a444cc8fbb1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 17 20:10:14 2010 -0400
+
+ Remove old nostalgic internal doc
+
+commit e75aea23a746d7a9071c030486fda4dab59fc563
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 17 20:09:01 2010 -0400
+
+ Remove old comments
+
+commit 1fb4f46dff0fd2c26dea106aaabd2d04a67e912f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 17 14:35:33 2010 -0400
+
+ MK_TRACE: Get MONKEY_TRACE value just on start up
+
+commit 59f97f3a9a12fb3368e1cb77db11b07c03910ebc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 17 10:15:33 2010 -0400
+
+ MK_TRACE: Read MONKEY_TRACE env var to focus on specific source files
+
+commit 59fbca2af7af16a9b2b9a450a9aab774ae47ed3e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 17 10:10:10 2010 -0400
+
+ Improve comment
+
+commit b4f3f464a06cfb707541079401fc7e94b90fe754
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 17 10:07:37 2010 -0400
+
+ Remove comment
+
+commit 1d6339c6d27a3cedade92b85a380a9daad7a06d5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 17 06:30:19 2010 -0400
+
+ Fix connection header responses
+
+commit 369cc1ea57dca21fe63195654793e1c499243d93
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 17 06:00:15 2010 -0400
+
+ QA: Add scripts to check connection header on HTTP/1.1
+
+commit 6e00e9e0f24ddec2b990e4acc6d57958c7adea3b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 20:50:31 2010 -0400
+
+ QA: Add scripts to check connection header on HTTP/1.0
+
+commit a83c61ef5477f8364f9bd4d7d884fb9e0101304c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 20:22:26 2010 -0400
+
+ Comment block debug
+
+commit 552d2bab317270f5a4a1dfa3bcfedfc9fbde7960
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 20:19:03 2010 -0400
+
+ Fix Headers TOC parser, use body length as limit
+
+commit 817ae134f3ccc302d48b19715306906c5b416428
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 18:11:24 2010 -0400
+
+ Close request if 'Connection: close' was specified
+
+commit 12b7719ad682a099689201262f0d4c9aecce1b21
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 17:57:06 2010 -0400
+
+ Send Connection header for HTTP/1.0, for HTTP/1.1 just if a KA was specified
+
+commit 298b24d41cbcc08762ef4bbc5bdc4968d5365002
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 16:20:55 2010 -0400
+
+ Fix Pipelining check
+
+commit ae9dc05f992f97b4a81652b7e53b2508b5ebeb8d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 13:20:52 2010 -0400
+
+ Add CRLF to default mimetype
+
+commit 3513dc9ef9b11d037e0637d784ad0165860b4e93
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 12:34:53 2010 -0400
+
+ Monkey 0.10.0-rc3
+
+commit c9384332d6361bac86a0486e5ff256f9bb24d6cb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 10:12:48 2010 -0400
+
+ Fix conx timeout, for KA use KeepAliveTimeout value
+
+commit 8777601d9c0c48bdaa518d3ebb63801c5b866d52
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 10:01:38 2010 -0400
+
+ Fix timeout check / update scheduler for KA connections
+
+commit a930ebd8948c4f40b7de1253cb767596d403f209
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 09:34:07 2010 -0400
+
+ Fix access log / EXIT_NORMAL value
+
+commit bcdfe84d57033359604485a1566d256d8768cd76
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 09:25:04 2010 -0400
+
+ Fix error log formatter
+
+commit c9970f74590ef1df28ffb2a7fe30af4e9e988358
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 09:03:20 2010 -0400
+
+ Fix content type header for error pages
+
+commit 2499c5f6a9baf05539ad5d2cf80f9535778e2025
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 08:58:30 2010 -0400
+
+ QA: Add script to test hexadecimal request
+
+commit 152ba4b48fb3b656a3a350eb4b6af7f4a9a54d4f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 16 08:58:12 2010 -0400
+
+ mk_utils_buffer_cat() requires buffer lengths
+
+commit 339e5437fee655259f2d4d2ce6d5a4125e7170ab
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 15 00:16:12 2010 -0400
+
+ Little improve in pipelining exception
+
+commit 79ba6d1c763c0ec10099d5f50bf5aa524c043b8a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 14 23:56:37 2010 -0400
+
+ Fix broken Pipelining support
+
+commit 2a5dfc7f9f4862de227ffe6e0d6683397090c9bd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 11 19:12:52 2010 -0300
+
+ Monkey 0.10.0-rc2
+
+commit d591a1f080e7c9bd39eb41f4297fe40d2482fb18
+Merge: 4a98db4 306b7d1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 11 18:35:14 2010 -0300
+
+ Merge branch 'master' of git+ssh://repo.or.cz/srv/git/MonkeyD
+
+commit 4a98db4b8fced0fd11bddebd938c06b7bbc58219
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 11 18:33:22 2010 -0300
+
+ Change mimetype's list order
+
+commit 306b7d1b85c6d87d8ebe25bd3d297d0b7281b4ef
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Thu Mar 11 19:05:22 2010 -0200
+
+ Fix line width in utils.h
+
+commit 623c267466ad47db6130222755175d1ccffb112f
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Thu Mar 11 18:57:57 2010 -0200
+
+ Adjust buffer size in mk_utils_int2mkp
+
+commit d5ce48f646aa2c61b4a2230f4ab6cf7bba80f55f
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Thu Mar 11 18:47:50 2010 -0200
+
+ Remove unused function mk_utils_toupper
+
+commit ae20aa03cac2621a55f7b58e60d73a71c3d84a39
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Wed Mar 10 19:46:21 2010 -0200
+
+ Add path traversal tests to QA package
+
+commit 41cc8bfb7d8f067abc639c7eac46a26bc4500f13
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 10 13:10:36 2010 -0300
+
+ Mimetype: free memory used by 'type'
+
+commit 75b4743cc86b1f460242f606edf86a35e726006f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 10 13:06:41 2010 -0300
+
+ Mimetype config reader: use new config.c API
+
+commit 9c944b02362d09ab4f88539ff8298062421528d8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 10 13:02:01 2010 -0300
+
+ Fix config reader, do not read empty spaces
+
+commit 41ab255740030383bbc82fdd7cd1029b8690e208
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 10 12:29:41 2010 -0300
+
+ Just allow HTTP method and protocol request in uppercase
+
+commit b941b74d318878f0710934d14df71c95eefed2af
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 10 12:02:29 2010 -0300
+
+ Fix mimetype add overflow
+
+commit 4f51da08d9bc4abaffb87fb639714d5373573ac5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 10 01:04:01 2010 -0300
+
+ Revert mimetype changes
+
+commit 9fe3146871e92b7b94d3b6a3c348925959548f35
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 9 21:59:00 2010 -0300
+
+ Improve response headers composer
+
+commit f3273bee74e4ec848c58e8ba5308c93deaee6b09
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 9 18:17:20 2010 -0300
+
+ Remove MK_IOV_HEADER_VALUE
+
+commit 175ae3ce5dc37767cc6a7499bc0d8fbf79d7018a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 9 16:38:49 2010 -0300
+
+ Pre alloc IPv4 memory buffer
+
+commit 77450cdb45f62f676904f5af92e182f4431734fe
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 9 16:26:44 2010 -0300
+
+ Free ipv4 mk_pointer
+
+commit f30a6f206c329520db702ac4cea05f7dbebae3c7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Mar 7 14:34:14 2010 -0300
+
+ Abort dummy connections
+
+commit 676590f43bc3eaafcfe097ff77a919104eccc7a3
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Sun Mar 7 12:53:35 2010 -0300
+
+ Fix bug in backward directory check (Directory Transversal Vulnerability)
+
+commit ddb98ea2fd573d398f7399575c0302df1fa3d380
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 6 00:58:22 2010 -0300
+
+ Remove htdocs/php directory
+
+commit fe006c18627474d7308352d36053f4a20d5ba2b0
+Merge: fed4b4c b509b0a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Mar 5 22:09:15 2010 -0300
+
+ Merge branch 'master' of git+ssh://repo.or.cz/srv/git/MonkeyD
+
+commit fed4b4c670060907b4094bc91c3f9a5bd9060585
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Mar 5 22:01:32 2010 -0300
+
+ Change Website URL in default index.html
+
+commit 5df493be908591a92574fb497e8e7480ae753ed2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 3 15:44:09 2010 -0300
+
+ Set non-blocking socket on accept with accept4()
+
+commit af406812ec7bdbf9d0aa85f5cb508960106a078d
+Merge: 90d308d b509b0a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 3 14:36:19 2010 -0300
+
+ Merge branch 'master' into v0.11.0-dev
+
+commit b509b0aa20832bafecca73de8bef68820e10b73d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 3 14:26:44 2010 -0300
+
+ Cheetah: Remove connections counter
+
+commit f021ec45b944692cef51b19157e223a91419d739
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 3 14:20:07 2010 -0300
+
+ Remove connections counter
+
+commit 90d308d9ec799424c2e6c37c4352ffcb1f1b7625
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 3 09:06:05 2010 -0300
+
+ Update version number to 0.11.0-dev
+
+commit 7665dde054961a1933a19534c8ed5a8141c9127c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 3 08:54:38 2010 -0300
+
+ Add missed plugins Makefile
+
+commit 91b45a755e0feaf5f1994e175f446101a391c9eb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 3 08:52:08 2010 -0300
+
+ Add DirListing module
+
+commit 82930bcf08f8c82bcea45e6b3ecd6b1b16e935a4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 3 08:49:38 2010 -0300
+
+ Add Palm Plugin
+
+commit dd0c1e749c1b37db33ead939d8c6b74d687c8ef5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 3 08:47:18 2010 -0300
+
+ Add Palm server
+
+commit 94f8ca3d923f8af10b4a423d2674b41867cf278f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 2 17:53:11 2010 -0300
+
+ Monkey 0.10.0-rc1
+
+commit 3393ae7a35bd6fb69ae1ff20b7da23f5a782b427
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Mar 2 17:38:52 2010 -0300
+
+ Remove development code
+
+commit d49af57b2d5bf2b6e4254bf3a57e646f130f9ef1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 1 22:40:30 2010 -0300
+
+ Add cast to trace formatter
+
+commit 9093e2628fe89baee318cb2c80ac293059018146
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 1 22:26:40 2010 -0300
+
+ Add Eduardo's email to copyright header files
+
+commit 2e294fd900c2829150a9f6d0bed92000cd0fcd15
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 1 22:23:57 2010 -0300
+
+ Update Copyright date in files
+
+commit 34345f8dbc2b874615230acdad104a5142d46f51
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 1 19:01:19 2010 -0300
+
+ Change Monkey HTTP signature
+
+commit 42e2c966da6db4f725cc0ec8e90cad97a3ef760f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 1 18:35:19 2010 -0300
+
+ Remove old data
+
+commit 38a4520838fd7d71c4182efc077ad5427bde3a4a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 1 18:30:39 2010 -0300
+
+ Minor fixes
+
+commit 6df45ac3ae32b2a18d77b87801c6477c2ebdd555
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 20 12:08:29 2010 -0300
+
+ Add TRACE message when connection arrives
+
+commit 02d5c2db9409a732732af472ae96d21b296edefe
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 19 18:04:50 2010 -0300
+
+ Palm Plugin: add mk_plugin_send_chunk()
+
+commit 4c052c3510696edb98b61746f613060f5c0f7a71
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 19 17:15:04 2010 -0300
+
+ Experimental Palm Plugin (disabled by default)
+
+commit 5241718aa79a27fe67a0d1e796599982c48f610b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 19 17:11:34 2010 -0300
+
+ Configure script: do not try to compile plugins if they contains a file called DISABLED'
+
+commit 2696771d2b11070e1a1980454c2d4efe82fa207b
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Feb 19 16:51:23 2010 -0300
+
+ Remove line that say something about run monkey in benchmark mode, this option doesn't exists
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit e71941aa183a63be1c58c9eabc5808d8d3c39561
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Feb 19 16:50:43 2010 -0300
+
+ Initialize var for colors in mk_utils_trace
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit f16599603132c6049a4128e19198efdcf421bed5
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Feb 19 16:37:26 2010 -0300
+
+ Initialize the var event at mk_epoll_add_client()
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit aeb80aaf5bda55baf74c7c9a65a9519942dd25d2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 19 16:55:34 2010 -0300
+
+ Add some TRACE messages
+ Remove old socket_timeout function
+ Code cleanup
+
+commit 531de6c29da45dac8d2de492e78e12bf1ba817dc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 18 16:48:48 2010 -0300
+
+ Add TRACE messsage when calling plugin stages
+
+commit 1a0f7211d2931c7236f21cf9180de9159938e65e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 18 15:57:58 2010 -0300
+
+ Fix trace message without compiler conditional
+
+commit 0e176c1afe3af0d21e9d7a54c53a1303b5ca1bf1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 18 15:37:29 2010 -0300
+
+ Add 'trace enable' message
+
+commit 202bf06978457559fe7eed2c2f9d28d698ac2d75
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 18 15:32:10 2010 -0300
+
+ Improve TRACE colors output (just for dark background terminals)
+
+commit 9645a0513233041a3e7c7e72c1efa23e1f401e7a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 18 11:24:06 2010 -0300
+
+ Plugin API: Export PLUGIN_TRACE macro function
+
+commit 15f021f3ccfd8ea453bcbac343a8bc8df8947fee
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 18 11:01:37 2010 -0300
+
+ New TRACE mode, configure with --trace to enable trace messages
+
+commit 26402a33dea877b29f9e1654a21b2c41479d6c4e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 16 00:25:00 2010 -0300
+
+ Remove old files: modules.c and modules.h
+
+commit 48188460d235d4e752f32305f236d9b4b3b3ee3b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 16 00:13:38 2010 -0300
+
+ Remove trash
+
+commit a9ce2ded6d5d243852718c6ad83c29793f204526
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Feb 16 00:09:14 2010 -0300
+
+ Plugin: New interface for STAGE 40, it allows async calls to read
+ and write events on demand by async plugins
+ Plugin: Removed sub call stage_40 loop
+
+commit bc0a375465dfd547e25b57c5caa4f3e00f622c36
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 14 21:12:32 2010 -0300
+
+ Logger: move specific values to header
+
+commit a79268333bea7a29a9b412b9819ff8f7126fa548
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Feb 14 13:56:39 2010 -0300
+
+ Config: Add new Listen directive to restrict the incoming connection to a specific network interface
+
+commit c95bf34111a974cee3d48e618f179bf687a781d9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 13 23:50:33 2010 -0300
+
+ Add --debug option description to configure help
+
+commit 45e7e540a2493dda5800de3e1725948be94556c4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 12 18:35:37 2010 -0300
+
+ Cheetah: CTRL-D runs 'quit' command
+
+commit 9bb65d647dfe57a8b2ecd5f259e5956679c5792a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 12 18:31:52 2010 -0300
+
+ Cheetah: Fix segfault when pressing Ctrl-D
+
+commit 100bd0be93f5ebc31b3ab85bd37abe569c5f7715
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 12 18:04:51 2010 -0300
+
+ Log Error: add URI requested to 404 and 501 status message
+
+commit b5a0b534072c86b75ef839de42540e593862b610
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Feb 12 17:18:01 2010 -0300
+
+ Fix to use mk_pointer_set and mk_mem_malloc_z
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit ea5164fa5a943d587fdd3a05197a3e40ccda9fa1
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Feb 12 17:06:24 2010 -0300
+
+ Fix mk_config_get_host to create a pipe only if the (Access|Error)Log entry exists. Fix mk_logger_worker_init to check if the pipe exist before add it to the list
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit cc0ac7eea72d9e400432bdc4e1b147341aa2924b
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Feb 12 17:04:33 2010 -0300
+
+ Change char *ipv4 for mk_pointer ipv4 in sched_connection. Fix all the code to use the new form
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 99416fd62ffa9082654e1a7fbd05898fc4bb83cd
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Fri Feb 12 15:29:10 2010 -0300
+
+ Added option --debug so it will use -g to compile by default it will use '-O2 -Wall' and move strip to 'make install
+
+commit 4fedc5c542d8b58afb49d81b5d8302a1b0468722
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 12 14:06:58 2010 -0300
+
+ Add compiler name and version to welcome message
+
+commit 589c614558a8a6c951285fb09deba18f7d8ae06e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 12 13:18:52 2010 -0300
+
+ Plugin: add mk_plugin_preworker_calls(), it allows
+ to each plugin to set a pthread key (plugins runs
+ under thread context
+
+commit 0b3e2b44a4daefe86135ed1f8049d882299d5dbb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 12 13:00:54 2010 -0300
+
+ Replace header files mode from width 8 to 4
+
+commit 6ac9c63d074d2ee99152ac151cd4a05254ed7d6a
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Feb 11 22:55:12 2010 -0300
+
+ Added .gitignore so 'git status' will not show any *.so,*.o,Makefile and *~
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit 411a933bf9721ee700dd68cc90e6d0b68922ad58
+Author: Jonathan Gonzalez V <zeus@gnu.org>
+Date: Thu Feb 11 22:46:36 2010 -0300
+
+ Change the FSF address and update LICENSE with the new address and some texts
+
+ Signed-off-by: Eduardo Silva <edsiper@gmail.com>
+
+commit d5fea5c1bdc0b1026057ada429971a01c2bce960
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 11 14:33:26 2010 -0300
+
+ QA: Remove range test 04 until httest fix their bug
+
+commit 6d567eaeea3330000546a9f36258c0340f1208c7
+Merge: 0e9bac7 09b403e
+Author: edsiper <edsiper@monotop.(none)>
+Date: Thu Feb 11 13:54:38 2010 -0300
+
+ Merge branch 'master' of git://repo.or.cz/MonkeyD
+
+commit 0e9bac71af626a0e77bbd6801749361aad645aec
+Author: edsiper <edsiper@monotop.(none)>
+Date: Thu Feb 11 13:54:22 2010 -0300
+
+ QA: Add missed scripts
+
+commit 09b403ea9b6eb5d0fb61db7cf5a75b59222f01e2
+Merge: 2079cff bce7ace
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 11 13:50:25 2010 -0300
+
+ Merge branch 'master' of git://repo.or.cz/MonkeyD
+
+commit 2079cffb07b93697e746392f4a94c8adb7963964
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Feb 11 13:48:32 2010 -0300
+
+ Plugins: Add _mk_plugin_stage_40_loop() call
+
+commit bce7ace91fd6ebde6889f942db2015740edc7754
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Wed Feb 10 07:07:31 2010 -0300
+
+ Q/A test improvements
+
+commit dbc1569b94258fd83f93aabacc2a00e454b90ab8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 21 13:26:33 2010 -0300
+
+ Using Apache development C Language Style
+ http://httpd.apache.org/dev/styleguide.html
+
+commit 2d4ff8a01731a8e4e27a33f1a21ab777f4494c04
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 21 13:18:05 2010 -0300
+
+ Improve plugin handler return values and actions
+
+commit 00754101ddc997daae4ff4eff4634c8871e6c117
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 4 17:13:27 2010 -0300
+
+ Configuration reader: add 'read line by values'
+
+commit 5485636390b0a94641e9445f4ac6ac2d426f0d40
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 4 16:53:42 2010 -0300
+
+ Reduce worker client capacity to 50% in order to allow on each request open a new file descriptor
+
+commit 4b70581f6b1105c06a20f691cc86c62f6eb097cc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 4 14:26:59 2010 -0300
+
+ Configure: add --plugdir option to specify target directory for plugins
+
+commit b6f1e1fa7e92d29770b337d16ade1ed1bea34498
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jan 2 18:32:58 2010 -0300
+
+ Add old entries to Changelog
+
+commit d2cce9a9d499e307cc344da7f6f6f84cbf3d7be3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jan 2 17:51:41 2010 -0300
+
+ Update configure
+
+commit 5a86cec7a07b0c8f18217e62ce654feb5e1c2c4a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jan 2 11:52:10 2010 -0300
+
+ Security plugin: add shortname
+
+commit 06ec147ff5c0d831a3fcf8ed43ae9fc713811bbf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jan 2 11:45:26 2010 -0300
+
+ Cheetah plugin: add shortname
+
+commit 61113ec23373dffbdb967266ed92c3710fe55554
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jan 2 11:39:32 2010 -0300
+
+ Plugin: Load plugin and give new configuration directory assigned
+ Dirlisting plugin: use new directory assigned
+
+commit c896b0f3d8d300d0a66340dd38c10970af14eb9b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 1 11:50:59 2010 -0300
+
+ Move plugins configuration files to conf/plugins/MODULENAME
+
+commit 102a110a8f76b42fec0622a39c207573e1fd3293
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 1 11:44:29 2010 -0300
+
+ Drop old configuration and adapt configure
+
+commit 0c9cb7bec6f34b50f82f0a2bcfed757c6f152374
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 1 11:18:35 2010 -0300
+
+ Remove 'extras' (old modules interface)
+
+commit 32522cd411b77bbff2d93ecd68813c3f2138a124
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 1 11:12:04 2010 -0300
+
+ Deprecate CGI interface
+ Palm Server: add debug environment var 'PALM_DEBUG'
+
+commit a5583817722804f8256973b808213820a5f33351
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Dec 29 17:49:41 2009 -0300
+
+ Palm: change website url
+
+commit d9291f5eb85bfe9bedf05fce9b4fa3f8ae8b039b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Dec 29 17:32:20 2009 -0300
+
+ Plugin API: Add mk_plugin_load_symbol
+
+commit 4b3615e4b0d55497a8e1a5f16125a89b082d6af0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Dec 9 14:04:14 2009 -0300
+
+ Add MK_PLUGIN_STAGE_00 to plugin stages
+
+commit f2fe4903d7a990e8aa5c926f0a1d803dae58b5c8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Dec 8 08:26:42 2009 -0300
+
+ Plugin: read configuration file using config API
+
+commit 3d77acb11f5daed074ca427abcf1e214006eb2e8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Dec 8 08:19:23 2009 -0300
+
+ Plugin API: Export mk_iov_print
+
+commit 90bf701569e08d8b04884a15719879cc1494592c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 7 15:03:26 2009 -0300
+
+ Plugin: Export mk_socket_xyz calls
+
+commit 5b9c80d0f90941818b525ad5c8a36c055ae9f181
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 7 13:59:26 2009 -0300
+
+ Add dummy stage MK_PLUGIN_STAGE_00
+ Plugin: Export mk_pointer_set() as pointer_set()
+
+commit 51f470c08ce1015a1b40398c2942eff6a50c5b3a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 7 12:52:31 2009 -0300
+
+ Add mk_string_line()
+
+commit 7b1576ba1898c5c38c2332a75f7b4a5ae0b1b046
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 7 09:50:47 2009 -0300
+
+ Config reader: value ends when LR is found
+
+commit 517eaa5e729ff42b178d59772e59b106e3c17dc3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 7 09:50:08 2009 -0300
+
+ Remove palm from main configuration reader
+
+commit cd44d282f0b0ff2670af1fb99b783034e2973426
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 7 09:23:43 2009 -0300
+
+ Do not allow backward directory requests '..'
+
+commit f75e14248da2a646fefb3ac3e168689b7e0153ec
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 7 07:25:45 2009 -0300
+
+ Initialize uninitialized variables
+
+commit 1fc574ba7ab8278900b903f5cf339618a2ad2272
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Dec 6 22:07:54 2009 -0300
+
+ iov: buf to free non-zero allocation
+
+commit f9aebdc3ddba3ee560e37a28b73a5ecccc6898c4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Dec 6 22:01:48 2009 -0300
+
+ Set iov struct to zero
+
+commit 56a17e76f3cc1876aca26920f6608bcfdba2c9fb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Dec 4 12:06:21 2009 -0300
+
+ Add MK_PLUGIN_STAGE_30
+ Security Plugin: add rules for URI
+
+commit df12846d397b6dc8c4349a116ec9d82901ed84e4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 3 23:51:37 2009 -0300
+
+ Deprecate deny.c
+
+commit 90518c21544f7c98812c6e805a34841b8ff486ae
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 3 23:49:12 2009 -0300
+
+ Add security plugin file configuration
+
+commit ab2df2c02746c3aac65b9b34cf8dd38fe7b9c2f3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 3 23:48:57 2009 -0300
+
+ New Plugin: Security
+
+commit 814a1b4344edae09863090bfd5c1c8047c5cf8bc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 3 23:47:50 2009 -0300
+
+ Add MK_PLUGIN_STAGE_20
+
+commit 61bd256b545184b51169cbbb46bda74dd2698927
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 3 18:36:44 2009 -0300
+
+ Plugins :: Export new mk_config_* calls
+
+commit e30ce56348f1cb8f3b053fb0d560211957ec556b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 3 15:21:59 2009 -0300
+
+ Refactoring read/write handlers and pointers
+
+commit 4a2cc99fa9716ba4f0448e8dce320ea912fd3976
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Dec 2 12:20:48 2009 -0300
+
+ Change connection status when server will send content
+
+commit 5bed1d4b2ef1e5068de0135ad0e3f1481a22e0e9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Dec 2 07:09:13 2009 -0300
+
+ Add CFLAGS environment variable to Makefiles
+
+commit 3d4d69d119bae7b057b9f37b554d2fea486820cf
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Dec 1 16:51:13 2009 -0300
+
+ New configuration files handler
+
+commit 4b9978014a07532c5b7c416f143100ec735a75ff
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Dec 1 10:17:37 2009 -0300
+
+ Add plugins README file
+
+commit 63efae9c1334eb84e2316df16075a2657456d0e2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Dec 1 10:13:22 2009 -0300
+
+ Dirlisting :: validate file/directory struct
+
+commit 3f58cb866131c9117299deb7a36e52dad0aea696
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Dec 1 10:11:26 2009 -0300
+
+ Move plugins directory to root path
+
+commit d086213a240a59266e2752257816803c1057f1de
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Nov 29 20:22:59 2009 -0300
+
+ If URI is not found, before to send 404, check if a plugins on stage 40 would like to handle it
+
+commit 78bb4001fd3ccaa1ddb8ad023dbae3d0a0f6dc11
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 28 16:37:43 2009 -0300
+
+ On error, do not send content if it has not been set
+
+commit 13dfe273ddbbfd723ec5cf8e173cae52d723d554
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 28 16:32:12 2009 -0300
+
+ error to set_default_page return pointer
+
+commit 085d9cb8980b3c2aac91741f3ffcec098379647a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 28 13:33:28 2009 -0300
+
+ Fix configure Makefile creator for plugins
+
+commit 3f72ff8ab491f41a4214079b5e169396b9eafe1b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 28 13:24:23 2009 -0300
+
+ Update URL in welcome message
+
+commit d7f899b5b504bce9f75193884ea939e9662a188f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Nov 27 13:56:03 2009 -0300
+
+ Plugins :: Add _mk_plugin_worker_init() callback
+
+commit 3fb5bb5e3b0b95775431c7fc93b2d1a56d5d8525
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Nov 25 13:24:10 2009 -0300
+
+ EPoll: add handlers for close and timeout events
+
+commit 5cfe72a405985422482e3fcbe541735f4f8c7421
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Nov 25 13:09:03 2009 -0300
+
+ Fix gcc warnings
+
+commit 30ced4a77bdc65d99b45b76f4c7a4eba982e299f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Nov 25 11:54:02 2009 -0300
+
+ Remove unnecessary casts
+
+commit ac64677397669db7b60c5a306363feff2ec727f3
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Wed Nov 25 09:58:47 2009 -0300
+
+ Fix Charlie email in QA/README
+
+commit 85ae250851e330498c7d92ac8478f27e7e71b08c
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Wed Nov 25 09:57:54 2009 -0300
+
+ QA package
+
+commit 7a0dabad9e36f2e24e13f875345dd27e9e7197e8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Nov 25 08:59:25 2009 -0300
+
+ Fix method check length
+
+commit 9e4a9a32674069b23d2d2a0047007826be5fcef4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 24 16:05:53 2009 -0300
+
+ Fix TCP_CORK usage
+
+commit f3a99cccc9cc4f26a73392b2e0fc5b09764f93aa
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 24 13:56:09 2009 -0300
+
+ EPoll: change handlers struct and calls
+ Rename conn_switch.c to connection.c
+
+commit cd7e2623b05b6dfd82f1a4c100ae3a4755aa9790
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 23 13:54:19 2009 -0300
+
+ Deprecate CheckFile() and CheckDir()
+ Config: do not handle AddScript directive
+
+commit e313dbca4a21715411d8783e528ef65f1bef0e40
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 23 13:49:02 2009 -0300
+
+ Free client request struct when client hung up
+
+commit 792ccef8b207e14a23b0af1e232078ae6b2cdd0e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Nov 20 14:16:54 2009 -0300
+
+ Do not send Connection close header for clients < HTTP/1.1
+
+commit 23a70887740bc4e43937376a7923be9b562e1fae
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Nov 19 21:05:06 2009 -0300
+
+ HTTP: Optimize request parser
+
+commit c78896f7fa2b20a776511f8a9450607cb8e69dce
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Nov 19 15:32:52 2009 -0300
+
+ IOV: Free iov->buf_to_free allocation
+ Dirlisting plugin: Free tag entries
+
+commit bbc10cf70689dfb6bca1c1e1612e685852f94647
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 16 14:06:10 2009 -0300
+
+ HTTP: Close connections if KeepAlive is not specified
+
+commit 754f49d9de0b62e5ead1b70bf9cd29b6e2257323
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 16 13:54:08 2009 -0300
+
+ Dirlisting Plugin: send chunked data just for HTTP/1.1 clients
+
+commit 13c1cf14533cfe32cb76b21cf1ae3212885b7711
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 16 13:41:05 2009 -0300
+
+ Chunked Transfer Encoding: fix length
+
+commit 21105f9b770beed6ec638ce6e917920e47381323
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 14 18:24:46 2009 -0300
+
+ Plugin API: export mk_pointer_set
+ Dir listing Plugin: set content type to html
+
+commit 939f6731ef3878dd818e810ef4eda1e9d867fc4e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 14 18:11:59 2009 -0300
+
+ Fix directory validation after handler
+
+commit 9c251fc1a7cb30e6057f034f522e738cd0ff6826
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 14 17:51:38 2009 -0300
+
+ Cheetah Plugin: little 'help' text changes
+
+commit d0d8124cc519a641dc66ab33c09802b85e2a682d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 14 17:34:18 2009 -0300
+
+ Cheetah Plugin: New option 'plugins' to list loaded plugins
+
+commit 9e848ba129761c6614229ff81b0cc3aa0e8584e0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 14 16:56:29 2009 -0300
+
+ Forbidden access to directories without handler
+
+commit ec344b77cc40494a408232d36649bf3a0ed04697
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 14 16:45:13 2009 -0300
+
+ Push Directory Listing plugin
+
+commit 64deaf01865e92109f48870a746e3b18198aa0eb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 14 16:43:33 2009 -0300
+
+ Plugin and Core: Add functional STAGE_40 (handlers)
+ Plugin: Add directory listing plugin!
+
+commit 6ffe561b1cc8c657333cd0b5140c623e955d5262
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 14 11:21:47 2009 -0300
+
+ Merge struct file_info into struct request
+
+commit 769143fb8e7c3f071bbc0bbb9e4d73ce55de00e3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Nov 14 11:12:57 2009 -0300
+
+ Plugin API: Export 16 monkey functions
+ Dirlisting Module: use new API
+
+commit 877762e2cde8b3257277831046cf9a236b3571c2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Nov 11 11:46:09 2009 -0300
+
+ Configure: disable plugins by default
+
+commit cb923808a681bdf246d5e551f2f0a52b97d8f1c1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Nov 11 07:39:43 2009 -0300
+
+ Remove dir_html
+
+commit c7adfc26c6ab0660c41d17bb4a04cae243f4ef23
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 10 22:52:49 2009 -0300
+
+ free request comments
+
+commit e461cb259490bb969381b797cf444ec29b8cf9a5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 10 22:43:30 2009 -0300
+
+ Free client request headers->content_length_p
+
+commit 74d0a70b664083375c367ef12398c8a3b46ed7f8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 10 21:05:32 2009 -0300
+
+ Free client request log->size_p
+
+commit 6b6f5f7b56fed6209ff99e669fb0f6d79283a8bb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Nov 8 21:44:35 2009 -0300
+
+ Full connection Timeouts
+
+commit b487878a2bdcebd9132d88c290052c782a3a5e6e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Nov 6 19:17:15 2009 -0300
+
+ Add Timeout for processing connections
+
+commit 36ff69b5d14f434f1885d2ae00c9513d6b50bd2c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 30 14:55:10 2009 -0300
+
+ Remove benchmark mode, we do not needed anymore :D
+
+commit 10fda15061fe9ecde667922058c129de4e80798e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 30 14:37:44 2009 -0300
+
+ Remove dir_html feature
+
+commit 9b17eea1825fbdfb7f93734fe3575c6067755a57
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Sep 29 02:30:13 2009 -0400
+
+ Plugins loader autoconfigutarion
+
+commit 320235c5e70cddf726860075e476e318a1a010d9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Sep 28 22:18:33 2009 -0400
+
+ Plugin API: add malloc()
+
+commit af15c044d5e51a3383c2b0d538ce6ee12fc11d36
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Sep 28 18:32:14 2009 -0400
+
+ First plugin: Cheetah\!
+
+commit a947c4b95548f59d055378d696376cc63b3157c0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Sep 28 18:31:25 2009 -0400
+
+ Plugins: recognize plugins dir
+
+commit 023332cfea456a308a76136df65cbdcc6124391f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Sep 28 14:19:30 2009 -0400
+
+ Remove cheetah code from core
+
+commit 5cb0fe6dadda62bfa9b24d4ac7f905cf91a9d858
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Sep 28 12:43:48 2009 -0400
+
+ Plugin: Add STAGE_10 Loader
+
+commit 586a3192d028b082762f1d48fff813d1fce1657c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Sep 25 14:23:51 2009 -0400
+
+ Plugin: add register calls
+
+commit 3338ba5f12e53c867c54c2bfe501bcaf5daa282a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Sep 25 07:35:20 2009 -0400
+
+ Plugin: set to null next node
+
+commit a88c1bfd6648cf5da5e64d1c602e6727224b2675
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Sep 24 22:11:40 2009 -0400
+
+ Plugin loader
+
+commit 4e224354585557a928dde0efd1f2097ff9e6d14c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Sep 9 11:19:16 2009 -0400
+
+ Client request struct: add init connection time
+
+commit 2fc827a77c0d5ade9f49dba7425b5404a13d8865
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Sep 8 20:39:07 2009 -0400
+
+ Cheetah: Sync active/closed requests counter with keepalive
+ Cheetah: Update counters just if cheetah is running
+
+commit d70d554536fcb17f5264e484bd34da891ffc69f4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Sep 8 13:42:34 2009 -0400
+
+ Cheetah: first try for worker memory usage
+
+commit ee0f73b425ad3786a1ea4066dd22737edc38ec05
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Sep 7 13:37:04 2009 -0400
+
+ Cheetah: show task id in workers list
+
+commit 88849c2e9196a99ad23be26be7a44c38a60e8238
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Sep 7 13:36:36 2009 -0400
+
+ Workers export task id (pid)
+
+commit 19aa64a01847cce57a8c2a4ac6f68f9e125975f7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Sep 6 21:30:27 2009 -0400
+
+ Cheetah: Print running username in 'status'
+
+commit 967d9f047886ceb50456835ece57379ffa5f2039
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Sep 5 10:55:34 2009 -0400
+
+ Fix #34: mk_string_casestr is not ignoring case
+
+commit a55ebcb5b8e7c167ad9ddbde6af960aa11be65d2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Sep 5 08:48:52 2009 -0400
+
+ Add Monkey favicon.ico
+
+commit dd071fafd8f3b62cc7d2e32c1ee6ae1823633ed7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Sep 3 21:11:17 2009 -0400
+
+ New Cheetah Shell !!!
+ Add connections counter
+ Fix broken pipes on threads, avoid signal
+ Fix Post method validation
+
+commit 9de9fffc73b70cdac7e5ffe67fb212dc97cfb7e4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 30 16:57:50 2009 -0400
+
+ User home string to mk_pointer
+
+commit a21165c689be874f924c884404aaa145f63eee4e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 30 14:11:25 2009 -0400
+
+ Fix KeepAlive struct cleaner for next connection
+
+commit c6aca66f83ed9f4f859661a4aba83c90b7b3704b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 30 12:43:57 2009 -0400
+
+ HTTP: Default Keep Alive connections for HTTP/1.1
+
+commit 270ed5731f05e231c4ac31fee7bbdc88bb48a88b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 29 23:20:11 2009 -0400
+
+ Little internal changes
+
+commit bef7eb7196db16c839a43a80c66ab276d0482862
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 29 21:24:25 2009 -0400
+
+ Set TCP_CORK off after first sendfile() chunk of data
+
+commit 2af8085e9ce5b02b2133c2e99373fb72e4020f1e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 29 18:38:28 2009 -0400
+
+ Logfile: use clock cache for unix time
+
+commit faddaa90fc747e36501654def75b885df8fc0128
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Aug 29 18:32:25 2009 -0400
+
+ Do not re-check first method
+
+commit 93367fe47503cfc9c7b2cb64b720301109902729
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Aug 27 09:59:31 2009 -0400
+
+ Move back socket server to accept
+
+commit 9167765ad3a7a399721a7707adbb669e8fcd1dd5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Aug 27 09:44:24 2009 -0400
+
+ Fix compiling warning
+
+commit d6bbcd1302e5100aaaf4d1ee6046d37c609ddfe1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 23 21:36:08 2009 -0400
+
+ Fix bind error message
+
+commit a960c90a9e6ed88c3f52dd69121f123da3fa7366
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jul 28 19:31:00 2009 -0400
+
+ No delay socket server
+
+commit 8d9957b21f4de9979c79f93caf6a86596649bbde
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jul 28 13:59:33 2009 -0400
+
+ Remove redundant time conversion
+
+commit 603698fc2c2bcc1596f70fa99c190fb1b7ef112d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jul 28 13:40:12 2009 -0400
+
+ Fix check pending Post method
+
+commit 06c12d4fb5964d2d5a54c06947171f658aec6fdd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jul 28 09:20:15 2009 -0400
+
+ Server accept() after epoll notification
+
+commit 7015754e680a1b27d22675ccc1c6da4c398ffeee
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 27 22:10:02 2009 -0400
+
+ content type to mk_pointer
+
+commit 072304af9ff00bf28766df07c5040e63917edc90
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 27 21:12:07 2009 -0400
+
+ Reduce iovec entries
+
+commit 0ed4a449c37c8cfe8da5c669d0e0255bc7d30c75
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jul 17 09:01:31 2009 -0400
+
+ Remove old CGI call: M_CGI_change_dir
+
+commit 39a800a2e9af055a919d20b762e256e2f3f8978f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 16 01:38:15 2009 -0400
+
+ Catch write() return value
+
+commit 8efce2435d757dc0c907c19c4fcacb47243ebd7a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 16 01:35:42 2009 -0400
+
+ Add debug macro DEBUG_HEADERS_OUT
+
+commit 8e10b37e0bdeb40535a584ab97eb4f82adf6ff51
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 16 01:29:37 2009 -0400
+
+ Global egid and euid
+
+commit dac19c2fbaaa8129ca6634d2c838423154de33ad
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 5 13:53:00 2009 -0400
+
+ Rename HowItWorks doc to HowItUsedToWork
+
+commit 50859e6b2279711bb2414309e98c9e8aed270f0c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 5 12:32:07 2009 -0400
+
+ Remove old configuration directive for header and footer files
+
+commit dfa23a0584b5ed124cc915ecd2a4a7dd6265aa3c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jul 4 22:32:02 2009 -0400
+
+ dir_html :: list symbolic links
+
+commit b2fbd73c583b22c585de1c8fb77733497cd694fe
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jul 4 22:24:21 2009 -0400
+
+ dir_html :: Do not show hidden files
+
+commit 55ccebb42408d684349a307d8654e9289c970ca4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jul 4 13:47:24 2009 -0400
+
+ Add body NULL byte when receiving request
+
+commit bd0a0577b1d619e25a2d76b129fabbe843d9a607
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 29 22:48:34 2009 -0400
+
+ Fix status 501 message
+
+commit c4e655c73ac12dcdf0060ccf5cfa8d3e03c8bc3d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 28 20:38:38 2009 -0400
+
+ Adjust init details, port added
+
+commit 251073b94eac963e91cfdbe8da751cbb72f2be38
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 28 11:48:38 2009 -0400
+
+ Fix query string limits
+
+commit 18937e3eac72b9cb8fc244dcecdaa296c8be657c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 28 11:16:58 2009 -0400
+
+ Remove old macro
+
+commit c04c25bce0c5fdcc581bdb03ecd6a96d37fec13f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 28 00:06:47 2009 -0400
+
+ Add Palm files license
+
+commit a8b016473703cc61e77bc6f68552d4f6f9fd081c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 28 00:01:58 2009 -0400
+
+ Add Palm Server
+
+commit 22b5b5d6eee5bf44c420294c46dede70eddc5373
+Author: GreenFox <random247561mailtowatchutube@gmail.com>
+Date: Sat Jun 27 21:56:18 2009 -0400
+
+ Fix #29: add ico image/x-icon to mime type to support favicon.ico. Removed duplicate mime declare
+
+commit f65b6950013726642c017f6431aeaa7cf24532ab
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 27 21:48:32 2009 -0400
+
+ Fix #28: Crafted request produces Denial Of Service
+
+commit 646a287a0b2662ebb4bfcfa85c0ec00ed7956f8f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 27 20:44:39 2009 -0400
+
+ read :: Do not omit last byte
+
+commit 0b9440830a2b6c8b79b90795276a7a56592f8624
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Sat Jun 27 20:09:31 2009 -0400
+
+ Fix #26: Fix POST method
+
+commit 0881b47840c9923759356e46617f59058e3e5eee
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Sat Jun 27 19:05:49 2009 -0400
+
+ Fix #27 Small english typo
+
+commit b98f347846110fdffed48bf586e8dea88cdf06d9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 27 18:36:05 2009 -0400
+
+ dir_html :: merge new tags - part 2
+
+commit e56a4efcceba47f7256dbd475973a2e307559f36
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Apr 27 23:24:05 2009 -0400
+
+ dir_html :: merge new tags, part 1
+
+commit bcb5047702fa37b92dbdd7f77e6430525285ecbe
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 21 16:09:56 2009 -0400
+
+ New sanity check: test if O_NOATIME can be used
+
+commit 02328c50bc25cb69843c78a938af8a8ef4e1b91c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 21 10:22:19 2009 -0400
+
+ Add validation to open() when serve static files
+
+commit caec1541cb2f1fb1828732b58106a6d4d7ce891a
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Sat Mar 21 10:17:44 2009 -0400
+
+ Fix #25: Cannot serve files when execution user is changed
+
+commit 4e1a6d091b221c70582dd56f231b7b75433dc2e4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 21 10:14:47 2009 -0400
+
+ Fix function parameter
+
+commit 0b5e234802e9a1cc5e5d93a2feb747e0c74a052e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Mar 20 17:34:21 2009 -0400
+
+ Check for logfile permission
+
+commit 947bb00838d4e345aeee53c85fb6a1aa5786cea3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Mar 20 08:34:30 2009 -0400
+
+ Change default security configuration
+
+commit 9604701f6818e74ce2f09d886e24526286c39f59
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Thu Mar 19 16:15:32 2009 -0400
+
+ Fix #16: Set workers default
+
+commit 1bda3836279370030bf5ff4cbcc5495eae78feb8
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Thu Mar 19 16:04:54 2009 -0400
+
+ Fix #18: Wrong content-length when sending error responses
+
+commit a55a7844bf3720baed7b7400917e13ffaf7af54c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 19 10:15:14 2009 -0400
+
+ Reduce unnecessary strlen() calls
+
+commit 0812e887dc729f79a24970128a5bc50c5ee89572
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 18 17:51:16 2009 -0400
+
+ replacing strncpy w memcpy
+
+commit 8ef0021ab95a387aac15d0a7ec735c7126336f57
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Mar 18 16:17:23 2009 -0400
+
+ Little changes to improve speed
+
+commit b8800d620d39048f46c83a74fa507e7f39ecfe58
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 16 15:36:50 2009 -0400
+
+ Use memcpy in mk_string_copy_substr instead of strncpy
+
+commit 6077fce3c1e541182f336ec2d9708b18243be773
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Mar 16 15:09:34 2009 -0400
+
+ mk_mem_alloc_z() now uses bzero()
+
+commit ff08b195ea8924f8e909d20f353123944db8357a
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Mon Mar 16 14:24:11 2009 -0400
+
+ Fix #24: no memory freed
+
+commit 5a9c836775efaf63fb66611b891ed17c28e134d5
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Mon Mar 16 14:18:02 2009 -0400
+
+ Fix #22: Memory leak at dirhtml, no freed memory
+
+commit 25db2a83e560b680dfeb76f85f4ec06e4729322f
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Mon Mar 16 14:01:01 2009 -0400
+
+ Fix #20: Uninitialized request_index
+
+commit 2c81b5f499295cf291903dbb4ef3cfe1ea36a18c
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Mon Mar 16 13:56:02 2009 -0400
+
+ Fix #23: Feature that allow to show directory of local users is not working
+
+commit ad3001370f7accf191ed17d134ab919bdb17ef5b
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Mon Mar 16 12:40:14 2009 -0400
+
+ Fix #23: Wrong size in mk_mem_mallox_z
+
+commit 2b615b515a7063684933f059754d1aa3ab2fb056
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Sat Jan 3 10:39:35 2009 -0500
+
+ Fix empty content-length when status = 301 (Moved Permanently)
+
+commit 538f7094c2ee5991dae6f3ee62d33ee5b6e8ce27
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Sat Jan 3 10:35:56 2009 -0500
+
+ Fix regression in mk_request_header_find
+
+commit 646917d6d9a9514402cd567f418efba7cadfdd50
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 2 15:17:26 2009 -0500
+
+ Avoid memory allocation when checking method
+
+commit a6e890d0f2a6e93d9b8a1d14de192f5eb6ee45e3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 2 14:47:37 2009 -0500
+
+ Improve client list using an index
+
+commit 965ceed5165d73c387c125d0d7d41505985c70e8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Dec 26 13:45:51 2008 -0500
+
+ Reset header TOC before use it
+
+commit ded951e87690c130d09f6a3b35a4886b9987acaa
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Dec 26 11:39:54 2008 -0500
+
+ Add header TOC
+
+commit a964699b995f714860483263f87b651e1bcffe90
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 25 20:19:25 2008 -0500
+
+ Tune monkey using file descriptor system limit
+
+commit 973978aefac6fffdd5ede21c5c41de768d49d932
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 25 12:46:38 2008 -0500
+
+ Cleanup code
+
+commit 5cae27bb6c812b2ac733abeb8422db15aa39cca3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 25 12:17:45 2008 -0500
+
+ New server loop call, cleanup code
+
+commit ee243ce40581ccbc52fe3437fbb587f1ea93ef3a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 25 11:44:53 2008 -0500
+
+ Remove old convention for header and footer files for directories shown
+
+commit 3dd7a1a0e5923fe5c6cbf00a7e72fbd01f75da1a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 25 11:40:15 2008 -0500
+
+ Rename signal calls
+
+commit 06b2a42d2ead814e5e78e9a582e1ab54df769ae2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 25 11:26:57 2008 -0500
+
+ Separate worker call
+
+commit 33ad589f69e9b3efdb2de9e5da995465b0b05a8d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 25 11:02:52 2008 -0500
+
+ Socket server creation cleanup
+
+commit d2fc71d3951eadbd0b6c33994df082e23e7c5a55
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 25 09:50:18 2008 -0500
+
+ Close directory file descriptor
+
+commit 20b59dbad078dc5085bd9be0675dce4497f8435e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 25 01:56:38 2008 -0500
+
+ Fix worker logger I/O timeout
+
+commit c27a816dc24bc08db9b6554b8ed947452c51ef81
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Dec 25 01:02:04 2008 -0500
+
+ Fix get ip from socket
+
+commit 1157205b8f45ef083ffe9e386dad97737a55e469
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Dec 24 17:40:24 2008 -0500
+
+ Renaming functions and avoid gcc warnings
+
+commit 0069fdcee6dd60ae9b7ec449afe3b2ac595cc717
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Dec 24 17:04:47 2008 -0500
+
+ Palm, alloc buffer just for process request
+
+commit 538d126a33a6ecaaa112cae23be0ea88085f2320
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Dec 24 17:03:36 2008 -0500
+
+ Replacing deprecated inet_ntoa() with inet_ntop()
+
+commit 2df74272f5c39cb06ea2c451c2c36ca00a496987
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Dec 23 21:03:15 2008 -0500
+
+ Free uri processed
+
+commit 9bbf67c55720345456023a4ef9c26546df6fe959
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 22 21:21:59 2008 -0300
+
+ Close connection when client has not sent the full request and server buffer is full
+
+commit 30887e6dcb2e6c0e317e3eedfdc4b44e181b4b9d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Dec 21 23:07:43 2008 -0300
+
+ Fix end post method string in header check
+
+commit dbc90438f6b7e33a1eb806db7b5ec56baf883a61
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Dec 21 19:05:11 2008 -0300
+
+ Replacing bad english expression
+
+commit 443ff906d3f671ff072f52950132cc090f086358
+Author: Carlos Ghan <charlie.brown.uy@gmail.com>
+Date: Sun Dec 21 18:37:09 2008 -0300
+
+ Fix iov.c, thanks to charlie
+
+commit 3c101c86d5239158f0a941e7256e9ce83eefc2f9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Dec 21 18:06:42 2008 -0300
+
+ Fix #11: Reading beyond array due to missing list terminator, bug discovered and patched by Charlie
+
+commit 69c84c334549fdc78257b6e9760bb72803d19792
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Dec 21 17:55:31 2008 -0300
+
+ Fix invalid log error status, thanks to Charlie for report this bug
+
+commit c5a522ea8fec30fe1eecb9ad26dd40ca4a706e69
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Dec 19 09:24:55 2008 -0500
+
+ Improve uri check and code cleanup
+
+commit a7628885af7f1c9e85e55cf9817d1ba519da17c7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 15 18:10:33 2008 -0500
+
+ Reset iov buf to free idx
+
+commit b3fb2d534225e7bb8cfed676deed423b169bddc8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 15 07:56:31 2008 -0300
+
+ Add header iov struct cache
+
+commit d1fb540a868b28d485adde1e621fe42cd82d9531
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 15 07:25:01 2008 -0300
+
+ Fix Ticket #8: Fix logged method (in access.log), HEAD method, thanks charlie!
+
+commit 3cea704d31d8faaafcea51b8dd134636e0df145e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 15 07:17:39 2008 -0300
+
+ Fix ticket #7: A little fix in content-range response (thanks to Charlie!)
+
+commit 9af2c78dbb2a2963553d7a8835b0cf397daebe63
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Dec 14 18:25:51 2008 -0300
+
+ Add cache for log iov struct
+ Improves to Palm protocol
+ Remove unnecessary calls
+ on mk_mem_free, do not check if pointer is NULL
+
+commit f5152b5c343541c018609e64e786de6b3a41210f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Dec 1 18:59:30 2008 -0300
+
+ Experimental "Palm protocol" support
+ Add missed clock.c file to configure script
+ Remove old functions
+
+commit c387f495f524cde4075a72babecdb294d28884cf
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Wed Nov 26 00:51:17 2008 -0300
+
+ set socket TCP_NODELAY flag
+ little fixes
+
+commit e7a00c8b855b2b31c91562e7a49413e1c3cc5a9f
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Mon Nov 24 22:23:50 2008 -0300
+
+ Using mk_pointer for content length
+ Fix content-type sent in header
+
+commit eb938f18cb84b7840030fb9e333503b7820a82bc
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Mon Nov 24 21:35:44 2008 -0300
+
+ iov add separator CRLF and LF
+
+commit 6bfe6b01876ab0de601170a7eeaf35c20d5cab85
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Mon Nov 24 19:23:21 2008 -0300
+
+ Ticket #5: Byte-range request misbehavior (thanks to Carlos Ghan)
+
+commit 1204932a53b7a7040381345eb201995ed95606ff
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Mon Nov 24 19:15:44 2008 -0300
+
+ Ticket #4: Byte-range request will crash monkeyd (thanks to Carlos Ghan)
+
+commit b524ce25d6d4f0e9885a2392a7b283cc11ace84d
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Mon Nov 24 19:12:34 2008 -0300
+
+ header.c code cleanup
+
+commit 922c180a96e87a5928eaaf302c1876ac25fa50f7
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Mon Nov 24 18:56:21 2008 -0300
+
+ Use mk_pointer for iov static data
+
+commit c344a1ab277aceb5b91530b84f133c8e0a518fe4
+Author: edsiper <edsiper@monotop.(none)>
+Date: Mon Nov 24 16:42:00 2008 -0500
+
+ Improve mimetype calls
+
+commit 02cc8108f1f9ddf92a6bbb383478cb6606684523
+Author: edsiper <edsiper@monotop.(none)>
+Date: Mon Nov 24 15:00:28 2008 -0500
+
+ Add GTM time to clock worker
+
+commit e50e4959238aedb6fa8fe7a167edd0cb146a699e
+Author: edsiper <edsiper@monotop.(none)>
+Date: Mon Nov 24 12:48:33 2008 -0500
+
+ Keep http status as str
+
+commit 77b227df74e37773c14d71f8a68708f2ba299ebe
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Sat Nov 22 09:46:15 2008 -0300
+
+ Remove old PutTime() func
+
+commit 7425d2d9f9530870d8d3b743e7a8d0122f4a5784
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Sat Nov 22 09:42:09 2008 -0300
+
+ New timer clock to replace the amount of strftime() calls
+ Request headers to mk_pointer
+
+commit c4b9c5597c8e78286cbc57269c3c0b8f0cfa9ef6
+Author: edsiper <edsiper@monotop.(none)>
+Date: Fri Nov 21 11:08:31 2008 -0500
+
+ Improve mk_string_search performance
+
+commit bb0fd6da25c580b048a35831029ebd4c05f5255d
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Thu Nov 20 07:07:02 2008 -0300
+
+ remove string search debug message
+
+commit a3297cb186b502abacd38768f54a047b5867ce3e
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Thu Nov 20 07:03:22 2008 -0300
+
+ Header responses to mk_pointers
+ http decides when request reader stop to read client request
+ Post method working again
+ Restricted CRLF on headers, no more support for LFLF
+ Close socket when client close connection without bytes sent
+
+commit bdb928d30ddcc1409fa57f4bea85e50d3d141d23
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Mon Nov 17 07:06:53 2008 -0300
+
+ remove comments
+
+commit f5331effeb20374b22e291207f6295a0170541f2
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Mon Nov 17 07:03:02 2008 -0300
+
+ #2 Fix denied URL checking @ deny.c (Charlie)
+
+commit f9201766137018e3ed0256c632a9c059563eb36e
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Mon Nov 17 07:01:21 2008 -0300
+
+ Fix double-slash problem in URI when requesting a directory (Charlie)
+
+commit 5ddcdbea4f500f1b48950ec02a552078329a7a12
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Sat Nov 15 11:37:43 2008 -0300
+
+ Fix query string parser
+
+commit d61b5fde821f0c6f5d706958c87402b169fd03e7
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Sat Nov 15 09:28:00 2008 -0300
+
+ Fix logger + missed protocol
+
+commit 43feae5b5df59e5e994812b54abbcb11ec89a5ba
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Sat Nov 15 08:53:26 2008 -0300
+
+ Fix first header parser
+
+commit aef0b2695940cc3382e675fabaa5679464bb29cf
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Fri Nov 14 22:49:09 2008 -0300
+
+ missed 501 Method text
+
+commit 9e34a8a4ca852df6fec9453c097ed275e64549b0
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Fri Nov 14 22:46:37 2008 -0300
+
+ Add response: 501 Method Not Implemented
+
+commit 0108d692e2bb6bf8a0a5c06f56ab717b77c01d9a
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Fri Nov 14 22:06:03 2008 -0300
+
+ mk_pointer fix (Thanks to Charlie)
+
+commit 7ebd110d70523d8bfe13c2b98c06187211f0187f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Nov 11 06:58:05 2008 -0300
+
+ conn_switch.c header
+
+commit a16ab122072dabe9b10ace22ce4bb250107ef6f3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Nov 10 22:22:31 2008 -0300
+
+ dir_html :: fix toc free
+
+commit 544802787f523c7c92740201896a3b0a181a0530
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Nov 9 22:27:18 2008 -0300
+
+ dir_html :: free memory
+
+commit 81663c76c825d461d023e9ce64edb2ed2d0e7cd3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Nov 9 09:25:48 2008 -0300
+
+ Add DEBUG file with debug available macros
+
+commit af1dfdcb4d0ff7bcefebcdd374e0aa1487032d17
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Nov 9 09:25:29 2008 -0300
+
+ dir_html :: contributors list
+
+commit 7fe47dc094868be029b1b43057d6a6aa6e9f441f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Nov 9 09:17:23 2008 -0300
+
+ dir_html :: using linked list instead of realloc array
+
+commit 6e02483185f6fe1c98e893764c7709337356c1ff
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 21 00:51:03 2008 -0300
+
+ dir_html :: add new logo to guineo theme
+
+commit 5a002775c0b5e17ee0802e05a6008486287facb3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 21 00:32:29 2008 -0300
+
+ New index page + new logo
+
+commit fc9807908d1e9146f228ed8268efdb979e1bcaf1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 20 21:10:49 2008 -0300
+
+ dir_html :: add chunked transfer encoding
+
+commit be633b0fb03c18fa367bdd9760fd10d395a1607e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 20 19:49:22 2008 -0300
+
+ iov :: add offset support
+
+commit 5cd05a86ced0dcd6c60c4f91a1d0c7aa391ad31c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 20 18:46:33 2008 -0300
+
+ Fix banana script (thanks to Carlos)
+
+commit ba612d89233054f1e8988ddd347be036f64c53bd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 20 18:38:49 2008 -0300
+
+ dir_html :: test close connection
+
+commit f43b46275a004336c75a1cadf7daab5fa28ed6fd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 19 02:58:22 2008 -0300
+
+ dir_html :: dynamic mem for midification time
+
+commit f01aadf03a489bf051641a05a4e46f0602931ba0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Oct 18 00:21:42 2008 -0300
+
+ dir_html :: realloc entries
+ Complete exit on ctrl-c press
+ Add macro DEBUG_IOV
+ iov with debug print array size error
+
+commit 7ba641fccd0d8e5679a5f7f5c10805843fec2c58
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Oct 16 02:14:37 2008 -0300
+
+ dir_html :: no slash for modificaton time
+
+commit 012e67ac588db8ca0a10c361c184e5c5a75db40d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Oct 16 02:09:08 2008 -0300
+
+ dir_html :: add entry modification time
+
+commit 9db021996ac43c89150d897bfd61c9fbbb2549c8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Oct 14 23:29:00 2008 -0300
+
+ dir_html :: size to human readable, thanks to Felipe Astroza
+
+commit a4fb04acd577c04349874ef8902a9b123a0e84f7
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 13 23:14:20 2008 -0300
+
+ dir_html :: add size type
+
+commit 7df80a21617e29b06414121e16fdb33004041cf6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 13 20:17:05 2008 -0300
+
+ dir_html :: guineo template improves + add entry size
+
+commit cb91fbb94225b7a4be5caf77fafd4a5cfd89c7ac
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 12 12:21:53 2008 -0300
+
+ http :: allow case sensitive check
+
+commit 66679c7f39b18f7f44c88c67392f56219be77026
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Oct 12 12:17:25 2008 -0300
+
+ dir_html :: internal improvements
+
+commit 3b3be2446418fc7abe12bc69d466f50746739f37
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Oct 10 19:26:22 2008 -0400
+
+ Fix directory redirect
+
+commit 1972bf6a1aa24012ec92f34ea50611ad485c5871
+Author: edsiper <edsiper@gmail.com>
+Date: Thu Oct 9 18:28:43 2008 -0400
+
+ Fix hex to string parser
+
+commit ee683c0a34e0977308da02e69901e3c1cfd0541d
+Author: edsiper <edsiper@gmail.com>
+Date: Tue Oct 7 14:04:01 2008 -0400
+
+ dir_html :: sort entries
+
+commit b34646518e537048fbc8f64e6365910c9d81af13
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Oct 6 23:44:54 2008 -0400
+
+ dir_html :: send html
+
+commit b2f1f63a653105289fd8be8d1049017b2bafa140
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Sep 30 20:00:39 2008 -0400
+
+ dir_html: compose theme to stdout
+
+commit 92aab3c4495476f2fa3428bd90f4b5e3f9e183d5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Sep 28 22:28:32 2008 -0400
+
+ Testing creating dynamic response template
+
+commit f27e8ecfd458c816200d3c18715786c7da827da9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Sep 28 10:08:24 2008 -0400
+
+ DEBUG_THEME: show tag instead NULL
+
+commit 10d3df3ce0aced117e0ca04e28d3477318078b35
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Sep 28 10:03:56 2008 -0400
+
+ Add DEBUG_THEME feature
+
+commit 26a74a13d2a80e1beb8ab732d91c1c62ea56124a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Sep 27 21:27:08 2008 -0400
+
+ Parsing theme to template struct
+
+commit 5c54312c7cbda975f364f6332dc2634e68f06a4a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Sep 27 09:49:04 2008 -0400
+
+ dir_html: Parsing theme
+
+commit 6a526bb44af303a8b8122808f05fbdd64d9a92fb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Sep 25 09:46:13 2008 -0400
+
+ testing dirhtml_conf
+
+commit 66615f981ab98d096dae25fb0588bb434e4d5eaa
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Sep 25 07:38:52 2008 -0400
+
+ add mk_file_to_buffer func
+
+commit 0c953534f1889f3baadf9a56fa1a88858a81d80e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Sep 25 07:22:48 2008 -0400
+
+ Initial dirhtml support
+
+commit 96237ea8a195fa73abb884833dcce2462e89e356
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Sep 16 19:58:58 2008 -0400
+
+ Do not allow keep alive if client has not requested
+
+commit 3432c233e09f941899d643fba000a6e0109eccee
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Sep 16 19:55:38 2008 -0400
+
+ little fixes dir_html
+
+commit 6a786ad323e78e60bc81529cf1db1889d1b5556c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Sep 8 20:21:22 2008 -0400
+
+ dir_html 2/3
+
+commit 36e37427ec2d6d29dcf3d549f2f4e3caf9bb1369
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Aug 3 21:17:49 2008 -0400
+
+ Headers & new dir_html 1/3
+ Reducing memory allocation on sending headers
+
+commit ad88177e27ab339d8694a20ca05a4699911c1ef8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jul 23 21:41:35 2008 -0400
+
+ ups
+
+commit b941b49de531e6805fe8c88165f69a1ce4304509
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jul 23 21:39:23 2008 -0400
+
+ Send content-length in header when error pages are created
+ Deleting old vhost convention
+ Fix bug when directory shower runs more than one time
+
+commit 3383230e0dda2160404b30d89d36bbe465021562
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jul 22 21:52:53 2008 -0400
+
+ Handle log errors 2/2
+
+commit 7c6ae0e2168b293c32af681acdf8db112a364b92
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jul 22 05:33:58 2008 -0400
+
+ Handle log errors 1/2
+
+commit c6c3b0db1bf3620123fcd1c71f1b474367db6df0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 13 22:10:45 2008 -0400
+
+ Logger: add client ip address
+
+commit 54d43688d2e7f472ac5d2e163f5ca8a2c44a5225
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 13 21:41:59 2008 -0400
+
+ Renaming request calls
+
+commit 162cf432a5b3204b42d2b9d16e0b3f46aa89bf4b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 13 19:48:41 2008 -0400
+
+ enable mk_string_search_n
+
+commit 9e3e03d0ddc124068c000020ee92b341b677104b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jul 13 18:29:58 2008 -0400
+
+ Using mk_pointer to handle request header
+
+commit 65dc1fecf6e21b69da89d8ac1f185ecb20eb8788
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jul 7 21:10:45 2008 -0400
+
+ New mk_pointer
+
+commit b660f9cd91b6ec2a4373ff55be0dbed00639f3e2
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Sun Jul 6 19:56:46 2008 -0400
+
+ Little optmz
+
+commit eb7b16f171f719597cf6f68317f940e5c35b80a9
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jul 3 22:07:34 2008 -0400
+
+ Optimize buffer builder
+
+commit c183fe2a89bce1fa1258d8e0674631c625d626d4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jul 1 00:17:27 2008 -0400
+
+ Worker logger
+
+commit e586ee3dc1418d8cdc5bf9d78c036260fbdbcd68
+Author: edsiper <edsiper@gmail.com>
+Date: Tue Jun 24 09:32:21 2008 -0400
+
+ add memory.c and str.c
+
+commit cf7d0f66392daa893857408c3d9ff314d9785b2a
+Author: edsiper <edsiper@gmail.com>
+Date: Tue Jun 24 09:31:29 2008 -0400
+
+ Code reorganization
+
+commit 1ac323d1bf94f5709ff86035d9d5a0e875a6d5d1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 22 12:58:08 2008 -0400
+
+ Symlink fix
+
+commit 0588038329de27879da323099b1305b54c7e2add
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 21 16:08:13 2008 -0400
+
+ Close connection on error
+
+commit 0d8f033bf8143ae170d2fdae0c01ad787c8154df
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 21 16:01:29 2008 -0400
+
+ Fix symlink check
+
+commit 338cd5fd241ba4c58de77ac26760aefce6507f43
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Jun 21 09:49:57 2008 -0400
+
+ Improve string search
+
+commit 48c24f7c477dcf8bedc727344bf6b3c34e370375
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 12 20:01:28 2008 -0400
+
+ Partial download (ranges) working again
+
+commit 1bc2c11931b979ff069b273daf207e337e74aa96
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 12 19:49:49 2008 -0400
+
+ KeepAlive alive again
+
+commit 44ea3c861afed4ecf7bc63bc7eee9014784528f1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 10 20:39:02 2008 -0400
+
+ close connection on sendfile() error
+
+commit 9acefc842023b80ff77d6be42fdf8cc952bacdba
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 10 20:37:22 2008 -0400
+
+ Less I/O on SendFile
+
+commit 895c573e040b73a296b518152d292a74cd56f654
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 10 07:25:19 2008 -0400
+
+ remove silly cmp
+
+commit da1ac85e3238c5ab20d01083871efda0acfeccdc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 9 21:20:09 2008 -0400
+
+ remove sendfile option from configure
+
+commit f10de3bcc2edb92795cf59f2cdfa74f1ce117412
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 9 21:17:51 2008 -0400
+
+ Nostalgic commit: deleting old SendFile()
+
+commit 2abc9697945e1306be6b3784b915b3a0a2734e55
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 9 20:07:01 2008 -0400
+
+ keep alive's back
+
+commit 8c746aadbc7a6d34fd316f21793acebf4ea82060
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Fri Jun 6 20:22:31 2008 -0400
+
+ Fix Bug: method not allowed, thanks to Felipe (aka max)
+
+commit 7277b323704e9cd6ee176e74a007b8c0e893731b
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Fri Jun 6 20:02:24 2008 -0400
+
+ new connection switch
+
+commit e9f0c789d42fd9e49869dd1380bc4e8c103eaf5e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 5 23:10:34 2008 -0400
+
+ new file.c
+
+commit 8512ddca1f4d9c57daebe841349c051f416e0f8a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jun 5 23:09:50 2008 -0400
+
+ Lot of improves in memory and I/O
+
+commit 138ea37b1766bbecd616c4b0e016a61a39ea2325
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 4 20:02:33 2008 -0400
+
+ new http.c file
+
+commit 6facb4ad9f8da893279317a8aec3135e72e6f9dc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jun 4 19:49:13 2008 -0400
+
+ Little fixes
+
+commit 4d5162695fdc7ef0dc776a5d9e1d75ed7bd47f06
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 3 23:06:44 2008 -0400
+
+ new strip arg and add of strcasestr
+
+commit 1a4c4c85167bec9895977aa9860be14af133f3a1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 3 21:30:58 2008 -0400
+
+ Little improve when free_list_requests() is called
+
+commit 63ca0ce5afe71025d2509ca51ce7263ccaca7cf0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 3 21:22:04 2008 -0400
+
+ Free some used memory
+
+commit bf5cbdb8ab48ae6574ae5d719d2da4cbf290d18b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 3 20:08:42 2008 -0400
+
+ Async sendfile()
+
+commit 7e754de9e48fcb726028c73a8ccae4abadefb4fc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 3 10:02:29 2008 -0400
+
+ Missed header file
+
+commit b00ca0bf969f428e99c563e1507310653fca7871
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jun 3 07:54:28 2008 -0400
+
+ mk_header_iov_free can free specified buffers in struct iov
+
+commit 3d8553024399c1d74144da65b1859452e75e099a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jun 2 23:32:42 2008 -0400
+
+ New header handler
+
+commit 27d9b0788ce0c8929500f5fd06cf436be9061189
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 1 22:00:25 2008 -0400
+
+ Indent M_Method_send_headers()
+
+commit 47e026380a0310c320d4a44c6fddee64e7c070fb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 1 21:34:25 2008 -0400
+
+ remove WTF! send headers code
+
+commit 03de80253bda392e2949bca9bca8416b71dc5134
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 1 21:25:44 2008 -0400
+
+ Using TCP_CORK
+
+commit aa0f64e60264c10b0f6a4a7dfc7b445deba7b19f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jun 1 19:34:16 2008 -0400
+
+ Scheduler fixes: a bug causing write to sockets before read data has been fixed, no visible broken connections with benchmark test.
+ Delete unused functions and remove some silly debug comments
+
+commit 59f282de2fdbbefbe67e23c0881543fd5ddf3d81
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Fri May 30 21:07:07 2008 -0400
+
+ Scheduler improves, now using pthread_keys
+ Fix bug on broken connection
+
+commit e64f65ac977469aecead7c1c3645c900d29e6047
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Thu May 29 23:46:12 2008 -0400
+
+ Comment some debug lines
+
+commit 2934b421b903e55185f587fab3e65427deb66c52
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Thu May 29 23:40:13 2008 -0400
+
+ New network handler/scheduler
+
+commit 4fd7179f981378b28476c6f46bec68bc24439e19
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Thu May 29 07:32:54 2008 -0400
+
+ Delete old headers
+
+commit 23ca2eb6721df92d69bbaa1af0c3c8f53de47e57
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Thu May 29 07:31:46 2008 -0400
+
+ Delete invalid line
+
+commit 611990a22ce8ccc7be9b3c367e0bf1de93d2e076
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Thu May 29 07:27:40 2008 -0400
+
+ Moving to epoll
+
+commit 3ff9f481734df23e440233a40ecc6c27a2f0e8b2
+Author: Eduardo Silva <edsiper@monotop.(none)>
+Date: Tue Mar 25 23:59:21 2008 -0300
+
+ Missed header
+
+commit c05169bdfbee0e5ccb101c6f19faa22c2e63c357
+Author: Felipe Astroza <felipe.astroza@gmail.com>
+Date: Mon Mar 24 17:25:15 2008 -0400
+
+ mk_thread use flags and mutex defined by POSIX.
+
+ The main problem to create an own implementation using FUTEX is:
+ There're necessary pieces of assembler code in order to use atomic operations, which makes
+ a little difficult port the current code between different archs.
+ Check the GNU libc repository, they have done this in pthread.
+
+commit 742be85595570e99ede8f03bc2a9133a7e42d514
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 15 17:39:43 2008 -0400
+
+ Clean dirty msg
+
+commit 236de82434d0cb3d15911f2c9a5a4a31628f8d45
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Mar 15 17:39:09 2008 -0400
+
+ Testing logger-worker thread
+
+commit 8acef78282055a74c3d3976a9d467b672f60c7ac
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Mar 13 00:05:25 2008 -0400
+
+ Back to single-thread mode
+
+commit e605067c62fbdd08f11641e2711f8a21513fddb0
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 29 20:19:21 2008 -0300
+
+ Missed mk_common.c
+
+commit 8ff37a36c6ad5f176072a04dca7a4753854c336d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Feb 20 22:20:17 2008 -0300
+
+ pre-threading improves (Felipe)
+
+commit 232f05edffc947d0393a05072056bb962c215bbc
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Feb 11 09:32:54 2008 -0300
+
+ Testing a pre-threading mode ;)
+
+commit 11aa96aabba0e76139e822dc108b4573e26d5843
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sat Feb 2 10:11:01 2008 -0300
+
+ Fix parser for POST request without content-length header
+
+commit 62cd0e38fea60df9914482fb2766a77869b658e6
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 1 17:29:13 2008 -0300
+
+ POST method improves
+
+commit c61d267cac6904d82181f45eb280544973f9b938
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 1 16:14:36 2008 -0300
+
+ Update CGI module to new structure
+
+commit 655369834b7fb4562f21672917848d6274770a55
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Feb 1 00:27:45 2008 -0300
+
+ host signature improves
+
+commit 629ecce1ab5cac296b138bd9391656c35905a409
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 31 01:02:14 2008 -0300
+
+ Config: look for host configuration files under 'sites'
+
+commit 41ff8bf4b99984292e30c7661eaca64fa47cbed5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 30 20:35:52 2008 -0300
+
+ Update french translation scripts
+
+commit 14a512e99cc467462f671b54a20556b1649af10f
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 30 20:25:44 2008 -0300
+
+ Update spanish translation scripts
+
+commit dcb528ad51527ff7f63310efcf5dfc4afb32f59b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 30 20:10:58 2008 -0300
+
+ Add missed 'sites' dir
+
+commit d771ad279f24af604000697f44b556aa1464340a
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 30 20:09:44 2008 -0300
+
+ Update configure script in order to create the new configuration files
+
+commit 16e27b46c47312ccde11b71511961fe396b33409
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 30 17:47:42 2008 -0300
+
+ Remove old alloc() glib-2.0 compatibility
+
+commit dd9024bf0eb1ae5d2bbef97da4159cc1e4df9c99
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 30 17:40:10 2008 -0300
+
+ Internal changes: vhost, configuration files
+
+commit 33d7c536140e4ef3bc2bc5079bc1a6ebd6937be8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 28 15:02:18 2008 -0300
+
+ Configure script: create bin and logs directories
+
+commit beb5b3e5780f1828f4fe70b6bae6899a207e3ddb
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 28 11:38:58 2008 -0300
+
+ remove old func def
+
+commit d20fa1310d341279c208058acb09bcad6c95c6d5
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 28 11:37:55 2008 -0300
+
+ New option in configure script to force monkey do not use the sendfile() syscall
+
+commit 738f77f8d74e166cdb50446ce2a6c1a1b646a487
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Sun Jan 27 22:46:38 2008 -0300
+
+ Use linux sendfile() system call to send static files
+
+commit 644f26433872148241089d28455709d345a66f07
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 25 15:38:13 2008 -0300
+
+ Allow keepalive connections on HTTP/1.0
+
+commit e6a0def4529729590c20e8ca2e6e9496f70d5129
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 25 14:53:44 2008 -0300
+
+ Add benchmark mode
+
+commit e314a6a6ec373737eb61ce18546c31fe8be95b10
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Fri Jan 25 07:39:50 2008 -0300
+
+ Fix closing connection
+
+commit 202c4489f3949b30eefd85e52c9f4a82d415a2ae
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 24 21:27:31 2008 -0300
+
+ Enable logs and keepalive
+
+commit 9561969192ee47a768fc3d32b025e2c3e59fbfbd
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 24 18:54:04 2008 -0300
+
+ Allow HEAD method on pipelined requests
+
+commit b8a3054dc1b98ae7276919f6b67032047c59a3d8
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 24 18:49:41 2008 -0300
+
+ Fix protocol check
+
+commit 29a59ad689801ed334161c140d943e94beae074b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 24 18:27:02 2008 -0300
+
+ Force pipelined request to GET method
+
+commit 01b4f5e740e8d4434ac233127aabcd0c43235f15
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 24 16:33:47 2008 -0300
+
+ Improve remove_space()
+
+commit 3b034ed407f6b0f27da242b206cc76ec730be901
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 24 16:30:34 2008 -0300
+
+ New request header checks
+
+commit 393d5a0c0552f9744ad039cac8b937a3d1b0665e
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 24 12:15:27 2008 -0300
+
+ Set pipelined connection
+
+commit c6906df327397bec608935d7bdfd92e51dc45874
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 24 11:40:22 2008 -0300
+
+ Improve free request list
+
+commit 38cba9f3025f1103cb08aed736122e7cc33093e2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 24 02:11:04 2008 -0300
+
+ Fix free_request()
+
+commit 61bba201db3673155671e1fefa2ae6f82c77e336
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 24 00:56:59 2008 -0300
+
+ Missed return value
+
+commit f3596f167a878d8dc93eea7fa49f9af412401468
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Thu Jan 24 00:52:44 2008 -0300
+
+ Fix request parser: allow different end strings
+
+commit c6ac76f9d73cd2ce1b81783b62f10b23b597e587
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 23 07:00:49 2008 -0300
+
+ Improve request parser
+
+commit 1a3032d8292105b2ef66936c1cfef21f9a7d8b43
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Wed Jan 23 05:38:12 2008 -0300
+
+ Fix memory issues and some comments translation
+
+commit d8ae52d964ec7cc70d6d5cb084b731e8cbdd6af1
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 22 19:28:06 2008 -0300
+
+ Add DEBUG function
+
+commit 2e426f18d80211a7123f11dff3ed6bb2cb52a5e2
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 22 18:50:55 2008 -0300
+
+ Update process module
+
+commit ea18051bbe7ec6ac4f4ded168561e82cf1a0d3e4
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 22 18:45:42 2008 -0300
+
+ Update user module in order to use new client structure
+
+commit 4a476936a656f2034c8a1a3610fca6ab7bd77b7c
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Tue Jan 22 18:40:59 2008 -0300
+
+ Update cgi module in order to user new client structure
+
+commit b29396485e8b6b428012648aa27fb55bd2a42861
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 21 20:44:51 2008 -0300
+
+ Updating dir_html.c
+
+commit 7f533489ab8e4fc0eb8252475d8678480a89f08d
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 21 20:40:38 2008 -0300
+
+ Using struct client_request
+
+commit 749ef3cf9879feef026ebf70d2ce96b64d80aa82
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 21 20:31:16 2008 -0300
+
+ request.c: cleanup code
+
+commit fbd9b3a9361cfa3411092d6a7c5bda3d1c2cd115
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 21 19:46:55 2008 -0300
+
+ Replacing old vars
+
+commit bba620a52f3448faeb517db3192c6ccd9778756b
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 21 19:14:33 2008 -0300
+
+ change version name to 'git'
+
+commit 49a5cd928f82f2141c3e6e9d7ea8114c9e36a6a3
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 21 18:58:12 2008 -0300
+
+ Parsing pipelined connections
+
+commit bc30b2a79d9f82ac2764bb065895c7306476f714
+Author: Eduardo Silva <edsiper@gmail.com>
+Date: Mon Jan 21 18:49:10 2008 -0300
+
+ Initial import: version 0.9.2
diff --git a/fluent-bit/lib/monkey/ChangeLog.old b/fluent-bit/lib/monkey/ChangeLog.old
new file mode 100644
index 000000000..11e5b52b3
--- /dev/null
+++ b/fluent-bit/lib/monkey/ChangeLog.old
@@ -0,0 +1,233 @@
+Monkey HTTP Daemon - ChangeLog
+==============================
+
+v0.9.2 (2008/01/16):
+ - Translations: New translation of Monkey+PHP to
+ polish language and a funny 1337!, thanks
+ to Sugarush!
+
+ - Bug fix: negative memory allocation when a request
+ doesn't contain a '?' string. Thanks to Daniel
+ Hope for discover this problem and submit a patch!
+
+v0.9.1 (2004/04/13):
+ - BUG FIXES: Thanks to Rob and Tavis of gentoo security
+ team for report it. A bug found causes a DoS when it's
+ requested a file with 0 bytes of lenght and another one
+ that was found on cgi.c where exist the possibility to
+ run any code we wished before the connection be closed.
+
+v0.9.0 (2004/10/28):
+ - Some internal changes.
+ - Fixed bug in if_modified_since feature.
+ - POST_TIMEOUT value changed to value 10 to fix a problem
+ found with lagged connections (thanks to Federico Fuga).
+ - A little Virtualhost bug has been fixed.
+ - Fixed limit of max persistent connections for virtualhosts.
+ - Persistent connection now works with directory nagivation.
+ - Fixed GetDir problem with special vhost configurations.
+ - Fixed 'close connection on dir request without / '.
+ - Memory leak fixes :) .
+
+v0.8.5 (2004/08/28):
+ - Now monkey works on NetBSD (Matthew Gream)
+ - Fixed a lot of memory leaks, thanks to Matthew Gream.
+
+v0.8.4-2 (2004/06/10) :
+ - A bug found on users home feature has been fixed (oops!).
+
+v0.8.4 (2004/06/10) :
+ - Length of client IP now it's checked, are not allowed
+ anormal IP strings (thanks to BSD Chile team for
+ report possible bugs).
+
+v0.8.4-RC2 (2004/06/08) :
+ - Fixed bug found on get_real_string() (thanks to Luigi for
+ report this bug).
+ - Header and footer files now are hidden to dir listing.
+ - SymLink, Max_IP and Timeout initial values are been added
+ to configuration (src/config.c).
+ - Fixed check path of Addscript var on src/config.c.
+
+v0.8.4-RC1 (2004/06/03) :
+ - New Binary size: 44.8KB (compiled with gcc-3.3)!!!.
+ - Better memory management!!!.
+ - A lot of snprintf and sprintf has been replaced.
+ - A lot of internal changes, now all headers are sent to
+ the same time (same buffer), now response from server
+ to client it's a little more faster. Ah, now you can
+ test monkey with Apache Benchmark without problems.
+ - New translation of Monkey+PHP to portuguess has been added.
+ - New mutex has been added to thread_counter var
+ (mutex_thread_counter).
+ - Glibc needs __USE_XOPEN to be defined in order to add
+ a prototype for strptime (src/utils.c)
+ - Fixed 'if' warning produced by src/deny.c.
+
+v0.8.3 (2004/05/28) :
+ - Added Check for Symbolic links (allow/deny).
+ - Added French translation (thanks to Dominique Voillemot).
+ - Fixed Cache comparison check.
+ - Fixed header date time of file, now server send time
+ in GMT.
+
+v0.8.2 (2004/02/10) :
+ - Fixed 'server signature' overwrite address.
+ - Fixed DoS bug caused by get_real_string() (function rewrited).
+ - Fixed bad timeout response when a persistent connection have
+ a timeout.
+
+v0.8.1 (2004/01/14) :
+ - Little corrections in system to set limit of connections from
+ same IP address.
+ - Fixed response 301 with a little delay in response to HTTP/1.1 request.
+
+v0.8.0 (2003/10/18) :
+ - Added a new feature to limit maximum of clients from same
+ IP address connected to server.
+ - New translation of Monkey+PHP document to Russian, thanks to Toto.
+ - Fixed little problem with files with length = 0, persistent
+ connection now in this case are closed.
+ - Now make clean don't remove bin/banana file.
+
+v0.7.2 (2003/09/09) :
+ - Added a new feature to show information by
+ directories, are two new variables in monkey.conf:header_file
+ and footer_file. This allow define a special file to be
+ showed when a full directory is shown.
+ - CGI support has been optimized. Post method is more
+ faster.
+
+v0.7.1 (2003/05/30) :
+ - Little bugs has been fixed in resume and virtualhost
+ supports.
+ - pthread_mutex_* functions has been added.
+ - strtok() has been replaced with strtok_r().
+ - Some english translation has been fixed.
+ - Bug fixed in free_request().
+
+v0.7.0 (2003/05/11) :
+ - Resume support has been added.
+ - Added MySQL module. This allow you register the log
+ entries in a MySQL database (UNDER DEVELOPMENT!, just for
+ test it).
+ - New variable 'Include' in monkey.conf has been added, this
+ allow you include another files in main configuration
+ (Implemented by Rodrigo Mayorga).
+ - Some little problems reading config files has
+ fixed (thanks to Olatunji Oluwabukunmi).
+ - Added new functions to validate malloc(), free() and
+ strdup().
+ - Deny_Check() now check query string.
+ - Added validation to return value of pipe().
+ - Include directory has been moved into src/.
+ - Memory leaks has been fixed.
+ - Codes cleanup.
+
+v0.6.3 (2003/04/07) :
+ - New variable 'VirtualForceGetDir' in VirtualHost section,
+ this variable force to show full directory information.
+ - Some header files has been included (T).
+ - Bug searching path component in cgi_alias() has been
+ fixed. Thanks to 'T' for report this problem.
+ - Code cleanup.
+ - Persistent connection support has been fixed.
+ - License updates.
+
+v0.6.2 (2003/03/24) :
+ - Post_Method() security fixes: Request with post buffer
+ more long than MAX_REQUEST_BODY would cause the server to
+ fail, denying service to other (Matthew Murphy).
+ - Post_Method() security fixes: Request without
+ 'Content-Type' header make crash monkey (Eduardo).
+ - Added http_status.h file (JCI).
+
+v0.6.1 (2002/12/31) :
+ - ISO 8859-15 character table has been added to chars.c.
+ - Header files has been added for every module.
+ - New variable in monkey.conf 'HideVersion', allow hide
+ the version of the WebServer to clients.
+ - Information about Server Protocol has been added.
+ - Fixed a little problem when are checked access
+ permission of files , 'Forbidden' header now is sent
+ in all cases, cgi.c and request.c files has been modified.
+
+v0.6.0 (2002/12/28) :
+ - Hexa URI request support has been added.
+ - include/chars.h file has been added.
+ - New way to control subprocess (process.c).
+ - Optimized chunked transfer encoding.
+
+v0.5.2 (2002/12/02) :
+ - Makefile now work with $CC and $STRIP environment vars.
+ - If some script fail now server report an 'Internal Server
+ Error' to client.
+ - '505 Internal Server Error' header has been fixed.
+ - AddScript function has been fixed. Now check if path
+ of binary files is an valid regular file.
+ - A little problem with extensions of files has been fixed.
+ - MAX_REQUEST_URI size has been increased. (Glenn Neidermeier)
+ - Referer header has been added.
+ - Some little bugs located into add_log_pid() and
+ remove_log_pid() functions from logfile.c file has been
+ fixed.
+
+v0.5.1 (2002/10/29) :
+ - Chunked transfer coding has been added.
+ - Removed uninstall option from Makefile .
+ - Virtualhost configuration has been changed.
+ - Overflow in User_main has been fixed.
+ - cgi_send() has been rewritten.
+ - Post method: some security fixes.
+
+v0.5.0 (2002/09/22) :
+ - Persistent connections counter fixed.
+ - Monkey+PHP document updates.
+ - Changelog and home page has been translated into english.
+ - New document HowToWorks.txt has been added.
+ - New variable ServerName was added to monkey.conf.
+ - Timeout now works from begin to the end of request.
+ - Cookie support was added.
+ - Configure script now checks if pthread lib exist.
+ - Post_Method() fixes.
+
+v0.4.2 (2002/09/16) :
+ - Modificacion en configure script -> src/Makefile.
+ - Traduccion de monkey+php al Ingles (Davidlhor Bueso).
+ - Pequeños cambios en request.c y cgi.c .
+ - Cambios en la verificacion de metodos.
+
+v0.4.1-1 (2002/09/03) :
+ - Correcion en falla de seguridad en Set_Page_Default().
+
+v0.4.1 (2002/09/03) :
+ - Modificaciones en configure script.
+ - No registro de errores en archivo de log corregido.
+ - Agregado Banana script para controlar monkey.
+ - Eliminacion de la opcion '-m stop'.
+ - Correccion en opcion -c sin argumento.
+ - Denegacion de conexion persistente a clientes HTTP/1.0.
+
+v0.4.0 (2002/06/15) :
+ - Correcciones en soporte CGI para VirtualHost.
+ - Nuevo soporte para conexiones persistentes.
+ - Nueva variable de configuracion "MaxClients".
+ - Actualizaciones en script configure.
+ - Pequena correccion en mimetype.c .
+ - Implementado soporte basico de multithreading.
+ - Reestructuracion de variables.
+
+v0.1.1 (2001/06/05) :
+ - Nueva variable Indexfile en monkey.conf
+ - Optimizacion de codigo (redundancias)
+
+v0.1 (2001/05/30) :
+ - Nuevo archivo de configuracion monkey.conf
+ - Implementado Content-Lenght
+ - Reconocimiento e implementacion de MimeTypes
+ - Correccion de Get Method
+ - Negacion a Methods no implementados
+ - Resstructuracion de directorios raiz
+
+v0.0.5 (2001/05/17) :
+ - Primera version
diff --git a/fluent-bit/lib/monkey/FUZZ.md b/fluent-bit/lib/monkey/FUZZ.md
new file mode 100644
index 000000000..9074cdfac
--- /dev/null
+++ b/fluent-bit/lib/monkey/FUZZ.md
@@ -0,0 +1,33 @@
+# Fuzz Monkey
+
+## Prepare and Build
+
+Set the compiler path:
+
+```
+$ export CC=PATH/TO/honggfuzz/hfuzz_cc/hfuzz-clang
+```
+
+Build Monkey Fuzz tool with the following options:
+
+```
+$ cd build/
+$ cmake -DMK_LOCAL=On -DMK_DEBUG=On \
+ -DMK_LIB_ONLY=On -DMK_SYSTEM_MALLOC=On \
+ -DMK_FUZZ_MODE=On ../
+$ make
+```
+
+the build process will generate two executables:
+
+- mk_fuzz_me: to be used with honggfuzz for the Fuzzing process
+- mk_check: used to validate a crash/fix
+
+## Run HonggFuzz with mk-fuzz-me
+
+Fuzz Monkey using Apache corpus and wordlist:
+
+```
+$ cd /path/to/honggfuzz/examples/apache-httpd/
+$ honggfuzz -Q --logfile out.log -f corpus_http1 -w ./httpd.wordlist -- /path/to/mk-fuzz-me
+```
diff --git a/fluent-bit/lib/monkey/INSTALL b/fluent-bit/lib/monkey/INSTALL
new file mode 100644
index 000000000..391318ed4
--- /dev/null
+++ b/fluent-bit/lib/monkey/INSTALL
@@ -0,0 +1,52 @@
+ Monkey HTTP Server - Install
+ ============================
+
+ For optimum performance, I recommend that Monkey be compiled with GCC >=
+ 2.95.3 and be running on a Linux OS with kernel >= 2.6.32 (minimum) and
+ Kernel >= 3.9 preferred..
+
+ Like every source program we must run 'configure' script and later
+ 'make':
+
+ #./configure
+ # make
+
+ Optionally, you have the option of 'make install', which will copy the main
+ directory of monkey where it has been specified in the configure script.
+
+ CONFIGURATION
+ ===============
+ monkey.conf is generated by ./configure (see above) and saved in conf/monkey.conf.
+ In this configuration file you can set the default port, and settings such as workers,
+ timeouts, default user directions, etc.
+
+ Running Monkey
+ ==============
+
+ bin/monkey
+
+ or
+
+ bin/monkey -D (to run monkey in background mode)
+
+ Optionally, you can specify the directory where the configuration files
+ are found, this can be done the following way:
+
+ bin/monkey -D -c conf/
+
+ This argument (conf/) was thought of for those wishing to have Monkey
+ running for various users, in distinctive Ports and it's own
+ configuration files. For more information see 'conf/monkey.conf'.
+
+ For more info try -h option.
+
+ Testing Monkey
+ ==============
+
+To see that Monkey is running, make a request from a browser, like lynx
+or netscape:
+
+ # lynx 127.0.0.1:2001
+
+ Note: In this example the '2001' corresponds to the connection port
+ assigned on 'conf/monkey.conf'.
diff --git a/fluent-bit/lib/monkey/LICENSE b/fluent-bit/lib/monkey/LICENSE
new file mode 100644
index 000000000..f433b1a53
--- /dev/null
+++ b/fluent-bit/lib/monkey/LICENSE
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/fluent-bit/lib/monkey/NOTICE b/fluent-bit/lib/monkey/NOTICE
new file mode 100644
index 000000000..83a93c316
--- /dev/null
+++ b/fluent-bit/lib/monkey/NOTICE
@@ -0,0 +1,12 @@
+Monkey HTTP Server
+==================
+Copyright 2001-2014 Monkey Software LLC
+
+This product includes software developed at
+Monkey Software LLC (http://monkey.io).
+
+note:
+-----
+Starting from May 8th 2014, the source code on this directory
+is Licensed under the Apache License v2.0 and Copyrighted to
+Monkey Software LLC.
diff --git a/fluent-bit/lib/monkey/README.md b/fluent-bit/lib/monkey/README.md
new file mode 100644
index 000000000..26040a45e
--- /dev/null
+++ b/fluent-bit/lib/monkey/README.md
@@ -0,0 +1,59 @@
+# Monkey Server
+
+[Monkey](http://monkey-project.com) is a fast and lightweight Web Server for Linux. It has been designed to be very scalable with low memory and CPU consumption, the perfect solution for Embedded Linux and high end production environments.
+
+Besides the common features as HTTP server, it expose a flexible C API which aims to behave as a fully HTTP development framework, so it can be extended as desired through the plugins interface.
+
+For more details please refer to the [official documentation](http://monkey-project.com/documentation/).
+
+## Features
+
+- HTTP/1.1 Compliant
+- Hybrid Networking Model: Asynchronous mode + fixed Threads
+- Indented configuration style
+- Versatile plugin subsystem / API
+- x86, x86_64 & ARM compatible
+- More features:
+ - SSL
+ - IPv6
+ - Basic Auth
+ - Log writer
+ - Security
+ - Directory Listing
+ - CGI
+ - FastCGI
+ - Much more!
+- Embeddable as a shared library
+
+## Requirements
+
+When building Monkey it needs:
+
+- CMake >= 2.8
+- Glibc >= 2.5
+- GNU C Compiler >= 3.2
+
+Monkey requires the following components on runtime:
+
+- Linux Kernel >= 2.6.32
+- Pthreads support
+
+## Writing Scalable Web Services
+
+If you are interested into use [Monkey](http://monkey-project.com) as a base platform build scalable web services, we recommend you check our [Duda I/O](http://duda.io) project made for that purpose.
+
+## Join us!
+
+Monkey is an open organization so we want to hear about you, we continue growing and you can be part of it!, you can reach us at:
+
+- Mailing list: http://lists.monkey-project.com
+- IRC: irc.freenode.net #monkey
+- Twitter: http://www.twitter.com/monkeywebserver
+- Linkedin: http://www.linkedin.com/groups/Monkey-HTTP-Daemon-3211216
+- Freecode: http://freecode.com/projects/monkey (R.I.P)
+
+If you want to get involved, please also refer to our [Contributing](https://github.com/monkey/monkey/blob/master/CONTRIBUTING.md) guidelines.
+
+## Author
+
+Eduardo Silva <eduardo@monkey.io>
diff --git a/fluent-bit/lib/monkey/api/CMakeLists.txt b/fluent-bit/lib/monkey/api/CMakeLists.txt
new file mode 100644
index 000000000..8833735ef
--- /dev/null
+++ b/fluent-bit/lib/monkey/api/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(src
+ test.c)
+
+add_executable(api_test ${src})
+
+set(src
+ errors.c
+ )
+
+add_executable(api_error ${src})
+
+if (CMAKE_SYSTEM_NAME MATCHES "Windows")
+ target_link_libraries(api_test monkey-core-static mk_core ws2_32)
+ target_link_libraries(api_error monkey-core-static mk_core ws2_32)
+else()
+ target_link_libraries(api_test monkey-core-static)
+ target_link_libraries(api_error monkey-core-static)
+endif()
diff --git a/fluent-bit/lib/monkey/api/errors.c b/fluent-bit/lib/monkey/api/errors.c
new file mode 100644
index 000000000..44e9c35fa
--- /dev/null
+++ b/fluent-bit/lib/monkey/api/errors.c
@@ -0,0 +1,103 @@
+#include <monkey/mk_lib.h>
+#include <mk_core/mk_unistd.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#define API_ADDR "127.0.0.1"
+#define API_PORT "2020"
+
+/* Main context set as global so the signal handler can use it */
+mk_ctx_t *ctx;
+
+static void signal_handler(int signal)
+{
+ write(STDERR_FILENO, "[engine] caught signal\n", 23);
+
+ switch (signal) {
+ case SIGTERM:
+ case SIGINT:
+ mk_stop(ctx);
+ mk_destroy(ctx);
+ _exit(EXIT_SUCCESS);
+ default:
+ break;
+ }
+}
+
+static void signal_init()
+{
+ signal(SIGINT, &signal_handler);
+ signal(SIGTERM, &signal_handler);
+}
+
+void cb_ok_200(mk_request_t *request, void *data)
+{
+ int i = 0;
+ (void) data;
+ char tmp[32];
+
+ mk_http_status(request, 200);
+ mk_http_header(request, "X-Monkey", 8, "OK", 2);
+
+ for (i = 0; i < 100; i++) {
+ int len;
+
+ len = snprintf(tmp, sizeof(tmp) - 1, "test %i\n", i);
+ mk_http_send(request, tmp, len, NULL);
+ }
+ mk_http_done(request);
+}
+
+void cb_error_404(mk_request_t *request, void *data)
+{
+ int i = 0;
+ (void) data;
+ char tmp[32];
+
+ mk_http_status(request, 404);
+ mk_http_header(request, "X-Monkey", 8, "OK", 2);
+
+ for (i = 0; i < 100; i++) {
+ int len;
+
+ len = snprintf(tmp, sizeof(tmp) - 1, "test %i\n", i);
+ mk_http_send(request, tmp, len, NULL);
+ }
+ mk_http_done(request);
+}
+
+int main()
+{
+ int vid;
+
+ signal_init();
+
+ ctx = mk_create();
+ if (!ctx) {
+ return -1;
+ }
+
+ mk_config_set(ctx,
+ "Listen", API_PORT,
+ NULL);
+
+ vid = mk_vhost_create(ctx, NULL);
+ mk_vhost_set(ctx, vid,
+ "Name", "mk_lib",
+ NULL);
+
+ mk_vhost_handler(ctx, vid, "/200", cb_ok_200, NULL);
+ mk_vhost_handler(ctx, vid, "/404", cb_error_404, NULL);
+ mk_info("Service: http://%s:%s/404", API_ADDR, API_PORT);
+ mk_start(ctx);
+
+ sleep(3600);
+
+ mk_stop(ctx);
+ mk_destroy(ctx);
+
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/api/test.c b/fluent-bit/lib/monkey/api/test.c
new file mode 100644
index 000000000..ffb96f135
--- /dev/null
+++ b/fluent-bit/lib/monkey/api/test.c
@@ -0,0 +1,186 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#include <monkey/mk_lib.h>
+#include <mk_core/mk_unistd.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#define API_ADDR "127.0.0.1"
+#define API_PORT "8080"
+
+/* Main context set as global so the signal handler can use it */
+mk_ctx_t *ctx;
+
+void cb_worker(void *data)
+{
+ mk_info("[api test] test worker callback; data=%p", data);
+}
+
+
+void cb_sp_test_task_detail(mk_request_t *request, void *data)
+{
+ (void) data;
+
+ mk_http_status(request, 200);
+ mk_http_send(request, "CB_SP_TEST_TASK_DETAIL", strlen("CB_SP_TEST_TASK_DETAIL"), NULL);
+ mk_http_done(request);
+}
+
+void cb_sp_test_task_main(mk_request_t *request, void *data)
+{
+ (void) data;
+
+ mk_http_status(request, 200);
+ mk_http_send(request, "CB_SP_TEST_TASK_MAIN", strlen("CB_SP_TEST_TASK_MAIN"), NULL);
+ mk_http_done(request);
+}
+
+void cb_main(mk_request_t *request, void *data)
+{
+ int i;
+ (void) data;
+
+ mk_http_status(request, 200);
+
+ for (i = 0; i < 20; i++) {
+ mk_http_send(request, "first", 5, NULL);
+ mk_http_send(request, "second", 6, NULL);
+ mk_http_send(request, "third", 5, NULL);
+ }
+ mk_http_done(request);
+}
+
+void cb_test_chunks(mk_request_t *request, void *data)
+{
+ int i = 0;
+ int len;
+ char tmp[32];
+ (void) data;
+
+ mk_http_status(request, 200);
+ mk_http_header(request, "X-Monkey", 8, "OK", 2);
+
+ for (i = 0; i < 4; i++) {
+ len = snprintf(tmp, sizeof(tmp) -1, "test-chunk %6i\n ", i);
+ mk_http_send(request, tmp, len, NULL);
+ }
+ mk_http_done(request);
+}
+
+void cb_test_big_chunk(mk_request_t *request, void *data)
+{
+ size_t chunk_size = 1024000000;
+ char *chunk;
+ (void) data;
+
+ mk_http_status(request, 200);
+ mk_http_header(request, "X-Monkey", 8, "OK", 2);
+
+ chunk = calloc(1, chunk_size);
+ mk_http_send(request, chunk, chunk_size, NULL);
+ free(chunk);
+ mk_http_done(request);
+}
+
+
+static void signal_handler(int signal)
+{
+ write(STDERR_FILENO, "[engine] caught signal\n", 23);
+
+ switch (signal) {
+ case SIGTERM:
+ case SIGINT:
+ mk_stop(ctx);
+ mk_destroy(ctx);
+ _exit(EXIT_SUCCESS);
+ default:
+ break;
+ }
+}
+
+static void signal_init()
+{
+ signal(SIGINT, &signal_handler);
+ signal(SIGTERM, &signal_handler);
+}
+
+static void cb_queue_message(mk_mq_t *queue, void *data, size_t size, void *ctx)
+{
+ size_t i;
+ char *buf;
+ (void) ctx;
+ (void) queue;
+
+ printf("=== cb queue message === \n");
+ printf(" => %zu bytes\n", size);
+ printf(" => ");
+
+ buf = data;
+ for (i = 0; i < size; i++) {
+ printf("%c", buf[i]);
+ }
+ printf("\n\n");
+}
+
+
+int main()
+{
+ int i = 0;
+ int len;
+ int vid;
+ int qid;
+ char msg[800000];
+
+ signal_init();
+
+ ctx = mk_create();
+ if (!ctx) {
+ return -1;
+ }
+
+ /* Create a message queue and a callback for each message */
+ qid = mk_mq_create(ctx, "/data", cb_queue_message, NULL);
+
+ mk_config_set(ctx,
+ "Listen", API_PORT,
+ //"Timeout", "1",
+ NULL);
+
+ vid = mk_vhost_create(ctx, NULL);
+ mk_vhost_set(ctx, vid,
+ "Name", "monotop",
+ NULL);
+
+ mk_vhost_handler(ctx, vid, "/api/v1/stream_processor/task/[A-Za-z_][0-9A-Za-z_\\-]*",
+ cb_sp_test_task_detail, NULL);
+
+ mk_vhost_handler(ctx, vid, "/api/v1/stream_processor/task",
+ cb_sp_test_task_main, NULL);
+
+ mk_vhost_handler(ctx, vid, "/test_chunks", cb_test_chunks, NULL);
+ mk_vhost_handler(ctx, vid, "/test_big_chunk", cb_test_big_chunk, NULL);
+ mk_vhost_handler(ctx, vid, "/", cb_main, NULL);
+
+
+ mk_worker_callback(ctx,
+ cb_worker,
+ ctx);
+
+ mk_info("Service: http://%s:%s/test_chunks", API_ADDR, API_PORT);
+ mk_start(ctx);
+
+ for (i = 0; i < 5; i++) {
+ len = snprintf(msg, sizeof(msg) - 1, "[...] message ID: %i\n", i);
+ mk_mq_send(ctx, qid, &msg, len);
+ }
+
+ sleep(3600);
+
+ mk_stop(ctx);
+ mk_destroy(ctx);
+
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/cmake/FindLibkqueue.cmake b/fluent-bit/lib/monkey/cmake/FindLibkqueue.cmake
new file mode 100644
index 000000000..131fc98a3
--- /dev/null
+++ b/fluent-bit/lib/monkey/cmake/FindLibkqueue.cmake
@@ -0,0 +1,18 @@
+find_path(LIBKQUEUE_INCLUDE_DIR sys/event.h
+ PATHS
+ "/usr/include"
+ "/usr/local/include"
+ PATH_SUFFIXES "kqueue"
+)
+
+find_library(LIBKQUEUE_LIBRARY
+ NAMES libkqueue.so
+ PATHS /usr/lib /usr/local/lib
+)
+
+if (LIBKQUEUE_INCLUDE_DIR AND LIBKQUEUE_LIBRARY)
+ set(LIBKQUEUE_FOUND TRUE)
+ set(LIBKQUEUE_LIBRARIES ${LIBKQUEUE_LIBRARY})
+else (LIBKQUEUE_INCLUDE_DIR AND LIBKQUEUE_LIBRARY)
+ set(LIBKQUEUE_FOUND FALSE)
+endif (LIBKQUEUE_INCLUDE_DIR AND LIBKQUEUE_LIBRARY)
diff --git a/fluent-bit/lib/monkey/conf/CMakeLists.txt b/fluent-bit/lib/monkey/conf/CMakeLists.txt
new file mode 100644
index 000000000..1a5b9e6ea
--- /dev/null
+++ b/fluent-bit/lib/monkey/conf/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Generate conf/monkey.conf
+configure_file(
+ "${PROJECT_SOURCE_DIR}/conf/monkey.conf.in"
+ "${PROJECT_BINARY_DIR}/conf/monkey.conf"
+ )
+
+# Generate (copy) conf/monkey.mime
+configure_file(
+ "${PROJECT_SOURCE_DIR}/conf/monkey.mime.in"
+ "${PROJECT_BINARY_DIR}/conf/monkey.mime"
+ )
+
+# Generate conf/sites/default
+configure_file(
+ "${PROJECT_SOURCE_DIR}/conf/sites/default.in"
+ "${PROJECT_BINARY_DIR}/conf/sites/default"
+ )
diff --git a/fluent-bit/lib/monkey/conf/monkey.conf.in b/fluent-bit/lib/monkey/conf/monkey.conf.in
new file mode 100644
index 000000000..32e626320
--- /dev/null
+++ b/fluent-bit/lib/monkey/conf/monkey.conf.in
@@ -0,0 +1,166 @@
+# Monkey HTTP Server - Configuration
+# ==================================
+# These are the main variables and their descriptions, defined in respect
+# to the configuration of the different types of directives.
+
+[SERVER]
+ # Listen:
+ # -------
+ # The Listen directive maps the port and optionally restricts the
+ # network interface from where Monkey will be listens for incoming
+ # connections. Multiple Listen directives are allowed.
+ #
+ # The Listen directive requires a port number, preceded by an
+ # optional IPv4 or IPv6 address separated by a colon (:).
+ # IPv6 addresses must be enclosed in brackets ([]), e.g:
+ #
+ # Listen 127.0.0.1:2001
+ # Listen [::1]:2001
+
+ Listen @MK_CONF_LISTEN@
+
+ # Workers:
+ # --------
+ # Monkey launches threads to attend clients; each worker thread is capable
+ # of attending more than one client request at one time. The amount of
+ # clients that can be handled by each thread is calculated using the
+ # number of file descriptors allowed by the system. If this variable
+ # is set to 0 monkey will launch one thread per processor.
+
+ Workers @MK_CONF_WORKERS@
+
+ # Timeout:
+ # --------
+ # The largest span of time, expressed in seconds, during which you should
+ # wait to receive the information or waiting time for the remote host to
+ # accept an answer. (Timeout > 0)
+
+ Timeout @MK_CONF_TIMEOUT@
+
+ # PidFile:
+ # --------
+ # File where the server guards the process number when starting.
+
+ PidFile @MK_PATH_PIDPATH@/@MK_PIDFILE@
+
+ # UserDir:
+ # --------
+ # Directory name for users home (~/user).
+
+ UserDir @MK_CONF_USERDIR@
+
+ # Indexfile:
+ # ----------
+ # Number of the initial file of aperture when calling a directory.
+
+ Indexfile @MK_CONF_INDEXFILE@
+
+ # HideVersion:
+ # ------------
+ # For security reasons, sometimes people want to hide the version of his
+ # own webserver to clients (values on/off).
+
+ HideVersion @MK_CONF_HIDEVERSION@
+
+ # Resume:
+ # -------
+ # Allow clients to request files by ranges (values on/off).
+
+ Resume @MK_CONF_RESUME@
+
+ # User:
+ # -----
+ # If you want the webserver to run as a process of a defined user, you can
+ # define it in this variable. For the change of user to work, it's necessary
+ # to execute Monkey with root privileges. If it's started by a user that
+ # that doesn't have root privileges, this variable will be omitted.
+
+ User @MK_CONF_USER@
+
+ # -----------------
+ # ADVANCED CONFIG
+ # -----------------
+ # Just change the next variables if you know what are you doing.
+
+ # KeepAlive:
+ # ----------
+ # Allow persistent connections. (on/off)
+
+ KeepAlive @MK_CONF_KA@
+
+ # KeepAliveTimeout
+ # ----------------
+ # Number of seconds to wait for the next request in a persistent
+ # connection (value > 0).
+
+ KeepAliveTimeout @MK_CONF_KA_TIMEOUT@
+
+ # MaxKeepAliveRequest:
+ # --------------------
+ # Maximum number of requests per connection. (value > 0)
+
+ MaxKeepAliveRequest @MK_CONF_KA_MAXREQ@
+
+ # MaxRequestSize:
+ # ---------------
+ # When a request arrives, Monkey allocs a 'chunk' of memory space
+ # to receive the incoming data. As many times the incoming data
+ # size is undeterminated, Monkey increases the buffer as required. This
+ # variable defines the maximum size that the buffer can grow in terms
+ # of KB. Example: defining 'MaxRequestSize 32' means 32 Kilobytes.
+ # The value defined must be greater than zero. Default value defined
+ # is 32.
+
+ MaxRequestSize @MK_CONF_REQ_SIZE@
+
+ # SymLink:
+ # --------
+ # Allow request to symbolic link files.
+
+ SymLink @MK_CONF_SYMLINK@
+
+ # DefaultMimeType:
+ # ----------------
+ # If a static content is requested and it does not contain a known extension,
+ # Monkey will send the mime type specified on this directive.
+
+ DefaultMimeType @MK_CONF_DEFAULT_MIME@
+
+ # FDT:
+ # ----
+ # The File Descriptor Table (FDT) it's an internal mechanism to share open
+ # file descriptors under specific threads and virtual host context. When
+ # enabled, it helps to reduce the number of opened file descriptors for the
+ # same resource and the number of required system calls to open and close
+ # files.
+ #
+ # The overhead in memory of this feature is around ~5KB per worker.
+
+ FDT @MK_CONF_FDT@
+
+ # OverCapacity:
+ # -------------
+ # When the server is over capacity at networking level, is required to
+ # prepare a contingency plan. The OverCapacity feature allows to define
+ # the behavior under this situation. Monkey defines three options:
+ #
+ # Drop : just drop any new incoming connection.
+ # Resist : try to serve all request, even some of them may delay.
+ # TooBusy: report a 503 Service Unavailable HTTP status.
+ #
+ # The default behavior is 'Resist'.
+
+ OverCapacity @MK_CONF_OVERCAPACITY@
+
+ # FDLimit:
+ # --------
+ # Defines the maximum number of file descriptors that the server
+ # can use, it can be translated to the maximum number of connections.
+ # If the value is not set, Monkey will use the soft limit imposed to
+ # the process (ulimit -n).
+ #
+ # If the variable is set, Monkey will try to increase or decrease
+ # the limit under it restrictions. For values higher that Hard Limit
+ # Monkey needs to be started by root user.
+ #
+ # FDLimit 4096
diff --git a/fluent-bit/lib/monkey/conf/monkey.mime.in b/fluent-bit/lib/monkey/conf/monkey.mime.in
new file mode 100644
index 000000000..bf474c504
--- /dev/null
+++ b/fluent-bit/lib/monkey/conf/monkey.mime.in
@@ -0,0 +1,145 @@
+[MIMETYPES]
+ html text/html
+ jpg image/jpeg
+ png image/png
+ js application/x-javascript
+ css text/css
+ xml text/xml
+ gif image/gif
+ flv video/x-flv
+ jpe image/jpeg
+
+ deb application/x-debian-package
+ jpeg image/jpeg
+ htm text/html
+ bmp image/bmp
+ ief image/ief
+ tiff image/tiff
+ tif image/tiff
+ wbmp image/vnd.wap.wbmp
+ ras image/x-cmu-raster
+ ico image/x-icon
+ pnm image/x-portable-anymap
+ pbm image/x-portable-bitmap
+ pgm image/x-portable-graymap
+ ppm image/x-portable-pixmap
+ rgb image/x-rgb
+ xbm image/x-xbitmap
+ xpm image/x-xpixmap
+ xwd image/x-xwindowdump
+ svg image/svg+xml
+ svgz image/svg+xml
+
+ json application/json
+ ez application/andrew-inset
+ hqx application/mac-binhex40
+ cpt application/mac-compactpro
+ doc application/msword
+ bin application/octet-stream
+ dms application/octet-stream
+ lha application/octet-stream
+ lhz application/octet-stream
+ exe application/octet-stream
+ oda application/oda
+ pdf application/pdf
+ api application/postscript
+ eps application/postscript
+ ps application/postscript
+ smi application/smil
+ smil application/smil
+ mif application/vnd.mif
+ xls application/vnd.ms-excel
+ ppt application/vnd.ms-powerpoint
+ vbxml application/vnd.wap.wbxml
+ wmlc application/vnd.wap.wmlc
+ wmlsc application/vnd.wap.wmlscriptc
+ bcpio application/x-bcpio
+ vcd application/x-cdlink
+ pgn application/x-chess-pgn
+ cpio application/x-cpio
+ csh application/x-csh
+ dcr application/x-director
+ dir application/x-director
+ dxr application/x-director
+ dvi application/x-dvi
+ spl application/x-futuresplash
+ gtar application/x-gtar
+ gz application/x-gzip
+ hdf application/x-hdf
+ skp application/x-koan
+ skd application/x-koan
+ skt application/x-koan
+ skm application/x-koan
+ latex application/x-latex
+ nc application/x-netcdf
+ cdf application/x-netcdf
+ sh application/x-sh
+ shar application/x-shar
+ swf application/x-shockwave-flash
+ sit application/x-stuffit
+ sv4cpio application/x-sv4cpio
+ sv4crc application/x-sv4crc
+ tar application/x-tar
+ tcl application/x-tcl
+ tex application/x-tex
+ texinfo application/x-texinfo
+ texi application/x-texinfo
+ t application/x-troff
+ tr application/x-troff
+ roff application/x-troff
+ man application/x-troff-man
+ me application/x-troff-me
+ ms application/x-troff-ms
+ untar application/x-ustar
+ src application/x-wais-source
+ zip application/zip
+
+ au audio/basic
+ snd audio/basic
+ mid audio/midi
+ midi audio/midi
+ kar audio/midi
+ mpga audio/mpeg
+ mp2 audio/mpeg
+ mp3 audio/mpeg
+ aif audio/x-aiff
+ aiff audio/x-aiff
+ aifc audio/x-aiff
+ ram audio/x-pn-realaudio
+ rm audio/x-pn-realaudio
+ rpm audio/x-pn-realaudio-plugin
+ ra audio/x-realaudio
+ wav audio/x-wav
+
+ pdb chemical/x-pdb
+ xyz chemical/x-pdb
+
+ igs model/iges
+ iges model/iges
+ msh model/mesh
+ mesh model/mesh
+ silo model/mesh
+ wrl model/vrml
+ vmrl model/vrml
+
+ asc text/plain
+ txt text/plain
+ rtx text/richtext
+ rtf text/rtf
+ sgml text/sgml
+ sgm text/sgml
+ tsv text/tab-separated-values
+ wml text/vnd.wap.wml
+ wmls text/vnd.wap.wmlscript
+ etx text/x-setext
+ xsl text/xml
+
+ mpeg video/mpeg
+ mpg video/mpeg
+ mpe video/mpeg
+ qt video/quicktime
+ mov video/quicktime
+ avi video/x-msvideo
+ movie video/x-sgi-movie
+
+ ice x-conference/x-cooltalk
diff --git a/fluent-bit/lib/monkey/conf/plugins.load.in b/fluent-bit/lib/monkey/conf/plugins.load.in
new file mode 100644
index 000000000..54019a010
--- /dev/null
+++ b/fluent-bit/lib/monkey/conf/plugins.load.in
@@ -0,0 +1,10 @@
+# Monkey Plugins Loader
+# =====================
+# Monkey plugins are extended functionalities for Monkey,
+# the main directive to load a plugin is LoadPlugin plus
+# the absolute path for the desired plugin.
+#
+# Please check the following list of available plugins:
+
+[PLUGINS]
+@MK_LOAD_PLUGINS@
diff --git a/fluent-bit/lib/monkey/conf/sites/default.in b/fluent-bit/lib/monkey/conf/sites/default.in
new file mode 100644
index 000000000..0d259ae9e
--- /dev/null
+++ b/fluent-bit/lib/monkey/conf/sites/default.in
@@ -0,0 +1,57 @@
+# Default Host - Configuration
+# ============================
+# Here the variable principals of the program are defined in respect
+# to the configuration of the different types of directives.
+
+[HOST]
+ # ServerName:
+ # -----------
+ # Allow you to set a host and domain name (e.g monkey.linuxchile.cl). If
+ # you are working in a local network just set your IP address or if you
+ # are working like localhost set your loopback address (127.0.0.1).
+
+ ServerName @MK_VH_SERVERNAME@
+
+ # DocumentRoot:
+ # -------------
+ # This variable corresponds to the location of the main server directory
+ # of the web pages, where the files of your site are located.
+ #
+ # Example:
+ # DocumentRoot /home/krypton/htdocs
+
+ DocumentRoot @MK_PATH_WWW@
+
+ # Redirect:
+ # ---------
+ # Under specific conditions, you may want the server performs a HTTP
+ # redirect when this Virtual Host is reach. If that is the case, append
+ # to the Redirect key the value of the address where to redirect the
+ # HTTP client.
+ #
+ # Redirect http://monkey-project.com
+
+[LOGGER]
+ # AccessLog:
+ # ----------
+ # Registration file of correct request.
+
+ AccessLog @MK_PATH_LOG@/access.log
+
+ # ErrorLog:
+ # ---------
+ # Registration file of incorrect request.
+
+ ErrorLog @MK_PATH_LOG@/error.log
+
+[ERROR_PAGES]
+ 404 404.html
+
+[HANDLERS]
+ # FastCGI
+ # =======
+ # Match /.*\.php fastcgi
+
+ # CGI
+ # ===
+ # Match /cgi-bin/.*\.cgi cgi
diff --git a/fluent-bit/lib/monkey/configure b/fluent-bit/lib/monkey/configure
new file mode 100755
index 000000000..49c801c17
--- /dev/null
+++ b/fluent-bit/lib/monkey/configure
@@ -0,0 +1,220 @@
+#!/bin/bash
+#
+# Monkey HTTP Server
+# ==================
+# Copyright 2001-2015 Monkey Software LLC <eduardo@monkey.io>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+if [ "x$(uname)" = "xLinux" ]; then
+ BOLD="\033[1m"
+ END_COLOR="\033[0m"
+ GREEN="\033[0;32m"
+ YELLOW="\033[1;33m"
+ RED="\033[0;31m"
+ BLUE="\033[0;34m"
+ ECHO_OPTS="-en"
+ ECHO_LF="\n"
+else
+ ECHO_OPTS=""
+ ECHO_LF=""
+fi
+
+#---------------------------#
+# Starting configure
+#---------------------------#
+cmake_opts=""
+
+for arg in $*; do
+ case "$arg" in
+ -*=*)
+ optarg=`echo "$arg" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *)
+ optarg= ;;
+ esac
+ case "$arg" in
+ # Path options
+ --prefix*)
+ cmake_opts+="-DCMAKE_INSTALL_PREFIX='$optarg' "
+ ;;
+ --sbindir*)
+ cmake_opts+="-DCMAKE_INSTALL_SBINDIR='$optarg' "
+ ;;
+ --mandir*)
+ cmake_opts+="-DCMAKE_INSTALL_MANDIR='$optarg' "
+ ;;
+ --sysconfdir*)
+ cmake_opts+="-DINSTALL_SYSCONFDIR='$optarg' "
+ ;;
+ --webroot*)
+ cmake_opts+="-DINSTALL_WEBROOTDIR='$optarg' "
+ ;;
+ --libdir*)
+ cmake_opts+="-DCMAKE_INSTALL_LIBDIR='$optarg' "
+ ;;
+ --includedir*)
+ cmake_opts+="-DINSTALL_INCLUDEDIR='$optarg' "
+ ;;
+ --logdir*)
+ cmake_opts+="-DINSTALL_LOGDIR='$optarg' "
+ ;;
+ --pidpath*)
+ cmake_opts+="-DPID_PATH='$optarg' "
+ ;;
+ --pidfile*)
+ cmake_opts+="-DPID_FILE='$optarg' "
+ ;;
+ # Build Options
+ --local*)
+ cmake_opts+="-DBUILD_LOCAL=1 "
+ ;;
+ --debug*)
+ cmake_opts+="-DWITH_DEBUG=1 "
+ ;;
+ --trace*)
+ cmake_opts+="-DWITH_TRACE=1 "
+ ;;
+ --no-backtrace*)
+ cmake_opts+="-DWITH_BACKTRACE=0 "
+ ;;
+ --linux-trace*)
+ cmake_opts+="-DWITH_LINUX_TRACE=1 "
+ ;;
+ --pthread-tls*)
+ cmake_opts+="-DWITH_PTHREAD_TLS=1 "
+ ;;
+ --malloc-libc*)
+ cmake_opts+="-DWITH_SYSTEM_MALLOC=1 "
+ ;;
+ --uclib-mode*)
+ cmake_opts+="-DWITH_UCLIB=1 "
+ ;;
+ --musl-mode*)
+ cmake_opts+="-DWITH_MUSL=1 "
+ ;;
+ --enable-plugins*)
+ cmake_opts+="-DWITH_PLUGINS='$optarg' "
+ ;;
+ --disable-plugins*)
+ cmake_opts+="-DWITHOUT_PLUGINS='$optarg' "
+ ;;
+ --static-plugins*)
+ cmake_opts+="-DSTATIC_PLUGINS='$optarg' "
+ ;;
+ --only-accept)
+ cmake_opts+="-DWITH_ACCEPT=1 -DWITH_ACCEPT4=0 "
+ ;;
+ --only-accept4)
+ cmake_opts+="-DWITH_ACCEPT=0 -DWITH_ACCEPT4=1 "
+ ;;
+ --linux-kqueue*)
+ cmake_opts+="-DWITH_LINUX_KQUEUE=1 "
+ ;;
+ --default-port*)
+ cmake_opts+="-DDEFAULT_PORT='$optarg' "
+ ;;
+ --default-user*)
+ cmake_opts+="-DDEFAULT_USER='$optarg' "
+ ;;
+ --systemddir*)
+ cmake_opts+="-DSYSTEMD_DIR='$optarg' "
+ ;;
+ --no-binary*)
+ cmake_opts+="-DWITHOUT_BIN=1 "
+ ;;
+ --static-lib-mode*)
+ cmake_opts+="-DWITH_STATIC_LIB_MODE=1 "
+ ;;
+ --skip-config*)
+ cmake_opts+="-DWITHOUT_CONF=1 "
+ ;;
+ --mbedtls-shared*)
+ cmake_opts+="-DWITH_MBEDTLS_SHARED=1 "
+ ;;
+ --version*)
+ echo -e $bldgrn"Monkey HTTP Server v$VERSION" $txtrst
+ echo "Copyright 2001-2015, Eduardo Silva <eduardo@monkey.io>"
+ echo "http://monkey-project.com"
+ echo
+ exit 1
+ ;;
+ *)
+ echo "Usage: ./configure [OPTION]... [VAR=VALUE]..."
+ echo
+ echo -e $bldwht"Optional Commands:" $txtrst
+ echo " --help Display this help and exit"
+ echo " --version Display version information and exit"
+ echo
+ echo -e $bldwht"Build options:" $txtrst
+ echo " --local Build locally, don't install (dev mode)"
+ echo " --debug Compile Monkey with debugging symbols"
+ echo " --trace Enable trace messages (don't use in production)"
+ echo " --no-backtrace Disable backtrace feature"
+ echo " --linux-trace Enable Linux Trace Toolkit"
+ echo " --musl-mode Enable musl compatibility mode"
+ echo " --uclib-mode Enable uClib compatibility mode"
+ echo " --malloc-libc Use system default memory allocator (default is jemalloc)"
+ echo " --pthread-tls Use Posix thread keys instead of compiler TLS"
+ echo " --no-binary Do not build binary"
+ echo " --static-lib-mode Build static library mode"
+ echo " --skip-config Do not include configuration files"
+ echo " --mbedtls-shared Use system mbedtls shared lib instead of the static one"
+ echo
+ echo -e $bldwht"Installation Directories:" $txtrst
+ echo " --prefix=PREFIX Root prefix directory"
+ echo " --sbindir=BINDIR Binary files (executables)"
+ echo " --libdir=LIBDIR Libraries"
+ echo " --includedir=INCDIR Header install path"
+ echo " --sysconfdir=SYSCONFDIR Configuration files"
+ echo " --webroot=WEB_ROOT Path to default web site files"
+ echo " --mandir=MANDIR Manpages - documentation"
+ echo " --logdir=LOGDIR Log files"
+ echo " --pidfile=PIDFILE Path to file to store PID"
+ echo " --systemddir[=DIR] Systemd directory path"
+ echo " --enable-plugins=a,b Enable the listed plugins"
+ echo " --disable-plugins=a,b Disable the listed plugins"
+ echo " --static-plugins=a,b Build plugins in static mode"
+ echo " --only-accept Use only accept(2)"
+ echo " --only-accept4 Use only accept4(2) (default and preferred)"
+ echo
+ echo -e $bldwht"Override Server Configuration:" $txtrst
+ echo " --default-port=PORT Override default TCP port (default: 2001)"
+ echo " --default-user=USER Override default web user (default: www-data)"
+ echo
+ exit 1
+ ;;
+ esac
+done
+
+echo $ECHO_OPTS $RED"********************************************"$ECHO_LF
+echo $ECHO_OPTS $RED"*"$GREEN$BOLD" Monkey HTTP Server "$RED"*"$ECHO_LF
+echo $ECHO_OPTS $RED"*"$YELLOW" monkey-project.com "$RED"*"$ECHO_LF
+echo $ECHO_OPTS "*"$BLUE" ---------------------------------------- "$RED"*"$ECHO_LF
+echo $ECHO_OPTS "*"$YELLOW" Monkey is the next generation "$RED"*"$ECHO_LF
+echo $ECHO_OPTS "*"$YELLOW" Web Server for Linux and Unix variants "$RED"*"$ECHO_LF
+echo $ECHO_OPTS "*"$YELLOW" "$RED"*"$ECHO_LF
+echo $ECHO_OPTS "*"$YELLOW" Feel free to reach us at: "$RED"*"$ECHO_LF
+echo $ECHO_OPTS "*"$YELLOW" "$RED"*"$ECHO_LF
+echo $ECHO_OPTS "*"$YELLOW" irc.freenode.net #monkey "$RED"*"$ECHO_LF
+echo $ECHO_OPTS "*"$YELLOW" "$RED"*"$ECHO_LF
+echo $ECHO_OPTS "*"$YELLOW" Thanks for using Monkey!!! "$RED"*"$ECHO_LF
+echo $ECHO_OPTS "*"$YELLOW" "$RED"*"$ECHO_LF
+echo $ECHO_OPTS "********************************************"$END_COLOR$ECHO_LF
+echo $ECHO_OPTS "Build: $(uname)"$ECHO_LF
+
+cd build/
+rm -rf CMakeCache.txt
+cmake $cmake_opts ../
+
+exit 0
diff --git a/fluent-bit/lib/monkey/debian.sh b/fluent-bit/lib/monkey/debian.sh
new file mode 100755
index 000000000..69d12674a
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+fakeroot debian/rules clean
+fakeroot debian/rules build
+fakeroot debian/rules binary
+
diff --git a/fluent-bit/lib/monkey/debian/changelog b/fluent-bit/lib/monkey/debian/changelog
new file mode 100644
index 000000000..9ea0858e0
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/changelog
@@ -0,0 +1,89 @@
+monkey (1.6.0-1) stable; urgency=low
+
+ * Work in process for v1.6.0
+
+ -- Eduardo Silva <eduardo@monkey.io> Fri, 18 Jul 2014 09:00:00 -0300
+
+monkey (1.5.2-1) stable; urgency=low
+
+ * Update Monkey release to v1.5.2
+
+ -- Eduardo Silva <eduardo@monkey.io> Fri, 18 Jul 2014 09:00:00 -0300
+
+monkey (1.5.1-1) stable; urgency=low
+
+ * Fix configure script parameters
+
+ -- Eduardo Silva <edsiper@gmail.com> Thu, 29 May 2014 09:00:00 -0300
+
+monkey (1.5.0-1) stable; urgency=low
+
+ * Update Monkey release to v1.5.0
+
+ -- Eduardo Silva <edsiper@gmail.com> Tue, 29 Apr 2014 09:00:00 -0300
+
+monkey (1.4.0-1) stable; urgency=low
+
+ * Update Monkey release to v1.4.0
+
+ -- Eduardo Silva <edsiper@gmail.com> Mon, 03 Feb 2013 09:00:00 -0300
+
+monkey (1.3.0-1) stable; urgency=low
+
+ * Update Monkey release to v1.3.0
+
+ -- Eduardo Silva <edsiper@gmail.com> Thu, 15 Oct 2013 09:00:00 -0300
+
+monkey (1.2.0-1) stable; urgency=low
+
+ * Update Monkey release to v1.2.0
+
+ -- Eduardo Silva <edsiper@gmail.com> Mon, 29 Apr 2013 10:00:00 -0300
+
+monkey (1.1.1-1) stable; urgency=low
+
+ * Update Monkey release to v1.1.1
+
+ -- Eduardo Silva <edsiper@gmail.com> Sat, 18 Aug 2012 10:00:00 -0300
+
+monkey (1.1.0-2) stable; urgency=low
+
+ * Add missing cgi plugin
+
+ -- Eduardo Silva <edsiper@gmail.com> Fri, 17 Aug 2012 12:00:00 -0300
+
+monkey (1.1.0-1) stable; urgency=low
+
+ * Update Monkey release to v1.1.0
+
+ -- Eduardo Silva <edsiper@gmail.com> Fri, 17 Aug 2012 10:00:00 -0300
+
+monkey (0.32.0-1) unstable; urgency=low
+
+ * Update Monkey release to v0.32.0
+
+ -- Eduardo Silva <edsiper@gmail.com> Fri, 09 Feb 2012 12:00:00 -0300
+
+monkey (0.31.0-1) unstable; urgency=low
+
+ * Update Monkey release to v0.31.0
+
+ -- Eduardo Silva <edsiper@gmail.com> Fri, 13 Jan 2012 12:00:00 -0300
+
+monkey (0.21.0-1) unstable; urgency=low
+
+ * Update Monkey release to v0.21.0
+
+ -- Eduardo Silva <edsiper@gmail.com> Thu, 28 Oct 2011 12:00:00 -0300
+
+monkey (0.20.4-1) unstable; urgency=low
+
+ * Add new monkey-dev package
+
+ -- Eduardo Silva <edsiper@gmail.com> Thu, 12 Oct 2011 12:00:00 -0300
+
+monkey (0.20.3-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Eduardo Silva <edsiper@gmail.com> Mon, 10 Oct 2011 22:33:20 -0300
diff --git a/fluent-bit/lib/monkey/debian/compat b/fluent-bit/lib/monkey/debian/compat
new file mode 100644
index 000000000..7f8f011eb
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/fluent-bit/lib/monkey/debian/control b/fluent-bit/lib/monkey/debian/control
new file mode 100644
index 000000000..54c2e4e35
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/control
@@ -0,0 +1,38 @@
+Source: monkey
+Section: httpd
+Priority: optional
+Maintainer: Eduardo Silva <eduardo@monkey.io>
+Build-Depends: debhelper (>= 7.0.50~), autotools-dev, libpolarssl-dev
+Standards-Version: 3.9.1
+Homepage: http://monkey-project.com
+Vcs-Git: https://github.com/monkey/monkey.git
+Vcs-Browser: https://github.com/monkey/monkey
+
+Package: monkey
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Fast and lightweight Web Server for Linux.
+ Monkey HTTP Server has been designed to be very scalable with low memory
+ and CPU consumption, the perfect solution for embedded environments. It
+ also provides a flexible API and plugins interface.
+
+Package: monkey-polarssl
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, monkey
+Description: SSL transport layer for Monkey Web Server based in PolarSSL.
+ This plugin enable Monkey Web Server with SSL encryption through the third
+ party PolarSSL library.
+
+Package: monkey-dev
+Architecture: any
+Depends: ${misc:Depends}, monkey (= ${binary:Version})
+Description: Monkey HTTP Server development files
+ This package distributes the C headers files required to perform
+ the development of a Monkey plugin. This package is not related to the
+ library version of Monkey.
+
+Package: monkey-doc
+Section: doc
+Architecture: all
+Description: Monkey documentation
+ Monkey HTTP Server documentation.
diff --git a/fluent-bit/lib/monkey/debian/copyright b/fluent-bit/lib/monkey/debian/copyright
new file mode 100644
index 000000000..f17fcf787
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/copyright
@@ -0,0 +1,34 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: monkey
+Source: http://monkey-project.com
+
+Files: *
+Copyright: 2001-2014 Eduardo Silva <eduardo@monkey.io>
+ 2010-2011 Jonathan Gonzalez <zeus@gnu.org>
+ 2009-2011 DavidLorh Bueso <dave@gnu.org>
+
+License:
+
+Files: debian/*
+Copyright: 2001-2014 Eduardo Silva <eduardo@monkey.io>
+License: LGPL-2
+
+License: Apache-2.0
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ .
+ http://www.apache.org/licenses/LICENSE-2.0
+ .
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 2 can be found in "/usr/share/common-licenses/Apache-2.0".
diff --git a/fluent-bit/lib/monkey/debian/docs b/fluent-bit/lib/monkey/debian/docs
new file mode 100644
index 000000000..b43bf86b5
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/docs
@@ -0,0 +1 @@
+README.md
diff --git a/fluent-bit/lib/monkey/debian/monkey-dev.install b/fluent-bit/lib/monkey/debian/monkey-dev.install
new file mode 100644
index 000000000..9811dd900
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/monkey-dev.install
@@ -0,0 +1,37 @@
+# Monkey headers
+debian/tmp/usr/include/monkey
+debian/tmp/usr/include/monkey/mk_memory.h
+debian/tmp/usr/include/monkey/mk_env.h
+debian/tmp/usr/include/monkey/mk_limits.h
+debian/tmp/usr/include/monkey/mk_epoll.h
+debian/tmp/usr/include/monkey/mk_http.h
+debian/tmp/usr/include/monkey/mk_api.h
+debian/tmp/usr/include/monkey/mk_header.h
+debian/tmp/usr/include/monkey/monkey.h
+debian/tmp/usr/include/monkey/mk_string.h
+debian/tmp/usr/include/monkey/mk_config.h
+debian/tmp/usr/include/monkey/mk_clock.h
+debian/tmp/usr/include/monkey/mk_request.h
+debian/tmp/usr/include/monkey/mk_http_status.h
+debian/tmp/usr/include/monkey/mk_macros.h
+debian/tmp/usr/include/monkey/mk_cache.h
+debian/tmp/usr/include/monkey/mk_scheduler.h
+debian/tmp/usr/include/monkey/mk_info.h
+debian/tmp/usr/include/monkey/mk_rbtree.h
+debian/tmp/usr/include/monkey/mk_method.h
+debian/tmp/usr/include/monkey/mk_user.h
+debian/tmp/usr/include/monkey/mk_file.h
+debian/tmp/usr/include/monkey/mk_signals.h
+debian/tmp/usr/include/monkey/mk_iov.h
+debian/tmp/usr/include/monkey/mk_server.h
+debian/tmp/usr/include/monkey/mk_mimetype.h
+debian/tmp/usr/include/monkey/mk_plugin.h
+debian/tmp/usr/include/monkey/mk_list.h
+debian/tmp/usr/include/monkey/mk_socket.h
+debian/tmp/usr/include/monkey/mk_utils.h
+debian/tmp/usr/include/monkey/mk_connection.h
+
+# Library headers
+debian/tmp/usr/include/monkey/mk_lib.h
+debian/tmp/usr/include/monkey/libmonkey.h
+
diff --git a/fluent-bit/lib/monkey/debian/monkey-doc.docs b/fluent-bit/lib/monkey/debian/monkey-doc.docs
new file mode 100644
index 000000000..d4f454258
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/monkey-doc.docs
@@ -0,0 +1 @@
+#DOCS#
diff --git a/fluent-bit/lib/monkey/debian/monkey-doc.install b/fluent-bit/lib/monkey/debian/monkey-doc.install
new file mode 100644
index 000000000..d4f454258
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/monkey-doc.install
@@ -0,0 +1 @@
+#DOCS#
diff --git a/fluent-bit/lib/monkey/debian/monkey-polarssl.install b/fluent-bit/lib/monkey/debian/monkey-polarssl.install
new file mode 100644
index 000000000..d4beea06c
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/monkey-polarssl.install
@@ -0,0 +1,6 @@
+# Plugins setup
+debian/tmp/etc/monkey/plugins/polarssl/*
+
+# Plugins / Libraries
+debian/tmp/usr/lib/monkey/monkey-polarssl.so
+
diff --git a/fluent-bit/lib/monkey/debian/monkey.init b/fluent-bit/lib/monkey/debian/monkey.init
new file mode 100755
index 000000000..1fd662582
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/monkey.init
@@ -0,0 +1,101 @@
+#!/bin/sh
+#
+# start/stop Monkey HTTP Daemon
+
+### BEGIN INIT INFO
+# Provides: monkey
+# Required-Start: $remote_fs $network $syslog
+# Required-Stop: $remote_fs $network $syslog
+# Should-Start: $named
+# Should-Stop: $named
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Start Monkey HTTP Daemon
+# Description: Start Monkey HTTP Daemon
+### END INIT INFO
+
+CONFDIR="/etc/monkey"
+BINMONKEY="/usr/sbin/monkey"
+
+PORT=$(sed -n '/^[ \t]*Port/s/^.* //p' "$CONFDIR/monkey.conf")
+PIDFILE=$(sed -n '/^[ \t]*PidFile/s/^.* //p' "$CONFDIR/monkey.conf")."$PORT"
+
+for arg in $*; do
+ case "$arg" in
+ -*=*) optarg=`echo "$arg" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ if ! test -f $PIDFILE ; then
+ STATUS="no"
+ else
+ PIDMONKEY=`cat $PIDFILE`
+ if ! kill -0 $PIDMONKEY 2>/dev/null; then
+ STATUS="no"
+ else
+ STATUS="yes"
+ fi
+ fi
+
+ case "$arg" in
+ start)
+ if [ "$STATUS" = "yes" ] ; then
+ echo "Monkey is running... (PID=$PIDMONKEY)"
+ exit 1
+ fi
+ if ! test -x $BINMONKEY ; then
+ echo "Error: I can't run binary file"
+ exit 1
+ else
+ if $BINMONKEY --daemon 2>/dev/null ; then
+ echo "Running Monkey -> OK"
+ exit 0
+ fi
+ fi
+ ;;
+ stop)
+ if [ "$STATUS" = "no" ]; then
+ echo "Monkey is not running."
+ exit 0
+ fi
+ kill -9 $PIDMONKEY
+ rm -rf $PIDFILE > /dev/null
+ echo "Monkey stopped ($PIDMONKEY)"
+ exit 0
+ ;;
+ force-reload|restart)
+ if [ "$STATUS" = "yes" ]; then
+ if ! kill $PIDMONKEY > /dev/null ; then
+ killall -9 monkey
+ else
+ echo -n "Stopping Monkey... "
+ fi
+ else
+ echo -n "Monkey is not running... "
+ fi
+ if ! test -x $BINMONKEY ; then
+ echo "Error: I can't run binary file"
+ exit 1
+ else
+ $BINMONKEY --daemon > /dev/null
+ echo "Restarting -> OK"
+ exit 0
+ fi
+ ;;
+ status)
+ if [ "$STATUS" = "yes" ]; then
+ echo "Monkey is running... (PID=$PIDMONKEY)"
+ else
+ echo "Monkey is not running... "
+ fi
+ exit 0
+ ;;
+ *)
+ echo "Usage : monkey [start|stop|restart|status|help]"
+ exit 1
+ ;;
+ esac
+done
+echo "Usage : monkey [start|stop|restart|status|help]"
+
+exit 0
diff --git a/fluent-bit/lib/monkey/debian/monkey.install b/fluent-bit/lib/monkey/debian/monkey.install
new file mode 100644
index 000000000..558d1c666
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/monkey.install
@@ -0,0 +1,51 @@
+# Binaries
+debian/tmp/usr/sbin/monkey
+
+# Configuration
+debian/tmp/etc/monkey/monkey.conf
+debian/tmp/etc/monkey/plugins.load
+debian/tmp/etc/monkey/monkey.mime
+debian/tmp/etc/monkey/sites/*
+
+# WWW Data
+debian/tmp/usr/share/monkey/404.html
+debian/tmp/usr/share/monkey/index.html
+debian/tmp/usr/share/monkey/favicon.ico
+debian/tmp/usr/share/monkey/imgs/monkey_logo.png
+debian/tmp/usr/share/monkey/imgs/info_pic.jpg
+debian/tmp/usr/share/monkey/css/bootstrap.min.css
+
+# Manpage
+debian/tmp/usr/share/man/man1/monkey.1
+
+# Auth Plugin
+debian/tmp/etc/monkey/plugins/auth/*
+debian/tmp/usr/lib/monkey/monkey-auth.so
+debian/tmp/usr/sbin/mk_passwd
+
+# CGI Plugin
+debian/tmp/etc/monkey/plugins/cgi/*
+debian/tmp/usr/lib/monkey/monkey-cgi.so
+
+# Cheetah Plugin
+debian/tmp/etc/monkey/plugins/cheetah/*
+debian/tmp/usr/lib/monkey/monkey-cheetah.so
+
+# Dirlisting Plugin
+debian/tmp/etc/monkey/plugins/dirlisting/*
+debian/tmp/usr/lib/monkey/monkey-dirlisting.so
+
+# FastCGI Plugin
+debian/tmp/etc/monkey/plugins/fastcgi/*
+debian/tmp/usr/lib/monkey/monkey-fastcgi.so
+
+# Liana Plugin
+debian/tmp/usr/lib/monkey/monkey-liana.so
+
+# Logger Plugin
+debian/tmp/etc/monkey/plugins/logger/*
+debian/tmp/usr/lib/monkey/monkey-logger.so
+
+# Mandril Plugin
+debian/tmp/etc/monkey/plugins/mandril/*
+debian/tmp/usr/lib/monkey/monkey-mandril.so
diff --git a/fluent-bit/lib/monkey/debian/monkey.postinst b/fluent-bit/lib/monkey/debian/monkey.postinst
new file mode 100644
index 000000000..de7fbcde9
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/monkey.postinst
@@ -0,0 +1,14 @@
+#!/bin/sh
+set -e
+
+if [ "$1" = "configure" ]; then
+ mkdir -p /var/log/monkey
+ chown www-data:www-data /var/log/monkey
+ chmod 0750 /var/log/monkey
+ touch /var/log/monkey/master.log
+ chown www-data:www-data /var/log/monkey/master.log
+fi
+
+#DEBHELPER#
+
+exit 0
diff --git a/fluent-bit/lib/monkey/debian/rules b/fluent-bit/lib/monkey/debian/rules
new file mode 100755
index 000000000..31775da8a
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/rules
@@ -0,0 +1,20 @@
+#!/usr/bin/make -f
+
+%:
+ dh $@ --with autotools_dev
+
+override_dh_auto_configure:
+ dh_auto_configure -- -DCMAKE_INSTALL_PREFIX='/usr' \
+ -DCMAKE_INSTALL_SBINDIR='/usr/sbin' \
+ -DCMAKE_INSTALL_MANDIR='/usr/share/man' \
+ -DINSTALL_SYSCONFDIR='/etc/monkey' \
+ -DINSTALL_WEBROOTDIR='/usr/share/monkey' \
+ -DINSTALL_LOGDIR='/var/log/monkey' \
+ -DINSTALL_INCLUDEDIR='/usr/include/monkey' \
+ -DDEFAULT_USER='www-data' \
+ -DDEFAULT_PORT='80' \
+ -DCMAKE_INSTALL_LIBDIR='/usr/lib/monkey' \
+ -DPID_PATH='/var/run/' \
+ -DWITH_PLUGIN_TLS=ON \
+ -DSTATIC_PLUGINS='tls' \
+ -DSYSTEMD_DIR='/lib/systemd/system/'
diff --git a/fluent-bit/lib/monkey/debian/source/format b/fluent-bit/lib/monkey/debian/source/format
new file mode 100644
index 000000000..163aaf8d8
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/fluent-bit/lib/monkey/debian/watch b/fluent-bit/lib/monkey/debian/watch
new file mode 100644
index 000000000..922f0b4df
--- /dev/null
+++ b/fluent-bit/lib/monkey/debian/watch
@@ -0,0 +1,2 @@
+version=3
+http://monkey-project.com/releases/([\d].*)/monkey-(.*)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))
diff --git a/fluent-bit/lib/monkey/deps/deps.txt b/fluent-bit/lib/monkey/deps/deps.txt
new file mode 100644
index 000000000..9957e6850
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/deps.txt
@@ -0,0 +1,3 @@
+1) Jemalloc v3.5.0-git-5f60afa01eb2cf7d44024d162a1ecc6cceedcca1
+
+ https://github.com/jemalloc/jemalloc
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/CMakeLists.txt b/fluent-bit/lib/monkey/deps/flb_libco/CMakeLists.txt
new file mode 100644
index 000000000..1f0c55395
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/CMakeLists.txt
@@ -0,0 +1,28 @@
+set(src
+ libco.c
+ )
+
+include(CheckSymbolExists)
+
+# Check for posix_memalign so that Apple Silicon can be supported
+check_symbol_exists(posix_memalign "stdlib.h" HAVE_POSIX_MEMALIGN_IN_STDLIB)
+
+IF(HAVE_POSIX_MEMALIGN_IN_STDLIB)
+ # We need HAVE_POSIX_MEMALIGN for the ifdefs to use posix_memalign
+ # We defined HAVE_POSIX_MEMALIGN_IN_STDLIB in order to avoid including in malloc.h
+ add_definitions(-DHAVE_POSIX_MEMALIGN_IN_STDLIB -DHAVE_POSIX_MEMALIGN)
+ MESSAGE("Found posix_memalign in stdlib.h -DHAVE_POSIX_MEMALIGN_IN_STDLIB -DHAVE_POSIX_MEMALIGN")
+ENDIF(HAVE_POSIX_MEMALIGN_IN_STDLIB)
+
+# Check for posix_memalign so that FreeBSD can be supported
+check_symbol_exists(posix_memalign "malloc_np.h" HAVE_POSIX_MEMALIGN_IN_PTHREAD_NP)
+
+IF(HAVE_POSIX_MEMALIGN_IN_PTHREAD_NP)
+ # We need HAVE_POSIX_MEMALIGN for the ifdefs to use posix_memalign
+ # We defined DHAVE_POSIX_MEMALIGN_IN_PTHREAD_NP in order to include malloc_np.h
+ add_definitions(-DHAVE_POSIX_MEMALIGN_IN_PTHREAD_NP -DHAVE_POSIX_MEMALIGN)
+ MESSAGE("Found posix_memalign in malloc_np.h -DHAVE_POSIX_MEMALIGN_IN_PTHREAD_NP -DHAVE_POSIX_MEMALIGN")
+ENDIF(HAVE_POSIX_MEMALIGN_IN_PTHREAD_NP)
+
+add_definitions(-DLIBCO_MP)
+add_library(co STATIC ${src})
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/README.md b/fluent-bit/lib/monkey/deps/flb_libco/README.md
new file mode 100644
index 000000000..4d934d740
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/README.md
@@ -0,0 +1,14 @@
+# Fork of libco for Fluent Bit
+
+This repository is a fork of the original library [libco](https://byuu.org/library/libco/) v18 created by Byuu. Compared to the original version it have the following changes:
+
+- Core
+ - ARMv8: workaround for [GCC bug](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90907).
+ - Added [aarch64.c](aarch64.c) backend file created by [webgeek1234](https://github.com/webgeek1234).
+ - Fixes on settings.h to get MacOS support.
+- API
+ - co_create() have a third argument to retrieve the real size of the stack created.
+
+This library is used inside [Fluent Bit](http://github.com/fluent/fluent-bit) project, so this repo aims to keep aligned with latest releases but including our required patches.
+
+Eduardo Silva <eduardo@monkey.io>
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/aarch64.c b/fluent-bit/lib/monkey/deps/flb_libco/aarch64.c
new file mode 100644
index 000000000..d01b2ca00
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/aarch64.c
@@ -0,0 +1,138 @@
+/*
+ libco.aarch64 (2017-06-26)
+ author: webgeek1234
+ license: public domain
+*/
+
+#define LIBCO_C
+#include "libco.h"
+#include "settings.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#if defined(HAVE_POSIX_MEMALIGN_IN_STDLIB)
+/* stdlib is already included */
+#elif defined(HAVE_POSIX_MEMALIGN_IN_PTHREAD_NP)
+#include <malloc_np.h>
+#else
+#include <malloc.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static thread_local uint64_t co_active_buffer[64];
+static thread_local cothread_t co_active_handle;
+
+asm (
+ ".text\n"
+ ".globl co_switch_aarch64\n"
+ ".globl _co_switch_aarch64\n"
+ "co_switch_aarch64:\n"
+ "_co_switch_aarch64:\n"
+ " stp x8, x9, [x1]\n"
+ " stp x10, x11, [x1, #16]\n"
+ " stp x12, x13, [x1, #32]\n"
+ " stp x14, x15, [x1, #48]\n"
+ " str x19, [x1, #72]\n"
+ " stp x20, x21, [x1, #80]\n"
+ " stp x22, x23, [x1, #96]\n"
+ " stp x24, x25, [x1, #112]\n"
+ " stp x26, x27, [x1, #128]\n"
+ " stp x28, x29, [x1, #144]\n"
+ " mov x16, sp\n"
+ " stp x16, x30, [x1, #160]\n"
+
+ " ldp x8, x9, [x0]\n"
+ " ldp x10, x11, [x0, #16]\n"
+ " ldp x12, x13, [x0, #32]\n"
+ " ldp x14, x15, [x0, #48]\n"
+ " ldr x19, [x0, #72]\n"
+ " ldp x20, x21, [x0, #80]\n"
+ " ldp x22, x23, [x0, #96]\n"
+ " ldp x24, x25, [x0, #112]\n"
+ " ldp x26, x27, [x0, #128]\n"
+ " ldp x28, x29, [x0, #144]\n"
+ " ldp x16, x17, [x0, #160]\n"
+ " mov sp, x16\n"
+ " br x17\n"
+ ".previous\n"
+ );
+
+/* ASM */
+void co_switch_aarch64(cothread_t handle, cothread_t current);
+
+static void crash(void)
+{
+ /* Called only if cothread_t entrypoint returns. */
+ assert(0);
+}
+
+cothread_t co_create(unsigned int size, void (*entrypoint)(void),
+ size_t *out_size)
+{
+ size = (size + 1023) & ~1023;
+ cothread_t handle = 0;
+#if HAVE_POSIX_MEMALIGN >= 1
+ if (posix_memalign(&handle, 1024, size + 512) < 0)
+ return 0;
+#else
+ handle = memalign(1024, size + 512);
+#endif
+
+ if (!handle)
+ return handle;
+
+ uint64_t *ptr = (uint64_t*)handle;
+ /* Non-volatiles. */
+ ptr[0] = 0; /* x8 */
+ ptr[1] = 0; /* x9 */
+ ptr[2] = 0; /* x10 */
+ ptr[3] = 0; /* x11 */
+ ptr[4] = 0; /* x12 */
+ ptr[5] = 0; /* x13 */
+ ptr[6] = 0; /* x14 */
+ ptr[7] = 0; /* x15 */
+ ptr[8] = 0; /* padding */
+ ptr[9] = 0; /* x19 */
+ ptr[10] = 0; /* x20 */
+ ptr[11] = 0; /* x21 */
+ ptr[12] = 0; /* x22 */
+ ptr[13] = 0; /* x23 */
+ ptr[14] = 0; /* x24 */
+ ptr[15] = 0; /* x25 */
+ ptr[16] = 0; /* x26 */
+ ptr[17] = 0; /* x27 */
+ ptr[18] = 0; /* x28 */
+ ptr[20] = (uintptr_t)ptr + size + 512 - 16; /* x30, stack pointer */
+ ptr[19] = ptr[20]; /* x29, frame pointer */
+ ptr[21] = (uintptr_t)entrypoint; /* PC (link register x31 gets saved here). */
+
+ *out_size = size + 512;
+ return handle;
+}
+
+cothread_t co_active(void)
+{
+ if (!co_active_handle)
+ co_active_handle = co_active_buffer;
+ return co_active_handle;
+}
+
+void co_delete(cothread_t handle)
+{
+ free(handle);
+}
+
+void co_switch(cothread_t handle)
+{
+ cothread_t co_previous_handle = co_active();
+ co_switch_aarch64(co_active_handle = handle, co_previous_handle);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/amd64.c b/fluent-bit/lib/monkey/deps/flb_libco/amd64.c
new file mode 100644
index 000000000..ae127e80c
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/amd64.c
@@ -0,0 +1,163 @@
+/*
+ libco.amd64 (2016-09-14)
+ author: byuu
+ license: public domain
+*/
+
+#define LIBCO_C
+#include "libco.h"
+#include "settings.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static thread_local long long co_active_buffer[64];
+static thread_local cothread_t co_active_handle = 0;
+static void (*co_swap)(cothread_t, cothread_t) = 0;
+
+#ifdef LIBCO_MPROTECT
+ alignas(4096)
+#else
+ text_section
+#endif
+#ifdef _WIN32
+ /* ABI: Win64 */
+ static const unsigned char co_swap_function[4096] = {
+ 0x48, 0x89, 0x22, /* mov [rdx],rsp */
+ 0x48, 0x8b, 0x21, /* mov rsp,[rcx] */
+ 0x58, /* pop rax */
+ 0x48, 0x89, 0x6a, 0x08, /* mov [rdx+ 8],rbp */
+ 0x48, 0x89, 0x72, 0x10, /* mov [rdx+16],rsi */
+ 0x48, 0x89, 0x7a, 0x18, /* mov [rdx+24],rdi */
+ 0x48, 0x89, 0x5a, 0x20, /* mov [rdx+32],rbx */
+ 0x4c, 0x89, 0x62, 0x28, /* mov [rdx+40],r12 */
+ 0x4c, 0x89, 0x6a, 0x30, /* mov [rdx+48],r13 */
+ 0x4c, 0x89, 0x72, 0x38, /* mov [rdx+56],r14 */
+ 0x4c, 0x89, 0x7a, 0x40, /* mov [rdx+64],r15 */
+ #if !defined(LIBCO_NO_SSE)
+ 0x0f, 0x29, 0x72, 0x50, /* movaps [rdx+ 80],xmm6 */
+ 0x0f, 0x29, 0x7a, 0x60, /* movaps [rdx+ 96],xmm7 */
+ 0x44, 0x0f, 0x29, 0x42, 0x70, /* movaps [rdx+112],xmm8 */
+ 0x48, 0x83, 0xc2, 0x70, /* add rdx,112 */
+ 0x44, 0x0f, 0x29, 0x4a, 0x10, /* movaps [rdx+ 16],xmm9 */
+ 0x44, 0x0f, 0x29, 0x52, 0x20, /* movaps [rdx+ 32],xmm10 */
+ 0x44, 0x0f, 0x29, 0x5a, 0x30, /* movaps [rdx+ 48],xmm11 */
+ 0x44, 0x0f, 0x29, 0x62, 0x40, /* movaps [rdx+ 64],xmm12 */
+ 0x44, 0x0f, 0x29, 0x6a, 0x50, /* movaps [rdx+ 80],xmm13 */
+ 0x44, 0x0f, 0x29, 0x72, 0x60, /* movaps [rdx+ 96],xmm14 */
+ 0x44, 0x0f, 0x29, 0x7a, 0x70, /* movaps [rdx+112],xmm15 */
+ #endif
+ 0x48, 0x8b, 0x69, 0x08, /* mov rbp,[rcx+ 8] */
+ 0x48, 0x8b, 0x71, 0x10, /* mov rsi,[rcx+16] */
+ 0x48, 0x8b, 0x79, 0x18, /* mov rdi,[rcx+24] */
+ 0x48, 0x8b, 0x59, 0x20, /* mov rbx,[rcx+32] */
+ 0x4c, 0x8b, 0x61, 0x28, /* mov r12,[rcx+40] */
+ 0x4c, 0x8b, 0x69, 0x30, /* mov r13,[rcx+48] */
+ 0x4c, 0x8b, 0x71, 0x38, /* mov r14,[rcx+56] */
+ 0x4c, 0x8b, 0x79, 0x40, /* mov r15,[rcx+64] */
+ #if !defined(LIBCO_NO_SSE)
+ 0x0f, 0x28, 0x71, 0x50, /* movaps xmm6, [rcx+ 80] */
+ 0x0f, 0x28, 0x79, 0x60, /* movaps xmm7, [rcx+ 96] */
+ 0x44, 0x0f, 0x28, 0x41, 0x70, /* movaps xmm8, [rcx+112] */
+ 0x48, 0x83, 0xc1, 0x70, /* add rcx,112 */
+ 0x44, 0x0f, 0x28, 0x49, 0x10, /* movaps xmm9, [rcx+ 16] */
+ 0x44, 0x0f, 0x28, 0x51, 0x20, /* movaps xmm10,[rcx+ 32] */
+ 0x44, 0x0f, 0x28, 0x59, 0x30, /* movaps xmm11,[rcx+ 48] */
+ 0x44, 0x0f, 0x28, 0x61, 0x40, /* movaps xmm12,[rcx+ 64] */
+ 0x44, 0x0f, 0x28, 0x69, 0x50, /* movaps xmm13,[rcx+ 80] */
+ 0x44, 0x0f, 0x28, 0x71, 0x60, /* movaps xmm14,[rcx+ 96] */
+ 0x44, 0x0f, 0x28, 0x79, 0x70, /* movaps xmm15,[rcx+112] */
+ #endif
+ 0xff, 0xe0, /* jmp rax */
+ };
+
+ #include <windows.h>
+
+ static void co_init() {
+ #ifdef LIBCO_MPROTECT
+ DWORD old_privileges;
+ VirtualProtect((void*)co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READ, &old_privileges);
+ #endif
+ }
+#else
+ /* ABI: SystemV */
+ static const unsigned char co_swap_function[4096] = {
+ 0x48, 0x89, 0x26, /* mov [rsi],rsp */
+ 0x48, 0x8b, 0x27, /* mov rsp,[rdi] */
+ 0x58, /* pop rax */
+ 0x48, 0x89, 0x6e, 0x08, /* mov [rsi+ 8],rbp */
+ 0x48, 0x89, 0x5e, 0x10, /* mov [rsi+16],rbx */
+ 0x4c, 0x89, 0x66, 0x18, /* mov [rsi+24],r12 */
+ 0x4c, 0x89, 0x6e, 0x20, /* mov [rsi+32],r13 */
+ 0x4c, 0x89, 0x76, 0x28, /* mov [rsi+40],r14 */
+ 0x4c, 0x89, 0x7e, 0x30, /* mov [rsi+48],r15 */
+ 0x48, 0x8b, 0x6f, 0x08, /* mov rbp,[rdi+ 8] */
+ 0x48, 0x8b, 0x5f, 0x10, /* mov rbx,[rdi+16] */
+ 0x4c, 0x8b, 0x67, 0x18, /* mov r12,[rdi+24] */
+ 0x4c, 0x8b, 0x6f, 0x20, /* mov r13,[rdi+32] */
+ 0x4c, 0x8b, 0x77, 0x28, /* mov r14,[rdi+40] */
+ 0x4c, 0x8b, 0x7f, 0x30, /* mov r15,[rdi+48] */
+ 0xff, 0xe0, /* jmp rax */
+ };
+
+ #include <unistd.h>
+ #include <sys/mman.h>
+
+ static void co_init() {
+ #ifdef LIBCO_MPROTECT
+ unsigned long long addr = (unsigned long long)co_swap_function;
+ unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE));
+ unsigned long long size = (addr - base) + sizeof co_swap_function;
+ mprotect((void*)base, size, PROT_READ | PROT_EXEC);
+ #endif
+ }
+#endif
+
+static void crash() {
+ assert(0); /* called only if cothread_t entrypoint returns */
+}
+
+cothread_t co_active() {
+ if(!co_active_handle) co_active_handle = &co_active_buffer;
+ return co_active_handle;
+}
+
+cothread_t co_create(unsigned int size, void (*entrypoint)(void),
+ size_t *out_size){
+ cothread_t handle;
+ if(!co_swap) {
+ co_init();
+ co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
+ }
+
+ if(!co_active_handle) co_active_handle = &co_active_buffer;
+ size += 512; /* allocate additional space for storage */
+ size &= ~15; /* align stack to 16-byte boundary */
+ *out_size = size;
+
+ if((handle = (cothread_t)malloc(size))) {
+ long long *p = (long long*)((char*)handle + size); /* seek to top of stack */
+ *--p = (long long)crash; /* crash if entrypoint returns */
+ *--p = (long long)entrypoint; /* start of function */
+ *(long long*)handle = (long long)p; /* stack pointer */
+ }
+
+ return handle;
+}
+
+void co_delete(cothread_t handle) {
+ free(handle);
+}
+
+void co_switch(cothread_t handle) {
+ register cothread_t co_previous_handle = co_active_handle;
+ co_swap(co_active_handle = handle, co_previous_handle);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/arm.c b/fluent-bit/lib/monkey/deps/flb_libco/arm.c
new file mode 100644
index 000000000..1bd8c043d
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/arm.c
@@ -0,0 +1,81 @@
+/*
+ libco.arm (2016-09-14)
+ author: byuu
+ license: public domain
+*/
+
+#define LIBCO_C
+#include "libco.h"
+#include "settings.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static thread_local unsigned long co_active_buffer[64];
+static thread_local cothread_t co_active_handle = 0;
+static void (*co_swap)(cothread_t, cothread_t) = 0;
+
+#ifdef LIBCO_MPROTECT
+ alignas(4096)
+#else
+ text_section
+#endif
+static const unsigned long co_swap_function[1024] = {
+ 0xe8a16ff0, /* stmia r1!, {r4-r11,sp,lr} */
+ 0xe8b0aff0, /* ldmia r0!, {r4-r11,sp,pc} */
+ 0xe12fff1e, /* bx lr */
+};
+
+static void co_init() {
+ #ifdef LIBCO_MPROTECT
+ unsigned long addr = (unsigned long)co_swap_function;
+ unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
+ unsigned long size = (addr - base) + sizeof co_swap_function;
+ mprotect((void*)base, size, PROT_READ | PROT_EXEC);
+ #endif
+}
+
+cothread_t co_active() {
+ if(!co_active_handle) co_active_handle = &co_active_buffer;
+ return co_active_handle;
+}
+
+cothread_t co_create(unsigned int size, void (*entrypoint)(void),
+ size_t *out_size) {
+ unsigned long* handle = 0;
+ if(!co_swap) {
+ co_init();
+ co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
+ }
+ if(!co_active_handle) co_active_handle = &co_active_buffer;
+ size += 256;
+ size &= ~15;
+ *out_size = size;
+
+ if(handle = (unsigned long*)malloc(size)) {
+ unsigned long* p = (unsigned long*)((unsigned char*)handle + size);
+ handle[8] = (unsigned long)p;
+ handle[9] = (unsigned long)entrypoint;
+ }
+
+ return handle;
+}
+
+void co_delete(cothread_t handle) {
+ free(handle);
+}
+
+void co_switch(cothread_t handle) {
+ cothread_t co_previous_handle = co_active_handle;
+ co_swap(co_active_handle = handle, co_previous_handle);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/doc/style.css b/fluent-bit/lib/monkey/deps/flb_libco/doc/style.css
new file mode 100755
index 000000000..5181afde6
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/doc/style.css
@@ -0,0 +1,8 @@
+body {
+ background: #333;
+ color: #fff;
+}
+
+code {
+ background: #444;
+}
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/doc/targets.html b/fluent-bit/lib/monkey/deps/flb_libco/doc/targets.html
new file mode 100755
index 000000000..d6211a15d
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/doc/targets.html
@@ -0,0 +1,89 @@
+<html>
+<head>
+ <title></title>
+ <link href="style.css" rel="stylesheet" type="text/css">
+</head>
+<body>
+
+<b>Supported targets:</b><br/><br/>
+
+Note that supported targets are only those that have been tested and confirmed
+working. It is quite possible that libco will work on more processors, compilers
+and operating systems than those listed below.
+<hr/>
+
+<b>libco.x86</b><br/>
+Overhead: ~5x<br/>
+Supported processor(s): 32-bit x86<br/>
+Supported compiler(s): any<br/>
+Supported operating system(s):<ul>
+<li>Windows</li>
+<li>Mac OS X</li>
+<li>Linux</li>
+<li>BSD</li>
+</ul>
+<hr/>
+
+<b>libco.amd64</b><br/>
+Overhead: ~10x (Windows), ~6x (all other platforms)<br/>
+Supported processor(s): 64-bit amd64<br/>
+Supported compiler(s): any<br/>
+Supported operating system(s):<ul>
+<li>Windows</li>
+<li>Mac OS X</li>
+<li>Linux</li>
+<li>BSD</li>
+</ul>
+<hr/>
+
+<b>libco.ppc</b><br/>
+Overhead: ~20x<br/>
+Supported processor(s): 32-bit PowerPC, 64-bit PowerPC<br/>
+Supported compiler(s): GNU GCC<br/>
+Supported operating system(s):<ul>
+</ul>
+<li>Mac OS X</li>
+<li>Linux</li>
+<li>BSD</li>
+<li>Playstation 3</li>
+</ul>
+<br/>
+
+Note: this module contains compiler flags to enable/disable FPU and Altivec
+support.
+
+<hr/>
+
+<b>libco.fiber</b><br/>
+Overhead: ~15x<br/>
+Supported processor(s): Processor independent<br/>
+Supported compiler(s): any<br/>
+Supported operating system(s):<ul>
+<li>Windows</li>
+</ul>
+<hr/>
+
+<b>libco.sjlj</b><br/>
+Overhead: ~30x<br/>
+Supported processor(s): Processor independent<br/>
+Supported compiler(s): any<br/>
+Supported operating system(s):<ul>
+<li>Mac OS X</li>
+<li>Linux</li>
+<li>BSD</li>
+<li>Solaris</li>
+</ul>
+<hr/>
+
+<b>libco.ucontext</b><br/>
+Overhead: <b><font color="#ff0000">~300x</font></b><br/>
+Supported processor(s): Processor independent<br/>
+Supported compiler(s): any<br/>
+Supported operating system(s):<ul>
+<li>Linux</li>
+<li>BSD</li>
+</ul>
+<hr/>
+
+</body>
+</html>
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/doc/usage.html b/fluent-bit/lib/monkey/deps/flb_libco/doc/usage.html
new file mode 100755
index 000000000..3f0d81ccd
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/doc/usage.html
@@ -0,0 +1,107 @@
+<html>
+<head>
+ <title></title>
+ <link href="style.css" rel="stylesheet" type="text/css">
+</head>
+<body>
+
+<b>License:</b><br/><br/>
+libco is released to the public domain.
+<hr/>
+
+<b>Contact:</b><br/><br/>
+At present, you may contact me at setsunakun0 at hotmail dot com.<br/>
+I am interested in knowing of any projects that make use of this library,
+though this is only a courtesy.
+<hr/>
+
+<b>Foreword:</b><br/><br/>
+libco is a cross-platform, public domain implementation of
+cooperative-multithreading; a feature that is sorely lacking
+from the ISO C/C++ standard.<br/>
+The library is designed for maximum speed and portability, and
+not for safety or features. If safety or extra functionality is desired,
+a wrapper API can easily be written to encapsulate all library functions.<br/>
+Behavior of executing operations that are listed as not permitted
+below result in undefined behavior. They may work anyway, they
+may cause undesired / unknown behavior, or they may crash the
+program entirely.<br/>
+The goal of this library was to simplify the base API as much as possible,
+implementing only that which cannot be implemented using pure C. Additional
+functionality after this would only complicate ports of this library to new
+platforms.
+<hr/>
+
+<b>Porting:</b><br/><br/>
+This document is included as a reference for porting libco. Please submit any
+ports you create to me, so that libco can become more useful. Please note that
+since libco is public domain, you must submit your code as a work of the
+public domain in order for it to be included in the official distribution.
+Full credit will be given in the source code of the official release. Please
+do not bother submitting code to me under any other license -- including GPL,
+LGPL, BSD or CC -- I am not interested in creating a library with multiple
+different licenses depending on which targets are used.
+<hr/>
+
+<b>Synopsis:</b><br/><br/>
+<code>
+typedef void* cothread_t;<br/>
+<br/>
+cothread_t co_active();<br/>
+cothread_t co_create(unsigned int heapsize, void (*coentry)(void));<br/>
+void &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;co_delete(cothread_t cothread);<br/>
+void &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;co_switch(cothread_t cothread);<br/>
+</code>
+<hr/>
+
+<b>Usage:</b>
+<hr/>
+
+<code>typedef void* cothread_t;</code><br/><br/>
+Handle to cothread.<br/>
+Handle must be of type void*.<br/>
+A value of null (0) indicates an uninitialized or invalid
+handle, whereas a non-zero value indicates a valid handle.
+<hr/>
+
+<code>cothread_t co_active();</code><br/><br/>
+Return handle to current cothread. Always returns a valid handle, even when
+called from the main program thread.
+<hr/>
+
+<code>cothread_t co_create(unsigned int heapsize, void (*coentry)(void));</code><br/><br/>
+Create new cothread.<br/>
+Heapsize is the amount of memory allocated for the cothread stack, specified
+in bytes. This is unfortunately impossible to make fully portable. It is
+recommended to specify sizes using `n * sizeof(void*)'. It is better to err
+on the side of caution and allocate more memory than will be needed to ensure
+compatibility with other platforms, within reason. A typical heapsize for a
+32-bit architecture is ~1MB.<br/>
+When the new cothread is first called, program execution jumps to coentry.
+This function does not take any arguments, due to portability issues with
+passing function arguments. However, arguments can be simulated by the use
+of global variables, which can be set before the first call to each cothread.<br/>
+coentry() must not return, and should end with an appropriate co_switch()
+statement. Behavior is undefined if entry point returns normally.<br/>
+Library is responsible for allocating cothread stack memory, to free
+the user from needing to allocate special memory capable of being used
+as program stack memory on platforms where this is required.<br/>
+User is always responsible for deleting cothreads with co_delete().<br/>
+Return value of null (0) indicates cothread creation failed.
+<hr/>
+
+<code>void co_delete(cothread_t cothread);</code><br/><br/>
+Delete specified cothread.<br/>
+Null (0) or invalid cothread handle is not allowed.<br/>
+Passing handle of active cothread to this function is not allowed.<br/>
+Passing handle of primary cothread is not allowed.
+<hr/>
+
+<code>void co_switch(cothread_t cothread);</code><br/><br/>
+Switch to specified cothread.<br/>
+Null (0) or invalid cothread handle is not allowed.<br/>
+Passing handle of active cothread to this function is not allowed.
+<hr/>
+
+</body>
+</html>
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/fiber.c b/fluent-bit/lib/monkey/deps/flb_libco/fiber.c
new file mode 100644
index 000000000..f91b912b7
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/fiber.c
@@ -0,0 +1,54 @@
+/*
+ libco.win (2008-01-28)
+ authors: Nach, byuu
+ license: public domain
+*/
+
+#define LIBCO_C
+#include "libco.h"
+#include "settings.h"
+
+#define WINVER 0x0400
+#define _WIN32_WINNT 0x0400
+#include <windows.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static thread_local cothread_t co_active_ = 0;
+
+static void __stdcall co_thunk(void* coentry) {
+ ((void (*)(void))coentry)();
+}
+
+cothread_t co_active() {
+ if(!co_active_) {
+ ConvertThreadToFiber(0);
+ co_active_ = GetCurrentFiber();
+ }
+ return co_active_;
+}
+
+cothread_t co_create(unsigned int heapsize, void (*coentry)(void),
+ size_t *out_size) {
+ if(!co_active_) {
+ ConvertThreadToFiber(0);
+ co_active_ = GetCurrentFiber();
+ }
+ *out_size = heapsize;
+ return (cothread_t)CreateFiber(heapsize, co_thunk, (void*)coentry);
+}
+
+void co_delete(cothread_t cothread) {
+ DeleteFiber(cothread);
+}
+
+void co_switch(cothread_t cothread) {
+ co_active_ = cothread;
+ SwitchToFiber(cothread);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/libco.c b/fluent-bit/lib/monkey/deps/flb_libco/libco.c
new file mode 100644
index 000000000..e0101d238
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/libco.c
@@ -0,0 +1,37 @@
+/*
+ libco
+ license: public domain
+*/
+
+#if defined(__clang__)
+ #pragma clang diagnostic ignored "-Wparentheses"
+#endif
+
+#if defined(__clang__) || defined(__GNUC__)
+ #if defined(__i386__)
+ #include "x86.c"
+ #elif defined(__amd64__)
+ #include "amd64.c"
+ #elif defined(__arm__)
+ #include "arm.c"
+ #elif defined(__aarch64__)
+ #include "aarch64.c"
+ #elif defined(_ARCH_PPC)
+ #include "ppc.c"
+ #elif defined(_WIN32)
+ #include "fiber.c"
+ #else
+ #include "sjlj.c"
+ #endif
+#elif defined(_MSC_VER)
+ #if defined(_M_IX86)
+ #include "x86.c"
+// Commented out due to SIGSEGV bug
+// #elif defined(_M_AMD64)
+// #include "amd64.c"
+ #else
+ #include "fiber.c"
+ #endif
+#else
+ #error "libco: unsupported processor, compiler or operating system"
+#endif
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/libco.h b/fluent-bit/lib/monkey/deps/flb_libco/libco.h
new file mode 100644
index 000000000..f2e2487aa
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/libco.h
@@ -0,0 +1,28 @@
+/*
+ libco v18 (2016-09-14)
+ author: byuu
+ license: public domain
+*/
+
+#ifndef LIBCO_H
+#define LIBCO_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void* cothread_t;
+
+cothread_t co_active();
+cothread_t co_create(unsigned int, void (*)(void), size_t *);
+void co_delete(cothread_t);
+void co_switch(cothread_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef LIBCO_H */
+#endif
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/ppc.c b/fluent-bit/lib/monkey/deps/flb_libco/ppc.c
new file mode 100644
index 000000000..533256b34
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/ppc.c
@@ -0,0 +1,369 @@
+/*
+ libco.ppc (2016-09-14)
+ author: blargg
+ license: public domain
+*/
+
+#define LIBCO_C
+#include "libco.h"
+#include "settings.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#if LIBCO_MPROTECT
+ #include <unistd.h>
+ #include <sys/mman.h>
+#endif
+
+/* state format (offsets in 32-bit words)
+
+ +0 pointer to swap code
+ rest of function descriptor for entry function
+ +8 PC
++10 SP
+ special registers
+ GPRs
+ FPRs
+ VRs
+ stack
+*/
+
+enum { state_size = 1024 };
+enum { above_stack = 2048 };
+enum { stack_align = 256 };
+
+static thread_local cothread_t co_active_handle = 0;
+
+/* determine environment */
+
+#define LIBCO_PPC64 (_ARCH_PPC64 || __PPC64__ || __ppc64__ || __powerpc64__)
+
+/* whether function calls are indirect through a descriptor, or are directly to function */
+#ifndef LIBCO_PPCDESC
+ #if !_CALL_SYSV && (_CALL_AIX || _CALL_AIXDESC || LIBCO_PPC64)
+ #define LIBCO_PPCDESC 1
+ #endif
+#endif
+
+#ifdef LIBCO_MPROTECT
+ alignas(4096)
+#else
+ text_section
+#endif
+static const uint32_t libco_ppc_code[1024] = {
+ #if LIBCO_PPC64
+ 0x7d000026, /* mfcr r8 */
+ 0xf8240028, /* std r1,40(r4) */
+ 0x7d2802a6, /* mflr r9 */
+ 0xf9c40048, /* std r14,72(r4) */
+ 0xf9e40050, /* std r15,80(r4) */
+ 0xfa040058, /* std r16,88(r4) */
+ 0xfa240060, /* std r17,96(r4) */
+ 0xfa440068, /* std r18,104(r4) */
+ 0xfa640070, /* std r19,112(r4) */
+ 0xfa840078, /* std r20,120(r4) */
+ 0xfaa40080, /* std r21,128(r4) */
+ 0xfac40088, /* std r22,136(r4) */
+ 0xfae40090, /* std r23,144(r4) */
+ 0xfb040098, /* std r24,152(r4) */
+ 0xfb2400a0, /* std r25,160(r4) */
+ 0xfb4400a8, /* std r26,168(r4) */
+ 0xfb6400b0, /* std r27,176(r4) */
+ 0xfb8400b8, /* std r28,184(r4) */
+ 0xfba400c0, /* std r29,192(r4) */
+ 0xfbc400c8, /* std r30,200(r4) */
+ 0xfbe400d0, /* std r31,208(r4) */
+ 0xf9240020, /* std r9,32(r4) */
+ 0xe8e30020, /* ld r7,32(r3) */
+ 0xe8230028, /* ld r1,40(r3) */
+ 0x48000009, /* bl 1 */
+ 0x7fe00008, /* trap */
+ 0x91040030, /*1:stw r8,48(r4) */
+ 0x80c30030, /* lwz r6,48(r3) */
+ 0x7ce903a6, /* mtctr r7 */
+ 0xe9c30048, /* ld r14,72(r3) */
+ 0xe9e30050, /* ld r15,80(r3) */
+ 0xea030058, /* ld r16,88(r3) */
+ 0xea230060, /* ld r17,96(r3) */
+ 0xea430068, /* ld r18,104(r3) */
+ 0xea630070, /* ld r19,112(r3) */
+ 0xea830078, /* ld r20,120(r3) */
+ 0xeaa30080, /* ld r21,128(r3) */
+ 0xeac30088, /* ld r22,136(r3) */
+ 0xeae30090, /* ld r23,144(r3) */
+ 0xeb030098, /* ld r24,152(r3) */
+ 0xeb2300a0, /* ld r25,160(r3) */
+ 0xeb4300a8, /* ld r26,168(r3) */
+ 0xeb6300b0, /* ld r27,176(r3) */
+ 0xeb8300b8, /* ld r28,184(r3) */
+ 0xeba300c0, /* ld r29,192(r3) */
+ 0xebc300c8, /* ld r30,200(r3) */
+ 0xebe300d0, /* ld r31,208(r3) */
+ 0x7ccff120, /* mtcr r6 */
+ #else
+ 0x7d000026, /* mfcr r8 */
+ 0x90240028, /* stw r1,40(r4) */
+ 0x7d2802a6, /* mflr r9 */
+ 0x91a4003c, /* stw r13,60(r4) */
+ 0x91c40040, /* stw r14,64(r4) */
+ 0x91e40044, /* stw r15,68(r4) */
+ 0x92040048, /* stw r16,72(r4) */
+ 0x9224004c, /* stw r17,76(r4) */
+ 0x92440050, /* stw r18,80(r4) */
+ 0x92640054, /* stw r19,84(r4) */
+ 0x92840058, /* stw r20,88(r4) */
+ 0x92a4005c, /* stw r21,92(r4) */
+ 0x92c40060, /* stw r22,96(r4) */
+ 0x92e40064, /* stw r23,100(r4) */
+ 0x93040068, /* stw r24,104(r4) */
+ 0x9324006c, /* stw r25,108(r4) */
+ 0x93440070, /* stw r26,112(r4) */
+ 0x93640074, /* stw r27,116(r4) */
+ 0x93840078, /* stw r28,120(r4) */
+ 0x93a4007c, /* stw r29,124(r4) */
+ 0x93c40080, /* stw r30,128(r4) */
+ 0x93e40084, /* stw r31,132(r4) */
+ 0x91240020, /* stw r9,32(r4) */
+ 0x80e30020, /* lwz r7,32(r3) */
+ 0x80230028, /* lwz r1,40(r3) */
+ 0x48000009, /* bl 1 */
+ 0x7fe00008, /* trap */
+ 0x91040030, /*1:stw r8,48(r4) */
+ 0x80c30030, /* lwz r6,48(r3) */
+ 0x7ce903a6, /* mtctr r7 */
+ 0x81a3003c, /* lwz r13,60(r3) */
+ 0x81c30040, /* lwz r14,64(r3) */
+ 0x81e30044, /* lwz r15,68(r3) */
+ 0x82030048, /* lwz r16,72(r3) */
+ 0x8223004c, /* lwz r17,76(r3) */
+ 0x82430050, /* lwz r18,80(r3) */
+ 0x82630054, /* lwz r19,84(r3) */
+ 0x82830058, /* lwz r20,88(r3) */
+ 0x82a3005c, /* lwz r21,92(r3) */
+ 0x82c30060, /* lwz r22,96(r3) */
+ 0x82e30064, /* lwz r23,100(r3) */
+ 0x83030068, /* lwz r24,104(r3) */
+ 0x8323006c, /* lwz r25,108(r3) */
+ 0x83430070, /* lwz r26,112(r3) */
+ 0x83630074, /* lwz r27,116(r3) */
+ 0x83830078, /* lwz r28,120(r3) */
+ 0x83a3007c, /* lwz r29,124(r3) */
+ 0x83c30080, /* lwz r30,128(r3) */
+ 0x83e30084, /* lwz r31,132(r3) */
+ 0x7ccff120, /* mtcr r6 */
+ #endif
+
+ #ifndef LIBCO_PPC_NOFP
+ 0xd9c400e0, /* stfd f14,224(r4) */
+ 0xd9e400e8, /* stfd f15,232(r4) */
+ 0xda0400f0, /* stfd f16,240(r4) */
+ 0xda2400f8, /* stfd f17,248(r4) */
+ 0xda440100, /* stfd f18,256(r4) */
+ 0xda640108, /* stfd f19,264(r4) */
+ 0xda840110, /* stfd f20,272(r4) */
+ 0xdaa40118, /* stfd f21,280(r4) */
+ 0xdac40120, /* stfd f22,288(r4) */
+ 0xdae40128, /* stfd f23,296(r4) */
+ 0xdb040130, /* stfd f24,304(r4) */
+ 0xdb240138, /* stfd f25,312(r4) */
+ 0xdb440140, /* stfd f26,320(r4) */
+ 0xdb640148, /* stfd f27,328(r4) */
+ 0xdb840150, /* stfd f28,336(r4) */
+ 0xdba40158, /* stfd f29,344(r4) */
+ 0xdbc40160, /* stfd f30,352(r4) */
+ 0xdbe40168, /* stfd f31,360(r4) */
+ 0xc9c300e0, /* lfd f14,224(r3) */
+ 0xc9e300e8, /* lfd f15,232(r3) */
+ 0xca0300f0, /* lfd f16,240(r3) */
+ 0xca2300f8, /* lfd f17,248(r3) */
+ 0xca430100, /* lfd f18,256(r3) */
+ 0xca630108, /* lfd f19,264(r3) */
+ 0xca830110, /* lfd f20,272(r3) */
+ 0xcaa30118, /* lfd f21,280(r3) */
+ 0xcac30120, /* lfd f22,288(r3) */
+ 0xcae30128, /* lfd f23,296(r3) */
+ 0xcb030130, /* lfd f24,304(r3) */
+ 0xcb230138, /* lfd f25,312(r3) */
+ 0xcb430140, /* lfd f26,320(r3) */
+ 0xcb630148, /* lfd f27,328(r3) */
+ 0xcb830150, /* lfd f28,336(r3) */
+ 0xcba30158, /* lfd f29,344(r3) */
+ 0xcbc30160, /* lfd f30,352(r3) */
+ 0xcbe30168, /* lfd f31,360(r3) */
+ #endif
+
+ #ifdef __ALTIVEC__
+ 0x7ca042a6, /* mfvrsave r5 */
+ 0x39040180, /* addi r8,r4,384 */
+ 0x39240190, /* addi r9,r4,400 */
+ 0x70a00fff, /* andi. r0,r5,4095 */
+ 0x90a40034, /* stw r5,52(r4) */
+ 0x4182005c, /* beq- 2 */
+ 0x7e8041ce, /* stvx v20,r0,r8 */
+ 0x39080020, /* addi r8,r8,32 */
+ 0x7ea049ce, /* stvx v21,r0,r9 */
+ 0x39290020, /* addi r9,r9,32 */
+ 0x7ec041ce, /* stvx v22,r0,r8 */
+ 0x39080020, /* addi r8,r8,32 */
+ 0x7ee049ce, /* stvx v23,r0,r9 */
+ 0x39290020, /* addi r9,r9,32 */
+ 0x7f0041ce, /* stvx v24,r0,r8 */
+ 0x39080020, /* addi r8,r8,32 */
+ 0x7f2049ce, /* stvx v25,r0,r9 */
+ 0x39290020, /* addi r9,r9,32 */
+ 0x7f4041ce, /* stvx v26,r0,r8 */
+ 0x39080020, /* addi r8,r8,32 */
+ 0x7f6049ce, /* stvx v27,r0,r9 */
+ 0x39290020, /* addi r9,r9,32 */
+ 0x7f8041ce, /* stvx v28,r0,r8 */
+ 0x39080020, /* addi r8,r8,32 */
+ 0x7fa049ce, /* stvx v29,r0,r9 */
+ 0x39290020, /* addi r9,r9,32 */
+ 0x7fc041ce, /* stvx v30,r0,r8 */
+ 0x7fe049ce, /* stvx v31,r0,r9 */
+ 0x80a30034, /*2:lwz r5,52(r3) */
+ 0x39030180, /* addi r8,r3,384 */
+ 0x39230190, /* addi r9,r3,400 */
+ 0x70a00fff, /* andi. r0,r5,4095 */
+ 0x7ca043a6, /* mtvrsave r5 */
+ 0x4d820420, /* beqctr */
+ 0x7e8040ce, /* lvx v20,r0,r8 */
+ 0x39080020, /* addi r8,r8,32 */
+ 0x7ea048ce, /* lvx v21,r0,r9 */
+ 0x39290020, /* addi r9,r9,32 */
+ 0x7ec040ce, /* lvx v22,r0,r8 */
+ 0x39080020, /* addi r8,r8,32 */
+ 0x7ee048ce, /* lvx v23,r0,r9 */
+ 0x39290020, /* addi r9,r9,32 */
+ 0x7f0040ce, /* lvx v24,r0,r8 */
+ 0x39080020, /* addi r8,r8,32 */
+ 0x7f2048ce, /* lvx v25,r0,r9 */
+ 0x39290020, /* addi r9,r9,32 */
+ 0x7f4040ce, /* lvx v26,r0,r8 */
+ 0x39080020, /* addi r8,r8,32 */
+ 0x7f6048ce, /* lvx v27,r0,r9 */
+ 0x39290020, /* addi r9,r9,32 */
+ 0x7f8040ce, /* lvx v28,r0,r8 */
+ 0x39080020, /* addi r8,r8,32 */
+ 0x7fa048ce, /* lvx v29,r0,r9 */
+ 0x39290020, /* addi r9,r9,32 */
+ 0x7fc040ce, /* lvx v30,r0,r8 */
+ 0x7fe048ce, /* lvx v31,r0,r9 */
+ #endif
+
+ 0x4e800420, /* bctr */
+};
+
+#if LIBCO_PPCDESC
+ /* function call goes through indirect descriptor */
+ #define CO_SWAP_ASM(x, y) ((void (*)(cothread_t, cothread_t))(uintptr_t)x)(x, y)
+#else
+ /* function call goes directly to code */
+ #define CO_SWAP_ASM(x, y) ((void (*)(cothread_t, cothread_t))(uintptr_t)libco_ppc_code)(x, y)
+#endif
+
+static uint32_t* co_create_(unsigned size, uintptr_t entry) {
+ (void)entry;
+
+ uint32_t* t = (uint32_t*)malloc(size);
+
+ #if LIBCO_PPCDESC
+ if(t) {
+ memcpy(t, (void*)entry, sizeof(void*) * 3); /* copy entry's descriptor */
+ *(const void**)t = libco_ppc_code; /* set function pointer to swap routine */
+ }
+ #endif
+
+ return t;
+}
+
+cothread_t co_create(unsigned int size, void (*entry_)(void),
+ size_t *out_size) {
+
+ uintptr_t entry = (uintptr_t)entry_;
+ uint32_t* t = 0;
+
+ /* be sure main thread was successfully allocated */
+ if(co_active()) {
+ size += state_size + above_stack + stack_align;
+ t = co_create_(size, entry);
+ }
+
+ if(t) {
+ uintptr_t sp;
+ int shift;
+
+ /* save current registers into new thread, so that any special ones will have proper values when thread is begun */
+ CO_SWAP_ASM(t, t);
+
+ #if LIBCO_PPCDESC
+ entry = (uintptr_t)*(void**)entry; /* get real address */
+ #endif
+
+ /* put stack near end of block, and align */
+ sp = (uintptr_t)t + size - above_stack;
+ sp -= sp % stack_align;
+
+ /* on PPC32, we save and restore GPRs as 32 bits. for PPC64, we
+ save and restore them as 64 bits, regardless of the size the ABI
+ uses. so, we manually write pointers at the proper size. we always
+ save and restore at the same address, and since PPC is big-endian,
+ we must put the low byte first on PPC32. */
+
+ /* if uintptr_t is 32 bits, >>32 is undefined behavior,
+ so we do two shifts and don't have to care how many bits uintptr_t is. */
+ #if LIBCO_PPC64
+ shift = 16;
+ #else
+ shift = 0;
+ #endif
+
+ /* set up so entry will be called on next swap */
+ t[ 8] = (uint32_t)(entry >> shift >> shift);
+ t[ 9] = (uint32_t)entry;
+
+ t[10] = (uint32_t)(sp >> shift >> shift);
+ t[11] = (uint32_t)sp;
+ }
+ *out_size = size;
+ return t;
+}
+
+void co_delete(cothread_t t) {
+ free(t);
+}
+
+static void co_init_(void) {
+ #if LIBCO_MPROTECT
+ long page_size = sysconf(_SC_PAGESIZE);
+ if(page_size > 0) {
+ uintptr_t align = page_size;
+ uintptr_t begin = (uintptr_t)libco_ppc_code;
+ uintptr_t end = begin + sizeof libco_ppc_code;
+
+ /* align beginning and end */
+ end += align - 1;
+ end -= end % align;
+ begin -= begin % align;
+
+ mprotect((void*)begin, end - begin, PROT_READ | PROT_EXEC);
+ }
+ #endif
+
+ co_active_handle = co_create_(state_size, (uintptr_t)&co_switch);
+}
+
+cothread_t co_active() {
+ if(!co_active_handle) co_init_();
+
+ return co_active_handle;
+}
+
+void co_switch(cothread_t t) {
+ cothread_t old = co_active_handle;
+ co_active_handle = t;
+
+ CO_SWAP_ASM(t, old);
+}
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/settings.h b/fluent-bit/lib/monkey/deps/flb_libco/settings.h
new file mode 100644
index 000000000..0c3db68e0
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/settings.h
@@ -0,0 +1,52 @@
+#ifdef LIBCO_C
+
+/*[amd64, arm, ppc, x86]:
+ by default, co_swap_function is marked as a text (code) section
+ if not supported, uncomment the below line to use mprotect instead */
+
+/*
+ * Testing Fluent Bit on Windows when doing co_swap it crash if the
+ * option LIBCO_MPROTECT is not defined.
+ */
+#ifdef _WIN32
+#define LIBCO_MPROTECT
+#endif
+
+/*[amd64]:
+ Win64 only: provides a substantial speed-up, but will thrash XMM regs
+ do not use this unless you are certain your application won't use SSE */
+/* #define LIBCO_NO_SSE */
+
+#ifdef LIBCO_C
+ #ifdef LIBCO_MP
+ #ifdef _MSC_VER
+ #define thread_local __declspec (thread)
+ #else
+ #define thread_local __thread
+ #endif
+ #else
+ #define thread_local
+ #endif
+#endif
+
+#if __STDC_VERSION__ >= 201112L
+ #ifndef _MSC_VER
+ #include <stdalign.h>
+ #endif
+#else
+ #define alignas(bytes)
+#endif
+
+#if defined(_MSC_VER)
+ #pragma data_seg(".text")
+ #define text_section __declspec(allocate(".text"))
+#elif defined(__APPLE__) && defined(__MACH__)
+ #define text_section __attribute__((section("__TEXT,__text")))
+#elif defined(__clang__)
+ #define text_section __attribute__((section(".text")))
+#else
+ #define text_section __attribute__((section(".text#")))
+#endif
+
+/* ifdef LIBCO_C */
+#endif
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/sjlj.c b/fluent-bit/lib/monkey/deps/flb_libco/sjlj.c
new file mode 100644
index 000000000..36d110b71
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/sjlj.c
@@ -0,0 +1,105 @@
+/*
+ libco.sjlj (2008-01-28)
+ author: Nach
+ license: public domain
+*/
+
+/*
+ note this was designed for UNIX systems. Based on ideas expressed in a paper by Ralf Engelschall.
+ for SJLJ on other systems, one would want to rewrite springboard() and co_create() and hack the jmb_buf stack pointer.
+*/
+
+#define LIBCO_C
+#include "libco.h"
+
+#include <stdlib.h>
+#include <signal.h>
+#include <setjmp.h>
+#include "settings.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ sigjmp_buf context;
+ void (*coentry)(void);
+ void* stack;
+} cothread_struct;
+
+static thread_local cothread_struct co_primary;
+static thread_local cothread_struct* creating;
+static thread_local cothread_struct* co_running = 0;
+
+static void springboard(int ignored) {
+ if(sigsetjmp(creating->context, 0)) {
+ co_running->coentry();
+ }
+}
+
+cothread_t co_active() {
+ if(!co_running) co_running = &co_primary;
+ return (cothread_t)co_running;
+}
+
+cothread_t co_create(unsigned int size, void (*coentry)(void),
+ size_t *out_size) {
+ if(!co_running) co_running = &co_primary;
+
+ cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct));
+ if(thread) {
+ struct sigaction handler;
+ struct sigaction old_handler;
+
+ stack_t stack;
+ stack_t old_stack;
+
+ thread->coentry = thread->stack = 0;
+
+ stack.ss_flags = 0;
+ stack.ss_size = size;
+ thread->stack = stack.ss_sp = malloc(size);
+ if(stack.ss_sp && !sigaltstack(&stack, &old_stack)) {
+ handler.sa_handler = springboard;
+ handler.sa_flags = SA_ONSTACK;
+ sigemptyset(&handler.sa_mask);
+ creating = thread;
+
+ if(!sigaction(SIGUSR1, &handler, &old_handler)) {
+ if(!raise(SIGUSR1)) {
+ thread->coentry = coentry;
+ }
+ sigaltstack(&old_stack, 0);
+ sigaction(SIGUSR1, &old_handler, 0);
+ }
+ }
+
+ if(thread->coentry != coentry) {
+ co_delete(thread);
+ thread = 0;
+ }
+ }
+
+ *out_size = size;
+ return (cothread_t)thread;
+}
+
+void co_delete(cothread_t cothread) {
+ if(cothread) {
+ if(((cothread_struct*)cothread)->stack) {
+ free(((cothread_struct*)cothread)->stack);
+ }
+ free(cothread);
+ }
+}
+
+void co_switch(cothread_t cothread) {
+ if(!sigsetjmp(co_running->context, 0)) {
+ co_running = (cothread_struct*)cothread;
+ siglongjmp(co_running->context, 1);
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/ucontext.c b/fluent-bit/lib/monkey/deps/flb_libco/ucontext.c
new file mode 100644
index 000000000..b252cb2d8
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/ucontext.c
@@ -0,0 +1,72 @@
+/*
+ libco.ucontext (2008-01-28)
+ author: Nach
+ license: public domain
+*/
+
+/*
+ WARNING: the overhead of POSIX ucontext is very high,
+ assembly versions of libco or libco_sjlj should be much faster
+
+ this library only exists for two reasons:
+ 1: as an initial test for the viability of a ucontext implementation
+ 2: to demonstrate the power and speed of libco over existing implementations,
+ such as pth (which defaults to wrapping ucontext on unix targets)
+
+ use this library only as a *last resort*
+*/
+
+#define LIBCO_C
+#include "libco.h"
+#include "settings.h"
+
+#define _BSD_SOURCE
+#include <stdlib.h>
+#include <ucontext.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static thread_local ucontext_t co_primary;
+static thread_local ucontext_t* co_running = 0;
+
+cothread_t co_active() {
+ if(!co_running) co_running = &co_primary;
+ return (cothread_t)co_running;
+}
+
+cothread_t co_create(unsigned int heapsize, void (*coentry)(void),
+ size_t *out_size) {
+ if(!co_running) co_running = &co_primary;
+ ucontext_t* thread = (ucontext_t*)malloc(sizeof(ucontext_t));
+ if(thread) {
+ if((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = malloc(heapsize))) {
+ thread->uc_link = co_running;
+ thread->uc_stack.ss_size = heapsize;
+ *out_size = heapsize;
+ makecontext(thread, coentry, 0);
+ } else {
+ co_delete((cothread_t)thread);
+ thread = 0;
+ }
+ }
+ return (cothread_t)thread;
+}
+
+void co_delete(cothread_t cothread) {
+ if(cothread) {
+ if(((ucontext_t*)cothread)->uc_stack.ss_sp) { free(((ucontext_t*)cothread)->uc_stack.ss_sp); }
+ free(cothread);
+ }
+}
+
+void co_switch(cothread_t cothread) {
+ ucontext_t* old_thread = co_running;
+ co_running = (ucontext_t*)cothread;
+ swapcontext(old_thread, co_running);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/fluent-bit/lib/monkey/deps/flb_libco/x86.c b/fluent-bit/lib/monkey/deps/flb_libco/x86.c
new file mode 100644
index 000000000..bfa50b84d
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/flb_libco/x86.c
@@ -0,0 +1,116 @@
+/*
+ libco.x86 (2016-09-14)
+ author: byuu
+ license: public domain
+*/
+
+#define LIBCO_C
+#include "libco.h"
+#include "settings.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__clang__) || defined(__GNUC__)
+ #define fastcall __attribute__((fastcall))
+#elif defined(_MSC_VER)
+ #define fastcall __fastcall
+#else
+ #error "libco: please define fastcall macro"
+#endif
+
+static thread_local long co_active_buffer[64];
+static thread_local cothread_t co_active_handle = 0;
+static void (fastcall *co_swap)(cothread_t, cothread_t) = 0;
+
+#ifdef LIBCO_MPROTECT
+ alignas(4096)
+#else
+ text_section
+#endif
+/* ABI: fastcall */
+static const unsigned char co_swap_function[4096] = {
+ 0x89, 0x22, /* mov [edx],esp */
+ 0x8b, 0x21, /* mov esp,[ecx] */
+ 0x58, /* pop eax */
+ 0x89, 0x6a, 0x04, /* mov [edx+ 4],ebp */
+ 0x89, 0x72, 0x08, /* mov [edx+ 8],esi */
+ 0x89, 0x7a, 0x0c, /* mov [edx+12],edi */
+ 0x89, 0x5a, 0x10, /* mov [edx+16],ebx */
+ 0x8b, 0x69, 0x04, /* mov ebp,[ecx+ 4] */
+ 0x8b, 0x71, 0x08, /* mov esi,[ecx+ 8] */
+ 0x8b, 0x79, 0x0c, /* mov edi,[ecx+12] */
+ 0x8b, 0x59, 0x10, /* mov ebx,[ecx+16] */
+ 0xff, 0xe0, /* jmp eax */
+};
+
+#ifdef _WIN32
+ #include <windows.h>
+
+ static void co_init() {
+ #ifdef LIBCO_MPROTECT
+ DWORD old_privileges;
+ VirtualProtect((void*)co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READ, &old_privileges);
+ #endif
+ }
+#else
+ #include <unistd.h>
+ #include <sys/mman.h>
+
+ static void co_init() {
+ #ifdef LIBCO_MPROTECT
+ unsigned long addr = (unsigned long)co_swap_function;
+ unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
+ unsigned long size = (addr - base) + sizeof co_swap_function;
+ mprotect((void*)base, size, PROT_READ | PROT_EXEC);
+ #endif
+ }
+#endif
+
+static void crash() {
+ assert(0); /* called only if cothread_t entrypoint returns */
+}
+
+cothread_t co_active() {
+ if(!co_active_handle) co_active_handle = &co_active_buffer;
+ return co_active_handle;
+}
+
+cothread_t co_create(unsigned int size, void (*entrypoint)(void),
+ size_t *out_size) {
+ cothread_t handle;
+ if(!co_swap) {
+ co_init();
+ co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function;
+ }
+ if(!co_active_handle) co_active_handle = &co_active_buffer;
+ size += 256; /* allocate additional space for storage */
+ size &= ~15; /* align stack to 16-byte boundary */
+ *out_size = size;
+
+ if(handle = (cothread_t)malloc(size)) {
+ long *p = (long*)((char*)handle + size); /* seek to top of stack */
+ *--p = (long)crash; /* crash if entrypoint returns */
+ *--p = (long)entrypoint; /* start of function */
+ *(long*)handle = (long)p; /* stack pointer */
+ }
+
+ return handle;
+}
+
+void co_delete(cothread_t handle) {
+ free(handle);
+}
+
+void co_switch(cothread_t handle) {
+ register cothread_t co_previous_handle = co_active_handle;
+ co_swap(co_active_handle = handle, co_previous_handle);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/fluent-bit/lib/monkey/deps/rbtree/CMakeLists.txt b/fluent-bit/lib/monkey/deps/rbtree/CMakeLists.txt
new file mode 100644
index 000000000..739260e2c
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/rbtree/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(src
+ rbtree.c
+ )
+
+add_library(rbtree STATIC ${src})
diff --git a/fluent-bit/lib/monkey/deps/rbtree/README.md b/fluent-bit/lib/monkey/deps/rbtree/README.md
new file mode 100644
index 000000000..00851601e
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/rbtree/README.md
@@ -0,0 +1,7 @@
+[Taken from: https://github.com/pvachon/rbtree]
+
+A simple, intrusive, zero-allocation Red-Black tree implementation.
+
+Designed exclusively for systems where determinism is needed.
+
+Licensed under a 2-clause BSD license for the sake of simplicity.
diff --git a/fluent-bit/lib/monkey/deps/rbtree/rbtree.c b/fluent-bit/lib/monkey/deps/rbtree/rbtree.c
new file mode 100644
index 000000000..99e56e0c8
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/rbtree/rbtree.c
@@ -0,0 +1,811 @@
+/*
+ Copyright (c) 2013, Phil Vachon <phil@cowpig.ca>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \defgroup rb_tree_implementation Implementation Details
+ * All the implementation details for the red-black tree, including functions for
+ * the maintenance of tree properties.
+ * @{
+ */
+
+/** \file rbtree.c
+ * An implementation of an intrusive red-black self-balancing tree, that can
+ * be used to implement red-black trees in situations where memory allocation
+ * is not an option.
+ *
+ * This file exclusively contains implementation details for the red-black tree, so
+ * probably is not of much interest to most people.
+ *
+ * \see rbtree.h
+ * \see rb_tree
+ * \see rb_tree_node
+ */
+
+#include <rbtree.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+/** \defgroup rb_tree_colors Colors for the red-black tree nodes
+ * @{
+ */
+
+/**
+ * Node is black
+ */
+#define COLOR_BLACK 0x0
+
+/**
+ * Node is red
+ */
+#define COLOR_RED 0x1
+/**@}*/
+
+static
+int __rb_tree_cmp_mapper(void *state, const void *lhs, const void *rhs)
+{
+ rb_cmp_func_t cmp = state;
+ return cmp(lhs, rhs);
+}
+
+rb_result_t rb_tree_new_ex(struct rb_tree *tree,
+ rb_cmp_func_ex_t compare,
+ void *state)
+{
+ rb_result_t ret = RB_OK;
+
+ RB_ASSERT_ARG(tree != NULL);
+ RB_ASSERT_ARG(compare != NULL);
+
+ tree->root = NULL;
+ tree->compare = compare;
+ tree->state = state;
+ tree->rightmost = NULL;
+
+ return ret;
+}
+
+rb_result_t rb_tree_new(struct rb_tree *tree,
+ rb_cmp_func_t compare)
+{
+ RB_ASSERT_ARG(tree != NULL);
+ RB_ASSERT_ARG(compare != NULL);
+
+ return rb_tree_new_ex(tree, __rb_tree_cmp_mapper, (void *)compare);
+}
+
+rb_result_t rb_tree_destroy(struct rb_tree *tree)
+{
+ rb_result_t ret = RB_OK;
+
+ RB_ASSERT_ARG(tree != NULL);
+
+ memset(tree, 0, sizeof(struct rb_tree));
+
+ return ret;
+}
+
+rb_result_t rb_tree_empty(struct rb_tree *tree,
+ int *is_empty)
+{
+ rb_result_t ret = RB_OK;
+
+ RB_ASSERT_ARG(tree != NULL);
+ RB_ASSERT_ARG(is_empty != NULL);
+
+ *is_empty = !!(tree->root == NULL);
+
+ return ret;
+}
+
+rb_result_t rb_tree_find(struct rb_tree *tree,
+ const void *key,
+ struct rb_tree_node **value)
+{
+ rb_result_t ret = RB_OK;
+
+ RB_ASSERT_ARG(tree != NULL);
+ RB_ASSERT_ARG(value != NULL);
+
+ *value = NULL;
+
+ if (RB_UNLIKELY(tree->root == NULL)) {
+ ret = RB_NOT_FOUND;
+ goto done;
+ }
+
+ struct rb_tree_node *node = tree->root;
+
+ while (node != NULL) {
+ int compare = tree->compare(tree->state, key, node->key);
+
+ if (compare < 0) {
+ node = node->left;
+ } else if (compare == 0) {
+ break; /* We found our node */
+ } else {
+ /* Otherwise, we want the right node, and continue iteration */
+ node = node->right;
+ }
+ }
+
+ if (node == NULL) {
+ ret = RB_NOT_FOUND;
+ goto done;
+ }
+
+ /* Return the node we found */
+ *value = node;
+
+done:
+ return ret;
+}
+
+/* Helper function to get a node's sibling */
+static inline
+struct rb_tree_node *__helper_get_sibling(struct rb_tree_node *node)
+{
+ if (node->parent == NULL) {
+ return NULL;
+ }
+
+ struct rb_tree_node *parent = node->parent;
+
+ if (node == parent->left) {
+ return parent->right;
+ } else {
+ return parent->left;
+ }
+}
+
+/* Helper function to get a node's grandparent */
+static inline
+struct rb_tree_node *__helper_get_grandparent(struct rb_tree_node *node)
+{
+ if (node->parent == NULL) {
+ return NULL;
+ }
+
+ struct rb_tree_node *parent_node = node->parent;
+
+ return parent_node->parent;
+}
+
+/* Helper function to get a node's uncle */
+static inline
+struct rb_tree_node *__helper_get_uncle(struct rb_tree_node *node)
+{
+ struct rb_tree_node *grandparent = __helper_get_grandparent(node);
+
+ if (grandparent == NULL) {
+ return NULL;
+ }
+
+ if (node->parent == grandparent->left) {
+ return grandparent->right;
+ } else {
+ return grandparent->left;
+ }
+}
+
+/* Helper function to do a left rotation of a given node */
+static inline
+void __helper_rotate_left(struct rb_tree *tree,
+ struct rb_tree_node *node)
+{
+ struct rb_tree_node *x = node;
+ struct rb_tree_node *y = x->right;
+
+ x->right = y->left;
+
+ if (y->left != NULL) {
+ struct rb_tree_node *yleft = y->left;
+ yleft->parent = x;
+ }
+
+ y->parent = x->parent;
+
+ if (x->parent == NULL) {
+ tree->root = y;
+ } else {
+ struct rb_tree_node *xp = x->parent;
+ if (x == xp->left) {
+ xp->left = y;
+ } else {
+ xp->right = y;
+ }
+ }
+
+ y->left = x;
+ x->parent = y;
+}
+
+/* Helper function to do a right rotation of a given node */
+static inline
+void __helper_rotate_right(struct rb_tree *tree,
+ struct rb_tree_node *node)
+{
+ struct rb_tree_node *x = node;
+ struct rb_tree_node *y = x->left;
+
+ x->left = y->right;
+
+ if (y->right != NULL) {
+ struct rb_tree_node *yright = y->right;
+ yright->parent = x;
+ }
+
+ y->parent = x->parent;
+
+ if (x->parent == NULL) {
+ tree->root = y;
+ } else {
+ struct rb_tree_node *xp = x->parent;
+ if (x == xp->left) {
+ xp->left = y;
+ } else {
+ xp->right = y;
+ }
+ }
+
+ y->right = x;
+ x->parent = y;
+}
+
+/* Function to perform a RB tree rebalancing after an insertion */
+static
+void __helper_rb_tree_insert_rebalance(struct rb_tree *tree,
+ struct rb_tree_node *node)
+{
+ struct rb_tree_node *new_node_parent = node->parent;
+
+ if (new_node_parent != NULL && new_node_parent->color != COLOR_BLACK) {
+ struct rb_tree_node *pnode = node;
+
+ /* Iterate until we're at the root (which we just color black) or
+ * until we the parent node is no longer red.
+ */
+ while ((tree->root != pnode) && (pnode->parent != NULL) &&
+ (pnode->parent->color == COLOR_RED))
+ {
+ struct rb_tree_node *parent = pnode->parent;
+ struct rb_tree_node *grandparent = __helper_get_grandparent(pnode);
+ struct rb_tree_node *uncle = NULL;
+ int uncle_is_left;
+
+ assert(pnode->color == COLOR_RED);
+
+ if (parent == grandparent->left) {
+ uncle_is_left = 0;
+ uncle = grandparent->right;
+ } else {
+ uncle_is_left = 1;
+ uncle = grandparent->left;
+ }
+
+ /* Case 1: Uncle is not black */
+ if (uncle && uncle->color == COLOR_RED) {
+ /* Color parent and uncle black */
+ parent->color = COLOR_BLACK;
+ uncle->color = COLOR_BLACK;
+
+ /* Color Grandparent as Black */
+ grandparent->color = COLOR_RED;
+ pnode = grandparent;
+ /* Continue iteration, processing grandparent */
+ } else {
+ /* Case 2 - node's parent is red, but uncle is black */
+ if (!uncle_is_left && parent->right == pnode) {
+ pnode = pnode->parent;
+ __helper_rotate_left(tree, pnode);
+ } else if (uncle_is_left && parent->left == pnode) {
+ pnode = pnode->parent;
+ __helper_rotate_right(tree, pnode);
+ }
+
+ /* Case 3 - Recolor and rotate*/
+ parent = pnode->parent;
+ parent->color = COLOR_BLACK;
+
+ grandparent = __helper_get_grandparent(pnode);
+ grandparent->color = COLOR_RED;
+ if (!uncle_is_left) {
+ __helper_rotate_right(tree, grandparent);
+ } else {
+ __helper_rotate_left(tree, grandparent);
+ }
+ }
+ }
+
+ /* Make sure the tree root is black (Case 1: Continued) */
+ struct rb_tree_node *tree_root = tree->root;
+ tree_root->color = COLOR_BLACK;
+ }
+}
+
+rb_result_t rb_tree_insert(struct rb_tree *tree,
+ const void *key,
+ struct rb_tree_node *node)
+{
+ rb_result_t ret = RB_OK;
+
+ int rightmost = 1;
+ struct rb_tree_node *nd = NULL;
+
+ RB_ASSERT_ARG(tree != NULL);
+ RB_ASSERT_ARG(node != NULL);
+
+ node->left = NULL;
+ node->right = NULL;
+ node->parent = NULL;
+ node->key = key;
+
+ /* Case 1: Simplest case -- tree is empty */
+ if (RB_UNLIKELY(tree->root == NULL)) {
+ tree->root = node;
+ tree->rightmost = node;
+ node->color = COLOR_BLACK;
+ goto done;
+ }
+
+ /* Otherwise, insert the node as you would typically in a BST */
+ nd = tree->root;
+ node->color = COLOR_RED;
+
+ rightmost = 1;
+
+ /* Insert a node into the tree as you normally would */
+ while (nd != NULL) {
+ int compare = tree->compare(tree->state, node->key, nd->key);
+
+ if (compare == 0) {
+ ret = RB_DUPLICATE;
+ goto done;
+ }
+
+ if (compare < 0) {
+ rightmost = 0;
+ if (nd->left == NULL) {
+ nd->left = node;
+ break;
+ } else {
+ nd = nd->left;
+ }
+ } else {
+ if (nd->right == NULL) {
+ nd->right = node;
+ break;
+ } else {
+ nd = nd->right;
+ }
+ }
+ }
+
+ node->parent = nd;
+
+ if (1 == rightmost) {
+ tree->rightmost = node;
+ }
+
+ /* Rebalance the tree about the node we just added */
+ __helper_rb_tree_insert_rebalance(tree, node);
+
+done:
+ return ret;
+}
+
+rb_result_t rb_tree_find_or_insert(struct rb_tree *tree,
+ void *key,
+ struct rb_tree_node *new_candidate,
+ struct rb_tree_node **value)
+{
+ rb_result_t ret = RB_OK;
+
+ RB_ASSERT_ARG(tree != NULL);
+ RB_ASSERT_ARG(value != NULL);
+ RB_ASSERT_ARG(new_candidate != NULL);
+
+ *value = NULL;
+ new_candidate->key = key;
+
+ struct rb_tree_node *node = tree->root;
+
+ /* Case 1: Tree is empty, so we just insert the node */
+ if (RB_UNLIKELY(tree->root == NULL)) {
+ tree->root = new_candidate;
+ tree->rightmost = new_candidate;
+ new_candidate->color = COLOR_BLACK;
+ node = new_candidate;
+ goto done;
+ }
+
+ struct rb_tree_node *node_prev = NULL;
+ int dir = 0, rightmost = 1;
+ while (node != NULL) {
+ int compare = tree->compare(tree->state, key, node->key);
+
+ if (compare < 0) {
+ node_prev = node;
+ dir = 0;
+ node = node->left;
+ rightmost = 0;
+ } else if (compare == 0) {
+ break; /* We found our node */
+ } else {
+ /* Otherwise, we want the right node, and continue iteration */
+ node_prev = node;
+ dir = 1;
+ node = node->right;
+ }
+ }
+
+ /* Case 2 - we didn't find the node, so insert the candidate */
+ if (node == NULL) {
+ if (dir == 0) {
+ rightmost = 0;
+ node_prev->left = new_candidate;
+ } else {
+ node_prev->right = new_candidate;
+ }
+
+ new_candidate->parent = node_prev;
+
+ node = new_candidate;
+ node->color = COLOR_RED;
+
+ if (1 == rightmost) {
+ tree->rightmost = new_candidate;
+ }
+
+ /* Rebalance the tree, preserving rb properties */
+ __helper_rb_tree_insert_rebalance(tree, node);
+ }
+
+done:
+ /* Return the node we found */
+ *value = node;
+
+ return ret;
+}
+
+/**
+ * Find the minimum of the subtree starting at node
+ */
+static
+struct rb_tree_node *__helper_rb_tree_find_minimum(struct rb_tree_node *node)
+{
+ struct rb_tree_node *x = node;
+
+ while (x->left != NULL) {
+ x = x->left;
+ }
+
+ return x;
+}
+
+static
+struct rb_tree_node *__helper_rb_tree_find_maximum(struct rb_tree_node *node)
+{
+ struct rb_tree_node *x = node;
+
+ while (x->right != NULL) {
+ x = x->right;
+ }
+
+ return x;
+}
+
+static
+struct rb_tree_node *__helper_rb_tree_find_successor(struct rb_tree_node *node)
+{
+ struct rb_tree_node *x = node;
+
+ if (x->right != NULL) {
+ return __helper_rb_tree_find_minimum(x->right);
+ }
+
+ struct rb_tree_node *y = x->parent;
+
+ while (y != NULL && x == y->right) {
+ x = y;
+ y = y->parent;
+ }
+
+ return y;
+}
+
+static
+struct rb_tree_node *__helper_rb_tree_find_predecessor(struct rb_tree_node *node)
+{
+ struct rb_tree_node *x = node;
+
+ if (x->left != NULL) {
+ return __helper_rb_tree_find_maximum(x->left);
+ }
+
+ struct rb_tree_node *y = x->parent;
+
+ while (y != NULL && x == y->left) {
+ x = y;
+ y = y->parent;
+ }
+
+ return y;
+}
+
+
+/* Replace x with y, inserting y where x previously was */
+static
+void __helper_rb_tree_swap_node(struct rb_tree *tree,
+ struct rb_tree_node *x,
+ struct rb_tree_node *y)
+{
+ struct rb_tree_node *left = x->left;
+ struct rb_tree_node *right = x->right;
+ struct rb_tree_node *parent = x->parent;
+
+ y->parent = parent;
+
+ if (parent != NULL) {
+ if (parent->left == x) {
+ parent->left = y;
+ } else {
+ parent->right = y;
+ }
+ } else {
+ if (tree->root == x) {
+ tree->root = y;
+ }
+ }
+
+ y->right = right;
+ if (right != NULL) {
+ right->parent = y;
+ }
+ x->right = NULL;
+
+ y->left = left;
+ if (left != NULL) {
+ left->parent = y;
+ }
+ x->left = NULL;
+
+ y->color = x->color;
+ x->parent = NULL;
+}
+
+static
+void __helper_rb_tree_delete_rebalance(struct rb_tree *tree,
+ struct rb_tree_node *node,
+ struct rb_tree_node *parent,
+ int node_is_left)
+{
+ struct rb_tree_node *x = node;
+ struct rb_tree_node *xp = parent;
+ int is_left = node_is_left;
+
+ while (x != tree->root && (x == NULL || x->color == COLOR_BLACK)) {
+ struct rb_tree_node *w = is_left ? xp->right : xp->left; /* Sibling */
+
+ if (w != NULL && w->color == COLOR_RED) {
+ /* Case 1: */
+ w->color = COLOR_BLACK;
+ xp->color = COLOR_RED;
+ if (is_left) {
+ __helper_rotate_left(tree, xp);
+ } else {
+ __helper_rotate_right(tree, xp);
+ }
+ w = is_left ? xp->right : xp->left;
+ }
+
+ struct rb_tree_node *wleft = w != NULL ? w->left : NULL;
+ struct rb_tree_node *wright = w != NULL ? w->right : NULL;
+ if ( (wleft == NULL || wleft->color == COLOR_BLACK) &&
+ (wright == NULL || wright->color == COLOR_BLACK) )
+ {
+ /* Case 2: */
+ if (w != NULL) {
+ w->color = COLOR_RED;
+ }
+ x = xp;
+ xp = x->parent;
+ is_left = xp && (x == xp->left);
+ } else {
+ if (is_left && (wright == NULL || wright->color == COLOR_BLACK)) {
+ /* Case 3a: */
+ w->color = COLOR_RED;
+ if (wleft) {
+ wleft->color = COLOR_BLACK;
+ }
+ __helper_rotate_right(tree, w);
+ w = xp->right;
+ } else if (!is_left && (wleft == NULL || wleft->color == COLOR_BLACK)) {
+ /* Case 3b: */
+ w->color = COLOR_RED;
+ if (wright) {
+ wright->color = COLOR_BLACK;
+ }
+ __helper_rotate_left(tree, w);
+ w = xp->left;
+ }
+
+ /* Case 4: */
+ wleft = w->left;
+ wright = w->right;
+
+ w->color = xp->color;
+ xp->color = COLOR_BLACK;
+
+ if (is_left && wright != NULL) {
+ wright->color = COLOR_BLACK;
+ __helper_rotate_left(tree, xp);
+ } else if (!is_left && wleft != NULL) {
+ wleft->color = COLOR_BLACK;
+ __helper_rotate_right(tree, xp);
+ }
+ x = tree->root;
+ }
+ }
+
+ if (x != NULL) {
+ x->color = COLOR_BLACK;
+ }
+}
+
+rb_result_t rb_tree_remove(struct rb_tree *tree,
+ struct rb_tree_node *node)
+{
+ rb_result_t ret = RB_OK;
+
+ RB_ASSERT_ARG(tree != NULL);
+ RB_ASSERT_ARG(node != NULL);
+
+ struct rb_tree_node *y;
+
+
+ if (node->left == NULL || node->right == NULL) {
+ y = node;
+ if (node == tree->rightmost) {
+ /* The new rightmost item is our successor */
+ tree->rightmost = __helper_rb_tree_find_predecessor(node);
+ }
+ } else {
+ y = __helper_rb_tree_find_successor(node);
+ }
+
+ struct rb_tree_node *x, *xp;
+
+ if (y->left != NULL) {
+ x = y->left;
+ } else {
+ x = y->right;
+ }
+
+ if (x != NULL) {
+ x->parent = y->parent;
+ xp = x->parent;
+ } else {
+ xp = y->parent;
+ }
+
+ int is_left = 0;
+ if (y->parent == NULL) {
+ tree->root = x;
+ xp = NULL;
+ } else {
+ struct rb_tree_node *yp = y->parent;
+ if (y == yp->left) {
+ yp->left = x;
+ is_left = 1;
+ } else {
+ yp->right = x;
+ is_left = 0;
+ }
+ }
+
+ int y_color = y->color;
+
+ /* Swap in the node */
+ if (y != node) {
+ __helper_rb_tree_swap_node(tree, node, y);
+ if (xp == node) {
+ xp = y;
+ }
+ }
+
+ if (y_color == COLOR_BLACK) {
+ __helper_rb_tree_delete_rebalance(tree, x, xp, is_left);
+ }
+
+ node->parent = NULL;
+ node->left = NULL;
+ node->right = NULL;
+
+ return ret;
+}
+
+/**
+ * \mainpage An Intrusive Red-Black Tree
+ *
+ * The goal of this implementation is to be both easy to use, but also
+ * sufficiently powerful enough to perform all the operations that one might
+ * typically want to do with a red-black tree.
+ *
+ * To make a structure usable with an rb_tree, you must embed the structure
+ * struct rb_tree_node.
+ * \code
+ struct my_sample_struct {
+ const char *name;
+ int data;
+ struct rb_tree_node rnode;
+ };
+ * \endcode
+ * \note `rb_tree_node` need not be initialized -- it is initialized during the
+ * insertion operation.
+ *
+ * Next, you must declare a comparison function that, given a pointer to two
+ * keys, returns a value less than 0 if the left-hand side is less than the
+ * right-hand side, 0 if the left-hand side is equal to the right-hand side,
+ * or greater than 0 if the left-hand side is greater than the left-hand side.
+ *
+ * A simple example for a string might use the `strcmp(3)` function directly,
+ * as such:
+ *
+ * \code
+ int my_sample_struct_compare_keys(void *lhs, void *rhs)
+ {
+ return strcmp((const char *)lhs, (const char *)rhs);
+ }
+ * \endcode
+ * \note the function you create for your comparison function must conform to
+ * rb_cmp_func_t, or the compiler will generate a warning and, if you're
+ * unlucky, you will fail catastrophically at a later date.
+ *
+ * Then, to create a new, empty red-black tree, call rb_tree_new, as so:
+ * \code
+ struct rb_tree my_rb_tree;
+ if (rb_tree_new(&my_rb_tree, my_sample_struct_compare_keys) != RB_OK) {
+ exit(EXIT_FAILURE);
+ }
+ * \endcode
+ *
+ * Items can be added to the red-black tree using the function `rb_tree_insert`:
+ * \code
+ struct my_sample_struct node = { .name = "test1", .date = 42 };
+ if (rb_tree_insert(&my_rb_tree, node.name, &(node.rnode)) != RB_OK) {
+ printf("Failed to insert a node into the RB tree!\n");
+ exit(EXIT_FAILURE);
+ }
+ * \endcode
+ *
+ * \see rb_tree
+ * \see rb_tree_node
+ * \see rb_functions
+ * \see rbtree.h
+ */
+
diff --git a/fluent-bit/lib/monkey/deps/rbtree/rbtree.h b/fluent-bit/lib/monkey/deps/rbtree/rbtree.h
new file mode 100644
index 000000000..e85b274c6
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/rbtree/rbtree.h
@@ -0,0 +1,459 @@
+#ifndef __INCLUDED_RBTREE_H__
+#define __INCLUDED_RBTREE_H__
+
+/** \file rbtree.h
+ * Declaration of associated structures and functions for a simple, intrusive
+ * red-black tree implementation.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <stdlib.h>
+#include <assert.h>
+
+/** \defgroup rb_tree_compiler_prims Compiler Abstractions
+ * Primitives used to abstract compiler-specific syntax for common details used in
+ * providing hints to the compiler for optimization or linker details.
+ * @{
+ */
+
+/**
+ * Macro to check if a given assertion about an argument is true
+ */
+#define RB_ASSERT_ARG(x) \
+ do { \
+ if (RB_UNLIKELY(!(x))) { \
+ assert(#x && 0); \
+ return RB_BAD_ARG; \
+ } \
+ } while (0)
+
+/**
+ * The tagged branch is unlikely to be taken
+ */
+#ifdef _WIN32
+#define RB_UNLIKELY(x) x
+#else
+#define RB_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#endif
+/**@}*/
+
+/** \defgroup rb_tree_state State Structures
+ * Structures that are used to represent state of a red-black tree, including the
+ * state of the tree itself, comparison functions used to determine how the tree
+ * is to be traversed, and representations of red-black tree nodes themselves.
+ * @{
+ */
+
+/**
+ * Structure that represents a node in a red-black tree. Embed this in your own
+ * structure in order to add your structure to the given red-black tree.
+ * Users of the rb_tree_node would embed it something like
+ * \code{.c}
+ struct my_sample_struct {
+ char *name;
+ int data;
+ struct rb_tree_node rnode;
+ };
+ * \endcode
+ *
+ * \note No user of `struct rb_tree_node` should ever modify or inspect any
+ * members of the structure.
+ */
+struct rb_tree_node {
+ /**
+ * The left child (`NULL` if empty)
+ */
+ struct rb_tree_node *left;
+
+ /**
+ * The right child (`NULL` if empty)
+ */
+ struct rb_tree_node *right;
+
+ /**
+ * The parent of this node (`NULL` if at root)
+ */
+ struct rb_tree_node *parent;
+
+ /**
+ * The key for this node
+ */
+ const void *key;
+
+ /**
+ * The color of the node
+ */
+ int color;
+};
+
+/**
+ * Pointer to a function to compare two keys, and returns as follows:
+ * - (0, +inf] if lhs > rhs
+ * - 0 if lhs == rhs
+ * - [-inf, 0) if lhs < rhs
+ */
+typedef int (*rb_cmp_func_t)(const void *lhs, const void *rhs);
+
+/**
+ * Pointer to a comparison function that allows passing along state.
+ * Return values are interpreted as follows:
+ * (0, +inf] if lhs > rhs
+ * 0 if lhs == rhs
+ * [-inf, 0) if lhs < rhs
+ */
+typedef int (*rb_cmp_func_ex_t)(void *state, const void *lhs, const void *rhs);
+
+/**
+ * Structure representing an RB tree's associated state. Contains all
+ * the information needed to manage the lifecycle of a RB tree.
+ * \note Typically users should not directly manipulate the structure,
+ * but rather use the provided accessor functions.
+ */
+struct rb_tree {
+ /**
+ * The root of the tree
+ */
+ struct rb_tree_node *root;
+
+ /**
+ * Predicate used for traversing the tree
+ */
+ rb_cmp_func_ex_t compare;
+
+ /**
+ * The right-most node of the rb-tree
+ */
+ struct rb_tree_node *rightmost;
+
+ /**
+ * Private state that can be used by the rb-tree owner
+ */
+ void *state;
+};
+
+/**@} rb_tree_state */
+
+/** \defgroup rb_result Function Results and Error Handling
+ * @{
+ */
+/** \typedef rb_result_t
+ * Value of a returned result code from a red-black tree function.
+ */
+typedef int rb_result_t;
+
+/** \defgroup rb_result_code Result Codes
+ * Error codes that can be returned from any function that returns an rb_result_t.
+ * @{
+ */
+
+/**
+ * Function was successful
+ */
+#define RB_OK 0x0
+/**
+ * Element was not found
+ */
+#define RB_NOT_FOUND 0x1
+/**
+ * Bad argument provided to function (typically unexpected NULL)
+ */
+#define RB_BAD_ARG 0x2
+/**
+ * Node is a duplicate of an existing node
+ */
+#define RB_DUPLICATE 0x3
+
+/**@} rb_result_code */
+/**@} rb_result */
+
+/** \brief Helper to get a pointer to a containing structure.
+ * Given a pointer to an rb_tree_node, a target type and a member name,
+ * return a pointer to the structure containing the `struct rb_tree_node`.
+ * \code{.c}
+ struct sample {
+ const char *name;
+ struct rb_tree_node node;
+ };
+
+ void test(void)
+ {
+ struct sample samp = { .name = "Test 123" };
+ struct rb_tree_node *samp_node = &(samp.node);
+ struct sample *samp2 = RB_CONTAINER_OF(samp_node, struct sample, node);
+
+ assert(&samp == samp2);
+ }
+ * \endcode
+ * \param x The pointer to the node
+ * \param type The type of the containing structure
+ * \param memb The name of the `struct rb_tree_node` in the containing structure
+ * \return Pointer to the containing structure of the specified type
+ */
+#define RB_CONTAINER_OF(x, type, memb) \
+ ({ \
+ const __typeof__( ((type *)0)->memb ) *__member = (x); \
+ (type *)( (char *)__member - __offsetof__(type, memb) ); \
+ })
+
+
+/** \defgroup rb_functions Functions for Manipulating Red-Black Trees
+ * All functions associated with manipulating Red-Black trees using `struct rb_tree`,
+ * inluding lifecycle functions and member manipulation and state checking functions.
+ * @{
+ */
+
+/**
+ * \brief Construct a new, empty red-black tree, with extended state
+ * Given a region of memory at least the size of a struct rb_tree to
+ * store the red-black tree metadata, update it to contain an initialized, empty
+ * red-black tree, with given private state.
+ * \param tree Pointer to the new tree.
+ * \param compare Function used to traverse the tree.
+ * \param state The private state to be passed to the compare function
+ * \return RB_OK on success, an error code otherwise
+ */
+rb_result_t rb_tree_new_ex(struct rb_tree *tree, rb_cmp_func_ex_t compare, void *state);
+
+/**
+ * \brief Construct a new, empty red-black tree.
+ * Given a region of memory at least the size of a struct rb_tree to
+ * store the red-black tree metadata, update it to contain an initialized, empty
+ * red-black tree.
+ * \param tree Pointer to the new tree.
+ * \param compare Function used to traverse the tree.
+ * \return RB_OK on success, an error code otherwise
+ */
+rb_result_t rb_tree_new(struct rb_tree *tree,
+ rb_cmp_func_t compare);
+
+/**
+ * \brief Destroy a Red-Black tree.
+ * Clean up the state structure, clearing out the state of the tree
+ * so that it no longer can be used.
+ * \note Assumes that external callers will deallocate all nodes through
+ * some application-specific mechanism.
+ * \param tree The reference to the pointer to the tree itself.
+ * \return RB_OK on success, an error code otherwise
+ */
+rb_result_t rb_tree_destroy(struct rb_tree *tree);
+
+/**
+ * \brief Check if an red-black tree is empty (has no nodes).
+ * If no nodes are present, returns a non-zero value in `is_empty` -- returns
+ * 0 if there are nodes present.
+ * \param tree The tree to check
+ * \param is_empty nonzero on true, 0 otherwise
+ * \return RB_OK on success, an error code otherwise
+ */
+rb_result_t rb_tree_empty(struct rb_tree *tree, int *is_empty);
+
+/**
+ * \brief Find a node in the Red-Black tree given the specified key.
+ * Given a key, search the RB-tree iteratively until the specified key is found.
+ * This traversal is in O(log n) time, per the properties of a binary search tree.
+ * \param tree The RB-tree to search
+ * \param key The key to search for
+ * \param value a reference to a pointer to receive the pointer to the rb_tree_node if key is found
+ * \return RB_OK on success, an error code otherwise
+ */
+rb_result_t rb_tree_find(struct rb_tree *tree,
+ const void *key,
+ struct rb_tree_node **value);
+
+/**
+ * \brief Insert a node into the tree.
+ * Given a node and key, insert the node into the red-black tree and rebalance
+ * the tree if appropriate. Insertion is O(log n) time, with two tree traversals
+ * possible -- one for insertion (guaranteed) and one for rebalancing.
+ * \param tree the RB tree to insert the node into
+ * \param key The key for the node (must live as long as the node itself is in the tree)
+ * \param node the node to be inserted into the tree
+ * \return RB_OK on sucess, an error code otherwise
+ */
+rb_result_t rb_tree_insert(struct rb_tree *tree,
+ const void *key,
+ struct rb_tree_node *node);
+
+/**
+ * \brief Remove the specified node from the Red-Black tree.
+ * Given a pointer to the node, splice the node out of the tree, then, if applicable
+ * rebalance the tree so the Red-Black properties are maintained.
+ * \param tree The tree we want to remove the node from
+ * \param node The the node we want to remove
+ * \return RB_OK on success, an error code otherwise
+ */
+rb_result_t rb_tree_remove(struct rb_tree *tree,
+ struct rb_tree_node *node);
+
+/**
+ * \brief Find a node. If not found, insert the candidate.
+ * Find a node with the given key. If the node is found, return it by
+ * reference, without modifying the tree. If the node is not found,
+ * insert the provided candidate node.
+ * \note This function always will return in *value the node inserted
+ * or the existing node. If you want to check if the candidate
+ * node was inserted, check if `*value == new_candidate`
+ *
+ * \param tree The tree in question
+ * \param key The key to search for
+ * \param new_candidate The candidate node to insert
+ * \param value The value at the given location
+ * \return RB_OK on success, an error code otherwise
+ */
+rb_result_t rb_tree_find_or_insert(struct rb_tree *tree,
+ void *key,
+ struct rb_tree_node *new_candidate,
+ struct rb_tree_node **value);
+
+/**
+ * \brief Find a node. If not found, insert the candidate.
+ * Find a node with the given key. If the node is found, return it by
+ * reference, without modifying the tree. If the node is not found,
+ * insert the provided candidate node.
+ * \note This function always will return in *value the node inserted
+ * or the existing node. If you want to check if the candidate
+ * node was inserted, check if `*value == new_candidate`
+ *
+ * \param tree The tree in question
+ * \param key The key to search for
+ * \param new_candidate The candidate node to insert
+ * \param value The value at the given location
+ *
+ * \return RB_OK on success, an error code otherwise
+ */
+rb_result_t rb_tree_find_or_insert(struct rb_tree *tree,
+ void *key,
+ struct rb_tree_node *new_candidate,
+ struct rb_tree_node **value);
+/**
+ * \brief Get the rightmost (greatest relative to predicate) node.
+ * Return the rightmost (i.e. greatest relative to predicate) node of the Red-Black tree.
+ */
+static inline
+rb_result_t rb_tree_get_rightmost(struct rb_tree *tree,
+ struct rb_tree_node **rightmost)
+{
+ if ( (NULL == tree) || (NULL == rightmost) ) {
+ return RB_BAD_ARG;
+ }
+
+ *rightmost = tree->rightmost;
+
+ return RB_OK;
+}
+
+
+/**
+ * Find the minimum of the given tree/subtree rooted at the given node.
+ */
+static inline
+rb_result_t __rb_tree_find_minimum(struct rb_tree_node *root,
+ struct rb_tree_node **min)
+{
+ struct rb_tree_node *x = root;
+
+ while (x->left != NULL) {
+ x = x->left;
+ }
+
+ *min = x;
+
+ return RB_OK;
+}
+
+/**
+ * Find the maximum of the given tree/subtree rooted at the given node.
+ */
+static inline
+rb_result_t __rb_tree_find_maximum(struct rb_tree_node *root,
+ struct rb_tree_node **max)
+{
+ struct rb_tree_node *x = root;
+
+ while (x->right != NULL) {
+ x = x->right;
+ }
+
+ *max = x;
+
+ return RB_OK;
+}
+
+/**
+ * Find the successor (greater than, relative to predicate) node of the given node.
+ */
+static inline
+rb_result_t rb_tree_find_successor(struct rb_tree *tree,
+ struct rb_tree_node *node,
+ struct rb_tree_node **successor)
+{
+ rb_result_t ret = RB_OK;
+
+ RB_ASSERT_ARG(tree != NULL);
+ RB_ASSERT_ARG(node != NULL);
+ RB_ASSERT_ARG(successor != NULL);
+
+ struct rb_tree_node *x = node;
+
+ if (x->right != NULL) {
+ __rb_tree_find_minimum(x->right, successor);
+ goto done;
+ }
+
+ struct rb_tree_node *y = x->parent;
+
+ while (y != NULL && (x == y->right)) {
+ x = y;
+ y = y->parent;
+ }
+
+ *successor = y;
+
+done:
+ return ret;
+}
+
+/**
+ * Find the predecessor (less than, relative to predicate) node of the given node.
+ */
+static inline
+rb_result_t rb_tree_find_predecessor(struct rb_tree *tree,
+ struct rb_tree_node *node,
+ struct rb_tree_node **pred)
+{
+ rb_result_t ret = RB_OK;
+ struct rb_tree_node *x = node;
+
+ RB_ASSERT_ARG(tree != NULL);
+ RB_ASSERT_ARG(node != NULL);
+ RB_ASSERT_ARG(pred != NULL);
+
+ if (x->left != NULL) {
+ __rb_tree_find_maximum(x->left, pred);
+ goto done;
+ }
+
+ struct rb_tree_node *y = x->parent;
+
+ while (y != NULL && (x == y->left)) {
+ x = y;
+ y = y->parent;
+ }
+
+ *pred = y;
+
+done:
+ return ret;
+}
+
+/**@} rb_functions */
+
+#ifdef __cplusplus
+} // extern "C"
+#endif /* __cplusplus */
+
+#endif /* __INCLUDED_RBTREE_H__ */
+
diff --git a/fluent-bit/lib/monkey/deps/regex/CMakeLists.txt b/fluent-bit/lib/monkey/deps/regex/CMakeLists.txt
new file mode 100644
index 000000000..ce1e9a3e6
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/regex/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(src
+ re.c
+ )
+
+add_library(regex STATIC ${src})
diff --git a/fluent-bit/lib/monkey/deps/regex/re.c b/fluent-bit/lib/monkey/deps/regex/re.c
new file mode 100644
index 000000000..a93177f0a
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/regex/re.c
@@ -0,0 +1,515 @@
+/*
+ *
+ * Mini regex-module inspired by Rob Pike's regex code described in:
+ *
+ * http://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html
+ *
+ *
+ *
+ * Supports:
+ * ---------
+ * '.' Dot, matches any character
+ * '^' Start anchor, matches beginning of string
+ * '$' End anchor, matches end of string
+ * '*' Asterisk, match zero or more (greedy)
+ * '+' Plus, match one or more (greedy)
+ * '?' Question, match zero or one (non-greedy)
+ * '[abc]' Character class, match if one of {'a', 'b', 'c'}
+ * '[^abc]' Inverted class, match if NOT one of {'a', 'b', 'c'} -- NOTE: feature is currently broken!
+ * '[a-zA-Z]' Character ranges, the character set of the ranges { a-z | A-Z }
+ * '\s' Whitespace, \t \f \r \n \v and spaces
+ * '\S' Non-whitespace
+ * '\w' Alphanumeric, [a-zA-Z0-9_]
+ * '\W' Non-alphanumeric
+ * '\d' Digits, [0-9]
+ * '\D' Non-digits
+ *
+ *
+ */
+
+
+
+#include "re.h"
+#include <stdio.h>
+#include <ctype.h>
+
+/* Private function declarations: */
+static int matchpattern(regex_t* pattern, const char* text, int* matchlength);
+static int matchcharclass(char c, const char* str);
+static int matchstar(regex_t p, regex_t* pattern, const char* text, int* matchlength);
+static int matchplus(regex_t p, regex_t* pattern, const char* text, int* matchlength);
+static int matchone(regex_t p, char c);
+static int matchdigit(char c);
+static int matchalpha(char c);
+static int matchwhitespace(char c);
+static int matchmetachar(char c, const char* str);
+static int matchrange(char c, const char* str);
+static int matchdot(char c);
+static int ismetachar(char c);
+
+
+
+/* Public functions: */
+int re_match(const char* pattern, const char* text, int* matchlength)
+{
+ return re_matchp(re_compile(pattern), text, matchlength);
+}
+
+int re_matchp(re_t pattern, const char* text, int* matchlength)
+{
+ int matchlength_;
+
+ if(NULL == matchlength)
+ {
+ matchlength = &matchlength_;
+ }
+
+ *matchlength = 0;
+ if (pattern != 0)
+ {
+ if (pattern[0].type == BEGIN)
+ {
+ return ((matchpattern(&pattern[1], text, matchlength)) ? 0 : -1);
+ }
+ else
+ {
+ int idx = -1;
+
+ do
+ {
+ idx += 1;
+
+ if (matchpattern(pattern, text, matchlength))
+ {
+ if (text[0] == '\0')
+ return -1;
+
+ return idx;
+ }
+ }
+ while (*text++ != '\0');
+ }
+ }
+ return -1;
+}
+
+re_t re_compile(const char* pattern)
+{
+ /* The sizes of the two static arrays below substantiates the static RAM usage of this module.
+ MAX_REGEXP_OBJECTS is the max number of symbols in the expression.
+ MAX_CHAR_CLASS_LEN determines the size of buffer for chars in all char-classes in the expression. */
+ static regex_t re_compiled[MAX_REGEXP_OBJECTS];
+ static unsigned char ccl_buf[MAX_CHAR_CLASS_LEN];
+ int ccl_bufidx = 1;
+
+ char c; /* current char in pattern */
+ int i = 0; /* index into pattern */
+ int j = 0; /* index into re_compiled */
+
+ while (pattern[i] != '\0' && (j+1 < MAX_REGEXP_OBJECTS))
+ {
+ c = pattern[i];
+
+ switch (c)
+ {
+ /* Meta-characters: */
+ case '^': { re_compiled[j].type = BEGIN; } break;
+ case '$': { re_compiled[j].type = END; } break;
+ case '.': { re_compiled[j].type = DOT; } break;
+ case '*': { re_compiled[j].type = STAR; } break;
+ case '+': { re_compiled[j].type = PLUS; } break;
+ case '?': { re_compiled[j].type = QUESTIONMARK; } break;
+/* case '|': { re_compiled[j].type = BRANCH; } break; <-- not working properly */
+
+ /* Escaped character-classes (\s \w ...): */
+ case '\\':
+ {
+ if (pattern[i+1] != '\0')
+ {
+ /* Skip the escape-char '\\' */
+ i += 1;
+ /* ... and check the next */
+ switch (pattern[i])
+ {
+ /* Meta-character: */
+ case 'd': { re_compiled[j].type = DIGIT; } break;
+ case 'D': { re_compiled[j].type = NOT_DIGIT; } break;
+ case 'w': { re_compiled[j].type = ALPHA; } break;
+ case 'W': { re_compiled[j].type = NOT_ALPHA; } break;
+ case 's': { re_compiled[j].type = WHITESPACE; } break;
+ case 'S': { re_compiled[j].type = NOT_WHITESPACE; } break;
+
+ /* Escaped character, e.g. '.' or '$' */
+ default:
+ {
+ re_compiled[j].type = RE_CHAR;
+ re_compiled[j].u.ch = pattern[i];
+ } break;
+ }
+ }
+ /* '\\' as last char in pattern -> invalid regular expression. */
+/*
+ else
+ {
+ re_compiled[j].type = RE_CHAR;
+ re_compiled[j].ch = pattern[i];
+ }
+*/
+ } break;
+
+ /* Character class: */
+ case '[':
+ {
+ /* Remember where the char-buffer starts. */
+ int buf_begin = ccl_bufidx;
+
+ /* Look-ahead to determine if negated */
+ if (pattern[i+1] == '^')
+ {
+ re_compiled[j].type = INV_CHAR_CLASS;
+ i += 1; /* Increment i to avoid including '^' in the char-buffer */
+ if (pattern[i+1] == 0) /* incomplete pattern, missing non-zero char after '^' */
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ re_compiled[j].type = CHAR_CLASS;
+ }
+
+ /* Copy characters inside [..] to buffer */
+ while ( (pattern[++i] != ']')
+ && (pattern[i] != '\0')) /* Missing ] */
+ {
+ if (pattern[i] == '\\')
+ {
+ if (ccl_bufidx >= MAX_CHAR_CLASS_LEN - 1)
+ {
+ //fputs("exceeded internal buffer!\n", stderr);
+ return 0;
+ }
+ if (pattern[i+1] == 0) /* incomplete pattern, missing non-zero char after '\\' */
+ {
+ return 0;
+ }
+ ccl_buf[ccl_bufidx++] = pattern[i++];
+ }
+ else if (ccl_bufidx >= MAX_CHAR_CLASS_LEN)
+ {
+ //fputs("exceeded internal buffer!\n", stderr);
+ return 0;
+ }
+ ccl_buf[ccl_bufidx++] = pattern[i];
+ }
+ if (ccl_bufidx >= MAX_CHAR_CLASS_LEN)
+ {
+ /* Catches cases such as [00000000000000000000000000000000000000][ */
+ //fputs("exceeded internal buffer!\n", stderr);
+ return 0;
+ }
+ /* Null-terminate string end */
+ ccl_buf[ccl_bufidx++] = 0;
+ re_compiled[j].u.ccl = &ccl_buf[buf_begin];
+ } break;
+
+ /* Other characters: */
+ default:
+ {
+ re_compiled[j].type = RE_CHAR;
+ re_compiled[j].u.ch = c;
+ } break;
+ }
+ /* no buffer-out-of-bounds access on invalid patterns - see https://github.com/kokke/tiny-regex-c/commit/1a279e04014b70b0695fba559a7c05d55e6ee90b */
+ if (pattern[i] == 0)
+ {
+ return 0;
+ }
+
+ i += 1;
+ j += 1;
+ }
+ /* 'UNUSED' is a sentinel used to indicate end-of-pattern */
+ re_compiled[j].type = UNUSED;
+
+ return (re_t) re_compiled;
+}
+
+void re_print(regex_t* pattern)
+{
+ const char* types[] = { "UNUSED", "DOT", "BEGIN", "END", "QUESTIONMARK", "STAR", "PLUS", "RE_CHAR", "CHAR_CLASS", "INV_CHAR_CLASS", "DIGIT", "NOT_DIGIT", "ALPHA", "NOT_ALPHA", "WHITESPACE", "NOT_WHITESPACE", "BRANCH" };
+
+ int i;
+ int j;
+ char c;
+ for (i = 0; i < MAX_REGEXP_OBJECTS; ++i)
+ {
+ if (pattern[i].type == UNUSED)
+ {
+ break;
+ }
+
+ printf("type: %s", types[pattern[i].type]);
+ if (pattern[i].type == CHAR_CLASS || pattern[i].type == INV_CHAR_CLASS)
+ {
+ printf(" [");
+ for (j = 0; j < MAX_CHAR_CLASS_LEN; ++j)
+ {
+ c = pattern[i].u.ccl[j];
+ if ((c == '\0') || (c == ']'))
+ {
+ break;
+ }
+ printf("%c", c);
+ }
+ printf("]");
+ }
+ else if (pattern[i].type == RE_CHAR)
+ {
+ printf(" '%c'", pattern[i].u.ch);
+ }
+ printf("\n");
+ }
+}
+
+
+
+/* Private functions: */
+static int matchdigit(char c)
+{
+ return isdigit(c);
+}
+static int matchalpha(char c)
+{
+ return isalpha(c);
+}
+static int matchwhitespace(char c)
+{
+ return isspace(c);
+}
+static int matchalphanum(char c)
+{
+ return ((c == '_') || matchalpha(c) || matchdigit(c));
+}
+static int matchrange(char c, const char* str)
+{
+ return ( (c != '-')
+ && (str[0] != '\0')
+ && (str[0] != '-')
+ && (str[1] == '-')
+ && (str[2] != '\0')
+ && ( (c >= str[0])
+ && (c <= str[2])));
+}
+static int matchdot(char c)
+{
+#if defined(RE_DOT_MATCHES_NEWLINE) && (RE_DOT_MATCHES_NEWLINE == 1)
+ (void)c;
+ return 1;
+#else
+ return c != '\n' && c != '\r';
+#endif
+}
+static int ismetachar(char c)
+{
+ return ((c == 's') || (c == 'S') || (c == 'w') || (c == 'W') || (c == 'd') || (c == 'D'));
+}
+
+static int matchmetachar(char c, const char* str)
+{
+ switch (str[0])
+ {
+ case 'd': return matchdigit(c);
+ case 'D': return !matchdigit(c);
+ case 'w': return matchalphanum(c);
+ case 'W': return !matchalphanum(c);
+ case 's': return matchwhitespace(c);
+ case 'S': return !matchwhitespace(c);
+ default: return (c == str[0]);
+ }
+}
+
+static int matchcharclass(char c, const char* str)
+{
+ do
+ {
+ if (matchrange(c, str))
+ {
+ return 1;
+ }
+ else if (str[0] == '\\')
+ {
+ /* Escape-char: increment str-ptr and match on next char */
+ str += 1;
+ if (matchmetachar(c, str))
+ {
+ return 1;
+ }
+ else if ((c == str[0]) && !ismetachar(c))
+ {
+ return 1;
+ }
+ }
+ else if (c == str[0])
+ {
+ if (c == '-')
+ {
+ return ((str[-1] == '\0') || (str[1] == '\0'));
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ }
+ while (*str++ != '\0');
+
+ return 0;
+}
+
+static int matchone(regex_t p, char c)
+{
+ switch (p.type)
+ {
+ case DOT: return matchdot(c);
+ case CHAR_CLASS: return matchcharclass(c, (const char*)p.u.ccl);
+ case INV_CHAR_CLASS: return !matchcharclass(c, (const char*)p.u.ccl);
+ case DIGIT: return matchdigit(c);
+ case NOT_DIGIT: return !matchdigit(c);
+ case ALPHA: return matchalphanum(c);
+ case NOT_ALPHA: return !matchalphanum(c);
+ case WHITESPACE: return matchwhitespace(c);
+ case NOT_WHITESPACE: return !matchwhitespace(c);
+ default: return (p.u.ch == c);
+ }
+}
+
+static int matchstar(regex_t p, regex_t* pattern, const char* text, int* matchlength)
+{
+ int prelen = *matchlength;
+ const char* prepoint = text;
+ while ((text[0] != '\0') && matchone(p, *text))
+ {
+ text++;
+ (*matchlength)++;
+ }
+ while (text >= prepoint)
+ {
+ if (matchpattern(pattern, text--, matchlength))
+ return 1;
+ (*matchlength)--;
+ }
+
+ *matchlength = prelen;
+ return 0;
+}
+
+static int matchplus(regex_t p, regex_t* pattern, const char* text, int* matchlength)
+{
+ const char* prepoint = text;
+ while ((text[0] != '\0') && matchone(p, *text))
+ {
+ text++;
+ (*matchlength)++;
+ }
+ while (text > prepoint)
+ {
+ if (matchpattern(pattern, text--, matchlength))
+ return 1;
+ (*matchlength)--;
+ }
+
+ return 0;
+}
+
+static int matchquestion(regex_t p, regex_t* pattern, const char* text, int* matchlength)
+{
+ if (p.type == UNUSED)
+ return 1;
+ if (matchpattern(pattern, text, matchlength))
+ return 1;
+ if (*text && matchone(p, *text++))
+ {
+ if (matchpattern(pattern, text, matchlength))
+ {
+ (*matchlength)++;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+#if 0
+
+/* Recursive matching */
+static int matchpattern(regex_t* pattern, const char* text, int *matchlength)
+{
+ int pre = *matchlength;
+ if ((pattern[0].type == UNUSED) || (pattern[1].type == QUESTIONMARK))
+ {
+ return matchquestion(pattern[1], &pattern[2], text, matchlength);
+ }
+ else if (pattern[1].type == STAR)
+ {
+ return matchstar(pattern[0], &pattern[2], text, matchlength);
+ }
+ else if (pattern[1].type == PLUS)
+ {
+ return matchplus(pattern[0], &pattern[2], text, matchlength);
+ }
+ else if ((pattern[0].type == END) && pattern[1].type == UNUSED)
+ {
+ return text[0] == '\0';
+ }
+ else if ((text[0] != '\0') && matchone(pattern[0], text[0]))
+ {
+ (*matchlength)++;
+ return matchpattern(&pattern[1], text+1);
+ }
+ else
+ {
+ *matchlength = pre;
+ return 0;
+ }
+}
+
+#else
+
+/* Iterative matching */
+static int matchpattern(regex_t* pattern, const char* text, int* matchlength)
+{
+ int pre = *matchlength;
+ do
+ {
+ if ((pattern[0].type == UNUSED) || (pattern[1].type == QUESTIONMARK))
+ {
+ return matchquestion(pattern[0], &pattern[2], text, matchlength);
+ }
+ else if (pattern[1].type == STAR)
+ {
+ return matchstar(pattern[0], &pattern[2], text, matchlength);
+ }
+ else if (pattern[1].type == PLUS)
+ {
+ return matchplus(pattern[0], &pattern[2], text, matchlength);
+ }
+ else if ((pattern[0].type == END) && pattern[1].type == UNUSED)
+ {
+ return (text[0] == '\0');
+ }
+/* Branching is not working properly
+ else if (pattern[1].type == BRANCH)
+ {
+ return (matchpattern(pattern, text) || matchpattern(&pattern[2], text));
+ }
+*/
+ (*matchlength)++;
+ }
+ while ((text[0] != '\0') && matchone(*pattern++, *text++));
+
+ *matchlength = pre;
+ return 0;
+}
+
+#endif
diff --git a/fluent-bit/lib/monkey/deps/regex/re.h b/fluent-bit/lib/monkey/deps/regex/re.h
new file mode 100644
index 000000000..34363e86b
--- /dev/null
+++ b/fluent-bit/lib/monkey/deps/regex/re.h
@@ -0,0 +1,87 @@
+/*
+ *
+ * Mini regex-module inspired by Rob Pike's regex code described in:
+ *
+ * http://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html
+ *
+ *
+ *
+ * Supports:
+ * ---------
+ * '.' Dot, matches any character
+ * '^' Start anchor, matches beginning of string
+ * '$' End anchor, matches end of string
+ * '*' Asterisk, match zero or more (greedy)
+ * '+' Plus, match one or more (greedy)
+ * '?' Question, match zero or one (non-greedy)
+ * '[abc]' Character class, match if one of {'a', 'b', 'c'}
+ * '[^abc]' Inverted class, match if NOT one of {'a', 'b', 'c'} -- NOTE: feature is currently broken!
+ * '[a-zA-Z]' Character ranges, the character set of the ranges { a-z | A-Z }
+ * '\s' Whitespace, \t \f \r \n \v and spaces
+ * '\S' Non-whitespace
+ * '\w' Alphanumeric, [a-zA-Z0-9_]
+ * '\W' Non-alphanumeric
+ * '\d' Digits, [0-9]
+ * '\D' Non-digits
+ *
+ *
+ */
+
+#ifndef _TINY_REGEX_C
+#define _TINY_REGEX_C
+
+
+#ifndef RE_DOT_MATCHES_NEWLINE
+/* Define to 0 if you DON'T want '.' to match '\r' + '\n' */
+#define RE_DOT_MATCHES_NEWLINE 1
+#endif
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* Definitions: */
+
+/* This was incremented because everything counts as a symbol, even literals and because
+ * of that the longer regular expressions matched wrong input text because they were only
+ * partially compiled
+ */
+#define MAX_REGEXP_OBJECTS 512 /* Max number of regex symbols in expression. */
+#define MAX_CHAR_CLASS_LEN 40 /* Max length of character-class buffer in. */
+
+
+enum { UNUSED, DOT, BEGIN, END, QUESTIONMARK, STAR, PLUS, RE_CHAR, CHAR_CLASS, INV_CHAR_CLASS, DIGIT, NOT_DIGIT, ALPHA, NOT_ALPHA, WHITESPACE, NOT_WHITESPACE, /* BRANCH */ };
+
+typedef struct regex_t
+{
+ unsigned char type; /* CHAR, STAR, etc. */
+ union
+ {
+ unsigned char ch; /* the character itself */
+ unsigned char* ccl; /* OR a pointer to characters in class */
+ } u;
+} regex_t;
+
+/* Typedef'd pointer to get abstract datatype. */
+typedef struct regex_t* re_t;
+
+#define REGEXP_SIZE (MAX_REGEXP_OBJECTS * sizeof(struct regex_t))
+
+/* Compile regex string pattern to a regex_t-array. */
+re_t re_compile(const char* pattern);
+
+
+/* Find matches of the compiled pattern inside text. */
+int re_matchp(re_t pattern, const char* text, int* matchlength);
+
+
+/* Find matches of the txt pattern inside text (will compile automatically first). */
+int re_match(const char* pattern, const char* text, int* matchlength);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ifndef _TINY_REGEX_C */
diff --git a/fluent-bit/lib/monkey/examples/README b/fluent-bit/lib/monkey/examples/README
new file mode 100644
index 000000000..bbb5b22c4
--- /dev/null
+++ b/fluent-bit/lib/monkey/examples/README
@@ -0,0 +1 @@
+These sample files show the usage of the Monkey library. They're under the GPLv2.
diff --git a/fluent-bit/lib/monkey/examples/hello.c b/fluent-bit/lib/monkey/examples/hello.c
new file mode 100644
index 000000000..d54c3dde7
--- /dev/null
+++ b/fluent-bit/lib/monkey/examples/hello.c
@@ -0,0 +1,68 @@
+/* Monkey HTTP Daemon
+ * ------------------
+ * Copyright (C) 2012, Lauri Kasanen <cand@gmx.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <libmonkey.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * This example shows how to start the server, and point it to /tmp.
+ * It also creates /tmp/index.html.
+*/
+
+static void write_index() {
+
+ const char *path = "/tmp/index.html";
+
+ FILE *f = fopen(path, "w");
+ if (!f) exit(1);
+
+ fprintf(f, "<html><body><h2>Hello Monkey</h2></body></html>");
+
+ fclose(f);
+}
+
+int main() {
+
+ int ret;
+
+ write_index();
+
+ // All defaults. Bind to all interfaces, port 2001, default plugins, /tmp.
+ // No callbacks are used.
+ mklib_ctx ctx = mklib_init(NULL, 0, 0, "/tmp");
+ if (!ctx) return 1;
+
+ // The default has no index files, let's set index.html as one.
+ ret = mklib_config(ctx, MKC_INDEXFILE, "index.html", NULL);
+ if (!ret) return 1;
+
+ // Start the server.
+ mklib_start(ctx);
+
+ // I'm now free to do my own things. I'm just going to wait for a keypress.
+ printf("All set and running! Visit me, I default to localhost:2001.\n");
+ printf("Press a key to exit.\n");
+ getchar();
+
+ mklib_stop(ctx);
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/examples/hello.py b/fluent-bit/lib/monkey/examples/hello.py
new file mode 100644
index 000000000..bf4b5becd
--- /dev/null
+++ b/fluent-bit/lib/monkey/examples/hello.py
@@ -0,0 +1,12 @@
+import monkey
+
+f = open('/tmp/index.html', 'w')
+f.write("<html><body><h2>Hello Monkey</h2></body></html>")
+f.close()
+
+monkey.init(None, 0, 0, '/tmp/')
+monkey.configure(indexfile='index.html')
+
+monkey.start()
+raw_input("Press enter to stop the server...")
+monkey.stop()
diff --git a/fluent-bit/lib/monkey/examples/image.h b/fluent-bit/lib/monkey/examples/image.h
new file mode 100644
index 000000000..31b4ba992
--- /dev/null
+++ b/fluent-bit/lib/monkey/examples/image.h
@@ -0,0 +1,256 @@
+#ifndef MONKEY_HEAD_PNG_H
+#define MONKEY_HEAD_PNG_H
+static const unsigned char monkey_head_png[] = {
+0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
+0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x28,
+0x08, 0x06, 0x00, 0x00, 0x00, 0xb8, 0x87, 0x79, 0x71, 0x00, 0x00, 0x00,
+0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64,
+0x88, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x03,
+0x2c, 0x00, 0x00, 0x03, 0x2c, 0x01, 0x90, 0x94, 0x1c, 0x83, 0x00, 0x00,
+0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61,
+0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63,
+0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x00,
+0x00, 0x0b, 0x41, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xc5, 0x99, 0x7b,
+0x6c, 0x5b, 0xd7, 0x7d, 0xc7, 0x3f, 0xe7, 0xdc, 0x07, 0x49, 0x51, 0xd4,
+0x83, 0xa2, 0x1e, 0xf1, 0x53, 0xb2, 0x5d, 0x5b, 0x88, 0xd5, 0xda, 0xf3,
+0x62, 0x59, 0x8d, 0xd7, 0xcc, 0x71, 0x3b, 0x07, 0x1b, 0x86, 0xac, 0x58,
+0xe7, 0x24, 0x76, 0x92, 0xc2, 0x49, 0x80, 0x60, 0x6b, 0xd7, 0x17, 0x32,
+0x14, 0x29, 0xda, 0x6d, 0x19, 0xba, 0x66, 0xb3, 0xb7, 0x2e, 0xd8, 0x30,
+0x2c, 0x59, 0xff, 0x58, 0xb2, 0xba, 0xb1, 0x9b, 0x64, 0xc1, 0x90, 0xc4,
+0x49, 0xe7, 0x2c, 0xb6, 0xe1, 0x24, 0xae, 0x15, 0xcb, 0xad, 0xe3, 0x34,
+0x7e, 0x49, 0xab, 0x6c, 0xbd, 0xac, 0x07, 0x25, 0x51, 0x12, 0x25, 0x8a,
+0xe4, 0xe5, 0xbd, 0x67, 0xd7, 0x67, 0xa2, 0x4a, 0x50, 0x6c, 0x2a, 0xa7,
+0x5e, 0xfb, 0x11, 0xbe, 0x38, 0xc0, 0xbd, 0xc4, 0xe5, 0xf7, 0x7b, 0xce,
+0xef, 0x77, 0xcf, 0xa5, 0xae, 0x50, 0x4a, 0x71, 0xa3, 0x88, 0xbf, 0xd0,
+0xda, 0x80, 0xc3, 0xdf, 0x48, 0x41, 0xab, 0x82, 0x25, 0x28, 0x2a, 0x10,
+0x48, 0xc0, 0x05, 0xd2, 0x40, 0x52, 0x08, 0xde, 0x12, 0x4a, 0x3c, 0x11,
+0xdd, 0xf5, 0xce, 0x49, 0x6e, 0x00, 0x37, 0x24, 0x40, 0xfc, 0x60, 0xeb,
+0x5d, 0x02, 0xfe, 0x0a, 0xc1, 0x3a, 0x14, 0x82, 0xc5, 0x31, 0xeb, 0x29,
+0xf6, 0xd7, 0x59, 0x1d, 0x9f, 0x63, 0xa7, 0x72, 0x7f, 0x2d, 0x01, 0x46,
+0xff, 0xad, 0x39, 0x42, 0xa8, 0xe2, 0x0d, 0xa0, 0x95, 0x0f, 0x8b, 0x20,
+0x25, 0x11, 0xdf, 0x88, 0xde, 0xf3, 0xce, 0x13, 0x7c, 0x10, 0xdf, 0xb9,
+0xc5, 0x4a, 0x54, 0x53, 0x56, 0xbd, 0xf3, 0x47, 0x53, 0xa0, 0xd4, 0x2f,
+0x1d, 0x60, 0xec, 0xe0, 0x96, 0x4f, 0x7b, 0xa8, 0x83, 0x02, 0x82, 0xdc,
+0x00, 0x14, 0x9c, 0xad, 0x35, 0x53, 0xad, 0xec, 0x7c, 0x3f, 0x4b, 0x01,
+0x53, 0x2f, 0xdc, 0x1a, 0xcd, 0xe6, 0x72, 0x7b, 0x81, 0x3f, 0x02, 0xaa,
+0x80, 0x04, 0x8a, 0x27, 0x62, 0x56, 0xe3, 0xe3, 0xec, 0x7c, 0xde, 0xfd,
+0x50, 0x01, 0x46, 0x9f, 0xdd, 0xf2, 0xfb, 0x48, 0xf5, 0x32, 0x20, 0xb8,
+0x81, 0x08, 0x18, 0x33, 0x32, 0xc6, 0x2d, 0x55, 0x7b, 0x4e, 0x5e, 0x01,
+0x48, 0xbc, 0x70, 0xcb, 0x0a, 0x37, 0x27, 0x4f, 0x02, 0x4b, 0x28, 0x42,
+0x08, 0x9e, 0xa9, 0xb9, 0xe7, 0xd4, 0x03, 0xd7, 0x1d, 0x20, 0xf1, 0xfc,
+0xe6, 0xad, 0xae, 0x2b, 0x8e, 0x03, 0x06, 0xd7, 0x81, 0x19, 0x6b, 0x21,
+0xfc, 0x1b, 0x5f, 0x46, 0xda, 0x15, 0x28, 0x37, 0x8d, 0x33, 0xf8, 0x0e,
+0xa9, 0xf3, 0x4f, 0xa3, 0x9c, 0x14, 0x45, 0x64, 0x31, 0xd5, 0xc7, 0x62,
+0xe7, 0x4f, 0x77, 0x8d, 0xad, 0xdd, 0xfc, 0x96, 0x82, 0x5b, 0xa1, 0x34,
+0x52, 0xca, 0x3b, 0xae, 0x2b, 0x40, 0xef, 0x81, 0x8f, 0x55, 0x97, 0x89,
+0xe0, 0x10, 0x60, 0x73, 0x1d, 0x94, 0x7d, 0xf4, 0x61, 0xec, 0xe6, 0xcf,
+0x92, 0x4e, 0x67, 0x29, 0x2f, 0x2f, 0x27, 0x8f, 0x97, 0x1e, 0x67, 0xfa,
+0xf4, 0x5e, 0xb2, 0x7d, 0xc7, 0x28, 0x62, 0x0a, 0x21, 0x76, 0xa3, 0xd4,
+0x21, 0x00, 0x37, 0xe7, 0x31, 0x78, 0x29, 0x8e, 0xeb, 0x7a, 0x34, 0xac,
+0xae, 0x21, 0x10, 0xb6, 0xd1, 0x08, 0x0e, 0x5d, 0x57, 0x80, 0xd1, 0x03,
+0xad, 0xc7, 0x11, 0xdc, 0xc6, 0x75, 0x60, 0x56, 0xaf, 0x23, 0xbb, 0x69,
+0x1f, 0x87, 0x8f, 0x1c, 0x26, 0x5c, 0x1e, 0xe6, 0xdc, 0xb9, 0x73, 0x94,
+0x87, 0x22, 0x7c, 0xe5, 0x4b, 0x8f, 0xa0, 0xf1, 0x1c, 0x26, 0x8f, 0x7e,
+0x1e, 0x27, 0xfe, 0x2e, 0x45, 0x38, 0x80, 0x05, 0x70, 0xe9, 0xed, 0xcb,
+0x8c, 0xf6, 0x24, 0x90, 0x86, 0x20, 0x18, 0x0e, 0x70, 0xf3, 0xf6, 0x35,
+0xf9, 0x10, 0x9d, 0xe6, 0xa2, 0xcd, 0x3f, 0xdf, 0x76, 0x7b, 0xb1, 0x79,
+0x23, 0xb2, 0x9c, 0xf2, 0x5b, 0xbe, 0x8a, 0x55, 0xbf, 0x19, 0xe5, 0x39,
+0x78, 0xa9, 0x11, 0x52, 0xef, 0x3d, 0x45, 0xa6, 0xf7, 0xbf, 0xc9, 0x13,
+0xde, 0xf4, 0x15, 0xbe, 0xf0, 0xe8, 0x9f, 0xd1, 0xd2, 0xb2, 0x9e, 0x44,
+0x22, 0xc1, 0xf8, 0xf8, 0x38, 0x47, 0x8f, 0x1e, 0x65, 0xc3, 0x86, 0x8d,
+0x6c, 0xdf, 0xf6, 0x49, 0x90, 0x16, 0x91, 0x4f, 0xec, 0x65, 0xe2, 0xf0,
+0x1e, 0xbc, 0x99, 0x41, 0x0a, 0xd0, 0xe6, 0x27, 0xae, 0x4e, 0x92, 0x1a,
+0x9f, 0xa1, 0xbc, 0xc2, 0x46, 0x08, 0x81, 0x94, 0x8a, 0x81, 0xf7, 0x06,
+0x58, 0xf5, 0xf1, 0x26, 0x6d, 0xc1, 0x64, 0xb1, 0xb8, 0xde, 0x7e, 0x0a,
+0xb0, 0x6f, 0x6a, 0x23, 0x73, 0xf3, 0xd7, 0xd8, 0x7f, 0xf8, 0x55, 0x0c,
+0xe3, 0x1c, 0x7d, 0x3d, 0x7d, 0xdc, 0x7b, 0xcf, 0xfd, 0x34, 0x6d, 0xfd,
+0x16, 0xc1, 0x8f, 0x7c, 0x86, 0xa9, 0x37, 0x1f, 0x01, 0x69, 0x32, 0x1b,
+0x5c, 0xc3, 0xc9, 0x93, 0x3f, 0xa4, 0xb7, 0xb7, 0x87, 0x54, 0x2a, 0xa5,
+0x03, 0xb8, 0xae, 0xcb, 0x6b, 0x3f, 0x78, 0x15, 0x1d, 0x00, 0x90, 0x81,
+0x6a, 0xca, 0xfd, 0xa0, 0x53, 0x6f, 0x7d, 0xb5, 0x54, 0x63, 0x13, 0x2e,
+0xb7, 0xb4, 0x79, 0x21, 0x41, 0x0a, 0x81, 0x61, 0xcc, 0x77, 0xb2, 0x92,
+0x2c, 0x82, 0xf1, 0x67, 0xdb, 0x6e, 0x06, 0x96, 0x92, 0x47, 0x5a, 0xa4,
+0x1a, 0x1f, 0x64, 0xef, 0x3f, 0xec, 0x63, 0x66, 0x66, 0x9a, 0x9e, 0x9e,
+0x1e, 0xba, 0xaf, 0x74, 0xf3, 0x27, 0x5f, 0xfc, 0x63, 0x32, 0x99, 0x0c,
+0x56, 0xdd, 0x26, 0x22, 0xb7, 0xfe, 0x35, 0x66, 0xe5, 0x1a, 0xc6, 0xc6,
+0xc7, 0xc8, 0xe5, 0x72, 0xfa, 0x33, 0xf1, 0x78, 0x5c, 0x9b, 0x07, 0x58,
+0xb1, 0x62, 0x25, 0x73, 0xe8, 0x63, 0x46, 0xc3, 0x56, 0x64, 0x59, 0x1d,
+0xc5, 0x98, 0xb6, 0x41, 0xa8, 0xdc, 0xf2, 0x65, 0x13, 0x0a, 0xdb, 0x04,
+0xfd, 0x31, 0xe0, 0x1f, 0xd3, 0x28, 0x3a, 0x16, 0x15, 0xc0, 0x93, 0xee,
+0xb7, 0x28, 0x20, 0xb4, 0xf6, 0x2e, 0x2e, 0xf6, 0x24, 0x78, 0xfb, 0xc4,
+0xdb, 0x1c, 0x3f, 0x7e, 0x9c, 0x63, 0xc7, 0x8e, 0x71, 0xe2, 0xc4, 0x09,
+0x2e, 0x5e, 0xbc, 0xc0, 0x2b, 0xaf, 0xbe, 0x0c, 0x80, 0xbd, 0x64, 0x2b,
+0x65, 0xeb, 0xf7, 0xd0, 0xd4, 0xd8, 0xc4, 0x7d, 0xbb, 0xef, 0xa7, 0x90,
+0xca, 0xca, 0x4a, 0xb6, 0xdd, 0x76, 0x7b, 0xde, 0xbc, 0x0e, 0x98, 0xc9,
+0x3a, 0x04, 0xd7, 0xfc, 0xe1, 0xc2, 0x00, 0x96, 0x24, 0x58, 0x66, 0xfb,
+0xb2, 0x08, 0x86, 0x2d, 0x02, 0xfe, 0x18, 0x8e, 0x96, 0x01, 0xa0, 0x14,
+0x47, 0x4c, 0x16, 0x85, 0xb8, 0xa3, 0xb8, 0x7c, 0xfa, 0x2f, 0x74, 0x32,
+0x34, 0x34, 0xa4, 0x55, 0x48, 0x4d, 0xb4, 0x86, 0x3c, 0xa6, 0xdf, 0x1b,
+0x00, 0x7f, 0xf1, 0xf5, 0xc7, 0x08, 0x06, 0x83, 0x74, 0x77, 0x77, 0xfb,
+0x46, 0x33, 0x3c, 0xfe, 0xcd, 0xbf, 0x65, 0xa5, 0xbf, 0x02, 0x79, 0xf3,
+0x79, 0x05, 0x96, 0x7c, 0x12, 0xfc, 0x1e, 0x2a, 0x44, 0x9a, 0x06, 0xb6,
+0x6f, 0x5a, 0x08, 0x7c, 0x09, 0xad, 0x40, 0x75, 0x18, 0x00, 0x0b, 0xe7,
+0x8d, 0xf9, 0xbb, 0xd0, 0xf0, 0xfe, 0x2d, 0x4d, 0x86, 0xe9, 0xed, 0x40,
+0xd0, 0x00, 0x72, 0xd8, 0x53, 0xe2, 0x3f, 0xeb, 0x76, 0xb5, 0x0f, 0x0f,
+0x3d, 0xf3, 0xf1, 0x46, 0x33, 0xe0, 0x5e, 0xa6, 0x80, 0xe8, 0xa7, 0x5f,
+0x65, 0x7c, 0x46, 0xf0, 0x7b, 0x77, 0xde, 0xc1, 0x48, 0x7c, 0x84, 0x3c,
+0xa1, 0x50, 0x88, 0xd7, 0x5f, 0x3b, 0xc2, 0xf2, 0x65, 0xcb, 0xf1, 0x3c,
+0x4f, 0xcb, 0x34, 0x4d, 0x4a, 0xb0, 0xc0, 0xbc, 0xe3, 0x38, 0x94, 0x85,
+0x82, 0xa4, 0x0e, 0xed, 0x00, 0x2f, 0x47, 0x1e, 0x37, 0xe3, 0x90, 0x1d,
+0x4b, 0xea, 0x00, 0xcc, 0x05, 0xb0, 0x6b, 0x2b, 0x10, 0x52, 0xbe, 0x19,
+0xdb, 0x75, 0xea, 0xb7, 0x25, 0x40, 0xfc, 0x40, 0xeb, 0x97, 0x0c, 0x53,
+0x5d, 0x00, 0xf1, 0x14, 0x4a, 0x3c, 0x86, 0x52, 0x4f, 0x4a, 0xbc, 0xde,
+0xd1, 0x83, 0x9b, 0xbf, 0x6d, 0xd8, 0xce, 0x9d, 0x14, 0x20, 0xac, 0x72,
+0x64, 0xa8, 0x96, 0x58, 0x2c, 0xc6, 0x3f, 0xff, 0xd3, 0x93, 0x34, 0xaf,
+0x6b, 0xa6, 0x2c, 0x54, 0xc6, 0xaa, 0xa6, 0xd5, 0xbc, 0xf4, 0xe2, 0xa1,
+0xbc, 0xf9, 0xbc, 0xb1, 0xc5, 0x9a, 0xd7, 0x63, 0xd6, 0xc9, 0x61, 0x94,
+0xd5, 0x53, 0x88, 0xb4, 0x4c, 0xcc, 0xe0, 0x35, 0x59, 0xe8, 0x31, 0x6c,
+0x5f, 0x33, 0x0f, 0x9e, 0xf8, 0x3b, 0x00, 0x31, 0xf6, 0xfd, 0x2d, 0x3b,
+0xfc, 0x2f, 0x3c, 0xcc, 0xcf, 0x67, 0x0a, 0xa8, 0x98, 0x0f, 0x60, 0x86,
+0xa8, 0xd9, 0x79, 0xbc, 0xa4, 0x29, 0xc3, 0x30, 0x0a, 0xcd, 0xeb, 0x63,
+0x91, 0x48, 0x64, 0x31, 0xe6, 0xb5, 0x6c, 0xdb, 0x26, 0xf0, 0xfe, 0x63,
+0x38, 0xc3, 0xa7, 0x29, 0xc4, 0x4b, 0xa5, 0x41, 0x29, 0x74, 0x19, 0xf9,
+0x9f, 0xc1, 0x34, 0xce, 0xc7, 0x76, 0x75, 0xb4, 0x80, 0x52, 0xd2, 0xbf,
+0xe0, 0x23, 0x7c, 0x30, 0x15, 0x14, 0xa0, 0x72, 0xb3, 0x78, 0xe9, 0x04,
+0x45, 0xe4, 0xcd, 0x2f, 0x30, 0x97, 0xcd, 0x66, 0x17, 0x61, 0x5e, 0x4b,
+0x97, 0x87, 0xca, 0xa5, 0x29, 0x46, 0xda, 0x96, 0x2f, 0x13, 0xe1, 0x8f,
+0xbe, 0x79, 0x14, 0xfc, 0xbd, 0x4e, 0x04, 0x48, 0x21, 0x44, 0x1b, 0x73,
+0x38, 0x99, 0x1c, 0xbd, 0x67, 0xaf, 0xd2, 0x7d, 0xf2, 0x32, 0x13, 0x7d,
+0x09, 0x5c, 0xc7, 0xa5, 0x14, 0xde, 0xcc, 0x00, 0x45, 0xe4, 0xcd, 0x2f,
+0x30, 0x98, 0x4c, 0x26, 0x17, 0x63, 0x5e, 0xcb, 0xb2, 0x2c, 0xdc, 0xa9,
+0x6e, 0x16, 0x60, 0x1a, 0xbe, 0x4c, 0xb4, 0x60, 0xd0, 0x7f, 0x6a, 0x7d,
+0x76, 0x3e, 0x1c, 0x90, 0x04, 0x50, 0x4a, 0x71, 0xe6, 0xd0, 0x05, 0xc6,
+0x7b, 0xc6, 0xc9, 0xcd, 0x66, 0x49, 0x0e, 0x26, 0x48, 0xf6, 0x8d, 0x53,
+0x8a, 0xdc, 0x44, 0xf7, 0x62, 0xcc, 0xeb, 0x71, 0x7a, 0x7a, 0x1a, 0x55,
+0x7c, 0x7e, 0xa1, 0xf4, 0x35, 0x6c, 0xa9, 0x10, 0x46, 0x84, 0x92, 0x08,
+0xc1, 0x1c, 0x4f, 0x15, 0x3e, 0x72, 0x4b, 0x50, 0x9d, 0x00, 0x53, 0x23,
+0xd3, 0x08, 0x3c, 0xec, 0x80, 0x81, 0x75, 0x4d, 0xb6, 0x89, 0xba, 0x76,
+0xf1, 0x54, 0x86, 0x62, 0x32, 0xdd, 0x2f, 0x2f, 0xca, 0x7c, 0xbe, 0x0f,
+0x04, 0xba, 0x3f, 0x0a, 0xcf, 0x2f, 0x30, 0x1f, 0x0e, 0x87, 0x09, 0xd9,
+0x92, 0x48, 0xcb, 0x17, 0xb1, 0xab, 0x36, 0xf0, 0x01, 0x9c, 0xa1, 0x00,
+0xa9, 0x24, 0xba, 0x9b, 0x33, 0xd3, 0x59, 0x02, 0x73, 0xe6, 0xed, 0x80,
+0xa9, 0x77, 0x40, 0xc3, 0x92, 0xb8, 0x33, 0xb3, 0x14, 0xe3, 0x8c, 0xbe,
+0x47, 0x6e, 0xa2, 0xeb, 0x17, 0x98, 0xd7, 0xd2, 0xb7, 0x51, 0xe5, 0x64,
+0x30, 0x72, 0x33, 0xba, 0x44, 0x4a, 0xcd, 0xbc, 0x94, 0x92, 0xda, 0x9a,
+0x28, 0xde, 0xf4, 0x30, 0x89, 0xf8, 0x18, 0x76, 0xc3, 0x36, 0x3f, 0xc4,
+0x46, 0x4a, 0xe1, 0x09, 0xc6, 0x28, 0x40, 0xd6, 0xde, 0xdd, 0xf1, 0x03,
+0x14, 0x47, 0x62, 0x8d, 0xd5, 0x84, 0x22, 0x01, 0xbd, 0x02, 0xa6, 0x2d,
+0x31, 0x2d, 0x03, 0xc3, 0x97, 0x40, 0xa0, 0xb2, 0x0e, 0xc5, 0xa4, 0x3b,
+0x9f, 0x2b, 0x0a, 0x50, 0x6c, 0x5e, 0xcf, 0xbe, 0xde, 0x1b, 0xc8, 0xcd,
+0xa2, 0xd2, 0x93, 0x04, 0x49, 0x53, 0x5d, 0x55, 0x39, 0xdf, 0xf0, 0x4a,
+0x29, 0xfd, 0x78, 0xdd, 0xb8, 0x72, 0x05, 0x46, 0x3a, 0x8e, 0x72, 0xd2,
+0xcc, 0x8c, 0xf4, 0x63, 0x44, 0x1a, 0xb0, 0xa3, 0xbf, 0x89, 0x0c, 0xc4,
+0x28, 0x46, 0x2a, 0xf6, 0x50, 0x80, 0xd4, 0xa9, 0xe0, 0x61, 0x69, 0xc8,
+0x81, 0x86, 0xe6, 0x7a, 0x5d, 0x3a, 0xff, 0x67, 0x5e, 0x62, 0x98, 0x06,
+0xd2, 0x94, 0xe0, 0xba, 0x0b, 0x03, 0xfc, 0xf4, 0x15, 0xbc, 0xa1, 0x13,
+0xda, 0xc4, 0xcf, 0x31, 0xaf, 0x67, 0x36, 0x5a, 0x19, 0xc1, 0x4b, 0x27,
+0x51, 0xb9, 0x0c, 0x6a, 0x26, 0x8e, 0x91, 0xec, 0xa7, 0xa1, 0x2a, 0x48,
+0xd3, 0xb2, 0x06, 0xd6, 0x34, 0x2e, 0xe3, 0xa6, 0xea, 0x10, 0x8c, 0x5f,
+0xd2, 0xe7, 0xdc, 0xd4, 0x04, 0xfa, 0x4e, 0xa4, 0x5c, 0x10, 0x12, 0xbb,
+0xea, 0xa3, 0x94, 0xe0, 0xfe, 0xe4, 0x77, 0xb7, 0xd4, 0x50, 0x18, 0xa0,
+0x6e, 0xf7, 0xa9, 0x6e, 0xa4, 0xd8, 0x1e, 0xa9, 0xaf, 0x18, 0x8c, 0xad,
+0xad, 0xc7, 0x0c, 0x58, 0x18, 0x73, 0x21, 0xa4, 0x1f, 0x42, 0x6f, 0x1c,
+0x0b, 0x7e, 0x37, 0x28, 0x92, 0x27, 0xff, 0x92, 0x80, 0x9a, 0x06, 0x58,
+0x60, 0x1e, 0xd0, 0x9b, 0x9d, 0x98, 0x1d, 0x05, 0x37, 0xed, 0x2b, 0x83,
+0x72, 0xb3, 0xa4, 0x7b, 0xcf, 0x92, 0xe9, 0x39, 0x8d, 0x1b, 0xbf, 0x80,
+0x3b, 0x7c, 0x0e, 0x77, 0xb4, 0x0b, 0x32, 0x33, 0x3a, 0xe0, 0xc0, 0x99,
+0x37, 0x89, 0xad, 0x5e, 0x0f, 0x6e, 0x16, 0x00, 0x33, 0xdc, 0x84, 0x90,
+0x16, 0x45, 0x04, 0x33, 0x96, 0xf7, 0x60, 0x61, 0x00, 0x4d, 0xec, 0xee,
+0x77, 0x3a, 0x71, 0xd5, 0xed, 0x76, 0x24, 0xd8, 0x1d, 0x59, 0x5e, 0xa3,
+0x77, 0x3e, 0x61, 0x18, 0xbe, 0x24, 0x5c, 0x93, 0x10, 0x2c, 0x40, 0x01,
+0x13, 0x7d, 0x54, 0x97, 0x07, 0xf4, 0x03, 0x9a, 0x5f, 0xef, 0x5a, 0x65,
+0x65, 0x65, 0xac, 0x58, 0xb1, 0x9c, 0x0a, 0x2b, 0x8b, 0x3b, 0x3d, 0xc2,
+0xe4, 0xa9, 0x57, 0x70, 0xc6, 0xfa, 0xc9, 0xf4, 0x9e, 0xe3, 0xca, 0xde,
+0xbb, 0xe8, 0x7f, 0xf2, 0x4f, 0x75, 0x18, 0xbd, 0x2a, 0xae, 0x16, 0x5e,
+0x7a, 0x9a, 0xa1, 0xf7, 0x7e, 0x48, 0x20, 0x68, 0xea, 0xe3, 0x1a, 0x61,
+0x20, 0xed, 0xea, 0x52, 0x5f, 0xdb, 0xb2, 0x20, 0x80, 0x0e, 0x71, 0x5f,
+0xc7, 0x25, 0x66, 0xed, 0x8d, 0x86, 0x6d, 0x3c, 0x63, 0x47, 0x23, 0x18,
+0xd7, 0x42, 0x98, 0x12, 0xa4, 0xa4, 0x14, 0x56, 0xe5, 0x7a, 0x6d, 0xc4,
+0x9b, 0xe8, 0xa5, 0xcc, 0x19, 0x63, 0x49, 0x34, 0xcc, 0x8a, 0xba, 0x4a,
+0x96, 0xd6, 0x84, 0xb1, 0x92, 0x57, 0xf0, 0x12, 0x7d, 0x4c, 0xb6, 0xbf,
+0xc4, 0xe0, 0x77, 0x1f, 0x65, 0xe4, 0xa5, 0x7f, 0xc4, 0x08, 0x57, 0x62,
+0x45, 0x97, 0x12, 0x68, 0xdc, 0x00, 0xd7, 0x4c, 0xba, 0xbe, 0x72, 0x59,
+0xad, 0xab, 0xe7, 0xcf, 0x12, 0x6b, 0x6e, 0xd3, 0x1b, 0x99, 0x9a, 0x9d,
+0x24, 0x8f, 0x30, 0x2b, 0x4a, 0xf4, 0x81, 0x68, 0x67, 0x0e, 0x93, 0x22,
+0x62, 0x0f, 0xbe, 0x9d, 0x04, 0x1e, 0x88, 0x1f, 0xd8, 0xf2, 0x9a, 0x08,
+0x06, 0xfe, 0x15, 0xa5, 0xaa, 0x11, 0x82, 0x52, 0x98, 0xe5, 0x4d, 0xa0,
+0xdc, 0xb9, 0xd9, 0x4c, 0x43, 0x6a, 0x14, 0x94, 0xe7, 0x4b, 0xe9, 0x51,
+0xf9, 0x0a, 0x35, 0xb6, 0x10, 0x6c, 0xdc, 0x48, 0xf9, 0xc6, 0x3b, 0x30,
+0x82, 0x41, 0x56, 0x3d, 0x7a, 0x10, 0xe5, 0xe6, 0xf4, 0xac, 0xe3, 0x79,
+0x80, 0x47, 0x76, 0x7a, 0x9a, 0xa8, 0x7f, 0x3e, 0xdb, 0xff, 0x2e, 0xda,
+0xbc, 0x2a, 0xec, 0x39, 0x0f, 0x00, 0x85, 0xca, 0x08, 0x21, 0xff, 0x0b,
+0xa5, 0x2e, 0xab, 0xb4, 0xfd, 0xbd, 0x45, 0xfc, 0x5f, 0x48, 0xff, 0x90,
+0x59, 0xe6, 0x49, 0xef, 0xdf, 0x81, 0xed, 0x94, 0x20, 0xdc, 0xf4, 0x00,
+0x46, 0xb4, 0x09, 0x19, 0x8a, 0x82, 0x52, 0xda, 0x30, 0x79, 0xe1, 0xcd,
+0x19, 0x54, 0x20, 0x24, 0xca, 0x75, 0xb4, 0xb1, 0x7c, 0x38, 0xb4, 0x94,
+0x3e, 0xde, 0xd7, 0x75, 0x85, 0xda, 0x4d, 0x3b, 0x08, 0x4c, 0x9e, 0x87,
+0xcc, 0x14, 0x85, 0xcc, 0x0e, 0xbc, 0x8c, 0x9b, 0x1e, 0x06, 0xc5, 0x1b,
+0xb1, 0xdd, 0xa7, 0x7e, 0x87, 0x22, 0x24, 0x1f, 0x40, 0xf4, 0xde, 0xf6,
+0x7e, 0xff, 0xa1, 0xe9, 0x53, 0x02, 0x5e, 0x2c, 0xbd, 0x39, 0x4a, 0xbc,
+0xa9, 0xab, 0x28, 0x67, 0x16, 0x3d, 0xa3, 0xf3, 0xd2, 0x65, 0xf1, 0xb3,
+0x3a, 0xcf, 0xa6, 0x20, 0x97, 0x2f, 0x97, 0x8c, 0x96, 0xf2, 0xe5, 0x39,
+0x69, 0x86, 0xfa, 0xe3, 0xac, 0xdc, 0xf1, 0x10, 0xa3, 0x3f, 0x79, 0x6b,
+0x81, 0x79, 0x95, 0x9b, 0xc1, 0xcd, 0xc4, 0x01, 0x90, 0x86, 0xfc, 0x73,
+0x4a, 0x20, 0xf9, 0x85, 0x28, 0xa5, 0x66, 0xed, 0x07, 0x80, 0x01, 0x8a,
+0xf0, 0x72, 0x49, 0xf0, 0x5c, 0xbc, 0xe4, 0x20, 0xda, 0x94, 0xd6, 0xcf,
+0x9a, 0x93, 0x9c, 0x0e, 0xe3, 0xab, 0xa0, 0x59, 0xb5, 0xd2, 0xcc, 0x4e,
+0x8e, 0x32, 0x9a, 0xc8, 0x11, 0xf1, 0xcb, 0xcb, 0x2a, 0xaf, 0x22, 0x71,
+0xb1, 0x1d, 0x85, 0x02, 0x2d, 0x34, 0xd9, 0xc9, 0xf7, 0xe7, 0x56, 0x93,
+0x44, 0xf4, 0xee, 0xf6, 0xf6, 0x45, 0x07, 0x28, 0xd9, 0x17, 0x82, 0x33,
+0x0b, 0x02, 0x64, 0x46, 0x01, 0x50, 0x99, 0x24, 0xb9, 0x44, 0x2f, 0x38,
+0xa9, 0xf9, 0x15, 0x50, 0x05, 0x2b, 0xe0, 0xe9, 0x60, 0x69, 0x3c, 0xff,
+0xbc, 0xe7, 0xd7, 0x78, 0xbc, 0xa7, 0x07, 0x63, 0xe5, 0x36, 0x96, 0x6d,
+0xdb, 0xcd, 0xec, 0xd8, 0x55, 0xc6, 0x2f, 0x9d, 0x62, 0xf2, 0xf2, 0xbb,
+0xfa, 0xfe, 0xaf, 0xf2, 0x7f, 0x5e, 0x96, 0xdc, 0xd4, 0x85, 0x7c, 0xfd,
+0x7f, 0x0f, 0x4a, 0x63, 0xb2, 0x58, 0x14, 0x83, 0x14, 0xe1, 0x4c, 0x5d,
+0xc2, 0x2c, 0x5f, 0x0d, 0xc0, 0x40, 0x67, 0x17, 0xc9, 0xa1, 0x5e, 0xa2,
+0xcb, 0x9b, 0xa8, 0xa8, 0x89, 0x11, 0xa8, 0xa8, 0xc4, 0xb0, 0x02, 0x28,
+0x5c, 0x1d, 0x60, 0x7a, 0x74, 0x84, 0xac, 0x11, 0x25, 0xb4, 0x6c, 0x03,
+0x86, 0x17, 0x27, 0xb2, 0xbc, 0x79, 0xfe, 0x19, 0xad, 0x63, 0xdf, 0x67,
+0x71, 0xd3, 0x49, 0xf0, 0x72, 0x28, 0x69, 0x22, 0x84, 0x81, 0xe3, 0xf7,
+0x83, 0xf2, 0x1c, 0x50, 0x24, 0x6b, 0x77, 0x9f, 0xfe, 0xf2, 0x2f, 0x1d,
+0x40, 0x21, 0x7a, 0x04, 0x8a, 0x42, 0xdc, 0xd9, 0x01, 0xbd, 0x0a, 0x32,
+0x10, 0x63, 0xd9, 0xda, 0xd5, 0xa8, 0x75, 0xcd, 0x5c, 0xed, 0xee, 0x65,
+0x78, 0x64, 0x86, 0x9a, 0xd8, 0x06, 0x7f, 0x66, 0x3b, 0x88, 0x36, 0x6f,
+0x26, 0x50, 0xdf, 0x40, 0x76, 0xf6, 0x1c, 0xcb, 0x6e, 0xdb, 0x09, 0x40,
+0x7a, 0x6c, 0x90, 0xec, 0xd4, 0x28, 0x0a, 0xb8, 0x70, 0xf0, 0x71, 0xa6,
+0x07, 0x3a, 0x09, 0x46, 0xeb, 0x51, 0x80, 0x00, 0x72, 0x33, 0x3d, 0x64,
+0x13, 0x3f, 0xca, 0x17, 0xf0, 0x83, 0xe8, 0x3a, 0x2a, 0x8d, 0x64, 0xb1,
+0x28, 0xef, 0x0c, 0x25, 0x48, 0x0f, 0x1f, 0x45, 0xcf, 0x14, 0x20, 0x94,
+0xc3, 0xd2, 0xa6, 0x9b, 0x58, 0xb9, 0x76, 0x29, 0xce, 0xc8, 0x45, 0x2a,
+0x9b, 0x5a, 0x70, 0xa6, 0x27, 0x29, 0xab, 0x5d, 0xc1, 0xd2, 0x4f, 0x7c,
+0x86, 0xe1, 0x1f, 0xbf, 0x0e, 0x80, 0xe7, 0x3a, 0xbc, 0xff, 0xf4, 0xd7,
+0x79, 0xfd, 0xa1, 0x66, 0x26, 0xfe, 0xe7, 0xc7, 0x00, 0x54, 0x2c, 0x5b,
+0x8d, 0xbe, 0x29, 0xa4, 0xfa, 0xc8, 0x0c, 0x1f, 0xc9, 0x7b, 0x3e, 0x55,
+0x7b, 0x6f, 0xc7, 0x7f, 0xdc, 0xb0, 0xf7, 0x03, 0x63, 0x07, 0x5a, 0xbf,
+0xa9, 0x04, 0xdf, 0x40, 0x70, 0x59, 0x28, 0x4e, 0x28, 0xb8, 0x0f, 0xc0,
+0x08, 0xd4, 0x12, 0xa8, 0xdf, 0x8e, 0xb4, 0x2a, 0xf2, 0x35, 0x8b, 0x52,
+0xfa, 0x49, 0x93, 0xc1, 0x9f, 0xf6, 0x32, 0xda, 0xdd, 0x45, 0xd5, 0xaa,
+0x8d, 0x24, 0xfb, 0x2f, 0xf9, 0xea, 0xd4, 0xa6, 0x0b, 0xd0, 0x3b, 0x7e,
+0xdb, 0xe7, 0x1f, 0x27, 0x12, 0x1c, 0xf3, 0xcd, 0x1f, 0xcb, 0x37, 0x72,
+0x7f, 0x2c, 0xe9, 0xad, 0xe2, 0xe1, 0xd3, 0xce, 0x8d, 0x0a, 0xa0, 0x19,
+0x39, 0xd8, 0x56, 0x3f, 0x55, 0x35, 0x36, 0xb1, 0xe6, 0x77, 0xbb, 0x32,
+0xa3, 0xcf, 0xb5, 0x3e, 0x8c, 0xc7, 0x93, 0x80, 0x14, 0xd2, 0x22, 0x10,
+0xdb, 0x8a, 0x19, 0xf9, 0xc8, 0x5c, 0x00, 0x17, 0xe5, 0xe5, 0xc0, 0x73,
+0x98, 0x99, 0x9a, 0xe1, 0xcc, 0xf3, 0x4f, 0x33, 0x3d, 0x78, 0x85, 0x62,
+0x82, 0xd5, 0x75, 0xb4, 0xdc, 0xfd, 0x39, 0x2a, 0xad, 0x4e, 0x72, 0x53,
+0x5d, 0x79, 0xf3, 0xe3, 0x63, 0xe1, 0xa9, 0xc6, 0x75, 0x77, 0x5e, 0x4c,
+0xfe, 0xbf, 0xbf, 0x62, 0x1a, 0x7e, 0xae, 0xad, 0xcd, 0xf0, 0xbc, 0xa3,
+0x40, 0x08, 0xbd, 0x3b, 0xaf, 0xc2, 0xaa, 0x5a, 0x8f, 0xb4, 0x6b, 0x50,
+0x80, 0xde, 0x91, 0x3d, 0x0f, 0x4f, 0x41, 0xef, 0x4f, 0xce, 0xd1, 0xd7,
+0xfe, 0x3a, 0xb9, 0x74, 0x8a, 0xf2, 0x86, 0x46, 0x1a, 0x36, 0xde, 0x4a,
+0x5d, 0x43, 0x1a, 0x4f, 0xd7, 0xfb, 0x3c, 0x5d, 0x6e, 0x2e, 0xf3, 0x5b,
+0xf5, 0xf7, 0x9f, 0x1d, 0xf9, 0xd5, 0xbd, 0x23, 0xfb, 0x97, 0x96, 0x72,
+0x51, 0x1d, 0xde, 0x0f, 0xea, 0x0f, 0x00, 0x01, 0x80, 0x30, 0x31, 0x82,
+0x75, 0xc8, 0xb2, 0x25, 0x48, 0xab, 0x5a, 0xbf, 0x13, 0xc0, 0x9b, 0xdb,
+0xf0, 0x54, 0x16, 0x77, 0x76, 0x04, 0x2f, 0x9b, 0x28, 0xfa, 0xad, 0xc2,
+0xbe, 0x9a, 0x5d, 0xa7, 0xbe, 0xf6, 0x2b, 0x7f, 0xc9, 0x97, 0x67, 0xe2,
+0xc0, 0xa6, 0x95, 0xae, 0xb4, 0xbe, 0xaf, 0x94, 0x6a, 0x05, 0xe4, 0xa2,
+0x0c, 0x80, 0xe3, 0x29, 0x8e, 0x92, 0x95, 0x5f, 0xa8, 0xdd, 0xd3, 0xde,
+0xf5, 0xeb, 0x78, 0x4b, 0xb9, 0x90, 0x17, 0x84, 0x11, 0x77, 0x5b, 0xf7,
+0x48, 0xa5, 0x1e, 0x52, 0xd0, 0x0c, 0x84, 0x00, 0x7b, 0x2e, 0x94, 0x03,
+0x8c, 0x03, 0x7d, 0x0a, 0x5e, 0xac, 0xdd, 0xd5, 0xb1, 0x4f, 0xd7, 0xd9,
+0x87, 0xe4, 0x7f, 0x01, 0x9c, 0x0b, 0xc5, 0xc1, 0xee, 0xb9, 0xae, 0x42,
+0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
+};
+#endif
diff --git a/fluent-bit/lib/monkey/examples/list.c b/fluent-bit/lib/monkey/examples/list.c
new file mode 100644
index 000000000..7156fd2c2
--- /dev/null
+++ b/fluent-bit/lib/monkey/examples/list.c
@@ -0,0 +1,91 @@
+/* Monkey HTTP Daemon
+ * ------------------
+ * Copyright (C) 2012, Lauri Kasanen <cand@gmx.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <libmonkey.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * This example shows a directory listing of /tmp, with no access to files. Fun eh?
+*/
+
+enum {
+ bufsize = 4096
+};
+static char buf[bufsize];
+
+static int list(const mklib_session *sr, const char *vhost, const char *url,
+ const char *get, unsigned long getlen,
+ const char *post, unsigned long postlen,
+ unsigned int *status, const char **content, unsigned long *content_len,
+ char *header) {
+
+ sprintf(buf, "<html><body><h2>Hello friend. You asked for %s.</h2>\n", url);
+ strcat(buf, "<pre>");
+
+ FILE *f = popen("ls -lh /tmp", "r");
+ if (!f) exit(1);
+
+
+ char mybuf[bufsize - 200];
+
+ while (fgets(mybuf, bufsize - 200, f)) {
+ // Note: this is dangerous. Only used for demonstration purposes.
+ strcat(buf, mybuf);
+ }
+ pclose(f);
+
+ strcat(buf, "</pre></body></html>");
+
+ *content = buf;
+ *content_len = strlen(buf);
+ sprintf(header, "Content-type: text/html");
+
+ // TRUE here means we handled this request.
+ return MKLIB_TRUE;
+}
+
+/* The callback setting interface can't check the callback for compatibility.
+ * This makes sure the callback function has the right arguments. */
+static cb_data listf = list;
+
+int main() {
+
+ // Bind to all interfaces, port 2001, default plugins, no directory.
+ // Lacking the directory means that no files can be accessed, just what we want.
+ // We use the data callback.
+ mklib_ctx ctx = mklib_init(NULL, 0, 0, NULL);
+ if (!ctx) return 1;
+
+ mklib_callback_set(ctx, MKCB_DATA, listf);
+
+ // Start the server.
+ mklib_start(ctx);
+
+ // I'm now free to do my own things. I'm just going to wait for a keypress.
+ printf("All set and running! Visit me, I default to localhost:2001.\n");
+ printf("Press a key to exit.\n");
+ getchar();
+
+ mklib_stop(ctx);
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/examples/list.py b/fluent-bit/lib/monkey/examples/list.py
new file mode 100644
index 000000000..d401d4280
--- /dev/null
+++ b/fluent-bit/lib/monkey/examples/list.py
@@ -0,0 +1,24 @@
+import monkey
+import subprocess
+
+content = ''
+
+def list_cb(vhost, url, get, get_len, post, post_len, header):
+ global content
+ content = "<html><body><h2>Hello friend. You asked for %s.</h2>\n"
+ content += "<pre>"
+ content += subprocess.check_output(['ls', '-lh', '/tmp'])
+ content += "</pre></body></html>"
+
+ ret = {}
+ ret['return'] = 1
+ ret['content'] = content
+ ret['content_len'] = len(ret['content'])
+
+ return ret
+
+monkey.init(None, 0, 0, None)
+monkey.set_callback('data', list_cb)
+monkey.start()
+raw_input("Press enter to stop the server...")
+monkey.stop()
diff --git a/fluent-bit/lib/monkey/examples/quiz.c b/fluent-bit/lib/monkey/examples/quiz.c
new file mode 100644
index 000000000..9914cb794
--- /dev/null
+++ b/fluent-bit/lib/monkey/examples/quiz.c
@@ -0,0 +1,124 @@
+/* Monkey HTTP Daemon
+ * ------------------
+ * Copyright (C) 2012, Lauri Kasanen <cand@gmx.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <libmonkey.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "image.h"
+
+/*
+ * This example shows a simple quiz. It includes POST data handling, and
+ * an image embedded in the code.
+*/
+
+enum {
+ bufsize = 4096
+};
+static char buf[bufsize];
+
+static void front() {
+
+ sprintf(buf, "<html><body><center><h2>Hello friend."
+ " Have you seen this guy?</h2>\n"
+ "<br><br><img src=\"/image.png\">"
+ "<br><br><form action=/ method=post>"
+ "<input type=radio name=q1 value=yes>Why yes I have<br>"
+ "<input type=radio name=q1 value=no>No, who's he?<br>"
+ "<input type=radio name=q1 value=who>Canada<hr width='20%%'>"
+ "<input type=submit>"
+ "</form>"
+ "</center></body></html>");
+
+}
+
+static void points() {
+
+ sprintf(buf, "<html><body><center><h2>Correct!</h2>\n"
+ "<br><br><a href='http://monkey-project.com'>Visit him.</a>"
+ "</center></body></html>");
+
+}
+
+static void wrong() {
+
+ sprintf(buf, "<html><body><center><h2>I'm a sad puppy.</h2>\n"
+ "</center></body></html>");
+}
+
+static int list(const mklib_session *sr, const char *vhost, const char *url,
+ const char *get, unsigned long getlen,
+ const char *post, unsigned long postlen,
+ unsigned int *status, const char **content, unsigned long *content_len,
+ char *header) {
+
+ if (strcmp(url, "/image.png") == 0) {
+ *content = (char *) monkey_head_png;
+ *content_len = sizeof(monkey_head_png);
+ sprintf(header, "Content-type: image/png");
+
+ return MKLIB_TRUE;
+ }
+
+ if (!post) {
+ front();
+ } else {
+ if (strstr(post, "q1=who") || strstr(post, "q1=yes"))
+ points();
+ else
+ wrong();
+ }
+
+ *content = buf;
+ *content_len = strlen(buf);
+ sprintf(header, "Content-type: text/html");
+
+
+ // TRUE here means we handled this request.
+ return MKLIB_TRUE;
+}
+
+/* The callback setting interface can't check the callback for compatibility.
+ * This makes sure the callback function has the right arguments. */
+static cb_data listf = list;
+
+int main() {
+
+ // Bind to all interfaces, port 2001, default plugins, no directory.
+ // Lacking the directory means that no files can be accessed, just what we want.
+ // We use the data callback.
+ mklib_ctx ctx = mklib_init(NULL, 0, 0, NULL);
+ if (!ctx) return 1;
+
+ mklib_callback_set(ctx, MKCB_DATA, listf);
+
+ // Start the server.
+ mklib_start(ctx);
+
+ // I'm now free to do my own things. I'm just going to wait for a keypress.
+ printf("All set and running! Visit me, I default to localhost:2001.\n");
+ printf("Press a key to exit.\n");
+ getchar();
+
+ mklib_stop(ctx);
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/examples/quiz.py b/fluent-bit/lib/monkey/examples/quiz.py
new file mode 100644
index 000000000..96dfa31bd
--- /dev/null
+++ b/fluent-bit/lib/monkey/examples/quiz.py
@@ -0,0 +1,298 @@
+import monkey
+
+content = ''
+
+image = ''.join(chr(x) for x in
+[
+0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
+0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x28,
+0x08, 0x06, 0x00, 0x00, 0x00, 0xb8, 0x87, 0x79, 0x71, 0x00, 0x00, 0x00,
+0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64,
+0x88, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x03,
+0x2c, 0x00, 0x00, 0x03, 0x2c, 0x01, 0x90, 0x94, 0x1c, 0x83, 0x00, 0x00,
+0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61,
+0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63,
+0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x00,
+0x00, 0x0b, 0x41, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xc5, 0x99, 0x7b,
+0x6c, 0x5b, 0xd7, 0x7d, 0xc7, 0x3f, 0xe7, 0xdc, 0x07, 0x49, 0x51, 0xd4,
+0x83, 0xa2, 0x1e, 0xf1, 0x53, 0xb2, 0x5d, 0x5b, 0x88, 0xd5, 0xda, 0xf3,
+0x62, 0x59, 0x8d, 0xd7, 0xcc, 0x71, 0x3b, 0x07, 0x1b, 0x86, 0xac, 0x58,
+0xe7, 0x24, 0x76, 0x92, 0xc2, 0x49, 0x80, 0x60, 0x6b, 0xd7, 0x17, 0x32,
+0x14, 0x29, 0xda, 0x6d, 0x19, 0xba, 0x66, 0xb3, 0xb7, 0x2e, 0xd8, 0x30,
+0x2c, 0x59, 0xff, 0x58, 0xb2, 0xba, 0xb1, 0x9b, 0x64, 0xc1, 0x90, 0xc4,
+0x49, 0xe7, 0x2c, 0xb6, 0xe1, 0x24, 0xae, 0x15, 0xcb, 0xad, 0xe3, 0x34,
+0x7e, 0x49, 0xab, 0x6c, 0xbd, 0xac, 0x07, 0x25, 0x51, 0x12, 0x25, 0x8a,
+0xe4, 0xe5, 0xbd, 0x67, 0xd7, 0x67, 0xa2, 0x4a, 0x50, 0x6c, 0x2a, 0xa7,
+0x5e, 0xfb, 0x11, 0xbe, 0x38, 0xc0, 0xbd, 0xc4, 0xe5, 0xf7, 0x7b, 0xce,
+0xef, 0x77, 0xcf, 0xa5, 0xae, 0x50, 0x4a, 0x71, 0xa3, 0x88, 0xbf, 0xd0,
+0xda, 0x80, 0xc3, 0xdf, 0x48, 0x41, 0xab, 0x82, 0x25, 0x28, 0x2a, 0x10,
+0x48, 0xc0, 0x05, 0xd2, 0x40, 0x52, 0x08, 0xde, 0x12, 0x4a, 0x3c, 0x11,
+0xdd, 0xf5, 0xce, 0x49, 0x6e, 0x00, 0x37, 0x24, 0x40, 0xfc, 0x60, 0xeb,
+0x5d, 0x02, 0xfe, 0x0a, 0xc1, 0x3a, 0x14, 0x82, 0xc5, 0x31, 0xeb, 0x29,
+0xf6, 0xd7, 0x59, 0x1d, 0x9f, 0x63, 0xa7, 0x72, 0x7f, 0x2d, 0x01, 0x46,
+0xff, 0xad, 0x39, 0x42, 0xa8, 0xe2, 0x0d, 0xa0, 0x95, 0x0f, 0x8b, 0x20,
+0x25, 0x11, 0xdf, 0x88, 0xde, 0xf3, 0xce, 0x13, 0x7c, 0x10, 0xdf, 0xb9,
+0xc5, 0x4a, 0x54, 0x53, 0x56, 0xbd, 0xf3, 0x47, 0x53, 0xa0, 0xd4, 0x2f,
+0x1d, 0x60, 0xec, 0xe0, 0x96, 0x4f, 0x7b, 0xa8, 0x83, 0x02, 0x82, 0xdc,
+0x00, 0x14, 0x9c, 0xad, 0x35, 0x53, 0xad, 0xec, 0x7c, 0x3f, 0x4b, 0x01,
+0x53, 0x2f, 0xdc, 0x1a, 0xcd, 0xe6, 0x72, 0x7b, 0x81, 0x3f, 0x02, 0xaa,
+0x80, 0x04, 0x8a, 0x27, 0x62, 0x56, 0xe3, 0xe3, 0xec, 0x7c, 0xde, 0xfd,
+0x50, 0x01, 0x46, 0x9f, 0xdd, 0xf2, 0xfb, 0x48, 0xf5, 0x32, 0x20, 0xb8,
+0x81, 0x08, 0x18, 0x33, 0x32, 0xc6, 0x2d, 0x55, 0x7b, 0x4e, 0x5e, 0x01,
+0x48, 0xbc, 0x70, 0xcb, 0x0a, 0x37, 0x27, 0x4f, 0x02, 0x4b, 0x28, 0x42,
+0x08, 0x9e, 0xa9, 0xb9, 0xe7, 0xd4, 0x03, 0xd7, 0x1d, 0x20, 0xf1, 0xfc,
+0xe6, 0xad, 0xae, 0x2b, 0x8e, 0x03, 0x06, 0xd7, 0x81, 0x19, 0x6b, 0x21,
+0xfc, 0x1b, 0x5f, 0x46, 0xda, 0x15, 0x28, 0x37, 0x8d, 0x33, 0xf8, 0x0e,
+0xa9, 0xf3, 0x4f, 0xa3, 0x9c, 0x14, 0x45, 0x64, 0x31, 0xd5, 0xc7, 0x62,
+0xe7, 0x4f, 0x77, 0x8d, 0xad, 0xdd, 0xfc, 0x96, 0x82, 0x5b, 0xa1, 0x34,
+0x52, 0xca, 0x3b, 0xae, 0x2b, 0x40, 0xef, 0x81, 0x8f, 0x55, 0x97, 0x89,
+0xe0, 0x10, 0x60, 0x73, 0x1d, 0x94, 0x7d, 0xf4, 0x61, 0xec, 0xe6, 0xcf,
+0x92, 0x4e, 0x67, 0x29, 0x2f, 0x2f, 0x27, 0x8f, 0x97, 0x1e, 0x67, 0xfa,
+0xf4, 0x5e, 0xb2, 0x7d, 0xc7, 0x28, 0x62, 0x0a, 0x21, 0x76, 0xa3, 0xd4,
+0x21, 0x00, 0x37, 0xe7, 0x31, 0x78, 0x29, 0x8e, 0xeb, 0x7a, 0x34, 0xac,
+0xae, 0x21, 0x10, 0xb6, 0xd1, 0x08, 0x0e, 0x5d, 0x57, 0x80, 0xd1, 0x03,
+0xad, 0xc7, 0x11, 0xdc, 0xc6, 0x75, 0x60, 0x56, 0xaf, 0x23, 0xbb, 0x69,
+0x1f, 0x87, 0x8f, 0x1c, 0x26, 0x5c, 0x1e, 0xe6, 0xdc, 0xb9, 0x73, 0x94,
+0x87, 0x22, 0x7c, 0xe5, 0x4b, 0x8f, 0xa0, 0xf1, 0x1c, 0x26, 0x8f, 0x7e,
+0x1e, 0x27, 0xfe, 0x2e, 0x45, 0x38, 0x80, 0x05, 0x70, 0xe9, 0xed, 0xcb,
+0x8c, 0xf6, 0x24, 0x90, 0x86, 0x20, 0x18, 0x0e, 0x70, 0xf3, 0xf6, 0x35,
+0xf9, 0x10, 0x9d, 0xe6, 0xa2, 0xcd, 0x3f, 0xdf, 0x76, 0x7b, 0xb1, 0x79,
+0x23, 0xb2, 0x9c, 0xf2, 0x5b, 0xbe, 0x8a, 0x55, 0xbf, 0x19, 0xe5, 0x39,
+0x78, 0xa9, 0x11, 0x52, 0xef, 0x3d, 0x45, 0xa6, 0xf7, 0xbf, 0xc9, 0x13,
+0xde, 0xf4, 0x15, 0xbe, 0xf0, 0xe8, 0x9f, 0xd1, 0xd2, 0xb2, 0x9e, 0x44,
+0x22, 0xc1, 0xf8, 0xf8, 0x38, 0x47, 0x8f, 0x1e, 0x65, 0xc3, 0x86, 0x8d,
+0x6c, 0xdf, 0xf6, 0x49, 0x90, 0x16, 0x91, 0x4f, 0xec, 0x65, 0xe2, 0xf0,
+0x1e, 0xbc, 0x99, 0x41, 0x0a, 0xd0, 0xe6, 0x27, 0xae, 0x4e, 0x92, 0x1a,
+0x9f, 0xa1, 0xbc, 0xc2, 0x46, 0x08, 0x81, 0x94, 0x8a, 0x81, 0xf7, 0x06,
+0x58, 0xf5, 0xf1, 0x26, 0x6d, 0xc1, 0x64, 0xb1, 0xb8, 0xde, 0x7e, 0x0a,
+0xb0, 0x6f, 0x6a, 0x23, 0x73, 0xf3, 0xd7, 0xd8, 0x7f, 0xf8, 0x55, 0x0c,
+0xe3, 0x1c, 0x7d, 0x3d, 0x7d, 0xdc, 0x7b, 0xcf, 0xfd, 0x34, 0x6d, 0xfd,
+0x16, 0xc1, 0x8f, 0x7c, 0x86, 0xa9, 0x37, 0x1f, 0x01, 0x69, 0x32, 0x1b,
+0x5c, 0xc3, 0xc9, 0x93, 0x3f, 0xa4, 0xb7, 0xb7, 0x87, 0x54, 0x2a, 0xa5,
+0x03, 0xb8, 0xae, 0xcb, 0x6b, 0x3f, 0x78, 0x15, 0x1d, 0x00, 0x90, 0x81,
+0x6a, 0xca, 0xfd, 0xa0, 0x53, 0x6f, 0x7d, 0xb5, 0x54, 0x63, 0x13, 0x2e,
+0xb7, 0xb4, 0x79, 0x21, 0x41, 0x0a, 0x81, 0x61, 0xcc, 0x77, 0xb2, 0x92,
+0x2c, 0x82, 0xf1, 0x67, 0xdb, 0x6e, 0x06, 0x96, 0x92, 0x47, 0x5a, 0xa4,
+0x1a, 0x1f, 0x64, 0xef, 0x3f, 0xec, 0x63, 0x66, 0x66, 0x9a, 0x9e, 0x9e,
+0x1e, 0xba, 0xaf, 0x74, 0xf3, 0x27, 0x5f, 0xfc, 0x63, 0x32, 0x99, 0x0c,
+0x56, 0xdd, 0x26, 0x22, 0xb7, 0xfe, 0x35, 0x66, 0xe5, 0x1a, 0xc6, 0xc6,
+0xc7, 0xc8, 0xe5, 0x72, 0xfa, 0x33, 0xf1, 0x78, 0x5c, 0x9b, 0x07, 0x58,
+0xb1, 0x62, 0x25, 0x73, 0xe8, 0x63, 0x46, 0xc3, 0x56, 0x64, 0x59, 0x1d,
+0xc5, 0x98, 0xb6, 0x41, 0xa8, 0xdc, 0xf2, 0x65, 0x13, 0x0a, 0xdb, 0x04,
+0xfd, 0x31, 0xe0, 0x1f, 0xd3, 0x28, 0x3a, 0x16, 0x15, 0xc0, 0x93, 0xee,
+0xb7, 0x28, 0x20, 0xb4, 0xf6, 0x2e, 0x2e, 0xf6, 0x24, 0x78, 0xfb, 0xc4,
+0xdb, 0x1c, 0x3f, 0x7e, 0x9c, 0x63, 0xc7, 0x8e, 0x71, 0xe2, 0xc4, 0x09,
+0x2e, 0x5e, 0xbc, 0xc0, 0x2b, 0xaf, 0xbe, 0x0c, 0x80, 0xbd, 0x64, 0x2b,
+0x65, 0xeb, 0xf7, 0xd0, 0xd4, 0xd8, 0xc4, 0x7d, 0xbb, 0xef, 0xa7, 0x90,
+0xca, 0xca, 0x4a, 0xb6, 0xdd, 0x76, 0x7b, 0xde, 0xbc, 0x0e, 0x98, 0xc9,
+0x3a, 0x04, 0xd7, 0xfc, 0xe1, 0xc2, 0x00, 0x96, 0x24, 0x58, 0x66, 0xfb,
+0xb2, 0x08, 0x86, 0x2d, 0x02, 0xfe, 0x18, 0x8e, 0x96, 0x01, 0xa0, 0x14,
+0x47, 0x4c, 0x16, 0x85, 0xb8, 0xa3, 0xb8, 0x7c, 0xfa, 0x2f, 0x74, 0x32,
+0x34, 0x34, 0xa4, 0x55, 0x48, 0x4d, 0xb4, 0x86, 0x3c, 0xa6, 0xdf, 0x1b,
+0x00, 0x7f, 0xf1, 0xf5, 0xc7, 0x08, 0x06, 0x83, 0x74, 0x77, 0x77, 0xfb,
+0x46, 0x33, 0x3c, 0xfe, 0xcd, 0xbf, 0x65, 0xa5, 0xbf, 0x02, 0x79, 0xf3,
+0x79, 0x05, 0x96, 0x7c, 0x12, 0xfc, 0x1e, 0x2a, 0x44, 0x9a, 0x06, 0xb6,
+0x6f, 0x5a, 0x08, 0x7c, 0x09, 0xad, 0x40, 0x75, 0x18, 0x00, 0x0b, 0xe7,
+0x8d, 0xf9, 0xbb, 0xd0, 0xf0, 0xfe, 0x2d, 0x4d, 0x86, 0xe9, 0xed, 0x40,
+0xd0, 0x00, 0x72, 0xd8, 0x53, 0xe2, 0x3f, 0xeb, 0x76, 0xb5, 0x0f, 0x0f,
+0x3d, 0xf3, 0xf1, 0x46, 0x33, 0xe0, 0x5e, 0xa6, 0x80, 0xe8, 0xa7, 0x5f,
+0x65, 0x7c, 0x46, 0xf0, 0x7b, 0x77, 0xde, 0xc1, 0x48, 0x7c, 0x84, 0x3c,
+0xa1, 0x50, 0x88, 0xd7, 0x5f, 0x3b, 0xc2, 0xf2, 0x65, 0xcb, 0xf1, 0x3c,
+0x4f, 0xcb, 0x34, 0x4d, 0x4a, 0xb0, 0xc0, 0xbc, 0xe3, 0x38, 0x94, 0x85,
+0x82, 0xa4, 0x0e, 0xed, 0x00, 0x2f, 0x47, 0x1e, 0x37, 0xe3, 0x90, 0x1d,
+0x4b, 0xea, 0x00, 0xcc, 0x05, 0xb0, 0x6b, 0x2b, 0x10, 0x52, 0xbe, 0x19,
+0xdb, 0x75, 0xea, 0xb7, 0x25, 0x40, 0xfc, 0x40, 0xeb, 0x97, 0x0c, 0x53,
+0x5d, 0x00, 0xf1, 0x14, 0x4a, 0x3c, 0x86, 0x52, 0x4f, 0x4a, 0xbc, 0xde,
+0xd1, 0x83, 0x9b, 0xbf, 0x6d, 0xd8, 0xce, 0x9d, 0x14, 0x20, 0xac, 0x72,
+0x64, 0xa8, 0x96, 0x58, 0x2c, 0xc6, 0x3f, 0xff, 0xd3, 0x93, 0x34, 0xaf,
+0x6b, 0xa6, 0x2c, 0x54, 0xc6, 0xaa, 0xa6, 0xd5, 0xbc, 0xf4, 0xe2, 0xa1,
+0xbc, 0xf9, 0xbc, 0xb1, 0xc5, 0x9a, 0xd7, 0x63, 0xd6, 0xc9, 0x61, 0x94,
+0xd5, 0x53, 0x88, 0xb4, 0x4c, 0xcc, 0xe0, 0x35, 0x59, 0xe8, 0x31, 0x6c,
+0x5f, 0x33, 0x0f, 0x9e, 0xf8, 0x3b, 0x00, 0x31, 0xf6, 0xfd, 0x2d, 0x3b,
+0xfc, 0x2f, 0x3c, 0xcc, 0xcf, 0x67, 0x0a, 0xa8, 0x98, 0x0f, 0x60, 0x86,
+0xa8, 0xd9, 0x79, 0xbc, 0xa4, 0x29, 0xc3, 0x30, 0x0a, 0xcd, 0xeb, 0x63,
+0x91, 0x48, 0x64, 0x31, 0xe6, 0xb5, 0x6c, 0xdb, 0x26, 0xf0, 0xfe, 0x63,
+0x38, 0xc3, 0xa7, 0x29, 0xc4, 0x4b, 0xa5, 0x41, 0x29, 0x74, 0x19, 0xf9,
+0x9f, 0xc1, 0x34, 0xce, 0xc7, 0x76, 0x75, 0xb4, 0x80, 0x52, 0xd2, 0xbf,
+0xe0, 0x23, 0x7c, 0x30, 0x15, 0x14, 0xa0, 0x72, 0xb3, 0x78, 0xe9, 0x04,
+0x45, 0xe4, 0xcd, 0x2f, 0x30, 0x97, 0xcd, 0x66, 0x17, 0x61, 0x5e, 0x4b,
+0x97, 0x87, 0xca, 0xa5, 0x29, 0x46, 0xda, 0x96, 0x2f, 0x13, 0xe1, 0x8f,
+0xbe, 0x79, 0x14, 0xfc, 0xbd, 0x4e, 0x04, 0x48, 0x21, 0x44, 0x1b, 0x73,
+0x38, 0x99, 0x1c, 0xbd, 0x67, 0xaf, 0xd2, 0x7d, 0xf2, 0x32, 0x13, 0x7d,
+0x09, 0x5c, 0xc7, 0xa5, 0x14, 0xde, 0xcc, 0x00, 0x45, 0xe4, 0xcd, 0x2f,
+0x30, 0x98, 0x4c, 0x26, 0x17, 0x63, 0x5e, 0xcb, 0xb2, 0x2c, 0xdc, 0xa9,
+0x6e, 0x16, 0x60, 0x1a, 0xbe, 0x4c, 0xb4, 0x60, 0xd0, 0x7f, 0x6a, 0x7d,
+0x76, 0x3e, 0x1c, 0x90, 0x04, 0x50, 0x4a, 0x71, 0xe6, 0xd0, 0x05, 0xc6,
+0x7b, 0xc6, 0xc9, 0xcd, 0x66, 0x49, 0x0e, 0x26, 0x48, 0xf6, 0x8d, 0x53,
+0x8a, 0xdc, 0x44, 0xf7, 0x62, 0xcc, 0xeb, 0x71, 0x7a, 0x7a, 0x1a, 0x55,
+0x7c, 0x7e, 0xa1, 0xf4, 0x35, 0x6c, 0xa9, 0x10, 0x46, 0x84, 0x92, 0x08,
+0xc1, 0x1c, 0x4f, 0x15, 0x3e, 0x72, 0x4b, 0x50, 0x9d, 0x00, 0x53, 0x23,
+0xd3, 0x08, 0x3c, 0xec, 0x80, 0x81, 0x75, 0x4d, 0xb6, 0x89, 0xba, 0x76,
+0xf1, 0x54, 0x86, 0x62, 0x32, 0xdd, 0x2f, 0x2f, 0xca, 0x7c, 0xbe, 0x0f,
+0x04, 0xba, 0x3f, 0x0a, 0xcf, 0x2f, 0x30, 0x1f, 0x0e, 0x87, 0x09, 0xd9,
+0x92, 0x48, 0xcb, 0x17, 0xb1, 0xab, 0x36, 0xf0, 0x01, 0x9c, 0xa1, 0x00,
+0xa9, 0x24, 0xba, 0x9b, 0x33, 0xd3, 0x59, 0x02, 0x73, 0xe6, 0xed, 0x80,
+0xa9, 0x77, 0x40, 0xc3, 0x92, 0xb8, 0x33, 0xb3, 0x14, 0xe3, 0x8c, 0xbe,
+0x47, 0x6e, 0xa2, 0xeb, 0x17, 0x98, 0xd7, 0xd2, 0xb7, 0x51, 0xe5, 0x64,
+0x30, 0x72, 0x33, 0xba, 0x44, 0x4a, 0xcd, 0xbc, 0x94, 0x92, 0xda, 0x9a,
+0x28, 0xde, 0xf4, 0x30, 0x89, 0xf8, 0x18, 0x76, 0xc3, 0x36, 0x3f, 0xc4,
+0x46, 0x4a, 0xe1, 0x09, 0xc6, 0x28, 0x40, 0xd6, 0xde, 0xdd, 0xf1, 0x03,
+0x14, 0x47, 0x62, 0x8d, 0xd5, 0x84, 0x22, 0x01, 0xbd, 0x02, 0xa6, 0x2d,
+0x31, 0x2d, 0x03, 0xc3, 0x97, 0x40, 0xa0, 0xb2, 0x0e, 0xc5, 0xa4, 0x3b,
+0x9f, 0x2b, 0x0a, 0x50, 0x6c, 0x5e, 0xcf, 0xbe, 0xde, 0x1b, 0xc8, 0xcd,
+0xa2, 0xd2, 0x93, 0x04, 0x49, 0x53, 0x5d, 0x55, 0x39, 0xdf, 0xf0, 0x4a,
+0x29, 0xfd, 0x78, 0xdd, 0xb8, 0x72, 0x05, 0x46, 0x3a, 0x8e, 0x72, 0xd2,
+0xcc, 0x8c, 0xf4, 0x63, 0x44, 0x1a, 0xb0, 0xa3, 0xbf, 0x89, 0x0c, 0xc4,
+0x28, 0x46, 0x2a, 0xf6, 0x50, 0x80, 0xd4, 0xa9, 0xe0, 0x61, 0x69, 0xc8,
+0x81, 0x86, 0xe6, 0x7a, 0x5d, 0x3a, 0xff, 0x67, 0x5e, 0x62, 0x98, 0x06,
+0xd2, 0x94, 0xe0, 0xba, 0x0b, 0x03, 0xfc, 0xf4, 0x15, 0xbc, 0xa1, 0x13,
+0xda, 0xc4, 0xcf, 0x31, 0xaf, 0x67, 0x36, 0x5a, 0x19, 0xc1, 0x4b, 0x27,
+0x51, 0xb9, 0x0c, 0x6a, 0x26, 0x8e, 0x91, 0xec, 0xa7, 0xa1, 0x2a, 0x48,
+0xd3, 0xb2, 0x06, 0xd6, 0x34, 0x2e, 0xe3, 0xa6, 0xea, 0x10, 0x8c, 0x5f,
+0xd2, 0xe7, 0xdc, 0xd4, 0x04, 0xfa, 0x4e, 0xa4, 0x5c, 0x10, 0x12, 0xbb,
+0xea, 0xa3, 0x94, 0xe0, 0xfe, 0xe4, 0x77, 0xb7, 0xd4, 0x50, 0x18, 0xa0,
+0x6e, 0xf7, 0xa9, 0x6e, 0xa4, 0xd8, 0x1e, 0xa9, 0xaf, 0x18, 0x8c, 0xad,
+0xad, 0xc7, 0x0c, 0x58, 0x18, 0x73, 0x21, 0xa4, 0x1f, 0x42, 0x6f, 0x1c,
+0x0b, 0x7e, 0x37, 0x28, 0x92, 0x27, 0xff, 0x92, 0x80, 0x9a, 0x06, 0x58,
+0x60, 0x1e, 0xd0, 0x9b, 0x9d, 0x98, 0x1d, 0x05, 0x37, 0xed, 0x2b, 0x83,
+0x72, 0xb3, 0xa4, 0x7b, 0xcf, 0x92, 0xe9, 0x39, 0x8d, 0x1b, 0xbf, 0x80,
+0x3b, 0x7c, 0x0e, 0x77, 0xb4, 0x0b, 0x32, 0x33, 0x3a, 0xe0, 0xc0, 0x99,
+0x37, 0x89, 0xad, 0x5e, 0x0f, 0x6e, 0x16, 0x00, 0x33, 0xdc, 0x84, 0x90,
+0x16, 0x45, 0x04, 0x33, 0x96, 0xf7, 0x60, 0x61, 0x00, 0x4d, 0xec, 0xee,
+0x77, 0x3a, 0x71, 0xd5, 0xed, 0x76, 0x24, 0xd8, 0x1d, 0x59, 0x5e, 0xa3,
+0x77, 0x3e, 0x61, 0x18, 0xbe, 0x24, 0x5c, 0x93, 0x10, 0x2c, 0x40, 0x01,
+0x13, 0x7d, 0x54, 0x97, 0x07, 0xf4, 0x03, 0x9a, 0x5f, 0xef, 0x5a, 0x65,
+0x65, 0x65, 0xac, 0x58, 0xb1, 0x9c, 0x0a, 0x2b, 0x8b, 0x3b, 0x3d, 0xc2,
+0xe4, 0xa9, 0x57, 0x70, 0xc6, 0xfa, 0xc9, 0xf4, 0x9e, 0xe3, 0xca, 0xde,
+0xbb, 0xe8, 0x7f, 0xf2, 0x4f, 0x75, 0x18, 0xbd, 0x2a, 0xae, 0x16, 0x5e,
+0x7a, 0x9a, 0xa1, 0xf7, 0x7e, 0x48, 0x20, 0x68, 0xea, 0xe3, 0x1a, 0x61,
+0x20, 0xed, 0xea, 0x52, 0x5f, 0xdb, 0xb2, 0x20, 0x80, 0x0e, 0x71, 0x5f,
+0xc7, 0x25, 0x66, 0xed, 0x8d, 0x86, 0x6d, 0x3c, 0x63, 0x47, 0x23, 0x18,
+0xd7, 0x42, 0x98, 0x12, 0xa4, 0xa4, 0x14, 0x56, 0xe5, 0x7a, 0x6d, 0xc4,
+0x9b, 0xe8, 0xa5, 0xcc, 0x19, 0x63, 0x49, 0x34, 0xcc, 0x8a, 0xba, 0x4a,
+0x96, 0xd6, 0x84, 0xb1, 0x92, 0x57, 0xf0, 0x12, 0x7d, 0x4c, 0xb6, 0xbf,
+0xc4, 0xe0, 0x77, 0x1f, 0x65, 0xe4, 0xa5, 0x7f, 0xc4, 0x08, 0x57, 0x62,
+0x45, 0x97, 0x12, 0x68, 0xdc, 0x00, 0xd7, 0x4c, 0xba, 0xbe, 0x72, 0x59,
+0xad, 0xab, 0xe7, 0xcf, 0x12, 0x6b, 0x6e, 0xd3, 0x1b, 0x99, 0x9a, 0x9d,
+0x24, 0x8f, 0x30, 0x2b, 0x4a, 0xf4, 0x81, 0x68, 0x67, 0x0e, 0x93, 0x22,
+0x62, 0x0f, 0xbe, 0x9d, 0x04, 0x1e, 0x88, 0x1f, 0xd8, 0xf2, 0x9a, 0x08,
+0x06, 0xfe, 0x15, 0xa5, 0xaa, 0x11, 0x82, 0x52, 0x98, 0xe5, 0x4d, 0xa0,
+0xdc, 0xb9, 0xd9, 0x4c, 0x43, 0x6a, 0x14, 0x94, 0xe7, 0x4b, 0xe9, 0x51,
+0xf9, 0x0a, 0x35, 0xb6, 0x10, 0x6c, 0xdc, 0x48, 0xf9, 0xc6, 0x3b, 0x30,
+0x82, 0x41, 0x56, 0x3d, 0x7a, 0x10, 0xe5, 0xe6, 0xf4, 0xac, 0xe3, 0x79,
+0x80, 0x47, 0x76, 0x7a, 0x9a, 0xa8, 0x7f, 0x3e, 0xdb, 0xff, 0x2e, 0xda,
+0xbc, 0x2a, 0xec, 0x39, 0x0f, 0x00, 0x85, 0xca, 0x08, 0x21, 0xff, 0x0b,
+0xa5, 0x2e, 0xab, 0xb4, 0xfd, 0xbd, 0x45, 0xfc, 0x5f, 0x48, 0xff, 0x90,
+0x59, 0xe6, 0x49, 0xef, 0xdf, 0x81, 0xed, 0x94, 0x20, 0xdc, 0xf4, 0x00,
+0x46, 0xb4, 0x09, 0x19, 0x8a, 0x82, 0x52, 0xda, 0x30, 0x79, 0xe1, 0xcd,
+0x19, 0x54, 0x20, 0x24, 0xca, 0x75, 0xb4, 0xb1, 0x7c, 0x38, 0xb4, 0x94,
+0x3e, 0xde, 0xd7, 0x75, 0x85, 0xda, 0x4d, 0x3b, 0x08, 0x4c, 0x9e, 0x87,
+0xcc, 0x14, 0x85, 0xcc, 0x0e, 0xbc, 0x8c, 0x9b, 0x1e, 0x06, 0xc5, 0x1b,
+0xb1, 0xdd, 0xa7, 0x7e, 0x87, 0x22, 0x24, 0x1f, 0x40, 0xf4, 0xde, 0xf6,
+0x7e, 0xff, 0xa1, 0xe9, 0x53, 0x02, 0x5e, 0x2c, 0xbd, 0x39, 0x4a, 0xbc,
+0xa9, 0xab, 0x28, 0x67, 0x16, 0x3d, 0xa3, 0xf3, 0xd2, 0x65, 0xf1, 0xb3,
+0x3a, 0xcf, 0xa6, 0x20, 0x97, 0x2f, 0x97, 0x8c, 0x96, 0xf2, 0xe5, 0x39,
+0x69, 0x86, 0xfa, 0xe3, 0xac, 0xdc, 0xf1, 0x10, 0xa3, 0x3f, 0x79, 0x6b,
+0x81, 0x79, 0x95, 0x9b, 0xc1, 0xcd, 0xc4, 0x01, 0x90, 0x86, 0xfc, 0x73,
+0x4a, 0x20, 0xf9, 0x85, 0x28, 0xa5, 0x66, 0xed, 0x07, 0x80, 0x01, 0x8a,
+0xf0, 0x72, 0x49, 0xf0, 0x5c, 0xbc, 0xe4, 0x20, 0xda, 0x94, 0xd6, 0xcf,
+0x9a, 0x93, 0x9c, 0x0e, 0xe3, 0xab, 0xa0, 0x59, 0xb5, 0xd2, 0xcc, 0x4e,
+0x8e, 0x32, 0x9a, 0xc8, 0x11, 0xf1, 0xcb, 0xcb, 0x2a, 0xaf, 0x22, 0x71,
+0xb1, 0x1d, 0x85, 0x02, 0x2d, 0x34, 0xd9, 0xc9, 0xf7, 0xe7, 0x56, 0x93,
+0x44, 0xf4, 0xee, 0xf6, 0xf6, 0x45, 0x07, 0x28, 0xd9, 0x17, 0x82, 0x33,
+0x0b, 0x02, 0x64, 0x46, 0x01, 0x50, 0x99, 0x24, 0xb9, 0x44, 0x2f, 0x38,
+0xa9, 0xf9, 0x15, 0x50, 0x05, 0x2b, 0xe0, 0xe9, 0x60, 0x69, 0x3c, 0xff,
+0xbc, 0xe7, 0xd7, 0x78, 0xbc, 0xa7, 0x07, 0x63, 0xe5, 0x36, 0x96, 0x6d,
+0xdb, 0xcd, 0xec, 0xd8, 0x55, 0xc6, 0x2f, 0x9d, 0x62, 0xf2, 0xf2, 0xbb,
+0xfa, 0xfe, 0xaf, 0xf2, 0x7f, 0x5e, 0x96, 0xdc, 0xd4, 0x85, 0x7c, 0xfd,
+0x7f, 0x0f, 0x4a, 0x63, 0xb2, 0x58, 0x14, 0x83, 0x14, 0xe1, 0x4c, 0x5d,
+0xc2, 0x2c, 0x5f, 0x0d, 0xc0, 0x40, 0x67, 0x17, 0xc9, 0xa1, 0x5e, 0xa2,
+0xcb, 0x9b, 0xa8, 0xa8, 0x89, 0x11, 0xa8, 0xa8, 0xc4, 0xb0, 0x02, 0x28,
+0x5c, 0x1d, 0x60, 0x7a, 0x74, 0x84, 0xac, 0x11, 0x25, 0xb4, 0x6c, 0x03,
+0x86, 0x17, 0x27, 0xb2, 0xbc, 0x79, 0xfe, 0x19, 0xad, 0x63, 0xdf, 0x67,
+0x71, 0xd3, 0x49, 0xf0, 0x72, 0x28, 0x69, 0x22, 0x84, 0x81, 0xe3, 0xf7,
+0x83, 0xf2, 0x1c, 0x50, 0x24, 0x6b, 0x77, 0x9f, 0xfe, 0xf2, 0x2f, 0x1d,
+0x40, 0x21, 0x7a, 0x04, 0x8a, 0x42, 0xdc, 0xd9, 0x01, 0xbd, 0x0a, 0x32,
+0x10, 0x63, 0xd9, 0xda, 0xd5, 0xa8, 0x75, 0xcd, 0x5c, 0xed, 0xee, 0x65,
+0x78, 0x64, 0x86, 0x9a, 0xd8, 0x06, 0x7f, 0x66, 0x3b, 0x88, 0x36, 0x6f,
+0x26, 0x50, 0xdf, 0x40, 0x76, 0xf6, 0x1c, 0xcb, 0x6e, 0xdb, 0x09, 0x40,
+0x7a, 0x6c, 0x90, 0xec, 0xd4, 0x28, 0x0a, 0xb8, 0x70, 0xf0, 0x71, 0xa6,
+0x07, 0x3a, 0x09, 0x46, 0xeb, 0x51, 0x80, 0x00, 0x72, 0x33, 0x3d, 0x64,
+0x13, 0x3f, 0xca, 0x17, 0xf0, 0x83, 0xe8, 0x3a, 0x2a, 0x8d, 0x64, 0xb1,
+0x28, 0xef, 0x0c, 0x25, 0x48, 0x0f, 0x1f, 0x45, 0xcf, 0x14, 0x20, 0x94,
+0xc3, 0xd2, 0xa6, 0x9b, 0x58, 0xb9, 0x76, 0x29, 0xce, 0xc8, 0x45, 0x2a,
+0x9b, 0x5a, 0x70, 0xa6, 0x27, 0x29, 0xab, 0x5d, 0xc1, 0xd2, 0x4f, 0x7c,
+0x86, 0xe1, 0x1f, 0xbf, 0x0e, 0x80, 0xe7, 0x3a, 0xbc, 0xff, 0xf4, 0xd7,
+0x79, 0xfd, 0xa1, 0x66, 0x26, 0xfe, 0xe7, 0xc7, 0x00, 0x54, 0x2c, 0x5b,
+0x8d, 0xbe, 0x29, 0xa4, 0xfa, 0xc8, 0x0c, 0x1f, 0xc9, 0x7b, 0x3e, 0x55,
+0x7b, 0x6f, 0xc7, 0x7f, 0xdc, 0xb0, 0xf7, 0x03, 0x63, 0x07, 0x5a, 0xbf,
+0xa9, 0x04, 0xdf, 0x40, 0x70, 0x59, 0x28, 0x4e, 0x28, 0xb8, 0x0f, 0xc0,
+0x08, 0xd4, 0x12, 0xa8, 0xdf, 0x8e, 0xb4, 0x2a, 0xf2, 0x35, 0x8b, 0x52,
+0xfa, 0x49, 0x93, 0xc1, 0x9f, 0xf6, 0x32, 0xda, 0xdd, 0x45, 0xd5, 0xaa,
+0x8d, 0x24, 0xfb, 0x2f, 0xf9, 0xea, 0xd4, 0xa6, 0x0b, 0xd0, 0x3b, 0x7e,
+0xdb, 0xe7, 0x1f, 0x27, 0x12, 0x1c, 0xf3, 0xcd, 0x1f, 0xcb, 0x37, 0x72,
+0x7f, 0x2c, 0xe9, 0xad, 0xe2, 0xe1, 0xd3, 0xce, 0x8d, 0x0a, 0xa0, 0x19,
+0x39, 0xd8, 0x56, 0x3f, 0x55, 0x35, 0x36, 0xb1, 0xe6, 0x77, 0xbb, 0x32,
+0xa3, 0xcf, 0xb5, 0x3e, 0x8c, 0xc7, 0x93, 0x80, 0x14, 0xd2, 0x22, 0x10,
+0xdb, 0x8a, 0x19, 0xf9, 0xc8, 0x5c, 0x00, 0x17, 0xe5, 0xe5, 0xc0, 0x73,
+0x98, 0x99, 0x9a, 0xe1, 0xcc, 0xf3, 0x4f, 0x33, 0x3d, 0x78, 0x85, 0x62,
+0x82, 0xd5, 0x75, 0xb4, 0xdc, 0xfd, 0x39, 0x2a, 0xad, 0x4e, 0x72, 0x53,
+0x5d, 0x79, 0xf3, 0xe3, 0x63, 0xe1, 0xa9, 0xc6, 0x75, 0x77, 0x5e, 0x4c,
+0xfe, 0xbf, 0xbf, 0x62, 0x1a, 0x7e, 0xae, 0xad, 0xcd, 0xf0, 0xbc, 0xa3,
+0x40, 0x08, 0xbd, 0x3b, 0xaf, 0xc2, 0xaa, 0x5a, 0x8f, 0xb4, 0x6b, 0x50,
+0x80, 0xde, 0x91, 0x3d, 0x0f, 0x4f, 0x41, 0xef, 0x4f, 0xce, 0xd1, 0xd7,
+0xfe, 0x3a, 0xb9, 0x74, 0x8a, 0xf2, 0x86, 0x46, 0x1a, 0x36, 0xde, 0x4a,
+0x5d, 0x43, 0x1a, 0x4f, 0xd7, 0xfb, 0x3c, 0x5d, 0x6e, 0x2e, 0xf3, 0x5b,
+0xf5, 0xf7, 0x9f, 0x1d, 0xf9, 0xd5, 0xbd, 0x23, 0xfb, 0x97, 0x96, 0x72,
+0x51, 0x1d, 0xde, 0x0f, 0xea, 0x0f, 0x00, 0x01, 0x80, 0x30, 0x31, 0x82,
+0x75, 0xc8, 0xb2, 0x25, 0x48, 0xab, 0x5a, 0xbf, 0x13, 0xc0, 0x9b, 0xdb,
+0xf0, 0x54, 0x16, 0x77, 0x76, 0x04, 0x2f, 0x9b, 0x28, 0xfa, 0xad, 0xc2,
+0xbe, 0x9a, 0x5d, 0xa7, 0xbe, 0xf6, 0x2b, 0x7f, 0xc9, 0x97, 0x67, 0xe2,
+0xc0, 0xa6, 0x95, 0xae, 0xb4, 0xbe, 0xaf, 0x94, 0x6a, 0x05, 0xe4, 0xa2,
+0x0c, 0x80, 0xe3, 0x29, 0x8e, 0x92, 0x95, 0x5f, 0xa8, 0xdd, 0xd3, 0xde,
+0xf5, 0xeb, 0x78, 0x4b, 0xb9, 0x90, 0x17, 0x84, 0x11, 0x77, 0x5b, 0xf7,
+0x48, 0xa5, 0x1e, 0x52, 0xd0, 0x0c, 0x84, 0x00, 0x7b, 0x2e, 0x94, 0x03,
+0x8c, 0x03, 0x7d, 0x0a, 0x5e, 0xac, 0xdd, 0xd5, 0xb1, 0x4f, 0xd7, 0xd9,
+0x87, 0xe4, 0x7f, 0x01, 0x9c, 0x0b, 0xc5, 0xc1, 0xee, 0xb9, 0xae, 0x42,
+0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+])
+
+def front():
+ global content
+ content = "<html><body><center><h2>Hello friend. Have you seen this guy?</h2>\n<br><br><img src=\"/image.png\"><br><br><form action=/ method=post><input type=radio name=q1 value=yes>Why yes I have<br><input type=radio name=q1 value=no>No, who's he?<br><input type=radio name=q1 value=who>Canada<hr width='20%%'><input type=submit></form></center></body></html>"
+
+def points():
+ global content
+ content = "<html><body><center><h2>Correct!</h2>\n<br><br><a href='http://monkey-project.com'>Visit him.</a></center></body></html>"
+
+def wrong():
+ global content
+ content = "<html><body><center><h2>I'm a sad puppy.</h2>\n</center></body></html>"
+
+def listf(vhost, url, get, get_len, post, post_len, header):
+ global content
+ global image
+ ret = {}
+ if url == '/image.png':
+ ret['content'] = image
+ ret['content_len'] = len(ret['content'])
+ ret['return'] = 1
+ return ret
+ if post is None:
+ front()
+ elif 'q1=who' in post or 'q1=yes' in post:
+ points()
+ else:
+ wrong()
+
+ ret['content'] = content
+ ret['content_len'] = len(ret['content'])
+ ret['return'] = 1
+
+ return ret
+
+monkey.init(None, 0, 0, None)
+monkey.set_callback('data', listf)
+monkey.start()
+raw_input("Press enter to stop the server...")
+monkey.stop()
diff --git a/fluent-bit/lib/monkey/fuzz/CMakeLists.txt b/fluent-bit/lib/monkey/fuzz/CMakeLists.txt
new file mode 100644
index 000000000..48100f5f3
--- /dev/null
+++ b/fluent-bit/lib/monkey/fuzz/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(src
+ mk_fuzz_me.c)
+
+add_executable(mk_fuzz_me ${src})
+target_link_libraries(mk_fuzz_me monkey-core-static)
+
+set(src
+ mk_check.c)
+
+add_executable(mk_check ${src})
+target_link_libraries(mk_check monkey-core-static)
diff --git a/fluent-bit/lib/monkey/fuzz/mk_check.c b/fluent-bit/lib/monkey/fuzz/mk_check.c
new file mode 100644
index 000000000..acae6cba0
--- /dev/null
+++ b/fluent-bit/lib/monkey/fuzz/mk_check.c
@@ -0,0 +1,113 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#include <monkey/mk_lib.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+#define API_ADDR "127.0.0.1"
+#define API_PORT "8080"
+
+/* Main context set as global so the signal handler can use it */
+mk_ctx_t *ctx;
+
+void cb_main(mk_request_t *request, void *data)
+{
+ (void) data;
+
+ mk_http_status(request, 200);
+ mk_http_header(request, "X-Monkey", 8, "OK", 2);
+
+ mk_http_send(request, ":)\n", 3, NULL);
+ mk_http_done(request);
+}
+
+void cb_test_chunks(mk_request_t *request, void *data)
+{
+ int i = 0;
+ int len;
+ char tmp[32];
+ (void) data;
+
+ mk_http_status(request, 200);
+ mk_http_header(request, "X-Monkey", 8, "OK", 2);
+
+ for (i = 0; i < 1000; i++) {
+ len = snprintf(tmp, sizeof(tmp) -1, "test-chunk %6i\n ", i);
+ mk_http_send(request, tmp, len, NULL);
+ }
+ mk_http_done(request);
+}
+
+void cb_test_big_chunk(mk_request_t *request, void *data)
+{
+ size_t chunk_size = 1024000000;
+ char *chunk;
+ (void) data;
+
+ mk_http_status(request, 200);
+ mk_http_header(request, "X-Monkey", 8, "OK", 2);
+
+ chunk = calloc(1, chunk_size);
+ mk_http_send(request, chunk, chunk_size, NULL);
+ free(chunk);
+ mk_http_done(request);
+}
+
+
+static void signal_handler(int signal)
+{
+ write(STDERR_FILENO, "[engine] caught signal\n", 23);
+
+ switch (signal) {
+ case SIGTERM:
+ case SIGINT:
+ mk_stop(ctx);
+ mk_destroy(ctx);
+ _exit(EXIT_SUCCESS);
+ default:
+ break;
+ }
+}
+
+static void signal_init()
+{
+ signal(SIGINT, &signal_handler);
+ signal(SIGTERM, &signal_handler);
+}
+
+int main()
+{
+ int vid;
+
+ signal_init();
+
+ ctx = mk_create();
+ if (!ctx) {
+ return -1;
+ }
+
+ mk_config_set(ctx,
+ "Listen", API_PORT,
+ NULL);
+
+ vid = mk_vhost_create(ctx, NULL);
+ mk_vhost_set(ctx, vid,
+ "Name", "monotop",
+ NULL);
+ mk_vhost_handler(ctx, vid, "/test_chunks", cb_test_chunks, NULL);
+ mk_vhost_handler(ctx, vid, "/test_big_chunk", cb_test_big_chunk, NULL);
+ mk_vhost_handler(ctx, vid, "/", cb_main, NULL);
+
+ mk_info("Service: http://%s:%s/test_chunks", API_ADDR, API_PORT);
+ mk_start(ctx);
+
+ sleep(3600);
+
+ mk_stop(ctx);
+ mk_destroy(ctx);
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/fuzz/mk_fuzz_me.c b/fluent-bit/lib/monkey/fuzz/mk_fuzz_me.c
new file mode 100644
index 000000000..0a88d3f1f
--- /dev/null
+++ b/fluent-bit/lib/monkey/fuzz/mk_fuzz_me.c
@@ -0,0 +1,143 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#include <monkey/mk_lib.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+#define API_ADDR "127.0.0.1"
+#define API_PORT "8080"
+
+/* Main context set as global so the signal handler can use it */
+mk_ctx_t *ctx;
+
+void cb_main(mk_request_t *request, void *data)
+{
+ (void) data;
+
+ mk_http_status(request, 200);
+ mk_http_header(request, "X-Monkey", 8, "OK", 2);
+ mk_http_send(request, ":)\n", 3, NULL);
+ mk_http_done(request);
+}
+
+void cb_test_chunks(mk_request_t *request, void *data)
+{
+ int i = 0;
+ int len;
+ char tmp[32];
+ (void) data;
+
+ mk_http_status(request, 200);
+ mk_http_header(request, "X-Monkey", 8, "OK", 2);
+
+ for (i = 0; i < 1000; i++) {
+ len = snprintf(tmp, sizeof(tmp) -1, "test-chunk %6i\n ", i);
+ mk_http_send(request, tmp, len, NULL);
+ }
+ mk_http_done(request);
+}
+
+void cb_test_big_chunk(mk_request_t *request, void *data)
+{
+ size_t chunk_size = 1024000000;
+ char *chunk;
+ (void) data;
+
+ mk_http_status(request, 200);
+ mk_http_header(request, "X-Monkey", 8, "OK", 2);
+
+ chunk = calloc(1, chunk_size);
+ mk_http_send(request, chunk, chunk_size, NULL);
+ free(chunk);
+ mk_http_done(request);
+}
+
+
+static void signal_handler(int signal)
+{
+ write(STDERR_FILENO, "[engine] caught signal\n", 23);
+
+ switch (signal) {
+ case SIGTERM:
+ case SIGINT:
+ mk_stop(ctx);
+ mk_destroy(ctx);
+ _exit(EXIT_SUCCESS);
+ default:
+ break;
+ }
+}
+
+static void signal_init()
+{
+ signal(SIGINT, &signal_handler);
+ signal(SIGTERM, &signal_handler);
+}
+
+static void cb_queue_message(mk_mq_t *queue, void *data, size_t size, void *ctx)
+{
+ size_t i;
+ char *buf;
+ (void) ctx;
+ (void) queue;
+
+ printf("=== cb queue message === \n");
+ printf(" => %lu bytes\n", size);
+ printf(" => ");
+
+ buf = data;
+ for (i = 0; i < size; i++) {
+ printf("%c", buf[i]);
+ }
+ printf("\n\n");
+}
+
+
+HFND_FUZZING_ENTRY_FUNCTION(int argc, const char *const *argv)
+{
+ int i = 0;
+ int len;
+ int vid;
+ int qid;
+ char msg[800000];
+
+ signal_init();
+
+ ctx = mk_create();
+ if (!ctx) {
+ return -1;
+ }
+
+ /* Create a message queue and a callback for each message */
+ qid = mk_mq_create(ctx, "/data", cb_queue_message, NULL);
+
+ mk_config_set(ctx,
+ "Listen", API_PORT,
+ NULL);
+
+ vid = mk_vhost_create(ctx, NULL);
+ mk_vhost_set(ctx, vid,
+ "Name", "monotop",
+ NULL);
+ mk_vhost_handler(ctx, vid, "/test_chunks", cb_test_chunks, NULL);
+ mk_vhost_handler(ctx, vid, "/test_big_chunk", cb_test_big_chunk, NULL);
+ mk_vhost_handler(ctx, vid, "/", cb_main, NULL);
+
+ mk_info("Service: http://%s:%s/test_chunks", API_ADDR, API_PORT);
+ mk_start(ctx);
+
+ for (i = 0; i < 5; i++) {
+ len = snprintf(msg, sizeof(msg) - 1, "[...] message ID: %i\n", i);
+ mk_mq_send(ctx, qid, &msg, len);
+ }
+
+ sleep(3600);
+
+ mk_stop(ctx);
+ mk_destroy(ctx);
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/htdocs/CMakeLists.txt b/fluent-bit/lib/monkey/htdocs/CMakeLists.txt
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/CMakeLists.txt
@@ -0,0 +1 @@
+
diff --git a/fluent-bit/lib/monkey/htdocs/css/bootstrap.min.css b/fluent-bit/lib/monkey/htdocs/css/bootstrap.min.css
new file mode 100644
index 000000000..052f28afd
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/css/bootstrap.min.css
@@ -0,0 +1,7 @@
+@import url("//fonts.googleapis.com/css?family=Lato:400,700,400italic");/*!
+ * bootswatch v3.3.4+1
+ * Homepage: http://bootswatch.com
+ * Copyright 2012-2015 Thomas Park
+ * Licensed under MIT
+ * Based on Bootstrap
+*//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,*:before,*:after{background:transparent !important;color:#000 !important;-webkit-box-shadow:none !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff !important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before,.glyphicon-eur:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:15px;line-height:1.42857143;color:#2c3e50;background-color:#ffffff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#18bc9c;text-decoration:none}a:hover,a:focus{color:#18bc9c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#ffffff;border:1px solid #ecf0f1;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:21px;margin-bottom:21px;border:0;border-top:1px solid #ecf0f1}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role="button"]{cursor:pointer}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:400;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#b4bcc2}h1,.h1,h2,.h2,h3,.h3{margin-top:21px;margin-bottom:10.5px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10.5px;margin-bottom:10.5px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:39px}h2,.h2{font-size:32px}h3,.h3{font-size:26px}h4,.h4{font-size:19px}h5,.h5{font-size:15px}h6,.h6{font-size:13px}p{margin:0 0 10.5px}.lead{margin-bottom:21px;font-size:17px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:22.5px}}small,.small{font-size:86%}mark,.mark{background-color:#f39c12;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#b4bcc2}.text-primary{color:#2c3e50}a.text-primary:hover{color:#1a242f}.text-success{color:#ffffff}a.text-success:hover{color:#e6e6e6}.text-info{color:#ffffff}a.text-info:hover{color:#e6e6e6}.text-warning{color:#ffffff}a.text-warning:hover{color:#e6e6e6}.text-danger{color:#ffffff}a.text-danger:hover{color:#e6e6e6}.bg-primary{color:#fff;background-color:#2c3e50}a.bg-primary:hover{background-color:#1a242f}.bg-success{background-color:#18bc9c}a.bg-success:hover{background-color:#128f76}.bg-info{background-color:#3498db}a.bg-info:hover{background-color:#217dbb}.bg-warning{background-color:#f39c12}a.bg-warning:hover{background-color:#c87f0a}.bg-danger{background-color:#e74c3c}a.bg-danger:hover{background-color:#d62c1a}.page-header{padding-bottom:9.5px;margin:42px 0 21px;border-bottom:1px solid transparent}ul,ol{margin-top:0;margin-bottom:10.5px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:21px}dt,dd{line-height:1.42857143}dt{font-weight:bold}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #b4bcc2}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10.5px 21px;margin:0 0 21px;font-size:18.75px;border-left:5px solid #ecf0f1}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#b4bcc2}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #ecf0f1;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:21px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#ffffff;background-color:#333333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25)}kbd kbd{padding:0;font-size:100%;font-weight:bold;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:10px;margin:0 0 10.5px;font-size:14px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;color:#7b8a8b;background-color:#ecf0f1;border:1px solid #cccccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0%}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0%}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0%}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0%}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#b4bcc2;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:21px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ecf0f1}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ecf0f1}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ecf0f1}.table .table{background-color:#ffffff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ecf0f1}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ecf0f1}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#ecf0f1}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#ecf0f1}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#dde4e6}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#18bc9c}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#15a589}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#3498db}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#258cd1}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#f39c12}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#e08e0b}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#e74c3c}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#e43725}.table-responsive{overflow-x:auto;min-height:0.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15.75px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ecf0f1}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:21px;font-size:22.5px;line-height:inherit;color:#2c3e50;border:0;border-bottom:1px solid transparent}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}input[type="range"]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:11px;font-size:15px;line-height:1.42857143;color:#2c3e50}.form-control{display:block;width:100%;height:43px;padding:10px 15px;font-size:15px;line-height:1.42857143;color:#2c3e50;background-color:#ffffff;background-image:none;border:1px solid #dce4ec;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#2c3e50;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(44,62,80,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(44,62,80,0.6)}.form-control::-moz-placeholder{color:#acb6c0;opacity:1}.form-control:-ms-input-placeholder{color:#acb6c0}.form-control::-webkit-input-placeholder{color:#acb6c0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#ecf0f1;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type="search"]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type="date"],input[type="time"],input[type="datetime-local"],input[type="month"]{line-height:43px}input[type="date"].input-sm,input[type="time"].input-sm,input[type="datetime-local"].input-sm,input[type="month"].input-sm,.input-group-sm input[type="date"],.input-group-sm input[type="time"],.input-group-sm input[type="datetime-local"],.input-group-sm input[type="month"]{line-height:33px}input[type="date"].input-lg,input[type="time"].input-lg,input[type="datetime-local"].input-lg,input[type="month"].input-lg,.input-group-lg input[type="date"],.input-group-lg input[type="time"],.input-group-lg input[type="datetime-local"],.input-group-lg input[type="month"]{line-height:64px}}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{min-height:21px;padding-left:20px;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{position:absolute;margin-left:-20px;margin-top:4px \9}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:normal;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"].disabled,input[type="checkbox"].disabled,fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:11px;padding-bottom:11px;margin-bottom:0;min-height:36px}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.input-sm{height:33px;padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}select.input-sm{height:33px;line-height:33px}textarea.input-sm,select[multiple].input-sm{height:auto}.form-group-sm .form-control{height:33px;padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}select.form-group-sm .form-control{height:33px;line-height:33px}textarea.form-group-sm .form-control,select[multiple].form-group-sm .form-control{height:auto}.form-group-sm .form-control-static{height:33px;padding:6px 9px;font-size:13px;line-height:1.5;min-height:34px}.input-lg{height:64px;padding:18px 27px;font-size:19px;line-height:1.3333333;border-radius:6px}select.input-lg{height:64px;line-height:64px}textarea.input-lg,select[multiple].input-lg{height:auto}.form-group-lg .form-control{height:64px;padding:18px 27px;font-size:19px;line-height:1.3333333;border-radius:6px}select.form-group-lg .form-control{height:64px;line-height:64px}textarea.form-group-lg .form-control,select[multiple].form-group-lg .form-control{height:auto}.form-group-lg .form-control-static{height:64px;padding:18px 27px;font-size:19px;line-height:1.3333333;min-height:40px}.has-feedback{position:relative}.has-feedback .form-control{padding-right:53.75px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:43px;height:43px;line-height:43px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:64px;height:64px;line-height:64px}.input-sm+.form-control-feedback{width:33px;height:33px;line-height:33px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label{color:#ffffff}.has-success .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-success .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#18bc9c}.has-success .form-control-feedback{color:#ffffff}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label{color:#ffffff}.has-warning .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-warning .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#f39c12}.has-warning .form-control-feedback{color:#ffffff}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label{color:#ffffff}.has-error .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-error .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#e74c3c}.has-error .form-control-feedback{color:#ffffff}.has-feedback label~.form-control-feedback{top:26px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#597ea2}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:11px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:32px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:11px}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:24.9999994px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:7px}}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:10px 15px;font-size:15px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#ffffff;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#ffffff;background-color:#95a5a6;border-color:#95a5a6}.btn-default:hover,.btn-default:focus,.btn-default.focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#ffffff;background-color:#798d8f;border-color:#74898a}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#95a5a6;border-color:#95a5a6}.btn-default .badge{color:#95a5a6;background-color:#ffffff}.btn-primary{color:#ffffff;background-color:#2c3e50;border-color:#2c3e50}.btn-primary:hover,.btn-primary:focus,.btn-primary.focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#ffffff;background-color:#1a242f;border-color:#161f29}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#2c3e50;border-color:#2c3e50}.btn-primary .badge{color:#2c3e50;background-color:#ffffff}.btn-success{color:#ffffff;background-color:#18bc9c;border-color:#18bc9c}.btn-success:hover,.btn-success:focus,.btn-success.focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#ffffff;background-color:#128f76;border-color:#11866f}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#18bc9c;border-color:#18bc9c}.btn-success .badge{color:#18bc9c;background-color:#ffffff}.btn-info{color:#ffffff;background-color:#3498db;border-color:#3498db}.btn-info:hover,.btn-info:focus,.btn-info.focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#ffffff;background-color:#217dbb;border-color:#2077b2}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#3498db;border-color:#3498db}.btn-info .badge{color:#3498db;background-color:#ffffff}.btn-warning{color:#ffffff;background-color:#f39c12;border-color:#f39c12}.btn-warning:hover,.btn-warning:focus,.btn-warning.focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#ffffff;background-color:#c87f0a;border-color:#be780a}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f39c12;border-color:#f39c12}.btn-warning .badge{color:#f39c12;background-color:#ffffff}.btn-danger{color:#ffffff;background-color:#e74c3c;border-color:#e74c3c}.btn-danger:hover,.btn-danger:focus,.btn-danger.focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#ffffff;background-color:#d62c1a;border-color:#cd2a19}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#e74c3c;border-color:#e74c3c}.btn-danger .badge{color:#e74c3c;background-color:#ffffff}.btn-link{color:#18bc9c;font-weight:normal;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#18bc9c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#b4bcc2;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:18px 27px;font-size:19px;line-height:1.3333333;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:13px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height, visibility;-o-transition-property:height, visibility;transition-property:height, visibility;-webkit-transition-duration:0.35s;-o-transition-duration:0.35s;transition-duration:0.35s;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-right:4px solid transparent;border-left:4px solid transparent}.dropup,.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:15px;text-align:left;background-color:#ffffff;border:1px solid #cccccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);-webkit-background-clip:padding-box;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.42857143;color:#7b8a8b;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#ffffff;background-color:#2c3e50}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#ffffff;text-decoration:none;outline:0;background-color:#2c3e50}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#b4bcc2}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:13px;line-height:1.42857143;color:#b4bcc2;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:4px;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle="buttons"]>.btn input[type="radio"],[data-toggle="buttons"]>.btn-group>.btn input[type="radio"],[data-toggle="buttons"]>.btn input[type="checkbox"],[data-toggle="buttons"]>.btn-group>.btn input[type="checkbox"]{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:64px;padding:18px 27px;font-size:19px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:64px;line-height:64px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:33px;padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:33px;line-height:33px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:10px 15px;font-size:15px;font-weight:normal;line-height:1;color:#2c3e50;text-align:center;background-color:#ecf0f1;border:1px solid #dce4ec;border-radius:4px}.input-group-addon.input-sm{padding:6px 9px;font-size:13px;border-radius:3px}.input-group-addon.input-lg{padding:18px 27px;font-size:19px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#ecf0f1}.nav>li.disabled>a{color:#b4bcc2}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#b4bcc2;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#ecf0f1;border-color:#18bc9c}.nav .nav-divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ecf0f1}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#ecf0f1 #ecf0f1 #ecf0f1}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#2c3e50;background-color:#ffffff;border:1px solid #ecf0f1;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ecf0f1}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ecf0f1;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#ffffff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#ffffff;background-color:#2c3e50}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ecf0f1}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ecf0f1;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#ffffff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:60px;margin-bottom:21px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block !important;height:auto !important;padding-bottom:0;overflow:visible !important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:19.5px 15px;font-size:19px;line-height:21px;height:60px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:13px;margin-bottom:13px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:9.75px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:21px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:21px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:19.5px;padding-bottom:19.5px}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);margin-top:8.5px;margin-bottom:8.5px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8.5px;margin-bottom:8.5px}.navbar-btn.btn-sm{margin-top:13.5px;margin-bottom:13.5px}.navbar-btn.btn-xs{margin-top:19px;margin-bottom:19px}.navbar-text{margin-top:19.5px;margin-bottom:19.5px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}}@media (min-width:768px){.navbar-left{float:left !important}.navbar-right{float:right !important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#2c3e50;border-color:transparent}.navbar-default .navbar-brand{color:#ffffff}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#18bc9c;background-color:transparent}.navbar-default .navbar-text{color:#777777}.navbar-default .navbar-nav>li>a{color:#ffffff}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#18bc9c;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#ffffff;background-color:#1a242f}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#cccccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#1a242f}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#1a242f}.navbar-default .navbar-toggle .icon-bar{background-color:#ffffff}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:transparent}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#1a242f;color:#ffffff}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#ffffff}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#18bc9c;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#ffffff;background-color:#1a242f}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#cccccc;background-color:transparent}}.navbar-default .navbar-link{color:#ffffff}.navbar-default .navbar-link:hover{color:#18bc9c}.navbar-default .btn-link{color:#ffffff}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#18bc9c}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#cccccc}.navbar-inverse{background-color:#18bc9c;border-color:transparent}.navbar-inverse .navbar-brand{color:#ffffff}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#2c3e50;background-color:transparent}.navbar-inverse .navbar-text{color:#ffffff}.navbar-inverse .navbar-nav>li>a{color:#ffffff}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#2c3e50;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#ffffff;background-color:#15a589}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#cccccc;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#128f76}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#128f76}.navbar-inverse .navbar-toggle .icon-bar{background-color:#ffffff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#149c82}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#15a589;color:#ffffff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#ffffff}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#2c3e50;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#ffffff;background-color:#15a589}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#cccccc;background-color:transparent}}.navbar-inverse .navbar-link{color:#ffffff}.navbar-inverse .navbar-link:hover{color:#2c3e50}.navbar-inverse .btn-link{color:#ffffff}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#2c3e50}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#cccccc}.breadcrumb{padding:8px 15px;margin-bottom:21px;list-style:none;background-color:#ecf0f1;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#cccccc}.breadcrumb>.active{color:#95a5a6}.pagination{display:inline-block;padding-left:0;margin:21px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:10px 15px;line-height:1.42857143;text-decoration:none;color:#ffffff;background-color:#18bc9c;border:1px solid transparent;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#ffffff;background-color:#0f7864;border-color:transparent}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#ffffff;background-color:#0f7864;border-color:transparent;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#ecf0f1;background-color:#3be6c4;border-color:transparent;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:18px 27px;font-size:19px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:6px 9px;font-size:13px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:21px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#18bc9c;border:1px solid transparent;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#0f7864}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#ffffff;background-color:#18bc9c;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#ffffff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#ffffff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#95a5a6}.label-default[href]:hover,.label-default[href]:focus{background-color:#798d8f}.label-primary{background-color:#2c3e50}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#1a242f}.label-success{background-color:#18bc9c}.label-success[href]:hover,.label-success[href]:focus{background-color:#128f76}.label-info{background-color:#3498db}.label-info[href]:hover,.label-info[href]:focus{background-color:#217dbb}.label-warning{background-color:#f39c12}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#c87f0a}.label-danger{background-color:#e74c3c}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#d62c1a}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:13px;font-weight:bold;color:#ffffff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#2c3e50;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge,.btn-group-xs>.btn .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#ffffff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#2c3e50;background-color:#ffffff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#ecf0f1}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:23px;font-weight:200}.jumbotron>hr{border-top-color:#cfd9db}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:67.5px}}.thumbnail{display:block;padding:4px;margin-bottom:21px;line-height:1.42857143;background-color:#ffffff;border:1px solid #ecf0f1;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#18bc9c}.thumbnail .caption{padding:9px;color:#2c3e50}.alert{padding:15px;margin-bottom:21px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#18bc9c;border-color:#18bc9c;color:#ffffff}.alert-success hr{border-top-color:#15a589}.alert-success .alert-link{color:#e6e6e6}.alert-info{background-color:#3498db;border-color:#3498db;color:#ffffff}.alert-info hr{border-top-color:#258cd1}.alert-info .alert-link{color:#e6e6e6}.alert-warning{background-color:#f39c12;border-color:#f39c12;color:#ffffff}.alert-warning hr{border-top-color:#e08e0b}.alert-warning .alert-link{color:#e6e6e6}.alert-danger{background-color:#e74c3c;border-color:#e74c3c;color:#ffffff}.alert-danger hr{border-top-color:#e43725}.alert-danger .alert-link{color:#e6e6e6}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:21px;margin-bottom:21px;background-color:#ecf0f1;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0%;height:100%;font-size:13px;line-height:21px;color:#ffffff;text-align:center;background-color:#2c3e50;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#18bc9c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#3498db}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#f39c12}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#e74c3c}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{zoom:1;overflow:hidden}.media-body{width:10000px}.media-object{display:block}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-left,.media-right,.media-body{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#ffffff;border:1px solid #ecf0f1}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item{color:#555555}a.list-group-item .list-group-item-heading{color:#333333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;color:#555555;background-color:#ecf0f1}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{background-color:#ecf0f1;color:#b4bcc2;cursor:not-allowed}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#b4bcc2}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#ffffff;background-color:#2c3e50;border-color:#2c3e50}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#8aa4be}.list-group-item-success{color:#ffffff;background-color:#18bc9c}a.list-group-item-success{color:#ffffff}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#ffffff;background-color:#15a589}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-info{color:#ffffff;background-color:#3498db}a.list-group-item-info{color:#ffffff}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#ffffff;background-color:#258cd1}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-warning{color:#ffffff;background-color:#f39c12}a.list-group-item-warning{color:#ffffff}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#ffffff;background-color:#e08e0b}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-danger{color:#ffffff;background-color:#e74c3c}a.list-group-item-danger{color:#ffffff}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#ffffff;background-color:#e43725}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:21px;background-color:#ffffff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:17px;color:inherit}.panel-title>a,.panel-title>small,.panel-title>.small,.panel-title>small>a,.panel-title>.small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#ecf0f1;border-top:1px solid #ecf0f1;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table caption,.panel>.table-responsive>.table caption,.panel>.panel-collapse>.table caption{padding-left:15px;padding-right:15px}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-left-radius:3px;border-bottom-right-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ecf0f1}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:21px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body,.panel-group .panel-heading+.panel-collapse>.list-group{border-top:1px solid #ecf0f1}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ecf0f1}.panel-default{border-color:#ecf0f1}.panel-default>.panel-heading{color:#2c3e50;background-color:#ecf0f1;border-color:#ecf0f1}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ecf0f1}.panel-default>.panel-heading .badge{color:#ecf0f1;background-color:#2c3e50}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ecf0f1}.panel-primary{border-color:#2c3e50}.panel-primary>.panel-heading{color:#ffffff;background-color:#2c3e50;border-color:#2c3e50}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#2c3e50}.panel-primary>.panel-heading .badge{color:#2c3e50;background-color:#ffffff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#2c3e50}.panel-success{border-color:#18bc9c}.panel-success>.panel-heading{color:#ffffff;background-color:#18bc9c;border-color:#18bc9c}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#18bc9c}.panel-success>.panel-heading .badge{color:#18bc9c;background-color:#ffffff}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#18bc9c}.panel-info{border-color:#3498db}.panel-info>.panel-heading{color:#ffffff;background-color:#3498db;border-color:#3498db}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#3498db}.panel-info>.panel-heading .badge{color:#3498db;background-color:#ffffff}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#3498db}.panel-warning{border-color:#f39c12}.panel-warning>.panel-heading{color:#ffffff;background-color:#f39c12;border-color:#f39c12}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f39c12}.panel-warning>.panel-heading .badge{color:#f39c12;background-color:#ffffff}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f39c12}.panel-danger{border-color:#e74c3c}.panel-danger>.panel-heading{color:#ffffff;background-color:#e74c3c;border-color:#e74c3c}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#e74c3c}.panel-danger>.panel-heading .badge{color:#e74c3c;background-color:#ffffff}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#e74c3c}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#ecf0f1;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:22.5px;font-weight:bold;line-height:1;color:#000000;text-shadow:none;opacity:0.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0, -25%);-ms-transform:translate(0, -25%);-o-transform:translate(0, -25%);transform:translate(0, -25%);-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#ffffff;border:1px solid #999999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);-webkit-background-clip:padding-box;background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:0.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.42857143px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:20px}.modal-footer{padding:20px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:0.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000000}.tooltip.top-left .tooltip-arrow{bottom:0;right:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:15px;font-weight:normal;line-height:1.42857143;text-align:left;background-color:#ffffff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #cccccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:15px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#ffffff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999999;border-right-color:rgba(0,0,0,0.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#ffffff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#ffffff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999999;border-left-color:rgba(0,0,0,0.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#ffffff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.next,.carousel-inner>.item.active.right{-webkit-transform:translate3d(100%, 0, 0);transform:translate3d(100%, 0, 0);left:0}.carousel-inner>.item.prev,.carousel-inner>.item.active.left{-webkit-transform:translate3d(-100%, 0, 0);transform:translate3d(-100%, 0, 0);left:0}.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);left:0}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:0.5;filter:alpha(opacity=50);font-size:20px;color:#ffffff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-webkit-gradient(linear, left top, right top, from(rgba(0,0,0,0.5)), to(rgba(0,0,0,0.0001)));background-image:linear-gradient(to right, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-webkit-gradient(linear, left top, right top, from(rgba(0,0,0,0.0001)), to(rgba(0,0,0,0.5)));background-image:linear-gradient(to right, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;line-height:1;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #ffffff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#ffffff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#ffffff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (max-width:767px){.visible-xs-block{display:block !important}}@media (max-width:767px){.visible-xs-inline{display:inline !important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (min-width:1200px){.visible-lg-block{display:block !important}}@media (min-width:1200px){.visible-lg-inline{display:inline !important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media (max-width:767px){.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}}.navbar{border-width:0}.navbar-default .badge{background-color:#fff;color:#2c3e50}.navbar-inverse .badge{background-color:#fff;color:#18bc9c}.navbar-brand{line-height:1}.btn:active{-webkit-box-shadow:none;box-shadow:none}.btn-group.open .dropdown-toggle{-webkit-box-shadow:none;box-shadow:none}.text-primary,.text-primary:hover{color:#2c3e50}.text-success,.text-success:hover{color:#18bc9c}.text-danger,.text-danger:hover{color:#e74c3c}.text-warning,.text-warning:hover{color:#f39c12}.text-info,.text-info:hover{color:#3498db}table a:not(.btn),.table a:not(.btn){text-decoration:underline}table .dropdown-menu a,.table .dropdown-menu a{text-decoration:none}table .success,.table .success,table .warning,.table .warning,table .danger,.table .danger,table .info,.table .info{color:#fff}table .success>th>a,.table .success>th>a,table .warning>th>a,.table .warning>th>a,table .danger>th>a,.table .danger>th>a,table .info>th>a,.table .info>th>a,table .success>td>a,.table .success>td>a,table .warning>td>a,.table .warning>td>a,table .danger>td>a,.table .danger>td>a,table .info>td>a,.table .info>td>a,table .success>a,.table .success>a,table .warning>a,.table .warning>a,table .danger>a,.table .danger>a,table .info>a,.table .info>a{color:#fff}table>thead>tr>th,.table>thead>tr>th,table>tbody>tr>th,.table>tbody>tr>th,table>tfoot>tr>th,.table>tfoot>tr>th,table>thead>tr>td,.table>thead>tr>td,table>tbody>tr>td,.table>tbody>tr>td,table>tfoot>tr>td,.table>tfoot>tr>td{border:none}table-bordered>thead>tr>th,.table-bordered>thead>tr>th,table-bordered>tbody>tr>th,.table-bordered>tbody>tr>th,table-bordered>tfoot>tr>th,.table-bordered>tfoot>tr>th,table-bordered>thead>tr>td,.table-bordered>thead>tr>td,table-bordered>tbody>tr>td,.table-bordered>tbody>tr>td,table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ecf0f1}.form-control,input{border-width:2px;-webkit-box-shadow:none;box-shadow:none}.form-control:focus,input:focus{-webkit-box-shadow:none;box-shadow:none}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning .form-control-feedback{color:#f39c12}.has-warning .form-control,.has-warning .form-control:focus{border:2px solid #f39c12}.has-warning .input-group-addon{border-color:#f39c12}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error .form-control-feedback{color:#e74c3c}.has-error .form-control,.has-error .form-control:focus{border:2px solid #e74c3c}.has-error .input-group-addon{border-color:#e74c3c}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success .form-control-feedback{color:#18bc9c}.has-success .form-control,.has-success .form-control:focus{border:2px solid #18bc9c}.has-success .input-group-addon{border-color:#18bc9c}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{border-color:transparent}.pager a,.pager a:hover{color:#fff}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{background-color:#3be6c4}.close{color:#fff;text-decoration:none;opacity:0.4}.close:hover,.close:focus{color:#fff;opacity:1}.alert .alert-link{color:#fff;text-decoration:underline}.progress{height:10px;-webkit-box-shadow:none;box-shadow:none}.progress .progress-bar{font-size:10px;line-height:10px}.well{-webkit-box-shadow:none;box-shadow:none}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{border-color:#ecf0f1}a.list-group-item-success.active{background-color:#18bc9c}a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{background-color:#15a589}a.list-group-item-warning.active{background-color:#f39c12}a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{background-color:#e08e0b}a.list-group-item-danger.active{background-color:#e74c3c}a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{background-color:#e43725}.panel-default .close{color:#2c3e50}.modal .close{color:#2c3e50}.popover{color:#2c3e50} \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/htdocs/css/freelancer.css b/fluent-bit/lib/monkey/htdocs/css/freelancer.css
new file mode 100644
index 000000000..89038db25
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/css/freelancer.css
@@ -0,0 +1,459 @@
+/*!
+ * Start Bootstrap - Freelancer Bootstrap Theme (http://startbootstrap.com)
+ * Code licensed under the Apache License v2.0.
+ * For details, see http://www.apache.org/licenses/LICENSE-2.0.
+ */
+
+body {
+ overflow-x: hidden;
+}
+
+p {
+ font-size: 20px;
+}
+
+p.small {
+ font-size: 16px;
+}
+
+a,
+a:hover,
+a:focus,
+a:active,
+a.active {
+ outline: 0;
+ color: #18bc9c;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ text-transform: uppercase;
+ font-family: Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;
+ font-weight: 700;
+}
+
+hr.star-light,
+hr.star-primary {
+ margin: 25px auto 30px;
+ padding: 0;
+ max-width: 250px;
+ border: 0;
+ border-top: solid 5px;
+ text-align: center;
+}
+
+hr.star-light:after,
+hr.star-primary:after {
+ content: "\f005";
+ display: inline-block;
+ position: relative;
+ top: -.8em;
+ padding: 0 .25em;
+ font-family: FontAwesome;
+ font-size: 2em;
+}
+
+hr.star-light {
+ border-color: #fff;
+}
+
+hr.star-light:after {
+ color: #fff;
+ background-color: #18bc9c;
+}
+
+hr.star-primary {
+ border-color: #2c3e50;
+}
+
+hr.star-primary:after {
+ color: #2c3e50;
+ background-color: #fff;
+}
+
+.img-centered {
+ margin: 0 auto;
+}
+
+header {
+ text-align: center;
+ color: #fff;
+ background: #18bc9c;
+}
+
+header .container {
+ padding-top: 100px;
+ padding-bottom: 50px;
+}
+
+header img {
+ display: block;
+ margin: 0 auto 20px;
+}
+
+header .intro-text .name {
+ display: block;
+ text-transform: uppercase;
+ font-family: Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;
+ font-size: 2em;
+ font-weight: 700;
+}
+
+header .intro-text .skills {
+ font-size: 1.25em;
+ font-weight: 300;
+}
+
+@media(min-width:768px) {
+ header .container {
+ padding-top: 200px;
+ padding-bottom: 100px;
+ }
+
+ header .intro-text .name {
+ font-size: 4.75em;
+ }
+
+ header .intro-text .skills {
+ font-size: 1.75em;
+ }
+}
+
+@media(min-width:768px) {
+ .navbar-fixed-top {
+ padding: 25px 0;
+ -webkit-transition: padding .3s;
+ -moz-transition: padding .3s;
+ transition: padding .3s;
+ }
+
+ .navbar-fixed-top .navbar-brand {
+ font-size: 2em;
+ -webkit-transition: all .3s;
+ -moz-transition: all .3s;
+ transition: all .3s;
+ }
+
+ .navbar-fixed-top.navbar-shrink {
+ padding: 10px 0;
+ }
+
+ .navbar-fixed-top.navbar-shrink .navbar-brand {
+ font-size: 1.5em;
+ }
+}
+
+.navbar {
+ text-transform: uppercase;
+ font-family: Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;
+ font-weight: 700;
+}
+
+.navbar a:focus {
+ outline: 0;
+
+}
+.navbar .navbar-nav {
+ letter-spacing: 1px;
+}
+
+.navbar .navbar-nav li a:focus {
+ outline: 0;
+}
+
+.navbar-default,
+.navbar-inverse {
+ border: 0;
+}
+
+section {
+ padding: 100px 0;
+}
+
+section h2 {
+ margin: 0;
+ font-size: 3em;
+}
+
+section.success {
+ color: #fff;
+ background: #18bc9c;
+}
+
+section.success a,
+section.success a:hover,
+section.success a:focus,
+section.success a:active,
+section.success a.active {
+ outline: 0;
+ color: #2c3e50;
+}
+
+@media(max-width:767px) {
+ section {
+ padding: 75px 0;
+ }
+
+ section.first {
+ padding-top: 75px;
+ }
+}
+
+#portfolio .portfolio-item {
+ right: 0;
+ margin: 0 0 15px;
+}
+
+#portfolio .portfolio-item .portfolio-link {
+ display: block;
+ position: relative;
+ margin: 0 auto;
+ max-width: 400px;
+}
+
+#portfolio .portfolio-item .portfolio-link .caption {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+ background: rgba(24,188,156,.9);
+ -webkit-transition: all ease .5s;
+ -moz-transition: all ease .5s;
+ transition: all ease .5s;
+}
+
+#portfolio .portfolio-item .portfolio-link .caption:hover {
+ opacity: 1;
+}
+
+#portfolio .portfolio-item .portfolio-link .caption .caption-content {
+ position: absolute;
+ top: 50%;
+ width: 100%;
+ height: 20px;
+ margin-top: -12px;
+ text-align: center;
+ font-size: 20px;
+ color: #fff;
+}
+
+#portfolio .portfolio-item .portfolio-link .caption .caption-content i {
+ margin-top: -12px;
+}
+
+#portfolio .portfolio-item .portfolio-link .caption .caption-content h3,
+#portfolio .portfolio-item .portfolio-link .caption .caption-content h4 {
+ margin: 0;
+}
+
+#portfolio * {
+ z-index: 2;
+}
+
+@media(min-width:767px) {
+ #portfolio .portfolio-item {
+ margin: 0 0 30px;
+ }
+}
+
+.btn-outline {
+ margin-top: 15px;
+ border: solid 2px #fff;
+ font-size: 20px;
+ color: #fff;
+ background: 0 0;
+ transition: all .3s ease-in-out;
+}
+
+.btn-outline:hover,
+.btn-outline:focus,
+.btn-outline:active,
+.btn-outline.active {
+ border: solid 2px #fff;
+ color: #18bc9c;
+ background: #fff;
+}
+
+.floating-label-form-group {
+ position: relative;
+ margin-bottom: 0;
+ padding-bottom: .5em;
+ border-bottom: 1px solid #eee;
+}
+
+.floating-label-form-group input,
+.floating-label-form-group textarea {
+ z-index: 1;
+ position: relative;
+ padding-right: 0;
+ padding-left: 0;
+ border: 0;
+ border-radius: 0;
+ font-size: 1.5em;
+ background: 0 0;
+ box-shadow: none!important;
+ resize: none;
+}
+
+.floating-label-form-group label {
+ display: block;
+ z-index: 0;
+ position: relative;
+ top: 2em;
+ margin: 0;
+ font-size: .85em;
+ line-height: 1.764705882em;
+ vertical-align: middle;
+ vertical-align: baseline;
+ opacity: 0;
+ -webkit-transition: top .3s ease,opacity .3s ease;
+ -moz-transition: top .3s ease,opacity .3s ease;
+ -ms-transition: top .3s ease,opacity .3s ease;
+ transition: top .3s ease,opacity .3s ease;
+}
+
+.floating-label-form-group::not(:first-child) {
+ padding-left: 14px;
+ border-left: 1px solid #eee;
+}
+
+.floating-label-form-group-with-value label {
+ top: 0;
+ opacity: 1;
+}
+
+.floating-label-form-group-with-focus label {
+ color: #18bc9c;
+}
+
+form .row:first-child .floating-label-form-group {
+ border-top: 1px solid #eee;
+}
+
+footer {
+ color: #fff;
+}
+
+footer h3 {
+ margin-bottom: 30px;
+}
+
+footer .footer-above {
+ padding-top: 50px;
+ background-color: #2c3e50;
+}
+
+footer .footer-col {
+ margin-bottom: 50px;
+}
+
+footer .footer-below {
+ padding: 25px 0;
+ background-color: #233140;
+}
+
+.btn-social {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ border: 2px solid #fff;
+ border-radius: 100%;
+ text-align: center;
+ font-size: 20px;
+ line-height: 45px;
+}
+
+.btn:focus,
+.btn:active,
+.btn.active {
+ outline: 0;
+}
+
+.scroll-top {
+ z-index: 1049;
+ position: fixed;
+ right: 2%;
+ bottom: 2%;
+ width: 50px;
+ height: 50px;
+}
+
+.scroll-top .btn {
+ width: 50px;
+ height: 50px;
+ border-radius: 100%;
+ font-size: 20px;
+ line-height: 28px;
+}
+
+.scroll-top .btn:focus {
+ outline: 0;
+}
+
+.portfolio-modal .modal-content {
+ padding: 100px 0;
+ min-height: 100%;
+ border: 0;
+ border-radius: 0;
+ text-align: center;
+ background-clip: border-box;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+.portfolio-modal .modal-content h2 {
+ margin: 0;
+ font-size: 3em;
+}
+
+.portfolio-modal .modal-content img {
+ margin-bottom: 30px;
+}
+
+.portfolio-modal .modal-content .item-details {
+ margin: 30px 0;
+}
+
+.portfolio-modal .close-modal {
+ position: absolute;
+ top: 25px;
+ right: 25px;
+ width: 75px;
+ height: 75px;
+ background-color: transparent;
+ cursor: pointer;
+}
+
+.portfolio-modal .close-modal:hover {
+ opacity: .3;
+}
+
+.portfolio-modal .close-modal .lr {
+ z-index: 1051;
+ width: 1px;
+ height: 75px;
+ margin-left: 35px;
+ background-color: #2c3e50;
+ -webkit-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ transform: rotate(45deg);
+}
+
+.portfolio-modal .close-modal .lr .rl {
+ z-index: 1052;
+ width: 1px;
+ height: 75px;
+ background-color: #2c3e50;
+ -webkit-transform: rotate(90deg);
+ -ms-transform: rotate(90deg);
+ transform: rotate(90deg);
+}
+
+.portfolio-modal .modal-backdrop {
+ display: none;
+ opacity: 0;
+} \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/htdocs/css/monkey.css b/fluent-bit/lib/monkey/htdocs/css/monkey.css
new file mode 100644
index 000000000..6eeba5ccf
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/css/monkey.css
@@ -0,0 +1,59 @@
+header {
+ background-color: #C57407;
+}
+
+
+.navbar-default {
+ background-color: #191F26;
+}
+
+.navbar-brand {
+ margin-top: 15px;
+ max-width: 80%;
+ padding: 0;
+}
+
+ul.nav li a {
+ color: #FFF !important;
+}
+
+ul.nav li a:hover, ul.nav li a:active {
+ color: #ff9212 !important;
+}
+
+
+header a, a:hover, a:link, a:focus, a:active {
+ outline: 0;
+ color: #fff;
+ text-decoration: none;
+}
+
+
+#about a {
+ outline: 0;
+ color: #d77604;
+ font-weight: bold;
+ text-decoration: none;
+ font-size: 1.2em;
+}
+
+footer a, a:active{
+ outline: 0;
+ color: #d77604;
+}
+
+h1 small {
+ color: #ffeeda;
+}
+
+footer .footer-above {
+ background-color: #1D262F;
+}
+
+footer .footer-below {
+ background-color: #191F26;
+}
+
+i, .fa:hover, .fa:active, .fa:visited {
+ color: #C57407;
+}
diff --git a/fluent-bit/lib/monkey/htdocs/favicon.ico b/fluent-bit/lib/monkey/htdocs/favicon.ico
new file mode 100644
index 000000000..f5cfefdfd
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/favicon.ico
Binary files differ
diff --git a/fluent-bit/lib/monkey/htdocs/font-awesome/css/font-awesome.min.css b/fluent-bit/lib/monkey/htdocs/font-awesome/css/font-awesome.min.css
new file mode 100644
index 000000000..ec53d4d6d
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/font-awesome/css/font-awesome.min.css
@@ -0,0 +1,4 @@
+/*!
+ * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
+ * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.2.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"} \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/FontAwesome.otf b/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/FontAwesome.otf
new file mode 100644
index 000000000..81c9ad949
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/FontAwesome.otf
Binary files differ
diff --git a/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.eot b/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.eot
new file mode 100644
index 000000000..84677bc0c
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.eot
Binary files differ
diff --git a/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.svg b/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.svg
new file mode 100644
index 000000000..d907b25ae
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.svg
@@ -0,0 +1,520 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="fontawesomeregular" horiz-adv-x="1536" >
+<font-face units-per-em="1792" ascent="1536" descent="-256" />
+<missing-glyph horiz-adv-x="448" />
+<glyph unicode=" " horiz-adv-x="448" />
+<glyph unicode="&#x09;" horiz-adv-x="448" />
+<glyph unicode="&#xa0;" horiz-adv-x="448" />
+<glyph unicode="&#xa8;" horiz-adv-x="1792" />
+<glyph unicode="&#xa9;" horiz-adv-x="1792" />
+<glyph unicode="&#xae;" horiz-adv-x="1792" />
+<glyph unicode="&#xb4;" horiz-adv-x="1792" />
+<glyph unicode="&#xc6;" horiz-adv-x="1792" />
+<glyph unicode="&#xd8;" horiz-adv-x="1792" />
+<glyph unicode="&#x2000;" horiz-adv-x="768" />
+<glyph unicode="&#x2001;" horiz-adv-x="1537" />
+<glyph unicode="&#x2002;" horiz-adv-x="768" />
+<glyph unicode="&#x2003;" horiz-adv-x="1537" />
+<glyph unicode="&#x2004;" horiz-adv-x="512" />
+<glyph unicode="&#x2005;" horiz-adv-x="384" />
+<glyph unicode="&#x2006;" horiz-adv-x="256" />
+<glyph unicode="&#x2007;" horiz-adv-x="256" />
+<glyph unicode="&#x2008;" horiz-adv-x="192" />
+<glyph unicode="&#x2009;" horiz-adv-x="307" />
+<glyph unicode="&#x200a;" horiz-adv-x="85" />
+<glyph unicode="&#x202f;" horiz-adv-x="307" />
+<glyph unicode="&#x205f;" horiz-adv-x="384" />
+<glyph unicode="&#x2122;" horiz-adv-x="1792" />
+<glyph unicode="&#x221e;" horiz-adv-x="1792" />
+<glyph unicode="&#x2260;" horiz-adv-x="1792" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#xf000;" horiz-adv-x="1792" d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" />
+<glyph unicode="&#xf001;" d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf002;" horiz-adv-x="1664" d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+<glyph unicode="&#xf003;" horiz-adv-x="1792" d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf004;" horiz-adv-x="1792" d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 q-18 -18 -44 -18z" />
+<glyph unicode="&#xf005;" horiz-adv-x="1664" d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf006;" horiz-adv-x="1664" d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf007;" horiz-adv-x="1408" d="M1408 131q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q9 0 42 -21.5t74.5 -48t108 -48t133.5 -21.5t133.5 21.5t108 48t74.5 48t42 21.5q61 0 111.5 -20t85.5 -53.5t62 -81 t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf008;" horiz-adv-x="1920" d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf009;" horiz-adv-x="1664" d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf00a;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf00b;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf00c;" horiz-adv-x="1792" d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" />
+<glyph unicode="&#xf00d;" horiz-adv-x="1408" d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 t-28 -68l-294 -294l294 -294q28 -28 28 -68z" />
+<glyph unicode="&#xf00e;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+<glyph unicode="&#xf010;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z " />
+<glyph unicode="&#xf011;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" />
+<glyph unicode="&#xf012;" horiz-adv-x="1792" d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf013;" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" />
+<glyph unicode="&#xf014;" horiz-adv-x="1408" d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf015;" horiz-adv-x="1664" d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" />
+<glyph unicode="&#xf016;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z " />
+<glyph unicode="&#xf017;" d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf018;" horiz-adv-x="1920" d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" />
+<glyph unicode="&#xf019;" horiz-adv-x="1664" d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" />
+<glyph unicode="&#xf01a;" d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01b;" d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01c;" d="M1023 576h316q-1 3 -2.5 8t-2.5 8l-212 496h-708l-212 -496q-1 -2 -2.5 -8t-2.5 -8h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 q25 -61 25 -123z" />
+<glyph unicode="&#xf01d;" d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01e;" d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q14 0 25 -9 l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" />
+<glyph unicode="&#xf021;" d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf022;" horiz-adv-x="1792" d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 t47 -113z" />
+<glyph unicode="&#xf023;" horiz-adv-x="1152" d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf024;" horiz-adv-x="1792" d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf025;" horiz-adv-x="1664" d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" />
+<glyph unicode="&#xf026;" horiz-adv-x="768" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf027;" horiz-adv-x="1152" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" />
+<glyph unicode="&#xf028;" horiz-adv-x="1664" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" />
+<glyph unicode="&#xf029;" horiz-adv-x="1408" d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" />
+<glyph unicode="&#xf02a;" horiz-adv-x="1792" d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" />
+<glyph unicode="&#xf02b;" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91z" />
+<glyph unicode="&#xf02c;" horiz-adv-x="1920" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" />
+<glyph unicode="&#xf02d;" horiz-adv-x="1664" d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" />
+<glyph unicode="&#xf02e;" horiz-adv-x="1280" d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf02f;" horiz-adv-x="1664" d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" />
+<glyph unicode="&#xf030;" horiz-adv-x="1920" d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf031;" horiz-adv-x="1664" d="M725 977l-170 -450q33 0 136.5 -2t160.5 -2q19 0 57 2q-87 253 -184 452zM0 -128l2 79q23 7 56 12.5t57 10.5t49.5 14.5t44.5 29t31 50.5l237 616l280 724h75h53q8 -14 11 -21l205 -480q33 -78 106 -257.5t114 -274.5q15 -34 58 -144.5t72 -168.5q20 -45 35 -57 q19 -15 88 -29.5t84 -20.5q6 -38 6 -57q0 -4 -0.5 -13t-0.5 -13q-63 0 -190 8t-191 8q-76 0 -215 -7t-178 -8q0 43 4 78l131 28q1 0 12.5 2.5t15.5 3.5t14.5 4.5t15 6.5t11 8t9 11t2.5 14q0 16 -31 96.5t-72 177.5t-42 100l-450 2q-26 -58 -76.5 -195.5t-50.5 -162.5 q0 -22 14 -37.5t43.5 -24.5t48.5 -13.5t57 -8.5t41 -4q1 -19 1 -58q0 -9 -2 -27q-58 0 -174.5 10t-174.5 10q-8 0 -26.5 -4t-21.5 -4q-80 -14 -188 -14z" />
+<glyph unicode="&#xf032;" horiz-adv-x="1408" d="M555 15q74 -32 140 -32q376 0 376 335q0 114 -41 180q-27 44 -61.5 74t-67.5 46.5t-80.5 25t-84 10.5t-94.5 2q-73 0 -101 -10q0 -53 -0.5 -159t-0.5 -158q0 -8 -1 -67.5t-0.5 -96.5t4.5 -83.5t12 -66.5zM541 761q42 -7 109 -7q82 0 143 13t110 44.5t74.5 89.5t25.5 142 q0 70 -29 122.5t-79 82t-108 43.5t-124 14q-50 0 -130 -13q0 -50 4 -151t4 -152q0 -27 -0.5 -80t-0.5 -79q0 -46 1 -69zM0 -128l2 94q15 4 85 16t106 27q7 12 12.5 27t8.5 33.5t5.5 32.5t3 37.5t0.5 34v35.5v30q0 982 -22 1025q-4 8 -22 14.5t-44.5 11t-49.5 7t-48.5 4.5 t-30.5 3l-4 83q98 2 340 11.5t373 9.5q23 0 68.5 -0.5t67.5 -0.5q70 0 136.5 -13t128.5 -42t108 -71t74 -104.5t28 -137.5q0 -52 -16.5 -95.5t-39 -72t-64.5 -57.5t-73 -45t-84 -40q154 -35 256.5 -134t102.5 -248q0 -100 -35 -179.5t-93.5 -130.5t-138 -85.5t-163.5 -48.5 t-176 -14q-44 0 -132 3t-132 3q-106 0 -307 -11t-231 -12z" />
+<glyph unicode="&#xf033;" horiz-adv-x="1024" d="M0 -126l17 85q6 2 81.5 21.5t111.5 37.5q28 35 41 101q1 7 62 289t114 543.5t52 296.5v25q-24 13 -54.5 18.5t-69.5 8t-58 5.5l19 103q33 -2 120 -6.5t149.5 -7t120.5 -2.5q48 0 98.5 2.5t121 7t98.5 6.5q-5 -39 -19 -89q-30 -10 -101.5 -28.5t-108.5 -33.5 q-8 -19 -14 -42.5t-9 -40t-7.5 -45.5t-6.5 -42q-27 -148 -87.5 -419.5t-77.5 -355.5q-2 -9 -13 -58t-20 -90t-16 -83.5t-6 -57.5l1 -18q17 -4 185 -31q-3 -44 -16 -99q-11 0 -32.5 -1.5t-32.5 -1.5q-29 0 -87 10t-86 10q-138 2 -206 2q-51 0 -143 -9t-121 -11z" />
+<glyph unicode="&#xf034;" horiz-adv-x="1792" d="M1744 128q33 0 42 -18.5t-11 -44.5l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80zM81 1407l54 -27q12 -5 211 -5q44 0 132 2 t132 2q36 0 107.5 -0.5t107.5 -0.5h293q6 0 21 -0.5t20.5 0t16 3t17.5 9t15 17.5l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 48t-14.5 73.5t-7.5 35.5q-6 8 -12 12.5t-15.5 6t-13 2.5t-18 0.5t-16.5 -0.5 q-17 0 -66.5 0.5t-74.5 0.5t-64 -2t-71 -6q-9 -81 -8 -136q0 -94 2 -388t2 -455q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q19 42 19 383q0 101 -3 303t-3 303v117q0 2 0.5 15.5t0.5 25t-1 25.5t-3 24t-5 14q-11 12 -162 12q-33 0 -93 -12t-80 -26q-19 -13 -34 -72.5t-31.5 -111t-42.5 -53.5q-42 26 -56 44v383z" />
+<glyph unicode="&#xf035;" d="M81 1407l54 -27q12 -5 211 -5q44 0 132 2t132 2q70 0 246.5 1t304.5 0.5t247 -4.5q33 -1 56 31l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 47.5t-15 73.5t-7 36q-10 13 -27 19q-5 2 -66 2q-30 0 -93 1t-103 1 t-94 -2t-96 -7q-9 -81 -8 -136l1 -152v52q0 -55 1 -154t1.5 -180t0.5 -153q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q7 16 11.5 74t6 145.5t1.5 155t-0.5 153.5t-0.5 89q0 7 -2.5 21.5t-2.5 22.5q0 7 0.5 44t1 73t0 76.5t-3 67.5t-6.5 32q-11 12 -162 12q-41 0 -163 -13.5t-138 -24.5q-19 -12 -34 -71.5t-31.5 -111.5t-42.5 -54q-42 26 -56 44v383zM1310 125q12 0 42 -19.5t57.5 -41.5 t59.5 -49t36 -30q26 -21 26 -49t-26 -49q-4 -3 -36 -30t-59.5 -49t-57.5 -41.5t-42 -19.5q-13 0 -20.5 10.5t-10 28.5t-2.5 33.5t1.5 33t1.5 19.5h-1024q0 -2 1.5 -19.5t1.5 -33t-2.5 -33.5t-10 -28.5t-20.5 -10.5q-12 0 -42 19.5t-57.5 41.5t-59.5 49t-36 30q-26 21 -26 49 t26 49q4 3 36 30t59.5 49t57.5 41.5t42 19.5q13 0 20.5 -10.5t10 -28.5t2.5 -33.5t-1.5 -33t-1.5 -19.5h1024q0 2 -1.5 19.5t-1.5 33t2.5 33.5t10 28.5t20.5 10.5z" />
+<glyph unicode="&#xf036;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf037;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf038;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf039;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf03a;" horiz-adv-x="1792" d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03b;" horiz-adv-x="1792" d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03c;" horiz-adv-x="1792" d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03d;" horiz-adv-x="1792" d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 q39 -17 39 -59z" />
+<glyph unicode="&#xf03e;" horiz-adv-x="1920" d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf040;" d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 q53 0 91 -38l235 -234q37 -39 37 -91z" />
+<glyph unicode="&#xf041;" horiz-adv-x="1024" d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" />
+<glyph unicode="&#xf042;" d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf043;" horiz-adv-x="1024" d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" />
+<glyph unicode="&#xf044;" horiz-adv-x="1792" d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" />
+<glyph unicode="&#xf045;" horiz-adv-x="1664" d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf046;" horiz-adv-x="1664" d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 q24 -24 24 -57t-24 -57z" />
+<glyph unicode="&#xf047;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf048;" horiz-adv-x="1024" d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19z" />
+<glyph unicode="&#xf049;" horiz-adv-x="1792" d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19l710 710 q19 19 32 13t13 -32v-710q4 11 13 19z" />
+<glyph unicode="&#xf04a;" horiz-adv-x="1664" d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-8 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q5 11 13 19z" />
+<glyph unicode="&#xf04b;" horiz-adv-x="1408" d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" />
+<glyph unicode="&#xf04c;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04d;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04e;" horiz-adv-x="1664" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf050;" horiz-adv-x="1792" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19l-710 -710 q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf051;" horiz-adv-x="1024" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19z" />
+<glyph unicode="&#xf052;" horiz-adv-x="1538" d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" />
+<glyph unicode="&#xf053;" horiz-adv-x="1280" d="M1171 1235l-531 -531l531 -531q19 -19 19 -45t-19 -45l-166 -166q-19 -19 -45 -19t-45 19l-742 742q-19 19 -19 45t19 45l742 742q19 19 45 19t45 -19l166 -166q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf054;" horiz-adv-x="1280" d="M1107 659l-742 -742q-19 -19 -45 -19t-45 19l-166 166q-19 19 -19 45t19 45l531 531l-531 531q-19 19 -19 45t19 45l166 166q19 19 45 19t45 -19l742 -742q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf055;" d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf056;" d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
+<glyph unicode="&#xf057;" d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf058;" d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf059;" d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05a;" d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05b;" d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf05c;" d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05d;" d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05e;" d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" />
+<glyph unicode="&#xf060;" d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 t32.5 -90.5z" />
+<glyph unicode="&#xf061;" d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" />
+<glyph unicode="&#xf062;" horiz-adv-x="1664" d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 q37 -39 37 -91z" />
+<glyph unicode="&#xf063;" horiz-adv-x="1664" d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
+<glyph unicode="&#xf064;" horiz-adv-x="1792" d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" />
+<glyph unicode="&#xf065;" d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf066;" d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" />
+<glyph unicode="&#xf067;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf068;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf069;" horiz-adv-x="1664" d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" />
+<glyph unicode="&#xf06a;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" />
+<glyph unicode="&#xf06b;" d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf06c;" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-30 0 -51 11t-31 24t-27 42q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" />
+<glyph unicode="&#xf06d;" horiz-adv-x="1408" d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" />
+<glyph unicode="&#xf06e;" horiz-adv-x="1792" d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" />
+<glyph unicode="&#xf070;" horiz-adv-x="1792" d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 q-105 -188 -315 -566t-316 -567l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z " />
+<glyph unicode="&#xf071;" horiz-adv-x="1792" d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" />
+<glyph unicode="&#xf072;" horiz-adv-x="1408" d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" />
+<glyph unicode="&#xf073;" horiz-adv-x="1664" d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf074;" horiz-adv-x="1792" d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+<glyph unicode="&#xf075;" horiz-adv-x="1792" d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf076;" d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf077;" horiz-adv-x="1792" d="M1683 205l-166 -165q-19 -19 -45 -19t-45 19l-531 531l-531 -531q-19 -19 -45 -19t-45 19l-166 165q-19 19 -19 45.5t19 45.5l742 741q19 19 45 19t45 -19l742 -741q19 -19 19 -45.5t-19 -45.5z" />
+<glyph unicode="&#xf078;" horiz-adv-x="1792" d="M1683 728l-742 -741q-19 -19 -45 -19t-45 19l-742 741q-19 19 -19 45.5t19 45.5l166 165q19 19 45 19t45 -19l531 -531l531 531q19 19 45 19t45 -19l166 -165q19 -19 19 -45.5t-19 -45.5z" />
+<glyph unicode="&#xf079;" horiz-adv-x="1920" d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -11 7 -21 zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z " />
+<glyph unicode="&#xf07a;" horiz-adv-x="1664" d="M640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5 l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5 t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf07b;" horiz-adv-x="1664" d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07c;" horiz-adv-x="1920" d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07d;" horiz-adv-x="768" d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf07e;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf080;" horiz-adv-x="2048" d="M640 640v-512h-256v512h256zM1024 1152v-1024h-256v1024h256zM2048 0v-128h-2048v1536h128v-1408h1920zM1408 896v-768h-256v768h256zM1792 1280v-1152h-256v1152h256z" />
+<glyph unicode="&#xf081;" d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf082;" d="M1536 160q0 -119 -84.5 -203.5t-203.5 -84.5h-192v608h203l30 224h-233v143q0 54 28 83t96 29l132 1v207q-96 9 -180 9q-136 0 -218 -80.5t-82 -225.5v-166h-224v-224h224v-608h-544q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 q119 0 203.5 -84.5t84.5 -203.5v-960z" />
+<glyph unicode="&#xf083;" horiz-adv-x="1792" d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf084;" horiz-adv-x="1792" d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" />
+<glyph unicode="&#xf085;" horiz-adv-x="1920" d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -10 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -9 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" />
+<glyph unicode="&#xf086;" horiz-adv-x="1792" d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" />
+<glyph unicode="&#xf087;" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" />
+<glyph unicode="&#xf088;" d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 32 18 69t-17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -74 49 -163z" />
+<glyph unicode="&#xf089;" horiz-adv-x="896" d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" />
+<glyph unicode="&#xf08a;" horiz-adv-x="1792" d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 q224 0 351 -124t127 -344z" />
+<glyph unicode="&#xf08b;" horiz-adv-x="1664" d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" />
+<glyph unicode="&#xf08c;" d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf08d;" horiz-adv-x="1152" d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" />
+<glyph unicode="&#xf08e;" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf090;" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf091;" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf092;" d="M394 184q-8 -9 -20 3q-13 11 -4 19q8 9 20 -3q12 -11 4 -19zM352 245q9 -12 0 -19q-8 -6 -17 7t0 18q9 7 17 -6zM291 305q-5 -7 -13 -2q-10 5 -7 12q3 5 13 2q10 -5 7 -12zM322 271q-6 -7 -16 3q-9 11 -2 16q6 6 16 -3q9 -11 2 -16zM451 159q-4 -12 -19 -6q-17 4 -13 15 t19 7q16 -5 13 -16zM514 154q0 -11 -16 -11q-17 -2 -17 11q0 11 16 11q17 2 17 -11zM572 164q2 -10 -14 -14t-18 8t14 15q16 2 18 -9zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-224q-16 0 -24.5 1t-19.5 5t-16 14.5t-5 27.5v239q0 97 -52 142q57 6 102.5 18t94 39 t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103 q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -103t0.5 -68q0 -22 -11 -33.5t-22 -13t-33 -1.5 h-224q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf093;" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" />
+<glyph unicode="&#xf094;" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -10 1 -18.5t3 -17t4 -13.5t6.5 -16t6.5 -17q16 -40 25 -118.5t9 -136.5z" />
+<glyph unicode="&#xf095;" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174 q2 -1 19 -11.5t24 -14t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" />
+<glyph unicode="&#xf096;" horiz-adv-x="1408" d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf097;" horiz-adv-x="1280" d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf098;" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5t320.5 -216.5q6 -2 30 -11t33 -12.5 t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf099;" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
+<glyph unicode="&#xf09a;" horiz-adv-x="1024" d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" />
+<glyph unicode="&#xf09b;" d="M1536 640q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -39.5 7t-12.5 30v211q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5 q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23 q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -89t0.5 -54q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf09c;" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" />
+<glyph unicode="&#xf09d;" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
+<glyph unicode="&#xf09e;" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" />
+<glyph unicode="&#xf0a0;" d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" />
+<glyph unicode="&#xf0a1;" horiz-adv-x="1792" d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" />
+<glyph unicode="&#xf0a2;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM246 128h1300q-266 300 -266 832q0 51 -24 105t-69 103t-121.5 80.5t-169.5 31.5t-169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -532 -266 -832z M1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5 t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
+<glyph unicode="&#xf0a3;" d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" />
+<glyph unicode="&#xf0a4;" horiz-adv-x="1792" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" />
+<glyph unicode="&#xf0a5;" horiz-adv-x="1792" d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-2 3 -3.5 4.5t-4 4.5t-4.5 5q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576 q-50 0 -89 -38.5t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45 t45 -19t45 19t19 45zM1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128 q0 122 81.5 189t206.5 67q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf0a6;" d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" />
+<glyph unicode="&#xf0a7;" d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" />
+<glyph unicode="&#xf0a8;" d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0a9;" d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0aa;" d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ab;" d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ac;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 10.5t-9.5 10.5q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-5 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10t17 -20q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q7 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" />
+<glyph unicode="&#xf0ad;" horiz-adv-x="1664" d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" />
+<glyph unicode="&#xf0ae;" horiz-adv-x="1792" d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0b0;" horiz-adv-x="1408" d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" />
+<glyph unicode="&#xf0b1;" horiz-adv-x="1792" d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0b2;" d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z " />
+<glyph unicode="&#xf0c0;" horiz-adv-x="1920" d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" />
+<glyph unicode="&#xf0c1;" horiz-adv-x="1664" d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" />
+<glyph unicode="&#xf0c2;" horiz-adv-x="1920" d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z " />
+<glyph unicode="&#xf0c3;" horiz-adv-x="1664" d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" />
+<glyph unicode="&#xf0c4;" horiz-adv-x="1792" d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" />
+<glyph unicode="&#xf0c5;" horiz-adv-x="1792" d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" />
+<glyph unicode="&#xf0c6;" horiz-adv-x="1408" d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 z" />
+<glyph unicode="&#xf0c7;" d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0c8;" d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0c9;" d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0ca;" horiz-adv-x="1792" d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf0cb;" horiz-adv-x="1792" d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 122t0.5 121v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5 t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf0cc;" horiz-adv-x="1792" d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 97 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -55 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" />
+<glyph unicode="&#xf0cd;" d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" />
+<glyph unicode="&#xf0ce;" horiz-adv-x="1664" d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 z" />
+<glyph unicode="&#xf0d0;" horiz-adv-x="1664" d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" />
+<glyph unicode="&#xf0d1;" horiz-adv-x="1792" d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d2;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0d3;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" />
+<glyph unicode="&#xf0d4;" d="M829 318q0 -76 -58.5 -112.5t-139.5 -36.5q-41 0 -80.5 9.5t-75.5 28.5t-58 53t-22 78q0 46 25 80t65.5 51.5t82 25t84.5 7.5q20 0 31 -2q2 -1 23 -16.5t26 -19t23 -18t24.5 -22t19 -22.5t17 -26t9 -26.5t4.5 -31.5zM755 863q0 -60 -33 -99.5t-92 -39.5q-53 0 -93 42.5 t-57.5 96.5t-17.5 106q0 61 32 104t92 43q53 0 93.5 -45t58 -101t17.5 -107zM861 1120l88 64h-265q-85 0 -161 -32t-127.5 -98t-51.5 -153q0 -93 64.5 -154.5t158.5 -61.5q22 0 43 3q-13 -29 -13 -54q0 -44 40 -94q-175 -12 -257 -63q-47 -29 -75.5 -73t-28.5 -95 q0 -43 18.5 -77.5t48.5 -56.5t69 -37t77.5 -21t76.5 -6q60 0 120.5 15.5t113.5 46t86 82.5t33 117q0 49 -20 89.5t-49 66.5t-58 47.5t-49 44t-20 44.5t15.5 42.5t37.5 39.5t44 42t37.5 59.5t15.5 82.5q0 60 -22.5 99.5t-72.5 90.5h83zM1152 672h128v64h-128v128h-64v-128 h-128v-64h128v-160h64v160zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0d5;" horiz-adv-x="1664" d="M735 740q0 -36 32 -70.5t77.5 -68t90.5 -73.5t77 -104t32 -142q0 -90 -48 -173q-72 -122 -211 -179.5t-298 -57.5q-132 0 -246.5 41.5t-171.5 137.5q-37 60 -37 131q0 81 44.5 150t118.5 115q131 82 404 100q-32 42 -47.5 74t-15.5 73q0 36 21 85q-46 -4 -68 -4 q-148 0 -249.5 96.5t-101.5 244.5q0 82 36 159t99 131q77 66 182.5 98t217.5 32h418l-138 -88h-131q74 -63 112 -133t38 -160q0 -72 -24.5 -129.5t-59 -93t-69.5 -65t-59.5 -61.5t-24.5 -66zM589 836q38 0 78 16.5t66 43.5q53 57 53 159q0 58 -17 125t-48.5 129.5 t-84.5 103.5t-117 41q-42 0 -82.5 -19.5t-65.5 -52.5q-47 -59 -47 -160q0 -46 10 -97.5t31.5 -103t52 -92.5t75 -67t96.5 -26zM591 -37q58 0 111.5 13t99 39t73 73t27.5 109q0 25 -7 49t-14.5 42t-27 41.5t-29.5 35t-38.5 34.5t-36.5 29t-41.5 30t-36.5 26q-16 2 -48 2 q-53 0 -105 -7t-107.5 -25t-97 -46t-68.5 -74.5t-27 -105.5q0 -70 35 -123.5t91.5 -83t119 -44t127.5 -14.5zM1401 839h213v-108h-213v-219h-105v219h-212v108h212v217h105v-217z" />
+<glyph unicode="&#xf0d6;" horiz-adv-x="1920" d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d7;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d8;" horiz-adv-x="1024" d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0d9;" horiz-adv-x="640" d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf0da;" horiz-adv-x="640" d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0db;" horiz-adv-x="1664" d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0dc;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0dd;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0de;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0e0;" horiz-adv-x="1792" d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" />
+<glyph unicode="&#xf0e1;" d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" />
+<glyph unicode="&#xf0e2;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" />
+<glyph unicode="&#xf0e3;" horiz-adv-x="1792" d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" />
+<glyph unicode="&#xf0e4;" horiz-adv-x="1792" d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf0e5;" horiz-adv-x="1792" d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf0e6;" horiz-adv-x="1792" d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" />
+<glyph unicode="&#xf0e7;" horiz-adv-x="896" d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" />
+<glyph unicode="&#xf0e8;" horiz-adv-x="1792" d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 z" />
+<glyph unicode="&#xf0e9;" horiz-adv-x="1664" d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf0ea;" horiz-adv-x="1792" d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0eb;" horiz-adv-x="1024" d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" />
+<glyph unicode="&#xf0ec;" horiz-adv-x="1792" d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+<glyph unicode="&#xf0ed;" horiz-adv-x="1920" d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0ee;" horiz-adv-x="1920" d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0f0;" horiz-adv-x="1408" d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf0f1;" horiz-adv-x="1408" d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" />
+<glyph unicode="&#xf0f2;" horiz-adv-x="1792" d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 t66 -158z" />
+<glyph unicode="&#xf0f3;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5 t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
+<glyph unicode="&#xf0f4;" horiz-adv-x="1920" d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf0f5;" horiz-adv-x="1408" d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f6;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M384 736q0 14 9 23t23 9h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64zM1120 512q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704zM1120 256q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704 q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704z" />
+<glyph unicode="&#xf0f7;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f8;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f9;" horiz-adv-x="1920" d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0fa;" horiz-adv-x="1792" d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf0fb;" horiz-adv-x="1920" d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q261 -58 287 -93z" />
+<glyph unicode="&#xf0fc;" horiz-adv-x="1664" d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" />
+<glyph unicode="&#xf0fd;" d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0fe;" d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf100;" horiz-adv-x="1024" d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" />
+<glyph unicode="&#xf101;" horiz-adv-x="1024" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf102;" horiz-adv-x="1152" d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf103;" horiz-adv-x="1152" d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf104;" horiz-adv-x="640" d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf105;" horiz-adv-x="640" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf106;" horiz-adv-x="1152" d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf107;" horiz-adv-x="1152" d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf108;" horiz-adv-x="1920" d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf109;" horiz-adv-x="1920" d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" />
+<glyph unicode="&#xf10a;" horiz-adv-x="1152" d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf10b;" horiz-adv-x="768" d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf10c;" d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf10d;" horiz-adv-x="1664" d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" />
+<glyph unicode="&#xf10e;" horiz-adv-x="1664" d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" />
+<glyph unicode="&#xf110;" horiz-adv-x="1568" d="M496 192q0 -60 -42.5 -102t-101.5 -42q-60 0 -102 42t-42 102t42 102t102 42q59 0 101.5 -42t42.5 -102zM928 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -66 -47 -113t-113 -47t-113 47t-47 113 t47 113t113 47t113 -47t47 -113zM1360 192q0 -46 -33 -79t-79 -33t-79 33t-33 79t33 79t79 33t79 -33t33 -79zM528 1088q0 -73 -51.5 -124.5t-124.5 -51.5t-124.5 51.5t-51.5 124.5t51.5 124.5t124.5 51.5t124.5 -51.5t51.5 -124.5zM992 1280q0 -80 -56 -136t-136 -56 t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1536 640q0 -40 -28 -68t-68 -28t-68 28t-28 68t28 68t68 28t68 -28t28 -68zM1328 1088q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5z" />
+<glyph unicode="&#xf111;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf112;" horiz-adv-x="1792" d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" />
+<glyph unicode="&#xf113;" horiz-adv-x="1664" d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 q0 -87 -27 -168q136 -160 136 -398z" />
+<glyph unicode="&#xf114;" horiz-adv-x="1664" d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf115;" horiz-adv-x="1920" d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z " />
+<glyph unicode="&#xf116;" horiz-adv-x="1792" />
+<glyph unicode="&#xf117;" horiz-adv-x="1792" />
+<glyph unicode="&#xf118;" d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf119;" d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf11a;" d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf11b;" horiz-adv-x="1920" d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" />
+<glyph unicode="&#xf11c;" horiz-adv-x="1920" d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf11d;" horiz-adv-x="1792" d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+<glyph unicode="&#xf11e;" horiz-adv-x="1792" d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+<glyph unicode="&#xf120;" horiz-adv-x="1664" d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 t9 -23z" />
+<glyph unicode="&#xf121;" horiz-adv-x="1920" d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" />
+<glyph unicode="&#xf122;" horiz-adv-x="1792" d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" />
+<glyph unicode="&#xf123;" horiz-adv-x="1664" d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" />
+<glyph unicode="&#xf124;" horiz-adv-x="1408" d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" />
+<glyph unicode="&#xf125;" horiz-adv-x="1664" d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf126;" horiz-adv-x="1024" d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 q-2 -287 -226 -414q-68 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" />
+<glyph unicode="&#xf127;" horiz-adv-x="1664" d="M439 265l-256 -256q-10 -9 -23 -9q-12 0 -23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
+<glyph unicode="&#xf128;" horiz-adv-x="1024" d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" />
+<glyph unicode="&#xf129;" horiz-adv-x="640" d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf12a;" horiz-adv-x="640" d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" />
+<glyph unicode="&#xf12b;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1534 846v-206h-514l-3 27 q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5t-65.5 -51.5t-30.5 -63h232v80 h126z" />
+<glyph unicode="&#xf12c;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1536 -50v-206h-514l-4 27 q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73h232v80h126z" />
+<glyph unicode="&#xf12d;" horiz-adv-x="1920" d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" />
+<glyph unicode="&#xf12e;" horiz-adv-x="1664" d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" />
+<glyph unicode="&#xf130;" horiz-adv-x="1152" d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" />
+<glyph unicode="&#xf131;" horiz-adv-x="1408" d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" />
+<glyph unicode="&#xf132;" horiz-adv-x="1280" d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf133;" horiz-adv-x="1664" d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf134;" horiz-adv-x="1408" d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" />
+<glyph unicode="&#xf135;" horiz-adv-x="1664" d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" />
+<glyph unicode="&#xf136;" horiz-adv-x="1792" d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" />
+<glyph unicode="&#xf137;" d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf138;" d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf139;" d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13a;" d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13b;" horiz-adv-x="1408" d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" />
+<glyph unicode="&#xf13c;" horiz-adv-x="1792" d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" />
+<glyph unicode="&#xf13d;" horiz-adv-x="1792" d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-13 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf13e;" horiz-adv-x="1152" d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 v-320h736z" />
+<glyph unicode="&#xf140;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf141;" horiz-adv-x="1408" d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf142;" horiz-adv-x="384" d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf143;" d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 232 -177 396t-396 177q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128q13 0 23 10 t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf144;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 q16 -8 32 -8q17 0 32 9z" />
+<glyph unicode="&#xf145;" horiz-adv-x="1792" d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" />
+<glyph unicode="&#xf146;" d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf147;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf148;" horiz-adv-x="1024" d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" />
+<glyph unicode="&#xf149;" horiz-adv-x="1024" d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" />
+<glyph unicode="&#xf14a;" d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14b;" d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14c;" d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14d;" d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q10 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14e;" d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf150;" d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf151;" d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf152;" d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf153;" horiz-adv-x="1024" d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" />
+<glyph unicode="&#xf154;" horiz-adv-x="1024" d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" />
+<glyph unicode="&#xf155;" horiz-adv-x="1024" d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 t53 -63.5t31.5 -76.5t13 -94z" />
+<glyph unicode="&#xf156;" horiz-adv-x="898" d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf157;" horiz-adv-x="1027" d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" />
+<glyph unicode="&#xf158;" horiz-adv-x="1280" d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" />
+<glyph unicode="&#xf159;" horiz-adv-x="1792" d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf15a;" horiz-adv-x="1280" d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" />
+<glyph unicode="&#xf15b;" d="M1024 1024v472q22 -14 36 -28l408 -408q14 -14 28 -36h-472zM896 992q0 -40 28 -68t68 -28h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544z" />
+<glyph unicode="&#xf15c;" d="M1468 1060q14 -14 28 -36h-472v472q22 -14 36 -28zM992 896h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544q0 -40 28 -68t68 -28zM1152 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23z" />
+<glyph unicode="&#xf15d;" horiz-adv-x="1664" d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 l230 -662h70z" />
+<glyph unicode="&#xf15e;" horiz-adv-x="1664" d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 v119h121z" />
+<glyph unicode="&#xf160;" horiz-adv-x="1792" d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf161;" horiz-adv-x="1792" d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf162;" d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" />
+<glyph unicode="&#xf163;" d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" />
+<glyph unicode="&#xf164;" horiz-adv-x="1664" d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" />
+<glyph unicode="&#xf165;" horiz-adv-x="1664" d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" />
+<glyph unicode="&#xf166;" d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 16 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 q21 -28 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78l24 -69t23 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38q-51 0 -78 -38 q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf167;" d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-37 -51 -106 -51q-67 0 -105 51 q-28 38 -28 118v175q0 80 28 117q38 51 105 51q69 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" />
+<glyph unicode="&#xf168;" horiz-adv-x="1408" d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 q25 45 64 45h241q22 0 31 -15z" />
+<glyph unicode="&#xf169;" d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf16a;" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" />
+<glyph unicode="&#xf16b;" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
+<glyph unicode="&#xf16c;" horiz-adv-x="1408" d="M928 135v-151l-707 -1v151zM1169 481v-701l-1 -35v-1h-1132l-35 1h-1v736h121v-618h928v618h120zM241 393l704 -65l-13 -150l-705 65zM309 709l683 -183l-39 -146l-683 183zM472 1058l609 -360l-77 -130l-609 360zM832 1389l398 -585l-124 -85l-399 584zM1285 1536 l121 -697l-149 -26l-121 697z" />
+<glyph unicode="&#xf16d;" d="M1362 110v648h-135q20 -63 20 -131q0 -126 -64 -232.5t-174 -168.5t-240 -62q-197 0 -337 135.5t-140 327.5q0 68 20 131h-141v-648q0 -26 17.5 -43.5t43.5 -17.5h1069q25 0 43 17.5t18 43.5zM1078 643q0 124 -90.5 211.5t-218.5 87.5q-127 0 -217.5 -87.5t-90.5 -211.5 t90.5 -211.5t217.5 -87.5q128 0 218.5 87.5t90.5 211.5zM1362 1003v165q0 28 -20 48.5t-49 20.5h-174q-29 0 -49 -20.5t-20 -48.5v-165q0 -29 20 -49t49 -20h174q29 0 49 20t20 49zM1536 1211v-1142q0 -81 -58 -139t-139 -58h-1142q-81 0 -139 58t-58 139v1142q0 81 58 139 t139 58h1142q81 0 139 -58t58 -139z" />
+<glyph unicode="&#xf16e;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
+<glyph unicode="&#xf170;" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf171;" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" />
+<glyph unicode="&#xf172;" d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf173;" horiz-adv-x="1024" d="M944 207l80 -237q-23 -35 -111 -66t-177 -32q-104 -2 -190.5 26t-142.5 74t-95 106t-55.5 120t-16.5 118v544h-168v215q72 26 129 69.5t91 90t58 102t34 99t15 88.5q1 5 4.5 8.5t7.5 3.5h244v-424h333v-252h-334v-518q0 -30 6.5 -56t22.5 -52.5t49.5 -41.5t81.5 -14 q78 2 134 29z" />
+<glyph unicode="&#xf174;" d="M1136 75l-62 183q-44 -22 -103 -22q-36 -1 -62 10.5t-38.5 31.5t-17.5 40.5t-5 43.5v398h257v194h-256v326h-188q-8 0 -9 -10q-5 -44 -17.5 -87t-39 -95t-77 -95t-118.5 -68v-165h130v-418q0 -57 21.5 -115t65 -111t121 -85.5t176.5 -30.5q69 1 136.5 25t85.5 50z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf175;" horiz-adv-x="768" d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" />
+<glyph unicode="&#xf176;" horiz-adv-x="768" d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" />
+<glyph unicode="&#xf177;" horiz-adv-x="1792" d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf178;" horiz-adv-x="1792" d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" />
+<glyph unicode="&#xf179;" horiz-adv-x="1408" d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q112 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" />
+<glyph unicode="&#xf17a;" horiz-adv-x="1664" d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" />
+<glyph unicode="&#xf17b;" horiz-adv-x="1408" d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" />
+<glyph unicode="&#xf17c;" d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-7 -10 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18l-4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-14 -1 -7 -7l4 -2 q14 -4 18 -31q0 -3 8 2zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5t-30 -18.5 t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43q-19 4 -51 9.5 t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49t-14 -48 q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54q110 143 124 195 q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5t-40.5 -33.5t-61 -14 q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5t15.5 47.5q1 -31 8 -56.5 t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" />
+<glyph unicode="&#xf17d;" d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -6 6.5 -17.5t7.5 -16.5q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf17e;" d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" />
+<glyph unicode="&#xf180;" horiz-adv-x="1280" d="M1000 1102l37 194q5 23 -9 40t-35 17h-712q-23 0 -38.5 -17t-15.5 -37v-1101q0 -7 6 -1l291 352q23 26 38 33.5t48 7.5h239q22 0 37 14.5t18 29.5q24 130 37 191q4 21 -11.5 40t-36.5 19h-294q-29 0 -48 19t-19 48v42q0 29 19 47.5t48 18.5h346q18 0 35 13.5t20 29.5z M1227 1324q-15 -73 -53.5 -266.5t-69.5 -350t-35 -173.5q-6 -22 -9 -32.5t-14 -32.5t-24.5 -33t-38.5 -21t-58 -10h-271q-13 0 -22 -10q-8 -9 -426 -494q-22 -25 -58.5 -28.5t-48.5 5.5q-55 22 -55 98v1410q0 55 38 102.5t120 47.5h888q95 0 127 -53t10 -159zM1227 1324 l-158 -790q4 17 35 173.5t69.5 350t53.5 266.5z" />
+<glyph unicode="&#xf181;" d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf182;" horiz-adv-x="1280" d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf183;" horiz-adv-x="1024" d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf184;" d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf185;" horiz-adv-x="1792" d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" />
+<glyph unicode="&#xf186;" d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" />
+<glyph unicode="&#xf187;" horiz-adv-x="1792" d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf188;" horiz-adv-x="1664" d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" />
+<glyph unicode="&#xf189;" horiz-adv-x="1920" d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-78 -100 -90 -131q-17 -41 14 -81q17 -21 81 -82h1l1 -1l1 -1l2 -2q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q17 19 38 30q53 26 239 24 q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 q39 5 64 -2.5t31 -16.5z" />
+<glyph unicode="&#xf18a;" horiz-adv-x="1792" d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" />
+<glyph unicode="&#xf18b;" d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" />
+<glyph unicode="&#xf18c;" horiz-adv-x="1408" d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56 t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -5 1 -50.5t-1 -71.5q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5 t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" />
+<glyph unicode="&#xf18d;" horiz-adv-x="1280" d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z " />
+<glyph unicode="&#xf18e;" d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf190;" d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf191;" d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf192;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5 t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf193;" horiz-adv-x="1664" d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 16 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" />
+<glyph unicode="&#xf194;" d="M1254 899q16 85 -21 132q-52 65 -187 45q-17 -3 -41 -12.5t-57.5 -30.5t-64.5 -48.5t-59.5 -70t-44.5 -91.5q80 7 113.5 -16t26.5 -99q-5 -52 -52 -143q-43 -78 -71 -99q-44 -32 -87 14q-23 24 -37.5 64.5t-19 73t-10 84t-8.5 71.5q-23 129 -34 164q-12 37 -35.5 69 t-50.5 40q-57 16 -127 -25q-54 -32 -136.5 -106t-122.5 -102v-7q16 -8 25.5 -26t21.5 -20q21 -3 54.5 8.5t58 10.5t41.5 -30q11 -18 18.5 -38.5t15 -48t12.5 -40.5q17 -46 53 -187q36 -146 57 -197q42 -99 103 -125q43 -12 85 -1.5t76 31.5q131 77 250 237 q104 139 172.5 292.5t82.5 226.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf195;" horiz-adv-x="1152" d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf196;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf197;" horiz-adv-x="2176" d="M620 416q-110 -64 -268 -64h-128v64h-64q-13 0 -22.5 23.5t-9.5 56.5q0 24 7 49q-58 2 -96.5 10.5t-38.5 20.5t38.5 20.5t96.5 10.5q-7 25 -7 49q0 33 9.5 56.5t22.5 23.5h64v64h128q158 0 268 -64h1113q42 -7 106.5 -18t80.5 -14q89 -15 150 -40.5t83.5 -47.5t22.5 -40 t-22.5 -40t-83.5 -47.5t-150 -40.5q-16 -3 -80.5 -14t-106.5 -18h-1113zM1739 668q53 -36 53 -92t-53 -92l81 -30q68 48 68 122t-68 122zM625 400h1015q-217 -38 -456 -80q-57 0 -113 -24t-83 -48l-28 -24l-288 -288q-26 -26 -70.5 -45t-89.5 -19h-96l-93 464h29 q157 0 273 64zM352 816h-29l93 464h96q46 0 90 -19t70 -45l288 -288q4 -4 11 -10.5t30.5 -23t48.5 -29t61.5 -23t72.5 -10.5l456 -80h-1015q-116 64 -273 64z" />
+<glyph unicode="&#xf198;" horiz-adv-x="1664" d="M1519 760q62 0 103.5 -40.5t41.5 -101.5q0 -97 -93 -130l-172 -59l56 -167q7 -21 7 -47q0 -59 -42 -102t-101 -43q-47 0 -85.5 27t-53.5 72l-55 165l-310 -106l55 -164q8 -24 8 -47q0 -59 -42 -102t-102 -43q-47 0 -85 27t-53 72l-55 163l-153 -53q-29 -9 -50 -9 q-61 0 -101.5 40t-40.5 101q0 47 27.5 85t71.5 53l156 53l-105 313l-156 -54q-26 -8 -48 -8q-60 0 -101 40.5t-41 100.5q0 47 27.5 85t71.5 53l157 53l-53 159q-8 24 -8 47q0 60 42 102.5t102 42.5q47 0 85 -27t53 -72l54 -160l310 105l-54 160q-8 24 -8 47q0 59 42.5 102 t101.5 43q47 0 85.5 -27.5t53.5 -71.5l53 -161l162 55q21 6 43 6q60 0 102.5 -39.5t42.5 -98.5q0 -45 -30 -81.5t-74 -51.5l-157 -54l105 -316l164 56q24 8 46 8zM725 498l310 105l-105 315l-310 -107z" />
+<glyph unicode="&#xf199;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM1280 352v436q-31 -35 -64 -55q-34 -22 -132.5 -85t-151.5 -99q-98 -69 -164 -69v0v0q-66 0 -164 69 q-46 32 -141.5 92.5t-142.5 92.5q-12 8 -33 27t-31 27v-436q0 -40 28 -68t68 -28h832q40 0 68 28t28 68zM1280 925q0 41 -27.5 70t-68.5 29h-832q-40 0 -68 -28t-28 -68q0 -37 30.5 -76.5t67.5 -64.5q47 -32 137.5 -89t129.5 -83q3 -2 17 -11.5t21 -14t21 -13t23.5 -13 t21.5 -9.5t22.5 -7.5t20.5 -2.5t20.5 2.5t22.5 7.5t21.5 9.5t23.5 13t21 13t21 14t17 11.5l267 174q35 23 66.5 62.5t31.5 73.5z" />
+<glyph unicode="&#xf19a;" horiz-adv-x="1792" d="M127 640q0 163 67 313l367 -1005q-196 95 -315 281t-119 411zM1415 679q0 -19 -2.5 -38.5t-10 -49.5t-11.5 -44t-17.5 -59t-17.5 -58l-76 -256l-278 826q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-75 1 -202 10q-12 1 -20.5 -5t-11.5 -15t-1.5 -18.5t9 -16.5 t19.5 -8l80 -8l120 -328l-168 -504l-280 832q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-7 0 -23 0.5t-26 0.5q105 160 274.5 253.5t367.5 93.5q147 0 280.5 -53t238.5 -149h-10q-55 0 -92 -40.5t-37 -95.5q0 -12 2 -24t4 -21.5t8 -23t9 -21t12 -22.5t12.5 -21 t14.5 -24t14 -23q63 -107 63 -212zM909 573l237 -647q1 -6 5 -11q-126 -44 -255 -44q-112 0 -217 32zM1570 1009q95 -174 95 -369q0 -209 -104 -385.5t-279 -278.5l235 678q59 169 59 276q0 42 -6 79zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286 t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 -215q173 0 331.5 68t273 182.5t182.5 273t68 331.5t-68 331.5t-182.5 273t-273 182.5t-331.5 68t-331.5 -68t-273 -182.5t-182.5 -273t-68 -331.5t68 -331.5t182.5 -273 t273 -182.5t331.5 -68z" />
+<glyph unicode="&#xf19b;" horiz-adv-x="1792" d="M1086 1536v-1536l-272 -128q-228 20 -414 102t-293 208.5t-107 272.5q0 140 100.5 263.5t275 205.5t391.5 108v-172q-217 -38 -356.5 -150t-139.5 -255q0 -152 154.5 -267t388.5 -145v1360zM1755 954l37 -390l-525 114l147 83q-119 70 -280 99v172q277 -33 481 -157z" />
+<glyph unicode="&#xf19c;" horiz-adv-x="2048" d="M960 1536l960 -384v-128h-128q0 -26 -20.5 -45t-48.5 -19h-1526q-28 0 -48.5 19t-20.5 45h-128v128zM256 896h256v-768h128v768h256v-768h128v768h256v-768h128v768h256v-768h59q28 0 48.5 -19t20.5 -45v-64h-1664v64q0 26 20.5 45t48.5 19h59v768zM1851 -64 q28 0 48.5 -19t20.5 -45v-128h-1920v128q0 26 20.5 45t48.5 19h1782z" />
+<glyph unicode="&#xf19d;" horiz-adv-x="2304" d="M1774 700l18 -316q4 -69 -82 -128t-235 -93.5t-323 -34.5t-323 34.5t-235 93.5t-82 128l18 316l574 -181q22 -7 48 -7t48 7zM2304 1024q0 -23 -22 -31l-1120 -352q-4 -1 -10 -1t-10 1l-652 206q-43 -34 -71 -111.5t-34 -178.5q63 -36 63 -109q0 -69 -58 -107l58 -433 q2 -14 -8 -25q-9 -11 -24 -11h-192q-15 0 -24 11q-10 11 -8 25l58 433q-58 38 -58 107q0 73 65 111q11 207 98 330l-333 104q-22 8 -22 31t22 31l1120 352q4 1 10 1t10 -1l1120 -352q22 -8 22 -31z" />
+<glyph unicode="&#xf19e;" d="M859 579l13 -707q-62 11 -105 11q-41 0 -105 -11l13 707q-40 69 -168.5 295.5t-216.5 374.5t-181 287q58 -15 108 -15q43 0 111 15q63 -111 133.5 -229.5t167 -276.5t138.5 -227q37 61 109.5 177.5t117.5 190t105 176t107 189.5q54 -14 107 -14q56 0 114 14v0 q-28 -39 -60 -88.5t-49.5 -78.5t-56.5 -96t-49 -84q-146 -248 -353 -610z" />
+<glyph unicode="&#xf1a0;" horiz-adv-x="1280" d="M981 197q0 25 -7 49t-14.5 42t-27 41.5t-29.5 35t-38.5 34.5t-36.5 29t-41.5 30t-36.5 26q-16 2 -49 2q-53 0 -104.5 -7t-107 -25t-97 -46t-68.5 -74.5t-27 -105.5q0 -56 23.5 -102t61 -75.5t87 -50t100 -29t101.5 -8.5q58 0 111.5 13t99 39t73 73t27.5 109zM864 1055 q0 59 -17 125.5t-48 129t-84 103.5t-117 41q-42 0 -82.5 -19.5t-66.5 -52.5q-46 -59 -46 -160q0 -46 10 -97.5t31.5 -103t52 -92.5t75 -67t96.5 -26q37 0 77.5 16.5t65.5 43.5q53 56 53 159zM752 1536h417l-137 -88h-132q75 -63 113 -133t38 -160q0 -72 -24.5 -129.5 t-59.5 -93t-69.5 -65t-59 -61.5t-24.5 -66q0 -36 32 -70.5t77 -68t90.5 -73.5t77.5 -104t32 -142q0 -91 -49 -173q-71 -122 -209.5 -179.5t-298.5 -57.5q-132 0 -246.5 41.5t-172.5 137.5q-36 59 -36 131q0 81 44.5 150t118.5 115q131 82 404 100q-32 41 -47.5 73.5 t-15.5 73.5q0 40 21 85q-46 -4 -68 -4q-148 0 -249.5 96.5t-101.5 244.5q0 82 36 159t99 131q76 66 182 98t218 32z" />
+<glyph unicode="&#xf1a1;" horiz-adv-x="1984" d="M831 572q0 -56 -40.5 -96t-96.5 -40q-57 0 -98 40t-41 96q0 57 41.5 98t97.5 41t96.5 -41t40.5 -98zM1292 711q56 0 96.5 -41t40.5 -98q0 -56 -40.5 -96t-96.5 -40q-57 0 -98 40t-41 96q0 57 41.5 98t97.5 41zM1984 722q0 -62 -31 -114t-83 -82q5 -33 5 -61 q0 -121 -68.5 -230.5t-197.5 -193.5q-125 -82 -285.5 -125.5t-335.5 -43.5q-176 0 -336.5 43.5t-284.5 125.5q-129 84 -197.5 193t-68.5 231q0 29 5 66q-48 31 -77 81.5t-29 109.5q0 94 66 160t160 66q83 0 148 -55q248 158 592 164l134 423q4 14 17.5 21.5t28.5 4.5 l347 -82q22 50 68.5 81t102.5 31q77 0 131.5 -54.5t54.5 -131.5t-54.5 -132t-131.5 -55q-76 0 -130.5 54t-55.5 131l-315 74l-116 -366q327 -14 560 -166q64 58 151 58q94 0 160 -66t66 -160zM1664 1459q-45 0 -77 -32t-32 -77t32 -77t77 -32t77 32t32 77t-32 77t-77 32z M77 722q0 -67 51 -111q49 131 180 235q-36 25 -82 25q-62 0 -105.5 -43.5t-43.5 -105.5zM1567 105q112 73 171.5 166t59.5 194t-59.5 193.5t-171.5 165.5q-116 75 -265.5 115.5t-313.5 40.5t-313.5 -40.5t-265.5 -115.5q-112 -73 -171.5 -165.5t-59.5 -193.5t59.5 -194 t171.5 -166q116 -75 265.5 -115.5t313.5 -40.5t313.5 40.5t265.5 115.5zM1850 605q57 46 57 117q0 62 -43.5 105.5t-105.5 43.5q-49 0 -86 -28q131 -105 178 -238zM1258 237q11 11 27 11t27 -11t11 -27.5t-11 -27.5q-99 -99 -319 -99h-2q-220 0 -319 99q-11 11 -11 27.5 t11 27.5t27 11t27 -11q77 -77 265 -77h2q188 0 265 77z" />
+<glyph unicode="&#xf1a2;" d="M950 393q7 7 17.5 7t17.5 -7t7 -18t-7 -18q-65 -64 -208 -64h-1h-1q-143 0 -207 64q-8 7 -8 18t8 18q7 7 17.5 7t17.5 -7q49 -51 172 -51h1h1q122 0 173 51zM671 613q0 -37 -26 -64t-63 -27t-63 27t-26 64t26 63t63 26t63 -26t26 -63zM1214 1049q-29 0 -50 21t-21 50 q0 30 21 51t50 21q30 0 51 -21t21 -51q0 -29 -21 -50t-51 -21zM1216 1408q132 0 226 -94t94 -227v-894q0 -133 -94 -227t-226 -94h-896q-132 0 -226 94t-94 227v894q0 133 94 227t226 94h896zM1321 596q35 14 57 45.5t22 70.5q0 51 -36 87.5t-87 36.5q-60 0 -98 -48 q-151 107 -375 115l83 265l206 -49q1 -50 36.5 -85t84.5 -35q50 0 86 35.5t36 85.5t-36 86t-86 36q-36 0 -66 -20.5t-45 -53.5l-227 54q-9 2 -17.5 -2.5t-11.5 -14.5l-95 -302q-224 -4 -381 -113q-36 43 -93 43q-51 0 -87 -36.5t-36 -87.5q0 -37 19.5 -67.5t52.5 -45.5 q-7 -25 -7 -54q0 -98 74 -181.5t201.5 -132t278.5 -48.5q150 0 277.5 48.5t201.5 132t74 181.5q0 27 -6 54zM971 702q37 0 63 -26t26 -63t-26 -64t-63 -27t-63 27t-26 64t26 63t63 26z" />
+<glyph unicode="&#xf1a3;" d="M866 697l90 27v62q0 79 -58 135t-138 56t-138 -55.5t-58 -134.5v-283q0 -20 -14 -33.5t-33 -13.5t-32.5 13.5t-13.5 33.5v120h-151v-122q0 -82 57.5 -139t139.5 -57q81 0 138.5 56.5t57.5 136.5v280q0 19 13.5 33t33.5 14q19 0 32.5 -14t13.5 -33v-54zM1199 502v122h-150 v-126q0 -20 -13.5 -33.5t-33.5 -13.5q-19 0 -32.5 14t-13.5 33v123l-90 -26l-60 28v-123q0 -80 58 -137t139 -57t138.5 57t57.5 139zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103 t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1a4;" horiz-adv-x="1920" d="M1062 824v118q0 42 -30 72t-72 30t-72 -30t-30 -72v-612q0 -175 -126 -299t-303 -124q-178 0 -303.5 125.5t-125.5 303.5v266h328v-262q0 -43 30 -72.5t72 -29.5t72 29.5t30 72.5v620q0 171 126.5 292t301.5 121q176 0 302 -122t126 -294v-136l-195 -58zM1592 602h328 v-266q0 -178 -125.5 -303.5t-303.5 -125.5q-177 0 -303 124.5t-126 300.5v268l131 -61l195 58v-270q0 -42 30 -71.5t72 -29.5t72 29.5t30 71.5v275z" />
+<glyph unicode="&#xf1a5;" d="M1472 160v480h-704v704h-480q-93 0 -158.5 -65.5t-65.5 -158.5v-480h704v-704h480q93 0 158.5 65.5t65.5 158.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf1a6;" horiz-adv-x="2048" d="M328 1254h204v-983h-532v697h328v286zM328 435v369h-123v-369h123zM614 968v-697h205v697h-205zM614 1254v-204h205v204h-205zM901 968h533v-942h-533v163h328v82h-328v697zM1229 435v369h-123v-369h123zM1516 968h532v-942h-532v163h327v82h-327v697zM1843 435v369h-123 v-369h123z" />
+<glyph unicode="&#xf1a7;" d="M1046 516q0 -64 -38 -109t-91 -45q-43 0 -70 15v277q28 17 70 17q53 0 91 -45.5t38 -109.5zM703 944q0 -64 -38 -109.5t-91 -45.5q-43 0 -70 15v277q28 17 70 17q53 0 91 -45t38 -109zM1265 513q0 134 -88 229t-213 95q-20 0 -39 -3q-23 -78 -78 -136q-87 -95 -211 -101 v-636l211 41v206q51 -19 117 -19q125 0 213 95t88 229zM922 940q0 134 -88.5 229t-213.5 95q-74 0 -141 -36h-186v-840l211 41v206q55 -19 116 -19q125 0 213.5 95t88.5 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1a8;" horiz-adv-x="2038" d="M1222 607q75 3 143.5 -20.5t118 -58.5t101 -94.5t84 -108t75.5 -120.5q33 -56 78.5 -109t75.5 -80.5t99 -88.5q-48 -30 -108.5 -57.5t-138.5 -59t-114 -47.5q-44 37 -74 115t-43.5 164.5t-33 180.5t-42.5 168.5t-72.5 123t-122.5 48.5l-10 -2l-6 -4q4 -5 13 -14 q6 -5 28 -23.5t25.5 -22t19 -18t18 -20.5t11.5 -21t10.5 -27.5t4.5 -31t4 -40.5l1 -33q1 -26 -2.5 -57.5t-7.5 -52t-12.5 -58.5t-11.5 -53q-35 1 -101 -9.5t-98 -10.5q-39 0 -72 10q-2 16 -2 47q0 74 3 96q2 13 31.5 41.5t57 59t26.5 51.5q-24 2 -43 -24 q-36 -53 -111.5 -99.5t-136.5 -46.5q-25 0 -75.5 63t-106.5 139.5t-84 96.5q-6 4 -27 30q-482 -112 -513 -112q-16 0 -28 11t-12 27q0 15 8.5 26.5t22.5 14.5l486 106q-8 14 -8 25t5.5 17.5t16 11.5t20 7t23 4.5t18.5 4.5q4 1 15.5 7.5t17.5 6.5q15 0 28 -16t20 -33 q163 37 172 37q17 0 29.5 -11t12.5 -28q0 -15 -8.5 -26t-23.5 -14l-182 -40l-1 -16q-1 -26 81.5 -117.5t104.5 -91.5q47 0 119 80t72 129q0 36 -23.5 53t-51 18.5t-51 11.5t-23.5 34q0 16 10 34l-68 19q43 44 43 117q0 26 -5 58q82 16 144 16q44 0 71.5 -1.5t48.5 -8.5 t31 -13.5t20.5 -24.5t15.5 -33.5t17 -47.5t24 -60l50 25q-3 -40 -23 -60t-42.5 -21t-40 -6.5t-16.5 -20.5zM1282 842q-5 5 -13.5 15.5t-12 14.5t-10.5 11.5t-10 10.5l-8 8t-8.5 7.5t-8 5t-8.5 4.5q-7 3 -14.5 5t-20.5 2.5t-22 0.5h-32.5h-37.5q-126 0 -217 -43 q16 30 36 46.5t54 29.5t65.5 36t46 36.5t50 55t43.5 50.5q12 -9 28 -31.5t32 -36.5t38 -13l12 1v-76l22 -1q247 95 371 190q28 21 50 39t42.5 37.5t33 31t29.5 34t24 31t24.5 37t23 38t27 47.5t29.5 53l7 9q-2 -53 -43 -139q-79 -165 -205 -264t-306 -142q-14 -3 -42 -7.5 t-50 -9.5t-39 -14q3 -19 24.5 -46t21.5 -34q0 -11 -26 -30zM1061 -79q39 26 131.5 47.5t146.5 21.5q9 0 22.5 -15.5t28 -42.5t26 -50t24 -51t14.5 -33q-121 -45 -244 -45q-61 0 -125 11zM822 568l48 12l109 -177l-73 -48zM1323 51q3 -15 3 -16q0 -7 -17.5 -14.5t-46 -13 t-54 -9.5t-53.5 -7.5t-32 -4.5l-7 43q21 2 60.5 8.5t72 10t60.5 3.5h14zM866 679l-96 -20l-6 17q10 1 32.5 7t34.5 6q19 0 35 -10zM1061 45h31l10 -83l-41 -12v95zM1950 1535v1v-1zM1950 1535l-1 -5l-2 -2l1 3zM1950 1535l1 1z" />
+<glyph unicode="&#xf1a9;" d="M1167 -50q-5 19 -24 5q-30 -22 -87 -39t-131 -17q-129 0 -193 49q-5 4 -13 4q-11 0 -26 -12q-7 -6 -7.5 -16t7.5 -20q34 -32 87.5 -46t102.5 -12.5t99 4.5q41 4 84.5 20.5t65 30t28.5 20.5q12 12 7 29zM1128 65q-19 47 -39 61q-23 15 -76 15q-47 0 -71 -10 q-29 -12 -78 -56q-26 -24 -12 -44q9 -8 17.5 -4.5t31.5 23.5q3 2 10.5 8.5t10.5 8.5t10 7t11.5 7t12.5 5t15 4.5t16.5 2.5t20.5 1q27 0 44.5 -7.5t23 -14.5t13.5 -22q10 -17 12.5 -20t12.5 1q23 12 14 34zM1483 346q0 22 -5 44.5t-16.5 45t-34 36.5t-52.5 14 q-33 0 -97 -41.5t-129 -83.5t-101 -42q-27 -1 -63.5 19t-76 49t-83.5 58t-100 49t-111 19q-115 -1 -197 -78.5t-84 -178.5q-2 -112 74 -164q29 -20 62.5 -28.5t103.5 -8.5q57 0 132 32.5t134 71t120 70.5t93 31q26 -1 65 -31.5t71.5 -67t68 -67.5t55.5 -32q35 -3 58.5 14 t55.5 63q28 41 42.5 101t14.5 106zM1536 506q0 -164 -62 -304.5t-166 -236t-242.5 -149.5t-290.5 -54t-293 57.5t-247.5 157t-170.5 241.5t-64 302q0 89 19.5 172.5t49 145.5t70.5 118.5t78.5 94t78.5 69.5t64.5 46.5t42.5 24.5q14 8 51 26.5t54.5 28.5t48 30t60.5 44 q36 28 58 72.5t30 125.5q129 -155 186 -193q44 -29 130 -68t129 -66q21 -13 39 -25t60.5 -46.5t76 -70.5t75 -95t69 -122t47 -148.5t19.5 -177.5z" />
+<glyph unicode="&#xf1aa;" d="M1070 463l-160 -160l-151 -152l-30 -30q-65 -64 -151.5 -87t-171.5 -2q-16 -70 -72 -115t-129 -45q-85 0 -145 60.5t-60 145.5q0 72 44.5 128t113.5 72q-22 86 1 173t88 152l12 12l151 -152l-11 -11q-37 -37 -37 -89t37 -90q37 -37 89 -37t89 37l30 30l151 152l161 160z M729 1145l12 -12l-152 -152l-12 12q-37 37 -89 37t-89 -37t-37 -89.5t37 -89.5l29 -29l152 -152l160 -160l-151 -152l-161 160l-151 152l-30 30q-68 67 -90 159.5t5 179.5q-70 15 -115 71t-45 129q0 85 60 145.5t145 60.5q76 0 133.5 -49t69.5 -123q84 20 169.5 -3.5 t149.5 -87.5zM1536 78q0 -85 -60 -145.5t-145 -60.5q-74 0 -131 47t-71 118q-86 -28 -179.5 -6t-161.5 90l-11 12l151 152l12 -12q37 -37 89 -37t89 37t37 89t-37 89l-30 30l-152 152l-160 160l152 152l160 -160l152 -152l29 -30q64 -64 87.5 -150.5t2.5 -171.5 q76 -11 126.5 -68.5t50.5 -134.5zM1534 1202q0 -77 -51 -135t-127 -69q26 -85 3 -176.5t-90 -158.5l-12 -12l-151 152l12 12q37 37 37 89t-37 89t-89 37t-89 -37l-30 -30l-152 -152l-160 -160l-152 152l161 160l152 152l29 30q67 67 159 89.5t178 -3.5q11 75 68.5 126 t135.5 51q85 0 145 -60.5t60 -145.5z" />
+<glyph unicode="&#xf1ab;" d="M654 458q-1 -3 -12.5 0.5t-31.5 11.5l-20 9q-44 20 -87 49q-7 5 -41 31.5t-38 28.5q-67 -103 -134 -181q-81 -95 -105 -110q-4 -2 -19.5 -4t-18.5 0q6 4 82 92q21 24 85.5 115t78.5 118q17 30 51 98.5t36 77.5q-8 1 -110 -33q-8 -2 -27.5 -7.5t-34.5 -9.5t-17 -5 q-2 -2 -2 -10.5t-1 -9.5q-5 -10 -31 -15q-23 -7 -47 0q-18 4 -28 21q-4 6 -5 23q6 2 24.5 5t29.5 6q58 16 105 32q100 35 102 35q10 2 43 19.5t44 21.5q9 3 21.5 8t14.5 5.5t6 -0.5q2 -12 -1 -33q0 -2 -12.5 -27t-26.5 -53.5t-17 -33.5q-25 -50 -77 -131l64 -28 q12 -6 74.5 -32t67.5 -28q4 -1 10.5 -25.5t4.5 -30.5zM449 944q3 -15 -4 -28q-12 -23 -50 -38q-30 -12 -60 -12q-26 3 -49 26q-14 15 -18 41l1 3q3 -3 19.5 -5t26.5 0t58 16q36 12 55 14q17 0 21 -17zM1147 815l63 -227l-139 42zM39 15l694 232v1032l-694 -233v-1031z M1280 332l102 -31l-181 657l-100 31l-216 -536l102 -31l45 110l211 -65zM777 1294l573 -184v380zM1088 -29l158 -13l-54 -160l-40 66q-130 -83 -276 -108q-58 -12 -91 -12h-84q-79 0 -199.5 39t-183.5 85q-8 7 -8 16q0 8 5 13.5t13 5.5q4 0 18 -7.5t30.5 -16.5t20.5 -11 q73 -37 159.5 -61.5t157.5 -24.5q95 0 167 14.5t157 50.5q15 7 30.5 15.5t34 19t28.5 16.5zM1536 1050v-1079l-774 246q-14 -6 -375 -127.5t-368 -121.5q-13 0 -18 13q0 1 -1 3v1078q3 9 4 10q5 6 20 11q106 35 149 50v384l558 -198q2 0 160.5 55t316 108.5t161.5 53.5 q20 0 20 -21v-418z" />
+<glyph unicode="&#xf1ac;" horiz-adv-x="1792" d="M288 1152q66 0 113 -47t47 -113v-1088q0 -66 -47 -113t-113 -47h-128q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h128zM1664 989q58 -34 93 -93t35 -128v-768q0 -106 -75 -181t-181 -75h-864q-66 0 -113 47t-47 113v1536q0 40 28 68t68 28h672q40 0 88 -20t76 -48 l152 -152q28 -28 48 -76t20 -88v-163zM928 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 512v128q0 14 -9 23 t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128 q14 0 23 9t9 23zM1184 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 256v128q0 14 -9 23t-23 9h-128 q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1536 896v256h-160q-40 0 -68 28t-28 68v160h-640v-512h896z" />
+<glyph unicode="&#xf1ad;" d="M1344 1536q26 0 45 -19t19 -45v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280zM512 1248v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 992v-64q0 -14 9 -23t23 -9h64q14 0 23 9 t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 736v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 480v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 160v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM384 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 -96v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9 t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM896 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 928v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 160v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9 t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23z" />
+<glyph unicode="&#xf1ae;" horiz-adv-x="1280" d="M1188 988l-292 -292v-824q0 -46 -33 -79t-79 -33t-79 33t-33 79v384h-64v-384q0 -46 -33 -79t-79 -33t-79 33t-33 79v824l-292 292q-28 28 -28 68t28 68t68 28t68 -28l228 -228h368l228 228q28 28 68 28t68 -28t28 -68t-28 -68zM864 1152q0 -93 -65.5 -158.5 t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf1b0;" horiz-adv-x="1664" d="M780 1064q0 -60 -19 -113.5t-63 -92.5t-105 -39q-76 0 -138 57.5t-92 135.5t-30 151q0 60 19 113.5t63 92.5t105 39q77 0 138.5 -57.5t91.5 -135t30 -151.5zM438 581q0 -80 -42 -139t-119 -59q-76 0 -141.5 55.5t-100.5 133.5t-35 152q0 80 42 139.5t119 59.5 q76 0 141.5 -55.5t100.5 -134t35 -152.5zM832 608q118 0 255 -97.5t229 -237t92 -254.5q0 -46 -17 -76.5t-48.5 -45t-64.5 -20t-76 -5.5q-68 0 -187.5 45t-182.5 45q-66 0 -192.5 -44.5t-200.5 -44.5q-183 0 -183 146q0 86 56 191.5t139.5 192.5t187.5 146t193 59zM1071 819 q-61 0 -105 39t-63 92.5t-19 113.5q0 74 30 151.5t91.5 135t138.5 57.5q61 0 105 -39t63 -92.5t19 -113.5q0 -73 -30 -151t-92 -135.5t-138 -57.5zM1503 923q77 0 119 -59.5t42 -139.5q0 -74 -35 -152t-100.5 -133.5t-141.5 -55.5q-77 0 -119 59t-42 139q0 74 35 152.5 t100.5 134t141.5 55.5z" />
+<glyph unicode="&#xf1b1;" horiz-adv-x="768" d="M704 1008q0 -145 -57 -243.5t-152 -135.5l45 -821q2 -26 -16 -45t-44 -19h-192q-26 0 -44 19t-16 45l45 821q-95 37 -152 135.5t-57 243.5q0 128 42.5 249.5t117.5 200t160 78.5t160 -78.5t117.5 -200t42.5 -249.5z" />
+<glyph unicode="&#xf1b2;" horiz-adv-x="1792" d="M896 -93l640 349v636l-640 -233v-752zM832 772l698 254l-698 254l-698 -254zM1664 1024v-768q0 -35 -18 -65t-49 -47l-704 -384q-28 -16 -61 -16t-61 16l-704 384q-31 17 -49 47t-18 65v768q0 40 23 73t61 47l704 256q22 8 44 8t44 -8l704 -256q38 -14 61 -47t23 -73z " />
+<glyph unicode="&#xf1b3;" horiz-adv-x="2304" d="M640 -96l384 192v314l-384 -164v-342zM576 358l404 173l-404 173l-404 -173zM1664 -96l384 192v314l-384 -164v-342zM1600 358l404 173l-404 173l-404 -173zM1152 651l384 165v266l-384 -164v-267zM1088 1030l441 189l-441 189l-441 -189zM2176 512v-416q0 -36 -19 -67 t-52 -47l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-5 2 -7 4q-2 -2 -7 -4l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-33 16 -52 47t-19 67v416q0 38 21.5 70t56.5 48l434 186v400q0 38 21.5 70t56.5 48l448 192q23 10 50 10t50 -10l448 -192q35 -16 56.5 -48t21.5 -70 v-400l434 -186q36 -16 57 -48t21 -70z" />
+<glyph unicode="&#xf1b4;" horiz-adv-x="2048" d="M1848 1197h-511v-124h511v124zM1596 771q-90 0 -146 -52.5t-62 -142.5h408q-18 195 -200 195zM1612 186q63 0 122 32t76 87h221q-100 -307 -427 -307q-214 0 -340.5 132t-126.5 347q0 208 130.5 345.5t336.5 137.5q138 0 240.5 -68t153 -179t50.5 -248q0 -17 -2 -47h-658 q0 -111 57.5 -171.5t166.5 -60.5zM277 236h296q205 0 205 167q0 180 -199 180h-302v-347zM277 773h281q78 0 123.5 36.5t45.5 113.5q0 144 -190 144h-260v-294zM0 1282h594q87 0 155 -14t126.5 -47.5t90 -96.5t31.5 -154q0 -181 -172 -263q114 -32 172 -115t58 -204 q0 -75 -24.5 -136.5t-66 -103.5t-98.5 -71t-121 -42t-134 -13h-611v1260z" />
+<glyph unicode="&#xf1b5;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM499 1041h-371v-787h382q117 0 197 57.5t80 170.5q0 158 -143 200q107 52 107 164q0 57 -19.5 96.5 t-56.5 60.5t-79 29.5t-97 8.5zM477 723h-176v184h163q119 0 119 -90q0 -94 -106 -94zM486 388h-185v217h189q124 0 124 -113q0 -104 -128 -104zM1136 356q-68 0 -104 38t-36 107h411q1 10 1 30q0 132 -74.5 220.5t-203.5 88.5q-128 0 -210 -86t-82 -216q0 -135 79 -217 t213 -82q205 0 267 191h-138q-11 -34 -47.5 -54t-75.5 -20zM1126 722q113 0 124 -122h-254q4 56 39 89t91 33zM964 988h319v-77h-319v77z" />
+<glyph unicode="&#xf1b6;" horiz-adv-x="1792" d="M1582 954q0 -101 -71.5 -172.5t-172.5 -71.5t-172.5 71.5t-71.5 172.5t71.5 172.5t172.5 71.5t172.5 -71.5t71.5 -172.5zM812 212q0 104 -73 177t-177 73q-27 0 -54 -6l104 -42q77 -31 109.5 -106.5t1.5 -151.5q-31 -77 -107 -109t-152 -1q-21 8 -62 24.5t-61 24.5 q32 -60 91 -96.5t130 -36.5q104 0 177 73t73 177zM1642 953q0 126 -89.5 215.5t-215.5 89.5q-127 0 -216.5 -89.5t-89.5 -215.5q0 -127 89.5 -216t216.5 -89q126 0 215.5 89t89.5 216zM1792 953q0 -189 -133.5 -322t-321.5 -133l-437 -319q-12 -129 -109 -218t-229 -89 q-121 0 -214 76t-118 192l-230 92v429l389 -157q79 48 173 48q13 0 35 -2l284 407q2 187 135.5 319t320.5 132q188 0 321.5 -133.5t133.5 -321.5z" />
+<glyph unicode="&#xf1b7;" d="M1242 889q0 80 -57 136.5t-137 56.5t-136.5 -57t-56.5 -136q0 -80 56.5 -136.5t136.5 -56.5t137 56.5t57 136.5zM632 301q0 -83 -58 -140.5t-140 -57.5q-56 0 -103 29t-72 77q52 -20 98 -40q60 -24 120 1.5t85 86.5q24 60 -1.5 120t-86.5 84l-82 33q22 5 42 5 q82 0 140 -57.5t58 -140.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v153l172 -69q20 -92 93.5 -152t168.5 -60q104 0 181 70t87 173l345 252q150 0 255.5 105.5t105.5 254.5q0 150 -105.5 255.5t-255.5 105.5 q-148 0 -253 -104.5t-107 -252.5l-225 -322q-9 1 -28 1q-75 0 -137 -37l-297 119v468q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5zM1289 887q0 -100 -71 -170.5t-171 -70.5t-170.5 70.5t-70.5 170.5t70.5 171t170.5 71q101 0 171.5 -70.5t70.5 -171.5z " />
+<glyph unicode="&#xf1b8;" horiz-adv-x="1792" d="M836 367l-15 -368l-2 -22l-420 29q-36 3 -67 31.5t-47 65.5q-11 27 -14.5 55t4 65t12 55t21.5 64t19 53q78 -12 509 -28zM449 953l180 -379l-147 92q-63 -72 -111.5 -144.5t-72.5 -125t-39.5 -94.5t-18.5 -63l-4 -21l-190 357q-17 26 -18 56t6 47l8 18q35 63 114 188 l-140 86zM1680 436l-188 -359q-12 -29 -36.5 -46.5t-43.5 -20.5l-18 -4q-71 -7 -219 -12l8 -164l-230 367l211 362l7 -173q170 -16 283 -5t170 33zM895 1360q-47 -63 -265 -435l-317 187l-19 12l225 356q20 31 60 45t80 10q24 -2 48.5 -12t42 -21t41.5 -33t36 -34.5 t36 -39.5t32 -35zM1550 1053l212 -363q18 -37 12.5 -76t-27.5 -74q-13 -20 -33 -37t-38 -28t-48.5 -22t-47 -16t-51.5 -14t-46 -12q-34 72 -265 436l313 195zM1407 1279l142 83l-220 -373l-419 20l151 86q-34 89 -75 166t-75.5 123.5t-64.5 80t-47 46.5l-17 13l405 -1 q31 3 58 -10.5t39 -28.5l11 -15q39 -61 112 -190z" />
+<glyph unicode="&#xf1b9;" horiz-adv-x="2048" d="M480 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM516 768h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5zM1888 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM2048 544v-384 q0 -14 -9 -23t-23 -9h-96v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-1024v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5t179 63.5h768q98 0 179 -63.5t104 -157.5 l105 -419h28q93 0 158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf1ba;" horiz-adv-x="2048" d="M1824 640q93 0 158.5 -65.5t65.5 -158.5v-384q0 -14 -9 -23t-23 -9h-96v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-1024v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5 t179 63.5h128v224q0 14 9 23t23 9h448q14 0 23 -9t9 -23v-224h128q98 0 179 -63.5t104 -157.5l105 -419h28zM320 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM516 640h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5z M1728 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47z" />
+<glyph unicode="&#xf1bb;" d="M1504 64q0 -26 -19 -45t-45 -19h-462q1 -17 6 -87.5t5 -108.5q0 -25 -18 -42.5t-43 -17.5h-320q-25 0 -43 17.5t-18 42.5q0 38 5 108.5t6 87.5h-462q-26 0 -45 19t-19 45t19 45l402 403h-229q-26 0 -45 19t-19 45t19 45l402 403h-197q-26 0 -45 19t-19 45t19 45l384 384 q19 19 45 19t45 -19l384 -384q19 -19 19 -45t-19 -45t-45 -19h-197l402 -403q19 -19 19 -45t-19 -45t-45 -19h-229l402 -403q19 -19 19 -45z" />
+<glyph unicode="&#xf1bc;" d="M1127 326q0 32 -30 51q-193 115 -447 115q-133 0 -287 -34q-42 -9 -42 -52q0 -20 13.5 -34.5t35.5 -14.5q5 0 37 8q132 27 243 27q226 0 397 -103q19 -11 33 -11q19 0 33 13.5t14 34.5zM1223 541q0 40 -35 61q-237 141 -548 141q-153 0 -303 -42q-48 -13 -48 -64 q0 -25 17.5 -42.5t42.5 -17.5q7 0 37 8q122 33 251 33q279 0 488 -124q24 -13 38 -13q25 0 42.5 17.5t17.5 42.5zM1331 789q0 47 -40 70q-126 73 -293 110.5t-343 37.5q-204 0 -364 -47q-23 -7 -38.5 -25.5t-15.5 -48.5q0 -31 20.5 -52t51.5 -21q11 0 40 8q133 37 307 37 q159 0 309.5 -34t253.5 -95q21 -12 40 -12q29 0 50.5 20.5t21.5 51.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1bd;" d="M1397 1408q58 0 98.5 -40.5t40.5 -98.5v-1258q0 -58 -40.5 -98.5t-98.5 -40.5h-1258q-58 0 -98.5 40.5t-40.5 98.5v1258q0 58 40.5 98.5t98.5 40.5h1258zM1465 11v1258q0 28 -20 48t-48 20h-1258q-28 0 -48 -20t-20 -48v-1258q0 -28 20 -48t48 -20h1258q28 0 48 20t20 48 zM694 749l188 -387l533 145v-496q0 -7 -5.5 -12.5t-12.5 -5.5h-1258q-7 0 -12.5 5.5t-5.5 12.5v141l711 195l-212 439q4 1 12 2.5t12 1.5q170 32 303.5 21.5t221 -46t143.5 -94.5q27 -28 -25 -42q-64 -16 -256 -62l-97 198q-111 7 -240 -16zM1397 1287q7 0 12.5 -5.5 t5.5 -12.5v-428q-85 30 -188 52q-294 64 -645 12l-18 -3l-65 134h-233l85 -190q-132 -51 -230 -137v560q0 7 5.5 12.5t12.5 5.5h1258zM286 387q-14 -3 -26 4.5t-14 21.5q-24 203 166 305l129 -270z" />
+<glyph unicode="&#xf1be;" horiz-adv-x="2304" d="M784 164l16 241l-16 523q-1 10 -7.5 17t-16.5 7q-9 0 -16 -7t-7 -17l-14 -523l14 -241q1 -10 7.5 -16.5t15.5 -6.5q22 0 24 23zM1080 193l11 211l-12 586q0 16 -13 24q-8 5 -16 5t-16 -5q-13 -8 -13 -24l-1 -6l-10 -579q0 -1 11 -236v-1q0 -10 6 -17q9 -11 23 -11 q11 0 20 9q9 7 9 20zM35 533l20 -128l-20 -126q-2 -9 -9 -9t-9 9l-17 126l17 128q2 9 9 9t9 -9zM121 612l26 -207l-26 -203q-2 -9 -10 -9q-9 0 -9 10l-23 202l23 207q0 9 9 9q8 0 10 -9zM401 159zM213 650l25 -245l-25 -237q0 -11 -11 -11q-10 0 -12 11l-21 237l21 245 q2 12 12 12q11 0 11 -12zM307 657l23 -252l-23 -244q-2 -13 -14 -13q-13 0 -13 13l-21 244l21 252q0 13 13 13q12 0 14 -13zM401 639l21 -234l-21 -246q-2 -16 -16 -16q-6 0 -10.5 4.5t-4.5 11.5l-20 246l20 234q0 6 4.5 10.5t10.5 4.5q14 0 16 -15zM784 164zM495 785 l21 -380l-21 -246q0 -7 -5 -12.5t-12 -5.5q-16 0 -18 18l-18 246l18 380q2 18 18 18q7 0 12 -5.5t5 -12.5zM589 871l19 -468l-19 -244q0 -8 -5.5 -13.5t-13.5 -5.5q-18 0 -20 19l-16 244l16 468q2 19 20 19q8 0 13.5 -5.5t5.5 -13.5zM687 911l18 -506l-18 -242 q-2 -21 -22 -21q-19 0 -21 21l-16 242l16 506q0 9 6.5 15.5t14.5 6.5q9 0 15 -6.5t7 -15.5zM1079 169v0v0zM881 915l15 -510l-15 -239q0 -10 -7.5 -17.5t-17.5 -7.5t-17 7t-8 18l-14 239l14 510q0 11 7.5 18t17.5 7t17.5 -7t7.5 -18zM980 896l14 -492l-14 -236q0 -11 -8 -19 t-19 -8t-19 8t-9 19l-12 236l12 492q1 12 9 20t19 8t18.5 -8t8.5 -20zM1192 404l-14 -231v0q0 -13 -9 -22t-22 -9t-22 9t-10 22l-6 114l-6 117l12 636v3q2 15 12 24q9 7 20 7q8 0 15 -5q14 -8 16 -26zM2304 423q0 -117 -83 -199.5t-200 -82.5h-786q-13 2 -22 11t-9 22v899 q0 23 28 33q85 34 181 34q195 0 338 -131.5t160 -323.5q53 22 110 22q117 0 200 -83t83 -201z" />
+<glyph unicode="&#xf1c0;" d="M768 768q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 0q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127 t443 -43zM768 384q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 1536q208 0 385 -34.5t280 -93.5t103 -128v-128q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5 t-103 128v128q0 69 103 128t280 93.5t385 34.5z" />
+<glyph unicode="&#xf1c1;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M894 465q33 -26 84 -56q59 7 117 7q147 0 177 -49q16 -22 2 -52q0 -1 -1 -2l-2 -2v-1q-6 -38 -71 -38q-48 0 -115 20t-130 53q-221 -24 -392 -83q-153 -262 -242 -262q-15 0 -28 7l-24 12q-1 1 -6 5q-10 10 -6 36q9 40 56 91.5t132 96.5q14 9 23 -6q2 -2 2 -4q52 85 107 197 q68 136 104 262q-24 82 -30.5 159.5t6.5 127.5q11 40 42 40h21h1q23 0 35 -15q18 -21 9 -68q-2 -6 -4 -8q1 -3 1 -8v-30q-2 -123 -14 -192q55 -164 146 -238zM318 54q52 24 137 158q-51 -40 -87.5 -84t-49.5 -74zM716 974q-15 -42 -2 -132q1 7 7 44q0 3 7 43q1 4 4 8 q-1 1 -1 2t-0.5 1.5t-0.5 1.5q-1 22 -13 36q0 -1 -1 -2v-2zM592 313q135 54 284 81q-2 1 -13 9.5t-16 13.5q-76 67 -127 176q-27 -86 -83 -197q-30 -56 -45 -83zM1238 329q-24 24 -140 24q76 -28 124 -28q14 0 18 1q0 1 -2 3z" />
+<glyph unicode="&#xf1c2;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M233 768v-107h70l164 -661h159l128 485q7 20 10 46q2 16 2 24h4l3 -24q1 -3 3.5 -20t5.5 -26l128 -485h159l164 661h70v107h-300v-107h90l-99 -438q-5 -20 -7 -46l-2 -21h-4l-3 21q-1 5 -4 21t-5 25l-144 545h-114l-144 -545q-2 -9 -4.5 -24.5t-3.5 -21.5l-4 -21h-4l-2 21 q-2 26 -7 46l-99 438h90v107h-300z" />
+<glyph unicode="&#xf1c3;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M429 106v-106h281v106h-75l103 161q5 7 10 16.5t7.5 13.5t3.5 4h2q1 -4 5 -10q2 -4 4.5 -7.5t6 -8t6.5 -8.5l107 -161h-76v-106h291v106h-68l-192 273l195 282h67v107h-279v-107h74l-103 -159q-4 -7 -10 -16.5t-9 -13.5l-2 -3h-2q-1 4 -5 10q-6 11 -17 23l-106 159h76v107 h-290v-107h68l189 -272l-194 -283h-68z" />
+<glyph unicode="&#xf1c4;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M416 106v-106h327v106h-93v167h137q76 0 118 15q67 23 106.5 87t39.5 146q0 81 -37 141t-100 87q-48 19 -130 19h-368v-107h92v-555h-92zM769 386h-119v268h120q52 0 83 -18q56 -33 56 -115q0 -89 -62 -120q-31 -15 -78 -15z" />
+<glyph unicode="&#xf1c5;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M1280 320v-320h-1024v192l192 192l128 -128l384 384zM448 512q-80 0 -136 56t-56 136t56 136t136 56t136 -56t56 -136t-56 -136t-136 -56z" />
+<glyph unicode="&#xf1c6;" d="M640 1152v128h-128v-128h128zM768 1024v128h-128v-128h128zM640 896v128h-128v-128h128zM768 768v128h-128v-128h128zM1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400 v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-128v-128h-128v128h-512v-1536h1280zM781 593l107 -349q8 -27 8 -52q0 -83 -72.5 -137.5t-183.5 -54.5t-183.5 54.5t-72.5 137.5q0 25 8 52q21 63 120 396v128h128v-128h79 q22 0 39 -13t23 -34zM640 128q53 0 90.5 19t37.5 45t-37.5 45t-90.5 19t-90.5 -19t-37.5 -45t37.5 -45t90.5 -19z" />
+<glyph unicode="&#xf1c7;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M620 686q20 -8 20 -30v-544q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-166 167h-131q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h131l166 167q16 15 35 7zM1037 -3q31 0 50 24q129 159 129 363t-129 363q-16 21 -43 24t-47 -14q-21 -17 -23.5 -43.5t14.5 -47.5 q100 -123 100 -282t-100 -282q-17 -21 -14.5 -47.5t23.5 -42.5q18 -15 40 -15zM826 145q27 0 47 20q87 93 87 219t-87 219q-18 19 -45 20t-46 -17t-20 -44.5t18 -46.5q52 -57 52 -131t-52 -131q-19 -20 -18 -46.5t20 -44.5q20 -17 44 -17z" />
+<glyph unicode="&#xf1c8;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M768 768q52 0 90 -38t38 -90v-384q0 -52 -38 -90t-90 -38h-384q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h384zM1260 766q20 -8 20 -30v-576q0 -22 -20 -30q-8 -2 -12 -2q-14 0 -23 9l-265 266v90l265 266q9 9 23 9q4 0 12 -2z" />
+<glyph unicode="&#xf1c9;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M480 768q8 11 21 12.5t24 -6.5l51 -38q11 -8 12.5 -21t-6.5 -24l-182 -243l182 -243q8 -11 6.5 -24t-12.5 -21l-51 -38q-11 -8 -24 -6.5t-21 12.5l-226 301q-14 19 0 38zM1282 467q14 -19 0 -38l-226 -301q-8 -11 -21 -12.5t-24 6.5l-51 38q-11 8 -12.5 21t6.5 24l182 243 l-182 243q-8 11 -6.5 24t12.5 21l51 38q11 8 24 6.5t21 -12.5zM662 6q-13 2 -20.5 13t-5.5 24l138 831q2 13 13 20.5t24 5.5l63 -10q13 -2 20.5 -13t5.5 -24l-138 -831q-2 -13 -13 -20.5t-24 -5.5z" />
+<glyph unicode="&#xf1ca;" d="M1497 709v-198q-101 -23 -198 -23q-65 -136 -165.5 -271t-181.5 -215.5t-128 -106.5q-80 -45 -162 3q-28 17 -60.5 43.5t-85 83.5t-102.5 128.5t-107.5 184t-105.5 244t-91.5 314.5t-70.5 390h283q26 -218 70 -398.5t104.5 -317t121.5 -235.5t140 -195q169 169 287 406 q-142 72 -223 220t-81 333q0 192 104 314.5t284 122.5q178 0 273 -105.5t95 -297.5q0 -159 -58 -286q-7 -1 -19.5 -3t-46 -2t-63 6t-62 25.5t-50.5 51.5q31 103 31 184q0 87 -29 132t-79 45q-53 0 -85 -49.5t-32 -140.5q0 -186 105 -293.5t267 -107.5q62 0 121 14z" />
+<glyph unicode="&#xf1cb;" horiz-adv-x="1792" d="M216 367l603 -402v359l-334 223zM154 511l193 129l-193 129v-258zM973 -35l603 402l-269 180l-334 -223v-359zM896 458l272 182l-272 182l-272 -182zM485 733l334 223v359l-603 -402zM1445 640l193 -129v258zM1307 733l269 180l-603 402v-359zM1792 913v-546 q0 -41 -34 -64l-819 -546q-21 -13 -43 -13t-43 13l-819 546q-34 23 -34 64v546q0 41 34 64l819 546q21 13 43 13t43 -13l819 -546q34 -23 34 -64z" />
+<glyph unicode="&#xf1cc;" horiz-adv-x="2048" d="M1800 764q111 -46 179.5 -145.5t68.5 -221.5q0 -164 -118 -280.5t-285 -116.5q-4 0 -11.5 0.5t-10.5 0.5h-1209h-1h-2h-5q-170 10 -288 125.5t-118 280.5q0 110 55 203t147 147q-12 39 -12 82q0 115 82 196t199 81q95 0 172 -58q75 154 222.5 248t326.5 94 q166 0 306 -80.5t221.5 -218.5t81.5 -301q0 -6 -0.5 -18t-0.5 -18zM468 498q0 -122 84 -193t208 -71q137 0 240 99q-16 20 -47.5 56.5t-43.5 50.5q-67 -65 -144 -65q-55 0 -93.5 33.5t-38.5 87.5q0 53 38.5 87t91.5 34q44 0 84.5 -21t73 -55t65 -75t69 -82t77 -75t97 -55 t121.5 -21q121 0 204.5 71.5t83.5 190.5q0 121 -84 192t-207 71q-143 0 -241 -97q14 -16 29.5 -34t34.5 -40t29 -34q66 64 142 64q52 0 92 -33t40 -84q0 -57 -37 -91.5t-94 -34.5q-43 0 -82.5 21t-72 55t-65.5 75t-69.5 82t-77.5 75t-96.5 55t-118.5 21q-122 0 -207 -70.5 t-85 -189.5z" />
+<glyph unicode="&#xf1cd;" horiz-adv-x="1792" d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 1408q-190 0 -361 -90l194 -194q82 28 167 28t167 -28l194 194q-171 90 -361 90zM218 279l194 194 q-28 82 -28 167t28 167l-194 194q-90 -171 -90 -361t90 -361zM896 -128q190 0 361 90l-194 194q-82 -28 -167 -28t-167 28l-194 -194q171 -90 361 -90zM896 256q159 0 271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5 t271.5 -112.5zM1380 473l194 -194q90 171 90 361t-90 361l-194 -194q28 -82 28 -167t-28 -167z" />
+<glyph unicode="&#xf1ce;" horiz-adv-x="1792" d="M1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348q0 222 101 414.5t276.5 317t390.5 155.5v-260q-221 -45 -366.5 -221t-145.5 -406q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 q0 230 -145.5 406t-366.5 221v260q215 -31 390.5 -155.5t276.5 -317t101 -414.5z" />
+<glyph unicode="&#xf1d0;" horiz-adv-x="1792" d="M19 662q8 217 116 406t305 318h5q0 -1 -1 -3q-8 -8 -28 -33.5t-52 -76.5t-60 -110.5t-44.5 -135.5t-14 -150.5t39 -157.5t108.5 -154q50 -50 102 -69.5t90.5 -11.5t69.5 23.5t47 32.5l16 16q39 51 53 116.5t6.5 122.5t-21 107t-26.5 80l-14 29q-10 25 -30.5 49.5t-43 41 t-43.5 29.5t-35 19l-13 6l104 115q39 -17 78 -52t59 -61l19 -27q1 48 -18.5 103.5t-40.5 87.5l-20 31l161 183l160 -181q-33 -46 -52.5 -102.5t-22.5 -90.5l-4 -33q22 37 61.5 72.5t67.5 52.5l28 17l103 -115q-44 -14 -85 -50t-60 -65l-19 -29q-31 -56 -48 -133.5t-7 -170 t57 -156.5q33 -45 77.5 -60.5t85 -5.5t76 26.5t57.5 33.5l21 16q60 53 96.5 115t48.5 121.5t10 121.5t-18 118t-37 107.5t-45.5 93t-45 72t-34.5 47.5l-13 17q-14 13 -7 13l10 -3q40 -29 62.5 -46t62 -50t64 -58t58.5 -65t55.5 -77t45.5 -88t38 -103t23.5 -117t10.5 -136 q3 -259 -108 -465t-312 -321t-456 -115q-185 0 -351 74t-283.5 198t-184 293t-60.5 353z" />
+<glyph unicode="&#xf1d1;" horiz-adv-x="1792" d="M874 -102v-66q-208 6 -385 109.5t-283 275.5l58 34q29 -49 73 -99l65 57q148 -168 368 -212l-17 -86q65 -12 121 -13zM276 428l-83 -28q22 -60 49 -112l-57 -33q-98 180 -98 385t98 385l57 -33q-30 -56 -49 -112l82 -28q-35 -100 -35 -212q0 -109 36 -212zM1528 251 l58 -34q-106 -172 -283 -275.5t-385 -109.5v66q56 1 121 13l-17 86q220 44 368 212l65 -57q44 50 73 99zM1377 805l-233 -80q14 -42 14 -85t-14 -85l232 -80q-31 -92 -98 -169l-185 162q-57 -67 -147 -85l48 -241q-52 -10 -98 -10t-98 10l48 241q-90 18 -147 85l-185 -162 q-67 77 -98 169l232 80q-14 42 -14 85t14 85l-233 80q33 93 99 169l185 -162q59 68 147 86l-48 240q44 10 98 10t98 -10l-48 -240q88 -18 147 -86l185 162q66 -76 99 -169zM874 1448v-66q-65 -2 -121 -13l17 -86q-220 -42 -368 -211l-65 56q-38 -42 -73 -98l-57 33 q106 172 282 275.5t385 109.5zM1705 640q0 -205 -98 -385l-57 33q27 52 49 112l-83 28q36 103 36 212q0 112 -35 212l82 28q-19 56 -49 112l57 33q98 -180 98 -385zM1585 1063l-57 -33q-35 56 -73 98l-65 -56q-148 169 -368 211l17 86q-56 11 -121 13v66q209 -6 385 -109.5 t282 -275.5zM1748 640q0 173 -67.5 331t-181.5 272t-272 181.5t-331 67.5t-331 -67.5t-272 -181.5t-181.5 -272t-67.5 -331t67.5 -331t181.5 -272t272 -181.5t331 -67.5t331 67.5t272 181.5t181.5 272t67.5 331zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71 t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf1d2;" d="M582 228q0 -66 -93 -66q-107 0 -107 63q0 64 98 64q102 0 102 -61zM546 694q0 -85 -74 -85q-77 0 -77 84q0 90 77 90q36 0 55 -25.5t19 -63.5zM712 769v125q-78 -29 -135 -29q-50 29 -110 29q-86 0 -145 -57t-59 -143q0 -50 29.5 -102t73.5 -67v-3q-38 -17 -38 -85 q0 -53 41 -77v-3q-113 -37 -113 -139q0 -45 20 -78.5t54 -51t72 -25.5t81 -8q224 0 224 188q0 67 -48 99t-126 46q-27 5 -51.5 20.5t-24.5 39.5q0 44 49 52q77 15 122 70t45 134q0 24 -10 52q37 9 49 13zM771 350h137q-2 27 -2 82v387q0 46 2 69h-137q3 -23 3 -71v-392 q0 -50 -3 -75zM1280 366v121q-30 -21 -68 -21q-53 0 -53 82v225h52q9 0 26.5 -1t26.5 -1v117h-105q0 82 3 102h-140q4 -24 4 -55v-47h-60v-117q36 3 37 3q3 0 11 -0.5t12 -0.5v-2h-2v-217q0 -37 2.5 -64t11.5 -56.5t24.5 -48.5t43.5 -31t66 -12q64 0 108 24zM924 1072 q0 36 -24 63.5t-60 27.5t-60.5 -27t-24.5 -64q0 -36 25 -62.5t60 -26.5t59.5 27t24.5 62zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1d3;" horiz-adv-x="1792" d="M595 22q0 100 -165 100q-158 0 -158 -104q0 -101 172 -101q151 0 151 105zM536 777q0 61 -30 102t-89 41q-124 0 -124 -145q0 -135 124 -135q119 0 119 137zM805 1101v-202q-36 -12 -79 -22q16 -43 16 -84q0 -127 -73 -216.5t-197 -112.5q-40 -8 -59.5 -27t-19.5 -58 q0 -31 22.5 -51.5t58 -32t78.5 -22t86 -25.5t78.5 -37.5t58 -64t22.5 -98.5q0 -304 -363 -304q-69 0 -130 12.5t-116 41t-87.5 82t-32.5 127.5q0 165 182 225v4q-67 41 -67 126q0 109 63 137v4q-72 24 -119.5 108.5t-47.5 165.5q0 139 95 231.5t235 92.5q96 0 178 -47 q98 0 218 47zM1123 220h-222q4 45 4 134v609q0 94 -4 128h222q-4 -33 -4 -124v-613q0 -89 4 -134zM1724 442v-196q-71 -39 -174 -39q-62 0 -107 20t-70 50t-39.5 78t-18.5 92t-4 103v351h2v4q-7 0 -19 1t-18 1q-21 0 -59 -6v190h96v76q0 54 -6 89h227q-6 -41 -6 -165h171 v-190q-15 0 -43.5 2t-42.5 2h-85v-365q0 -131 87 -131q61 0 109 33zM1148 1389q0 -58 -39 -101.5t-96 -43.5q-58 0 -98 43.5t-40 101.5q0 59 39.5 103t98.5 44q58 0 96.5 -44.5t38.5 -102.5z" />
+<glyph unicode="&#xf1d4;" d="M825 547l343 588h-150q-21 -39 -63.5 -118.5t-68 -128.5t-59.5 -118.5t-60 -128.5h-3q-21 48 -44.5 97t-52 105.5t-46.5 92t-54 104.5t-49 95h-150l323 -589v-435h134v436zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1d5;" horiz-adv-x="1280" d="M842 964q0 -80 -57 -136.5t-136 -56.5q-60 0 -111 35q-62 -67 -115 -146q-247 -371 -202 -859q1 -22 -12.5 -38.5t-34.5 -18.5h-5q-20 0 -35 13.5t-17 33.5q-14 126 -3.5 247.5t29.5 217t54 186t69 155.5t74 125q61 90 132 165q-16 35 -16 77q0 80 56.5 136.5t136.5 56.5 t136.5 -56.5t56.5 -136.5zM1223 953q0 -158 -78 -292t-212.5 -212t-292.5 -78q-64 0 -131 14q-21 5 -32.5 23.5t-6.5 39.5q5 20 23 31.5t39 7.5q51 -13 108 -13q97 0 186 38t153 102t102 153t38 186t-38 186t-102 153t-153 102t-186 38t-186 -38t-153 -102t-102 -153 t-38 -186q0 -114 52 -218q10 -20 3.5 -40t-25.5 -30t-39.5 -3t-30.5 26q-64 123 -64 265q0 119 46.5 227t124.5 186t186 124t226 46q158 0 292.5 -78t212.5 -212.5t78 -292.5z" />
+<glyph unicode="&#xf1d6;" horiz-adv-x="1792" d="M270 730q-8 19 -8 52q0 20 11 49t24 45q-1 22 7.5 53t22.5 43q0 139 92.5 288.5t217.5 209.5q139 66 324 66q133 0 266 -55q49 -21 90 -48t71 -56t55 -68t42 -74t32.5 -84.5t25.5 -89.5t22 -98l1 -5q55 -83 55 -150q0 -14 -9 -40t-9 -38q0 -1 1.5 -3.5t3.5 -5t2 -3.5 q77 -114 120.5 -214.5t43.5 -208.5q0 -43 -19.5 -100t-55.5 -57q-9 0 -19.5 7.5t-19 17.5t-19 26t-16 26.5t-13.5 26t-9 17.5q-1 1 -3 1l-5 -4q-59 -154 -132 -223q20 -20 61.5 -38.5t69 -41.5t35.5 -65q-2 -4 -4 -16t-7 -18q-64 -97 -302 -97q-53 0 -110.5 9t-98 20 t-104.5 30q-15 5 -23 7q-14 4 -46 4.5t-40 1.5q-41 -45 -127.5 -65t-168.5 -20q-35 0 -69 1.5t-93 9t-101 20.5t-74.5 40t-32.5 64q0 40 10 59.5t41 48.5q11 2 40.5 13t49.5 12q4 0 14 2q2 2 2 4l-2 3q-48 11 -108 105.5t-73 156.5l-5 3q-4 0 -12 -20q-18 -41 -54.5 -74.5 t-77.5 -37.5h-1q-4 0 -6 4.5t-5 5.5q-23 54 -23 100q0 275 252 466z" />
+<glyph unicode="&#xf1d7;" horiz-adv-x="2048" d="M580 1075q0 41 -25 66t-66 25q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 66 24.5t25 65.5zM1323 568q0 28 -25.5 50t-65.5 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q40 0 65.5 22t25.5 51zM1087 1075q0 41 -24.5 66t-65.5 25 q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 65.5 24.5t24.5 65.5zM1722 568q0 28 -26 50t-65 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q39 0 65 22t26 51zM1456 965q-31 4 -70 4q-169 0 -311 -77t-223.5 -208.5t-81.5 -287.5 q0 -78 23 -152q-35 -3 -68 -3q-26 0 -50 1.5t-55 6.5t-44.5 7t-54.5 10.5t-50 10.5l-253 -127l72 218q-290 203 -290 490q0 169 97.5 311t264 223.5t363.5 81.5q176 0 332.5 -66t262 -182.5t136.5 -260.5zM2048 404q0 -117 -68.5 -223.5t-185.5 -193.5l55 -181l-199 109 q-150 -37 -218 -37q-169 0 -311 70.5t-223.5 191.5t-81.5 264t81.5 264t223.5 191.5t311 70.5q161 0 303 -70.5t227.5 -192t85.5 -263.5z" />
+<glyph unicode="&#xf1d8;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-453 185l-242 -295q-18 -23 -49 -23q-13 0 -22 4q-19 7 -30.5 23.5t-11.5 36.5v349l864 1059l-1069 -925l-395 162q-37 14 -40 55q-2 40 32 59l1664 960q15 9 32 9q20 0 36 -11z" />
+<glyph unicode="&#xf1d9;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-527 215l-298 -327q-18 -21 -47 -21q-14 0 -23 4q-19 7 -30 23.5t-11 36.5v452l-472 193q-37 14 -40 55q-3 39 32 59l1664 960q35 21 68 -2zM1422 26l221 1323l-1434 -827l336 -137 l863 639l-478 -797z" />
+<glyph unicode="&#xf1da;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298zM896 928v-448q0 -14 -9 -23 t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1db;" d="M768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1dc;" horiz-adv-x="1792" d="M1682 -128q-44 0 -132.5 3.5t-133.5 3.5q-44 0 -132 -3.5t-132 -3.5q-24 0 -37 20.5t-13 45.5q0 31 17 46t39 17t51 7t45 15q33 21 33 140l-1 391q0 21 -1 31q-13 4 -50 4h-675q-38 0 -51 -4q-1 -10 -1 -31l-1 -371q0 -142 37 -164q16 -10 48 -13t57 -3.5t45 -15 t20 -45.5q0 -26 -12.5 -48t-36.5 -22q-47 0 -139.5 3.5t-138.5 3.5q-43 0 -128 -3.5t-127 -3.5q-23 0 -35.5 21t-12.5 45q0 30 15.5 45t36 17.5t47.5 7.5t42 15q33 23 33 143l-1 57v813q0 3 0.5 26t0 36.5t-1.5 38.5t-3.5 42t-6.5 36.5t-11 31.5t-16 18q-15 10 -45 12t-53 2 t-41 14t-18 45q0 26 12 48t36 22q46 0 138.5 -3.5t138.5 -3.5q42 0 126.5 3.5t126.5 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17 -43.5t-38.5 -14.5t-49.5 -4t-43 -13q-35 -21 -35 -160l1 -320q0 -21 1 -32q13 -3 39 -3h699q25 0 38 3q1 11 1 32l1 320q0 139 -35 160 q-18 11 -58.5 12.5t-66 13t-25.5 49.5q0 26 12.5 48t37.5 22q44 0 132 -3.5t132 -3.5q43 0 129 3.5t129 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17.5 -44t-40 -14.5t-51.5 -3t-44 -12.5q-35 -23 -35 -161l1 -943q0 -119 34 -140q16 -10 46 -13.5t53.5 -4.5t41.5 -15.5t18 -44.5 q0 -26 -12 -48t-36 -22z" />
+<glyph unicode="&#xf1dd;" horiz-adv-x="1280" d="M1278 1347v-73q0 -29 -18.5 -61t-42.5 -32q-50 0 -54 -1q-26 -6 -32 -31q-3 -11 -3 -64v-1152q0 -25 -18 -43t-43 -18h-108q-25 0 -43 18t-18 43v1218h-143v-1218q0 -25 -17.5 -43t-43.5 -18h-108q-26 0 -43.5 18t-17.5 43v496q-147 12 -245 59q-126 58 -192 179 q-64 117 -64 259q0 166 88 286q88 118 209 159q111 37 417 37h479q25 0 43 -18t18 -43z" />
+<glyph unicode="&#xf1de;" d="M352 128v-128h-352v128h352zM704 256q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM864 640v-128h-864v128h864zM224 1152v-128h-224v128h224zM1536 128v-128h-736v128h736zM576 1280q26 0 45 -19t19 -45v-256 q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1216 768q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1536 640v-128h-224v128h224zM1536 1152v-128h-864v128h864z" />
+<glyph unicode="&#xf1e0;" d="M1216 512q133 0 226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5q0 12 2 34l-360 180q-92 -86 -218 -86q-133 0 -226.5 93.5t-93.5 226.5t93.5 226.5t226.5 93.5q126 0 218 -86l360 180q-2 22 -2 34q0 133 93.5 226.5t226.5 93.5 t226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5q-126 0 -218 86l-360 -180q2 -22 2 -34t-2 -34l360 -180q92 86 218 86z" />
+<glyph unicode="&#xf1e1;" d="M1280 341q0 88 -62.5 151t-150.5 63q-84 0 -145 -58l-241 120q2 16 2 23t-2 23l241 120q61 -58 145 -58q88 0 150.5 63t62.5 151t-62.5 150.5t-150.5 62.5t-151 -62.5t-63 -150.5q0 -7 2 -23l-241 -120q-62 57 -145 57q-88 0 -150.5 -62.5t-62.5 -150.5t62.5 -150.5 t150.5 -62.5q83 0 145 57l241 -120q-2 -16 -2 -23q0 -88 63 -150.5t151 -62.5t150.5 62.5t62.5 150.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1e2;" horiz-adv-x="1792" d="M571 947q-10 25 -34 35t-49 0q-108 -44 -191 -127t-127 -191q-10 -25 0 -49t35 -34q13 -5 24 -5q42 0 60 40q34 84 98.5 148.5t148.5 98.5q25 11 35 35t0 49zM1513 1303l46 -46l-244 -243l68 -68q19 -19 19 -45.5t-19 -45.5l-64 -64q89 -161 89 -343q0 -143 -55.5 -273.5 t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5q182 0 343 -89l64 64q19 19 45.5 19t45.5 -19l68 -68zM1521 1359q-10 -10 -22 -10q-13 0 -23 10l-91 90q-9 10 -9 23t9 23q10 9 23 9t23 -9l90 -91 q10 -9 10 -22.5t-10 -22.5zM1751 1129q-11 -9 -23 -9t-23 9l-90 91q-10 9 -10 22.5t10 22.5q9 10 22.5 10t22.5 -10l91 -90q9 -10 9 -23t-9 -23zM1792 1312q0 -14 -9 -23t-23 -9h-96q-14 0 -23 9t-9 23t9 23t23 9h96q14 0 23 -9t9 -23zM1600 1504v-96q0 -14 -9 -23t-23 -9 t-23 9t-9 23v96q0 14 9 23t23 9t23 -9t9 -23zM1751 1449l-91 -90q-10 -10 -22 -10q-13 0 -23 10q-10 9 -10 22.5t10 22.5l90 91q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
+<glyph unicode="&#xf1e3;" horiz-adv-x="1792" d="M609 720l287 208l287 -208l-109 -336h-355zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM1515 186q149 203 149 454v3l-102 -89l-240 224l63 323 l134 -12q-150 206 -389 282l53 -124l-287 -159l-287 159l53 124q-239 -76 -389 -282l135 12l62 -323l-240 -224l-102 89v-3q0 -251 149 -454l30 132l326 -40l139 -298l-116 -69q117 -39 240 -39t240 39l-116 69l139 298l326 40z" />
+<glyph unicode="&#xf1e4;" horiz-adv-x="1792" d="M448 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM256 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM832 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM66 768q-28 0 -47 19t-19 46v129h514v-129q0 -27 -19 -46t-46 -19h-383zM1216 224v-192q0 -14 -9 -23t-23 -9h-192 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1600 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23 zM1408 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1016v-13h-514v10q0 104 -382 102q-382 -1 -382 -102v-10h-514v13q0 17 8.5 43t34 64t65.5 75.5t110.5 76t160 67.5t224 47.5t293.5 18.5t293 -18.5t224 -47.5 t160.5 -67.5t110.5 -76t65.5 -75.5t34 -64t8.5 -43zM1792 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 962v-129q0 -27 -19 -46t-46 -19h-384q-27 0 -46 19t-19 46v129h514z" />
+<glyph unicode="&#xf1e5;" horiz-adv-x="1792" d="M704 1216v-768q0 -26 -19 -45t-45 -19v-576q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v512l249 873q7 23 31 23h424zM1024 1216v-704h-256v704h256zM1792 320v-512q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v576q-26 0 -45 19t-19 45v768h424q24 0 31 -23z M736 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23zM1408 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1e6;" horiz-adv-x="1792" d="M1755 1083q37 -37 37 -90t-37 -91l-401 -400l150 -150l-160 -160q-163 -163 -389.5 -186.5t-411.5 100.5l-362 -362h-181v181l362 362q-124 185 -100.5 411.5t186.5 389.5l160 160l150 -150l400 401q38 37 91 37t90 -37t37 -90.5t-37 -90.5l-400 -401l234 -234l401 400 q38 37 91 37t90 -37z" />
+<glyph unicode="&#xf1e7;" horiz-adv-x="1792" d="M873 796q0 -83 -63.5 -142.5t-152.5 -59.5t-152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59t152.5 -59t63.5 -143zM1375 796q0 -83 -63 -142.5t-153 -59.5q-89 0 -152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59q90 0 153 -59t63 -143zM1600 616v667q0 87 -32 123.5 t-111 36.5h-1112q-83 0 -112.5 -34t-29.5 -126v-673q43 -23 88.5 -40t81 -28t81 -18.5t71 -11t70 -4t58.5 -0.5t56.5 2t44.5 2q68 1 95 -27q6 -6 10 -9q26 -25 61 -51q7 91 118 87q5 0 36.5 -1.5t43 -2t45.5 -1t53 1t54.5 4.5t61 8.5t62 13.5t67 19.5t67.5 27t72 34.5z M1763 621q-121 -149 -372 -252q84 -285 -23 -465q-66 -113 -183 -148q-104 -32 -182 15q-86 51 -82 164l-1 326v1q-8 2 -24.5 6t-23.5 5l-1 -338q4 -114 -83 -164q-79 -47 -183 -15q-117 36 -182 150q-105 180 -22 463q-251 103 -372 252q-25 37 -4 63t60 -1q3 -2 11 -7 t11 -8v694q0 72 47 123t114 51h1257q67 0 114 -51t47 -123v-694l21 15q39 27 60 1t-4 -63z" />
+<glyph unicode="&#xf1e8;" horiz-adv-x="1792" d="M896 1102v-434h-145v434h145zM1294 1102v-434h-145v434h145zM1294 342l253 254v795h-1194v-1049h326v-217l217 217h398zM1692 1536v-1013l-434 -434h-326l-217 -217h-217v217h-398v1158l109 289h1483z" />
+<glyph unicode="&#xf1e9;" d="M773 217v-127q-1 -292 -6 -305q-12 -32 -51 -40q-54 -9 -181.5 38t-162.5 89q-13 15 -17 36q-1 12 4 26q4 10 34 47t181 216q1 0 60 70q15 19 39.5 24.5t49.5 -3.5q24 -10 37.5 -29t12.5 -42zM624 468q-3 -55 -52 -70l-120 -39q-275 -88 -292 -88q-35 2 -54 36 q-12 25 -17 75q-8 76 1 166.5t30 124.5t56 32q13 0 202 -77q70 -29 115 -47l84 -34q23 -9 35.5 -30.5t11.5 -48.5zM1450 171q-7 -54 -91.5 -161t-135.5 -127q-37 -14 -63 7q-14 10 -184 287l-47 77q-14 21 -11.5 46t19.5 46q35 43 83 26q1 -1 119 -40q203 -66 242 -79.5 t47 -20.5q28 -22 22 -61zM778 803q5 -102 -54 -122q-58 -17 -114 71l-378 598q-8 35 19 62q41 43 207.5 89.5t224.5 31.5q40 -10 49 -45q3 -18 22 -305.5t24 -379.5zM1440 695q3 -39 -26 -59q-15 -10 -329 -86q-67 -15 -91 -23l1 2q-23 -6 -46 4t-37 32q-30 47 0 87 q1 1 75 102q125 171 150 204t34 39q28 19 65 2q48 -23 123 -133.5t81 -167.5v-3z" />
+<glyph unicode="&#xf1ea;" horiz-adv-x="2048" d="M1024 1024h-384v-384h384v384zM1152 384v-128h-640v128h640zM1152 1152v-640h-640v640h640zM1792 384v-128h-512v128h512zM1792 640v-128h-512v128h512zM1792 896v-128h-512v128h512zM1792 1152v-128h-512v128h512zM256 192v960h-128v-960q0 -26 19 -45t45 -19t45 19 t19 45zM1920 192v1088h-1536v-1088q0 -33 -11 -64h1483q26 0 45 19t19 45zM2048 1408v-1216q0 -80 -56 -136t-136 -56h-1664q-80 0 -136 56t-56 136v1088h256v128h1792z" />
+<glyph unicode="&#xf1eb;" horiz-adv-x="2048" d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121 q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73t380 -73t320 -205q10 -10 10 -22q0 -18 -75 -93t-92 -75z M1838 827q-11 0 -22 9q-179 157 -371.5 236.5t-420.5 79.5t-420.5 -79.5t-371.5 -236.5q-11 -9 -22 -9q-17 0 -92.5 75t-75.5 93q0 13 10 23q187 186 445 288t527 102t527 -102t445 -288q10 -10 10 -23q0 -18 -75.5 -93t-92.5 -75z" />
+<glyph unicode="&#xf1ec;" horiz-adv-x="1792" d="M384 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5 t37.5 90.5zM384 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 768q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1536 0v384q0 52 -38 90t-90 38t-90 -38t-38 -90v-384q0 -52 38 -90t90 -38t90 38t38 90zM1152 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1536 1088v256q0 26 -19 45t-45 19h-1280q-26 0 -45 -19t-19 -45v-256q0 -26 19 -45t45 -19h1280q26 0 45 19t19 45zM1536 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1408v-1536q0 -52 -38 -90t-90 -38 h-1408q-52 0 -90 38t-38 90v1536q0 52 38 90t90 38h1408q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1ed;" horiz-adv-x="1792" d="M1112 1090q0 159 -237 159h-70q-32 0 -59.5 -21.5t-34.5 -52.5l-63 -276q-2 -5 -2 -16q0 -24 17 -39.5t41 -15.5h53q69 0 128.5 13t112.5 41t83.5 81.5t30.5 126.5zM1716 938q0 -265 -220 -428q-219 -161 -612 -161h-61q-32 0 -59 -21.5t-34 -52.5l-73 -316 q-8 -36 -40.5 -61.5t-69.5 -25.5h-213q-31 0 -53 20t-22 51q0 10 13 65h151q34 0 64 23.5t38 56.5l73 316q8 33 37.5 57t63.5 24h61q390 0 607 160t217 421q0 129 -51 207q183 -92 183 -335zM1533 1123q0 -264 -221 -428q-218 -161 -612 -161h-60q-32 0 -59.5 -22t-34.5 -53 l-73 -315q-8 -36 -40 -61.5t-69 -25.5h-214q-31 0 -52.5 19.5t-21.5 51.5q0 8 2 20l300 1301q8 36 40.5 61.5t69.5 25.5h444q68 0 125 -4t120.5 -15t113.5 -30t96.5 -50.5t77.5 -74t49.5 -103.5t18.5 -136z" />
+<glyph unicode="&#xf1ee;" horiz-adv-x="1792" d="M602 949q19 -61 31 -123.5t17 -141.5t-14 -159t-62 -145q-21 81 -67 157t-95.5 127t-99 90.5t-78.5 57.5t-33 19q-62 34 -81.5 100t14.5 128t101 81.5t129 -14.5q138 -83 238 -177zM927 1236q11 -25 20.5 -46t36.5 -100.5t42.5 -150.5t25.5 -179.5t0 -205.5t-47.5 -209.5 t-105.5 -208.5q-51 -72 -138 -72q-54 0 -98 31q-57 40 -69 109t28 127q60 85 81 195t13 199.5t-32 180.5t-39 128t-22 52q-31 63 -8.5 129.5t85.5 97.5q34 17 75 17q47 0 88.5 -25t63.5 -69zM1248 567q-17 -160 -72 -311q-17 131 -63 246q25 174 -5 361q-27 178 -94 342 q114 -90 212 -211q9 -37 15 -80q26 -179 7 -347zM1520 1440q9 -17 23.5 -49.5t43.5 -117.5t50.5 -178t34 -227.5t5 -269t-47 -300t-112.5 -323.5q-22 -48 -66 -75.5t-95 -27.5q-39 0 -74 16q-67 31 -92.5 100t4.5 136q58 126 90 257.5t37.5 239.5t-3.5 213.5t-26.5 180.5 t-38.5 138.5t-32.5 90t-15.5 32.5q-34 65 -11.5 135.5t87.5 104.5q37 20 81 20q49 0 91.5 -25.5t66.5 -70.5z" />
+<glyph unicode="&#xf1f0;" horiz-adv-x="2304" d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27 q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24.5 38.5t70.5 16.5q70 1 124 -24l15 -8zM2042 960h-128 q-65 0 -87 -54l-246 -588h174l35 96h212q5 -22 20 -96h154zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f1;" horiz-adv-x="2304" d="M671 603h-13q-47 0 -47 -32q0 -22 20 -22q17 0 28 15t12 39zM1066 639h62v3q1 4 0.5 6.5t-1 7t-2 8t-4.5 6.5t-7.5 5t-11.5 2q-28 0 -36 -38zM1606 603h-12q-48 0 -48 -32q0 -22 20 -22q17 0 28 15t12 39zM1925 629q0 41 -30 41q-19 0 -31 -20t-12 -51q0 -42 28 -42 q20 0 32.5 20t12.5 52zM480 770h87l-44 -262h-56l32 201l-71 -201h-39l-4 200l-34 -200h-53l44 262h81l2 -163zM733 663q0 -6 -4 -42q-16 -101 -17 -113h-47l1 22q-20 -26 -58 -26q-23 0 -37.5 16t-14.5 42q0 39 26 60.5t73 21.5q14 0 23 -1q0 3 0.5 5.5t1 4.5t0.5 3 q0 20 -36 20q-29 0 -59 -10q0 4 7 48q38 11 67 11q74 0 74 -62zM889 721l-8 -49q-22 3 -41 3q-27 0 -27 -17q0 -8 4.5 -12t21.5 -11q40 -19 40 -60q0 -72 -87 -71q-34 0 -58 6q0 2 7 49q29 -8 51 -8q32 0 32 19q0 7 -4.5 11.5t-21.5 12.5q-43 20 -43 59q0 72 84 72 q30 0 50 -4zM977 721h28l-7 -52h-29q-2 -17 -6.5 -40.5t-7 -38.5t-2.5 -18q0 -16 19 -16q8 0 16 2l-8 -47q-21 -7 -40 -7q-43 0 -45 47q0 12 8 56q3 20 25 146h55zM1180 648q0 -23 -7 -52h-111q-3 -22 10 -33t38 -11q30 0 58 14l-9 -54q-30 -8 -57 -8q-95 0 -95 95 q0 55 27.5 90.5t69.5 35.5q35 0 55.5 -21t20.5 -56zM1319 722q-13 -23 -22 -62q-22 2 -31 -24t-25 -128h-56l3 14q22 130 29 199h51l-3 -33q14 21 25.5 29.5t28.5 4.5zM1506 763l-9 -57q-28 14 -50 14q-31 0 -51 -27.5t-20 -70.5q0 -30 13.5 -47t38.5 -17q21 0 48 13 l-10 -59q-28 -8 -50 -8q-45 0 -71.5 30.5t-26.5 82.5q0 70 35.5 114.5t91.5 44.5q26 0 61 -13zM1668 663q0 -18 -4 -42q-13 -79 -17 -113h-46l1 22q-20 -26 -59 -26q-23 0 -37 16t-14 42q0 39 25.5 60.5t72.5 21.5q15 0 23 -1q2 7 2 13q0 20 -36 20q-29 0 -59 -10q0 4 8 48 q38 11 67 11q73 0 73 -62zM1809 722q-14 -24 -21 -62q-23 2 -31.5 -23t-25.5 -129h-56l3 14q19 104 29 199h52q0 -11 -4 -33q15 21 26.5 29.5t27.5 4.5zM1950 770h56l-43 -262h-53l3 19q-23 -23 -52 -23q-31 0 -49.5 24t-18.5 64q0 53 27.5 92t64.5 39q31 0 53 -29z M2061 640q0 148 -72.5 273t-198 198t-273.5 73q-181 0 -328 -110q127 -116 171 -284h-50q-44 150 -158 253q-114 -103 -158 -253h-50q44 168 171 284q-147 110 -328 110q-148 0 -273.5 -73t-198 -198t-72.5 -273t72.5 -273t198 -198t273.5 -73q181 0 328 110 q-120 111 -165 264h50q46 -138 152 -233q106 95 152 233h50q-45 -153 -165 -264q147 -110 328 -110q148 0 273.5 73t198 198t72.5 273zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f2;" horiz-adv-x="2304" d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42 q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0 -71 44l-42 -40q44 -64 115 -64q51 0 83 30.5t32 79.5zM1008 604 v77q-37 -37 -78 -37q-49 0 -80.5 32.5t-31.5 82.5q0 48 31.5 81.5t77.5 33.5q43 0 81 -38v77q-40 20 -80 20q-74 0 -125.5 -50.5t-51.5 -123.5t51 -123.5t125 -50.5q42 0 81 19zM2240 0v527q-65 -40 -144.5 -84t-237.5 -117t-329.5 -137.5t-417.5 -134.5t-504 -118h1569 q26 0 45 19t19 45zM1389 757q0 75 -53 128t-128 53t-128 -53t-53 -128t53 -128t128 -53t128 53t53 128zM1541 584l144 342h-71l-90 -224l-89 224h-71l142 -342h35zM1714 593h184v56h-119v90h115v56h-115v74h119v57h-184v-333zM2105 593h80l-105 140q76 16 76 94q0 47 -31 73 t-87 26h-97v-333h65v133h9zM2304 1274v-1268q0 -56 -38.5 -95t-93.5 -39h-2040q-55 0 -93.5 39t-38.5 95v1268q0 56 38.5 95t93.5 39h2040q55 0 93.5 -39t38.5 -95z" />
+<glyph unicode="&#xf1f3;" horiz-adv-x="2304" d="M119 854h89l-45 108zM740 328l74 79l-70 79h-163v-49h142v-55h-142v-54h159zM898 406l99 -110v217zM1186 453q0 33 -40 33h-84v-69h83q41 0 41 36zM1475 457q0 29 -42 29h-82v-61h81q43 0 43 32zM1197 923q0 29 -42 29h-82v-60h81q43 0 43 31zM1656 854h89l-44 108z M699 1009v-271h-66v212l-94 -212h-57l-94 212v-212h-132l-25 60h-135l-25 -60h-70l116 271h96l110 -257v257h106l85 -184l77 184h108zM1255 453q0 -20 -5.5 -35t-14 -25t-22.5 -16.5t-26 -10t-31.5 -4.5t-31.5 -1t-32.5 0.5t-29.5 0.5v-91h-126l-80 90l-83 -90h-256v271h260 l80 -89l82 89h207q109 0 109 -89zM964 794v-56h-217v271h217v-57h-152v-49h148v-55h-148v-54h152zM2304 235v-229q0 -55 -38.5 -94.5t-93.5 -39.5h-2040q-55 0 -93.5 39.5t-38.5 94.5v678h111l25 61h55l25 -61h218v46l19 -46h113l20 47v-47h541v99l10 1q10 0 10 -14v-86h279 v23q23 -12 55 -18t52.5 -6.5t63 0.5t51.5 1l25 61h56l25 -61h227v58l34 -58h182v378h-180v-44l-25 44h-185v-44l-23 44h-249q-69 0 -109 -22v22h-172v-22q-24 22 -73 22h-628l-43 -97l-43 97h-198v-44l-22 44h-169l-78 -179v391q0 55 38.5 94.5t93.5 39.5h2040 q55 0 93.5 -39.5t38.5 -94.5v-678h-120q-51 0 -81 -22v22h-177q-55 0 -78 -22v22h-316v-22q-31 22 -87 22h-209v-22q-23 22 -91 22h-234l-54 -58l-50 58h-349v-378h343l55 59l52 -59h211v89h21q59 0 90 13v-102h174v99h8q8 0 10 -2t2 -10v-87h529q57 0 88 24v-24h168 q60 0 95 17zM1546 469q0 -23 -12 -43t-34 -29q25 -9 34 -26t9 -46v-54h-65v45q0 33 -12 43.5t-46 10.5h-69v-99h-65v271h154q48 0 77 -15t29 -58zM1269 936q0 -24 -12.5 -44t-33.5 -29q26 -9 34.5 -25.5t8.5 -46.5v-53h-65q0 9 0.5 26.5t0 25t-3 18.5t-8.5 16t-17.5 8.5 t-29.5 3.5h-70v-98h-64v271l153 -1q49 0 78 -14.5t29 -57.5zM1798 327v-56h-216v271h216v-56h-151v-49h148v-55h-148v-54zM1372 1009v-271h-66v271h66zM2065 357q0 -86 -102 -86h-126v58h126q34 0 34 25q0 16 -17 21t-41.5 5t-49.5 3.5t-42 22.5t-17 55q0 39 26 60t66 21 h130v-57h-119q-36 0 -36 -25q0 -16 17.5 -20.5t42 -4t49 -2.5t42 -21.5t17.5 -54.5zM2304 407v-101q-24 -35 -88 -35h-125v58h125q33 0 33 25q0 13 -12.5 19t-31 5.5t-40 2t-40 8t-31 24t-12.5 48.5q0 39 26.5 60t66.5 21h129v-57h-118q-36 0 -36 -25q0 -20 29 -22t68.5 -5 t56.5 -26zM2139 1008v-270h-92l-122 203v-203h-132l-26 60h-134l-25 -60h-75q-129 0 -129 133q0 138 133 138h63v-59q-7 0 -28 1t-28.5 0.5t-23 -2t-21.5 -6.5t-14.5 -13.5t-11.5 -23t-3 -33.5q0 -38 13.5 -58t49.5 -20h29l92 213h97l109 -256v256h99l114 -188v188h66z" />
+<glyph unicode="&#xf1f4;" horiz-adv-x="2304" d="M322 689h-15q-19 0 -19 18q0 28 19 85q5 15 15 19.5t28 4.5q77 0 77 -49q0 -41 -30.5 -59.5t-74.5 -18.5zM664 528q-47 0 -47 29q0 62 123 62l3 -3q-5 -88 -79 -88zM1438 687h-15q-19 0 -19 19q0 28 19 85q5 15 14.5 19t28.5 4q77 0 77 -49q0 -41 -30.5 -59.5 t-74.5 -18.5zM1780 527q-47 0 -47 30q0 62 123 62l3 -3q-5 -89 -79 -89zM373 894h-128q-8 0 -14.5 -4t-8.5 -7.5t-7 -12.5q-3 -7 -45 -190t-42 -192q0 -7 5.5 -12.5t13.5 -5.5h62q25 0 32.5 34.5l15 69t32.5 34.5q47 0 87.5 7.5t80.5 24.5t63.5 52.5t23.5 84.5 q0 36 -14.5 61t-41 36.5t-53.5 15.5t-62 4zM719 798q-38 0 -74 -6q-2 0 -8.5 -1t-9 -1.5l-7.5 -1.5t-7.5 -2t-6.5 -3t-6.5 -4t-5 -5t-4.5 -7t-4 -9q-9 -29 -9 -39t9 -10q5 0 21.5 5t19.5 6q30 8 58 8q74 0 74 -36q0 -11 -10 -14q-8 -2 -18 -3t-21.5 -1.5t-17.5 -1.5 q-38 -4 -64.5 -10t-56.5 -19.5t-45.5 -39t-15.5 -62.5q0 -38 26 -59.5t64 -21.5q24 0 45.5 6.5t33 13t38.5 23.5q-3 -7 -3 -15t5.5 -13.5t12.5 -5.5h56q1 1 7 3.5t7.5 3.5t5 3.5t5 5.5t2.5 8l45 194q4 13 4 30q0 81 -145 81zM1247 793h-74q-22 0 -39 -23q-5 -7 -29.5 -51 t-46.5 -81.5t-26 -38.5l-5 4q0 77 -27 166q-1 5 -3.5 8.5t-6 6.5t-6.5 5t-8.5 3t-8.5 1.5t-9.5 1t-9 0.5h-10h-8.5q-38 0 -38 -21l1 -5q5 -53 25 -151t25 -143q2 -16 2 -24q0 -19 -30.5 -61.5t-30.5 -58.5q0 -13 40 -13q61 0 76 25l245 415q10 20 10 26q0 9 -8 9zM1489 892 h-129q-18 0 -29 -23q-6 -13 -46.5 -191.5t-40.5 -190.5q0 -20 43 -20h7.5h9h9t9.5 1t8.5 2t8.5 3t6.5 4.5t5.5 6t3 8.5l21 91q2 10 10.5 17t19.5 7q47 0 87.5 7t80.5 24.5t63.5 52.5t23.5 84q0 36 -14.5 61t-41 36.5t-53.5 15.5t-62 4zM1835 798q-26 0 -74 -6 q-38 -6 -48 -16q-7 -8 -11 -19q-8 -24 -8 -39q0 -10 8 -10q1 0 41 12q30 8 58 8q74 0 74 -36q0 -12 -10 -14q-4 -1 -57 -7q-38 -4 -64.5 -10t-56.5 -19.5t-45.5 -39t-15.5 -62.5t26 -58.5t64 -21.5q24 0 45 6t34 13t38 24q-3 -15 -3 -16q0 -5 2 -8.5t6.5 -5.5t8 -3.5 t10.5 -2t9.5 -0.5h9.5h8q42 0 48 25l45 194q3 15 3 31q0 81 -145 81zM2157 889h-55q-25 0 -33 -40q-10 -44 -36.5 -167t-42.5 -190v-5q0 -16 16 -18h1h57q10 0 18.5 6.5t10.5 16.5l83 374h-1l1 5q0 7 -5.5 12.5t-13.5 5.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048 q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f5;" horiz-adv-x="2304" d="M1597 633q0 -69 -21 -106q-19 -35 -52 -35q-23 0 -41 9v224q29 30 57 30q57 0 57 -122zM2035 669h-110q6 98 56 98q51 0 54 -98zM476 534q0 59 -33 91.5t-101 57.5q-36 13 -52 24t-16 25q0 26 38 26q58 0 124 -33l18 112q-67 32 -149 32q-77 0 -123 -38q-48 -39 -48 -109 q0 -58 32.5 -90.5t99.5 -56.5q39 -14 54.5 -25.5t15.5 -27.5q0 -31 -48 -31q-29 0 -70 12.5t-72 30.5l-18 -113q72 -41 168 -41q81 0 129 37q51 41 51 117zM771 749l19 111h-96v135l-129 -21l-18 -114l-46 -8l-17 -103h62v-219q0 -84 44 -120q38 -30 111 -30q32 0 79 11v118 q-32 -7 -44 -7q-42 0 -42 50v197h77zM1087 724v139q-15 3 -28 3q-32 0 -55.5 -16t-33.5 -46l-10 56h-131v-471h150v306q26 31 82 31q16 0 26 -2zM1124 389h150v471h-150v-471zM1746 638q0 122 -45 179q-40 52 -111 52q-64 0 -117 -56l-8 47h-132v-645l150 25v151 q36 -11 68 -11q83 0 134 56q61 65 61 202zM1278 986q0 33 -23 56t-56 23t-56 -23t-23 -56t23 -56.5t56 -23.5t56 23.5t23 56.5zM2176 629q0 113 -48 176q-50 64 -144 64q-96 0 -151.5 -66t-55.5 -180q0 -128 63 -188q55 -55 161 -55q101 0 160 40l-16 103q-57 -31 -128 -31 q-43 0 -63 19q-23 19 -28 66h248q2 14 2 52zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f6;" horiz-adv-x="2048" d="M1558 684q61 -356 298 -556q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5zM1024 -176q16 0 16 16t-16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5zM2026 1424q8 -10 7.5 -23.5t-10.5 -22.5 l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5 l418 363q10 8 23.5 7t21.5 -11z" />
+<glyph unicode="&#xf1f7;" horiz-adv-x="2048" d="M1040 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM503 315l877 760q-42 88 -132.5 146.5t-223.5 58.5q-93 0 -169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -384 -137 -645zM1856 128 q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5l149 129h757q-166 187 -227 459l111 97q61 -356 298 -556zM1942 1520l84 -96q8 -10 7.5 -23.5t-10.5 -22.5l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161 q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5l418 363q10 8 23.5 7t21.5 -11z" />
+<glyph unicode="&#xf1f8;" horiz-adv-x="1408" d="M512 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM768 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1024 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704 q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167 q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1f9;" d="M1150 462v-109q0 -50 -36.5 -89t-94 -60.5t-118 -32.5t-117.5 -11q-205 0 -342.5 139t-137.5 346q0 203 136 339t339 136q34 0 75.5 -4.5t93 -18t92.5 -34t69 -56.5t28 -81v-109q0 -16 -16 -16h-118q-16 0 -16 16v70q0 43 -65.5 67.5t-137.5 24.5q-140 0 -228.5 -91.5 t-88.5 -237.5q0 -151 91.5 -249.5t233.5 -98.5q68 0 138 24t70 66v70q0 7 4.5 11.5t10.5 4.5h119q6 0 11 -4.5t5 -11.5zM768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1fa;" d="M972 761q0 108 -53.5 169t-147.5 61q-63 0 -124 -30.5t-110 -84.5t-79.5 -137t-30.5 -180q0 -112 53.5 -173t150.5 -61q96 0 176 66.5t122.5 166t42.5 203.5zM1536 640q0 -111 -37 -197t-98.5 -135t-131.5 -74.5t-145 -27.5q-6 0 -15.5 -0.5t-16.5 -0.5q-95 0 -142 53 q-28 33 -33 83q-52 -66 -131.5 -110t-173.5 -44q-161 0 -249.5 95.5t-88.5 269.5q0 157 66 290t179 210.5t246 77.5q87 0 155 -35.5t106 -99.5l2 19l11 56q1 6 5.5 12t9.5 6h118q5 0 13 -11q5 -5 3 -16l-120 -614q-5 -24 -5 -48q0 -39 12.5 -52t44.5 -13q28 1 57 5.5t73 24 t77 50t57 89.5t24 137q0 292 -174 466t-466 174q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51q228 0 405 144q11 9 24 8t21 -12l41 -49q8 -12 7 -24q-2 -13 -12 -22q-102 -83 -227.5 -128t-258.5 -45q-156 0 -298 61 t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q344 0 556 -212t212 -556z" />
+<glyph unicode="&#xf1fb;" horiz-adv-x="1792" d="M1698 1442q94 -94 94 -226.5t-94 -225.5l-225 -223l104 -104q10 -10 10 -23t-10 -23l-210 -210q-10 -10 -23 -10t-23 10l-105 105l-603 -603q-37 -37 -90 -37h-203l-256 -128l-64 64l128 256v203q0 53 37 90l603 603l-105 105q-10 10 -10 23t10 23l210 210q10 10 23 10 t23 -10l104 -104l223 225q93 94 225.5 94t226.5 -94zM512 64l576 576l-192 192l-576 -576v-192h192z" />
+<glyph unicode="&#xf1fc;" horiz-adv-x="1792" d="M1615 1536q70 0 122.5 -46.5t52.5 -116.5q0 -63 -45 -151q-332 -629 -465 -752q-97 -91 -218 -91q-126 0 -216.5 92.5t-90.5 219.5q0 128 92 212l638 579q59 54 130 54zM706 502q39 -76 106.5 -130t150.5 -76l1 -71q4 -213 -129.5 -347t-348.5 -134q-123 0 -218 46.5 t-152.5 127.5t-86.5 183t-29 220q7 -5 41 -30t62 -44.5t59 -36.5t46 -17q41 0 55 37q25 66 57.5 112.5t69.5 76t88 47.5t103 25.5t125 10.5z" />
+<glyph unicode="&#xf1fd;" horiz-adv-x="1792" d="M1792 128v-384h-1792v384q45 0 85 14t59 27.5t47 37.5q30 27 51.5 38t56.5 11t55.5 -11t52.5 -38q29 -25 47 -38t58 -27t86 -14q45 0 85 14.5t58 27t48 37.5q21 19 32.5 27t31 15t43.5 7q35 0 56.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14t85 14t59 27.5t47 37.5 q30 27 51.5 38t56.5 11q34 0 55.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14zM1792 448v-192q-35 0 -55.5 11t-52.5 38q-29 25 -47 38t-58 27t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-22 -19 -33 -27t-31 -15t-44 -7q-35 0 -56.5 11t-51.5 38q-29 25 -47 38t-58 27 t-86 14q-45 0 -85 -14.5t-58 -27t-48 -37.5q-21 -19 -32.5 -27t-31 -15t-43.5 -7q-35 0 -56.5 11t-51.5 38q-28 24 -47 37.5t-59 27.5t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-30 -27 -51.5 -38t-56.5 -11v192q0 80 56 136t136 56h64v448h256v-448h256v448h256v-448h256v448 h256v-448h64q80 0 136 -56t56 -136zM512 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1024 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51 t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1536 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150z" />
+<glyph unicode="&#xf1fe;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1664 1024l256 -896h-1664v576l448 576l576 -576z" />
+<glyph unicode="&#xf200;" horiz-adv-x="1792" d="M768 646l546 -546q-106 -108 -247.5 -168t-298.5 -60q-209 0 -385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103v-762zM955 640h773q0 -157 -60 -298.5t-168 -247.5zM1664 768h-768v768q209 0 385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf201;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1920 1248v-435q0 -21 -19.5 -29.5t-35.5 7.5l-121 121l-633 -633q-10 -10 -23 -10t-23 10l-233 233l-416 -416l-192 192l585 585q10 10 23 10t23 -10l233 -233l464 464l-121 121q-16 16 -7.5 35.5t29.5 19.5h435q14 0 23 -9 t9 -23z" />
+<glyph unicode="&#xf202;" horiz-adv-x="1792" d="M1292 832q0 -6 10 -41q10 -29 25 -49.5t41 -34t44 -20t55 -16.5q325 -91 325 -332q0 -146 -105.5 -242.5t-254.5 -96.5q-59 0 -111.5 18.5t-91.5 45.5t-77 74.5t-63 87.5t-53.5 103.5t-43.5 103t-39.5 106.5t-35.5 95q-32 81 -61.5 133.5t-73.5 96.5t-104 64t-142 20 q-96 0 -183 -55.5t-138 -144.5t-51 -185q0 -160 106.5 -279.5t263.5 -119.5q177 0 258 95q56 63 83 116l84 -152q-15 -34 -44 -70l1 -1q-131 -152 -388 -152q-147 0 -269.5 79t-190.5 207.5t-68 274.5q0 105 43.5 206t116 176.5t172 121.5t204.5 46q87 0 159 -19t123.5 -50 t95 -80t72.5 -99t58.5 -117t50.5 -124.5t50 -130.5t55 -127q96 -200 233 -200q81 0 138.5 48.5t57.5 128.5q0 42 -19 72t-50.5 46t-72.5 31.5t-84.5 27t-87.5 34t-81 52t-65 82t-39 122.5q-3 16 -3 33q0 110 87.5 192t198.5 78q78 -3 120.5 -14.5t90.5 -53.5h-1 q12 -11 23 -24.5t26 -36t19 -27.5l-129 -99q-26 49 -54 70v1q-23 21 -97 21q-49 0 -84 -33t-35 -83z" />
+<glyph unicode="&#xf203;" d="M1432 484q0 173 -234 239q-35 10 -53 16.5t-38 25t-29 46.5q0 2 -2 8.5t-3 12t-1 7.5q0 36 24.5 59.5t60.5 23.5q54 0 71 -15h-1q20 -15 39 -51l93 71q-39 54 -49 64q-33 29 -67.5 39t-85.5 10q-80 0 -142 -57.5t-62 -137.5q0 -7 2 -23q16 -96 64.5 -140t148.5 -73 q29 -8 49 -15.5t45 -21.5t38.5 -34.5t13.5 -46.5v-5q1 -58 -40.5 -93t-100.5 -35q-97 0 -167 144q-23 47 -51.5 121.5t-48 125.5t-54 110.5t-74 95.5t-103.5 60.5t-147 24.5q-101 0 -192 -56t-144 -148t-50 -192v-1q4 -108 50.5 -199t133.5 -147.5t196 -56.5q186 0 279 110 q20 27 31 51l-60 109q-42 -80 -99 -116t-146 -36q-115 0 -191 87t-76 204q0 105 82 189t186 84q112 0 170 -53.5t104 -172.5q8 -21 25.5 -68.5t28.5 -76.5t31.5 -74.5t38.5 -74t45.5 -62.5t55.5 -53.5t66 -33t80 -13.5q107 0 183 69.5t76 174.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf204;" horiz-adv-x="2048" d="M1152 640q0 104 -40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM1920 640q0 104 -40.5 198.5 t-109.5 163.5t-163.5 109.5t-198.5 40.5h-386q119 -90 188.5 -224t69.5 -288t-69.5 -288t-188.5 -224h386q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM2048 640q0 -130 -51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5 t-136.5 204t-51 248.5t51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5z" />
+<glyph unicode="&#xf205;" horiz-adv-x="2048" d="M0 640q0 130 51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5t-51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5t-136.5 204t-51 248.5zM1408 128q104 0 198.5 40.5t163.5 109.5 t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5z" />
+<glyph unicode="&#xf206;" horiz-adv-x="2304" d="M762 384h-314q-40 0 -57.5 35t6.5 67l188 251q-65 31 -137 31q-132 0 -226 -94t-94 -226t94 -226t226 -94q115 0 203 72.5t111 183.5zM576 512h186q-18 85 -75 148zM1056 512l288 384h-480l-99 -132q105 -103 126 -252h165zM2176 448q0 132 -94 226t-226 94 q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94t226 94t94 226zM2304 448q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 97 39.5 183.5t109.5 149.5l-65 98l-353 -469 q-18 -26 -51 -26h-197q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q114 0 215 -55l137 183h-224q-26 0 -45 19t-19 45t19 45t45 19h384v-128h435l-85 128h-222q-26 0 -45 19t-19 45t19 45t45 19h256q33 0 53 -28l267 -400 q91 44 192 44q185 0 316.5 -131.5t131.5 -316.5z" />
+<glyph unicode="&#xf207;" d="M384 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1362 716l-72 384q-5 23 -22.5 37.5t-40.5 14.5 h-918q-23 0 -40.5 -14.5t-22.5 -37.5l-72 -384q-5 -30 14 -53t49 -23h1062q30 0 49 23t14 53zM1136 1328q0 20 -14 34t-34 14h-640q-20 0 -34 -14t-14 -34t14 -34t34 -14h640q20 0 34 14t14 34zM1536 603v-603h-128v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5v128h-768v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5v128h-128v603q0 112 25 223l103 454q9 78 97.5 137t230 89t312.5 30t312.5 -30t230 -89t97.5 -137l105 -454q23 -102 23 -223z" />
+<glyph unicode="&#xf208;" horiz-adv-x="2048" d="M1463 704q0 -35 -25 -60.5t-61 -25.5h-702q-36 0 -61 25.5t-25 60.5t25 60.5t61 25.5h702q36 0 61 -25.5t25 -60.5zM1677 704q0 86 -23 170h-982q-36 0 -61 25t-25 60q0 36 25 61t61 25h908q-88 143 -235 227t-320 84q-177 0 -327.5 -87.5t-238 -237.5t-87.5 -327 q0 -86 23 -170h982q36 0 61 -25t25 -60q0 -36 -25 -61t-61 -25h-908q88 -143 235.5 -227t320.5 -84q132 0 253 51.5t208 139t139 208t52 253.5zM2048 959q0 -35 -25 -60t-61 -25h-131q17 -85 17 -170q0 -167 -65.5 -319.5t-175.5 -263t-262.5 -176t-319.5 -65.5 q-246 0 -448.5 133t-301.5 350h-189q-36 0 -61 25t-25 61q0 35 25 60t61 25h132q-17 85 -17 170q0 167 65.5 319.5t175.5 263t262.5 176t320.5 65.5q245 0 447.5 -133t301.5 -350h188q36 0 61 -25t25 -61z" />
+<glyph unicode="&#xf209;" horiz-adv-x="1280" d="M953 1158l-114 -328l117 -21q165 451 165 518q0 56 -38 56q-57 0 -130 -225zM654 471l33 -88q37 42 71 67l-33 5.5t-38.5 7t-32.5 8.5zM362 1367q0 -98 159 -521q18 10 49 10q15 0 75 -5l-121 351q-75 220 -123 220q-19 0 -29 -17.5t-10 -37.5zM283 608q0 -36 51.5 -119 t117.5 -153t100 -70q14 0 25.5 13t11.5 27q0 24 -32 102q-13 32 -32 72t-47.5 89t-61.5 81t-62 32q-20 0 -45.5 -27t-25.5 -47zM125 273q0 -41 25 -104q59 -145 183.5 -227t281.5 -82q227 0 382 170q152 169 152 427q0 43 -1 67t-11.5 62t-30.5 56q-56 49 -211.5 75.5 t-270.5 26.5q-37 0 -49 -11q-12 -5 -12 -35q0 -34 21.5 -60t55.5 -40t77.5 -23.5t87.5 -11.5t85 -4t70 0h23q24 0 40 -19q15 -19 19 -55q-28 -28 -96 -54q-61 -22 -93 -46q-64 -46 -108.5 -114t-44.5 -137q0 -31 18.5 -88.5t18.5 -87.5l-3 -12q-4 -12 -4 -14 q-137 10 -146 216q-8 -2 -41 -2q2 -7 2 -21q0 -53 -40.5 -89.5t-94.5 -36.5q-82 0 -166.5 78t-84.5 159q0 34 33 67q52 -64 60 -76q77 -104 133 -104q12 0 26.5 8.5t14.5 20.5q0 34 -87.5 145t-116.5 111q-43 0 -70 -44.5t-27 -90.5zM11 264q0 101 42.5 163t136.5 88 q-28 74 -28 104q0 62 61 123t122 61q29 0 70 -15q-163 462 -163 567q0 80 41 130.5t119 50.5q131 0 325 -581q6 -17 8 -23q6 16 29 79.5t43.5 118.5t54 127.5t64.5 123t70.5 86.5t76.5 36q71 0 112 -49t41 -122q0 -108 -159 -550q61 -15 100.5 -46t58.5 -78t26 -93.5 t7 -110.5q0 -150 -47 -280t-132 -225t-211 -150t-278 -55q-111 0 -223 42q-149 57 -258 191.5t-109 286.5z" />
+<glyph unicode="&#xf20a;" horiz-adv-x="2048" d="M785 528h207q-14 -158 -98.5 -248.5t-214.5 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-203q-5 64 -35.5 99t-81.5 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t40 -51.5t66 -18q95 0 109 139zM1497 528h206 q-14 -158 -98 -248.5t-214 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-204q-4 64 -35 99t-81 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t39.5 -51.5t65.5 -18q49 0 76.5 38t33.5 101zM1856 647q0 207 -15.5 307 t-60.5 161q-6 8 -13.5 14t-21.5 15t-16 11q-86 63 -697 63q-625 0 -710 -63q-5 -4 -17.5 -11.5t-21 -14t-14.5 -14.5q-45 -60 -60 -159.5t-15 -308.5q0 -208 15 -307.5t60 -160.5q6 -8 15 -15t20.5 -14t17.5 -12q44 -33 239.5 -49t470.5 -16q610 0 697 65q5 4 17 11t20.5 14 t13.5 16q46 60 61 159t15 309zM2048 1408v-1536h-2048v1536h2048z" />
+<glyph unicode="&#xf20b;" d="M992 912v-496q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v496q0 112 -80 192t-192 80h-272v-1152q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v1344q0 14 9 23t23 9h464q135 0 249 -66.5t180.5 -180.5t66.5 -249zM1376 1376v-880q0 -135 -66.5 -249t-180.5 -180.5 t-249 -66.5h-464q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h160q14 0 23 -9t9 -23v-768h272q112 0 192 80t80 192v880q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf20c;" d="M1311 694v-114q0 -24 -13.5 -38t-37.5 -14h-202q-24 0 -38 14t-14 38v114q0 24 14 38t38 14h202q24 0 37.5 -14t13.5 -38zM821 464v250q0 53 -32.5 85.5t-85.5 32.5h-133q-68 0 -96 -52q-28 52 -96 52h-130q-53 0 -85.5 -32.5t-32.5 -85.5v-250q0 -22 21 -22h55 q22 0 22 22v230q0 24 13.5 38t38.5 14h94q24 0 38 -14t14 -38v-230q0 -22 21 -22h54q22 0 22 22v230q0 24 14 38t38 14h97q24 0 37.5 -14t13.5 -38v-230q0 -22 22 -22h55q21 0 21 22zM1410 560v154q0 53 -33 85.5t-86 32.5h-264q-53 0 -86 -32.5t-33 -85.5v-410 q0 -21 22 -21h55q21 0 21 21v180q31 -42 94 -42h191q53 0 86 32.5t33 85.5zM1536 1176v-1072q0 -96 -68 -164t-164 -68h-1072q-96 0 -164 68t-68 164v1072q0 96 68 164t164 68h1072q96 0 164 -68t68 -164z" />
+<glyph unicode="&#xf20d;" horiz-adv-x="1792" />
+<glyph unicode="&#xf20e;" horiz-adv-x="1792" />
+<glyph unicode="&#xf500;" horiz-adv-x="1792" />
+</font>
+</defs></svg> \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.ttf b/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.ttf
new file mode 100644
index 000000000..96a3639cd
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.ttf
Binary files differ
diff --git a/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.woff b/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.woff
new file mode 100644
index 000000000..628b6a52a
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/font-awesome/fonts/fontawesome-webfont.woff
Binary files differ
diff --git a/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.eot b/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 000000000..b93a4953f
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.eot
Binary files differ
diff --git a/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.svg b/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 000000000..94fb5490a
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,288 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
+<font-face units-per-em="1200" ascent="960" descent="-240" />
+<missing-glyph horiz-adv-x="500" />
+<glyph horiz-adv-x="0" />
+<glyph horiz-adv-x="400" />
+<glyph unicode=" " />
+<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" />
+<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xa0;" />
+<glyph unicode="&#xa5;" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" />
+<glyph unicode="&#x2000;" horiz-adv-x="650" />
+<glyph unicode="&#x2001;" horiz-adv-x="1300" />
+<glyph unicode="&#x2002;" horiz-adv-x="650" />
+<glyph unicode="&#x2003;" horiz-adv-x="1300" />
+<glyph unicode="&#x2004;" horiz-adv-x="433" />
+<glyph unicode="&#x2005;" horiz-adv-x="325" />
+<glyph unicode="&#x2006;" horiz-adv-x="216" />
+<glyph unicode="&#x2007;" horiz-adv-x="216" />
+<glyph unicode="&#x2008;" horiz-adv-x="162" />
+<glyph unicode="&#x2009;" horiz-adv-x="260" />
+<glyph unicode="&#x200a;" horiz-adv-x="72" />
+<glyph unicode="&#x202f;" horiz-adv-x="260" />
+<glyph unicode="&#x205f;" horiz-adv-x="325" />
+<glyph unicode="&#x20ac;" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" />
+<glyph unicode="&#x20bd;" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" />
+<glyph unicode="&#x2212;" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#x231b;" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#x2601;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" />
+<glyph unicode="&#x26fa;" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " />
+<glyph unicode="&#x2709;" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" />
+<glyph unicode="&#x270f;" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" />
+<glyph unicode="&#xe001;" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" />
+<glyph unicode="&#xe002;" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" />
+<glyph unicode="&#xe003;" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" />
+<glyph unicode="&#xe005;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" />
+<glyph unicode="&#xe006;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" />
+<glyph unicode="&#xe007;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" />
+<glyph unicode="&#xe008;" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" />
+<glyph unicode="&#xe009;" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" />
+<glyph unicode="&#xe010;" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe011;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" />
+<glyph unicode="&#xe012;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe013;" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" />
+<glyph unicode="&#xe014;" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" />
+<glyph unicode="&#xe015;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe016;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe017;" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" />
+<glyph unicode="&#xe018;" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe019;" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" />
+<glyph unicode="&#xe020;" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" />
+<glyph unicode="&#xe021;" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" />
+<glyph unicode="&#xe022;" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" />
+<glyph unicode="&#xe023;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe024;" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" />
+<glyph unicode="&#xe025;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe026;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " />
+<glyph unicode="&#xe027;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" />
+<glyph unicode="&#xe028;" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" />
+<glyph unicode="&#xe029;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
+<glyph unicode="&#xe030;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" />
+<glyph unicode="&#xe031;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" />
+<glyph unicode="&#xe032;" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe033;" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" />
+<glyph unicode="&#xe034;" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" />
+<glyph unicode="&#xe035;" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" />
+<glyph unicode="&#xe036;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" />
+<glyph unicode="&#xe037;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" />
+<glyph unicode="&#xe038;" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" />
+<glyph unicode="&#xe039;" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" />
+<glyph unicode="&#xe040;" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" />
+<glyph unicode="&#xe041;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
+<glyph unicode="&#xe042;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
+<glyph unicode="&#xe043;" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" />
+<glyph unicode="&#xe044;" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe045;" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" />
+<glyph unicode="&#xe046;" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" />
+<glyph unicode="&#xe047;" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" />
+<glyph unicode="&#xe048;" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" />
+<glyph unicode="&#xe049;" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" />
+<glyph unicode="&#xe050;" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" />
+<glyph unicode="&#xe051;" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" />
+<glyph unicode="&#xe052;" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe053;" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe054;" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe055;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe056;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe057;" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe058;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe059;" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" />
+<glyph unicode="&#xe060;" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" />
+<glyph unicode="&#xe062;" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" />
+<glyph unicode="&#xe063;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" />
+<glyph unicode="&#xe064;" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" />
+<glyph unicode="&#xe065;" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" />
+<glyph unicode="&#xe066;" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" />
+<glyph unicode="&#xe067;" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" />
+<glyph unicode="&#xe068;" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" />
+<glyph unicode="&#xe069;" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe070;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe071;" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" />
+<glyph unicode="&#xe072;" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" />
+<glyph unicode="&#xe073;" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe074;" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" />
+<glyph unicode="&#xe075;" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" />
+<glyph unicode="&#xe076;" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe077;" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe078;" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe079;" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" />
+<glyph unicode="&#xe080;" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" />
+<glyph unicode="&#xe081;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" />
+<glyph unicode="&#xe082;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" />
+<glyph unicode="&#xe083;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" />
+<glyph unicode="&#xe084;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" />
+<glyph unicode="&#xe085;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe086;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe087;" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" />
+<glyph unicode="&#xe088;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="&#xe089;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="&#xe090;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" />
+<glyph unicode="&#xe091;" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" />
+<glyph unicode="&#xe092;" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" />
+<glyph unicode="&#xe093;" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" />
+<glyph unicode="&#xe094;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe095;" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" />
+<glyph unicode="&#xe096;" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" />
+<glyph unicode="&#xe097;" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" />
+<glyph unicode="&#xe101;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe102;" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" />
+<glyph unicode="&#xe103;" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" />
+<glyph unicode="&#xe104;" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" />
+<glyph unicode="&#xe105;" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
+<glyph unicode="&#xe106;" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
+<glyph unicode="&#xe107;" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" />
+<glyph unicode="&#xe108;" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" />
+<glyph unicode="&#xe109;" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" />
+<glyph unicode="&#xe110;" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" />
+<glyph unicode="&#xe111;" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" />
+<glyph unicode="&#xe112;" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" />
+<glyph unicode="&#xe113;" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" />
+<glyph unicode="&#xe114;" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" />
+<glyph unicode="&#xe115;" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe116;" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" />
+<glyph unicode="&#xe117;" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" />
+<glyph unicode="&#xe118;" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" />
+<glyph unicode="&#xe119;" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe120;" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" />
+<glyph unicode="&#xe121;" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" />
+<glyph unicode="&#xe122;" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" />
+<glyph unicode="&#xe123;" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" />
+<glyph unicode="&#xe124;" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" />
+<glyph unicode="&#xe125;" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe126;" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" />
+<glyph unicode="&#xe127;" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe128;" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe129;" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe130;" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" />
+<glyph unicode="&#xe131;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" />
+<glyph unicode="&#xe132;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" />
+<glyph unicode="&#xe133;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" />
+<glyph unicode="&#xe134;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe135;" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" />
+<glyph unicode="&#xe136;" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" />
+<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " />
+<glyph unicode="&#xe138;" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" />
+<glyph unicode="&#xe139;" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" />
+<glyph unicode="&#xe140;" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" />
+<glyph unicode="&#xe141;" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" />
+<glyph unicode="&#xe142;" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" />
+<glyph unicode="&#xe143;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" />
+<glyph unicode="&#xe144;" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" />
+<glyph unicode="&#xe145;" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" />
+<glyph unicode="&#xe146;" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" />
+<glyph unicode="&#xe148;" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" />
+<glyph unicode="&#xe149;" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" />
+<glyph unicode="&#xe150;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe151;" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " />
+<glyph unicode="&#xe152;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " />
+<glyph unicode="&#xe153;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" />
+<glyph unicode="&#xe154;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" />
+<glyph unicode="&#xe155;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" />
+<glyph unicode="&#xe156;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" />
+<glyph unicode="&#xe157;" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" />
+<glyph unicode="&#xe158;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
+<glyph unicode="&#xe159;" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" />
+<glyph unicode="&#xe160;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" />
+<glyph unicode="&#xe161;" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
+<glyph unicode="&#xe162;" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" />
+<glyph unicode="&#xe163;" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
+<glyph unicode="&#xe164;" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" />
+<glyph unicode="&#xe165;" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" />
+<glyph unicode="&#xe166;" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe167;" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe168;" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" />
+<glyph unicode="&#xe169;" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe170;" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe171;" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" />
+<glyph unicode="&#xe172;" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" />
+<glyph unicode="&#xe173;" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="&#xe174;" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" />
+<glyph unicode="&#xe175;" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe176;" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe177;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" />
+<glyph unicode="&#xe178;" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" />
+<glyph unicode="&#xe179;" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" />
+<glyph unicode="&#xe180;" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" />
+<glyph unicode="&#xe181;" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" />
+<glyph unicode="&#xe182;" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" />
+<glyph unicode="&#xe183;" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" />
+<glyph unicode="&#xe184;" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe185;" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " />
+<glyph unicode="&#xe186;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
+<glyph unicode="&#xe187;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
+<glyph unicode="&#xe188;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" />
+<glyph unicode="&#xe189;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" />
+<glyph unicode="&#xe190;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" />
+<glyph unicode="&#xe191;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" />
+<glyph unicode="&#xe192;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" />
+<glyph unicode="&#xe193;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" />
+<glyph unicode="&#xe194;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" />
+<glyph unicode="&#xe195;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" />
+<glyph unicode="&#xe197;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe198;" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" />
+<glyph unicode="&#xe199;" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" />
+<glyph unicode="&#xe200;" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" />
+<glyph unicode="&#xe201;" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" />
+<glyph unicode="&#xe202;" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" />
+<glyph unicode="&#xe203;" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" />
+<glyph unicode="&#xe204;" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" />
+<glyph unicode="&#xe205;" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" />
+<glyph unicode="&#xe206;" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" />
+<glyph unicode="&#xe209;" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" />
+<glyph unicode="&#xe210;" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe211;" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe212;" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe213;" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe214;" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe215;" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe216;" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" />
+<glyph unicode="&#xe218;" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" />
+<glyph unicode="&#xe219;" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" />
+<glyph unicode="&#xe221;" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe223;" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" />
+<glyph unicode="&#xe224;" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " />
+<glyph unicode="&#xe225;" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe226;" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" />
+<glyph unicode="&#xe227;" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" />
+<glyph unicode="&#xe230;" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" />
+<glyph unicode="&#xe231;" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
+<glyph unicode="&#xe232;" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
+<glyph unicode="&#xe233;" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" />
+<glyph unicode="&#xe234;" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
+<glyph unicode="&#xe235;" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
+<glyph unicode="&#xe236;" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe237;" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" />
+<glyph unicode="&#xe238;" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe239;" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" />
+<glyph unicode="&#xe240;" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" />
+<glyph unicode="&#xe241;" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" />
+<glyph unicode="&#xe242;" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" />
+<glyph unicode="&#xe243;" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" />
+<glyph unicode="&#xe244;" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" />
+<glyph unicode="&#xe245;" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" />
+<glyph unicode="&#xe246;" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" />
+<glyph unicode="&#xe247;" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe248;" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" />
+<glyph unicode="&#xe249;" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe250;" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" />
+<glyph unicode="&#xe251;" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" />
+<glyph unicode="&#xe252;" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" />
+<glyph unicode="&#xe253;" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" />
+<glyph unicode="&#xe254;" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" />
+<glyph unicode="&#xe255;" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" />
+<glyph unicode="&#xe256;" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" />
+<glyph unicode="&#xe257;" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" />
+<glyph unicode="&#xe258;" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" />
+<glyph unicode="&#xe259;" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" />
+<glyph unicode="&#xe260;" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" />
+<glyph unicode="&#xf8ff;" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" />
+<glyph unicode="&#x1f511;" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" />
+<glyph unicode="&#x1f6aa;" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" />
+</font>
+</defs></svg> \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.ttf b/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 000000000..1413fc609
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.ttf
Binary files differ
diff --git a/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.woff b/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 000000000..9e612858f
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.woff
Binary files differ
diff --git a/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.woff2 b/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.woff2
new file mode 100644
index 000000000..64539b54c
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/fonts/glyphicons-halflings-regular.woff2
Binary files differ
diff --git a/fluent-bit/lib/monkey/htdocs/img/mk_banner.png b/fluent-bit/lib/monkey/htdocs/img/mk_banner.png
new file mode 100644
index 000000000..bdf8a989d
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/img/mk_banner.png
Binary files differ
diff --git a/fluent-bit/lib/monkey/htdocs/img/mk_logo.png b/fluent-bit/lib/monkey/htdocs/img/mk_logo.png
new file mode 100644
index 000000000..f7dd843dc
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/img/mk_logo.png
Binary files differ
diff --git a/fluent-bit/lib/monkey/htdocs/img/mk_signature.png b/fluent-bit/lib/monkey/htdocs/img/mk_signature.png
new file mode 100644
index 000000000..1b257192d
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/img/mk_signature.png
Binary files differ
diff --git a/fluent-bit/lib/monkey/htdocs/index.html b/fluent-bit/lib/monkey/htdocs/index.html
new file mode 100644
index 000000000..a5b6e16c7
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/index.html
@@ -0,0 +1,207 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <title>Monkey Server v1.6</title>
+
+ <!-- Bootstrap Core CSS - Uses Bootswatch Flatly Theme: http://bootswatch.com/flatly/ -->
+ <link href="css/bootstrap.min.css" rel="stylesheet">
+
+ <!-- Custom CSS -->
+ <link href="css/freelancer.css" rel="stylesheet">
+ <link href="css/monkey.css" rel="stylesheet">
+
+ <!-- Custom Fonts -->
+ <link href="font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">
+ <link href="http://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css">
+ <link href="http://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic" rel="stylesheet" type="text/css">
+
+ <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
+ <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
+ <!--[if lt IE 9]>
+ <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
+ <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
+ <![endif]-->
+
+</head>
+
+<body id="page-top" class="index">
+
+ <!-- Navigation -->
+ <nav class="navbar navbar-default navbar-fixed-top">
+ <div class="container">
+ <!-- Brand and toggle get grouped for better mobile display -->
+ <div class="navbar-header page-scroll">
+ <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+ <span class="sr-only">Toggle navigation</span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <a class="navbar-brand" href="#page-top"><img class="img-responsive" src="img/mk_banner.png"></a>
+ </div>
+
+ <!-- Collect the nav links, forms, and other content for toggling -->
+ <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+ <ul class="nav navbar-nav navbar-right">
+ <li class="hidden">
+ <a href="#page-top"></a>
+ </li>
+ <li class="page-scroll">
+ <a href="http://monkey-project.com/documentation/1.6/" target="_blank">
+ Documentation
+ </a>
+ </li>
+ <li class="page-scroll">
+ <a href="http://blog.monkey-project.com" target="_blank">Blog</a>
+ </li>
+ <li class="page-scroll">
+ <a href="http://github.com/monkey/monkey" target="_blank">Source Code</a>
+ </li>
+ </ul>
+ </div>
+ <!-- /.navbar-collapse -->
+ </div>
+ <!-- /.container-fluid -->
+ </nav>
+
+ <!-- Header -->
+ <header>
+ <div class="container">
+ <div class="row">
+ <div class="col-lg-12">
+ <img class="img-responsive" src="img/mk_logo.png" alt="">
+ <h1>Monkey Server <small>v1.6</small></h1>
+ <div class="row">
+ <div class="col-lg-8 col-lg-offset-2">
+ <p>
+ <a href="http://monkey-project.com">Monkey</a> is a high performance Open Source Web Server and
+ development stack. It has been designed to be scalable by nature through low memory and CPU consumption, the
+ right choice for High-End production servers and Embedded devices.
+ </p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </header>
+
+ <!-- About Section -->
+ <section id="about">
+ <div class="container">
+ <div class="row">
+ <div class="col-md-6">
+ <h3>Release Notes</h3>
+ <p><small>Monkey v1.6.0</small></p>
+ <p>
+ This version is a major improvement since the previous series: improved TLS, add additional support for OSX and BSD, the scheduler is aware about protocol handlers (HTTP2 is coming!), a new HTTP parser have been implemented, the plugins can be static or dynamic, the build system is now based on CMake, general performance have been improved and much more. We invite you to read our official release notes:
+ </p>
+ <p>
+ <div class="notes">
+ <a href="http://monkey-project.com/Announcements/v1.6.0">
+ http://monkey-project.com/announcements/v1.6.0
+ </a>
+ </div>
+ </p>
+ </div>
+ <div class="col-md-6">
+ <h3>Design, goals and Vision</h3>
+ <p><small>Performance & Innovation</small></p>
+ <p>
+ <a href="http://monkey-project.com">Monkey</a> is a complete event-driven HTTP framework. It have been designed as a
+ small core capable to extend it behavior through the plugin interface.
+ </p>
+ <p>
+ It have been highly optimize to reduce the memory and CPU consumption, making it a great choice for Embedded Linux
+ environments.
+ </p>
+ </div>
+ </div>
+ </div>
+ </section>
+
+ <!-- Footer -->
+ <footer class="text-center">
+ <div class="footer-above">
+ <div class="container">
+ <div class="row">
+ <div class="footer-col col-md-4">
+ <img src="img/mk_signature.png">
+ </div>
+ <div class="footer-col col-md-4">
+ <h3>Join us!</h3>
+ <ul class="list-inline">
+ <li>
+ <a href="https://plus.google.com/communities/109231235096868947735" class="btn-social btn-outline">
+ <i class="fa fa-fw fa-google-plus">
+ </i></a>
+ </li>
+ <li>
+ <a href="https://twitter.com/monkeywebserver" class="btn-social btn-outline"><i class="fa fa-fw fa-twitter"></i></a>
+ </li>
+ <li>
+ <a href="https://www.linkedin.com/grp/home?gid=3211216" class="btn-social btn-outline"><i class="fa fa-fw fa-linkedin"></i></a>
+ </li>
+ <li>
+ <a href="https://github.com/monkey/monkey" class="btn-social btn-outline">
+ <i class="fa fa-fw fa-github"></i>
+ </a>
+ </li>
+
+ </ul>
+ </div>
+ <div class="footer-col col-md-4">
+ <h3>License</h3>
+ <p>
+ Monkey is under the terms of the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License v2.0</a>. You can find a copy of the
+ license inside of this program source or at our <a href="http://github.com/monkey/monkey">repository</a>.
+ </p>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="footer-below">
+ <div class="container">
+ <div class="row">
+ <div class="col-lg-12">
+ Copyright &copy; Monkey Project 2015
+ </div>
+ </div>
+ </div>
+ </div>
+ </footer>
+
+ <!-- Scroll to Top Button (Only visible on small and extra-small screen sizes) -->
+ <div class="scroll-top page-scroll visible-xs visible-sm">
+ <a class="btn btn-primary" href="#page-top">
+ <i class="fa fa-chevron-up"></i>
+ </a>
+ </div>
+
+ <!-- jQuery -->
+ <script src="js/jquery.js"></script>
+
+ <!-- Bootstrap Core JavaScript -->
+ <script src="js/bootstrap.min.js"></script>
+
+ <!-- Plugin JavaScript -->
+ <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js"></script>
+ <script src="js/classie.js"></script>
+ <script src="js/cbpAnimatedHeader.js"></script>
+
+ <!-- Contact Form JavaScript -->
+ <script src="js/jqBootstrapValidation.js"></script>
+
+ <!-- Custom Theme JavaScript -->
+ <script src="js/freelancer.js"></script>
+
+</body>
+
+</html>
diff --git a/fluent-bit/lib/monkey/htdocs/js/bootstrap.min.js b/fluent-bit/lib/monkey/htdocs/js/bootstrap.min.js
new file mode 100644
index 000000000..c8f82e592
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/js/bootstrap.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v3.3.4 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.4",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.4",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.4",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.4",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.4",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(b){if(/(38|40|27|32)/.test(b.which)&&!/input|textarea/i.test(b.target.tagName)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var e=c(d),g=e.hasClass("open");if(!g&&27!=b.which||g&&27==b.which)return 27==b.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find('[role="menu"]'+h+', [role="listbox"]'+h);if(i.length){var j=i.index(b.target);38==b.which&&j>0&&j--,40==b.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",'[role="menu"]',g.prototype.keydown).on("keydown.bs.dropdown.data-api",'[role="listbox"]',g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.4",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in").attr("aria-hidden",!1),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a('<div class="modal-backdrop '+e+'" />').appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.init("tooltip",a,b)};c.VERSION="3.3.4",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport),this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c&&c.$tip&&c.$tip.is(":visible")?void(c.hoverState="in"):(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.options.container?a(this.options.container):this.$element.parent(),p=this.getPosition(o);h="bottom"==h&&k.bottom+m>p.bottom?"top":"top"==h&&k.top-m<p.top?"bottom":"right"==h&&k.right+l>p.width?"left":"left"==h&&k.left-l<p.left?"right":h,f.removeClass(n).addClass(h)}var q=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(q,h);var r=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",r).emulateTransitionEnd(c.TRANSITION_DURATION):r()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top=b.top+g,b.left=b.left+h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type)})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.4",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.4",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.4",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){
+var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.4",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=a(document.body).height();"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/htdocs/js/cbpAnimatedHeader.js b/fluent-bit/lib/monkey/htdocs/js/cbpAnimatedHeader.js
new file mode 100644
index 000000000..7c3bbc172
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/js/cbpAnimatedHeader.js
@@ -0,0 +1,44 @@
+/**
+ * cbpAnimatedHeader.js v1.0.0
+ * http://www.codrops.com
+ *
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * Copyright 2013, Codrops
+ * http://www.codrops.com
+ */
+var cbpAnimatedHeader = (function() {
+
+ var docElem = document.documentElement,
+ header = document.querySelector( '.navbar-fixed-top' ),
+ didScroll = false,
+ changeHeaderOn = 300;
+
+ function init() {
+ window.addEventListener( 'scroll', function( event ) {
+ if( !didScroll ) {
+ didScroll = true;
+ setTimeout( scrollPage, 250 );
+ }
+ }, false );
+ }
+
+ function scrollPage() {
+ var sy = scrollY();
+ if ( sy >= changeHeaderOn ) {
+ classie.add( header, 'navbar-shrink' );
+ }
+ else {
+ classie.remove( header, 'navbar-shrink' );
+ }
+ didScroll = false;
+ }
+
+ function scrollY() {
+ return window.pageYOffset || docElem.scrollTop;
+ }
+
+ init();
+
+})(); \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/htdocs/js/cbpAnimatedHeader.min.js b/fluent-bit/lib/monkey/htdocs/js/cbpAnimatedHeader.min.js
new file mode 100644
index 000000000..b39cb0dcd
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/js/cbpAnimatedHeader.min.js
@@ -0,0 +1,11 @@
+/**
+ * cbpAnimatedHeader.min.js v1.0.0
+ * http://www.codrops.com
+ *
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * Copyright 2013, Codrops
+ * http://www.codrops.com
+ */
+var cbpAnimatedHeader=(function(){var b=document.documentElement,g=document.querySelector(".cbp-af-header"),e=false,a=300;function f(){window.addEventListener("scroll",function(h){if(!e){e=true;setTimeout(d,250)}},false)}function d(){var h=c();if(h>=a){classie.add(g,"cbp-af-header-shrink")}else{classie.remove(g,"cbp-af-header-shrink")}e=false}function c(){return window.pageYOffset||b.scrollTop}f()})(); \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/htdocs/js/classie.js b/fluent-bit/lib/monkey/htdocs/js/classie.js
new file mode 100644
index 000000000..a96755488
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/js/classie.js
@@ -0,0 +1,80 @@
+/*!
+ * classie - class helper functions
+ * from bonzo https://github.com/ded/bonzo
+ *
+ * classie.has( elem, 'my-class' ) -> true/false
+ * classie.add( elem, 'my-new-class' )
+ * classie.remove( elem, 'my-unwanted-class' )
+ * classie.toggle( elem, 'my-class' )
+ */
+
+/*jshint browser: true, strict: true, undef: true */
+/*global define: false */
+
+( function( window ) {
+
+'use strict';
+
+// class helper functions from bonzo https://github.com/ded/bonzo
+
+function classReg( className ) {
+ return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
+}
+
+// classList support for class management
+// altho to be fair, the api sucks because it won't accept multiple classes at once
+var hasClass, addClass, removeClass;
+
+if ( 'classList' in document.documentElement ) {
+ hasClass = function( elem, c ) {
+ return elem.classList.contains( c );
+ };
+ addClass = function( elem, c ) {
+ elem.classList.add( c );
+ };
+ removeClass = function( elem, c ) {
+ elem.classList.remove( c );
+ };
+}
+else {
+ hasClass = function( elem, c ) {
+ return classReg( c ).test( elem.className );
+ };
+ addClass = function( elem, c ) {
+ if ( !hasClass( elem, c ) ) {
+ elem.className = elem.className + ' ' + c;
+ }
+ };
+ removeClass = function( elem, c ) {
+ elem.className = elem.className.replace( classReg( c ), ' ' );
+ };
+}
+
+function toggleClass( elem, c ) {
+ var fn = hasClass( elem, c ) ? removeClass : addClass;
+ fn( elem, c );
+}
+
+var classie = {
+ // full names
+ hasClass: hasClass,
+ addClass: addClass,
+ removeClass: removeClass,
+ toggleClass: toggleClass,
+ // short names
+ has: hasClass,
+ add: addClass,
+ remove: removeClass,
+ toggle: toggleClass
+};
+
+// transport
+if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( classie );
+} else {
+ // browser global
+ window.classie = classie;
+}
+
+})( window );
diff --git a/fluent-bit/lib/monkey/htdocs/js/freelancer.js b/fluent-bit/lib/monkey/htdocs/js/freelancer.js
new file mode 100644
index 000000000..b1f77b360
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/js/freelancer.js
@@ -0,0 +1,37 @@
+/*!
+ * Start Bootstrap - Freelancer Bootstrap Theme (http://startbootstrap.com)
+ * Code licensed under the Apache License v2.0.
+ * For details, see http://www.apache.org/licenses/LICENSE-2.0.
+ */
+
+// jQuery for page scrolling feature - requires jQuery Easing plugin
+$(function() {
+ $('body').on('click', '.page-scroll a', function(event) {
+ var $anchor = $(this);
+ $('html, body').stop().animate({
+ scrollTop: $($anchor.attr('href')).offset().top
+ }, 1500, 'easeInOutExpo');
+ event.preventDefault();
+ });
+});
+
+// Floating label headings for the contact form
+$(function() {
+ $("body").on("input propertychange", ".floating-label-form-group", function(e) {
+ $(this).toggleClass("floating-label-form-group-with-value", !! $(e.target).val());
+ }).on("focus", ".floating-label-form-group", function() {
+ $(this).addClass("floating-label-form-group-with-focus");
+ }).on("blur", ".floating-label-form-group", function() {
+ $(this).removeClass("floating-label-form-group-with-focus");
+ });
+});
+
+// Highlight the top nav as scrolling occurs
+$('body').scrollspy({
+ target: '.navbar-fixed-top'
+})
+
+// Closes the Responsive Menu on Menu Item Click
+$('.navbar-collapse ul li a').click(function() {
+ $('.navbar-toggle:visible').click();
+});
diff --git a/fluent-bit/lib/monkey/htdocs/js/jqBootstrapValidation.js b/fluent-bit/lib/monkey/htdocs/js/jqBootstrapValidation.js
new file mode 100644
index 000000000..29cbb083e
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/js/jqBootstrapValidation.js
@@ -0,0 +1,912 @@
+/* jqBootstrapValidation
+ * A plugin for automating validation on Twitter Bootstrap formatted forms.
+ *
+ * v1.3.6
+ *
+ * License: MIT <http://opensource.org/licenses/mit-license.php> - see LICENSE file
+ *
+ * http://ReactiveRaven.github.com/jqBootstrapValidation/
+ */
+
+(function( $ ){
+
+ var createdElements = [];
+
+ var defaults = {
+ options: {
+ prependExistingHelpBlock: false,
+ sniffHtml: true, // sniff for 'required', 'maxlength', etc
+ preventSubmit: true, // stop the form submit event from firing if validation fails
+ submitError: false, // function called if there is an error when trying to submit
+ submitSuccess: false, // function called just before a successful submit event is sent to the server
+ semanticallyStrict: false, // set to true to tidy up generated HTML output
+ autoAdd: {
+ helpBlocks: true
+ },
+ filter: function () {
+ // return $(this).is(":visible"); // only validate elements you can see
+ return true; // validate everything
+ }
+ },
+ methods: {
+ init : function( options ) {
+
+ var settings = $.extend(true, {}, defaults);
+
+ settings.options = $.extend(true, settings.options, options);
+
+ var $siblingElements = this;
+
+ var uniqueForms = $.unique(
+ $siblingElements.map( function () {
+ return $(this).parents("form")[0];
+ }).toArray()
+ );
+
+ $(uniqueForms).bind("submit", function (e) {
+ var $form = $(this);
+ var warningsFound = 0;
+ var $inputs = $form.find("input,textarea,select").not("[type=submit],[type=image]").filter(settings.options.filter);
+ $inputs.trigger("submit.validation").trigger("validationLostFocus.validation");
+
+ $inputs.each(function (i, el) {
+ var $this = $(el),
+ $controlGroup = $this.parents(".control-group").first();
+ if (
+ $controlGroup.hasClass("warning")
+ ) {
+ $controlGroup.removeClass("warning").addClass("error");
+ warningsFound++;
+ }
+ });
+
+ $inputs.trigger("validationLostFocus.validation");
+
+ if (warningsFound) {
+ if (settings.options.preventSubmit) {
+ e.preventDefault();
+ }
+ $form.addClass("error");
+ if ($.isFunction(settings.options.submitError)) {
+ settings.options.submitError($form, e, $inputs.jqBootstrapValidation("collectErrors", true));
+ }
+ } else {
+ $form.removeClass("error");
+ if ($.isFunction(settings.options.submitSuccess)) {
+ settings.options.submitSuccess($form, e);
+ }
+ }
+ });
+
+ return this.each(function(){
+
+ // Get references to everything we're interested in
+ var $this = $(this),
+ $controlGroup = $this.parents(".control-group").first(),
+ $helpBlock = $controlGroup.find(".help-block").first(),
+ $form = $this.parents("form").first(),
+ validatorNames = [];
+
+ // create message container if not exists
+ if (!$helpBlock.length && settings.options.autoAdd && settings.options.autoAdd.helpBlocks) {
+ $helpBlock = $('<div class="help-block" />');
+ $controlGroup.find('.controls').append($helpBlock);
+ createdElements.push($helpBlock[0]);
+ }
+
+ // =============================================================
+ // SNIFF HTML FOR VALIDATORS
+ // =============================================================
+
+ // *snort sniff snuffle*
+
+ if (settings.options.sniffHtml) {
+ var message = "";
+ // ---------------------------------------------------------
+ // PATTERN
+ // ---------------------------------------------------------
+ if ($this.attr("pattern") !== undefined) {
+ message = "Not in the expected format<!-- data-validation-pattern-message to override -->";
+ if ($this.data("validationPatternMessage")) {
+ message = $this.data("validationPatternMessage");
+ }
+ $this.data("validationPatternMessage", message);
+ $this.data("validationPatternRegex", $this.attr("pattern"));
+ }
+ // ---------------------------------------------------------
+ // MAX
+ // ---------------------------------------------------------
+ if ($this.attr("max") !== undefined || $this.attr("aria-valuemax") !== undefined) {
+ var max = ($this.attr("max") !== undefined ? $this.attr("max") : $this.attr("aria-valuemax"));
+ message = "Too high: Maximum of '" + max + "'<!-- data-validation-max-message to override -->";
+ if ($this.data("validationMaxMessage")) {
+ message = $this.data("validationMaxMessage");
+ }
+ $this.data("validationMaxMessage", message);
+ $this.data("validationMaxMax", max);
+ }
+ // ---------------------------------------------------------
+ // MIN
+ // ---------------------------------------------------------
+ if ($this.attr("min") !== undefined || $this.attr("aria-valuemin") !== undefined) {
+ var min = ($this.attr("min") !== undefined ? $this.attr("min") : $this.attr("aria-valuemin"));
+ message = "Too low: Minimum of '" + min + "'<!-- data-validation-min-message to override -->";
+ if ($this.data("validationMinMessage")) {
+ message = $this.data("validationMinMessage");
+ }
+ $this.data("validationMinMessage", message);
+ $this.data("validationMinMin", min);
+ }
+ // ---------------------------------------------------------
+ // MAXLENGTH
+ // ---------------------------------------------------------
+ if ($this.attr("maxlength") !== undefined) {
+ message = "Too long: Maximum of '" + $this.attr("maxlength") + "' characters<!-- data-validation-maxlength-message to override -->";
+ if ($this.data("validationMaxlengthMessage")) {
+ message = $this.data("validationMaxlengthMessage");
+ }
+ $this.data("validationMaxlengthMessage", message);
+ $this.data("validationMaxlengthMaxlength", $this.attr("maxlength"));
+ }
+ // ---------------------------------------------------------
+ // MINLENGTH
+ // ---------------------------------------------------------
+ if ($this.attr("minlength") !== undefined) {
+ message = "Too short: Minimum of '" + $this.attr("minlength") + "' characters<!-- data-validation-minlength-message to override -->";
+ if ($this.data("validationMinlengthMessage")) {
+ message = $this.data("validationMinlengthMessage");
+ }
+ $this.data("validationMinlengthMessage", message);
+ $this.data("validationMinlengthMinlength", $this.attr("minlength"));
+ }
+ // ---------------------------------------------------------
+ // REQUIRED
+ // ---------------------------------------------------------
+ if ($this.attr("required") !== undefined || $this.attr("aria-required") !== undefined) {
+ message = settings.builtInValidators.required.message;
+ if ($this.data("validationRequiredMessage")) {
+ message = $this.data("validationRequiredMessage");
+ }
+ $this.data("validationRequiredMessage", message);
+ }
+ // ---------------------------------------------------------
+ // NUMBER
+ // ---------------------------------------------------------
+ if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "number") {
+ message = settings.builtInValidators.number.message;
+ if ($this.data("validationNumberMessage")) {
+ message = $this.data("validationNumberMessage");
+ }
+ $this.data("validationNumberMessage", message);
+ }
+ // ---------------------------------------------------------
+ // EMAIL
+ // ---------------------------------------------------------
+ if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "email") {
+ message = "Not a valid email address<!-- data-validator-validemail-message to override -->";
+ if ($this.data("validationValidemailMessage")) {
+ message = $this.data("validationValidemailMessage");
+ } else if ($this.data("validationEmailMessage")) {
+ message = $this.data("validationEmailMessage");
+ }
+ $this.data("validationValidemailMessage", message);
+ }
+ // ---------------------------------------------------------
+ // MINCHECKED
+ // ---------------------------------------------------------
+ if ($this.attr("minchecked") !== undefined) {
+ message = "Not enough options checked; Minimum of '" + $this.attr("minchecked") + "' required<!-- data-validation-minchecked-message to override -->";
+ if ($this.data("validationMincheckedMessage")) {
+ message = $this.data("validationMincheckedMessage");
+ }
+ $this.data("validationMincheckedMessage", message);
+ $this.data("validationMincheckedMinchecked", $this.attr("minchecked"));
+ }
+ // ---------------------------------------------------------
+ // MAXCHECKED
+ // ---------------------------------------------------------
+ if ($this.attr("maxchecked") !== undefined) {
+ message = "Too many options checked; Maximum of '" + $this.attr("maxchecked") + "' required<!-- data-validation-maxchecked-message to override -->";
+ if ($this.data("validationMaxcheckedMessage")) {
+ message = $this.data("validationMaxcheckedMessage");
+ }
+ $this.data("validationMaxcheckedMessage", message);
+ $this.data("validationMaxcheckedMaxchecked", $this.attr("maxchecked"));
+ }
+ }
+
+ // =============================================================
+ // COLLECT VALIDATOR NAMES
+ // =============================================================
+
+ // Get named validators
+ if ($this.data("validation") !== undefined) {
+ validatorNames = $this.data("validation").split(",");
+ }
+
+ // Get extra ones defined on the element's data attributes
+ $.each($this.data(), function (i, el) {
+ var parts = i.replace(/([A-Z])/g, ",$1").split(",");
+ if (parts[0] === "validation" && parts[1]) {
+ validatorNames.push(parts[1]);
+ }
+ });
+
+ // =============================================================
+ // NORMALISE VALIDATOR NAMES
+ // =============================================================
+
+ var validatorNamesToInspect = validatorNames;
+ var newValidatorNamesToInspect = [];
+
+ do // repeatedly expand 'shortcut' validators into their real validators
+ {
+ // Uppercase only the first letter of each name
+ $.each(validatorNames, function (i, el) {
+ validatorNames[i] = formatValidatorName(el);
+ });
+
+ // Remove duplicate validator names
+ validatorNames = $.unique(validatorNames);
+
+ // Pull out the new validator names from each shortcut
+ newValidatorNamesToInspect = [];
+ $.each(validatorNamesToInspect, function(i, el) {
+ if ($this.data("validation" + el + "Shortcut") !== undefined) {
+ // Are these custom validators?
+ // Pull them out!
+ $.each($this.data("validation" + el + "Shortcut").split(","), function(i2, el2) {
+ newValidatorNamesToInspect.push(el2);
+ });
+ } else if (settings.builtInValidators[el.toLowerCase()]) {
+ // Is this a recognised built-in?
+ // Pull it out!
+ var validator = settings.builtInValidators[el.toLowerCase()];
+ if (validator.type.toLowerCase() === "shortcut") {
+ $.each(validator.shortcut.split(","), function (i, el) {
+ el = formatValidatorName(el);
+ newValidatorNamesToInspect.push(el);
+ validatorNames.push(el);
+ });
+ }
+ }
+ });
+
+ validatorNamesToInspect = newValidatorNamesToInspect;
+
+ } while (validatorNamesToInspect.length > 0)
+
+ // =============================================================
+ // SET UP VALIDATOR ARRAYS
+ // =============================================================
+
+ var validators = {};
+
+ $.each(validatorNames, function (i, el) {
+ // Set up the 'override' message
+ var message = $this.data("validation" + el + "Message");
+ var hasOverrideMessage = (message !== undefined);
+ var foundValidator = false;
+ message =
+ (
+ message
+ ? message
+ : "'" + el + "' validation failed <!-- Add attribute 'data-validation-" + el.toLowerCase() + "-message' to input to change this message -->"
+ )
+ ;
+
+ $.each(
+ settings.validatorTypes,
+ function (validatorType, validatorTemplate) {
+ if (validators[validatorType] === undefined) {
+ validators[validatorType] = [];
+ }
+ if (!foundValidator && $this.data("validation" + el + formatValidatorName(validatorTemplate.name)) !== undefined) {
+ validators[validatorType].push(
+ $.extend(
+ true,
+ {
+ name: formatValidatorName(validatorTemplate.name),
+ message: message
+ },
+ validatorTemplate.init($this, el)
+ )
+ );
+ foundValidator = true;
+ }
+ }
+ );
+
+ if (!foundValidator && settings.builtInValidators[el.toLowerCase()]) {
+
+ var validator = $.extend(true, {}, settings.builtInValidators[el.toLowerCase()]);
+ if (hasOverrideMessage) {
+ validator.message = message;
+ }
+ var validatorType = validator.type.toLowerCase();
+
+ if (validatorType === "shortcut") {
+ foundValidator = true;
+ } else {
+ $.each(
+ settings.validatorTypes,
+ function (validatorTemplateType, validatorTemplate) {
+ if (validators[validatorTemplateType] === undefined) {
+ validators[validatorTemplateType] = [];
+ }
+ if (!foundValidator && validatorType === validatorTemplateType.toLowerCase()) {
+ $this.data("validation" + el + formatValidatorName(validatorTemplate.name), validator[validatorTemplate.name.toLowerCase()]);
+ validators[validatorType].push(
+ $.extend(
+ validator,
+ validatorTemplate.init($this, el)
+ )
+ );
+ foundValidator = true;
+ }
+ }
+ );
+ }
+ }
+
+ if (! foundValidator) {
+ $.error("Cannot find validation info for '" + el + "'");
+ }
+ });
+
+ // =============================================================
+ // STORE FALLBACK VALUES
+ // =============================================================
+
+ $helpBlock.data(
+ "original-contents",
+ (
+ $helpBlock.data("original-contents")
+ ? $helpBlock.data("original-contents")
+ : $helpBlock.html()
+ )
+ );
+
+ $helpBlock.data(
+ "original-role",
+ (
+ $helpBlock.data("original-role")
+ ? $helpBlock.data("original-role")
+ : $helpBlock.attr("role")
+ )
+ );
+
+ $controlGroup.data(
+ "original-classes",
+ (
+ $controlGroup.data("original-clases")
+ ? $controlGroup.data("original-classes")
+ : $controlGroup.attr("class")
+ )
+ );
+
+ $this.data(
+ "original-aria-invalid",
+ (
+ $this.data("original-aria-invalid")
+ ? $this.data("original-aria-invalid")
+ : $this.attr("aria-invalid")
+ )
+ );
+
+ // =============================================================
+ // VALIDATION
+ // =============================================================
+
+ $this.bind(
+ "validation.validation",
+ function (event, params) {
+
+ var value = getValue($this);
+
+ // Get a list of the errors to apply
+ var errorsFound = [];
+
+ $.each(validators, function (validatorType, validatorTypeArray) {
+ if (value || value.length || (params && params.includeEmpty) || (!!settings.validatorTypes[validatorType].blockSubmit && params && !!params.submitting)) {
+ $.each(validatorTypeArray, function (i, validator) {
+ if (settings.validatorTypes[validatorType].validate($this, value, validator)) {
+ errorsFound.push(validator.message);
+ }
+ });
+ }
+ });
+
+ return errorsFound;
+ }
+ );
+
+ $this.bind(
+ "getValidators.validation",
+ function () {
+ return validators;
+ }
+ );
+
+ // =============================================================
+ // WATCH FOR CHANGES
+ // =============================================================
+ $this.bind(
+ "submit.validation",
+ function () {
+ return $this.triggerHandler("change.validation", {submitting: true});
+ }
+ );
+ $this.bind(
+ [
+ "keyup",
+ "focus",
+ "blur",
+ "click",
+ "keydown",
+ "keypress",
+ "change"
+ ].join(".validation ") + ".validation",
+ function (e, params) {
+
+ var value = getValue($this);
+
+ var errorsFound = [];
+
+ $controlGroup.find("input,textarea,select").each(function (i, el) {
+ var oldCount = errorsFound.length;
+ $.each($(el).triggerHandler("validation.validation", params), function (j, message) {
+ errorsFound.push(message);
+ });
+ if (errorsFound.length > oldCount) {
+ $(el).attr("aria-invalid", "true");
+ } else {
+ var original = $this.data("original-aria-invalid");
+ $(el).attr("aria-invalid", (original !== undefined ? original : false));
+ }
+ });
+
+ $form.find("input,select,textarea").not($this).not("[name=\"" + $this.attr("name") + "\"]").trigger("validationLostFocus.validation");
+
+ errorsFound = $.unique(errorsFound.sort());
+
+ // Were there any errors?
+ if (errorsFound.length) {
+ // Better flag it up as a warning.
+ $controlGroup.removeClass("success error").addClass("warning");
+
+ // How many errors did we find?
+ if (settings.options.semanticallyStrict && errorsFound.length === 1) {
+ // Only one? Being strict? Just output it.
+ $helpBlock.html(errorsFound[0] +
+ ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
+ } else {
+ // Multiple? Being sloppy? Glue them together into an UL.
+ $helpBlock.html("<ul role=\"alert\"><li>" + errorsFound.join("</li><li>") + "</li></ul>" +
+ ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
+ }
+ } else {
+ $controlGroup.removeClass("warning error success");
+ if (value.length > 0) {
+ $controlGroup.addClass("success");
+ }
+ $helpBlock.html($helpBlock.data("original-contents"));
+ }
+
+ if (e.type === "blur") {
+ $controlGroup.removeClass("success");
+ }
+ }
+ );
+ $this.bind("validationLostFocus.validation", function () {
+ $controlGroup.removeClass("success");
+ });
+ });
+ },
+ destroy : function( ) {
+
+ return this.each(
+ function() {
+
+ var
+ $this = $(this),
+ $controlGroup = $this.parents(".control-group").first(),
+ $helpBlock = $controlGroup.find(".help-block").first();
+
+ // remove our events
+ $this.unbind('.validation'); // events are namespaced.
+ // reset help text
+ $helpBlock.html($helpBlock.data("original-contents"));
+ // reset classes
+ $controlGroup.attr("class", $controlGroup.data("original-classes"));
+ // reset aria
+ $this.attr("aria-invalid", $this.data("original-aria-invalid"));
+ // reset role
+ $helpBlock.attr("role", $this.data("original-role"));
+ // remove all elements we created
+ if (createdElements.indexOf($helpBlock[0]) > -1) {
+ $helpBlock.remove();
+ }
+
+ }
+ );
+
+ },
+ collectErrors : function(includeEmpty) {
+
+ var errorMessages = {};
+ this.each(function (i, el) {
+ var $el = $(el);
+ var name = $el.attr("name");
+ var errors = $el.triggerHandler("validation.validation", {includeEmpty: true});
+ errorMessages[name] = $.extend(true, errors, errorMessages[name]);
+ });
+
+ $.each(errorMessages, function (i, el) {
+ if (el.length === 0) {
+ delete errorMessages[i];
+ }
+ });
+
+ return errorMessages;
+
+ },
+ hasErrors: function() {
+
+ var errorMessages = [];
+
+ this.each(function (i, el) {
+ errorMessages = errorMessages.concat(
+ $(el).triggerHandler("getValidators.validation") ? $(el).triggerHandler("validation.validation", {submitting: true}) : []
+ );
+ });
+
+ return (errorMessages.length > 0);
+ },
+ override : function (newDefaults) {
+ defaults = $.extend(true, defaults, newDefaults);
+ }
+ },
+ validatorTypes: {
+ callback: {
+ name: "callback",
+ init: function ($this, name) {
+ return {
+ validatorName: name,
+ callback: $this.data("validation" + name + "Callback"),
+ lastValue: $this.val(),
+ lastValid: true,
+ lastFinished: true
+ };
+ },
+ validate: function ($this, value, validator) {
+ if (validator.lastValue === value && validator.lastFinished) {
+ return !validator.lastValid;
+ }
+
+ if (validator.lastFinished === true)
+ {
+ validator.lastValue = value;
+ validator.lastValid = true;
+ validator.lastFinished = false;
+
+ var rrjqbvValidator = validator;
+ var rrjqbvThis = $this;
+ executeFunctionByName(
+ validator.callback,
+ window,
+ $this,
+ value,
+ function (data) {
+ if (rrjqbvValidator.lastValue === data.value) {
+ rrjqbvValidator.lastValid = data.valid;
+ if (data.message) {
+ rrjqbvValidator.message = data.message;
+ }
+ rrjqbvValidator.lastFinished = true;
+ rrjqbvThis.data("validation" + rrjqbvValidator.validatorName + "Message", rrjqbvValidator.message);
+ // Timeout is set to avoid problems with the events being considered 'already fired'
+ setTimeout(function () {
+ rrjqbvThis.trigger("change.validation");
+ }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
+ }
+ }
+ );
+ }
+
+ return false;
+
+ }
+ },
+ ajax: {
+ name: "ajax",
+ init: function ($this, name) {
+ return {
+ validatorName: name,
+ url: $this.data("validation" + name + "Ajax"),
+ lastValue: $this.val(),
+ lastValid: true,
+ lastFinished: true
+ };
+ },
+ validate: function ($this, value, validator) {
+ if (""+validator.lastValue === ""+value && validator.lastFinished === true) {
+ return validator.lastValid === false;
+ }
+
+ if (validator.lastFinished === true)
+ {
+ validator.lastValue = value;
+ validator.lastValid = true;
+ validator.lastFinished = false;
+ $.ajax({
+ url: validator.url,
+ data: "value=" + value + "&field=" + $this.attr("name"),
+ dataType: "json",
+ success: function (data) {
+ if (""+validator.lastValue === ""+data.value) {
+ validator.lastValid = !!(data.valid);
+ if (data.message) {
+ validator.message = data.message;
+ }
+ validator.lastFinished = true;
+ $this.data("validation" + validator.validatorName + "Message", validator.message);
+ // Timeout is set to avoid problems with the events being considered 'already fired'
+ setTimeout(function () {
+ $this.trigger("change.validation");
+ }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
+ }
+ },
+ failure: function () {
+ validator.lastValid = true;
+ validator.message = "ajax call failed";
+ validator.lastFinished = true;
+ $this.data("validation" + validator.validatorName + "Message", validator.message);
+ // Timeout is set to avoid problems with the events being considered 'already fired'
+ setTimeout(function () {
+ $this.trigger("change.validation");
+ }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
+ }
+ });
+ }
+
+ return false;
+
+ }
+ },
+ regex: {
+ name: "regex",
+ init: function ($this, name) {
+ return {regex: regexFromString($this.data("validation" + name + "Regex"))};
+ },
+ validate: function ($this, value, validator) {
+ return (!validator.regex.test(value) && ! validator.negative)
+ || (validator.regex.test(value) && validator.negative);
+ }
+ },
+ required: {
+ name: "required",
+ init: function ($this, name) {
+ return {};
+ },
+ validate: function ($this, value, validator) {
+ return !!(value.length === 0 && ! validator.negative)
+ || !!(value.length > 0 && validator.negative);
+ },
+ blockSubmit: true
+ },
+ match: {
+ name: "match",
+ init: function ($this, name) {
+ var element = $this.parents("form").first().find("[name=\"" + $this.data("validation" + name + "Match") + "\"]").first();
+ element.bind("validation.validation", function () {
+ $this.trigger("change.validation", {submitting: true});
+ });
+ return {"element": element};
+ },
+ validate: function ($this, value, validator) {
+ return (value !== validator.element.val() && ! validator.negative)
+ || (value === validator.element.val() && validator.negative);
+ },
+ blockSubmit: true
+ },
+ max: {
+ name: "max",
+ init: function ($this, name) {
+ return {max: $this.data("validation" + name + "Max")};
+ },
+ validate: function ($this, value, validator) {
+ return (parseFloat(value, 10) > parseFloat(validator.max, 10) && ! validator.negative)
+ || (parseFloat(value, 10) <= parseFloat(validator.max, 10) && validator.negative);
+ }
+ },
+ min: {
+ name: "min",
+ init: function ($this, name) {
+ return {min: $this.data("validation" + name + "Min")};
+ },
+ validate: function ($this, value, validator) {
+ return (parseFloat(value) < parseFloat(validator.min) && ! validator.negative)
+ || (parseFloat(value) >= parseFloat(validator.min) && validator.negative);
+ }
+ },
+ maxlength: {
+ name: "maxlength",
+ init: function ($this, name) {
+ return {maxlength: $this.data("validation" + name + "Maxlength")};
+ },
+ validate: function ($this, value, validator) {
+ return ((value.length > validator.maxlength) && ! validator.negative)
+ || ((value.length <= validator.maxlength) && validator.negative);
+ }
+ },
+ minlength: {
+ name: "minlength",
+ init: function ($this, name) {
+ return {minlength: $this.data("validation" + name + "Minlength")};
+ },
+ validate: function ($this, value, validator) {
+ return ((value.length < validator.minlength) && ! validator.negative)
+ || ((value.length >= validator.minlength) && validator.negative);
+ }
+ },
+ maxchecked: {
+ name: "maxchecked",
+ init: function ($this, name) {
+ var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
+ elements.bind("click.validation", function () {
+ $this.trigger("change.validation", {includeEmpty: true});
+ });
+ return {maxchecked: $this.data("validation" + name + "Maxchecked"), elements: elements};
+ },
+ validate: function ($this, value, validator) {
+ return (validator.elements.filter(":checked").length > validator.maxchecked && ! validator.negative)
+ || (validator.elements.filter(":checked").length <= validator.maxchecked && validator.negative);
+ },
+ blockSubmit: true
+ },
+ minchecked: {
+ name: "minchecked",
+ init: function ($this, name) {
+ var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
+ elements.bind("click.validation", function () {
+ $this.trigger("change.validation", {includeEmpty: true});
+ });
+ return {minchecked: $this.data("validation" + name + "Minchecked"), elements: elements};
+ },
+ validate: function ($this, value, validator) {
+ return (validator.elements.filter(":checked").length < validator.minchecked && ! validator.negative)
+ || (validator.elements.filter(":checked").length >= validator.minchecked && validator.negative);
+ },
+ blockSubmit: true
+ }
+ },
+ builtInValidators: {
+ email: {
+ name: "Email",
+ type: "shortcut",
+ shortcut: "validemail"
+ },
+ validemail: {
+ name: "Validemail",
+ type: "regex",
+ regex: "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\.[A-Za-z]{2,4}",
+ message: "Not a valid email address<!-- data-validator-validemail-message to override -->"
+ },
+ passwordagain: {
+ name: "Passwordagain",
+ type: "match",
+ match: "password",
+ message: "Does not match the given password<!-- data-validator-paswordagain-message to override -->"
+ },
+ positive: {
+ name: "Positive",
+ type: "shortcut",
+ shortcut: "number,positivenumber"
+ },
+ negative: {
+ name: "Negative",
+ type: "shortcut",
+ shortcut: "number,negativenumber"
+ },
+ number: {
+ name: "Number",
+ type: "regex",
+ regex: "([+-]?\\\d+(\\\.\\\d*)?([eE][+-]?[0-9]+)?)?",
+ message: "Must be a number<!-- data-validator-number-message to override -->"
+ },
+ integer: {
+ name: "Integer",
+ type: "regex",
+ regex: "[+-]?\\\d+",
+ message: "No decimal places allowed<!-- data-validator-integer-message to override -->"
+ },
+ positivenumber: {
+ name: "Positivenumber",
+ type: "min",
+ min: 0,
+ message: "Must be a positive number<!-- data-validator-positivenumber-message to override -->"
+ },
+ negativenumber: {
+ name: "Negativenumber",
+ type: "max",
+ max: 0,
+ message: "Must be a negative number<!-- data-validator-negativenumber-message to override -->"
+ },
+ required: {
+ name: "Required",
+ type: "required",
+ message: "This is required<!-- data-validator-required-message to override -->"
+ },
+ checkone: {
+ name: "Checkone",
+ type: "minchecked",
+ minchecked: 1,
+ message: "Check at least one option<!-- data-validation-checkone-message to override -->"
+ }
+ }
+ };
+
+ var formatValidatorName = function (name) {
+ return name
+ .toLowerCase()
+ .replace(
+ /(^|\s)([a-z])/g ,
+ function(m,p1,p2) {
+ return p1+p2.toUpperCase();
+ }
+ )
+ ;
+ };
+
+ var getValue = function ($this) {
+ // Extract the value we're talking about
+ var value = $this.val();
+ var type = $this.attr("type");
+ if (type === "checkbox") {
+ value = ($this.is(":checked") ? value : "");
+ }
+ if (type === "radio") {
+ value = ($('input[name="' + $this.attr("name") + '"]:checked').length > 0 ? value : "");
+ }
+ return value;
+ };
+
+ function regexFromString(inputstring) {
+ return new RegExp("^" + inputstring + "$");
+ }
+
+ /**
+ * Thanks to Jason Bunting via StackOverflow.com
+ *
+ * http://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string#answer-359910
+ * Short link: http://tinyurl.com/executeFunctionByName
+ **/
+ function executeFunctionByName(functionName, context /*, args*/) {
+ var args = Array.prototype.slice.call(arguments).splice(2);
+ var namespaces = functionName.split(".");
+ var func = namespaces.pop();
+ for(var i = 0; i < namespaces.length; i++) {
+ context = context[namespaces[i]];
+ }
+ return context[func].apply(this, args);
+ }
+
+ $.fn.jqBootstrapValidation = function( method ) {
+
+ if ( defaults.methods[method] ) {
+ return defaults.methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
+ } else if ( typeof method === 'object' || ! method ) {
+ return defaults.methods.init.apply( this, arguments );
+ } else {
+ $.error( 'Method ' + method + ' does not exist on jQuery.jqBootstrapValidation' );
+ return null;
+ }
+
+ };
+
+ $.jqBootstrapValidation = function (options) {
+ $(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this,arguments);
+ };
+
+})( jQuery );
diff --git a/fluent-bit/lib/monkey/htdocs/js/jquery.js b/fluent-bit/lib/monkey/htdocs/js/jquery.js
new file mode 100644
index 000000000..d1608e37f
--- /dev/null
+++ b/fluent-bit/lib/monkey/htdocs/js/jquery.js
@@ -0,0 +1,4 @@
+/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="<select msallowclip=''><option selected=''></option></select>",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=lb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=mb(b);function pb(){}pb.prototype=d.filters=d.pseudos,d.setFilters=new pb,g=fb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fb.error(a):z(a,i).slice(0)};function qb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;
+if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[m.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=Z.test(e)?this.mouseHooks:Y.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new m.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||y),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||y,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==cb()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===cb()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return m.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return m.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=m.extend(new m.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?m.event.trigger(e,null,b):m.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},m.removeEvent=y.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===K&&(a[d]=null),a.detachEvent(d,c))},m.Event=function(a,b){return this instanceof m.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ab:bb):this.type=a,b&&m.extend(this,b),this.timeStamp=a&&a.timeStamp||m.now(),void(this[m.expando]=!0)):new m.Event(a,b)},m.Event.prototype={isDefaultPrevented:bb,isPropagationStopped:bb,isImmediatePropagationStopped:bb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ab,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ab,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ab,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},m.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){m.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!m.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.submitBubbles||(m.event.special.submit={setup:function(){return m.nodeName(this,"form")?!1:void m.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=m.nodeName(b,"input")||m.nodeName(b,"button")?b.form:void 0;c&&!m._data(c,"submitBubbles")&&(m.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),m._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&m.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return m.nodeName(this,"form")?!1:void m.event.remove(this,"._submit")}}),k.changeBubbles||(m.event.special.change={setup:function(){return X.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(m.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),m.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),m.event.simulate("change",this,a,!0)})),!1):void m.event.add(this,"beforeactivate._change",function(a){var b=a.target;X.test(b.nodeName)&&!m._data(b,"changeBubbles")&&(m.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||m.event.simulate("change",this.parentNode,a,!0)}),m._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return m.event.remove(this,"._change"),!X.test(this.nodeName)}}),k.focusinBubbles||m.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){m.event.simulate(b,a.target,m.event.fix(a),!0)};m.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=m._data(d,b);e||d.addEventListener(a,c,!0),m._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=m._data(d,b)-1;e?m._data(d,b,e):(d.removeEventListener(a,c,!0),m._removeData(d,b))}}}),m.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=bb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return m().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=m.guid++)),this.each(function(){m.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,m(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=bb),this.each(function(){m.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){m.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?m.event.trigger(a,b,c,!0):void 0}});function db(a){var b=eb.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var eb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",fb=/ jQuery\d+="(?:null|\d+)"/g,gb=new RegExp("<(?:"+eb+")[\\s/>]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/<tbody/i,lb=/<|&#?\w+;/,mb=/<(?:script|style|link)/i,nb=/checked\s*(?:[^=]|=\s*.checked.)/i,ob=/^$|\/(?:java|ecma)script/i,pb=/^true\/(.*)/,qb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,rb={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:k.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1></$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?"<table>"!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Cb[0].contentWindow||Cb[0].contentDocument).document,b.write(),b.close(),c=Eb(a,b),Cb.detach()),Db[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Gb=/^margin/,Hb=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ib,Jb,Kb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ib=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Hb.test(g)&&Gb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ib=function(a){return a.currentStyle},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Hb.test(g)&&!Kb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Lb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight)),b.innerHTML="<table><tr><td></td><td>t</td></tr></table>",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Mb=/alpha\([^)]*\)/i,Nb=/opacity\s*=\s*([^)]*)/,Ob=/^(none|table(?!-c[ea]).+)/,Pb=new RegExp("^("+S+")(.*)$","i"),Qb=new RegExp("^([+-])=("+S+")","i"),Rb={position:"absolute",visibility:"hidden",display:"block"},Sb={letterSpacing:"0",fontWeight:"400"},Tb=["Webkit","O","Moz","ms"];function Ub(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Tb.length;while(e--)if(b=Tb[e]+c,b in a)return b;return d}function Vb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fb(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wb(a,b,c){var d=Pb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Yb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ib(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Jb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Hb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xb(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Jb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ub(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ub(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Jb(a,b,d)),"normal"===f&&b in Sb&&(f=Sb[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Ob.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Rb,function(){return Yb(a,b,d)}):Yb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ib(a);return Wb(a,c,d?Xb(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Nb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Mb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Mb.test(f)?f.replace(Mb,e):f+" "+e)}}),m.cssHooks.marginRight=Lb(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Jb,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Gb.test(a)||(m.cssHooks[a+b].set=Wb)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ib(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Vb(this,!0)},hide:function(){return Vb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Zb(a,b,c,d,e){return new Zb.prototype.init(a,b,c,d,e)}m.Tween=Zb,Zb.prototype={constructor:Zb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")
+},cur:function(){var a=Zb.propHooks[this.prop];return a&&a.get?a.get(this):Zb.propHooks._default.get(this)},run:function(a){var b,c=Zb.propHooks[this.prop];return this.pos=b=this.options.duration?m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Zb.propHooks._default.set(this),this}},Zb.prototype.init.prototype=Zb.prototype,Zb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Zb.propHooks.scrollTop=Zb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Zb.prototype.init,m.fx.step={};var $b,_b,ac=/^(?:toggle|show|hide)$/,bc=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cc=/queueHooks$/,dc=[ic],ec={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bc.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bc.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fc(){return setTimeout(function(){$b=void 0}),$b=m.now()}function gc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hc(a,b,c){for(var d,e=(ec[b]||[]).concat(ec["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ic(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fb(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fb(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ac.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fb(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hc(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jc(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kc(a,b,c){var d,e,f=0,g=dc.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$b||fc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$b||fc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jc(k,j.opts.specialEasing);g>f;f++)if(d=dc[f].call(j,a,k,j.opts))return d;return m.map(k,hc,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kc,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],ec[c]=ec[c]||[],ec[c].unshift(b)},prefilter:function(a,b){b?dc.unshift(a):dc.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kc(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gc(b,!0),a,d,e)}}),m.each({slideDown:gc("show"),slideUp:gc("hide"),slideToggle:gc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($b=m.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||m.fx.stop(),$b=void 0},m.fx.timer=function(a){m.timers.push(a),a()?m.fx.start():m.timers.pop()},m.fx.interval=13,m.fx.start=function(){_b||(_b=setInterval(m.fx.tick,m.fx.interval))},m.fx.stop=function(){clearInterval(_b),_b=null},m.fx.speeds={slow:600,fast:200,_default:400},m.fn.delay=function(a,b){return a=m.fx?m.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e;b=y.createElement("div"),b.setAttribute("className","t"),b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lc=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lc,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mc,nc,oc=m.expr.attrHandle,pc=/^(?:checked|selected)$/i,qc=k.getSetAttribute,rc=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nc:mc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rc&&qc||!pc.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qc?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nc={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rc&&qc||!pc.test(c)?a.setAttribute(!qc&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=oc[b]||m.find.attr;oc[b]=rc&&qc||!pc.test(b)?function(a,b,d){var e,f;return d||(f=oc[b],oc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,oc[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rc&&qc||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mc&&mc.set(a,b,c)}}),qc||(mc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},oc.id=oc.name=oc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mc.set},m.attrHooks.contenteditable={set:function(a,b,c){mc.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sc=/^(?:input|select|textarea|button|object)$/i,tc=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sc.test(a.nodeName)||tc.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var uc=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(uc," ").indexOf(b)>=0)return!0;return!1}}),m.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vc=m.now(),wc=/\?/,xc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yc,zc,Ac=/#.*$/,Bc=/([?&])_=[^&]*/,Cc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Dc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ec=/^(?:GET|HEAD)$/,Fc=/^\/\//,Gc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hc={},Ic={},Jc="*/".concat("*");try{zc=location.href}catch(Kc){zc=y.createElement("a"),zc.href="",zc=zc.href}yc=Gc.exec(zc.toLowerCase())||[];function Lc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mc(a,b,c,d){var e={},f=a===Ic;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nc(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Oc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zc,type:"GET",isLocal:Dc.test(yc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nc(Nc(a,m.ajaxSettings),b):Nc(m.ajaxSettings,a)},ajaxPrefilter:Lc(Hc),ajaxTransport:Lc(Ic),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zc)+"").replace(Ac,"").replace(Fc,yc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yc[1]&&c[2]===yc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yc[3]||("http:"===yc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mc(Hc,k,b,v),2===t)return v;h=k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Ec.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bc.test(e)?e.replace(Bc,"$1_="+vc++):e+(wc.test(e)?"&":"?")+"_="+vc++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mc(Ic,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Oc(k,v,c)),u=Pc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qc=/%20/g,Rc=/\[\]$/,Sc=/\r?\n/g,Tc=/^(?:submit|button|image|reset|file)$/i,Uc=/^(?:input|select|textarea|keygen)/i;function Vc(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rc.test(a)?d(a,e):Vc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vc(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vc(c,a[c],b,e);return d.join("&").replace(Qc,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Uc.test(this.nodeName)&&!Tc.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sc,"\r\n")}}):{name:b.name,value:c.replace(Sc,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zc()||$c()}:Zc;var Wc=0,Xc={},Yc=m.ajaxSettings.xhr();a.ActiveXObject&&m(a).on("unload",function(){for(var a in Xc)Xc[a](void 0,!0)}),k.cors=!!Yc&&"withCredentials"in Yc,Yc=k.ajax=!!Yc,Yc&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xc[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zc(){try{return new a.XMLHttpRequest}catch(b){}}function $c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _c=[],ad=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_c.pop()||m.expando+"_"+vc++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ad.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ad.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ad,"$1"+e):b.jsonp!==!1&&(b.url+=(wc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_c.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bd=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bd)return bd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("<div>").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cd=a.document.documentElement;function dd(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dd(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cd;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cd})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dd(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=Lb(k.pixelPosition,function(a,c){return c?(c=Jb(a,b),Hb.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ed=a.jQuery,fd=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fd),b&&a.jQuery===m&&(a.jQuery=ed),m},typeof b===K&&(a.jQuery=a.$=m),m}); \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/include/CMakeLists.txt b/fluent-bit/lib/monkey/include/CMakeLists.txt
new file mode 100644
index 000000000..78af01bcc
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/CMakeLists.txt
@@ -0,0 +1,11 @@
+# MK_CORE
+if(NOT WITHOUT_HEADERS)
+ install(FILES "mk_core.h"
+ DESTINATION include/
+ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+
+ file(GLOB headers "mk_core/*.h")
+ install(FILES ${headers}
+ DESTINATION include/mk_core
+ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+endif()
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_api.h b/fluent-bit/lib/monkey/include/monkey/mk_api.h
new file mode 100644
index 000000000..fa5489cfe
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_api.h
@@ -0,0 +1,102 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ------------------
+ * Copyright (C) 2001-2015, Eduardo Silva P. <edsiper@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef MONKEY_PLUGIN_API_H
+#define MONKEY_PLUGIN_API_H
+
+#define _GNU_SOURCE
+
+/* Monkey Headers */
+#include <monkey/monkey.h>
+#include <monkey/mk_socket.h>
+#include <monkey/mk_plugin.h>
+#include <monkey/mk_vhost.h>
+#include <monkey/mk_http.h>
+#include <monkey/mk_socket.h>
+#include <monkey/mk_kernel.h>
+#include <monkey/mk_core.h>
+
+/* General Headers */
+#include <errno.h>
+
+/* global vars */
+struct plugin_api *mk_api;
+
+pthread_key_t MK_EXPORT _mkp_data;
+
+#define MONKEY_PLUGIN(a, b, c, d) \
+ struct mk_plugin_info MK_EXPORT _plugin_info = {a, b, c, d}
+
+#ifdef MK_TRACE
+#undef MK_TRACE
+#endif
+
+#ifdef TRACE
+
+#define MK_TRACE(api, ...) \
+ api->trace("pl", \
+ MK_TRACE_PLUGIN, \
+ __FUNCTION__, \
+ __FILENAME__, \
+ __LINE__, \
+ __VA_ARGS__)
+#define PLUGIN_TRACE MK_TRACE
+#else
+#define MK_TRACE(...) do {} while(0)
+#define PLUGIN_TRACE(...) do{} while(0)
+#endif
+
+/*
+ * Redefine messages macros
+ */
+
+#undef mk_info_ex
+#define mk_info_ex(api, ...) api->_error(MK_INFO, __VA_ARGS__)
+
+#undef mk_err_ex
+#define mk_err_ex(api, ...) api->_error(MK_ERR, __VA_ARGS__)
+
+#undef mk_warn_ex
+#define mk_warn_ex(api, ...) api->_error(MK_WARN, __VA_ARGS__)
+
+#undef mk_bug_ex
+#define mk_bug_ex(api, condition) do { \
+ if (mk_unlikely((condition)!=0)) { \
+ api->_error(MK_BUG, "[%s] Bug found in %s() at %s:%d", \
+ _plugin_info.shortname, __FUNCTION__, __FILE__, __LINE__); \
+ abort(); \
+ } \
+ } while(0)
+
+#undef mk_info
+#define mk_info(...) mk_info_ex(mk_api, __VA_ARGS__)
+
+#undef mk_err
+#define mk_err(...) mk_error_ex(mk_api, __VA_ARGS__)
+
+#undef mk_warn
+#define mk_warn(...) mk_error_ex(mk_api, __VA_ARGS__)
+
+#undef mk_bug
+#define mk_bug(condition) mk_bug_ex(mk_api, condition)
+
+#endif
+
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_cache.h b/fluent-bit/lib/monkey/include/monkey/mk_cache.h
new file mode 100644
index 000000000..40c2f83c3
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_cache.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_CACHE_H
+#define MK_CACHE_H
+
+void mk_cache_worker_init();
+void mk_cache_worker_exit();
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_cache_tls.h b/fluent-bit/lib/monkey/include/monkey/mk_cache_tls.h
new file mode 100644
index 000000000..be3cbf98a
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_cache_tls.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_CACHE_TLS_H
+#define MK_CACHE_TLS_H
+
+#ifdef MK_HAVE_C_TLS /* Use Compiler Thread Local Storage (TLS) */
+
+__thread mk_ptr_t *mk_tls_cache_header_cl;
+__thread mk_ptr_t *mk_tls_cache_header_lm;
+__thread struct tm *mk_tls_cache_gmtime;
+__thread struct mk_gmt_cache *mk_tls_cache_gmtext;
+
+#else
+
+pthread_key_t mk_tls_cache_iov_header;
+pthread_key_t mk_tls_cache_header_cl;
+pthread_key_t mk_tls_cache_header_lm;
+pthread_key_t mk_tls_cache_gmtime;
+pthread_key_t mk_tls_cache_gmtext;
+
+#endif /* MK_HACE_C_TLS */
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_clock.h b/fluent-bit/lib/monkey/include/monkey/mk_clock.h
new file mode 100644
index 000000000..814f39651
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_clock.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* clock.h */
+
+#ifndef MK_CLOCK_H
+#define MK_CLOCK_H
+
+#include <time.h>
+#include <monkey/mk_core.h>
+
+extern time_t log_current_utime;
+extern time_t monkey_init_time;
+
+extern mk_ptr_t log_current_time;
+extern mk_ptr_t headers_preset;
+
+#define MK_CLOCK_GMT_DATEFORMAT "Date: %a, %d %b %Y %H:%M:%S GMT\r\n"
+#define HEADER_PRESET_SIZE 128
+#define HEADER_TIME_BUFFER_SIZE 64
+#define LOG_TIME_BUFFER_SIZE 30
+
+struct mk_server;
+
+struct mk_clock_context {
+ pthread_t mk_clock_tid;
+
+ time_t log_current_utime;
+ time_t monkey_init_time;
+
+ mk_ptr_t log_current_time;
+ mk_ptr_t headers_preset;
+
+ char *log_time_buffers[2];
+ char *header_time_buffers[2];
+};
+
+void *mk_clock_worker_init(void *args);
+void mk_clock_set_time(void);
+void mk_clock_sequential_init(struct mk_server *server);
+void mk_clock_exit(struct mk_server *server);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_config.h b/fluent-bit/lib/monkey/include/monkey/mk_config.h
new file mode 100644
index 000000000..f65528153
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_config.h
@@ -0,0 +1,227 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_CONFIG_H
+#define MK_CONFIG_H
+
+#define _GNU_SOURCE
+#include <monkey/mk_core.h>
+
+#include <monkey/mk_info.h>
+#include "../../deps/rbtree/rbtree.h"
+
+#ifdef _WIN32
+typedef uint32_t mode_t;
+typedef uint32_t uid_t;
+typedef uint32_t gid_t;
+#endif
+
+#ifndef O_NOATIME
+#define O_NOATIME 01000000
+#endif
+
+#define MK_DEFAULT_CONFIG_FILE "monkey.conf"
+#define MK_DEFAULT_MIMES_CONF_FILE "monkey.mime"
+#define MK_DEFAULT_PLUGIN_LOAD_CONF_FILE "plugins.load"
+#define MK_DEFAULT_SITES_CONF_DIR "sites/"
+#define MK_DEFAULT_PLUGINS_CONF_DIR "plugins/"
+#define MK_DEFAULT_LISTEN_ADDR "0.0.0.0"
+#define MK_DEFAULT_LISTEN_PORT "2001"
+#define MK_WORKERS_DEFAULT 1
+
+/* Core capabilities, used as identifiers to match plugins */
+#define MK_CAP_HTTP 1
+
+/* HTTP/2: only if enabled */
+#ifdef MK_HAVE_HTTP2
+#define MK_CAP_HTTP2 2
+#endif
+
+#define MK_CAP_SOCK_PLAIN 4
+#define MK_CAP_SOCK_TLS 8
+
+struct plugin_api;
+struct mk_clock_context;
+
+struct mk_config_listener
+{
+ char *address; /* address to bind */
+ char *port; /* TCP port */
+ uint32_t flags; /* properties: http | http2 | ssl */
+ struct mk_list _head;
+};
+
+/* Base struct of server */
+struct mk_server
+{
+ int server_fd; /* server socket file descriptor */
+ int kernel_version; /* Running Linux Kernel version */
+ int kernel_features; /* Hold different server setup status */
+ int fd_limit; /* Limit of file descriptors */
+ unsigned int server_capacity; /* total server capacity */
+ short int workers; /* number of worker threads */
+ short int manual_tcp_cork; /* If enabled it will handle TCP_CORK */
+
+ int8_t fdt; /* is FDT enabled ? */
+ int8_t is_daemon;
+ int8_t is_seteuid;
+ int8_t scheduler_mode; /* Scheduler balancing mode */
+
+ /* Configuration paths (absolute paths) */
+ char *path_conf_root; /* absolute path to configuration files */
+ char *path_conf_pidfile; /* absolute path to PID file */
+
+ /* Specific names for configuration files or directories */
+ char *conf_mimetype; /* mimetype file name */
+ char *conf_main; /* name of main configuration file */
+ char *conf_sites; /* directory name for virtual host files */
+ char *conf_plugin_load; /* file name which load dynamic plugins */
+ char *conf_plugins; /* directory name for plugins conf files */
+ char *conf_user_pub; /* directory name for users public content */
+
+ mk_ptr_t server_software;
+
+ struct mk_list listeners;
+
+ char *one_shot;
+ char *port_override;
+ char *user;
+ char **request_headers_allowed;
+
+ int timeout; /* max time to wait for a new connection */
+ int standard_port; /* common port used in web servers (80) */
+ int pid_status;
+ int8_t hideversion; /* hide version of server to clients ? */
+ int8_t resume; /* Resume (on/off) */
+ int8_t symlink; /* symbolic links */
+
+ /* keep alive */
+ int8_t keep_alive; /* it's a persisten connection ? */
+ int max_keep_alive_request; /* max persistent connections to allow */
+ int keep_alive_timeout; /* persistent connection timeout */
+
+ /* counter of threads working */
+ int thread_counter;
+
+ /* real user */
+ uid_t egid;
+ gid_t euid;
+
+ int max_request_size;
+
+ struct mk_list *index_files;
+
+ /* configured host quantity */
+ int nhosts;
+ struct mk_list hosts;
+
+ mode_t open_flags;
+ struct mk_list plugins;
+
+ /* Safe EPOLLOUT event */
+ int safe_event_write;
+
+ /*
+ * Optional reference to force a specific transport, this one
+ * is used when overriding the configuration from some caller
+ */
+ char *transport_layer;
+
+ /* Define the default mime type when is not possible to find the proper one */
+ struct mk_list mimetype_list;
+ struct rb_tree mimetype_rb_head;
+ void *mimetype_default;
+ char *mimetype_default_str;
+
+ char server_signature[16];
+ char server_signature_header[32];
+ int server_signature_header_len;
+
+ /* Library mode */
+ int lib_mode; /* is running in Library mode ? */
+
+ int lib_ch_manager[2]; /* lib channel manager */
+ struct mk_event_loop *lib_evl; /* lib event loop */
+ struct mk_event lib_ch_event; /* lib channel manager event ? */
+ int lib_ch_start[2]; /* lib start signal channel */
+ struct mk_event_loop *lib_evl_start; /* lib start event loop */
+ struct mk_event lib_ch_start_event; /* lib start event */
+
+ /* Scheduler context (struct mk_sched_ctx) */
+ void *sched_ctx;
+
+ /*
+ * This list head, allow to link a set of callbacks that Monkey core
+ * must invoke inside each thread worker once created. This list is
+ * populated from mk_lib.c:mk_config_worker_callback(..).
+ */
+ struct mk_list sched_worker_callbacks;
+
+ /* source configuration from files */
+ struct mk_rconf *config;
+
+ /* FIXME: temporal map of Network Layer plugin */
+ struct mk_plugin_network *network;
+
+ /* Thread initializator helpers (sched_launch_thread) */
+ int pth_init;
+ pthread_cond_t pth_cond;
+ pthread_mutex_t pth_mutex;
+
+ /* Used for vhost initialization synchronization */
+ pthread_mutex_t vhost_fdt_mutex;
+
+ /* worker_id as used by mk_sched_register_thread, it was moved here
+ * because it has to be local to each mk_server instance.
+ */
+ int worker_id;
+
+ struct plugin_api *api;
+ struct mk_clock_context *clock_context;
+
+ /* Direct map to Stage plugins */
+ struct mk_list stage10_handler;
+ struct mk_list stage20_handler;
+ struct mk_list stage30_handler;
+ struct mk_list stage40_handler;
+ struct mk_list stage50_handler;
+};
+
+/* Functions */
+struct mk_server_config *mk_config_init();
+void mk_config_start_configure(struct mk_server *server);
+void mk_config_signature(struct mk_server *server);
+void mk_config_add_index(char *indexname);
+void mk_config_set_init_values(struct mk_server *config);
+int mk_config_listen_parse(char *value, struct mk_server *server);
+
+/* config helpers */
+void mk_config_error(const char *path, int line, const char *msg);
+struct mk_config_listener *mk_config_listener_add(char *address,
+ char *port, int flags,
+ struct mk_server *server);
+int mk_config_listen_check_busy(struct mk_server *server);
+void mk_config_listeners_free(struct mk_server *server);
+
+int mk_config_get_bool(char *value);
+void mk_config_read_hosts(char *path);
+void mk_config_sanity_check(struct mk_server *server);
+void mk_config_free_all(struct mk_server *server);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core.h b/fluent-bit/lib/monkey/include/monkey/mk_core.h
new file mode 100644
index 000000000..b8068739d
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_CORE_H
+#define MK_CORE_H
+
+#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
+extern "C" {
+#endif
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+
+#include <mk_core/mk_core_info.h>
+#include "mk_core/mk_pthread.h"
+#include "mk_core/mk_iov.h"
+#include "mk_core/mk_uio.h"
+#include "mk_core/mk_list.h"
+#include "mk_core/mk_pthread.h"
+#include "mk_core/mk_unistd.h"
+
+/* WIN32 */
+#ifdef _WIN32
+/* Posix function name deprecation warning */
+#pragma warning(disable : 4996)
+/* Type casting issues, only disabled momentarily*/
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4267)
+#pragma warning(disable : 4133)
+#endif
+
+#include "mk_core/mk_getopt.h"
+#include "mk_core/mk_pipe.h"
+#include "mk_core/mk_sleep.h"
+/* --- end --- */
+
+#include "mk_core/mk_memory.h"
+#include "mk_core/mk_file.h"
+#include "mk_core/mk_event.h"
+#include "mk_core/mk_rconf.h"
+#include "mk_core/mk_string.h"
+#include "mk_core/mk_macros.h"
+#include "mk_core/mk_utils.h"
+#include "mk_core/mk_unistd.h"
+
+#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
+}
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/external/dirent.h b/fluent-bit/lib/monkey/include/monkey/mk_core/external/dirent.h
new file mode 100644
index 000000000..ffa4761bd
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/external/dirent.h
@@ -0,0 +1,1027 @@
+/*
+ * Dirent interface for Microsoft Visual Studio
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent. Dirent may be freely distributed
+ * under the MIT license. For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#ifndef DIRENT_H
+#define DIRENT_H
+
+/* Hide warnings about unreferenced local functions */
+#if defined(__clang__)
+# pragma clang diagnostic ignored "-Wunused-function"
+#elif defined(_MSC_VER)
+# pragma warning(disable:4505)
+#elif defined(__GNUC__)
+# pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+/*
+ * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
+ * Windows Sockets 2.0.
+ */
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+#include <string.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <ctype.h>
+
+/* Indicates that d_type field is available in dirent structure */
+#define _DIRENT_HAVE_D_TYPE
+
+/* Indicates that d_namlen field is available in dirent structure */
+#define _DIRENT_HAVE_D_NAMLEN
+
+/* Entries missing from MSVC 6.0 */
+#if !defined(FILE_ATTRIBUTE_DEVICE)
+# define FILE_ATTRIBUTE_DEVICE 0x40
+#endif
+
+/* File type and permission flags for stat(), general mask */
+#if !defined(S_IFMT)
+# define S_IFMT _S_IFMT
+#endif
+
+/* Directory bit */
+#if !defined(S_IFDIR)
+# define S_IFDIR _S_IFDIR
+#endif
+
+/* Character device bit */
+#if !defined(S_IFCHR)
+# define S_IFCHR _S_IFCHR
+#endif
+
+/* Pipe bit */
+#if !defined(S_IFFIFO)
+# define S_IFFIFO _S_IFFIFO
+#endif
+
+/* Regular file bit */
+#if !defined(S_IFREG)
+# define S_IFREG _S_IFREG
+#endif
+
+/* Read permission */
+#if !defined(S_IREAD)
+# define S_IREAD _S_IREAD
+#endif
+
+/* Write permission */
+#if !defined(S_IWRITE)
+# define S_IWRITE _S_IWRITE
+#endif
+
+/* Execute permission */
+#if !defined(S_IEXEC)
+# define S_IEXEC _S_IEXEC
+#endif
+
+/* Pipe */
+#if !defined(S_IFIFO)
+# define S_IFIFO _S_IFIFO
+#endif
+
+/* Block device */
+#if !defined(S_IFBLK)
+# define S_IFBLK 0
+#endif
+
+/* Link */
+#if !defined(S_IFLNK)
+# define S_IFLNK 0
+#endif
+
+/* Socket */
+#if !defined(S_IFSOCK)
+# define S_IFSOCK 0
+#endif
+
+/* Read user permission */
+#if !defined(S_IRUSR)
+# define S_IRUSR S_IREAD
+#endif
+
+/* Write user permission */
+#if !defined(S_IWUSR)
+# define S_IWUSR S_IWRITE
+#endif
+
+/* Execute user permission */
+#if !defined(S_IXUSR)
+# define S_IXUSR 0
+#endif
+
+/* Read group permission */
+#if !defined(S_IRGRP)
+# define S_IRGRP 0
+#endif
+
+/* Write group permission */
+#if !defined(S_IWGRP)
+# define S_IWGRP 0
+#endif
+
+/* Execute group permission */
+#if !defined(S_IXGRP)
+# define S_IXGRP 0
+#endif
+
+/* Read others permission */
+#if !defined(S_IROTH)
+# define S_IROTH 0
+#endif
+
+/* Write others permission */
+#if !defined(S_IWOTH)
+# define S_IWOTH 0
+#endif
+
+/* Execute others permission */
+#if !defined(S_IXOTH)
+# define S_IXOTH 0
+#endif
+
+/* Maximum length of file name */
+#if !defined(PATH_MAX)
+# define PATH_MAX MAX_PATH
+#endif
+#if !defined(FILENAME_MAX)
+# define FILENAME_MAX MAX_PATH
+#endif
+#if !defined(NAME_MAX)
+# define NAME_MAX FILENAME_MAX
+#endif
+
+/* File type flags for d_type */
+#define DT_UNKNOWN 0
+#define DT_REG S_IFREG
+#define DT_DIR S_IFDIR
+#define DT_FIFO S_IFIFO
+#define DT_SOCK S_IFSOCK
+#define DT_CHR S_IFCHR
+#define DT_BLK S_IFBLK
+#define DT_LNK S_IFLNK
+
+/* Macros for converting between st_mode and d_type */
+#define IFTODT(mode) ((mode) & S_IFMT)
+#define DTTOIF(type) (type)
+
+/*
+ * File type macros. Note that block devices, sockets and links cannot be
+ * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
+ * only defined for compatibility. These macros should always return false
+ * on Windows.
+ */
+#if !defined(S_ISFIFO)
+# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISDIR)
+# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG)
+# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISLNK)
+# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK)
+# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISCHR)
+# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISBLK)
+# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
+#endif
+
+/* Return the exact length of the file name without zero terminator */
+#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
+
+/* Return the maximum size of a file name */
+#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Wide-character version */
+struct _wdirent {
+ /* Always zero */
+ long d_ino;
+
+ /* File position within stream */
+ long d_off;
+
+ /* Structure size */
+ unsigned short d_reclen;
+
+ /* Length of name without \0 */
+ size_t d_namlen;
+
+ /* File type */
+ int d_type;
+
+ /* File name */
+ wchar_t d_name[PATH_MAX+1];
+};
+typedef struct _wdirent _wdirent;
+
+struct _WDIR {
+ /* Current directory entry */
+ struct _wdirent ent;
+
+ /* Private file data */
+ WIN32_FIND_DATAW data;
+
+ /* True if data is valid */
+ int cached;
+
+ /* Win32 search handle */
+ HANDLE handle;
+
+ /* Initial directory name */
+ wchar_t *patt;
+};
+typedef struct _WDIR _WDIR;
+
+/* Multi-byte character version */
+struct dirent {
+ /* Always zero */
+ long d_ino;
+
+ /* File position within stream */
+ long d_off;
+
+ /* Structure size */
+ unsigned short d_reclen;
+
+ /* Length of name without \0 */
+ size_t d_namlen;
+
+ /* File type */
+ int d_type;
+
+ /* File name */
+ char d_name[PATH_MAX+1];
+};
+typedef struct dirent dirent;
+
+struct DIR {
+ struct dirent ent;
+ struct _WDIR *wdirp;
+};
+typedef struct DIR DIR;
+
+
+/* Dirent functions */
+static DIR *opendir(const char *dirname);
+static _WDIR *_wopendir(const wchar_t *dirname);
+
+static struct dirent *readdir(DIR *dirp);
+static struct _wdirent *_wreaddir(_WDIR *dirp);
+
+static int readdir_r(
+ DIR *dirp, struct dirent *entry, struct dirent **result);
+static int _wreaddir_r(
+ _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);
+
+static int closedir(DIR *dirp);
+static int _wclosedir(_WDIR *dirp);
+
+static void rewinddir(DIR* dirp);
+static void _wrewinddir(_WDIR* dirp);
+
+static int scandir(const char *dirname, struct dirent ***namelist,
+ int (*filter)(const struct dirent*),
+ int (*compare)(const struct dirent**, const struct dirent**));
+
+static int alphasort(const struct dirent **a, const struct dirent **b);
+
+static int versionsort(const struct dirent **a, const struct dirent **b);
+
+static int strverscmp(const char *a, const char *b);
+
+/* For compatibility with Symbian */
+#define wdirent _wdirent
+#define WDIR _WDIR
+#define wopendir _wopendir
+#define wreaddir _wreaddir
+#define wclosedir _wclosedir
+#define wrewinddir _wrewinddir
+
+/* Compatibility with older Microsoft compilers and non-Microsoft compilers */
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+# define wcstombs_s dirent_wcstombs_s
+# define mbstowcs_s dirent_mbstowcs_s
+#endif
+
+/* Optimize dirent_set_errno() away on modern Microsoft compilers */
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+# define dirent_set_errno _set_errno
+#endif
+
+
+/* Internal utility functions */
+static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp);
+static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp);
+
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+static int dirent_mbstowcs_s(
+ size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords,
+ const char *mbstr, size_t count);
+#endif
+
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+static int dirent_wcstombs_s(
+ size_t *pReturnValue, char *mbstr, size_t sizeInBytes,
+ const wchar_t *wcstr, size_t count);
+#endif
+
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+static void dirent_set_errno(int error);
+#endif
+
+
+/*
+ * Open directory stream DIRNAME for read and return a pointer to the
+ * internal working area that is used to retrieve individual directory
+ * entries.
+ */
+static _WDIR *_wopendir(const wchar_t *dirname)
+{
+ wchar_t *p;
+
+ /* Must have directory name */
+ if (dirname == NULL || dirname[0] == '\0') {
+ dirent_set_errno(ENOENT);
+ return NULL;
+ }
+
+ /* Allocate new _WDIR structure */
+ _WDIR *dirp = (_WDIR*) malloc(sizeof(struct _WDIR));
+ if (!dirp)
+ return NULL;
+
+ /* Reset _WDIR structure */
+ dirp->handle = INVALID_HANDLE_VALUE;
+ dirp->patt = NULL;
+ dirp->cached = 0;
+
+ /*
+ * Compute the length of full path plus zero terminator
+ *
+ * Note that on WinRT there's no way to convert relative paths
+ * into absolute paths, so just assume it is an absolute path.
+ */
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ /* Desktop */
+ DWORD n = GetFullPathNameW(dirname, 0, NULL, NULL);
+#else
+ /* WinRT */
+ size_t n = wcslen(dirname);
+#endif
+
+ /* Allocate room for absolute directory name and search pattern */
+ dirp->patt = (wchar_t*) malloc(sizeof(wchar_t) * n + 16);
+ if (dirp->patt == NULL)
+ goto exit_closedir;
+
+ /*
+ * Convert relative directory name to an absolute one. This
+ * allows rewinddir() to function correctly even when current
+ * working directory is changed between opendir() and rewinddir().
+ *
+ * Note that on WinRT there's no way to convert relative paths
+ * into absolute paths, so just assume it is an absolute path.
+ */
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ /* Desktop */
+ n = GetFullPathNameW(dirname, n, dirp->patt, NULL);
+ if (n <= 0)
+ goto exit_closedir;
+#else
+ /* WinRT */
+ wcsncpy_s(dirp->patt, n+1, dirname, n);
+#endif
+
+ /* Append search pattern \* to the directory name */
+ p = dirp->patt + n;
+ switch (p[-1]) {
+ case '\\':
+ case '/':
+ case ':':
+ /* Directory ends in path separator, e.g. c:\temp\ */
+ /*NOP*/;
+ break;
+
+ default:
+ /* Directory name doesn't end in path separator */
+ *p++ = '\\';
+ }
+ *p++ = '*';
+ *p = '\0';
+
+ /* Open directory stream and retrieve the first entry */
+ if (!dirent_first(dirp))
+ goto exit_closedir;
+
+ /* Success */
+ return dirp;
+
+ /* Failure */
+exit_closedir:
+ _wclosedir(dirp);
+ return NULL;
+}
+
+/*
+ * Read next directory entry.
+ *
+ * Returns pointer to static directory entry which may be overwritten by
+ * subsequent calls to _wreaddir().
+ */
+static struct _wdirent *_wreaddir(_WDIR *dirp)
+{
+ /*
+ * Read directory entry to buffer. We can safely ignore the return
+ * value as entry will be set to NULL in case of error.
+ */
+ struct _wdirent *entry;
+ (void) _wreaddir_r(dirp, &dirp->ent, &entry);
+
+ /* Return pointer to statically allocated directory entry */
+ return entry;
+}
+
+/*
+ * Read next directory entry.
+ *
+ * Returns zero on success. If end of directory stream is reached, then sets
+ * result to NULL and returns zero.
+ */
+static int _wreaddir_r(
+ _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result)
+{
+ /* Read next directory entry */
+ WIN32_FIND_DATAW *datap = dirent_next(dirp);
+ if (!datap) {
+ /* Return NULL to indicate end of directory */
+ *result = NULL;
+ return /*OK*/0;
+ }
+
+ /*
+ * Copy file name as wide-character string. If the file name is too
+ * long to fit in to the destination buffer, then truncate file name
+ * to PATH_MAX characters and zero-terminate the buffer.
+ */
+ size_t n = 0;
+ while (n < PATH_MAX && datap->cFileName[n] != 0) {
+ entry->d_name[n] = datap->cFileName[n];
+ n++;
+ }
+ entry->d_name[n] = 0;
+
+ /* Length of file name excluding zero terminator */
+ entry->d_namlen = n;
+
+ /* File type */
+ DWORD attr = datap->dwFileAttributes;
+ if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
+ entry->d_type = DT_CHR;
+ else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ entry->d_type = DT_DIR;
+ else
+ entry->d_type = DT_REG;
+
+ /* Reset dummy fields */
+ entry->d_ino = 0;
+ entry->d_off = 0;
+ entry->d_reclen = sizeof(struct _wdirent);
+
+ /* Set result address */
+ *result = entry;
+ return /*OK*/0;
+}
+
+/*
+ * Close directory stream opened by opendir() function. This invalidates the
+ * DIR structure as well as any directory entry read previously by
+ * _wreaddir().
+ */
+static int _wclosedir(_WDIR *dirp)
+{
+ if (!dirp) {
+ dirent_set_errno(EBADF);
+ return /*failure*/-1;
+ }
+
+ /* Release search handle */
+ if (dirp->handle != INVALID_HANDLE_VALUE)
+ FindClose(dirp->handle);
+
+ /* Release search pattern */
+ free(dirp->patt);
+
+ /* Release directory structure */
+ free(dirp);
+ return /*success*/0;
+}
+
+/*
+ * Rewind directory stream such that _wreaddir() returns the very first
+ * file name again.
+ */
+static void _wrewinddir(_WDIR* dirp)
+{
+ if (!dirp)
+ return;
+
+ /* Release existing search handle */
+ if (dirp->handle != INVALID_HANDLE_VALUE)
+ FindClose(dirp->handle);
+
+ /* Open new search handle */
+ dirent_first(dirp);
+}
+
+/* Get first directory entry */
+static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp)
+{
+ if (!dirp)
+ return NULL;
+
+ /* Open directory and retrieve the first entry */
+ dirp->handle = FindFirstFileExW(
+ dirp->patt, FindExInfoStandard, &dirp->data,
+ FindExSearchNameMatch, NULL, 0);
+ if (dirp->handle == INVALID_HANDLE_VALUE)
+ goto error;
+
+ /* A directory entry is now waiting in memory */
+ dirp->cached = 1;
+ return &dirp->data;
+
+error:
+ /* Failed to open directory: no directory entry in memory */
+ dirp->cached = 0;
+
+ /* Set error code */
+ DWORD errorcode = GetLastError();
+ switch (errorcode) {
+ case ERROR_ACCESS_DENIED:
+ /* No read access to directory */
+ dirent_set_errno(EACCES);
+ break;
+
+ case ERROR_DIRECTORY:
+ /* Directory name is invalid */
+ dirent_set_errno(ENOTDIR);
+ break;
+
+ case ERROR_PATH_NOT_FOUND:
+ default:
+ /* Cannot find the file */
+ dirent_set_errno(ENOENT);
+ }
+ return NULL;
+}
+
+/* Get next directory entry */
+static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp)
+{
+ /* Is the next directory entry already in cache? */
+ if (dirp->cached) {
+ /* Yes, a valid directory entry found in memory */
+ dirp->cached = 0;
+ return &dirp->data;
+ }
+
+ /* No directory entry in cache */
+ if (dirp->handle == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ /* Read the next directory entry from stream */
+ if (FindNextFileW(dirp->handle, &dirp->data) == FALSE)
+ goto exit_close;
+
+ /* Success */
+ return &dirp->data;
+
+ /* Failure */
+exit_close:
+ FindClose(dirp->handle);
+ dirp->handle = INVALID_HANDLE_VALUE;
+ return NULL;
+}
+
+/* Open directory stream using plain old C-string */
+static DIR *opendir(const char *dirname)
+{
+ /* Must have directory name */
+ if (dirname == NULL || dirname[0] == '\0') {
+ dirent_set_errno(ENOENT);
+ return NULL;
+ }
+
+ /* Allocate memory for DIR structure */
+ struct DIR *dirp = (DIR*) malloc(sizeof(struct DIR));
+ if (!dirp)
+ return NULL;
+
+ /* Convert directory name to wide-character string */
+ wchar_t wname[PATH_MAX + 1];
+ size_t n;
+ int error = mbstowcs_s(&n, wname, PATH_MAX + 1, dirname, PATH_MAX+1);
+ if (error)
+ goto exit_failure;
+
+ /* Open directory stream using wide-character name */
+ dirp->wdirp = _wopendir(wname);
+ if (!dirp->wdirp)
+ goto exit_failure;
+
+ /* Success */
+ return dirp;
+
+ /* Failure */
+exit_failure:
+ free(dirp);
+ return NULL;
+}
+
+/* Read next directory entry */
+static struct dirent *readdir(DIR *dirp)
+{
+ /*
+ * Read directory entry to buffer. We can safely ignore the return
+ * value as entry will be set to NULL in case of error.
+ */
+ struct dirent *entry;
+ (void) readdir_r(dirp, &dirp->ent, &entry);
+
+ /* Return pointer to statically allocated directory entry */
+ return entry;
+}
+
+/*
+ * Read next directory entry into called-allocated buffer.
+ *
+ * Returns zero on success. If the end of directory stream is reached, then
+ * sets result to NULL and returns zero.
+ */
+static int readdir_r(
+ DIR *dirp, struct dirent *entry, struct dirent **result)
+{
+ /* Read next directory entry */
+ WIN32_FIND_DATAW *datap = dirent_next(dirp->wdirp);
+ if (!datap) {
+ /* No more directory entries */
+ *result = NULL;
+ return /*OK*/0;
+ }
+
+ /* Attempt to convert file name to multi-byte string */
+ size_t n;
+ int error = wcstombs_s(
+ &n, entry->d_name, PATH_MAX + 1,
+ datap->cFileName, PATH_MAX + 1);
+
+ /*
+ * If the file name cannot be represented by a multi-byte string, then
+ * attempt to use old 8+3 file name. This allows the program to
+ * access files although file names may seem unfamiliar to the user.
+ *
+ * Be ware that the code below cannot come up with a short file name
+ * unless the file system provides one. At least VirtualBox shared
+ * folders fail to do this.
+ */
+ if (error && datap->cAlternateFileName[0] != '\0') {
+ error = wcstombs_s(
+ &n, entry->d_name, PATH_MAX + 1,
+ datap->cAlternateFileName, PATH_MAX + 1);
+ }
+
+ if (!error) {
+ /* Length of file name excluding zero terminator */
+ entry->d_namlen = n - 1;
+
+ /* File attributes */
+ DWORD attr = datap->dwFileAttributes;
+ if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
+ entry->d_type = DT_CHR;
+ else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ entry->d_type = DT_DIR;
+ else
+ entry->d_type = DT_REG;
+
+ /* Reset dummy fields */
+ entry->d_ino = 0;
+ entry->d_off = 0;
+ entry->d_reclen = sizeof(struct dirent);
+ } else {
+ /*
+ * Cannot convert file name to multi-byte string so construct
+ * an erroneous directory entry and return that. Note that
+ * we cannot return NULL as that would stop the processing
+ * of directory entries completely.
+ */
+ entry->d_name[0] = '?';
+ entry->d_name[1] = '\0';
+ entry->d_namlen = 1;
+ entry->d_type = DT_UNKNOWN;
+ entry->d_ino = 0;
+ entry->d_off = -1;
+ entry->d_reclen = 0;
+ }
+
+ /* Return pointer to directory entry */
+ *result = entry;
+ return /*OK*/0;
+}
+
+/* Close directory stream */
+static int closedir(DIR *dirp)
+{
+ int ok;
+
+ if (!dirp)
+ goto exit_failure;
+
+ /* Close wide-character directory stream */
+ ok = _wclosedir(dirp->wdirp);
+ dirp->wdirp = NULL;
+
+ /* Release multi-byte character version */
+ free(dirp);
+ return ok;
+
+exit_failure:
+ /* Invalid directory stream */
+ dirent_set_errno(EBADF);
+ return /*failure*/-1;
+}
+
+/* Rewind directory stream to beginning */
+static void rewinddir(DIR* dirp)
+{
+ if (!dirp)
+ return;
+
+ /* Rewind wide-character string directory stream */
+ _wrewinddir(dirp->wdirp);
+}
+
+/* Scan directory for entries */
+static int scandir(
+ const char *dirname, struct dirent ***namelist,
+ int (*filter)(const struct dirent*),
+ int (*compare)(const struct dirent**, const struct dirent**))
+{
+ int result;
+
+ /* Open directory stream */
+ DIR *dir = opendir(dirname);
+ if (!dir) {
+ /* Cannot open directory */
+ return /*Error*/ -1;
+ }
+
+ /* Read directory entries to memory */
+ struct dirent *tmp = NULL;
+ struct dirent **files = NULL;
+ size_t size = 0;
+ size_t allocated = 0;
+ while (1) {
+ /* Allocate room for a temporary directory entry */
+ if (!tmp) {
+ tmp = (struct dirent*) malloc(sizeof(struct dirent));
+ if (!tmp)
+ goto exit_failure;
+ }
+
+ /* Read directory entry to temporary area */
+ struct dirent *entry;
+ if (readdir_r(dir, tmp, &entry) != /*OK*/0)
+ goto exit_failure;
+
+ /* Stop if we already read the last directory entry */
+ if (entry == NULL)
+ goto exit_success;
+
+ /* Determine whether to include the entry in results */
+ if (filter && !filter(tmp))
+ continue;
+
+ /* Enlarge pointer table to make room for another pointer */
+ if (size >= allocated) {
+ /* Compute number of entries in the new table */
+ size_t num_entries = size * 2 + 16;
+
+ /* Allocate new pointer table or enlarge existing */
+ void *p = realloc(files, sizeof(void*) * num_entries);
+ if (!p)
+ goto exit_failure;
+
+ /* Got the memory */
+ files = (dirent**) p;
+ allocated = num_entries;
+ }
+
+ /* Store the temporary entry to ptr table */
+ files[size++] = tmp;
+ tmp = NULL;
+ }
+
+exit_failure:
+ /* Release allocated file entries */
+ for (size_t i = 0; i < size; i++) {
+ free(files[i]);
+ }
+
+ /* Release the pointer table */
+ free(files);
+ files = NULL;
+
+ /* Exit with error code */
+ result = /*error*/ -1;
+ goto exit_status;
+
+exit_success:
+ /* Sort directory entries */
+ qsort(files, size, sizeof(void*),
+ (int (*) (const void*, const void*)) compare);
+
+ /* Pass pointer table to caller */
+ if (namelist)
+ *namelist = files;
+
+ /* Return the number of directory entries read */
+ result = (int) size;
+
+exit_status:
+ /* Release temporary directory entry, if we had one */
+ free(tmp);
+
+ /* Close directory stream */
+ closedir(dir);
+ return result;
+}
+
+/* Alphabetical sorting */
+static int alphasort(const struct dirent **a, const struct dirent **b)
+{
+ return strcoll((*a)->d_name, (*b)->d_name);
+}
+
+/* Sort versions */
+static int versionsort(const struct dirent **a, const struct dirent **b)
+{
+ return strverscmp((*a)->d_name, (*b)->d_name);
+}
+
+/* Compare strings */
+static int strverscmp(const char *a, const char *b)
+{
+ size_t i = 0;
+ size_t j;
+
+ /* Find first difference */
+ while (a[i] == b[i]) {
+ if (a[i] == '\0') {
+ /* No difference */
+ return 0;
+ }
+ ++i;
+ }
+
+ /* Count backwards and find the leftmost digit */
+ j = i;
+ while (j > 0 && isdigit(a[j-1])) {
+ --j;
+ }
+
+ /* Determine mode of comparison */
+ if (a[j] == '0' || b[j] == '0') {
+ /* Find the next non-zero digit */
+ while (a[j] == '0' && a[j] == b[j]) {
+ j++;
+ }
+
+ /* String with more digits is smaller, e.g 002 < 01 */
+ if (isdigit(a[j])) {
+ if (!isdigit(b[j])) {
+ return -1;
+ }
+ } else if (isdigit(b[j])) {
+ return 1;
+ }
+ } else if (isdigit(a[j]) && isdigit(b[j])) {
+ /* Numeric comparison */
+ size_t k1 = j;
+ size_t k2 = j;
+
+ /* Compute number of digits in each string */
+ while (isdigit(a[k1])) {
+ k1++;
+ }
+ while (isdigit(b[k2])) {
+ k2++;
+ }
+
+ /* Number with more digits is bigger, e.g 999 < 1000 */
+ if (k1 < k2)
+ return -1;
+ else if (k1 > k2)
+ return 1;
+ }
+
+ /* Alphabetical comparison */
+ return (int) ((unsigned char) a[i]) - ((unsigned char) b[i]);
+}
+
+/* Convert multi-byte string to wide character string */
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+static int dirent_mbstowcs_s(
+ size_t *pReturnValue, wchar_t *wcstr,
+ size_t sizeInWords, const char *mbstr, size_t count)
+{
+ /* Older Visual Studio or non-Microsoft compiler */
+ size_t n = mbstowcs(wcstr, mbstr, sizeInWords);
+ if (wcstr && n >= count)
+ return /*error*/ 1;
+
+ /* Zero-terminate output buffer */
+ if (wcstr && sizeInWords) {
+ if (n >= sizeInWords)
+ n = sizeInWords - 1;
+ wcstr[n] = 0;
+ }
+
+ /* Length of multi-byte string with zero terminator */
+ if (pReturnValue) {
+ *pReturnValue = n + 1;
+ }
+
+ /* Success */
+ return 0;
+}
+#endif
+
+/* Convert wide-character string to multi-byte string */
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+static int dirent_wcstombs_s(
+ size_t *pReturnValue, char *mbstr,
+ size_t sizeInBytes, const wchar_t *wcstr, size_t count)
+{
+ /* Older Visual Studio or non-Microsoft compiler */
+ size_t n = wcstombs(mbstr, wcstr, sizeInBytes);
+ if (mbstr && n >= count)
+ return /*error*/1;
+
+ /* Zero-terminate output buffer */
+ if (mbstr && sizeInBytes) {
+ if (n >= sizeInBytes) {
+ n = sizeInBytes - 1;
+ }
+ mbstr[n] = '\0';
+ }
+
+ /* Length of resulting multi-bytes string WITH zero-terminator */
+ if (pReturnValue) {
+ *pReturnValue = n + 1;
+ }
+
+ /* Success */
+ return 0;
+}
+#endif
+
+/* Set errno variable */
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+static void dirent_set_errno(int error)
+{
+ /* Non-Microsoft compiler or older Microsoft compiler */
+ errno = error;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*DIRENT_H*/
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/external/wingetopt.h b/fluent-bit/lib/monkey/include/monkey/mk_core/external/wingetopt.h
new file mode 100644
index 000000000..29ea1002c
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/external/wingetopt.h
@@ -0,0 +1,282 @@
+/* This is a drop-in replacement of getopt library, based on the work of
+ * musl libc. This file is distributed under MIT License.
+ *
+ * ----
+ * Copyright © 2005-2014 Rich Felker, et al.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _WINGETOPT_H
+#define _WINGETOPT_H
+
+#define _GNU_SOURCE
+#include <wchar.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+struct option {
+ const char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+static char *optarg;
+static int optind=1, opterr=1, optopt, __optpos, __optreset=0;
+
+#define optpos __optpos
+#define optreset __optreset
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+/*
+ * Implementation of getopt()
+ */
+static inline void __getopt_msg(const char *a, const char *b, const char *c, size_t l)
+{
+ FILE *f = stderr;
+ fputs(a, f);
+ fwrite(b, strlen(b), 1, f);
+ fwrite(c, 1, l, f);
+ putc('\n', f);
+}
+
+static int getopt(int argc, char * const argv[], const char *optstring)
+{
+ int i;
+ wchar_t c, d;
+ int k, l;
+ char *optchar;
+
+ if (!optind || __optreset) {
+ __optreset = 0;
+ __optpos = 0;
+ optind = 1;
+ }
+
+ if (optind >= argc || !argv[optind])
+ return -1;
+
+ if (argv[optind][0] != '-') {
+ if (optstring[0] == '-') {
+ optarg = argv[optind++];
+ return 1;
+ }
+ return -1;
+ }
+
+ if (!argv[optind][1])
+ return -1;
+
+ if (argv[optind][1] == '-' && !argv[optind][2])
+ return optind++, -1;
+
+ if (!optpos) optpos++;
+ if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) {
+ k = 1;
+ c = 0xfffd; /* replacement char */
+ }
+ optchar = argv[optind]+optpos;
+ optpos += k;
+
+ if (!argv[optind][optpos]) {
+ optind++;
+ optpos = 0;
+ }
+
+ if (optstring[0] == '-' || optstring[0] == '+')
+ optstring++;
+
+ i = 0;
+ d = 0;
+ do {
+ l = mbtowc(&d, optstring+i, MB_LEN_MAX);
+ if (l>0) i+=l; else i++;
+ } while (l && d != c);
+
+ if (d != c || c == ':') {
+ optopt = c;
+ if (optstring[0] != ':' && opterr)
+ __getopt_msg(argv[0], ": unrecognized option: ", optchar, k);
+ return '?';
+ }
+ if (optstring[i] == ':') {
+ optarg = 0;
+ if (optstring[i+1] != ':' || optpos) {
+ optarg = argv[optind++] + optpos;
+ optpos = 0;
+ }
+ if (optind > argc) {
+ optopt = c;
+ if (optstring[0] == ':') return ':';
+ if (opterr) __getopt_msg(argv[0],
+ ": option requires an argument: ",
+ optchar, k);
+ return '?';
+ }
+ }
+ return c;
+}
+
+/*
+ * Implementation of getopt_long() and getopt_long_only()
+ */
+static inline void __getopt_permute(char *const *argv, int dest, int src)
+{
+ char **av = (char **)argv;
+ char *tmp = av[src];
+ int i;
+ for (i=src; i>dest; i--)
+ av[i] = av[i-1];
+ av[dest] = tmp;
+}
+
+static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly);
+
+static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
+{
+ int ret, skipped, resumed;
+ if (!optind || __optreset) {
+ __optreset = 0;
+ __optpos = 0;
+ optind = 1;
+ }
+ if (optind >= argc || !argv[optind]) return -1;
+ skipped = optind;
+ if (optstring[0] != '+' && optstring[0] != '-') {
+ int i;
+ for (i=optind; ; i++) {
+ if (i >= argc || !argv[i]) return -1;
+ if (argv[i][0] == '-' && argv[i][1]) break;
+ }
+ optind = i;
+ }
+ resumed = optind;
+ ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
+ if (resumed > skipped) {
+ int i, cnt = optind-resumed;
+ for (i=0; i<cnt; i++)
+ __getopt_permute(argv, skipped, optind-1);
+ optind = skipped + cnt;
+ }
+ return ret;
+}
+
+static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
+{
+ optarg = 0;
+ if (longopts && argv[optind][0] == '-' &&
+ ((longonly && argv[optind][1] && argv[optind][1] != '-') ||
+ (argv[optind][1] == '-' && argv[optind][2])))
+ {
+ int colon = optstring[optstring[0]=='+'||optstring[0]=='-']==':';
+ int i, cnt, match;
+ char *arg, *opt, *start = argv[optind]+1;
+ for (cnt=i=0; longopts[i].name; i++) {
+ const char *name = longopts[i].name;
+ opt = start;
+ if (*opt == '-') opt++;
+ while (*opt && *opt != '=' && *opt == *name)
+ name++, opt++;
+ if (*opt && *opt != '=') continue;
+ arg = opt;
+ match = i;
+ if (!*name) {
+ cnt = 1;
+ break;
+ }
+ cnt++;
+ }
+ if (cnt==1 && longonly && arg-start == mblen(start, MB_LEN_MAX)) {
+ int l = arg-start;
+ for (i=0; optstring[i]; i++) {
+ int j;
+ for (j=0; j<l && start[j]==optstring[i+j]; j++);
+ if (j==l) {
+ cnt++;
+ break;
+ }
+ }
+ }
+ if (cnt==1) {
+ i = match;
+ opt = arg;
+ optind++;
+ if (*opt == '=') {
+ if (!longopts[i].has_arg) {
+ optopt = longopts[i].val;
+ if (colon || !opterr)
+ return '?';
+ __getopt_msg(argv[0],
+ ": option does not take an argument: ",
+ longopts[i].name,
+ strlen(longopts[i].name));
+ return '?';
+ }
+ optarg = opt+1;
+ } else if (longopts[i].has_arg == required_argument) {
+ if (!(optarg = argv[optind])) {
+ optopt = longopts[i].val;
+ if (colon) return ':';
+ if (!opterr) return '?';
+ __getopt_msg(argv[0],
+ ": option requires an argument: ",
+ longopts[i].name,
+ strlen(longopts[i].name));
+ return '?';
+ }
+ optind++;
+ }
+ if (idx) *idx = i;
+ if (longopts[i].flag) {
+ *longopts[i].flag = longopts[i].val;
+ return 0;
+ }
+ return longopts[i].val;
+ }
+ if (argv[optind][1] == '-') {
+ optopt = 0;
+ if (!colon && opterr)
+ __getopt_msg(argv[0], cnt ?
+ ": option is ambiguous: " :
+ ": unrecognized option: ",
+ argv[optind]+2,
+ strlen(argv[optind]+2));
+ optind++;
+ return '?';
+ }
+ }
+ return getopt(argc, argv, optstring);
+}
+
+static int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
+{
+ return __getopt_long(argc, argv, optstring, longopts, idx, 0);
+}
+
+static int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
+{
+ return __getopt_long(argc, argv, optstring, longopts, idx, 1);
+}
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/external/winpthreads.h b/fluent-bit/lib/monkey/include/monkey/mk_core/external/winpthreads.h
new file mode 100644
index 000000000..97045a69a
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/external/winpthreads.h
@@ -0,0 +1,340 @@
+/*
+ * Posix Threads library for Microsoft Windows
+ *
+ * Use at own risk, there is no implied warranty to this code.
+ * It uses undocumented features of Microsoft Windows that can change
+ * at any time in the future.
+ *
+ * (C) 2010 Lockless Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Lockless Inc. nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WIN_PTHREADS
+#define WIN_PTHREADS
+
+#define _WINSOCKAPI_
+#include <windows.h>
+#include <errno.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef ETIMEDOUT
+#define ETIMEDOUT 110
+#endif
+#ifndef ENOTSUP
+#define ENOTSUP 134
+#endif
+
+#ifndef PTHREAD_STACK_MIN
+#define PTHREAD_STACK_MIN 65535
+#endif
+
+#define PTHREAD_CANCEL_DISABLE 0
+#define PTHREAD_CANCEL_ENABLE 0x01
+
+#define PTHREAD_CANCEL_DEFERRED 0
+#define PTHREAD_CANCEL_ASYNCHRONOUS 0x02
+
+#define PTHREAD_CREATE_JOINABLE 0
+#define PTHREAD_CREATE_DETACHED 0x04
+
+#define PTHREAD_EXPLICT_SCHED 0
+#define PTHREAD_INHERIT_SCHED 0x08
+
+#define PTHREAD_SCOPE_PROCESS 0
+#define PTHREAD_SCOPE_SYSTEM 0x10
+
+#define PTHREAD_DEFAULT_ATTR (PTHREAD_CANCEL_ENABLE)
+
+#define PTHREAD_CANCELED ((void *) 0xDEADBEEF)
+
+#define PTHREAD_ONCE_INIT 0
+#define PTHREAD_MUTEX_INITIALIZER {(void*)-1,-1,0,0,0,0}
+#define PTHREAD_RWLOCK_INITIALIZER {0}
+#define PTHREAD_COND_INITIALIZER {0}
+#define PTHREAD_BARRIER_INITIALIZER \
+ {0,0,PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER}
+#define PTHREAD_SPINLOCK_INITIALIZER 0
+
+#define PTHREAD_DESTRUCTOR_ITERATIONS 256
+#define PTHREAD_KEYS_MAX (1<<20)
+
+#define PTHREAD_MUTEX_NORMAL 0
+#define PTHREAD_MUTEX_ERRORCHECK 1
+#define PTHREAD_MUTEX_RECURSIVE 2
+#define PTHREAD_MUTEX_DEFAULT 3
+#define PTHREAD_MUTEX_SHARED 4
+#define PTHREAD_MUTEX_PRIVATE 0
+#define PTHREAD_PRIO_NONE 0
+#define PTHREAD_PRIO_INHERIT 8
+#define PTHREAD_PRIO_PROTECT 16
+#define PTHREAD_PRIO_MULT 32
+#define PTHREAD_PROCESS_SHARED 0
+#define PTHREAD_PROCESS_PRIVATE 1
+
+#define PTHREAD_BARRIER_SERIAL_THREAD 1
+
+/* Windows doesn't have this, so declare it ourselves. */
+#if (_MSC_VER < 1900)
+struct timespec
+{
+ /* long long in windows is the same as long in unix for 64bit */
+ long long tv_sec;
+ long long tv_nsec;
+};
+#else
+#include <time.h>
+#endif
+
+struct _pthread_v;
+typedef struct _pthread_v *pthread_t;
+
+struct pthread_barrier_t
+{
+ int count;
+ int total;
+ CRITICAL_SECTION m;
+ CONDITION_VARIABLE cv;
+};
+
+typedef struct pthread_barrier_t pthread_barrier_t;
+
+struct pthread_attr_t
+{
+ unsigned p_state;
+ void *stack;
+ size_t s_size;
+};
+
+typedef struct pthread_attr_t pthread_attr_t;
+
+typedef long pthread_once_t;
+typedef unsigned pthread_mutexattr_t;
+typedef SRWLOCK pthread_rwlock_t;
+typedef CRITICAL_SECTION pthread_mutex_t;
+typedef unsigned pthread_key_t;
+typedef void *pthread_barrierattr_t;
+typedef long pthread_spinlock_t;
+typedef int pthread_condattr_t;
+typedef CONDITION_VARIABLE pthread_cond_t;
+typedef int pthread_rwlockattr_t;
+
+extern pthread_t pthread_self(void);
+
+extern int pthread_once(pthread_once_t *o, void(*func)(void));
+
+extern int pthread_mutex_lock(pthread_mutex_t *m);
+
+extern int pthread_mutex_unlock(pthread_mutex_t *m);
+
+extern int pthread_mutex_trylock(pthread_mutex_t *m);
+
+extern int pthread_mutex_init(pthread_mutex_t *m, pthread_mutexattr_t *a);
+
+extern int pthread_mutex_destroy(pthread_mutex_t *m);
+
+#define pthread_mutex_getprioceiling(M, P) ENOTSUP
+#define pthread_mutex_setprioceiling(M, P) ENOTSUP
+
+extern int pthread_equal(pthread_t t1, pthread_t t2);
+
+extern int pthread_rwlock_init(pthread_rwlock_t *l, pthread_rwlockattr_t *a);
+
+extern int pthread_rwlock_destroy(pthread_rwlock_t *l);
+
+extern int pthread_rwlock_rdlock(pthread_rwlock_t *l);
+
+extern int pthread_rwlock_wrlock(pthread_rwlock_t *l);
+
+extern int pthread_rwlock_unlock(pthread_rwlock_t *l);
+
+extern int pthread_rwlock_tryrdlock(pthread_rwlock_t *l);
+
+extern int pthread_rwlock_trywrlock(pthread_rwlock_t *l);
+
+extern void pthread_tls_init(void);
+
+extern int pthread_rwlock_timedrdlock(pthread_rwlock_t *l, const struct timespec *ts);
+
+extern int pthread_rwlock_timedwrlock(pthread_rwlock_t *l, const struct timespec *ts);
+
+extern int pthread_get_concurrency(int *val);
+
+extern int pthread_set_concurrency(int val);
+
+#define pthread_getschedparam(T, P, S) ENOTSUP
+#define pthread_setschedparam(T, P, S) ENOTSUP
+#define pthread_getcpuclockid(T, C) ENOTSUP
+
+extern int pthread_exit(void *res);
+
+extern void pthread_testcancel(void);
+
+extern int pthread_cancel(pthread_t t);
+
+extern int pthread_attr_init(pthread_attr_t *attr);
+
+extern int pthread_attr_destroy(pthread_attr_t *attr);
+
+extern int pthread_attr_setdetachstate(pthread_attr_t *a, int flag);
+
+extern int pthread_attr_getdetachstate(pthread_attr_t *a, int *flag);
+
+extern int pthread_attr_setinheritsched(pthread_attr_t *a, int flag);
+
+extern int pthread_attr_getinheritsched(pthread_attr_t *a, int *flag);
+
+extern int pthread_attr_setscope(pthread_attr_t *a, int flag);
+
+extern int pthread_attr_getscope(pthread_attr_t *a, int *flag);
+
+extern int pthread_attr_getstackaddr(pthread_attr_t *attr, void **stack);
+
+extern int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack);
+
+extern int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *size);
+
+extern int pthread_attr_setstacksize(pthread_attr_t *attr, size_t size);
+
+#define pthread_attr_getguardsize(A, S) ENOTSUP
+#define pthread_attr_setgaurdsize(A, S) ENOTSUP
+#define pthread_attr_getschedparam(A, S) ENOTSUP
+#define pthread_attr_setschedparam(A, S) ENOTSUP
+#define pthread_attr_getschedpolicy(A, S) ENOTSUP
+#define pthread_attr_setschedpolicy(A, S) ENOTSUP
+
+extern int pthread_setcancelstate(int state, int *oldstate);
+
+extern int pthread_setcanceltype(int type, int *oldtype);
+
+extern unsigned __stdcall pthread_create_wrapper(void *args);
+
+extern int pthread_create(pthread_t *th, pthread_attr_t *attr, void *(*func)(void *), void *arg);
+
+extern int pthread_join(pthread_t t, void **res);
+
+extern int pthread_detach(pthread_t t);
+
+extern int pthread_mutexattr_init(pthread_mutexattr_t *a);
+
+extern int pthread_mutexattr_destroy(pthread_mutexattr_t *a);
+
+extern int pthread_mutexattr_gettype(pthread_mutexattr_t *a, int *type);
+
+extern int pthread_mutexattr_settype(pthread_mutexattr_t *a, int type);
+
+extern int pthread_mutexattr_getpshared(pthread_mutexattr_t *a, int *type);
+
+extern int pthread_mutexattr_setpshared(pthread_mutexattr_t * a, int type);
+
+extern int pthread_mutexattr_getprotocol(pthread_mutexattr_t *a, int *type);
+
+extern int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int type);
+
+extern int pthread_mutexattr_getprioceiling(pthread_mutexattr_t *a, int * prio);
+
+extern int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *a, int prio);
+
+extern int pthread_mutex_timedlock(pthread_mutex_t *m, struct timespec *ts);
+
+extern int pthread_barrier_destroy(pthread_barrier_t *b);
+
+extern int pthread_barrier_init(pthread_barrier_t *b, void *attr, int count);
+
+extern int pthread_barrier_wait(pthread_barrier_t *b);
+
+extern int pthread_barrierattr_init(void **attr);
+
+extern int pthread_barrierattr_destroy(void **attr);
+
+extern int pthread_barrierattr_setpshared(void **attr, int s);
+
+extern int pthread_barrierattr_getpshared(void **attr, int *s);
+
+extern int pthread_key_create(pthread_key_t *key, void(*dest)(void *));
+
+extern int pthread_key_delete(pthread_key_t key);
+
+extern void *pthread_getspecific(pthread_key_t key);
+
+extern int pthread_setspecific(pthread_key_t key, const void *value);
+
+extern int pthread_spin_init(pthread_spinlock_t *l, int pshared);
+
+extern int pthread_spin_destroy(pthread_spinlock_t *l);
+
+extern int pthread_spin_lock(pthread_spinlock_t *l);
+
+extern int pthread_spin_trylock(pthread_spinlock_t *l);
+
+extern int pthread_spin_unlock(pthread_spinlock_t *l);
+
+extern int pthread_cond_init(pthread_cond_t *c, pthread_condattr_t *a);
+
+extern int pthread_cond_signal(pthread_cond_t *c);
+
+extern int pthread_cond_broadcast(pthread_cond_t *c);
+
+extern int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m);
+
+extern int pthread_cond_destroy(pthread_cond_t *c);
+
+extern int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, struct timespec *t);
+
+extern int pthread_condattr_destroy(pthread_condattr_t *a);
+
+#define pthread_condattr_getclock(A, C) ENOTSUP
+#define pthread_condattr_setclock(A, C) ENOTSUP
+
+extern int pthread_condattr_init(pthread_condattr_t *a);
+
+extern int pthread_condattr_getpshared(pthread_condattr_t *a, int *s);
+
+extern int pthread_condattr_setpshared(pthread_condattr_t *a, int s);
+
+extern int pthread_rwlockattr_destroy(pthread_rwlockattr_t *a);
+
+extern int pthread_rwlockattr_init(pthread_rwlockattr_t *a);
+
+extern int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *a, int *s);
+
+extern int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *a, int s);
+
+/* No fork() in windows - so ignore this */
+#define pthread_atfork(F1,F2,F3) 0
+
+/* Windows has rudimentary signals support */
+#define pthread_kill(T, S) 0
+#define pthread_sigmask(H, S1, S2) 0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WIN_PTHREADS */
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/external/winuio.h b/fluent-bit/lib/monkey/include/monkey/mk_core/external/winuio.h
new file mode 100644
index 000000000..4ae747888
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/external/winuio.h
@@ -0,0 +1,54 @@
+#ifndef _WINUIO_H
+#define _WINUIO_H
+
+#include <inttypes.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#include <errno.h>
+#include <io.h>
+#include <BaseTsd.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+typedef SSIZE_T ssize_t;
+#endif
+
+struct mk_iovec
+{
+ void *iov_base; /* Base address of a memory region for input or output */
+ size_t iov_len; /* The size of the memory pointed to by iov_base */
+};
+
+/* Long way to go here, it's mostly a placeholder */
+
+static inline ssize_t readv(int fildes, const struct mk_iovec *iov, int iovcnt)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static inline ssize_t writev(int fildes, const struct mk_iovec *iov, int iovcnt)
+{
+ int i;
+ uint32_t bytes_written = 0;
+
+ for (i = 0; i < iovcnt; i++) {
+ int len;
+
+ len = send((SOCKET)fildes, iov[i].iov_base, (int)iov[i].iov_len, 0);
+ if (len == SOCKET_ERROR) {
+ uint32_t err = GetLastError();
+ // errno = win_to_posix_error(err);
+ bytes_written = -1;
+ break;
+ }
+ bytes_written += len;
+ }
+
+ return bytes_written;
+}
+
+
+#endif /* _WINUIO_H */
+
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_core_info.h.in b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_core_info.h.in
new file mode 100644
index 000000000..1bd09e54a
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_core_info.h.in
@@ -0,0 +1,26 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2015 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_CORE_INFO_H
+#define MK_CORE_INFO_H
+
+/* General flags set by CMakeLists.txt */
+@MK_CORE_BUILD_FLAGS@
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_dep_unistd.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_dep_unistd.h
new file mode 100644
index 000000000..46c3a874e
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_dep_unistd.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#ifndef _UNISTD_H
+#define _UNISTD_H 1
+
+/* This file intended to serve as a drop-in replacement for
+ * unistd.h on Windows
+ * Please add functionality as neeeded
+ */
+
+#include <stdlib.h>
+#include <io.h>
+
+/* Skip getopt.h for now */
+//#include <getopt.h> /* getopt at: https://gist.github.com/ashelly/7776712 */
+#include <process.h> /* for getpid() and the exec..() family */
+#include <direct.h> /* for _getcwd() and _chdir() */
+
+#define srandom srand
+#define random rand
+
+/* Values for the second argument to access.
+ These may be OR'd together. */
+#define R_OK 4 /* Test for read permission. */
+#define W_OK 2 /* Test for write permission. */
+//#define X_OK 1 /* execute permission - unsupported in windows*/
+#define F_OK 0 /* Test for existence. */
+
+#define access _access
+#define dup2 _dup2
+#define execve _execve
+#define ftruncate _chsize
+#define unlink _unlink
+#define fileno _fileno
+#define getcwd _getcwd
+#define chdir _chdir
+#define isatty _isatty
+#define lseek _lseek
+/* read, write, and close are NOT being #defined here, because while there are file handle specific versions for Windows, they probably don't work for sockets. You need to look at your app and consider whether to call e.g. closesocket(). */
+
+#define ssize_t SSIZE_T
+
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+/* should be in some equivalent to <sys/types.h> */
+typedef __int8 int8_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+
+#endif /* unistd.h */
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_dirent.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_dirent.h
new file mode 100644
index 000000000..ed1527c1f
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_dirent.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_DIRENT_H
+#define MK_DIRENT_H
+
+#include <mk_core/mk_core_info.h>
+
+#ifdef _WIN32
+#include "external/dirent.h"
+#else
+#include <dirent.h>
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event.h
new file mode 100644
index 000000000..e1990e878
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event.h
@@ -0,0 +1,156 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include "mk_macros.h"
+#include "mk_list.h"
+
+#ifndef MK_EVENT_H
+#define MK_EVENT_H
+
+/* Events type family */
+#define MK_EVENT_UNMODIFIED -1 /* keep old event type */
+#define MK_EVENT_NOTIFICATION 0 /* notification channel (pipe) */
+#define MK_EVENT_LISTENER 1 /* listener socket */
+#define MK_EVENT_FIFO 2 /* FIFO - Messaging */
+#define MK_EVENT_CONNECTION 3 /* data on active connection */
+#define MK_EVENT_CUSTOM 4 /* custom fd registered */
+#define MK_EVENT_THREAD 5 /* thread-coroutine */
+
+/* Event triggered for file descriptors */
+#define MK_EVENT_EMPTY 0
+#define MK_EVENT_READ 1
+#define MK_EVENT_WRITE 4
+#define MK_EVENT_SLEEP 8
+#define MK_EVENT_CLOSE (16 | 8 | 8192)
+#define MK_EVENT_IDLE (16 | 8)
+
+/* The event queue size */
+#define MK_EVENT_QUEUE_SIZE 256
+
+/* Events behaviors */
+#define MK_EVENT_LEVEL 256
+#define MK_EVENT_EDGE 512
+
+/* Event status */
+#define MK_EVENT_NONE 1 /* nothing */
+#define MK_EVENT_REGISTERED 2 /* event is registered into the ev loop */
+
+/* Priority bucket queue */
+#define MK_EVENT_PRIORITY_DEFAULT 6 /* default priority */
+
+/* Legacy definitions: temporal
+ * ----------------------------
+ *
+ * Once a connection is dropped, define
+ * a reason.
+ */
+#define MK_EP_SOCKET_CLOSED 0
+#define MK_EP_SOCKET_ERROR 1
+#define MK_EP_SOCKET_TIMEOUT 2
+#define MK_EP_SOCKET_DONE 3
+/* ---- end ---- */
+
+
+#define MK_EVENT_IS_REGISTERED(event) ((event->status & MK_EVENT_REGISTERED) != 0)
+
+#if defined(_WIN32)
+ #include "mk_event_libevent.h"
+#elif defined(MK_HAVE_EVENT_SELECT)
+ #include "mk_event_select.h"
+#elif defined(__linux__) && !defined(LINUX_KQUEUE)
+ #include "mk_event_epoll.h"
+#else
+ #include "mk_event_kqueue.h"
+#endif
+
+#if defined(_WIN32)
+ #define mk_event_closesocket(s) evutil_closesocket(s)
+#else
+ #define mk_event_closesocket(s) close(s)
+#endif
+
+/* Event reported by the event loop */
+struct mk_event {
+ int fd; /* monitored file descriptor */
+ int type; /* event type */
+ uint32_t mask; /* events mask */
+ uint8_t status; /* internal status */
+ void *data; /* custom data reference */
+
+ /* function handler for custom type */
+ int (*handler)(void *data);
+ struct mk_list _head;
+ struct mk_list _priority_head;
+ char priority; /* optional priority */
+};
+
+struct mk_event_loop {
+ int size; /* size of events array */
+ int n_events; /* number of events reported */
+ struct mk_event *events; /* copy or reference of events triggered */
+ void *data; /* mk_event_ctx_t from backend */
+};
+
+static inline void MK_EVENT_INIT(struct mk_event *ev, int fd, void *data,
+ int (*callback)(void *))
+{
+ ev->fd = fd;
+ ev->type = MK_EVENT_CUSTOM;
+ ev->mask = MK_EVENT_EMPTY;
+ ev->status = MK_EVENT_NONE;
+ ev->data = data;
+ ev->handler = callback;
+}
+
+static inline void MK_EVENT_ZERO(struct mk_event *e)
+{
+ MK_EVENT_INIT(e, -1, NULL, NULL);
+}
+
+static inline void MK_EVENT_NEW(struct mk_event *e)
+{
+ e->mask = MK_EVENT_EMPTY;
+ e->status = MK_EVENT_NONE;
+}
+
+int mk_event_init();
+int mk_event_initialize();
+struct mk_event_loop *mk_event_loop_create(int size);
+void mk_event_loop_destroy(struct mk_event_loop *loop);
+int mk_event_add(struct mk_event_loop *loop, int fd,
+ int type, uint32_t mask, void *data);
+int mk_event_del(struct mk_event_loop *loop, struct mk_event *event);
+int mk_event_inject(struct mk_event_loop *loop, struct mk_event *event,
+ int flags, int prevent_duplication);
+int mk_event_timeout_create(struct mk_event_loop *loop,
+ time_t sec, long nsec,void *data);
+int mk_event_timeout_disable(struct mk_event_loop *loop, void *data);
+int mk_event_timeout_destroy(struct mk_event_loop *loop, void *data);
+int mk_event_channel_create(struct mk_event_loop *loop,
+ int *r_fd, int *w_fd, void *data);
+int mk_event_channel_destroy(struct mk_event_loop *loop,
+ int r_fd, int w_fd, void *data);
+int mk_event_wait(struct mk_event_loop *loop);
+int mk_event_wait_2(struct mk_event_loop *loop, int timeout);
+int mk_event_translate(struct mk_event_loop *loop);
+char *mk_event_backend();
+struct mk_event_fdt *mk_event_get_fdt();
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_epoll.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_epoll.h
new file mode 100644
index 000000000..5180ef8b7
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_epoll.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/epoll.h>
+
+#ifndef MK_EVENT_EPOLL_H
+#define MK_EVENT_EPOLL_H
+
+struct mk_event_ctx {
+ int efd;
+ int queue_size;
+ struct epoll_event *events;
+};
+
+#define mk_event_foreach(event, evl) \
+ int __i; \
+ struct mk_event_ctx *__ctx = evl->data; \
+ \
+ if (evl->n_events > 0) { \
+ event = __ctx->events[0].data.ptr; \
+ } \
+ \
+ for (__i = 0; \
+ __i < evl->n_events; \
+ __i++, \
+ event = ((__i < evl->n_events) ? __ctx->events[__i].data.ptr : NULL) \
+ )
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_kqueue.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_kqueue.h
new file mode 100644
index 000000000..ad6c1b9a2
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_kqueue.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef MK_EVENT_KQUEUE_H
+#define MK_EVENT_KQUEUE_H
+
+#ifndef __linux__
+ #include <sys/types.h>
+ #include <sys/event.h>
+ #include <sys/time.h>
+#endif
+
+#ifdef LINUX_KQUEUE
+ #include <kqueue/sys/event.h>
+
+ /* Not defined */
+ #ifndef NOTE_SECONDS
+ #define NOTE_SECONDS 0x00000001
+ #endif
+#endif
+
+struct mk_event_ctx {
+ int kfd;
+ int queue_size;
+ struct kevent *events;
+};
+
+static inline int filter_mask(int16_t f)
+{
+ if (f == EVFILT_READ) {
+ return MK_EVENT_READ;
+ }
+
+ if (f == EVFILT_WRITE) {
+ return MK_EVENT_WRITE;
+ }
+
+ return 0;
+}
+
+
+#define mk_event_foreach(event, evl) \
+ int __i; \
+ struct mk_event_ctx *__ctx = evl->data; \
+ \
+ if (evl->n_events > 0) { \
+ event = __ctx->events[0].udata; \
+ } \
+ \
+ for (__i = 0; \
+ __i < evl->n_events; \
+ __i++, \
+ event = ((__i < evl->n_events) ? __ctx->events[__i].udata : NULL) \
+ )
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_libevent.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_libevent.h
new file mode 100644
index 000000000..543788dd6
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_libevent.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_EVENT_LIBEVENT_H
+#define MK_EVENT_LIBEVENT_H
+
+#include <event.h>
+
+struct mk_event_ctx {
+ size_t queue_size;
+ int fired_count;
+ struct event_base *base;
+ struct mk_event *fired; /* used to create iteration array */
+};
+
+#define mk_event_foreach(event, evl) \
+ int __i; \
+ struct mk_event_ctx *__ctx = evl->data; \
+ \
+ if (evl->n_events > 0) { \
+ event = __ctx->fired[0].data; \
+ } \
+ \
+ for (__i = 0; \
+ __i < evl->n_events; \
+ __i++, \
+ event = ((__i < evl->n_events) ? __ctx->fired[__i].data : NULL) \
+ )
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_select.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_select.h
new file mode 100644
index 000000000..b69c0ba38
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_event_select.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_EVENT_SELECT_H
+#define MK_EVENT_SELECT_H
+
+#ifdef _WIN32
+#include <Winsock2.h>
+#else
+#include <sys/select.h>
+#endif
+
+struct mk_event_ctx {
+ int max_fd;
+
+ /* Original set of file descriptors */
+ fd_set rfds;
+ fd_set wfds;
+
+ /* Populated before every select(2) */
+ fd_set _rfds;
+ fd_set _wfds;
+
+ int queue_size;
+ struct mk_event **events; /* full array to register all events */
+ struct mk_event *fired; /* used to create iteration array */
+};
+
+#define mk_event_foreach(event, evl) \
+ int __i; \
+ struct mk_event_ctx *__ctx = evl->data; \
+ \
+ if (evl->n_events > 0) { \
+ event = __ctx->fired[0].data; \
+ } \
+ \
+ for (__i = 0; \
+ __i < evl->n_events; \
+ __i++, \
+ event = ((__i < evl->n_events) ? __ctx->fired[__i].data : NULL) \
+ )
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_file.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_file.h
new file mode 100644
index 000000000..2ae360471
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_file.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_FILE_H
+#define MK_FILE_H
+
+#include <time.h>
+
+#define MK_FILE_EXISTS 1
+#define MK_FILE_READ 2
+#define MK_FILE_EXEC 4
+
+struct file_info
+{
+ size_t size;
+ time_t last_modification;
+
+ /* Suggest flags to open this file */
+ int flags_read_only;
+
+ unsigned char exists;
+ unsigned char is_file;
+ unsigned char is_link;
+ unsigned char is_directory;
+ unsigned char exec_access;
+ unsigned char read_access;
+};
+
+int mk_file_get_info(const char *path, struct file_info *f_info, int mode);
+char *mk_file_to_buffer(const char *path);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_getopt.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_getopt.h
new file mode 100644
index 000000000..fde355628
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_getopt.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_GETOPT_H
+#define MK_GETOPT_H
+
+#include <mk_core/mk_core_info.h>
+
+#ifdef __GNUC__ /* Heaven */
+#include <getopt.h>
+#else /* Not Heaven */
+#include "external/wingetopt.h"
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_iov.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_iov.h
new file mode 100644
index 000000000..78152c49e
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_iov.h
@@ -0,0 +1,127 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_IOV_H
+#define MK_IOV_H
+
+#include <stdio.h>
+#include "mk_uio.h"
+#include "mk_utils.h"
+#include "mk_macros.h"
+
+/* iov separators */
+#define MK_IOV_CRLF "\r\n"
+#define MK_IOV_CRLFCRLF "\r\n\r\n"
+#define MK_IOV_LF "\n"
+#define MK_IOV_LFLF "\n\n"
+#define MK_IOV_LFLFLFLF "\n\n\n\n"
+#define MK_IOV_SPACE " "
+#define MK_IOV_SLASH "/"
+#define MK_IOV_NONE ""
+#define MK_IOV_EQUAL "="
+
+#include "mk_memory.h"
+
+extern const mk_ptr_t mk_iov_crlf;
+extern const mk_ptr_t mk_iov_lf;
+extern const mk_ptr_t mk_iov_space;
+extern const mk_ptr_t mk_iov_slash;
+extern const mk_ptr_t mk_iov_none;
+extern const mk_ptr_t mk_iov_equal;
+
+struct mk_iov {
+ int iov_idx;
+ int buf_idx;
+ int size;
+ unsigned long total_len;
+ struct mk_iovec *io;
+ void **buf_to_free;
+};
+
+struct mk_iov *mk_iov_create(int n, int offset);
+struct mk_iov *mk_iov_realloc(struct mk_iov *mk_io, int new_size);
+
+int mk_iov_add_separator(struct mk_iov *mk_io, mk_ptr_t sep);
+
+ssize_t mk_iov_send(int fd, struct mk_iov *mk_io);
+
+void mk_iov_free(struct mk_iov *mk_io);
+
+int _mk_iov_add(struct mk_iov *mk_io, void *buf, int len,
+ mk_ptr_t sep, int free, int idx);
+
+int mk_iov_set_entry(struct mk_iov *mk_io, void *buf, int len,
+ int free, int idx);
+
+void mk_iov_separators_init(void);
+void mk_iov_free_marked(struct mk_iov *mk_io);
+void mk_iov_print(struct mk_iov *mk_io);
+int mk_iov_consume(struct mk_iov *mk_io, size_t bytes);
+
+/* Initialize an IOV instance */
+static inline int mk_iov_init(struct mk_iov *iov, int n, int offset)
+{
+ int i;
+
+ iov->iov_idx = offset;
+ iov->buf_idx = 0;
+ iov->total_len = 0;
+ iov->size = n;
+
+ /*
+ * Make sure to set to zero initial entries when an offset
+ * is specified
+ */
+ if (offset > 0) {
+ for (i = 0; i < offset; i++) {
+ iov->io[i].iov_base = NULL;
+ iov->io[i].iov_len = 0;
+ }
+ }
+
+ return 0;
+}
+
+static inline void _mk_iov_set_free(struct mk_iov *mk_io, void *buf)
+{
+ mk_io->buf_to_free[mk_io->buf_idx] = (void *) buf;
+ mk_io->buf_idx++;
+}
+
+static inline int mk_iov_add(struct mk_iov *mk_io, void *buf, int len,
+ int free)
+{
+ mk_io->io[mk_io->iov_idx].iov_base = (unsigned char *) buf;
+ mk_io->io[mk_io->iov_idx].iov_len = len;
+ mk_io->iov_idx++;
+ mk_io->total_len += len;
+
+ if (free == MK_TRUE) {
+ _mk_iov_set_free(mk_io, buf);
+ }
+
+ if (mk_io->iov_idx > mk_io->size) {
+ MK_TRACE("[iov] buffer without space");
+ return -1;
+ }
+
+ return mk_io->iov_idx;
+}
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_limits.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_limits.h
new file mode 100644
index 000000000..0d5358b75
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_limits.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_LIMITS_H
+#define MK_LIMITS_H
+
+/* Configuration */
+#define MK_HOSTNAME_LEN 64
+
+/* Networking */
+#define MK_SOMAXCONN 128
+
+/* File system */
+#define MK_PATH_BASE 128
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_list.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_list.h
new file mode 100644
index 000000000..0a87381a8
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_list.h
@@ -0,0 +1,244 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ * Copyright (C) 2010, Jonathan Gonzalez V. <zeus@gnu.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_LIST_H_
+#define MK_LIST_H_
+
+#include <stddef.h>
+#include "mk_macros.h"
+
+#ifdef _WIN32
+/* Windows */
+#define container_of(address, type, field) ((type *)( \
+ (PCHAR)(address) - \
+ (ULONG_PTR)(&((type *)0)->field)))
+#else
+/* Rest of the world */
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
+struct mk_list
+{
+ struct mk_list *prev, *next;
+};
+
+static inline void mk_list_init(struct mk_list *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+static inline void __mk_list_add(struct mk_list *_new, struct mk_list *prev,
+ struct mk_list *next)
+{
+ next->prev = _new;
+ _new->next = next;
+ _new->prev = prev;
+ prev->next = _new;
+}
+
+static inline void mk_list_add(struct mk_list *_new, struct mk_list *head)
+{
+ __mk_list_add(_new, head->prev, head);
+}
+
+static inline void mk_list_add_after(struct mk_list *_new,
+ struct mk_list *prev,
+ struct mk_list *head)
+{
+ struct mk_list *next;
+
+ if (head->prev == head->next || head->prev == prev) {
+ mk_list_add(_new, head);
+ return;
+ }
+
+ next = prev->next;
+ _new->next = next;
+ _new->prev = prev;
+ prev->next = _new;
+ next->prev = _new;
+}
+
+static inline int mk_list_is_empty(struct mk_list *head)
+{
+ if (head->next == head) return 0;
+ else return -1;
+}
+
+static inline void mk_list_add_before(struct mk_list *_new,
+ struct mk_list *next,
+ struct mk_list *head)
+{
+ struct mk_list *prev;
+
+ if (_new == NULL || next == NULL || head == NULL) {
+ return;
+ }
+
+ if (mk_list_is_empty(head) == 0 /*empty*/||
+ next == head) {
+ mk_list_add(_new, head);
+ return;
+ }
+
+ prev = next->prev;
+ _new->next = next;
+ _new->prev = prev;
+ prev->next = _new;
+ next->prev = _new;
+}
+
+static inline void mk_list_append(struct mk_list *_new, struct mk_list *head)
+{
+ if (mk_list_is_empty(head) == 0) {
+ __mk_list_add(_new, head->prev, head);
+ }
+ else {
+ mk_list_add_after(_new,
+ head->prev,
+ head);
+ }
+}
+
+static inline void mk_list_prepend(struct mk_list *_new, struct mk_list *head)
+{
+ if (mk_list_is_empty(head) == 0) {
+ __mk_list_add(_new, head->prev, head);
+ }
+ else {
+ mk_list_add_before(_new,
+ head->next,
+ head);
+ }
+}
+
+static inline void __mk_list_del(struct mk_list *prev, struct mk_list *next)
+{
+ prev->next = next;
+ next->prev = prev;
+}
+
+static inline void mk_list_del(struct mk_list *entry)
+{
+ __mk_list_del(entry->prev, entry->next);
+ entry->prev = NULL;
+ entry->next = NULL;
+}
+
+static inline int mk_list_is_set(struct mk_list *head)
+{
+ if (head->next && head->prev) {
+ return 0;
+ }
+
+ return -1;
+}
+
+static inline int mk_list_size(struct mk_list *head)
+{
+ int ret = 0;
+ struct mk_list *it;
+ for (it = head->next; it != head; it = it->next, ret++);
+ return ret;
+}
+
+static inline void mk_list_entry_init(struct mk_list *list)
+{
+ list->next = NULL;
+ list->prev = NULL;
+}
+
+static inline int mk_list_entry_is_orphan(struct mk_list *head)
+{
+ if (head->next != NULL &&
+ head->prev != NULL) {
+ return MK_FALSE;
+ }
+
+ return MK_TRUE;
+}
+
+static inline int mk_list_entry_orphan(struct mk_list *head)
+{
+ if (head->next && head->prev) {
+ return 0;
+ }
+
+ return -1;
+}
+
+static inline void mk_list_cat(struct mk_list *list, struct mk_list *head)
+{
+ struct mk_list *last;
+
+ last = head->prev;
+ last->next = list->next;
+ list->next->prev = last;
+ list->prev->next = head;
+ head->prev = list->prev;
+}
+
+#define mk_list_foreach(curr, head) for( curr = (head)->next; curr != (head); curr = curr->next )
+#define mk_list_foreach_safe(curr, n, head) \
+ for (curr = (head)->next, n = curr->next; curr != (head); curr = n, n = curr->next)
+
+
+#define mk_list_foreach_r(curr, head) for( curr = (head)->prev; curr != (head); curr = curr->prev )
+#define mk_list_foreach_safe_r(curr, n, head) \
+ for (curr = (head)->prev, n = curr->prev; curr != (head); curr = n, n = curr->prev)
+
+#define mk_list_entry( ptr, type, member ) container_of( ptr, type, member )
+
+/*
+ * First node of the list
+ * ----------------------
+ * Be careful with this Macro, its intended to be used when some node is already linked
+ * to the list (ptr). If the list is empty it will return the list address as it points
+ * to it self: list == list->prev == list->next.
+ *
+ * If exists some possiblity that your code handle an empty list, use mk_list_is_empty()
+ * previously to check if its empty or not.
+ */
+#define mk_list_entry_first(ptr, type, member) container_of((ptr)->next, type, member)
+
+/* First node of the list
+ * ---------------------
+ * Be careful with this Macro, its intended to be used when some node is already linked
+ * to the list (ptr). If the list is empty it will return the list address as it points
+ * to it self: list == list->prev == list->next.
+ *
+ * If exists some possiblity that your code handle an empty list, use mk_list_is_empty()
+ * previously to check if its empty or not.
+ */
+#define mk_list_entry_last(ptr, type, member) container_of((ptr)->prev, type, member)
+
+/* Next node */
+#define mk_list_entry_next(ptr, type, member, head) \
+ (ptr)->next == (head) ? container_of((head)->next, type, member) : \
+ container_of((ptr)->next, type, member);
+
+#endif /* !MK_LIST_H_ */
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_macros.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_macros.h
new file mode 100644
index 000000000..f5179faa1
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_macros.h
@@ -0,0 +1,184 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_MACROS_H
+#define MK_MACROS_H
+
+#include <stdlib.h>
+#include "mk_limits.h"
+
+/* Boolean */
+#define MK_FALSE 0
+#define MK_TRUE !MK_FALSE
+#define MK_ERROR -1
+
+/* Architecture */
+#define INTSIZE sizeof(int)
+
+/* Print macros */
+#define MK_INFO 0x1000
+#define MK_ERR 0X1001
+#define MK_WARN 0x1002
+#define MK_BUG 0x1003
+
+#define mk_info(...) mk_print(MK_INFO, __VA_ARGS__)
+#define mk_err(...) mk_print(MK_ERR, __VA_ARGS__)
+#define mk_warn(...) mk_print(MK_WARN, __VA_ARGS__)
+
+/* ANSI Colors */
+#ifndef _MSC_VER
+#define ANSI_RESET "\033[0m"
+#define ANSI_BOLD "\033[1m"
+#define ANSI_CYAN "\033[96m"
+#define ANSI_MAGENTA "\033[95m"
+#define ANSI_RED "\033[91m"
+#define ANSI_YELLOW "\033[93m"
+#define ANSI_BLUE "\033[94m"
+#define ANSI_GREEN "\033[92m"
+#define ANSI_WHITE "\033[97m"
+#else
+#define ANSI_RESET ""
+#define ANSI_BOLD ""
+#define ANSI_CYAN ""
+#define ANSI_MAGENTA ""
+#define ANSI_RED ""
+#define ANSI_YELLOW ""
+#define ANSI_BLUE ""
+#define ANSI_GREEN ""
+#define ANSI_WHITE ""
+#endif
+
+#define ANSI_BOLD_CYAN ANSI_BOLD ANSI_CYAN
+#define ANSI_BOLD_MAGENTA ANSI_BOLD ANSI_MAGENTA
+#define ANSI_BOLD_RED ANSI_BOLD ANSI_RED
+#define ANSI_BOLD_YELLOW ANSI_BOLD ANSI_YELLOW
+#define ANSI_BOLD_BLUE ANSI_BOLD ANSI_BLUE
+#define ANSI_BOLD_GREEN ANSI_BOLD ANSI_GREEN
+#define ANSI_BOLD_WHITE ANSI_BOLD ANSI_WHITE
+
+/* Tags */
+#define MK_BANNER_ENTRY ANSI_BOLD "[" ANSI_GREEN "+" ANSI_RESET ANSI_BOLD "] " \
+ ANSI_RESET
+
+/* Transport type */
+#define MK_TRANSPORT_HTTP "http"
+#define MK_TRANSPORT_HTTPS "https"
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+#ifdef __GNUC__ /* GCC supports this since 2.3. */
+ #define PRINTF_WARNINGS(a,b) __attribute__ ((format (printf, a, b)))
+#else
+ #define PRINTF_WARNINGS(a,b)
+#endif
+
+#ifdef __GNUC__ /* GCC supports this since 2.7. */
+ #define UNUSED_PARAM __attribute__ ((unused))
+#else
+ #define UNUSED_PARAM
+#endif
+
+/*
+ * Validation macros
+ * -----------------
+ * Based on article http://lwn.net/Articles/13183/
+ *
+ * ---
+ * ChangeSet 1.803, 2002/10/18 16:28:57-07:00, torvalds@home.transmeta.com
+ *
+ * Make a polite version of BUG_ON() - WARN_ON() which doesn't
+ * kill the machine.
+ *
+ * Damn I hate people who kill the machine for no good reason.
+ * ---
+ *
+ */
+
+#ifdef __GNUC__
+ #define mk_unlikely(x) __builtin_expect((x),0)
+ #define mk_likely(x) __builtin_expect((x),1)
+ #define mk_prefetch(x, ...) __builtin_prefetch(x, __VA_ARGS__)
+#else
+ #define mk_unlikely(x) (x)
+ #define mk_likely(x) (x)
+ #define mk_prefetch(x, ...) (x, __VA_ARGS__)
+#endif
+
+#define mk_is_bool(x) ((x == MK_TRUE || x == MK_FALSE) ? 1 : 0)
+
+#define mk_bug(condition) do { \
+ if (mk_unlikely((condition)!=0)) { \
+ mk_print(MK_BUG, "Bug found in %s() at %s:%d", \
+ __FUNCTION__, __FILE__, __LINE__); \
+ abort(); \
+ } \
+ } while(0)
+
+#define mk_exception() do { \
+ mk_print(MK_WARN, "Exception found in %s() at %s:%d", \
+ __FUNCTION__, __FILE__, __LINE__); \
+ } while(0)
+
+/*
+ * Macros to calculate sub-net data using ip address and sub-net prefix. Macros
+ * written by Zeus (@sxd).
+ *
+ * Zeus, why the hell you did not documented the macros data type ???.
+ *
+ * addr = struct in_addr -> s_addr.
+ * pos = numeric position for the octect (0, 1, 2..)
+ * net = integer representing the short network mask (e.g: /24)
+ */
+
+#define MK_NET_IP_OCTECT(addr,pos) (addr >> (8 * pos) & 255)
+#define MK_NET_NETMASK(addr,net) htonl((0xffffffff << (32 - net)))
+#define MK_NET_BROADCAST(addr,net) (addr | ~MK_NET_NETMASK(addr,net))
+#define MK_NET_NETWORK(addr,net) (addr & MK_NET_NETMASK(addr,net))
+#define MK_NET_WILDCARD(addr,net) (MK_NET_BROADCAST(addr,net) ^ MK_NET_NETWORK(addr,net))
+#define MK_NET_HOSTMIN(addr,net) net == 31 ? MK_NET_NETWORK(addr,net) : (MK_NET_NETWORK(addr,net) + 0x01000000)
+#define MK_NET_HOSTMAX(addr,net) net == 31 ? MK_NET_BROADCAST(addr,net) : (MK_NET_BROADCAST(addr,net) - 0x01000000)
+
+#ifdef __GNUC__
+ #if __GNUC__ >= 4
+ #define MK_EXPORT __attribute__ ((visibility ("default")))
+ #else
+ #define MK_EXPORT
+ #endif
+#elif defined(_WIN32)
+ #define MK_EXPORT __declspec(dllexport)
+#endif
+
+#ifdef _WIN32
+ #define MK_INLINE __forceinline
+#else
+ #define MK_INLINE inline __attribute__((always_inline))
+#endif
+
+/* Some old libc do not declare O_CLOEXEC */
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 02000000 /* set close_on_exec */
+#endif
+
+/* Wrapper (mk_utils) libc error helpers */
+#define mk_libc_error(c) mk_utils_libc_error(c, __FILE__, __LINE__)
+#define mk_libc_warn(c) mk_utils_libc_warn(c, __FILE__, __LINE__)
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_memory.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_memory.h
new file mode 100644
index 000000000..6da593454
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_memory.h
@@ -0,0 +1,125 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_MEM_H
+#define MK_MEM_H
+
+#include <stdio.h>
+
+#ifdef MALLOC_JEMALLOC
+#include <jemalloc/jemalloc.h>
+#endif
+
+#include "mk_macros.h"
+
+typedef struct
+{
+ char *data;
+ unsigned long len;
+} mk_ptr_t;
+
+#ifdef __GNUC__
+ #if ((__GNUC__ * 100 + __GNUC__MINOR__) > 430) /* gcc version > 4.3 */
+ #define ALLOCSZ_ATTR(x,...) __attribute__ ((alloc_size(x, ##__VA_ARGS__)))
+ #else
+ #define ALLOCSZ_ATTR(x,...)
+ #endif
+#else
+ #define ALLOCSZ_ATTR(x,...)
+#endif
+
+static inline ALLOCSZ_ATTR(1)
+void *mk_mem_alloc(const size_t size)
+{
+#ifdef MALLOC_JEMALLOC
+ void *aux = je_malloc(size);
+#else
+ void *aux = malloc(size);
+#endif
+
+ if (mk_unlikely(!aux && size)) {
+ perror("malloc");
+ return NULL;
+ }
+
+ return aux;
+}
+
+static inline ALLOCSZ_ATTR(1)
+void *mk_mem_alloc_z(const size_t size)
+{
+#ifdef MALLOC_JEMALLOC
+ void *buf = je_calloc(1, size);
+#else
+ void *buf = calloc(1, size);
+#endif
+
+ if (mk_unlikely(!buf)) {
+ return NULL;
+ }
+
+ return buf;
+}
+
+static inline ALLOCSZ_ATTR(2)
+void *mk_mem_realloc(void *ptr, const size_t size)
+{
+#ifdef MALLOC_JEMALLOC
+ void *aux = je_realloc(ptr, size);
+#else
+ void *aux = realloc(ptr, size);
+#endif
+
+ if (mk_unlikely(!aux && size)) {
+ perror("realloc");
+ return NULL;
+ }
+
+ return aux;
+}
+
+static inline void mk_mem_free(void *ptr)
+{
+#ifdef MALLOC_JEMALLOC
+ je_free(ptr);
+#else
+ free(ptr);
+#endif
+}
+
+void mk_mem_free(void *ptr);
+void mk_mem_pointers_init(void);
+
+/* mk_ptr_t_* */
+mk_ptr_t mk_ptr_create(char *buf, long init, long end);
+void mk_ptr_free(mk_ptr_t * p);
+void mk_ptr_print(mk_ptr_t p);
+char *mk_ptr_to_buf(mk_ptr_t p);
+void mk_ptr_set(mk_ptr_t * p, char *data);
+
+static inline void mk_ptr_reset(mk_ptr_t * p)
+{
+ p->data = NULL;
+ p->len = 0;
+}
+
+
+#define mk_ptr_init(a) {a, sizeof(a) - 1}
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_pipe.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_pipe.h
new file mode 100644
index 000000000..ae2b4c25f
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_pipe.h
@@ -0,0 +1,32 @@
+/*-*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_PIPE_H
+#define MK_PIPE_H
+
+#include <mk_core/mk_core_info.h>
+
+/* For Windows we need a workaround to play with pipe(2) */
+#ifdef _WIN32
+#include <io.h>
+#include <fcntl.h>
+#define pipe(fds) _pipe(fds, 4096, _O_BINARY)
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_pthread.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_pthread.h
new file mode 100644
index 000000000..b9a7de60f
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_pthread.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_PTHREAD_H
+#define MK_PTHREAD_H
+
+#include <mk_core/mk_core_info.h>
+
+#if defined (MK_THREADS_POSIX) /* Heaven */
+#include <pthread.h>
+#elif defined (MK_THREADS_WIN32) /* Not Heaven */
+#include "external/winpthreads.h"
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_rconf.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_rconf.h
new file mode 100644
index 000000000..800e0087c
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_rconf.h
@@ -0,0 +1,92 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_RCONF_H
+#define MK_RCONF_H
+
+#include <limits.h>
+
+#include "mk_list.h"
+#include "mk_memory.h"
+
+#define MK_RCONF_ON "on"
+#define MK_RCONF_OFF "off"
+
+#define MK_RCONF_STR 0
+#define MK_RCONF_NUM 1
+#define MK_RCONF_BOOL 2
+#define MK_RCONF_LIST 3
+
+/* default buffer size when reading a configuration line */
+#define MK_RCONF_KV_SIZE 4096
+
+struct mk_rconf_section
+{
+ char *name;
+
+ struct mk_list entries;
+ struct mk_list _head;
+};
+
+struct mk_rconf_entry
+{
+ char *key;
+ char *val;
+
+ struct mk_list _head;
+};
+
+struct mk_rconf_file
+{
+ char *path;
+ struct mk_list _head;
+};
+
+
+struct mk_rconf
+{
+ int level;
+ int created;
+ char *file;
+ char *root_path;
+
+ /* included files */
+ struct mk_list includes;
+
+ /* meta instructions */
+ struct mk_list metas;
+
+ /* list of sections */
+ struct mk_list sections;
+};
+
+void mk_rconf_free(struct mk_rconf *conf);
+void mk_rconf_free_entries(struct mk_rconf_section *section);
+
+struct mk_rconf *mk_rconf_open(const char *path);
+struct mk_rconf *mk_rconf_create(const char *path);
+struct mk_rconf_section *mk_rconf_section_add(struct mk_rconf *conf,
+ char *name);
+struct mk_rconf_section *mk_rconf_section_get(struct mk_rconf *conf,
+ const char *name);
+void *mk_rconf_section_get_key(struct mk_rconf_section *section,
+ char *key, int mode);
+char *mk_rconf_meta_get(struct mk_rconf *conf, char *key);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_sleep.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_sleep.h
new file mode 100644
index 000000000..44f4d5aa6
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_sleep.h
@@ -0,0 +1,59 @@
+/*-*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_SLEEP_H
+#define MK_SLEEP_H
+
+#include <mk_core/mk_core_info.h>
+
+#ifdef __GNUC__ /* Heaven */
+#include <time.h>
+#include <unistd.h>
+#elif _WIN32 /* Not Heaven */
+
+/* WIN32 conversion */
+#define sleep(x) _sleep(x * 1000)
+
+#define _WINSOCKAPI_
+#include <windows.h> /* WinAPI */
+
+/* Windows sleep in 100ns units */
+static inline BOOLEAN nanosleep(LONGLONG ns){
+ /* Declarations */
+ HANDLE timer; /* Timer handle */
+ LARGE_INTEGER li; /* Time defintion */
+ /* Create timer */
+ if(!(timer = CreateWaitableTimer(NULL, TRUE, NULL)))
+ return FALSE;
+ /* Set timer properties */
+ li.QuadPart = -ns;
+ if(!SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE)){
+ CloseHandle(timer);
+ return FALSE;
+ }
+ /* Start & wait for timer */
+ WaitForSingleObject(timer, INFINITE);
+ /* Clean resources */
+ CloseHandle(timer);
+ /* Slept without problems */
+ return TRUE;
+}
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_string.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_string.h
new file mode 100644
index 000000000..dddf9c6ce
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_string.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_STR_H
+#define MK_STR_H
+
+#include <stdint.h>
+#include <mk_core/mk_core_info.h>
+#include "mk_memory.h"
+#include "mk_list.h"
+#include "mk_macros.h"
+
+#if defined(_WIN32) || defined(_WIN64)
+ #define snprintf _snprintf
+ #define vsnprintf _vsnprintf
+ #define strcasecmp _stricmp
+ #define strncasecmp _strnicmp
+#endif
+
+/* Case sensitive OFF */
+#define MK_STR_SENSITIVE 0
+
+/* Case sensitive ON */
+#define MK_STR_INSENSITIVE 1
+
+struct mk_string_line
+{
+ char *val;
+ int len;
+
+ struct mk_list _head;
+};
+
+#if !defined(MK_HAVE_MEMRCHR)
+void *memrchr(const void *s, int c, size_t n);
+#endif
+
+#ifndef MK_HAVE_MEMMEM
+void *memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen);
+#endif
+
+/* Lookup char into string, return position */
+int mk_string_char_search(const char *string, int c, int len);
+
+/* Find char into string searching in reverse order, returns position */
+int mk_string_char_search_r(const char *string, int c, int len);
+
+/* Locate a substring, returns the position of the substring */
+int mk_string_search(const char *haystack, const char *needle, int sensitive);
+
+/* Locate a substring, compare the first n bytes of haystack */
+int mk_string_search_n(const char *haystack, const char *needle, int sensitive, int len);
+
+char *mk_string_remove_space(char *buf);
+char *mk_string_casestr(char *heystack, char *needle);
+char *mk_string_dup(const char *s);
+struct mk_list *mk_string_split_line(const char *line);
+void mk_string_split_free(struct mk_list *list);
+int mk_string_trim(char **str);
+char *mk_string_build(char **buffer, unsigned long *len,
+ const char *format, ...) PRINTF_WARNINGS(3,4);
+
+#if defined (__GNUC__) || defined (_WIN32)
+int mk_string_itop(uint64_t value, mk_ptr_t *p);
+#endif
+
+char *mk_string_copy_substr(const char *string, int pos_init, int pos_end);
+
+char *mk_string_tolower(const char *in);
+
+#if defined (__APPLE__) || defined (_WIN32)
+void *memrchr(const void *s, int c, size_t n);
+#endif
+
+#ifdef _WIN32
+char *strndup (const char *s, size_t n);
+char *strcasestr(const char *phaystack, const char *pneedle);
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_thread.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_thread.h
new file mode 100644
index 000000000..411769e9b
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_thread.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server (Duda I/O)
+ * -----------------------------
+ * Copyright 2017 Eduardo Silva <eduardo@monkey.io>
+ * Copyright 2014, Zeying Xie <swpdtz at gmail dot com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_THREAD_H
+#define MK_THREAD_H
+
+#include <mk_core/mk_pthread.h>
+#include "mk_thread_channel.h"
+
+#define MK_THREAD_DEAD 0
+#define MK_THREAD_READY 1
+#define MK_THREAD_RUNNING 2
+#define MK_THREAD_SUSPEND 3
+
+pthread_key_t mk_thread_scheduler;
+
+typedef void (*mk_thread_func)(void *data);
+
+struct mk_thread_scheduler *mk_thread_open();
+void mk_thread_close(struct mk_thread_scheduler *sch);
+
+int mk_thread_create(mk_thread_func func, void *data);
+int mk_thread_status(int id);
+void mk_thread_yield();
+void mk_thread_resume(int id);
+int mk_thread_running();
+
+void mk_thread_add_channel(int id, struct mk_thread_channel *chan);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_thread_channel.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_thread_channel.h
new file mode 100644
index 000000000..de91ce9c1
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_thread_channel.h
@@ -0,0 +1,127 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server (Duda I/O)
+ * -----------------------------
+ * Copyright 2017 Eduardo Silva <eduardo@monkey.io>
+ * Copyright 2014, Zeying Xie <swpdtz at gmail dot com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_THREAD_CHANNEL_H
+#define MK_THREAD_CHANNEL_H
+
+#include <errno.h>
+#include "mk_list.h"
+
+#define MK_THREAD_CHANNEL_OK 0
+#define MK_THREAD_CHANNEL_BROKEN -EPIPE
+
+struct mk_thread_channel {
+ int size;
+ int used;
+ struct mk_list bufs;
+ int sender;
+ int receiver;
+ int ended;
+ int done;
+ struct mk_list _head;
+};
+
+/*
+ * @METHOD_NAME: chan_get_sender
+ * @METHOD_DESC: get sender of the given channel.
+ * @METHOD_PROTO: int chan_get_sender(mk_thread_channel_t *chan)
+ * @METHOD_PARAM: chan the target channel.
+ * @METHOD_RETURN: the dthread id of sender of the channel.
+ */
+static inline int mk_thread_channel_get_sender(struct mk_thread_channel *chan)
+{
+ return chan->sender;
+}
+
+/*
+ * @METHOD_NAME: chan_set_sender
+ * @METHOD_DESC: set sender of the given channel.
+ * @METHOD_PROTO: void chan_set_sender(mk_thread_channel_t *chan, int sender)
+ * @METHOD_PARAM: chan the target channel.
+ * @METHOD_PARAM: sender the dthread id of target sender.
+ * @METHOD_RETURN: this method do not return any value.
+ */
+static inline void mk_thread_channel_set_sender(struct mk_thread_channel *chan,
+ int sender)
+{
+ chan->sender = sender;
+}
+
+/*
+ * @METHOD_NAME: chan_get_receiver
+ * @METHOD_DESC: get receiver of the given channel.
+ * @METHOD_PROTO: int chan_get_receiver(mk_thread_channel_t *chan)
+ * @METHOD_PARAM: chan the target channel.
+ * @METHOD_RETURN: the dthread id of receiver of the channel.
+ */
+static inline int mk_thread_channel_get_receiver(struct mk_thread_channel *chan)
+{
+ return chan->receiver;
+}
+
+void mk_thread_add_channel(int id, struct mk_thread_channel *chan);
+
+/*
+ * @METHOD_NAME: chan_set_receiver
+ * @METHOD_DESC: set receiver of the given channel.
+ * @METHOD_PROTO: void chan_set_receiver(mk_thread_channel_t *chan, int receiver)
+ * @METHOD_PARAM: chan the target channel.
+ * @METHOD_PARAM: receiver the dthread id of target receiver.
+ * @METHOD_RETURN: this method do not return any value.
+ */
+static inline void mk_thread_channel_set_receiver(struct mk_thread_channel *chan,
+ int receiver)
+{
+ chan->receiver = receiver;
+ mk_thread_add_channel(receiver, chan);
+}
+
+/*
+ * @METHOD_NAME: chan_done
+ * @METHOD_DESC: whether the channel is no longer necessary(this will be the case
+ * that a channel is empty and the sender won't send any more).
+ * @METHOD_PROTO: int chan_done(mk_thread_channel_t *chan)
+ * @METHOD_PARAM: chan the target channel.
+ * @METHOD_RETURN: returns 1 if the channel is no longer necessary, otherwise 0.
+ */
+static inline int mk_thread_channel_done(struct mk_thread_channel *chan)
+{
+ return chan->done;
+}
+
+/*
+ * @METHOD_NAME: chan_end
+ * @METHOD_DESC: it is used by the sender to tell the channel no more data will be
+ * sent.
+ * @METHOD_PROTO: void chan_end(mk_thread_channel_t *chan)
+ * @METHOD_PARAM: chan the target channel.
+ * @METHOD_RETURN: this method do not return any value.
+ */
+static inline void mk_thread_channel_end(struct mk_thread_channel *chan)
+{
+ chan->ended = 1;
+}
+
+struct mk_thread_channel *mk_thread_channel_create(int size);
+void mk_thread_channel_free(struct mk_thread_channel *chan);
+int mk_thread_channel_send(struct mk_thread_channel *chan, void *data);
+void *mk_thread_channel_recv(struct mk_thread_channel *chan);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_uio.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_uio.h
new file mode 100644
index 000000000..8bb9a3ac9
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_uio.h
@@ -0,0 +1,13 @@
+#ifndef MK_UIO_H
+#define MK_UIO_H
+
+#include <mk_core/mk_core_info.h>
+
+#ifdef MK_HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#define mk_iovec iovec
+#else
+#include "external/winuio.h"
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_unistd.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_unistd.h
new file mode 100644
index 000000000..45df7fc4d
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_unistd.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_UNISTD_H
+#define MK_UNISTD_H
+
+#include <mk_core/mk_core_info.h>
+
+#ifdef MK_HAVE_UNISTD_H
+#include <unistd.h>
+#else
+#include "mk_dep_unistd.h"
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_core/mk_utils.h b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_utils.h
new file mode 100644
index 000000000..2a91af65b
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_core/mk_utils.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_CORE_UTILS_H
+#define MK_CORE_UTILS_H
+
+#include "mk_macros.h"
+
+#include <string.h>
+#include <errno.h>
+
+#include "mk_pthread.h"
+
+/* Trace definitions */
+#ifdef MK_HAVE_TRACE
+
+#define MK_TRACE_CORE 0
+#define MK_TRACE_PLUGIN 1
+#define MK_TRACE_COMP_CORE "mk"
+
+#define MK_TRACE(...) mk_utils_trace(MK_TRACE_COMP_CORE, MK_TRACE_CORE, \
+ __FUNCTION__, __FILENAME__, __LINE__, __VA_ARGS__)
+
+#else
+
+#ifdef MK_TRACE
+#undef MK_TRACE
+#endif
+
+#define MK_TRACE(...) do {} while (0)
+#endif
+
+void mk_print(int type, const char *format, ...) PRINTF_WARNINGS(2,3);
+
+#ifdef MK_HAVE_TRACE
+void mk_utils_trace(const char *component, int color, const char *function,
+ char *file, int line, const char* format, ...);
+int mk_utils_print_errno(int n);
+#endif
+
+
+/* Thread key to hold a re-entrant buffer for strerror formatting */
+#define MK_UTILS_ERROR_SIZE 128
+extern pthread_key_t mk_utils_error_key;
+
+/* Windows don't have strerror_r, instead it have strerror_s */
+#ifdef _WIN32
+ /* Reset as this is defined by mk_pthread.h */
+ #ifdef strerror_r
+ #undef strerror_r
+ #endif
+ #define strerror_r(errno, buf, len) strerror_s(buf, len, errno)
+#elif !defined(__APPLE__) && !defined(__unix__)
+ #ifdef __cplusplus
+ extern "C"
+ {
+ #endif
+ extern int __xpg_strerror_r(int errcode,char* buffer,size_t length);
+ #define strerror_r __xpg_strerror_r
+ #ifdef __cplusplus
+ }
+ #endif
+#endif
+
+/*
+ * Helpers to format and print out common errno errors.
+ */
+#define MK_UTILS_LIBC_ERRNO_BUFFER() \
+ char buf[MK_UTILS_ERROR_SIZE]; \
+ int _err; \
+ _err = errno; \
+ if (strerror_r(_err, buf, MK_UTILS_ERROR_SIZE) != 0) { \
+ mk_err("strerror_r() failed"); \
+ }
+
+static inline void mk_utils_libc_error(char *caller, char *file, int line)
+{
+ MK_UTILS_LIBC_ERRNO_BUFFER();
+ mk_err("%s: %s, errno=%i at %s:%i", caller, buf, _err, file, line);
+}
+
+static inline void mk_utils_libc_warn(char *caller, char *file, int line)
+{
+ MK_UTILS_LIBC_ERRNO_BUFFER();
+ mk_warn("%s: %s, errno=%i at %s:%i", caller, buf, _err, file, line);
+}
+
+int mk_utils_worker_spawn(void (*func) (void *), void *arg, pthread_t *tid);
+int mk_utils_worker_rename(const char *title);
+
+#ifndef _WIN32
+int mk_utils_set_daemon();
+int mk_utils_register_pid(char *path);
+int mk_utils_remove_pid(char *path);
+#endif
+
+int mk_core_init();
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_env.h.in b/fluent-bit/lib/monkey/include/monkey/mk_env.h.in
new file mode 100644
index 000000000..33e6a8661
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_env.h.in
@@ -0,0 +1,26 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2015 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_ENV_H
+#define MK_ENV_H
+
+#define CC "@CMAKE_C_COMPILER@"
+#define AR "@CMAKE_AR@"
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_fifo.h b/fluent-bit/lib/monkey/include/monkey/mk_fifo.h
new file mode 100644
index 000000000..39fa450a0
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_fifo.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_FIFO_H
+#define MK_FIFO_H
+
+#include <monkey/mk_info.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_core.h>
+
+#define MK_FIFO_BUF_SIZE 32768
+
+#ifdef _WIN32
+#ifdef _WIN64
+typedef long long mk_fifo_channel_fd;
+#else
+typedef long long mk_fifo_channel_fd;
+#endif
+#else
+typedef int mk_fifo_channel_fd;
+#endif
+
+struct mk_fifo_worker {
+ struct mk_event event; /* event loop 'event' */
+ int worker_id; /* worker ID */
+ mk_fifo_channel_fd channel[2]; /* pipe(2) communication channel */
+ void *data; /* opaque data for thread */
+
+ /* Read buffer */
+ char *buf_data;
+ size_t buf_len;
+ size_t buf_size;
+
+ void *fifo; /* original FIFO context associated with */
+ struct mk_list _head; /* link to paremt mk_msg.workers list */
+};
+
+struct mk_fifo_msg {
+ uint32_t length;
+ uint16_t flags;
+ uint16_t queue_id;
+ char data[];
+};
+
+struct mk_fifo_queue {
+ uint16_t id; /* queue id */
+ char name[16]; /* queue name */
+ struct mk_list _head; /* link to parent mk_msg.queues list */
+
+ /*
+ * Callback function to be used by message reader once a complete
+ * message is ready to be processed. This callback is invoked
+ * from a thread context (pipe read end).
+ */
+ void (*cb_message)(struct mk_fifo_queue *, void *, size_t, void *);
+ void *data;
+};
+
+struct mk_fifo {
+ pthread_key_t *key; /* pthread key */
+ pthread_mutex_t mutex_init; /* pthread mutex used for initialization */
+ void *data; /* opate data context */
+ struct mk_list queues; /* list of registered queues */
+ struct mk_list workers; /* context for Monkey workers */
+};
+
+void mk_fifo_worker_setup(void *data);
+int mk_fifo_worker_read(void *event);
+
+struct mk_fifo *mk_fifo_create(pthread_key_t *key, void *data);
+int mk_fifo_queue_create(struct mk_fifo *ctx, char *name,
+ void (*cb)(struct mk_fifo_queue *, void *,
+ size_t, void *),
+ void *data);
+struct mk_fifo_queue *mk_fifo_queue_get(struct mk_fifo *ctx, int id);
+int mk_fifo_queue_destroy(struct mk_fifo *ctx, struct mk_fifo_queue *q);
+int mk_fifo_queue_id_destroy(struct mk_fifo *ctx, int id);
+int mk_fifo_destroy(struct mk_fifo *ctx);
+int mk_fifo_send(struct mk_fifo *ctx, int id, void *data, size_t size);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_header.h b/fluent-bit/lib/monkey/include/monkey/mk_header.h
new file mode 100644
index 000000000..df1205a53
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_header.h
@@ -0,0 +1,113 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_HEADER_H
+#define MK_HEADER_H
+
+#include "mk_http.h"
+#include "mk_http_status.h"
+
+#define MK_HEADER_BREAKLINE 1
+
+/*
+ * header response: We handle this as static global data in order
+ * to save some process time when building the response header.
+ */
+
+/* Informational */
+#define MK_RH_INFO_CONTINUE "HTTP/1.1 100 Continue\r\n"
+#define MK_RH_INFO_SWITCH_PROTOCOL "HTTP/1.1 101 Switching Protocols\r\n"
+
+/* Successfull */
+#define MK_RH_HTTP_OK "HTTP/1.1 200 OK\r\n"
+#define MK_RH_HTTP_CREATED "HTTP/1.1 201 Created\r\n"
+#define MK_RH_HTTP_ACCEPTED "HTTP/1.1 202 Accepted\r\n"
+#define MK_RH_HTTP_NON_AUTH_INFO "HTTP/1.1 203 Non-Authoritative Information\r\n"
+#define MK_RH_HTTP_NOCONTENT "HTTP/1.1 204 No Content\r\n"
+#define MK_RH_HTTP_RESET "HTTP/1.1 205 Reset Content\r\n"
+#define MK_RH_HTTP_PARTIAL "HTTP/1.1 206 Partial Content\r\n"
+
+/* Redirections */
+#define MK_RH_REDIR_MULTIPLE "HTTP/1.1 300 Multiple Choices\r\n"
+#define MK_RH_REDIR_MOVED "HTTP/1.1 301 Moved Permanently\r\n"
+#define MK_RH_REDIR_MOVED_T "HTTP/1.1 302 Found\r\n"
+#define MK_RH_REDIR_SEE_OTHER "HTTP/1.1 303 See Other\r\n"
+#define MK_RH_NOT_MODIFIED "HTTP/1.1 304 Not Modified\r\n"
+#define MK_RH_REDIR_USE_PROXY "HTTP/1.1 305 Use Proxy\r\n"
+
+/* Client side errors */
+#define MK_RH_CLIENT_BAD_REQUEST "HTTP/1.1 400 Bad Request\r\n"
+#define MK_RH_CLIENT_UNAUTH "HTTP/1.1 401 Unauthorized\r\n"
+#define MK_RH_CLIENT_PAYMENT_REQ "HTTP/1.1 402 Payment Required\r\n"
+#define MK_RH_CLIENT_FORBIDDEN "HTTP/1.1 403 Forbidden\r\n"
+#define MK_RH_CLIENT_NOT_FOUND "HTTP/1.1 404 Not Found\r\n"
+#define MK_RH_CLIENT_METHOD_NOT_ALLOWED "HTTP/1.1 405 Method Not Allowed\r\n"
+#define MK_RH_CLIENT_NOT_ACCEPTABLE "HTTP/1.1 406 Not Acceptable\r\n"
+#define MK_RH_CLIENT_PROXY_AUTH "HTTP/1.1 407 Proxy Authentication Required\r\n"
+#define MK_RH_CLIENT_REQUEST_TIMEOUT "HTTP/1.1 408 Request Timeout\r\n"
+#define MK_RH_CLIENT_CONFLICT "HTTP/1.1 409 Conflict\r\n"
+#define MK_RH_CLIENT_GONE "HTTP/1.1 410 Gone\r\n"
+#define MK_RH_CLIENT_LENGTH_REQUIRED "HTTP/1.1 411 Length Required\r\n"
+#define MK_RH_CLIENT_PRECOND_FAILED "HTTP/1.1 412 Precondition Failed\r\n"
+#define MK_RH_CLIENT_REQUEST_ENTITY_TOO_LARGE \
+ "HTTP/1.1 413 Request Entity Too Large\r\n"
+#define MK_RH_CLIENT_REQUEST_URI_TOO_LONG "HTTP/1.1 414 Request-URI Too Long\r\n"
+#define MK_RH_CLIENT_UNSUPPORTED_MEDIA "HTTP/1.1 415 Unsupported Media Type\r\n"
+#define MK_RH_CLIENT_REQUESTED_RANGE_NOT_SATISF \
+ "HTTP/1.1 416 Requested Range Not Satisfiable\r\n"
+
+/* Server side errors */
+#define MK_RH_SERVER_INTERNAL_ERROR "HTTP/1.1 500 Internal Server Error\r\n"
+#define MK_RH_SERVER_NOT_IMPLEMENTED "HTTP/1.1 501 Not Implemented\r\n"
+#define MK_RH_SERVER_BAD_GATEWAY "HTTP/1.1 502 Bad Gateway\r\n"
+#define MK_RH_SERVER_SERVICE_UNAV "HTTP/1.1 503 Service Unavailable\r\n"
+#define MK_RH_SERVER_GATEWAY_TIMEOUT "HTTP/1.1 504 Gateway Timeout\r\n"
+#define MK_RH_SERVER_HTTP_VERSION_UNSUP "HTTP/1.1 505 HTTP Version Not Supported\r\n"
+
+struct header_status_response {
+ int status;
+ int length;
+ char *response;
+};
+
+#define MK_HEADER_TE_TYPE_CHUNKED 0
+#define MK_HEADER_CONN_UPGRADED 11
+#define MK_HEADER_UPGRADED_H2C 20
+
+extern const mk_ptr_t mk_header_short_date;
+extern const mk_ptr_t mk_header_short_location;
+extern const mk_ptr_t mk_header_short_ct;
+
+/* mk pointers with response server headers */
+extern const mk_ptr_t mk_header_conn_ka;
+extern const mk_ptr_t mk_header_conn_close;
+extern const mk_ptr_t mk_header_content_length;
+extern const mk_ptr_t mk_header_content_encoding;
+extern const mk_ptr_t mk_header_accept_ranges;
+extern const mk_ptr_t mk_header_te_chunked;
+extern const mk_ptr_t mk_header_last_modified;
+
+int mk_header_prepare(struct mk_http_session *cs, struct mk_http_request *sr,
+ struct mk_server *server);
+
+void mk_header_response_reset(struct response_headers *header);
+void mk_header_set_http_status(struct mk_http_request *sr, int status);
+void mk_header_set_content_length(struct mk_http_request *sr, long len);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_http.h b/fluent-bit/lib/monkey/include/monkey/mk_http.h
new file mode 100644
index 000000000..42204f9c6
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_http.h
@@ -0,0 +1,225 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_HTTP_H
+#define MK_HTTP_H
+
+#include <monkey/mk_scheduler.h>
+#include <monkey/mk_core.h>
+#include <monkey/mk_http_parser.h>
+
+#define MK_CRLF "\r\n"
+
+/* Request buffer chunks = 4KB */
+#define MK_REQUEST_CHUNK (int) 4096
+#define MK_REQUEST_DEFAULT_PAGE "<HTML><HEAD><STYLE type=\"text/css\"> body {font-size: 12px;} </STYLE></HEAD><BODY><H1>%s</H1>%s<BR><HR><ADDRESS>Powered by %s</ADDRESS></BODY></HTML>"
+
+/* Hard coded restrictions */
+#define MK_HTTP_DIRECTORY_BACKWARD ".."
+
+#define MK_METHOD_GET_STR "GET"
+#define MK_METHOD_POST_STR "POST"
+#define MK_METHOD_HEAD_STR "HEAD"
+#define MK_METHOD_PUT_STR "PUT"
+#define MK_METHOD_DELETE_STR "DELETE"
+#define MK_METHOD_OPTIONS_STR "OPTIONS"
+
+/* Headers */
+#define RH_ACCEPT "Accept:"
+#define RH_ACCEPT_CHARSET "Accept-Charset:"
+#define RH_ACCEPT_ENCODING "Accept-Encoding:"
+#define RH_ACCEPT_LANGUAGE "Accept-Language:"
+#define RH_CONNECTION "Connection:"
+#define RH_COOKIE "Cookie:"
+#define RH_CONTENT_LENGTH "Content-Length:"
+#define RH_CONTENT_RANGE "Content-Range:"
+#define RH_CONTENT_TYPE "Content-Type:"
+#define RH_IF_MODIFIED_SINCE "If-Modified-Since:"
+#define RH_HOST "Host:"
+#define RH_LAST_MODIFIED "Last-Modified:"
+#define RH_LAST_MODIFIED_SINCE "Last-Modified-Since:"
+#define RH_REFERER "Referer:"
+#define RH_RANGE "Range:"
+#define RH_USER_AGENT "User-Agent:"
+
+#define MK_REQUEST_STATUS_INCOMPLETE -1
+#define MK_REQUEST_STATUS_COMPLETED 0
+
+#define MK_EXIT_OK 0
+#define MK_EXIT_ERROR -1
+#define MK_EXIT_ABORT -2
+#define MK_EXIT_PCONNECTION 24
+
+/* Available methods */
+#define MK_HTTP_METHOD_AVAILABLE \
+ MK_HTTP_METHOD_GET_STR "," MK_HTTP_METHOD_POST_STR "," \
+ MK_HTTP_METHOD_HEAD_STR "," MK_HTTP_METHOD_PUT_STR "," \
+ MK_HTTP_METHOD_DELETE_STR "," MK_HTTP_METHOD_OPTIONS_STR \
+ MK_CRLF
+
+#define MK_HTTP_PROTOCOL_UNKNOWN (-1)
+#define MK_HTTP_PROTOCOL_09 (9)
+#define MK_HTTP_PROTOCOL_10 (10)
+#define MK_HTTP_PROTOCOL_11 (11)
+
+#define MK_HTTP_PROTOCOL_09_STR "HTTP/0.9"
+#define MK_HTTP_PROTOCOL_10_STR "HTTP/1.0"
+#define MK_HTTP_PROTOCOL_11_STR "HTTP/1.1"
+
+extern const mk_ptr_t mk_http_method_get_p;
+extern const mk_ptr_t mk_http_method_post_p;
+extern const mk_ptr_t mk_http_method_head_p;
+extern const mk_ptr_t mk_http_method_put_p;
+extern const mk_ptr_t mk_http_method_delete_p;
+extern const mk_ptr_t mk_http_method_options_p;
+extern const mk_ptr_t mk_http_method_null_p;
+
+extern const mk_ptr_t mk_http_protocol_09_p;
+extern const mk_ptr_t mk_http_protocol_10_p;
+extern const mk_ptr_t mk_http_protocol_11_p;
+extern const mk_ptr_t mk_http_protocol_null_p;
+
+/*
+ * A HTTP session represents an incoming session
+ * from a client, a session can be used for pipelined or
+ * keepalive requests.
+ */
+
+struct mk_http_session
+{
+ /*
+ * The first field of the struct appended to the sched_conn memory
+ * space needs to be an integer, the scheduler will set this flag
+ * to MK_FALSE to indicate it was just created. This work as a helper
+ * to the protocol handler.
+ *
+ * C rule: a pointer to a structure always points to it's first member.
+ */
+ int _sched_init; /* initialized ? */
+
+ int socket; /* socket associated */
+ int pipelined; /* Pipelined request */
+ int counter_connections; /* Count persistent connections */
+ int status; /* Request status */
+ int close_now; /* Close the session ASAP */
+
+ struct mk_channel *channel;
+ struct mk_sched_conn *conn;
+
+ unsigned int body_size;
+ unsigned int body_length;
+
+ /* head for mk_http_request list nodes, each request is linked here */
+ struct mk_list request_list;
+
+ /* creation time for this HTTP session */
+ time_t init_time;
+
+ /* request body buffer */
+ char *body;
+
+ /* Initial fixed size buffer for small requests */
+ char body_fixed[MK_REQUEST_CHUNK];
+
+ /*
+ * FIXME: in previous versions of Monkey we used to parse the complete request
+ * for pipelined requests and generate a linked lists of request. With the new
+ * parser we are taking the approach to parse one request and process it before
+ * parsing others, from that point of view we should not need a linked list
+ * of requests.
+ *
+ * Still testing...
+ */
+ struct mk_http_request sr_fixed;
+
+ /*
+ * Parser context: we only held one parser per connection
+ * which is re-used everytime we have a new request.
+ */
+ struct mk_http_parser parser;
+
+ /* Server context */
+ struct mk_server *server;
+};
+
+static inline int mk_http_status_completed(struct mk_http_session *cs,
+ struct mk_sched_conn *conn)
+{
+ (void) conn;
+
+ if (cs->status == MK_REQUEST_STATUS_COMPLETED) {
+ MK_TRACE("HTTP Completed but already completed, aborting conx");
+ return -1;
+ }
+
+ cs->status = MK_REQUEST_STATUS_COMPLETED;
+ return 0;
+}
+
+int mk_http_error(int http_status, struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ struct mk_server *server);
+
+int mk_http_method_check(mk_ptr_t method);
+mk_ptr_t mk_http_method_check_str(int method);
+int mk_http_method_get(char *body);
+
+int mk_http_protocol_check(char *protocol, int len);
+mk_ptr_t mk_http_protocol_check_str(int protocol);
+
+int mk_http_init(struct mk_http_session *cs, struct mk_http_request *sr,
+ struct mk_server *server);
+
+int mk_http_keepalive_check(struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ struct mk_server *server);
+
+int mk_http_pending_request(struct mk_http_session *cs);
+int mk_http_send_file(struct mk_http_session *cs, struct mk_http_request *sr);
+
+/* http session */
+int mk_http_session_init(struct mk_http_session *cs,
+ struct mk_sched_conn *conn,
+ struct mk_server *server);
+void mk_http_session_remove(struct mk_http_session *cs,
+ struct mk_server *server);
+
+/* event handlers */
+int mk_http_handler_read(struct mk_sched_conn *conn, struct mk_http_session *cs,
+ struct mk_server *server);
+
+int mk_http_handler_write(int socket, struct mk_http_session *cs);
+
+void mk_http_request_free(struct mk_http_request *sr, struct mk_server *server);
+void mk_http_request_free_list(struct mk_http_session *cs,
+ struct mk_server *server);
+
+void mk_http_request_init(struct mk_http_session *session,
+ struct mk_http_request *request,
+ struct mk_server *server);
+struct mk_http_header *mk_http_header_get(int name, struct mk_http_request *req,
+ const char *key, unsigned int len);
+
+int mk_http_request_end(struct mk_http_session *cs, struct mk_server *server);
+
+#define mk_http_session_get(conn) \
+ (struct mk_http_session *) \
+ (((uint8_t *) conn) + sizeof(struct mk_sched_conn))
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_http2.h b/fluent-bit/lib/monkey/include/monkey/mk_http2.h
new file mode 100644
index 000000000..46463632c
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_http2.h
@@ -0,0 +1,182 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_HTTP2_H
+#define MK_HTTP2_H
+
+#include <stdint.h>
+#include <monkey/mk_stream.h>
+#include <monkey/mk_http2_settings.h>
+
+/* Connection was just upgraded */
+#define MK_HTTP2_UPGRADED 1
+#define MK_HTTP2_OK 2
+
+/*
+ * The Client 'sent' the SETTINGS frame according to Section 6.5:
+ *
+ * https://httpwg.github.io/specs/rfc7540.html#ConnectionHeader
+ * https://httpwg.github.io/specs/rfc7540.html#SETTINGS
+ */
+#define MK_HTTP2_CLIENT_SETTINGS 2
+
+
+
+/* A buffer chunk size */
+#define MK_HTTP2_CHUNK 4096
+
+#define MK_HTTP2_HEADER_SIZE 9 /* Frame header size */
+
+/*
+ * 4.1 HTTP2 Frame format
+ *
+ * +-----------------------------------------------+
+ * | Length (24) |
+ * +---------------+---------------+---------------+
+ * | Type (8) | Flags (8) |
+ * +-+-------------+---------------+-------------------------------+
+ * |R| Stream Identifier (31) |
+ * +=+=============================================================+
+ * | Frame Payload (0...) ...
+ * +---------------------------------------------------------------+
+ *
+ */
+
+/* Structure to represent an incoming frame (not to write) */
+struct mk_http2_frame {
+ uint32_t len_type; /* (24 length + 8 type) */
+ uint8_t flags;
+ uint32_t stream_id;
+ void *payload;
+};
+
+/* a=target variable, b=bit number to act upon 0-n */
+#define BIT_CLEAR(a,b) ((a) &= ~(1<<(b)))
+
+static inline uint32_t mk_http2_bitdec_32u(uint8_t *b)
+{
+ return (uint32_t) ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
+}
+
+static inline uint32_t mk_http2_bitdec_stream_id(uint8_t *b)
+{
+ uint32_t sid = mk_http2_bitdec_32u(b);
+ return BIT_CLEAR(sid, 31);
+}
+
+static inline uint8_t mk_http2_frame_type(struct mk_http2_frame *f)
+{
+ return (uint8_t) (0xFFFFFF & f->len_type);
+}
+
+static inline uint32_t mk_http2_frame_len(struct mk_http2_frame *f)
+{
+ return (uint32_t) (f->len_type >> 8);
+}
+
+/* HTTP/2 General flags */
+
+#define MK_HTTP2_SETTINGS_ACK 0x1
+
+/*
+ * HTTP/2 Frame types
+ */
+#define MK_HTTP2_DATA 0x0 /* Section 6.1 */
+#define MK_HTTP2_HEADERS 0x1 /* Section 6.2 */
+#define MK_HTTP2_PRIORITY 0x2 /* Section 6.3 */
+#define MK_HTTP2_RST_STREAM 0x3 /* Section 6.4 */
+#define MK_HTTP2_SETTINGS 0x4 /* Section 6.5 */
+#define MK_HTTP2_PUSH_PROMISE 0x5 /* Section 6.6 */
+#define MK_HTTP2_PING 0x6 /* Section 6.7 */
+#define MK_HTTP2_GOAWAY 0x7 /* Section 6.8 */
+#define MK_HTTP2_WINDOW_UPDATE 0x8 /* Section 6.9 */
+#define MK_HTTP2_CONTINUATION 0x9 /* Section 6.10 */
+
+/*
+ * HTTP/2 Settings Parameters (Section 6.5.2)
+ * ------------------------------------------
+ */
+
+/*
+ * HTTP/2 Error codes
+ * ------------------
+ */
+
+/* The associated condition is not a result of an error */
+#define MK_HTTP2_NO_ERROR 0x0
+/* The endpoint detected an unspecific protocol error */
+#define MK_HTTP2_PROTOCOL_ERROR 0x1
+/* The endpoint encountered an unexpected internal error */
+#define MK_HTTP2_INTERNAL_ERROR 0x2
+/* The endpoint detected that its peer violated the flow-control protocol */
+#define MK_HTTP2_FLOW_CONTROL_ERROR 0x3
+/* The endpoint sent a SETTINGS frame but did not receive a response */
+#define MK_HTTP2_SETTINGS_TIMEOUT 0x4
+/* The endpoint received a frame after a stream was half-closed */
+#define MK_HTTP2_STREAM_CLOSED 0x5
+/* The endpoint received a frame with an invalid size */
+#define MK_HTTP2_FRAME_SIZE_ERROR 0x6
+/* The endpoint refused the stream prior to performing any application processing */
+#define MK_HTTP2_REFUSED_STREAM 0x7
+/* Used by the endpoint to indicate that the stream is no longer needed */
+#define MK_HTTP2_CANCEL 0x8
+/* The endpoint is unable to maintain the header compression context for the connection */
+#define MK_HTTP2_COMPRESSION_ERROR 0x9
+/* The connection established in response to a CONNECT request was reset */
+#define MK_HTTP2_CONNECT_ERROR 0xa
+/* The endpoint detected that its peer is exhibiting a behavior that might be generating excessive load */
+#define MK_HTTP2_ENHANCE_YOUR_CALM 0xb
+/* The underlying transport has properties that do not meet minimum security requirements (see Section 9.2) */
+#define MK_HTTP2_INADEQUATE_SECURITY 0xc
+/* The endpoint requires that HTTP/1.1 be used instead of HTTP/2 */
+#define MK_HTTP2_HTTP_1_1_REQUIRED 0xd
+
+
+#ifdef TRACE
+#define MK_H2_TRACE(conn, fmt, ...) \
+ mk_utils_trace("mk", \
+ MK_TRACE_CORE, \
+ __FUNCTION__, __FILENAME__, __LINE__, \
+ "[%sH2%s] (fd=%i) " fmt, \
+ ANSI_RESET ANSI_WHITE, ANSI_RED, \
+ conn->event.fd, ##__VA_ARGS__)
+#else
+#define MK_H2_TRACE(...) do {} while (0)
+#endif
+
+#define mk_http2_send_raw(conn, buf, length) \
+ mk_stream_set(NULL, MK_STREAM_RAW, &conn->channel, \
+ buf, length, NULL, NULL, NULL, NULL)
+
+struct mk_http2_session {
+ int status;
+
+ /* Buffer used to read data */
+ unsigned int buffer_size;
+ unsigned int buffer_length;
+ char *buffer;
+ char buffer_fixed[MK_HTTP2_CHUNK];
+
+ /* Session Settings */
+ struct mk_http2_settings settings;
+
+ struct mk_stream stream_settings;
+};
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_http2_settings.h b/fluent-bit/lib/monkey/include/monkey/mk_http2_settings.h
new file mode 100644
index 000000000..85af39664
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_http2_settings.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_HTTP2_SETTINGS_H
+#define MK_HTTP2_SETTINGS_H
+
+struct mk_http2_settings {
+ uint32_t header_table_size;
+ uint32_t enable_push;
+ uint32_t max_concurrent_streams;
+ uint32_t initial_window_size;
+ uint32_t max_frame_size;
+ uint32_t max_header_list_size;
+};
+
+
+const struct mk_http2_settings MK_HTTP2_SETTINGS_DEFAULT =
+ {
+ .header_table_size = 4096,
+ .enable_push = 1,
+ .max_concurrent_streams = 64,
+ .initial_window_size = 65535,
+ .max_frame_size = 16384, /* 6.5.2 -> 2^14 */
+ .max_header_list_size = UINT32_MAX
+ };
+
+/*
+ * Default settings of Monkey, we send this upon a new connection arrives
+ * to the HTTP/2 handler.
+ */
+#define MK_HTTP2_SETTINGS_DEFAULT_FRAME \
+ "\x00\x00\x0c" /* frame length */ \
+ "\x04" /* type=SETTINGS */ \
+ "\x00" /* flags */ \
+ "\x00\x00\x00\x00" /* stream ID */ \
+ \
+ /* SETTINGS_MAX_CONCURRENT_STREAMS */ \
+ "\x00\x03" \
+ "\x00\x00\x00\x40" /* value=64 */ \
+ \
+ /* SETTINGS_INITIAL_WINDOW_SIZE */ \
+ "\x00\x04" \
+ "\x00\x00\xff\xff" /* value=65535 */
+
+#define MK_HTTP2_SETTINGS_ACK_FRAME \
+ "\x00\x00\x00\x04\x01\x00\x00\x00\x00"
+
+#define MK_HTTP2_SETTINGS_HEADER_TABLE_SIZE 0x1
+#define MK_HTTP2_SETTINGS_ENABLE_PUSH 0x2
+#define MK_HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS 0x3
+#define MK_HTTP2_SETTINGS_INITIAL_WINDOW_SIZE 0x4
+#define MK_HTTP2_SETTINGS_MAX_FRAME_SIZE 0x5
+#define MK_HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE 0x6
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_http_internal.h b/fluent-bit/lib/monkey/include/monkey/mk_http_internal.h
new file mode 100644
index 000000000..4d82191a6
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_http_internal.h
@@ -0,0 +1,197 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_HTTP_INTERNAL_H
+#define MK_HTTP_INTERNAL_H
+
+#include <monkey/mk_stream.h>
+
+#define MK_HEADER_IOV 32
+#define MK_HEADER_ETAG_SIZE 32
+
+struct response_headers
+{
+ int status;
+
+ /* Connection flag, if equal -1, the connection header is ommited */
+ int connection;
+
+ /*
+ * If some plugins wants to set a customized HTTP status, here
+ * is the 'how and where'
+ */
+ mk_ptr_t custom_status;
+
+ /* Length of the content to send */
+ long content_length;
+
+ /* Private value, real length of the file requested */
+ long real_length;
+
+ int cgi;
+ int pconnections_left;
+ int breakline;
+
+ int transfer_encoding;
+
+ int upgrade;
+
+ int ranges[2];
+
+ time_t last_modified;
+ mk_ptr_t allow_methods;
+ mk_ptr_t content_type;
+ mk_ptr_t content_encoding;
+ char *location;
+
+ int etag_len;
+ char etag_buf[MK_HEADER_ETAG_SIZE];
+
+ /*
+ * This field allow plugins to add their own response
+ * headers
+ */
+ struct mk_iov *_extra_rows;
+
+ /* Flag to track if the response headers were sent */
+ int sent;
+
+ /* IOV dirty hack */
+ struct mk_iov headers_iov;
+ struct mk_iovec __iov_io[MK_HEADER_IOV];
+ void *__iov_buf[MK_HEADER_IOV];
+};
+
+struct mk_http_request
+{
+ int status;
+ int protocol;
+
+ /* is it serving a user's home directory ? */
+ int user_home;
+
+ /*-Connection-*/
+ long port;
+ /*------------*/
+
+ /* Body Stream size */
+ uint64_t stream_size;
+
+ /* Streams handling: headers and static file */
+ struct mk_stream stream;
+ struct mk_stream_input in_headers;
+ struct mk_stream_input in_headers_extra;
+ struct mk_stream_input in_file;
+ struct mk_stream_input page_stream;
+
+ int headers_len;
+
+ /*----First header of client request--*/
+ int method;
+ mk_ptr_t method_p;
+ mk_ptr_t uri; /* original request */
+ mk_ptr_t uri_processed; /* processed request (decoded) */
+
+ mk_ptr_t protocol_p;
+
+ mk_ptr_t body;
+
+ /*---Request headers--*/
+ int content_length;
+
+ mk_ptr_t _content_length;
+ mk_ptr_t content_type;
+ mk_ptr_t connection;
+
+ mk_ptr_t host;
+ mk_ptr_t host_port;
+ mk_ptr_t if_modified_since;
+ mk_ptr_t last_modified_since;
+ mk_ptr_t range;
+
+ /*---------------------*/
+
+ /* POST/PUT data */
+ mk_ptr_t data;
+ /*-----------------*/
+
+ /*-Internal-*/
+ mk_ptr_t real_path; /* Absolute real path */
+
+ /*
+ * If a full URL length is less than MAX_PATH_BASE (defined in limits.h),
+ * it will be stored here and real_path will point this buffer
+ */
+ char real_path_static[MK_PATH_BASE];
+
+ /* Query string: ?.... */
+ mk_ptr_t query_string;
+
+
+ /*
+ * STAGE_30 block flag: in mk_http_init() when the file is not found, it
+ * triggers the plugin STAGE_30 to look for a plugin handler. In some
+ * cases the plugin would overwrite the real path of the requested file
+ * and make Monkey handle the new path for the static file. At this point
+ * we need to block STAGE_30 calls from mk_http_init().
+ *
+ * For short.. if a plugin overwrites the real_path, let Monkey handle that
+ * and do not trigger more STAGE_30's.
+ */
+ int stage30_blocked;
+
+ /*
+ * If the connection is being managed by a plugin (e.g: CGI), associate the
+ * plugin reference to the stage30_handler field. This is useful to handle
+ * protocol exception and notify the handlers about it.
+ */
+ void *stage30_handler;
+
+ /* Static file information */
+ int file_fd;
+ struct file_info file_info;
+
+ /* Vhost */
+ int vhost_fdt_id;
+ unsigned int vhost_fdt_hash;
+ int vhost_fdt_enabled;
+
+ struct mk_vhost *host_conf; /* root vhost config */
+ struct mk_vhost_alias *host_alias; /* specific vhost matched */
+
+ /*
+ * Reference used outside of Monkey Core, e.g: Plugins. It can be used
+ * to store some relevant information associated to a request.
+ */
+ void *handler_data;
+
+ /* Parent Session */
+ struct mk_http_session *session;
+
+ /* coroutine thread (if any) */
+ void *thread;
+
+ /* Head to list of requests */
+ struct mk_list _head;
+
+ /* Response headers */
+ struct response_headers headers;
+};
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_http_parser.h b/fluent-bit/lib/monkey/include/monkey/mk_http_parser.h
new file mode 100644
index 000000000..6d45c3941
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_http_parser.h
@@ -0,0 +1,348 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_HTTP_PARSER_H
+#define MK_HTTP_PARSER_H
+
+#define _GNU_SOURCE
+#include <ctype.h>
+
+#include <monkey/mk_core.h>
+#include <monkey/mk_http.h>
+#include <monkey/mk_http_internal.h>
+
+/* General status */
+#define MK_HTTP_PARSER_PENDING -10 /* cannot complete until more data arrives */
+#define MK_HTTP_PARSER_ERROR -1 /* found an error when parsing the string */
+#define MK_HTTP_PARSER_OK 0 /* parser OK, ready to go */
+
+/* Connection header values */
+#define MK_HTTP_PARSER_CONN_EMPTY 0
+#define MK_HTTP_PARSER_CONN_UNKNOWN -1
+#define MK_HTTP_PARSER_CONN_KA 1
+#define MK_HTTP_PARSER_CONN_CLOSE 2
+#define MK_HTTP_PARSER_CONN_UPGRADE 4
+#define MK_HTTP_PARSER_CONN_HTTP2_SE 8
+
+/* Upgrades supported */
+#define MK_HTTP_PARSER_UPGRADE_NONE 0
+#define MK_HTTP_PARSER_UPGRADE_H2 1
+#define MK_HTTP_PARSER_UPGRADE_H2C 2
+
+#define MK_HEADER_EXTRA_SIZE 50
+
+/* Request levels
+ * ==============
+ *
+ * 1. FIRST_LINE : Method, URI (+ QS) + Protocol version + CRLF
+ * 2. HEADERS (optional) : KEY, SEP, VALUE + CRLF
+ * 3. BODY (option) : data based on Content-Length or Chunked transfer encoding
+ */
+
+enum {
+ REQ_LEVEL_FIRST = 1,
+ REQ_LEVEL_CONTINUE ,
+ REQ_LEVEL_HEADERS ,
+ REQ_LEVEL_END ,
+ REQ_LEVEL_BODY
+};
+
+/* Statuses per levels */
+enum {
+ /* REQ_LEVEL_FIRST */
+ MK_ST_REQ_METHOD = 1,
+ MK_ST_REQ_URI ,
+ MK_ST_REQ_QUERY_STRING ,
+ MK_ST_REQ_PROT_VERSION ,
+ MK_ST_FIRST_CONTINUE ,
+ MK_ST_FIRST_FINALIZING , /* LEVEL_FIRST finalize the request */
+ MK_ST_FIRST_COMPLETE ,
+
+ /* REQ_HEADERS */
+ MK_ST_HEADER_KEY ,
+ MK_ST_HEADER_SEP ,
+ MK_ST_HEADER_VAL_STARTS ,
+ MK_ST_HEADER_VALUE ,
+ MK_ST_HEADER_END ,
+ MK_ST_BLOCK_END
+};
+
+/* Known HTTP Methods */
+enum mk_request_methods {
+ MK_METHOD_GET = 0,
+ MK_METHOD_POST ,
+ MK_METHOD_HEAD ,
+ MK_METHOD_PUT ,
+ MK_METHOD_DELETE ,
+ MK_METHOD_OPTIONS ,
+ MK_METHOD_SIZEOF ,
+ MK_METHOD_UNKNOWN
+};
+
+/*
+ * Define a list of known headers, they are used to perform headers
+ * lookups in the parser and further Monkey core.
+ */
+enum mk_request_headers {
+ MK_HEADER_ACCEPT = 0,
+ MK_HEADER_ACCEPT_CHARSET ,
+ MK_HEADER_ACCEPT_ENCODING ,
+ MK_HEADER_ACCEPT_LANGUAGE ,
+ MK_HEADER_AUTHORIZATION ,
+ MK_HEADER_CACHE_CONTROL ,
+ MK_HEADER_COOKIE ,
+ MK_HEADER_CONNECTION ,
+ MK_HEADER_CONTENT_LENGTH ,
+ MK_HEADER_CONTENT_RANGE ,
+ MK_HEADER_CONTENT_TYPE ,
+ MK_HEADER_HOST ,
+ MK_HEADER_HTTP2_SETTINGS ,
+ MK_HEADER_IF_MODIFIED_SINCE ,
+ MK_HEADER_LAST_MODIFIED ,
+ MK_HEADER_LAST_MODIFIED_SINCE ,
+ MK_HEADER_RANGE ,
+ MK_HEADER_REFERER ,
+ MK_HEADER_UPGRADE ,
+ MK_HEADER_USER_AGENT ,
+ MK_HEADER_SIZEOF ,
+
+ /* used by the core for custom headers */
+ MK_HEADER_OTHER
+};
+
+/*
+ * Expected Header values that are used to take logic
+ * decision.
+ */
+#define MK_CONN_KEEP_ALIVE "keep-alive"
+#define MK_CONN_CLOSE "close"
+#define MK_CONN_UPGRADE "upgrade"
+
+/* HTTP Upgrade options available */
+#define MK_UPGRADE_H2 "h2"
+#define MK_UPGRADE_H2C "h2c"
+
+struct mk_http_header {
+ /* The header type/name, e.g: MK_HEADER_CONTENT_LENGTH */
+ int type;
+
+ /* Reference the header Key name, e.g: 'Content-Lentth' */
+ mk_ptr_t key;
+
+ /* Reference the header Value, e/g: '123456' */
+ mk_ptr_t val;
+
+ /*
+ * Link to head list, it's used to reference this node and
+ * iterate it as a linked list
+ */
+ struct mk_list _head;
+};
+
+/* This structure is the 'Parser Context' */
+struct mk_http_parser {
+ int i;
+ int level; /* request level */
+ int status; /* level status */
+ int next; /* something next after status ? */
+ int length;
+ int method;
+
+ /* lookup fields */
+ int start;
+ int end;
+ int chars;
+
+ /* it stores the numeric value of Content-Length header */
+ int header_host_port;
+
+ long int body_received;
+ long int header_content_length;
+
+ /*
+ * connection header value discovered: it can be set with
+ * values:
+ *
+ * MK_HTTP_PARSER_CONN_EMPTY : header not set
+ * MK_HTTP_PARSER_CONN_UNKNOWN: unexpected value
+ * MK_HTTP_PARSER_CONN_KA : keep-alive
+ * MK_HTTP_PARSER_CONN_CLOSE : close
+ */
+ int header_connection;
+
+ /* upgrade request: we suppport the following values:
+ *
+ * MK_HTTP_PARSER_UPGRADE_H2 : HTTP/2.0 over TLS
+ * MK_HTTP_PARSER_UPGRADE_H2C : HTTP/2.0 (plain TCP)
+ */
+ int header_upgrade;
+
+ /* probable current header, fly parsing */
+ int header_key;
+ int header_sep;
+ int header_val;
+ int header_min;
+ int header_max;
+ int headers_extra_count;
+
+ /* Known headers */
+ struct mk_http_header headers[MK_HEADER_SIZEOF];
+
+ /* Head of linked list for all headers found in the request */
+ int header_count;
+ struct mk_list header_list;
+
+ /* Extra headers */
+ struct mk_http_header headers_extra[MK_HEADER_EXTRA_SIZE];
+};
+
+
+#ifdef HTTP_STANDALONE
+
+/* ANSI Colors */
+
+#define ANSI_RESET "\033[0m"
+#define ANSI_BOLD "\033[1m"
+
+#define ANSI_CYAN "\033[36m"
+#define ANSI_BOLD_CYAN ANSI_BOLD ANSI_CYAN
+#define ANSI_MAGENTA "\033[35m"
+#define ANSI_BOLD_MAGENTA ANSI_BOLD ANSI_MAGENTA
+#define ANSI_RED "\033[31m"
+#define ANSI_BOLD_RED ANSI_BOLD ANSI_RED
+#define ANSI_YELLOW "\033[33m"
+#define ANSI_BOLD_YELLOW ANSI_BOLD ANSI_YELLOW
+#define ANSI_BLUE "\033[34m"
+#define ANSI_BOLD_BLUE ANSI_BOLD ANSI_BLUE
+#define ANSI_GREEN "\033[32m"
+#define ANSI_BOLD_GREEN ANSI_BOLD ANSI_GREEN
+#define ANSI_WHITE "\033[37m"
+#define ANSI_BOLD_WHITE ANSI_BOLD ANSI_WHITE
+
+#define TEST_OK 0
+#define TEST_FAIL 1
+
+
+static inline void p_field(struct mk_http_parser *req, char *buffer)
+{
+ int i;
+
+ printf("'");
+ for (i = req->start; i < req->end; i++) {
+ printf("%c", buffer[i]);
+ }
+ printf("'");
+
+}
+
+static inline int eval_field(struct mk_http_parser *req, char *buffer)
+{
+ if (req->level == REQ_LEVEL_FIRST) {
+ printf("[ \033[35mfirst level\033[0m ] ");
+ }
+ else {
+ printf("[ \033[36mheaders\033[0m ] ");
+ }
+
+ printf(" ");
+ switch (req->status) {
+ case MK_ST_REQ_METHOD:
+ printf("MK_ST_REQ_METHOD : ");
+ break;
+ case MK_ST_REQ_URI:
+ printf("MK_ST_REQ_URI : ");
+ break;
+ case MK_ST_REQ_QUERY_STRING:
+ printf("MK_ST_REQ_QUERY_STRING : ");
+ break;
+ case MK_ST_REQ_PROT_VERSION:
+ printf("MK_ST_REQ_PROT_VERSION : ");
+ break;
+ case MK_ST_HEADER_KEY:
+ printf("MK_ST_HEADER_KEY : ");
+ break;
+ case MK_ST_HEADER_VAL_STARTS:
+ printf("MK_ST_HEADER_VAL_STARTS: ");
+ break;
+ case MK_ST_HEADER_VALUE:
+ printf("MK_ST_HEADER_VALUE : ");
+ break;
+ case MK_ST_HEADER_END:
+ printf("MK_ST_HEADER_END : ");
+ break;
+ default:
+ printf("\033[31mUNKNOWN STATUS (%i)\033[0m : ", req->status);
+ break;
+ };
+
+
+ p_field(req, buffer);
+ printf("\n");
+
+ return 0;
+}
+#endif /* HTTP_STANDALONE */
+
+#define mk_http_set_minor_version(c) \
+ if (c == '1') { \
+ req->protocol = MK_HTTP_PROTOCOL_11; \
+ } \
+ else if (c == '0') { \
+ req->protocol = MK_HTTP_PROTOCOL_10; \
+ } \
+ else { \
+ req->protocol = MK_HTTP_PROTOCOL_UNKNOWN; \
+ }
+
+
+static inline void mk_http_parser_init(struct mk_http_parser *p)
+{
+ memset(p, '\0', sizeof(struct mk_http_parser));
+
+ p->level = REQ_LEVEL_FIRST;
+ p->status = MK_ST_REQ_METHOD;
+ p->chars = -1;
+ p->method = -1;
+
+ /* init headers */
+ p->header_key = -1;
+ p->header_sep = -1;
+ p->header_val = -1;
+ p->header_min = -1;
+ p->header_max = -1;
+ p->header_content_length = -1;
+
+ /* init list header */
+ p->header_count = 0;
+ mk_list_init(&p->header_list);
+}
+
+static inline int mk_http_parser_more(struct mk_http_parser *p, int len)
+{
+ if (abs(len - p->i) - 1 > 0) {
+ return MK_TRUE;
+ }
+
+ return MK_FALSE;
+}
+
+int mk_http_parser(struct mk_http_request *req, struct mk_http_parser *p,
+ char *buffer, int buf_len, struct mk_server *server);
+
+#endif /* MK_HTTP_H */
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_http_status.h b/fluent-bit/lib/monkey/include/monkey/mk_http_status.h
new file mode 100644
index 000000000..568bf3802
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_http_status.h
@@ -0,0 +1,84 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_HTTP_STATUS_H
+#define MK_HTTP_STATUS_H
+
+#include <monkey/mk_core.h>
+
+/*
+ * - New macro names and structure by Monkey Dev Team
+ * - Initial HTTP Status provided by Juan C. Inostroza <jci@codemonkey.cl>
+ */
+
+/* Monkey allow plugins to set their customized status */
+#define MK_CUSTOM_STATUS 7
+
+/* Informational status */
+#define MK_INFO_CONTINUE 100
+#define MK_INFO_SWITCH_PROTOCOL 101
+
+/* Succesful */
+#define MK_HTTP_OK 200
+#define MK_HTTP_CREATED 201
+#define MK_HTTP_ACCEPTED 202
+#define MK_HTTP_NON_AUTH_INFO 203
+#define MK_HTTP_NOCONTENT 204
+#define MK_HTTP_RESET 205
+#define MK_HTTP_PARTIAL 206
+
+/* Redirections */
+#define MK_REDIR_MULTIPLE 300
+#define MK_REDIR_MOVED 301
+#define MK_REDIR_MOVED_T 302
+#define MK_REDIR_SEE_OTHER 303
+#define MK_NOT_MODIFIED 304
+#define MK_REDIR_USE_PROXY 305
+
+/* Client Errors */
+#define MK_CLIENT_BAD_REQUEST 400
+#define MK_CLIENT_UNAUTH 401
+#define MK_CLIENT_PAYMENT_REQ 402 /* Wtf?! :-) */
+#define MK_CLIENT_FORBIDDEN 403
+#define MK_CLIENT_NOT_FOUND 404
+#define MK_CLIENT_METHOD_NOT_ALLOWED 405
+#define MK_CLIENT_NOT_ACCEPTABLE 406
+#define MK_CLIENT_PROXY_AUTH 407
+#define MK_CLIENT_REQUEST_TIMEOUT 408
+#define MK_CLIENT_CONFLICT 409
+#define MK_CLIENT_GONE 410
+#define MK_CLIENT_LENGTH_REQUIRED 411
+#define MK_CLIENT_PRECOND_FAILED 412
+#define MK_CLIENT_REQUEST_ENTITY_TOO_LARGE 413
+#define MK_CLIENT_REQUEST_URI_TOO_LONG 414
+#define MK_CLIENT_UNSUPPORTED_MEDIA 415
+#define MK_CLIENT_REQUESTED_RANGE_NOT_SATISF 416
+
+/* Server Errors */
+#define MK_SERVER_INTERNAL_ERROR 500
+#define MK_SERVER_NOT_IMPLEMENTED 501
+#define MK_SERVER_BAD_GATEWAY 502
+#define MK_SERVER_SERVICE_UNAV 503
+#define MK_SERVER_GATEWAY_TIMEOUT 504
+#define MK_SERVER_HTTP_VERSION_UNSUP 505
+
+/* Text header messages */
+#define M_HTTP_OK_TXT "HTTP/1.1 200 OK\r\n"
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_http_thread.h b/fluent-bit/lib/monkey/include/monkey/mk_http_thread.h
new file mode 100644
index 000000000..9c267d60c
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_http_thread.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2016 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_HTTP_THREAD_H
+#define MK_HTTP_THREAD_H
+
+#include <monkey/mk_http.h>
+#include <monkey/mk_thread.h>
+#include <monkey/mk_vhost.h>
+
+#define MK_HTTP_THREAD_LIB 0
+#define MK_HTTP_THREAD_PLUGIN 1
+
+struct mk_http_thread {
+ int close; /* Close TCP connection ? */
+ struct mk_http_session *session; /* HTTP session */
+ struct mk_http_request *request; /* HTTP request */
+ struct mk_thread *parent; /* Parent thread */
+ struct mk_list _head; /* Link to worker->threads */
+};
+
+extern MK_TLS_DEFINE(struct mk_http_libco_params, mk_http_thread_libco_params);
+extern MK_TLS_DEFINE(struct mk_thread, mk_thread);
+
+static MK_INLINE void mk_http_thread_resume(struct mk_http_thread *mth)
+{
+ mk_thread_resume(mth->parent);
+}
+
+void mk_http_thread_initialize_tls();
+
+struct mk_http_thread *mk_http_thread_create(int type,
+ struct mk_vhost_handler *handler,
+ struct mk_http_session *session,
+ struct mk_http_request *request,
+ int n_params,
+ struct mk_list *params);
+int mk_http_thread_destroy(struct mk_http_thread *mth);
+
+int mk_http_thread_event(struct mk_event *event);
+
+int mk_http_thread_start(struct mk_http_thread *mth);
+int mk_http_thread_purge(struct mk_http_thread *mth, int close);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_info.h.in b/fluent-bit/lib/monkey/include/monkey/mk_info.h.in
new file mode 100644
index 000000000..a4ef0a127
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_info.h.in
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2015 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_INFO_H
+#define MK_INFO_H
+
+#include <monkey/mk_core.h>
+
+/* Monkey Version */
+#define MK_VERSION_MAJOR @MK_VERSION_MAJOR@
+#define MK_VERSION_MINOR @MK_VERSION_MINOR@
+#define MK_VERSION_PATCH @MK_VERSION_PATCH@
+#define MK_VERSION (MK_VERSION_MAJOR * 10000 \
+ MK_VERSION_MINOR * 100 \
+ MK_VERSION_PATCH)
+#define MK_VERSION_STR "@MK_VERSION_STR@"
+
+/* Build system information */
+#define MK_BUILD_OS "@CMAKE_SYSTEM_NAME@"
+#define MK_BUILD_UNAME "@CMAKE_SYSTEM@"
+#define MK_BUILD_CMD "@MK_BUILD_CMD@"
+
+/* Default paths */
+#define MK_PATH_CONF "@MK_PATH_CONF@"
+#define MK_PLUGIN_DIR "/home/edsiper/coding/monkey/plugins"
+
+/* General flags set by CMakeLists.txt */
+@MK_BUILD_FLAGS@
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_kernel.h b/fluent-bit/lib/monkey/include/monkey/mk_kernel.h
new file mode 100644
index 000000000..fcaf56d03
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_kernel.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_KERNEL_H
+#define MK_KERNEL_H
+
+/* Server features: depends on server setup and Linux Kernel version */
+#define MK_KERNEL_TCP_FASTOPEN 1
+#define MK_KERNEL_SO_REUSEPORT 2
+#define MK_KERNEL_TCP_AUTOCORKING 4
+
+#define MK_KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
+
+int mk_kernel_version();
+int mk_kernel_features(int version);
+int mk_kernel_features_print(char *buffer, size_t size,
+ struct mk_server *server);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_lib.h b/fluent-bit/lib/monkey/include/monkey/mk_lib.h
new file mode 100644
index 000000000..d02ac6987
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_lib.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_LIB_H
+#define MK_LIB_H
+
+#define _GNU_SOURCE
+
+#include <monkey/mk_info.h>
+#include <monkey/mk_tls.h>
+#include <monkey/mk_vhost.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_fifo.h>
+#include <monkey/mk_http_internal.h>
+#include <monkey/mk_core.h>
+
+struct mk_lib_ctx {
+ pthread_t worker_tid;
+ struct mk_server *server;
+ struct mk_fifo *fifo;
+};
+
+typedef struct mk_fifo_queue mk_mq_t;
+typedef struct mk_lib_ctx mk_ctx_t;
+typedef struct mk_http_request mk_request_t;
+typedef struct mk_http_session mk_session_t;
+
+MK_EXPORT int mk_start(mk_ctx_t *ctx);
+MK_EXPORT int mk_stop(mk_ctx_t *ctx);
+
+MK_EXPORT mk_ctx_t *mk_create();
+MK_EXPORT int mk_destroy(mk_ctx_t *ctx);
+
+MK_EXPORT int mk_config_set(mk_ctx_t *ctx, ...);
+MK_EXPORT struct mk_vhost *mk_vhost_lookup(mk_ctx_t *ctx, int id);
+MK_EXPORT int mk_vhost_create(mk_ctx_t *ctx, char *name);
+
+MK_EXPORT int mk_vhost_set(mk_ctx_t *ctx, int vid, ...);
+MK_EXPORT int mk_vhost_handler(mk_ctx_t *ctx, int vid, char *regex,
+ void (*cb)(mk_request_t *, void *), void *data);
+
+MK_EXPORT int mk_http_status(mk_request_t *req, int status);
+MK_EXPORT int mk_http_header(mk_request_t *req,
+ char *key, int key_len,
+ char *val, int val_len);
+MK_EXPORT int mk_http_send(mk_request_t *req, char *buf, size_t len,
+ void (*cb_finish)(mk_request_t *));
+MK_EXPORT int mk_http_done(mk_request_t *req);
+
+MK_EXPORT int mk_worker_callback(mk_ctx_t *ctx,
+ void (*cb_func) (void *),
+ void *data);
+//MK_EXPORT int mk_mq_create(mk_ctx_t *ctx, char *name);
+MK_EXPORT int mk_mq_create(mk_ctx_t *ctx, char *name, void (*cb), void *data);
+
+MK_EXPORT int mk_mq_send(mk_ctx_t *ctx, int qid, void *data, size_t size);
+
+MK_EXPORT int mk_main();
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_linuxtrace.h b/fluent-bit/lib/monkey/include/monkey/mk_linuxtrace.h
new file mode 100644
index 000000000..abdf88c87
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_linuxtrace.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef LINUX_TRACE
+
+#undef TRACEPOINT_PROVIDER
+#define TRACEPOINT_PROVIDER monkey
+
+#if !defined(_MK_LINUXTRACE_PROVIDER_H) || defined(TRACEPOINT_HEADER_MULTI_READ)
+#define _MK_LINUXTRACE_PROVIDER_H
+#include <lttng/tracepoint.h>
+
+/* Trace point for epoll(2) events */
+TRACEPOINT_EVENT(
+ monkey,
+ epoll,
+ TP_ARGS(int, fd,
+ char *, text),
+ TP_FIELDS(
+ ctf_integer(int, fd, fd)
+ ctf_string(event, text)
+ )
+ )
+
+TRACEPOINT_EVENT(
+ monkey,
+ epoll_state,
+ TP_ARGS(int, fd,
+ int, mode,
+ char *, text),
+ TP_FIELDS(
+ ctf_integer(int, fd, fd)
+ ctf_string(event, text)
+ )
+ )
+
+TRACEPOINT_EVENT(
+ monkey,
+ scheduler,
+ TP_ARGS(int, fd,
+ char *, text),
+ TP_FIELDS(ctf_integer(int, fd, fd)
+ ctf_string(event, text))
+ )
+
+#endif
+
+#undef TRACEPOINT_INCLUDE
+#define TRACEPOINT_INCLUDE "./monkey/mk_linuxtrace.h"
+
+#include <lttng/tracepoint-event.h>
+
+/* Monkey Linux Trace helper macros */
+#define MK_LT_EPOLL(fd, event) tracepoint(monkey, epoll, fd, event)
+#define MK_LT_EPOLL_STATE(fd, mode, event) \
+ tracepoint(monkey, epoll_state, fd, mode, event)
+#define MK_LT_SCHED(fd, event) tracepoint(monkey, scheduler, fd, event)
+
+#else /* NO LINUX_TRACE */
+
+#define MK_LT_EPOLL(fd, event) do {} while(0)
+#define MK_LT_EPOLL_STATE(fd, mode, event) do{} while(0)
+#define MK_LT_SCHED(fd, event) do {} while(0)
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_mimetype.h b/fluent-bit/lib/monkey/include/monkey/mk_mimetype.h
new file mode 100644
index 000000000..4c45cbde3
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_mimetype.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_core.h>
+#include <rbtree.h>
+
+#ifndef MK_MIMETYPE_H
+#define MK_MIMETYPE_H
+
+#define MIMETYPE_DEFAULT_TYPE "text/plain\r\n"
+#define MIMETYPE_DEFAULT_NAME "default"
+
+struct mk_mimetype
+{
+ char *name;
+ mk_ptr_t type;
+ mk_ptr_t header_type;
+ struct mk_list _head;
+ struct rb_tree_node _rb_head;
+};
+
+int mk_mimetype_init(struct mk_server *server);
+int mk_mimetype_add(struct mk_server *server, char *name, const char *type);
+int mk_mimetype_read_config(struct mk_server *server);
+struct mk_mimetype *mk_mimetype_find(struct mk_server *server, mk_ptr_t *filename);
+struct mk_mimetype *mk_mimetype_lookup(struct mk_server *server, char *name);
+void mk_mimetype_free_all(struct mk_server *server);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_net.h b/fluent-bit/lib/monkey/include/monkey/mk_net.h
new file mode 100644
index 000000000..1bcfac88f
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_net.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2016 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_NET_H
+#define MK_NET_H
+
+#include <monkey/mk_core.h>
+#include <monkey/mk_stream.h>
+
+struct mk_net_connection {
+ struct mk_event event;
+ int fd;
+ char *host;
+ int port;
+ void *thread;
+};
+
+int mk_net_init();
+
+struct mk_net_connection *mk_net_conn_create(char *addr, int port);
+int mk_net_conn_write(struct mk_channel *channel,
+ void *data, size_t len);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_plugin.h b/fluent-bit/lib/monkey/include/monkey/mk_plugin.h
new file mode 100644
index 000000000..c180c143a
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_plugin.h
@@ -0,0 +1,384 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_PLUGIN_H
+#define MK_PLUGIN_H
+
+#include <monkey/monkey.h>
+#include <monkey/mk_kernel.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_socket.h>
+#include <monkey/mk_header.h>
+#include <monkey/mk_http_status.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_info.h>
+#include <monkey/mk_plugin_net.h>
+#include <monkey/mk_core.h>
+
+#define MK_PLUGIN_ERROR -1 /* plugin execution error */
+#define MK_PLUGIN_
+
+/* Plugin: Stages */
+#define MK_PLUGIN_STAGE_10 (4) /* Connection just accept()ed */
+#define MK_PLUGIN_STAGE_20 (8) /* HTTP Request arrived */
+#define MK_PLUGIN_STAGE_30 (16) /* Object handler */
+#define MK_PLUGIN_STAGE_40 (32) /* Content served */
+#define MK_PLUGIN_STAGE_50 (64) /* Conection ended */
+
+/* Plugin: Network type */
+#define MK_PLUGIN_NETWORK_LAYER (128)
+#define MK_PLUGIN_STAGE (256)
+
+/* Return values */
+#define MK_PLUGIN_RET_NOT_ME -1
+#define MK_PLUGIN_RET_CONTINUE 100
+#define MK_PLUGIN_RET_END 200
+#define MK_PLUGIN_RET_CLOSE_CONX 300
+#define MK_PLUGIN_HEADER_EXTRA_ROWS 18
+
+/* Plugin types */
+#define MK_PLUGIN_STATIC 0 /* built-in into core */
+#define MK_PLUGIN_DYNAMIC 1 /* shared library */
+
+/* Plugin Flags */
+#define MK_PLUGIN_THREAD 1 /* It runs in a Monkey coroutine/thread */
+
+/*
+ * Event return values
+ * -------------------
+ * Any plugin can hook to any socket event, when a worker thread receives
+ * a socket event through epoll(), it will check first the plugins hooks
+ * before return the control to Monkey core.
+ */
+
+ /* The plugin request to the caller to continue invoking next plugins */
+#define MK_PLUGIN_RET_EVENT_NEXT -300
+
+/* The plugin has taken some action and no other plugin should go
+ * over the event in question, return as soon as possible
+ */
+#define MK_PLUGIN_RET_EVENT_OWNED -400
+
+/* The plugin request to finalize the session request */
+#define MK_PLUGIN_RET_EVENT_CLOSE -500
+
+/* The plugin request to the caller skip event hooks */
+#define MK_PLUGIN_RET_EVENT_CONTINUE -600
+
+struct mk_plugin;
+
+/* API functions exported to plugins */
+struct plugin_api
+{
+ /* socket functions */
+ int (*socket_cork_flag) (int, int);
+ int (*socket_reset) (int);
+ int (*socket_set_tcp_fastopen) (int);
+ int (*socket_set_tcp_nodelay) (int);
+ int (*socket_set_tcp_reuseport) (int);
+ int (*socket_connect) (char *, int, int);
+ int (*socket_open) (char *, int);
+ int (*socket_set_nonblocking) (int);
+ int (*socket_create) ();
+ int (*socket_close) (int);
+ int (*socket_read) (int, void *, int);
+ int (*socket_send_file) (int, int, off_t *, size_t);
+ int (*socket_ip_str) (int, char **, int, unsigned long *);
+
+ /* Async Network */
+ struct mk_net_connection *(*net_conn_create) (char *, int);
+
+ struct mk_server_config *config;
+ struct mk_list *plugins;
+
+ /* Error helper */
+ void (*_error) (int, const char *, ...) PRINTF_WARNINGS(2,3);
+
+ /* HTTP request function */
+ int (*http_request_end) (struct mk_plugin *plugin,
+ struct mk_http_session *cs, int close);
+ int (*http_request_error) (int, struct mk_http_session *,
+ struct mk_http_request *, struct mk_plugin *);
+
+ /* memory functions */
+ void *(*mem_alloc) (const size_t size);
+ void *(*mem_alloc_z) (const size_t size);
+ void *(*mem_realloc) (void *, const size_t size);
+ void (*mem_free) (void *);
+ void (*pointer_set) (mk_ptr_t *, char *);
+ void (*pointer_print) (mk_ptr_t);
+ char *(*pointer_to_buf) (mk_ptr_t);
+
+ /* string functions */
+ int (*str_itop) (uint64_t, mk_ptr_t *);
+ int (*str_search) (const char *, const char *, int);
+ int (*str_search_n) (const char *, const char *, int, int);
+ int (*str_char_search) (const char *, int, int);
+
+ char *(*str_build) (char **, unsigned long *, const char *, ...) PRINTF_WARNINGS(3,4);
+ char *(*str_dup) (const char *);
+ char *(*str_copy_substr) (const char *, int, int);
+ struct mk_list *(*str_split_line) (const char *);
+ void (*str_split_free) (struct mk_list *);
+
+ /* file functions */
+ char *(*file_to_buffer) (const char *);
+ int (*file_get_info) (const char *, struct file_info *, int);
+
+ /* header */
+ int (*header_prepare) (struct mk_plugin *,
+ struct mk_http_session *,
+ struct mk_http_request *);
+ struct mk_http_header *(*header_get) (int, struct mk_http_request *,
+ const char *, unsigned int);
+ int (*header_add) (struct mk_http_request *, char *row, int len);
+ void (*header_set_http_status) (struct mk_http_request *, int);
+
+ /* channel / stream handling */
+ struct mk_stream *(*stream_new) (int, struct mk_channel *, void *, size_t,
+ void *,
+ void (*) (struct mk_stream *),
+ void (*) (struct mk_stream *, long),
+ void (*) (struct mk_stream *, int));
+ struct mk_channel *(*channel_new) (int, int);
+ int (*channel_flush) (struct mk_channel *);
+ int (*channel_write) (struct mk_channel *, size_t *);
+ void (*channel_append_stream) (struct mk_channel *, struct mk_stream *stream);
+ void (*stream_set) (struct mk_stream *, int, struct mk_channel *, void *, size_t,
+ void *,
+ void (*) (struct mk_stream *),
+ void (*) (struct mk_stream *, long),
+ void (*) (struct mk_stream *, int));
+
+ /* iov functions */
+ struct mk_iov *(*iov_create) (int, int);
+ struct mk_iov *(*iov_realloc) (struct mk_iov *, int);
+ void (*iov_free) (struct mk_iov *);
+ void (*iov_free_marked) (struct mk_iov *);
+ int (*iov_add) (struct mk_iov *, void *, int, int);
+ int (*iov_set_entry) (struct mk_iov *, void *, int, int, int);
+ ssize_t (*iov_send) (int, struct mk_iov *);
+ void (*iov_print) (struct mk_iov *);
+
+ /* plugin functions */
+ void *(*plugin_load_symbol) (void *, const char *);
+
+ /* core events mechanism */
+ struct mk_event_loop *(*ev_loop_create) (int);
+ struct mk_event_fdt *(*ev_get_fdt) ();
+ int (*ev_add) (struct mk_event_loop *, int, int, uint32_t, void *);
+ int (*ev_del) (struct mk_event_loop *, struct mk_event *);
+ int (*ev_timeout_create) (struct mk_event_loop *, time_t, long, void *);
+ int (*ev_channel_create) (struct mk_event_loop *, int *, int *, void *);
+ int (*ev_wait) (struct mk_event_loop *);
+ char *(*ev_backend) ();
+
+ /* Mime type */
+ struct mk_mimetype *(*mimetype_lookup) (struct mk_server *, char *);
+
+ /* configuration reader functions */
+ struct mk_rconf *(*config_open) (const char *);
+ struct mk_rconf *(*config_create) (const char *);
+ void (*config_free) (struct mk_rconf *);
+ struct mk_rconf_section *(*config_section_get) (struct mk_rconf *,
+ const char *);
+ void *(*config_section_get_key) (struct mk_rconf_section *, char *, int);
+
+ /* Scheduler */
+ struct mk_event_loop *(*sched_loop)();
+ int (*sched_remove_client) (int, struct mk_server *);
+ struct mk_sched_conn *(*sched_get_connection)(struct mk_sched_worker *,
+ int);
+ void (*sched_event_free) (struct mk_event *);
+ struct mk_sched_worker *(*sched_worker_info)();
+
+ /* worker's functions */
+ int (*worker_spawn) (void (*func) (void *), void *, pthread_t *);
+ int (*worker_rename) (const char *);
+
+ /* event's functions */
+ int (*event_add) (int, int, struct mk_plugin *, unsigned int);
+ int (*event_del) (int);
+ struct plugin_event *(*event_get) (int);
+
+ int (*event_socket_change_mode) (int, int, unsigned int);
+
+ /* Time utils functions */
+ int (*time_unix) ();
+ int (*time_to_gmt) (char **, time_t);
+ mk_ptr_t *(*time_human) ();
+
+#ifdef TRACE
+ void (*trace)(const char *, int, const char *, char *, int, const char *, ...);
+ int (*errno_print) (int);
+#endif
+ void (*stacktrace)(void);
+
+ /* kernel interfaces */
+ int (*kernel_version) ();
+ int (*kernel_features_print) (char *, size_t, struct mk_server *);
+
+ /* Handler */
+ struct mk_vhost_handler_param *(*handler_param_get)(int, struct mk_list *);
+
+#ifdef JEMALLOC_STATS
+ int (*je_mallctl) (const char *, void *, size_t *, void *, size_t);
+#endif
+};
+
+extern struct plugin_api *api;
+
+struct mk_plugin_event
+{
+ struct mk_event event; /* event loop context */
+ struct mk_plugin *handler; /* plugin owner/handler */
+};
+
+struct mk_plugin_stage;
+
+/* Info: used to register a plugin */
+struct mk_plugin {
+ int flags;
+
+ /* Identification */
+ const char *shortname;
+ const char *name;
+ const char *version;
+
+ /* Hooks and capabilities */
+ unsigned int hooks;
+ char capabilities;
+
+ struct plugin_api *api;
+
+ /* Init / Exit */
+ int (*init_plugin) (struct mk_plugin *, char *);
+ int (*exit_plugin) (struct mk_plugin *);
+
+ /* Init Levels */
+ int (*master_init) (struct mk_server *);
+ void (*worker_init) (struct mk_server *);
+
+ /* Callback references for plugin type */
+ struct mk_plugin_network *network; /* MK_NETWORK_LAYER */
+ struct mk_plugin_stage *stage; /* MK_PLUGIN_STAGE */
+
+ /* Internal use variables */
+ void *handler; /* DSO handler */
+ char *path; /* Path for dynamic plugin */
+ pthread_key_t *thread_key; /* Worker thread key */
+ struct mk_list _head; /* Link to config->plugins list */
+ struct mk_list stage_list; /* Stages head list */
+
+ /* Load type: MK_PLUGIN_STATIC / MK_PLUGIN_DYNAMIC */
+ int load_type;
+
+ /* Sever context */
+ struct mk_server *server_ctx;
+};
+
+struct mk_plugin_stage {
+ int (*stage10) (int);
+ int (*stage20) (struct mk_http_session *, struct mk_http_request *);
+ int (*stage30) (struct mk_plugin *, struct mk_http_session *,
+ struct mk_http_request *, int, struct mk_list *);
+ void (*stage30_thread) (struct mk_plugin *, struct mk_http_session *,
+ struct mk_http_request *, int, struct mk_list *);
+ int (*stage30_hangup) (struct mk_plugin *, struct mk_http_session *,
+ struct mk_http_request *);
+ int (*stage40) (struct mk_http_session *, struct mk_http_request *);
+ int (*stage50) (int);
+
+ /* Just a reference to the parent plugin */
+ struct mk_plugin *plugin;
+
+ /* Only used when doing direct mapping from config->stageN_handler; */
+ struct mk_list _head;
+
+ struct mk_list _parent_head;
+};
+
+
+void mk_plugin_api_init(struct mk_server *server);
+void mk_plugin_load_all(struct mk_server *server);
+void mk_plugin_exit_all(struct mk_server *server);
+void mk_plugin_exit_worker();
+
+void mk_plugin_event_init_list();
+
+int mk_plugin_stage_run(unsigned int stage,
+ unsigned int socket,
+ struct mk_sched_conn *conx,
+ struct mk_http_session *cs, struct mk_http_request *sr);
+
+void mk_plugin_core_process(struct mk_server *server);
+void mk_plugin_core_thread(struct mk_server *server);
+
+void mk_plugin_preworker_calls(struct mk_server *server);
+
+/* Plugins events interface */
+int mk_plugin_event_add(int socket, int mode,
+ struct mk_plugin *handler,
+ unsigned int behavior);
+int mk_plugin_event_del(int socket);
+struct plugin_event *mk_plugin_event_get(int socket);
+
+int mk_plugin_event_socket_change_mode(int socket, int mode, unsigned int behavior);
+
+struct mk_plugin *mk_plugin_load(int type, const char *shortname,
+ void *data, struct mk_server *server);
+
+void *mk_plugin_load_symbol(void *handler, const char *symbol);
+int mk_plugin_http_error(int http_status, struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ struct mk_plugin *plugin);
+int mk_plugin_http_request_end(struct mk_plugin *plugin,
+ struct mk_http_session *cs, int close);
+
+/* Register functions */
+struct plugin *mk_plugin_register(struct plugin *p);
+void mk_plugin_unregister(struct mk_plugin *p);
+
+struct plugin *mk_plugin_alloc(void *handler, const char *path);
+void mk_plugin_free(struct mk_plugin *p);
+
+int mk_plugin_time_now_unix(struct mk_server *server);
+mk_ptr_t *mk_plugin_time_now_human(struct mk_server *server);
+
+int mk_plugin_sched_remove_client(int socket, struct mk_server *server);
+
+
+int mk_plugin_header_prepare(struct mk_plugin *plugin,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr);
+
+int mk_plugin_header_add(struct mk_http_request *sr, char *row, int len);
+int mk_plugin_header_get(struct mk_http_request *sr,
+ mk_ptr_t query,
+ mk_ptr_t *result);
+
+struct mk_sched_worker *mk_plugin_sched_get_thread_conf();
+struct mk_plugin *mk_plugin_cap(char cap, struct mk_server *server);
+struct mk_plugin *mk_plugin_lookup(char *shortname, struct mk_server *server);
+
+void mk_plugin_load_static(struct mk_server *server);
+struct mk_vhost_handler_param *mk_handler_param_get(int id,
+ struct mk_list *params);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_plugin_net.h b/fluent-bit/lib/monkey/include/monkey/mk_plugin_net.h
new file mode 100644
index 000000000..e60c74cf7
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_plugin_net.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_PLUGIN_NET_H
+#define MK_PLUGIN_NET_H
+
+#include <monkey/mk_core.h>
+
+/*
+ * Network plugin: a plugin that provides a network layer, eg: plain
+ * sockets or SSL.
+ */
+struct mk_plugin;
+struct mk_plugin_network {
+ int (*read) (struct mk_plugin *, int, void *, int);
+ int (*write) (struct mk_plugin *, int, const void *, size_t);
+ int (*writev) (struct mk_plugin *, int, struct mk_iov *);
+ int (*close) (struct mk_plugin *, int);
+ int (*send_file) (struct mk_plugin *, int, int, off_t *, size_t);
+ int buffer_size;
+ struct mk_plugin *plugin;
+};
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_plugin_stage.h b/fluent-bit/lib/monkey/include/monkey/mk_plugin_stage.h
new file mode 100644
index 000000000..5ad4b73ec
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_plugin_stage.h
@@ -0,0 +1,99 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_PLUGIN_STAGE_H
+#define MK_PLUGIN_STAGE_H
+
+static inline int mk_plugin_stage_run_10(int socket, struct mk_server *server)
+{
+ int ret;
+ struct mk_list *head;
+ struct mk_plugin_stage *stage;
+
+ mk_list_foreach(head, &server->stage10_handler) {
+ stage = mk_list_entry(head, struct mk_plugin_stage, _head);
+ ret = stage->stage10(socket);
+ switch (ret) {
+ case MK_PLUGIN_RET_CLOSE_CONX:
+ MK_TRACE("return MK_PLUGIN_RET_CLOSE_CONX");
+ return MK_PLUGIN_RET_CLOSE_CONX;
+ }
+ }
+
+ return -1;
+}
+
+static inline int mk_plugin_stage_run_20(struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ struct mk_server *server)
+{
+ int ret;
+ struct mk_list *head;
+ struct mk_plugin_stage *stage;
+
+ mk_list_foreach(head, &server->stage20_handler) {
+ stage = mk_list_entry(head, struct mk_plugin_stage, _head);
+ ret = stage->stage20(cs, sr);
+ switch (ret) {
+ case MK_PLUGIN_RET_CLOSE_CONX:
+ MK_TRACE("return MK_PLUGIN_RET_CLOSE_CONX");
+ return MK_PLUGIN_RET_CLOSE_CONX;
+ }
+ }
+
+ return -1;
+}
+
+static inline int mk_plugin_stage_run_40(struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ struct mk_server *server)
+{
+ struct mk_list *head;
+ struct mk_plugin_stage *stage;
+
+ mk_list_foreach(head, &server->stage40_handler) {
+ stage = mk_list_entry(head, struct mk_plugin_stage, _head);
+ stage->stage40(cs, sr);
+ }
+
+ return -1;
+}
+
+static inline int mk_plugin_stage_run_50(int socket, struct mk_server *server)
+{
+ int ret;
+
+ struct mk_list *head;
+ struct mk_plugin_stage *stage;
+
+ mk_list_foreach(head, &server->stage50_handler) {
+ stage = mk_list_entry(head, struct mk_plugin_stage, _head);
+ ret = stage->stage50(socket);
+ switch (ret) {
+ case MK_PLUGIN_RET_NOT_ME:
+ break;
+ case MK_PLUGIN_RET_CONTINUE:
+ return MK_PLUGIN_RET_CONTINUE;
+ }
+ }
+
+ return -1;
+}
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_scheduler.h b/fluent-bit/lib/monkey/include/monkey/mk_scheduler.h
new file mode 100644
index 000000000..f749cba54
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_scheduler.h
@@ -0,0 +1,353 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <monkey/mk_info.h>
+#include <monkey/mk_tls.h>
+
+#include <monkey/mk_core.h>
+#include <monkey/mk_server.h>
+#include <monkey/mk_stream.h>
+#include <monkey/mk_net.h>
+
+#ifndef MK_SCHEDULER_H
+#define MK_SCHEDULER_H
+
+#define MK_SCHED_CONN_TIMEOUT -1
+#define MK_SCHED_CONN_CLOSED -2
+
+#define MK_SCHED_SIGNAL_DEADBEEF 0xDEADBEEF
+#define MK_SCHED_SIGNAL_FREE_ALL 0xFFEE0000
+#define MK_SCHED_SIGNAL_EVENT_LOOP_BREAK 0xEEFFAACC
+
+#ifdef _WIN32
+ /* The pid field in the mk_sched_worker structure is ignored in platforms other than
+ * linux and mac os so it can be safely plugged in this meaningless way
+ */
+ typedef uint64_t pid_t;
+#endif
+
+/*
+ * Scheduler balancing mode:
+ *
+ * - Fair Balancing: use a single socket and upon accept
+ * new connections, lookup the less loaded thread and
+ * assign the socket to that specific epoll queue.
+ *
+ * - ReusePort: Use new Linux Kernel 3.9 feature that
+ * allows thread to share binded address on a lister
+ * socket. We let the Kernel to decide how to balance.
+ */
+#define MK_SCHEDULER_FAIR_BALANCING 0
+#define MK_SCHEDULER_REUSEPORT 1
+
+/*
+ * Thread-scope structure/variable that holds the Scheduler context for the
+ * worker (or thread) in question.
+ */
+struct mk_sched_worker
+{
+ /* The event loop on this scheduler thread */
+ struct mk_event_loop *loop;
+
+ unsigned long long accepted_connections;
+ unsigned long long closed_connections;
+ unsigned long long over_capacity;
+
+ /*
+ * The timeout queue represents client connections that
+ * have not initiated it requests or the request status
+ * is incomplete. This linear lists allows the scheduler
+ * to perform a fast check upon every timeout.
+ */
+ struct mk_list timeout_queue;
+
+ short int idx;
+ unsigned char initialized;
+
+ pthread_t tid;
+
+ pid_t pid;
+
+ /* store the memory page size (_SC_PAGESIZE) */
+ unsigned int mem_pagesize;
+
+ struct mk_http_session *request_handler;
+
+
+ struct mk_list event_free_queue;
+
+ /*
+ * This variable is used to signal the active workers,
+ * just available because of ULONG_MAX bug described
+ * on mk_scheduler.c .
+ */
+ int signal_channel_r;
+ int signal_channel_w;
+
+ /* If using REUSEPORT, this points to the list of listeners */
+ struct mk_list *listeners;
+
+ /*
+ * List head for finished requests that need to be cleared after each
+ * event loop round.
+ */
+ struct mk_list requests_done;
+
+ /* List of co-routine threads */
+ struct mk_list threads;
+ struct mk_list threads_purge;
+
+};
+
+
+/* Every connection in the server is represented by this structure */
+struct mk_sched_conn
+{
+ struct mk_event event; /* event loop context */
+ int status; /* connection status */
+ uint32_t properties;
+ char is_timeout_on; /* registered to timeout queue? */
+ time_t arrive_time; /* arrive time */
+ struct mk_sched_handler *protocol; /* protocol handler */
+ struct mk_server_listen *server_listen;
+ struct mk_plugin_network *net; /* I/O network layer */
+ struct mk_channel channel; /* stream channel */
+ struct mk_list timeout_head; /* link to the timeout queue */
+ void *data; /* optional ref for protocols */
+};
+
+/* Protocol capabilities */
+#define MK_SCHED_CONN_CAP(conn) conn->protocol->capabilities
+
+/* Connection properties */
+#define MK_SCHED_CONN_PROP(conn) conn->server_listen->listen->flags
+
+/*
+ * It defines a Handler for a connection in questions. This struct
+ * is used inside mk_sched_conn to define which protocol/handler
+ * needs to take care of every action.
+ */
+struct mk_sched_handler
+{
+ /*
+ * Protocol definition and callbacks:
+ *
+ * - name : the protocol handler name.
+ * - cb_read : callback triggered when there is data on the socket to read.
+ * - cb_close: callback triggered when the socket channel have been closed.
+ * - cb_done : callback triggered when the whole channel data have been
+ * written. This callback is optional. The return value of this
+ * callback indicate to the scheduler of the channel should be
+ * closed or not: -1 = close, 0 = leave it open and wait for more
+ * data.
+ */
+ const char *name;
+ int (*cb_read) (struct mk_sched_conn *, struct mk_sched_worker *,
+ struct mk_server *);
+ int (*cb_close) (struct mk_sched_conn *, struct mk_sched_worker *, int,
+ struct mk_server *);
+ int (*cb_done) (struct mk_sched_conn *, struct mk_sched_worker *,
+ struct mk_server *);
+ int (*cb_upgrade) (void *, void *, struct mk_server *);
+
+ /*
+ * This extra field is a small hack. The scheduler connection context
+ * contains information about the connection, and setting this field
+ * will let the scheduler allocate some extra memory bytes on the
+ * context memory reference:
+ *
+ * e.g:
+ *
+ * t_size = (sizeof(struct mk_sched_conn) + sched_extra_size);
+ * struct sched_conn *conn = malloc(t_size);
+ *
+ * This is useful for protocol or handlers where a socket connection
+ * represents one unique instance, the use case is HTTP, e.g:
+ *
+ * HTTP : 1 connection = 1 client (one request at a time)
+ * HTTP2: 1 connection = 1 client with multiple-framed requests
+ *
+ * The purpose is to avoid protocol handlers to perform more memory
+ * allocations and connection lookups the sched context is good enough
+ * to help on this, e.g:
+ *
+ * t_size = (sizeof(struct mk_sched_conn) + (sizeof(struct mk_http_session);
+ * conn = malloc(t_size);
+ */
+ int sched_extra_size;
+ char capabilities;
+};
+
+struct mk_sched_notif {
+ struct mk_event event;
+};
+
+/* Struct under thread context */
+struct mk_sched_thread_conf {
+ struct mk_server *server;
+};
+
+struct mk_sched_worker_cb {
+ void (*cb_func) (void *);
+ void *data;
+ struct mk_list _head;
+};
+
+/*
+ * All data required by the Scheduler interface is mapped inside this
+ * struct which is later linked into config->scheduler_ctx.
+ */
+struct mk_sched_ctx {
+ /* Array of sched_worker */
+ struct mk_sched_worker *workers;
+};
+
+
+struct mk_sched_worker *mk_sched_next_target(struct mk_server *server);
+int mk_sched_init(struct mk_server *server);
+int mk_sched_exit(struct mk_server *server);
+
+int mk_sched_launch_thread(struct mk_server *server, pthread_t *tout);
+
+void *mk_sched_launch_epoll_loop(void *thread_conf);
+struct mk_sched_worker *mk_sched_get_handler_owner(void);
+
+static inline struct rb_root *mk_sched_get_request_list()
+{
+ return MK_TLS_GET(mk_tls_sched_cs);
+}
+
+static inline struct mk_sched_worker *mk_sched_get_thread_conf()
+{
+ return MK_TLS_GET(mk_tls_sched_worker_node);
+}
+
+static inline struct mk_event_loop *mk_sched_loop()
+{
+ struct mk_sched_worker *w;
+
+ w = MK_TLS_GET(mk_tls_sched_worker_node);
+ return w->loop;
+}
+
+void mk_sched_update_thread_status(struct mk_sched_worker *sched,
+ int active, int closed);
+
+int mk_sched_drop_connection(struct mk_sched_conn *conn,
+ struct mk_sched_worker *sched,
+ struct mk_server *server);
+
+int mk_sched_check_timeouts(struct mk_sched_worker *sched,
+ struct mk_server *server);
+
+
+struct mk_sched_conn *mk_sched_add_connection(int remote_fd,
+ struct mk_server_listen *listener,
+ struct mk_sched_worker *sched,
+ struct mk_server *server);
+
+int mk_sched_remove_client(struct mk_sched_conn *conn,
+ struct mk_sched_worker *sched,
+ struct mk_server *server);
+
+struct mk_sched_conn *mk_sched_get_connection(struct mk_sched_worker
+ *sched, int remote_fd);
+int mk_sched_update_conn_status(struct mk_sched_worker *sched, int remote_fd,
+ int status);
+int mk_sched_sync_counters();
+void mk_sched_worker_free(struct mk_server *server);
+
+struct mk_sched_handler *mk_sched_handler_cap(char cap);
+
+/* Event handlers */
+int mk_sched_event_read(struct mk_sched_conn *conn,
+ struct mk_sched_worker *sched,
+ struct mk_server *server);
+
+int mk_sched_event_write(struct mk_sched_conn *conn,
+ struct mk_sched_worker *sched,
+ struct mk_server *server);
+
+
+int mk_sched_event_close(struct mk_sched_conn *conn,
+ struct mk_sched_worker *sched,
+ int type, struct mk_server *server);
+
+void mk_sched_event_free(struct mk_event *event);
+
+
+static inline void mk_sched_event_free_all(struct mk_sched_worker *sched)
+{
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_event *event;
+
+ mk_list_foreach_safe(head, tmp, &sched->event_free_queue) {
+ event = mk_list_entry(head, struct mk_event, _head);
+ mk_list_del(&event->_head);
+ mk_mem_free(event);
+ }
+}
+
+static inline void mk_sched_conn_timeout_add(struct mk_sched_conn *conn,
+ struct mk_sched_worker *sched)
+{
+ if (conn->is_timeout_on == MK_FALSE) {
+ mk_list_add(&conn->timeout_head, &sched->timeout_queue);
+ conn->is_timeout_on = MK_TRUE;
+ }
+}
+
+static inline void mk_sched_conn_timeout_del(struct mk_sched_conn *conn)
+{
+ if (conn->is_timeout_on == MK_TRUE) {
+ mk_list_del(&conn->timeout_head);
+ conn->is_timeout_on = MK_FALSE;
+ }
+}
+
+
+#define mk_sched_conn_read(conn, buf, s) \
+ conn->net->read(conn->net->plugin, conn->event.fd, buf, s)
+#define mk_sched_conn_write(ch, buf, s) \
+ mk_net_conn_write(ch, buf, s)
+#define mk_sched_conn_writev(ch, iov) \
+ ch->io->writev(ch->io->plugin, ch->fd, iov)
+#define mk_sched_conn_sendfile(ch, f_fd, f_offs, f_count) \
+ ch->io->send_file(ch->io->plugin, ch->fd, f_fd, f_offs, f_count)
+
+#define mk_sched_switch_protocol(conn, cap) \
+ conn->protocol = mk_sched_handler_cap(cap)
+
+int mk_sched_worker_cb_add(struct mk_server *server,
+ void (*cb_func) (void *),
+ void *data);
+
+void mk_sched_worker_cb_free(struct mk_server *server);
+int mk_sched_send_signal(struct mk_sched_worker *worker, uint64_t val);
+int mk_sched_broadcast_signal(struct mk_server *server, uint64_t val);
+int mk_sched_workers_join(struct mk_server *server);
+int mk_sched_threads_purge(struct mk_sched_worker *sched);
+int mk_sched_threads_destroy_all(struct mk_sched_worker *sched);
+int mk_sched_threads_destroy_conn(struct mk_sched_worker *sched,
+ struct mk_sched_conn *conn);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_scheduler_tls.h b/fluent-bit/lib/monkey/include/monkey/mk_scheduler_tls.h
new file mode 100644
index 000000000..e645684bd
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_scheduler_tls.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_SCHEDULER_TLS_H
+#define MK_SCHEDULER_TLS_H
+
+#ifdef MK_HAVE_C_TLS /* Use Compiler Thread Local Storage (TLS) */
+
+__thread struct rb_root *mk_tls_sched_cs;
+__thread struct mk_list *mk_tls_sched_cs_incomplete;
+__thread struct mk_sched_notif *mk_tls_sched_worker_notif;
+__thread struct mk_sched_worker *mk_tls_sched_worker_node;
+
+#else
+
+pthread_key_t mk_tls_sched_cs;
+pthread_key_t mk_tls_sched_cs_incomplete;
+pthread_key_t mk_tls_sched_worker_notif;
+pthread_key_t mk_tls_sched_worker_node;
+
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_server.h b/fluent-bit/lib/monkey/include/monkey/mk_server.h
new file mode 100644
index 000000000..f84a7d632
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_server.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_SERVER_H
+#define MK_SERVER_H
+
+#define _GNU_SOURCE
+#include <monkey/mk_socket.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_core.h>
+
+#define MK_SERVER_SIGNAL_START 0xEEEEEEEE
+#define MK_SERVER_SIGNAL_STOP 0xDDDDDDDD
+
+struct mk_server_listen
+{
+ struct mk_event event;
+
+ int server_fd;
+ struct mk_plugin *network;
+ struct mk_sched_handler *protocol;
+ struct mk_config_listener *listen;
+ struct mk_list _head;
+};
+
+struct mk_server_timeout {
+ struct mk_event event;
+};
+
+extern pthread_key_t mk_server_fifo_key;
+
+#ifdef MK_HAVE_C_TLS
+extern __thread struct mk_list *server_listen;
+extern __thread struct mk_server_timeout *server_timeout;
+#endif
+
+struct mk_sched_worker;
+
+int mk_socket_set_cork_flag(int fd, int state);
+
+static inline int mk_server_cork_flag(int fd, int state)
+{
+ return mk_socket_set_cork_flag(fd, state);
+}
+
+struct mk_server *mk_server_create();
+int mk_server_listen_check(struct mk_server_listen *listen, int server_fd);
+
+void mk_server_listen_free();
+struct mk_list *mk_server_listen_init(struct mk_server *server);
+
+unsigned int mk_server_capacity(struct mk_server *server);
+void mk_server_launch_workers(struct mk_server *server);
+void mk_server_worker_loop(struct mk_server *server);
+void mk_server_loop_balancer(struct mk_server *server);
+void mk_server_worker_loop(struct mk_server *server);
+void mk_server_loop(struct mk_server *server);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_server_tls.h b/fluent-bit/lib/monkey/include/monkey/mk_server_tls.h
new file mode 100644
index 000000000..1e47ee1b1
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_server_tls.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_SERVER_TLS_H
+#define MK_SERVER_TLS_H
+
+#ifdef MK_HAVE_C_TLS /* Use Compiler Thread Local Storage (TLS) */
+
+__thread struct mk_list *mk_tls_server_listen;
+__thread struct mk_server_timeout *mk_tls_server_timeout;
+
+#else
+
+pthread_key_t mk_tls_server_listen;
+pthread_key_t mk_tls_server_timeout;
+
+#endif
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_socket.h b/fluent-bit/lib/monkey/include/monkey/mk_socket.h
new file mode 100644
index 000000000..67d290f08
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_socket.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_SOCKET_H
+#define MK_SOCKET_H
+
+#include <fcntl.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <afunix.h>
+#else
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/un.h>
+#endif
+
+#include <monkey/mk_core.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_info.h>
+
+#ifndef SOCK_NONBLOCK
+#define SOCK_NONBLOCK 04000
+#endif
+
+#ifndef SO_REUSEPORT
+#define SO_REUSEPORT 15
+#endif
+
+/*
+ * TCP_FASTOPEN: as this is a very new option in the Linux Kernel, the value is
+ * not yet exported and can be missing, lets make sure is available for all
+ * cases:
+ *
+ * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=1046716368979dee857a2b8a91c4a8833f21b9cb
+ */
+#ifndef TCP_FASTOPEN
+#define TCP_FASTOPEN 23
+#endif
+
+#define TCP_CORK_ON 1
+#define TCP_CORK_OFF 0
+
+#define TCP_CORKING_PATH "/proc/sys/net/ipv4/tcp_autocorking"
+
+int mk_socket_set_cork_flag(int fd, int state);
+int mk_socket_set_tcp_fastopen(int sockfd);
+int mk_socket_set_tcp_nodelay(int sockfd);
+int mk_socket_set_tcp_defer_accept(int sockfd);
+int mk_socket_set_tcp_reuseport(int sockfd);
+int mk_socket_set_nonblocking(int sockfd);
+
+int mk_socket_create(int domain, int type, int protocol);
+int mk_socket_connect(char *host, int port, int async);
+int mk_socket_open(char *path, int async);
+int mk_socket_reset(int socket);
+int mk_socket_bind(int socket_fd, const struct sockaddr *addr,
+ socklen_t addrlen, int backlog, struct mk_server *server);
+int mk_socket_server(char *port, char *listen_addr,
+ int reuse_port, struct mk_server *server);
+int mk_socket_ip_str(int socket_fd, char **buf, int size, unsigned long *len);
+int mk_socket_accept(int server_fd);
+
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_static_plugins.h.in b/fluent-bit/lib/monkey/include/monkey/mk_static_plugins.h.in
new file mode 100644
index 000000000..33e3447bc
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_static_plugins.h.in
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2016 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_STATIC_PLUGINS_H
+#define MK_STATIC_PLUGINS_H
+
+#include <monkey/mk_core.h>
+#include <monkey/mk_plugin.h>
+#include <monkey/mk_plugin_net.h>
+
+@STATIC_PLUGINS_DECL@
+
+static int mk_static_plugin_attach(struct mk_list *plugins,
+ struct mk_plugin *plugin)
+{
+ struct mk_plugin *instance;
+ struct mk_plugin_network *network;
+
+ instance = mk_mem_alloc_z(sizeof(struct mk_plugin));
+
+ if (instance == NULL) {
+ return MK_FALSE;
+ }
+
+ memcpy(instance, plugin, sizeof(struct mk_plugin));
+
+ network = mk_mem_alloc(sizeof(struct mk_plugin_network));
+
+ if (network == NULL) {
+ mk_mem_free(instance);
+
+ return MK_FALSE;
+ }
+
+ memcpy(network, plugin->network, sizeof(struct mk_plugin_network));
+
+ instance->network = network;
+
+ mk_list_add(&instance->_head, plugins);
+
+ return MK_TRUE;
+}
+
+static void mk_static_plugins(struct mk_list *plugins)
+{
+ struct mk_plugin *p;
+
+ (void) p;
+
+ @STATIC_PLUGINS_INIT@
+}
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_stream.h b/fluent-bit/lib/monkey/include/monkey/mk_stream.h
new file mode 100644
index 000000000..9dc81ba8e
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_stream.h
@@ -0,0 +1,398 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_STREAM_H
+#define MK_STREAM_H
+
+#include <monkey/mk_core.h>
+#include <monkey/mk_plugin_net.h>
+
+/*
+ * Stream types: each stream can have a different
+ * source of information and for hence it handler
+ * may need to be different for each cases.
+ */
+#define MK_STREAM_RAW 0 /* raw data from buffer */
+#define MK_STREAM_IOV 1 /* mk_iov struct */
+#define MK_STREAM_FILE 2 /* opened file */
+#define MK_STREAM_SOCKET 3 /* socket, scared.. */
+
+/* Channel return values for write event */
+#define MK_CHANNEL_OK 0 /* channel is ok (channel->status) */
+#define MK_CHANNEL_DONE 1 /* channel consumed all streams */
+#define MK_CHANNEL_ERROR 2 /* exception when flusing data */
+#define MK_CHANNEL_FLUSH 4 /* channel flushed some data */
+#define MK_CHANNEL_EMPTY 8 /* no streams available */
+#define MK_CHANNEL_BUSY 16 /* cannot write, busy (EAGAIN) */
+#define MK_CHANNEL_UNKNOWN 32 /* unhandled */
+
+/* Channel status */
+#define MK_CHANNEL_DISABLED 0 /* channel is sleeping */
+#define MK_CHANNEL_ENABLED 1 /* channel enabled, have some data */
+
+/*
+ * Channel types: by default the only channel supported
+ * is a direct write to the network layer.
+ */
+#define MK_CHANNEL_SOCKET 0
+
+/*
+ * A channel represents an end-point of a stream, for short
+ * where the stream data consumed and is send to. The channel
+ * knows how to read/write to a TCP connection through a
+ * defined network plugin.
+ */
+struct mk_channel {
+ int type;
+ int fd;
+ int status;
+
+ struct mk_event *event;
+ struct mk_plugin_network *io;
+ struct mk_list streams;
+ void *thread;
+};
+
+/* Stream input source */
+struct mk_stream_input {
+ int type; /* input type */
+ int fd; /* file descriptor (files) */
+ int dynamic;
+
+ size_t bytes_total; /* Total of data from the input */
+ off_t bytes_offset; /* Data already sent */
+
+ /*
+ * Based on the stream input type, 'data' could reference a RAW buffer
+ * or a mk_iov struct.
+ */
+ void *buffer;
+ void *context;
+
+ /* callbacks */
+ void (*cb_consumed)(struct mk_stream_input *, long);
+ void (*cb_finished)(struct mk_stream_input *);
+
+ struct mk_stream *stream; /* reference to parent stream */
+ struct mk_list _head; /* link to inputs stream list */
+};
+
+/*
+ * A stream holds a queue of components that refers to different
+ * data sources such as: static file, raw buffer, etc.
+ */
+struct mk_stream {
+ int preserve; /* preserve stream? (do not unlink) */
+ int encoding; /* some output encoding ? */
+ int dynamic; /* dynamic allocated ? */
+
+ size_t bytes_total; /* Total of data from stream_input */
+ off_t bytes_offset; /* Data already sent */
+
+ /* the outgoing channel, we do this for all streams */
+ struct mk_channel *channel;
+
+ /* Context the caller may want to reference with the stream (optional) */
+ void *context;
+
+ /* callbacks */
+ void (*cb_finished) (struct mk_stream *);
+ void (*cb_bytes_consumed) (struct mk_stream *, long);
+ void (*cb_exception) (struct mk_stream *, int);
+
+ /* Head of stream_input nodes */
+ struct mk_list inputs;
+
+ /* Link to the Channel parent */
+ struct mk_list _head;
+};
+
+int mk_stream_in_release(struct mk_stream_input *in);
+
+
+static inline int mk_channel_is_empty(struct mk_channel *channel)
+{
+ return mk_list_is_empty(&channel->streams);
+}
+
+static inline void mk_channel_append_stream(struct mk_channel *channel,
+ struct mk_stream *stream)
+{
+ mk_list_add(&stream->_head, &channel->streams);
+}
+
+static inline void mk_stream_append(struct mk_stream_input *in,
+ struct mk_stream *stream)
+{
+ mk_list_add(&in->_head, &stream->inputs);
+}
+
+static inline int mk_stream_input(struct mk_stream *stream,
+ struct mk_stream_input *in,
+ int type,
+ int fd,
+ void *buffer, size_t size,
+ off_t offset,
+ void (*cb_consumed) (struct mk_stream_input *, long),
+ void (*cb_finished)(struct mk_stream_input *))
+
+{
+ struct mk_iov *iov;
+
+ if (!in) {
+ in = mk_mem_alloc(sizeof(struct mk_stream_input));
+ if (!in) {
+ return -1;
+ }
+ in->dynamic = MK_TRUE;
+ }
+ else {
+ in->dynamic = MK_FALSE;
+ }
+
+ in->fd = fd;
+ in->type = type;
+ in->bytes_offset = offset;
+ in->buffer = buffer;
+ in->cb_consumed = cb_consumed;
+ in->cb_finished = cb_finished;
+ in->stream = stream;
+
+ if (type == MK_STREAM_IOV) {
+ iov = buffer;
+ in->bytes_total = iov->total_len;
+ }
+ else {
+ in->bytes_total = size;
+ }
+
+ mk_list_add(&in->_head, &stream->inputs);
+ return 0;
+}
+
+static inline int mk_stream_in_file(struct mk_stream *stream,
+ struct mk_stream_input *in, int fd,
+ size_t total_bytes,
+ off_t offset,
+ void (*cb_consumed)(struct mk_stream_input *, long),
+ void (*cb_finished)(struct mk_stream_input *))
+
+{
+ return mk_stream_input(stream,
+ in,
+ MK_STREAM_FILE,
+ fd,
+ NULL, total_bytes, offset,
+ cb_consumed, cb_finished);
+}
+
+static inline int mk_stream_in_iov(struct mk_stream *stream,
+ struct mk_stream_input *in,
+ struct mk_iov *iov,
+ void (*cb_consumed)(struct mk_stream_input *, long),
+ void (*cb_finished)(struct mk_stream_input *))
+
+{
+ return mk_stream_input(stream,
+ in,
+ MK_STREAM_IOV,
+ 0,
+ iov, 0, 0,
+ cb_consumed, cb_finished);
+}
+
+static inline int mk_stream_in_raw(struct mk_stream *stream,
+ struct mk_stream_input *in,
+ char *buf, size_t length,
+ void (*cb_consumed)(struct mk_stream_input *, long),
+ void (*cb_finished)(struct mk_stream_input *))
+{
+ return mk_stream_input(stream,
+ in,
+ MK_STREAM_RAW,
+ -1,
+ buf, length,
+ 0,
+ cb_consumed, cb_finished);
+}
+
+
+static inline void mk_stream_release(struct mk_stream *stream)
+{
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_stream_input *in;
+
+ /* Release any pending input */
+ mk_list_foreach_safe(head, tmp, &stream->inputs) {
+ in = mk_list_entry(head, struct mk_stream_input, _head);
+ mk_stream_in_release(in);
+ }
+
+ if (stream->cb_finished) {
+ stream->cb_finished(stream);
+ }
+
+ stream->channel = NULL;
+ mk_list_del(&stream->_head);
+ if (stream->dynamic == MK_TRUE) {
+ mk_mem_free(stream);
+ }
+}
+
+static inline
+struct mk_stream *mk_stream_set(struct mk_stream *stream,
+ struct mk_channel *channel,
+ void *data,
+ void (*cb_finished) (struct mk_stream *),
+ void (*cb_bytes_consumed) (struct mk_stream *, long),
+ void (*cb_exception) (struct mk_stream *, int))
+{
+ /*
+ * The copybuf stream type it's a lazy stream mechanism on which the
+ * stream it self and the buffer are allocated dynamically. It just
+ * exists as an optional interface that do not care too much about
+ * performance and aim to make things easier. The COPYBUF type is not
+ * used by Monkey core, at the moment the only caller is the CGI plugin.
+ */
+ if (!stream) {
+ stream = mk_mem_alloc(sizeof(struct mk_stream));
+ if (!stream) {
+ return NULL;
+ }
+ stream->dynamic = MK_TRUE;
+ }
+ else {
+ stream->dynamic = MK_FALSE;
+ }
+
+ stream->channel = channel;
+ stream->bytes_offset = 0;
+ stream->context = data;
+ stream->preserve = MK_FALSE;
+
+ /* callbacks */
+ stream->cb_finished = cb_finished;
+ stream->cb_bytes_consumed = cb_bytes_consumed;
+ stream->cb_exception = cb_exception;
+
+ mk_list_init(&stream->inputs);
+ mk_list_add(&stream->_head, &channel->streams);
+
+ return stream;
+}
+
+static inline void mk_stream_input_unlink(struct mk_stream_input *in)
+{
+ mk_list_del(&in->_head);
+}
+
+/* Mark a specific number of bytes served (just on successfull flush) */
+static inline void mk_stream_input_consume(struct mk_stream_input *in, long bytes)
+{
+#ifdef TRACE
+ char *fmt = NULL;
+
+ if (in->type == MK_STREAM_RAW) {
+ fmt = "[INPUT_RAW %p] bytes consumed %lu/%lu";
+ }
+ else if (in->type == MK_STREAM_IOV) {
+ fmt = "[INPUT_IOV %p] bytes consumed %lu/%lu";
+ }
+ else if (in->type == MK_STREAM_FILE) {
+ fmt = "[INPUT_FILE %p] bytes consumed %lu/%lu";
+ }
+ else if (in->type == MK_STREAM_SOCKET) {
+ fmt = "[INPUT_SOCK %p] bytes consumed %lu/%lu";
+ }
+ else if (in->type == MK_STREAM_COPYBUF) {
+ fmt = "[INPUT_CBUF %p] bytes consumed %lu/%lu";
+ }
+ else {
+ fmt = "[INPUT_UNKW %p] bytes consumed %lu/%lu";
+ }
+ MK_TRACE(fmt, in, bytes, in->bytes_total);
+#endif
+
+ in->bytes_total -= bytes;
+}
+
+#ifdef TRACE
+static inline void mk_channel_debug(struct mk_channel *channel)
+{
+ int i = 0;
+ int i_input;
+ struct mk_list *head;
+ struct mk_list *h_inputs;
+ struct mk_stream *stream;
+ struct mk_stream_input *in;
+
+ printf("\n*** Channel ***\n");
+ mk_list_foreach(head, &channel->streams) {
+ stream = mk_list_entry(head, struct mk_stream, _head);
+ i_input = 0;
+
+ mk_list_foreach(h_inputs, &stream->inputs) {
+ in = mk_list_entry(h_inputs, struct mk_stream_input, _head);
+ switch (in->type) {
+ case MK_STREAM_RAW:
+ printf(" in.%i] %p RAW : ", i_input, in);
+ break;
+ case MK_STREAM_IOV:
+ printf(" in.%i] %p IOV : ", i_input, in);
+ break;
+ case MK_STREAM_FILE:
+ printf(" in.%i] %p FILE : ", i_input, in);
+ break;
+ case MK_STREAM_SOCKET:
+ printf(" in.%i] %p SOCKET : ", i_input, in);
+ break;
+ case MK_STREAM_COPYBUF:
+ printf(" in.%i] %p COPYBUF: ", i_input, in);
+ break;
+ case MK_STREAM_EOF:
+ printf("%i) [%p] STREAM EOF : ", i, stream);
+ break;
+ }
+#if defined(__APPLE__)
+ printf("bytes=%lld/%lu\n", in->bytes_offset, in->bytes_total);
+#else
+ printf("bytes=%ld/%zu\n", in->bytes_offset, in->bytes_total);
+#endif
+ i_input++;
+ }
+ }
+}
+#endif
+
+struct mk_stream *mk_stream_new(int type, struct mk_channel *channel,
+ void *buffer, size_t size, void *data,
+ void (*cb_finished) (struct mk_stream *),
+ void (*cb_bytes_consumed) (struct mk_stream *, long),
+ void (*cb_exception) (struct mk_stream *, int));
+
+int mk_channel_stream_write(struct mk_stream *stream, size_t *count);
+
+struct mk_channel *mk_channel_new(int type, int fd);
+int mk_channel_release(struct mk_channel *channel);
+
+int mk_channel_flush(struct mk_channel *channel);
+int mk_channel_write(struct mk_channel *channel, size_t *count);
+int mk_channel_clean(struct mk_channel *channel);
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_thread.h b/fluent-bit/lib/monkey/include/monkey/mk_thread.h
new file mode 100644
index 000000000..59ea38c8f
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_thread.h
@@ -0,0 +1,25 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2016 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_THREAD_H
+#define MK_THREAD_H
+
+#include <monkey/mk_thread_libco.h>
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_thread_libco.h b/fluent-bit/lib/monkey/include/monkey/mk_thread_libco.h
new file mode 100644
index 000000000..28c320fc5
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_thread_libco.h
@@ -0,0 +1,123 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2016 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_THREAD_LIBCO_H
+#define MK_THREAD_LIBCO_H
+
+#include <monkey/mk_info.h>
+#include <monkey/mk_core.h>
+#include <libco.h>
+
+#include <limits.h>
+
+#ifdef MK_HAVE_VALGRIND
+#include <valgrind/valgrind.h>
+#endif
+
+#include <monkey/mk_tls.h>
+
+struct mk_thread {
+
+#ifdef MK_HAVE_VALGRIND
+ unsigned int valgrind_stack_id;
+#endif
+
+ /* libco 'contexts' */
+ cothread_t caller;
+ cothread_t callee;
+
+ void *data;
+
+ /*
+ * Callback invoked before the thread is destroyed. Used to release
+ * any pending info in MK_THREAD_DATA(...).
+ */
+ void (*cb_destroy) (void *);
+};
+
+#define MK_THREAD_STACK_SIZE ((3 * PTHREAD_STACK_MIN) / 2)
+#define MK_THREAD_DATA(th) (((char *) th) + sizeof(struct mk_thread))
+
+extern MK_EXPORT MK_TLS_DEFINE(struct mk_thread, mk_thread);
+
+static MK_INLINE void mk_thread_yield(struct mk_thread *th)
+{
+ co_switch(th->caller);
+}
+
+static MK_INLINE void mk_thread_destroy(struct mk_thread *th)
+{
+ if (th->cb_destroy) {
+ th->cb_destroy(MK_THREAD_DATA(th));
+ }
+
+ MK_TRACE("[thread] destroy thread=%p data=%p", th, MK_THREAD_DATA(th));
+
+#ifdef MK_HAVE_VALGRIND
+ VALGRIND_STACK_DEREGISTER(th->valgrind_stack_id);
+#endif
+
+ co_delete(th->callee);
+ mk_mem_free(th);
+}
+
+#define mk_thread_return(th) co_switch(th->caller)
+
+static MK_INLINE void mk_thread_resume(struct mk_thread *th)
+{
+ MK_TLS_SET(mk_thread, th);
+
+ /*
+ * In the past we used to have a flag to mark when a coroutine
+ * has finished (th->ended == MK_TRUE), now we let the coroutine
+ * to submit an event to the event loop indicating what's going on
+ * through the call MK_OUTPUT_RETURN(...).
+ *
+ * So we just swap context and let the event loop to handle all
+ * the cleanup required.
+ */
+
+ th->caller = co_active();
+ co_switch(th->callee);
+}
+
+static MK_INLINE struct mk_thread *mk_thread_new(size_t data_size,
+ void (*cb_destroy) (void *))
+
+{
+ void *p;
+ struct mk_thread *th;
+
+ /* Create a thread context and initialize */
+ p = mk_mem_alloc(sizeof(struct mk_thread) + data_size);
+ if (!p) {
+
+ return NULL;
+ }
+
+ th = (struct mk_thread *) p;
+ th->cb_destroy = cb_destroy;
+
+ MK_TRACE("[thread %p] created (custom data at %p, size=%lu",
+ th, MK_THREAD_DATA(th), data_size);
+
+ return th;
+}
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_thread_ucontext.h b/fluent-bit/lib/monkey/include/monkey/mk_thread_ucontext.h
new file mode 100644
index 000000000..1d5272932
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_thread_ucontext.h
@@ -0,0 +1,129 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2016 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_THREAD_UCONTEXT_H
+#define MK_THREAD_UCONTEXT_H
+
+#include <ucontext.h>
+#include <pthread.h>
+#include <limits.h>
+#include <valgrind/valgrind.h>
+
+#include <monkey/mk_core.h>
+#include <monkey/mk_tls.h>
+
+struct mk_thread {
+ int id;
+
+ unsigned int valgrind_stack_id;
+
+ /* ucontext 'contexts' */
+ ucontext_t caller;
+ ucontext_t callee;
+
+ /*
+ * Callback invoked before the thread is destroyed. Used to release
+ * any pending info in MK_THREAD_DATA(...).
+ */
+ void (*cb_destroy) (void *);
+};
+
+#define MK_THREAD_STACK(th) (((char *) th) + sizeof(struct mk_thread))
+#define MK_THREAD_STACK_SIZE ((3 * PTHREAD_STACK_MIN) / 2)
+#define MK_THREAD_STACK_END(th) ((char *) MK_THREAD_STACK(th) + MK_THREAD_STACK_SIZE)
+#define MK_THREAD_DATA(th) ((char *) MK_THREAD_STACK_END(th))
+#define MK_THREAD_SIZE() (sizeof(struct mk_thread) + MK_THREAD_STACK_SIZE)
+
+extern MK_EXPORT MK_TLS_DEFINE(struct mk_thread, mk_thread);
+
+static MK_INLINE void *mk_thread_get()
+{
+ return MK_TLS_GET(mk_thread);
+}
+
+static MK_INLINE void mk_thread_yield(struct mk_thread *th, int ended)
+{
+ (void) ended;
+
+ swapcontext(&th->callee, &th->caller);
+}
+
+static MK_INLINE void mk_thread_destroy(struct mk_thread *th)
+{
+ if (th->cb_destroy) {
+ th->cb_destroy(MK_THREAD_DATA(th));
+ }
+
+ VALGRIND_STACK_DEREGISTER(th->valgrind_stack_id);
+
+ free(th);
+}
+
+static MK_INLINE void mk_thread_resume(struct mk_thread *th)
+{
+ MK_TLS_SET(mk_thread, th);
+
+ /*
+ * In the past we used to have a flag to mark when a coroutine
+ * has finished (th->ended == MK_TRUE), now we let the coroutine
+ * to submit an event to the event loop indicating what's going on
+ * through the call MK_OUTPUT_RETURN(...).
+ *
+ * So we just swap context and let the event loop to handle all
+ * the cleanup required.
+ */
+ swapcontext(&th->caller, &th->callee);
+}
+
+static inline struct mk_thread *mk_thread_new(size_t data_size,
+ void (*cb_destroy) (void *))
+
+{
+ int ret;
+ void *p;
+ struct mk_thread *th;
+
+ /* Create a thread context and initialize */
+ p = malloc(sizeof(struct mk_thread) + MK_THREAD_STACK_SIZE + data_size);
+ if (!p) {
+ return NULL;
+ }
+
+ th = (struct mk_thread *) p;
+ th->cb_destroy = cb_destroy;
+
+ ret = getcontext(&th->callee);
+ if (ret == -1) {
+ free(th);
+ return NULL;
+ }
+
+ /* Thread context */
+ th->callee.uc_stack.ss_sp = MK_THREAD_STACK(p);
+ th->callee.uc_stack.ss_size = MK_THREAD_STACK_SIZE;
+ th->callee.uc_stack.ss_flags = 0;
+ th->callee.uc_link = &th->caller;
+
+ th->valgrind_stack_id = VALGRIND_STACK_REGISTER(MK_THREAD_STACK(p),
+ MK_THREAD_STACK(p) + MK_THREAD_STACK_SIZE);
+
+ return th;
+}
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_tls.h b/fluent-bit/lib/monkey/include/monkey/mk_tls.h
new file mode 100644
index 000000000..fe80e3131
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_tls.h
@@ -0,0 +1,110 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_TLS_H
+#define MK_TLS_H
+
+#include <monkey/mk_info.h>
+
+#define MK_INIT_INITIALIZE_TLS_UNIVERSAL() \
+ /* mk_utils.c */ \
+ pthread_key_create(&mk_utils_error_key, NULL); \
+ /* mk_lib.c */ \
+ pthread_key_create(&mk_server_fifo_key, NULL);
+
+#ifdef MK_HAVE_C_TLS /* Use Compiler Thread Local Storage (TLS) */
+
+/* mk_cache.c */
+extern __thread struct mk_iov *mk_tls_cache_iov_header;
+extern __thread mk_ptr_t *mk_tls_cache_header_cl;
+extern __thread mk_ptr_t *mk_tls_cache_header_lm;
+extern __thread struct tm *mk_tls_cache_gmtime;
+extern __thread struct mk_gmt_cache *mk_tls_cache_gmtext;
+
+/* mk_vhost.c */
+extern __thread struct mk_list *mk_tls_vhost_fdt;
+
+/* mk_scheduler.c */
+extern __thread struct rb_root *mk_tls_sched_cs;
+extern __thread struct mk_list *mk_tls_sched_cs_incomplete;
+extern __thread struct mk_sched_notif *mk_tls_sched_worker_notif;
+extern __thread struct mk_sched_worker *mk_tls_sched_worker_node;
+
+/* mk_server.c */
+extern __thread struct mk_list *mk_tls_server_listen;
+extern __thread struct mk_server_timeout *mk_tls_server_timeout;
+
+/* TLS helper macros */
+#define MK_TLS_SET(key, val) key=val
+#define MK_TLS_GET(key) key
+#define MK_TLS_INIT(key) do {} while (0)
+#define MK_TLS_DEFINE(type, name) __thread type *name;
+
+#define MK_INIT_INITIALIZE_TLS() do {} while (0)
+
+#else /* Use Posix Thread Keys */
+
+/* mk_cache.c */
+extern pthread_key_t mk_tls_cache_iov_header;
+extern pthread_key_t mk_tls_cache_header_cl;
+extern pthread_key_t mk_tls_cache_header_lm;
+extern pthread_key_t mk_tls_cache_gmtime;
+extern pthread_key_t mk_tls_cache_gmtext;
+
+/* mk_vhost.c */
+extern pthread_key_t mk_tls_vhost_fdt;
+
+/* mk_scheduler.c */
+extern pthread_key_t mk_tls_sched_cs;
+extern pthread_key_t mk_tls_sched_cs_incomplete;
+extern pthread_key_t mk_tls_sched_worker_notif;
+extern pthread_key_t mk_tls_sched_worker_node;
+
+/* mk_server.c */
+extern pthread_key_t mk_tls_server_listen;
+extern pthread_key_t mk_tls_server_timeout;
+
+#define MK_TLS_SET(key, val) pthread_setspecific(key, (void *) val)
+#define MK_TLS_GET(key) pthread_getspecific(key)
+#define MK_TLS_INIT(key) pthread_key_create(&key, NULL)
+#define MK_TLS_DEFINE(type, name) pthread_key_t name;
+
+#define MK_INIT_INITIALIZE_TLS() \
+ /* mk_cache.c */ \
+ pthread_key_create(&mk_tls_cache_iov_header, NULL); \
+ pthread_key_create(&mk_tls_cache_header_cl, NULL); \
+ pthread_key_create(&mk_tls_cache_header_lm, NULL); \
+ pthread_key_create(&mk_tls_cache_gmtime, NULL); \
+ pthread_key_create(&mk_tls_cache_gmtext, NULL); \
+ \
+ /* mk_vhost.c */ \
+ pthread_key_create(&mk_tls_vhost_fdt, NULL); \
+ \
+ /* mk_scheduler.c */ \
+ pthread_key_create(&mk_tls_sched_cs, NULL); \
+ pthread_key_create(&mk_tls_sched_cs_incomplete, NULL); \
+ pthread_key_create(&mk_tls_sched_worker_notif, NULL); \
+ pthread_key_create(&mk_tls_sched_worker_node, NULL); \
+ \
+ /* mk_server.c */ \
+ pthread_key_create(&mk_tls_server_listen, NULL); \
+ pthread_key_create(&mk_tls_server_timeout, NULL);
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_user.h b/fluent-bit/lib/monkey/include/monkey/mk_user.h
new file mode 100644
index 000000000..69a47a040
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_user.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_USER_H
+#define MK_USER_H
+
+#include "mk_http.h"
+#include "mk_http_internal.h"
+
+/* User home string */
+#define MK_USER_HOME '~'
+
+/* user.c */
+int mk_user_init(struct mk_http_session *cs, struct mk_http_request *sr,
+ struct mk_server *server);
+int mk_user_set_uidgid(struct mk_server *server);
+int mk_user_undo_uidgid(struct mk_server *server);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_utils.h b/fluent-bit/lib/monkey/include/monkey/mk_utils.h
new file mode 100644
index 000000000..7cf325e5d
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_utils.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_UTILS_H
+#define MK_UTILS_H
+
+#define _GNU_SOURCE
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <monkey/mk_core.h>
+
+#define MK_UTILS_INT2MKP_BUFFER_LEN 16 /* Maximum buffer length when
+ * converting an int to mk_ptr_t */
+#define MK_GMT_CACHES 10
+
+struct mk_gmt_cache {
+ time_t time;
+ char text[32];
+ unsigned long long hits;
+};
+
+int mk_utils_get_system_core_count();
+int mk_utils_get_system_page_size();
+
+int mk_utils_utime2gmt(char **data, time_t date);
+time_t mk_utils_gmt2utime(char *date);
+
+int mk_buffer_cat(mk_ptr_t * p, char *buf1, int len1, char *buf2, int len2);
+
+char *mk_utils_url_decode(mk_ptr_t req_uri);
+void mk_utils_stacktrace(void);
+
+unsigned int mk_utils_gen_hash(const void *key, int len);
+
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_vhost.h b/fluent-bit/lib/monkey/include/monkey/mk_vhost.h
new file mode 100644
index 000000000..efb8f31c8
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_vhost.h
@@ -0,0 +1,123 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_VHOST_H
+#define MK_VHOST_H
+
+#include <monkey/mk_core.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_http.h>
+
+/* Custom error page */
+struct mk_vhost_error_page {
+ short int status;
+ char *file;
+ char *real_path;
+ struct mk_list _head;
+};
+
+struct mk_vhost_handler_param {
+ mk_ptr_t p;
+ struct mk_list _head;
+};
+
+struct mk_vhost_handler {
+ void *match; /* regex match rule */
+ char *name; /* plugin handler name */
+ int n_params; /* number of parameters */
+
+ /* optional callback and opaque data for lib mode */
+ void (*cb) (struct mk_http_request *, void *);
+ void *data;
+
+ struct mk_list params; /* parameters given by config */
+ struct mk_plugin *handler; /* handler plugin */
+ struct mk_list _head; /* link to vhost->handlers */
+};
+
+struct mk_vhost
+{
+ int id;
+ char *file; /* configuration file */
+ struct mk_list server_names; /* host names (a b c...) */
+
+ mk_ptr_t documentroot;
+ mk_ptr_t header_redirect;
+
+ /* source configuration */
+ struct mk_rconf *config;
+
+ /* custom error pages */
+ struct mk_list error_pages;
+
+ /* content handlers */
+ struct mk_list handlers;
+
+ /* link node */
+ struct mk_list _head;
+};
+
+struct mk_vhost_alias
+{
+ char *name;
+ unsigned int len;
+
+ struct mk_list _head;
+};
+
+
+#define VHOST_FDT_HASHTABLE_SIZE 64
+#define VHOST_FDT_HASHTABLE_CHAINS 8
+
+struct vhost_fdt_hash_chain {
+ int fd;
+ int readers;
+ unsigned int hash;
+};
+
+struct vhost_fdt_hash_table {
+ int av_slots;
+ struct vhost_fdt_hash_chain chain[VHOST_FDT_HASHTABLE_CHAINS];
+};
+
+struct vhost_fdt_host {
+ struct mk_vhost *host;
+ struct vhost_fdt_hash_table hash_table[VHOST_FDT_HASHTABLE_SIZE];
+ struct mk_list _head;
+};
+
+struct mk_vhost *mk_vhost_read(char *path);
+int mk_vhost_get(mk_ptr_t host, struct mk_vhost **vhost, struct
+ mk_vhost_alias **alias,
+ struct mk_server *server);
+void mk_vhost_set_single(char *path, struct mk_server *server);
+void mk_vhost_init(char *path, struct mk_server *server);
+
+int mk_vhost_fdt_worker_init(struct mk_server *server);
+int mk_vhost_fdt_worker_exit(struct mk_server *server);
+int mk_vhost_open(struct mk_http_request *sr, struct mk_server *server);
+int mk_vhost_close(struct mk_http_request *sr, struct mk_server *server);
+void mk_vhost_free_all(struct mk_server *server);
+int mk_vhost_map_handlers(struct mk_server *server);
+struct mk_vhost_handler *mk_vhost_handler_match(char *match,
+ void (*cb)(struct mk_http_request *,
+ void *),
+ void *data);
+int mk_vhost_destroy(struct mk_vhost *vh);
+#endif
diff --git a/fluent-bit/lib/monkey/include/monkey/mk_vhost_tls.h b/fluent-bit/lib/monkey/include/monkey/mk_vhost_tls.h
new file mode 100644
index 000000000..19dee4346
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/mk_vhost_tls.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_info.h>
+
+
+#ifndef MK_VHOST_TLS_H
+#define MK_VHOST_TLS_H
+
+#include <monkey/mk_core.h>
+
+#ifdef MK_HAVE_C_TLS /* Use Compiler Thread Local Storage (TLS) */
+
+__thread struct mk_list *mk_tls_vhost_fdt;
+
+#else
+
+pthread_key_t mk_tls_vhost_fdt;
+
+#endif /* MK_HAVE_C_TLS */
+
+#endif /* MK_VHOST_TLS_H */
diff --git a/fluent-bit/lib/monkey/include/monkey/monkey.h b/fluent-bit/lib/monkey/include/monkey/monkey.h
new file mode 100644
index 000000000..0da8901e3
--- /dev/null
+++ b/fluent-bit/lib/monkey/include/monkey/monkey.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ------------------
+ * Copyright (C) 2001-2015, Eduardo Silva P. <edsiper@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef MK_MONKEY_H
+#define MK_MONKEY_H
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <monkey/mk_core.h>
+
+#ifdef LINUX_TRACE
+#define TRACEPOINT_CREATE_PROBES
+#define TRACEPOINT_DEFINE
+#include <monkey/mk_linuxtrace.h>
+#endif
+
+#include <monkey/mk_core.h>
+#include <monkey/mk_server.h>
+#include <monkey/mk_kernel.h>
+#include <monkey/mk_user.h>
+#include <monkey/mk_clock.h>
+#include <monkey/mk_cache.h>
+#include <monkey/mk_plugin.h>
+#include <monkey/mk_env.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_scheduler.h>
+#include <monkey/mk_tls.h>
+
+/* Max Path lenth */
+#define MK_MAX_PATH 1024
+
+/* Send_Header(...,int cgi) */
+#define SH_NOCGI 0
+#define SH_CGI 1
+
+/* Monkey Protocol */
+extern const mk_ptr_t mk_monkey_protocol;
+
+struct mk_server *mk_server_init();
+
+void mk_server_info(struct mk_server *server);
+int mk_server_setup(struct mk_server *server);
+void mk_thread_keys_init();
+void mk_exit_all(struct mk_server *config);
+
+#endif
diff --git a/fluent-bit/lib/monkey/man/CMakeLists.txt b/fluent-bit/lib/monkey/man/CMakeLists.txt
new file mode 100644
index 000000000..1ed0dc634
--- /dev/null
+++ b/fluent-bit/lib/monkey/man/CMakeLists.txt
@@ -0,0 +1,3 @@
+install(FILES
+ "monkey.1"
+ DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" COMPONENT doc)
diff --git a/fluent-bit/lib/monkey/man/monkey.1 b/fluent-bit/lib/monkey/man/monkey.1
new file mode 100644
index 000000000..cabda22b9
--- /dev/null
+++ b/fluent-bit/lib/monkey/man/monkey.1
@@ -0,0 +1,127 @@
+.TH Monkey 1 "Jul 01, 2015"
+.\" Please update the above date whenever this man page is modified.
+.SH NAME
+monkey \- Monkey HTTP Server
+.SH SYNOPSIS
+.B monkey [options]
+.SH DESCRIPTION
+\fBmonkey\fP is fast and scalable web server for Linux, OSX and FreeBSD.
+This manual page only lists the command line arguments available. For further and
+more detailed information regarding the program configuration see the Monkey manual,
+found at http://monkey-project.com/documentation .
+
+.SH OPTIONS
+This command will launch the Monkey webserver. It accepts the
+following options:
+.TP 8
+
+.B \-c, --configdir=DIR
+Allows to specify an optional configuration directory where the required
+configuration files by Monkey are located. It's expected that under this directory
+exists the files: monkey.conf, monkey.mime, plugins.load and the plugins/ directory.
+.TP 8
+
+.B \-s, --serverconf=FILE
+Overrides the default path of the 'monkey.conf' configuration file.
+.TP 8
+
+.B \-d, --daemon
+Launches the server as a daemon (background process). The default behaviour is to
+stay attached to the controlling terminal.
+.TP 8
+
+.B \-I, --pid-file=FILE
+Overrides the default path for the 'pid' file.
+.TP 8
+
+.B \-p, --port=PORT
+Specify a single listener TCP port, this option overrides the content of the
+configuration file.
+.TP 8
+
+.B \-o, --one-shot=DIR
+The one-shot mode and directory path associated, makes to serve that directory
+content as the document root of the default virtual host.
+.TP 8
+
+.B \-t, --transport=TRANSPORT
+Specify a transport layer plugin. This option overrides the configuration file
+and allows just one plugin, either 'liana' for plain sockets or 'tls' for SSL/TLS
+support (just if 'tls' plugin was compiled and available).
+.TP 8
+
+.B \-w, --workers=N
+Specify the number of worker threads that Monkey will spawn upon start. Each worker
+thread is capable to handle several connections, is suggested to spawn a worker per
+CPU core available. By default Monkey set this value to zero (--workers=0) which
+let's Monkey core to detect the number of CPU core available and spawn one worker
+per core.
+.TP 8
+
+.B \-m, --mimes-conf-file=FILE
+Specify a configuration file that holds the mime types available.
+.TP 8
+
+.B \-l, --plugins-load-conf-file=FILE
+Specify a configuration file that holds the list of dynamic plugins to load.
+.TP 8
+
+.B \-S, --sites-conf-dir=DIR
+Specify the directory path where the files that defines the virtual hosts are
+available.
+.TP 8
+
+.B \-P, --plugins-conf-dir=DIR
+Specify the directory path where the plugins can locate their configuration files.
+.TP 8
+
+.B \-b, --balancing-mode
+This option enable the OLD balancing mode when receiving connections. It means that
+for every TCP connection that arrives, the Monkey Scheduler will assign the
+connection to the least-busy worker thread.
+
+The default and new mechanism is based on the shared TCP sockets implementation,
+which let the OS Kernel to decide to which worker thread assign the new connection.
+.TP 8
+
+.B \-T, --allow-shared-sockets
+When using shared TCP sockets (no --balancing-mode), multiple instances of Monkey
+can be started. Monkey will detect if the TCP port is in use by another process,
+despite the address can be shared, Monkey will notify this and abort. This option
+let Monkey know that despites the address is shared and in-use, continue anyways.
+.TP 8
+
+.B \-b, --build
+Print build information and exit. It prints to the standard output the configure
+options, default paths, built-in plugins and others.
+.TP 8
+
+.B \-v, --version
+Prints Monkey's version and exit.
+.TP 8
+
+.B \-h, --help
+Prints this help.
+.TP 8
+
+.SH SIGNALS
+The following signals are supported by Monkey:
+.TP 8
+\fBSIGTERM\fR, Exits
+.TP 8
+\fBSIGINT\fR, Exits
+.TP 8
+\fBSIGHUP\fR, Exits
+.TP 8
+\fBSIGBUS\fR, Print invalid address
+.TP 8
+\fBSIGSEGV\fR, Print invalid address
+
+.SH BUGS
+.SS Bug reports
+In general, send bug reports to the bug report mailing list at <monkey@lists.monkey-project.com>. You are requested to use a descriptive subject for your email message, perhaps parts of the error message.
+
+.SH AUTHOR
+Eduardo Silva <eduardo@monkey.io> and the rest of the Monkey Project team.
+.PP
+This manpage is maintained by the Monkey HTTP Daemon Project team.
diff --git a/fluent-bit/lib/monkey/mk_bin/CMakeLists.txt b/fluent-bit/lib/monkey/mk_bin/CMakeLists.txt
new file mode 100644
index 000000000..b3edc2e92
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_bin/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(src
+ monkey.c
+ mk_signals.c
+ )
+
+add_executable(monkey-bin ${src})
+target_link_libraries(monkey-bin monkey-core-static)
+set_target_properties(monkey-bin PROPERTIES OUTPUT_NAME monkey)
+
+if(MK_BUILD_LOCAL)
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "../${CMAKE_CURRENT_BINARY_DIR}/")
+else()
+ install(TARGETS monkey-bin RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_SBINDIR})
+ configure_file (
+ "${CMAKE_CURRENT_SOURCE_DIR}/systemd.in"
+ "${PROJECT_SOURCE_DIR}/monkey.service"
+ )
+ if(SYSTEMD_DIR)
+ install(FILES ${PROJECT_SOURCE_DIR}/monkey.service DESTINATION ${SYSTEMD_DIR})
+ endif()
+endif()
diff --git a/fluent-bit/lib/monkey/mk_bin/mk_signals.c b/fluent-bit/lib/monkey/mk_bin/mk_signals.c
new file mode 100644
index 000000000..b2c9eb6e8
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_bin/mk_signals.c
@@ -0,0 +1,103 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2015 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/monkey.h>
+#include <monkey/mk_core.h>
+
+#include "monkey.h"
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static struct mk_server *server_context;
+
+void mk_signal_context(struct mk_server *ctx)
+{
+ server_context = ctx;
+}
+
+/* when we catch a signal and want to exit we call this function
+ to do it gracefully */
+static void mk_signal_exit()
+{
+ /* ignore future signals to properly handle the cleanup */
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+
+ mk_user_undo_uidgid(server_context);
+ mk_utils_remove_pid(server_context->path_conf_pidfile);
+ mk_exit_all(server_context);
+
+ mk_info("Exiting... >:(");
+ _exit(EXIT_SUCCESS);
+}
+
+static void mk_signal_handler(int signo, siginfo_t *si, void *context UNUSED_PARAM)
+{
+ switch (signo) {
+ case SIGTERM:
+ case SIGINT:
+ mk_signal_exit();
+ break;
+ case SIGHUP:
+ /*
+ * TODO:
+ * we should implement the httpd config reload here (not in SIGUSR2).
+ * Daemon processes “overload†this signal with a mechanism to instruct them to
+ * reload their configuration files. Sending SIGHUP to Apache, for example,
+ * instructs it to reread httpd.conf.
+ */
+ mk_signal_exit();
+ break;
+ case SIGBUS:
+ case SIGSEGV:
+#ifdef DEBUG
+ mk_utils_stacktrace();
+#endif
+ mk_err("%s (%d), code=%d, addr=%p",
+ strsignal(signo), signo, si->si_code, si->si_addr);
+ //close(sched->server_fd);
+ //pthread_exit(NULL);
+ abort();
+ default:
+ /* let the kernel handle it */
+ kill(getpid(), signo);
+ }
+
+}
+
+void mk_signal_init(void *context)
+{
+ struct sigaction act;
+ memset(&act, 0x0, sizeof(act));
+
+ /* allow signals to be handled concurrently */
+ act.sa_flags = SA_SIGINFO | SA_NODEFER;
+ act.sa_sigaction = &mk_signal_handler;
+
+ sigaction(SIGSEGV, &act, NULL);
+ sigaction(SIGBUS, &act, NULL);
+ sigaction(SIGHUP, &act, NULL);
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+
+ mk_signal_context(context);
+}
diff --git a/fluent-bit/lib/monkey/mk_bin/mk_signals.h b/fluent-bit/lib/monkey/mk_bin/mk_signals.h
new file mode 100644
index 000000000..a1eb731d5
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_bin/mk_signals.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2015 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_SIGNAL_H
+#define MK_SIGNAL_H
+
+void mk_signal_init(struct mk_server *server);
+void mk_signal_context(struct mk_server *ctx);
+void mk_signal_thread_sigpipe_safe(void);
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_bin/monkey.c b/fluent-bit/lib/monkey/mk_bin/monkey.c
new file mode 100644
index 000000000..15d695ba6
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_bin/monkey.c
@@ -0,0 +1,328 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2015 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/monkey.h>
+
+#include "monkey.h"
+#include "mk_signals.h"
+
+#include <signal.h>
+#include <getopt.h>
+
+#if defined(__DATE__) && defined(__TIME__)
+static const char MONKEY_BUILT[] = __DATE__ " " __TIME__;
+#else
+static const char MONKEY_BUILT[] = "Unknown";
+#endif
+
+
+static void mk_version(void)
+{
+ printf("Monkey HTTP Server v%s\n", MK_VERSION_STR);
+ printf("Built : %s (%s %i.%i.%i)\n",
+ MONKEY_BUILT, CC, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
+ printf("Home : http://monkey-project.com\n");
+ fflush(stdout);
+}
+
+static void mk_build_info(void)
+{
+ struct mk_list *head;
+ struct mk_plugin *p;
+ struct mk_server *server;
+
+ mk_version();
+
+ printf("\n");
+ printf("%s[system: %s]%s\n", ANSI_BOLD, MK_BUILD_OS, ANSI_RESET);
+ printf("%s", MK_BUILD_UNAME);
+
+ printf("\n\n%s[configure]%s\n", ANSI_BOLD, ANSI_RESET);
+ printf("%s", MK_BUILD_CMD);
+
+ printf("\n\n%s[setup]%s\n", ANSI_BOLD, ANSI_RESET);
+ printf("configuration dir: %s\n", MK_PATH_CONF);
+
+ /* Initialize list */
+ server = mk_mem_alloc(sizeof(struct mk_server));
+ mk_list_init(&server->plugins);
+ mk_plugin_load_static(server);
+
+ printf("\n\n%s[built-in plugins]%s\n", ANSI_BOLD, ANSI_RESET);
+ mk_list_foreach(head, &server->plugins) {
+ p = mk_list_entry(head, struct mk_plugin, _head);
+ printf("%-20s%s\n", p->shortname, p->name);
+ }
+ mk_mem_free(server);
+ printf("\n");
+}
+
+static void mk_help(int rc)
+{
+ printf("Usage : monkey [OPTION]\n\n");
+ printf("%sAvailable Options%s\n", ANSI_BOLD, ANSI_RESET);
+ printf(" -c, --configdir=DIR\t\t\tspecify configuration files directory\n");
+ printf(" -s, --serverconf=FILE\t\t\tspecify main server configuration file\n");
+ printf(" -D, --daemon\t\t\t\trun Monkey as daemon (background mode)\n");
+ printf(" -I, --pid-file\t\t\tset full path for the PID file (override config)\n");
+ printf(" -p, --port=PORT\t\t\tset listener TCP port (override config)\n");
+ printf(" -o, --one-shot=DIR\t\t\tone-shot, serve a single directory\n");
+ printf(" -t, --transport=TRANSPORT\t\tspecify transport layer (override config)\n");
+ printf(" -w, --workers=N\t\t\tset number of workers (override config)\n");
+ printf(" -m, --mimes-conf-file=FILE\t\tspecify mimes configuration file\n");
+ printf(" -l, --plugins-load-conf-file=FILE\tspecify plugins.load configuration file\n");
+ printf(" -S, --sites-conf-dir=dir\t\tspecify sites configuration directory\n");
+ printf(" -P, --plugins-conf-dir=dir\t\tspecify plugin configuration directory\n");
+ printf(" -B, --balancing-mode\t\t\tforce old balancing mode\n");
+ printf(" -T, --allow-shared-sockets\t\tif Listen is busy, try shared TCP sockets\n\n");
+
+ printf("%sInformational%s\n", ANSI_BOLD, ANSI_RESET);
+ printf(" -b, --build\t\t\t\tprint build information\n");
+ printf(" -v, --version\t\t\t\tshow version number\n");
+ printf(" -h, --help\t\t\t\tprint this help\n\n");
+
+ printf("%sDocumentation%s\n", ANSI_BOLD, ANSI_RESET);
+ printf(" http://monkey-project.com/documentation\n\n");
+
+ exit(rc);
+}
+
+/* MAIN */
+int main(int argc, char **argv)
+{
+ int opt;
+ char *port_override = NULL;
+ int workers_override = -1;
+ int run_daemon = 0;
+ int balancing_mode = MK_FALSE;
+ int allow_shared_sockets = MK_FALSE;
+ char *one_shot = NULL;
+ char *pid_file = NULL;
+ char *transport_layer = NULL;
+ char *path_config = NULL;
+ char *server_conf_file = NULL;
+ char *plugin_load_conf_file = NULL;
+ char *sites_conf_dir = NULL;
+ char *plugins_conf_dir = NULL;
+ char *mimes_conf_file = NULL;
+ struct mk_server *server;
+
+ static const struct option long_opts[] = {
+ { "configdir", required_argument, NULL, 'c' },
+ { "serverconf", required_argument, NULL, 's' },
+ { "build", no_argument, NULL, 'b' },
+ { "daemon", no_argument, NULL, 'D' },
+ { "pid-file", required_argument, NULL, 'I' },
+ { "port", required_argument, NULL, 'p' },
+ { "one-shot", required_argument, NULL, 'o' },
+ { "transport", required_argument, NULL, 't' },
+ { "workers", required_argument, NULL, 'w' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { "mimes-conf-file", required_argument, NULL, 'm' },
+ { "plugin-load-conf-file", required_argument, NULL, 'l' },
+ { "plugins-conf-dir", required_argument, NULL, 'P' },
+ { "sites-conf-dir", required_argument, NULL, 'S' },
+ { "balancing-mode", no_argument, NULL, 'B' },
+ { "allow-shared-sockets", no_argument, NULL, 'T' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ while ((opt = getopt_long(argc, argv, "bDI:Svhp:o:t:w:c:s:m:l:P:S:BT",
+ long_opts, NULL)) != -1) {
+ switch (opt) {
+ case 'b':
+ mk_build_info();
+ exit(EXIT_SUCCESS);
+ case 'v':
+ mk_version();
+ exit(EXIT_SUCCESS);
+ case 'h':
+ mk_help(EXIT_SUCCESS);
+ break;
+ case 'D':
+ run_daemon = 1;
+ break;
+ case 'I':
+ pid_file = optarg;
+ break;
+ case 'p':
+ port_override = optarg;
+ break;
+ case 'o':
+ one_shot = optarg;
+ break;
+ case 't':
+ transport_layer = mk_string_dup(optarg);
+ break;
+ case 'w':
+ workers_override = atoi(optarg);
+ break;
+ case 'c':
+ path_config = optarg;
+ break;
+ case 's':
+ server_conf_file = optarg;
+ break;
+ case 'm':
+ mimes_conf_file = optarg;
+ break;
+ case 'P':
+ plugins_conf_dir = optarg;
+ break;
+ case 'S':
+ sites_conf_dir = optarg;
+ break;
+ case 'B':
+ balancing_mode = MK_TRUE;
+ break;
+ case 'T':
+ allow_shared_sockets = MK_TRUE;
+ break;
+ case 'l':
+ plugin_load_conf_file = optarg;
+ break;
+ case '?':
+ mk_help(EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * Initialize Monkey Server context. Once is created, we need to start
+ * populating some relevant configuration fields that will affect the
+ * server behavior.
+ */
+ server = mk_server_create();
+
+ /* set configuration path */
+ if (!path_config) {
+ server->path_conf_root = MK_PATH_CONF;
+ }
+ else {
+ server->path_conf_root = path_config;
+ }
+
+ /* set target configuration file for the server */
+ if (!server_conf_file) {
+ server->conf_main = MK_DEFAULT_CONFIG_FILE;
+ }
+ else {
+ server->conf_main = server_conf_file;
+ }
+
+ if (!pid_file) {
+ server->path_conf_pidfile = NULL;
+ }
+ else {
+ server->path_conf_pidfile = pid_file;
+ }
+
+ if (run_daemon) {
+ server->is_daemon = MK_TRUE;
+ }
+ else {
+ server->is_daemon = MK_FALSE;
+ }
+
+ if (!mimes_conf_file) {
+ server->conf_mimetype = MK_DEFAULT_MIMES_CONF_FILE;
+ }
+ else {
+ server->conf_mimetype = mimes_conf_file;
+ }
+
+ if (!plugin_load_conf_file) {
+ server->conf_plugin_load = MK_DEFAULT_PLUGIN_LOAD_CONF_FILE;
+ }
+ else {
+ server->conf_plugin_load = plugin_load_conf_file;
+ }
+
+ if (!sites_conf_dir) {
+ server->conf_sites = MK_DEFAULT_SITES_CONF_DIR;
+ }
+ else {
+ server->conf_sites = sites_conf_dir;
+ }
+
+ if (!plugins_conf_dir) {
+ server->conf_plugins = MK_DEFAULT_PLUGINS_CONF_DIR;
+ }
+ else {
+ server->conf_plugins = plugins_conf_dir;
+ }
+
+ /* Override some configuration */
+ server->one_shot = one_shot;
+ server->port_override = port_override;
+ server->transport_layer = transport_layer;
+
+ mk_version();
+ mk_signal_init(server);
+
+ /* Override number of thread workers */
+ if (workers_override >= 0) {
+ server->workers = workers_override;
+ }
+ else {
+ server->workers = -1;
+ }
+
+ if (balancing_mode == MK_TRUE) {
+ server->scheduler_mode = MK_SCHEDULER_FAIR_BALANCING;
+ }
+
+
+ /* Running Monkey as daemon */
+ if (server->is_daemon == MK_TRUE) {
+ mk_utils_set_daemon();
+ }
+
+ if (server->scheduler_mode == MK_SCHEDULER_REUSEPORT &&
+ mk_config_listen_check_busy(server) == MK_TRUE &&
+ allow_shared_sockets == MK_FALSE) {
+ mk_warn("Some Listen interface is busy, re-try using -T. Aborting.");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Once the all configuration is set, let mk_server configure the
+ * internals. Not accepting connections yet.
+ */
+ mk_server_setup(server);
+
+ /* Register PID of Monkey */
+ mk_utils_register_pid(server->path_conf_pidfile);
+
+ /* Print server details */
+ mk_server_info(server);
+
+ /* Change process owner */
+ mk_user_set_uidgid(server);
+
+ /* Server loop, let's listen for incomming clients */
+ mk_server_loop(server);
+
+ /* Hang here, basically do nothing as threads are doing the job. */
+ sigset_t mask;
+ sigprocmask(0, NULL, &mask);
+ sigsuspend(&mask);
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_bin/systemd.in b/fluent-bit/lib/monkey/mk_bin/systemd.in
new file mode 100644
index 000000000..d51cef3a6
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_bin/systemd.in
@@ -0,0 +1,13 @@
+[Unit]
+Description=Monkey HTTP Server
+Requires=network.target
+After=network.target
+
+[Service]
+Type=forking
+ExecStart=@CMAKE_INSTALL_FULL_SBINDIR@/monkey --daemon
+PIDFile=@MK_PATH_PIDPATH@/@MK_PIDFILE@
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
diff --git a/fluent-bit/lib/monkey/mk_core/CMakeLists.txt b/fluent-bit/lib/monkey/mk_core/CMakeLists.txt
new file mode 100644
index 000000000..86cc7fcb4
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/CMakeLists.txt
@@ -0,0 +1,156 @@
+include (CheckCSourceCompiles)
+
+set(src
+ mk_rconf.c
+ mk_string.c
+ mk_memory.c
+ mk_event.c
+ mk_utils.c
+ )
+
+# Headers
+include_directories(../include/monkey/)
+
+# It set's a definition and register into the mk_core_info.h file */
+macro(MK_DEFINITION var)
+ add_definitions(-D${var})
+ set(MK_CORE_BUILD_FLAGS "${MK_CORE_BUILD_FLAGS}#ifndef ${var}\n#define ${var}\n#endif\n")
+endmacro()
+
+# Set threading system
+if (CMAKE_SYSTEM_NAME MATCHES "Windows")
+ MK_DEFINITION(MK_THREADS_WIN32)
+ set(src
+ ${src}
+ "external/winpthreads.c"
+ )
+ add_subdirectory(deps/)
+else()
+ MK_DEFINITION(MK_THREADS_POSIX)
+endif()
+
+# Check for full stat(2) support
+check_c_source_compiles("
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ int main() {
+ struct stat st;
+ return 0;
+ }" HAVE_STAT_H)
+if (HAVE_STAT_H)
+ set(src "${src}"
+ mk_file.c
+ )
+ MK_DEFINITION(MK_HAVE_STAT_H)
+endif()
+
+# Check if sys/uio.h exists
+check_c_source_compiles("
+ #include <sys/uio.h>
+ int main() {
+ return 0;
+ }" HAVE_SYS_UIO_H)
+
+if (HAVE_SYS_UIO_H)
+ MK_DEFINITION(MK_HAVE_SYS_UIO_H)
+endif()
+
+# We need to compile mk_iov regardless of system UIO support
+set(src "${src}"
+ mk_iov.c
+ )
+
+check_c_source_compiles("
+ #include <string.h>
+ int main() {
+ char haystack[] = \"1234\";
+ char needle[] = \"23\";
+ void *result;
+
+ result = memmem(haystack, sizeof(haystack) - 1, needle, sizeof(needle) - 1);
+
+ return (NULL != result);
+ }" HAVE_MEMMEM)
+
+if (HAVE_MEMMEM)
+ MK_DEFINITION(MK_HAVE_MEMMEM)
+endif()
+
+# Check for unistd.h
+check_c_source_compiles("
+ #include <unistd.h>
+ int main() {
+ return 0;
+ }" HAVE_UNISTD_H)
+if (HAVE_UNISTD_H)
+ MK_DEFINITION(MK_HAVE_UNISTD_H)
+endif()
+
+# Lookup event-loop mechanism: do we need to fallback to select(2) ?
+check_c_source_compiles("
+ #include <sys/epoll.h>
+ int main() {
+ return epoll_create(1);
+ }" HAVE_EPOLL)
+
+check_c_source_compiles("
+ #include <sys/event.h>
+ int main() {
+ return kqueue();
+ }" HAVE_KQUEUE)
+
+
+if ((NOT HAVE_EPOLL AND NOT HAVE_KQUEUE) OR MK_USE_EVENT_SELECT)
+ message(STATUS "Event loop backend > select(2)")
+ MK_DEFINITION(MK_HAVE_EVENT_SELECT)
+endif()
+
+# Validate timerfd_create()
+check_c_source_compiles("
+ #include <sys/timerfd.h>
+ int main() {
+ return timerfd_create(CLOCK_REALTIME, 0);
+ }" HAVE_TIMERFD_CREATE)
+
+if (HAVE_TIMERFD_CREATE)
+ MK_DEFINITION(MK_HAVE_TIMERFD_CREATE)
+endif()
+
+# Validate eventfd()
+check_c_source_compiles("
+ #include <sys/eventfd.h>
+ int main() {
+ return eventfd(0, EFD_CLOEXEC);
+ }" HAVE_EVENTFD)
+
+if (HAVE_EVENTFD)
+ MK_DEFINITION(MK_HAVE_EVENTFD)
+endif()
+
+# Validate memrchr()
+check_c_source_compiles("
+ #define _GNU_SOURCE
+ #include <string.h>
+ int main() {
+ memrchr(\"test\", 'e', 4);
+ return 0;
+ }" MK_HAVE_MEMRCHR)
+
+include(CheckFunctionExists)
+CHECK_FUNCTION_EXISTS(memrchr MK_HAVE_MEMRCHR)
+
+if (MK_HAVE_MEMRCHR)
+ MK_DEFINITION(MK_HAVE_MEMRCHR)
+endif()
+
+configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/../include/monkey/mk_core/mk_core_info.h.in"
+ "${PROJECT_BINARY_DIR}/include/monkey/mk_core/mk_core_info.h"
+ )
+
+add_library(mk_core STATIC ${src})
+target_link_libraries(mk_core ${CMAKE_THREAD_LIBS_INIT})
+
+if (CMAKE_SYSTEM_NAME MATCHES "Windows")
+ target_link_libraries(mk_core event)
+endif()
diff --git a/fluent-bit/lib/monkey/mk_core/deps/CMakeLists.txt b/fluent-bit/lib/monkey/mk_core/deps/CMakeLists.txt
new file mode 100644
index 000000000..08ca13cc0
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/CMakeLists.txt
@@ -0,0 +1,13 @@
+macro(FORCE_OPTION option value)
+ set(${option} ${value} CACHE "" INTERNAL FORCE)
+endmacro()
+
+FORCE_OPTION(EVENT__DISABLE_THREAD_SUPPORT ON)
+FORCE_OPTION(EVENT__DISABLE_OPENSSL ON)
+FORCE_OPTION(EVENT__DISABLE_BENCHMARK ON)
+FORCE_OPTION(EVENT__DISABLE_TESTS ON)
+FORCE_OPTION(EVENT__DISABLE_REGRESS ON)
+FORCE_OPTION(EVENT__DISABLE_SAMPLES ON)
+FORCE_OPTION(EVENT__BUILD_SHARED_LIBRARIES OFF)
+
+add_subdirectory(libevent)
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/.clang-format b/fluent-bit/lib/monkey/mk_core/deps/libevent/.clang-format
new file mode 100644
index 000000000..a9722db28
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/.clang-format
@@ -0,0 +1,63 @@
+---
+Language: Cpp
+BasedOnStyle: LLVM
+
+AccessModifierOffset: -4
+
+AlignAfterOpenBracket: DontAlign
+AlignEscapedNewlinesLeft: true
+# AlignOperands: true
+AlignTrailingComments: true
+
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+
+AlwaysBreakAfterDefinitionReturnType: All
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
+
+# BinPackArguments: false
+# BinPackParameters: true
+
+BreakBeforeBinaryOperators: false
+BreakBeforeBraces: Custom
+BraceWrapping: { AfterFunction: true }
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: true
+
+ColumnLimit: 80
+
+ContinuationIndentWidth: 4
+
+DerivePointerAlignment: false #XXX
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false #XXX
+ForEachMacros: [ LIST_FOREACH, SIMPLEQ_FOREACH, CIRCLEQ_FOREACH, TAILQ_FOREACH, TAILQ_FOREACH_REVERSE, HT_FOREACH ]
+
+IndentCaseLabels: false
+IndentFunctionDeclarationAfterType: false
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+
+KeepEmptyLinesAtTheStartOfBlocks: true
+MaxEmptyLinesToKeep: 2
+
+PointerAlignment: Right #XXX
+
+# SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+Standard: Cpp03
+TabWidth: 4
+UseTab: Always
+SortIncludes: false
+...
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/.gitignore b/fluent-bit/lib/monkey/mk_core/deps/libevent/.gitignore
new file mode 100644
index 000000000..996100453
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/.gitignore
@@ -0,0 +1,149 @@
+### These files should get ignored no matter where they appear.
+
+# Editors leave these lying around
+\#*\#
+.#*
+*~
+*.swp
+
+# C stuff
+*.o
+
+# Windows stuff
+*.obj
+*.exe
+*.lib
+
+# Patch leaves these lying arround
+*.orig
+*.rej
+
+# gcov stuff
+*.gcno
+*.gcov
+*.gcda
+
+# gdb stuff
+.gdb_history
+
+# Autotools stuff
+.deps
+.dirstamp
+Makefile
+Makefile.in
+
+# Libtool stuff
+.libs
+*.lo
+*.la
+
+# ctags stuff
+TAGS
+tags
+
+# cscope stuff
+cscope*
+
+# Stuff made by our makefiles
+*.pc
+*.log
+*.trs
+
+## The initial / makes these files only get ignored in particular directories.
+/autom4te.cache
+
+# configure in progress
+/.cyg*
+/confdefs.*
+/conftest.*
+
+# Libtool adds these, at least sometimes
+/m4/libtool.m4
+/m4/ltoptions.m4
+/m4/ltsugar.m4
+/m4/ltversion.m4
+/m4/lt~obsolete.m4
+
+/aclocal.m4
+/compile
+/doxygen
+/config.cache
+/config.guess
+/config.log
+/config.status
+/config.sub
+/configure
+/configure.lineno
+/depcomp
+/config.h
+/config.h.in
+/install-sh
+/libtool
+/ltmain.sh
+/missing
+/stamp-h1
+/stamp-h2
+
+/include/event2/event-config.h
+/evconfig-private.h
+
+/sample/dns-example
+/sample/event-read-fifo
+/sample/hello-world
+/sample/http-server
+/sample/http-connect
+/sample/le-proxy
+/sample/https-client
+/sample/signal-test
+/sample/time-test
+/sample/event-test
+
+/test-driver
+/test/bench
+/test/bench_cascade
+/test/bench_http
+/test/bench_httpclient
+/test/regress
+/test/regress.gen.c
+/test/regress.gen.h
+/test/rpcgen-attempted
+/test/test-dumpevents
+/test/test-eof
+/test/test-closed
+/test/test-init
+/test/test-ratelim
+/test/test-script.sh
+/test/test-time
+/test/test-weof
+/test/test-changelist
+/test/test-fdleak
+
+
+# Files generated by cmake
+/CMakeCache.txt
+/CMakeFiles/
+/CTestTestfile.cmake
+/DartConfiguration.tcl
+/LibeventConfig.cmake
+/LibeventConfigVersion.cmake
+/LibeventTargets.cmake
+/bin/
+/cmake_install.cmake
+/include/evconfig-private.h
+/lib/
+/tmp/
+/verify_tests.sh
+/verify_tests.bat
+/event.dir
+/event_core.dir
+/event_extra.dir
+*.vcxproj
+*.sln
+*.filters
+
+# make dist
+/COPYING
+/INSTALL
+/*.tar.gz
+
+/.vagrant
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/.travis.yml b/fluent-bit/lib/monkey/mk_core/deps/libevent/.travis.yml
new file mode 100644
index 000000000..acc85e6a7
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/.travis.yml
@@ -0,0 +1,88 @@
+os:
+ - linux
+ - osx
+sudo: false
+
+env:
+ matrix:
+ - EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS="-DEVENT__COVERAGE=ON -DCMAKE_BUILD_TYPE=debug" COVERALLS=yes
+ - EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS=""
+ - EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS="-DEVENT__DISABLE_OPENSSL=ON"
+ - EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS="-DEVENT__DISABLE_THREAD_SUPPORT=ON"
+ - EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS="-DEVENT__DISABLE_DEBUG_MODE=ON"
+ - EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS="-DEVENT__DISABLE_MM_REPLACEMENT=ON"
+ - EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS="-DEVENT__ENABLE_VERBOSE_DEBUG=ON"
+ - EVENT_BUILD_METHOD=autotools EVENT_CONFIGURE_OPTIONS=""
+ - EVENT_BUILD_METHOD=autotools EVENT_CONFIGURE_OPTIONS="--disable-openssl"
+ - EVENT_BUILD_METHOD=autotools EVENT_CONFIGURE_OPTIONS="--disable-thread-support"
+ - EVENT_BUILD_METHOD=autotools EVENT_CONFIGURE_OPTIONS="--disable-debug-mode"
+ - EVENT_BUILD_METHOD=autotools EVENT_CONFIGURE_OPTIONS="--disable-malloc-replacement"
+
+language: c
+compiler:
+ - gcc
+ - clang
+
+before_install:
+ - if [ -n "$COVERALLS" ]; then
+ pip install --user cpp-coveralls;
+ fi
+ - if [ "$TRAVIS_OS_NAME" == "osx" ]; then
+ brew update;
+ brew uninstall libtool && brew install libtool;
+ brew install openssl;
+ brew install lcov;
+ if [ "$CC" == "gcc" ]; then
+ export CC=$(ls -t /usr/local/bin/gcc-?.?);
+ fi
+
+ export OPENSSL_ROOT=$(echo /usr/local/Cellar/openssl/*);
+ export
+ CMAKE_INCLUDE_PATH=$OPENSSL_ROOT/include
+ CMAKE_LIBRARY_PATH=$OPENSSL_ROOT/lib;
+ export
+ CFLAGS=-I$CMAKE_INCLUDE_PATH
+ LDFLAGS=-L$CMAKE_LIBRARY_PATH;
+ fi
+
+addons:
+ apt:
+ packages:
+ - zlib1g-dev
+ - libssl-dev
+ - build-essential
+ - automake
+ - autoconf
+ - cmake
+ - lcov
+
+script:
+ - if [ "$EVENT_BUILD_METHOD" = "autotools" ]; then
+ ./autogen.sh &&
+ ./configure $EVENT_CONFIGURE_OPTIONS &&
+ make &&
+ make verify;
+ fi
+ - if [ "$EVENT_BUILD_METHOD" = "cmake" ]; then
+ mkdir build &&
+ cd build &&
+ cmake .. $EVENT_CMAKE_OPTIONS &&
+ cmake --build . &&
+ CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --target verify;
+ fi
+
+after_script:
+ - if [ -n "$COVERALLS" ]; then
+ coveralls
+ --build-root .
+ --root ..
+ --exclude test
+ --exclude sample
+ --exclude cmake
+ --exclude build/CMakeFiles/CheckTypeSize
+ --exclude build/CMakeFiles/CompilerIdC
+ --gcov-options '\-lp';
+ fi
+
+notifications:
+ irc: "irc.oftc.net#libevent"
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/.uncrustify b/fluent-bit/lib/monkey/mk_core/deps/libevent/.uncrustify
new file mode 100644
index 000000000..da2daa135
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/.uncrustify
@@ -0,0 +1,55 @@
+input_tab_size = 8
+output_tab_size = 8
+indent_with_tabs = 2
+indent_cmt_with_tabs = false
+indent_brace_parent = false
+indent_func_call_param = true
+indent_func_def_param = true
+sp_enum_before_assign = add
+sp_enum_after_assign = add
+sp_inside_paren = remove
+sp_paren_brace = add
+sp_before_ptr_star = add
+sp_before_unnamed_ptr_star = add
+sp_between_ptr_star = remove
+sp_after_ptr_star = remove
+sp_after_ptr_star_func = add
+sp_before_ptr_star_func = add
+sp_before_sparen = add
+sp_inside_sparen = remove
+sp_inside_sparen_close = remove
+sp_after_sparen = add
+sp_sparen_brace = add
+sp_special_semi = remove
+sp_before_semi_for = remove
+sp_after_comma = add
+sp_after_cast = remove
+sp_inside_braces_struct = add
+sp_type_func = remove
+sp_func_def_paren = remove
+sp_inside_fparen = remove
+sp_fparen_brace = add
+sp_func_call_paren = remove
+sp_else_brace = add
+sp_after_oc_block_caret = remove
+align_keep_tabs = true
+align_with_tabs = true
+align_on_tabstop = true
+nl_fcall_brace = remove
+nl_enum_brace = remove
+nl_struct_brace = remove
+nl_union_brace = remove
+nl_if_brace = remove
+nl_brace_else = remove
+nl_elseif_brace = remove
+nl_else_brace = remove
+nl_else_if = remove
+nl_for_brace = remove
+sp_after_semi_for_empty = remove
+nl_while_brace = remove
+nl_do_brace = remove
+nl_brace_while = remove
+nl_switch_brace = remove
+nl_func_type_name = add
+nl_fdef_brace = add
+mod_paren_on_return = ignore
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/CMakeLists.txt b/fluent-bit/lib/monkey/mk_core/deps/libevent/CMakeLists.txt
new file mode 100644
index 000000000..7a839decf
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/CMakeLists.txt
@@ -0,0 +1,1458 @@
+#
+# Libevent CMake project
+#
+# Based on initial work by:
+# Alexey Ozeritsky
+#
+# Additional changes:
+# Brodie Thiesfield
+# Joakim Soderberg
+# Trond Norbye
+# Sergei Nikulov
+#
+# Build example:
+#
+# cd libevent
+# md build
+# cd build
+# cmake -G "Visual Studio 10" ..
+# start libevent.sln
+#
+if (WIN32)
+ cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+else()
+ cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR)
+endif()
+
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release
+ CACHE STRING "Set build type to Debug o Release (default Release)" FORCE)
+endif()
+string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER)
+
+# get rid of the extra default configurations
+# what? why would you get id of other useful build types? - Ellzey
+set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Limited configurations" FORCE)
+
+project(libevent C)
+
+set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
+string(REGEX MATCH "SunOS" SOLARIS "${CMAKE_SYSTEM_NAME}")
+
+
+include(CheckTypeSize)
+include(CheckFunctionExistsEx)
+include(CheckFileOffsetBits)
+include(CheckFunctionExists)
+include(CheckIncludeFile)
+include(CheckIncludeFiles)
+include(CheckVariableExists)
+include(CheckSymbolExists)
+include(CheckStructHasMember)
+include(CheckCSourceCompiles)
+include(CheckPrototypeDefinition)
+include(CheckFunctionKeywords)
+include(AddCompilerFlags)
+include(VersionViaGit)
+
+event_fuzzy_version_from_git()
+
+set(EVENT_VERSION_MAJOR ${EVENT_GIT___VERSION_MAJOR})
+set(EVENT_VERSION_MINOR ${EVENT_GIT___VERSION_MINOR})
+set(EVENT_VERSION_PATCH ${EVENT_GIT___VERSION_PATCH})
+set(EVENT_VERSION_STAGE ${EVENT_GIT___VERSION_STAGE})
+
+
+set(EVENT_ABI_MAJOR ${EVENT_VERSION_MAJOR})
+set(EVENT_ABI_MINOR ${EVENT_VERSION_MINOR})
+set(EVENT_ABI_PATCH ${EVENT_VERSION_PATCH})
+
+set(EVENT_ABI_LIBVERSION
+ "${EVENT_ABI_MAJOR}.${EVENT_ABI_MINOR}.${EVENT_ABI_PATCH}")
+
+set(EVENT_PACKAGE_VERSION
+ "${EVENT_VERSION_MAJOR}.${EVENT_VERSION_MINOR}.${EVENT_VERSION_PATCH}")
+
+set(EVENT_NUMERIC_VERSION 0x02010700)
+
+# only a subset of names can be used, defaults to "beta"
+set(EVENT_STAGE_NAME ${EVENT_VERSION_STAGE}
+ CACHE STRING "set the stage name (beta|alpha|release)")
+
+# a list that defines what can set for EVENT_STAGE_VERSION
+set(EVENT__ALLOWED_STAGE_NAMES
+ rc
+ beta
+ alpha
+ release)
+
+# attempt to find the EVENT__STAGE_VERSION in the allowed list
+# of accepted stage names, the return value is stord in
+# EVENT__STAGE_RET
+
+list(FIND EVENT__ALLOWED_STAGE_NAMES
+ ${EVENT_STAGE_NAME}
+ EVENT__STAGE_RET)
+
+if (EVENT__STAGE_RET EQUAL "-1")
+ set(EVENT_STAGE_NAME beta)
+endif()
+
+set(EVENT_VERSION
+ "${EVENT_VERSION_MAJOR}.${EVENT_VERSION_MINOR}.${EVENT_VERSION_PATCH}-${EVENT_STAGE_NAME}")
+
+option(EVENT__BUILD_SHARED_LIBRARIES
+ "Define if libevent should be built with shared libraries instead of archives" OFF)
+
+option(EVENT__DISABLE_DEBUG_MODE
+ "Define if libevent should build without support for a debug mode" OFF)
+
+option(EVENT__ENABLE_VERBOSE_DEBUG
+ "Enables verbose debugging" OFF)
+
+option(EVENT__DISABLE_MM_REPLACEMENT
+ "Define if libevent should not allow replacing the mm functions" OFF)
+
+option(EVENT__DISABLE_THREAD_SUPPORT
+ "Define if libevent should not be compiled with thread support" OFF)
+
+option(EVENT__DISABLE_OPENSSL
+ "Define if libevent should build without support for OpenSSL encrpytion" OFF)
+
+option(EVENT__DISABLE_BENCHMARK
+ "Defines if libevent should build without the benchmark exectuables" OFF)
+
+option(EVENT__DISABLE_TESTS
+ "If tests should be compiled or not" OFF)
+
+option(EVENT__DISABLE_REGRESS
+ "Disable the regress tests" OFF)
+
+option(EVENT__DISABLE_SAMPLES
+ "Disable sample files" OFF)
+
+option(EVENT__DISABLE_CLOCK_GETTIME
+ "Do not use clock_gettime even if it is available" OFF)
+
+option(EVENT__FORCE_KQUEUE_CHECK
+ "When crosscompiling forces running a test program that verifies that Kqueue works with pipes. Note that this requires you to manually run the test program on the the cross compilation target to verify that it works. See cmake documentation for try_run for more details" OFF)
+
+# TODO: Add --disable-largefile omit support for large files
+option(EVENT__COVERAGE
+"Enable running gcov to get a test coverage report (only works with GCC/CLang). Make sure to enable -DCMAKE_BUILD_TYPE=Debug as well." OFF)
+
+# Put the libaries and binaries that get built into directories at the
+# top of the build tree rather than in hard-to-find leaf directories.
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
+
+if (EVENT__ENABLE_VERBOSE_DEBUG)
+ add_definitions(-DUSE_DEBUG=1)
+endif()
+
+# Setup compiler flags for coverage.
+if (EVENT__COVERAGE)
+ if (NOT "${CMAKE_BUILD_TYPE_LOWER}" STREQUAL "debug")
+ message(FATAL_ERROR "Coverage requires -DCMAKE_BUILD_TYPE=Debug")
+ endif()
+
+ message(STATUS "Setting coverage compiler flags")
+
+ set(CMAKE_REQUIRED_LIBRARIES "--coverage")
+ add_compiler_flags(-g -O0 --coverage)
+ set(CMAKE_REQUIRED_LIBRARIES "")
+endif()
+
+# GCC specific options.
+if (CMAKE_COMPILER_IS_GNUCC)
+ option(EVENT__DISABLE_GCC_WARNINGS "Disable verbose warnings with GCC" OFF)
+ option(EVENT__ENABLE_GCC_HARDENING "Enable compiler security checks" OFF)
+ option(EVENT__ENABLE_GCC_FUNCTION_SECTIONS "Enable gcc function sections" OFF)
+ option(EVENT__ENABLE_GCC_WARNINGS "Make all GCC warnings into errors" OFF)
+
+ list(APPEND __FLAGS -Wall -Wswitch)
+
+ if (EVENT__DISABLE_GCC_WARNINGS)
+ list(APPEND __FLAGS -w)
+ endif()
+
+ if (EVENT__ENABLE_GCC_HARDENING)
+ list(APPEND __FLAGS
+ -fstack-protector-all
+ -fwrapv
+ -fPIE
+ -Wstack-protector
+ "--param ssp-buffer-size=1")
+
+ add_definitions(-D_FORTIFY_SOURCE=2)
+ endif()
+
+ if (EVENT__ENABLE_GCC_FUNCTION_SECTIONS)
+ list(APPEND __FLAGS -ffunction-sections)
+ # TODO: Add --gc-sections support. We need some checks for NetBSD to ensure this works.
+ endif()
+
+ if (EVENT__ENABLE_GCC_WARNINGS)
+ list(APPEND __FLAGS -Werror)
+ endif()
+
+ # We need to test for at least gcc 2.95 here, because older versions don't
+ # have -fno-strict-aliasing
+ list(APPEND __FLAGS -fno-strict-aliasing)
+
+ add_compiler_flags(${__FLAGS})
+endif()
+
+if (APPLE)
+ # Get rid of deprecated warnings for OpenSSL on OSX 10.7 and greater.
+ add_compiler_flags(
+ -Wno-error=deprecated-declarations
+ -Qunused-arguments
+ )
+endif()
+
+# Winsock.
+if(WIN32)
+ set(CMAKE_EXTRA_INCLUDE_FILES winsock2.h ws2tcpip.h)
+ set(CMAKE_REQUIRED_LIBRARIES ws2_32.lib)
+ set(CMAKE_REQUIRED_DEFINITIONS -FIwinsock2.h -FIws2tcpip.h)
+endif()
+if (SOLARIS)
+ set(CMAKE_REQUIRED_LIBRARIES socket nsl)
+endif()
+
+# Check if _GNU_SOURCE is available.
+CHECK_SYMBOL_EXISTS(__GNU_LIBRARY__ "features.h" _GNU_SOURCE)
+
+if (_GNU_SOURCE)
+ add_definitions(-D_GNU_SOURCE)
+endif()
+
+CHECK_INCLUDE_FILE(sys/types.h EVENT__HAVE_SYS_TYPES_H)
+if(EVENT__HAVE_SYS_TYPES_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES sys/types.h)
+endif()
+
+CHECK_INCLUDE_FILE(sys/socket.h EVENT__HAVE_SYS_SOCKET_H)
+if(EVENT__HAVE_SYS_SOCKET_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES sys/socket.h)
+endif()
+
+CHECK_INCLUDE_FILE(netinet/in.h EVENT__HAVE_NETINET_IN_H)
+if(EVENT__HAVE_NETINET_IN_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES netinet/in.h)
+endif()
+
+CHECK_INCLUDE_FILE(netinet/in6.h EVENT__HAVE_NETINET_IN6_H)
+if(EVENT__HAVE_NETINET_IN6_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES netinet/in6.h)
+endif()
+
+CHECK_INCLUDE_FILE(unistd.h EVENT__HAVE_UNISTD_H)
+CHECK_INCLUDE_FILE(netdb.h EVENT__HAVE_NETDB_H)
+CHECK_INCLUDE_FILE(dlfcn.h EVENT__HAVE_DLFCN_H)
+CHECK_INCLUDE_FILE(arpa/inet.h EVENT__HAVE_ARPA_INET_H)
+CHECK_INCLUDE_FILE(fcntl.h EVENT__HAVE_FCNTL_H)
+if(EVENT__HAVE_FCNTL_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES fcntl.h)
+endif()
+CHECK_INCLUDE_FILE(inttypes.h EVENT__HAVE_INTTYPES_H)
+CHECK_INCLUDE_FILE(memory.h EVENT__HAVE_MEMORY_H)
+CHECK_INCLUDE_FILE(poll.h EVENT__HAVE_POLL_H)
+CHECK_INCLUDE_FILE(port.h EVENT__HAVE_PORT_H)
+if(EVENT__HAVE_PORT_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES port.h)
+endif()
+CHECK_INCLUDE_FILE(signal.h EVENT__HAVE_SIGNAL_H)
+CHECK_INCLUDE_FILE(stdarg.h EVENT__HAVE_STDARG_H)
+CHECK_INCLUDE_FILE(stddef.h EVENT__HAVE_STDDEF_H)
+CHECK_INCLUDE_FILE(stdint.h EVENT__HAVE_STDINT_H)
+CHECK_INCLUDE_FILE(stdlib.h EVENT__HAVE_STDLIB_H)
+CHECK_INCLUDE_FILE(strings.h EVENT__HAVE_STRINGS_H)
+CHECK_INCLUDE_FILE(string.h EVENT__HAVE_STRING_H)
+CHECK_INCLUDE_FILE(sys/devpoll.h EVENT__HAVE_SYS_DEVPOLL_H)
+CHECK_INCLUDE_FILE(sys/epoll.h EVENT__HAVE_SYS_EPOLL_H)
+CHECK_INCLUDE_FILE(sys/eventfd.h EVENT__HAVE_SYS_EVENTFD_H)
+CHECK_INCLUDE_FILE(sys/event.h EVENT__HAVE_SYS_EVENT_H)
+CHECK_INCLUDE_FILE(sys/ioctl.h EVENT__HAVE_SYS_IOCTL_H)
+CHECK_INCLUDE_FILE(sys/mman.h EVENT__HAVE_SYS_MMAN_H)
+CHECK_INCLUDE_FILE(sys/param.h EVENT__HAVE_SYS_PARAM_H)
+CHECK_INCLUDE_FILE(sys/queue.h EVENT__HAVE_SYS_QUEUE_H)
+CHECK_INCLUDE_FILE(sys/select.h EVENT__HAVE_SYS_SELECT_H)
+CHECK_INCLUDE_FILE(sys/sendfile.h EVENT__HAVE_SYS_SENDFILE_H)
+CHECK_INCLUDE_FILE(sys/stat.h EVENT__HAVE_SYS_STAT_H)
+CHECK_INCLUDE_FILE(sys/time.h EVENT__HAVE_SYS_TIME_H)
+if(EVENT__HAVE_SYS_TIME_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES sys/time.h)
+endif()
+CHECK_INCLUDE_FILE(sys/uio.h EVENT__HAVE_SYS_UIO_H)
+CHECK_INCLUDE_FILES("sys/types.h;ifaddrs.h" EVENT__HAVE_IFADDRS_H)
+CHECK_INCLUDE_FILE(mach/mach_time.h EVENT__HAVE_MACH_MACH_TIME_H)
+CHECK_INCLUDE_FILE(netinet/tcp.h EVENT__HAVE_NETINET_TCP_H)
+CHECK_INCLUDE_FILE(sys/wait.h EVENT__HAVE_SYS_WAIT_H)
+CHECK_INCLUDE_FILE(sys/resource.h EVENT__HAVE_SYS_RESOURCE_H)
+CHECK_INCLUDE_FILE(sys/sysctl.h EVENT__HAVE_SYS_SYSCTL_H)
+CHECK_INCLUDE_FILE(sys/timerfd.h EVENT__HAVE_SYS_TIMERFD_H)
+CHECK_INCLUDE_FILE(errno.h EVENT__HAVE_ERRNO_H)
+
+
+CHECK_FUNCTION_EXISTS_EX(epoll_create EVENT__HAVE_EPOLL)
+CHECK_FUNCTION_EXISTS_EX(epoll_ctl EVENT__HAVE_EPOLL_CTL)
+CHECK_FUNCTION_EXISTS_EX(eventfd EVENT__HAVE_EVENTFD)
+if(NOT EVENT__DISABLE_CLOCK_GETTIME)
+ CHECK_FUNCTION_EXISTS_EX(clock_gettime EVENT__HAVE_CLOCK_GETTIME)
+endif()
+CHECK_FUNCTION_EXISTS_EX(fcntl EVENT__HAVE_FCNTL)
+CHECK_FUNCTION_EXISTS_EX(getaddrinfo EVENT__HAVE_GETADDRINFO)
+CHECK_FUNCTION_EXISTS_EX(getnameinfo EVENT__HAVE_GETNAMEINFO)
+CHECK_FUNCTION_EXISTS_EX(gettimeofday EVENT__HAVE_GETTIMEOFDAY)
+CHECK_FUNCTION_EXISTS_EX(getprotobynumber EVENT__HAVE_GETPROTOBYNUMBER)
+CHECK_FUNCTION_EXISTS_EX(getservbyname EVENT__HAVE_GETSERVBYNAME)
+CHECK_FUNCTION_EXISTS_EX(inet_ntop EVENT__HAVE_INET_NTOP)
+CHECK_FUNCTION_EXISTS_EX(inet_pton EVENT__HAVE_INET_PTON)
+CHECK_FUNCTION_EXISTS_EX(kqueue EVENT__HAVE_KQUEUE)
+CHECK_FUNCTION_EXISTS_EX(mmap EVENT__HAVE_MMAP)
+CHECK_FUNCTION_EXISTS_EX(pipe EVENT__HAVE_PIPE)
+CHECK_FUNCTION_EXISTS_EX(pipe2 EVENT__HAVE_PIPE2)
+CHECK_FUNCTION_EXISTS_EX(poll EVENT__HAVE_POLL)
+CHECK_FUNCTION_EXISTS_EX(port_create EVENT__HAVE_PORT_CREATE)
+CHECK_FUNCTION_EXISTS_EX(sendfile EVENT__HAVE_SENDFILE)
+CHECK_FUNCTION_EXISTS_EX(sigaction EVENT__HAVE_SIGACTION)
+CHECK_FUNCTION_EXISTS_EX(signal EVENT__HAVE_SIGNAL)
+CHECK_FUNCTION_EXISTS_EX(splice EVENT__HAVE_SPLICE)
+CHECK_FUNCTION_EXISTS_EX(strlcpy EVENT__HAVE_STRLCPY)
+CHECK_FUNCTION_EXISTS_EX(strsep EVENT__HAVE_STRSEP)
+CHECK_FUNCTION_EXISTS_EX(strtok_r EVENT__HAVE_STRTOK_R)
+CHECK_FUNCTION_EXISTS_EX(strtoll EVENT__HAVE_STRTOLL)
+CHECK_FUNCTION_EXISTS_EX(vasprintf EVENT__HAVE_VASPRINTF)
+CHECK_FUNCTION_EXISTS_EX(sysctl EVENT__HAVE_SYSCTL)
+CHECK_FUNCTION_EXISTS_EX(accept4 EVENT__HAVE_ACCEPT4)
+CHECK_FUNCTION_EXISTS_EX(arc4random EVENT__HAVE_ARC4RANDOM)
+CHECK_FUNCTION_EXISTS_EX(arc4random_buf EVENT__HAVE_ARC4RANDOM_BUF)
+CHECK_FUNCTION_EXISTS_EX(epoll_create1 EVENT__HAVE_EPOLL_CREATE1)
+CHECK_FUNCTION_EXISTS_EX(getegid EVENT__HAVE_GETEGID)
+CHECK_FUNCTION_EXISTS_EX(geteuid EVENT__HAVE_GETEUID)
+CHECK_FUNCTION_EXISTS_EX(getifaddrs EVENT__HAVE_GETIFADDRS)
+CHECK_FUNCTION_EXISTS_EX(issetugid EVENT__HAVE_ISSETUGID)
+CHECK_FUNCTION_EXISTS_EX(mach_absolute_time EVENT__HAVE_MACH_ABSOLUTE_TIME)
+CHECK_FUNCTION_EXISTS_EX(nanosleep EVENT__HAVE_NANOSLEEP)
+CHECK_FUNCTION_EXISTS_EX(usleep EVENT__HAVE_USLEEP)
+CHECK_FUNCTION_EXISTS_EX(timeradd EVENT__HAVE_TIMERADD)
+CHECK_FUNCTION_EXISTS_EX(timerclear EVENT__HAVE_TIMERCLEAR)
+CHECK_FUNCTION_EXISTS_EX(timercmp EVENT__HAVE_TIMERCMP)
+CHECK_FUNCTION_EXISTS_EX(timerfd_create HAVE_TIMERFD_CREATE)
+CHECK_FUNCTION_EXISTS_EX(timerisset EVENT__HAVE_TIMERISSET)
+CHECK_FUNCTION_EXISTS_EX(putenv EVENT__HAVE_PUTENV)
+CHECK_FUNCTION_EXISTS_EX(setenv EVENT__HAVE_SETENV)
+CHECK_FUNCTION_EXISTS_EX(setrlimit EVENT__HAVE_SETRLIMIT)
+CHECK_FUNCTION_EXISTS_EX(umask EVENT__HAVE_UMASK)
+CHECK_FUNCTION_EXISTS_EX(unsetenv EVENT__HAVE_UNSETENV)
+
+# Get the gethostbyname_r prototype.
+CHECK_FUNCTION_EXISTS_EX(gethostbyname_r EVENT__HAVE_GETHOSTBYNAME_R)
+
+if(EVENT__HAVE_GETHOSTBYNAME_R)
+ CHECK_PROTOTYPE_DEFINITION(gethostbyname_r
+ "int gethostbyname_r(const char *name, struct hostent *hp, struct hostent_data *hdata)"
+ "0"
+ "netdb.h"
+ EVENT__HAVE_GETHOSTBYNAME_R_3_ARG)
+
+ CHECK_PROTOTYPE_DEFINITION(gethostbyname_r
+ "struct hostent *gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen, int *herr)"
+ "NULL"
+ "netdb.h"
+ EVENT__HAVE_GETHOSTBYNAME_R_5_ARG)
+
+ CHECK_PROTOTYPE_DEFINITION(gethostbyname_r
+ "int gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen, struct hostent **result, int *herr)"
+ "0"
+ "netdb.h"
+ EVENT__HAVE_GETHOSTBYNAME_R_6_ARG)
+endif()
+
+if(HAVE_PORT_H AND HAVE_PORT_CREATE)
+ set(EVENT__HAVE_EVENT_PORTS 1)
+endif()
+
+if(NOT WIN32)
+ CHECK_FUNCTION_EXISTS_EX(select EVENT__HAVE_SELECT)
+endif()
+
+CHECK_TYPE_SIZE("uint8_t" EVENT__HAVE_UINT8_T)
+CHECK_TYPE_SIZE("uint16_t" EVENT__HAVE_UINT16_T)
+CHECK_TYPE_SIZE("uint32_t" EVENT__HAVE_UINT32_T)
+CHECK_TYPE_SIZE("uint64_t" EVENT__HAVE_UINT64_T)
+CHECK_TYPE_SIZE("short" EVENT__SIZEOF_SHORT BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("int" EVENT__SIZEOF_INT BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("unsigned" EVENT__SIZEOF_UNSIGNED BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("unsigned int" EVENT__SIZEOF_UNSIGNED_INT BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("long" EVENT__SIZEOF_LONG BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("long long" EVENT__SIZEOF_LONG_LONG BUILTIN_TYPES_ONLY)
+
+if(WIN32)
+ # These aren't available until Windows Vista.
+ # But you can still link them. They just won't be found when running the exe.
+ set(EVENT__HAVE_INET_NTOP 0)
+ set(EVENT__HAVE_INET_PTON 0)
+endif()
+
+# Check for different inline keyword versions.
+check_function_keywords("inline" "__inline" "__inline__")
+
+if (HAVE_INLINE)
+ set (EVENT__inline inline)
+elseif (HAVE___INLINE)
+ set(EVENT__inline __inline)
+elseif(HAVE___INLINE__)
+ set(EVENT__inline __inline__)
+else()
+ set(EVENT__inline)
+endif()
+
+CHECK_SYMBOL_EXISTS(TAILQ_FOREACH sys/queue.h EVENT__HAVE_TAILQFOREACH)
+CHECK_SYMBOL_EXISTS(CTL_KERN sys/sysctl.h EVENT__HAVE_DECL_CTL_KERN)
+CHECK_SYMBOL_EXISTS(KERN_ARND sys/sysctl.h EVENT__HAVE_DECL_KERN_ARND)
+CHECK_SYMBOL_EXISTS(KERN_RANDOM sys/sysctl.h EVENT__HAVE_DECL_KERN_RANDOM)
+CHECK_SYMBOL_EXISTS(RANDOM_UUID sys/sysctl.h EVENT__HAVE_DECL_RANDOM_UUID)
+CHECK_SYMBOL_EXISTS(F_SETFD fcntl.h EVENT__HAVE_SETFD)
+
+CHECK_TYPE_SIZE(fd_mask EVENT__HAVE_FD_MASK)
+
+CHECK_TYPE_SIZE(size_t EVENT__SIZEOF_SIZEE_T)
+if(NOT EVENT__SIZEOF_SIZE_T)
+ set(EVENT__size_t "unsigned")
+ set(EVENT__SIZEOF_SIZE_T ${EVENT__SIZEOF_UNSIGNED})
+else()
+ set(EVENT__size_t size_t)
+endif()
+
+CHECK_TYPE_SIZE("off_t" EVENT__SIZEOF_OFF_T LANGUAGE C)
+
+
+# XXX we should functionalize these size and type sets. --elley
+
+# Winssck.
+if (_MSC_VER)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES BaseTsd.h)
+endif()
+CHECK_TYPE_SIZE("ssize_t" EVENT__SIZEOF_SSIZE_T_LOWER LANGUAGE C)
+CHECK_TYPE_SIZE("SSIZE_T" EVENT__SIZEOF_SSIZE_T_UPPER LANGUAGE C)
+
+if (EVENT__SIZEOF_SSIZE_T_LOWER)
+ set(EVENT__ssize_t "ssize_t")
+ set(EVENT__SIZEOF_SSIZE_T ${EVENT__SIZEOF_SSIZE_T_LOWER})
+elseif (EVENT__SIZEOF_SSIZE_T_UPPER)
+ set(EVENT__ssize_t "SSIZE_T")
+ set(EVENT__SIZEOF_SSIZE_T ${EVENT__SIZEOF_SSIZE_T_UPPER})
+else()
+ set(EVENT__ssize_t "int")
+ set(EVENT__SIZEOF_SSIZE_T ${EVENT__SIZEOF_INT})
+endif()
+
+
+CHECK_TYPE_SIZE(socklen_t EVENT__SIZEOF_SOCKLEN_T)
+if(NOT EVENT__SIZEOF_SOCKLEN_T)
+ set(EVENT__socklen_t "unsigned int")
+ set(EVENT__SIZEOF_SOCKLEN_T ${EVENT__SIZEOF_UNSIGNED_INT})
+else()
+ set(EVENT__socklen_t "socklen_t")
+endif()
+
+CHECK_TYPE_SIZE(pid_t EVENT__SIZEOF_PID_T)
+if(NOT EVENT__SIZEOF_PID_T)
+ set(EVENT__pid_t "int")
+ set(EVENT__SIZEOF_PID_T ${EVENT__SIZEOF_INT})
+else()
+ set(EVENT__pid_t "pid_t")
+ set(EVENT__SIZEOF_PID_T EVENT__SIZEOF_PID_T)
+endif()
+
+if (NOT EVENT__DISABLE_THREAD_SUPPORT)
+ CHECK_TYPE_SIZE(pthread_t EVENT__SIZEOF_PTHREAD_T)
+endif()
+
+if(EVENT__HAVE_CLOCK_GETTIME)
+ set(EVENT__DNS_USE_CPU_CLOCK_FOR_ID 1)
+endif()
+
+# we're just getting lazy now.
+CHECK_TYPE_SIZE("uintptr_t" EVENT__HAVE_UINTPTR_T)
+CHECK_TYPE_SIZE("void *" EVENT__SIZEOF_VOID_P)
+
+# Tests file offset bits.
+# TODO: Add AIX test for if -D_LARGE_FILES is needed.
+
+# XXX: Why is this here? we don't even use it. Well, we don't even use it
+# on top of that, why is it set in the config.h?! IT_MAKES_NO_SENSE
+# I'm commenting it out for now.
+# - ellzey
+
+#CHECK_FILE_OFFSET_BITS()
+#set(EVENT___FILE_OFFSET_BITS _FILE_OFFSET_BITS)
+
+include(CheckWaitpidSupportWNOWAIT)
+
+# Verify kqueue works with pipes.
+if (EVENT__HAVE_KQUEUE)
+ if (CMAKE_CROSSCOMPILING AND NOT EVENT__FORCE_KQUEUE_CHECK)
+ message(WARNING "Cannot check if kqueue works with pipes when crosscompiling, use EVENT__FORCE_KQUEUE_CHECK to be sure (this requires manually running a test program on the cross compilation target)")
+ set(EVENT__HAVE_WORKING_KQUEUE 1)
+ else()
+ message(STATUS "Checking if kqueue works with pipes...")
+ include(CheckWorkingKqueue)
+ endif()
+endif()
+
+CHECK_SYMBOL_EXISTS(_MINIX "stdio.h" EVENT___MINIX)
+CHECK_SYMBOL_EXISTS(_POSIX_1_SOURCE "stdio.h" EVENT___POSIX_1_SOURCE)
+CHECK_SYMBOL_EXISTS(_POSIX_SOURCE "stdio.h" EVENT___POSIX_SOURCE)
+
+if(EVENT__HAVE_NETDB_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES netdb.h)
+ CHECK_TYPE_SIZE("struct addrinfo" EVENT__HAVE_STRUCT_ADDRINFO)
+elseif(WIN32)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES ws2tcpip.h)
+ CHECK_TYPE_SIZE("struct addrinfo" EVENT__HAVE_STRUCT_ADDRINFO)
+endif()
+
+# Check for sockaddr structure sizes.
+set(SOCKADDR_HEADERS)
+if (WIN32)
+ set(CMAKE_REQUIRED_DEFINITIONS "-DWIN32_LEAN_AND_MEAN")
+ if (_MSC_VER LESS 1300)
+ set(SOCKADDR_HEADERS winsock.h)
+ else()
+ set(SOCKADDR_HEADERS winsock2.h ws2tcpip.h)
+ endif()
+else()
+ if (EVENT__HAVE_NETINET_IN_H)
+ set(SOCKADDR_HEADERS ${SOCKADDR_HEADERS} netinet/in.h)
+ endif()
+
+ if (EVENT__HAVE_NETINET_IN6_H)
+ set(SOCKADDR_HEADERS ${SOCKADDR_HEADERS} netinet/in6.h)
+ endif()
+
+ if (EVENT__HAVE_SYS_SOCKET_H)
+ set(SOCKADDR_HEADERS ${SOCKADDR_HEADERS} sys/socket.h)
+ endif()
+
+ if (EVENT__HAVE_NETDB_H)
+ set(SOCKADDR_HEADERS ${SOCKADDR_HEADERS} netdb.h)
+ endif()
+endif()
+
+CHECK_TYPE_SIZE("struct in6_addr" EVENT__HAVE_STRUCT_IN6_ADDR)
+if(EVENT__HAVE_STRUCT_IN6_ADDR)
+ CHECK_STRUCT_HAS_MEMBER("struct in6_addr"
+ s6_addr16 "${SOCKADDR_HEADERS}"
+ EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR16)
+
+ CHECK_STRUCT_HAS_MEMBER("struct in6_addr"
+ s6_addr32 "${SOCKADDR_HEADERS}"
+ EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR32)
+endif()
+
+CHECK_TYPE_SIZE("sa_family_t" EVENT__HAVE_SA_FAMILY_T)
+CHECK_TYPE_SIZE("struct sockaddr_in6" EVENT__HAVE_STRUCT_SOCKADDR_IN6)
+
+if(EVENT__HAVE_STRUCT_SOCKADDR_IN6)
+ CHECK_STRUCT_HAS_MEMBER("struct sockaddr_in6"
+ sin6_len "${SOCKADDR_HEADERS}"
+ EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN)
+
+ CHECK_STRUCT_HAS_MEMBER("struct sockaddr_in6"
+ sin_len "${SOCKADDR_HEADERS}"
+ EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN)
+endif()
+
+CHECK_TYPE_SIZE("struct sockaddr_storage" EVENT__HAVE_STRUCT_SOCKADDR_STORAGE)
+if(EVENT__HAVE_STRUCT_SOCKADDR_STORAGE)
+ CHECK_STRUCT_HAS_MEMBER("struct sockaddr_storage"
+ ss_family "${SOCKADDR_HEADERS}"
+ EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY)
+
+ CHECK_STRUCT_HAS_MEMBER("struct sockaddr_storage"
+ __ss_family "${SOCKADDR_HEADERS}" EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY)
+endif()
+
+# Group the source files.
+set(HDR_PRIVATE
+ bufferevent-internal.h
+ changelist-internal.h
+ defer-internal.h
+ epolltable-internal.h
+ evbuffer-internal.h
+ event-internal.h
+ evmap-internal.h
+ evrpc-internal.h
+ evsignal-internal.h
+ evthread-internal.h
+ ht-internal.h
+ http-internal.h
+ iocp-internal.h
+ ipv6-internal.h
+ log-internal.h
+ minheap-internal.h
+ mm-internal.h
+ ratelim-internal.h
+ strlcpy-internal.h
+ util-internal.h
+ evconfig-private.h
+ compat/sys/queue.h)
+
+set(HDR_COMPAT
+ include/evdns.h
+ include/evrpc.h
+ include/event.h
+ include/evhttp.h
+ include/evutil.h)
+
+set(HDR_PUBLIC
+ include/event2/buffer.h
+ include/event2/bufferevent.h
+ include/event2/bufferevent_compat.h
+ include/event2/bufferevent_struct.h
+ include/event2/buffer_compat.h
+ include/event2/dns.h
+ include/event2/dns_compat.h
+ include/event2/dns_struct.h
+ include/event2/event.h
+ include/event2/event_compat.h
+ include/event2/event_struct.h
+ include/event2/http.h
+ include/event2/http_compat.h
+ include/event2/http_struct.h
+ include/event2/keyvalq_struct.h
+ include/event2/listener.h
+ include/event2/rpc.h
+ include/event2/rpc_compat.h
+ include/event2/rpc_struct.h
+ include/event2/tag.h
+ include/event2/tag_compat.h
+ include/event2/thread.h
+ include/event2/util.h
+ include/event2/visibility.h
+ ${PROJECT_BINARY_DIR}/include/event2/event-config.h)
+
+set(SRC_CORE
+ buffer.c
+ bufferevent.c
+ bufferevent_filter.c
+ bufferevent_pair.c
+ bufferevent_ratelim.c
+ bufferevent_sock.c
+ event.c
+ evmap.c
+ evthread.c
+ evutil.c
+ evutil_rand.c
+ evutil_time.c
+ listener.c
+ log.c
+ signal.c
+ strlcpy.c)
+
+if(EVENT__HAVE_SELECT)
+ list(APPEND SRC_CORE select.c)
+endif()
+
+if(EVENT__HAVE_POLL)
+ list(APPEND SRC_CORE poll.c)
+endif()
+
+if(EVENT__HAVE_KQUEUE)
+ list(APPEND SRC_CORE kqueue.c)
+endif()
+
+if(EVENT__HAVE_DEVPOLL)
+ list(APPEND SRC_CORE devpoll.c)
+endif()
+
+if(EVENT__HAVE_EPOLL)
+ list(APPEND SRC_CORE epoll_sub.c epoll.c)
+endif()
+
+if(EVENT__HAVE_EVENT_PORTS)
+ list(APPEND SRC_CORE evport.c)
+endif()
+
+if (NOT EVENT__DISABLE_OPENSSL)
+ find_package(OpenSSL REQUIRED)
+
+ set(EVENT__HAVE_OPENSSL 1)
+
+ message(STATUS "OpenSSL include: ${OPENSSL_INCLUDE_DIR}")
+ message(STATUS "OpenSSL lib: ${OPENSSL_LIBRARIES}")
+
+ include_directories(${OPENSSL_INCLUDE_DIR})
+
+ list(APPEND SRC_CORE bufferevent_openssl.c)
+ list(APPEND HDR_PUBLIC include/event2/bufferevent_ssl.h)
+ list(APPEND LIB_APPS ${OPENSSL_LIBRARIES})
+endif()
+
+if (NOT EVENT__DISABLE_THREAD_SUPPORT)
+ if (WIN32)
+ list(APPEND SRC_CORE evthread_win32.c)
+ else()
+ find_package(Threads REQUIRED)
+ if (NOT CMAKE_USE_PTHREADS_INIT)
+ message(FATAL_ERROR
+ "Failed to find Pthreads, set EVENT__DISABLE_THREAD_SUPPORT to disable")
+ endif()
+
+ set(EVENT__HAVE_PTHREADS 1)
+ list(APPEND SRC_CORE evthread_pthread.c)
+ list(APPEND LIB_APPS ${CMAKE_THREAD_LIBS_INIT})
+ endif()
+endif()
+
+if (NOT EVENT__DISABLE_TESTS)
+ # Zlib is only used for testing.
+ find_package(ZLIB)
+
+ if (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
+ include_directories(${ZLIB_INCLUDE_DIRS})
+
+ set(EVENT__HAVE_LIBZ 1)
+ list(APPEND LIB_APPS ${ZLIB_LIBRARIES})
+ endif()
+endif()
+
+set(SRC_EXTRA
+ event_tagging.c
+ http.c
+ evdns.c
+ evrpc.c)
+
+add_definitions(-DHAVE_CONFIG_H)
+
+# We use BEFORE here so we don't accidentally look in system directories
+# first for some previous versions of the headers that are installed.
+include_directories(BEFORE ${PROJECT_SOURCE_DIR}
+ ${PROJECT_SOURCE_DIR}/compat
+ ${PROJECT_SOURCE_DIR}/include)
+
+if(WIN32)
+ list(APPEND SRC_CORE
+ buffer_iocp.c
+ bufferevent_async.c
+ event_iocp.c
+ win32select.c)
+
+ list(APPEND HDR_PRIVATE WIN32-Code/getopt.h)
+
+ set(EVENT__DNS_USE_FTIME_FOR_ID 1)
+ set(LIB_PLATFORM ws2_32)
+ add_definitions(
+ -D_CRT_SECURE_NO_WARNINGS
+ -D_CRT_NONSTDC_NO_DEPRECATE)
+
+ include_directories(./WIN32-Code)
+endif()
+
+if (UNIX)
+ list(APPEND LIB_PLATFORM m)
+endif()
+
+if (SOLARIS)
+ list(APPEND LIB_PLATFORM socket nsl)
+endif()
+
+source_group("Headers Private" FILES ${HDR_PRIVATE})
+source_group("Header Compat" FILES ${HDR_COMPAT})
+source_group("Headers Public" FILES ${HDR_PUBLIC})
+source_group("Source Core" FILES ${SRC_CORE})
+source_group("Source Extra" FILES ${SRC_EXTRA})
+
+# Generate the configure headers.
+# (Place them in the build dir so we don't polute the source tree with generated files).
+include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include)
+
+if (EVENT__BUILD_SHARED_LIBRARIES)
+ set(EVENT__LIBRARY_TYPE SHARED)
+
+ if ((CMAKE_COMPILER_IS_GNUCC) OR (${CMAKE_C_COMPILER_ID} STREQUAL "Clang"))
+ add_compiler_flags(-fvisibility=hidden)
+ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "SunPro")
+ add_compiler_flags(-xldscope=hidden)
+ endif()
+
+ set(EVENT__NEED_DLLIMPORT 1)
+else (EVENT__BUILD_SHARED_LIBRARIES)
+ set(EVENT__LIBRARY_TYPE STATIC)
+endif (EVENT__BUILD_SHARED_LIBRARIES)
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/event-config.h.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/include/event2/event-config.h
+ NEWLINE_STYLE UNIX)
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/evconfig-private.h.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/include/evconfig-private.h)
+
+#
+# Create the libraries.
+#
+
+# TODO: Add dynamic versions of the libraries as well.
+add_library(event_core ${EVENT__LIBRARY_TYPE}
+ ${HDR_PRIVATE}
+ ${HDR_COMPAT}
+ ${HDR_PUBLIC}
+ ${SRC_CORE})
+
+add_library(event_extra ${EVENT__LIBRARY_TYPE}
+ ${HDR_PRIVATE}
+ ${HDR_COMPAT}
+ ${HDR_PUBLIC}
+ ${SRC_CORE}
+ ${SRC_EXTRA})
+
+# library exists for historical reasons; it contains the contents of
+# both libevent_core and libevent_extra. You shouldn’t use it; it may
+# go away in a future version of Libevent.
+add_library(event ${EVENT__LIBRARY_TYPE}
+ ${HDR_PRIVATE}
+ ${HDR_COMPAT}
+ ${HDR_PUBLIC}
+ ${SRC_CORE}
+ ${SRC_EXTRA})
+
+if (EVENT__BUILD_SHARED_LIBRARIES)
+ # Prepare static library to be linked to tests that need hidden symbols
+ add_library(event_extra_static STATIC
+ ${HDR_PRIVATE}
+ ${HDR_COMPAT}
+ ${HDR_PUBLIC}
+ ${SRC_CORE}
+ ${SRC_EXTRA})
+
+ set(EVENT_EXTRA_FOR_TEST event_extra_static)
+
+ target_link_libraries(event_core ${OPENSSL_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${LIB_PLATFORM})
+
+ target_link_libraries(event ${OPENSSL_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${LIB_PLATFORM})
+
+ target_link_libraries(event_extra ${OPENSSL_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${LIB_PLATFORM})
+
+ set_target_properties(event
+ PROPERTIES SOVERSION
+ ${EVENT_ABI_LIBVERSION})
+
+ set_target_properties(event_core
+ PROPERTIES SOVERSION
+ ${EVENT_ABI_LIBVERSION})
+
+ set_target_properties(event_extra
+ PROPERTIES SOVERSION
+ ${EVENT_ABI_LIBVERSION})
+
+else (EVENT__BUILD_SHARED_LIBRARIES)
+ set(EVENT_EXTRA_FOR_TEST event_extra)
+endif (EVENT__BUILD_SHARED_LIBRARIES)
+
+#
+# Samples.
+#
+
+if (NOT EVENT__DISABLE_SAMPLES)
+ set(SAMPLES
+ dns-example
+ event-read-fifo
+ hello-world
+ signal-test
+ http-server
+ http-connect
+ time-test)
+
+ if (NOT EVENT__DISABLE_OPENSSL AND OPENSSL_LIBRARIES)
+ set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES})
+ CHECK_FUNCTION_EXISTS_EX(ERR_remove_thread_state EVENT__HAVE_ERR_REMOVE_THREAD_STATE)
+ set(CMAKE_REQUIRED_LIBRARIES "")
+
+ # Special sample with more than one file.
+ add_executable(https-client
+ sample/https-client.c
+ sample/openssl_hostname_validation.c
+ sample/hostcheck.c)
+
+ target_link_libraries(https-client
+ event_extra
+ ${LIB_APPS}
+ ${LIB_PLATFORM})
+
+ add_dependencies(https-client event_extra)
+
+ # Requires OpenSSL.
+ list(APPEND SAMPLES le-proxy)
+ endif()
+
+ foreach(SAMPLE ${SAMPLES})
+ add_executable(${SAMPLE}
+ sample/${SAMPLE}.c)
+
+ target_link_libraries(${SAMPLE}
+ event_extra
+ ${LIB_APPS}
+ ${LIB_PLATFORM})
+
+ add_dependencies(${SAMPLE} event_extra)
+ endforeach()
+
+ if (WIN32)
+ target_sources(dns-example PUBLIC
+ WIN32-Code/getopt.c
+ WIN32-Code/getopt_long.c)
+ endif()
+endif()
+
+if (NOT EVENT__DISABLE_BENCHMARK)
+ foreach (BENCHMARK bench bench_cascade bench_http bench_httpclient)
+ set(BENCH_SRC test/${BENCHMARK}.c)
+
+ if (WIN32)
+ list(APPEND BENCH_SRC
+ WIN32-Code/getopt.c
+ WIN32-Code/getopt_long.c)
+ endif()
+
+ add_executable(${BENCHMARK} ${BENCH_SRC})
+
+ target_link_libraries(${BENCHMARK}
+ event_extra
+ ${LIB_PLATFORM})
+
+ add_dependencies(${BENCHMARK} event_extra)
+ endforeach()
+endif()
+
+if (NOT EVENT__DISABLE_TESTS)
+ #
+ # Generate Regress tests.
+ #
+ if (NOT EVENT__DISABLE_REGRESS)
+
+ # (We require python2 to generate the regress tests)
+ foreach (PY python2.6 python2.7 python2)
+ unset(FIND_PYTHON2 CACHE)
+ find_program(FIND_PYTHON2 ${PY})
+ if (FIND_PYTHON2)
+ set(PYTHON_EXECUTABLE "${PY}")
+ break()
+ endif()
+ endforeach()
+ find_package(PythonInterp)
+
+ if (PYTHONINTERP_FOUND AND PYTHON_VERSION_STRING VERSION_LESS "3.0.0")
+ set(__FOUND_USABLE_PYTHON 1)
+ endif()
+
+ if (__FOUND_USABLE_PYTHON)
+ message(STATUS "Generating regress tests...")
+
+ add_definitions(-DTINYTEST_LOCAL)
+
+ add_custom_command(
+ OUTPUT
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/regress.gen.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/regress.gen.h
+ DEPENDS
+ event_rpcgen.py
+ test/regress.rpc
+ COMMAND ${PYTHON_EXECUTABLE} ../event_rpcgen.py regress.rpc
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+
+ list(APPEND SRC_REGRESS
+ test/regress.c
+ test/regress.gen.c
+ test/regress.gen.h
+ test/regress_buffer.c
+ test/regress_bufferevent.c
+ test/regress_dns.c
+ test/regress_et.c
+ test/regress_finalize.c
+ test/regress_http.c
+ test/regress_listener.c
+ test/regress_main.c
+ test/regress_minheap.c
+ test/regress_rpc.c
+ test/regress_testutils.c
+ test/regress_testutils.h
+ test/regress_util.c
+ test/tinytest.c
+ ${SRC_CORE}
+ ${SRC_EXTRA})
+
+ if (WIN32)
+ list(APPEND SRC_REGRESS test/regress_iocp.c)
+ if (NOT EVENT__DISABLE_THREAD_SUPPORT)
+ list(APPEND SRC_REGRESS test/regress_thread.c)
+ endif()
+ endif()
+
+ if (CMAKE_USE_PTHREADS_INIT)
+ list(APPEND SRC_REGRESS test/regress_thread.c)
+ endif()
+
+ if (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
+ list(APPEND SRC_REGRESS test/regress_zlib.c)
+ endif()
+
+ if (OPENSSL_LIBRARIES)
+ list(APPEND SRC_REGRESS test/regress_ssl.c)
+ endif()
+
+ add_executable(regress ${SRC_REGRESS})
+
+ # While building the test suite we don't want the visibility
+ # header trying to "dllimport" the symbols on windows (it
+ # generates a ton of warnings due to different link
+ # attributes for all of the symbols)
+ SET_TARGET_PROPERTIES(regress
+ PROPERTIES COMPILE_DEFINITIONS
+ "EVENT_BUILDING_REGRESS_TEST=1")
+
+ target_link_libraries(regress
+ ${LIB_APPS}
+ ${LIB_PLATFORM})
+ else()
+ message(WARNING "No suitable Python interpreter found, cannot generate regress tests!")
+ endif()
+ endif()
+
+ #
+ # Test programs.
+ #
+ # all of these, including the cmakelists.txt should be moved
+ # into the dirctory 'tests' first.
+ #
+ # doing this, we can remove all the DISABLE_TESTS stuff, and simply
+ # do something like:
+ #
+ # add_custom_targets(tests)
+ # add_executable(... EXCLUDE_FROM_ALL ...c)
+ # add_dependencis(tests testa testb testc)
+ # add_test(....)
+ #
+ # then you can just run 'make tests' instead of them all
+ # auto-compile|running
+ # - ellzey
+ set(TESTPROGS test-changelist
+ test-eof
+ test-fdleak
+ test-init
+ test-time
+ test-weof)
+
+ set(ALL_TESTPROGS
+ ${TESTPROGS}
+ test-dumpevents
+ test-ratelim)
+
+ # Create test program executables.
+ foreach (TESTPROG ${ALL_TESTPROGS})
+ add_executable(${TESTPROG}
+ test/${TESTPROG}.c)
+
+ target_link_libraries(${TESTPROG}
+ ${EVENT_EXTRA_FOR_TEST}
+ ${LIB_PLATFORM})
+
+ add_dependencies(${TESTPROG}
+ ${EVENT_EXTRA_FOR_TEST})
+ endforeach()
+
+ #
+ # We run all tests with the different backends turned on one at a time.
+ #
+
+ # Add event backends based on system introspection result.
+ set(BACKENDS "")
+
+ if (EVENT__HAVE_EPOLL)
+ list(APPEND BACKENDS EPOLL)
+ endif()
+
+ if (EVENT__HAVE_SELECT)
+ list(APPEND BACKENDS SELECT)
+ endif()
+
+ if (EVENT__HAVE_POLL)
+ list(APPEND BACKENDS POLL)
+ endif()
+
+ if (EVENT__HAVE_KQUEUE)
+ list(APPEND BACKENDS KQUEUE)
+ endif()
+
+ if (EVENT__HAVE_EVENT_PORTS)
+ list(APPEND BACKENDS EVPORT)
+ endif()
+
+ if (EVENT__HAVE_DEVPOLL)
+ list(APPEND BACKENDS DEVPOLL)
+ endif()
+
+ if (WIN32)
+ list(APPEND BACKENDS WIN32)
+ endif()
+
+
+ # Default environment variables turns off all event systems,
+ # then we enable each one, one at a time when creating the tests.
+ set(DEFAULT_TEST_ENV_VARS "EVENT_SHOW_METHOD=1;")
+ foreach(BACKEND ${BACKENDS})
+ set(BACKEND_ENV_VAR "EVENT_NO${BACKEND}=1")
+ list(APPEND DEFAULT_TEST_ENV_VARS "${BACKEND_ENV_VAR}")
+ endforeach()
+
+ # Macro that creates the ctest test for a backend.
+ macro(add_backend_test BACKEND_TEST_NAME ENV_VARS)
+ set(TEST_NAMES "")
+
+ foreach (TESTPROG ${TESTPROGS})
+ set(TEST_NAME ${TESTPROG}__${BACKEND_TEST_NAME})
+
+ add_test(${TEST_NAME}
+ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTPROG})
+
+ list(APPEND TEST_NAMES ${TEST_NAME})
+
+ set_tests_properties(${TEST_NAME}
+ PROPERTIES ENVIRONMENT "${ENV_VARS}")
+ endforeach()
+
+ # Dump events test.
+ if (__FOUND_USABLE_PYTHON)
+ set(TEST_NAME test-dumpevents__${BACKEND_TEST_NAME})
+
+ add_test(${TEST_NAME}
+ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-dumpevents |
+ ${PYTHON_EXECUTABLE}
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/check-dumpevents.py)
+
+ set_tests_properties(${TEST_NAME}
+ PROPERTIES ENVIRONMENT "${ENV_VARS}")
+ else()
+ message(WARNING "test-dumpevents will be run without output check since python was not found!")
+ set(TEST_NAME test-dumpevents__${BACKEND_TEST_NAME}_no_check)
+
+ add_test(${TEST_NAME}
+ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-dumpevents)
+
+ set_tests_properties(${TEST_NAME}
+ PROPERTIES ENVIRONMENT "${ENV_VARS}")
+ endif()
+
+ # Regress tests.
+ if (NOT EVENT__DISABLE_REGRESS AND __FOUND_USABLE_PYTHON)
+ set(TEST_NAME regress__${BACKEND_TEST_NAME})
+
+ add_test(${TEST_NAME}
+ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/regress)
+
+ set_tests_properties(${TEST_NAME}
+ PROPERTIES ENVIRONMENT "${ENV_VARS}")
+
+ add_test(${TEST_NAME}_debug
+ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/regress)
+
+ set_tests_properties(${TEST_NAME}_debug
+ PROPERTIES ENVIRONMENT "${ENV_VARS};EVENT_DEBUG_MODE=1")
+ endif()
+ endmacro()
+
+ # Add the tests for each backend.
+ foreach(BACKEND ${BACKENDS})
+ # Enable this backend only.
+ set(BACKEND_ENV_VARS ${DEFAULT_TEST_ENV_VARS})
+ list(REMOVE_ITEM BACKEND_ENV_VARS EVENT_NO${BACKEND}=1)
+
+ # Epoll has some extra settings.
+ if (${BACKEND} STREQUAL "EPOLL")
+ add_backend_test(timerfd_${BACKEND}
+ "${BACKEND_ENV_VARS};EVENT_PRECISE_TIMER=1")
+
+ add_backend_test(changelist_${BACKEND}
+ "${BACKEND_ENV_VARS};EVENT_EPOLL_USE_CHANGELIST=yes")
+
+ add_backend_test(timerfd_changelist_${BACKEND}
+ "${BACKEND_ENV_VARS};EVENT_EPOLL_USE_CHANGELIST=yes;EVENT_PRECISE_TIMER=1")
+ else()
+ add_backend_test(${BACKEND} "${BACKEND_ENV_VARS}")
+ endif()
+ endforeach()
+
+ #
+ # Rate limiter tests.
+ #
+
+ # Group limits, no connection limit.
+ set(RL_BIN ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-ratelim)
+
+ add_test(test-ratelim__group_lim
+ ${RL_BIN}
+ -g 30000
+ -n 30
+ -t 100
+ --check-grouplimit 1000
+ --check-stddev 100)
+
+ # Connection limit, no group limit.
+ add_test(test-ratelim__con_lim
+ ${RL_BIN}
+ -c 1000
+ -n 30
+ -t 100
+ --check-connlimit 50
+ --check-stddev 50)
+
+ # Connection limit and group limit.
+ add_test(test-ratelim__group_con_lim
+ ${RL_BIN}
+ -c 1000
+ -g 30000
+ -n 30
+ -t 100
+ --check-grouplimit 1000
+ --check-connlimit 50
+ --check-stddev 50)
+
+ # Connection limit and group limit with independent drain.
+ add_test(test-ratelim__group_con_lim_drain
+ ${RL_BIN}
+ -c 1000
+ -g 35000
+ -n 30
+ -t 100
+ -G 500
+ --check-grouplimit 1000
+ --check-connlimit 50
+ --check-stddev 50)
+
+ # Add a "make verify" target, same as for autoconf.
+ # (Important! This will unset all EVENT_NO* environment variables.
+ # If they are set in the shell the tests are running using simply "ctest" or "make test" will fail)
+ if (WIN32)
+ # Windows doesn't have "unset". But you can use "set VAR=" instead.
+ # We need to guard against the possibility taht EVENT_NOWIN32 is set, and all test failing
+ # since no event backend being available.
+ file(TO_NATIVE_PATH ${CMAKE_CTEST_COMMAND} WINDOWS_CTEST_COMMAND)
+
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/tmp/verify_tests.bat
+ "
+ set EVENT_NOWIN32=
+ \"${WINDOWS_CTEST_COMMAND}\"
+ ")
+
+ message(STATUS "${WINDOWS_CTEST_COMMAND}")
+
+ file(COPY ${CMAKE_CURRENT_BINARY_DIR}/tmp/verify_tests.bat
+ DESTINATION
+ ${CMAKE_CURRENT_BINARY_DIR}
+ FILE_PERMISSIONS
+ OWNER_READ
+ OWNER_WRITE
+ OWNER_EXECUTE
+ GROUP_READ
+ GROUP_EXECUTE
+ WORLD_READ WORLD_EXECUTE)
+
+ file(TO_NATIVE_PATH
+ "${CMAKE_CURRENT_BINARY_DIR}/verify_tests.bat" VERIFY_PATH)
+
+ add_custom_target(verify COMMAND "${VERIFY_PATH}"
+ DEPENDS event ${ALL_TESTPROGS})
+ else()
+ # On some platforms doing exec(unset) as CMake does won't work, so make sure
+ # we run the unset command in a shell instead.
+ # First we write the script contents.
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/tmp/verify_tests.sh
+ "
+ #!/bin/bash
+ unset EVENT_NOEPOLL; unset EVENT_NOPOLL; unset EVENT_NOSELECT; unset EVENT_NOWIN32; unset EVENT_NOEVPORT; unset EVENT_NOKQUEUE; unset EVENT_NODEVPOLL
+ ${CMAKE_CTEST_COMMAND}
+ ")
+
+ # Then we copy the file (this allows us to set execute permission on it)
+ file(COPY ${CMAKE_CURRENT_BINARY_DIR}/tmp/verify_tests.sh
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
+ FILE_PERMISSIONS
+ OWNER_READ
+ OWNER_WRITE
+ OWNER_EXECUTE
+ GROUP_READ
+ GROUP_EXECUTE
+ WORLD_READ
+ WORLD_EXECUTE)
+
+ # Create the target that runs the script.
+ add_custom_target(verify
+ COMMAND
+ ${CMAKE_CURRENT_BINARY_DIR}/verify_tests.sh
+ DEPENDS
+ event
+ ${ALL_TESTPROGS})
+ endif()
+
+ if (NOT EVENT__DISABLE_REGRESS AND __FOUND_USABLE_PYTHON)
+ add_dependencies(verify regress)
+ endif()
+
+ if (EVENT__COVERAGE)
+ include(CodeCoverage)
+
+ setup_target_for_coverage(
+ verify_coverage # Coverage target name "make verify_coverage"
+ make # Test runner.
+ coverage # Output directory.
+ verify) # Arguments passed to test runner. "make verify"
+ endif()
+
+ enable_testing()
+
+ include(CTest)
+endif()
+
+#
+# Installation preparation.
+#
+
+# Allow the user to override installation directories.
+set(EVENT_INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries")
+set(EVENT_INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables")
+set(EVENT_INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
+
+if(WIN32 AND NOT CYGWIN)
+ set(DEF_INSTALL_CMAKE_DIR cmake)
+else()
+ set(DEF_INSTALL_CMAKE_DIR lib/cmake/libevent)
+endif()
+
+set(EVENT_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files")
+
+# Make sure the paths are absolute.
+foreach(p LIB BIN INCLUDE CMAKE)
+ set(var EVENT_INSTALL_${p}_DIR)
+ if(NOT IS_ABSOLUTE "${${var}}")
+ set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}")
+ endif()
+endforeach()
+
+# Export targets (This is used for other CMake projects to easily find the libraries and include files).
+export(TARGETS event event_extra event_core
+ FILE "${PROJECT_BINARY_DIR}/LibeventTargets.cmake")
+export(PACKAGE libevent)
+
+# Generate the config file for the build-tree.
+set(EVENT__INCLUDE_DIRS
+ "${PROJECT_SOURCE_DIR}/include"
+ "${PROJECT_BINARY_DIR}/include")
+
+set(LIBEVENT_INCLUDE_DIRS
+ ${EVENT__INCLUDE_DIRS}
+ CACHE PATH "Libevent include directories")
+
+configure_file(${PROJECT_SOURCE_DIR}/cmake/LibeventConfigBuildTree.cmake.in
+ ${PROJECT_BINARY_DIR}/LibeventConfig.cmake
+ @ONLY)
+
+# Generate the config file for the installation tree.
+file(RELATIVE_PATH
+ REL_INCLUDE_DIR
+ "${EVENT_INSTALL_CMAKE_DIR}"
+ "${EVENT_INSTALL_INCLUDE_DIR}") # Calculate the relative directory from the Cmake dir.
+
+# Note the EVENT_CMAKE_DIR is defined in LibeventConfig.cmake.in,
+# we escape it here so it's evaluated when it is included instead
+# so that the include dirs are givenrelative to where the
+# config file is located.
+set(EVENT__INCLUDE_DIRS
+ "\${EVENT_CMAKE_DIR}/${REL_INCLUDE_DIR}")
+
+configure_file(${PROJECT_SOURCE_DIR}/cmake/LibeventConfig.cmake.in
+ ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/LibeventConfig.cmake
+ @ONLY)
+
+# Generate version info for both build-tree and install-tree.
+configure_file(${PROJECT_SOURCE_DIR}/cmake/LibeventConfigVersion.cmake.in
+ ${PROJECT_BINARY_DIR}/LibeventConfigVersion.cmake
+ @ONLY)
+
+# Define the public headers.
+set_target_properties(event event_core event_extra
+ PROPERTIES PUBLIC_HEADER "${HDR_PUBLIC}")
+
+#
+# Install targets.
+#
+install(TARGETS event event_core event_extra
+ EXPORT LibeventTargets
+ RUNTIME DESTINATION "${EVENT_INSTALL_BIN_DIR}" COMPONENT bin
+ LIBRARY DESTINATION "${EVENT_INSTALL_LIB_DIR}" COMPONENT lib
+ ARCHIVE DESTINATION "${EVENT_INSTALL_LIB_DIR}" COMPONENT lib
+ PUBLIC_HEADER DESTINATION "${EVENT_INSTALL_INCLUDE_DIR}/event2" COMPONENT dev)
+
+# Install compat headers
+install(FILES ${HDR_COMPAT}
+ DESTINATION
+ "${EVENT_INSTALL_INCLUDE_DIR}"
+ COMPONENT dev)
+
+# Install the configs.
+install(FILES
+ ${PROJECT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/LibeventConfig.cmake
+ ${PROJECT_BINARY_DIR}/LibeventConfigVersion.cmake
+ DESTINATION
+ "${EVENT_INSTALL_CMAKE_DIR}"
+ COMPONENT dev)
+
+# Install exports for the install-tree.
+install(EXPORT LibeventTargets
+ DESTINATION
+ "${EVENT_INSTALL_CMAKE_DIR}"
+ COMPONENT dev)
+
+set(LIBEVENT_LIBRARIES
+ event
+ event_core
+ event_extra
+ CACHE STRING "Libevent libraries")
+
+message(STATUS "")
+message(STATUS " ---( Libevent " ${EVENT_VERSION} " )---")
+message(STATUS "")
+message(STATUS "Available event backends: ${BACKENDS}")
+message(STATUS "CMAKE_BINARY_DIR: " ${CMAKE_BINARY_DIR})
+message(STATUS "CMAKE_CURRENT_BINARY_DIR: " ${CMAKE_CURRENT_BINARY_DIR})
+message(STATUS "CMAKE_SOURCE_DIR: " ${CMAKE_SOURCE_DIR})
+message(STATUS "CMAKE_CURRENT_SOURCE_DIR: " ${CMAKE_CURRENT_SOURCE_DIR})
+message(STATUS "PROJECT_BINARY_DIR: " ${PROJECT_BINARY_DIR})
+message(STATUS "PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR})
+message(STATUS "CMAKE_MODULE_PATH: " ${CMAKE_MODULE_PATH})
+message(STATUS "CMAKE_COMMAND: " ${CMAKE_COMMAND})
+message(STATUS "CMAKE_ROOT: " ${CMAKE_ROOT} )
+message(STATUS "CMAKE_SYSTEM: " ${CMAKE_SYSTEM} )
+message(STATUS "CMAKE_SYSTEM_NAME: " ${CMAKE_SYSTEM_NAME} )
+message(STATUS "CMAKE_SYSTEM_VERSION: " ${CMAKE_SYSTEM_VERSION} )
+message(STATUS "CMAKE_SYSTEM_PROCESSOR: " ${CMAKE_SYSTEM_PROCESSOR} )
+message(STATUS "CMAKE_SKIP_RPATH: " ${CMAKE_SKIP_RPATH} )
+message(STATUS "CMAKE_VERBOSE_MAKEFILE: " ${CMAKE_VERBOSE_MAKEFILE} )
+message(STATUS "CMAKE_C_FLAGS: " ${CMAKE_C_FLAGS} )
+message(STATUS "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE} )
+message(STATUS "CMAKE_C_COMPILER: " ${CMAKE_C_COMPILER} )
+message(STATUS "CMAKE_AR: " ${CMAKE_AR} )
+message(STATUS "CMAKE_RANLIB: " ${CMAKE_RANLIB} )
+message(STATUS "")
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/CONTRIBUTING.md b/fluent-bit/lib/monkey/mk_core/deps/libevent/CONTRIBUTING.md
new file mode 100644
index 000000000..387569397
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/CONTRIBUTING.md
@@ -0,0 +1,35 @@
+# Contributing to the libevent
+
+## Coding style
+
+First and most generic rule: **just look around**.
+
+But, we have a script for checking patches/files/git-refs:
+```shell
+# Chech HEAD git ref
+./checkpatch.sh -r
+./checkpatch.sh -r HEAD
+
+# Check patch
+git format-patch --stdout -1 | ./checkpatch.sh -p
+git show -1 | ./checkpatch.sh -p
+
+# Or via regular files
+git format-patch --stdout -2
+./checkpatch.sh *.patch
+
+# Over a file
+./checkpatch.sh -d event.c
+./checkpatch.sh -d < event.c
+
+# And print the whole file not only summary
+./checkpatch.sh -f event.c
+./checkpatch.sh -f < event.c
+
+# See
+./checkpatch.sh -h
+```
+
+## Testing
+- Write new unit test in `test/regress_{MORE_SUITABLE_FOR_YOU}.c`
+- `make verify`
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/ChangeLog b/fluent-bit/lib/monkey/mk_core/deps/libevent/ChangeLog
new file mode 100644
index 000000000..358dc22a9
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/ChangeLog
@@ -0,0 +1,1811 @@
+Changes in version 2.1.7-rc (2 Novemer 2016)
+
+ Libevent 2.1.7-rc contains openssl 1.1 support, build fixes, CI improvements
+ and plus Vagrantfile for testing under multiple OS'es.
+
+
+ Continious Integration:
+ o Use coveralls.io via travis (9ac000c Azat Khuzhin)
+ o travis-ci: use container-based infrastructure (7e12e96 Azat Khuzhin)
+ o travis-ci/osx: fix compiling/linking openssl libraries (9d2f8d4 Azat Khuzhin)
+ o travis-ci: use gcc-5 (fixes osx|gcc failures) (d7ceae5 Azat Khuzhin)
+ o Testing with vagrant for 6 OS and cmake+autoconf (9585338 Azat Khuzhin)
+ o travis-ci/osx: install lcov (e4e099b Azat Khuzhin)
+
+ Build Improvements/Fixes:
+ o Fix cmake -DEVENT__COVERAGE=ON (40fbffc Azat Khuzhin)
+ o autogen.sh: learn about gmake (9376ac4 Azat Khuzhin)
+ o autogen.sh: remove all autoconf/automake caches, if any (69cce25 Azat Khuzhin)
+ o cmake: fix finding python2, and check that it is really 2 (3453c08 Azat Khuzhin)
+ o cmake: fix CheckFunctionExistsEx/CheckPrototypeDefinition (CMP0054) (43b69b2 Azat Khuzhin)
+ o cmake: cleanup (dc624ad Zonr Chang)
+ o cmake/win32: fix running regress, but fixing finding python2 interpreter (bcb990a Azat Khuzhin)
+ o cmake: use PYTHON_EXECUTABLE to find python2 (a4d044c Azat Khuzhin)
+ o Merge branch 'force-disable-clockgettime' (83c7cdf Azat Khuzhin)
+
+ Code Improvements (core)
+ o use ev_uint16_t instead of unsigned short for port (e983712 Thomas Bernard)
+ o Merge branch 'contrib-guide-v2' (b9c5077 Azat Khuzhin)
+ o poll: Prevent libevent from spinning if POLLNVAL occurs (675974c Tim Hentenaar)
+
+ Testing:
+ o test/regress: cover a polling of invalid fd (cb0df5c Tim Hentenaar)
+
+ Code Improvements (bufferevent_openssl)
+ o Make it build using OpenSSL 1.1.0 (3e9e0a0 Kurt Roeckx)
+ o Don't call BIO_number_{read|written} on NULL BIOs. (6702da1 Adam Langley)
+ o Switch from a 512 to 2048-bit RSA key. (f9803a6 Adam Langley)
+
+ Trivial fixes:
+ o Ignore temporary configure files (8fb08ae Azat Khuzhin)
+ o README.md: fix typo: ar -> are (2361616 Simone Basso)
+ o be: just a simple mistake, reinclude the <errno.h> (7521664 Seven)
+
+Changes in version 2.1.6-beta (4 July 2016)
+
+ Libevent 2.1.6-beta contains mostly bug fixes (evbuffers, evthread, evdns,
+ bufferevents, core, http, samples), improvements but mostly to fix some
+ possible issues (EVHTTP_CON_LINGERING_CLOSE), a lot of new unit tests and new
+ appveyor integration.
+
+ Security Fixes (utils)
+ o evutil_parse_sockaddr_port(): fix buffer overflow (329acc1 Azat Khuzhin)
+
+ Security Fixes (evdns)
+ o evdns: name_parse(): fix remote stack overread (96f64a0 Azat Khuzhin)
+ o evdns: fix searching empty hostnames (ec65c42 Azat Khuzhin)
+
+ New APIs (evdns)
+ o New function to get address for nameserver. (537177d Nick Mathewson)
+
+ New APIs (bufferevents)
+ o expose bufferevent_incref/decref (with fewer modifications) (1ed6718 Mark Ellzey)
+
+ New APIs (internal)
+ o evdns: export cancel via callbacks in util (like async lib core/extra issues) (8cbe65d Azat Khuzhin)
+
+ New APIs/Improvements (http)
+ o http: take EVHTTP_CON_LINGERING_CLOSE into account for "Expect: 100-Continue" (ac448a7 Azat Khuzhin)
+ o http: lingering close (like nginx have) for entity-too-large (9fde518 Azat Khuzhin)
+ o http: read server response even after server closed the connection (680742e Azat Khuzhin)
+ o http: export evhttp_connection_set_family() (714fc70 Azat Khuzhin)
+ o http: reuse connected address only with EVHTTP_CON_REUSE_CONNECTED_ADDR (a50f5f0 Azat Khuzhin)
+ o http: use IP address that we got before (if any) during retrying (54c887d Azat Khuzhin)
+
+ Bugfixes (core)
+ o Fix getaddrinfo under solaris (for multiprotocol case) (40730ae Azat Khuzhin)
+ o Check for Mac OS X 10.4 kqueue bug properly (df6f99e Mark Mentovai)
+ o event_reinit: make signals works after fork() without evsig_add() (88640aa Nicholas Marriott)
+ o event_reinit: always re-init signal's socketpair (ad0c237 Nicholas Marriott)
+ o Free event queues even for recursive finalizers (7c8d015 Azat Khuzhin)
+ o Fix checking for make_base_notifiable() (f337296 Azat Khuzhin)
+ o Set correct socklen for PF_INET6 sockaddr len (3499ad9 Mark Ellzey)
+ o Fix garbage value in socketpair util function, stdint? (043ae74 Mark Ellzey)
+ o fix the return value of event_deferred_cb_schedule_ (38cef64 Greg Hazel)
+ o event_free_debug_globals_locks(): disable lock debugging (e5c87d1 Azat Khuzhin)
+ o event: call event_disable_debug_mode() in libevent_global_shutdown() (941faae Azat Khuzhin)
+ o ht-internal: don't reset hth_table_length explicitly in name_##HT_CLEAR (597c7b2 Azat Khuzhin)
+
+ Bugfixes (evthread)
+ o evthread: fix evthread_setup_global_lock_() for debug-lock with a real-lock case (e4556fc Azat Khuzhin)
+ o evthread: evthreadimpl_disable_lock_debugging_() for libevent_global_shutdown() (ccc5593 Azat Khuzhin)
+
+ Bugfixes (evdns)
+ o evdns: avoid double-free in evdns_base_free() for probing requests (4db15e0 Azat Khuzhin)
+ o evdns: evdns_base_free(): fix UAF of evdns_base with @fail_requests (00313c5 Azat Khuzhin)
+ o evdns: evdns_base_free(): free requests before namservers (14f84bb Azat Khuzhin)
+ o evdns: fix randomize-case by make case-insensitive as required (9c238de Azat Khuzhin)
+
+ Bugfixes (bufferevents)
+ o be_sock: handle readv() returns ECONNREFUSED (freebsd 9.2) (3189eb0 Azat Khuzhin)
+ o be_filter: avoid data stuck under active watermarks (b627ad8 Eduardo Panisset)
+ o Fix bufferevent_pair to properly set BEV_EVENT_{READING,WRITING} on flush. (2851889 David Paschich)
+ o be_openssl: clear all pending errors before SSL_*() calls (38e0f4a Azat Khuzhin)
+ o be_sock: cancel in-progress dns requests (86dfd2c Azat Khuzhin)
+ o be_sock: unfreeze buffers on fd changing (255525d Azat Khuzhin)
+ o be_sock: bufferevent_socket_connect_hostname(): make it thread-safe (809bb39 Azat Khuzhin)
+ o be_openssl: don't call do_write() directly from outbuf_cb (da52933 Azat Khuzhin)
+ o be_openssl: use bufferevent_enable() instead of bufferevent_add_event_() (0c66d32 Azat Khuzhin)
+ o be_openssl: don't add events during bev creation (like be_sock) (f4b6284 Azat Khuzhin)
+ o Fix lock leak in be_pair_flush() if flush type is BEV_NORMAL (f45d39d Bill Vaughan)
+ o be_openssl: don't use *_auto() in do_handshake() we can't have fd == -1 there (877280d Azat Khuzhin)
+ o be_openssl: don't call set_open_callbacks() if fd == -1 (e8a2da9 Azat Khuzhin)
+ o be_openssl: get rid off hackish "fd_is_set", to fix some corner cases (40b0379 Azat Khuzhin)
+ o be: we don't need to use getpeername() we we have conn_address (2c271e2 Azat Khuzhin)
+ o Call underlying bev ctrl SET_FD on filtered bufferevents (c2aa7dc Mark Ellzey)
+ o be_pair: release shared lock with the latest of bufferevent_pair (92a359e Azat Khuzhin)
+
+ Bugfixes (http)
+ o [Issue #313] set method to ASCII "NULL" if evhttp_method() returns NULL (17cc636 Mark Ellzey)
+ o evhttp_have_expect(): fix -Wlogical-not-parentheses (24b5214 Azat Khuzhin)
+ o http: set fd to -1 unconditioally, to avoid leaking of DNS requests (7a4b472 Azat Khuzhin)
+ o http: avoid leaking of fd in evhttp_connection_free() (f0e1341 Azat Khuzhin)
+ o http: get fd from be layer during connection reset (4a53c54 Azat Khuzhin)
+ o http: fix EVHTTP_CON_READ_ON_WRITE_ERROR when it doesn't supported by OS (2ff164a Azat Khuzhin)
+ o http: do not do function calls under EVUTIL_ASSERT() to fix NDEBUG builds (7c89999 Azat Khuzhin)
+ o http: fix leaking of response_code_line (8f18a62 Azat Khuzhin)
+ o http: fix "Expect: 100-continue" client side (0b46b39 Azat Khuzhin)
+ o http: fix conflicts EVHTTP_CON_AUTOFREE and EVHTTP_CON_REUSE_CONNECTED_ADDR (4dc0979 Azat Khuzhin)
+ o http: avoid epoll_ctl() on already closed fd (triggers by http/chunk_out) (ab3bc69 Azat Khuzhin)
+ o http: install timeout for read too during connect for ssl (040000d Azat Khuzhin)
+ o http: fix evhttp_request_own() by checking EVHTTP_USER_OWNED in more cases (b0d3964 Azat Khuzhin)
+ o http: fix detecting EOF without write (7ed02ac Azat Khuzhin)
+ o evhttp: Fix failure to send all output data for POST/PUT requests (24eea0d John Ohl)
+ o Fix evhttp_uriencode() regression. (c6b1ec1 Mark Ellzey)
+ o removed unused vars (e94250c Mark Ellzey)
+ o pointer overflow checks for evhttp_uriencode (72afe4c Zonr Chang)
+
+ Bugfixes (evbuffers)
+ o buffer: fix overflow check in evbuffer_expand_singlechain() (a3f4ccd Azat Khuzhin)
+ o buffer: evbuffer_add_buffer(): clean empty chains from destination buffer (26fd932 Azat Khuzhin)
+ o Fix n_add_for_cb in evbuffer_prepend() in case of new buffer required (0abd039 Azat Khuzhin)
+ o be_filter: actually disable output_filter during processing output (c031215 Simon Perreault)
+ o evbuffer_add: Use last_with_datap if set, not last. (a8769ef Marcus Sundberg)
+ o EVBUFFER_PTR_SET -> EVBUFFER_PTR_ADD (8674e4f jer-gentoo)
+
+ Bugfixes (evconnlistener)
+ o listener: unlock lev on error in listener_read_cb() (2a71b33 Azat Khuzhin)
+ o Fix potential fd leak in listener_read_cb() (a695a72 Mark Ellzey)
+
+ Testing
+ o tests: use waitpid(..., WNOWAIT) to fix failing of main/fork under solaris (43eb56c Azat Khuzhin)
+ o test: replace sleeping with syncing pair in main/fork (16d220c Azat Khuzhin)
+ o test/http: do not run tests that based on backlog filling (freebsd) (500b6b7 Azat Khuzhin)
+ o test/bufferevent/iocp: fix test name for "bufferevent_connect_fail_eventcb" (4410e9d Azat Khuzhin)
+ o test/ssl: use send()/recv()/EVUTIL_ERR_RW_RETRIABLE()/EVUTIL_SOCKET_ERROR() to fix win32 (a9e8cd6 Azat Khuzhin)
+ o test/https_basic: increase timeout for complete write (fixes win32) (d5a2f2f Azat Khuzhin)
+ o test: fix building with --disable-thread-support under win32 (a487706 Azat Khuzhin)
+ o test/buffer: evbuffer_add_buffer() with empty chains (a272bc4 Azat Khuzhin)
+ o test/buffer: evbuffer_remove_buffer() with empty chains (prepend) (f0cfa14 Azat Khuzhin)
+ o test/buffer: evbuffer_remove_buffer() with empty chains (evbuffer_add_buffer()) (2880ce6 Azat Khuzhin)
+ o test/buffer: cover evbuffer_expand() for overflow (48dab7a Azat Khuzhin)
+ o test/be_filter: creating test case for data stuck with active watermarks (766194b Eduardo Panisset)
+ o test/http: avoid using conditionals with omitted operands (fixes VS2015) (2a4bf29 Azat Khuzhin)
+ o test/http: don't mix declarations and code (fixes -Wdeclaration-after-statement) (aabf1c2 Azat Khuzhin)
+ o test/buffer: fix leak in test_evbuffer_prepend() (c08d90b Azat Khuzhin)
+ o test/buffer: avoid errors with --no-fork (reinitialize static vars) (e7d1e39 Azat Khuzhin)
+ o test/buffer: cover n_add_for_cb when evbuffer_prepend() need to allocate buffer (e77ff41 Azat Khuzhin)
+ o test/tinytest_macros: add new one tt_nstr_op() (bd19a28 Azat Khuzhin)
+ o test/bufferevent: check that output_filter disabled during processing output (ae28812 Azat Khuzhin)
+ o test/listener: regression for missing unlock in listener_read_cb() (7d85651 Azat Khuzhin)
+ o test/regress: add tests for evbuffer_add() breakage on empty last chain (d5ee739 Marcus Sundberg)
+ o test/http: fix running some tests sequential (with --no-fork) (bddad71 Azat Khuzhin)
+ o test/http: localize evhttp server structure (cbc3209 Azat Khuzhin)
+ o test/dns: regression for empty hostname (d7348ba Azat Khuzhin)
+ o test/http: fix SERVER_TIMEOUT tests under win32 (d49a658 Azat Khuzhin)
+ o test/http: add a helper for creating timedout/failed request (376f107 Azat Khuzhin)
+ o test/http: adopt for C90 (mixed code and declarations) (d02a285 Azat Khuzhin)
+ o test/http: cover NS timed out during request cancellations separatelly (0c343af Azat Khuzhin)
+ o test/http: request cancellation with resolving/{conn,write}-timeouts in progress (334340d Azat Khuzhin)
+ o test/http: exit from the loop in the errorcb to wait cancellation (927ab33 Azat Khuzhin)
+ o regress_clean_dnsserver(): reset global port vars (351207f Azat Khuzhin)
+ o test/http: read_on_write_error: fix it for win32 (3b58169 Azat Khuzhin)
+ o test/http: separate coverage for EVHTTP_CON_READ_ON_WRITE_ERROR (5c2b4c1 Azat Khuzhin)
+ o test/http: cover "Expect: 100-continue" client-server interaction (31d8116 Azat Khuzhin)
+ o test/http: *lingering tests shouldn't have "Expect: 100-continue" (ed469ab Azat Khuzhin)
+ o test: use EVUTIL_SHUT_WR (04fc82f Azat Khuzhin)
+ o test/http: avoid huge stack allocations to fix win32 builds (3166765 Azat Khuzhin)
+ o test: http/lingering_close: cover EVHTTP_SERVER_LINGERING_CLOSE (e122ca1 Azat Khuzhin)
+ o test: http/non_lingering_close: cover ~EVHTTP_SERVER_LINGERING_CLOSE (f41e1b0 Azat Khuzhin)
+ o test: http/*: update expected HTTP codes for body exceeds `max_body_size` (addf2b9 Azat Khuzhin)
+ o test: http/data_length_constrains: set EVHTTP_CON_READ_ON_WRITE_ERROR (d38a723 Azat Khuzhin)
+ o test: increase buffer size for http/data_length_constraints to trigger EPIPE (0792e1e Azat Khuzhin)
+ o test/tinytest_demo: include <windows.h> for win32 to fix tdm-gcc (f062bbe Azat Khuzhin)
+ o test/regress: cover event_del() waiting mechanism (5b58b70 Azat Khuzhin)
+ o test/regress: cover existing signal callbacks and fork() + event_reinit() (ceddc60 Azat Khuzhin)
+ o test/regress: cover signals after fork() + event_reinit() (b075b81 Azat Khuzhin)
+ o test/regress: main/fork: rewrite assertions by just removing event in callback (088d8b3 Azat Khuzhin)
+ o test/dns: check exit code of evdns_getaddrinfo() (0b9d432 Azat Khuzhin)
+ o test/dns: cover evdns_getaddrinfo() and evdns_base_free() with @fail_requests (4ad3483 Azat Khuzhin)
+ o test/dns: cover @fail_requests for evdns_base_free() (d6c6fb4 Azat Khuzhin)
+ o test/dns: more graceful coverage of @fail_requests (123d372 Azat Khuzhin)
+ o test/ssl: cover busy-loop (i.e. {read,write}-blocked-on-{write,read} stuff) (da0ea7a Azat Khuzhin)
+ o test/http: write_during_read for https (23c77b6 Azat Khuzhin)
+ o test/http: connection_fail for https (7ea26f7 Azat Khuzhin)
+ o test/http: stream_out for https (ac04968 Azat Khuzhin)
+ o test/http: chunk_out for https (a71ffb9 Azat Khuzhin)
+ o test/regress: fix ssl-less builds (need to make this prettier) (3160716 Azat Khuzhin)
+ o test/http: allow dirty shutdown for ssl to fix https_incomplete (1ede326 Azat Khuzhin)
+ o test/http: https basic (59714b4 Azat Khuzhin)
+ o test/http: incomplete{,_timeout} for https (615490d Azat Khuzhin)
+ o test/http: add simplest test for http/https/https_dirty_shutdown (93b19dc Azat Khuzhin)
+ o test/http: https: retry coverage (7c2d24a Azat Khuzhin)
+ o test/http: https server support (plus some helpers) (a7088ad Azat Khuzhin)
+ o test/http: more sanity checks (a27c53c Azat Khuzhin)
+ o test/ssl: export getkey()/getcert()/get_ssl_ctx()/init_ssl() for https (0c4c387 Azat Khuzhin)
+ o test/regress_be: basic coverage bufferevent_flush() for pair/sock layers (ad52602 Azat Khuzhin)
+ o test/regress_be: socket_filter_inactive: check bufferevent after creation (f8081af Azat Khuzhin)
+ o test/regress_be: cover finalizers from inactive to active queue (337684b Azat Khuzhin)
+ o test/regress_buffer: fix clang compilation warnings (d8fd4c0 Azat Khuzhin)
+ o test/regress_http: fix compilation warnings (-Wmissing-field-initializers) (cd422e0 Azat Khuzhin)
+ o test/regress_dns: fix compilation warnings (-Wmissing-field-initializers/for) (f55db98 Azat Khuzhin)
+ o tests/regress_dns: cover that randomize-case works case-insensitive (1e8bfbc Azat Khuzhin)
+ o test: fix bufferevent/bufferevent_pair_release_lock in debug mode (3f749e9 Azat Khuzhin)
+ o test: fix bufferevent/bufferevent_pair_release_lock for freebsd (79f9ace Azat Khuzhin)
+ o test/regress_be: bufferevent_enable() shouldn't call eventcb by it's own (a0f308d Azat Khuzhin)
+ o test/regress_be: introduce fake_listener_create() (37dc9e0 Azat Khuzhin)
+ o test/regress_http: cover evhttp_request_own() (6f6fa0d Azat Khuzhin)
+ o test/regress_http: cover write during read (3d15aeb Azat Khuzhin)
+ o test/regress_http: verify that closecb will be called without multiple write (4be6c70 Azat Khuzhin)
+ o test/regress: fix bufferevent_pair_release_lock with EVENT_DEBUG_MODE (6ea6655 Azat Khuzhin)
+ o test/regress_ssl: check events fd/pending after timeout triggered (cdafdf0 Azat Khuzhin)
+ o test/regress_ssl: cover case when server didn't up (failed with timeout) (74845f1 Azat Khuzhin)
+ o test/regress_ssl: covert that we can't change fd with underlying (df507af Azat Khuzhin)
+ o test/regress_ssl: cover that events (read/write) at finish not pending (762edb4 Azat Khuzhin)
+ o test/regress_ssl: cover fd manipulations (b78a829 Azat Khuzhin)
+ o test/regress_ssl: convert open_ssl_bufevs() to mask (46bba73 Azat Khuzhin)
+ o test/regress_ssl: convert client/server to mask too (3455991 Azat Khuzhin)
+ o test/regress_ssl: cover "allow_dirty_shutdown" (0430327 Azat Khuzhin)
+ o test/regress_ssl: convert regress_bufferevent_openssl() to bitmask (342e116 Azat Khuzhin)
+ o tests/regress_ssl: drop duplicated assert (25e56fd Azat Khuzhin)
+ o test/regress_http: initialize "dns_base" to avoid reading trash (9f0bff3 Azat Khuzhin)
+ o test/http: cover retrying with saved conn_address by shutting down dns server (f4874d8 Azat Khuzhin)
+ o be_pair/regress: cover use of shared lock (lock/unlock/free) (a558fcd Azat Khuzhin)
+ o regress_dns: drop hack for event_debug_map_HT_GROW in leak tests (3540a19 Azat Khuzhin)
+
+ Sample code
+ o Fix memory leak in signal-test.c (666db91 basavesh.as)
+ o sample/hello-world: exAmple, not eXMple (2d3cd35 kirillDanshin)
+ o dns-example: allow to set ns from args (df19a97 Azat Khuzhin)
+ o dns-example: convert to getopt() (32f8592 Azat Khuzhin)
+ o http-connect: make it win32 compilable (1bf7595 Azat Khuzhin)
+ o sample/https-client: allow to change path to ca-certificates (fdf713a Azat Khuzhin)
+ o sample/https-client: check for ERR_remove_thread_state() existence (c4e9d9b Azat Khuzhin)
+ o sample/https-client: replace ERR_remove_state() by ERR_remove_thread_state() (77ad68a Azat Khuzhin)
+ o sample/https-client: add -timeout option (4637aa8 Azat Khuzhin)
+ o sample/https-client: don't try to free uninitialized SSL (f3d7ff5 Azat Khuzhin)
+ o sample/https-client: graceful exit with freeing memory (to make valgrind happy) (24a1f25 Azat Khuzhin)
+ o https-client: correctly handle URLs with no path (like "https://host:port") (29a0482 Andrey Skriabin)
+ o sample/http-connect: don't use assert() to make it work with NDEBUG (6dc71e7 Azat Khuzhin)
+ o sample/http-connect: made it compatible with C90 (f976d43 Azat Khuzhin)
+ o sample: add HTTP CONNECT tunnelling example using libevent http layer (1d34498 Azat Khuzhin)
+ o Update dns-example. (620ff24 Mark Ellzey)
+
+ Documentation
+ o Update README.md (b8ec70c Mark Ellzey)
+ o Update README.md (80faee9 Mark Ellzey)
+ o Update README.md (ad4a897 Mark Ellzey)
+ o Update README.md (a2b2e1e Mark Ellzey)
+ o Update README.md (0dfa5dc Mark Ellzey)
+
+ Code Improvements (evthread)
+ o evthread: add evthread_get_{lock,condition}_callbacks() helpers (c0b34f6 Azat Khuzhin)
+
+ Code Improvements (core)
+ o util: make @sa const for evutil_socket_connect_() (a8d32c2 Azat Khuzhin)
+
+ Code Improvements (http)
+ o http: assert's that evbuffer_drain() success on connection reset (2185e63 Azat Khuzhin)
+ o http: introduce evhttp_request_free_() helper (22061ac Azat Khuzhin)
+ o http: introduce evhttp_is_request_connection_close() helper (6540da3 Azat Khuzhin)
+
+ Code Improvements (bufferevents)
+ o be_sock: bufferevent_socket_set_conn_address(): assert instead of silent no-op (0ab88c2 Azat Khuzhin)
+ o be_sock: sanity check in bufferevent_socket_set_conn_address() (eedbeff Azat Khuzhin)
+ o be: replace sockaddr_storage with sockaddr_in6 for conn_address (3889612 Azat Khuzhin)
+ o be: replace conn_address by full struct instead of pointer (e5615aa Azat Khuzhin)
+ o bufferevent: move conn_address out from http into bufferevent (8bb3842 Azat Khuzhin)
+ o be: make @sa const for bufferevent_socket_connect() (dc33c78 Azat Khuzhin)
+
+ Cleanups (core)
+ o Refactoring conditional directives that break parts of statements. (4b41eeb lzmths)
+ o epoll: introduce PRINT_CHANGES() macro to avoid copy-pasting (a1b142b Azat Khuzhin)
+ o tab (6e7a580 Greg Hazel)
+
+ Cleanups (evbuffers)
+ o buffer_compat: fix comment -- we have EVBUFFER_EOL_ANY not EOL_STYLE_ANY (575ff67 Azat Khuzhin)
+
+ Cleanups (bufferevents)
+ o be_sock: evutil_getaddrinfo_async_() always return 0 (dbff101 Azat Khuzhin)
+ o be_sock: drop be_sock_add() macro (useless and debug unfriendly) (fad5fe2 Azat Khuzhin)
+ o be: introduce bufferevent_generic_adj_existing_timeouts_() (3c1f58f Azat Khuzhin)
+ o be: add_event: use evutil_timerisset() (a96b73b Azat Khuzhin)
+ o be_openssl: introduce be_openssl_auto_fd() helper (2a8a711 Azat Khuzhin)
+ o be_openssl: introduce set_open_callbacks_auto() (510da71 Azat Khuzhin)
+
+ Cleanups (http)
+ o http: make fallback for EVHTTP_CON_READ_ON_WRITE_ERROR more cleaner (d405492 Azat Khuzhin)
+ o http: coding style issue (365f181 Azat Khuzhin)
+
+ Cleanups (evdns)
+ o evnds: inline TEST_NAME macro to make debuggin easier (0c615f4 Azat Khuzhin)
+
+ Portability Fixes
+ o [#372] check for errno.h (3031617 Mark Ellzey)
+ o Fixed Unicode issue in error messages. (e8b7895 Mattes D)
+ o Assume that ke_udata is an integer type on CloudABI. (5602e45 Ed Schouten)
+ o Add missing include of <netinet/in.h>. (b2c68bc Ed Schouten)
+ o Include <sys/ioctl.h>, <sys/resource.h> and <sys/wait.h> optionally. (c1404b5 Ed Schouten)
+ o Test against SO_REUSEADDR (along with _WIN32). (ce1776c Ed Schouten)
+ o Always define missing TAILQ functions from sys/queue.h (2828bdb Christopher Wiley)
+ o Don't use BSD u_* types. (fd36647 Ed Schouten)
+ o Remove BSD-ism: TIMEVAL_TO_TIMESPEC(). (193c7de Ed Schouten)
+ o be: include all variations of headers for sockaddr_in6 struct (c212291 Azat Khuzhin)
+ o be: fix sockaddr_in6 type definition for win32 (c42bc6b Azat Khuzhin)
+
+ Continious Integration:
+ o travis: split long lines, and make it cleaner (685a6a1 Azat Khuzhin)
+ o travis: fix autotools on osx by reinstalling libtool (088ea5e Azat Khuzhin)
+ o appveyor/autotools: link with openssl by passing LDFLAGS/CFLAGS (6fcfa25 Azat Khuzhin)
+ o appveyor: image already had openssl installed (4634b85 Azat Khuzhin)
+ o appveyor: check -DUNICODE -D_UNICODE according to ReleaseChecklist (cmake only) (e9acc44 Azat Khuzhin)
+ o appveyor: ignore failure of mingw-get (1810857 Azat Khuzhin)
+ o appveyor: drop shallow_clone, since we use tags for detecting version in cmake (ac90133 Azat Khuzhin)
+ o appveyor: support cmake & autotools using build matrix (like travis-ci has) (8f95015 Azat Khuzhin)
+ o travis-ci/osx: relink gcc/g++ instead of clang (481481d Azat Khuzhin)
+ o travis-ci: enable multi-os mode (osx, linux) (79917e4 Azat Khuzhin)
+ o travis-ci: increase matrix (--disable-foo) (59649f7 Azat Khuzhin)
+ o travis-ci: adjust alignment (c8be339 Azat Khuzhin)
+ o travis: add builds without debug mode into matrix (3e56da2 Azat Khuzhin)
+ o test: run regress with EVENT_DEBUG_MODE=1 and without (cf2cf2a Azat Khuzhin)
+ o Update travis config for status updates (37453ab Mark Ellzey)
+ o Use autotools for appveyor until cmake is fixed. (1cc2e29 Mark Ellzey)
+ o Fix the link for appveyor OpenSSL installer (WIN32) (107d565 Mark Ellzey)
+ o Forgot to install OpenSSL for appveyor (26164a5 Joakim Söderberg)
+ o Add support for appveyor.com windows CI (5f89c37 Joakim Söderberg)
+
+ Build Improvements/Fixes:
+ o evutil: mark ai_find_protocol() static (prototype-less) (5a157c8 Azat Khuzhin)
+ o cmake/solaris: set CMAKE_REQUIRED_LIBRARIES to fix functions detections (dc95823 Azat Khuzhin)
+ o cmake/solaris: fix building (link with socket,nsl) (050bfc7 Azat Khuzhin)
+ o cmake: check for ZLIB_INCLUDE_DIR, since we can have only library without headers (c4dfb93 Azat Khuzhin)
+ o autotools/win32: fix searching ssl library (671a24f Azat Khuzhin)
+ o cmake/win32: do not compile regress_thread on -DEVENT__DISABLE_THREAD_SUPPORT=ON (de0c196 Azat Khuzhin)
+ o cmake/win32: do not compile evthread_win32 on -DEVENT__DISABLE_THREAD_SUPPORT=ON (ecb0ec8 Azat Khuzhin)
+ o cmake: fix -DEVENT__ENABLE_VERBOSE_DEBUG (typo on -DUSE_DEBUG) (e35f224 Azat Khuzhin)
+ o cmake: do not use stderr for notifications/version-info (38716c6 Azat Khuzhin)
+ o autoconf: fix --disable-thread-support build under win32 (bb09535 Azat Khuzhin)
+ o buffer: don't mix code and declarations (8892f4c Azat Khuzhin)
+ o Update gitignore file to ignore cscope gen'ed files (0aaa4fb Neeraj Badlani)
+ o For non GCC/clang on OSX the -Wno-deprecated-declarations may not be valid (b5ca365 Rainer Keller)
+ o automake: define serial-tests only if automake have this option (61179de Azat Khuzhin)
+ o test/automake: don't use paralell test harness (since automake 1.12) (44d755e Azat Khuzhin)
+ o Ignore all pkgconfig generated stuff (ce38993 Azat Khuzhin)
+ o libevent_core and libevent_extra also deserve a pkgconfig file (b8d7c62 Jan Heylen)
+ o Ignore verify_tests.bat (win32 version) (0f2de10 Azat Khuzhin)
+ o cmake: require 3.1 only for win32 to make it work under ubunty precise (87f7238 Azat Khuzhin)
+ o cmake: require at least 3.1 for target_sources() (c46ead5 Azat Khuzhin)
+ o cmake: fix adding of compiler flags, and now it will (36588e1 Azat Khuzhin)
+ o Replace -Wswitch-enum with -Wswitch, and add it into cmake rules too (f29f59e Azat Khuzhin)
+ o test/regress_ssl: Fix compile problems for win32 (73d0360 Trond Norbye)
+ o util: fix "%zu" format on TDM-gcc/MinGW-w64 (79b69d8 Azat Khuzhin)
+ o cmake: don't define EVENT__NEED_DLLIMPORT always (fixes VS2013 static build) (49bd790 Azat Khuzhin)
+ o Add missing return statement to del_wait_thread so libevent can build. (4f778ab Nick Mathewson)
+ o cmake: fix building dns-example under win32 (missing getopt) (a1609a8 Azat Khuzhin)
+ o visibility: align it to make it more readable (bb6b53d Azat Khuzhin)
+ o cmake: Fix detection of ssize_t/SSIZE_T (7707f6b Azat Khuzhin)
+ o Ignore more configure stuff (configure.lineno) (8d34302 Azat Khuzhin)
+ o Fixed issue with cmake version generation (d56efd9 Mark Ellzey)
+ o Cmake is now officially working. (7f9646d Mark Ellzey)
+ o More cmake updates, lot's of missing definitions (49a5381 Mark Ellzey)
+ o CMake syntax fixes fo .in files (6aad23d Mark Ellzey)
+ o Revert "The Windows socket type is defined as SOCKET." (a264da8 Mark Ellzey)
+ o CMAKE CMAKE CMAKE CLEANUPS (a9db46a Mark Ellzey)
+ o Lot's of cmake updates (8b228e2 Mark Ellzey)
+ o Provide a mechanism for building the library on Windows with different compiler flags. Add a batch file that builds it for the M[DT][d] options and performs a hunt and gather of the different output libraries. (ded8086 billsegall)
+ o The Windows socket type is defined as SOCKET. (c9e6c3d billsegall)
+ o autotools: fix getservbyname() detection (959a4c2 Azat Khuzhin)
+ o Add missing <string.h> for openssl_hostname_validation module (3316a21 Azat Khuzhin)
+ o make test/regress_ssl.c compile without warnings (9f02a44 Thomas Bernard)
+ o test/regress_be: drop debug __asm__(int3) to fix arm build (8240379 Azat Khuzhin)
+ o event_debug_created_threadable_ctx_: fix compilation without debug mode (a068f2e Azat Khuzhin)
+ o Add a prototype for event_disable_debug_mode() (bfcedee Sebastian Hahn)
+ o http: eliminate warning about "socklen" in evhttp_connection_connect_() (dfad1a4 Azat Khuzhin)
+ o Updated gitignore (1dbb55d Mark Ellzey)
+ o Update bench_httpclient.c (cb96931 Seungmo Koo)
+ o *fix: bench_httpclient to support win32 (4e9325e zeliard)
+ o Commented out a WIN32 threading / timing test for now (e84e269 Mark Ellzey)
+ o Fix mixed declarations and code (forbidden by ISO C90) (0c7f217 Thomas Bernard)
+ o Fix "function declaration isn’t a prototype" (746d2c5 Thomas Bernard)
+ o This fixes a bug introduced in 27bd9faf498b91923296cc91643e03ec4055c230 (19ba454 Joakim Söderberg)
+ o changed strtotimeval signature as per #211 (bdbc823 Xiao Bao Clark)
+ o Added cmake-generated files to ignore list. (6c12bfe Matyas Dolak)
+ o Ignore `make dist` generated files (8a2c6c7 Azat Khuzhin)
+
+ Debugging
+ o Debug mode option to error on evthread init AFTER other event calls. (dcfb19a Mark Ellzey)
+
+
+
+Changes in version 2.1.5-beta (5 January 2015)
+
+ Security Fixes (evbuffers)
+ o Avoid integer overflow bugs in evbuffer_add() and related functions. See CVE-2014-6272 advisory for more information. (d49bc0e88b81a5812116074dc007f1db0ca1eecd)
+
+ New APIs (evconnlistener)
+ o Provide support for SO_REUSEPORT through LEV_OPT_REUSABLE_PORT (b625361 Maciej Soltysiak)
+
+ Bugfixes (core)
+ o Fix use-after-free error in EV_CLOSURE_EVENT callback (3cc0eac John Ohl)
+ o Fix race caused by event_active (3c7d6fc vjpai)
+
+ Bugfixes (evbuffer)
+ o Fix evbuffer_peek() with len==-1 and start_at non-NULL. (ba59923)
+ o Consistently check for failure from evbuffer_pullup() (60f8f72)
+ o Fix evbuffer_peek() with len==-1 and start_at non-NULL. (fb7e76a)
+
+ Bugfixes (windows, IOCP)
+ o be async: avoid double close() (f133b86 Azat Khuzhin)
+
+ Bugfixes (bufferevents)
+ o Fix issue #127, double free for filterevents that use BEV_OPT_CLOSE_ON_FREE (2c82aa0 John Ohl)
+ o make bufferevent_getwatermark api more robust (a21e510 ufo2243)
+ o [Bugfix] fix bufferevent setwatermark suspend_read (b34e4ac ufo2243)
+ o bufferevent_openssl: reset fd_is_set when setfd with -1 is called (3da84c2 Azat Khuzhin)
+ o Fix compilation for older OpenSSL versions. (5c7282f Joakim Soderberg)
+
+ New APIs (evhttp)
+ o Add evhttp_connection_set_family() to set addrinfo->family for DNS requests (12c29b0 Azat Khuzhin)
+ o Implement interface that provides the ability to have an outbound evhttp_connection free itself once all requests have completed (2b9ec4c,10fe4f John Ohl)
+
+ New APIs (core)
+ o Implement new/free for struct evutil_monotonic_timer and export monotonic time functions (f2645f8 Andrea Shepard)
+
+ Bugfixes (evdns)
+ o Load hosts file on Windows. (a0b247c Vilmos Nebehaj)
+ o Don't truncate hosts file path on Windows. (d0dc861 Vilmos Nebehaj)
+ o Fix a crash in evdns related to shutting down evdns (9f39c88,e8fe749)
+ o evdns: avoid read-after-free in evdns_request_timeout_callback() (61262a0 Azat Khuzhin)
+ o Correctly handle allocation failures in evdns_getaddrinfo (6a53d15)
+ o evdns: fix EVDNS_BASE_DISABLE_WHEN_INACTIVE in case retransmit/retry (74d0eee Azat Khuzhin)
+ o evdns: add retry/reissue tests for EVDNS_BASE_DISABLE_WHEN_INACTIVE (3ca9d43 Azat Khuzhin)
+ o evdns: fail ns after we are failing/retrasmitting request (97c750d Azat Khuzhin)
+
+ Bugfixes (evhttp)
+ o http: reset connection before installing retry timer (fix http retries handling) (bc79cc5 Azat Khuzhin)
+
+
+ Testing
+ o regress_dns: fix leaks in getaddrinfo_async{,_cancel_stress} tests (2fdc5f2 Azat Khuzhin)
+ o test: add family argument for http_connection_test_() (177b8a7 Azat Khuzhin)
+ o test: add regress for evhttp_connection_set_family() with AF_INET and AF_UNSPEC (42aefeb Azat Khuzhin)
+ o test/http: add regress test for set family to AF_INET6 (3fbf3cc Azat Khuzhin)
+ o Update to a more recent tinytest_macros. (8da5a18)
+ o test/regress: add simplestsignal: to track reorder bugs separately (b897bef Azat Khuzhin)
+ o test/evbuffer_peek: add regress in case we have first buffer greater (e2d139d Azat Khuzhin)
+ o More evbuffer_peek() test cases (154006a)
+ o use correct tt macro for pointer compare (08c88ea)
+ o regress_buffer: fix 'memcmp' compare size (79800df Maks Naumov)
+ o Fix a use-after-free in unit tests. CID 752027 (3739057)
+ o Fix a dead-code warning in unit tests. CID 1193548 (c119f24)
+ o Use evutil_weakrand() in unit tests. (a677b72, 364c110)
+ o Use a more precise calculation for max in time-ratelim.c (ca5b5c7)
+ o Make a buffer larger in the tests to avoid a scary evbuffer_copyout_from() (fb57b8b)
+ o Fix several memory leaks in the unit tests. (89c1a3b)
+ o Add test for evhttp_connection_free_on_completion (b0e9924 John Ohl)
+ o Fix annoying heisenbug in test-time.c (cb73704)
+
+ Sample code
+ o Make http-server.c output into good html5 (6d72bdc)
+ o Use FindClose for handle from FindFirstFile in http-server.c (6466e88)
+ o https-client: add -retries argument, for connection retries (d9da844 Azat Khuzhin)
+
+ Bugfixes (build)
+ o Add missing headerfile for cmake (15d90cc Trond Norbye)
+ o ignore one more test binary (b6593aa Michael Richardson)
+ o ignore config.cache/test-driver files (c83f333 Mike Frysinger)
+ o add a --disable-samples configure flag (0c492b3 Mike Frysinger)
+ o Add a few files created by "make verify" to .gitignore. (1a8295a Pierre Phaneuf)
+ o updates in cmake build (27bd9fa Sergey Nikulov)
+ o Fix cmake error when the Module path has more than one entry. (befbd13 Acer Yang)
+ o Fix CMake shared library build (e69d910 Nobuaki Sukegawa)
+ o Fix warnings when compiling with clang 3.5 (f5b4765 John Ohl)
+ o Fix mixed declarations and code (forbidden by ISO C90) (8afbdbc Thomas Bernard)
+
+ Bugfixes (miscellaneous)
+ o tree.h: drop duplicated content of tree.h (6193187 Azat Khuzhin)
+ o evdns: disable probing with EVDNS_BASE_DISABLE_WHEN_INACTIVE (610410b,ad0493e,fea86a6,d83b337,5ca9e97 Azat Khuzhin)
+ o [Bugfix] fix grammer error (3a4d249 ufo2243)
+ o Change return type of evutil_load_windows_system_library_ to HMODULE (f691389)
+ o Fix a c90 warning (76643dd)
+ o Fix a typo in a doxygen comment. Reported by 亦得. (be1aeff)
+ o remove trailing comma from enum (b361b8a Jean-Philippe Ouellet)
+
+ Bugfixes (FreeBSD)
+ o Handle ENOTCAPABLE from FreeBSD - this is returned if an event in the changelist is for an FD that has been closed. (6fd7394 Adrian Chadd)
+
+
+
+Changes in version 2.1.4-alpha (21 Mar 2014)
+
+ Libevent 2.1.4-alpha adds a number of new miscellaneous APIs to make
+ Libevent more useful, including support for early close detection with
+ epoll via EPOLLRDHUP, triggering bufferevent callbacks, adding more
+ evhttp callbacks, and more. There are also numerous bugfixes, including
+ a number for finalize-related issues from 2.1.3-alpha; and an
+ alternative (non-primary!) cmake-based build mechanism.
+
+ New APIs (core)
+ o Added event_base_get_num_events() (0fa107d Mobai Zhang)
+ o New event_base_active_by_fd API (865a142 Greg Hazel, 5c9da9a, 87fa2b0)
+ o Add event_base_active_by_signal by analogy (4865943)
+ o Add access to max event count stats (5173bef, efbd3dc, 26230a2
+ Andrew Sweeney)
+ o Implemented EV_CLOSED event for epoll backend
+ (EPOLLRDHUP). (b1b69ac Diego Giagio, 53d2793, 43ffcf6, dfe1e52
+ Marcin Juszkiewicz, ff26633 Joakim Soderberg, 3908a5e)
+
+ New APIs (evutil_secure_rng)
+ o Add evutil_secure_rng_set_urandom_device_file (2bbb5d7)
+
+ New APIs (bufferevents)
+ o Add function to fetch underlying ratelimit cfg (4b3d5af Mark Ellzey)
+ o Pass and return const for bufferevent_get_token_bucket_cfg (1c77fbb
+ Mark Ellzey)
+ o Add watermark introspection (4ce242b Ondřej Kuzník)
+ o Add an option to trigger bufferevent I/O callbacks (61ee18b Ondřej Kuzník)
+ o Add an option to trigger bufferevent event callbacks (a7384c7
+ Ondřej Kuzník)
+ o Clarifications in response to merge req. comments (bd41947 Ondřej
+ Kuzník)
+ o Minor optimizations on bufferevent_trigger options (a3172a4)
+
+ New APIs (evhttp)
+ o Add evhttp_connection_get_server(). (a7f82a3 Maxime Henrion)
+ o add a http default content type option (5a5acd9 Nicolas Martyanoff)
+ o http: implement new evhttp_connection_get_addr() api. (0c7f040 Azat
+ Khuzhin)
+ o Add a variant of evhttp_send_reply_chunk() with a callback on
+ evhttp_write_buffer() (8d8decf Julien BLACHE)
+ o Allow registering callback for parsing HTTP headers (b0bd7fe Balint Reczey)
+ o Provide on request complete callback facility (b083ca0 Andrew Sweeney)
+ o evhttp_request_set_on_complete_cb to be more specific about what
+ the function actually does and usage (da86dda Andrew Sweeney)
+ o Update unit test to make sure that the callback happens after the
+ output data is written (b85f398 Andrew Sweeney)
+
+ Features (evdns)
+ o bug fix for issues #293 evdns_base_load_hosts doesn't remove
+ outdated addresses (954d2f9, f03d353, 45eba6f Kuldeep Gupta)
+
+ Features: (cmake build support)
+ o Initial CMake commit. (e415196 Joakim Soderberg)
+ o Add all tests and benchmarks to CMake project. (e9fc014 Joakim Soderberg)
+ o More work on adding tests to CMake project (99c1dc3 Joakim Soderberg)
+ o Generate a dummy evconfig-private.h so things build
+ properly. (ce14def Joakim Soderberg)
+ o Link libm on unix platforms. (58fcd42 Joakim Soderberg)
+ o Added some GCC specific options. (19222e5 Joakim Soderberg)
+ o Use evutil_closesocket instead. (dbf2b51 Joakim Soderberg)
+ o Add copyright and licensing files for CMake modules. (c259d53
+ Joakim Soderberg)
+ o Only include WIN32 getopt where it is used. (9bbce0b Joakim Soderberg)
+ o Fix bench_cascade program on Windows. (78da644 Joakim Soderberg)
+ o Don't segfault on no found event backend. (8f2af50 Joakim Soderberg)
+ o Only test the event backends available on the system. (7ea4159
+ Joakim Soderberg)
+ o Added a "make verify" target. (e053c4f Joakim Soderberg)
+ o Fix the make "verify" target on Windows. (67e5d74 Joakim Soderberg)
+ o Get rid of deprecation warnings for OpenSSL on OSX 10.7+ (69c3516
+ Joakim Söderberg)
+ o Fix kqueue support. (a831f2f Joakim Söderberg)
+ o Added a test for testing if kqueue works with pipes. (2799b35
+ Joakim Söderberg)
+ o Change the BSD license from 4 to 3-clause. (86df3ed Joakim Soderberg)
+ o Minimum required python version is 2.4. (968e97b Joakim Soderberg)
+ o Get rid of unknown pragma warnings. (0ef1d04 Joakim Soderberg)
+ o Add a "make verify_coverage" target generation coverage
+ info. (f2483f8 Joakim Soderberg)
+ o Fix the "make verify" target on NetBSD (4ac086a Joakim Soderberg)
+ o Only look for ZLib when it is used (if tests are
+ included). (f780593 Joakim Soderberg)
+ o Added EVENT__ENABLE_GCC_WARNINGS, turns all warnings into
+ errors. (dd413bd Joakim Soderberg)
+ o Add CMake config and install targets. (f3446ed Joakim Soderberg)
+ o Fix typo (4b754df Joakim Soderberg)
+ o Some work on making it possible to simply do add_subdirectory() on
+ the project. (49ab363 Joakim Soderberg)
+ o Set USE_DEBUG=1 on EVENT__ENABLE_VERBOSE_DEBUG (fd42e70 Joakim Soderberg)
+ o Fix so that old nmake project still builds. (24d6466 Joakim
+ Soderberg)
+ o Rename README to README.md and use markdown to format. (d2bc39a
+ Joakim Soderberg)
+ o Update README with CMake build instructions. (604b8cc Joakim Soderberg)
+ o Clean up the README some. (8d4cb35 JoakimSoderberg)
+ o Forgotten headers for old nmake project compatability. (8697b99
+ Joakim Soderberg)
+ o Change all uses of WIN32 to _WIN32 (4e14395 Joakim Söderberg)
+ o Fix include bug. (2024467 Joakim Söderberg)
+ o Check if we're on OSX before disabling deprecation in le-proxy
+ (8b40a5b Joakim Söderberg)
+ o Fix broken autotools build. (ae1bd82 Joakim Söderberg)
+ o Disclaimerize cmake a little in the README (d03b5bf)
+ o Fix CMake compile when OpenSSL is disabled. (e423d42 Joakim
+ Söderberg)
+ o CMake: Get rid of python not found warning when regress tests
+ turned off. (d38d798 Joakim Söderberg)
+ o Fix https-client compilation on Windows. (d7be788 Joakim Soderberg)
+ o Guard against EVENT_NOWIN32 being set during testing. (f1715b4
+ Joakim Soderberg)
+ o Check for OSX when checking for clang. (e212c54 Joakim Soderberg)
+ o Added a Travis-CI configuration file. (8c0f0a9 Joakim Soderberg)
+ o Added -Qunused-arguments for clang on macosx (ed99d92 Trond Norbye)
+ o Rename event_extras to event_extra (a0dd5df Trond Norbye)
+ o Add option to build shared library (4545fa9 Trond Norbye)
+ o Add -Qunused-arguments for clang on macos (b56611d Trond Norbye)
+ o Add cmake-related files to .gitignore (e061321 Trond Norbye)
+ o Export event_extra not event_extras. (2b41bcf Joakim Söderberg)
+
+ Bugfixes (core)
+ o If evsel->del() fails, don't leave the evmap in an inconsistent
+ state (9b5a527 Maxime Henrion)
+ o Move event_debug_note_teardown_ before mm_free. (69b5c64)
+ o Check CLOCK_MONOTONIC_* at runtime if needed. (911abf3)
+ o Fix reinit of fds with EV_WRITE but not EV_READ. (ebfd8a8 maksqwe)
+ o Tweaked callbacks to prevent race condition
+ (https://github.com/libevent/libevent/issues/104) (40830f1, 2ea15ed
+ John Ohl)
+ o Move assert(ev) to before we use ev in EV_CLOSURE_EVENT_FINALIZE
+ case (9805972)
+
+ Bugfixes (evhttp)
+ o Fix a double close() bug in evhttp when the underlying bufferevent uses
+ BEV_OPT_CLOSE_ON_FREE. (31db8a0 Maxime Henrion)
+ o Fix an unlikely but possible error case for http connections (f22049e)
+ o Avoid racy bufferevent activation (5eb1788 Nate Rosenblum)
+
+ Bugfixes on 2.0 (Windows)
+ o Use windows vsnprintf fixup logic on all windows environments (e826f19)
+ o libevent/win32_dealloc() : fix sizeof(pointer) vs sizeof(*pointer)
+ (b8f5980 Frank Denis)
+
+ Bugfixes (evutil_secure_rng)
+ o When we seed from /proc/sys/kernel/random/uuid, count it as success
+ (e35b540)
+ o We should return after arc4random_buf() (1ea1f26 Makoto Kato)
+ o Avoid other RNG initialization FS reads when urandom file is
+ specified (9695e9c)
+ o Really remove RNG seeds from the stack (f5ced88)
+ o Fix another arc4random_buf-related warning (e64a2b0)
+
+ Bugfixes (bufferevents)
+ o Initialize async bufferevent timeout CBs unconditionally (af9b2a7)
+
+ Bugfixes (evdns)
+ o Checking request nameserver for NULL, before using it. (5c710c0
+ Belobrov Andrey)
+ o Fix SEGFAULT after evdns_base_resume if no nameservers
+ installed. (14971a8 Azat Khuzhin)
+ o Actually use the log facility for reporting evdns problems. (e1766a1)
+ o Fix SEGFAULT after evdns_base_resume if no nameservers
+ installed. (f8d7df8 Azat Khuzhin)
+ o fix for ServFail from RIPE Atlas release (62f596b Antony Antony)
+
+ Bugfixes (compilation)
+ o Fix test compilation with nmake: add the gdi.lib dependency (5ba8ab7)
+ o Whoops. It is gdi.lib, not gdi32.lib. (github issue #61) (8ab612e)
+ o Don't use return since return type is void and build error occurs
+ using clang (838161d Makoto Kato)
+ o Use void casts to suppress some "unchecked return value" warns (7080d55)
+ o rpcgen: Generate regress.gen.[c,h] in build rather than src dir
+ (243386c Ross Lagerwall)
+ o Fix a compiler warning when checking for arc4random_buf linker
+ breakage. (5cb3865)
+ o Fix 'make distcheck' by adding regress.gen.[ch] to DISTCLEANFILES
+ (239d834)
+
+ o Fix a c90 warning (c207682)
+ o Fix consts in WIN32-Code/getopt*.[ch] (57abb35)
+
+ Bugfixes (locks, synchronization)
+ o Missed lock acquire/release in event_base_cancel_single_callback_()
+ (d3d999a Azat Khuzhin)
+ o Fix locking in bufferevent_get_options_(). (dbc9cd4 Maxime Henrion)
+
+ Bugfixes (leaks)
+ o Avoid leaking segment mappings when offset is not a page multiple (d409514)
+
+ Testing
+ o Add tests for evdns_base_resume(). (1cd9ff5 Azat Khuzhin)
+ o Fix dns/leak_resume_send_err test. (7e876df Azat Khuzhin)
+ o Add checks for evhttp_connection_get_server() in unit
+ tests. (fbc323b Maxime Henrion)
+ o Fix a (failure-only) null dereference in the unit tests (1104d0b)
+ o Fix a logic error in test_evbuffer_freeze (7765884)
+ o Add missing check to test_evbuffer_file_segment_add_cleanup_cb (eba4506)
+ o Fix some crash-on-fail cases in DNS regression tests (87cd6f0)
+ o DNS tests: add a missing check (f314900)
+ o Finalize tests: add a missing check (82b6956)
+ o test_evutil_rtrim: add another missing check. (e193c95)
+ o regress_main: logging all if env EVENT_DEBUG_LOGGING_ALL isset
+ (611e28b Azat Khuzhin)
+ o regress_http: add tests for evhttp_connection_get_addr() (4dd500c
+ Azat Khuzhin)
+ o Update to the latest version of tinytest (7a80476)
+ o Heap-allocate zlib data structure in regress_zlib tests (4947c18)
+
+ Performance tweaks (core)
+ o Avoid redundant syscall to make a nonblocking socket nonblocking
+ (42c03da Maxime Henrion)
+ o Avoid redundant syscall if making a socket cloexec twice (1f29b18)
+ o Avoid redundant invocations of init_extension_functions for IOCP (3b77d62)
+
+ Documentation
+ o Document that arc4random is not a great cryptographic PRNG. (6e49696)
+ o Small doxygen tweaks (6e67b51)
+ o Try another doxygen tweak (ccf432b)
+ o Clarify event_base_loop exit conditions (031a803)
+ o Fix a typo (be7bf2c Ondřej Kuzník)
+ o Document deferred eventcb behaviour (13a9a02 Ondřej Kuzník)
+ o Typo fixes from Linus Nordberg (cec62cb, 8cd695b)
+ o Fix duplicate paragraph in evbuffer_ptr documentation (58408ee)
+
+ Code Improvements (coverity)
+ o Fix a pile of coverity warnings in the unit tests (867f401)
+ o Fix coverity warnings in benchmark tools. (ff7f739)
+ o Whoops; fix compilation in bench.c (544cf88)
+ o Remove spurious checks in evrpc.c error cases (coverity) (991b362)
+ o Fix a couple of compilation warnings in regress_http.c (860767e)
+ o Fix even more coverity warnings. (d240328)
+ o Stop checking for inet_aton; we don't use it. (f665d5c)
+ o Add an include to evrpc-internal to fix openbsd compilation warning
+ (5e161c6)
+
+ Cleanups
+ o Remove an unreachable return statement in minheap-internal.h (e639a9e)
+ o Refactor evmap_{io,signal}_active_() to tolerate bad inputs (974c60e)
+ o Fix needless bufferevent includes in evdns.c (254c04e)
+ o Fix a couple of "#ifdef WIN32" instances (88ecda3)
+ o Remove unneeded declaration in bufferevent-internal.h (4c8ebcd)
+
+ Sample code
+ o le-proxy: Fail more gracefully if opening listener fails (44b2491)
+ o http-server: drop uri_root from base_url in http-server. (6171e1c Azat Khuzhin)
+ o https-client: POST supported, args supported (c5887f7 Alexey Ozeritsky)
+ o https-client: code cleanup (29af65e Alexey Ozeritsky)
+ o https-client: Small tweaks to https-client.c (90786eb)
+ o https-client: Set hostname for SNI extension (by f69m) (d1976f8)
+ o https-client: add a cast to https-client.c (462e6b6)
+
+
+
+Changes in version 2.1.3-alpha (1 May 2013)
+
+ Libevent 2.1.3-alpha fixes various bugs, adds new unit tests, and cleans
+ up the code in a couple of places. It has a new callback in evhttp for
+ reporting errors during a request, a new feature for allowing evdns to
+ not keep the event_base looping when there are no requests inflight, and
+ example code for writing an https client.
+
+ Libevent 2.1.3-alpha also has an important new (experimental) event
+ finalization feature to allow safe event teardown in multithreaded
+ programs. This ought to fix the longstanding bug with deadlocks in
+ multithreaded use of SSL-based bufferevents that some people have been
+ experiencing since Libevent 2.0.
+
+
+ Core (event finalization)
+ o Implement event_finalize() and related functions to avoid certain
+ deadlocks (8eedeab)
+ o Use finalization feature so bufferevents can avoid deadlocks (02fbf68)
+ o Always run pending finalizers when event_base_free() is called (e9ebef8)
+ o Remove bufferevent_del_generic_timeout_cbs as now unused (4ea4c6a)
+ o More documentation for finalization feature (a800b91)
+ o Make the event_finalize* functions return an error code (5d11f4f)
+ o Mark the finalize stuff as experiemental in case it needs to
+ change (23e2e29)
+
+ Evdns
+ o evdns: New flag to make evdns not prevent the event loop from
+ exiting (6b7fa62 Azat Khuzhin)
+
+ Bugfixes (Core)
+ o Make event_remove_timer behave correctly with persistent timers (5623e80)
+ o Unit test for event_remove_timer with EV_PERSIST. (96150dd)
+ o Double-check next timeout when adding events (9443868 Nate Rosenblum)
+ o event_base_update_cache_time should be a no-op if the loop isn't
+ running (5e6fa2a)
+
+ Bugfixes (evhttp, crash fix, from 2.0)
+ o fix #73 and fix http_connection_fail_test to catch it (b618204 Greg Hazel)
+
+ Bugfixes (compilation and portability, from 2.0)
+ o Fix compilation with WIN32_HAVE_CONDITION_VARIABLES enabled (7e45739)
+ o Fix missing AC_PROG_SED on older Autoconfs (9ab2b3f Tay Ray Chuan)
+ o Backport libevent to vanilla Autoconf 2.59 (as used in RHEL5)
+ (74d4c44 Kevin Bowling)
+ o Use AC_CONFIG_HEADERS in place of AM_CONFIG_HEADERS for autmake
+ 1.13 compat (817ea36)
+ o Rename configure.in to configure.ac to appease newer autoconfs (0c79787)
+ o Avoid using top_srcdir in TESTS: new automakes do not like this (a55514e)
+
+ Bugfixes (resource leaks/lock errors on error, from 2.0)
+ o Avoid leaking fds on evconnlistener with no callback set (69db261)
+ o Avoid double-close on getsockname error in evutil_ersatz_socketpair
+ (0a822a6)
+ o Fix a locking error in bufferevent_socket_get_dns_error. (0a5eb2e)
+
+ Documentation Fixes (from 2.0)
+ o Fix a mistake in evbuffer_remove() arguments in example http server code
+ (c322c20 Gyepi Sam)
+ o Fix a typo in a comment in buffer.h. Spotted by Alt_F4 (773b0a5)
+
+ Documentation Fixes
+ o minor documentation typos (809586a Patrick Pelletier)
+ o Fix cut-and-paste err in whatsnew-2.1 (49905ac)
+ o Fix comment to refer to sample/include.am correctly (9e8cdf3 Sebastian
+ Hahn)
+ o Fix typo : Dispatching instead of Dispaching (0c2bacc Volker Lendecke)
+ o fix some hinky indentation in evhttp_make_request (80e220e Patrick
+ Pelletier)
+ o "buffer" spelling (a452811 Patrick Pelletier)
+ o Specify return behavior in header for evbuffer_pullup() in corner case
+ (cf8d1cd Dan Petro)
+ o Clarify an important point about event_base_foreach_event() (920a5e6)
+
+ Compilation Fixes/Tool Support
+ o avoid valgrind false positive by zeroing epoll_event (1258614 Patrick
+ Pelletier)
+ o Fix harmless clang enum warning (b452a43 Sebastian Hahn)
+ o remove all exes on "make clean", not just regress.exe (974bfa0 Patrick
+ Pelletier)
+ o Make --disable-libevent-regress work again (787fd74)
+ o Do not build strlcpy.c when it will have no code. (4914620)
+
+ Portability Fixes
+ o When EWOULDBLOCK is not EAGAIN, treat it as equivalent to it (bf7a0ff)
+ o Preliminary changes for Minix3. (0dda56a Nicholas Heath)
+ o Use AC_CONFIG_HEADERS in place of AM_CONFIG_HEADERS for autmake 1.13
+ compat (bf278b)
+ o Avoid using $(top_srcdir) in TESTS. (2863c83)
+ o build test/test-script.sh on systems with a less-featureful $< (f935e21)
+ o Implement EVUTIL_ERR_IS_EAGAIN on windows. (42aaf4d)
+
+ Evhttp changes:
+ o Fix ipv6 support for http. When URL contain domain, not IP
+ address. (71e709c Azat Khuzhin)
+ o uri decode: fix for warning "use of uninitialised value" (64b6ece Azat
+ Khuzhin)
+ o uri decode: changed the test for the existence of the next character
+ (e1903e3 Azat Khuzhin)
+ o Move prototype of evhttp_decode_uri_internal() to http-internal.h
+ (de8101a Azat Khuzhin)
+ o Test: decoding just part of string with evhttp_decode_uri_internal()
+ (1367653 Azat Khuzhin)
+ o Add new error_cb for actual reporting of HTTP request errors. (7b07719
+ Azat Khuzhin)
+ o Add test for EVREQ_HTTP_REQUEST_CANCEL into http_cancel_test() (862c217
+ Azat Khuzhin)
+ o Drop extra header http_struct.h from regress_http.c (54cc800 Azat Khuzhin)
+
+ Testing
+ o Add regress test ipv6_for_domain. (9ec88bd Azat Khuzhin)
+ o Add an environment variable (EVENT_DEBUG_MODE) to run unit tests in debug
+ mode (2fad0f3)
+ o Add a test with an active_later event at event_base_free time. (1c3147f)
+ o Make all tests pass under EVENT_DEBUG_MODE=1 (b1b054f)
+ o Add some verbose notes to bufferevent unit tests (9d893c9)
+ o New test for active_later->active transition on event_active (a153874)
+ o New tests for event_base_foreach_event() (0b096ef)
+ o Unit tests for event_base_gettimeofday_cached() and
+ event_base_update_cache_time() (30ea291)
+ o A test for event_get_assignment() (f09629e)
+ o More unit tests for initializing common timeouts. (d596739)
+ o Fix a bug in the new main/event_foreach test (702c9aa)
+
+ Windows:
+ o use FormatMessage for winsock errors (0c6ec5d, 2078e9b, 4ccdd53, c9ad3af
+ Patrick Pelletier)
+ o a program to print out the error strings for winsock errors (7296512
+ Patrick Pelletier)
+ o Fix a warning introduced in 0c6ec5d8 (eeb700c)
+ o Fix another warning introduced in 0c6ec5d8 (ed26561)
+
+ Examples (http)
+ o Add sample/https-client.c, an example of stacking evhttp as a client on
+ top of bufferevent_ssl. (be46c99 Catalin Patulea)
+ o use ${OPENSSL_LIBS} instead of -lssl -lcrypto (bf31fa5 Patrick Pelletier)
+ o https-client was putting newlines at 256-byte boundaries (42d7441 Patrick
+ Pelletier)
+ o better handling of OpenSSL errors (5754d96 Patrick Pelletier)
+ o use Debian's default root certificate location (aacd674 Patrick Pelletier)
+ o use iSECPartners code to validate hostname in certificate (64d9f16
+ Patrick Pelletier)
+ o avoid sign mismatch warning in openssl_hostname_validation.c (6021cb5
+ Patrick Pelletier)
+ o pull in wildcard matching code from cURL (4db9da6 Patrick Pelletier)
+ o Another tweak to https-client.c (95acdaa)
+ o Remove http_struct.h usage in sample/https-client.c (8a90a85)
+
+
+
+Changes in version 2.1.2-alpha (18 Nov 2012)
+
+ Libevent 2.1.2-alpha includes more portable for monotonic timers,
+ refactors much of Libevent's internal and external infrastructure,
+ closes some longstanding gaps in the interface, makde other
+ improvements. Ths log below tries to organize features by rough area of
+ effect. It omits a few commits which were pure bugfixes on other commits
+ listed below. For more detail, see the git changelogs. For more
+ insight, see the "whatsnew-2.1.txt" document included in the Libevent
+ 2.1.2-alpha distribution.
+
+ Libevent 2.1.2-alpha also includes all changes made in 2.0.19-stable
+ through 2.0.21-stable inclusive.
+
+ Performance (core):
+ o Replace pipe-based notification with EVFILT_USER where possible. This
+ should make multithreaded programs on OSX and *BSD alert the main thread a
+ little faster. (53a07fe)
+ o Make th_base_lock nonrecursive. (9cd5acb)
+
+ New/Changed API Functions:
+ o New event_get_priority() function to return an event's priority (f90e255)
+ o Add a bufferevent_get_priority() function (bd39554)
+ o Add an event_base_loopcontinue() to tell Libevent to rescan for more
+ events right away (7d6aa5e)
+ o Add a new callback to get called on evbuffer_file_segment free
+ (e9f8feb yangacer, 64051b9)
+ o Expose event_base_foreach_event() as a public API. (84fd6d7 Roman
+ Puls, 232055e, ffe1643)
+ o Add an event_remove_timer() to remove timer on an event without
+ deleting it (e3b2e08)
+ o Make bufferevent_set_timeouts(bev, NULL, NULL) have plausible
+ semantics (9dee36b)
+ o Rename event_enable_lock_debuging() to ..._debugging(). (The old name
+ should still work.) (07e132e)
+ o Add missing implementation for event_enable_debug_logging (3b3e21d)
+
+ PORTABLE MONOTONIC TIMERS:
+
+ Libevent 2.1.2 includes internal support for monotonic timers on
+ (nearly) all supported platforms, including Windows, and OSX. Libevent
+ applications should now be more resilient to jumps forwards or backwards
+ in the system clock. Also, on Linux systems with epoll, we now
+ optionally support microsecond-level timeouts (whereas epoll only
+ supports millisecond-precision timeouts).
+
+ o Use mach_absolute_time() for monotonic clock support on OSX. (b8fd6f9)
+ o Do not track use_monotonic field when is no monotonic clock (cb653a0)
+ o EVENT_BASE_FLAG_PRECISE_TIMER indicates we want fine timer precision
+ (ddd69d3)
+ o On Linux, use CLOCK_MONOTONIC_COARSE by default (55780a7)
+ o Implement a GetTickCount-based monotonic timer for Windows (d5e1d5a)
+ o Refactor monotonic timer handling into a new type and set of
+ functions; add a gettimeofday-based ratcheting implementation (f5e4eb0)
+ o Add EVENT_PRECISE_TIMER environment var for selecting precise-but-slow
+ timer (a2598ec)
+ o Implement fast/precise monotonic clocks on Windows (2c47045)
+ o Simple unit tests for monotonic timers (630f077)
+ o Improve the monotonic-time unit test: make it check the step size (7428c78)
+ o When PRECISE_TIMERS is set with epoll, use timerfd for microsecond
+ precision (26c7582)
+ o Split out time-related evutil functions into a new evutil_time.c (c419485)
+ o Split out time-related prototypes into time-internal.h (71bca50)
+ o Add evutil_time.obj to Makefile.nmake (0ba0683)
+ o Avoid giving a spurious warning when timerfd support is unavailable
+ (1aaf9f0 Dave Hart)
+ o Make test_evutil_monotonic a little more tolerant (def3b83)
+ o Avoid unused-var warning on systems with clock_gettime but without
+ CLOCK_MONOTONIC_COARSE (9be5468)
+
+EVENT_BASE_ONCE LEAKS:
+ If a callback added by event_base_once() is never invoked, Libevent no
+ longer leaks internal memory.
+
+ o Free dangling event_once objects on event_base_free() (c17dd59)
+ o Add a unit test in which an event is created with event_base_once()
+ but never fires (4343edf)
+
+TESTING SUPPORT, FIXES AND IMPROVEMENTS:
+
+ Libevent now disables by default its unit tests that would touch the
+ network, or that tend to fail on heavily-loaded systems. To re-enable
+ them, invoke the ./test/regress program with the @all alias.
+
+ o Simplify test.sh code significantly. (9b856fd Ross Lagerwall)
+ o Make all tests that hit the network disabled by default (f2cea87)
+ o Avoid a resource leak on error in http client benchmark (ea92fba)
+ o Update to latest tinytest (911b4f0349377) (ef7c4f7)
+ o Avoid (unlikely) overflow in bench_httpclient.c (5671033)
+ o Shave 700 msec off the persistent_timeout_jump test (21205b8)
+ o Check return value of write() in regress.c (c8009d2)
+ o Make load-dependent monotonic timer tests off-by-default (2b6fe8b)
+ o Add deferred_cb_skew to list of timing-dependent tests (34c8f31)
+ o Avoid test -e; older shs don't have one. (f1bd938)
+ o Fix renegotiation test to work around openssl 1.0.1 bug (c2f3086)
+ o Fix a couple of compile warnings in the unit tests (5a9a014)
+
+MISC:
+ o Change evutil_weakrand_() to avoid platform random() (e86af4b Nicholas
+ Marriott, 3aa4415)
+
+INFRASTRUCTURE (Active-later events):
+ As a simplification and optimization to Libevent's "deferred callback"
+ logic (introduced in 2.0 to avoid callback recursion), Libevent now
+ treats all of its deferrable callback types using the same logic it uses
+ for active events. Now deferred events no longer cause priority
+ inversion, no longer require special code to cancel them, and so on.
+
+ o Refactor the callback part of an event into its own event_callback
+ type (cba59e5)
+ o Add "active later" event_callbacks to supersede deferred (745a63d)
+ o event_base_assert_ok: check value of event_active_count for
+ correctness (fec8bae)
+ o Replace deferred_cbs with event_callback-based implementation. (ae2b84b)
+ o Replace more deferred_cb names with event_callback (a4079aa)
+ o Give event_base_process_active a single exit path (581b5be)
+ o Restore our priority-inversion-prevention code with deferreds (c0e425a)
+ o Refactor event_persist_closure: raise and extract some common logic
+ (bec22b4)
+ o Remove the unused bits from EVLIST_ALL (9889a3d)
+||||||| merged common ancestors
+Changes in version 2.0.22-stable (?? Dec 2013)
+
+ (As of 3b77d62829c4393bda6f9105a5d3b73b48a64b71.)
+
+BUGFIXES (evhttp)
+ o fix #73 and fix http_connection_fail_test to catch it (crash fix) (b618204 Greg Hazel)
+ o Avoid racy bufferevent activation (5eb1788 Nate Rosenblum)
+
+BUGFIXES (compilation and portability)
+ o Fix compilation with WIN32_HAVE_CONDITION_VARIABLES enabled (7e45739)
+ o Fix missing AC_PROG_SED on older Autoconfs (9ab2b3f Tay Ray Chuan)
+ o Backport libevent to vanilla Autoconf 2.59 (as used in RHEL5) (74d4c44 Kevin Bowling)
+ o Use AC_CONFIG_HEADERS in place of AM_CONFIG_HEADERS for autmake 1.13 compat (817ea36)
+ o Rename configure.in to configure.ac to appease newer autoconfs (0c79787)
+ o Avoid using top_srcdir in TESTS: new automakes do not like this (a55514e)
+ o Use windows vsnprintf fixup logic on all windows environments (e826f19)
+ o Fix a compiler warning when checking for arc4random_buf linker breakage. (5cb3865)
+ o Fix another arc4random_buf-related warning (e64a2b0)
+
+BUGFIXES (resource leaks/lock errors on error)
+ o Avoid leaking fds on evconnlistener with no callback set (69db261)
+ o Avoid double-close on getsockname error in evutil_ersatz_socketpair (0a822a6)
+ o Fix a locking error in bufferevent_socket_get_dns_error. (0a5eb2e)
+ o libevent/win32_dealloc() : fix sizeof(pointer) vs sizeof(*pointer) (b8f5980 Frank Denis)
+
+BUGFIXES (miscellaneous)
+ o Avoid other RNG initialization FS reads when urandom file is specified (9695e9c, bb52471)
+ o Avoid redundant invocations of init_extension_functions for IOCP (3b77d62)
+
+BUFGIXES (evdns)
+ o Checking request nameserver for NULL, before using it. (5c710c0 Belobrov Andrey)
+ o Fix SEGFAULT after evdns_base_resume if no nameservers installed. (f8d7df8 Azat Khuzhin)
+
+BUGFIXES (evutil_secure_random)
+ o When we seed from /proc/sys/kernel/random/uuid, count it as success (e35b540)
+ o Document that arc4random is not a great cryptographic PRNG. (6e49696)
+ o Add evutil_secure_rng_set_urandom_device_file (2bbb5d7)
+ o Really remove RNG seeds from the stack (f5ced88)
+
+
+DOCUMENTATION FIXES
+ o Fix a mistake in evbuffer_remove() arguments in example http server code (c322c20 Gyepi Sam)
+ o Fix a typo in a comment in buffer.h. Spotted by Alt_F4 (773b0a5)
+
+
+
+Changes in version 2.0.21-stable (18 Nov 2012)
+BUGFIXES:
+ o ssl: Don't discard SSL read event when timeout and read come close together (576b29f)
+ o ssl: Stop looping in "consider_reading" if reading is suspended. (f719b8a Joachim Bauch)
+ o ssl: No need to reserve space if reading is suspended. (1acf2eb Joachim Bauch)
+ o dns: Avoid a memory-leak on OOM in evdns. (73e85dd, f2bff75 George Danchev)
+ o build: Use python2 rather than python (0eb0109 Ross Lagerwall)
+ o build: Compile without warnings on mingw64 (94866c2)
+ o build: Fix compilation on mingw64 with -DUSE_DEBUG (62bd2c4)
+ o build: Make rpcgen_wrapper.sh work on systems without a "python2" binary (f3009e4)
+ o iocp: Close IOCP listener socket on free when LEV_OPT_CLOSE_ON_FREE is set (cb853ea Juan Pablo Fernandez)
+ o core: Avoid crash when event_pending() called with no event_base set on event (e3cccf3)
+ o misc: remove stray 'x' so print_err will compile when uncommented (ac35650 Patrick Pelletier)
+ o tests: Fix renegotiation test to work around openssl 1.0.1 bug (c2f3086)
+ o tests: Warn when openssl version in unit test mismatches compiled version. (ac009f9)
+
+
+Changes in version 2.0.20-stable (23 Aug 2012)
+BUGFIXES:
+ o core: Make event_pending() threadsafe. (be7a95c Simon Liu)
+ o win32: avoid crash when waiting forever on zero fds. (160e58b)
+ o evhttp: Fix a memory leak on error in evhttp_uriencode (11c8b31)
+ o evbuffer: Avoid possible needless call to writev. Found by coverity. (6a4ec5c)
+ o evdns: memset sockaddr_in before using it. Found by coverity. (a1a0e67)
+ o evhttp: Check more setsockopt return values when binding sockets. Found by coverity (a0912e3)
+ o evdns: Avoid segfault on weird timeout during name lookup. (dc32077 Greg Hazel)
+ o bufferevent_ssl: Correctly invoke callbacks when a SSL bufferevent reads some and then blocks. (606ac43)
+
+
+PORTABILITY FIXES:
+ o check for arc4random_buf at runtime, on OS X (bff5f94 Greg Hazel)
+ o Correctly check for arc4random_buf (fcec3e8 Sebastian Hahn)
+ o Add explicit AC_PROG_SED to configure.in so all autoconfs will expose $(SED) (ca80ea6)
+
+BUILD FIXES:
+ o Add GCC annotations so that the vsprintf functions get checked properly (117e327)
+ o Fix an unused variable warning on *BSD. (c0720c1)
+
+UNIT TEST FIXES:
+ o Fix a couple of memory leaks (found with Valgrind). (3b2529a Ross Lagerwall)
+ o Remove deadcode in http regression tests. Found by coverity. (5553346)
+ o Fix possible uninitialized read in dns regression tests. Found by coverity. (2259777)
+ o Set umask before calling mkstemp in unit tests. Found by coverity (f1ce15d)
+ o Fix various check-after-dereference issues in unit tests: found by coverity (4f3732d)
+ o Fix resource leaks in the unit tests; found by coverity (270f279)
+ o Add some missing null checks to unit tests; found by coverity (f021c3d)
+ o Avoid more crashes/bad calls in unit tests; found by coverity (3cde5bf)
+ o Remove unused variable; spotted by coverity (6355b2a)
+ o Add checks to various return values in unit tests. Found by coverity (b9e7329)
+ o Move assignment outside tt_assert in ssl unit tests. Appeases coverity. (a2006c0)
+
+
+
+Changes in version 2.0.19-stable (3 May 2012)
+BUGFIXES (CORE):
+ o Refactor event_persist_closure: raise and extract some common logic (bec22b4)
+ o If time has jumped so we'd reschedule a periodic event in the past, schedule it for the future instead (dfd808c)
+ o If a higher-priority event becomes active, don't continue running events of the current priority. (2bfda40)
+
+BUGFIXES (SSL):
+ o Fixed potential double-readcb execution with openssl bufferevents. (4e62cd1 Mark Ellzey)
+
+BUGFIXES (DNS):
+ o Cancel a probe request when the server is freed, and ignore cancelled probe callbacks (94d2336 Greg Hazel)
+ o Remove redundant DNS_ERR_CANCEL check, move comment (46b8060 Greg Hazel)
+ o When retransmitting a timed-out DNS request, pick a fresh nameserver. (3d9e52a)
+
+DOCUMENTATION FIXES:
+ o Fix a typo in the bufferevent documentation (98e9119)
+ o Add missing ) to changelog; spotted by rransom (4c7ee6b)
+ o Fix the website URL in the readme (f775521)
+
+COMPILATION FIXES:
+ o Fix a compilation error with MSVC 2005 due to use of mode_t (336dcae)
+ o Configure with gcc older than 2.95 (4a6fd43 Sebastian Hahn)
+ o Generate event-config.h with a single sed script (30b6f88 Zack Weinberg)
+
+FORWARD-COMPATIBILITY:
+ o Backport: provide EVENT_LOG_* names, and deprecate _EVENT_LOG_* (d1a03b2)
+
+TESTING/DEBUGGING SUPPORT:
+ o dns-example.c can now take a resolv.conf file on the commandline (6610fa5)
+ o Make some evdns.c debug logs more verbose (d873d67)
+ o Work-around a stupid gcov-breaking bug in OSX 10.6 (b3887cd)
+
+
+
+Changes in version 2.0.18-stable (22 Mar 2012)
+BUGFIXES (core):
+ o Make uses of open() close-on-exec safe by introducing an internal evutil_open_closeonexec. (d2b5f72 Ross Lagerwall, 03dce42)
+
+BUGFIXES (kqueue):
+ o Properly zero the kevent in kq_setup_kevent() (c2c7b39 Sebastian Hahn)
+
+BUILD FIXES:
+ o Added OPENSSL_LDFLAGS env variable which is appended to SSL checks. (9278196 Mark Ellzey)
+ o Changed OPENSSL_LDFLAGS to OPENSSL_LIBADD (2d67b63 Mark Ellzey)
+ o Don't do clang version detection when disabling some flags (083296b Sebastian Hahn)
+
+BUGFIXES (dns):
+ o Stop crashing in evdns when nameserver probes give a weird error (bec5068)
+
+
+Changes in version 2.0.17-stable (10 Feb 2012)
+
+BUGFIXES (core):
+ o Be absolutely sure to clear pncalls before leaving event_signal_closure (11f36a5)
+ o check for sysctl before we use it (358c745 Mike Frysinger)
+ o Remove bogus casts of socket to int before calling ev_callback (f032516)
+ o Make evconnlistener work around bug in older Linux when getting nmapped (ecfc720)
+ o Fix a list corruption bug when using event_reinit() with signals present (6e41cdc)
+ o Fix a fd leak in event_reinit() (3f18ad1)
+ o Do a memberwise comparison of threading function tables (c94a5f2 Nate R)
+ o Use C-style comments in C source files (for compatibility with compilers such as xlc on AIX). (d84d917 Greg Hewgill)
+ o Avoid crash when freeing event_iocp and using event_set_mem_functions (19715a6)
+ o In the kqueue backend, do not report EBADF as an EV_READ (5d7bfa1 Nicholas Marriott)
+
+BUGFIXES (evbuffer and bufferevents):
+ o Fix behavior of evbuffer_peek(buf,-1,NULL,NULL,0) (c986f23 Zack Weinberg)
+ o Loop on filtering SSL reads until we are blocked or exhausted. (5b4b812)
+
+BUGFIXES (evhttp):
+ o Force strict validation of HTTP version in response. (790f6b3 Catalin Patulea)
+
+BUGFIXES (evdns):
+ o evdns: fix a bug in circular-queue implementation (d6094b1)
+
+BUILD FIXES:
+ o Fix a silly compilation error with the sun compiler (1927776 Colin Watt)
+ o Suppress a gcc warning from ignoring fwrite return in http-sample.c (7206e8c)
+
+DOCUMENTATION FIXES:
+ o Slightly clarify evbuffer_peek documentation (7bbf6ca)
+ o Update copyright notices to 2012 (e49e289)
+
+NEW APIS:
+ o Backport evhttp_connection_get_bufferevent to Libevent 2.0 (da70fa7 Arno Bakker)
+
+TESTS AND TEST FIXES:
+ o Fix a race condition in the dns/bufferevent_connect_hostname test. (cba48c7)
+ o Add function to check referential integrity of an event_base (27737d5)
+ o Check event_base correctness at end of each unit test (3312b02)
+ o Workaround in the unit tests for an apparent epoll bug in Linux 3.2 (dab9187)
+ o Better workaround for Linux 3.2 edge-triggered epoll bug (9f9e259)
+
+Changes in version 2.0.16-stable (18 Nov 2011)
+BUGFIXES (core):
+ o More detailed message in case of libevent self-debugging failure. (9e6a4ef Leonid Evdokimov)
+ o epoll: close fd on alloc fail at initialization (1aee718 Jamie Iles)
+ o Fix compile warning from saying event2/*.h inside a comment (447b0ba)
+ o Warn when unable to construct base because of failing make_base_notifiable (4e797f3)
+ o Don't try to make notifiable event_base when no threading fns are configured (e787413)
+
+BUGFIXES (evbuffer):
+ o unit test for remove_buffer bug (90bd620 Greg Hazel)
+ o Fix an evbuffer crash in evbuffer_remove_buffer() (c37069c)
+
+BUGFIXES (bufferevent_openssl):
+ o Refactor amount-to-read calculations in buffervent_ssl consider_reading() (a186e73 Mark Ellzey)
+ o Move SSL rate-limit enforcement into bytes_to_read() (96c562f)
+ o Avoid spinning on OpenSSL reads (2aa036f Mark Ellzey)
+
+BUGFIXES (dns)
+ o Empty DNS reply with OK status is another way to say NODATA. (21a08d6 Leonid Evdokimov)
+
+TESTING:
+ o Tests for 94fba5b and f72e8f6 (d58c15e Leonid Evdokimov)
+ o Test for commit aff6ba1 (f7841bf Leonid Evdokimov)
+ o Style and comment tweaks for dns/leak* tests (5e42202)
+ o improve test to remove at least one buffer from src (7eb52eb Greg Hazel)
+
+DOCUMENTATION:
+ o Add note about evhttp_send_reply_end to its doxygen (724bfb5)
+ o Update copyright dates to 2011. (3c824bd)
+ o Fix typo in whatsnew-2.0.txt (674bc6a Mansour Moufid)
+ o Improve win32 behavior of dns-sample.c code (a3f320e Gisle Vanem)
+
+
+
+Changes in version 2.0.15-stable (12 Oct 2011)
+BUGFIXES (DNS):
+ o DNS: add ttl for negative answers using RFC 2308 idea. (f72e8f6 Leonid Evdokimov)
+ o Add DNS_ERR_NODATA error code to handle empty replies. (94fba5b Leonid Evdokimov)
+
+BUFGIXES (bufferevents and evbuffers):
+ o Make evbuffer callbacks get the right n_added value after evbuffer_add (1ef1f68 Alex)
+ o Prefer mmap to sendfile unless a DRAINS_TO_FD flag is set. Allows add_file to work with SSL. (0ba0af9)
+
+BUGFIXES (event loop):
+ o When a signal callback is activated to run multiple times, allow event_base_loopbreak to work even before they all have run. (4e8eb6a)
+
+DOCUMENTATION FIXES:
+ o Fix docstring in dns.h (2b6eae5 Leonid Evdokimov)
+ o refer to non-deprecated evdns functions in comments (ba5c27d Greg Hazel)
+
+BUILD AND TESTING FIXES:
+ o le-proxy and regress depend on openssl directly (9ae061a Sergey Avseyev)
+ o Use _SOURCES, not _sources, in sample/Makefile.am (7f82382)
+ o Fixed compiler warnings for unchecked read/write calls. (c3b62fd Mark Ellzey)
+ o Make write-checking fixes use tt_fail_perror (2b76847)
+ o Fix some "value never used" warnings with gcc 4.6.1 (39c0cf7)
+
+
+
+Changes in version 2.0.14-stable (31 Aug 2011)
+BUGFIXES (bufferevents and evbuffers):
+ o Propagate errors on the underlying bufferevent to the user. (4a34394 Joachim Bauch)
+ o Ignore OpenSSL deprecation warnings on OS X (5d1b255 Sebastian Hahn)
+ o Fix handling of group rate limits under 64 bytes of burst (6d5440e)
+ o Solaris sendfile: correctly detect amount of data sent (643922e Michael Herf)
+ o Make rate limiting work with common_timeout logic (5b18f13)
+ o clear read watermark on underlying bufferevent when creating filtering bev to fix potentially failing fragmented ssl handshakes (54f7e61 Joachim Bauch)
+
+BUGFIXES (IOCP):
+ o IOCP: don't launch reads or writes on an unconnected socket (495c227)
+ o Make IOCP rate-limiting group support stricter and less surprising. (a98da7b)
+ o Have test-ratelim.c support IOCP (0ff2c5a)
+ o Make overlapped reads result in evbuffer callbacks getting invoked (6acfbdd)
+ o Correctly terminate IO on an async bufferevent on bufferevent_free (e6af35d)
+
+BUGFIXES (other):
+ o Fix evsig_dealloc memory leak with debugging turned on. (9b724b2 Leonid Evdokimov)
+ o Fix request_finished memory leak with debugging turned on. (aff6ba1 Leonid Evdokimov)
+
+BUILD AND TESTING FIXES:
+ o Allow OS-neutral builds for platforms where some versions have arc4random_buf (b442302 Mitchell Livingston)
+ o Try to fix 'make distcheck' errors when building out-of-tree (04656ea Dave Hart)
+ o Clean up some problems identified by Coverity. (7c11e51 Harlan Stenn)
+
+
+Changes in version 2.0.13-stable (18 Jul 2011)
+BUGFIXES
+ o Avoid race-condition when initializing global locks (b683cae)
+ o Fix bug in SSL bufferevents backed by a bev with a write high-watermarks (e050703 Joachim Bauch)
+ o Speed up invoke_callbacks on evbuffers when there are no callbacks (f87f568 Mark Ellzey)
+ o Avoid a segfault when all methods are disabled or broken (27ce38b)
+ o Fix incorrect results from evbuffer_search_eol(EOL_LF) (4461f1a)
+ o Add some missing checks for mm_calloc failures (89d5e09)
+ o Replace an assertion for event_base_free(NULL) with a check-and-warn (09fe97d)
+ o Report kqueue ebadf, epipe, and eperm as EV_READ events (1fd34ab)
+ o Check if the `evhttp_new_object' function in `http.c' returns NULL. (446cc7a Mansour Moufid)
+ o Use the correct printf args when formatting size_t (3203f88)
+ o Complain if the caller tries to change threading cbs after setting them (cb6ecee)
+
+DOCUMENTATION FIXES AND IMPROVEMENTS
+ o Revise the event/evbuffer/bufferevent doxygen for clarity and accuracy (2888fac)
+ o Update Doxyfile to produce more useful output (aea0555)
+
+TEST FIXES
+ o Fix up test_evutil_snprintf (caf695a)
+ o Fix tinytest invocation from windows shell (57def34 Ed Day)
+
+BUILD FIXES
+ o Use AM_CPPFLAGS in sample/Makefile.am, not AM_CFLAGS (4a5c82d)
+ o Fix select.c compilation on systems with no NFDBITS (49d1136)
+ o Fix a few warnings on OpenBSD (8ee9f9c Nicholas Marriott)
+ o Don't break when building tests from git without python installed (b031adf)
+ o Don't install event_rpcgen.py when --disable-libevent-install is used (e23cda3 Harlan Stenn)
+ o Fix AIX build issue with TAILQ_FOREACH definition (e934096)
+
+
+Changes in version 2.0.12-stable (4 Jun 2011)
+BUGFIXES
+ o Fix a warn-and-fail bug in kqueue by providing kevent() room to report errors (28317a0)
+ o Fix an assert-inducing fencepost bug in the select backend (d90149d)
+ o Fix failing http assertion introducd in commit 0d6622e (0848814 Kevin Ko)
+ o Fix a bug that prevented us from configuring IPv6 nameservers. (74760f1)
+ o Prevent size_t overflow in evhttp_htmlescape. (06c51cd Mansour Moufid)
+ o Added several checks for under/overflow conditions in evhttp_handle_chunked_read (a279272 Mark Ellzey)
+ o Added overflow checks in evhttp_read_body and evhttp_get_body (84560fc Mark Ellzey)
+
+DOCUMENTATION:
+ o Add missing words to EVLOOP_NONBLOCK documentation (9556a7d)
+
+BUILD FIXES
+ o libssl depends on libcrypto, not the other way around. (274dd03 Peter Rosin)
+ o Libtool brings in the dependencies of libevent_openssl.la automatically (7b819f2 Peter Rosin)
+ o Use OPENSSL_LIBS in Makefile.am (292092e Sebastian Hahn)
+ o Move the win32 detection in configure.in (ceb03b9 Sebastian Hahn)
+ o Correctly detect openssl on windows (6619385 Sebastian Hahn)
+ o Fix a compile warning with zlib 1.2.4 and 1.2.5 (5786b91 Sebastian Hahn)
+ o Fix compilation with GCC 2, which had no __builtin_expect (09d39a1 Dave Hart)
+ o Fix new warnings from GCC 4.6 (06a714f)
+ o Link with -lshell32 and -ladvapi32 on Win32. (86090ee Peter Rosin)
+ o Make the tests build when OpenSSL is not available. (07c41be Peter Rosin)
+ o Bring in the compile script from automake, if needed. (f3c7a4c Peter Rosin)
+ o MSVC does not provide S_ISDIR, so provide it manually. (70be7d1 Peter Rosin)
+ o unistd.h and sys/time.h might not exist. (fe93022 Peter Rosin)
+ o Make sure TINYTEST_LOCAL is defined when building tinytest.c (8fa030c Peter Rosin)
+ o Fix winsock2.h #include issues with MSVC (3d768dc Peter Rosin)
+ o Use evutil_gettimeofday instead of relying on the system gettimeofday. (0de87fe Peter Rosin)
+ o Always use evutil_snprintf, even if OS provides it (d1b2d11 Sebastian Hahn)
+ o InitializeCriticalSectionAndSpinCount requires _WIN32_WINNT >= 0x0403. (816115a Peter Rosin)
+ o cygwin: make it possible to build DLLs (d54d3fc)
+
+
+
+Changes in version 2.0.11-stable (27 Apr 2011)
+ [Autogenerated from the Git log, sorted and cleaned by hand.]
+BUGFIXES:
+ o Fix evport handling of POLLHUP and POLLERR (b42ce4b)
+ o Fix compilation on Windows with NDEBUG (cb8059d)
+ o Check for POLLERR, POLLHUP and POLLNVAL for Solaris event ports (0144886 Trond Norbye)
+ o Detect and handle more allocation failures. (666b096 Jardel Weyrich)
+ o Use event_err() only if the failure is truly unrecoverable. (3f8d22a Jardel Weyrich)
+ o Handle resize failures in the select backend better. (83e805a)
+ o Correctly free selectop fields when select_resize fails in select_init (0c0ec0b)
+ o Make --enable-gcc-warnings a no-op if not using gcc (3267703)
+ o Fix a type error in our (unused) arc4random_stir() (f736198)
+ o Correctly detect and stop non-chunked http requests when the body is too long (63a715e)
+ o Have event_base_gettimeofday_cached() always return wall-clock time (a459ef7)
+ o Workaround for http crash bug 3078187 (5dc5662 Tomash Brechko)
+ o Fix incorrect assertions and possible use-after-free in evrpc_free() (4b8f02f Christophe Fillot)
+ o Reset outgoing http connection when read data in idle state. (272823f Tomash Brechko)
+ o Fix subtle recursion in evhttp_connection_cb_cleanup(). (218cf19 Tomash Brechko)
+ o Fix the case when failed evhttp_make_request() leaved request in the queue. (0d6622e Tomash Brechko)
+ o Fix a crash bug in evdns server circular list code (00e91b3)
+ o Handle calloc failure in evdns. (Found by Dave Hart) (364291e)
+ o Fix a memory leak on win32 socket->event map. (b4f89f0)
+ o Add a forgotten NULL check to evhttp_parse_headers (12311ff Sebastian Hahn)
+ o Fix possible NULL-deref in evdns_cancel_request (5208544 Sebastian Hahn)
+
+PORTABILITY:
+ o Fall back to sscanf if we have no other way to implement strtoll (453317b)
+ o Build correctly on platforms without sockaddr_storage (9184563)
+ o Try to build correctly on platforms with no IPv6 support (713c254)
+ o Build on systems without AI_PASSIVE (cb92113)
+ o Fix http unit test on non-windows platforms without getaddrinfo (6092f12)
+ o Do not check for gethostbyname_r versions if we have getaddrinfo (c1260b0)
+ o Include arpa/inet.h as needed on HPUX (10c834c Harlan Stenn)
+ o Include util-internal.h as needed to build on platforms with no sockaddr_storage (bbf5515 Harlan Stenn)
+ o Check for getservbyname even if not on win32. (af08a94 Harlan Stenn)
+ o Add -D_OSF_SOURCE to fix hpux builds (0b33479 Harlan Stenn)
+ o Check for allocation failures in apply_socktype_protocol_hack (637d17a)
+ o Fix the check for multicast or broadcast addresses in evutil_check_interfaces (1a21d7b)
+ o Avoid a free(NULL) if out-of-memory in evdns_getaddrinfo. Found by Dave Hart (3417f68)
+
+DEFENSIVE PROGRAMMING:
+ o Add compile-time check for AF_UNSPEC==PF_UNSPEC (3c8f4e7)
+
+BUGS IN TESTS:
+ o Fix test.sh output on solaris (b4f89b6 Dave Hart)
+ o Make test-eof fail with a timeout if we never get an eof. (05a2c22 Harlan Stenn)
+ o Use %s with printf in test.sh (039b9bd)
+ o Add an assert to appease clang's static analyzer (b0ff7eb Sebastian Hahn)
+ o Add a forgotten return value check in the unit tests (3819b62 Sebastian Hahn)
+ o Actually send NULL request in http_bad_request_test (b693c32 Sebastian Hahn)
+ o add some (void) casts for unused variables (65707d7 Sebastian Hahn)
+ o Refactor test_getaddrinfo_async_cancel_stress() (48c44a6 Sebastian Hahn)
+ o Be nice and "handle" error return values in sample code (4bac793 Sebastian Hahn)
+ o Check return value of evbuffer_add_cb in tests (93a1abb Sebastian Hahn)
+ o Remote some dead code from dns-example.c (744c745 Sebastian Hahn)
+ o Zero a struct sockaddr_in before using it (646f9fe Sebastian Hahn)
+
+BUILD FIXES:
+ o Fix warnings about AC_LANG_PROGRAM usage (f663112 Sebastian Hahn)
+ o Skip check for zlib if we have no zlib.h (a317c06 Harlan Stenn)
+ o Fix autoconf bracket issues; make check for getaddrinfo include netdb.h (833e5e9 Harlan Stenn)
+ o Correct an AM_CFLAGS to an AM_CPPFLAGS in test/Makefile.am (9c469db Dave Hart)
+ o Fix make distcheck & installation of libevent 1 headers (b5a1f9f Dave Hart)
+ o Fix compilation under LLVM/clang with --enable-gcc-warnings (ad9ff58 Sebastian Hahn)
+
+FEATURES:
+ o Make URI parser able to tolerate nonconformant URIs. (95060b5)
+
+DOCUMENTATION:
+ o Clarify event_set_mem_functions doc (926f816)
+ o Correct evhttp_del_accept_socket documentation on whether socket is closed (f665924)
+ o fix spelling mistake in whatsnew-2.0.txt (deb2f73)
+ o Fix sample/http-server ipv6 fixes (eb692be)
+ o Comment internal headers used in sample code. (4eb281c)
+ o Be explicit about how long event loops run in event.h documentation (f95bafb)
+ o Add comment to configure.in to explain gc-sections test logic (c621359)
+ o Fix a couple of memory leaks in samples/http-server.c. Found by Dave Hart. (2e9f665)
+
+
+
+BUILD IMPROVEMENTS:
+ Libevent 2.1.2-alpha modernizes Libevent's use of autotools, and makes
+ numerous other build system. Parallel builds should be faster, and all
+ builds should be quieter.
+
+ o Split long lists in Makefile.am into one-item-per-line (2711cda)
+ o Remove unnecessary code in configure.in. (e65914f Ross Lagerwall)
+ o attempt to support OpenSSL in Makefile.nmake (eba0eb2 Patrick Pelletier)
+ o Use newer syntax for autoconf/automake init (7d60ba8)
+ o Enable silent build rules by default. Override with V=1 (7b18e5c)
+ o Switch to non-recursive makefiles (7092f3b)
+ o Rename subordinate Makefile.ams to include.am (6cdfeeb)
+ o Make quiet build even quieter (371a123)
+ o New --quiet option for event_rpcgen.py (aa59c1e)
+ o Be quiet when making regress.gen.[ch] (607a8ff)
+ o Fix handling of no-python case for nonrecursive make (1e3123d)
+ o We now require automake 1.9 or later. Modernize! (b7f6e89)
+ o Rename configure.in to configure.ac. (b3fea67 Ross Lagerwall)
+ o Use correct openssl libs and includes in pkgconfig file (d70af27)
+ o Use the same CFLAGS for openssl when building unit tests as with
+ libevent (1d9d511)
+
+DOCUMENTATION
+ o Note that make_base_notifiable should not be necessary (26ee5f9)
+ o Be more clear that LEV_OPT_DEFERRED_ACCEPT has tricky prereqs (371efeb)
+ o Add caveat to docs about bufferevent_free() with data in outbuf (6fab9ee)
+ o Make it more clear that NOLOCK means "I promise, no multithreading"
+ (9444524)
+ o Fix a comment in test-fdleak after 077c7e949. (3881d8f Ross Lagerwall)
+ o Make the Makefile.nmake warning slightly less dire (e7bf4c8)
+ o Fix typo : events instead of evets (05f1aca Azat Khuzhin)
+ o Additional comments about OPENSSL_DIR variable, prompted by Dave Hart
+ (6bde2ef Patrick Pelletier)
+
+EVHTTP:
+ o ignore LWS after field-content in headers (370a2c0 Artem Germanov)
+ o Clean up rtrim implementation (aa59d80)
+ o Remove trailing tabs in HTTP headers as well. (ac42519)
+ o Remove internal ws from multiline http headers correctly (c6ff381)
+ o Move evutil_rtrim_lws_ to evutil.c where it belongs (61b93af)
+ o add evhttp_request_get_response_code_line (4f4d0c9 Jay R. Wren)
+ o Use EVUTIL_SOCKET_ERROR() wrapper to save/restore errno in
+ evhttp_connection_fail_ (7afbd60)
+ o preserve errno in evhttp_connection_fail_ for inspection by the
+ callback (36d0ee5 Patrick Pelletier)
+
+BUGFIXES:
+ o Correctly handle running on a system where accept4 doesn't work. (9fbfe9b)
+ o Avoid double-free on error in evbuffer_add_file. Found by
+ coverity. (6a81b1f)
+ o Fix another possible uninitialized read in dns regression tests. Found
+ by coverity. (13525c5)
+ o Add checks for functions in test-ratelim.c; found by Coverity (aa501e1)
+ o Avoid memory leak in test_event_calloc unit test; found by coverity
+ (92817a1)
+ o Fix a shadowed variable in addfile_test_readcb; found by coverity
+ (225344c)
+ o Check return value when using LEV_OPT_DEFERRED_ACCEPT. Found by
+ coverity (6487f63)
+ o Prevent reference leak of bufferevent if getaddrinfo fails. (b757786
+ Joachim Bauch)
+ o Make event_base_getnpriorities work with old "implicit base" code
+ (c46cb9c)
+ o Simplify and correct evutil_open_closeonexec_ (0de587f)
+ o Fix event_dlist definition when sys/queue not included (81b6209
+ Derrick Pallas)
+
+
+
+Changes in version 2.1.1-alpha (4 Apr 2012)
+
+ Libevent 2.1.1-alpha includes a number of new features and performance
+ improvements. The log below tries to organize them by rough area of
+ effect. It omits some commits which were pure bugfixes on other commits
+ listed below. For more detail, see the git changelogs. For more
+ insight, see the "whatsnew-2.1.txt" document included in the Libevent
+ 2.1.1-alpha distribution.
+
+ Performance: Core
+ o Replace several TAILQ users with LIST. LIST can be a little faster than
+ TAILQ for cases where we don't need queue-like behavior. (f9db33d,
+ 6494772, d313c29, 974d004)
+ o Disabled code to optimize the case where we reinsert an existing
+ timeout (e47042f, 09cbc3d)
+ o Remove a needless base-notify when rescheduling the first timeout (77a96fd)
+ o Save a needless comparison when removing/adjusting timeouts (dd5189b)
+ o Possible optimization: split event_queue_insert/remove into
+ separate functions. needs testing (efc4dc5)
+ o Make event_count maintenance branchless at the expense of an
+ extra shift. Needs benchmarking (d1cee3b)
+ o In the 2.1 branch, let's try out lazy gettimeofday/clock_gettime
+ comparison (2a83ecc)
+ o Optimization in event_process_active(): ignore maxcb & endtime
+ for highest priority events. (a9866aa Alexander Drozdov)
+ o Bypass event_add when using event_base_once() for a 0-sec timeout (35c5c95)
+ o Remove the eventqueue list and the ev_next pointers. (604569b 066775e)
+
+ Performance: Evbuffers
+ o Roughly 20% speed increase when line-draining a buffer using
+ EVBUFFER_EOL_CRLF (5dde0f0 Mina Naguib)
+ o Try to squeeze a little more speed out of EVBUFFER_EOL_CRLF (7b9d139)
+ o Fix a bug in the improved EOL_CRLF code (d927965)
+ o Remove a needless branch in evbuffer_drain() (d19a326)
+
+ Performance: Linux
+ o Infrastructure for using faster/fewer syscalls when creating
+ sockets (a1c042b)
+ o Minimize syscalls during socket creation in listener.c (7e9e289)
+ o Use a wrapper function to create the notification
+ pipe/socketpair/eventfd (ca76cd9)
+ o Use pipes for telling signals to main thread when possible (a35f396)
+ o Save syscalls when constructing listener sockets for evhttp (af6c9d8)
+ o Save some syscalls when creating evdns sockets (713e570)
+ o Save some syscalls when constructing a socket for a bufferevent (33fca62)
+ o Prefer epoll_create1 on Linuxen that have it (bac906c)
+
+ Performance: Epoll backend
+ o Use current event set rather than current pending change when
+ deciding whether to no-op a del (04ba27e Mike Smellie)
+ o Replace big chain of if/thens in epoll.c with a table lookup (8c83eb6)
+ o Clean up error handling in epoll_apply_one_change() a little (2d55a19)
+
+ Performance: Evport backend
+ o evport: use evmap_io to track fdinfo status. Should save time and
+ RAM. (4687ce4)
+ o evport: Remove a linear search over recent events when
+ reactivating them (0f77efe)
+ o evport: Use portev_user to remember fdinfo struct (276ec0e)
+ o evport: don't scan more events in ed_pending than needed (849a5cf)
+ o evport: Remove artificial low limit on max events per getn call (c04d927)
+ o Reenable main/many_events_slow_add for evport in 2.1 (e903db3)
+
+ Performance: Windows
+ o Use GetSystemTimeAsFileTime to implement gettimeofday on
+ win32. It's faster and more accurate than our old
+ approach. (b8b8aa5)
+
+ New functions and features: debugging
+ o Add event_enable_debug_logging() to control use of debug logs (e30a82f)
+
+ New functions and features: core
+ o Add event_config function to limit time/callbacks between calls
+ to dispatch (fd4de1e, 9fa56bd, a37a0c0, 3c63edd)
+ o New EVLOOP_NO_EXIT_ON_EMPTY option to keep looping even when no
+ events are pending (084e68f)
+ o Add event_base_get_npriorities() function. (ee3a4ee Alexander Drozdov)
+ o Make evbase_priority_init() and evbase_get_npriorities()
+ threadsafe (3c55b5e)
+ o New event_base_update_cache_time() to set cached_tv to current
+ time (212533e Abel Mathew)
+ o Add event_self_cbarg() to be used in conjunction with
+ event_new(). (ed36e6a Ross Lagerwall, fa931bb, 09a1906, 1338e6c,
+ 33e43ef)
+ o Add a new libevent_global_shutdown() to free all globals before
+ exiting. (041ca00 Mark Ellzey, f98c158, 15296d0, 55e991b)
+ o Use getifaddrs to detect our interfaces if possible (7085a45)
+ o Add event_base_get_running_event() to get the event* whose cb we
+ are in (c5732fd, 13dad99)
+
+ New functions and features: building
+ o Implement --enable-gcc-hardening configure option (7550267 Sebastian Hahn)
+
+ New functions and features: evbuffers
+ o Add evbuffer_add_file_segment() so one fd can be used efficiently
+ in more than one evbuffer_add_file at a time (e72afae, c2d9884,
+ 3f405d2, 0aad014)
+ o Fix windows file segment mappings (8254de7)
+ o Allow evbuffer_ptr_set to yield a point just after the end of the
+ buffer. (e6fe1da)
+ o Allow evbuffer_ptr to point to position 0 in an empty evbuffer
+ (7aeb2fd Nir Soffer)
+ o Set the special "not found" evbuffer_ptr consistently. (e3e97ae Nir Soffer)
+ o support adding buffers to other buffers non-destructively
+ (9d7368a Joachim Bauch)
+ o prevent nested multicast references, reworked locking (26041a8
+ Joachim Bauch)
+ o New EVBUFFER_EOL_NUL to read NUL-terminated strings from an
+ evbuffer (d7a8b36 Andrea Montefusco, 54142c9)
+ o Make evbuffer_file_segment_types adaptable (c6bbbf1)
+ o Added evbuffer_add_iovec and unit tests. (aaec5ac Mark Ellzey, 27b5398)
+ o Add evbuffer_copyout_from to copy data from the middle of a
+ buffer (27e2225)
+
+ New functions and features: bufferevents
+ o Allow users to set allow_dirty_shutdown (099d27d Catalin Patulea)
+ o Tweak allow_dirty_shutdown documentation (a44cd2b)
+ o Fix two issues in the allow_dirty_shutdown code. (f3b89de)
+ o Add a bufferevent_getcb() to find a bufferevent's current
+ callbacks (a650394)
+ o bufferevent: Add functions to set/get max_single_read/write
+ values. (998c813 Alexander Drozdov)
+ o bev_ssl: Be more specific in event callbacks. evhttp in particular gets
+ confused without at least one of BEV_EVENT_{READING|WRITING}. (f7eb69a
+ Catalin Patulea)
+
+ New functions and features: evconnlisteners
+ o Support TCP_DEFER_ACCEPT sockopts for listeners (5880e4a Mark Ellzey,
+ a270728)
+ o Add another caveat to the TCP_DEFER_ACCEPT documentation (a270728)
+ o Allow evconnlistener to be created in disabled state. (9593a33
+ Alexander Drozdov)
+ o The LEV_OPT_CLOSE_ON_EXEC flag now applies to accepted listener
+ sockets too (4970329)
+
+ Evhttp:
+ o Add new evhttp_{connection_}set_timeout_tv() functions to set
+ finger-grained http timeouts (6350e6c Constantine Verutin)
+ o Performance tweak to evhttp_parse_request_line. (aee1a97 Mark Ellzey)
+ o Add missing break to evhttp_parse_request_line (0fcc536)
+ o Add evhttp callback for bufferevent creation; this lets evhttp
+ support SSL. (8d3a850)
+ o Remove calls to deprecated bufferevent functions from evhttp.c (4d63758)
+ o evhttp: Add evhttp_foreach_bound_socket. (a2c48e3 Samy Al Bahra)
+
+ Build improvements:
+ o Add AC_USE_SYSTEM_EXTENSIONS to configure.in. Requires follow on
+ patches for correctness and robustness. (1fa7dbe Kevin Bowling)
+ o Filter '# define' statements from autoconf and generate
+ event-private.h (321b558 Kevin Bowling)
+ o Remove internal usage of _GNU_SOURCE (3b26541 Kevin Bowling)
+ o Eliminate a couple more manual internal _GNU_SOURCE defines (c51ef93
+ Kevin Bowling)
+ o Add AC_GNU_SOURCE to the fallback case. (ea8fa4c Kevin Bowling)
+ o Use a Configuration Header Template for evconfig-private.h (868f888
+ Kevin Bowling)
+ o Fix a comment warning and add evconfig-private.h to .gitignore
+ (f6d66bc Kevin Bowling)
+ o Include evconfig-private.h in internal files for great good. (0915ca0
+ Kevin Bowling)
+ o Backport libevent to vanilla Autoconf 2.59 (as used in RHEL5)
+ (ad03952 Kevin Bowling)
+ o Prefer the ./configure evconfig-private.h in MinGW, just in
+ case. (f964b72 Kevin Bowling)
+ o Shell hack for weird mkdir -p commands (fd7b5a8 Kevin Bowling)
+ o Add evconfig-private to remaining files (ded0a09 Kevin Bowling)
+ o Allow use of --enable-silent-rules for quieter compilation with
+ automake 1.11 (f1f8514 Dave Hart)
+ o Use "_WIN32", not WIN32: it's standard and we don't need to fake it
+ (9f560b)
+ o In configure, test for _WIN32 not WIN32. (85078b1 Peter Rosin)
+ o Do not define WIN32 in Makefile.nmake (d41f3ea Peter Rosin)
+ o Provide the autoconf m4 macros for the new OpenSSL via pkg-config
+ stuff. (674dc3d Harlan Stenn)
+ o Use pkg-config (if available) to handle OpenSSL. (1c63860 Harlan Stenn)
+ o We need AM_CPPFLAGS when compiling bufferevent_openssl.c (6d2613b
+ Harlan Stenn)
+ o Fix OSX build: $(OPENSSL_INCS) needs to be after
+ $(AM_CPPFLAGS). (46f1769 Zack Weinberg)
+ o Make gcc warnings on by default, and --enable-gcc-warnings only add
+ -Werror (d46517e Sebastian Hahn)
+ o Split up extra-long AC_CHECK_FUNCS/HEADERS lines in configure.in (88a30ad)
+ o Move libevent 1.x headers to include/, to put all public headers in
+ one place. (bbea8d6)
+ o Put #ifdef around some files to support alternate build
+ systems. (76d4c92 Ross Lagerwall)
+ o Also make win32select.c conditional for IDE users (bf2c5a7)
+
+ Debugging:
+ o Add a magic number to debug_locks to better catch lock-coding
+ errors. (b4a29c0 Dave Hart)
+ o munge the debug_lock signature before freeing it: it might help us
+ catch use-after-free (f28084d)
+ o Added --enable-event-debugging in configure (bc7b4e4, a9c2c9a Mark Ellzey)
+ o Debug addition for printing usec on TIMEOUT debugging. (ac43ce0 Mark Ellzey)
+ o Added usec debug in another area for debug (3baab0d Mark Ellzey)
+ o added timeout debug logs to include event ptr. (4b7d298 Mark Ellzey)
+ o more event dbg updates (6727543 Mark Ellzey)
+ o Clarify event_enable_debug_logging a little (6207826)
+ o Make --enable-verbose-debug option match its help text (10c3450)
+ o Add argument checks to some memory functions in `event.c'. (c8953d1
+ Mansour Moufid)
+
+ Testing:
+ o More abstraction in test.sh (cd74c4e)
+ o Add failing test for evbuffer_search_range. (8e26154 Nir Soffer)
+ o Tweaks to return types with end-of-buf ptrs (9ab8ab8)
+ o Add an (internal) usleep function for use by unit tests (f25d9d3)
+ o Synchronize with upstream tinytest (6c81be7)
+ o Make test-changelist faster (7622d26)
+ o Reduce the timeout in the main/fork test. (ab14f7c)
+ o New evhttp function to adjust initial retry timeout (350a3c4)
+ o Make regression tests run over 3x faster. (67a1763)
+ o Use test_timeval_diff_eq more consistently (b77b43f)
+ o Allow more slop in deferred_cb_skew test; freebsd needs it (b9f7e5f)
+ o When including an -internal.h header outside the main tree, do so
+ early (95e2455)
+ o Add a new test: test-fdleak which tests for fd leaks by creating many
+ sockets. (2ef9278 Ross Lagerwall, f7af194, 1c4288f, etc)
+ o Add a unit test for event_base_dump_events() (7afe48a, 8d08cce)
+ o Test more bufferevent_ratelim features (c24f91a)
+
+ Documentation:
+ o Improve evbuffer_ptr documentation (261ba63)
+ o added comments to describe refcounting of multicast chains (ba24f61
+ Joachim Bauch)
+ o Add doxygen for event_base_dump_events (cad5753)
+
+ OSX:
+ o Use "unlimited select" on OSX so that we can have more than
+ FD_SETSIZE fds (1fb5cc6)
+
+ KQueue:
+ o Use SIG_IGN instead of a do-nothing handler for signal events with
+ kqueue (148458e Zack Weinberg)
+
+ evprc:
+ o event_rpcgen.py now prints status information to stdout and errors to
+ stderr. (ffb0ba0 Ross Lagerwall)
+
+ Code improvement and refactoring:
+ o Make event_reinit() more robust and maintainable (272033e)
+ o Restore fast-path event_reinit() for slower backends (2c4b5de)
+ o Check changelist as part of checking representational integrity (39b3f38)
+ o Fix a compile warning in event_reinit (e4a56ed Sebastian Hahn)
+ o Refactor the functions that run over every event. (c89b4e6)
+ o Remove the last vestiges of _EVENT_USE_EVENTLIST (a3cec90)
+ o Make event-config.h depend on Makefile.am (2958a5c)
+
+ Build fixes:
+ o Don't do clang version detection when disabling some flags (083296b
+ Sebastian Hahn)
+
+ C standards conformance:
+ o Check for NULL return on win32 mm_calloc, and set ENOMEM. (af7ba69)
+ o Convert event-config.h macros to avoid reserved identifiers (68120d9)
+ o Generate event-config.h using the correct macros. (f82c57e)
+ o Convert include-guard macro convention to avoid reserved identifiers
+ (3f8c7cd)
+ o Make event_rpcgen.py output conform to identifier conventions (372bff1)
+ o Stop referring to an obsolete include guard in bench_http.h (5c0f7e0)
+ o Make the generated event-config.h use correct include guards (639383a)
+ o Fix all identifiers with names beginning with underscore. (cb9da0b)
+ o Make event_rpcgen.py output conform to identifier conventions, more
+ (bcefd24)
+ o Fix some problems introduced by automated identifier cleanup script
+ (c963534)
+ o Have all visible internal function names end with an underscore. (8ac3c4c)
+ o Apply the naming convention to our EVUTIL_IS* functions (c7848fa)
+ o Clean up lingering _identifiers. (946b584)
+ o Fix doxygen to use new macro conventions (da455e9)
+
+ Bugfixes:
+ o Do not use system EAI/AI values if we are not using the system
+ getaddrinfo. (7bcac07)
+
+ Sample Code:
+ o Fix up sample/event-test.c to use newer interfaces and make it
+ actually work. (19bab4f Ross Lagerwall)
+ o On Unix, remove event.fifo left by sample/event-test.c. (c0dacd2 Ross
+ Lagerwall)
+ o Rename event-test.c to event-read-fifo.c. (a5b370a Ross Lagerwall)
+ o event-read-fifo: Use EV_PERSIST appropriately (24dab0b)
+
+
+
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/ChangeLog-1.4 b/fluent-bit/lib/monkey/mk_core/deps/libevent/ChangeLog-1.4
new file mode 100644
index 000000000..166d30872
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/ChangeLog-1.4
@@ -0,0 +1,231 @@
+Changes in 1.4.14b-stable
+ o Set the VERSION_INFO correctly for 1.4.14
+
+Changes in 1.4.14-stable
+ o Add a .gitignore file for the 1.4 branch. (d014edb)
+ o Backport evbuffer_readln(). (b04cc60 Nicholas Marriott)
+ o Make the evbuffer_readln backport follow the current API (c545485)
+ o Valgrind fix: Clear struct kevent before checking for OSX bug. (5713d5d William Ahern)
+ o Fix a crash when reading badly formatted resolve.conf (5b10d00 Yasuoka Masahiko)
+ o Fix memory-leak of signal handler array with kqueue. [backport] (01f3775)
+ o Update sample/signal-test.c to use newer APIs and not leak. (891765c Evan Jones)
+ o Correct all versions in 1.4 branch (ac0d213)
+ o Make evutil_make_socket_nonblocking() leave any other flags alone. (81c26ba Jardel Weyrich)
+ o Adjusted fcntl() retval comparison on evutil_make_socket_nonblocking(). (5f2e250 Jardel Weyrich)
+ o Correct a debug message in evhttp_parse_request_line (35df59e)
+ o Merge branch 'readln-backport' into patches-1.4 (8771d5b)
+ o Do not send an HTTP error when we've already closed or responded. (4fd2dd9 Pavel Plesov)
+ o Re-add event_siglcb; some old code _was_ still using it. :( (bd03d06)
+ o Make Libevent 1.4 build on win32 with Unicode enabled. (bce58d6 Brodie Thiesfield)
+ o Distribute nmake makefile for 1.4 (20d706d)
+ o do not fail while sending on http connections the client closed. (5c8b446)
+ o make evhttp_send() safe against terminated connections, too (01ea0c5)
+ o Fix a free(NULL) in min_heap.h (2458934)
+ o Fix memory leak when setting up priorities; reported by Alexander Drozdov (cb1a722)
+ o Clean up properly when adding a signal handler fails. (ae6ece0 Gilad Benjamini)
+ o Do not abort HTTP requests missing a reason string. (29d7b32 Pierre Phaneuf)
+ o Fix compile warning in http.c (906d573)
+ o Define _REENTRANT as needed on Solaris, elsewhere (6cbea13)
+
+
+Changes in 1.4.13-stable:
+ o If the kernel tells us that there are a negative number of bytes to read from a socket, do not believe it. Fixes bug 2841177; found by Alexander Pronchenkov.
+ o Do not allocate the maximum event queue and fd array for the epoll backend at startup. Instead, start out accepting 32 events at a time, and double the queue's size when it seems that the OS is generating events faster than we're requesting them. Saves up to 512K per epoll-based event_base. Resolves bug 2839240.
+ o Fix compilation on Android, which forgot to define fd_mask in its sys/select.h
+ o Do not drop data from evbuffer when out of memory; reported by Jacek Masiulaniec
+ o Rename our replacement compat/sys/_time.h header to avoid build a conflict on HPUX; reported by Kathryn Hogg.
+ o Build kqueue.c correctly on GNU/kFreeBSD platforms. Patch pulled upstream from Debian.
+ o Fix a problem with excessive memory allocation when using multiple event priorities.
+ o When running set[ug]id, don't check the environment. Based on a patch from OpenBSD.
+
+
+Changes in 1.4.12-stable:
+ o Try to contain degree of failure when running on a win32 version so heavily firewalled that we can't fake a socketpair.
+ o Fix an obscure timing-dependent, allocator-dependent crash in the evdns code.
+ o Use __VA_ARGS__ syntax for varargs macros in event_rpcgen when compiler is not GCC.
+ o Activate fd events in a pseudorandom order with O(N) backends, so that we don't systematically favor low fds (select) or earlier-added fds (poll, win32).
+ o Fix another pair of fencepost bugs in epoll.c. [Patch from Adam Langley.]
+ o Do not break evdns connections to nameservers when our IP changes.
+ o Set truncated flag correctly in evdns server replies.
+ o Disable strict aliasing with GCC: our code is not compliant with it.
+
+Changes in 1.4.11-stable:
+ o Fix a bug when removing a timeout from the heap. [Patch from Marko Kreen]
+ o Remove the limit on size of HTTP headers by removing static buffers.
+ o Fix a nasty dangling pointer bug in epoll.c that could occur after epoll_recalc(). [Patch from Kevin Springborn]
+ o Distribute Win32-Code/event-config.h, not ./event-config.h
+
+Changes in 1.4.10-stable:
+ o clean up buffered http connection data on reset; reported by Brian O'Kelley
+ o bug fix and potential race condition in signal handling; from Alexander Drozdov
+ o rename the Solaris event ports backend to evport
+ o support compilation on Haiku
+ o fix signal processing when a signal callback delivers a signal; from Alexander Drozdov
+ o const-ify some arguments to evdns functions.
+ o off-by-one error in epoll_recalc; reported by Victor Goya
+ o include Doxyfile in tar ball; from Jeff Garzik
+ o correctly parse queries with encoded \r, \n or + characters
+
+Changes in 1.4.9-stable:
+ o event_add would not return error for some backends; from Dean McNamee
+ o Clear the timer cache on entering the event loop; reported by Victor Chang
+ o Only bind the socket on connect when a local address has been provided; reported by Alejo Sanchez
+ o Allow setting of local port for evhttp connections to support millions of connections from a single system; from Richard Jones.
+ o Clear the timer cache when leaving the event loop; reported by Robin Haberkorn
+ o Fix a typo in setting the global event base; reported by lance.
+ o Fix a memory leak when reading multi-line headers
+ o Fix a memory leak by not running explicit close detection for server connections
+
+Changes in 1.4.8-stable:
+ o Match the query in DNS replies to the query in the request; from Vsevolod Stakhov.
+ o Fix a merge problem in which name_from_addr returned pointers to the stack; found by Jiang Hong.
+ o Do not remove Accept-Encoding header
+
+Changes in 1.4.7-stable:
+ o Fix a bug where headers arriving in multiple packets were not parsed; fix from Jiang Hong; test by me.
+
+Changes in 1.4.6-stable:
+ o evutil.h now includes <stdarg.h> directly
+ o switch all uses of [v]snprintf over to evutil
+ o Correct handling of trailing headers in chunked replies; from Scott Lamb.
+ o Support multi-line HTTP headers; based on a patch from Moshe Litvin
+ o Reject negative Content-Length headers; anonymous bug report
+ o Detect CLOCK_MONOTONIC at runtime for evdns; anonymous bug report
+ o Fix a bug where deleting signals with the kqueue backend would cause subsequent adds to fail
+ o Support multiple events listening on the same signal; make signals regular events that go on the same event queue; problem report by Alexander Drozdov.
+ o Deal with evbuffer_read() returning -1 on EINTR|EAGAIN; from Adam Langley.
+ o Fix a bug in which the DNS server would incorrectly set the type of a cname reply to a.
+ o Fix a bug where setting the timeout on a bufferevent would take not effect if the event was already pending.
+ o Fix a memory leak when using signals for some event bases; reported by Alexander Drozdov.
+ o Add libevent.vcproj file to distribution to help with Windows build.
+ o Fix a problem with epoll() and reinit; problem report by Alexander Drozdov.
+ o Fix off-by-one errors in devpoll; from Ian Bell
+ o Make event_add not change any state if it fails; reported by Ian Bell.
+ o Do not warn on accept when errno is either EAGAIN or EINTR
+
+Changes in 1.4.5-stable:
+ o Fix connection keep-alive behavior for HTTP/1.0
+ o Fix use of freed memory in event_reinit; pointed out by Peter Postma
+ o Constify struct timeval * where possible; pointed out by Forest Wilkinson
+ o allow min_heap_erase to be called on removed members; from liusifan.
+ o Rename INPUT and OUTPUT to EVRPC_INPUT and EVRPC_OUTPUT. Retain INPUT/OUTPUT aliases on on-win32 platforms for backwards compatibility.
+ o Do not use SO_REUSEADDR when connecting
+ o Fix Windows build
+ o Fix a bug in event_rpcgen when generated fixed-sized entries
+
+Changes in 1.4.4-stable:
+ o Correct the documentation on buffer printf functions.
+ o Don't warn on unimplemented epoll_create(): this isn't a problem, just a reason to fall back to poll or select.
+ o Correctly handle timeouts larger than 35 minutes on Linux with epoll.c. This is probably a kernel defect, but we'll have to support old kernels anyway even if it gets fixed.
+ o Fix a potential stack corruption bug in tagging on 64-bit CPUs.
+ o expose bufferevent_setwatermark via header files and fix high watermark on read
+ o fix a bug in bufferevent read water marks and add a test for them
+ o introduce bufferevent_setcb and bufferevent_setfd to allow better manipulation of bufferevents
+ o use libevent's internal timercmp on all platforms, to avoid bugs on old platforms where timercmp(a,b,<=) is buggy.
+ o reduce system calls for getting current time by caching it.
+ o fix evhttp_bind_socket() so that multiple sockets can be bound by the same http server.
+ o Build test directory correctly with CPPFLAGS set.
+ o Fix build under Visual C++ 2005.
+ o Expose evhttp_accept_socket() API.
+ o Merge windows gettimeofday() replacement into a new evutil_gettimeofday() function.
+ o Fix autoconf script behavior on IRIX.
+ o Make sure winsock2.h include always comes before windows.h include.
+
+Changes in 1.4.3-stable:
+ o include Content-Length in reply for HTTP/1.0 requests with keep-alive
+ o Patch from Tani Hosokawa: make some functions in http.c threadsafe.
+ o Do not free the kqop file descriptor in other processes, also allow it to be 0; from Andrei Nigmatulin
+ o make event_rpcgen.py generate code include event-config.h; reported by Sam Banks.
+ o make event methods static so that they are not exported; from Andrei Nigmatulin
+ o make RPC replies use application/octet-stream as mime type
+ o do not delete uninitialized timeout event in evdns
+
+Changes in 1.4.2-rc:
+ o remove pending timeouts on event_base_free()
+ o also check EAGAIN for Solaris' event ports; from W.C.A. Wijngaards
+ o devpoll and evport need reinit; tested by W.C.A Wijngaards
+ o event_base_get_method; from Springande Ulv
+ o Send CRLF after each chunk in HTTP output, for compliance with RFC2626. Patch from "propanbutan". Fixes bug 1894184.
+ o Add a int64_t parsing function, with unit tests, so we can apply Scott Lamb's fix to allow large HTTP values.
+ o Use a 64-bit field to hold HTTP content-lengths. Patch from Scott Lamb.
+ o Allow regression code to build even without Python installed
+ o remove NDEBUG ifdefs from evdns.c
+ o update documentation of event_loop and event_base_loop; from Tani Hosokawa.
+ o detect integer types properly on platforms without stdint.h
+ o Remove "AM_MAINTAINER_MODE" declaration in configure.in: now makefiles and configure should get re-generated automatically when Makefile.am or configure.in chanes.
+ o do not insert event into list when evsel->add fails
+
+Changes in 1.4.1-beta:
+ o free minheap on event_base_free(); from Christopher Layne
+ o debug cleanups in signal.c; from Christopher Layne
+ o provide event_base_new() that does not set the current_base global
+ o bufferevent_write now uses a const source argument; report from Charles Kerr
+ o better documentation for event_base_loopexit; from Scott Lamb.
+ o Make kqueue have the same behavior as other backends when a signal is caught between event_add() and event_loop(). Previously, it would catch and ignore such signals.
+ o Make kqueue restore signal handlers correctly when event_del() is called.
+ o provide event_reinit() to reintialize an event_base after fork
+ o small improvements to evhttp documentation
+ o always generate Date and Content-Length headers for HTTP/1.1 replies
+ o set the correct event base for HTTP close events
+ o New function, event_{base_}loopbreak. Like event_loopexit, it makes an event loop stop executing and return. Unlike event_loopexit, it keeps subsequent pending events from getting executed. Patch from Scott Lamb
+ o Removed obsoleted recalc code
+ o pull setters/getters out of RPC structures into a base class to which we just need to store a pointer; this reduces the memory footprint of these structures.
+ o fix a bug with event_rpcgen for integers
+ o move EV_PERSIST handling out of the event backends
+ o support for 32-bit tag numbers in rpc structures; this is wire compatible, but changes the API slightly.
+ o prefix {encode,decode}_tag functions with evtag to avoid collisions
+ o Correctly handle DNS replies with no answers set (Fixes bug 1846282)
+ o The configure script now takes an --enable-gcc-warnigns option that turns on many optional gcc warnings. (Nick has been building with these for a while, but they might be useful to other developers.)
+ o When building with GCC, use the "format" attribute to verify type correctness of calls to printf-like functions.
+ o removed linger from http server socket; reported by Ilya Martynov
+ o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
+ o demote most http warnings to debug messages
+ o Fix Solaris compilation; from Magne Mahre
+ o Add a "Date" header to HTTP responses, as required by HTTP 1.1.
+ o Support specifying the local address of an evhttp_connection using set_local_address
+ o Fix a memory leak in which failed HTTP connections would not free the request object
+ o Make adding of array members in event_rpcgen more efficient, but doubling memory allocation
+ o Fix a memory leak in the DNS server
+ o Fix compilation when DNS_USE_OPENSSL_FOR_ID is enabled
+ o Fix buffer size and string generation in evdns_resolve_reverse_ipv6().
+ o Respond to nonstandard DNS queries with "NOTIMPL" rather than by ignoring them.
+ o In DNS responses, the CD flag should be preserved, not the TC flag.
+ o Fix http.c to compile properly with USE_DEBUG; from Christopher Layne
+ o Handle NULL timeouts correctly on Solaris; from Trond Norbye
+ o Recalculate pending events properly when reallocating event array on Solaris; from Trond Norbye
+ o Add Doxygen documentation to header files; from Mark Heily
+ o Add a evdns_set_transaction_id_fn() function to override the default
+ transaction ID generation code.
+ o Add an evutil module (with header evutil.h) to implement our standard cross-platform hacks, on the theory that somebody else would like to use them too.
+ o Fix signals implementation on windows.
+ o Fix http module on windows to close sockets properly.
+ o Make autogen.sh script run correctly on systems where /bin/sh isn't bash. (Patch from Trond Norbye, rewritten by Hagne Mahre and then Hannah Schroeter.)
+ o Skip calling gettime() in timeout_process if we are not in fact waiting for any events. (Patch from Trond Norbye)
+ o Make test subdirectory compile under mingw.
+ o Fix win32 buffer.c behavior so that it is correct for sockets (which do not like ReadFile and WriteFile).
+ o Make the test.sh script run unit tests for the evpoll method.
+ o Make the entire evdns.h header enclosed in "extern C" as appropriate.
+ o Fix implementation of strsep on platforms that lack it
+ o Fix implementation of getaddrinfo on platforms that lack it; mainly, this will make Windows http.c work better. Original patch by Lubomir Marinov.
+ o Fix evport implementation: port_disassociate called on unassociated events resulting in bogus errors; more efficient memory management; from Trond Norbye and Prakash Sangappa
+ o support for hooks on rpc input and output; can be used to implement rpc independent processing such as compression or authentication.
+ o use a min heap instead of a red-black tree for timeouts; as a result finding the min is a O(1) operation now; from Maxim Yegorushkin
+ o associate an event base with an rpc pool
+ o added two additional libraries: libevent_core and libevent_extra in addition to the regular libevent. libevent_core contains only the event core whereas libevent_extra contains dns, http and rpc support
+ o Begin using libtool's library versioning support correctly. If we don't mess up, this will more or less guarantee binaries linked against old versions of libevent continue working when we make changes to libevent that do not break backward compatibility.
+ o Fix evhttp.h compilation when TAILQ_ENTRY is not defined.
+ o Small code cleanups in epoll_dispatch().
+ o Increase the maximum number of addresses read from a packet in evdns to 32.
+ o Remove support for the rtsig method: it hasn't compiled for a while, and nobody seems to miss it very much. Let us know if there's a good reason to put it back in.
+ o Rename the "class" field in evdns_server_request to dns_question_class, so that it won't break compilation under C++. Use a macro so that old code won't break. Mark the macro as deprecated.
+ o Fix DNS unit tests so that having a DNS server with broken IPv6 support is no longer cause for aborting the unit tests.
+ o Make event_base_free() succeed even if there are pending non-internal events on a base. This may still leak memory and fds, but at least it no longer crashes.
+ o Post-process the config.h file into a new, installed event-config.h file that we can install, and whose macros will be safe to include in header files.
+ o Remove the long-deprecated acconfig.h file.
+ o Do not require #include <sys/types.h> before #include <event.h>.
+ o Add new evutil_timer* functions to wrap (or replace) the regular timeval manipulation functions.
+ o Fix many build issues when using the Microsoft C compiler.
+ o Remove a bash-ism in autogen.sh
+ o When calling event_del on a signal, restore the signal handler's previous value rather than setting it to SIG_DFL. Patch from Christopher Layne.
+ o Make the logic for active events work better with internal events; patch from Christopher Layne.
+ o We do not need to specially remove a timeout before calling event_del; patch from Christopher Layne.
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/ChangeLog-2.0 b/fluent-bit/lib/monkey/mk_core/deps/libevent/ChangeLog-2.0
new file mode 100644
index 000000000..a925d33b1
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/ChangeLog-2.0
@@ -0,0 +1,1280 @@
+Changes in version 2.0.21-stable (18 Nov 2012)
+BUGFIXES:
+ o ssl: Don't discard SSL read event when timeout and read come close together (576b29f)
+ o ssl: Stop looping in "consider_reading" if reading is suspended. (f719b8a Joachim Bauch)
+ o ssl: No need to reserve space if reading is suspended. (1acf2eb Joachim Bauch)
+ o dns: Avoid a memory-leak on OOM in evdns. (73e85dd, f2bff75 George Danchev)
+ o build: Use python2 rather than python (0eb0109 Ross Lagerwall)
+ o build: Compile without warnings on mingw64 (94866c2)
+ o build: Fix compilation on mingw64 with -DUSE_DEBUG (62bd2c4)
+ o build: Make rpcgen_wrapper.sh work on systems without a "python2" binary (f3009e4)
+ o iocp: Close IOCP listener socket on free when LEV_OPT_CLOSE_ON_FREE is set (cb853ea Juan Pablo Fernandez)
+ o core: Avoid crash when event_pending() called with no event_base set on event (e3cccf3)
+ o misc: remove stray 'x' so print_err will compile when uncommented (ac35650 Patrick Pelletier)
+ o tests: Fix renegotiation test to work around openssl 1.0.1 bug (c2f3086)
+ o tests: Warn when openssl version in unit test mismatches compiled version. (ac009f9)
+
+
+Changes in version 2.0.20-stable (23 Aug 2012)
+BUGFIXES:
+ o core: Make event_pending() threadsafe. (be7a95c Simon Liu)
+ o win32: avoid crash when waiting forever on zero fds. (160e58b)
+ o evhttp: Fix a memory leak on error in evhttp_uriencode (11c8b31)
+ o evbuffer: Avoid possible needless call to writev. Found by coverity. (6a4ec5c)
+ o evdns: memset sockaddr_in before using it. Found by coverity. (a1a0e67)
+ o evhttp: Check more setsockopt return values when binding sockets. Found by coverity (a0912e3)
+ o evdns: Avoid segfault on weird timeout during name lookup. (dc32077 Greg Hazel)
+ o bufferevent_ssl: Correctly invoke callbacks when a SSL bufferevent reads some and then blocks. (606ac43)
+
+
+PORTABILITY FIXES:
+ o check for arc4random_buf at runtime, on OS X (bff5f94 Greg Hazel)
+ o Correctly check for arc4random_buf (fcec3e8 Sebastian Hahn)
+ o Add explicit AC_PROG_SED to configure.in so all autoconfs will expose $(SED) (ca80ea6)
+
+BUILD FIXES:
+ o Add GCC annotations so that the vsprintf functions get checked properly (117e327)
+ o Fix an unused variable warning on *BSD. (c0720c1)
+
+UNIT TEST FIXES:
+ o Fix a couple of memory leaks (found with Valgrind). (3b2529a Ross Lagerwall)
+ o Remove deadcode in http regression tests. Found by coverity. (5553346)
+ o Fix possible uninitialized read in dns regression tests. Found by coverity. (2259777)
+ o Set umask before calling mkstemp in unit tests. Found by coverity (f1ce15d)
+ o Fix various check-after-dereference issues in unit tests: found by coverity (4f3732d)
+ o Fix resource leaks in the unit tests; found by coverity (270f279)
+ o Add some missing null checks to unit tests; found by coverity (f021c3d)
+ o Avoid more crashes/bad calls in unit tests; found by coverity (3cde5bf)
+ o Remove unused variable; spotted by coverity (6355b2a)
+ o Add checks to various return values in unit tests. Found by coverity (b9e7329)
+ o Move assignment outside tt_assert in ssl unit tests. Appeases coverity. (a2006c0)
+
+
+
+Changes in version 2.0.19-stable (3 May 2012)
+BUGFIXES (CORE):
+ o Refactor event_persist_closure: raise and extract some common logic (bec22b4)
+ o If time has jumped so we'd reschedule a periodic event in the past, schedule it for the future instead (dfd808c)
+ o If a higher-priority event becomes active, don't continue running events of the current priority. (2bfda40)
+
+BUGFIXES (SSL):
+ o Fixed potential double-readcb execution with openssl bufferevents. (4e62cd1 Mark Ellzey)
+
+BUGFIXES (DNS):
+ o Cancel a probe request when the server is freed, and ignore cancelled probe callbacks (94d2336 Greg Hazel)
+ o Remove redundant DNS_ERR_CANCEL check, move comment (46b8060 Greg Hazel)
+ o When retransmitting a timed-out DNS request, pick a fresh nameserver. (3d9e52a)
+
+DOCUMENTATION FIXES:
+ o Fix a typo in the bufferevent documentation (98e9119)
+ o Add missing ) to changelog; spotted by rransom (4c7ee6b)
+ o Fix the website URL in the readme (f775521)
+
+COMPILATION FIXES:
+ o Fix a compilation error with MSVC 2005 due to use of mode_t (336dcae)
+ o Configure with gcc older than 2.95 (4a6fd43 Sebastian Hahn)
+ o Generate event-config.h with a single sed script (30b6f88 Zack Weinberg)
+
+FORWARD-COMPATIBILITY:
+ o Backport: provide EVENT_LOG_* names, and deprecate _EVENT_LOG_* (d1a03b2)
+
+TESTING/DEBUGGING SUPPORT:
+ o dns-example.c can now take a resolv.conf file on the commandline (6610fa5)
+ o Make some evdns.c debug logs more verbose (d873d67)
+ o Work-around a stupid gcov-breaking bug in OSX 10.6 (b3887cd)
+
+
+
+Changes in version 2.0.18-stable (22 Mar 2012)
+BUGFIXES (core):
+ o Make uses of open() close-on-exec safe by introducing an internal evutil_open_closeonexec. (d2b5f72 Ross Lagerwall, 03dce42)
+
+BUGFIXES (kqueue):
+ o Properly zero the kevent in kq_setup_kevent() (c2c7b39 Sebastian Hahn)
+
+BUILD FIXES:
+ o Added OPENSSL_LDFLAGS env variable which is appended to SSL checks. (9278196 Mark Ellzey)
+ o Changed OPENSSL_LDFLAGS to OPENSSL_LIBADD (2d67b63 Mark Ellzey)
+ o Don't do clang version detection when disabling some flags (083296b Sebastian Hahn)
+
+BUGFIXES (dns):
+ o Stop crashing in evdns when nameserver probes give a weird error (bec5068)
+
+
+Changes in version 2.0.17-stable (10 Feb 2012)
+
+BUGFIXES (core):
+ o Be absolutely sure to clear pncalls before leaving event_signal_closure (11f36a5)
+ o check for sysctl before we use it (358c745 Mike Frysinger)
+ o Remove bogus casts of socket to int before calling ev_callback (f032516)
+ o Make evconnlistener work around bug in older Linux when getting nmapped (ecfc720)
+ o Fix a list corruption bug when using event_reinit() with signals present (6e41cdc)
+ o Fix a fd leak in event_reinit() (3f18ad1)
+ o Do a memberwise comparison of threading function tables (c94a5f2 Nate R)
+ o Use C-style comments in C source files (for compatibility with compilers such as xlc on AIX). (d84d917 Greg Hewgill)
+ o Avoid crash when freeing event_iocp and using event_set_mem_functions (19715a6)
+ o In the kqueue backend, do not report EBADF as an EV_READ (5d7bfa1 Nicholas Marriott)
+
+BUGFIXES (evbuffer and bufferevents):
+ o Fix behavior of evbuffer_peek(buf,-1,NULL,NULL,0) (c986f23 Zack Weinberg)
+ o Loop on filtering SSL reads until we are blocked or exhausted. (5b4b812)
+
+BUGFIXES (evhttp):
+ o Force strict validation of HTTP version in response. (790f6b3 Catalin Patulea)
+
+BUGFIXES (evdns):
+ o evdns: fix a bug in circular-queue implementation (d6094b1)
+
+BUILD FIXES:
+ o Fix a silly compilation error with the sun compiler (1927776 Colin Watt)
+ o Suppress a gcc warning from ignoring fwrite return in http-sample.c (7206e8c)
+
+DOCUMENTATION FIXES:
+ o Slightly clarify evbuffer_peek documentation (7bbf6ca)
+ o Update copyright notices to 2012 (e49e289)
+
+NEW APIS:
+ o Backport evhttp_connection_get_bufferevent to Libevent 2.0 (da70fa7 Arno Bakker)
+
+TESTS AND TEST FIXES:
+ o Fix a race condition in the dns/bufferevent_connect_hostname test. (cba48c7)
+ o Add function to check referential integrity of an event_base (27737d5)
+ o Check event_base correctness at end of each unit test (3312b02)
+ o Workaround in the unit tests for an apparent epoll bug in Linux 3.2 (dab9187)
+ o Better workaround for Linux 3.2 edge-triggered epoll bug (9f9e259)
+
+Changes in version 2.0.16-stable (18 Nov 2011)
+BUGFIXES (core):
+ o More detailed message in case of libevent self-debugging failure. (9e6a4ef Leonid Evdokimov)
+ o epoll: close fd on alloc fail at initialization (1aee718 Jamie Iles)
+ o Fix compile warning from saying event2/*.h inside a comment (447b0ba)
+ o Warn when unable to construct base because of failing make_base_notifiable (4e797f3)
+ o Don't try to make notifiable event_base when no threading fns are configured (e787413)
+
+BUGFIXES (evbuffer):
+ o unit test for remove_buffer bug (90bd620 Greg Hazel)
+ o Fix an evbuffer crash in evbuffer_remove_buffer() (c37069c)
+
+BUGFIXES (bufferevent_openssl):
+ o Refactor amount-to-read calculations in buffervent_ssl consider_reading() (a186e73 Mark Ellzey)
+ o Move SSL rate-limit enforcement into bytes_to_read() (96c562f)
+ o Avoid spinning on OpenSSL reads (2aa036f Mark Ellzey)
+
+BUGFIXES (dns)
+ o Empty DNS reply with OK status is another way to say NODATA. (21a08d6 Leonid Evdokimov)
+
+TESTING:
+ o Tests for 94fba5b and f72e8f6 (d58c15e Leonid Evdokimov)
+ o Test for commit aff6ba1 (f7841bf Leonid Evdokimov)
+ o Style and comment tweaks for dns/leak* tests (5e42202)
+ o improve test to remove at least one buffer from src (7eb52eb Greg Hazel)
+
+DOCUMENTATION:
+ o Add note about evhttp_send_reply_end to its doxygen (724bfb5)
+ o Update copyright dates to 2011. (3c824bd)
+ o Fix typo in whatsnew-2.0.txt (674bc6a Mansour Moufid)
+ o Improve win32 behavior of dns-sample.c code (a3f320e Gisle Vanem)
+
+
+
+Changes in version 2.0.15-stable (12 Oct 2011)
+BUGFIXES (DNS):
+ o DNS: add ttl for negative answers using RFC 2308 idea. (f72e8f6 Leonid Evdokimov)
+ o Add DNS_ERR_NODATA error code to handle empty replies. (94fba5b Leonid Evdokimov)
+
+BUFGIXES (bufferevents and evbuffers):
+ o Make evbuffer callbacks get the right n_added value after evbuffer_add (1ef1f68 Alex)
+ o Prefer mmap to sendfile unless a DRAINS_TO_FD flag is set. Allows add_file to work with SSL. (0ba0af9)
+
+BUGFIXES (event loop):
+ o When a signal callback is activated to run multiple times, allow event_base_loopbreak to work even before they all have run. (4e8eb6a)
+
+DOCUMENTATION FIXES:
+ o Fix docstring in dns.h (2b6eae5 Leonid Evdokimov)
+ o refer to non-deprecated evdns functions in comments (ba5c27d Greg Hazel)
+
+BUILD AND TESTING FIXES:
+ o le-proxy and regress depend on openssl directly (9ae061a Sergey Avseyev)
+ o Use _SOURCES, not _sources, in sample/Makefile.am (7f82382)
+ o Fixed compiler warnings for unchecked read/write calls. (c3b62fd Mark Ellzey)
+ o Make write-checking fixes use tt_fail_perror (2b76847)
+ o Fix some "value never used" warnings with gcc 4.6.1 (39c0cf7)
+
+
+
+Changes in version 2.0.14-stable (31 Aug 2011)
+BUGFIXES (bufferevents and evbuffers):
+ o Propagate errors on the underlying bufferevent to the user. (4a34394 Joachim Bauch)
+ o Ignore OpenSSL deprecation warnings on OS X (5d1b255 Sebastian Hahn)
+ o Fix handling of group rate limits under 64 bytes of burst (6d5440e)
+ o Solaris sendfile: correctly detect amount of data sent (643922e Michael Herf)
+ o Make rate limiting work with common_timeout logic (5b18f13)
+ o clear read watermark on underlying bufferevent when creating filtering bev to fix potentially failing fragmented ssl handshakes (54f7e61 Joachim Bauch)
+
+BUGFIXES (IOCP):
+ o IOCP: don't launch reads or writes on an unconnected socket (495c227)
+ o Make IOCP rate-limiting group support stricter and less surprising. (a98da7b)
+ o Have test-ratelim.c support IOCP (0ff2c5a)
+ o Make overlapped reads result in evbuffer callbacks getting invoked (6acfbdd)
+ o Correctly terminate IO on an async bufferevent on bufferevent_free (e6af35d)
+
+BUGFIXES (other):
+ o Fix evsig_dealloc memory leak with debugging turned on. (9b724b2 Leonid Evdokimov)
+ o Fix request_finished memory leak with debugging turned on. (aff6ba1 Leonid Evdokimov)
+
+BUILD AND TESTING FIXES:
+ o Allow OS-neutral builds for platforms where some versions have arc4random_buf (b442302 Mitchell Livingston)
+ o Try to fix 'make distcheck' errors when building out-of-tree (04656ea Dave Hart)
+ o Clean up some problems identified by Coverity. (7c11e51 Harlan Stenn)
+
+
+Changes in version 2.0.13-stable (18 Jul 2011)
+BUGFIXES
+ o Avoid race-condition when initializing global locks (b683cae)
+ o Fix bug in SSL bufferevents backed by a bev with a write high-watermarks (e050703 Joachim Bauch)
+ o Speed up invoke_callbacks on evbuffers when there are no callbacks (f87f568 Mark Ellzey)
+ o Avoid a segfault when all methods are disabled or broken (27ce38b)
+ o Fix incorrect results from evbuffer_search_eol(EOL_LF) (4461f1a)
+ o Add some missing checks for mm_calloc failures (89d5e09)
+ o Replace an assertion for event_base_free(NULL) with a check-and-warn (09fe97d)
+ o Report kqueue ebadf, epipe, and eperm as EV_READ events (1fd34ab)
+ o Check if the `evhttp_new_object' function in `http.c' returns NULL. (446cc7a Mansour Moufid)
+ o Use the correct printf args when formatting size_t (3203f88)
+ o Complain if the caller tries to change threading cbs after setting them (cb6ecee)
+
+DOCUMENTATION FIXES AND IMPROVEMENTS
+ o Revise the event/evbuffer/bufferevent doxygen for clarity and accuracy (2888fac)
+ o Update Doxyfile to produce more useful output (aea0555)
+
+TEST FIXES
+ o Fix up test_evutil_snprintf (caf695a)
+ o Fix tinytest invocation from windows shell (57def34 Ed Day)
+
+BUILD FIXES
+ o Use AM_CPPFLAGS in sample/Makefile.am, not AM_CFLAGS (4a5c82d)
+ o Fix select.c compilation on systems with no NFDBITS (49d1136)
+ o Fix a few warnings on OpenBSD (8ee9f9c Nicholas Marriott)
+ o Don't break when building tests from git without python installed (b031adf)
+ o Don't install event_rpcgen.py when --disable-libevent-install is used (e23cda3 Harlan Stenn)
+ o Fix AIX build issue with TAILQ_FOREACH definition (e934096)
+
+
+Changes in version 2.0.12-stable (4 Jun 2011)
+BUGFIXES
+ o Fix a warn-and-fail bug in kqueue by providing kevent() room to report errors (28317a0)
+ o Fix an assert-inducing fencepost bug in the select backend (d90149d)
+ o Fix failing http assertion introducd in commit 0d6622e (0848814 Kevin Ko)
+ o Fix a bug that prevented us from configuring IPv6 nameservers. (74760f1)
+ o Prevent size_t overflow in evhttp_htmlescape. (06c51cd Mansour Moufid)
+ o Added several checks for under/overflow conditions in evhttp_handle_chunked_read (a279272 Mark Ellzey)
+ o Added overflow checks in evhttp_read_body and evhttp_get_body (84560fc Mark Ellzey)
+
+DOCUMENTATION:
+ o Add missing words to EVLOOP_NONBLOCK documentation (9556a7d)
+
+BUILD FIXES
+ o libssl depends on libcrypto, not the other way around. (274dd03 Peter Rosin)
+ o Libtool brings in the dependencies of libevent_openssl.la automatically (7b819f2 Peter Rosin)
+ o Use OPENSSL_LIBS in Makefile.am (292092e Sebastian Hahn)
+ o Move the win32 detection in configure.in (ceb03b9 Sebastian Hahn)
+ o Correctly detect openssl on windows (6619385 Sebastian Hahn)
+ o Fix a compile warning with zlib 1.2.4 and 1.2.5 (5786b91 Sebastian Hahn)
+ o Fix compilation with GCC 2, which had no __builtin_expect (09d39a1 Dave Hart)
+ o Fix new warnings from GCC 4.6 (06a714f)
+ o Link with -lshell32 and -ladvapi32 on Win32. (86090ee Peter Rosin)
+ o Make the tests build when OpenSSL is not available. (07c41be Peter Rosin)
+ o Bring in the compile script from automake, if needed. (f3c7a4c Peter Rosin)
+ o MSVC does not provide S_ISDIR, so provide it manually. (70be7d1 Peter Rosin)
+ o unistd.h and sys/time.h might not exist. (fe93022 Peter Rosin)
+ o Make sure TINYTEST_LOCAL is defined when building tinytest.c (8fa030c Peter Rosin)
+ o Fix winsock2.h #include issues with MSVC (3d768dc Peter Rosin)
+ o Use evutil_gettimeofday instead of relying on the system gettimeofday. (0de87fe Peter Rosin)
+ o Always use evutil_snprintf, even if OS provides it (d1b2d11 Sebastian Hahn)
+ o InitializeCriticalSectionAndSpinCount requires _WIN32_WINNT >= 0x0403. (816115a Peter Rosin)
+ o cygwin: make it possible to build DLLs (d54d3fc)
+
+
+
+Changes in version 2.0.11-stable (27 Apr 2011)
+ [Autogenerated from the Git log, sorted and cleaned by hand.]
+BUGFIXES:
+ o Fix evport handling of POLLHUP and POLLERR (b42ce4b)
+ o Fix compilation on Windows with NDEBUG (cb8059d)
+ o Check for POLLERR, POLLHUP and POLLNVAL for Solaris event ports (0144886 Trond Norbye)
+ o Detect and handle more allocation failures. (666b096 Jardel Weyrich)
+ o Use event_err() only if the failure is truly unrecoverable. (3f8d22a Jardel Weyrich)
+ o Handle resize failures in the select backend better. (83e805a)
+ o Correctly free selectop fields when select_resize fails in select_init (0c0ec0b)
+ o Make --enable-gcc-warnings a no-op if not using gcc (3267703)
+ o Fix a type error in our (unused) arc4random_stir() (f736198)
+ o Correctly detect and stop non-chunked http requests when the body is too long (63a715e)
+ o Have event_base_gettimeofday_cached() always return wall-clock time (a459ef7)
+ o Workaround for http crash bug 3078187 (5dc5662 Tomash Brechko)
+ o Fix incorrect assertions and possible use-after-free in evrpc_free() (4b8f02f Christophe Fillot)
+ o Reset outgoing http connection when read data in idle state. (272823f Tomash Brechko)
+ o Fix subtle recursion in evhttp_connection_cb_cleanup(). (218cf19 Tomash Brechko)
+ o Fix the case when failed evhttp_make_request() leaved request in the queue. (0d6622e Tomash Brechko)
+ o Fix a crash bug in evdns server circular list code (00e91b3)
+ o Handle calloc failure in evdns. (Found by Dave Hart) (364291e)
+ o Fix a memory leak on win32 socket->event map. (b4f89f0)
+ o Add a forgotten NULL check to evhttp_parse_headers (12311ff Sebastian Hahn)
+ o Fix possible NULL-deref in evdns_cancel_request (5208544 Sebastian Hahn)
+
+PORTABILITY:
+ o Fall back to sscanf if we have no other way to implement strtoll (453317b)
+ o Build correctly on platforms without sockaddr_storage (9184563)
+ o Try to build correctly on platforms with no IPv6 support (713c254)
+ o Build on systems without AI_PASSIVE (cb92113)
+ o Fix http unit test on non-windows platforms without getaddrinfo (6092f12)
+ o Do not check for gethostbyname_r versions if we have getaddrinfo (c1260b0)
+ o Include arpa/inet.h as needed on HPUX (10c834c Harlan Stenn)
+ o Include util-internal.h as needed to build on platforms with no sockaddr_storage (bbf5515 Harlan Stenn)
+ o Check for getservbyname even if not on win32. (af08a94 Harlan Stenn)
+ o Add -D_OSF_SOURCE to fix hpux builds (0b33479 Harlan Stenn)
+ o Check for allocation failures in apply_socktype_protocol_hack (637d17a)
+ o Fix the check for multicast or broadcast addresses in evutil_check_interfaces (1a21d7b)
+ o Avoid a free(NULL) if out-of-memory in evdns_getaddrinfo. Found by Dave Hart (3417f68)
+
+DEFENSIVE PROGRAMMING:
+ o Add compile-time check for AF_UNSPEC==PF_UNSPEC (3c8f4e7)
+
+BUGS IN TESTS:
+ o Fix test.sh output on solaris (b4f89b6 Dave Hart)
+ o Make test-eof fail with a timeout if we never get an eof. (05a2c22 Harlan Stenn)
+ o Use %s with printf in test.sh (039b9bd)
+ o Add an assert to appease clang's static analyzer (b0ff7eb Sebastian Hahn)
+ o Add a forgotten return value check in the unit tests (3819b62 Sebastian Hahn)
+ o Actually send NULL request in http_bad_request_test (b693c32 Sebastian Hahn)
+ o add some (void) casts for unused variables (65707d7 Sebastian Hahn)
+ o Refactor test_getaddrinfo_async_cancel_stress() (48c44a6 Sebastian Hahn)
+ o Be nice and "handle" error return values in sample code (4bac793 Sebastian Hahn)
+ o Check return value of evbuffer_add_cb in tests (93a1abb Sebastian Hahn)
+ o Remote some dead code from dns-example.c (744c745 Sebastian Hahn)
+ o Zero a struct sockaddr_in before using it (646f9fe Sebastian Hahn)
+
+BUILD FIXES:
+ o Fix warnings about AC_LANG_PROGRAM usage (f663112 Sebastian Hahn)
+ o Skip check for zlib if we have no zlib.h (a317c06 Harlan Stenn)
+ o Fix autoconf bracket issues; make check for getaddrinfo include netdb.h (833e5e9 Harlan Stenn)
+ o Correct an AM_CFLAGS to an AM_CPPFLAGS in test/Makefile.am (9c469db Dave Hart)
+ o Fix make distcheck & installation of libevent 1 headers (b5a1f9f Dave Hart)
+ o Fix compilation under LLVM/clang with --enable-gcc-warnings (ad9ff58 Sebastian Hahn)
+
+FEATURES:
+ o Make URI parser able to tolerate nonconformant URIs. (95060b5)
+
+DOCUMENTATION:
+ o Clarify event_set_mem_functions doc (926f816)
+ o Correct evhttp_del_accept_socket documentation on whether socket is closed (f665924)
+ o fix spelling mistake in whatsnew-2.0.txt (deb2f73)
+ o Fix sample/http-server ipv6 fixes (eb692be)
+ o Comment internal headers used in sample code. (4eb281c)
+ o Be explicit about how long event loops run in event.h documentation (f95bafb)
+ o Add comment to configure.in to explain gc-sections test logic (c621359)
+ o Fix a couple of memory leaks in samples/http-server.c. Found by Dave Hart. (2e9f665)
+
+BUILD IMPROVEMENTS:
+ o Use the gcc -ffunction-segments feature to allow gc when linking with static libevent (0965c56 Dave Hart)
+ o Add configure options to disable installation, regression tests (49e9bb7 Dave Hart)
+
+
+
+Changes in version 2.0.10-stable (16 Dec 2010)
+ [Autogenerated from the Git log, sorted and cleaned by hand.]
+BUGFIXES
+ o Minor fix for IOCP shutdown handling fix (2599b2d Kelly Brock)
+ o Correctly notify the main thread when activating an event from a subthread (5beeec9)
+ o Reject overlong http requests early when Expect:100-continue is set (d23839f Constantine Verutin)
+ o EVUTIL_ASSERT: Use sizeof() to avoid "unused variable" warnings with -DNDEBUG. (b63ab17 Evan Jones)
+
+CODE CLEANUPS
+ o bufferevent-internal.h: Use the new event2/util.h header, not evutil.h (ef5e65a Evan Jones)
+ o Use relative includes instead of system includes consistently. (fbe64f2 Evan Jones)
+ o Make whitespace more consistent
+
+TESTING
+ o tests: Use new event2 headers instead of old compatibility headers. (4f33209 Evan Jones)
+
+DOCUMENTATION
+ o Document that the cpu_hint is only used on Windows with IOCP for now (57689c4)
+ o Add stuff to "whats new in 2.0" based on reading include changes since August. (18adc3f)
+
+
+Changes in 2.0.9-rc (30 Nov 2010):
+ [Autogenerated from the Git log, sorted and cleaned by hand.]
+NEW AND MODIFIED APIs
+ o Add a function to change a listener's callback. (46ee061)
+ o Make evbuffer_add_file take ev_off_t, not off_t (ac7e52d)
+ o Make rate-limits go up to SIZE_MAX/EV_SSIZE_MAX, not just INT32_MAX (2cbb1a1)
+ o Add a bufferevent_get_base function (aab49b6)
+
+MAJOR BUGFIXES
+ o Disable changelist for epoll by default because of Linux dup() bug; add an option and/or an envvar to reenable it for speed. (9531763)
+ o Fix a 100%-CPU bug where an SSL connection would sometimes never stop trying to write (1213d3d)
+ o Fix a nasty bug related to use of dup() with epoll on Linux (c281aba)
+ o Fix bugs in posix thread-id calculation when sizeof(pthread_t) != sizeof(long) (fbaf077)
+ o Fix some ints to evutil_socket_t; make tests pass on win64. (f817bfa Dimitre Piskyulev)
+ o Set _EVENT_SIZEOF_VOID_P correctly on win32 and win64 (1ae82cd Dimitre Piskyulev)
+ o Avoid double-invocation of user callback with EVUTIL_EAI_CANCEL (abf01ed)
+ o Set SO_UPDATE_ACCEPT_CONTEXT on sockets from AcceptEx so that shutdown() can work (52aa419)
+ o When closing a filtering bufferevent, clear callbacks on the underlying bufferevent (fc7b1b0)
+
+NEW AND MODIFIED HTTP APIs
+ o Add evhttp_parse_query_str to be used with evhttp_uri_parse. (2075fbc)
+ o Add evhttp_response_code to remove one more reason to include http_struct.h (22e0a9b)
+ o Define enumerators for all HTTP methods, including PATCH from RFC5789 (75a7341 Felix Nawothnig)
+ o Functions to actually use evhttp_bound_socket with/as evconnlistener. (006efa7)
+ o Add evhttp_request_get_command so code can tell GET from POST without peeking at the struct. (49f4bf7)
+ o Introduce absolute URI parsing helpers. (86dd720 Pavel Plesov)
+ o Revise evhttp_uri_parse implementation to handle more of RFC3986 (eaa5f1d)
+ o Add evhttp_connection_get_base() to get the event_base from an http connection (cd00079)
+ o Let evhttp_parse_query return -1 on failure (b1756d0)
+ o New evhttp_uri(encode|decode) functions to handle + and NUL characters right (a8148ce)
+ o Add evhttp_response_code to remove one more reason to include http_struct.h (22e0a9b)
+ o Tweak interface for allowed methods (f5b391e)
+ o Add evhttp server alias interface, correct flagging of proxy requests. (aab8c38 Christopher Davis)
+
+HTTP BUGFIXES
+ o Add some comments to http.c and make a few functions static. (90b3ed5)
+ o Fix Content-Length when trying send more than 100GB of data (!) on an evhttp. (525da3e)
+ o Fix a bug where we would read too much data in HTTP bodies or requests. (58a1cc6)
+ o Correctly count req->body_size on http usage without Content-Length (8e342e5)
+ o Avoid missed-request bug when entire http request arrives before data is flushed (74c0e86)
+ o reset "chunked" flag when sending non-chunked reply (aa5f55f Joachim Bauch)
+ o evhttp_encode_uri encodes all reserved characters, including !$'()*+,/:=@ (2e63a60)
+ o Replace exact-version checks for HTTP/1.1 with >= or < checks (647e094)
+ o evhttp: Return 501 when we get an unrecognized method, not 400. (536311a)
+ o Don't disable reading from the HTTP connection after sending the request to be notified of connection-close in time (c76640b Felix Nawothnig)
+ o Never call evhttp_readcb while writing. (0512487)
+ o Try to fix an assertion failure related to close detection (0faaa39)
+ o Correctly detect timeouts during http connects (04861d5)
+ o Preliminary support for Continue expectation in evhttp. (fa9305f Christopher Davis)
+
+OTHER BUGFIXES
+ o Correct logic for realigning a chain in evbuffer_add (e4f34e8)
+ o Fix a minor syntax error that most compilers didn't care about (e56ff65)
+ o Fix some uses of int for socket in regress (5d389dc)
+ o Check return value for ioctlsocket on win32 (f5ad31c Trond Norbye)
+ o Fix som event_warns that should have been event_warnx (19c71e7)
+ o Fix signal handler types for win64. (b81217f)
+ o Try to clear up more size_t vs int/long issues. (598d133)
+ o Make sure IOCP evconnlistener uses virtual events. (7b40a00 Christopher Davis)
+ o Don't free evdns_request handles until after the callback is invoked (9ed30de)
+ o Fix some more cancel-related bugs in getaddrinfo_async (c7cfbcf)
+ o Make evdns_getaddrinfo_cancel threadsafe (d51b2fc)
+ o Only clear underlying callbacks when the user hasn't reset them. (1ac5b23)
+ o Fix bug in bufferevent_connect on an openssl bufferevent that already had an fd (4f228a1)
+ o Resolve an evport bug in the thread/forking test (3a67d0b)
+ o Make sure the CLOEXEC flag is set on fds we open for base notification (3ab578f)
+ o Fix IRIX build. sa_family collides with a #define in sys/socket.h on IRIX. (e874982 Kevin Bowling)
+ o If not WIN32, include <sys/socket.h> in event2/util.h. (1cd45e5 Kevin Bowling)
+ o Fix some C99-style comments to work with the xlC compiler. (c2e5e22 Kevin Bowling)
+ o Add some checks since lack of TAILQ_FOREACH doesn't imply lack of FIRST, END, NEXT, or INSERT_BEFORE. Quiet some warnings in XL C. (c4dc335 Kevin Bowling)
+ o Reworked AIX __ss_family workaround to use AC_STRUCT_MEMBER. (2e2a3d7 Kevin Bowling)
+ o Take select from <sys/select.h> when testing in autoconf. AIX build fix. (a3a9f6b Kevin Bowling)
+ o Fix snprintf related failures on IRIX. (3239073 Kevin Bowling)
+ o Remove _event_initialized(); make event_initialized() a function(); make it consistent on windows and non-windows (652024b)
+ o Do not let EVLOOP_ONCE exit the loop until all deferred callbacks have run (2d5e1bd)
+ o Make EVLOOP_ONCE ignore internal events (0617a81)
+ o Possible crash fix when freeing an underlying bufferevent of an openssl bufferevent (29f7623)
+
+HTTP CLEANUPS
+ o Stop using Libevent-1 headers in regress_http (1f507d7)
+ o Modernize header usage in bench_http.c (e587069)
+ o fix signed/unsigned warnings in http.c (74a91e5)
+ o Update the HTTP regression tests to use Libevent2 apis for non-http stuff (d9ffa89)
+ o Start porting http tests to not use legacy interfaces (8505a74)
+ o Convert the rest of the http tests to be non-legacy unit tests. (9bb8239)
+ o Rename the confusing "base" static variable in regress_http.c (353402a)
+ o Stop accessing http request struct directly from in the unit tests. (0b137f4)
+ o Refactor http version parsing into a single function (a38140b)
+
+TESTING
+ o Improvements to tinytest_macros.h (ad923a1)
+ o Add a huge pile of tests for the new URI functions, and make them pass. (a5a76e6)
+ o Unit tests for evhttp_uri_set* (bc98f5e)
+ o Increase the skew tolerance to 2 seconds in thread/deferred_cb_skew (f806476 Christopher Davis)
+ o Reorder backends in test.sh to match preference order in event.c (ece974f)
+ o Add a stress test for getaddrinfo_cancel (da1bf52)
+ o Units test for unexpected evhttp methods. (75e3320)
+
+DOCUMENTATION
+ o Document behavior of URI parsing more thoroughly. (3a33462)
+ o Document that two bufferevent functions only work on socket bufferevents (70e1b60)
+ o add a requested docstring for event_rpcgen.CommandLine.__init__ (f1250eb)
+ o Fix a mistake in http documentation found by Julien Blache (229714d)
+ o Add a basic example of how to write a static HTTP server. (4e794d5)
+ o Document event_get_assignment (88be27d)
+ o Note that reentrant calls to libevent from logging cbs may fail badly (e431bcd)
+ o Clarify EVLOOP_* documentation to be more precise. (057a514)
+
+CLEANUPS
+ o Simplify the logic for choosing EPOLL_CTL_ADD vs EPOLL_CTL_MOD (2c66983)
+ o Rename "size" variables in win32select that were really fd counts. (b6a158c)
+ o Fix even more win64 warnings (7484df6)
+ o Fix even more win64 warnings: buffer, event_tagging, http, evdns, evrpc (545a611)
+ o Fix more wn64 warnings. (34b84b9 Christopher Davis)
+ o Use the label_len local variable in evdns instead of recalculating it over and over (ba01456)
+ o Fix some irix compilation warnings spotted by Kevin Bowling (7bcace2)
+
+
+
+Changes in 2.0.8-rc (14 Oct 2010):
+ [Autogenerated from the Git log, sorted and cleaned by hand.]
+NEW APIS
+ o Add error callback to evconnlistener (c4be8d8 Simon Perreault)
+ o Add a LEV_OPT_THREADSAFE option for threadsafe evconnlisteners (127d4f2)
+
+CHANGED BEHAVIOR
+ o Correct logic on disabling underlying bufferevents when disabling a filter (ac27eb8)
+
+BUGFIXES
+ o Obey enabled status when unsuspending (040a019 Simon Perreault)
+ o Warn when using the error-prone EV_SIGNAL interface in an error-prone way. Also, fix a couple of race conditions in signal.c (720bd93)
+ O Make default signal backend fully threadsafe (95a7d41)
+ o Put internal events at highest priority (90651b3)
+ o Fix warnings in the main codebase flagged by -Wsigned-compare (9c8db0, 5e4bafb, 5c214a, 6be589a, e06f514)
+ o Fix compile in kqueue.c (b395392 Sebastian Hahn)
+ o Do not search outside of the system directory for windows DLLs (d49b5e3)
+ o Fix a spurious-call bug on epoll.c (0faaee0)
+ o Send a shutdown(SHUT_WR) before closing an http connection (e0fd870 Christopher Davis)
+ o Fix warnings on mingw with gcc 4.5 (5b7a370)
+ o Fix an EINVAL on evbuffer_write_iovec on OpenSolaris. (fdc640b)
+ o Fix allocation error for IOCP listeners. Probably harmless, since struct event is big (481ef92)
+ o Make iocp/listener/error work; don't accept again if lev is disabled. (62b429a Christopher Davis)
+ o Handle rate-limiting for reading on OpenSSL bufferevents correctly. (819b171)
+ o Fix serious bugs in per-bufferevent rate-limiting code (34d64f8)
+ o Avoid spurious reads from just-created open openssl bufferevents (223ee40)
+ o Fix a case where an ssl bufferevent with CLOSE_ON_FREE didn't close its fd (93bb7d8)
+ o The corrected bufferevent filter semantics let us fix our openssl tests (34331e4)
+
+TESTING
+ o Make SSL tests cover enabling/disabling EV_READ. (a5ce9ad)
+ o Bump to the latest version of tinytest (f0bd83e)
+ o Unit tests for listener error callbacks (045eef4)
+ o New unit test for ssl bufferevents starting with connected SSLs. (02f6259)
+
+DEBUGGABILITY
+ o Make debugging output for epoll backend more comprehensive (ec2b05e)
+ o Make event.c debugging messages report fds (e119899)
+ o Make the --enable-gcc-warnings option include signed comparison warnings (d3b096c)
+
+DEADCODE REMOVAL
+ o Remove the now-useless evsig_caught and evsig_process (4858b79)
+ o Remove event_base.evsigbase; nothing used it. (38d0960)
+
+
+
+Changes in 2.0.7-rc (9 Sep 2010):
+ [Autogenerated from the Git log, sorted and cleaned by hand.]
+NEW APIS
+ o Expose a evdns_base_nameserver_sockaddr_add() function to add a nameserver by sockaddr (1952143)
+ o Add event_config_set_num_cpus_hint() for tuning win32 IOCP thread pools, etc. (2447fe8 Christopher Davis)
+
+BUGFIXES
+ o Fix a nasty dangling-event bug when using rate-limiting groups (0bffe43)
+ o Clean up syntax on TAILQ_ENTRY() usage to build correctly with recent MSVC (60433a0 Gilad Benjamini)
+ o Make definition of WIN32_LEAN_AND_MEAN in event.h conditional (3920172 Gilad Benjamini)
+ o Correctly detect failure to delete bufferevent read-timeout event (da6e7cd)
+ o Set close-on-exec bit for filedescriptors created by dns subsystem (d0b8843)
+ o Fix kqueue correctness test on x84_64 (6123d12)
+ o Detect events with no ev_base; warn instead of crashing (f1074b7)
+ o Fix an issue with forking and signal socketpairs in select/poll backends (d61b2f3)
+ o Stop using global arrays to implement the EVUTIL_ctype functions (1fdec20)
+ o On windows, make lock/thread function tables static (5de2bcb)
+ o Close th_notify_fds and open a new pair on reinit (495ed66)
+ o Declare signal handler function as "__cdecl" on Windows (f0056d0)
+ o Use the _func() replacements for open, fstat, etc in evutil.c on win32 (e50c0fc)
+ o Only process up to MAX_DEFERRED deferred_cbs at a time (17a14f1 Christopher Davis)
+
+THREADING BUGFIXES
+ o Avoid deadlock when activating signals (970e6ad)
+ o Add a condition variable backend, with implementations for pthreads and win32 (d4977b5)
+ o Use conditions instead of current_event_lock to fix a deadlock (e0972c2)
+ o Fix logic error in win32 TRY_LOCK that caused problems with rate-limiting (4c32b9d)
+ o Avoid needlessly calling evthread_notify_base() when the loop is not running (c7a06bf)
+ o Minimize calls to base_notify implementation functions, thereby avoiding needless syscalls (4632b78)
+
+IOCP BUGFIXES
+ o IOCP-related evbuffer fixes (03afa20 Christopher Davis)
+ o Stop IOCP when freeing the event_base (d844242 Christopher Davis)
+ o Some IOCP bufferevent tweaks (76f7e7a Christopher Davis)
+
+TESTS
+ o Make the regress_pthread.c tests work on windows with current test APIs (d74ae38)
+ o Add a unit test for conditions (5fb1095)
+ o Allow more than one copy of regression tests to run at once (a97320a)
+ o Fix event_del(0) instance in bench.c (b0f284c Shuo Chen)
+ o Fix a few memory leaks in the tests (1115366)
+ o IOCP-related unit test tweaks (499452f Christopher Davis)
+ o Improve testing of when thread-notification occurs (ce85280)
+
+BUILD AND DISTRIBUTION
+ o Add pkgconfig files for libevent_{openssl,pthreads} (ebcb1f0)
+ o Change include order in Makefile.nmake (4022b28)
+ o Make include/event2/event-config.h not included in source dist (a4af9be)
+ o Honor NDEBUG; build without warnings with NDEBUG; make NDEBUG always-off in unit test code (743f866)
+ o Declare evkeyvalq and event_list even if event_struct.h comes before sys/queue.h (d3ceca8)
+ o Move evkeyvalq into a separate header for evhttp_parse_query users (ca9048f)
+ o Prefer autoreconf -ivf to manual autogen.sh (7ea8e89)
+
+CLEANUP
+ o Completely remove the (mostly-removed) obsolete thread functions (3808168)
+ o Rename regress_pthread.c to regress_thread.c (041989f)
+ o Make defer-internal.h use lock macros, not direct calls to lock fns (5218d2a)
+
+DOCUMENTATION
+ o Document that DNS_NO_SEARCH is an obsolete alias for DNS_QUERY_NO_SEARCH (33200e7)
+ o Update the whatsnew-2.0.txt document (4991669)
+
+
+
+Changes in 2.0.6-rc (6 Aug 2010):
+ [Autogenerated from the Git log, sorted by hand.]
+DOCUMENTATION
+ o Document a change in the semantics of event_get_struct_event_size() (e21f5d1)
+ o Add a comment to describe our plan for library versioning (9659ece)
+ o Fix sentence fragment in docs for event_get_struct_event_size() (7b259b6)
+
+NEW FEATURES AND INTERFACE CHANGES
+ o Remove the obsolete evthread interfaces (c5bab56)
+ o Let evhttp_send_error infer the right error reasons (3990669)
+ o Add a function to retrieve the other side of a bufferevent pair (17a8e2d)
+ o Add bufferevent_lock()/bufferevent_unlock() (215e629)
+ o Stop asserting when asked for a (unsupported) TCP dns port. Just return NULL. (7e87a59)
+ o Replace (unused,always 0) is_tcp argument to evdns_add_server_port*() with flags (e1c1167)
+ o Constify a couple of arguments to evdns_server_request_add_*_reply (cc2379d)
+ o Add an interface to expose min_share in ratelimiting groups (6ae53d6)
+
+BUGFIXES
+ o Avoid event_del on uninitialized event in event_base_free (6d19510)
+ o Add some missing includes to fix Linux build again (75701e8)
+ o Avoid close of uninitialized socket in evbuffer unit test (bda21e7)
+ o Correctly recognize .255 addresses as link-local when looking for interfaces (8c3452b)
+ o If no evdns request can be launched, return NULL, not a handle (b14f151)
+ o Use generic win32 interfaces, not ASCII-only ones, where possible. (899b0a3)
+ o Fix the default HTTP error template (06bd056 Felix Nawothnig)
+ o Close the file in evutil_read_file whether there's an error or not. (0798dd1 Pierre Phaneuf)
+ o Fix possible nullptr dereference in evhttp_send_reply_end() (29b2e23 Felix Nawothnig)
+ o never let bufferevent_rlim functions return negative (0859870)
+ o Make sample/hello_world work on windows (d89fdba)
+ o Fix a deadlock related to event-base notification. Diagnosed by Zhou Li, Avi Bab, and Scott Lamb. (17522d2)
+ o Possible fix to 100% cpu usage with epoll and openssl (cf249e7 Mike Smellie)
+ o Don't race when calling event_active/event_add on a running signal event (fc5e0a2)
+ o Suppress a spurious EPERM warning in epoll.c (e73cbde)
+ o Fix wrong size calculation of iovec buffers when exact=1 (65abdc2 niks)
+ o Change bufferevent_openssl::do_write so it doesn't call SSL_write with a 0 length buffer (c991317 Mike Smellie)
+ o Fixed compilation of sample/le-proxy.c on win32 (13b912e Trond Norbye)
+ o Fix rate-limit calculation on openssl bufferevents. (009f300)
+ o Remember to initialize timeout events for bufferevent_async (de1f5d6 Christopher Davis)
+
+BUILD AND DISTRIBUTION CHANGES
+ o Test the unlocked-deferred callback case of bufferevents (dfb75ab)
+ o Remove the now-unusable EVTHREAD_LOCK/UNLOCK constants (fdfc3fc)
+ o Use -Wlogical-op on gcc 4.5 or higher (d14bb92)
+ o Add the libtool-generated /m4/* stuff to .gitignore (c21c663)
+ o Remove some automake-generated files from version control. (9b14911)
+ o Have autogen.sh pass --force-missing to automake (8a44062)
+ o Set library version for libevent_pthreads correctly (b2d7440)
+ o Really only add libevent_core.la to LIBADD on mingw (1425003 Sebastian Hahn)
+ o Build more cleanly with NetBSDs that dislike toupper(char) (42a8c71)
+ o Fix unit tests with -DUSE_DEBUG enabled (28f31a4)
+ o Fix evdns build with -DUNICODE (5fa30d2)
+ o Move event-config.h to include/event2 (ec347b9)
+
+TESTING
+ o Add options to test-ratelim.c to check its results (2b44dcc)
+ o Make test-ratelim clean up after itself better. (b5bfc44)
+ o Remove the now-obsolete setup_test() and cleanup_test() functions (e73f1d7)
+ o Remove all non-error prints from test/regress.c (8bc1e3d)
+ o Make test.sh exit with nonzero status if tests fail (faf2a04)
+ o Have the unit tests report errors from test.sh (3689bd2)
+ o Fix logic in correcting high values from FIONREAD (3467f2f)
+ o Add test for behavior on remote socket close (44d57ee)
+ o Unit test for event_get_struct_event_size() (7510aac)
+ o Make test/test.sh call test-changelist (7c92691)
+ o Fix badly-behaved subtest of dns/bufferevent_connect_hostname (840a72f Joachim Bauch)
+ o Add option to test-ratelim to test min_share (42f6b62)
+ o Fix an assertion bug in test-ratelim (b2c6202)
+ o Make tests quieter on local dns resolver failure (e996b3d)
+ o Increase the tolerance in our unit tests for sloppy clocks. (170ffd2)
+ o Use AF_INET socketpair to test sendfile on Solaris (9b60209)
+ o Make test-changelist count cpu usage right on win32 (ea1ea3d)
+
+INTERNALS, PERFORMANCE, AND CODE CLEANUPS
+ o Mark the event_err() functions as __attribute__((noreturn)) (33bbbed)
+ o Do not check that event_base is set in EVBASE_ACQUIRE_LOCK (218a3c3)
+ o Replace (safe) use of strcpy with memcpy to appease OpenBSD (caca2f4)
+ o Remove some dead assignments (47c5dfb)
+ o Fix a pedantic gcc 4.4 warning in event2/event.h (276e7ee)
+ o Drain th_notify_fd[0] more bytes at a time. (a5bc15b)
+ o Tidy up the code in evthread_make_base_notifiable a little (61e1eee)
+ o Pass flags to fcntl(F_SETFL) and fcntl(F_SETFD) as int, not long (7c2dea1)
+ o Remove unused variables in test/test-changelist.c (b00d4c0)
+ o Fix whitespace. (cb927a5)
+ o Improve error message for failed epoll to make debugging easier. (9e725f7)
+ o Turn our socketpair() replacement into its own function (57b30cd)
+
+
+
+Changes in 2.0.5-beta (10 May 2010):
+ [Autogenerated from the Git log, sorted by hand.]
+DOCUMENTATION
+ o Update all our copyright notices to say "2010" (17efc1c)
+ o Add Christopher Clark and Maxim Yegorushkin to the LICENSE file (38b7b57)
+ o Clarify Christopher Clark's status as writer of original ht code. (78772c3)
+ o Try to comment some of the event code more (cdd4c49)
+ o Add a few more evmap/changelist comments (c247adc)
+ o Add a comment to explain why evdns_request is now separte from request (ceefbe8)
+ o Document evutil_secure_rng_init() and evutil_secure_rng_add_bytes() (a5bf43a)
+ o Stop distributing and installing manpages: they were too inaccurate (7731ec8)
+
+NEW FEATURES AND INTERFACE CHANGES
+ o Remove signal_assign() and signal_new() macros. (2fac0f7)
+ o Make evdns use the regular logging system by default (b2f2be6)
+ o Allow evbuffer_read() to split across more than 2 iovecs (e470ad3)
+ o Functions to manipulate existing rate limiting groups. (ee41aca)
+ o Functions to track the total bytes sent over a rate limit group. (fb366c1)
+ o Detect and refuse reentrant event_base_loop() calls (b557b17)
+ o Limit the maximum number of events on each socket to 65535 (819f949)
+ o Add evbuffer_copyout to copy data from an evbuffer without draining (eb86c8c)
+ o Expose the request and reply members of rpc_req_generic() (07edf78 Shuo Chen)
+ o Add void* arguments to request_new and reply_new evrpc hooks (755fbf1 Shuo Chen)
+ o Seed the RNG using sysctl() as well as /dev/urandom (71fc3eb)
+ o Make evutil_secure_rng_init() work even with builtin arc4random (f980716)
+ o Report DNS error when lookup fails during bufferevent_socket_connect_hostname. (0ef4070 Christopher Davis)
+ o Release locks on bufferevents while executing callbacks (a5208fe Joachim Bauch) o Make debug mode catch mixed ET and non-ET events on an fd (cb67074)
+ o Catch attempts to enable debug_mode too late (9ecf0d4)
+ o Refuse null keys in evhttp_parse_query() (953e229 Frank Denis)
+
+BUGFIXES
+ o Avoid a spurious close(-1) on Linux (70a44b6)
+ o Do not close(-1) when freeing an uninitialized socket bufferevent (b34abf3)
+ o Free evdns_base->req_heads on evdns_base_free (859af67)
+ o Avoid an (untriggerable so far) crash bug in bufferevent_free() (0cf1431)
+ o Set mem_offset for every bufferevent type (657d1b6)
+ o Fix infrequent memory leak in bufferevent_init_common(). (8398641 Jardel Weyrich)
+ o Make evutil_signal_active() match declaration. (e1e703d Patrick Galbraith)
+ o Fix minheap code to use replacement malloc functions (a527618)
+ o Fix a free(NULL) in minheap-internal.h (6f20492)
+ o Fix critical bug in evbuffer_write when writev is not available (cda56ab)
+ o Make the no_iovecs case of write_atmost compile (8e227b0)
+ o Fix a memory leak when appending/prepending to a buffer with unused space. (45068a3)
+ o Clean up a mistake in pointer manipulation in evbuffer_remove (28bfed4 Christopher Davis)
+ o Always round up when there's a fractional number of msecs. (8f9e60c Christopher Davis)
+ o Fix compiler warnings under WIN32 (d469c50 Giuseppe Scrivano)
+ o Clean up properly when adding a signal handler fails. (b84b598 Gilad Benjamini) o Ensure that evdns_request is a persistent handle. (15bb82d Christopher Davis)
+ o Free search state when finished searching to avoid an infinite loop. (a625840 Christopher Davis)
+ o Assert for valid requests as necessary. (67072f3 Christopher Davis)
+ o do not leak the request object on persistent connections (9d8edf2)
+ o Make evdns logging threadsafe (b1c7950)
+ o Fix a couple of bugs in the BSD sysctl arc4seed logic (a47a4b7)
+ o Remove one last bug in last_with_datap logic. Found with valgrind (d49b92a)
+ o fix a leak when unpausing evrpc requests (94ee125)
+ o Fix a memory leak when unmarshalling RPC object arrays (f6ab2a2)
+ o Fix compilation when openssl support is disabled (40c301b)
+ o Allow empty reason line in HTTP status (739e688 Pierre Phaneuf)
+ o Fix a compile warning introduced in 739e688 (bd1ed5f Sebastian Hahn)
+ o Fix nonstandard TAILQ_FOREACH_REVERSE() definition (71afc52 Frank Denis)
+ o Try /proc on Linux as entropy fallback; use sysctl as last resort (20fda29)
+ o Fix symbol conflict between mm_*() macros and libmm (99e50e9)
+ o Fix some crazy macro mistakes in arc4random.c (90d4225)
+ o Make evbuffer_add_file() work on windows (dcdae6b)
+ o Fix unused-variable warning when building with threads disabled (ad811cd)
+ o Numerous opensolaris compilation fixes (c44de06)
+ o Fix getaddrinfo with protocol unset on Solaris 9. Found by Dagobert Michelsen (2cf2a28)
+ o Fix another nasty solaris getaddrinfo() behavior (3557071)
+ o Define _REENTRANT as needed on Solaris, elsewhere (c1cd32a)
+ o Fix some autoconf issues on OpenBSD (7c519df)
+
+BUILD AND DISTRIBUTION CHANGES
+ o Distribute libevent.pc.in, not libevent.pc (22aff04)
+ o Avoid errors in evutil.c when building with _UNICODE defined (b677032 Brodie Thiesfield)
+ o Avoid errors in http.c when building with VC 2003 .NET (13e4f3b Brodie Thiesfield)
+ o Support the standard 'make check' target in place of 'make verify' (426c8fb)
+ o Remove redundant stuff from EXTRA_DIST (b660edf)
+ o Switch to using AM conditionals in place of AC_LIBOBJ (2e898f5)
+ o Remove an orphaned RELEASE flag in Makefile.am (0794b0d)
+ o Give a better warning for bad automake versions. (77c917d)
+ o Use dist_bin_SCRIPTS, not EXTRA_DIST, to distribute scripts (9eb2fd7)
+ o Never test for select() on windows (3eb044d Trond Norbye)
+ o Do not inhibit automake dependencies generation (10c4c90 Giuseppe Scrivano)
+ o Create shared libraries under Windows (3cbca86 Giuseppe Scrivano)
+ o Add ctags/etags files to .gitignore (0861d17)
+ o Only specify -no-undefined on mingw (25433b9)
+ o Only add libevent_core.la to LIBADD on mingw (fdc6297)
+
+TESTING
+ o Get bench_http to work on Windows; add a switch to enable IOCP. (4ac38a5 Christopher Davis)
+ o VC has no getopt(), so do without in bench_http. (1273d2f Christopher Davis)
+ o Fix an obnoxious typo in the bufferevent_timeout_filter test (0d047c3)
+ o Fix a write of uninitialized RAM in regression tests (68dc742)
+ o Fix some memory leaks in the unit tests (274a7bd)
+ o Make 'main/many_events' test 70 fds, not 64. (33874b0)
+ o Unit-test every evbuffer_add_file() implementation. (06a4443)
+ o Add more unit tests for evbuffer_expand (8c83e99)
+ o Test another case of evbuffer_prepend (1234b95)
+ o Fix a possible double-free bug in SSL bufferevents with CLOSE_ON_FREE (7501895) o Add dns/search_cancel unit test. (39b870b Christopher Davis)
+ o Make http_base_test stop leaking an event_base. (96730d3)
+ o Detect broken unsetenv at unit-test runtime (f37cd4c)
+ o Implement regress_make_tempfile on win32 to test evbuffer_add_file (b4f12a1)
+ o add more (currently skipped) add_file tests on win32 (05de45d)
+ o Fix bench_http build on win32. (384d124)
+ o Make unit test for add_file able to tell "error" from "done" (88a543f)
+ o Make test for bufferevent_connect_hostname system-neutral (f89168e)
+ o Make test.sh support mingw/msys on win32 (0ee6f6c)
+ o Fix test.sh on freebsd (3d9e05b)
+
+INTERNALS, PERFORMANCE, AND AND CODE CLEANUPS
+ o Improve the speed of evbuffer_readln() (cc1600a)
+ o more whitespace normalization (2c2618d)
+ o Revise evbuffer to add last_with_data (2a6d2a1)
+ o Use last_with_data in place of previous_to_last (c8ac57f)
+ o Remove previous_to_last from evbuffer (6f47bd1)
+ o Fix last_with_data compilation on windows (1e7b986)
+ o Add some glass-box tests for the last_with_data code. (17da042)
+ o Improve robustness for refcounting (f1bc125)
+ o Remove a needless min_heap_shift_up_() call (7204b91)
+ o Increase MIN_BUFFER_SIZE to 512 (1024 on 64-bit) (2014ae4)
+ o Do not use evbuffer_expand() to add the first chain to a buffer (5c0ebb3)
+ o Make evbuffer_prepend handle empty buffers better (c87272b)
+ o Replace last_with_data with a slightly smarter version (b7442f8)
+ o Turn the increasingly complex *_CHAIN() macros into functions (96865c4)
+ o Rewrite evbuffer_expand and its users (d5ebcf3)
+ o Add evutil_tv_to_msec for safe conversion of timevals to milliseconds. (850c3ff Christopher Davis)
+ o Initialize last_with_datap correctly in evbuffer_overlapped (a0983b6)
+ o Replace EVUTIL_CLOSESOCKET macro with a function (899c1dc Sebastian Sjöberg)
+ o Move domain search state to evdns_request. (beaa14a Christopher Davis)
+ o Remove redundant checks for lock!=NULL before calling EVLOCK_LOCK (50ec59f)
+ o Rename current_base symbol to event_global_current_base_ (c16e684)
+ o Fix whitespace in evutil.c (935e150)
+ o Replace users of "int fd" with "evutil_socket_t fd" in portable code (c7cf6f0)
+
+
+
+Changes in 2.0.4-alpha (28 Feb 2010):
+ [Autogenerated from the Git log, sorted by hand.]
+DOCUMENTATION
+ o Add stub header for 2.0.4-alpha changelog. (94d0065)
+ o Improve the README with more information and links. (0b42726)
+ o Add more people who wrote patches to the acknowledgments (0af10d5)
+ o Add a warning about the use of event_initialized. (f32b575)
+ o Add a LICENSE file so people can find our license easily (7067006)
+ o Add a new "hello world" sample program (becb9f9)
+ o Clarify status of example programs (d60a1bd)
+ o Update time-test.c to use event2 (f4190bf)
+ o Add the arc4random.c license to the LICENSE file. (e15e1e9)
+
+NEW FEATURES AND INTERFACE CHANGES
+ o Improved optional lock debugging. (0cd3bb9)
+ o Rate-limiting for bufferevents; group and individual limits are supported. (737c9cd)
+ o Testing code for bufferevent rate-limiting. (f0c0124)
+ o Make the initial nameserver probe timeout configurable. (1e56a32)
+ o Revise the locking API: deprecate the old locking callbacks and add trylock. (347952f)
+ o Do not make bufferevent_setfd implicitly disable EV_READ and EV_WRITE. (8274379)
+ o Do not ignore bufferevent_enable(EV_READ) before bufferevent_connect(). (4a5b534)
+ o Introduced evutil_make_socket_closeonexec() to preserve fd flags for F_SETFD. (d0939d2 Jardel Weyrich)
+ o evdns_getaddrinfo() now supports the /etc/hosts file. (72dd666)
+ o Look at the proper /etc/hosts file on windows. (66c02c7)
+ o Allow http connections to use evdns for hostname looksups. (c698b77)
+ o Changelist code to defer event changes until just before dispatch (27308aa)
+ o do not use a function to assign the evdns base; instead assign it via evhttp_connection_base_new() which is a new function introduced in 2.0 (5032e52)
+ o Functions to access more fields of struct event. (0683950)
+ o Make kqueue use changelists. (45e5ae3)
+ o Remove kqueue->pend_changes. (3225dfb)
+ o Minimize epoll_ctl calls by using changelist (c8c6a89)
+ o Add support for a "debug mode" to try to catch common errors. (cd17c3a)
+ o Note a missing ratelim function (361da8f)
+ o Add ev_[u]intptr_t to include/event2/util.h (1fa4c81)
+ o const-ify a few more functions in event.h (d38a7a1)
+ o Deprecate EVENT_FD and EVENT_SIGNAL. (f6b2694)
+ o Remove EVUTIL_CHECK_FMT. (6c21c89)
+ o Add EV_*_MAX macros to event2/util.h to expose limits for ev_* types. (aba1fff) o Functions to view and manipulate rate-limiting buckets. (85047a6)
+ o Add the rest of the integer limits, and add a test for them. (60742d5)
+ o Remove the 'flags' argument from evdns_base_set_option() (1dd7e6d)
+ o Add an arc4random implementation for use by evdns (d4de062)
+ o Use off_t for the length parameter of evbuffer_add_file (3fe60fd)
+ o Construct Windows locks using InitializeCriticalSectionAndSpinCount (32c6f1b)
+ o Expose view of current rate limit as constrained by group limit (162ce8a)
+ o Provide consistent, tested semantics for bufferevent timeouts (d328829)
+
+BUGFIXES AND TESTS
+ o Tolerate code that returns from a fatal_cb. (91fe23f)
+ o Parenthesize macro arguments more aggressively (07e9e9b)
+ o Fix memory-leak of signal handler array with kqueue. (e1ffbb8)
+ o Stop passing EVTHREAD_READ and EVTHREAD_WRITE to non-rw locks. (76cd2b7)
+ o Fix two use-after-free bugs in unit tests spoted by lock debugging (d84d838)
+ o Fix a locking bug in event_base_loop() (da1718b)
+ o Fix an evdns lock violation. (2df1f82 Zhuang Yuyao)
+ o Valgrind fix: Clear struct kevent before checking for OSX bug. (56771a3 William Ahern)
+ o Fix up evthread compilation on windows (bd6f1ba Roman Puls)
+ o Fix regress_iocp.c usage of old lock allocation macros. (31687b4 unknown)
+ o Update nmake makefile to build evthread.c (b62d979 unknown)
+ o Fix a crash when reading badly formatted resolve.conf; from Yasuoka Masahiko (6c7c579 Yasuoka Masahiko)
+ o Fix a snow leopard compile warning in the unit tests. (7ae9445)
+ o Fix compile on Snow Leopard with gcc warnings enabled (70cdfe4 Sebastian Hahn)
+ o Only define _GNU_SOURCE if it is not already defined. (ea6b1df Joachim Bauch)
+ o Update sample/signal-test.c to use newer APIs and not leak. (f6430ac Evan Jones)
+ o Fix a segfault when writing a very fragmented evbuffer onto an SSL (a6adeca Joachim Bauch)
+ o Fix a segfault when freeing SSL bufferevents in an unusual order (a773df5 Joachim Bauch)
+ o Drop install-sh from our git repo: a mismatched version could break "make dist" (6799527)
+ o Set all instances of the version number correctly. (5a112d3)
+ o Fix a few locking issues on windows. (c51bb3c unknown)
+ o Use evutil_socket_t, not int, when logging socket errors. (292467c)
+ o Fix up behavior of never-defered callbacks a little (390e056)
+ o Replace some cases of uint32_t with ev_uint32_t. (a47d88d)
+ o Fix compilation of devpoll.c by adding missing thread includes. (fee2c77 Dagobert Michelsen)
+ o Make evutil_make_socket_nonblocking() leave any other flags alone. (4c8b7cd Jardel Weyrich)
+ o Fix an fd leak in evconnlistener_new_bind(). (24fb502 Jardel Weyrich)
+ o Fix a bogus free in evutil_new_addrinfo() (0d64051 Jardel Weyrich)
+ o Adjusted fcntl() retval comparison on evutil_make_socket_nonblocking(). (4df7dbc Jardel Weyrich)
+ o Fix the code that allowed DNS options to not end with : (ee4953f)
+ o Fix crash bugs when a bufferevent's eventcb is not set. (2e8eeea)
+ o Fix test-ratelim compilation on Linux. (885b427)
+ o Fix compilation of rate-limiting code on win32. (165d30e)
+ o Eradicated the last free() call. Let mm_free() take care of deallocation. (0546ce1 Jardel Weyrich)
+ o Fix byte counts when mixing deferred and non-deferred evbuffer callbacks. (29151e6)
+ o Fixed a memory leak on windows threads implementation. The CRITICAL_SECTION was not being free'd in evthread_win32_lock_free(). (2f33e00 Jardel Weyrich)
+ o Fixed a fd leak in start_accepting(), plus cosmetic changes (4367a33 Jardel Weyrich)
+ o Improved error handling in evconnlistener_new_async(). Also keeping the fd open because it is not opened by this function, so the caller is responsible for closing it. Additionally, since evconnlistener_new_bind() creates a socket and passes it to the function above, it required error checking to close the same socket. (fec66f9 Jardel Weyrich)
+ o Don't use a bind address for nameservers on loopback (8d4aaf9)
+ o Fix compilation of rate-limit code when threading support is disabled (97a8c79)
+ o Detect setenv/unsetenv; skip main/base_environ test if we can't fake them. (7296971)
+ o Check more internal event_add() calls for failure (ff3f6cd)
+ o Fix windows and msvc build (5c7a7bc)
+ o Call event_debug_unassign on internal events (a19b4a0)
+ o Try to fix a warning in hash_debug_entry (137f2c6)
+ o Fix a dumb typo in ev_intptr_t definitions. (27c9a40)
+ o do not fail while sending on http connections the client closed. (93d7369)
+ o make evhttp_send() safe against terminated connections, too (3978180)
+ o Make Libevent 1.4.12 build on win32 with Unicode enabled. (000a33e Brodie Thiesfield)
+ o Fix some additional -DUNICODE issues on win32. (a7a9431)
+ o Add a check to make soure our EVUTIL_AI flags do not conflict with the native ones (c18490e)
+ o Always use our own gai_strerror() replacement. (6810bdb)
+ o Make RNG work when we have arc4random() but not arc4random_buf() (4ec8fea)
+ o validate close cb on server when client connection closes (2f782af)
+ o Fix two unlocked reads in evbuffer. (7116bf2)
+ o When working without a current event base, don't try to use IOCP listeners (cb52838)
+ o Fix getpid() usage on Windows (ff2a134)
+ o Add a unit test for secure rng. (48a29b6)
+ o Add some headers to fix freebsd compilation (b72be50)
+ o When connect() succeeds immediately, don't invoke the callback immediately. (7515de9)
+ o Suspend read/write on bufferevents during hostname lookup (db08f64)
+ o Make bufferevent_free() clear all callbacks immediately. (b2fbeb3)
+ o Fix some race conditions in persistent events and event_reinit (e2642f0)
+ o Fix a bug in resetting timeouts on persistent events when IO triggers. (38ec0a7)
+ o Add a test for timeouts on filtering bufferevents. (c02bfe1)
+ o Add test for periodic timers that get activated for other reasons (8fcb7a1)
+ o Use new timeval diff comparison function in bufferevent test (f3dfe46)
+ o Delete stack-alloced event in new unit test before returning. (7ffd387)
+ o Fix mingw compilation (23170a6)
+ o Try to define a sane _EVENT_SIZEOF_SIZE_T for msvc compilation (1e14f82)
+ o Fix arc4random compilation on MSVC. (98edb89)
+ o deal with connect() failing immediately (7bc48bf)
+ o Small cleanups on freebsd-connect-refused patch. (57b7248)
+
+BUILD AND DISTRIBUTION CHANGES
+ o Remove the contents of WIN32-Prj as unmaintained. (c69d5a5)
+ o Allow the user to redirect the verbose output of test/test.sh to a file (c382de6)
+ o Allow test.sh to be run as ./test/test.sh (7dfbe94)
+ o Never believe that we have pthreads on win32, even if gcc thinks we do. (78ed097)
+ o Make it compile under gcc --std=c89. (e2ca403)
+ o Fix a number of warnings from gcc -pedantic (918e9c5)
+ o Add the msvc-generated .lib files to .gitignore. (e244a2e)
+ o Add the "compile" script to gitignore. (1ba6bed)
+
+INTERNALS AND CODE CLEANUPS
+ o Add a .gitignore file. (ba34071)
+ o New EVTHREAD_TRY_LOCK function to try to grab a lock. (689fc09)
+ o Add the abilitity to mark some buffer callbacks as never-deferred. (438f9ed)
+ o Refactor our 'suspend operation' logic on bufferevents. (0d744aa)
+ o Simplify the read high-watermark checking. (5846bf6)
+ o Improve readability of evutil_unparse_protoname() (5a43df8 Jardel Weyrich)
+ o Expose our cached gettimeofday value with a new interface (47854a8)
+ o Whitespace fixes in test.sh (0b151a9)
+ o Enable branch-prediction hints with EVUTIL_UNLIKELY. (eaaf27f)
+ o Refactor code from evdns into a new internal "read a file" function. (0f7144f)
+ o Comestic changes in evconnlistener_new(), new_accepting_socket(), accepted_socket_invoke_user_cb() and iocp_listener_enable(). (510ab6b Jardel Weyrich)
+ o Add unit-test for bad_request bug fixed in 1.4 recently. (6cc79c6 Pavel Plesov) o Add a comment on evthread_enable_lock_debuging. (b9f43b2)
+ o Fix test.sh on shells without echo -n (94131e9)
+ o More unit tests for getaddrinfo_async: v4timeout and cancel. (a334b31)
+ o Make http use evconnlistener. (ec34533)
+ o move dns utility functions into a separate file so that we can use them for http testing (b822639)
+ o add a test for evhttp_connection_base_new with a dns_base (26714ca)
+ o forgot to add void to test function (78a50fe)
+ o Add a forgotten header (changelist-internal.h) (4b9f307)
+ o Remove some commented-out code in evutil (26e1b6f)
+ o Remove a needless include of rpc_compat.h (70a4a3e)
+ o Use less memory for each entry in a hashtable (a66e947)
+ o Try to untangle the logic in server_port_flush(). (439aea0)
+ o Use ev_[u]intptr_t types in place of [u]intptr_t (cef61a2)
+ o Reduce windows header includes in our own headers. (da6135e)
+ o clean up terminate_chunked test (e8a9782)
+ o Increment the submicro version number. (63e868e)
+ o Update event-config.h version number to match configure.in (aae7db5)
+ o Clean up formatting: Disallow space-before-tab. (8fdf09c)
+ o Clean up formatting: use tabs, not 8-spaces, to indent. (e5bbd40)
+ o Clean up formatting: remove trailing spaces (e5cf987)
+ o Clean up formatting: function/keyword spacing consistency. (4faeaea)
+
+
+
+Changes in 2.0.3-alpha (20 Nov 2009):
+ o Add a new code to support SSL/TLS on bufferevents, using the OpenSSL library (where available).
+ o Fix a bug where we didn't allocate enough memory in event_get_supported_methods().
+ o Avoid segfault during failed allocation of locked evdns_base. (Found by Rocco Carbone.)
+ o Export new evutil_ascii_* functions to perform locale-independent character type operations.
+ o Try to compile better with MSVC: patches from Brodie Thiesfield
+ o New evconnlistener_get_fd function to expose a listener's associated socket.
+ o Expose an ev_socklen_t type for consistent use across platforms.
+ o Make bufferevent_socket_connect() work when the original fd was -1.
+ o Fix a bug in bufferevent_socket_connect() when the connection succeeds too quickly.
+ o Export an evutil_sockaddr_cmp() to compare to sockaddr objects for equality.
+ o Add a bufferevent_get_enabled() to tell what a bufferevent has been configured to do.
+ o Add an evbuffer_search_eol() function to locate the end of a line nondestructively.
+ o Add an evbuffer_search_range() function to search a bounded range of a buffer.
+ o Fix a rare crash bug in evdns.
+ o Have bufferevent_socket_connect() with no arguments put a bufferevent into connecting mode.
+ o Support sendfile on Solaris: patch from Caitlin Mercer.
+ o New functions to explicitly reference a socket used by an evhttp object. Patches from David Reiss.
+ o When we send a BEV_EVENT_CONNECTED to indicate connected status, we no longer invoke the write callback as well unless we actually wrote data too.
+ o If the kernel tells us that there are a negative number of bytes to read from a socket, do not believe it. Fixes bug 2841177; found by Alexander Pronchenkov.
+ o Do not detect whether we have monotonic clock support every time a new event base is created: instead do it only once. Patch taken from Chromium.
+ o Do not allocate the maximum event queue for the epoll backend at startup. Instead, start out accepting 32 events at a time, and double the queue's size when it seems that the OS is generating events faster than we're requesting them. Saves up to 374K per epoll-based event_base. Resolves bug 2839240.
+ o Treat an event with a negative fd as valid but untriggerable by Libevent. This is useful for applications that want to manually activate events.
+ o Fix compilation on Android, which forgot to define fd_mask in its sys/select.h
+ o Do not drop data from evbuffer when out of memory; reported by Jacek Masiulaniec
+ o New event_base_got_exit() and event_base_got_break() functions to tell whether an event loop exited because of an event_base_loopexit() or an event_base_loopbreak(). Patch from Ka-Hing Cheung.
+ o When adding or deleting an event from a non-main thread, only wake up the main thread when its behavior actually needs to change.
+ o Fix some bugs when using the old evdns interfaces to initialize the evdns module.
+ o Detect errors during bufferevent_connect(). Patch from Christopher Davis.
+ o Fix compilation for listener.h for C++ - missing extern "C". Patch from Ferenc Szalai.
+ o Make the event_base_loop() family of functions respect thread-safety better. This should clear up a few hard-to-debug race conditions.
+ o Fix a bug when using a specialized memory allocator on win32.
+ o Have the win32 select() backend label TCP-socket-connected events as EV_WRITE, not EV_READ. This should bring it in line with the other backends, and improve portability. Patch from Christopher Davis.
+ o Stop using enums as arguments or return values when what we mean is a bitfield of enum values. C++ doesn't believe that you can OR two enum values together and get another enum, and C++ takes its typing seriously. Patch from Christopher Davis.
+ o Add an API to replace all fatal calls to exit() with a user-provided panic function.
+ o Replace all assert() calls with a variant that is aware of the user-provided logging and panic functions.
+ o Add a return value to event_assign so that it can fail rather than asserting when the user gives it bad input. event_set still dies on bad input.
+ o The event_base_new() and event_base_new_with_config() functions now never call exit() on failure. For backward "compatibility", event_init() still does, but more consistently.
+ o Remove compat/sys/_time.h. It interfered with system headers on HPUX, and its functionality has been subsumed by event2/util.h and util-internal.h.
+ o Add a new bufferevent_socket_connect_hostname() to encapsulate the resolve-then-connect operation.
+ o Build kqueue.c correctly on GNU/kFreeBSD platforms. Patch pulled upstream from Debian.
+ o Alternative queue-based timeout algorithm for programs that use a large number of timeouts with the same value.
+ o New event_base_config option to disable the timeval cache entirely.
+ o Make EV_PERSIST timeouts more accurate: schedule the next event based on the scheduled time of the previous event, not based on the current time.
+ o Allow http.c to handle cases where getaddrinfo returns an IPv6 address. Patch from Ryan Phillips.
+ o Fix a problem with excessive memory allocation when using multiple event priorities.
+ o Default to using arc4random for DNS transaction IDs on systems that have it; from OpenBSD.
+ o Never check the environment when we're running setuid or setgid; from OpenBSD.
+ o Options passed to evdns_set_option() no longer need to end with a colon.
+ o Add an evutil_getaddrinfo() function to clone getaddrinfo on platforms that don't have it.
+ o Add an evdns_getaddrinfo() function to provide a nonblocking getaddrinfo using evdns, so programs can perform useful hostname lookup.
+ o Finally expose the IOCP-based bufferevent backend. It passes its unit tests, but probably still has some bugs remaining. Code by Nick Mathewson and Christopher Davis.
+ o Numerous other bugfixes.
+ o On FreeBSD and other OSes, connect can return ECONREFUSED immediately; instead of failing the function call, pretend with faileld in the callback.
+ o Fix a race condition in the pthreads test case; found by Nick Mathewson
+ o Remove most calls to event_err() in http and deal with memory errors instead
+
+
+
+Changes in 2.0.2-alpha (25 Jul 2009):
+ o Add a new flag to bufferevents to make all callbacks automatically deferred.
+ o Make evdns functionality locked, and automatically defer dns callbacks.
+ o Fix a possible free(NULL) when freeing an event_base with no signals.
+ o Add a flag to disable checking environment varibles when making an event_base
+ o Disallow setting less than 1 priority.
+ o Fix a bug when removing a timeout from the heap. [Patch from Marko Kreen]
+ o Use signal.h, not sys/signal.h. [Patch from mmadia]
+ o Try harder to build with certain older c99 compilers.
+ o Make sure that an event_config's flags field is always initialized to 0. [Bug report from Victor Goya]
+ o Avoid data corruption when reading data entirely into the second-to-last chain of an evbuffer. [Bug report from Victor Goya]
+ o Make sendfile work on FreeBSD
+ o Do not use vararg macros for accessing evrpc structures; this is not backwards compatible, but we did not promise any backwards compatibility for the rpc code.
+ o Actually define the event_config_set_flag() function.
+ o Try harder to compile with Visual C++.
+ o Move event_set() and its allies to event2/event_compat.h where they belong.
+ o Remove the event_gotsig code, which has long been deprecated and unused.
+ o Add an event_get_base() function to return the base assigned to an event.
+ o New function to automate connecting on a socket-based bufferevent.
+ o New functions to automate listening for incoming TCP connections.
+ o Do case-insensitive checks with a locale-independent comparison function.
+ o Rename the evbuffercb and everrorcb callbacks to bufferevent_data_cb and bufferevent_event_cb respectively. The old names are available in bufferevent_compat.h.
+ o Rename the EVBUFFER_* codes used by bufferevent event callbacks to BEV_EVENT_*, to avoid namespace collision with evbuffer flags. The old names are available in bufferevent_compat.h.
+ o Move the EVBUFFER_INPUT and EVBUFFER_OUTPUT macros to bufferevent_compat.h
+ o Add a bufferevent_getfd() function to mirror bufferevent_setfd()
+ o Make bufferevent_setfd() return an error code if the operation is not successful.
+ o Shave 22 bytes off struct event on 32-bit platforms by shrinking and re-ordering fields. The savings on 64-bit platforms is likely higher.
+ o Cap the maximum number of priorities at 256.
+ o Change the semantics of evbuffer_cb_set_flags() to be set-flag only; add a new evbuffer_cb_clear_flags() to remove set flags.
+ o Change the interface of evbuffer_add_reference so that the cleanup callback gets more information
+ o Revise the new evbuffer_reserve_space/evbuffer_commit_space() interfaces so that you can use them without causing extraneous copies or leaving gaps in the evbuffer.
+ o Add a new evbuffer_peek() interface to inspect data in an evbuffer without removing it.
+ o Fix a deadlock when suspending reads in a bufferevent due to a full buffer. (Spotted by Joachim Bauch.)
+ o Fix a memory error when freeing a thread-enabled event base with registered events. (Spotted by Joachim Bauch.)
+ o Try to contain degree of failure when running on a win32 version so heavily firewalled that we can't fake a socketpair.
+ o Activate fd events in a pseudorandom order with O(N) backends, so that we don't systematically favor low fds (select) or earlier-added fds (poll, win32).
+ o Replace some read()/write() instances with send()/recv() to work properly on win32.
+ o Set truncated flag correctly in evdns server replies.
+ o Raise RpcGenError in event_rpcgen.py; from jmanison and Zack Weinberg
+ o Fix preamble of rpcgen-generated files to rely on event2 includes; based on work by jmansion; patch from Zack Weinberg.
+ o Allow specifying the output filename for rpcgen; based on work by jmansion; patch from Zack Weinberg.
+ o Allow C identifiers as struct names; allow multiple comments in .rpc files; from Zack Weinberg
+ o Mitigate a race condition when using socket bufferevents in multiple threads.
+ o Use AC_SEARCH_LIBS, not AC_CHECK_LIB to avoid needless library use.
+ o Do not allow event_del(ev) to return while that event's callback is executing in another thread. This fixes a nasty race condition.
+ o event_get_supported_methods() now lists methods that have been disabled with the EVENT_NO* environment options.
+ o Rename encode_int[64] to evtag_encode_int[64] to avoid polluting the global namespace. The old method names are still available as macros in event2/tag_compat.h.
+
+
+
+Changes in 2.0.1-alpha (17 Apr 2009):
+ o free minheap on event_base_free(); from Christopher Layne
+ o debug cleanups in signal.c; from Christopher Layne
+ o provide event_base_new() that does not set the current_base global
+ o bufferevent_write now uses a const source argument; report from Charles Kerr
+ o improve documentation on event_base_loopexit; patch from Scott Lamb
+ o New function, event_{base_}loopbreak. Like event_loopexit, it makes an event loop stop executing and return. Unlike event_loopexit, it keeps subsequent pending events from getting executed. Patch from Scott Lamb
+ o Check return value of event_add in signal.c
+ o provide event_reinit() to reintialize an event_base after fork
+ o New function event_set_mem_functinons. It allows the user to give libevent replacement functions to use for memory management in place of malloc(), free(), etc. This should be generally useful for memory instrumentation, specialized allocators, and so on.
+ o The kqueue implementation now catches signals that are raised after event_add() is called but before the event_loop() call. This makes it match the other implementations.
+ o The kqueue implementation now restores original signal handlers correctly when its signal events are removed.
+ o Check return value of event_add in signal.c
+ o Add a more powerful evbuffer_readln as a replacement for evbuffer_readline. The new function handles more newline styles, and is more useful with buffers that may contain a nul characters.
+ o Do not mangle socket handles on 64-bit windows.
+ o The configure script now takes an --enable-gcc-warnigns option that turns on many optional gcc warnings. (Nick has been building with these for a while, but they might be useful to other developers.)
+ o move EV_PERSIST handling out of the event backends
+ o small improvements to evhttp documentation
+ o always generate Date and Content-Length headers for HTTP/1.1 replies
+ o set the correct event base for HTTP close events
+ o When building with GCC, use the "format" attribute to verify type correctness of calls to printf-like functions.
+ o Rewrite win32.c backend to be O(n lg n) rather than O(n^2).
+ o Removed obsoleted recalc code
+ o support for 32-bit tag numbers in rpc structures; this is wire compatible, but changes the API slightly.
+ o pull setters/getters out of RPC structures into a base class to which we just need to store a pointer; this reduces the memory footprint of these structures.
+ o prefix {encode,decode}_tag functions with evtag to avoid collisions
+ o fix a bug with event_rpcgen for integers
+ o Correctly handle DNS replies with no answers set (Fixes bug 1846282)
+ o add -Wstrict-aliasing to warnings and more cleanup
+ o removed linger from http server socket; reported by Ilya Martynov
+ o event_rpcgen now allows creating integer arrays
+ o support string arrays in event_rpcgen
+ o change evrpc hooking to allow pausing of RPCs; this will make it possible for the hook to do some meaning ful work; this is not backwards compatible.
+ o allow an http request callback to take ownership of a request structure
+ o allow association of meta data with RPC requests for hook processing
+ o associate more context for hooks to query such as the connection object
+ o remove pending timeouts on event_base_free()
+ o also check EAGAIN for Solaris' event ports; from W.C.A. Wijngaards
+ o devpoll and evport need reinit; tested by W.C.A Wijngaards
+ o event_base_get_method; from Springande Ulv
+ o Send CRLF after each chunk in HTTP output, for compliance with RFC2626. Patch from "propanbutan". Fixes bug 1894184.
+ o Add a int64_t parsing function, with unit tests, so we can apply Scott Lamb's fix to allow large HTTP values.
+ o Use a 64-bit field to hold HTTP content-lengths. Patch from Scott Lamb.
+ o Allow regression code to build even without Python installed
+ o remove NDEBUG ifdefs from evdns.c
+ o detect integer types properly on platforms without stdint.h
+ o udpate documentation of event_loop and event_base_loop; from Tani Hosokawa.
+ o simplify evbuffer by removing orig_buffer
+ o do not insert event into list when evsel->add fails
+ o add support for PUT/DELETE requests; from Josh Rotenberg
+ o introduce evhttp_accept_socket() to accept from an already created socket
+ o include Content-Length in reply for HTTP/1.0 requests with keep-alive
+ o increase listen queue for http sockets to 128; if that is not enough the evhttp_accpet_socket() api can be used with a prepared socket.
+ o Patch from Tani Hosokawa: make some functions in http.c threadsafe.
+ o test support for PUT/DELETE requests; from Josh Rotenberg
+ o rewrite of the evbuffer code to reduce memory copies
+ o Some older Solaris versions demand that _REENTRANT be defined to get strtok_r(); do so.
+ o Do not free the kqop file descriptor in other processes, also allow it to be 0; from Andrei Nigmatulin
+ o Provide OpenSSL style support for multiple threads accessing the same event_base
+ o make event_rpcgen.py generate code include event-config.h; reported by Sam Banks.
+ o switch thread support so that locks get allocated as they are needed.
+ o make event methods static so that they are not exported; from Andrei Nigmatulin
+ o make RPC replies use application/octet-stream as mime type
+ o do not delete uninitialized timeout event in evdns
+ o Correct the documentation on buffer printf functions.
+ o Don't warn on unimplemented epoll_create(): this isn't a problem, just a reason to fall back to poll or select.
+ o Correctly handle timeouts larger than 35 minutes on Linux with epoll.c. This is probably a kernel defect, but we'll have to support old kernels anyway even if it gets fixed.
+ o Make name_from_addr() threadsafe in http.c
+ o Add new thread-safe interfaces to evdns functions.
+ o Make all event_tagging interfaces threadsafe.
+ o Rename internal memory management functions.
+ o New functions (event_assign, event_new, event_free) for use by apps that want to be safely threadsafe, or want to remain ignorant of the contents of struct event.
+ o introduce bufferevent_read_buffer; allows reading without memory copy.
+ o expose bufferevent_setwatermark via header files and fix high watermark on read
+ o fix a bug in buffrevent read water marks and add a test for them
+ o fix a bug in which bufferevent_write_buffer would not schedule a write event
+ o provide bufferevent_input and bufferevent_output without requiring knowledge of the structure
+ o introduce bufferevent_setcb and bufferevent_setfd to allow better manipulation of bufferevents
+ o convert evhttp_connection to use bufferevents.
+ o use libevent's internal timercmp on all platforms, to avoid bugs on old platforms where timercmp(a,b,<=) is buggy.
+ o Remove the never-exported, never-used evhttp_hostportfile function.
+ o Support input/output filters for bufferevents; somewhat similar to libio's model. This will allow us to implement SSL, compression, etc, transparently to users of bufferevents such as the http layer.
+ o allow connections to be removed from an rpc pool
+ o add new evtimer_assign, signal_assign, evtimer_new, and signal_new functions to manipulate timer and signal events, analagous to the now-recommended event_assign and event_new
+ o switch internal uses of event_set over to use event_assign.
+ o introduce evbuffer_contiguous_space() api that tells a user how much data is available in the first buffer chain
+ o introduce evbuffer_reserve_space() and evbuffer_commit_space() to make processing in filters more efficient.
+ o reduce system calls for getting current time by caching it.
+ o separate signal events from io events; making the code less complex.
+ o support for periodic timeouts
+ o support for virtual HTTP hosts.
+ o turn event_initialized() into a function, and add function equivalents to EVENT_SIGNAL and EVENT_FD so that people don't need to include event_struct.h
+ o Build test directory correctly with CPPFLAGS set.
+ o Provide an API for retrieving the supported event mechanisms.
+ o event_base_new_with_config() and corresponding config APIs.
+ o migrate the evhttp header to event2/ but accessors are still missing.
+ o deprecate timeout_* event functions by moving them to event_compat.h
+ o Move windows gettimeofday replacement into a new evutil_gettimeofday().
+ o Make configure script work on IRIX.
+ o provide a method for canceling ongoing http requests.
+ o Make vsnprintf() returns consistent on win32.
+ o Fix connection keep-alive behavior for HTTP/1.0
+ o Fix use of freed memory in event_reinit; pointed out by Peter Postma
+ o constify struct timeval * where possible
+ o make event_get_supported_methods obey environment variables
+ o support for edge-triggered events on epoll and kqueue backends: patch from Valery Kholodkov
+ o support for selecting event backends by their features, and for querying the features of a backend.
+ o change failing behavior of event_base_new_with_config: if a config is provided and no backend is selected, return NULL instead of aborting.
+ o deliver partial data to request callbacks when chunked callback is set even if there is no chunking on the http level; allows cancelation of requests from within the chunked callback; from Scott Lamb.
+ o allow min_heap_erase to be called on removed members; from liusifan.
+ o Rename INPUT and OUTPUT to EVRPC_INPUT and EVRPC_OUTPUT. Retain INPUT/OUTPUT aliases on on-win32 platforms for backwards compatibility.
+ o Do not use SO_REUSEADDR when connecting
+ o Support 64-bit integers in RPC structs
+ o Correct handling of trailing headers in chunked replies; from Scott Lamb.
+ o Support multi-line HTTP headers; based on a patch from Moshe Litvin
+ o Reject negative Content-Length headers; anonymous bug report
+ o Detect CLOCK_MONOTONIC at runtime for evdns; anonymous bug report
+ o Various HTTP correctness fixes from Scott Lamb
+ o Fix a bug where deleting signals with the kqueue backend would cause subsequent adds to fail
+ o Support multiple events listening on the same signal; make signals regular events that go on the same event queue; problem report by Alexander Drozdov.
+ o Fix a problem with epoll() and reinit; problem report by Alexander Drozdov.
+ o Fix off-by-one errors in devpoll; from Ian Bell
+ o Make event_add not change any state if it fails; reported by Ian Bell.
+ o Fix a bug where headers arriving in multiple packets were not parsed; fix from Jiang Hong; test by me.
+ o Match the query in DNS replies to the query in the request; from Vsevolod Stakhov.
+ o Add new utility functions to correctly observe and log winsock errors.
+ o Do not remove Accept-Encoding header
+ o Clear the timer cache on entering the event loop; reported by Victor Chang
+ o Only bind the socket on connect when a local address has been provided; reported by Alejo Sanchez
+ o Allow setting of local port for evhttp connections to support millions of connections from a single system; from Richard Jones.
+ o Clear the timer cache when leaving the event loop; reported by Robin Haberkorn
+ o Fix a typo in setting the global event base; reported by lance.
+ o Set the 0x20 bit on outgoing alphabetic characters in DNS requests randomly, and insist on a match in replies. This helps resist DNS poisoning attacks.
+ o Make the http connection close detection work properly with bufferevents and fix a potential memory leak associated with it.
+ o Restructure the event backends so that they do not need to keep track of events themselves, as a side effect multiple events can use the same fd or signal.
+ o Add generic implementations for parsing and emiting IPv6 addresses on platforms that do not have inet_ntop and/or inet_pton.
+ o Allow DNS servers that have IPv6 addresses.
+ o Add an evbuffer_write_atmost() function to write a limited number of bytes to an fd.
+ o Refactor internal notify-main-thread logic to prefer eventfd to pipe, then pipe to socketpair, and only use socketpairs as a last resort.
+ o Try harder to pack all evbuffer reads into as few chains as possible, using readv/WSARecv as appropriate.
+ o New evthread_use_windows_threads() and evthread_use_pthreads() functions to set up the evthread callbacks with reasonable defaults.
+ o Change the semantics of timeouts in conjunction with EV_PERSIST; timeouts in that case will now repeat until deleted.
+ o sendfile, mmap and memory reference support for evbuffers.
+ o New evutil_make_listen_socket_reuseable() to abstract SO_REUSEADDR.
+ o New bind-to option to allow DNS clients to bind to an arbitrary port for outgoing requests.
+ o evbuffers can now be "frozen" to prevent operations at one or both ends.
+ o Bufferevents now notice external attempts to add data to an inbuf or remove it from an outbuf, and stop them.
+ o Fix parsing of queries where the encoded queries contained \r, \n or +
+ o Do not allow internal events to starve lower-priority events.
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/Doxyfile b/fluent-bit/lib/monkey/mk_core/deps/libevent/Doxyfile
new file mode 100644
index 000000000..d9d660345
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/Doxyfile
@@ -0,0 +1,257 @@
+# Doxyfile 1.5.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = libevent
+
+# Place all output under 'doxygen/'
+
+OUTPUT_DIRECTORY = doxygen/
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = include/
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = \
+ include/event2/buffer.h \
+ include/event2/buffer_compat.h \
+ include/event2/bufferevent.h \
+ include/event2/bufferevent_compat.h \
+ include/event2/bufferevent_ssl.h \
+ include/event2/dns.h \
+ include/event2/dns_compat.h \
+ include/event2/event.h \
+ include/event2/event_compat.h \
+ include/event2/http.h \
+ include/event2/http_compat.h \
+ include/event2/listener.h \
+ include/event2/rpc.h \
+ include/event2/rpc_compat.h \
+ include/event2/tag.h \
+ include/event2/tag_compat.h \
+ include/event2/thread.h \
+ include/event2/util.h
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = TAILQ_ENTRY RB_ENTRY EVENT_DEFINED_TQENTRY_ EVENT_IN_DOXYGEN_
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/LICENSE b/fluent-bit/lib/monkey/mk_core/deps/libevent/LICENSE
new file mode 100644
index 000000000..402ca5089
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/LICENSE
@@ -0,0 +1,99 @@
+Libevent is available for use under the following license, commonly known
+as the 3-clause (or "modified") BSD license:
+
+==============================
+Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+==============================
+
+Portions of Libevent are based on works by others, also made available by
+them under the three-clause BSD license above. The copyright notices are
+available in the corresponding source files; the license is as above. Here's
+a list:
+
+log.c:
+ Copyright (c) 2000 Dug Song <dugsong@monkey.org>
+ Copyright (c) 1993 The Regents of the University of California.
+
+strlcpy.c:
+ Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+
+win32select.c:
+ Copyright (c) 2003 Michael A. Davis <mike@datanerds.net>
+
+evport.c:
+ Copyright (c) 2007 Sun Microsystems
+
+ht-internal.h:
+ Copyright (c) 2002 Christopher Clark
+
+minheap-internal.h:
+ Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
+
+==============================
+
+The arc4module is available under the following, sometimes called the
+"OpenBSD" license:
+
+ Copyright (c) 1996, David Mazieres <dm@uun.org>
+ Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+
+ Permission to use, copy, modify, and distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+==============================
+
+The Windows timer code is based on code from libutp, which is
+distributed under this license, sometimes called the "MIT" license.
+
+
+Copyright (c) 2010 BitTorrent, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/Makefile.am b/fluent-bit/lib/monkey/mk_core/deps/libevent/Makefile.am
new file mode 100644
index 000000000..c7f1d19a1
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/Makefile.am
@@ -0,0 +1,305 @@
+# Makefile.am for libevent
+# Copyright 2000-2007 Niels Provos
+# Copyright 2007-2012 Niels Provos and Nick Mathewson
+#
+# See LICENSE for copying information.
+
+ACLOCAL_AMFLAGS = -I m4
+
+# This is the "Release" of the Libevent ABI. It takes precedence over
+# the VERSION_INFO, so that two versions of Libevent with the same
+# "Release" are never binary-compatible.
+#
+# This number incremented once for the 2.0 release candidate, and
+# will increment for each series until we revise our interfaces enough
+# that we can seriously expect ABI compatibility between series.
+#
+RELEASE = -release 2.1
+
+# This is the version info for the libevent binary API. It has three
+# numbers:
+# Current -- the number of the binary API that we're implementing
+# Revision -- which iteration of the implementation of the binary
+# API are we supplying?
+# Age -- How many previous binary API versions do we also
+# support?
+#
+# To increment a VERSION_INFO (current:revision:age):
+# If the ABI didn't change:
+# Return (current:revision+1:age)
+# If the ABI changed, but it's backward-compatible:
+# Return (current+1:0:age+1)
+# If the ABI changed and it isn't backward-compatible:
+# Return (current+1:0:0)
+#
+# Once an RC is out, DO NOT MAKE ANY ABI-BREAKING CHANGES IN THAT SERIES
+# UNLESS YOU REALLY REALLY HAVE TO.
+VERSION_INFO = 6:1:0
+
+# History: RELEASE VERSION_INFO
+# 2.0.1-alpha -- 2.0 1:0:0
+# 2.0.2-alpha -- 2:0:0
+# 2.0.3-alpha -- 2:0:0 (should have incremented; didn't.)
+# 2.0.4-alpha -- 3:0:0
+# 2.0.5-beta -- 4:0:0
+# 2.0.6-rc -- 2.0 2:0:0
+# 2.0.7-rc -- 2.0 3:0:1
+# 2.0.8-rc -- 2.0 4:0:2
+# 2.0.9-rc -- 2.0 5:0:0 (ABI changed slightly)
+# 2.0.10-stable-- 2.0 5:1:0 (No ABI change)
+# 2.0.11-stable-- 2.0 6:0:1 (ABI changed, backward-compatible)
+# 2.0.12-stable-- 2.0 6:1:1 (No ABI change)
+# 2.0.13-stable-- 2.0 6:2:1 (No ABI change)
+# 2.0.14-stable-- 2.0 6:3:1 (No ABI change)
+# 2.0.15-stable-- 2.0 6:3:1 (Forgot to update :( )
+# 2.0.16-stable-- 2.0 6:4:1 (No ABI change)
+# 2.0.17-stable-- 2.0 6:5:1 (No ABI change)
+# 2.0.18-stable-- 2.0 6:6:1 (No ABI change)
+# 2.0.19-stable-- 2.0 6:7:1 (No ABI change)
+# 2.0.20-stable-- 2.0 6:8:1 (No ABI change)
+# 2.0.21-stable-- 2.0 6:9:1 (No ABI change)
+#
+# For Libevent 2.1:
+# 2.1.1-alpha -- 2.1 1:0:0
+# 2.1.2-alpha -- 2.1 1:0:0 (should have been 2:0:1)
+# 2.1.3-alpha -- 2.1 3:0:0 (ABI changed slightly)
+# 2.1.4-alpha -- 2.1 4:0:0 (ABI changed slightly)
+# 2.1.5-beta -- 2.1 5:0:0 (ABI changed slightly)
+# 2.1.6-beta -- 2.1 6:0:0 (ABI changed slightly)
+# 2.1.7-beta -- 2.1 6:1:0 (ABI changed slightly)
+
+# ABI version history for this package effectively restarts every time
+# we change RELEASE. Version 1.4.x had RELEASE of 1.4.
+#
+# Ideally, we would not be using RELEASE at all; instead we could just
+# use the VERSION_INFO field to label our backward-incompatible ABI
+# changes, and those would be few and far between. Unfortunately,
+# Libevent still exposes far too many volatile structures in its
+# headers, so we pretty much have to assume that most development
+# series will break ABI compatibility. For now, it's simplest just to
+# keep incrementing the RELEASE between series and resetting VERSION_INFO.
+#
+# Eventually, when we get to the point where the structures in the
+# headers are all non-changing (or not there at all!), we can shift to
+# a more normal worldview where backward-incompatible ABI changes are
+# nice and rare. For the next couple of years, though, 'struct event'
+# is user-visible, and so we can pretty much guarantee that release
+# series won't be binary-compatible.
+
+if INSTALL_LIBEVENT
+dist_bin_SCRIPTS = event_rpcgen.py
+endif
+
+pkgconfigdir=$(libdir)/pkgconfig
+LIBEVENT_PKGCONFIG=libevent.pc libevent_core.pc libevent_extra.pc
+
+# These sources are conditionally added by configure.ac or conditionally
+# included from other files.
+PLATFORM_DEPENDENT_SRC = \
+ arc4random.c \
+ epoll_sub.c
+
+EXTRA_DIST = \
+ ChangeLog-1.4 \
+ ChangeLog-2.0 \
+ Doxyfile \
+ LICENSE \
+ Makefile.nmake test/Makefile.nmake \
+ autogen.sh \
+ event_rpcgen.py \
+ libevent.pc.in \
+ make-event-config.sed \
+ whatsnew-2.0.txt \
+ whatsnew-2.1.txt \
+ $(PLATFORM_DEPENDENT_SRC)
+
+LIBEVENT_LIBS_LA = libevent.la libevent_core.la libevent_extra.la
+if PTHREADS
+LIBEVENT_LIBS_LA += libevent_pthreads.la
+LIBEVENT_PKGCONFIG += libevent_pthreads.pc
+endif
+if OPENSSL
+LIBEVENT_LIBS_LA += libevent_openssl.la
+LIBEVENT_PKGCONFIG += libevent_openssl.pc
+endif
+
+if INSTALL_LIBEVENT
+lib_LTLIBRARIES = $(LIBEVENT_LIBS_LA)
+pkgconfig_DATA = $(LIBEVENT_PKGCONFIG)
+else
+noinst_LTLIBRARIES = $(LIBEVENT_LIBS_LA)
+endif
+
+EXTRA_SOURCE=
+noinst_HEADERS=
+noinst_PROGRAMS=
+EXTRA_PROGRAMS=
+CLEANFILES=
+DISTCLEANFILES=
+BUILT_SOURCES =
+include include/include.am
+include sample/include.am
+include test/include.am
+
+if BUILD_WIN32
+
+SYS_LIBS = -lws2_32 -lshell32 -ladvapi32
+SYS_SRC = win32select.c buffer_iocp.c event_iocp.c \
+ bufferevent_async.c
+SYS_INCLUDES = -IWIN32-Code -IWIN32-Code/nmake
+
+if THREADS
+SYS_SRC += evthread_win32.c
+endif
+
+else
+
+SYS_LIBS =
+SYS_SRC =
+SYS_INCLUDES =
+
+endif
+
+if STRLCPY_IMPL
+SYS_SRC += strlcpy.c
+endif
+if SELECT_BACKEND
+SYS_SRC += select.c
+endif
+if POLL_BACKEND
+SYS_SRC += poll.c
+endif
+if DEVPOLL_BACKEND
+SYS_SRC += devpoll.c
+endif
+if KQUEUE_BACKEND
+SYS_SRC += kqueue.c
+endif
+if EPOLL_BACKEND
+SYS_SRC += epoll.c
+endif
+if EVPORT_BACKEND
+SYS_SRC += evport.c
+endif
+if SIGNAL_SUPPORT
+SYS_SRC += signal.c
+endif
+
+BUILT_SOURCES += include/event2/event-config.h
+
+include/event2/event-config.h: config.h make-event-config.sed
+ $(AM_V_GEN)test -d include/event2 || $(MKDIR_P) include/event2
+ $(AM_V_at)$(SED) -f $(srcdir)/make-event-config.sed < config.h > $@T
+ $(AM_V_at)mv -f $@T $@
+
+CORE_SRC = \
+ buffer.c \
+ bufferevent.c \
+ bufferevent_filter.c \
+ bufferevent_pair.c \
+ bufferevent_ratelim.c \
+ bufferevent_sock.c \
+ event.c \
+ evmap.c \
+ evthread.c \
+ evutil.c \
+ evutil_rand.c \
+ evutil_time.c \
+ listener.c \
+ log.c \
+ $(SYS_SRC)
+
+EXTRAS_SRC = \
+ evdns.c \
+ event_tagging.c \
+ evrpc.c \
+ http.c
+
+if BUILD_WITH_NO_UNDEFINED
+NO_UNDEFINED = -no-undefined
+MAYBE_CORE = libevent_core.la
+else
+NO_UNDEFINED =
+MAYBE_CORE =
+endif
+
+GENERIC_LDFLAGS = -version-info $(VERSION_INFO) $(RELEASE) $(NO_UNDEFINED)
+
+libevent_la_SOURCES = $(CORE_SRC) $(EXTRAS_SRC)
+libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
+libevent_la_LDFLAGS = $(GENERIC_LDFLAGS)
+
+libevent_core_la_SOURCES = $(CORE_SRC)
+libevent_core_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
+libevent_core_la_LDFLAGS = $(GENERIC_LDFLAGS)
+
+if PTHREADS
+libevent_pthreads_la_SOURCES = evthread_pthread.c
+libevent_pthreads_la_LIBADD = $(MAYBE_CORE)
+libevent_pthreads_la_LDFLAGS = $(GENERIC_LDFLAGS)
+endif
+
+libevent_extra_la_SOURCES = $(EXTRAS_SRC)
+libevent_extra_la_LIBADD = $(MAYBE_CORE) $(SYS_LIBS)
+libevent_extra_la_LDFLAGS = $(GENERIC_LDFLAGS)
+
+if OPENSSL
+libevent_openssl_la_SOURCES = bufferevent_openssl.c
+libevent_openssl_la_LIBADD = $(MAYBE_CORE) $(OPENSSL_LIBS)
+libevent_openssl_la_LDFLAGS = $(GENERIC_LDFLAGS)
+libevent_openssl_la_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS)
+endif
+
+noinst_HEADERS += \
+ WIN32-Code/nmake/evconfig-private.h \
+ WIN32-Code/nmake/event2/event-config.h \
+ WIN32-Code/tree.h \
+ bufferevent-internal.h \
+ changelist-internal.h \
+ compat/sys/queue.h \
+ defer-internal.h \
+ epolltable-internal.h \
+ evbuffer-internal.h \
+ evconfig-private.h \
+ event-internal.h \
+ evmap-internal.h \
+ evrpc-internal.h \
+ evsignal-internal.h \
+ evthread-internal.h \
+ ht-internal.h \
+ http-internal.h \
+ iocp-internal.h \
+ ipv6-internal.h \
+ kqueue-internal.h \
+ log-internal.h \
+ minheap-internal.h \
+ mm-internal.h \
+ ratelim-internal.h \
+ ratelim-internal.h \
+ strlcpy-internal.h \
+ time-internal.h \
+ util-internal.h
+
+EVENT1_HDRS = \
+ include/evdns.h \
+ include/event.h \
+ include/evhttp.h \
+ include/evrpc.h \
+ include/evutil.h
+
+if INSTALL_LIBEVENT
+include_HEADERS = $(EVENT1_HDRS)
+else
+noinst_HEADERS += $(EVENT1_HDRS)
+endif
+
+AM_CPPFLAGS = -I$(srcdir)/compat -I$(srcdir)/include -I./include $(SYS_INCLUDES)
+
+verify: check
+
+doxygen: FORCE
+ doxygen $(srcdir)/Doxyfile
+FORCE:
+
+DISTCLEANFILES += *~ libevent.pc libevent_core.pc libevent_extra.pc ./include/event2/event-config.h
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/Makefile.nmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/Makefile.nmake
new file mode 100644
index 000000000..f27cd6194
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/Makefile.nmake
@@ -0,0 +1,82 @@
+# WATCH OUT! This makefile is a work in progress. -*- makefile -*-
+#
+# I'm not very knowledgeable about MSVC and nmake beyond their most basic
+# aspects. If anything here looks wrong to you, please let me know.
+
+# If OPENSSL_DIR is not set, builds without OpenSSL support. If you want
+# OpenSSL support, you can set the OPENSSL_DIR variable to where you
+# installed OpenSSL. This can be done in the environment:
+# set OPENSSL_DIR=c:\openssl
+# Or on the nmake command line:
+# nmake OPENSSL_DIR=C:\openssl -f Makefile.nmake
+# Or by uncommenting the following line here in the makefile...
+
+# OPENSSL_DIR=c:\openssl
+
+!IFDEF OPENSSL_DIR
+SSL_CFLAGS=/I$(OPENSSL_DIR)\include /DEVENT__HAVE_OPENSSL
+!ELSE
+SSL_CFLAGS=
+!ENDIF
+
+# Needed for correctness
+CFLAGS=/IWIN32-Code /IWIN32-Code/nmake /Iinclude /Icompat /DHAVE_CONFIG_H /I. $(SSL_CFLAGS)
+
+# For optimization and warnings
+CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo
+
+# XXXX have a debug mode
+
+LIBFLAGS=/nologo
+
+CORE_OBJS=event.obj buffer.obj bufferevent.obj bufferevent_sock.obj \
+ bufferevent_pair.obj listener.obj evmap.obj log.obj evutil.obj \
+ strlcpy.obj signal.obj bufferevent_filter.obj evthread.obj \
+ bufferevent_ratelim.obj evutil_rand.obj evutil_time.obj
+WIN_OBJS=win32select.obj evthread_win32.obj buffer_iocp.obj \
+ event_iocp.obj bufferevent_async.obj
+EXTRA_OBJS=event_tagging.obj http.obj evdns.obj evrpc.obj
+
+!IFDEF OPENSSL_DIR
+SSL_OBJS=bufferevent_openssl.obj
+SSL_LIBS=libevent_openssl.lib
+!ELSE
+SSL_OBJS=
+SSL_LIBS=
+!ENDIF
+
+ALL_OBJS=$(CORE_OBJS) $(WIN_OBJS) $(EXTRA_OBJS) $(SSL_OBJS)
+STATIC_LIBS=libevent_core.lib libevent_extras.lib libevent.lib $(SSL_LIBS)
+
+
+all: static_libs tests
+
+static_libs: $(STATIC_LIBS)
+
+libevent_core.lib: $(CORE_OBJS) $(WIN_OBJS)
+ lib $(LIBFLAGS) $(CORE_OBJS) $(WIN_OBJS) /out:libevent_core.lib
+
+libevent_extras.lib: $(EXTRA_OBJS)
+ lib $(LIBFLAGS) $(EXTRA_OBJS) /out:libevent_extras.lib
+
+libevent.lib: $(CORE_OBJS) $(WIN_OBJS) $(EXTRA_OBJS)
+ lib $(LIBFLAGS) $(CORE_OBJS) $(EXTRA_OBJS) $(WIN_OBJS) /out:libevent.lib
+
+libevent_openssl.lib: $(SSL_OBJS)
+ lib $(LIBFLAGS) $(SSL_OBJS) /out:libevent_openssl.lib
+
+clean:
+ del $(ALL_OBJS)
+ del $(STATIC_LIBS)
+ cd test
+ $(MAKE) /F Makefile.nmake clean
+ cd ..
+
+tests:
+ cd test
+!IFDEF OPENSSL_DIR
+ $(MAKE) OPENSSL_DIR=$(OPENSSL_DIR) /F Makefile.nmake
+!ELSE
+ $(MAKE) /F Makefile.nmake
+!ENDIF
+ cd ..
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/README.md b/fluent-bit/lib/monkey/mk_core/deps/libevent/README.md
new file mode 100644
index 000000000..fd91087a5
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/README.md
@@ -0,0 +1,427 @@
+<p align="center">
+ <img src="https://strcpy.net/libevent3.png" alt="libevent logo"/>
+</p>
+
+
+
+[![Appveyor Win32 Build Status](https://ci.appveyor.com/api/projects/status/github/libevent/libevent?branch=master&svg=true)](https://ci.appveyor.com/project/nmathewson/libevent)
+[![Travis Build Status](https://travis-ci.org/libevent/libevent.svg?branch=master)](https://travis-ci.org/libevent/libevent)
+[![Coverage Status](https://coveralls.io/repos/github/libevent/libevent/badge.svg)](https://coveralls.io/github/libevent/libevent)
+
+
+
+# 0. BUILDING AND INSTALLATION (Briefly)
+
+## Autoconf
+
+ $ ./configure
+ $ make
+ $ make verify # (optional)
+ $ sudo make install
+
+## Cmake (General)
+
+
+The following Libevent specific Cmake variables are as follows (the values being
+the default).
+
+```
+# Installation directory for executables
+EVENT_INSTALL_BIN_DIR:PATH=bin
+
+# Installation directory for CMake files
+EVENT_INSTALL_CMAKE_DIR:PATH=lib/cmake/libevent
+
+## Installation directory for header files
+EVENT_INSTALL_INCLUDE_DIR:PATH=include
+
+## Installation directory for libraries
+EVENT_INSTALL_LIB_DIR:PATH=lib
+
+## Define if libevent should be built with shared libraries instead of archives
+EVENT__BUILD_SHARED_LIBRARIES:BOOL=OFF
+
+# Enable running gcov to get a test coverage report (only works with
+# GCC/CLang). Make sure to enable -DCMAKE_BUILD_TYPE=Debug as well.
+EVENT__COVERAGE:BOOL=OFF
+
+# Defines if libevent should build without the benchmark exectuables
+EVENT__DISABLE_BENCHMARK:BOOL=OFF
+
+# Define if libevent should build without support for a debug mode
+EVENT__DISABLE_DEBUG_MODE:BOOL=OFF
+
+# Define if libevent should not allow replacing the mm functions
+EVENT__DISABLE_MM_REPLACEMENT:BOOL=OFF
+
+# Define if libevent should build without support for OpenSSL encrpytion
+EVENT__DISABLE_OPENSSL:BOOL=ON
+
+# Disable the regress tests
+EVENT__DISABLE_REGRESS:BOOL=OFF
+
+# Disable sample files
+EVENT__DISABLE_SAMPLES:BOOL=OFF
+
+# If tests should be compiled or not
+EVENT__DISABLE_TESTS:BOOL=OFF
+
+# Define if libevent should not be compiled with thread support
+EVENT__DISABLE_THREAD_SUPPORT:BOOL=OFF
+
+# Enables verbose debugging
+EVENT__ENABLE_VERBOSE_DEBUG:BOOL=OFF
+
+# When crosscompiling forces running a test program that verifies that Kqueue
+# works with pipes. Note that this requires you to manually run the test program
+# on the the cross compilation target to verify that it works. See cmake
+# documentation for try_run for more details
+EVENT__FORCE_KQUEUE_CHECK:BOOL=OFF
+
+# set EVENT_STAGE_VERSION
+EVENT__STAGE_VERSION:STRING=beta
+```
+
+__More variables can be found by running `cmake -LAH <sourcedir_path>`__
+
+
+## CMake (Windows)
+
+Install CMake: <http://www.cmake.org>
+
+
+ $ md build && cd build
+ $ cmake -G "Visual Studio 10" .. # Or whatever generator you want to use cmake --help for a list.
+ $ start libevent.sln
+
+## CMake (Unix)
+
+ $ mkdir build && cd build
+ $ cmake .. # Default to Unix Makefiles.
+ $ make
+ $ make verify # (optional)
+
+
+# 1. BUILDING AND INSTALLATION (In Depth)
+
+## Autoconf
+
+To build libevent, type
+
+ $ ./configure && make
+
+
+ (If you got libevent from the git repository, you will
+ first need to run the included "autogen.sh" script in order to
+ generate the configure script.)
+
+You can run the regression tests by running
+
+ $ make verify
+
+Install as root via
+
+ $ make install
+
+Before reporting any problems, please run the regression tests.
+
+To enable the low-level tracing build the library as:
+
+ $ CFLAGS=-DUSE_DEBUG ./configure [...]
+
+Standard configure flags should work. In particular, see:
+
+ --disable-shared Only build static libraries
+ --prefix Install all files relative to this directory.
+
+
+The configure script also supports the following flags:
+
+ --enable-gcc-warnings Enable extra compiler checking with GCC.
+ --disable-malloc-replacement
+ Don't let applications replace our memory
+ management functions
+ --disable-openssl Disable support for OpenSSL encryption.
+ --disable-thread-support Don't support multithreaded environments.
+
+## CMake (Windows)
+
+(Note that autoconf is currently the most mature and supported build
+enviroment for libevent; the cmake instructions here are new and
+experimental, though they _should_ be solid. We hope that cmake will
+still be supported in future versions of Libevent, and will try to
+make sure that happens.)
+
+First of all install <http://www.cmake.org>.
+
+To build libevent using Microsoft Visual studio open the "Visual Studio Command prompt" and type:
+
+```
+$ cd <libevent source dir>
+$ mkdir build && cd build
+$ cmake -G "Visual Studio 10" .. # Or whatever generator you want to use cmake --help for a list.
+$ start libevent.sln
+```
+
+In the above, the ".." refers to the dir containing the Libevent source code.
+You can build multiple versions (with different compile time settings) from the same source tree
+by creating other build directories.
+
+It is highly recommended to build "out of source" when using
+CMake instead of "in source" like the normal behaviour of autoconf for this reason.
+
+The "NMake Makefiles" CMake generator can be used to build entirely via the command line.
+
+To get a list of settings available for the project you can type:
+
+```
+$ cmake -LH ..
+```
+
+### GUI
+
+CMake also provides a GUI that lets you specify the source directory and output (binary) directory
+that the build should be placed in.
+
+### OpenSSL support
+
+To build Libevent with OpenSSL support you will need to have OpenSSL binaries available when building,
+these can be found here: <http://www.openssl.org/related/binaries.html>
+
+# 2. USEFUL LINKS:
+
+For the latest released version of Libevent, see the official website at
+<http://libevent.org/> .
+
+There's a pretty good work-in-progress manual up at
+ <http://www.wangafu.net/~nickm/libevent-book/> .
+
+For the latest development versions of Libevent, access our Git repository
+via
+
+```
+$ git clone https://github.com/libevent/libevent.git
+```
+
+You can browse the git repository online at:
+
+<https://github.com/libevent/Libevent>
+
+To report bugs, issues, or ask for new features:
+
+__Patches__: https://github.com/libevent/libevent/pulls
+> OK, those are not really _patches_ You fork, modify, and hit the "Create Pull Request" button.
+> You can still submit normal git patchs via the mailing list.
+
+__Bugs, Features [RFC], and Issus__: https://github.com/libevent/libevent/issues
+> Or you can do it via the mailing list.
+
+There's also a libevent-users mailing list for talking about Libevent
+use and development:
+
+<http://archives.seul.org/libevent/users/>
+
+# 3. ACKNOWLEDGMENTS
+
+The following people have helped with suggestions, ideas, code or
+fixing bugs:
+
+ * Samy Al Bahra
+ * Antony Antony
+ * Jacob Appelbaum
+ * Arno Bakker
+ * Weston Andros Adamson
+ * William Ahern
+ * Ivan Andropov
+ * Sergey Avseyev
+ * Avi Bab
+ * Joachim Bauch
+ * Andrey Belobrov
+ * Gilad Benjamini
+ * Stas Bekman
+ * Denis Bilenko
+ * Julien Blache
+ * Kevin Bowling
+ * Tomash Brechko
+ * Kelly Brock
+ * Ralph Castain
+ * Adrian Chadd
+ * Lawnstein Chan
+ * Shuo Chen
+ * Ka-Hing Cheung
+ * Andrew Cox
+ * Paul Croome
+ * George Danchev
+ * Andrew Danforth
+ * Ed Day
+ * Christopher Davis
+ * Mike Davis
+ * Frank Denis
+ * Antony Dovgal
+ * Mihai Draghicioiu
+ * Alexander Drozdov
+ * Mark Ellzey
+ * Shie Erlich
+ * Leonid Evdokimov
+ * Juan Pablo Fernandez
+ * Christophe Fillot
+ * Mike Frysinger
+ * Remi Gacogne
+ * Artem Germanov
+ * Alexander von Gernler
+ * Diego Giagio
+ * Artur Grabowski
+ * Diwaker Gupta
+ * Kuldeep Gupta
+ * Sebastian Hahn
+ * Dave Hart
+ * Greg Hazel
+ * Nicholas Heath
+ * Michael Herf
+ * Savg He
+ * Mark Heily
+ * Maxime Henrion
+ * Michael Herf
+ * Greg Hewgill
+ * Andrew Hochhaus
+ * Aaron Hopkins
+ * Tani Hosokawa
+ * Jamie Iles
+ * Xiuqiang Jiang
+ * Claudio Jeker
+ * Evan Jones
+ * Marcin Juszkiewicz
+ * George Kadianakis
+ * Makoto Kato
+ * Phua Keat
+ * Azat Khuzhin
+ * Alexander Klauer
+ * Kevin Ko
+ * Brian Koehmstedt
+ * Marko Kreen
+ * Ondřej Kuzník
+ * Valery Kyholodov
+ * Ross Lagerwall
+ * Scott Lamb
+ * Christopher Layne
+ * Adam Langley
+ * Graham Leggett
+ * Volker Lendecke
+ * Philip Lewis
+ * Zhou Li
+ * David Libenzi
+ * Yan Lin
+ * Moshe Litvin
+ * Simon Liu
+ * Mitchell Livingston
+ * Hagne Mahre
+ * Lubomir Marinov
+ * Abilio Marques
+ * Nicolas Martyanoff
+ * Abel Mathew
+ * Nick Mathewson
+ * James Mansion
+ * Nicholas Marriott
+ * Andrey Matveev
+ * Caitlin Mercer
+ * Dagobert Michelsen
+ * Andrea Montefusco
+ * Mansour Moufid
+ * Mina Naguib
+ * Felix Nawothnig
+ * Trond Norbye
+ * Linus Nordberg
+ * Richard Nyberg
+ * Jon Oberheide
+ * John Ohl
+ * Phil Oleson
+ * Alexey Ozeritsky
+ * Dave Pacheco
+ * Derrick Pallas
+ * Tassilo von Parseval
+ * Catalin Patulea
+ * Patrick Pelletier
+ * Simon Perreault
+ * Dan Petro
+ * Pierre Phaneuf
+ * Amarin Phaosawasdi
+ * Ryan Phillips
+ * Dimitre Piskyulev
+ * Pavel Plesov
+ * Jon Poland
+ * Roman Puls
+ * Nate R
+ * Robert Ransom
+ * Balint Reczey
+ * Bert JW Regeer
+ * Nate Rosenblum
+ * Peter Rosin
+ * Maseeb Abdul Qadir
+ * Wang Qin
+ * Alex S
+ * Gyepi Sam
+ * Hanna Schroeter
+ * Ralf Schmitt
+ * Mike Smellie
+ * Steve Snyder
+ * Nir Soffer
+ * Dug Song
+ * Dongsheng Song
+ * Hannes Sowa
+ * Joakim Soderberg
+ * Joseph Spadavecchia
+ * Kevin Springborn
+ * Harlan Stenn
+ * Andrew Sweeney
+ * Ferenc Szalai
+ * Brodie Thiesfield
+ * Jason Toffaletti
+ * Brian Utterback
+ * Gisle Vanem
+ * Bas Verhoeven
+ * Constantine Verutin
+ * Colin Watt
+ * Zack Weinberg
+ * Jardel Weyrich
+ * Jay R. Wren
+ * Zack Weinberg
+ * Mobai Zhang
+ * Alejo
+ * Alex
+ * Taral
+ * propanbutan
+ * masksqwe
+ * mmadia
+ * yangacer
+ * Andrey Skriabin
+ * basavesh.as
+ * billsegall
+ * Bill Vaughan
+ * Christopher Wiley
+ * David Paschich
+ * Ed Schouten
+ * Eduardo Panisset
+ * Jan Heylen
+ * jer-gentoo
+ * Joakim Söderberg
+ * kirillDanshin
+ * lzmths
+ * Marcus Sundberg
+ * Mark Mentovai
+ * Mattes D
+ * Matyas Dolak
+ * Neeraj Badlani
+ * Nick Mathewson
+ * Rainer Keller
+ * Seungmo Koo
+ * Thomas Bernard
+ * Xiao Bao Clark
+ * zeliard
+ * Zonr Chang
+ * Kurt Roeckx
+ * Seven
+ * Simone Basso
+ * Vlad Shcherban
+ * Tim Hentenaar
+
+If we have forgotten your name, please contact us.
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/VERSION b/fluent-bit/lib/monkey/mk_core/deps/libevent/VERSION
new file mode 100644
index 000000000..3774b6ba9
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/VERSION
@@ -0,0 +1,5 @@
+commit 68def4352c270fe597d3253b3e20cbe974e2f7d5
+Merge: 23f9a20 360aa23
+Author: Azat Khuzhin <a3at.mail@gmail.com>
+Date: Mon Dec 19 01:26:43 2016 +0300
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/Vagrantfile b/fluent-bit/lib/monkey/mk_core/deps/libevent/Vagrantfile
new file mode 100644
index 000000000..94b2831b0
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/Vagrantfile
@@ -0,0 +1,400 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# DESCRIPTION:
+# ============
+# Vagrant for running libevent tests with:
+# - timeout 30min, to avoid hungs
+# - run tests in parallel under ctest (10 concurency)
+# - if you have uncommited changes, you should commit them first to check
+# - unix only, because of some tar'ing to avoid one vm affect another
+#
+# ENVIRONMENT:
+# ============
+# - NO_PKG -- do not install packages
+# - NO_CMAKE -- do not run with cmake
+# - NO_AUTOTOOLS -- do not run with autoconf/automake
+
+Vagrant.configure("2") do |config|
+ # to allow running boxes provisions in parallel, we can't share the same dirs
+ # via virtualbox, however sometimes it is the only way, so instead let's
+ # create an archive of HEAD (this way we will not have any trash there) and
+ # extract it for every box to the separate folder.
+ #
+ # P.S. we will change this --prefix with tar(1) --trasnform
+ system('git archive --prefix=libevent/ --output=.vagrant/libevent.tar HEAD')
+
+ config.vm.provider "virtualbox" do |vb|
+ vb.memory = "512"
+
+ # otherwise osx fails, anyway we do not need this
+ vb.customize ["modifyvm", :id, "--usb", "off"]
+ vb.customize ["modifyvm", :id, "--usbehci", "off"]
+ end
+
+ # disable /vagrant share, in case we will not use default mount
+ config.vm.synced_folder ".", "/vagrant", disabled: true
+
+ config.vm.define "ubuntu" do |ubuntu|
+ system('tar --overwrite --transform=s/libevent/libevent-linux/ -xf .vagrant/libevent.tar -C .vagrant/')
+
+ ubuntu.vm.box = "ubuntu/xenial64"
+ ubuntu.vm.synced_folder ".vagrant/libevent-linux", "/vagrant",
+ type: "rsync"
+
+ if ENV['NO_PKG'] != "true"
+ ubuntu.vm.provision "shell", inline: <<-SHELL
+ apt-get update
+ apt-get install -y zlib1g-dev libssl-dev python2.7
+ apt-get install -y build-essential cmake ninja-build
+ apt-get install -y autoconf automake libtool
+ SHELL
+ end
+
+ if ENV['NO_CMAKE'] != "true"
+ ubuntu.vm.provision "shell", privileged: false, inline: <<-SHELL
+ cd /vagrant
+ rm -fr .cmake-vagrant
+ mkdir -p .cmake-vagrant
+ cd .cmake-vagrant
+ cmake -G Ninja ..
+
+ export CTEST_TEST_TIMEOUT=1800
+ export CTEST_OUTPUT_ON_FAILURE=1
+ export CTEST_PARALLEL_LEVEL=10
+ cmake --build . --target verify
+ SHELL
+ end
+
+ if ENV['NO_AUTOTOOLS'] != "true"
+ ubuntu.vm.provision "shell", privileged: false, inline: <<-SHELL
+ cd /vagrant
+ ./autogen.sh
+ ./configure
+ make -j4 verify
+ SHELL
+ end
+ end
+
+ config.vm.define "freebsd" do |freebsd|
+ system('tar --overwrite --transform=s/libevent/libevent-freebsd/ -xf .vagrant/libevent.tar -C .vagrant/')
+
+ freebsd.vm.box = "freebsd/FreeBSD-11.0-STABLE"
+ freebsd.vm.synced_folder ".vagrant/libevent-freebsd", "/vagrant",
+ type: "rsync", group: "wheel"
+
+ # otherwise reports error
+ freebsd.ssh.shell = "sh"
+
+ if ENV['NO_PKG'] != "true"
+ freebsd.vm.provision "shell", inline: <<-SHELL
+ pkg install --yes openssl cmake ninja automake autotools
+ SHELL
+ end
+
+ if ENV['NO_CMAKE'] != "true"
+ freebsd.vm.provision "shell", privileged: false, inline: <<-SHELL
+ cd /vagrant
+ rm -fr .cmake-vagrant
+ mkdir -p .cmake-vagrant
+ cd .cmake-vagrant
+ cmake -G Ninja ..
+
+ export CTEST_TEST_TIMEOUT=1800
+ export CTEST_OUTPUT_ON_FAILURE=1
+ export CTEST_PARALLEL_LEVEL=10
+ cmake --build . --target verify
+ SHELL
+ end
+
+ if ENV['NO_AUTOTOOLS'] != "true"
+ freebsd.vm.provision "shell", privileged: false, inline: <<-SHELL
+ cd /vagrant
+ ./autogen.sh
+ ./configure
+ make -j4 verify
+ SHELL
+ end
+ end
+
+ config.vm.define "netbsd" do |netbsd|
+ system('tar --overwrite --transform=s/libevent/libevent-netbsd/ -xf .vagrant/libevent.tar -C .vagrant/')
+
+ netbsd.vm.box = "kja/netbsd-7-amd64"
+ netbsd.vm.synced_folder ".vagrant/libevent-netbsd", "/vagrant",
+ type: "rsync", group: "wheel"
+
+ # TODO: more reliable way to install packages
+ if ENV['NO_PKG'] != "true"
+ netbsd.vm.provision "shell", inline: <<-SHELL
+ pkg_add ftp://ftp.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/7.0_2016Q2/All/ncurses-6.0nb1.tgz
+ pkg_add ftp://ftp.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/7.0_2016Q2/All/ninja-build-1.7.1.tgz
+ pkg_add ftp://ftp.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/7.0_2016Q2/All/automake-1.15nb3.tgz
+ pkg_add ftp://ftp.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/7.0_2016Q2/All/cmake-3.5.2.tgz
+ SHELL
+ end
+
+ if ENV['NO_CMAKE'] != "true"
+ netbsd.vm.provision "shell", privileged: false, inline: <<-SHELL
+ cd /vagrant
+ rm -fr .cmake-vagrant
+ mkdir -p .cmake-vagrant
+ cd .cmake-vagrant
+ cmake -G Ninja ..
+
+ export CTEST_TEST_TIMEOUT=1800
+ export CTEST_OUTPUT_ON_FAILURE=1
+ export CTEST_PARALLEL_LEVEL=10
+ cmake --build . --target verify
+ SHELL
+ end
+
+ if ENV['NO_AUTOTOOLS'] != "true"
+ netbsd.vm.provision "shell", privileged: false, inline: <<-SHELL
+ cd /vagrant
+ ./autogen.sh
+ ./configure
+ make -j4 verify
+ SHELL
+ end
+ end
+
+ config.vm.define "solaris" do |solaris|
+ system('tar --overwrite --transform=s/libevent/libevent-solaris/ -xf .vagrant/libevent.tar -C .vagrant/')
+
+ # XXX:
+ # - solaris do not have '-or' it only has '-o' for find(1), so we can't use
+ # rsync
+ # - and autoconf(1) doesn't work on virtualbox share, ugh
+ solaris.vm.synced_folder ".vagrant/libevent-solaris", "/vagrant-vbox",
+ type: "virtualbox"
+
+ solaris.vm.box = "tnarik/solaris10-minimal"
+ if ENV['NO_PKG'] != "true"
+ # TODO: opencsw does not include ninja(1)
+ solaris.vm.provision "shell", inline: <<-SHELL
+ pkgadd -d http://get.opencsw.org/now
+ pkgutil -U
+ pkgutil -y -i libssl_dev cmake rsync python gmake gcc5core automake autoconf libtool
+ SHELL
+ end
+
+ # copy from virtualbox mount to newly created folder
+ solaris.vm.provision "shell", privileged: false, inline: <<-SHELL
+ rm -fr ~/vagrant
+ cp -r /vagrant-vbox ~/vagrant
+ SHELL
+
+ if ENV['NO_CMAKE'] != "true"
+ # builtin compiler cc(1) is a wrapper, so we should use gcc5 manually,
+ # otherwise it will not work.
+ # Plus we should set some paths so that cmake/compiler can find tham.
+ solaris.vm.provision "shell", privileged: false, inline: <<-SHELL
+ export CMAKE_INCLUDE_PATH=/opt/csw/include
+ export CMAKE_LIBRARY_PATH=/opt/csw/lib
+ export CFLAGS=-I$CMAKE_INCLUDE_PATH
+ export LDFLAGS=-L$CMAKE_LIBRARY_PATH
+
+ cd ~/vagrant
+ rm -rf .cmake-vagrant
+ mkdir -p .cmake-vagrant
+ cd .cmake-vagrant
+ cmake -DCMAKE_C_COMPILER=gcc ..
+
+ export CTEST_TEST_TIMEOUT=1800
+ export CTEST_OUTPUT_ON_FAILURE=1
+ export CTEST_PARALLEL_LEVEL=10
+ cmake --build . --target verify
+ SHELL
+ end
+
+ if ENV['NO_AUTOTOOLS'] != "true"
+ # and we should set MAKE for `configure` otherwise it will try to use
+ # `make`
+ solaris.vm.provision "shell", privileged: false, inline: <<-SHELL
+ cd ~/vagrant
+ ./autogen.sh
+ MAKE=gmake ./configure
+ gmake -j4 verify
+ SHELL
+ end
+ end
+
+ # known failures:
+ # - sometimes vm hangs
+ config.vm.define "osx" do |osx|
+ system('tar --overwrite --transform=s/libevent/libevent-osx/ -xf .vagrant/libevent.tar -C .vagrant/')
+
+ osx.vm.synced_folder ".vagrant/libevent-osx", "/vagrant",
+ type: "rsync", group: "wheel"
+
+ osx.vm.box = "jhcook/osx-elcapitan-10.11"
+ if ENV['NO_PKG'] != "true"
+ osx.vm.provision "shell", privileged: false, inline: <<-SHELL
+ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
+
+ brew uninstall libtool
+ brew install libtool openssl ninja cmake autoconf automake
+ SHELL
+ end
+
+ if ENV['NO_CMAKE'] != "true"
+ # we should set some paths so that cmake/compiler can find tham
+ osx.vm.provision "shell", privileged: false, inline: <<-SHELL
+ export OPENSSL_ROOT=$(echo /usr/local/Cellar/openssl/*)
+ export CMAKE_INCLUDE_PATH=$OPENSSL_ROOT/include
+ export CMAKE_LIBRARY_PATH=$OPENSSL_ROOT/lib
+
+ cd /vagrant
+ mkdir -p .cmake-vagrant
+ cd .cmake-vagrant
+ cmake -G Ninja ..
+
+ export CTEST_TEST_TIMEOUT=1800
+ export CTEST_OUTPUT_ON_FAILURE=1
+ export CTEST_PARALLEL_LEVEL=10
+ cmake --build . --target verify
+ SHELL
+ end
+
+ if ENV['NO_AUTOTOOLS'] != "true"
+ osx.vm.provision "shell", privileged: false, inline: <<-SHELL
+ export OPENSSL_ROOT=$(echo /usr/local/Cellar/openssl/*)
+ export CFLAGS=-I$OPENSSL_ROOT/include
+ export LDFLAGS=-L$OPENSSL_ROOT/lib
+
+ cd /vagrant
+ ./autogen.sh
+ ./configure
+ make -j4 verify
+ SHELL
+ end
+ end
+
+ config.vm.define "centos" do |centos|
+ system('tar --overwrite --transform=s/libevent/libevent-centos/ -xf .vagrant/libevent.tar -C .vagrant/')
+
+ centos.vm.synced_folder ".vagrant/libevent-centos", "/vagrant",
+ type: "rsync", group: "wheel"
+
+ centos.vm.box = "centos/7"
+ if ENV['NO_PKG'] != "true"
+ centos.vm.provision "shell", inline: <<-SHELL
+ echo "[russianfedora]" > /etc/yum.repos.d/russianfedora.repo
+ echo name=russianfedora >> /etc/yum.repos.d/russianfedora.repo
+ echo baseurl=http://mirror.yandex.ru/fedora/russianfedora/russianfedora/free/el/releases/7/Everything/x86_64/os/ >> /etc/yum.repos.d/russianfedora.repo
+ echo enabled=1 >> /etc/yum.repos.d/russianfedora.repo
+ echo gpgcheck=0 >> /etc/yum.repos.d/russianfedora.repo
+ SHELL
+ centos.vm.provision "shell", inline: <<-SHELL
+ yum -y install zlib-devel openssl-devel python
+ yum -y install gcc cmake ninja-build
+ yum -y install autoconf automake libtool
+ SHELL
+ end
+
+ if ENV['NO_CMAKE'] != "true"
+ centos.vm.provision "shell", privileged: false, inline: <<-SHELL
+ cd /vagrant
+ rm -fr .cmake-vagrant
+ mkdir -p .cmake-vagrant
+ cd .cmake-vagrant
+ cmake -G Ninja ..
+
+ export CTEST_TEST_TIMEOUT=1800
+ export CTEST_OUTPUT_ON_FAILURE=1
+ export CTEST_PARALLEL_LEVEL=10
+ cmake --build . --target verify
+ SHELL
+ end
+
+ if ENV['NO_AUTOTOOLS'] != "true"
+ centos.vm.provision "shell", privileged: false, inline: <<-SHELL
+ cd /vagrant
+ ./autogen.sh
+ ./configure
+ make -j4 verify
+ SHELL
+ end
+ end
+
+ # known failures:
+ # - issues with timers (not enough allowed error)
+ config.vm.define "win" do |win|
+ system('tar --overwrite --transform=s/libevent/libevent-win/ -xf .vagrant/libevent.tar -C .vagrant/')
+
+ # 512MB not enough after libtool install, huh
+ win.vm.provider "virtualbox" do |vb|
+ vb.memory = "1024"
+ end
+
+ # windows does not have rsync builtin, let's use virtualbox for now
+ win.vm.synced_folder ".vagrant/libevent-win", "/vagrant",
+ type: "virtualbox"
+
+ win.vm.box = "senglin/win-10-enterprise-vs2015community"
+ if ENV['NO_PKG'] != "true"
+ # box with vs2015 does not have C++ support, so let's install it manually
+ # plus chocolatey that includes in this box, can't handle sha1 checksum for
+ # cmake.install, so let's update it<
+ win.vm.provision "shell", inline: <<-SHELL
+ choco upgrade -y chocolatey -pre -f
+ choco install -y VisualStudioCommunity2013
+ choco install -y openssl.light
+ choco install -y cygwin cyg-get
+ choco install -y cmake
+ choco install -y cmake.install
+ choco install -y python2
+ SHELL
+
+ # chocolatey openssl.light package does not contains headers
+ win.vm.provision "shell", inline: <<-SHELL
+ (new-object System.Net.WebClient).DownloadFile('http://strcpy.net/packages/Win32OpenSSL-1_0_2a.exe', '/openssl.exe')
+ /openssl.exe /silent /verysilent /sp- /suppressmsgboxes
+ SHELL
+
+ # XXX:
+ # - cyg-get depends from cygwinsetup.exe
+ # https://github.com/chocolatey/chocolatey-coreteampackages/issues/200
+ # - cyg-get only downloads, do not installs them, ugh. so let's do not use
+ # it
+ win.vm.provision "shell", privileged: false, inline: <<-SHELL
+ (new-object System.Net.WebClient).DownloadFile('https://cygwin.com/setup-x86_64.exe', '/tools/cygwin/cygwinsetup.exe')
+
+ $env:PATH="/tools/cygwin/bin;$($env:PATH);/tools/cygwin"
+
+ cygwinsetup --root c:/tools/cygwin/ --local-package-dir c:/tools/cygwin/packages/ --no-desktop --no-startmenu --verbose --quiet-mode --download --packages automake,autoconf,gcc-core,libtool,make,python,openssl-devel
+ cygwinsetup --root c:/tools/cygwin/ --local-package-dir c:/tools/cygwin/packages/ --no-desktop --no-startmenu --verbose --quiet-mode --local-install --packages automake,autoconf,gcc-core,libtool,make,python,openssl-devel
+ SHELL
+ end
+
+ if ENV['NO_CMAKE'] != "true"
+ win.vm.provision "shell", privileged: false, inline: <<-SHELL
+ $env:PATH="/Program Files/CMake/bin;/tools/python2;$($env:PATH)"
+
+ cd /vagrant
+ Remove-Item -Recurse -Force .cmake-vagrant
+ mkdir -p .cmake-vagrant
+ cd .cmake-vagrant
+ cmake -G "Visual Studio 12" ..
+
+ $env:CTEST_TEST_TIMEOUT = "1800"
+ $env:CTEST_OUTPUT_ON_FAILURE = "1"
+ $env:CTEST_PARALLEL_LEVEL = "10"
+ cmake --build . --target verify
+ SHELL
+ end
+
+ if ENV['NO_AUTOTOOLS'] != "true"
+ win.vm.provision "shell", privileged: false, inline: <<-SHELL
+ $env:PATH="/tools/cygwin/bin;$($env:PATH)"
+
+ bash -lc "echo 'C:/tools/mingw64 /mingw ntfs binary 0 0' > /etc/fstab"
+ bash -lc "echo 'C:/OpenSSL-Win32 /ssl ntfs binary 0 0' >> /etc/fstab"
+ bash -lc "echo 'C:/vagrant /vagrant ntfs binary 0 0' >> /etc/fstab"
+
+ bash -lc "exec 0</dev/null; exec 2>&1; cd /vagrant; bash -x ./autogen.sh && ./configure LDFLAGS='-L/ssl -L/ssl/lib -L/ssl/lib/MinGW' CFLAGS=-I/ssl/include && make -j4 verify"
+ SHELL
+ end
+ end
+end
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/getopt.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/getopt.c
new file mode 100644
index 000000000..0fcba5d91
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/getopt.c
@@ -0,0 +1,149 @@
+/* $NetBSD: getopt.c,v 1.16 1999/12/02 13:15:56 kleink Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if 0
+static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#define __P(x) x
+#define _DIAGASSERT(x) assert(x)
+
+#ifdef __weak_alias
+__weak_alias(getopt,_getopt);
+#endif
+
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+static char * _progname __P((char *));
+int getopt_internal __P((int, char * const *, const char *));
+
+static char *
+_progname(nargv0)
+ char * nargv0;
+{
+ char * tmp;
+
+ _DIAGASSERT(nargv0 != NULL);
+
+ tmp = strrchr(nargv0, '/');
+ if (tmp)
+ tmp++;
+ else
+ tmp = nargv0;
+ return(tmp);
+}
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt(nargc, nargv, ostr)
+ int nargc;
+ char * const nargv[];
+ const char *ostr;
+{
+ static char *__progname = 0;
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+ __progname = __progname?__progname:_progname(*nargv);
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(ostr != NULL);
+
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return (-1);
+ }
+ if (place[1] && *++place == '-' /* found "--" */
+ && place[1] == '\0') {
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (optopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", __progname, optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ __progname, optopt);
+ return (BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* dump back option letter */
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/getopt.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/getopt.h
new file mode 100644
index 000000000..796f45505
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/getopt.h
@@ -0,0 +1,33 @@
+#ifndef __GETOPT_H__
+#define __GETOPT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int opterr; /* if error message should be printed */
+extern int optind; /* index into parent argv vector */
+extern int optopt; /* character checked for validity */
+extern int optreset; /* reset getopt */
+extern char *optarg; /* argument associated with option */
+
+struct option
+{
+ const char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+int getopt(int, char**, const char*);
+int getopt_long(int, char**, const char*, const struct option*, int*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GETOPT_H__ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/getopt_long.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/getopt_long.c
new file mode 100644
index 000000000..03f0c01a1
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/getopt_long.c
@@ -0,0 +1,233 @@
+
+/*
+ * Copyright (c) 1987, 1993, 1994, 1996
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "getopt.h"
+
+extern int opterr; /* if error message should be printed */
+extern int optind; /* index into parent argv vector */
+extern int optopt; /* character checked for validity */
+extern int optreset; /* reset getopt */
+extern char *optarg; /* argument associated with option */
+
+#define __P(x) x
+#define _DIAGASSERT(x) assert(x)
+
+static char * __progname __P((char *));
+int getopt_internal __P((int, char * const *, const char *));
+
+static char *
+__progname(nargv0)
+ char * nargv0;
+{
+ char * tmp;
+
+ _DIAGASSERT(nargv0 != NULL);
+
+ tmp = strrchr(nargv0, '/');
+ if (tmp)
+ tmp++;
+ else
+ tmp = nargv0;
+ return(tmp);
+}
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_internal(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(ostr != NULL);
+
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return (-1);
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ /* ++optind; */
+ place = EMSG;
+ return (-2);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (optopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", __progname(nargv[0]), optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ } else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if ((opterr) && (*ostr != ':'))
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ __progname(nargv[0]), optopt);
+ return (BADARG);
+ } else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* dump back option letter */
+}
+
+#if 0
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt2(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ int retval;
+
+ if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) {
+ retval = -1;
+ ++optind;
+ }
+ return(retval);
+}
+#endif
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(nargc, nargv, options, long_options, index)
+ int nargc;
+ char ** nargv;
+ const char * options;
+ const struct option * long_options;
+ int * index;
+{
+ int retval;
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(options != NULL);
+ _DIAGASSERT(long_options != NULL);
+ /* index may be NULL */
+
+ if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
+ char *current_argv = nargv[optind++] + 2, *has_equal;
+ int i, current_argv_len, match = -1;
+
+ if (*current_argv == '\0') {
+ return(-1);
+ }
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ if (strncmp(current_argv, long_options[i].name, current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == (unsigned)current_argv_len) {
+ match = i;
+ break;
+ }
+ if (match == -1)
+ match = i;
+ }
+ if (match != -1) {
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else
+ optarg = nargv[optind++];
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument, leading :
+ * indicates no error should be generated
+ */
+ if ((opterr) && (*options != ':'))
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %s\n",
+ __progname(nargv[0]), current_argv);
+ return (BADARG);
+ }
+ } else { /* No matching argument */
+ if ((opterr) && (*options != ':'))
+ (void)fprintf(stderr,
+ "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv);
+ return (BADCH);
+ }
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ retval = 0;
+ } else
+ retval = long_options[match].val;
+ if (index)
+ *index = match;
+ }
+ return(retval);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/nmake/evconfig-private.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/nmake/evconfig-private.h
new file mode 100644
index 000000000..88e206272
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/nmake/evconfig-private.h
@@ -0,0 +1,6 @@
+#if !defined(EVENT_EVCONFIG__PRIVATE_H_) && !defined(__MINGW32__)
+#define EVENT_EVCONFIG__PRIVATE_H_
+
+/* Nothing to see here. Move along. */
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/nmake/event2/event-config.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/nmake/event2/event-config.h
new file mode 100644
index 000000000..d96dfba1d
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/nmake/event2/event-config.h
@@ -0,0 +1,360 @@
+/* event2/event-config.h
+ *
+ * This file was generated by autoconf when libevent was built, and post-
+ * processed by Libevent so that its macros would have a uniform prefix.
+ *
+ * DO NOT EDIT THIS FILE.
+ *
+ * Do not rely on macros in this file existing in later versions.
+ */
+#ifndef EVENT_CONFIG_H__
+#define EVENT_CONFIG_H__
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define if libevent should not allow replacing the mm functions */
+/* #undef EVENT__DISABLE_MM_REPLACEMENT */
+
+/* Define if libevent should not be compiled with thread support */
+/* #undef EVENT__DISABLE_THREAD_SUPPORT */
+
+/* Define if clock_gettime is available in libc */
+/* #undef _EVENT_DNS_USE_CPU_CLOCK_FOR_ID */
+
+/* Define is no secure id variant is available */
+/* #define _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID 1 */
+#define EVENT_DNS_USE_FTIME_FOR_ID_ 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+/* #undef EVENT__HAVE_ARPA_INET_H */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+/* #undef EVENT__HAVE_CLOCK_GETTIME */
+
+/* Define if /dev/poll is available */
+/* #undef EVENT__HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #undef EVENT__HAVE_DLFCN_H */
+
+/* Define if your system supports the epoll system calls */
+/* #undef EVENT__HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef EVENT__HAVE_EPOLL_CTL */
+
+/* Define to 1 if you have the `eventfd' function. */
+/* #undef EVENT__HAVE_EVENTFD */
+
+/* Define if your system supports event ports */
+/* #undef EVENT__HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+/* #undef EVENT__HAVE_FCNTL */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define EVENT__HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define EVENT__HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define EVENT__HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getprotobynumber' function. */
+#define EVENT__HAVE_GETPROTOBYNUMBER 1
+
+/* Define to 1 if you have the `getservbyname' function. */
+#define EVENT__HAVE_GETSERVBYNAME 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+/* #define EVENT__HAVE_GETTIMEOFDAY 1 */
+
+/* Define to 1 if you have the `inet_ntop' function. */
+/* #undef EVENT__HAVE_INET_NTOP */
+
+/* Define to 1 if you have the `inet_pton' function. */
+/* #undef EVENT__HAVE_INET_PTON */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+/* #define EVENT__HAVE_INTTYPES_H 1 */
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef EVENT__HAVE_KQUEUE */
+
+/* Define if the system has zlib */
+/* #undef EVENT__HAVE_LIBZ */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define EVENT__HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mmap' function. */
+/* #undef EVENT__HAVE_MMAP */
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef EVENT__HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+/* #undef EVENT__HAVE_NETINET_IN_H */
+
+/* Define to 1 if you have the `pipe' function. */
+/* #undef EVENT__HAVE_PIPE */
+
+/* Define to 1 if you have the `poll' function. */
+/* #undef EVENT__HAVE_POLL */
+
+/* Define to 1 if you have the <poll.h> header file. */
+/* #undef EVENT__HAVE_POLL_H */
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef EVENT__HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef EVENT__HAVE_PORT_H */
+
+/* Define if you have POSIX threads libraries and header files. */
+/* #undef EVENT__HAVE_PTHREAD */
+
+/* Define if we have pthreads on this system */
+/* #undef EVENT__HAVE_PTHREADS */
+
+/* Define to 1 if the system has the type `sa_family_t'. */
+/* #undef EVENT__HAVE_SA_FAMILY_T */
+
+/* Define to 1 if you have the `select' function. */
+/* #undef EVENT__HAVE_SELECT */
+
+/* Define to 1 if you have the `sendfile' function. */
+/* #undef EVENT__HAVE_SENDFILE */
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+/* #undef EVENT__HAVE_SETFD */
+
+/* Define to 1 if you have the `sigaction' function. */
+/* #undef EVENT__HAVE_SIGACTION */
+
+/* Define to 1 if you have the `signal' function. */
+#define EVENT__HAVE_SIGNAL 1
+
+/* Define to 1 if you have the `splice' function. */
+/* #undef EVENT__HAVE_SPLICE */
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define EVENT__HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#define EVENT__HAVE_STDDEF_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+/* #define EVENT__HAVE_STDINT_H 1 */
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define EVENT__HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define EVENT__HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define EVENT__HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef EVENT__HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strsep' function. */
+/* #undef EVENT__HAVE_STRSEP */
+
+/* Define to 1 if you have the `strtok_r' function. */
+/* #undef EVENT__HAVE_STRTOK_R */
+
+/* Define to 1 if you have the `strtoll' function. */
+/* #define EVENT__HAVE_STRTOLL 1 */
+
+#define EVENT__HAVE_STRUCT_ADDRINFO 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define EVENT__HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if `s6_addr16' is member of `struct in6_addr'. */
+#define EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR16 1
+
+/* Define to 1 if `s6_addr32' is member of `struct in6_addr'. */
+#define EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR32 1
+
+/* Define to 1 if the system has the type `struct sockaddr_in6'. */
+#define EVENT__HAVE_STRUCT_SOCKADDR_IN6 1
+
+/* Define to 1 if `sin6_len' is member of `struct sockaddr_in6'. */
+/* #undef EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN */
+
+/* Define to 1 if `sin_len' is member of `struct sockaddr_in'. */
+/* #undef EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
+
+/* Define to 1 if the system has the type `struct sockaddr_storage'. */
+#define EVENT__HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef EVENT__HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef EVENT__HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/eventfd.h> header file. */
+/* #undef EVENT__HAVE_SYS_EVENTFD_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef EVENT__HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+/* #undef EVENT__HAVE_SYS_IOCTL_H */
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+/* #undef EVENT__HAVE_SYS_MMAN_H */
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+/* #define EVENT__HAVE_SYS_PARAM_H 1 */
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+/* #undef EVENT__HAVE_SYS_QUEUE_H */
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+/* #undef EVENT__HAVE_SYS_SELECT_H */
+
+/* Define to 1 if you have the <sys/sendfile.h> header file. */
+/* #undef EVENT__HAVE_SYS_SENDFILE_H */
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+/* #undef EVENT__HAVE_SYS_SOCKET_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define EVENT__HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+/* #define EVENT__HAVE_SYS_TIME_H 1 */
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define EVENT__HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+/* #undef EVENT__HAVE_SYS_UIO_H */
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+/* #undef EVENT__HAVE_TAILQFOREACH */
+
+/* Define if timeradd is defined in <sys/time.h> */
+/* #undef EVENT__HAVE_TIMERADD */
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define EVENT__HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define EVENT__HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define EVENT__HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+/* #define EVENT__HAVE_UINT16_T 1 */
+
+/* Define to 1 if the system has the type `uint32_t'. */
+/* #define EVENT__HAVE_UINT32_T 1 */
+
+/* Define to 1 if the system has the type `uint64_t'. */
+/* #define EVENT__HAVE_UINT64_T 1 */
+
+/* Define to 1 if the system has the type `uint8_t'. */
+/* #define EVENT__HAVE_UINT8_T 1 */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+/* #define EVENT__HAVE_UNISTD_H 1 */
+
+/* Define to 1 if you have the `vasprintf' function. */
+/* #undef EVENT__HAVE_VASPRINTF */
+
+/* Define if kqueue works correctly with pipes */
+/* #undef EVENT__HAVE_WORKING_KQUEUE */
+
+/* Numeric representation of the version */
+#define EVENT__NUMERIC_VERSION 0x02010700
+
+/* Name of package */
+#define EVENT__PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define EVENT__PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define EVENT__PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define EVENT__PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define EVENT__PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define EVENT__PACKAGE_VERSION ""
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+/* #undef EVENT__PTHREAD_CREATE_JOINABLE */
+
+/* The size of a `int', as computed by sizeof. */
+#define EVENT__SIZEOF_INT 4
+
+/* The size of a `long', as computed by sizeof. */
+#define EVENT__SIZEOF_LONG 4
+
+/* The size of a `long long', as computed by sizeof. */
+#define EVENT__SIZEOF_LONG_LONG 8
+
+/* The size of a `short', as computed by sizeof. */
+#define EVENT__SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#ifdef _WIN64
+#define EVENT__SIZEOF_SIZE_T 8
+#else
+#define EVENT__SIZEOF_SIZE_T 4
+#endif
+
+/* The size of `void *', as computed by sizeof. */
+#ifdef _WIN64
+#define EVENT__SIZEOF_VOID_P 8
+#else
+#define EVENT__SIZEOF_VOID_P 4
+#endif
+
+/* Define to 1 if you have the ANSI C header files. */
+#define EVENT__STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define EVENT__TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define EVENT__VERSION "2.1.7-beta"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+#define EVENT____func__ __FUNCTION__
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef EVENT__const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef _EVENT___cplusplus
+#define EVENT__inline __inline
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef EVENT__pid_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef EVENT__size_t */
+
+/* Define to unsigned int if you dont have it */
+#define EVENT__socklen_t unsigned int
+
+/* Define to `int' if <sys/types.h> does not define. */
+#define EVENT__ssize_t SSIZE_T
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/tree.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/tree.h
new file mode 100644
index 000000000..2ccfbf20a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/WIN32-Code/tree.h
@@ -0,0 +1,677 @@
+/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_TREE_H_
+#define _SYS_TREE_H_
+
+/*
+ * This file defines data structures for different types of trees:
+ * splay trees and red-black trees.
+ *
+ * A splay tree is a self-organizing data structure. Every operation
+ * on the tree causes a splay to happen. The splay moves the requested
+ * node to the root of the tree and partly rebalances it.
+ *
+ * This has the benefit that request locality causes faster lookups as
+ * the requested nodes move to the top of the tree. On the other hand,
+ * every lookup causes memory writes.
+ *
+ * The Balance Theorem bounds the total access time for m operations
+ * and n inserts on an initially empty tree as O((m + n)lg n). The
+ * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
+ *
+ * A red-black tree is a binary search tree with the node color as an
+ * extra attribute. It fulfills a set of conditions:
+ * - every search path from the root to a leaf consists of the
+ * same number of black nodes,
+ * - each red node (except for the root) has a black parent,
+ * - each leaf node is black.
+ *
+ * Every operation on a red-black tree is bounded as O(lg n).
+ * The maximum height of a red-black tree is 2lg (n+1).
+ */
+
+#define SPLAY_HEAD(name, type) \
+struct name { \
+ struct type *sph_root; /* root of the tree */ \
+}
+
+#define SPLAY_INITIALIZER(root) \
+ { NULL }
+
+#define SPLAY_INIT(root) do { \
+ (root)->sph_root = NULL; \
+} while (0)
+
+#define SPLAY_ENTRY(type) \
+struct { \
+ struct type *spe_left; /* left element */ \
+ struct type *spe_right; /* right element */ \
+}
+
+#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
+#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
+#define SPLAY_ROOT(head) (head)->sph_root
+#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
+
+/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
+#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (0)
+
+#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (0)
+
+#define SPLAY_LINKLEFT(head, tmp, field) do { \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+} while (0)
+
+#define SPLAY_LINKRIGHT(head, tmp, field) do { \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+} while (0)
+
+#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
+ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
+} while (0)
+
+/* Generates prototypes and inline functions */
+
+#define SPLAY_PROTOTYPE(name, type, field, cmp) \
+void name##_SPLAY(struct name *, struct type *); \
+void name##_SPLAY_MINMAX(struct name *, int); \
+struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
+struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
+ \
+/* Finds the node with the same key as elm */ \
+static __inline struct type * \
+name##_SPLAY_FIND(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) \
+ return(NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) \
+ return (head->sph_root); \
+ return (NULL); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_NEXT(struct name *head, struct type *elm) \
+{ \
+ name##_SPLAY(head, elm); \
+ if (SPLAY_RIGHT(elm, field) != NULL) { \
+ elm = SPLAY_RIGHT(elm, field); \
+ while (SPLAY_LEFT(elm, field) != NULL) { \
+ elm = SPLAY_LEFT(elm, field); \
+ } \
+ } else \
+ elm = NULL; \
+ return (elm); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_MIN_MAX(struct name *head, int val) \
+{ \
+ name##_SPLAY_MINMAX(head, val); \
+ return (SPLAY_ROOT(head)); \
+}
+
+/* Main splay operation.
+ * Moves node close to the key of elm to top
+ */
+#define SPLAY_GENERATE(name, type, field, cmp) \
+struct type * \
+name##_SPLAY_INSERT(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) { \
+ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
+ } else { \
+ int __comp; \
+ name##_SPLAY(head, elm); \
+ __comp = (cmp)(elm, (head)->sph_root); \
+ if(__comp < 0) { \
+ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
+ SPLAY_RIGHT(elm, field) = (head)->sph_root; \
+ SPLAY_LEFT((head)->sph_root, field) = NULL; \
+ } else if (__comp > 0) { \
+ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
+ SPLAY_LEFT(elm, field) = (head)->sph_root; \
+ SPLAY_RIGHT((head)->sph_root, field) = NULL; \
+ } else \
+ return ((head)->sph_root); \
+ } \
+ (head)->sph_root = (elm); \
+ return (NULL); \
+} \
+ \
+struct type * \
+name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *__tmp; \
+ if (SPLAY_EMPTY(head)) \
+ return (NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) { \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
+ } else { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
+ name##_SPLAY(head, elm); \
+ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
+ } \
+ return (elm); \
+ } \
+ return (NULL); \
+} \
+ \
+void \
+name##_SPLAY(struct name *head, struct type *elm) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+ int __comp; \
+\
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+ __left = __right = &__node; \
+\
+ while ((__comp = (cmp)(elm, (head)->sph_root))) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) > 0){ \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+} \
+ \
+/* Splay with either the minimum or the maximum element \
+ * Used to find minimum or maximum element in tree. \
+ */ \
+void name##_SPLAY_MINMAX(struct name *head, int __comp) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+\
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+ __left = __right = &__node; \
+\
+ while (1) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp > 0) { \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+}
+
+#define SPLAY_NEGINF -1
+#define SPLAY_INF 1
+
+#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
+#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
+#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
+#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
+#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
+#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
+
+#define SPLAY_FOREACH(x, name, head) \
+ for ((x) = SPLAY_MIN(name, head); \
+ (x) != NULL; \
+ (x) = SPLAY_NEXT(name, head, x))
+
+/* Macros that define a red-back tree */
+#define RB_HEAD(name, type) \
+struct name { \
+ struct type *rbh_root; /* root of the tree */ \
+}
+
+#define RB_INITIALIZER(root) \
+ { NULL }
+
+#define RB_INIT(root) do { \
+ (root)->rbh_root = NULL; \
+} while (0)
+
+#define RB_BLACK 0
+#define RB_RED 1
+#define RB_ENTRY(type) \
+struct { \
+ struct type *rbe_left; /* left element */ \
+ struct type *rbe_right; /* right element */ \
+ struct type *rbe_parent; /* parent element */ \
+ int rbe_color; /* node color */ \
+}
+
+#define RB_LEFT(elm, field) (elm)->field.rbe_left
+#define RB_RIGHT(elm, field) (elm)->field.rbe_right
+#define RB_PARENT(elm, field) (elm)->field.rbe_parent
+#define RB_COLOR(elm, field) (elm)->field.rbe_color
+#define RB_ROOT(head) (head)->rbh_root
+#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
+
+#define RB_SET(elm, parent, field) do { \
+ RB_PARENT(elm, field) = parent; \
+ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
+ RB_COLOR(elm, field) = RB_RED; \
+} while (0)
+
+#define RB_SET_BLACKRED(black, red, field) do { \
+ RB_COLOR(black, field) = RB_BLACK; \
+ RB_COLOR(red, field) = RB_RED; \
+} while (0)
+
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x)
+#endif
+
+#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
+ (tmp) = RB_RIGHT(elm, field); \
+ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \
+ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_LEFT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (0)
+
+#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
+ (tmp) = RB_LEFT(elm, field); \
+ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \
+ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_RIGHT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (0)
+
+/* Generates prototypes and inline functions */
+#define RB_PROTOTYPE(name, type, field, cmp) \
+void name##_RB_INSERT_COLOR(struct name *, struct type *); \
+void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
+struct type *name##_RB_REMOVE(struct name *, struct type *); \
+struct type *name##_RB_INSERT(struct name *, struct type *); \
+struct type *name##_RB_FIND(struct name *, struct type *); \
+struct type *name##_RB_NEXT(struct type *); \
+struct type *name##_RB_MINMAX(struct name *, int); \
+ \
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
+#define RB_GENERATE(name, type, field, cmp) \
+void \
+name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
+{ \
+ struct type *parent, *gparent, *tmp; \
+ while ((parent = RB_PARENT(elm, field)) && \
+ RB_COLOR(parent, field) == RB_RED) { \
+ gparent = RB_PARENT(parent, field); \
+ if (parent == RB_LEFT(gparent, field)) { \
+ tmp = RB_RIGHT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_RIGHT(parent, field) == elm) { \
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_RIGHT(head, gparent, tmp, field); \
+ } else { \
+ tmp = RB_LEFT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_LEFT(parent, field) == elm) { \
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_LEFT(head, gparent, tmp, field); \
+ } \
+ } \
+ RB_COLOR(head->rbh_root, field) = RB_BLACK; \
+} \
+ \
+void \
+name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
+{ \
+ struct type *tmp; \
+ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
+ elm != RB_ROOT(head)) { \
+ if (RB_LEFT(parent, field) == elm) { \
+ tmp = RB_RIGHT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
+ struct type *oleft; \
+ if ((oleft = RB_LEFT(tmp, field)))\
+ RB_COLOR(oleft, field) = RB_BLACK;\
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_RIGHT(head, tmp, oleft, field);\
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_RIGHT(tmp, field)) \
+ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } else { \
+ tmp = RB_LEFT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = RB_LEFT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
+ struct type *oright; \
+ if ((oright = RB_RIGHT(tmp, field)))\
+ RB_COLOR(oright, field) = RB_BLACK;\
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_LEFT(head, tmp, oright, field);\
+ tmp = RB_LEFT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_LEFT(tmp, field)) \
+ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } \
+ } \
+ if (elm) \
+ RB_COLOR(elm, field) = RB_BLACK; \
+} \
+ \
+struct type * \
+name##_RB_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *child, *parent, *old = elm; \
+ int color; \
+ if (RB_LEFT(elm, field) == NULL) \
+ child = RB_RIGHT(elm, field); \
+ else if (RB_RIGHT(elm, field) == NULL) \
+ child = RB_LEFT(elm, field); \
+ else { \
+ struct type *left; \
+ elm = RB_RIGHT(elm, field); \
+ while ((left = RB_LEFT(elm, field))) \
+ elm = left; \
+ child = RB_RIGHT(elm, field); \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+ if (RB_PARENT(elm, field) == old) \
+ parent = elm; \
+ (elm)->field = (old)->field; \
+ if (RB_PARENT(old, field)) { \
+ if (RB_LEFT(RB_PARENT(old, field), field) == old)\
+ RB_LEFT(RB_PARENT(old, field), field) = elm;\
+ else \
+ RB_RIGHT(RB_PARENT(old, field), field) = elm;\
+ RB_AUGMENT(RB_PARENT(old, field)); \
+ } else \
+ RB_ROOT(head) = elm; \
+ RB_PARENT(RB_LEFT(old, field), field) = elm; \
+ if (RB_RIGHT(old, field)) \
+ RB_PARENT(RB_RIGHT(old, field), field) = elm; \
+ if (parent) { \
+ left = parent; \
+ do { \
+ RB_AUGMENT(left); \
+ } while ((left = RB_PARENT(left, field))); \
+ } \
+ goto color; \
+ } \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+color: \
+ if (color == RB_BLACK) \
+ name##_RB_REMOVE_COLOR(head, parent, child); \
+ return (old); \
+} \
+ \
+/* Inserts a node into the RB tree */ \
+struct type * \
+name##_RB_INSERT(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp; \
+ struct type *parent = NULL; \
+ int comp = 0; \
+ tmp = RB_ROOT(head); \
+ while (tmp) { \
+ parent = tmp; \
+ comp = (cmp)(elm, parent); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ RB_SET(elm, parent, field); \
+ if (parent != NULL) { \
+ if (comp < 0) \
+ RB_LEFT(parent, field) = elm; \
+ else \
+ RB_RIGHT(parent, field) = elm; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = elm; \
+ name##_RB_INSERT_COLOR(head, elm); \
+ return (NULL); \
+} \
+ \
+/* Finds the node with the same key as elm */ \
+struct type * \
+name##_RB_FIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (NULL); \
+} \
+ \
+struct type * \
+name##_RB_NEXT(struct type *elm) \
+{ \
+ if (RB_RIGHT(elm, field)) { \
+ elm = RB_RIGHT(elm, field); \
+ while (RB_LEFT(elm, field)) \
+ elm = RB_LEFT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+struct type * \
+name##_RB_MINMAX(struct name *head, int val) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *parent = NULL; \
+ while (tmp) { \
+ parent = tmp; \
+ if (val < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else \
+ tmp = RB_RIGHT(tmp, field); \
+ } \
+ return (parent); \
+}
+
+#define RB_NEGINF -1
+#define RB_INF 1
+
+#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
+#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
+#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
+#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
+#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
+#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
+
+#define RB_FOREACH(x, name, head) \
+ for ((x) = RB_MIN(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_NEXT(x))
+
+#endif /* _SYS_TREE_H_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/appveyor.yml b/fluent-bit/lib/monkey/mk_core/deps/libevent/appveyor.yml
new file mode 100644
index 000000000..2b56b6333
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/appveyor.yml
@@ -0,0 +1,59 @@
+version: 2.1.7.{build}
+
+os: Visual Studio 2015
+
+build:
+ verbosity: detailed
+
+environment:
+ global:
+ CYG_ROOT: C:/MinGW/msys/1.0
+ matrix:
+ - EVENT_BUILD_METHOD: "autotools"
+ EVENT_CONFIGURE_OPTIONS: ""
+ - EVENT_BUILD_METHOD: "autotools"
+ EVENT_CONFIGURE_OPTIONS: "--disable-openssl"
+ - EVENT_BUILD_METHOD: "autotools"
+ EVENT_CONFIGURE_OPTIONS: "--disable-thread-support"
+ - EVENT_BUILD_METHOD: "autotools"
+ EVENT_CONFIGURE_OPTIONS: "--disable-debug-mode"
+ - EVENT_BUILD_METHOD: "autotools"
+ EVENT_CONFIGURE_OPTIONS: "--disable-malloc-replacement"
+ - EVENT_BUILD_METHOD: "cmake"
+ EVENT_CMAKE_OPTIONS: ""
+ - EVENT_BUILD_METHOD: "cmake"
+ EVENT_CMAKE_OPTIONS: "-DEVENT__DISABLE_OPENSSL=ON"
+ - EVENT_BUILD_METHOD: "cmake"
+ EVENT_CMAKE_OPTIONS: "-DEVENT__DISABLE_THREAD_SUPPORT=ON"
+ - EVENT_BUILD_METHOD: "cmake"
+ EVENT_CMAKE_OPTIONS: "-DEVENT__DISABLE_DEBUG_MODE=ON"
+ - EVENT_BUILD_METHOD: "cmake"
+ EVENT_CMAKE_OPTIONS: "-DEVENT__DISABLE_MM_REPLACEMENT=ON"
+ - EVENT_BUILD_METHOD: "cmake"
+ EVENT_CMAKE_OPTIONS: "-DEVENT__ENABLE_VERBOSE_DEBUG=ON"
+ - EVENT_BUILD_METHOD: "cmake"
+ EVENT_CMAKE_OPTIONS: "-DCMAKE_C_FLAGS='-DUNICODE -D_UNICODE'"
+init:
+ - 'echo Building libevent %version% for Windows'
+ - 'echo System architecture: %PLATFORM%'
+ - 'echo Repo build branch is: %APPVEYOR_REPO_BRANCH%'
+ - 'echo Build folder is: %APPVEYOR_BUILD_FOLDER%'
+ - 'echo Repo build commit is: %APPVEYOR_REPO_COMMIT%'
+ - 'echo Cygwin root is: %CYG_ROOT%'
+install:
+ - C:\MinGW\bin\mingw-get install autotools autoconf automake
+build_script:
+ - ps: |
+ if ($env:EVENT_BUILD_METHOD -eq 'autotools') {
+ $env:PATH="$env:CYG_ROOT\bin;C:\MinGW\bin;$($env:PATH)"
+ bash -lc "echo 'C:\MinGW /mingw' > /etc/fstab"
+ bash -lc "echo 'C:\OpenSSL-Win32 /ssl' >> /etc/fstab"
+ $env:APPVEYOR_BUILD_FOLDER = $env:APPVEYOR_BUILD_FOLDER -replace "\\", "/"
+ bash -lc "exec 0</dev/null; exec 2>&1; cd $env:APPVEYOR_BUILD_FOLDER; bash -x ./autogen.sh && ./configure LDFLAGS='-L/ssl -L/ssl/lib -L/ssl/lib/MinGW' CFLAGS=-I/ssl/include $env:EVENT_CONFIGURE_OPTIONS && make && make verify"
+ } else {
+ md build
+ cd build
+ cmake .. $env:EVENT_CMAKE_OPTIONS
+ cmake --build .
+ ctest --output-on-failure
+ }
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/arc4random.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/arc4random.c
new file mode 100644
index 000000000..a2338e692
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/arc4random.c
@@ -0,0 +1,556 @@
+/* Portable arc4random.c based on arc4random.c from OpenBSD.
+ * Portable version by Chris Davis, adapted for Libevent by Nick Mathewson
+ * Copyright (c) 2010 Chris Davis, Niels Provos, and Nick Mathewson
+ * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson
+ *
+ * Note that in Libevent, this file isn't compiled directly. Instead,
+ * it's included from evutil_rand.c
+ */
+
+/*
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Arc4 random number generator for OpenBSD.
+ *
+ * This code is derived from section 17.1 of Applied Cryptography,
+ * second edition, which describes a stream cipher allegedly
+ * compatible with RSA Labs "RC4" cipher (the actual description of
+ * which is a trade secret). The same algorithm is used as a stream
+ * cipher called "arcfour" in Tatu Ylonen's ssh package.
+ *
+ * Here the stream cipher has been modified always to include the time
+ * when initializing the state. That makes it impossible to
+ * regenerate the same random sequence twice, so this can't be used
+ * for encryption, but will generate good random numbers.
+ *
+ * RC4 is a registered trademark of RSA Laboratories.
+ */
+
+#ifndef ARC4RANDOM_EXPORT
+#define ARC4RANDOM_EXPORT
+#endif
+
+#ifndef ARC4RANDOM_UINT32
+#define ARC4RANDOM_UINT32 uint32_t
+#endif
+
+#ifndef ARC4RANDOM_NO_INCLUDES
+#include "evconfig-private.h"
+#ifdef _WIN32
+#include <wincrypt.h>
+#include <process.h>
+#else
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#ifdef EVENT__HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+#endif
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+/* Add platform entropy 32 bytes (256 bits) at a time. */
+#define ADD_ENTROPY 32
+
+/* Re-seed from the platform RNG after generating this many bytes. */
+#define BYTES_BEFORE_RESEED 1600000
+
+struct arc4_stream {
+ unsigned char i;
+ unsigned char j;
+ unsigned char s[256];
+};
+
+#ifdef _WIN32
+#define getpid _getpid
+#define pid_t int
+#endif
+
+static int rs_initialized;
+static struct arc4_stream rs;
+static pid_t arc4_stir_pid;
+static int arc4_count;
+static int arc4_seeded_ok;
+
+static inline unsigned char arc4_getbyte(void);
+
+static inline void
+arc4_init(void)
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ rs.s[n] = n;
+ rs.i = 0;
+ rs.j = 0;
+}
+
+static inline void
+arc4_addrandom(const unsigned char *dat, int datlen)
+{
+ int n;
+ unsigned char si;
+
+ rs.i--;
+ for (n = 0; n < 256; n++) {
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si + dat[n % datlen]);
+ rs.s[rs.i] = rs.s[rs.j];
+ rs.s[rs.j] = si;
+ }
+ rs.j = rs.i;
+}
+
+#ifndef _WIN32
+static ssize_t
+read_all(int fd, unsigned char *buf, size_t count)
+{
+ size_t numread = 0;
+ ssize_t result;
+
+ while (numread < count) {
+ result = read(fd, buf+numread, count-numread);
+ if (result<0)
+ return -1;
+ else if (result == 0)
+ break;
+ numread += result;
+ }
+
+ return (ssize_t)numread;
+}
+#endif
+
+#ifdef _WIN32
+#define TRY_SEED_WIN32
+static int
+arc4_seed_win32(void)
+{
+ /* This is adapted from Tor's crypto_seed_rng() */
+ static int provider_set = 0;
+ static HCRYPTPROV provider;
+ unsigned char buf[ADD_ENTROPY];
+
+ if (!provider_set) {
+ if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)) {
+ if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
+ return -1;
+ }
+ provider_set = 1;
+ }
+ if (!CryptGenRandom(provider, sizeof(buf), buf))
+ return -1;
+ arc4_addrandom(buf, sizeof(buf));
+ evutil_memclear_(buf, sizeof(buf));
+ arc4_seeded_ok = 1;
+ return 0;
+}
+#endif
+
+#if defined(EVENT__HAVE_SYS_SYSCTL_H) && defined(EVENT__HAVE_SYSCTL)
+#if EVENT__HAVE_DECL_CTL_KERN && EVENT__HAVE_DECL_KERN_RANDOM && EVENT__HAVE_DECL_RANDOM_UUID
+#define TRY_SEED_SYSCTL_LINUX
+static int
+arc4_seed_sysctl_linux(void)
+{
+ /* Based on code by William Ahern, this function tries to use the
+ * RANDOM_UUID sysctl to get entropy from the kernel. This can work
+ * even if /dev/urandom is inaccessible for some reason (e.g., we're
+ * running in a chroot). */
+ int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
+ unsigned char buf[ADD_ENTROPY];
+ size_t len, n;
+ unsigned i;
+ int any_set;
+
+ memset(buf, 0, sizeof(buf));
+
+ for (len = 0; len < sizeof(buf); len += n) {
+ n = sizeof(buf) - len;
+
+ if (0 != sysctl(mib, 3, &buf[len], &n, NULL, 0))
+ return -1;
+ }
+ /* make sure that the buffer actually got set. */
+ for (i=0,any_set=0; i<sizeof(buf); ++i) {
+ any_set |= buf[i];
+ }
+ if (!any_set)
+ return -1;
+
+ arc4_addrandom(buf, sizeof(buf));
+ evutil_memclear_(buf, sizeof(buf));
+ arc4_seeded_ok = 1;
+ return 0;
+}
+#endif
+
+#if EVENT__HAVE_DECL_CTL_KERN && EVENT__HAVE_DECL_KERN_ARND
+#define TRY_SEED_SYSCTL_BSD
+static int
+arc4_seed_sysctl_bsd(void)
+{
+ /* Based on code from William Ahern and from OpenBSD, this function
+ * tries to use the KERN_ARND syscall to get entropy from the kernel.
+ * This can work even if /dev/urandom is inaccessible for some reason
+ * (e.g., we're running in a chroot). */
+ int mib[] = { CTL_KERN, KERN_ARND };
+ unsigned char buf[ADD_ENTROPY];
+ size_t len, n;
+ int i, any_set;
+
+ memset(buf, 0, sizeof(buf));
+
+ len = sizeof(buf);
+ if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
+ for (len = 0; len < sizeof(buf); len += sizeof(unsigned)) {
+ n = sizeof(unsigned);
+ if (n + len > sizeof(buf))
+ n = len - sizeof(buf);
+ if (sysctl(mib, 2, &buf[len], &n, NULL, 0) == -1)
+ return -1;
+ }
+ }
+ /* make sure that the buffer actually got set. */
+ for (i=any_set=0; i<sizeof(buf); ++i) {
+ any_set |= buf[i];
+ }
+ if (!any_set)
+ return -1;
+
+ arc4_addrandom(buf, sizeof(buf));
+ evutil_memclear_(buf, sizeof(buf));
+ arc4_seeded_ok = 1;
+ return 0;
+}
+#endif
+#endif /* defined(EVENT__HAVE_SYS_SYSCTL_H) */
+
+#ifdef __linux__
+#define TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
+static int
+arc4_seed_proc_sys_kernel_random_uuid(void)
+{
+ /* Occasionally, somebody will make /proc/sys accessible in a chroot,
+ * but not /dev/urandom. Let's try /proc/sys/kernel/random/uuid.
+ * Its format is stupid, so we need to decode it from hex.
+ */
+ int fd;
+ char buf[128];
+ unsigned char entropy[64];
+ int bytes, n, i, nybbles;
+ for (bytes = 0; bytes<ADD_ENTROPY; ) {
+ fd = evutil_open_closeonexec_("/proc/sys/kernel/random/uuid", O_RDONLY, 0);
+ if (fd < 0)
+ return -1;
+ n = read(fd, buf, sizeof(buf));
+ close(fd);
+ if (n<=0)
+ return -1;
+ memset(entropy, 0, sizeof(entropy));
+ for (i=nybbles=0; i<n; ++i) {
+ if (EVUTIL_ISXDIGIT_(buf[i])) {
+ int nyb = evutil_hex_char_to_int_(buf[i]);
+ if (nybbles & 1) {
+ entropy[nybbles/2] |= nyb;
+ } else {
+ entropy[nybbles/2] |= nyb<<4;
+ }
+ ++nybbles;
+ }
+ }
+ if (nybbles < 2)
+ return -1;
+ arc4_addrandom(entropy, nybbles/2);
+ bytes += nybbles/2;
+ }
+ evutil_memclear_(entropy, sizeof(entropy));
+ evutil_memclear_(buf, sizeof(buf));
+ arc4_seeded_ok = 1;
+ return 0;
+}
+#endif
+
+#ifndef _WIN32
+#define TRY_SEED_URANDOM
+static char *arc4random_urandom_filename = NULL;
+
+static int arc4_seed_urandom_helper_(const char *fname)
+{
+ unsigned char buf[ADD_ENTROPY];
+ int fd;
+ size_t n;
+
+ fd = evutil_open_closeonexec_(fname, O_RDONLY, 0);
+ if (fd<0)
+ return -1;
+ n = read_all(fd, buf, sizeof(buf));
+ close(fd);
+ if (n != sizeof(buf))
+ return -1;
+ arc4_addrandom(buf, sizeof(buf));
+ evutil_memclear_(buf, sizeof(buf));
+ arc4_seeded_ok = 1;
+ return 0;
+}
+
+static int
+arc4_seed_urandom(void)
+{
+ /* This is adapted from Tor's crypto_seed_rng() */
+ static const char *filenames[] = {
+ "/dev/srandom", "/dev/urandom", "/dev/random", NULL
+ };
+ int i;
+ if (arc4random_urandom_filename)
+ return arc4_seed_urandom_helper_(arc4random_urandom_filename);
+
+ for (i = 0; filenames[i]; ++i) {
+ if (arc4_seed_urandom_helper_(filenames[i]) == 0) {
+ return 0;
+ }
+ }
+
+ return -1;
+}
+#endif
+
+static int
+arc4_seed(void)
+{
+ int ok = 0;
+ /* We try every method that might work, and don't give up even if one
+ * does seem to work. There's no real harm in over-seeding, and if
+ * one of these sources turns out to be broken, that would be bad. */
+#ifdef TRY_SEED_WIN32
+ if (0 == arc4_seed_win32())
+ ok = 1;
+#endif
+#ifdef TRY_SEED_URANDOM
+ if (0 == arc4_seed_urandom())
+ ok = 1;
+#endif
+#ifdef TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
+ if (arc4random_urandom_filename == NULL &&
+ 0 == arc4_seed_proc_sys_kernel_random_uuid())
+ ok = 1;
+#endif
+#ifdef TRY_SEED_SYSCTL_LINUX
+ /* Apparently Linux is deprecating sysctl, and spewing warning
+ * messages when you try to use it. */
+ if (!ok && 0 == arc4_seed_sysctl_linux())
+ ok = 1;
+#endif
+#ifdef TRY_SEED_SYSCTL_BSD
+ if (0 == arc4_seed_sysctl_bsd())
+ ok = 1;
+#endif
+ return ok ? 0 : -1;
+}
+
+static int
+arc4_stir(void)
+{
+ int i;
+
+ if (!rs_initialized) {
+ arc4_init();
+ rs_initialized = 1;
+ }
+
+ arc4_seed();
+ if (!arc4_seeded_ok)
+ return -1;
+
+ /*
+ * Discard early keystream, as per recommendations in
+ * "Weaknesses in the Key Scheduling Algorithm of RC4" by
+ * Scott Fluhrer, Itsik Mantin, and Adi Shamir.
+ * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
+ *
+ * Ilya Mironov's "(Not So) Random Shuffles of RC4" suggests that
+ * we drop at least 2*256 bytes, with 12*256 as a conservative
+ * value.
+ *
+ * RFC4345 says to drop 6*256.
+ *
+ * At least some versions of this code drop 4*256, in a mistaken
+ * belief that "words" in the Fluhrer/Mantin/Shamir paper refers
+ * to processor words.
+ *
+ * We add another sect to the cargo cult, and choose 12*256.
+ */
+ for (i = 0; i < 12*256; i++)
+ (void)arc4_getbyte();
+
+ arc4_count = BYTES_BEFORE_RESEED;
+
+ return 0;
+}
+
+
+static void
+arc4_stir_if_needed(void)
+{
+ pid_t pid = getpid();
+
+ if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid)
+ {
+ arc4_stir_pid = pid;
+ arc4_stir();
+ }
+}
+
+static inline unsigned char
+arc4_getbyte(void)
+{
+ unsigned char si, sj;
+
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si);
+ sj = rs.s[rs.j];
+ rs.s[rs.i] = sj;
+ rs.s[rs.j] = si;
+ return (rs.s[(si + sj) & 0xff]);
+}
+
+static inline unsigned int
+arc4_getword(void)
+{
+ unsigned int val;
+
+ val = arc4_getbyte() << 24;
+ val |= arc4_getbyte() << 16;
+ val |= arc4_getbyte() << 8;
+ val |= arc4_getbyte();
+
+ return val;
+}
+
+#ifndef ARC4RANDOM_NOSTIR
+ARC4RANDOM_EXPORT int
+arc4random_stir(void)
+{
+ int val;
+ ARC4_LOCK_();
+ val = arc4_stir();
+ ARC4_UNLOCK_();
+ return val;
+}
+#endif
+
+#ifndef ARC4RANDOM_NOADDRANDOM
+ARC4RANDOM_EXPORT void
+arc4random_addrandom(const unsigned char *dat, int datlen)
+{
+ int j;
+ ARC4_LOCK_();
+ if (!rs_initialized)
+ arc4_stir();
+ for (j = 0; j < datlen; j += 256) {
+ /* arc4_addrandom() ignores all but the first 256 bytes of
+ * its input. We want to make sure to look at ALL the
+ * data in 'dat', just in case the user is doing something
+ * crazy like passing us all the files in /var/log. */
+ arc4_addrandom(dat + j, datlen - j);
+ }
+ ARC4_UNLOCK_();
+}
+#endif
+
+#ifndef ARC4RANDOM_NORANDOM
+ARC4RANDOM_EXPORT ARC4RANDOM_UINT32
+arc4random(void)
+{
+ ARC4RANDOM_UINT32 val;
+ ARC4_LOCK_();
+ arc4_count -= 4;
+ arc4_stir_if_needed();
+ val = arc4_getword();
+ ARC4_UNLOCK_();
+ return val;
+}
+#endif
+
+ARC4RANDOM_EXPORT void
+arc4random_buf(void *buf_, size_t n)
+{
+ unsigned char *buf = buf_;
+ ARC4_LOCK_();
+ arc4_stir_if_needed();
+ while (n--) {
+ if (--arc4_count <= 0)
+ arc4_stir();
+ buf[n] = arc4_getbyte();
+ }
+ ARC4_UNLOCK_();
+}
+
+#ifndef ARC4RANDOM_NOUNIFORM
+/*
+ * Calculate a uniformly distributed random number less than upper_bound
+ * avoiding "modulo bias".
+ *
+ * Uniformity is achieved by generating new random numbers until the one
+ * returned is outside the range [0, 2**32 % upper_bound). This
+ * guarantees the selected random number will be inside
+ * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
+ * after reduction modulo upper_bound.
+ */
+ARC4RANDOM_EXPORT unsigned int
+arc4random_uniform(unsigned int upper_bound)
+{
+ ARC4RANDOM_UINT32 r, min;
+
+ if (upper_bound < 2)
+ return 0;
+
+#if (UINT_MAX > 0xffffffffUL)
+ min = 0x100000000UL % upper_bound;
+#else
+ /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
+ if (upper_bound > 0x80000000)
+ min = 1 + ~upper_bound; /* 2**32 - upper_bound */
+ else {
+ /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
+ min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
+ }
+#endif
+
+ /*
+ * This could theoretically loop forever but each retry has
+ * p > 0.5 (worst case, usually far better) of selecting a
+ * number inside the range we need, so it should rarely need
+ * to re-roll.
+ */
+ for (;;) {
+ r = arc4random();
+ if (r >= min)
+ break;
+ }
+
+ return r % upper_bound;
+}
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/autogen.sh b/fluent-bit/lib/monkey/mk_core/deps/libevent/autogen.sh
new file mode 100755
index 000000000..bcfe937a6
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/autogen.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+MAKE=make
+if command -v gmake >/dev/null 2>/dev/null; then
+ MAKE=gmake
+fi
+$MAKE maintainer-clean >/dev/null 2>/dev/null
+
+if [ -x "`which autoreconf 2>/dev/null`" ] ; then
+ exec autoreconf -ivf
+fi
+
+LIBTOOLIZE=libtoolize
+SYSNAME=`uname`
+if [ "x$SYSNAME" = "xDarwin" ] ; then
+ LIBTOOLIZE=glibtoolize
+fi
+aclocal -I m4 && \
+ autoheader && \
+ $LIBTOOLIZE && \
+ autoconf && \
+ automake --add-missing --force-missing --copy
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/buffer.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/buffer.c
new file mode 100644
index 000000000..b7e3a69f4
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/buffer.c
@@ -0,0 +1,3447 @@
+/*
+ * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <io.h>
+#endif
+
+#ifdef EVENT__HAVE_VASPRINTF
+/* If we have vasprintf, we need to define _GNU_SOURCE before we include
+ * stdio.h. This comes from evconfig-private.h.
+ */
+#endif
+
+#include <sys/types.h>
+
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef EVENT__HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef EVENT__HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef EVENT__HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#ifdef EVENT__HAVE_SYS_SENDFILE_H
+#include <sys/sendfile.h>
+#endif
+#ifdef EVENT__HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef EVENT__HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <limits.h>
+
+#include "event2/event.h"
+#include "event2/buffer.h"
+#include "event2/buffer_compat.h"
+#include "event2/bufferevent.h"
+#include "event2/bufferevent_compat.h"
+#include "event2/bufferevent_struct.h"
+#include "event2/thread.h"
+#include "log-internal.h"
+#include "mm-internal.h"
+#include "util-internal.h"
+#include "evthread-internal.h"
+#include "evbuffer-internal.h"
+#include "bufferevent-internal.h"
+
+/* some systems do not have MAP_FAILED */
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+/* send file support */
+#if defined(EVENT__HAVE_SYS_SENDFILE_H) && defined(EVENT__HAVE_SENDFILE) && defined(__linux__)
+#define USE_SENDFILE 1
+#define SENDFILE_IS_LINUX 1
+#elif defined(EVENT__HAVE_SENDFILE) && defined(__FreeBSD__)
+#define USE_SENDFILE 1
+#define SENDFILE_IS_FREEBSD 1
+#elif defined(EVENT__HAVE_SENDFILE) && defined(__APPLE__)
+#define USE_SENDFILE 1
+#define SENDFILE_IS_MACOSX 1
+#elif defined(EVENT__HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__)
+#define USE_SENDFILE 1
+#define SENDFILE_IS_SOLARIS 1
+#endif
+
+/* Mask of user-selectable callback flags. */
+#define EVBUFFER_CB_USER_FLAGS 0xffff
+/* Mask of all internal-use-only flags. */
+#define EVBUFFER_CB_INTERNAL_FLAGS 0xffff0000
+
+/* Flag set if the callback is using the cb_obsolete function pointer */
+#define EVBUFFER_CB_OBSOLETE 0x00040000
+
+/* evbuffer_chain support */
+#define CHAIN_SPACE_PTR(ch) ((ch)->buffer + (ch)->misalign + (ch)->off)
+#define CHAIN_SPACE_LEN(ch) ((ch)->flags & EVBUFFER_IMMUTABLE ? \
+ 0 : (ch)->buffer_len - ((ch)->misalign + (ch)->off))
+
+#define CHAIN_PINNED(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_ANY) != 0)
+#define CHAIN_PINNED_R(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_R) != 0)
+
+/* evbuffer_ptr support */
+#define PTR_NOT_FOUND(ptr) do { \
+ (ptr)->pos = -1; \
+ (ptr)->internal_.chain = NULL; \
+ (ptr)->internal_.pos_in_chain = 0; \
+} while (0)
+
+static void evbuffer_chain_align(struct evbuffer_chain *chain);
+static int evbuffer_chain_should_realign(struct evbuffer_chain *chain,
+ size_t datalen);
+static void evbuffer_deferred_callback(struct event_callback *cb, void *arg);
+static int evbuffer_ptr_memcmp(const struct evbuffer *buf,
+ const struct evbuffer_ptr *pos, const char *mem, size_t len);
+static struct evbuffer_chain *evbuffer_expand_singlechain(struct evbuffer *buf,
+ size_t datlen);
+static int evbuffer_ptr_subtract(struct evbuffer *buf, struct evbuffer_ptr *pos,
+ size_t howfar);
+static int evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg);
+static inline void evbuffer_chain_incref(struct evbuffer_chain *chain);
+
+static struct evbuffer_chain *
+evbuffer_chain_new(size_t size)
+{
+ struct evbuffer_chain *chain;
+ size_t to_alloc;
+
+ if (size > EVBUFFER_CHAIN_MAX - EVBUFFER_CHAIN_SIZE)
+ return (NULL);
+
+ size += EVBUFFER_CHAIN_SIZE;
+
+ /* get the next largest memory that can hold the buffer */
+ if (size < EVBUFFER_CHAIN_MAX / 2) {
+ to_alloc = MIN_BUFFER_SIZE;
+ while (to_alloc < size) {
+ to_alloc <<= 1;
+ }
+ } else {
+ to_alloc = size;
+ }
+
+ /* we get everything in one chunk */
+ if ((chain = mm_malloc(to_alloc)) == NULL)
+ return (NULL);
+
+ memset(chain, 0, EVBUFFER_CHAIN_SIZE);
+
+ chain->buffer_len = to_alloc - EVBUFFER_CHAIN_SIZE;
+
+ /* this way we can manipulate the buffer to different addresses,
+ * which is required for mmap for example.
+ */
+ chain->buffer = EVBUFFER_CHAIN_EXTRA(unsigned char, chain);
+
+ chain->refcnt = 1;
+
+ return (chain);
+}
+
+static inline void
+evbuffer_chain_free(struct evbuffer_chain *chain)
+{
+ EVUTIL_ASSERT(chain->refcnt > 0);
+ if (--chain->refcnt > 0) {
+ /* chain is still referenced by other chains */
+ return;
+ }
+
+ if (CHAIN_PINNED(chain)) {
+ /* will get freed once no longer dangling */
+ chain->refcnt++;
+ chain->flags |= EVBUFFER_DANGLING;
+ return;
+ }
+
+ /* safe to release chain, it's either a referencing
+ * chain or all references to it have been freed */
+ if (chain->flags & EVBUFFER_REFERENCE) {
+ struct evbuffer_chain_reference *info =
+ EVBUFFER_CHAIN_EXTRA(
+ struct evbuffer_chain_reference,
+ chain);
+ if (info->cleanupfn)
+ (*info->cleanupfn)(chain->buffer,
+ chain->buffer_len,
+ info->extra);
+ }
+ if (chain->flags & EVBUFFER_FILESEGMENT) {
+ struct evbuffer_chain_file_segment *info =
+ EVBUFFER_CHAIN_EXTRA(
+ struct evbuffer_chain_file_segment,
+ chain);
+ if (info->segment) {
+#ifdef _WIN32
+ if (info->segment->is_mapping)
+ UnmapViewOfFile(chain->buffer);
+#endif
+ evbuffer_file_segment_free(info->segment);
+ }
+ }
+ if (chain->flags & EVBUFFER_MULTICAST) {
+ struct evbuffer_multicast_parent *info =
+ EVBUFFER_CHAIN_EXTRA(
+ struct evbuffer_multicast_parent,
+ chain);
+ /* referencing chain is being freed, decrease
+ * refcounts of source chain and associated
+ * evbuffer (which get freed once both reach
+ * zero) */
+ EVUTIL_ASSERT(info->source != NULL);
+ EVUTIL_ASSERT(info->parent != NULL);
+ EVBUFFER_LOCK(info->source);
+ evbuffer_chain_free(info->parent);
+ evbuffer_decref_and_unlock_(info->source);
+ }
+
+ mm_free(chain);
+}
+
+static void
+evbuffer_free_all_chains(struct evbuffer_chain *chain)
+{
+ struct evbuffer_chain *next;
+ for (; chain; chain = next) {
+ next = chain->next;
+ evbuffer_chain_free(chain);
+ }
+}
+
+#ifndef NDEBUG
+static int
+evbuffer_chains_all_empty(struct evbuffer_chain *chain)
+{
+ for (; chain; chain = chain->next) {
+ if (chain->off)
+ return 0;
+ }
+ return 1;
+}
+#else
+/* The definition is needed for EVUTIL_ASSERT, which uses sizeof to avoid
+"unused variable" warnings. */
+static inline int evbuffer_chains_all_empty(struct evbuffer_chain *chain) {
+ return 1;
+}
+#endif
+
+/* Free all trailing chains in 'buf' that are neither pinned nor empty, prior
+ * to replacing them all with a new chain. Return a pointer to the place
+ * where the new chain will go.
+ *
+ * Internal; requires lock. The caller must fix up buf->last and buf->first
+ * as needed; they might have been freed.
+ */
+static struct evbuffer_chain **
+evbuffer_free_trailing_empty_chains(struct evbuffer *buf)
+{
+ struct evbuffer_chain **ch = buf->last_with_datap;
+ /* Find the first victim chain. It might be *last_with_datap */
+ while ((*ch) && ((*ch)->off != 0 || CHAIN_PINNED(*ch)))
+ ch = &(*ch)->next;
+ if (*ch) {
+ EVUTIL_ASSERT(evbuffer_chains_all_empty(*ch));
+ evbuffer_free_all_chains(*ch);
+ *ch = NULL;
+ }
+ return ch;
+}
+
+/* Add a single chain 'chain' to the end of 'buf', freeing trailing empty
+ * chains as necessary. Requires lock. Does not schedule callbacks.
+ */
+static void
+evbuffer_chain_insert(struct evbuffer *buf,
+ struct evbuffer_chain *chain)
+{
+ ASSERT_EVBUFFER_LOCKED(buf);
+ if (*buf->last_with_datap == NULL) {
+ /* There are no chains data on the buffer at all. */
+ EVUTIL_ASSERT(buf->last_with_datap == &buf->first);
+ EVUTIL_ASSERT(buf->first == NULL);
+ buf->first = buf->last = chain;
+ } else {
+ struct evbuffer_chain **chp;
+ chp = evbuffer_free_trailing_empty_chains(buf);
+ *chp = chain;
+ if (chain->off)
+ buf->last_with_datap = chp;
+ buf->last = chain;
+ }
+ buf->total_len += chain->off;
+}
+
+static inline struct evbuffer_chain *
+evbuffer_chain_insert_new(struct evbuffer *buf, size_t datlen)
+{
+ struct evbuffer_chain *chain;
+ if ((chain = evbuffer_chain_new(datlen)) == NULL)
+ return NULL;
+ evbuffer_chain_insert(buf, chain);
+ return chain;
+}
+
+void
+evbuffer_chain_pin_(struct evbuffer_chain *chain, unsigned flag)
+{
+ EVUTIL_ASSERT((chain->flags & flag) == 0);
+ chain->flags |= flag;
+}
+
+void
+evbuffer_chain_unpin_(struct evbuffer_chain *chain, unsigned flag)
+{
+ EVUTIL_ASSERT((chain->flags & flag) != 0);
+ chain->flags &= ~flag;
+ if (chain->flags & EVBUFFER_DANGLING)
+ evbuffer_chain_free(chain);
+}
+
+static inline void
+evbuffer_chain_incref(struct evbuffer_chain *chain)
+{
+ ++chain->refcnt;
+}
+
+struct evbuffer *
+evbuffer_new(void)
+{
+ struct evbuffer *buffer;
+
+ buffer = mm_calloc(1, sizeof(struct evbuffer));
+ if (buffer == NULL)
+ return (NULL);
+
+ LIST_INIT(&buffer->callbacks);
+ buffer->refcnt = 1;
+ buffer->last_with_datap = &buffer->first;
+
+ return (buffer);
+}
+
+int
+evbuffer_set_flags(struct evbuffer *buf, ev_uint64_t flags)
+{
+ EVBUFFER_LOCK(buf);
+ buf->flags |= (ev_uint32_t)flags;
+ EVBUFFER_UNLOCK(buf);
+ return 0;
+}
+
+int
+evbuffer_clear_flags(struct evbuffer *buf, ev_uint64_t flags)
+{
+ EVBUFFER_LOCK(buf);
+ buf->flags &= ~(ev_uint32_t)flags;
+ EVBUFFER_UNLOCK(buf);
+ return 0;
+}
+
+void
+evbuffer_incref_(struct evbuffer *buf)
+{
+ EVBUFFER_LOCK(buf);
+ ++buf->refcnt;
+ EVBUFFER_UNLOCK(buf);
+}
+
+void
+evbuffer_incref_and_lock_(struct evbuffer *buf)
+{
+ EVBUFFER_LOCK(buf);
+ ++buf->refcnt;
+}
+
+int
+evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base)
+{
+ EVBUFFER_LOCK(buffer);
+ buffer->cb_queue = base;
+ buffer->deferred_cbs = 1;
+ event_deferred_cb_init_(&buffer->deferred,
+ event_base_get_npriorities(base) / 2,
+ evbuffer_deferred_callback, buffer);
+ EVBUFFER_UNLOCK(buffer);
+ return 0;
+}
+
+int
+evbuffer_enable_locking(struct evbuffer *buf, void *lock)
+{
+#ifdef EVENT__DISABLE_THREAD_SUPPORT
+ return -1;
+#else
+ if (buf->lock)
+ return -1;
+
+ if (!lock) {
+ EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ if (!lock)
+ return -1;
+ buf->lock = lock;
+ buf->own_lock = 1;
+ } else {
+ buf->lock = lock;
+ buf->own_lock = 0;
+ }
+
+ return 0;
+#endif
+}
+
+void
+evbuffer_set_parent_(struct evbuffer *buf, struct bufferevent *bev)
+{
+ EVBUFFER_LOCK(buf);
+ buf->parent = bev;
+ EVBUFFER_UNLOCK(buf);
+}
+
+static void
+evbuffer_run_callbacks(struct evbuffer *buffer, int running_deferred)
+{
+ struct evbuffer_cb_entry *cbent, *next;
+ struct evbuffer_cb_info info;
+ size_t new_size;
+ ev_uint32_t mask, masked_val;
+ int clear = 1;
+
+ if (running_deferred) {
+ mask = EVBUFFER_CB_NODEFER|EVBUFFER_CB_ENABLED;
+ masked_val = EVBUFFER_CB_ENABLED;
+ } else if (buffer->deferred_cbs) {
+ mask = EVBUFFER_CB_NODEFER|EVBUFFER_CB_ENABLED;
+ masked_val = EVBUFFER_CB_NODEFER|EVBUFFER_CB_ENABLED;
+ /* Don't zero-out n_add/n_del, since the deferred callbacks
+ will want to see them. */
+ clear = 0;
+ } else {
+ mask = EVBUFFER_CB_ENABLED;
+ masked_val = EVBUFFER_CB_ENABLED;
+ }
+
+ ASSERT_EVBUFFER_LOCKED(buffer);
+
+ if (LIST_EMPTY(&buffer->callbacks)) {
+ buffer->n_add_for_cb = buffer->n_del_for_cb = 0;
+ return;
+ }
+ if (buffer->n_add_for_cb == 0 && buffer->n_del_for_cb == 0)
+ return;
+
+ new_size = buffer->total_len;
+ info.orig_size = new_size + buffer->n_del_for_cb - buffer->n_add_for_cb;
+ info.n_added = buffer->n_add_for_cb;
+ info.n_deleted = buffer->n_del_for_cb;
+ if (clear) {
+ buffer->n_add_for_cb = 0;
+ buffer->n_del_for_cb = 0;
+ }
+ for (cbent = LIST_FIRST(&buffer->callbacks);
+ cbent != LIST_END(&buffer->callbacks);
+ cbent = next) {
+ /* Get the 'next' pointer now in case this callback decides
+ * to remove itself or something. */
+ next = LIST_NEXT(cbent, next);
+
+ if ((cbent->flags & mask) != masked_val)
+ continue;
+
+ if ((cbent->flags & EVBUFFER_CB_OBSOLETE))
+ cbent->cb.cb_obsolete(buffer,
+ info.orig_size, new_size, cbent->cbarg);
+ else
+ cbent->cb.cb_func(buffer, &info, cbent->cbarg);
+ }
+}
+
+void
+evbuffer_invoke_callbacks_(struct evbuffer *buffer)
+{
+ if (LIST_EMPTY(&buffer->callbacks)) {
+ buffer->n_add_for_cb = buffer->n_del_for_cb = 0;
+ return;
+ }
+
+ if (buffer->deferred_cbs) {
+ if (event_deferred_cb_schedule_(buffer->cb_queue, &buffer->deferred)) {
+ evbuffer_incref_and_lock_(buffer);
+ if (buffer->parent)
+ bufferevent_incref_(buffer->parent);
+ }
+ EVBUFFER_UNLOCK(buffer);
+ }
+
+ evbuffer_run_callbacks(buffer, 0);
+}
+
+static void
+evbuffer_deferred_callback(struct event_callback *cb, void *arg)
+{
+ struct bufferevent *parent = NULL;
+ struct evbuffer *buffer = arg;
+
+ /* XXXX It would be better to run these callbacks without holding the
+ * lock */
+ EVBUFFER_LOCK(buffer);
+ parent = buffer->parent;
+ evbuffer_run_callbacks(buffer, 1);
+ evbuffer_decref_and_unlock_(buffer);
+ if (parent)
+ bufferevent_decref_(parent);
+}
+
+static void
+evbuffer_remove_all_callbacks(struct evbuffer *buffer)
+{
+ struct evbuffer_cb_entry *cbent;
+
+ while ((cbent = LIST_FIRST(&buffer->callbacks))) {
+ LIST_REMOVE(cbent, next);
+ mm_free(cbent);
+ }
+}
+
+void
+evbuffer_decref_and_unlock_(struct evbuffer *buffer)
+{
+ struct evbuffer_chain *chain, *next;
+ ASSERT_EVBUFFER_LOCKED(buffer);
+
+ EVUTIL_ASSERT(buffer->refcnt > 0);
+
+ if (--buffer->refcnt > 0) {
+ EVBUFFER_UNLOCK(buffer);
+ return;
+ }
+
+ for (chain = buffer->first; chain != NULL; chain = next) {
+ next = chain->next;
+ evbuffer_chain_free(chain);
+ }
+ evbuffer_remove_all_callbacks(buffer);
+ if (buffer->deferred_cbs)
+ event_deferred_cb_cancel_(buffer->cb_queue, &buffer->deferred);
+
+ EVBUFFER_UNLOCK(buffer);
+ if (buffer->own_lock)
+ EVTHREAD_FREE_LOCK(buffer->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ mm_free(buffer);
+}
+
+void
+evbuffer_free(struct evbuffer *buffer)
+{
+ EVBUFFER_LOCK(buffer);
+ evbuffer_decref_and_unlock_(buffer);
+}
+
+void
+evbuffer_lock(struct evbuffer *buf)
+{
+ EVBUFFER_LOCK(buf);
+}
+
+void
+evbuffer_unlock(struct evbuffer *buf)
+{
+ EVBUFFER_UNLOCK(buf);
+}
+
+size_t
+evbuffer_get_length(const struct evbuffer *buffer)
+{
+ size_t result;
+
+ EVBUFFER_LOCK(buffer);
+
+ result = (buffer->total_len);
+
+ EVBUFFER_UNLOCK(buffer);
+
+ return result;
+}
+
+size_t
+evbuffer_get_contiguous_space(const struct evbuffer *buf)
+{
+ struct evbuffer_chain *chain;
+ size_t result;
+
+ EVBUFFER_LOCK(buf);
+ chain = buf->first;
+ result = (chain != NULL ? chain->off : 0);
+ EVBUFFER_UNLOCK(buf);
+
+ return result;
+}
+
+size_t
+evbuffer_add_iovec(struct evbuffer * buf, struct evbuffer_iovec * vec, int n_vec) {
+ int n;
+ size_t res;
+ size_t to_alloc;
+
+ EVBUFFER_LOCK(buf);
+
+ res = to_alloc = 0;
+
+ for (n = 0; n < n_vec; n++) {
+ to_alloc += vec[n].iov_len;
+ }
+
+ if (evbuffer_expand_fast_(buf, to_alloc, 2) < 0) {
+ goto done;
+ }
+
+ for (n = 0; n < n_vec; n++) {
+ /* XXX each 'add' call here does a bunch of setup that's
+ * obviated by evbuffer_expand_fast_, and some cleanup that we
+ * would like to do only once. Instead we should just extract
+ * the part of the code that's needed. */
+
+ if (evbuffer_add(buf, vec[n].iov_base, vec[n].iov_len) < 0) {
+ goto done;
+ }
+
+ res += vec[n].iov_len;
+ }
+
+done:
+ EVBUFFER_UNLOCK(buf);
+ return res;
+}
+
+int
+evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
+ struct evbuffer_iovec *vec, int n_vecs)
+{
+ struct evbuffer_chain *chain, **chainp;
+ int n = -1;
+
+ EVBUFFER_LOCK(buf);
+ if (buf->freeze_end)
+ goto done;
+ if (n_vecs < 1)
+ goto done;
+ if (n_vecs == 1) {
+ if ((chain = evbuffer_expand_singlechain(buf, size)) == NULL)
+ goto done;
+
+ vec[0].iov_base = (void *)CHAIN_SPACE_PTR(chain);
+ vec[0].iov_len = (size_t)CHAIN_SPACE_LEN(chain);
+ EVUTIL_ASSERT(size<0 || (size_t)vec[0].iov_len >= (size_t)size);
+ n = 1;
+ } else {
+ if (evbuffer_expand_fast_(buf, size, n_vecs)<0)
+ goto done;
+ n = evbuffer_read_setup_vecs_(buf, size, vec, n_vecs,
+ &chainp, 0);
+ }
+
+done:
+ EVBUFFER_UNLOCK(buf);
+ return n;
+
+}
+
+static int
+advance_last_with_data(struct evbuffer *buf)
+{
+ int n = 0;
+ ASSERT_EVBUFFER_LOCKED(buf);
+
+ if (!*buf->last_with_datap)
+ return 0;
+
+ while ((*buf->last_with_datap)->next && (*buf->last_with_datap)->next->off) {
+ buf->last_with_datap = &(*buf->last_with_datap)->next;
+ ++n;
+ }
+ return n;
+}
+
+int
+evbuffer_commit_space(struct evbuffer *buf,
+ struct evbuffer_iovec *vec, int n_vecs)
+{
+ struct evbuffer_chain *chain, **firstchainp, **chainp;
+ int result = -1;
+ size_t added = 0;
+ int i;
+
+ EVBUFFER_LOCK(buf);
+
+ if (buf->freeze_end)
+ goto done;
+ if (n_vecs == 0) {
+ result = 0;
+ goto done;
+ } else if (n_vecs == 1 &&
+ (buf->last && vec[0].iov_base == (void *)CHAIN_SPACE_PTR(buf->last))) {
+ /* The user only got or used one chain; it might not
+ * be the first one with space in it. */
+ if ((size_t)vec[0].iov_len > (size_t)CHAIN_SPACE_LEN(buf->last))
+ goto done;
+ buf->last->off += vec[0].iov_len;
+ added = vec[0].iov_len;
+ if (added)
+ advance_last_with_data(buf);
+ goto okay;
+ }
+
+ /* Advance 'firstchain' to the first chain with space in it. */
+ firstchainp = buf->last_with_datap;
+ if (!*firstchainp)
+ goto done;
+ if (CHAIN_SPACE_LEN(*firstchainp) == 0) {
+ firstchainp = &(*firstchainp)->next;
+ }
+
+ chain = *firstchainp;
+ /* pass 1: make sure that the pointers and lengths of vecs[] are in
+ * bounds before we try to commit anything. */
+ for (i=0; i<n_vecs; ++i) {
+ if (!chain)
+ goto done;
+ if (vec[i].iov_base != (void *)CHAIN_SPACE_PTR(chain) ||
+ (size_t)vec[i].iov_len > CHAIN_SPACE_LEN(chain))
+ goto done;
+ chain = chain->next;
+ }
+ /* pass 2: actually adjust all the chains. */
+ chainp = firstchainp;
+ for (i=0; i<n_vecs; ++i) {
+ (*chainp)->off += vec[i].iov_len;
+ added += vec[i].iov_len;
+ if (vec[i].iov_len) {
+ buf->last_with_datap = chainp;
+ }
+ chainp = &(*chainp)->next;
+ }
+
+okay:
+ buf->total_len += added;
+ buf->n_add_for_cb += added;
+ result = 0;
+ evbuffer_invoke_callbacks_(buf);
+
+done:
+ EVBUFFER_UNLOCK(buf);
+ return result;
+}
+
+static inline int
+HAS_PINNED_R(struct evbuffer *buf)
+{
+ return (buf->last && CHAIN_PINNED_R(buf->last));
+}
+
+static inline void
+ZERO_CHAIN(struct evbuffer *dst)
+{
+ ASSERT_EVBUFFER_LOCKED(dst);
+ dst->first = NULL;
+ dst->last = NULL;
+ dst->last_with_datap = &(dst)->first;
+ dst->total_len = 0;
+}
+
+/* Prepares the contents of src to be moved to another buffer by removing
+ * read-pinned chains. The first pinned chain is saved in first, and the
+ * last in last. If src has no read-pinned chains, first and last are set
+ * to NULL. */
+static int
+PRESERVE_PINNED(struct evbuffer *src, struct evbuffer_chain **first,
+ struct evbuffer_chain **last)
+{
+ struct evbuffer_chain *chain, **pinned;
+
+ ASSERT_EVBUFFER_LOCKED(src);
+
+ if (!HAS_PINNED_R(src)) {
+ *first = *last = NULL;
+ return 0;
+ }
+
+ pinned = src->last_with_datap;
+ if (!CHAIN_PINNED_R(*pinned))
+ pinned = &(*pinned)->next;
+ EVUTIL_ASSERT(CHAIN_PINNED_R(*pinned));
+ chain = *first = *pinned;
+ *last = src->last;
+
+ /* If there's data in the first pinned chain, we need to allocate
+ * a new chain and copy the data over. */
+ if (chain->off) {
+ struct evbuffer_chain *tmp;
+
+ EVUTIL_ASSERT(pinned == src->last_with_datap);
+ tmp = evbuffer_chain_new(chain->off);
+ if (!tmp)
+ return -1;
+ memcpy(tmp->buffer, chain->buffer + chain->misalign,
+ chain->off);
+ tmp->off = chain->off;
+ *src->last_with_datap = tmp;
+ src->last = tmp;
+ chain->misalign += chain->off;
+ chain->off = 0;
+ } else {
+ src->last = *src->last_with_datap;
+ *pinned = NULL;
+ }
+
+ return 0;
+}
+
+static inline void
+RESTORE_PINNED(struct evbuffer *src, struct evbuffer_chain *pinned,
+ struct evbuffer_chain *last)
+{
+ ASSERT_EVBUFFER_LOCKED(src);
+
+ if (!pinned) {
+ ZERO_CHAIN(src);
+ return;
+ }
+
+ src->first = pinned;
+ src->last = last;
+ src->last_with_datap = &src->first;
+ src->total_len = 0;
+}
+
+static inline void
+COPY_CHAIN(struct evbuffer *dst, struct evbuffer *src)
+{
+ ASSERT_EVBUFFER_LOCKED(dst);
+ ASSERT_EVBUFFER_LOCKED(src);
+ dst->first = src->first;
+ if (src->last_with_datap == &src->first)
+ dst->last_with_datap = &dst->first;
+ else
+ dst->last_with_datap = src->last_with_datap;
+ dst->last = src->last;
+ dst->total_len = src->total_len;
+}
+
+static void
+APPEND_CHAIN(struct evbuffer *dst, struct evbuffer *src)
+{
+ struct evbuffer_chain **chp;
+
+ ASSERT_EVBUFFER_LOCKED(dst);
+ ASSERT_EVBUFFER_LOCKED(src);
+
+ chp = evbuffer_free_trailing_empty_chains(dst);
+ *chp = src->first;
+
+ if (src->last_with_datap == &src->first)
+ dst->last_with_datap = chp;
+ else
+ dst->last_with_datap = src->last_with_datap;
+ dst->last = src->last;
+ dst->total_len += src->total_len;
+}
+
+static inline void
+APPEND_CHAIN_MULTICAST(struct evbuffer *dst, struct evbuffer *src)
+{
+ struct evbuffer_chain *tmp;
+ struct evbuffer_chain *chain = src->first;
+ struct evbuffer_multicast_parent *extra;
+
+ ASSERT_EVBUFFER_LOCKED(dst);
+ ASSERT_EVBUFFER_LOCKED(src);
+
+ for (; chain; chain = chain->next) {
+ if (!chain->off || chain->flags & EVBUFFER_DANGLING) {
+ /* skip empty chains */
+ continue;
+ }
+
+ tmp = evbuffer_chain_new(sizeof(struct evbuffer_multicast_parent));
+ if (!tmp) {
+ event_warn("%s: out of memory", __func__);
+ return;
+ }
+ extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_multicast_parent, tmp);
+ /* reference evbuffer containing source chain so it
+ * doesn't get released while the chain is still
+ * being referenced to */
+ evbuffer_incref_(src);
+ extra->source = src;
+ /* reference source chain which now becomes immutable */
+ evbuffer_chain_incref(chain);
+ extra->parent = chain;
+ chain->flags |= EVBUFFER_IMMUTABLE;
+ tmp->buffer_len = chain->buffer_len;
+ tmp->misalign = chain->misalign;
+ tmp->off = chain->off;
+ tmp->flags |= EVBUFFER_MULTICAST|EVBUFFER_IMMUTABLE;
+ tmp->buffer = chain->buffer;
+ evbuffer_chain_insert(dst, tmp);
+ }
+}
+
+static void
+PREPEND_CHAIN(struct evbuffer *dst, struct evbuffer *src)
+{
+ ASSERT_EVBUFFER_LOCKED(dst);
+ ASSERT_EVBUFFER_LOCKED(src);
+ src->last->next = dst->first;
+ dst->first = src->first;
+ dst->total_len += src->total_len;
+ if (*dst->last_with_datap == NULL) {
+ if (src->last_with_datap == &(src)->first)
+ dst->last_with_datap = &dst->first;
+ else
+ dst->last_with_datap = src->last_with_datap;
+ } else if (dst->last_with_datap == &dst->first) {
+ dst->last_with_datap = &src->last->next;
+ }
+}
+
+int
+evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
+{
+ struct evbuffer_chain *pinned, *last;
+ size_t in_total_len, out_total_len;
+ int result = 0;
+
+ EVBUFFER_LOCK2(inbuf, outbuf);
+ in_total_len = inbuf->total_len;
+ out_total_len = outbuf->total_len;
+
+ if (in_total_len == 0 || outbuf == inbuf)
+ goto done;
+
+ if (outbuf->freeze_end || inbuf->freeze_start) {
+ result = -1;
+ goto done;
+ }
+
+ if (PRESERVE_PINNED(inbuf, &pinned, &last) < 0) {
+ result = -1;
+ goto done;
+ }
+
+ if (out_total_len == 0) {
+ /* There might be an empty chain at the start of outbuf; free
+ * it. */
+ evbuffer_free_all_chains(outbuf->first);
+ COPY_CHAIN(outbuf, inbuf);
+ } else {
+ APPEND_CHAIN(outbuf, inbuf);
+ }
+
+ RESTORE_PINNED(inbuf, pinned, last);
+
+ inbuf->n_del_for_cb += in_total_len;
+ outbuf->n_add_for_cb += in_total_len;
+
+ evbuffer_invoke_callbacks_(inbuf);
+ evbuffer_invoke_callbacks_(outbuf);
+
+done:
+ EVBUFFER_UNLOCK2(inbuf, outbuf);
+ return result;
+}
+
+int
+evbuffer_add_buffer_reference(struct evbuffer *outbuf, struct evbuffer *inbuf)
+{
+ size_t in_total_len, out_total_len;
+ struct evbuffer_chain *chain;
+ int result = 0;
+
+ EVBUFFER_LOCK2(inbuf, outbuf);
+ in_total_len = inbuf->total_len;
+ out_total_len = outbuf->total_len;
+ chain = inbuf->first;
+
+ if (in_total_len == 0)
+ goto done;
+
+ if (outbuf->freeze_end || outbuf == inbuf) {
+ result = -1;
+ goto done;
+ }
+
+ for (; chain; chain = chain->next) {
+ if ((chain->flags & (EVBUFFER_FILESEGMENT|EVBUFFER_SENDFILE|EVBUFFER_MULTICAST)) != 0) {
+ /* chain type can not be referenced */
+ result = -1;
+ goto done;
+ }
+ }
+
+ if (out_total_len == 0) {
+ /* There might be an empty chain at the start of outbuf; free
+ * it. */
+ evbuffer_free_all_chains(outbuf->first);
+ }
+ APPEND_CHAIN_MULTICAST(outbuf, inbuf);
+
+ outbuf->n_add_for_cb += in_total_len;
+ evbuffer_invoke_callbacks_(outbuf);
+
+done:
+ EVBUFFER_UNLOCK2(inbuf, outbuf);
+ return result;
+}
+
+int
+evbuffer_prepend_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
+{
+ struct evbuffer_chain *pinned, *last;
+ size_t in_total_len, out_total_len;
+ int result = 0;
+
+ EVBUFFER_LOCK2(inbuf, outbuf);
+
+ in_total_len = inbuf->total_len;
+ out_total_len = outbuf->total_len;
+
+ if (!in_total_len || inbuf == outbuf)
+ goto done;
+
+ if (outbuf->freeze_start || inbuf->freeze_start) {
+ result = -1;
+ goto done;
+ }
+
+ if (PRESERVE_PINNED(inbuf, &pinned, &last) < 0) {
+ result = -1;
+ goto done;
+ }
+
+ if (out_total_len == 0) {
+ /* There might be an empty chain at the start of outbuf; free
+ * it. */
+ evbuffer_free_all_chains(outbuf->first);
+ COPY_CHAIN(outbuf, inbuf);
+ } else {
+ PREPEND_CHAIN(outbuf, inbuf);
+ }
+
+ RESTORE_PINNED(inbuf, pinned, last);
+
+ inbuf->n_del_for_cb += in_total_len;
+ outbuf->n_add_for_cb += in_total_len;
+
+ evbuffer_invoke_callbacks_(inbuf);
+ evbuffer_invoke_callbacks_(outbuf);
+done:
+ EVBUFFER_UNLOCK2(inbuf, outbuf);
+ return result;
+}
+
+int
+evbuffer_drain(struct evbuffer *buf, size_t len)
+{
+ struct evbuffer_chain *chain, *next;
+ size_t remaining, old_len;
+ int result = 0;
+
+ EVBUFFER_LOCK(buf);
+ old_len = buf->total_len;
+
+ if (old_len == 0)
+ goto done;
+
+ if (buf->freeze_start) {
+ result = -1;
+ goto done;
+ }
+
+ if (len >= old_len && !HAS_PINNED_R(buf)) {
+ len = old_len;
+ for (chain = buf->first; chain != NULL; chain = next) {
+ next = chain->next;
+ evbuffer_chain_free(chain);
+ }
+
+ ZERO_CHAIN(buf);
+ } else {
+ if (len >= old_len)
+ len = old_len;
+
+ buf->total_len -= len;
+ remaining = len;
+ for (chain = buf->first;
+ remaining >= chain->off;
+ chain = next) {
+ next = chain->next;
+ remaining -= chain->off;
+
+ if (chain == *buf->last_with_datap) {
+ buf->last_with_datap = &buf->first;
+ }
+ if (&chain->next == buf->last_with_datap)
+ buf->last_with_datap = &buf->first;
+
+ if (CHAIN_PINNED_R(chain)) {
+ EVUTIL_ASSERT(remaining == 0);
+ chain->misalign += chain->off;
+ chain->off = 0;
+ break;
+ } else
+ evbuffer_chain_free(chain);
+ }
+
+ buf->first = chain;
+ EVUTIL_ASSERT(chain && remaining <= chain->off);
+ chain->misalign += remaining;
+ chain->off -= remaining;
+ }
+
+ buf->n_del_for_cb += len;
+ /* Tell someone about changes in this buffer */
+ evbuffer_invoke_callbacks_(buf);
+
+done:
+ EVBUFFER_UNLOCK(buf);
+ return result;
+}
+
+/* Reads data from an event buffer and drains the bytes read */
+int
+evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
+{
+ ev_ssize_t n;
+ EVBUFFER_LOCK(buf);
+ n = evbuffer_copyout_from(buf, NULL, data_out, datlen);
+ if (n > 0) {
+ if (evbuffer_drain(buf, n)<0)
+ n = -1;
+ }
+ EVBUFFER_UNLOCK(buf);
+ return (int)n;
+}
+
+ev_ssize_t
+evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen)
+{
+ return evbuffer_copyout_from(buf, NULL, data_out, datlen);
+}
+
+ev_ssize_t
+evbuffer_copyout_from(struct evbuffer *buf, const struct evbuffer_ptr *pos,
+ void *data_out, size_t datlen)
+{
+ /*XXX fails badly on sendfile case. */
+ struct evbuffer_chain *chain;
+ char *data = data_out;
+ size_t nread;
+ ev_ssize_t result = 0;
+ size_t pos_in_chain;
+
+ EVBUFFER_LOCK(buf);
+
+ if (pos) {
+ if (datlen > (size_t)(EV_SSIZE_MAX - pos->pos)) {
+ result = -1;
+ goto done;
+ }
+ chain = pos->internal_.chain;
+ pos_in_chain = pos->internal_.pos_in_chain;
+ if (datlen + pos->pos > buf->total_len)
+ datlen = buf->total_len - pos->pos;
+ } else {
+ chain = buf->first;
+ pos_in_chain = 0;
+ if (datlen > buf->total_len)
+ datlen = buf->total_len;
+ }
+
+
+ if (datlen == 0)
+ goto done;
+
+ if (buf->freeze_start) {
+ result = -1;
+ goto done;
+ }
+
+ nread = datlen;
+
+ while (datlen && datlen >= chain->off - pos_in_chain) {
+ size_t copylen = chain->off - pos_in_chain;
+ memcpy(data,
+ chain->buffer + chain->misalign + pos_in_chain,
+ copylen);
+ data += copylen;
+ datlen -= copylen;
+
+ chain = chain->next;
+ pos_in_chain = 0;
+ EVUTIL_ASSERT(chain || datlen==0);
+ }
+
+ if (datlen) {
+ EVUTIL_ASSERT(chain);
+ EVUTIL_ASSERT(datlen+pos_in_chain <= chain->off);
+
+ memcpy(data, chain->buffer + chain->misalign + pos_in_chain,
+ datlen);
+ }
+
+ result = nread;
+done:
+ EVBUFFER_UNLOCK(buf);
+ return result;
+}
+
+/* reads data from the src buffer to the dst buffer, avoids memcpy as
+ * possible. */
+/* XXXX should return ev_ssize_t */
+int
+evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
+ size_t datlen)
+{
+ /*XXX We should have an option to force this to be zero-copy.*/
+
+ /*XXX can fail badly on sendfile case. */
+ struct evbuffer_chain *chain, *previous;
+ size_t nread = 0;
+ int result;
+
+ EVBUFFER_LOCK2(src, dst);
+
+ chain = previous = src->first;
+
+ if (datlen == 0 || dst == src) {
+ result = 0;
+ goto done;
+ }
+
+ if (dst->freeze_end || src->freeze_start) {
+ result = -1;
+ goto done;
+ }
+
+ /* short-cut if there is no more data buffered */
+ if (datlen >= src->total_len) {
+ datlen = src->total_len;
+ evbuffer_add_buffer(dst, src);
+ result = (int)datlen; /*XXXX should return ev_ssize_t*/
+ goto done;
+ }
+
+ /* removes chains if possible */
+ while (chain->off <= datlen) {
+ /* We can't remove the last with data from src unless we
+ * remove all chains, in which case we would have done the if
+ * block above */
+ EVUTIL_ASSERT(chain != *src->last_with_datap);
+ nread += chain->off;
+ datlen -= chain->off;
+ previous = chain;
+ if (src->last_with_datap == &chain->next)
+ src->last_with_datap = &src->first;
+ chain = chain->next;
+ }
+
+ if (nread) {
+ /* we can remove the chain */
+ struct evbuffer_chain **chp;
+ chp = evbuffer_free_trailing_empty_chains(dst);
+
+ if (dst->first == NULL) {
+ dst->first = src->first;
+ } else {
+ *chp = src->first;
+ }
+ dst->last = previous;
+ previous->next = NULL;
+ src->first = chain;
+ advance_last_with_data(dst);
+
+ dst->total_len += nread;
+ dst->n_add_for_cb += nread;
+ }
+
+ /* we know that there is more data in the src buffer than
+ * we want to read, so we manually drain the chain */
+ evbuffer_add(dst, chain->buffer + chain->misalign, datlen);
+ chain->misalign += datlen;
+ chain->off -= datlen;
+ nread += datlen;
+
+ /* You might think we would want to increment dst->n_add_for_cb
+ * here too. But evbuffer_add above already took care of that.
+ */
+ src->total_len -= nread;
+ src->n_del_for_cb += nread;
+
+ if (nread) {
+ evbuffer_invoke_callbacks_(dst);
+ evbuffer_invoke_callbacks_(src);
+ }
+ result = (int)nread;/*XXXX should change return type */
+
+done:
+ EVBUFFER_UNLOCK2(src, dst);
+ return result;
+}
+
+unsigned char *
+evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size)
+{
+ struct evbuffer_chain *chain, *next, *tmp, *last_with_data;
+ unsigned char *buffer, *result = NULL;
+ ev_ssize_t remaining;
+ int removed_last_with_data = 0;
+ int removed_last_with_datap = 0;
+
+ EVBUFFER_LOCK(buf);
+
+ chain = buf->first;
+
+ if (size < 0)
+ size = buf->total_len;
+ /* if size > buf->total_len, we cannot guarantee to the user that she
+ * is going to have a long enough buffer afterwards; so we return
+ * NULL */
+ if (size == 0 || (size_t)size > buf->total_len)
+ goto done;
+
+ /* No need to pull up anything; the first size bytes are
+ * already here. */
+ if (chain->off >= (size_t)size) {
+ result = chain->buffer + chain->misalign;
+ goto done;
+ }
+
+ /* Make sure that none of the chains we need to copy from is pinned. */
+ remaining = size - chain->off;
+ EVUTIL_ASSERT(remaining >= 0);
+ for (tmp=chain->next; tmp; tmp=tmp->next) {
+ if (CHAIN_PINNED(tmp))
+ goto done;
+ if (tmp->off >= (size_t)remaining)
+ break;
+ remaining -= tmp->off;
+ }
+
+ if (CHAIN_PINNED(chain)) {
+ size_t old_off = chain->off;
+ if (CHAIN_SPACE_LEN(chain) < size - chain->off) {
+ /* not enough room at end of chunk. */
+ goto done;
+ }
+ buffer = CHAIN_SPACE_PTR(chain);
+ tmp = chain;
+ tmp->off = size;
+ size -= old_off;
+ chain = chain->next;
+ } else if (chain->buffer_len - chain->misalign >= (size_t)size) {
+ /* already have enough space in the first chain */
+ size_t old_off = chain->off;
+ buffer = chain->buffer + chain->misalign + chain->off;
+ tmp = chain;
+ tmp->off = size;
+ size -= old_off;
+ chain = chain->next;
+ } else {
+ if ((tmp = evbuffer_chain_new(size)) == NULL) {
+ event_warn("%s: out of memory", __func__);
+ goto done;
+ }
+ buffer = tmp->buffer;
+ tmp->off = size;
+ buf->first = tmp;
+ }
+
+ /* TODO(niels): deal with buffers that point to NULL like sendfile */
+
+ /* Copy and free every chunk that will be entirely pulled into tmp */
+ last_with_data = *buf->last_with_datap;
+ for (; chain != NULL && (size_t)size >= chain->off; chain = next) {
+ next = chain->next;
+
+ memcpy(buffer, chain->buffer + chain->misalign, chain->off);
+ size -= chain->off;
+ buffer += chain->off;
+ if (chain == last_with_data)
+ removed_last_with_data = 1;
+ if (&chain->next == buf->last_with_datap)
+ removed_last_with_datap = 1;
+
+ evbuffer_chain_free(chain);
+ }
+
+ if (chain != NULL) {
+ memcpy(buffer, chain->buffer + chain->misalign, size);
+ chain->misalign += size;
+ chain->off -= size;
+ } else {
+ buf->last = tmp;
+ }
+
+ tmp->next = chain;
+
+ if (removed_last_with_data) {
+ buf->last_with_datap = &buf->first;
+ } else if (removed_last_with_datap) {
+ if (buf->first->next && buf->first->next->off)
+ buf->last_with_datap = &buf->first->next;
+ else
+ buf->last_with_datap = &buf->first;
+ }
+
+ result = (tmp->buffer + tmp->misalign);
+
+done:
+ EVBUFFER_UNLOCK(buf);
+ return result;
+}
+
+/*
+ * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
+ * The returned buffer needs to be freed by the called.
+ */
+char *
+evbuffer_readline(struct evbuffer *buffer)
+{
+ return evbuffer_readln(buffer, NULL, EVBUFFER_EOL_ANY);
+}
+
+static inline ev_ssize_t
+evbuffer_strchr(struct evbuffer_ptr *it, const char chr)
+{
+ struct evbuffer_chain *chain = it->internal_.chain;
+ size_t i = it->internal_.pos_in_chain;
+ while (chain != NULL) {
+ char *buffer = (char *)chain->buffer + chain->misalign;
+ char *cp = memchr(buffer+i, chr, chain->off-i);
+ if (cp) {
+ it->internal_.chain = chain;
+ it->internal_.pos_in_chain = cp - buffer;
+ it->pos += (cp - buffer - i);
+ return it->pos;
+ }
+ it->pos += chain->off - i;
+ i = 0;
+ chain = chain->next;
+ }
+
+ return (-1);
+}
+
+static inline char *
+find_eol_char(char *s, size_t len)
+{
+#define CHUNK_SZ 128
+ /* Lots of benchmarking found this approach to be faster in practice
+ * than doing two memchrs over the whole buffer, doin a memchr on each
+ * char of the buffer, or trying to emulate memchr by hand. */
+ char *s_end, *cr, *lf;
+ s_end = s+len;
+ while (s < s_end) {
+ size_t chunk = (s + CHUNK_SZ < s_end) ? CHUNK_SZ : (s_end - s);
+ cr = memchr(s, '\r', chunk);
+ lf = memchr(s, '\n', chunk);
+ if (cr) {
+ if (lf && lf < cr)
+ return lf;
+ return cr;
+ } else if (lf) {
+ return lf;
+ }
+ s += CHUNK_SZ;
+ }
+
+ return NULL;
+#undef CHUNK_SZ
+}
+
+static ev_ssize_t
+evbuffer_find_eol_char(struct evbuffer_ptr *it)
+{
+ struct evbuffer_chain *chain = it->internal_.chain;
+ size_t i = it->internal_.pos_in_chain;
+ while (chain != NULL) {
+ char *buffer = (char *)chain->buffer + chain->misalign;
+ char *cp = find_eol_char(buffer+i, chain->off-i);
+ if (cp) {
+ it->internal_.chain = chain;
+ it->internal_.pos_in_chain = cp - buffer;
+ it->pos += (cp - buffer) - i;
+ return it->pos;
+ }
+ it->pos += chain->off - i;
+ i = 0;
+ chain = chain->next;
+ }
+
+ return (-1);
+}
+
+static inline int
+evbuffer_strspn(
+ struct evbuffer_ptr *ptr, const char *chrset)
+{
+ int count = 0;
+ struct evbuffer_chain *chain = ptr->internal_.chain;
+ size_t i = ptr->internal_.pos_in_chain;
+
+ if (!chain)
+ return 0;
+
+ while (1) {
+ char *buffer = (char *)chain->buffer + chain->misalign;
+ for (; i < chain->off; ++i) {
+ const char *p = chrset;
+ while (*p) {
+ if (buffer[i] == *p++)
+ goto next;
+ }
+ ptr->internal_.chain = chain;
+ ptr->internal_.pos_in_chain = i;
+ ptr->pos += count;
+ return count;
+ next:
+ ++count;
+ }
+ i = 0;
+
+ if (! chain->next) {
+ ptr->internal_.chain = chain;
+ ptr->internal_.pos_in_chain = i;
+ ptr->pos += count;
+ return count;
+ }
+
+ chain = chain->next;
+ }
+}
+
+
+static inline int
+evbuffer_getchr(struct evbuffer_ptr *it)
+{
+ struct evbuffer_chain *chain = it->internal_.chain;
+ size_t off = it->internal_.pos_in_chain;
+
+ if (chain == NULL)
+ return -1;
+
+ return (unsigned char)chain->buffer[chain->misalign + off];
+}
+
+struct evbuffer_ptr
+evbuffer_search_eol(struct evbuffer *buffer,
+ struct evbuffer_ptr *start, size_t *eol_len_out,
+ enum evbuffer_eol_style eol_style)
+{
+ struct evbuffer_ptr it, it2;
+ size_t extra_drain = 0;
+ int ok = 0;
+
+ /* Avoid locking in trivial edge cases */
+ if (start && start->internal_.chain == NULL) {
+ PTR_NOT_FOUND(&it);
+ if (eol_len_out)
+ *eol_len_out = extra_drain;
+ return it;
+ }
+
+ EVBUFFER_LOCK(buffer);
+
+ if (start) {
+ memcpy(&it, start, sizeof(it));
+ } else {
+ it.pos = 0;
+ it.internal_.chain = buffer->first;
+ it.internal_.pos_in_chain = 0;
+ }
+
+ /* the eol_style determines our first stop character and how many
+ * characters we are going to drain afterwards. */
+ switch (eol_style) {
+ case EVBUFFER_EOL_ANY:
+ if (evbuffer_find_eol_char(&it) < 0)
+ goto done;
+ memcpy(&it2, &it, sizeof(it));
+ extra_drain = evbuffer_strspn(&it2, "\r\n");
+ break;
+ case EVBUFFER_EOL_CRLF_STRICT: {
+ it = evbuffer_search(buffer, "\r\n", 2, &it);
+ if (it.pos < 0)
+ goto done;
+ extra_drain = 2;
+ break;
+ }
+ case EVBUFFER_EOL_CRLF: {
+ ev_ssize_t start_pos = it.pos;
+ /* Look for a LF ... */
+ if (evbuffer_strchr(&it, '\n') < 0)
+ goto done;
+ extra_drain = 1;
+ /* ... optionally preceeded by a CR. */
+ if (it.pos == start_pos)
+ break; /* If the first character is \n, don't back up */
+ /* This potentially does an extra linear walk over the first
+ * few chains. Probably, that's not too expensive unless you
+ * have a really pathological setup. */
+ memcpy(&it2, &it, sizeof(it));
+ if (evbuffer_ptr_subtract(buffer, &it2, 1)<0)
+ break;
+ if (evbuffer_getchr(&it2) == '\r') {
+ memcpy(&it, &it2, sizeof(it));
+ extra_drain = 2;
+ }
+ break;
+ }
+ case EVBUFFER_EOL_LF:
+ if (evbuffer_strchr(&it, '\n') < 0)
+ goto done;
+ extra_drain = 1;
+ break;
+ case EVBUFFER_EOL_NUL:
+ if (evbuffer_strchr(&it, '\0') < 0)
+ goto done;
+ extra_drain = 1;
+ break;
+ default:
+ goto done;
+ }
+
+ ok = 1;
+done:
+ EVBUFFER_UNLOCK(buffer);
+
+ if (!ok)
+ PTR_NOT_FOUND(&it);
+ if (eol_len_out)
+ *eol_len_out = extra_drain;
+
+ return it;
+}
+
+char *
+evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
+ enum evbuffer_eol_style eol_style)
+{
+ struct evbuffer_ptr it;
+ char *line;
+ size_t n_to_copy=0, extra_drain=0;
+ char *result = NULL;
+
+ EVBUFFER_LOCK(buffer);
+
+ if (buffer->freeze_start) {
+ goto done;
+ }
+
+ it = evbuffer_search_eol(buffer, NULL, &extra_drain, eol_style);
+ if (it.pos < 0)
+ goto done;
+ n_to_copy = it.pos;
+
+ if ((line = mm_malloc(n_to_copy+1)) == NULL) {
+ event_warn("%s: out of memory", __func__);
+ goto done;
+ }
+
+ evbuffer_remove(buffer, line, n_to_copy);
+ line[n_to_copy] = '\0';
+
+ evbuffer_drain(buffer, extra_drain);
+ result = line;
+done:
+ EVBUFFER_UNLOCK(buffer);
+
+ if (n_read_out)
+ *n_read_out = result ? n_to_copy : 0;
+
+ return result;
+}
+
+#define EVBUFFER_CHAIN_MAX_AUTO_SIZE 4096
+
+/* Adds data to an event buffer */
+
+int
+evbuffer_add(struct evbuffer *buf, const void *data_in, size_t datlen)
+{
+ struct evbuffer_chain *chain, *tmp;
+ const unsigned char *data = data_in;
+ size_t remain, to_alloc;
+ int result = -1;
+
+ EVBUFFER_LOCK(buf);
+
+ if (buf->freeze_end) {
+ goto done;
+ }
+ /* Prevent buf->total_len overflow */
+ if (datlen > EV_SIZE_MAX - buf->total_len) {
+ goto done;
+ }
+
+ if (*buf->last_with_datap == NULL) {
+ chain = buf->last;
+ } else {
+ chain = *buf->last_with_datap;
+ }
+
+ /* If there are no chains allocated for this buffer, allocate one
+ * big enough to hold all the data. */
+ if (chain == NULL) {
+ chain = evbuffer_chain_new(datlen);
+ if (!chain)
+ goto done;
+ evbuffer_chain_insert(buf, chain);
+ }
+
+ if ((chain->flags & EVBUFFER_IMMUTABLE) == 0) {
+ /* Always true for mutable buffers */
+ EVUTIL_ASSERT(chain->misalign >= 0 &&
+ (ev_uint64_t)chain->misalign <= EVBUFFER_CHAIN_MAX);
+ remain = chain->buffer_len - (size_t)chain->misalign - chain->off;
+ if (remain >= datlen) {
+ /* there's enough space to hold all the data in the
+ * current last chain */
+ memcpy(chain->buffer + chain->misalign + chain->off,
+ data, datlen);
+ chain->off += datlen;
+ buf->total_len += datlen;
+ buf->n_add_for_cb += datlen;
+ goto out;
+ } else if (!CHAIN_PINNED(chain) &&
+ evbuffer_chain_should_realign(chain, datlen)) {
+ /* we can fit the data into the misalignment */
+ evbuffer_chain_align(chain);
+
+ memcpy(chain->buffer + chain->off, data, datlen);
+ chain->off += datlen;
+ buf->total_len += datlen;
+ buf->n_add_for_cb += datlen;
+ goto out;
+ }
+ } else {
+ /* we cannot write any data to the last chain */
+ remain = 0;
+ }
+
+ /* we need to add another chain */
+ to_alloc = chain->buffer_len;
+ if (to_alloc <= EVBUFFER_CHAIN_MAX_AUTO_SIZE/2)
+ to_alloc <<= 1;
+ if (datlen > to_alloc)
+ to_alloc = datlen;
+ tmp = evbuffer_chain_new(to_alloc);
+ if (tmp == NULL)
+ goto done;
+
+ if (remain) {
+ memcpy(chain->buffer + chain->misalign + chain->off,
+ data, remain);
+ chain->off += remain;
+ buf->total_len += remain;
+ buf->n_add_for_cb += remain;
+ }
+
+ data += remain;
+ datlen -= remain;
+
+ memcpy(tmp->buffer, data, datlen);
+ tmp->off = datlen;
+ evbuffer_chain_insert(buf, tmp);
+ buf->n_add_for_cb += datlen;
+
+out:
+ evbuffer_invoke_callbacks_(buf);
+ result = 0;
+done:
+ EVBUFFER_UNLOCK(buf);
+ return result;
+}
+
+int
+evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
+{
+ struct evbuffer_chain *chain, *tmp;
+ int result = -1;
+
+ EVBUFFER_LOCK(buf);
+
+ if (buf->freeze_start) {
+ goto done;
+ }
+ if (datlen > EV_SIZE_MAX - buf->total_len) {
+ goto done;
+ }
+
+ chain = buf->first;
+
+ if (chain == NULL) {
+ chain = evbuffer_chain_new(datlen);
+ if (!chain)
+ goto done;
+ evbuffer_chain_insert(buf, chain);
+ }
+
+ /* we cannot touch immutable buffers */
+ if ((chain->flags & EVBUFFER_IMMUTABLE) == 0) {
+ /* Always true for mutable buffers */
+ EVUTIL_ASSERT(chain->misalign >= 0 &&
+ (ev_uint64_t)chain->misalign <= EVBUFFER_CHAIN_MAX);
+
+ /* If this chain is empty, we can treat it as
+ * 'empty at the beginning' rather than 'empty at the end' */
+ if (chain->off == 0)
+ chain->misalign = chain->buffer_len;
+
+ if ((size_t)chain->misalign >= datlen) {
+ /* we have enough space to fit everything */
+ memcpy(chain->buffer + chain->misalign - datlen,
+ data, datlen);
+ chain->off += datlen;
+ chain->misalign -= datlen;
+ buf->total_len += datlen;
+ buf->n_add_for_cb += datlen;
+ goto out;
+ } else if (chain->misalign) {
+ /* we can only fit some of the data. */
+ memcpy(chain->buffer,
+ (char*)data + datlen - chain->misalign,
+ (size_t)chain->misalign);
+ chain->off += (size_t)chain->misalign;
+ buf->total_len += (size_t)chain->misalign;
+ buf->n_add_for_cb += (size_t)chain->misalign;
+ datlen -= (size_t)chain->misalign;
+ chain->misalign = 0;
+ }
+ }
+
+ /* we need to add another chain */
+ if ((tmp = evbuffer_chain_new(datlen)) == NULL)
+ goto done;
+ buf->first = tmp;
+ if (buf->last_with_datap == &buf->first)
+ buf->last_with_datap = &tmp->next;
+
+ tmp->next = chain;
+
+ tmp->off = datlen;
+ EVUTIL_ASSERT(datlen <= tmp->buffer_len);
+ tmp->misalign = tmp->buffer_len - datlen;
+
+ memcpy(tmp->buffer + tmp->misalign, data, datlen);
+ buf->total_len += datlen;
+ buf->n_add_for_cb += datlen;
+
+out:
+ evbuffer_invoke_callbacks_(buf);
+ result = 0;
+done:
+ EVBUFFER_UNLOCK(buf);
+ return result;
+}
+
+/** Helper: realigns the memory in chain->buffer so that misalign is 0. */
+static void
+evbuffer_chain_align(struct evbuffer_chain *chain)
+{
+ EVUTIL_ASSERT(!(chain->flags & EVBUFFER_IMMUTABLE));
+ EVUTIL_ASSERT(!(chain->flags & EVBUFFER_MEM_PINNED_ANY));
+ memmove(chain->buffer, chain->buffer + chain->misalign, chain->off);
+ chain->misalign = 0;
+}
+
+#define MAX_TO_COPY_IN_EXPAND 4096
+#define MAX_TO_REALIGN_IN_EXPAND 2048
+
+/** Helper: return true iff we should realign chain to fit datalen bytes of
+ data in it. */
+static int
+evbuffer_chain_should_realign(struct evbuffer_chain *chain,
+ size_t datlen)
+{
+ return chain->buffer_len - chain->off >= datlen &&
+ (chain->off < chain->buffer_len / 2) &&
+ (chain->off <= MAX_TO_REALIGN_IN_EXPAND);
+}
+
+/* Expands the available space in the event buffer to at least datlen, all in
+ * a single chunk. Return that chunk. */
+static struct evbuffer_chain *
+evbuffer_expand_singlechain(struct evbuffer *buf, size_t datlen)
+{
+ struct evbuffer_chain *chain, **chainp;
+ struct evbuffer_chain *result = NULL;
+ ASSERT_EVBUFFER_LOCKED(buf);
+
+ chainp = buf->last_with_datap;
+
+ /* XXX If *chainp is no longer writeable, but has enough space in its
+ * misalign, this might be a bad idea: we could still use *chainp, not
+ * (*chainp)->next. */
+ if (*chainp && CHAIN_SPACE_LEN(*chainp) == 0)
+ chainp = &(*chainp)->next;
+
+ /* 'chain' now points to the first chain with writable space (if any)
+ * We will either use it, realign it, replace it, or resize it. */
+ chain = *chainp;
+
+ if (chain == NULL ||
+ (chain->flags & (EVBUFFER_IMMUTABLE|EVBUFFER_MEM_PINNED_ANY))) {
+ /* We can't use the last_with_data chain at all. Just add a
+ * new one that's big enough. */
+ goto insert_new;
+ }
+
+ /* If we can fit all the data, then we don't have to do anything */
+ if (CHAIN_SPACE_LEN(chain) >= datlen) {
+ result = chain;
+ goto ok;
+ }
+
+ /* If the chain is completely empty, just replace it by adding a new
+ * empty chain. */
+ if (chain->off == 0) {
+ goto insert_new;
+ }
+
+ /* If the misalignment plus the remaining space fulfills our data
+ * needs, we could just force an alignment to happen. Afterwards, we
+ * have enough space. But only do this if we're saving a lot of space
+ * and not moving too much data. Otherwise the space savings are
+ * probably offset by the time lost in copying.
+ */
+ if (evbuffer_chain_should_realign(chain, datlen)) {
+ evbuffer_chain_align(chain);
+ result = chain;
+ goto ok;
+ }
+
+ /* At this point, we can either resize the last chunk with space in
+ * it, use the next chunk after it, or If we add a new chunk, we waste
+ * CHAIN_SPACE_LEN(chain) bytes in the former last chunk. If we
+ * resize, we have to copy chain->off bytes.
+ */
+
+ /* Would expanding this chunk be affordable and worthwhile? */
+ if (CHAIN_SPACE_LEN(chain) < chain->buffer_len / 8 ||
+ chain->off > MAX_TO_COPY_IN_EXPAND ||
+ datlen >= (EVBUFFER_CHAIN_MAX - chain->off)) {
+ /* It's not worth resizing this chain. Can the next one be
+ * used? */
+ if (chain->next && CHAIN_SPACE_LEN(chain->next) >= datlen) {
+ /* Yes, we can just use the next chain (which should
+ * be empty. */
+ result = chain->next;
+ goto ok;
+ } else {
+ /* No; append a new chain (which will free all
+ * terminal empty chains.) */
+ goto insert_new;
+ }
+ } else {
+ /* Okay, we're going to try to resize this chain: Not doing so
+ * would waste at least 1/8 of its current allocation, and we
+ * can do so without having to copy more than
+ * MAX_TO_COPY_IN_EXPAND bytes. */
+ /* figure out how much space we need */
+ size_t length = chain->off + datlen;
+ struct evbuffer_chain *tmp = evbuffer_chain_new(length);
+ if (tmp == NULL)
+ goto err;
+
+ /* copy the data over that we had so far */
+ tmp->off = chain->off;
+ memcpy(tmp->buffer, chain->buffer + chain->misalign,
+ chain->off);
+ /* fix up the list */
+ EVUTIL_ASSERT(*chainp == chain);
+ result = *chainp = tmp;
+
+ if (buf->last == chain)
+ buf->last = tmp;
+
+ tmp->next = chain->next;
+ evbuffer_chain_free(chain);
+ goto ok;
+ }
+
+insert_new:
+ result = evbuffer_chain_insert_new(buf, datlen);
+ if (!result)
+ goto err;
+ok:
+ EVUTIL_ASSERT(result);
+ EVUTIL_ASSERT(CHAIN_SPACE_LEN(result) >= datlen);
+err:
+ return result;
+}
+
+/* Make sure that datlen bytes are available for writing in the last n
+ * chains. Never copies or moves data. */
+int
+evbuffer_expand_fast_(struct evbuffer *buf, size_t datlen, int n)
+{
+ struct evbuffer_chain *chain = buf->last, *tmp, *next;
+ size_t avail;
+ int used;
+
+ ASSERT_EVBUFFER_LOCKED(buf);
+ EVUTIL_ASSERT(n >= 2);
+
+ if (chain == NULL || (chain->flags & EVBUFFER_IMMUTABLE)) {
+ /* There is no last chunk, or we can't touch the last chunk.
+ * Just add a new chunk. */
+ chain = evbuffer_chain_new(datlen);
+ if (chain == NULL)
+ return (-1);
+
+ evbuffer_chain_insert(buf, chain);
+ return (0);
+ }
+
+ used = 0; /* number of chains we're using space in. */
+ avail = 0; /* how much space they have. */
+ /* How many bytes can we stick at the end of buffer as it is? Iterate
+ * over the chains at the end of the buffer, tring to see how much
+ * space we have in the first n. */
+ for (chain = *buf->last_with_datap; chain; chain = chain->next) {
+ if (chain->off) {
+ size_t space = (size_t) CHAIN_SPACE_LEN(chain);
+ EVUTIL_ASSERT(chain == *buf->last_with_datap);
+ if (space) {
+ avail += space;
+ ++used;
+ }
+ } else {
+ /* No data in chain; realign it. */
+ chain->misalign = 0;
+ avail += chain->buffer_len;
+ ++used;
+ }
+ if (avail >= datlen) {
+ /* There is already enough space. Just return */
+ return (0);
+ }
+ if (used == n)
+ break;
+ }
+
+ /* There wasn't enough space in the first n chains with space in
+ * them. Either add a new chain with enough space, or replace all
+ * empty chains with one that has enough space, depending on n. */
+ if (used < n) {
+ /* The loop ran off the end of the chains before it hit n
+ * chains; we can add another. */
+ EVUTIL_ASSERT(chain == NULL);
+
+ tmp = evbuffer_chain_new(datlen - avail);
+ if (tmp == NULL)
+ return (-1);
+
+ buf->last->next = tmp;
+ buf->last = tmp;
+ /* (we would only set last_with_data if we added the first
+ * chain. But if the buffer had no chains, we would have
+ * just allocated a new chain earlier) */
+ return (0);
+ } else {
+ /* Nuke _all_ the empty chains. */
+ int rmv_all = 0; /* True iff we removed last_with_data. */
+ chain = *buf->last_with_datap;
+ if (!chain->off) {
+ EVUTIL_ASSERT(chain == buf->first);
+ rmv_all = 1;
+ avail = 0;
+ } else {
+ /* can't overflow, since only mutable chains have
+ * huge misaligns. */
+ avail = (size_t) CHAIN_SPACE_LEN(chain);
+ chain = chain->next;
+ }
+
+
+ for (; chain; chain = next) {
+ next = chain->next;
+ EVUTIL_ASSERT(chain->off == 0);
+ evbuffer_chain_free(chain);
+ }
+ EVUTIL_ASSERT(datlen >= avail);
+ tmp = evbuffer_chain_new(datlen - avail);
+ if (tmp == NULL) {
+ if (rmv_all) {
+ ZERO_CHAIN(buf);
+ } else {
+ buf->last = *buf->last_with_datap;
+ (*buf->last_with_datap)->next = NULL;
+ }
+ return (-1);
+ }
+
+ if (rmv_all) {
+ buf->first = buf->last = tmp;
+ buf->last_with_datap = &buf->first;
+ } else {
+ (*buf->last_with_datap)->next = tmp;
+ buf->last = tmp;
+ }
+ return (0);
+ }
+}
+
+int
+evbuffer_expand(struct evbuffer *buf, size_t datlen)
+{
+ struct evbuffer_chain *chain;
+
+ EVBUFFER_LOCK(buf);
+ chain = evbuffer_expand_singlechain(buf, datlen);
+ EVBUFFER_UNLOCK(buf);
+ return chain ? 0 : -1;
+}
+
+/*
+ * Reads data from a file descriptor into a buffer.
+ */
+
+#if defined(EVENT__HAVE_SYS_UIO_H) || defined(_WIN32)
+#define USE_IOVEC_IMPL
+#endif
+
+#ifdef USE_IOVEC_IMPL
+
+#ifdef EVENT__HAVE_SYS_UIO_H
+/* number of iovec we use for writev, fragmentation is going to determine
+ * how much we end up writing */
+
+#define DEFAULT_WRITE_IOVEC 128
+
+#if defined(UIO_MAXIOV) && UIO_MAXIOV < DEFAULT_WRITE_IOVEC
+#define NUM_WRITE_IOVEC UIO_MAXIOV
+#elif defined(IOV_MAX) && IOV_MAX < DEFAULT_WRITE_IOVEC
+#define NUM_WRITE_IOVEC IOV_MAX
+#else
+#define NUM_WRITE_IOVEC DEFAULT_WRITE_IOVEC
+#endif
+
+#define IOV_TYPE struct iovec
+#define IOV_PTR_FIELD iov_base
+#define IOV_LEN_FIELD iov_len
+#define IOV_LEN_TYPE size_t
+#else
+#define NUM_WRITE_IOVEC 16
+#define IOV_TYPE WSABUF
+#define IOV_PTR_FIELD buf
+#define IOV_LEN_FIELD len
+#define IOV_LEN_TYPE unsigned long
+#endif
+#endif
+#define NUM_READ_IOVEC 4
+
+#define EVBUFFER_MAX_READ 4096
+
+/** Helper function to figure out which space to use for reading data into
+ an evbuffer. Internal use only.
+
+ @param buf The buffer to read into
+ @param howmuch How much we want to read.
+ @param vecs An array of two or more iovecs or WSABUFs.
+ @param n_vecs_avail The length of vecs
+ @param chainp A pointer to a variable to hold the first chain we're
+ reading into.
+ @param exact Boolean: if true, we do not provide more than 'howmuch'
+ space in the vectors, even if more space is available.
+ @return The number of buffers we're using.
+ */
+int
+evbuffer_read_setup_vecs_(struct evbuffer *buf, ev_ssize_t howmuch,
+ struct evbuffer_iovec *vecs, int n_vecs_avail,
+ struct evbuffer_chain ***chainp, int exact)
+{
+ struct evbuffer_chain *chain;
+ struct evbuffer_chain **firstchainp;
+ size_t so_far;
+ int i;
+ ASSERT_EVBUFFER_LOCKED(buf);
+
+ if (howmuch < 0)
+ return -1;
+
+ so_far = 0;
+ /* Let firstchain be the first chain with any space on it */
+ firstchainp = buf->last_with_datap;
+ if (CHAIN_SPACE_LEN(*firstchainp) == 0) {
+ firstchainp = &(*firstchainp)->next;
+ }
+
+ chain = *firstchainp;
+ for (i = 0; i < n_vecs_avail && so_far < (size_t)howmuch; ++i) {
+ size_t avail = (size_t) CHAIN_SPACE_LEN(chain);
+ if (avail > (howmuch - so_far) && exact)
+ avail = howmuch - so_far;
+ vecs[i].iov_base = (void *)CHAIN_SPACE_PTR(chain);
+ vecs[i].iov_len = avail;
+ so_far += avail;
+ chain = chain->next;
+ }
+
+ *chainp = firstchainp;
+ return i;
+}
+
+static int
+get_n_bytes_readable_on_socket(evutil_socket_t fd)
+{
+#if defined(FIONREAD) && defined(_WIN32)
+ unsigned long lng = EVBUFFER_MAX_READ;
+ if (ioctlsocket(fd, FIONREAD, &lng) < 0)
+ return -1;
+ /* Can overflow, but mostly harmlessly. XXXX */
+ return (int)lng;
+#elif defined(FIONREAD)
+ int n = EVBUFFER_MAX_READ;
+ if (ioctl(fd, FIONREAD, &n) < 0)
+ return -1;
+ return n;
+#else
+ return EVBUFFER_MAX_READ;
+#endif
+}
+
+/* TODO(niels): should this function return ev_ssize_t and take ev_ssize_t
+ * as howmuch? */
+int
+evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
+{
+ struct evbuffer_chain **chainp;
+ int n;
+ int result;
+
+#ifdef USE_IOVEC_IMPL
+ int nvecs, i, remaining;
+#else
+ struct evbuffer_chain *chain;
+ unsigned char *p;
+#endif
+
+ EVBUFFER_LOCK(buf);
+
+ if (buf->freeze_end) {
+ result = -1;
+ goto done;
+ }
+
+ n = get_n_bytes_readable_on_socket(fd);
+ if (n <= 0 || n > EVBUFFER_MAX_READ)
+ n = EVBUFFER_MAX_READ;
+ if (howmuch < 0 || howmuch > n)
+ howmuch = n;
+
+#ifdef USE_IOVEC_IMPL
+ /* Since we can use iovecs, we're willing to use the last
+ * NUM_READ_IOVEC chains. */
+ if (evbuffer_expand_fast_(buf, howmuch, NUM_READ_IOVEC) == -1) {
+ result = -1;
+ goto done;
+ } else {
+ IOV_TYPE vecs[NUM_READ_IOVEC];
+#ifdef EVBUFFER_IOVEC_IS_NATIVE_
+ nvecs = evbuffer_read_setup_vecs_(buf, howmuch, vecs,
+ NUM_READ_IOVEC, &chainp, 1);
+#else
+ /* We aren't using the native struct iovec. Therefore,
+ we are on win32. */
+ struct evbuffer_iovec ev_vecs[NUM_READ_IOVEC];
+ nvecs = evbuffer_read_setup_vecs_(buf, howmuch, ev_vecs, 2,
+ &chainp, 1);
+
+ for (i=0; i < nvecs; ++i)
+ WSABUF_FROM_EVBUFFER_IOV(&vecs[i], &ev_vecs[i]);
+#endif
+
+#ifdef _WIN32
+ {
+ DWORD bytesRead;
+ DWORD flags=0;
+ if (WSARecv(fd, vecs, nvecs, &bytesRead, &flags, NULL, NULL)) {
+ /* The read failed. It might be a close,
+ * or it might be an error. */
+ if (WSAGetLastError() == WSAECONNABORTED)
+ n = 0;
+ else
+ n = -1;
+ } else
+ n = bytesRead;
+ }
+#else
+ n = readv(fd, vecs, nvecs);
+#endif
+ }
+
+#else /*!USE_IOVEC_IMPL*/
+ /* If we don't have FIONREAD, we might waste some space here */
+ /* XXX we _will_ waste some space here if there is any space left
+ * over on buf->last. */
+ if ((chain = evbuffer_expand_singlechain(buf, howmuch)) == NULL) {
+ result = -1;
+ goto done;
+ }
+
+ /* We can append new data at this point */
+ p = chain->buffer + chain->misalign + chain->off;
+
+#ifndef _WIN32
+ n = read(fd, p, howmuch);
+#else
+ n = recv(fd, p, howmuch, 0);
+#endif
+#endif /* USE_IOVEC_IMPL */
+
+ if (n == -1) {
+ result = -1;
+ goto done;
+ }
+ if (n == 0) {
+ result = 0;
+ goto done;
+ }
+
+#ifdef USE_IOVEC_IMPL
+ remaining = n;
+ for (i=0; i < nvecs; ++i) {
+ /* can't overflow, since only mutable chains have
+ * huge misaligns. */
+ size_t space = (size_t) CHAIN_SPACE_LEN(*chainp);
+ /* XXXX This is a kludge that can waste space in perverse
+ * situations. */
+ if (space > EVBUFFER_CHAIN_MAX)
+ space = EVBUFFER_CHAIN_MAX;
+ if ((ev_ssize_t)space < remaining) {
+ (*chainp)->off += space;
+ remaining -= (int)space;
+ } else {
+ (*chainp)->off += remaining;
+ buf->last_with_datap = chainp;
+ break;
+ }
+ chainp = &(*chainp)->next;
+ }
+#else
+ chain->off += n;
+ advance_last_with_data(buf);
+#endif
+ buf->total_len += n;
+ buf->n_add_for_cb += n;
+
+ /* Tell someone about changes in this buffer */
+ evbuffer_invoke_callbacks_(buf);
+ result = n;
+done:
+ EVBUFFER_UNLOCK(buf);
+ return result;
+}
+
+#ifdef USE_IOVEC_IMPL
+static inline int
+evbuffer_write_iovec(struct evbuffer *buffer, evutil_socket_t fd,
+ ev_ssize_t howmuch)
+{
+ IOV_TYPE iov[NUM_WRITE_IOVEC];
+ struct evbuffer_chain *chain = buffer->first;
+ int n, i = 0;
+
+ if (howmuch < 0)
+ return -1;
+
+ ASSERT_EVBUFFER_LOCKED(buffer);
+ /* XXX make this top out at some maximal data length? if the
+ * buffer has (say) 1MB in it, split over 128 chains, there's
+ * no way it all gets written in one go. */
+ while (chain != NULL && i < NUM_WRITE_IOVEC && howmuch) {
+#ifdef USE_SENDFILE
+ /* we cannot write the file info via writev */
+ if (chain->flags & EVBUFFER_SENDFILE)
+ break;
+#endif
+ iov[i].IOV_PTR_FIELD = (void *) (chain->buffer + chain->misalign);
+ if ((size_t)howmuch >= chain->off) {
+ /* XXXcould be problematic when windows supports mmap*/
+ iov[i++].IOV_LEN_FIELD = (IOV_LEN_TYPE)chain->off;
+ howmuch -= chain->off;
+ } else {
+ /* XXXcould be problematic when windows supports mmap*/
+ iov[i++].IOV_LEN_FIELD = (IOV_LEN_TYPE)howmuch;
+ break;
+ }
+ chain = chain->next;
+ }
+ if (! i)
+ return 0;
+
+#ifdef _WIN32
+ {
+ DWORD bytesSent;
+ if (WSASend(fd, iov, i, &bytesSent, 0, NULL, NULL))
+ n = -1;
+ else
+ n = bytesSent;
+ }
+#else
+ n = writev(fd, iov, i);
+#endif
+ return (n);
+}
+#endif
+
+#ifdef USE_SENDFILE
+static inline int
+evbuffer_write_sendfile(struct evbuffer *buffer, evutil_socket_t dest_fd,
+ ev_ssize_t howmuch)
+{
+ struct evbuffer_chain *chain = buffer->first;
+ struct evbuffer_chain_file_segment *info =
+ EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment,
+ chain);
+ const int source_fd = info->segment->fd;
+#if defined(SENDFILE_IS_MACOSX) || defined(SENDFILE_IS_FREEBSD)
+ int res;
+ ev_off_t len = chain->off;
+#elif defined(SENDFILE_IS_LINUX) || defined(SENDFILE_IS_SOLARIS)
+ ev_ssize_t res;
+ ev_off_t offset = chain->misalign;
+#endif
+
+ ASSERT_EVBUFFER_LOCKED(buffer);
+
+#if defined(SENDFILE_IS_MACOSX)
+ res = sendfile(source_fd, dest_fd, chain->misalign, &len, NULL, 0);
+ if (res == -1 && !EVUTIL_ERR_RW_RETRIABLE(errno))
+ return (-1);
+
+ return (len);
+#elif defined(SENDFILE_IS_FREEBSD)
+ res = sendfile(source_fd, dest_fd, chain->misalign, chain->off, NULL, &len, 0);
+ if (res == -1 && !EVUTIL_ERR_RW_RETRIABLE(errno))
+ return (-1);
+
+ return (len);
+#elif defined(SENDFILE_IS_LINUX)
+ /* TODO(niels): implement splice */
+ res = sendfile(dest_fd, source_fd, &offset, chain->off);
+ if (res == -1 && EVUTIL_ERR_RW_RETRIABLE(errno)) {
+ /* if this is EAGAIN or EINTR return 0; otherwise, -1 */
+ return (0);
+ }
+ return (res);
+#elif defined(SENDFILE_IS_SOLARIS)
+ {
+ const off_t offset_orig = offset;
+ res = sendfile(dest_fd, source_fd, &offset, chain->off);
+ if (res == -1 && EVUTIL_ERR_RW_RETRIABLE(errno)) {
+ if (offset - offset_orig)
+ return offset - offset_orig;
+ /* if this is EAGAIN or EINTR and no bytes were
+ * written, return 0 */
+ return (0);
+ }
+ return (res);
+ }
+#endif
+}
+#endif
+
+int
+evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd,
+ ev_ssize_t howmuch)
+{
+ int n = -1;
+
+ EVBUFFER_LOCK(buffer);
+
+ if (buffer->freeze_start) {
+ goto done;
+ }
+
+ if (howmuch < 0 || (size_t)howmuch > buffer->total_len)
+ howmuch = buffer->total_len;
+
+ if (howmuch > 0) {
+#ifdef USE_SENDFILE
+ struct evbuffer_chain *chain = buffer->first;
+ if (chain != NULL && (chain->flags & EVBUFFER_SENDFILE))
+ n = evbuffer_write_sendfile(buffer, fd, howmuch);
+ else {
+#endif
+#ifdef USE_IOVEC_IMPL
+ n = evbuffer_write_iovec(buffer, fd, howmuch);
+#elif defined(_WIN32)
+ /* XXX(nickm) Don't disable this code until we know if
+ * the WSARecv code above works. */
+ void *p = evbuffer_pullup(buffer, howmuch);
+ EVUTIL_ASSERT(p || !howmuch);
+ n = send(fd, p, howmuch, 0);
+#else
+ void *p = evbuffer_pullup(buffer, howmuch);
+ EVUTIL_ASSERT(p || !howmuch);
+ n = write(fd, p, howmuch);
+#endif
+#ifdef USE_SENDFILE
+ }
+#endif
+ }
+
+ if (n > 0)
+ evbuffer_drain(buffer, n);
+
+done:
+ EVBUFFER_UNLOCK(buffer);
+ return (n);
+}
+
+int
+evbuffer_write(struct evbuffer *buffer, evutil_socket_t fd)
+{
+ return evbuffer_write_atmost(buffer, fd, -1);
+}
+
+unsigned char *
+evbuffer_find(struct evbuffer *buffer, const unsigned char *what, size_t len)
+{
+ unsigned char *search;
+ struct evbuffer_ptr ptr;
+
+ EVBUFFER_LOCK(buffer);
+
+ ptr = evbuffer_search(buffer, (const char *)what, len, NULL);
+ if (ptr.pos < 0) {
+ search = NULL;
+ } else {
+ search = evbuffer_pullup(buffer, ptr.pos + len);
+ if (search)
+ search += ptr.pos;
+ }
+ EVBUFFER_UNLOCK(buffer);
+ return search;
+}
+
+/* Subract <b>howfar</b> from the position of <b>pos</b> within
+ * <b>buf</b>. Returns 0 on success, -1 on failure.
+ *
+ * This isn't exposed yet, because of potential inefficiency issues.
+ * Maybe it should be. */
+static int
+evbuffer_ptr_subtract(struct evbuffer *buf, struct evbuffer_ptr *pos,
+ size_t howfar)
+{
+ if (pos->pos < 0)
+ return -1;
+ if (howfar > (size_t)pos->pos)
+ return -1;
+ if (pos->internal_.chain && howfar <= pos->internal_.pos_in_chain) {
+ pos->internal_.pos_in_chain -= howfar;
+ pos->pos -= howfar;
+ return 0;
+ } else {
+ const size_t newpos = pos->pos - howfar;
+ /* Here's the inefficient part: it walks over the
+ * chains until we hit newpos. */
+ return evbuffer_ptr_set(buf, pos, newpos, EVBUFFER_PTR_SET);
+ }
+}
+
+int
+evbuffer_ptr_set(struct evbuffer *buf, struct evbuffer_ptr *pos,
+ size_t position, enum evbuffer_ptr_how how)
+{
+ size_t left = position;
+ struct evbuffer_chain *chain = NULL;
+ int result = 0;
+
+ EVBUFFER_LOCK(buf);
+
+ switch (how) {
+ case EVBUFFER_PTR_SET:
+ chain = buf->first;
+ pos->pos = position;
+ position = 0;
+ break;
+ case EVBUFFER_PTR_ADD:
+ /* this avoids iterating over all previous chains if
+ we just want to advance the position */
+ if (pos->pos < 0 || EV_SIZE_MAX - position < (size_t)pos->pos) {
+ EVBUFFER_UNLOCK(buf);
+ return -1;
+ }
+ chain = pos->internal_.chain;
+ pos->pos += position;
+ position = pos->internal_.pos_in_chain;
+ break;
+ }
+
+ EVUTIL_ASSERT(EV_SIZE_MAX - left >= position);
+ while (chain && position + left >= chain->off) {
+ left -= chain->off - position;
+ chain = chain->next;
+ position = 0;
+ }
+ if (chain) {
+ pos->internal_.chain = chain;
+ pos->internal_.pos_in_chain = position + left;
+ } else if (left == 0) {
+ /* The first byte in the (nonexistent) chain after the last chain */
+ pos->internal_.chain = NULL;
+ pos->internal_.pos_in_chain = 0;
+ } else {
+ PTR_NOT_FOUND(pos);
+ result = -1;
+ }
+
+ EVBUFFER_UNLOCK(buf);
+
+ return result;
+}
+
+/**
+ Compare the bytes in buf at position pos to the len bytes in mem. Return
+ less than 0, 0, or greater than 0 as memcmp.
+ */
+static int
+evbuffer_ptr_memcmp(const struct evbuffer *buf, const struct evbuffer_ptr *pos,
+ const char *mem, size_t len)
+{
+ struct evbuffer_chain *chain;
+ size_t position;
+ int r;
+
+ ASSERT_EVBUFFER_LOCKED(buf);
+
+ if (pos->pos < 0 ||
+ EV_SIZE_MAX - len < (size_t)pos->pos ||
+ pos->pos + len > buf->total_len)
+ return -1;
+
+ chain = pos->internal_.chain;
+ position = pos->internal_.pos_in_chain;
+ while (len && chain) {
+ size_t n_comparable;
+ if (len + position > chain->off)
+ n_comparable = chain->off - position;
+ else
+ n_comparable = len;
+ r = memcmp(chain->buffer + chain->misalign + position, mem,
+ n_comparable);
+ if (r)
+ return r;
+ mem += n_comparable;
+ len -= n_comparable;
+ position = 0;
+ chain = chain->next;
+ }
+
+ return 0;
+}
+
+struct evbuffer_ptr
+evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start)
+{
+ return evbuffer_search_range(buffer, what, len, start, NULL);
+}
+
+struct evbuffer_ptr
+evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start, const struct evbuffer_ptr *end)
+{
+ struct evbuffer_ptr pos;
+ struct evbuffer_chain *chain, *last_chain = NULL;
+ const unsigned char *p;
+ char first;
+
+ EVBUFFER_LOCK(buffer);
+
+ if (start) {
+ memcpy(&pos, start, sizeof(pos));
+ chain = pos.internal_.chain;
+ } else {
+ pos.pos = 0;
+ chain = pos.internal_.chain = buffer->first;
+ pos.internal_.pos_in_chain = 0;
+ }
+
+ if (end)
+ last_chain = end->internal_.chain;
+
+ if (!len || len > EV_SSIZE_MAX)
+ goto done;
+
+ first = what[0];
+
+ while (chain) {
+ const unsigned char *start_at =
+ chain->buffer + chain->misalign +
+ pos.internal_.pos_in_chain;
+ p = memchr(start_at, first,
+ chain->off - pos.internal_.pos_in_chain);
+ if (p) {
+ pos.pos += p - start_at;
+ pos.internal_.pos_in_chain += p - start_at;
+ if (!evbuffer_ptr_memcmp(buffer, &pos, what, len)) {
+ if (end && pos.pos + (ev_ssize_t)len > end->pos)
+ goto not_found;
+ else
+ goto done;
+ }
+ ++pos.pos;
+ ++pos.internal_.pos_in_chain;
+ if (pos.internal_.pos_in_chain == chain->off) {
+ chain = pos.internal_.chain = chain->next;
+ pos.internal_.pos_in_chain = 0;
+ }
+ } else {
+ if (chain == last_chain)
+ goto not_found;
+ pos.pos += chain->off - pos.internal_.pos_in_chain;
+ chain = pos.internal_.chain = chain->next;
+ pos.internal_.pos_in_chain = 0;
+ }
+ }
+
+not_found:
+ PTR_NOT_FOUND(&pos);
+done:
+ EVBUFFER_UNLOCK(buffer);
+ return pos;
+}
+
+int
+evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len,
+ struct evbuffer_ptr *start_at,
+ struct evbuffer_iovec *vec, int n_vec)
+{
+ struct evbuffer_chain *chain;
+ int idx = 0;
+ ev_ssize_t len_so_far = 0;
+
+ /* Avoid locking in trivial edge cases */
+ if (start_at && start_at->internal_.chain == NULL)
+ return 0;
+
+ EVBUFFER_LOCK(buffer);
+
+ if (start_at) {
+ chain = start_at->internal_.chain;
+ len_so_far = chain->off
+ - start_at->internal_.pos_in_chain;
+ idx = 1;
+ if (n_vec > 0) {
+ vec[0].iov_base = (void *)(chain->buffer + chain->misalign
+ + start_at->internal_.pos_in_chain);
+ vec[0].iov_len = len_so_far;
+ }
+ chain = chain->next;
+ } else {
+ chain = buffer->first;
+ }
+
+ if (n_vec == 0 && len < 0) {
+ /* If no vectors are provided and they asked for "everything",
+ * pretend they asked for the actual available amount. */
+ len = buffer->total_len;
+ if (start_at) {
+ len -= start_at->pos;
+ }
+ }
+
+ while (chain) {
+ if (len >= 0 && len_so_far >= len)
+ break;
+ if (idx<n_vec) {
+ vec[idx].iov_base = (void *)(chain->buffer + chain->misalign);
+ vec[idx].iov_len = chain->off;
+ } else if (len<0) {
+ break;
+ }
+ ++idx;
+ len_so_far += chain->off;
+ chain = chain->next;
+ }
+
+ EVBUFFER_UNLOCK(buffer);
+
+ return idx;
+}
+
+
+int
+evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
+{
+ char *buffer;
+ size_t space;
+ int sz, result = -1;
+ va_list aq;
+ struct evbuffer_chain *chain;
+
+
+ EVBUFFER_LOCK(buf);
+
+ if (buf->freeze_end) {
+ goto done;
+ }
+
+ /* make sure that at least some space is available */
+ if ((chain = evbuffer_expand_singlechain(buf, 64)) == NULL)
+ goto done;
+
+ for (;;) {
+#if 0
+ size_t used = chain->misalign + chain->off;
+ buffer = (char *)chain->buffer + chain->misalign + chain->off;
+ EVUTIL_ASSERT(chain->buffer_len >= used);
+ space = chain->buffer_len - used;
+#endif
+ buffer = (char*) CHAIN_SPACE_PTR(chain);
+ space = (size_t) CHAIN_SPACE_LEN(chain);
+
+#ifndef va_copy
+#define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list))
+#endif
+ va_copy(aq, ap);
+
+ sz = evutil_vsnprintf(buffer, space, fmt, aq);
+
+ va_end(aq);
+
+ if (sz < 0)
+ goto done;
+ if (INT_MAX >= EVBUFFER_CHAIN_MAX &&
+ (size_t)sz >= EVBUFFER_CHAIN_MAX)
+ goto done;
+ if ((size_t)sz < space) {
+ chain->off += sz;
+ buf->total_len += sz;
+ buf->n_add_for_cb += sz;
+
+ advance_last_with_data(buf);
+ evbuffer_invoke_callbacks_(buf);
+ result = sz;
+ goto done;
+ }
+ if ((chain = evbuffer_expand_singlechain(buf, sz + 1)) == NULL)
+ goto done;
+ }
+ /* NOTREACHED */
+
+done:
+ EVBUFFER_UNLOCK(buf);
+ return result;
+}
+
+int
+evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
+{
+ int res = -1;
+ va_list ap;
+
+ va_start(ap, fmt);
+ res = evbuffer_add_vprintf(buf, fmt, ap);
+ va_end(ap);
+
+ return (res);
+}
+
+int
+evbuffer_add_reference(struct evbuffer *outbuf,
+ const void *data, size_t datlen,
+ evbuffer_ref_cleanup_cb cleanupfn, void *extra)
+{
+ struct evbuffer_chain *chain;
+ struct evbuffer_chain_reference *info;
+ int result = -1;
+
+ chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_reference));
+ if (!chain)
+ return (-1);
+ chain->flags |= EVBUFFER_REFERENCE | EVBUFFER_IMMUTABLE;
+ chain->buffer = (unsigned char *)data;
+ chain->buffer_len = datlen;
+ chain->off = datlen;
+
+ info = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_reference, chain);
+ info->cleanupfn = cleanupfn;
+ info->extra = extra;
+
+ EVBUFFER_LOCK(outbuf);
+ if (outbuf->freeze_end) {
+ /* don't call chain_free; we do not want to actually invoke
+ * the cleanup function */
+ mm_free(chain);
+ goto done;
+ }
+ evbuffer_chain_insert(outbuf, chain);
+ outbuf->n_add_for_cb += datlen;
+
+ evbuffer_invoke_callbacks_(outbuf);
+
+ result = 0;
+done:
+ EVBUFFER_UNLOCK(outbuf);
+
+ return result;
+}
+
+/* TODO(niels): we may want to add to automagically convert to mmap, in
+ * case evbuffer_remove() or evbuffer_pullup() are being used.
+ */
+struct evbuffer_file_segment *
+evbuffer_file_segment_new(
+ int fd, ev_off_t offset, ev_off_t length, unsigned flags)
+{
+ struct evbuffer_file_segment *seg =
+ mm_calloc(sizeof(struct evbuffer_file_segment), 1);
+ if (!seg)
+ return NULL;
+ seg->refcnt = 1;
+ seg->fd = fd;
+ seg->flags = flags;
+ seg->file_offset = offset;
+ seg->cleanup_cb = NULL;
+ seg->cleanup_cb_arg = NULL;
+#ifdef _WIN32
+#ifndef lseek
+#define lseek _lseeki64
+#endif
+#ifndef fstat
+#define fstat _fstat
+#endif
+#ifndef stat
+#define stat _stat
+#endif
+#endif
+ if (length == -1) {
+ struct stat st;
+ if (fstat(fd, &st) < 0)
+ goto err;
+ length = st.st_size;
+ }
+ seg->length = length;
+
+ if (offset < 0 || length < 0 ||
+ ((ev_uint64_t)length > EVBUFFER_CHAIN_MAX) ||
+ (ev_uint64_t)offset > (ev_uint64_t)(EVBUFFER_CHAIN_MAX - length))
+ goto err;
+
+#if defined(USE_SENDFILE)
+ if (!(flags & EVBUF_FS_DISABLE_SENDFILE)) {
+ seg->can_sendfile = 1;
+ goto done;
+ }
+#endif
+
+ if (evbuffer_file_segment_materialize(seg)<0)
+ goto err;
+
+#if defined(USE_SENDFILE)
+done:
+#endif
+ if (!(flags & EVBUF_FS_DISABLE_LOCKING)) {
+ EVTHREAD_ALLOC_LOCK(seg->lock, 0);
+ }
+ return seg;
+err:
+ mm_free(seg);
+ return NULL;
+}
+
+#ifdef EVENT__HAVE_MMAP
+static long
+get_page_size(void)
+{
+#ifdef SC_PAGE_SIZE
+ return sysconf(SC_PAGE_SIZE);
+#elif defined(_SC_PAGE_SIZE)
+ return sysconf(_SC_PAGE_SIZE);
+#else
+ return 1;
+#endif
+}
+#endif
+
+/* DOCDOC */
+/* Requires lock */
+static int
+evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg)
+{
+ const unsigned flags = seg->flags;
+ const int fd = seg->fd;
+ const ev_off_t length = seg->length;
+ const ev_off_t offset = seg->file_offset;
+
+ if (seg->contents)
+ return 0; /* already materialized */
+
+#if defined(EVENT__HAVE_MMAP)
+ if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
+ off_t offset_rounded = 0, offset_leftover = 0;
+ void *mapped;
+ if (offset) {
+ /* mmap implementations don't generally like us
+ * to have an offset that isn't a round */
+ long page_size = get_page_size();
+ if (page_size == -1)
+ goto err;
+ offset_leftover = offset % page_size;
+ offset_rounded = offset - offset_leftover;
+ }
+ mapped = mmap(NULL, length + offset_leftover,
+ PROT_READ,
+#ifdef MAP_NOCACHE
+ MAP_NOCACHE | /* ??? */
+#endif
+#ifdef MAP_FILE
+ MAP_FILE |
+#endif
+ MAP_PRIVATE,
+ fd, offset_rounded);
+ if (mapped == MAP_FAILED) {
+ event_warn("%s: mmap(%d, %d, %zu) failed",
+ __func__, fd, 0, (size_t)(offset + length));
+ } else {
+ seg->mapping = mapped;
+ seg->contents = (char*)mapped+offset_leftover;
+ seg->mmap_offset = 0;
+ seg->is_mapping = 1;
+ goto done;
+ }
+ }
+#endif
+#ifdef _WIN32
+ if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
+ intptr_t h = _get_osfhandle(fd);
+ HANDLE m;
+ ev_uint64_t total_size = length+offset;
+ if ((HANDLE)h == INVALID_HANDLE_VALUE)
+ goto err;
+ m = CreateFileMapping((HANDLE)h, NULL, PAGE_READONLY,
+ (total_size >> 32), total_size & 0xfffffffful,
+ NULL);
+ if (m != INVALID_HANDLE_VALUE) { /* Does h leak? */
+ seg->mapping_handle = m;
+ seg->mmap_offset = offset;
+ seg->is_mapping = 1;
+ goto done;
+ }
+ }
+#endif
+ {
+ ev_off_t start_pos = lseek(fd, 0, SEEK_CUR), pos;
+ ev_off_t read_so_far = 0;
+ char *mem;
+ int e;
+ ev_ssize_t n = 0;
+ if (!(mem = mm_malloc(length)))
+ goto err;
+ if (start_pos < 0) {
+ mm_free(mem);
+ goto err;
+ }
+ if (lseek(fd, offset, SEEK_SET) < 0) {
+ mm_free(mem);
+ goto err;
+ }
+ while (read_so_far < length) {
+ n = read(fd, mem+read_so_far, length-read_so_far);
+ if (n <= 0)
+ break;
+ read_so_far += n;
+ }
+
+ e = errno;
+ pos = lseek(fd, start_pos, SEEK_SET);
+ if (n < 0 || (n == 0 && length > read_so_far)) {
+ mm_free(mem);
+ errno = e;
+ goto err;
+ } else if (pos < 0) {
+ mm_free(mem);
+ goto err;
+ }
+
+ seg->contents = mem;
+ }
+
+done:
+ return 0;
+err:
+ return -1;
+}
+
+void evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment *seg,
+ evbuffer_file_segment_cleanup_cb cb, void* arg)
+{
+ EVUTIL_ASSERT(seg->refcnt > 0);
+ seg->cleanup_cb = cb;
+ seg->cleanup_cb_arg = arg;
+}
+
+void
+evbuffer_file_segment_free(struct evbuffer_file_segment *seg)
+{
+ int refcnt;
+ EVLOCK_LOCK(seg->lock, 0);
+ refcnt = --seg->refcnt;
+ EVLOCK_UNLOCK(seg->lock, 0);
+ if (refcnt > 0)
+ return;
+ EVUTIL_ASSERT(refcnt == 0);
+
+ if (seg->is_mapping) {
+#ifdef _WIN32
+ CloseHandle(seg->mapping_handle);
+#elif defined (EVENT__HAVE_MMAP)
+ off_t offset_leftover;
+ offset_leftover = seg->file_offset % get_page_size();
+ if (munmap(seg->mapping, seg->length + offset_leftover) == -1)
+ event_warn("%s: munmap failed", __func__);
+#endif
+ } else if (seg->contents) {
+ mm_free(seg->contents);
+ }
+
+ if ((seg->flags & EVBUF_FS_CLOSE_ON_FREE) && seg->fd >= 0) {
+ close(seg->fd);
+ }
+
+ if (seg->cleanup_cb) {
+ (*seg->cleanup_cb)((struct evbuffer_file_segment const*)seg,
+ seg->flags, seg->cleanup_cb_arg);
+ seg->cleanup_cb = NULL;
+ seg->cleanup_cb_arg = NULL;
+ }
+
+ EVTHREAD_FREE_LOCK(seg->lock, 0);
+ mm_free(seg);
+}
+
+int
+evbuffer_add_file_segment(struct evbuffer *buf,
+ struct evbuffer_file_segment *seg, ev_off_t offset, ev_off_t length)
+{
+ struct evbuffer_chain *chain;
+ struct evbuffer_chain_file_segment *extra;
+ int can_use_sendfile = 0;
+
+ EVBUFFER_LOCK(buf);
+ EVLOCK_LOCK(seg->lock, 0);
+ if (buf->flags & EVBUFFER_FLAG_DRAINS_TO_FD) {
+ can_use_sendfile = 1;
+ } else {
+ if (!seg->contents) {
+ if (evbuffer_file_segment_materialize(seg)<0) {
+ EVLOCK_UNLOCK(seg->lock, 0);
+ EVBUFFER_UNLOCK(buf);
+ return -1;
+ }
+ }
+ }
+ ++seg->refcnt;
+ EVLOCK_UNLOCK(seg->lock, 0);
+
+ if (buf->freeze_end)
+ goto err;
+
+ if (length < 0) {
+ if (offset > seg->length)
+ goto err;
+ length = seg->length - offset;
+ }
+
+ /* Can we actually add this? */
+ if (offset+length > seg->length)
+ goto err;
+
+ chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_file_segment));
+ if (!chain)
+ goto err;
+ extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment, chain);
+
+ chain->flags |= EVBUFFER_IMMUTABLE|EVBUFFER_FILESEGMENT;
+ if (can_use_sendfile && seg->can_sendfile) {
+ chain->flags |= EVBUFFER_SENDFILE;
+ chain->misalign = seg->file_offset + offset;
+ chain->off = length;
+ chain->buffer_len = chain->misalign + length;
+ } else if (seg->is_mapping) {
+#ifdef _WIN32
+ ev_uint64_t total_offset = seg->mmap_offset+offset;
+ ev_uint64_t offset_rounded=0, offset_remaining=0;
+ LPVOID data;
+ if (total_offset) {
+ SYSTEM_INFO si;
+ memset(&si, 0, sizeof(si)); /* cargo cult */
+ GetSystemInfo(&si);
+ offset_remaining = total_offset % si.dwAllocationGranularity;
+ offset_rounded = total_offset - offset_remaining;
+ }
+ data = MapViewOfFile(
+ seg->mapping_handle,
+ FILE_MAP_READ,
+ offset_rounded >> 32,
+ offset_rounded & 0xfffffffful,
+ length + offset_remaining);
+ if (data == NULL) {
+ mm_free(chain);
+ goto err;
+ }
+ chain->buffer = (unsigned char*) data;
+ chain->buffer_len = length+offset_remaining;
+ chain->misalign = offset_remaining;
+ chain->off = length;
+#else
+ chain->buffer = (unsigned char*)(seg->contents + offset);
+ chain->buffer_len = length;
+ chain->off = length;
+#endif
+ } else {
+ chain->buffer = (unsigned char*)(seg->contents + offset);
+ chain->buffer_len = length;
+ chain->off = length;
+ }
+
+ extra->segment = seg;
+ buf->n_add_for_cb += length;
+ evbuffer_chain_insert(buf, chain);
+
+ evbuffer_invoke_callbacks_(buf);
+
+ EVBUFFER_UNLOCK(buf);
+
+ return 0;
+err:
+ EVBUFFER_UNLOCK(buf);
+ evbuffer_file_segment_free(seg); /* Lowers the refcount */
+ return -1;
+}
+
+int
+evbuffer_add_file(struct evbuffer *buf, int fd, ev_off_t offset, ev_off_t length)
+{
+ struct evbuffer_file_segment *seg;
+ unsigned flags = EVBUF_FS_CLOSE_ON_FREE;
+ int r;
+
+ seg = evbuffer_file_segment_new(fd, offset, length, flags);
+ if (!seg)
+ return -1;
+ r = evbuffer_add_file_segment(buf, seg, 0, length);
+ if (r == 0)
+ evbuffer_file_segment_free(seg);
+ return r;
+}
+
+void
+evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg)
+{
+ EVBUFFER_LOCK(buffer);
+
+ if (!LIST_EMPTY(&buffer->callbacks))
+ evbuffer_remove_all_callbacks(buffer);
+
+ if (cb) {
+ struct evbuffer_cb_entry *ent =
+ evbuffer_add_cb(buffer, NULL, cbarg);
+ ent->cb.cb_obsolete = cb;
+ ent->flags |= EVBUFFER_CB_OBSOLETE;
+ }
+ EVBUFFER_UNLOCK(buffer);
+}
+
+struct evbuffer_cb_entry *
+evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg)
+{
+ struct evbuffer_cb_entry *e;
+ if (! (e = mm_calloc(1, sizeof(struct evbuffer_cb_entry))))
+ return NULL;
+ EVBUFFER_LOCK(buffer);
+ e->cb.cb_func = cb;
+ e->cbarg = cbarg;
+ e->flags = EVBUFFER_CB_ENABLED;
+ LIST_INSERT_HEAD(&buffer->callbacks, e, next);
+ EVBUFFER_UNLOCK(buffer);
+ return e;
+}
+
+int
+evbuffer_remove_cb_entry(struct evbuffer *buffer,
+ struct evbuffer_cb_entry *ent)
+{
+ EVBUFFER_LOCK(buffer);
+ LIST_REMOVE(ent, next);
+ EVBUFFER_UNLOCK(buffer);
+ mm_free(ent);
+ return 0;
+}
+
+int
+evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg)
+{
+ struct evbuffer_cb_entry *cbent;
+ int result = -1;
+ EVBUFFER_LOCK(buffer);
+ LIST_FOREACH(cbent, &buffer->callbacks, next) {
+ if (cb == cbent->cb.cb_func && cbarg == cbent->cbarg) {
+ result = evbuffer_remove_cb_entry(buffer, cbent);
+ goto done;
+ }
+ }
+done:
+ EVBUFFER_UNLOCK(buffer);
+ return result;
+}
+
+int
+evbuffer_cb_set_flags(struct evbuffer *buffer,
+ struct evbuffer_cb_entry *cb, ev_uint32_t flags)
+{
+ /* the user isn't allowed to mess with these. */
+ flags &= ~EVBUFFER_CB_INTERNAL_FLAGS;
+ EVBUFFER_LOCK(buffer);
+ cb->flags |= flags;
+ EVBUFFER_UNLOCK(buffer);
+ return 0;
+}
+
+int
+evbuffer_cb_clear_flags(struct evbuffer *buffer,
+ struct evbuffer_cb_entry *cb, ev_uint32_t flags)
+{
+ /* the user isn't allowed to mess with these. */
+ flags &= ~EVBUFFER_CB_INTERNAL_FLAGS;
+ EVBUFFER_LOCK(buffer);
+ cb->flags &= ~flags;
+ EVBUFFER_UNLOCK(buffer);
+ return 0;
+}
+
+int
+evbuffer_freeze(struct evbuffer *buffer, int start)
+{
+ EVBUFFER_LOCK(buffer);
+ if (start)
+ buffer->freeze_start = 1;
+ else
+ buffer->freeze_end = 1;
+ EVBUFFER_UNLOCK(buffer);
+ return 0;
+}
+
+int
+evbuffer_unfreeze(struct evbuffer *buffer, int start)
+{
+ EVBUFFER_LOCK(buffer);
+ if (start)
+ buffer->freeze_start = 0;
+ else
+ buffer->freeze_end = 0;
+ EVBUFFER_UNLOCK(buffer);
+ return 0;
+}
+
+#if 0
+void
+evbuffer_cb_suspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb)
+{
+ if (!(cb->flags & EVBUFFER_CB_SUSPENDED)) {
+ cb->size_before_suspend = evbuffer_get_length(buffer);
+ cb->flags |= EVBUFFER_CB_SUSPENDED;
+ }
+}
+
+void
+evbuffer_cb_unsuspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb)
+{
+ if ((cb->flags & EVBUFFER_CB_SUSPENDED)) {
+ unsigned call = (cb->flags & EVBUFFER_CB_CALL_ON_UNSUSPEND);
+ size_t sz = cb->size_before_suspend;
+ cb->flags &= ~(EVBUFFER_CB_SUSPENDED|
+ EVBUFFER_CB_CALL_ON_UNSUSPEND);
+ cb->size_before_suspend = 0;
+ if (call && (cb->flags & EVBUFFER_CB_ENABLED)) {
+ cb->cb(buffer, sz, evbuffer_get_length(buffer), cb->cbarg);
+ }
+ }
+}
+#endif
+
+int
+evbuffer_get_callbacks_(struct evbuffer *buffer, struct event_callback **cbs,
+ int max_cbs)
+{
+ int r = 0;
+ EVBUFFER_LOCK(buffer);
+ if (buffer->deferred_cbs) {
+ if (max_cbs < 1) {
+ r = -1;
+ goto done;
+ }
+ cbs[0] = &buffer->deferred;
+ r = 1;
+ }
+done:
+ EVBUFFER_UNLOCK(buffer);
+ return r;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/buffer_iocp.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/buffer_iocp.c
new file mode 100644
index 000000000..2d76a90e7
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/buffer_iocp.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ @file buffer_iocp.c
+
+ This module implements overlapped read and write functions for evbuffer
+ objects on Windows.
+*/
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include "event2/buffer.h"
+#include "event2/buffer_compat.h"
+#include "event2/util.h"
+#include "event2/thread.h"
+#include "util-internal.h"
+#include "evthread-internal.h"
+#include "evbuffer-internal.h"
+#include "iocp-internal.h"
+#include "mm-internal.h"
+
+#include <winsock2.h>
+#include <windows.h>
+#include <stdio.h>
+
+#define MAX_WSABUFS 16
+
+/** An evbuffer that can handle overlapped IO. */
+struct evbuffer_overlapped {
+ struct evbuffer buffer;
+ /** The socket that we're doing overlapped IO on. */
+ evutil_socket_t fd;
+
+ /** pending I/O type */
+ unsigned read_in_progress : 1;
+ unsigned write_in_progress : 1;
+
+ /** The first pinned chain in the buffer. */
+ struct evbuffer_chain *first_pinned;
+
+ /** How many chains are pinned; how many of the fields in buffers
+ * are we using. */
+ int n_buffers;
+ WSABUF buffers[MAX_WSABUFS];
+};
+
+/** Given an evbuffer, return the correponding evbuffer structure, or NULL if
+ * the evbuffer isn't overlapped. */
+static inline struct evbuffer_overlapped *
+upcast_evbuffer(struct evbuffer *buf)
+{
+ if (!buf || !buf->is_overlapped)
+ return NULL;
+ return EVUTIL_UPCAST(buf, struct evbuffer_overlapped, buffer);
+}
+
+/** Unpin all the chains noted as pinned in 'eo'. */
+static void
+pin_release(struct evbuffer_overlapped *eo, unsigned flag)
+{
+ int i;
+ struct evbuffer_chain *next, *chain = eo->first_pinned;
+
+ for (i = 0; i < eo->n_buffers; ++i) {
+ EVUTIL_ASSERT(chain);
+ next = chain->next;
+ evbuffer_chain_unpin_(chain, flag);
+ chain = next;
+ }
+}
+
+void
+evbuffer_commit_read_(struct evbuffer *evbuf, ev_ssize_t nBytes)
+{
+ struct evbuffer_overlapped *buf = upcast_evbuffer(evbuf);
+ struct evbuffer_chain **chainp;
+ size_t remaining, len;
+ unsigned i;
+
+ EVBUFFER_LOCK(evbuf);
+ EVUTIL_ASSERT(buf->read_in_progress && !buf->write_in_progress);
+ EVUTIL_ASSERT(nBytes >= 0); /* XXXX Can this be false? */
+
+ evbuffer_unfreeze(evbuf, 0);
+
+ chainp = evbuf->last_with_datap;
+ if (!((*chainp)->flags & EVBUFFER_MEM_PINNED_R))
+ chainp = &(*chainp)->next;
+ remaining = nBytes;
+ for (i = 0; remaining > 0 && i < (unsigned)buf->n_buffers; ++i) {
+ EVUTIL_ASSERT(*chainp);
+ len = buf->buffers[i].len;
+ if (remaining < len)
+ len = remaining;
+ (*chainp)->off += len;
+ evbuf->last_with_datap = chainp;
+ remaining -= len;
+ chainp = &(*chainp)->next;
+ }
+
+ pin_release(buf, EVBUFFER_MEM_PINNED_R);
+
+ buf->read_in_progress = 0;
+
+ evbuf->total_len += nBytes;
+ evbuf->n_add_for_cb += nBytes;
+
+ evbuffer_invoke_callbacks_(evbuf);
+
+ evbuffer_decref_and_unlock_(evbuf);
+}
+
+void
+evbuffer_commit_write_(struct evbuffer *evbuf, ev_ssize_t nBytes)
+{
+ struct evbuffer_overlapped *buf = upcast_evbuffer(evbuf);
+
+ EVBUFFER_LOCK(evbuf);
+ EVUTIL_ASSERT(buf->write_in_progress && !buf->read_in_progress);
+ evbuffer_unfreeze(evbuf, 1);
+ evbuffer_drain(evbuf, nBytes);
+ pin_release(buf,EVBUFFER_MEM_PINNED_W);
+ buf->write_in_progress = 0;
+ evbuffer_decref_and_unlock_(evbuf);
+}
+
+struct evbuffer *
+evbuffer_overlapped_new_(evutil_socket_t fd)
+{
+ struct evbuffer_overlapped *evo;
+
+ evo = mm_calloc(1, sizeof(struct evbuffer_overlapped));
+ if (!evo)
+ return NULL;
+
+ LIST_INIT(&evo->buffer.callbacks);
+ evo->buffer.refcnt = 1;
+ evo->buffer.last_with_datap = &evo->buffer.first;
+
+ evo->buffer.is_overlapped = 1;
+ evo->fd = fd;
+
+ return &evo->buffer;
+}
+
+int
+evbuffer_launch_write_(struct evbuffer *buf, ev_ssize_t at_most,
+ struct event_overlapped *ol)
+{
+ struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
+ int r = -1;
+ int i;
+ struct evbuffer_chain *chain;
+ DWORD bytesSent;
+
+ if (!buf) {
+ /* No buffer, or it isn't overlapped */
+ return -1;
+ }
+
+ EVBUFFER_LOCK(buf);
+ EVUTIL_ASSERT(!buf_o->read_in_progress);
+ if (buf->freeze_start || buf_o->write_in_progress)
+ goto done;
+ if (!buf->total_len) {
+ /* Nothing to write */
+ r = 0;
+ goto done;
+ } else if (at_most < 0 || (size_t)at_most > buf->total_len) {
+ at_most = buf->total_len;
+ }
+ evbuffer_freeze(buf, 1);
+
+ buf_o->first_pinned = NULL;
+ buf_o->n_buffers = 0;
+ memset(buf_o->buffers, 0, sizeof(buf_o->buffers));
+
+ chain = buf_o->first_pinned = buf->first;
+
+ for (i=0; i < MAX_WSABUFS && chain; ++i, chain=chain->next) {
+ WSABUF *b = &buf_o->buffers[i];
+ b->buf = (char*)( chain->buffer + chain->misalign );
+ evbuffer_chain_pin_(chain, EVBUFFER_MEM_PINNED_W);
+
+ if ((size_t)at_most > chain->off) {
+ /* XXXX Cast is safe for now, since win32 has no
+ mmaped chains. But later, we need to have this
+ add more WSAbufs if chain->off is greater than
+ ULONG_MAX */
+ b->len = (unsigned long)chain->off;
+ at_most -= chain->off;
+ } else {
+ b->len = (unsigned long)at_most;
+ ++i;
+ break;
+ }
+ }
+
+ buf_o->n_buffers = i;
+ evbuffer_incref_(buf);
+ if (WSASend(buf_o->fd, buf_o->buffers, i, &bytesSent, 0,
+ &ol->overlapped, NULL)) {
+ int error = WSAGetLastError();
+ if (error != WSA_IO_PENDING) {
+ /* An actual error. */
+ pin_release(buf_o, EVBUFFER_MEM_PINNED_W);
+ evbuffer_unfreeze(buf, 1);
+ evbuffer_free(buf); /* decref */
+ goto done;
+ }
+ }
+
+ buf_o->write_in_progress = 1;
+ r = 0;
+done:
+ EVBUFFER_UNLOCK(buf);
+ return r;
+}
+
+int
+evbuffer_launch_read_(struct evbuffer *buf, size_t at_most,
+ struct event_overlapped *ol)
+{
+ struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
+ int r = -1, i;
+ int nvecs;
+ int npin=0;
+ struct evbuffer_chain *chain=NULL, **chainp;
+ DWORD bytesRead;
+ DWORD flags = 0;
+ struct evbuffer_iovec vecs[MAX_WSABUFS];
+
+ if (!buf_o)
+ return -1;
+ EVBUFFER_LOCK(buf);
+ EVUTIL_ASSERT(!buf_o->write_in_progress);
+ if (buf->freeze_end || buf_o->read_in_progress)
+ goto done;
+
+ buf_o->first_pinned = NULL;
+ buf_o->n_buffers = 0;
+ memset(buf_o->buffers, 0, sizeof(buf_o->buffers));
+
+ if (evbuffer_expand_fast_(buf, at_most, MAX_WSABUFS) == -1)
+ goto done;
+ evbuffer_freeze(buf, 0);
+
+ nvecs = evbuffer_read_setup_vecs_(buf, at_most,
+ vecs, MAX_WSABUFS, &chainp, 1);
+ for (i=0;i<nvecs;++i) {
+ WSABUF_FROM_EVBUFFER_IOV(
+ &buf_o->buffers[i],
+ &vecs[i]);
+ }
+
+ buf_o->n_buffers = nvecs;
+ buf_o->first_pinned = chain = *chainp;
+
+ npin=0;
+ for ( ; chain; chain = chain->next) {
+ evbuffer_chain_pin_(chain, EVBUFFER_MEM_PINNED_R);
+ ++npin;
+ }
+ EVUTIL_ASSERT(npin == nvecs);
+
+ evbuffer_incref_(buf);
+ if (WSARecv(buf_o->fd, buf_o->buffers, nvecs, &bytesRead, &flags,
+ &ol->overlapped, NULL)) {
+ int error = WSAGetLastError();
+ if (error != WSA_IO_PENDING) {
+ /* An actual error. */
+ pin_release(buf_o, EVBUFFER_MEM_PINNED_R);
+ evbuffer_unfreeze(buf, 0);
+ evbuffer_free(buf); /* decref */
+ goto done;
+ }
+ }
+
+ buf_o->read_in_progress = 1;
+ r = 0;
+done:
+ EVBUFFER_UNLOCK(buf);
+ return r;
+}
+
+evutil_socket_t
+evbuffer_overlapped_get_fd_(struct evbuffer *buf)
+{
+ struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
+ return buf_o ? buf_o->fd : -1;
+}
+
+void
+evbuffer_overlapped_set_fd_(struct evbuffer *buf, evutil_socket_t fd)
+{
+ struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
+ EVBUFFER_LOCK(buf);
+ /* XXX is this right?, should it cancel current I/O operations? */
+ if (buf_o)
+ buf_o->fd = fd;
+ EVBUFFER_UNLOCK(buf);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent-internal.h
new file mode 100644
index 000000000..9960aefa5
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent-internal.h
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 2008-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef BUFFEREVENT_INTERNAL_H_INCLUDED_
+#define BUFFEREVENT_INTERNAL_H_INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "event2/event-config.h"
+#include "event2/event_struct.h"
+#include "evconfig-private.h"
+#include "event2/util.h"
+#include "defer-internal.h"
+#include "evthread-internal.h"
+#include "event2/thread.h"
+#include "ratelim-internal.h"
+#include "event2/bufferevent_struct.h"
+
+#include "ipv6-internal.h"
+#ifdef _WIN32
+#include <ws2tcpip.h>
+#endif
+#ifdef EVENT__HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef EVENT__HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+
+/* These flags are reasons that we might be declining to actually enable
+ reading or writing on a bufferevent.
+ */
+
+/* On a all bufferevents, for reading: used when we have read up to the
+ watermark value.
+
+ On a filtering bufferevent, for writing: used when the underlying
+ bufferevent's write buffer has been filled up to its watermark
+ value.
+*/
+#define BEV_SUSPEND_WM 0x01
+/* On a base bufferevent: when we have emptied a bandwidth buckets */
+#define BEV_SUSPEND_BW 0x02
+/* On a base bufferevent: when we have emptied the group's bandwidth bucket. */
+#define BEV_SUSPEND_BW_GROUP 0x04
+/* On a socket bufferevent: can't do any operations while we're waiting for
+ * name lookup to finish. */
+#define BEV_SUSPEND_LOOKUP 0x08
+/* On a base bufferevent, for reading: used when a filter has choked this
+ * (underlying) bufferevent because it has stopped reading from it. */
+#define BEV_SUSPEND_FILT_READ 0x10
+
+typedef ev_uint16_t bufferevent_suspend_flags;
+
+struct bufferevent_rate_limit_group {
+ /** List of all members in the group */
+ LIST_HEAD(rlim_group_member_list, bufferevent_private) members;
+ /** Current limits for the group. */
+ struct ev_token_bucket rate_limit;
+ struct ev_token_bucket_cfg rate_limit_cfg;
+
+ /** True iff we don't want to read from any member of the group.until
+ * the token bucket refills. */
+ unsigned read_suspended : 1;
+ /** True iff we don't want to write from any member of the group.until
+ * the token bucket refills. */
+ unsigned write_suspended : 1;
+ /** True iff we were unable to suspend one of the bufferevents in the
+ * group for reading the last time we tried, and we should try
+ * again. */
+ unsigned pending_unsuspend_read : 1;
+ /** True iff we were unable to suspend one of the bufferevents in the
+ * group for writing the last time we tried, and we should try
+ * again. */
+ unsigned pending_unsuspend_write : 1;
+
+ /*@{*/
+ /** Total number of bytes read or written in this group since last
+ * reset. */
+ ev_uint64_t total_read;
+ ev_uint64_t total_written;
+ /*@}*/
+
+ /** The number of bufferevents in the group. */
+ int n_members;
+
+ /** The smallest number of bytes that any member of the group should
+ * be limited to read or write at a time. */
+ ev_ssize_t min_share;
+ ev_ssize_t configured_min_share;
+
+ /** Timeout event that goes off once a tick, when the bucket is ready
+ * to refill. */
+ struct event master_refill_event;
+
+ /** Seed for weak random number generator. Protected by 'lock' */
+ struct evutil_weakrand_state weakrand_seed;
+
+ /** Lock to protect the members of this group. This lock should nest
+ * within every bufferevent lock: if you are holding this lock, do
+ * not assume you can lock another bufferevent. */
+ void *lock;
+};
+
+/** Fields for rate-limiting a single bufferevent. */
+struct bufferevent_rate_limit {
+ /* Linked-list elements for storing this bufferevent_private in a
+ * group.
+ *
+ * Note that this field is supposed to be protected by the group
+ * lock */
+ LIST_ENTRY(bufferevent_private) next_in_group;
+ /** The rate-limiting group for this bufferevent, or NULL if it is
+ * only rate-limited on its own. */
+ struct bufferevent_rate_limit_group *group;
+
+ /* This bufferevent's current limits. */
+ struct ev_token_bucket limit;
+ /* Pointer to the rate-limit configuration for this bufferevent.
+ * Can be shared. XXX reference-count this? */
+ struct ev_token_bucket_cfg *cfg;
+
+ /* Timeout event used when one this bufferevent's buckets are
+ * empty. */
+ struct event refill_bucket_event;
+};
+
+/** Parts of the bufferevent structure that are shared among all bufferevent
+ * types, but not exposed in bufferevent_struct.h. */
+struct bufferevent_private {
+ /** The underlying bufferevent structure. */
+ struct bufferevent bev;
+
+ /** Evbuffer callback to enforce watermarks on input. */
+ struct evbuffer_cb_entry *read_watermarks_cb;
+
+ /** If set, we should free the lock when we free the bufferevent. */
+ unsigned own_lock : 1;
+
+ /** Flag: set if we have deferred callbacks and a read callback is
+ * pending. */
+ unsigned readcb_pending : 1;
+ /** Flag: set if we have deferred callbacks and a write callback is
+ * pending. */
+ unsigned writecb_pending : 1;
+ /** Flag: set if we are currently busy connecting. */
+ unsigned connecting : 1;
+ /** Flag: set if a connect failed prematurely; this is a hack for
+ * getting around the bufferevent abstraction. */
+ unsigned connection_refused : 1;
+ /** Set to the events pending if we have deferred callbacks and
+ * an events callback is pending. */
+ short eventcb_pending;
+
+ /** If set, read is suspended until one or more conditions are over.
+ * The actual value here is a bitfield of those conditions; see the
+ * BEV_SUSPEND_* flags above. */
+ bufferevent_suspend_flags read_suspended;
+
+ /** If set, writing is suspended until one or more conditions are over.
+ * The actual value here is a bitfield of those conditions; see the
+ * BEV_SUSPEND_* flags above. */
+ bufferevent_suspend_flags write_suspended;
+
+ /** Set to the current socket errno if we have deferred callbacks and
+ * an events callback is pending. */
+ int errno_pending;
+
+ /** The DNS error code for bufferevent_socket_connect_hostname */
+ int dns_error;
+
+ /** Used to implement deferred callbacks */
+ struct event_callback deferred;
+
+ /** The options this bufferevent was constructed with */
+ enum bufferevent_options options;
+
+ /** Current reference count for this bufferevent. */
+ int refcnt;
+
+ /** Lock for this bufferevent. Shared by the inbuf and the outbuf.
+ * If NULL, locking is disabled. */
+ void *lock;
+
+ /** No matter how big our bucket gets, don't try to read more than this
+ * much in a single read operation. */
+ ev_ssize_t max_single_read;
+
+ /** No matter how big our bucket gets, don't try to write more than this
+ * much in a single write operation. */
+ ev_ssize_t max_single_write;
+
+ /** Rate-limiting information for this bufferevent */
+ struct bufferevent_rate_limit *rate_limiting;
+
+ /* Saved conn_addr, to extract IP address from it.
+ *
+ * Because some servers may reset/close connection without waiting clients,
+ * in that case we can't extract IP address even in close_cb.
+ * So we need to save it, just after we connected to remote server, or
+ * after resolving (to avoid extra dns requests during retrying, since UDP
+ * is slow) */
+ union {
+ struct sockaddr_in6 in6;
+ struct sockaddr_in in;
+ } conn_address;
+
+ struct evdns_getaddrinfo_request *dns_request;
+};
+
+/** Possible operations for a control callback. */
+enum bufferevent_ctrl_op {
+ BEV_CTRL_SET_FD,
+ BEV_CTRL_GET_FD,
+ BEV_CTRL_GET_UNDERLYING,
+ BEV_CTRL_CANCEL_ALL
+};
+
+/** Possible data types for a control callback */
+union bufferevent_ctrl_data {
+ void *ptr;
+ evutil_socket_t fd;
+};
+
+/**
+ Implementation table for a bufferevent: holds function pointers and other
+ information to make the various bufferevent types work.
+*/
+struct bufferevent_ops {
+ /** The name of the bufferevent's type. */
+ const char *type;
+ /** At what offset into the implementation type will we find a
+ bufferevent structure?
+
+ Example: if the type is implemented as
+ struct bufferevent_x {
+ int extra_data;
+ struct bufferevent bev;
+ }
+ then mem_offset should be offsetof(struct bufferevent_x, bev)
+ */
+ off_t mem_offset;
+
+ /** Enables one or more of EV_READ|EV_WRITE on a bufferevent. Does
+ not need to adjust the 'enabled' field. Returns 0 on success, -1
+ on failure.
+ */
+ int (*enable)(struct bufferevent *, short);
+
+ /** Disables one or more of EV_READ|EV_WRITE on a bufferevent. Does
+ not need to adjust the 'enabled' field. Returns 0 on success, -1
+ on failure.
+ */
+ int (*disable)(struct bufferevent *, short);
+
+ /** Detatches the bufferevent from related data structures. Called as
+ * soon as its reference count reaches 0. */
+ void (*unlink)(struct bufferevent *);
+
+ /** Free any storage and deallocate any extra data or structures used
+ in this implementation. Called when the bufferevent is
+ finalized.
+ */
+ void (*destruct)(struct bufferevent *);
+
+ /** Called when the timeouts on the bufferevent have changed.*/
+ int (*adj_timeouts)(struct bufferevent *);
+
+ /** Called to flush data. */
+ int (*flush)(struct bufferevent *, short, enum bufferevent_flush_mode);
+
+ /** Called to access miscellaneous fields. */
+ int (*ctrl)(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
+
+};
+
+extern const struct bufferevent_ops bufferevent_ops_socket;
+extern const struct bufferevent_ops bufferevent_ops_filter;
+extern const struct bufferevent_ops bufferevent_ops_pair;
+
+#define BEV_IS_SOCKET(bevp) ((bevp)->be_ops == &bufferevent_ops_socket)
+#define BEV_IS_FILTER(bevp) ((bevp)->be_ops == &bufferevent_ops_filter)
+#define BEV_IS_PAIR(bevp) ((bevp)->be_ops == &bufferevent_ops_pair)
+
+#ifdef _WIN32
+extern const struct bufferevent_ops bufferevent_ops_async;
+#define BEV_IS_ASYNC(bevp) ((bevp)->be_ops == &bufferevent_ops_async)
+#else
+#define BEV_IS_ASYNC(bevp) 0
+#endif
+
+/** Initialize the shared parts of a bufferevent. */
+int bufferevent_init_common_(struct bufferevent_private *, struct event_base *, const struct bufferevent_ops *, enum bufferevent_options options);
+
+/** For internal use: temporarily stop all reads on bufev, until the conditions
+ * in 'what' are over. */
+void bufferevent_suspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what);
+/** For internal use: clear the conditions 'what' on bufev, and re-enable
+ * reading if there are no conditions left. */
+void bufferevent_unsuspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what);
+
+/** For internal use: temporarily stop all writes on bufev, until the conditions
+ * in 'what' are over. */
+void bufferevent_suspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what);
+/** For internal use: clear the conditions 'what' on bufev, and re-enable
+ * writing if there are no conditions left. */
+void bufferevent_unsuspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what);
+
+#define bufferevent_wm_suspend_read(b) \
+ bufferevent_suspend_read_((b), BEV_SUSPEND_WM)
+#define bufferevent_wm_unsuspend_read(b) \
+ bufferevent_unsuspend_read_((b), BEV_SUSPEND_WM)
+
+/*
+ Disable a bufferevent. Equivalent to bufferevent_disable(), but
+ first resets 'connecting' flag to force EV_WRITE down for sure.
+
+ XXXX this method will go away in the future; try not to add new users.
+ See comment in evhttp_connection_reset_() for discussion.
+
+ @param bufev the bufferevent to be disabled
+ @param event any combination of EV_READ | EV_WRITE.
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_disable()
+ */
+int bufferevent_disable_hard_(struct bufferevent *bufev, short event);
+
+/** Internal: Set up locking on a bufferevent. If lock is set, use it.
+ * Otherwise, use a new lock. */
+int bufferevent_enable_locking_(struct bufferevent *bufev, void *lock);
+/** Internal: backwards compat macro for the now public function
+ * Increment the reference count on bufev. */
+#define bufferevent_incref_(bufev) bufferevent_incref(bufev)
+/** Internal: Lock bufev and increase its reference count.
+ * unlocking it otherwise. */
+void bufferevent_incref_and_lock_(struct bufferevent *bufev);
+/** Internal: backwards compat macro for the now public function
+ * Decrement the reference count on bufev. Returns 1 if it freed
+ * the bufferevent.*/
+#define bufferevent_decref_(bufev) bufferevent_decref(bufev)
+
+/** Internal: Drop the reference count on bufev, freeing as necessary, and
+ * unlocking it otherwise. Returns 1 if it freed the bufferevent. */
+int bufferevent_decref_and_unlock_(struct bufferevent *bufev);
+
+/** Internal: If callbacks are deferred and we have a read callback, schedule
+ * a readcb. Otherwise just run the readcb. Ignores watermarks. */
+void bufferevent_run_readcb_(struct bufferevent *bufev, int options);
+/** Internal: If callbacks are deferred and we have a write callback, schedule
+ * a writecb. Otherwise just run the writecb. Ignores watermarks. */
+void bufferevent_run_writecb_(struct bufferevent *bufev, int options);
+/** Internal: If callbacks are deferred and we have an eventcb, schedule
+ * it to run with events "what". Otherwise just run the eventcb.
+ * See bufferevent_trigger_event for meaning of "options". */
+void bufferevent_run_eventcb_(struct bufferevent *bufev, short what, int options);
+
+/** Internal: Run or schedule (if deferred or options contain
+ * BEV_TRIG_DEFER_CALLBACKS) I/O callbacks specified in iotype.
+ * Must already hold the bufev lock. Honors watermarks unless
+ * BEV_TRIG_IGNORE_WATERMARKS is in options. */
+static inline void bufferevent_trigger_nolock_(struct bufferevent *bufev, short iotype, int options);
+
+/* Making this inline since all of the common-case calls to this function in
+ * libevent use constant arguments. */
+static inline void
+bufferevent_trigger_nolock_(struct bufferevent *bufev, short iotype, int options)
+{
+ if ((iotype & EV_READ) && ((options & BEV_TRIG_IGNORE_WATERMARKS) ||
+ evbuffer_get_length(bufev->input) >= bufev->wm_read.low))
+ bufferevent_run_readcb_(bufev, options);
+ if ((iotype & EV_WRITE) && ((options & BEV_TRIG_IGNORE_WATERMARKS) ||
+ evbuffer_get_length(bufev->output) <= bufev->wm_write.low))
+ bufferevent_run_writecb_(bufev, options);
+}
+
+/** Internal: Add the event 'ev' with timeout tv, unless tv is set to 0, in
+ * which case add ev with no timeout. */
+int bufferevent_add_event_(struct event *ev, const struct timeval *tv);
+
+/* =========
+ * These next functions implement timeouts for bufferevents that aren't doing
+ * anything else with ev_read and ev_write, to handle timeouts.
+ * ========= */
+/** Internal use: Set up the ev_read and ev_write callbacks so that
+ * the other "generic_timeout" functions will work on it. Call this from
+ * the constructor function. */
+void bufferevent_init_generic_timeout_cbs_(struct bufferevent *bev);
+/** Internal use: Add or delete the generic timeout events as appropriate.
+ * (If an event is enabled and a timeout is set, we add the event. Otherwise
+ * we delete it.) Call this from anything that changes the timeout values,
+ * that enabled EV_READ or EV_WRITE, or that disables EV_READ or EV_WRITE. */
+int bufferevent_generic_adj_timeouts_(struct bufferevent *bev);
+int bufferevent_generic_adj_existing_timeouts_(struct bufferevent *bev);
+
+enum bufferevent_options bufferevent_get_options_(struct bufferevent *bev);
+
+const struct sockaddr*
+bufferevent_socket_get_conn_address_(struct bufferevent *bev);
+
+/** Internal use: We have just successfully read data into an inbuf, so
+ * reset the read timeout (if any). */
+#define BEV_RESET_GENERIC_READ_TIMEOUT(bev) \
+ do { \
+ if (evutil_timerisset(&(bev)->timeout_read)) \
+ event_add(&(bev)->ev_read, &(bev)->timeout_read); \
+ } while (0)
+/** Internal use: We have just successfully written data from an inbuf, so
+ * reset the read timeout (if any). */
+#define BEV_RESET_GENERIC_WRITE_TIMEOUT(bev) \
+ do { \
+ if (evutil_timerisset(&(bev)->timeout_write)) \
+ event_add(&(bev)->ev_write, &(bev)->timeout_write); \
+ } while (0)
+#define BEV_DEL_GENERIC_READ_TIMEOUT(bev) \
+ event_del(&(bev)->ev_read)
+#define BEV_DEL_GENERIC_WRITE_TIMEOUT(bev) \
+ event_del(&(bev)->ev_write)
+
+
+/** Internal: Given a bufferevent, return its corresponding
+ * bufferevent_private. */
+#define BEV_UPCAST(b) EVUTIL_UPCAST((b), struct bufferevent_private, bev)
+
+#ifdef EVENT__DISABLE_THREAD_SUPPORT
+#define BEV_LOCK(b) EVUTIL_NIL_STMT_
+#define BEV_UNLOCK(b) EVUTIL_NIL_STMT_
+#else
+/** Internal: Grab the lock (if any) on a bufferevent */
+#define BEV_LOCK(b) do { \
+ struct bufferevent_private *locking = BEV_UPCAST(b); \
+ EVLOCK_LOCK(locking->lock, 0); \
+ } while (0)
+
+/** Internal: Release the lock (if any) on a bufferevent */
+#define BEV_UNLOCK(b) do { \
+ struct bufferevent_private *locking = BEV_UPCAST(b); \
+ EVLOCK_UNLOCK(locking->lock, 0); \
+ } while (0)
+#endif
+
+
+/* ==== For rate-limiting. */
+
+int bufferevent_decrement_write_buckets_(struct bufferevent_private *bev,
+ ev_ssize_t bytes);
+int bufferevent_decrement_read_buckets_(struct bufferevent_private *bev,
+ ev_ssize_t bytes);
+ev_ssize_t bufferevent_get_read_max_(struct bufferevent_private *bev);
+ev_ssize_t bufferevent_get_write_max_(struct bufferevent_private *bev);
+
+int bufferevent_ratelim_init_(struct bufferevent_private *bev);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* BUFFEREVENT_INTERNAL_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent.c
new file mode 100644
index 000000000..490b59839
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent.c
@@ -0,0 +1,1015 @@
+/*
+ * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos, Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
+
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef EVENT__HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+#include "event2/util.h"
+#include "event2/buffer.h"
+#include "event2/buffer_compat.h"
+#include "event2/bufferevent.h"
+#include "event2/bufferevent_struct.h"
+#include "event2/bufferevent_compat.h"
+#include "event2/event.h"
+#include "event-internal.h"
+#include "log-internal.h"
+#include "mm-internal.h"
+#include "bufferevent-internal.h"
+#include "evbuffer-internal.h"
+#include "util-internal.h"
+
+static void bufferevent_cancel_all_(struct bufferevent *bev);
+static void bufferevent_finalize_cb_(struct event_callback *evcb, void *arg_);
+
+void
+bufferevent_suspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what)
+{
+ struct bufferevent_private *bufev_private =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+ BEV_LOCK(bufev);
+ if (!bufev_private->read_suspended)
+ bufev->be_ops->disable(bufev, EV_READ);
+ bufev_private->read_suspended |= what;
+ BEV_UNLOCK(bufev);
+}
+
+void
+bufferevent_unsuspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what)
+{
+ struct bufferevent_private *bufev_private =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+ BEV_LOCK(bufev);
+ bufev_private->read_suspended &= ~what;
+ if (!bufev_private->read_suspended && (bufev->enabled & EV_READ))
+ bufev->be_ops->enable(bufev, EV_READ);
+ BEV_UNLOCK(bufev);
+}
+
+void
+bufferevent_suspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what)
+{
+ struct bufferevent_private *bufev_private =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+ BEV_LOCK(bufev);
+ if (!bufev_private->write_suspended)
+ bufev->be_ops->disable(bufev, EV_WRITE);
+ bufev_private->write_suspended |= what;
+ BEV_UNLOCK(bufev);
+}
+
+void
+bufferevent_unsuspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what)
+{
+ struct bufferevent_private *bufev_private =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+ BEV_LOCK(bufev);
+ bufev_private->write_suspended &= ~what;
+ if (!bufev_private->write_suspended && (bufev->enabled & EV_WRITE))
+ bufev->be_ops->enable(bufev, EV_WRITE);
+ BEV_UNLOCK(bufev);
+}
+
+
+/* Callback to implement watermarks on the input buffer. Only enabled
+ * if the watermark is set. */
+static void
+bufferevent_inbuf_wm_cb(struct evbuffer *buf,
+ const struct evbuffer_cb_info *cbinfo,
+ void *arg)
+{
+ struct bufferevent *bufev = arg;
+ size_t size;
+
+ size = evbuffer_get_length(buf);
+
+ if (size >= bufev->wm_read.high)
+ bufferevent_wm_suspend_read(bufev);
+ else
+ bufferevent_wm_unsuspend_read(bufev);
+}
+
+static void
+bufferevent_run_deferred_callbacks_locked(struct event_callback *cb, void *arg)
+{
+ struct bufferevent_private *bufev_private = arg;
+ struct bufferevent *bufev = &bufev_private->bev;
+
+ BEV_LOCK(bufev);
+ if ((bufev_private->eventcb_pending & BEV_EVENT_CONNECTED) &&
+ bufev->errorcb) {
+ /* The "connected" happened before any reads or writes, so
+ send it first. */
+ bufev_private->eventcb_pending &= ~BEV_EVENT_CONNECTED;
+ bufev->errorcb(bufev, BEV_EVENT_CONNECTED, bufev->cbarg);
+ }
+ if (bufev_private->readcb_pending && bufev->readcb) {
+ bufev_private->readcb_pending = 0;
+ bufev->readcb(bufev, bufev->cbarg);
+ }
+ if (bufev_private->writecb_pending && bufev->writecb) {
+ bufev_private->writecb_pending = 0;
+ bufev->writecb(bufev, bufev->cbarg);
+ }
+ if (bufev_private->eventcb_pending && bufev->errorcb) {
+ short what = bufev_private->eventcb_pending;
+ int err = bufev_private->errno_pending;
+ bufev_private->eventcb_pending = 0;
+ bufev_private->errno_pending = 0;
+ EVUTIL_SET_SOCKET_ERROR(err);
+ bufev->errorcb(bufev, what, bufev->cbarg);
+ }
+ bufferevent_decref_and_unlock_(bufev);
+}
+
+static void
+bufferevent_run_deferred_callbacks_unlocked(struct event_callback *cb, void *arg)
+{
+ struct bufferevent_private *bufev_private = arg;
+ struct bufferevent *bufev = &bufev_private->bev;
+
+ BEV_LOCK(bufev);
+#define UNLOCKED(stmt) \
+ do { BEV_UNLOCK(bufev); stmt; BEV_LOCK(bufev); } while(0)
+
+ if ((bufev_private->eventcb_pending & BEV_EVENT_CONNECTED) &&
+ bufev->errorcb) {
+ /* The "connected" happened before any reads or writes, so
+ send it first. */
+ bufferevent_event_cb errorcb = bufev->errorcb;
+ void *cbarg = bufev->cbarg;
+ bufev_private->eventcb_pending &= ~BEV_EVENT_CONNECTED;
+ UNLOCKED(errorcb(bufev, BEV_EVENT_CONNECTED, cbarg));
+ }
+ if (bufev_private->readcb_pending && bufev->readcb) {
+ bufferevent_data_cb readcb = bufev->readcb;
+ void *cbarg = bufev->cbarg;
+ bufev_private->readcb_pending = 0;
+ UNLOCKED(readcb(bufev, cbarg));
+ }
+ if (bufev_private->writecb_pending && bufev->writecb) {
+ bufferevent_data_cb writecb = bufev->writecb;
+ void *cbarg = bufev->cbarg;
+ bufev_private->writecb_pending = 0;
+ UNLOCKED(writecb(bufev, cbarg));
+ }
+ if (bufev_private->eventcb_pending && bufev->errorcb) {
+ bufferevent_event_cb errorcb = bufev->errorcb;
+ void *cbarg = bufev->cbarg;
+ short what = bufev_private->eventcb_pending;
+ int err = bufev_private->errno_pending;
+ bufev_private->eventcb_pending = 0;
+ bufev_private->errno_pending = 0;
+ EVUTIL_SET_SOCKET_ERROR(err);
+ UNLOCKED(errorcb(bufev,what,cbarg));
+ }
+ bufferevent_decref_and_unlock_(bufev);
+#undef UNLOCKED
+}
+
+#define SCHEDULE_DEFERRED(bevp) \
+ do { \
+ if (event_deferred_cb_schedule_( \
+ (bevp)->bev.ev_base, \
+ &(bevp)->deferred)) \
+ bufferevent_incref_(&(bevp)->bev); \
+ } while (0)
+
+
+void
+bufferevent_run_readcb_(struct bufferevent *bufev, int options)
+{
+ /* Requires that we hold the lock and a reference */
+ struct bufferevent_private *p =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+ if (bufev->readcb == NULL)
+ return;
+ if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
+ p->readcb_pending = 1;
+ SCHEDULE_DEFERRED(p);
+ } else {
+ bufev->readcb(bufev, bufev->cbarg);
+ }
+}
+
+void
+bufferevent_run_writecb_(struct bufferevent *bufev, int options)
+{
+ /* Requires that we hold the lock and a reference */
+ struct bufferevent_private *p =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+ if (bufev->writecb == NULL)
+ return;
+ if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
+ p->writecb_pending = 1;
+ SCHEDULE_DEFERRED(p);
+ } else {
+ bufev->writecb(bufev, bufev->cbarg);
+ }
+}
+
+#define BEV_TRIG_ALL_OPTS ( \
+ BEV_TRIG_IGNORE_WATERMARKS| \
+ BEV_TRIG_DEFER_CALLBACKS \
+ )
+
+void
+bufferevent_trigger(struct bufferevent *bufev, short iotype, int options)
+{
+ bufferevent_incref_and_lock_(bufev);
+ bufferevent_trigger_nolock_(bufev, iotype, options&BEV_TRIG_ALL_OPTS);
+ bufferevent_decref_and_unlock_(bufev);
+}
+
+void
+bufferevent_run_eventcb_(struct bufferevent *bufev, short what, int options)
+{
+ /* Requires that we hold the lock and a reference */
+ struct bufferevent_private *p =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+ if (bufev->errorcb == NULL)
+ return;
+ if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
+ p->eventcb_pending |= what;
+ p->errno_pending = EVUTIL_SOCKET_ERROR();
+ SCHEDULE_DEFERRED(p);
+ } else {
+ bufev->errorcb(bufev, what, bufev->cbarg);
+ }
+}
+
+void
+bufferevent_trigger_event(struct bufferevent *bufev, short what, int options)
+{
+ bufferevent_incref_and_lock_(bufev);
+ bufferevent_run_eventcb_(bufev, what, options&BEV_TRIG_ALL_OPTS);
+ bufferevent_decref_and_unlock_(bufev);
+}
+
+int
+bufferevent_init_common_(struct bufferevent_private *bufev_private,
+ struct event_base *base,
+ const struct bufferevent_ops *ops,
+ enum bufferevent_options options)
+{
+ struct bufferevent *bufev = &bufev_private->bev;
+
+ if (!bufev->input) {
+ if ((bufev->input = evbuffer_new()) == NULL)
+ return -1;
+ }
+
+ if (!bufev->output) {
+ if ((bufev->output = evbuffer_new()) == NULL) {
+ evbuffer_free(bufev->input);
+ return -1;
+ }
+ }
+
+ bufev_private->refcnt = 1;
+ bufev->ev_base = base;
+
+ /* Disable timeouts. */
+ evutil_timerclear(&bufev->timeout_read);
+ evutil_timerclear(&bufev->timeout_write);
+
+ bufev->be_ops = ops;
+
+ bufferevent_ratelim_init_(bufev_private);
+
+ /*
+ * Set to EV_WRITE so that using bufferevent_write is going to
+ * trigger a callback. Reading needs to be explicitly enabled
+ * because otherwise no data will be available.
+ */
+ bufev->enabled = EV_WRITE;
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ if (options & BEV_OPT_THREADSAFE) {
+ if (bufferevent_enable_locking_(bufev, NULL) < 0) {
+ /* cleanup */
+ evbuffer_free(bufev->input);
+ evbuffer_free(bufev->output);
+ bufev->input = NULL;
+ bufev->output = NULL;
+ return -1;
+ }
+ }
+#endif
+ if ((options & (BEV_OPT_DEFER_CALLBACKS|BEV_OPT_UNLOCK_CALLBACKS))
+ == BEV_OPT_UNLOCK_CALLBACKS) {
+ event_warnx("UNLOCK_CALLBACKS requires DEFER_CALLBACKS");
+ return -1;
+ }
+ if (options & BEV_OPT_UNLOCK_CALLBACKS)
+ event_deferred_cb_init_(
+ &bufev_private->deferred,
+ event_base_get_npriorities(base) / 2,
+ bufferevent_run_deferred_callbacks_unlocked,
+ bufev_private);
+ else
+ event_deferred_cb_init_(
+ &bufev_private->deferred,
+ event_base_get_npriorities(base) / 2,
+ bufferevent_run_deferred_callbacks_locked,
+ bufev_private);
+
+ bufev_private->options = options;
+
+ evbuffer_set_parent_(bufev->input, bufev);
+ evbuffer_set_parent_(bufev->output, bufev);
+
+ return 0;
+}
+
+void
+bufferevent_setcb(struct bufferevent *bufev,
+ bufferevent_data_cb readcb, bufferevent_data_cb writecb,
+ bufferevent_event_cb eventcb, void *cbarg)
+{
+ BEV_LOCK(bufev);
+
+ bufev->readcb = readcb;
+ bufev->writecb = writecb;
+ bufev->errorcb = eventcb;
+
+ bufev->cbarg = cbarg;
+ BEV_UNLOCK(bufev);
+}
+
+void
+bufferevent_getcb(struct bufferevent *bufev,
+ bufferevent_data_cb *readcb_ptr,
+ bufferevent_data_cb *writecb_ptr,
+ bufferevent_event_cb *eventcb_ptr,
+ void **cbarg_ptr)
+{
+ BEV_LOCK(bufev);
+ if (readcb_ptr)
+ *readcb_ptr = bufev->readcb;
+ if (writecb_ptr)
+ *writecb_ptr = bufev->writecb;
+ if (eventcb_ptr)
+ *eventcb_ptr = bufev->errorcb;
+ if (cbarg_ptr)
+ *cbarg_ptr = bufev->cbarg;
+
+ BEV_UNLOCK(bufev);
+}
+
+struct evbuffer *
+bufferevent_get_input(struct bufferevent *bufev)
+{
+ return bufev->input;
+}
+
+struct evbuffer *
+bufferevent_get_output(struct bufferevent *bufev)
+{
+ return bufev->output;
+}
+
+struct event_base *
+bufferevent_get_base(struct bufferevent *bufev)
+{
+ return bufev->ev_base;
+}
+
+int
+bufferevent_get_priority(const struct bufferevent *bufev)
+{
+ if (event_initialized(&bufev->ev_read)) {
+ return event_get_priority(&bufev->ev_read);
+ } else {
+ return event_base_get_npriorities(bufev->ev_base) / 2;
+ }
+}
+
+int
+bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
+{
+ if (evbuffer_add(bufev->output, data, size) == -1)
+ return (-1);
+
+ return 0;
+}
+
+int
+bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf)
+{
+ if (evbuffer_add_buffer(bufev->output, buf) == -1)
+ return (-1);
+
+ return 0;
+}
+
+size_t
+bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
+{
+ return (evbuffer_remove(bufev->input, data, size));
+}
+
+int
+bufferevent_read_buffer(struct bufferevent *bufev, struct evbuffer *buf)
+{
+ return (evbuffer_add_buffer(buf, bufev->input));
+}
+
+int
+bufferevent_enable(struct bufferevent *bufev, short event)
+{
+ struct bufferevent_private *bufev_private =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+ short impl_events = event;
+ int r = 0;
+
+ bufferevent_incref_and_lock_(bufev);
+ if (bufev_private->read_suspended)
+ impl_events &= ~EV_READ;
+ if (bufev_private->write_suspended)
+ impl_events &= ~EV_WRITE;
+
+ bufev->enabled |= event;
+
+ if (impl_events && bufev->be_ops->enable(bufev, impl_events) < 0)
+ r = -1;
+
+ bufferevent_decref_and_unlock_(bufev);
+ return r;
+}
+
+int
+bufferevent_set_timeouts(struct bufferevent *bufev,
+ const struct timeval *tv_read,
+ const struct timeval *tv_write)
+{
+ int r = 0;
+ BEV_LOCK(bufev);
+ if (tv_read) {
+ bufev->timeout_read = *tv_read;
+ } else {
+ evutil_timerclear(&bufev->timeout_read);
+ }
+ if (tv_write) {
+ bufev->timeout_write = *tv_write;
+ } else {
+ evutil_timerclear(&bufev->timeout_write);
+ }
+
+ if (bufev->be_ops->adj_timeouts)
+ r = bufev->be_ops->adj_timeouts(bufev);
+ BEV_UNLOCK(bufev);
+
+ return r;
+}
+
+
+/* Obsolete; use bufferevent_set_timeouts */
+void
+bufferevent_settimeout(struct bufferevent *bufev,
+ int timeout_read, int timeout_write)
+{
+ struct timeval tv_read, tv_write;
+ struct timeval *ptv_read = NULL, *ptv_write = NULL;
+
+ memset(&tv_read, 0, sizeof(tv_read));
+ memset(&tv_write, 0, sizeof(tv_write));
+
+ if (timeout_read) {
+ tv_read.tv_sec = timeout_read;
+ ptv_read = &tv_read;
+ }
+ if (timeout_write) {
+ tv_write.tv_sec = timeout_write;
+ ptv_write = &tv_write;
+ }
+
+ bufferevent_set_timeouts(bufev, ptv_read, ptv_write);
+}
+
+
+int
+bufferevent_disable_hard_(struct bufferevent *bufev, short event)
+{
+ int r = 0;
+ struct bufferevent_private *bufev_private =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+
+ BEV_LOCK(bufev);
+ bufev->enabled &= ~event;
+
+ bufev_private->connecting = 0;
+ if (bufev->be_ops->disable(bufev, event) < 0)
+ r = -1;
+
+ BEV_UNLOCK(bufev);
+ return r;
+}
+
+int
+bufferevent_disable(struct bufferevent *bufev, short event)
+{
+ int r = 0;
+
+ BEV_LOCK(bufev);
+ bufev->enabled &= ~event;
+
+ if (bufev->be_ops->disable(bufev, event) < 0)
+ r = -1;
+
+ BEV_UNLOCK(bufev);
+ return r;
+}
+
+/*
+ * Sets the water marks
+ */
+
+void
+bufferevent_setwatermark(struct bufferevent *bufev, short events,
+ size_t lowmark, size_t highmark)
+{
+ struct bufferevent_private *bufev_private =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+
+ BEV_LOCK(bufev);
+ if (events & EV_WRITE) {
+ bufev->wm_write.low = lowmark;
+ bufev->wm_write.high = highmark;
+ }
+
+ if (events & EV_READ) {
+ bufev->wm_read.low = lowmark;
+ bufev->wm_read.high = highmark;
+
+ if (highmark) {
+ /* There is now a new high-water mark for read.
+ enable the callback if needed, and see if we should
+ suspend/bufferevent_wm_unsuspend. */
+
+ if (bufev_private->read_watermarks_cb == NULL) {
+ bufev_private->read_watermarks_cb =
+ evbuffer_add_cb(bufev->input,
+ bufferevent_inbuf_wm_cb,
+ bufev);
+ }
+ evbuffer_cb_set_flags(bufev->input,
+ bufev_private->read_watermarks_cb,
+ EVBUFFER_CB_ENABLED|EVBUFFER_CB_NODEFER);
+
+ if (evbuffer_get_length(bufev->input) >= highmark)
+ bufferevent_wm_suspend_read(bufev);
+ else if (evbuffer_get_length(bufev->input) < highmark)
+ bufferevent_wm_unsuspend_read(bufev);
+ } else {
+ /* There is now no high-water mark for read. */
+ if (bufev_private->read_watermarks_cb)
+ evbuffer_cb_clear_flags(bufev->input,
+ bufev_private->read_watermarks_cb,
+ EVBUFFER_CB_ENABLED);
+ bufferevent_wm_unsuspend_read(bufev);
+ }
+ }
+ BEV_UNLOCK(bufev);
+}
+
+int
+bufferevent_getwatermark(struct bufferevent *bufev, short events,
+ size_t *lowmark, size_t *highmark)
+{
+ if (events == EV_WRITE) {
+ BEV_LOCK(bufev);
+ if (lowmark)
+ *lowmark = bufev->wm_write.low;
+ if (highmark)
+ *highmark = bufev->wm_write.high;
+ BEV_UNLOCK(bufev);
+ return 0;
+ }
+
+ if (events == EV_READ) {
+ BEV_LOCK(bufev);
+ if (lowmark)
+ *lowmark = bufev->wm_read.low;
+ if (highmark)
+ *highmark = bufev->wm_read.high;
+ BEV_UNLOCK(bufev);
+ return 0;
+ }
+ return -1;
+}
+
+int
+bufferevent_flush(struct bufferevent *bufev,
+ short iotype,
+ enum bufferevent_flush_mode mode)
+{
+ int r = -1;
+ BEV_LOCK(bufev);
+ if (bufev->be_ops->flush)
+ r = bufev->be_ops->flush(bufev, iotype, mode);
+ BEV_UNLOCK(bufev);
+ return r;
+}
+
+void
+bufferevent_incref_and_lock_(struct bufferevent *bufev)
+{
+ struct bufferevent_private *bufev_private =
+ BEV_UPCAST(bufev);
+ BEV_LOCK(bufev);
+ ++bufev_private->refcnt;
+}
+
+#if 0
+static void
+bufferevent_transfer_lock_ownership_(struct bufferevent *donor,
+ struct bufferevent *recipient)
+{
+ struct bufferevent_private *d = BEV_UPCAST(donor);
+ struct bufferevent_private *r = BEV_UPCAST(recipient);
+ if (d->lock != r->lock)
+ return;
+ if (r->own_lock)
+ return;
+ if (d->own_lock) {
+ d->own_lock = 0;
+ r->own_lock = 1;
+ }
+}
+#endif
+
+int
+bufferevent_decref_and_unlock_(struct bufferevent *bufev)
+{
+ struct bufferevent_private *bufev_private =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+ int n_cbs = 0;
+#define MAX_CBS 16
+ struct event_callback *cbs[MAX_CBS];
+
+ EVUTIL_ASSERT(bufev_private->refcnt > 0);
+
+ if (--bufev_private->refcnt) {
+ BEV_UNLOCK(bufev);
+ return 0;
+ }
+
+ if (bufev->be_ops->unlink)
+ bufev->be_ops->unlink(bufev);
+
+ /* Okay, we're out of references. Let's finalize this once all the
+ * callbacks are done running. */
+ cbs[0] = &bufev->ev_read.ev_evcallback;
+ cbs[1] = &bufev->ev_write.ev_evcallback;
+ cbs[2] = &bufev_private->deferred;
+ n_cbs = 3;
+ if (bufev_private->rate_limiting) {
+ struct event *e = &bufev_private->rate_limiting->refill_bucket_event;
+ if (event_initialized(e))
+ cbs[n_cbs++] = &e->ev_evcallback;
+ }
+ n_cbs += evbuffer_get_callbacks_(bufev->input, cbs+n_cbs, MAX_CBS-n_cbs);
+ n_cbs += evbuffer_get_callbacks_(bufev->output, cbs+n_cbs, MAX_CBS-n_cbs);
+
+ event_callback_finalize_many_(bufev->ev_base, n_cbs, cbs,
+ bufferevent_finalize_cb_);
+
+#undef MAX_CBS
+ BEV_UNLOCK(bufev);
+
+ return 1;
+}
+
+static void
+bufferevent_finalize_cb_(struct event_callback *evcb, void *arg_)
+{
+ struct bufferevent *bufev = arg_;
+ struct bufferevent *underlying;
+ struct bufferevent_private *bufev_private =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+
+ BEV_LOCK(bufev);
+ underlying = bufferevent_get_underlying(bufev);
+
+ /* Clean up the shared info */
+ if (bufev->be_ops->destruct)
+ bufev->be_ops->destruct(bufev);
+
+ /* XXX what happens if refcnt for these buffers is > 1?
+ * The buffers can share a lock with this bufferevent object,
+ * but the lock might be destroyed below. */
+ /* evbuffer will free the callbacks */
+ evbuffer_free(bufev->input);
+ evbuffer_free(bufev->output);
+
+ if (bufev_private->rate_limiting) {
+ if (bufev_private->rate_limiting->group)
+ bufferevent_remove_from_rate_limit_group_internal_(bufev,0);
+ mm_free(bufev_private->rate_limiting);
+ bufev_private->rate_limiting = NULL;
+ }
+
+
+ BEV_UNLOCK(bufev);
+
+ if (bufev_private->own_lock)
+ EVTHREAD_FREE_LOCK(bufev_private->lock,
+ EVTHREAD_LOCKTYPE_RECURSIVE);
+
+ /* Free the actual allocated memory. */
+ mm_free(((char*)bufev) - bufev->be_ops->mem_offset);
+
+ /* Release the reference to underlying now that we no longer need the
+ * reference to it. We wait this long mainly in case our lock is
+ * shared with underlying.
+ *
+ * The 'destruct' function will also drop a reference to underlying
+ * if BEV_OPT_CLOSE_ON_FREE is set.
+ *
+ * XXX Should we/can we just refcount evbuffer/bufferevent locks?
+ * It would probably save us some headaches.
+ */
+ if (underlying)
+ bufferevent_decref_(underlying);
+}
+
+int
+bufferevent_decref(struct bufferevent *bufev)
+{
+ BEV_LOCK(bufev);
+ return bufferevent_decref_and_unlock_(bufev);
+}
+
+void
+bufferevent_free(struct bufferevent *bufev)
+{
+ BEV_LOCK(bufev);
+ bufferevent_setcb(bufev, NULL, NULL, NULL, NULL);
+ bufferevent_cancel_all_(bufev);
+ bufferevent_decref_and_unlock_(bufev);
+}
+
+void
+bufferevent_incref(struct bufferevent *bufev)
+{
+ struct bufferevent_private *bufev_private =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+
+ /* XXX: now that this function is public, we might want to
+ * - return the count from this function
+ * - create a new function to atomically grab the current refcount
+ */
+ BEV_LOCK(bufev);
+ ++bufev_private->refcnt;
+ BEV_UNLOCK(bufev);
+}
+
+int
+bufferevent_enable_locking_(struct bufferevent *bufev, void *lock)
+{
+#ifdef EVENT__DISABLE_THREAD_SUPPORT
+ return -1;
+#else
+ struct bufferevent *underlying;
+
+ if (BEV_UPCAST(bufev)->lock)
+ return -1;
+ underlying = bufferevent_get_underlying(bufev);
+
+ if (!lock && underlying && BEV_UPCAST(underlying)->lock) {
+ lock = BEV_UPCAST(underlying)->lock;
+ BEV_UPCAST(bufev)->lock = lock;
+ BEV_UPCAST(bufev)->own_lock = 0;
+ } else if (!lock) {
+ EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ if (!lock)
+ return -1;
+ BEV_UPCAST(bufev)->lock = lock;
+ BEV_UPCAST(bufev)->own_lock = 1;
+ } else {
+ BEV_UPCAST(bufev)->lock = lock;
+ BEV_UPCAST(bufev)->own_lock = 0;
+ }
+ evbuffer_enable_locking(bufev->input, lock);
+ evbuffer_enable_locking(bufev->output, lock);
+
+ if (underlying && !BEV_UPCAST(underlying)->lock)
+ bufferevent_enable_locking_(underlying, lock);
+
+ return 0;
+#endif
+}
+
+int
+bufferevent_setfd(struct bufferevent *bev, evutil_socket_t fd)
+{
+ union bufferevent_ctrl_data d;
+ int res = -1;
+ d.fd = fd;
+ BEV_LOCK(bev);
+ if (bev->be_ops->ctrl)
+ res = bev->be_ops->ctrl(bev, BEV_CTRL_SET_FD, &d);
+ BEV_UNLOCK(bev);
+ return res;
+}
+
+evutil_socket_t
+bufferevent_getfd(struct bufferevent *bev)
+{
+ union bufferevent_ctrl_data d;
+ int res = -1;
+ d.fd = -1;
+ BEV_LOCK(bev);
+ if (bev->be_ops->ctrl)
+ res = bev->be_ops->ctrl(bev, BEV_CTRL_GET_FD, &d);
+ BEV_UNLOCK(bev);
+ return (res<0) ? -1 : d.fd;
+}
+
+enum bufferevent_options
+bufferevent_get_options_(struct bufferevent *bev)
+{
+ struct bufferevent_private *bev_p =
+ EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+ enum bufferevent_options options;
+
+ BEV_LOCK(bev);
+ options = bev_p->options;
+ BEV_UNLOCK(bev);
+ return options;
+}
+
+
+static void
+bufferevent_cancel_all_(struct bufferevent *bev)
+{
+ union bufferevent_ctrl_data d;
+ memset(&d, 0, sizeof(d));
+ BEV_LOCK(bev);
+ if (bev->be_ops->ctrl)
+ bev->be_ops->ctrl(bev, BEV_CTRL_CANCEL_ALL, &d);
+ BEV_UNLOCK(bev);
+}
+
+short
+bufferevent_get_enabled(struct bufferevent *bufev)
+{
+ short r;
+ BEV_LOCK(bufev);
+ r = bufev->enabled;
+ BEV_UNLOCK(bufev);
+ return r;
+}
+
+struct bufferevent *
+bufferevent_get_underlying(struct bufferevent *bev)
+{
+ union bufferevent_ctrl_data d;
+ int res = -1;
+ d.ptr = NULL;
+ BEV_LOCK(bev);
+ if (bev->be_ops->ctrl)
+ res = bev->be_ops->ctrl(bev, BEV_CTRL_GET_UNDERLYING, &d);
+ BEV_UNLOCK(bev);
+ return (res<0) ? NULL : d.ptr;
+}
+
+static void
+bufferevent_generic_read_timeout_cb(evutil_socket_t fd, short event, void *ctx)
+{
+ struct bufferevent *bev = ctx;
+ bufferevent_incref_and_lock_(bev);
+ bufferevent_disable(bev, EV_READ);
+ bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_READING, 0);
+ bufferevent_decref_and_unlock_(bev);
+}
+static void
+bufferevent_generic_write_timeout_cb(evutil_socket_t fd, short event, void *ctx)
+{
+ struct bufferevent *bev = ctx;
+ bufferevent_incref_and_lock_(bev);
+ bufferevent_disable(bev, EV_WRITE);
+ bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING, 0);
+ bufferevent_decref_and_unlock_(bev);
+}
+
+void
+bufferevent_init_generic_timeout_cbs_(struct bufferevent *bev)
+{
+ event_assign(&bev->ev_read, bev->ev_base, -1, EV_FINALIZE,
+ bufferevent_generic_read_timeout_cb, bev);
+ event_assign(&bev->ev_write, bev->ev_base, -1, EV_FINALIZE,
+ bufferevent_generic_write_timeout_cb, bev);
+}
+
+int
+bufferevent_generic_adj_timeouts_(struct bufferevent *bev)
+{
+ const short enabled = bev->enabled;
+ struct bufferevent_private *bev_p =
+ EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+ int r1=0, r2=0;
+ if ((enabled & EV_READ) && !bev_p->read_suspended &&
+ evutil_timerisset(&bev->timeout_read))
+ r1 = event_add(&bev->ev_read, &bev->timeout_read);
+ else
+ r1 = event_del(&bev->ev_read);
+
+ if ((enabled & EV_WRITE) && !bev_p->write_suspended &&
+ evutil_timerisset(&bev->timeout_write) &&
+ evbuffer_get_length(bev->output))
+ r2 = event_add(&bev->ev_write, &bev->timeout_write);
+ else
+ r2 = event_del(&bev->ev_write);
+ if (r1 < 0 || r2 < 0)
+ return -1;
+ return 0;
+}
+
+int
+bufferevent_generic_adj_existing_timeouts_(struct bufferevent *bev)
+{
+ int r = 0;
+ if (event_pending(&bev->ev_read, EV_READ, NULL)) {
+ if (evutil_timerisset(&bev->timeout_read)) {
+ if (bufferevent_add_event_(&bev->ev_read, &bev->timeout_read) < 0)
+ r = -1;
+ } else {
+ event_remove_timer(&bev->ev_read);
+ }
+ }
+ if (event_pending(&bev->ev_write, EV_WRITE, NULL)) {
+ if (evutil_timerisset(&bev->timeout_write)) {
+ if (bufferevent_add_event_(&bev->ev_write, &bev->timeout_write) < 0)
+ r = -1;
+ } else {
+ event_remove_timer(&bev->ev_write);
+ }
+ }
+ return r;
+}
+
+int
+bufferevent_add_event_(struct event *ev, const struct timeval *tv)
+{
+ if (!evutil_timerisset(tv))
+ return event_add(ev, NULL);
+ else
+ return event_add(ev, tv);
+}
+
+/* For use by user programs only; internally, we should be calling
+ either bufferevent_incref_and_lock_(), or BEV_LOCK. */
+void
+bufferevent_lock(struct bufferevent *bev)
+{
+ bufferevent_incref_and_lock_(bev);
+}
+
+void
+bufferevent_unlock(struct bufferevent *bev)
+{
+ bufferevent_decref_and_unlock_(bev);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_async.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_async.c
new file mode 100644
index 000000000..6395e57a9
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_async.c
@@ -0,0 +1,686 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef EVENT__HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include <sys/queue.h>
+
+#include "event2/util.h"
+#include "event2/bufferevent.h"
+#include "event2/buffer.h"
+#include "event2/bufferevent_struct.h"
+#include "event2/event.h"
+#include "event2/util.h"
+#include "event-internal.h"
+#include "log-internal.h"
+#include "mm-internal.h"
+#include "bufferevent-internal.h"
+#include "util-internal.h"
+#include "iocp-internal.h"
+
+#ifndef SO_UPDATE_CONNECT_CONTEXT
+/* Mingw is sometimes missing this */
+#define SO_UPDATE_CONNECT_CONTEXT 0x7010
+#endif
+
+/* prototypes */
+static int be_async_enable(struct bufferevent *, short);
+static int be_async_disable(struct bufferevent *, short);
+static void be_async_destruct(struct bufferevent *);
+static int be_async_flush(struct bufferevent *, short, enum bufferevent_flush_mode);
+static int be_async_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
+
+struct bufferevent_async {
+ struct bufferevent_private bev;
+ struct event_overlapped connect_overlapped;
+ struct event_overlapped read_overlapped;
+ struct event_overlapped write_overlapped;
+ size_t read_in_progress;
+ size_t write_in_progress;
+ unsigned ok : 1;
+ unsigned read_added : 1;
+ unsigned write_added : 1;
+};
+
+const struct bufferevent_ops bufferevent_ops_async = {
+ "socket_async",
+ evutil_offsetof(struct bufferevent_async, bev.bev),
+ be_async_enable,
+ be_async_disable,
+ NULL, /* Unlink */
+ be_async_destruct,
+ bufferevent_generic_adj_timeouts_,
+ be_async_flush,
+ be_async_ctrl,
+};
+
+static inline struct bufferevent_async *
+upcast(struct bufferevent *bev)
+{
+ struct bufferevent_async *bev_a;
+ if (bev->be_ops != &bufferevent_ops_async)
+ return NULL;
+ bev_a = EVUTIL_UPCAST(bev, struct bufferevent_async, bev.bev);
+ return bev_a;
+}
+
+static inline struct bufferevent_async *
+upcast_connect(struct event_overlapped *eo)
+{
+ struct bufferevent_async *bev_a;
+ bev_a = EVUTIL_UPCAST(eo, struct bufferevent_async, connect_overlapped);
+ EVUTIL_ASSERT(BEV_IS_ASYNC(&bev_a->bev.bev));
+ return bev_a;
+}
+
+static inline struct bufferevent_async *
+upcast_read(struct event_overlapped *eo)
+{
+ struct bufferevent_async *bev_a;
+ bev_a = EVUTIL_UPCAST(eo, struct bufferevent_async, read_overlapped);
+ EVUTIL_ASSERT(BEV_IS_ASYNC(&bev_a->bev.bev));
+ return bev_a;
+}
+
+static inline struct bufferevent_async *
+upcast_write(struct event_overlapped *eo)
+{
+ struct bufferevent_async *bev_a;
+ bev_a = EVUTIL_UPCAST(eo, struct bufferevent_async, write_overlapped);
+ EVUTIL_ASSERT(BEV_IS_ASYNC(&bev_a->bev.bev));
+ return bev_a;
+}
+
+static void
+bev_async_del_write(struct bufferevent_async *beva)
+{
+ struct bufferevent *bev = &beva->bev.bev;
+
+ if (beva->write_added) {
+ beva->write_added = 0;
+ event_base_del_virtual_(bev->ev_base);
+ }
+}
+
+static void
+bev_async_del_read(struct bufferevent_async *beva)
+{
+ struct bufferevent *bev = &beva->bev.bev;
+
+ if (beva->read_added) {
+ beva->read_added = 0;
+ event_base_del_virtual_(bev->ev_base);
+ }
+}
+
+static void
+bev_async_add_write(struct bufferevent_async *beva)
+{
+ struct bufferevent *bev = &beva->bev.bev;
+
+ if (!beva->write_added) {
+ beva->write_added = 1;
+ event_base_add_virtual_(bev->ev_base);
+ }
+}
+
+static void
+bev_async_add_read(struct bufferevent_async *beva)
+{
+ struct bufferevent *bev = &beva->bev.bev;
+
+ if (!beva->read_added) {
+ beva->read_added = 1;
+ event_base_add_virtual_(bev->ev_base);
+ }
+}
+
+static void
+bev_async_consider_writing(struct bufferevent_async *beva)
+{
+ size_t at_most;
+ int limit;
+ struct bufferevent *bev = &beva->bev.bev;
+
+ /* Don't write if there's a write in progress, or we do not
+ * want to write, or when there's nothing left to write. */
+ if (beva->write_in_progress || beva->bev.connecting)
+ return;
+ if (!beva->ok || !(bev->enabled&EV_WRITE) ||
+ !evbuffer_get_length(bev->output)) {
+ bev_async_del_write(beva);
+ return;
+ }
+
+ at_most = evbuffer_get_length(bev->output);
+
+ /* This is safe so long as bufferevent_get_write_max never returns
+ * more than INT_MAX. That's true for now. XXXX */
+ limit = (int)bufferevent_get_write_max_(&beva->bev);
+ if (at_most >= (size_t)limit && limit >= 0)
+ at_most = limit;
+
+ if (beva->bev.write_suspended) {
+ bev_async_del_write(beva);
+ return;
+ }
+
+ /* XXXX doesn't respect low-water mark very well. */
+ bufferevent_incref_(bev);
+ if (evbuffer_launch_write_(bev->output, at_most,
+ &beva->write_overlapped)) {
+ bufferevent_decref_(bev);
+ beva->ok = 0;
+ bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
+ } else {
+ beva->write_in_progress = at_most;
+ bufferevent_decrement_write_buckets_(&beva->bev, at_most);
+ bev_async_add_write(beva);
+ }
+}
+
+static void
+bev_async_consider_reading(struct bufferevent_async *beva)
+{
+ size_t cur_size;
+ size_t read_high;
+ size_t at_most;
+ int limit;
+ struct bufferevent *bev = &beva->bev.bev;
+
+ /* Don't read if there is a read in progress, or we do not
+ * want to read. */
+ if (beva->read_in_progress || beva->bev.connecting)
+ return;
+ if (!beva->ok || !(bev->enabled&EV_READ)) {
+ bev_async_del_read(beva);
+ return;
+ }
+
+ /* Don't read if we're full */
+ cur_size = evbuffer_get_length(bev->input);
+ read_high = bev->wm_read.high;
+ if (read_high) {
+ if (cur_size >= read_high) {
+ bev_async_del_read(beva);
+ return;
+ }
+ at_most = read_high - cur_size;
+ } else {
+ at_most = 16384; /* FIXME totally magic. */
+ }
+
+ /* XXXX This over-commits. */
+ /* XXXX see also not above on cast on bufferevent_get_write_max_() */
+ limit = (int)bufferevent_get_read_max_(&beva->bev);
+ if (at_most >= (size_t)limit && limit >= 0)
+ at_most = limit;
+
+ if (beva->bev.read_suspended) {
+ bev_async_del_read(beva);
+ return;
+ }
+
+ bufferevent_incref_(bev);
+ if (evbuffer_launch_read_(bev->input, at_most, &beva->read_overlapped)) {
+ beva->ok = 0;
+ bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
+ bufferevent_decref_(bev);
+ } else {
+ beva->read_in_progress = at_most;
+ bufferevent_decrement_read_buckets_(&beva->bev, at_most);
+ bev_async_add_read(beva);
+ }
+
+ return;
+}
+
+static void
+be_async_outbuf_callback(struct evbuffer *buf,
+ const struct evbuffer_cb_info *cbinfo,
+ void *arg)
+{
+ struct bufferevent *bev = arg;
+ struct bufferevent_async *bev_async = upcast(bev);
+
+ /* If we added data to the outbuf and were not writing before,
+ * we may want to write now. */
+
+ bufferevent_incref_and_lock_(bev);
+
+ if (cbinfo->n_added)
+ bev_async_consider_writing(bev_async);
+
+ bufferevent_decref_and_unlock_(bev);
+}
+
+static void
+be_async_inbuf_callback(struct evbuffer *buf,
+ const struct evbuffer_cb_info *cbinfo,
+ void *arg)
+{
+ struct bufferevent *bev = arg;
+ struct bufferevent_async *bev_async = upcast(bev);
+
+ /* If we drained data from the inbuf and were not reading before,
+ * we may want to read now */
+
+ bufferevent_incref_and_lock_(bev);
+
+ if (cbinfo->n_deleted)
+ bev_async_consider_reading(bev_async);
+
+ bufferevent_decref_and_unlock_(bev);
+}
+
+static int
+be_async_enable(struct bufferevent *buf, short what)
+{
+ struct bufferevent_async *bev_async = upcast(buf);
+
+ if (!bev_async->ok)
+ return -1;
+
+ if (bev_async->bev.connecting) {
+ /* Don't launch anything during connection attempts. */
+ return 0;
+ }
+
+ if (what & EV_READ)
+ BEV_RESET_GENERIC_READ_TIMEOUT(buf);
+ if (what & EV_WRITE)
+ BEV_RESET_GENERIC_WRITE_TIMEOUT(buf);
+
+ /* If we newly enable reading or writing, and we aren't reading or
+ writing already, consider launching a new read or write. */
+
+ if (what & EV_READ)
+ bev_async_consider_reading(bev_async);
+ if (what & EV_WRITE)
+ bev_async_consider_writing(bev_async);
+ return 0;
+}
+
+static int
+be_async_disable(struct bufferevent *bev, short what)
+{
+ struct bufferevent_async *bev_async = upcast(bev);
+ /* XXXX If we disable reading or writing, we may want to consider
+ * canceling any in-progress read or write operation, though it might
+ * not work. */
+
+ if (what & EV_READ) {
+ BEV_DEL_GENERIC_READ_TIMEOUT(bev);
+ bev_async_del_read(bev_async);
+ }
+ if (what & EV_WRITE) {
+ BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
+ bev_async_del_write(bev_async);
+ }
+
+ return 0;
+}
+
+static void
+be_async_destruct(struct bufferevent *bev)
+{
+ struct bufferevent_async *bev_async = upcast(bev);
+ struct bufferevent_private *bev_p = BEV_UPCAST(bev);
+ evutil_socket_t fd;
+
+ EVUTIL_ASSERT(!upcast(bev)->write_in_progress &&
+ !upcast(bev)->read_in_progress);
+
+ bev_async_del_read(bev_async);
+ bev_async_del_write(bev_async);
+
+ fd = evbuffer_overlapped_get_fd_(bev->input);
+ if (fd != (evutil_socket_t)INVALID_SOCKET &&
+ (bev_p->options & BEV_OPT_CLOSE_ON_FREE)) {
+ evutil_closesocket(fd);
+ evbuffer_overlapped_set_fd_(bev->input, INVALID_SOCKET);
+ }
+}
+
+/* GetQueuedCompletionStatus doesn't reliably yield WSA error codes, so
+ * we use WSAGetOverlappedResult to translate. */
+static void
+bev_async_set_wsa_error(struct bufferevent *bev, struct event_overlapped *eo)
+{
+ DWORD bytes, flags;
+ evutil_socket_t fd;
+
+ fd = evbuffer_overlapped_get_fd_(bev->input);
+ WSAGetOverlappedResult(fd, &eo->overlapped, &bytes, FALSE, &flags);
+}
+
+static int
+be_async_flush(struct bufferevent *bev, short what,
+ enum bufferevent_flush_mode mode)
+{
+ return 0;
+}
+
+static void
+connect_complete(struct event_overlapped *eo, ev_uintptr_t key,
+ ev_ssize_t nbytes, int ok)
+{
+ struct bufferevent_async *bev_a = upcast_connect(eo);
+ struct bufferevent *bev = &bev_a->bev.bev;
+ evutil_socket_t sock;
+
+ BEV_LOCK(bev);
+
+ EVUTIL_ASSERT(bev_a->bev.connecting);
+ bev_a->bev.connecting = 0;
+ sock = evbuffer_overlapped_get_fd_(bev_a->bev.bev.input);
+ /* XXXX Handle error? */
+ setsockopt(sock, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);
+
+ if (ok)
+ bufferevent_async_set_connected_(bev);
+ else
+ bev_async_set_wsa_error(bev, eo);
+
+ bufferevent_run_eventcb_(bev,
+ ok? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR, 0);
+
+ event_base_del_virtual_(bev->ev_base);
+
+ bufferevent_decref_and_unlock_(bev);
+}
+
+static void
+read_complete(struct event_overlapped *eo, ev_uintptr_t key,
+ ev_ssize_t nbytes, int ok)
+{
+ struct bufferevent_async *bev_a = upcast_read(eo);
+ struct bufferevent *bev = &bev_a->bev.bev;
+ short what = BEV_EVENT_READING;
+ ev_ssize_t amount_unread;
+ BEV_LOCK(bev);
+ EVUTIL_ASSERT(bev_a->read_in_progress);
+
+ amount_unread = bev_a->read_in_progress - nbytes;
+ evbuffer_commit_read_(bev->input, nbytes);
+ bev_a->read_in_progress = 0;
+ if (amount_unread)
+ bufferevent_decrement_read_buckets_(&bev_a->bev, -amount_unread);
+
+ if (!ok)
+ bev_async_set_wsa_error(bev, eo);
+
+ if (bev_a->ok) {
+ if (ok && nbytes) {
+ BEV_RESET_GENERIC_READ_TIMEOUT(bev);
+ bufferevent_trigger_nolock_(bev, EV_READ, 0);
+ bev_async_consider_reading(bev_a);
+ } else if (!ok) {
+ what |= BEV_EVENT_ERROR;
+ bev_a->ok = 0;
+ bufferevent_run_eventcb_(bev, what, 0);
+ } else if (!nbytes) {
+ what |= BEV_EVENT_EOF;
+ bev_a->ok = 0;
+ bufferevent_run_eventcb_(bev, what, 0);
+ }
+ }
+
+ bufferevent_decref_and_unlock_(bev);
+}
+
+static void
+write_complete(struct event_overlapped *eo, ev_uintptr_t key,
+ ev_ssize_t nbytes, int ok)
+{
+ struct bufferevent_async *bev_a = upcast_write(eo);
+ struct bufferevent *bev = &bev_a->bev.bev;
+ short what = BEV_EVENT_WRITING;
+ ev_ssize_t amount_unwritten;
+
+ BEV_LOCK(bev);
+ EVUTIL_ASSERT(bev_a->write_in_progress);
+
+ amount_unwritten = bev_a->write_in_progress - nbytes;
+ evbuffer_commit_write_(bev->output, nbytes);
+ bev_a->write_in_progress = 0;
+
+ if (amount_unwritten)
+ bufferevent_decrement_write_buckets_(&bev_a->bev,
+ -amount_unwritten);
+
+
+ if (!ok)
+ bev_async_set_wsa_error(bev, eo);
+
+ if (bev_a->ok) {
+ if (ok && nbytes) {
+ BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
+ bufferevent_trigger_nolock_(bev, EV_WRITE, 0);
+ bev_async_consider_writing(bev_a);
+ } else if (!ok) {
+ what |= BEV_EVENT_ERROR;
+ bev_a->ok = 0;
+ bufferevent_run_eventcb_(bev, what, 0);
+ } else if (!nbytes) {
+ what |= BEV_EVENT_EOF;
+ bev_a->ok = 0;
+ bufferevent_run_eventcb_(bev, what, 0);
+ }
+ }
+
+ bufferevent_decref_and_unlock_(bev);
+}
+
+struct bufferevent *
+bufferevent_async_new_(struct event_base *base,
+ evutil_socket_t fd, int options)
+{
+ struct bufferevent_async *bev_a;
+ struct bufferevent *bev;
+ struct event_iocp_port *iocp;
+
+ options |= BEV_OPT_THREADSAFE;
+
+ if (!(iocp = event_base_get_iocp_(base)))
+ return NULL;
+
+ if (fd >= 0 && event_iocp_port_associate_(iocp, fd, 1)<0) {
+ int err = GetLastError();
+ /* We may have alrady associated this fd with a port.
+ * Let's hope it's this port, and that the error code
+ * for doing this neer changes. */
+ if (err != ERROR_INVALID_PARAMETER)
+ return NULL;
+ }
+
+ if (!(bev_a = mm_calloc(1, sizeof(struct bufferevent_async))))
+ return NULL;
+
+ bev = &bev_a->bev.bev;
+ if (!(bev->input = evbuffer_overlapped_new_(fd))) {
+ mm_free(bev_a);
+ return NULL;
+ }
+ if (!(bev->output = evbuffer_overlapped_new_(fd))) {
+ evbuffer_free(bev->input);
+ mm_free(bev_a);
+ return NULL;
+ }
+
+ if (bufferevent_init_common_(&bev_a->bev, base, &bufferevent_ops_async,
+ options)<0)
+ goto err;
+
+ evbuffer_add_cb(bev->input, be_async_inbuf_callback, bev);
+ evbuffer_add_cb(bev->output, be_async_outbuf_callback, bev);
+
+ event_overlapped_init_(&bev_a->connect_overlapped, connect_complete);
+ event_overlapped_init_(&bev_a->read_overlapped, read_complete);
+ event_overlapped_init_(&bev_a->write_overlapped, write_complete);
+
+ bufferevent_init_generic_timeout_cbs_(bev);
+
+ bev_a->ok = fd >= 0;
+
+ return bev;
+err:
+ bufferevent_free(&bev_a->bev.bev);
+ return NULL;
+}
+
+void
+bufferevent_async_set_connected_(struct bufferevent *bev)
+{
+ struct bufferevent_async *bev_async = upcast(bev);
+ bev_async->ok = 1;
+ bufferevent_init_generic_timeout_cbs_(bev);
+ /* Now's a good time to consider reading/writing */
+ be_async_enable(bev, bev->enabled);
+}
+
+int
+bufferevent_async_can_connect_(struct bufferevent *bev)
+{
+ const struct win32_extension_fns *ext =
+ event_get_win32_extension_fns_();
+
+ if (BEV_IS_ASYNC(bev) &&
+ event_base_get_iocp_(bev->ev_base) &&
+ ext && ext->ConnectEx)
+ return 1;
+
+ return 0;
+}
+
+int
+bufferevent_async_connect_(struct bufferevent *bev, evutil_socket_t fd,
+ const struct sockaddr *sa, int socklen)
+{
+ BOOL rc;
+ struct bufferevent_async *bev_async = upcast(bev);
+ struct sockaddr_storage ss;
+ const struct win32_extension_fns *ext =
+ event_get_win32_extension_fns_();
+
+ EVUTIL_ASSERT(ext && ext->ConnectEx && fd >= 0 && sa != NULL);
+
+ /* ConnectEx() requires that the socket be bound to an address
+ * with bind() before using, otherwise it will fail. We attempt
+ * to issue a bind() here, taking into account that the error
+ * code is set to WSAEINVAL when the socket is already bound. */
+ memset(&ss, 0, sizeof(ss));
+ if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = INADDR_ANY;
+ } else if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_addr = in6addr_any;
+ } else {
+ /* Well, the user will have to bind() */
+ return -1;
+ }
+ if (bind(fd, (struct sockaddr *)&ss, sizeof(ss)) < 0 &&
+ WSAGetLastError() != WSAEINVAL)
+ return -1;
+
+ event_base_add_virtual_(bev->ev_base);
+ bufferevent_incref_(bev);
+ rc = ext->ConnectEx(fd, sa, socklen, NULL, 0, NULL,
+ &bev_async->connect_overlapped.overlapped);
+ if (rc || WSAGetLastError() == ERROR_IO_PENDING)
+ return 0;
+
+ event_base_del_virtual_(bev->ev_base);
+ bufferevent_decref_(bev);
+
+ return -1;
+}
+
+static int
+be_async_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
+ union bufferevent_ctrl_data *data)
+{
+ switch (op) {
+ case BEV_CTRL_GET_FD:
+ data->fd = evbuffer_overlapped_get_fd_(bev->input);
+ return 0;
+ case BEV_CTRL_SET_FD: {
+ struct event_iocp_port *iocp;
+
+ if (data->fd == evbuffer_overlapped_get_fd_(bev->input))
+ return 0;
+ if (!(iocp = event_base_get_iocp_(bev->ev_base)))
+ return -1;
+ if (event_iocp_port_associate_(iocp, data->fd, 1) < 0)
+ return -1;
+ evbuffer_overlapped_set_fd_(bev->input, data->fd);
+ evbuffer_overlapped_set_fd_(bev->output, data->fd);
+ return 0;
+ }
+ case BEV_CTRL_CANCEL_ALL: {
+ struct bufferevent_async *bev_a = upcast(bev);
+ evutil_socket_t fd = evbuffer_overlapped_get_fd_(bev->input);
+ if (fd != (evutil_socket_t)INVALID_SOCKET &&
+ (bev_a->bev.options & BEV_OPT_CLOSE_ON_FREE)) {
+ closesocket(fd);
+ evbuffer_overlapped_set_fd_(bev->input, INVALID_SOCKET);
+ }
+ bev_a->ok = 0;
+ return 0;
+ }
+ case BEV_CTRL_GET_UNDERLYING:
+ default:
+ return -1;
+ }
+}
+
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_filter.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_filter.c
new file mode 100644
index 000000000..d47f9452b
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_filter.c
@@ -0,0 +1,623 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "evconfig-private.h"
+
+#include <sys/types.h>
+
+#include "event2/event-config.h"
+
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef EVENT__HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+#include "event2/util.h"
+#include "event2/bufferevent.h"
+#include "event2/buffer.h"
+#include "event2/bufferevent_struct.h"
+#include "event2/event.h"
+#include "log-internal.h"
+#include "mm-internal.h"
+#include "bufferevent-internal.h"
+#include "util-internal.h"
+
+/* prototypes */
+static int be_filter_enable(struct bufferevent *, short);
+static int be_filter_disable(struct bufferevent *, short);
+static void be_filter_unlink(struct bufferevent *);
+static void be_filter_destruct(struct bufferevent *);
+
+static void be_filter_readcb(struct bufferevent *, void *);
+static void be_filter_writecb(struct bufferevent *, void *);
+static void be_filter_eventcb(struct bufferevent *, short, void *);
+static int be_filter_flush(struct bufferevent *bufev,
+ short iotype, enum bufferevent_flush_mode mode);
+static int be_filter_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
+
+static void bufferevent_filtered_inbuf_cb(struct evbuffer *buf,
+ const struct evbuffer_cb_info *cbinfo, void *arg);
+
+static void bufferevent_filtered_outbuf_cb(struct evbuffer *buf,
+ const struct evbuffer_cb_info *info, void *arg);
+
+struct bufferevent_filtered {
+ struct bufferevent_private bev;
+
+ /** The bufferevent that we read/write filtered data from/to. */
+ struct bufferevent *underlying;
+ /** A callback on our inbuf to notice somebory removes data */
+ struct evbuffer_cb_entry *inbuf_cb;
+ /** A callback on our outbuf to notice when somebody adds data */
+ struct evbuffer_cb_entry *outbuf_cb;
+ /** True iff we have received an EOF callback from the underlying
+ * bufferevent. */
+ unsigned got_eof;
+
+ /** Function to free context when we're done. */
+ void (*free_context)(void *);
+ /** Input filter */
+ bufferevent_filter_cb process_in;
+ /** Output filter */
+ bufferevent_filter_cb process_out;
+ /** User-supplied argument to the filters. */
+ void *context;
+};
+
+const struct bufferevent_ops bufferevent_ops_filter = {
+ "filter",
+ evutil_offsetof(struct bufferevent_filtered, bev.bev),
+ be_filter_enable,
+ be_filter_disable,
+ be_filter_unlink,
+ be_filter_destruct,
+ bufferevent_generic_adj_timeouts_,
+ be_filter_flush,
+ be_filter_ctrl,
+};
+
+/* Given a bufferevent that's really the bev filter of a bufferevent_filtered,
+ * return that bufferevent_filtered. Returns NULL otherwise.*/
+static inline struct bufferevent_filtered *
+upcast(struct bufferevent *bev)
+{
+ struct bufferevent_filtered *bev_f;
+ if (bev->be_ops != &bufferevent_ops_filter)
+ return NULL;
+ bev_f = (void*)( ((char*)bev) -
+ evutil_offsetof(struct bufferevent_filtered, bev.bev));
+ EVUTIL_ASSERT(bev_f->bev.bev.be_ops == &bufferevent_ops_filter);
+ return bev_f;
+}
+
+#define downcast(bev_f) (&(bev_f)->bev.bev)
+
+/** Return 1 iff bevf's underlying bufferevent's output buffer is at or
+ * over its high watermark such that we should not write to it in a given
+ * flush mode. */
+static int
+be_underlying_writebuf_full(struct bufferevent_filtered *bevf,
+ enum bufferevent_flush_mode state)
+{
+ struct bufferevent *u = bevf->underlying;
+ return state == BEV_NORMAL &&
+ u->wm_write.high &&
+ evbuffer_get_length(u->output) >= u->wm_write.high;
+}
+
+/** Return 1 if our input buffer is at or over its high watermark such that we
+ * should not write to it in a given flush mode. */
+static int
+be_readbuf_full(struct bufferevent_filtered *bevf,
+ enum bufferevent_flush_mode state)
+{
+ struct bufferevent *bufev = downcast(bevf);
+ return state == BEV_NORMAL &&
+ bufev->wm_read.high &&
+ evbuffer_get_length(bufev->input) >= bufev->wm_read.high;
+}
+
+
+/* Filter to use when we're created with a NULL filter. */
+static enum bufferevent_filter_result
+be_null_filter(struct evbuffer *src, struct evbuffer *dst, ev_ssize_t lim,
+ enum bufferevent_flush_mode state, void *ctx)
+{
+ (void)state;
+ if (evbuffer_remove_buffer(src, dst, lim) == 0)
+ return BEV_OK;
+ else
+ return BEV_ERROR;
+}
+
+struct bufferevent *
+bufferevent_filter_new(struct bufferevent *underlying,
+ bufferevent_filter_cb input_filter,
+ bufferevent_filter_cb output_filter,
+ int options,
+ void (*free_context)(void *),
+ void *ctx)
+{
+ struct bufferevent_filtered *bufev_f;
+ int tmp_options = options & ~BEV_OPT_THREADSAFE;
+
+ if (!underlying)
+ return NULL;
+
+ if (!input_filter)
+ input_filter = be_null_filter;
+ if (!output_filter)
+ output_filter = be_null_filter;
+
+ bufev_f = mm_calloc(1, sizeof(struct bufferevent_filtered));
+ if (!bufev_f)
+ return NULL;
+
+ if (bufferevent_init_common_(&bufev_f->bev, underlying->ev_base,
+ &bufferevent_ops_filter, tmp_options) < 0) {
+ mm_free(bufev_f);
+ return NULL;
+ }
+ if (options & BEV_OPT_THREADSAFE) {
+ bufferevent_enable_locking_(downcast(bufev_f), NULL);
+ }
+
+ bufev_f->underlying = underlying;
+
+ bufev_f->process_in = input_filter;
+ bufev_f->process_out = output_filter;
+ bufev_f->free_context = free_context;
+ bufev_f->context = ctx;
+
+ bufferevent_setcb(bufev_f->underlying,
+ be_filter_readcb, be_filter_writecb, be_filter_eventcb, bufev_f);
+
+ bufev_f->inbuf_cb = evbuffer_add_cb(downcast(bufev_f)->input,
+ bufferevent_filtered_inbuf_cb, bufev_f);
+ evbuffer_cb_clear_flags(downcast(bufev_f)->input, bufev_f->inbuf_cb,
+ EVBUFFER_CB_ENABLED);
+
+ bufev_f->outbuf_cb = evbuffer_add_cb(downcast(bufev_f)->output,
+ bufferevent_filtered_outbuf_cb, bufev_f);
+
+ bufferevent_init_generic_timeout_cbs_(downcast(bufev_f));
+ bufferevent_incref_(underlying);
+
+ bufferevent_enable(underlying, EV_READ|EV_WRITE);
+ bufferevent_suspend_read_(underlying, BEV_SUSPEND_FILT_READ);
+
+ return downcast(bufev_f);
+}
+
+static void
+be_filter_unlink(struct bufferevent *bev)
+{
+ struct bufferevent_filtered *bevf = upcast(bev);
+ EVUTIL_ASSERT(bevf);
+
+ if (bevf->bev.options & BEV_OPT_CLOSE_ON_FREE) {
+ /* Yes, there is also a decref in bufferevent_decref_.
+ * That decref corresponds to the incref when we set
+ * underlying for the first time. This decref is an
+ * extra one to remove the last reference.
+ */
+ if (BEV_UPCAST(bevf->underlying)->refcnt < 2) {
+ event_warnx("BEV_OPT_CLOSE_ON_FREE set on an "
+ "bufferevent with too few references");
+ } else {
+ bufferevent_free(bevf->underlying);
+ }
+ } else {
+ if (bevf->underlying) {
+ if (bevf->underlying->errorcb == be_filter_eventcb)
+ bufferevent_setcb(bevf->underlying,
+ NULL, NULL, NULL, NULL);
+ bufferevent_unsuspend_read_(bevf->underlying,
+ BEV_SUSPEND_FILT_READ);
+ }
+ }
+}
+
+static void
+be_filter_destruct(struct bufferevent *bev)
+{
+ struct bufferevent_filtered *bevf = upcast(bev);
+ EVUTIL_ASSERT(bevf);
+ if (bevf->free_context)
+ bevf->free_context(bevf->context);
+
+ if (bevf->inbuf_cb)
+ evbuffer_remove_cb_entry(bev->input, bevf->inbuf_cb);
+
+ if (bevf->outbuf_cb)
+ evbuffer_remove_cb_entry(bev->output, bevf->outbuf_cb);
+}
+
+static int
+be_filter_enable(struct bufferevent *bev, short event)
+{
+ struct bufferevent_filtered *bevf = upcast(bev);
+ if (event & EV_WRITE)
+ BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
+
+ if (event & EV_READ) {
+ BEV_RESET_GENERIC_READ_TIMEOUT(bev);
+ bufferevent_unsuspend_read_(bevf->underlying,
+ BEV_SUSPEND_FILT_READ);
+ }
+ return 0;
+}
+
+static int
+be_filter_disable(struct bufferevent *bev, short event)
+{
+ struct bufferevent_filtered *bevf = upcast(bev);
+ if (event & EV_WRITE)
+ BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
+ if (event & EV_READ) {
+ BEV_DEL_GENERIC_READ_TIMEOUT(bev);
+ bufferevent_suspend_read_(bevf->underlying,
+ BEV_SUSPEND_FILT_READ);
+ }
+ return 0;
+}
+
+static enum bufferevent_filter_result
+be_filter_process_input(struct bufferevent_filtered *bevf,
+ enum bufferevent_flush_mode state,
+ int *processed_out)
+{
+ enum bufferevent_filter_result res;
+ struct bufferevent *bev = downcast(bevf);
+
+ if (state == BEV_NORMAL) {
+ /* If we're in 'normal' mode, don't urge data on the filter
+ * unless we're reading data and under our high-water mark.*/
+ if (!(bev->enabled & EV_READ) ||
+ be_readbuf_full(bevf, state))
+ return BEV_OK;
+ }
+
+ do {
+ ev_ssize_t limit = -1;
+ if (state == BEV_NORMAL && bev->wm_read.high)
+ limit = bev->wm_read.high -
+ evbuffer_get_length(bev->input);
+
+ res = bevf->process_in(bevf->underlying->input,
+ bev->input, limit, state, bevf->context);
+
+ if (res == BEV_OK)
+ *processed_out = 1;
+ } while (res == BEV_OK &&
+ (bev->enabled & EV_READ) &&
+ evbuffer_get_length(bevf->underlying->input) &&
+ !be_readbuf_full(bevf, state));
+
+ if (*processed_out)
+ BEV_RESET_GENERIC_READ_TIMEOUT(bev);
+
+ return res;
+}
+
+
+static enum bufferevent_filter_result
+be_filter_process_output(struct bufferevent_filtered *bevf,
+ enum bufferevent_flush_mode state,
+ int *processed_out)
+{
+ /* Requires references and lock: might call writecb */
+ enum bufferevent_filter_result res = BEV_OK;
+ struct bufferevent *bufev = downcast(bevf);
+ int again = 0;
+
+ if (state == BEV_NORMAL) {
+ /* If we're in 'normal' mode, don't urge data on the
+ * filter unless we're writing data, and the underlying
+ * bufferevent is accepting data, and we have data to
+ * give the filter. If we're in 'flush' or 'finish',
+ * call the filter no matter what. */
+ if (!(bufev->enabled & EV_WRITE) ||
+ be_underlying_writebuf_full(bevf, state) ||
+ !evbuffer_get_length(bufev->output))
+ return BEV_OK;
+ }
+
+ /* disable the callback that calls this function
+ when the user adds to the output buffer. */
+ evbuffer_cb_clear_flags(bufev->output, bevf->outbuf_cb,
+ EVBUFFER_CB_ENABLED);
+
+ do {
+ int processed = 0;
+ again = 0;
+
+ do {
+ ev_ssize_t limit = -1;
+ if (state == BEV_NORMAL &&
+ bevf->underlying->wm_write.high)
+ limit = bevf->underlying->wm_write.high -
+ evbuffer_get_length(bevf->underlying->output);
+
+ res = bevf->process_out(downcast(bevf)->output,
+ bevf->underlying->output,
+ limit,
+ state,
+ bevf->context);
+
+ if (res == BEV_OK)
+ processed = *processed_out = 1;
+ } while (/* Stop if the filter wasn't successful...*/
+ res == BEV_OK &&
+ /* Or if we aren't writing any more. */
+ (bufev->enabled & EV_WRITE) &&
+ /* Of if we have nothing more to write and we are
+ * not flushing. */
+ evbuffer_get_length(bufev->output) &&
+ /* Or if we have filled the underlying output buffer. */
+ !be_underlying_writebuf_full(bevf,state));
+
+ if (processed) {
+ /* call the write callback.*/
+ bufferevent_trigger_nolock_(bufev, EV_WRITE, 0);
+
+ if (res == BEV_OK &&
+ (bufev->enabled & EV_WRITE) &&
+ evbuffer_get_length(bufev->output) &&
+ !be_underlying_writebuf_full(bevf, state)) {
+ again = 1;
+ }
+ }
+ } while (again);
+
+ /* reenable the outbuf_cb */
+ evbuffer_cb_set_flags(bufev->output,bevf->outbuf_cb,
+ EVBUFFER_CB_ENABLED);
+
+ if (*processed_out)
+ BEV_RESET_GENERIC_WRITE_TIMEOUT(bufev);
+
+ return res;
+}
+
+/* Called when the size of our outbuf changes. */
+static void
+bufferevent_filtered_outbuf_cb(struct evbuffer *buf,
+ const struct evbuffer_cb_info *cbinfo, void *arg)
+{
+ struct bufferevent_filtered *bevf = arg;
+ struct bufferevent *bev = downcast(bevf);
+
+ if (cbinfo->n_added) {
+ int processed_any = 0;
+ /* Somebody added more data to the output buffer. Try to
+ * process it, if we should. */
+ bufferevent_incref_and_lock_(bev);
+ be_filter_process_output(bevf, BEV_NORMAL, &processed_any);
+ bufferevent_decref_and_unlock_(bev);
+ }
+}
+
+static void
+be_filter_read_nolock_(struct bufferevent *underlying, void *me_)
+{
+ struct bufferevent_filtered *bevf = me_;
+ enum bufferevent_filter_result res;
+ enum bufferevent_flush_mode state;
+ struct bufferevent *bufev = downcast(bevf);
+ struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
+ int processed_any = 0;
+
+ // It's possible our refcount is 0 at this point if another thread free'd our filterevent
+ EVUTIL_ASSERT(bufev_private->refcnt >= 0);
+
+ // If our refcount is > 0
+ if (bufev_private->refcnt > 0) {
+
+ if (bevf->got_eof)
+ state = BEV_FINISHED;
+ else
+ state = BEV_NORMAL;
+
+ /* XXXX use return value */
+ res = be_filter_process_input(bevf, state, &processed_any);
+ (void)res;
+
+ /* XXX This should be in process_input, not here. There are
+ * other places that can call process-input, and they should
+ * force readcb calls as needed. */
+ if (processed_any) {
+ bufferevent_trigger_nolock_(bufev, EV_READ, 0);
+ if (evbuffer_get_length(underlying->input) > 0 &&
+ be_readbuf_full(bevf, state)) {
+ /* data left in underlying buffer and filter input buffer
+ * hit its read high watermark.
+ * Schedule callback to avoid data gets stuck in underlying
+ * input buffer.
+ */
+ evbuffer_cb_set_flags(bufev->input, bevf->inbuf_cb,
+ EVBUFFER_CB_ENABLED);
+ }
+ }
+ }
+}
+
+/* Called when the size of our inbuf changes. */
+static void
+bufferevent_filtered_inbuf_cb(struct evbuffer *buf,
+ const struct evbuffer_cb_info *cbinfo, void *arg)
+{
+ struct bufferevent_filtered *bevf = arg;
+ enum bufferevent_flush_mode state;
+ struct bufferevent *bev = downcast(bevf);
+
+ BEV_LOCK(bev);
+
+ if (bevf->got_eof)
+ state = BEV_FINISHED;
+ else
+ state = BEV_NORMAL;
+
+
+ if (!be_readbuf_full(bevf, state)) {
+ /* opportunity to read data which was left in underlying
+ * input buffer because filter input buffer hit read
+ * high watermark.
+ */
+ evbuffer_cb_clear_flags(bev->input, bevf->inbuf_cb,
+ EVBUFFER_CB_ENABLED);
+ if (evbuffer_get_length(bevf->underlying->input) > 0)
+ be_filter_read_nolock_(bevf->underlying, bevf);
+ }
+
+ BEV_UNLOCK(bev);
+}
+
+/* Called when the underlying socket has read. */
+static void
+be_filter_readcb(struct bufferevent *underlying, void *me_)
+{
+ struct bufferevent_filtered *bevf = me_;
+ struct bufferevent *bev = downcast(bevf);
+
+ BEV_LOCK(bev);
+
+ be_filter_read_nolock_(underlying, me_);
+
+ BEV_UNLOCK(bev);
+}
+
+/* Called when the underlying socket has drained enough that we can write to
+ it. */
+static void
+be_filter_writecb(struct bufferevent *underlying, void *me_)
+{
+ struct bufferevent_filtered *bevf = me_;
+ struct bufferevent *bev = downcast(bevf);
+ struct bufferevent_private *bufev_private = BEV_UPCAST(bev);
+ int processed_any = 0;
+
+ BEV_LOCK(bev);
+
+ // It's possible our refcount is 0 at this point if another thread free'd our filterevent
+ EVUTIL_ASSERT(bufev_private->refcnt >= 0);
+
+ // If our refcount is > 0
+ if (bufev_private->refcnt > 0) {
+ be_filter_process_output(bevf, BEV_NORMAL, &processed_any);
+ }
+
+ BEV_UNLOCK(bev);
+}
+
+/* Called when the underlying socket has given us an error */
+static void
+be_filter_eventcb(struct bufferevent *underlying, short what, void *me_)
+{
+ struct bufferevent_filtered *bevf = me_;
+ struct bufferevent *bev = downcast(bevf);
+ struct bufferevent_private *bufev_private = BEV_UPCAST(bev);
+
+ BEV_LOCK(bev);
+
+ // It's possible our refcount is 0 at this point if another thread free'd our filterevent
+ EVUTIL_ASSERT(bufev_private->refcnt >= 0);
+
+ // If our refcount is > 0
+ if (bufev_private->refcnt > 0) {
+
+ /* All we can really to is tell our own eventcb. */
+ bufferevent_run_eventcb_(bev, what, 0);
+ }
+
+ BEV_UNLOCK(bev);
+}
+
+static int
+be_filter_flush(struct bufferevent *bufev,
+ short iotype, enum bufferevent_flush_mode mode)
+{
+ struct bufferevent_filtered *bevf = upcast(bufev);
+ int processed_any = 0;
+ EVUTIL_ASSERT(bevf);
+
+ bufferevent_incref_and_lock_(bufev);
+
+ if (iotype & EV_READ) {
+ be_filter_process_input(bevf, mode, &processed_any);
+ }
+ if (iotype & EV_WRITE) {
+ be_filter_process_output(bevf, mode, &processed_any);
+ }
+ /* XXX check the return value? */
+ /* XXX does this want to recursively call lower-level flushes? */
+ bufferevent_flush(bevf->underlying, iotype, mode);
+
+ bufferevent_decref_and_unlock_(bufev);
+
+ return processed_any;
+}
+
+static int
+be_filter_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
+ union bufferevent_ctrl_data *data)
+{
+ struct bufferevent_filtered *bevf;
+ switch (op) {
+ case BEV_CTRL_GET_UNDERLYING:
+ bevf = upcast(bev);
+ data->ptr = bevf->underlying;
+ return 0;
+ case BEV_CTRL_SET_FD:
+ bevf = upcast(bev);
+
+ if (bevf->underlying &&
+ bevf->underlying->be_ops &&
+ bevf->underlying->be_ops->ctrl) {
+ return (bevf->underlying->be_ops->ctrl)(bevf->underlying, op, data);
+ }
+
+ case BEV_CTRL_GET_FD:
+ case BEV_CTRL_CANCEL_ALL:
+ default:
+ return -1;
+ }
+
+ return -1;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_openssl.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_openssl.c
new file mode 100644
index 000000000..cbb7f8a50
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_openssl.c
@@ -0,0 +1,1486 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Get rid of OSX 10.7 and greater deprecation warnings.
+#if defined(__APPLE__) && defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
+
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef EVENT__HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+#include "event2/bufferevent.h"
+#include "event2/bufferevent_struct.h"
+#include "event2/bufferevent_ssl.h"
+#include "event2/buffer.h"
+#include "event2/event.h"
+
+#include "mm-internal.h"
+#include "bufferevent-internal.h"
+#include "log-internal.h"
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include "openssl-compat.h"
+
+/*
+ * Define an OpenSSL bio that targets a bufferevent.
+ */
+
+/* --------------------
+ A BIO is an OpenSSL abstraction that handles reading and writing data. The
+ library will happily speak SSL over anything that implements a BIO
+ interface.
+
+ Here we define a BIO implementation that directs its output to a
+ bufferevent. We'll want to use this only when none of OpenSSL's built-in
+ IO mechanisms work for us.
+ -------------------- */
+
+/* every BIO type needs its own integer type value. */
+#define BIO_TYPE_LIBEVENT 57
+/* ???? Arguably, we should set BIO_TYPE_FILTER or BIO_TYPE_SOURCE_SINK on
+ * this. */
+
+#if 0
+static void
+print_err(int val)
+{
+ int err;
+ printf("Error was %d\n", val);
+
+ while ((err = ERR_get_error())) {
+ const char *msg = (const char*)ERR_reason_error_string(err);
+ const char *lib = (const char*)ERR_lib_error_string(err);
+ const char *func = (const char*)ERR_func_error_string(err);
+
+ printf("%s in %s %s\n", msg, lib, func);
+ }
+}
+#else
+#define print_err(v) ((void)0)
+#endif
+
+/* Called to initialize a new BIO */
+static int
+bio_bufferevent_new(BIO *b)
+{
+ BIO_set_init(b, 0);
+ BIO_set_data(b, NULL); /* We'll be putting the bufferevent in this field.*/
+ return 1;
+}
+
+/* Called to uninitialize the BIO. */
+static int
+bio_bufferevent_free(BIO *b)
+{
+ if (!b)
+ return 0;
+ if (BIO_get_shutdown(b)) {
+ if (BIO_get_init(b) && BIO_get_data(b))
+ bufferevent_free(BIO_get_data(b));
+ BIO_free(b);
+ }
+ return 1;
+}
+
+/* Called to extract data from the BIO. */
+static int
+bio_bufferevent_read(BIO *b, char *out, int outlen)
+{
+ int r = 0;
+ struct evbuffer *input;
+
+ BIO_clear_retry_flags(b);
+
+ if (!out)
+ return 0;
+ if (!BIO_get_data(b))
+ return -1;
+
+ input = bufferevent_get_input(BIO_get_data(b));
+ if (evbuffer_get_length(input) == 0) {
+ /* If there's no data to read, say so. */
+ BIO_set_retry_read(b);
+ return -1;
+ } else {
+ r = evbuffer_remove(input, out, outlen);
+ }
+
+ return r;
+}
+
+/* Called to write data info the BIO */
+static int
+bio_bufferevent_write(BIO *b, const char *in, int inlen)
+{
+ struct bufferevent *bufev = BIO_get_data(b);
+ struct evbuffer *output;
+ size_t outlen;
+
+ BIO_clear_retry_flags(b);
+
+ if (!BIO_get_data(b))
+ return -1;
+
+ output = bufferevent_get_output(bufev);
+ outlen = evbuffer_get_length(output);
+
+ /* Copy only as much data onto the output buffer as can fit under the
+ * high-water mark. */
+ if (bufev->wm_write.high && bufev->wm_write.high <= (outlen+inlen)) {
+ if (bufev->wm_write.high <= outlen) {
+ /* If no data can fit, we'll need to retry later. */
+ BIO_set_retry_write(b);
+ return -1;
+ }
+ inlen = bufev->wm_write.high - outlen;
+ }
+
+ EVUTIL_ASSERT(inlen > 0);
+ evbuffer_add(output, in, inlen);
+ return inlen;
+}
+
+/* Called to handle various requests */
+static long
+bio_bufferevent_ctrl(BIO *b, int cmd, long num, void *ptr)
+{
+ struct bufferevent *bufev = BIO_get_data(b);
+ long ret = 1;
+
+ switch (cmd) {
+ case BIO_CTRL_GET_CLOSE:
+ ret = BIO_get_shutdown(b);
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ BIO_set_shutdown(b, (int)num);
+ break;
+ case BIO_CTRL_PENDING:
+ ret = evbuffer_get_length(bufferevent_get_input(bufev)) != 0;
+ break;
+ case BIO_CTRL_WPENDING:
+ ret = evbuffer_get_length(bufferevent_get_output(bufev)) != 0;
+ break;
+ /* XXXX These two are given a special-case treatment because
+ * of cargo-cultism. I should come up with a better reason. */
+ case BIO_CTRL_DUP:
+ case BIO_CTRL_FLUSH:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+/* Called to write a string to the BIO */
+static int
+bio_bufferevent_puts(BIO *b, const char *s)
+{
+ return bio_bufferevent_write(b, s, strlen(s));
+}
+
+/* Method table for the bufferevent BIO */
+static BIO_METHOD *methods_bufferevent;
+
+/* Return the method table for the bufferevents BIO */
+static BIO_METHOD *
+BIO_s_bufferevent(void)
+{
+ if (methods_bufferevent == NULL) {
+ methods_bufferevent = BIO_meth_new(BIO_TYPE_LIBEVENT, "bufferevent");
+ if (methods_bufferevent == NULL)
+ return NULL;
+ BIO_meth_set_write(methods_bufferevent, bio_bufferevent_write);
+ BIO_meth_set_read(methods_bufferevent, bio_bufferevent_read);
+ BIO_meth_set_puts(methods_bufferevent, bio_bufferevent_puts);
+ BIO_meth_set_ctrl(methods_bufferevent, bio_bufferevent_ctrl);
+ BIO_meth_set_create(methods_bufferevent, bio_bufferevent_new);
+ BIO_meth_set_destroy(methods_bufferevent, bio_bufferevent_free);
+ }
+ return methods_bufferevent;
+}
+
+/* Create a new BIO to wrap communication around a bufferevent. If close_flag
+ * is true, the bufferevent will be freed when the BIO is closed. */
+static BIO *
+BIO_new_bufferevent(struct bufferevent *bufferevent, int close_flag)
+{
+ BIO *result;
+ if (!bufferevent)
+ return NULL;
+ if (!(result = BIO_new(BIO_s_bufferevent())))
+ return NULL;
+ BIO_set_init(result, 1);
+ BIO_set_data(result, bufferevent);
+ BIO_set_shutdown(result, close_flag ? 1 : 0);
+ return result;
+}
+
+/* --------------------
+ Now, here's the OpenSSL-based implementation of bufferevent.
+
+ The implementation comes in two flavors: one that connects its SSL object
+ to an underlying bufferevent using a BIO_bufferevent, and one that has the
+ SSL object connect to a socket directly. The latter should generally be
+ faster, except on Windows, where your best bet is using a
+ bufferevent_async.
+
+ (OpenSSL supports many other BIO types, too. But we can't use any unless
+ we have a good way to get notified when they become readable/writable.)
+ -------------------- */
+
+struct bio_data_counts {
+ unsigned long n_written;
+ unsigned long n_read;
+};
+
+struct bufferevent_openssl {
+ /* Shared fields with common bufferevent implementation code.
+ If we were set up with an underlying bufferevent, we use the
+ events here as timers only. If we have an SSL, then we use
+ the events as socket events.
+ */
+ struct bufferevent_private bev;
+ /* An underlying bufferevent that we're directing our output to.
+ If it's NULL, then we're connected to an fd, not an evbuffer. */
+ struct bufferevent *underlying;
+ /* The SSL object doing our encryption. */
+ SSL *ssl;
+
+ /* A callback that's invoked when data arrives on our outbuf so we
+ know to write data to the SSL. */
+ struct evbuffer_cb_entry *outbuf_cb;
+
+ /* A count of how much data the bios have read/written total. Used
+ for rate-limiting. */
+ struct bio_data_counts counts;
+
+ /* If this value is greater than 0, then the last SSL_write blocked,
+ * and we need to try it again with this many bytes. */
+ ev_ssize_t last_write;
+
+#define NUM_ERRORS 3
+ ev_uint32_t errors[NUM_ERRORS];
+
+ /* When we next get available space, we should say "read" instead of
+ "write". This can happen if there's a renegotiation during a read
+ operation. */
+ unsigned read_blocked_on_write : 1;
+ /* When we next get data, we should say "write" instead of "read". */
+ unsigned write_blocked_on_read : 1;
+ /* Treat TCP close before SSL close on SSL >= v3 as clean EOF. */
+ unsigned allow_dirty_shutdown : 1;
+ /* XXX */
+ unsigned n_errors : 2;
+
+ /* Are we currently connecting, accepting, or doing IO? */
+ unsigned state : 2;
+ /* If we reset fd, we sould reset state too */
+ unsigned old_state : 2;
+};
+
+static int be_openssl_enable(struct bufferevent *, short);
+static int be_openssl_disable(struct bufferevent *, short);
+static void be_openssl_unlink(struct bufferevent *);
+static void be_openssl_destruct(struct bufferevent *);
+static int be_openssl_adj_timeouts(struct bufferevent *);
+static int be_openssl_flush(struct bufferevent *bufev,
+ short iotype, enum bufferevent_flush_mode mode);
+static int be_openssl_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
+
+const struct bufferevent_ops bufferevent_ops_openssl = {
+ "ssl",
+ evutil_offsetof(struct bufferevent_openssl, bev.bev),
+ be_openssl_enable,
+ be_openssl_disable,
+ be_openssl_unlink,
+ be_openssl_destruct,
+ be_openssl_adj_timeouts,
+ be_openssl_flush,
+ be_openssl_ctrl,
+};
+
+/* Given a bufferevent, return a pointer to the bufferevent_openssl that
+ * contains it, if any. */
+static inline struct bufferevent_openssl *
+upcast(struct bufferevent *bev)
+{
+ struct bufferevent_openssl *bev_o;
+ if (bev->be_ops != &bufferevent_ops_openssl)
+ return NULL;
+ bev_o = (void*)( ((char*)bev) -
+ evutil_offsetof(struct bufferevent_openssl, bev.bev));
+ EVUTIL_ASSERT(bev_o->bev.bev.be_ops == &bufferevent_ops_openssl);
+ return bev_o;
+}
+
+static inline void
+put_error(struct bufferevent_openssl *bev_ssl, unsigned long err)
+{
+ if (bev_ssl->n_errors == NUM_ERRORS)
+ return;
+ /* The error type according to openssl is "unsigned long", but
+ openssl never uses more than 32 bits of it. It _can't_ use more
+ than 32 bits of it, since it needs to report errors on systems
+ where long is only 32 bits.
+ */
+ bev_ssl->errors[bev_ssl->n_errors++] = (ev_uint32_t) err;
+}
+
+/* Have the base communications channel (either the underlying bufferevent or
+ * ev_read and ev_write) start reading. Take the read-blocked-on-write flag
+ * into account. */
+static int
+start_reading(struct bufferevent_openssl *bev_ssl)
+{
+ if (bev_ssl->underlying) {
+ bufferevent_unsuspend_read_(bev_ssl->underlying,
+ BEV_SUSPEND_FILT_READ);
+ return 0;
+ } else {
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+ int r;
+ r = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
+ if (r == 0 && bev_ssl->read_blocked_on_write)
+ r = bufferevent_add_event_(&bev->ev_write,
+ &bev->timeout_write);
+ return r;
+ }
+}
+
+/* Have the base communications channel (either the underlying bufferevent or
+ * ev_read and ev_write) start writing. Take the write-blocked-on-read flag
+ * into account. */
+static int
+start_writing(struct bufferevent_openssl *bev_ssl)
+{
+ int r = 0;
+ if (bev_ssl->underlying) {
+ ;
+ } else {
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+ r = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
+ if (!r && bev_ssl->write_blocked_on_read)
+ r = bufferevent_add_event_(&bev->ev_read,
+ &bev->timeout_read);
+ }
+ return r;
+}
+
+static void
+stop_reading(struct bufferevent_openssl *bev_ssl)
+{
+ if (bev_ssl->write_blocked_on_read)
+ return;
+ if (bev_ssl->underlying) {
+ bufferevent_suspend_read_(bev_ssl->underlying,
+ BEV_SUSPEND_FILT_READ);
+ } else {
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+ event_del(&bev->ev_read);
+ }
+}
+
+static void
+stop_writing(struct bufferevent_openssl *bev_ssl)
+{
+ if (bev_ssl->read_blocked_on_write)
+ return;
+ if (bev_ssl->underlying) {
+ ;
+ } else {
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+ event_del(&bev->ev_write);
+ }
+}
+
+static int
+set_rbow(struct bufferevent_openssl *bev_ssl)
+{
+ if (!bev_ssl->underlying)
+ stop_reading(bev_ssl);
+ bev_ssl->read_blocked_on_write = 1;
+ return start_writing(bev_ssl);
+}
+
+static int
+set_wbor(struct bufferevent_openssl *bev_ssl)
+{
+ if (!bev_ssl->underlying)
+ stop_writing(bev_ssl);
+ bev_ssl->write_blocked_on_read = 1;
+ return start_reading(bev_ssl);
+}
+
+static int
+clear_rbow(struct bufferevent_openssl *bev_ssl)
+{
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+ int r = 0;
+ bev_ssl->read_blocked_on_write = 0;
+ if (!(bev->enabled & EV_WRITE))
+ stop_writing(bev_ssl);
+ if (bev->enabled & EV_READ)
+ r = start_reading(bev_ssl);
+ return r;
+}
+
+
+static int
+clear_wbor(struct bufferevent_openssl *bev_ssl)
+{
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+ int r = 0;
+ bev_ssl->write_blocked_on_read = 0;
+ if (!(bev->enabled & EV_READ))
+ stop_reading(bev_ssl);
+ if (bev->enabled & EV_WRITE)
+ r = start_writing(bev_ssl);
+ return r;
+}
+
+static void
+conn_closed(struct bufferevent_openssl *bev_ssl, int when, int errcode, int ret)
+{
+ int event = BEV_EVENT_ERROR;
+ int dirty_shutdown = 0;
+ unsigned long err;
+
+ switch (errcode) {
+ case SSL_ERROR_ZERO_RETURN:
+ /* Possibly a clean shutdown. */
+ if (SSL_get_shutdown(bev_ssl->ssl) & SSL_RECEIVED_SHUTDOWN)
+ event = BEV_EVENT_EOF;
+ else
+ dirty_shutdown = 1;
+ break;
+ case SSL_ERROR_SYSCALL:
+ /* IO error; possibly a dirty shutdown. */
+ if ((ret == 0 || ret == -1) && ERR_peek_error() == 0)
+ dirty_shutdown = 1;
+ break;
+ case SSL_ERROR_SSL:
+ /* Protocol error. */
+ break;
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ /* XXXX handle this. */
+ break;
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_CONNECT:
+ case SSL_ERROR_WANT_ACCEPT:
+ default:
+ /* should be impossible; treat as normal error. */
+ event_warnx("BUG: Unexpected OpenSSL error code %d", errcode);
+ break;
+ }
+
+ while ((err = ERR_get_error())) {
+ put_error(bev_ssl, err);
+ }
+
+ if (dirty_shutdown && bev_ssl->allow_dirty_shutdown)
+ event = BEV_EVENT_EOF;
+
+ stop_reading(bev_ssl);
+ stop_writing(bev_ssl);
+
+ /* when is BEV_EVENT_{READING|WRITING} */
+ event = when | event;
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev, event, 0);
+}
+
+static void
+init_bio_counts(struct bufferevent_openssl *bev_ssl)
+{
+ BIO *rbio, *wbio;
+
+ wbio = SSL_get_wbio(bev_ssl->ssl);
+ bev_ssl->counts.n_written = wbio ? BIO_number_written(wbio) : 0;
+ rbio = SSL_get_rbio(bev_ssl->ssl);
+ bev_ssl->counts.n_read = rbio ? BIO_number_read(rbio) : 0;
+}
+
+static inline void
+decrement_buckets(struct bufferevent_openssl *bev_ssl)
+{
+ unsigned long num_w = BIO_number_written(SSL_get_wbio(bev_ssl->ssl));
+ unsigned long num_r = BIO_number_read(SSL_get_rbio(bev_ssl->ssl));
+ /* These next two subtractions can wrap around. That's okay. */
+ unsigned long w = num_w - bev_ssl->counts.n_written;
+ unsigned long r = num_r - bev_ssl->counts.n_read;
+ if (w)
+ bufferevent_decrement_write_buckets_(&bev_ssl->bev, w);
+ if (r)
+ bufferevent_decrement_read_buckets_(&bev_ssl->bev, r);
+ bev_ssl->counts.n_written = num_w;
+ bev_ssl->counts.n_read = num_r;
+}
+
+#define OP_MADE_PROGRESS 1
+#define OP_BLOCKED 2
+#define OP_ERR 4
+
+/* Return a bitmask of OP_MADE_PROGRESS (if we read anything); OP_BLOCKED (if
+ we're now blocked); and OP_ERR (if an error occurred). */
+static int
+do_read(struct bufferevent_openssl *bev_ssl, int n_to_read) {
+ /* Requires lock */
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+ struct evbuffer *input = bev->input;
+ int r, n, i, n_used = 0, atmost;
+ struct evbuffer_iovec space[2];
+ int result = 0;
+
+ if (bev_ssl->bev.read_suspended)
+ return 0;
+
+ atmost = bufferevent_get_read_max_(&bev_ssl->bev);
+ if (n_to_read > atmost)
+ n_to_read = atmost;
+
+ n = evbuffer_reserve_space(input, n_to_read, space, 2);
+ if (n < 0)
+ return OP_ERR;
+
+ for (i=0; i<n; ++i) {
+ if (bev_ssl->bev.read_suspended)
+ break;
+ ERR_clear_error();
+ r = SSL_read(bev_ssl->ssl, space[i].iov_base, space[i].iov_len);
+ if (r>0) {
+ result |= OP_MADE_PROGRESS;
+ if (bev_ssl->read_blocked_on_write)
+ if (clear_rbow(bev_ssl) < 0)
+ return OP_ERR | result;
+ ++n_used;
+ space[i].iov_len = r;
+ decrement_buckets(bev_ssl);
+ } else {
+ int err = SSL_get_error(bev_ssl->ssl, r);
+ print_err(err);
+ switch (err) {
+ case SSL_ERROR_WANT_READ:
+ /* Can't read until underlying has more data. */
+ if (bev_ssl->read_blocked_on_write)
+ if (clear_rbow(bev_ssl) < 0)
+ return OP_ERR | result;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ /* This read operation requires a write, and the
+ * underlying is full */
+ if (!bev_ssl->read_blocked_on_write)
+ if (set_rbow(bev_ssl) < 0)
+ return OP_ERR | result;
+ break;
+ default:
+ conn_closed(bev_ssl, BEV_EVENT_READING, err, r);
+ break;
+ }
+ result |= OP_BLOCKED;
+ break; /* out of the loop */
+ }
+ }
+
+ if (n_used) {
+ evbuffer_commit_space(input, space, n_used);
+ if (bev_ssl->underlying)
+ BEV_RESET_GENERIC_READ_TIMEOUT(bev);
+ }
+
+ return result;
+}
+
+/* Return a bitmask of OP_MADE_PROGRESS (if we wrote anything); OP_BLOCKED (if
+ we're now blocked); and OP_ERR (if an error occurred). */
+static int
+do_write(struct bufferevent_openssl *bev_ssl, int atmost)
+{
+ int i, r, n, n_written = 0;
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+ struct evbuffer *output = bev->output;
+ struct evbuffer_iovec space[8];
+ int result = 0;
+
+ if (bev_ssl->last_write > 0)
+ atmost = bev_ssl->last_write;
+ else
+ atmost = bufferevent_get_write_max_(&bev_ssl->bev);
+
+ n = evbuffer_peek(output, atmost, NULL, space, 8);
+ if (n < 0)
+ return OP_ERR | result;
+
+ if (n > 8)
+ n = 8;
+ for (i=0; i < n; ++i) {
+ if (bev_ssl->bev.write_suspended)
+ break;
+
+ /* SSL_write will (reasonably) return 0 if we tell it to
+ send 0 data. Skip this case so we don't interpret the
+ result as an error */
+ if (space[i].iov_len == 0)
+ continue;
+
+ ERR_clear_error();
+ r = SSL_write(bev_ssl->ssl, space[i].iov_base,
+ space[i].iov_len);
+ if (r > 0) {
+ result |= OP_MADE_PROGRESS;
+ if (bev_ssl->write_blocked_on_read)
+ if (clear_wbor(bev_ssl) < 0)
+ return OP_ERR | result;
+ n_written += r;
+ bev_ssl->last_write = -1;
+ decrement_buckets(bev_ssl);
+ } else {
+ int err = SSL_get_error(bev_ssl->ssl, r);
+ print_err(err);
+ switch (err) {
+ case SSL_ERROR_WANT_WRITE:
+ /* Can't read until underlying has more data. */
+ if (bev_ssl->write_blocked_on_read)
+ if (clear_wbor(bev_ssl) < 0)
+ return OP_ERR | result;
+ bev_ssl->last_write = space[i].iov_len;
+ break;
+ case SSL_ERROR_WANT_READ:
+ /* This read operation requires a write, and the
+ * underlying is full */
+ if (!bev_ssl->write_blocked_on_read)
+ if (set_wbor(bev_ssl) < 0)
+ return OP_ERR | result;
+ bev_ssl->last_write = space[i].iov_len;
+ break;
+ default:
+ conn_closed(bev_ssl, BEV_EVENT_WRITING, err, r);
+ bev_ssl->last_write = -1;
+ break;
+ }
+ result |= OP_BLOCKED;
+ break;
+ }
+ }
+ if (n_written) {
+ evbuffer_drain(output, n_written);
+ if (bev_ssl->underlying)
+ BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
+
+ bufferevent_trigger_nolock_(bev, EV_WRITE, 0);
+ }
+ return result;
+}
+
+#define WRITE_FRAME 15000
+
+#define READ_DEFAULT 4096
+
+/* Try to figure out how many bytes to read; return 0 if we shouldn't be
+ * reading. */
+static int
+bytes_to_read(struct bufferevent_openssl *bev)
+{
+ struct evbuffer *input = bev->bev.bev.input;
+ struct event_watermark *wm = &bev->bev.bev.wm_read;
+ int result = READ_DEFAULT;
+ ev_ssize_t limit;
+ /* XXX 99% of this is generic code that nearly all bufferevents will
+ * want. */
+
+ if (bev->write_blocked_on_read) {
+ return 0;
+ }
+
+ if (! (bev->bev.bev.enabled & EV_READ)) {
+ return 0;
+ }
+
+ if (bev->bev.read_suspended) {
+ return 0;
+ }
+
+ if (wm->high) {
+ if (evbuffer_get_length(input) >= wm->high) {
+ return 0;
+ }
+
+ result = wm->high - evbuffer_get_length(input);
+ } else {
+ result = READ_DEFAULT;
+ }
+
+ /* Respect the rate limit */
+ limit = bufferevent_get_read_max_(&bev->bev);
+ if (result > limit) {
+ result = limit;
+ }
+
+ return result;
+}
+
+
+/* Things look readable. If write is blocked on read, write till it isn't.
+ * Read from the underlying buffer until we block or we hit our high-water
+ * mark.
+ */
+static void
+consider_reading(struct bufferevent_openssl *bev_ssl)
+{
+ int r;
+ int n_to_read;
+ int all_result_flags = 0;
+
+ while (bev_ssl->write_blocked_on_read) {
+ r = do_write(bev_ssl, WRITE_FRAME);
+ if (r & (OP_BLOCKED|OP_ERR))
+ break;
+ }
+ if (bev_ssl->write_blocked_on_read)
+ return;
+
+ n_to_read = bytes_to_read(bev_ssl);
+
+ while (n_to_read) {
+ r = do_read(bev_ssl, n_to_read);
+ all_result_flags |= r;
+
+ if (r & (OP_BLOCKED|OP_ERR))
+ break;
+
+ if (bev_ssl->bev.read_suspended)
+ break;
+
+ /* Read all pending data. This won't hit the network
+ * again, and will (most importantly) put us in a state
+ * where we don't need to read anything else until the
+ * socket is readable again. It'll potentially make us
+ * overrun our read high-watermark (somewhat
+ * regrettable). The damage to the rate-limit has
+ * already been done, since OpenSSL went and read a
+ * whole SSL record anyway. */
+ n_to_read = SSL_pending(bev_ssl->ssl);
+
+ /* XXX This if statement is actually a bad bug, added to avoid
+ * XXX a worse bug.
+ *
+ * The bad bug: It can potentially cause resource unfairness
+ * by reading too much data from the underlying bufferevent;
+ * it can potentially cause read looping if the underlying
+ * bufferevent is a bufferevent_pair and deferred callbacks
+ * aren't used.
+ *
+ * The worse bug: If we didn't do this, then we would
+ * potentially not read any more from bev_ssl->underlying
+ * until more data arrived there, which could lead to us
+ * waiting forever.
+ */
+ if (!n_to_read && bev_ssl->underlying)
+ n_to_read = bytes_to_read(bev_ssl);
+ }
+
+ if (all_result_flags & OP_MADE_PROGRESS) {
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+
+ bufferevent_trigger_nolock_(bev, EV_READ, 0);
+ }
+
+ if (!bev_ssl->underlying) {
+ /* Should be redundant, but let's avoid busy-looping */
+ if (bev_ssl->bev.read_suspended ||
+ !(bev_ssl->bev.bev.enabled & EV_READ)) {
+ event_del(&bev_ssl->bev.bev.ev_read);
+ }
+ }
+}
+
+static void
+consider_writing(struct bufferevent_openssl *bev_ssl)
+{
+ int r;
+ struct evbuffer *output = bev_ssl->bev.bev.output;
+ struct evbuffer *target = NULL;
+ struct event_watermark *wm = NULL;
+
+ while (bev_ssl->read_blocked_on_write) {
+ r = do_read(bev_ssl, 1024); /* XXXX 1024 is a hack */
+ if (r & OP_MADE_PROGRESS) {
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+
+ bufferevent_trigger_nolock_(bev, EV_READ, 0);
+ }
+ if (r & (OP_ERR|OP_BLOCKED))
+ break;
+ }
+ if (bev_ssl->read_blocked_on_write)
+ return;
+ if (bev_ssl->underlying) {
+ target = bev_ssl->underlying->output;
+ wm = &bev_ssl->underlying->wm_write;
+ }
+ while ((bev_ssl->bev.bev.enabled & EV_WRITE) &&
+ (! bev_ssl->bev.write_suspended) &&
+ evbuffer_get_length(output) &&
+ (!target || (! wm->high || evbuffer_get_length(target) < wm->high))) {
+ int n_to_write;
+ if (wm && wm->high)
+ n_to_write = wm->high - evbuffer_get_length(target);
+ else
+ n_to_write = WRITE_FRAME;
+ r = do_write(bev_ssl, n_to_write);
+ if (r & (OP_BLOCKED|OP_ERR))
+ break;
+ }
+
+ if (!bev_ssl->underlying) {
+ if (evbuffer_get_length(output) == 0) {
+ event_del(&bev_ssl->bev.bev.ev_write);
+ } else if (bev_ssl->bev.write_suspended ||
+ !(bev_ssl->bev.bev.enabled & EV_WRITE)) {
+ /* Should be redundant, but let's avoid busy-looping */
+ event_del(&bev_ssl->bev.bev.ev_write);
+ }
+ }
+}
+
+static void
+be_openssl_readcb(struct bufferevent *bev_base, void *ctx)
+{
+ struct bufferevent_openssl *bev_ssl = ctx;
+ consider_reading(bev_ssl);
+}
+
+static void
+be_openssl_writecb(struct bufferevent *bev_base, void *ctx)
+{
+ struct bufferevent_openssl *bev_ssl = ctx;
+ consider_writing(bev_ssl);
+}
+
+static void
+be_openssl_eventcb(struct bufferevent *bev_base, short what, void *ctx)
+{
+ struct bufferevent_openssl *bev_ssl = ctx;
+ int event = 0;
+
+ if (what & BEV_EVENT_EOF) {
+ if (bev_ssl->allow_dirty_shutdown)
+ event = BEV_EVENT_EOF;
+ else
+ event = BEV_EVENT_ERROR;
+ } else if (what & BEV_EVENT_TIMEOUT) {
+ /* We sure didn't set this. Propagate it to the user. */
+ event = what;
+ } else if (what & BEV_EVENT_ERROR) {
+ /* An error occurred on the connection. Propagate it to the user. */
+ event = what;
+ } else if (what & BEV_EVENT_CONNECTED) {
+ /* Ignore it. We're saying SSL_connect() already, which will
+ eat it. */
+ }
+ if (event)
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev, event, 0);
+}
+
+static void
+be_openssl_readeventcb(evutil_socket_t fd, short what, void *ptr)
+{
+ struct bufferevent_openssl *bev_ssl = ptr;
+ bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
+ if (what == EV_TIMEOUT) {
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev,
+ BEV_EVENT_TIMEOUT|BEV_EVENT_READING, 0);
+ } else {
+ consider_reading(bev_ssl);
+ }
+ bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
+}
+
+static void
+be_openssl_writeeventcb(evutil_socket_t fd, short what, void *ptr)
+{
+ struct bufferevent_openssl *bev_ssl = ptr;
+ bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
+ if (what == EV_TIMEOUT) {
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev,
+ BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING, 0);
+ } else {
+ consider_writing(bev_ssl);
+ }
+ bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
+}
+
+static int
+be_openssl_auto_fd(struct bufferevent_openssl *bev_ssl, int fd)
+{
+ if (!bev_ssl->underlying) {
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+ if (event_initialized(&bev->ev_read) && fd < 0) {
+ fd = event_get_fd(&bev->ev_read);
+ }
+ }
+ return fd;
+}
+
+static int
+set_open_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
+{
+ if (bev_ssl->underlying) {
+ bufferevent_setcb(bev_ssl->underlying,
+ be_openssl_readcb, be_openssl_writecb, be_openssl_eventcb,
+ bev_ssl);
+ return 0;
+ } else {
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+ int rpending=0, wpending=0, r1=0, r2=0;
+
+ if (event_initialized(&bev->ev_read)) {
+ rpending = event_pending(&bev->ev_read, EV_READ, NULL);
+ wpending = event_pending(&bev->ev_write, EV_WRITE, NULL);
+
+ event_del(&bev->ev_read);
+ event_del(&bev->ev_write);
+ }
+
+ event_assign(&bev->ev_read, bev->ev_base, fd,
+ EV_READ|EV_PERSIST|EV_FINALIZE,
+ be_openssl_readeventcb, bev_ssl);
+ event_assign(&bev->ev_write, bev->ev_base, fd,
+ EV_WRITE|EV_PERSIST|EV_FINALIZE,
+ be_openssl_writeeventcb, bev_ssl);
+
+ if (rpending)
+ r1 = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
+ if (wpending)
+ r2 = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
+
+ return (r1<0 || r2<0) ? -1 : 0;
+ }
+}
+
+static int
+do_handshake(struct bufferevent_openssl *bev_ssl)
+{
+ int r;
+
+ switch (bev_ssl->state) {
+ default:
+ case BUFFEREVENT_SSL_OPEN:
+ EVUTIL_ASSERT(0);
+ return -1;
+ case BUFFEREVENT_SSL_CONNECTING:
+ case BUFFEREVENT_SSL_ACCEPTING:
+ ERR_clear_error();
+ r = SSL_do_handshake(bev_ssl->ssl);
+ break;
+ }
+ decrement_buckets(bev_ssl);
+
+ if (r==1) {
+ int fd = event_get_fd(&bev_ssl->bev.bev.ev_read);
+ /* We're done! */
+ bev_ssl->state = BUFFEREVENT_SSL_OPEN;
+ set_open_callbacks(bev_ssl, fd); /* XXXX handle failure */
+ /* Call do_read and do_write as needed */
+ bufferevent_enable(&bev_ssl->bev.bev, bev_ssl->bev.bev.enabled);
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev,
+ BEV_EVENT_CONNECTED, 0);
+ return 1;
+ } else {
+ int err = SSL_get_error(bev_ssl->ssl, r);
+ print_err(err);
+ switch (err) {
+ case SSL_ERROR_WANT_WRITE:
+ if (!bev_ssl->underlying) {
+ stop_reading(bev_ssl);
+ return start_writing(bev_ssl);
+ }
+ return 0;
+ case SSL_ERROR_WANT_READ:
+ if (!bev_ssl->underlying) {
+ stop_writing(bev_ssl);
+ return start_reading(bev_ssl);
+ }
+ return 0;
+ default:
+ conn_closed(bev_ssl, BEV_EVENT_READING, err, r);
+ return -1;
+ }
+ }
+}
+
+static void
+be_openssl_handshakecb(struct bufferevent *bev_base, void *ctx)
+{
+ struct bufferevent_openssl *bev_ssl = ctx;
+ do_handshake(bev_ssl);/* XXX handle failure */
+}
+
+static void
+be_openssl_handshakeeventcb(evutil_socket_t fd, short what, void *ptr)
+{
+ struct bufferevent_openssl *bev_ssl = ptr;
+
+ bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
+ if (what & EV_TIMEOUT) {
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev, BEV_EVENT_TIMEOUT, 0);
+ } else
+ do_handshake(bev_ssl);/* XXX handle failure */
+ bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
+}
+
+static int
+set_handshake_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
+{
+ if (bev_ssl->underlying) {
+ bufferevent_setcb(bev_ssl->underlying,
+ be_openssl_handshakecb, be_openssl_handshakecb,
+ be_openssl_eventcb,
+ bev_ssl);
+ return do_handshake(bev_ssl);
+ } else {
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+
+ if (event_initialized(&bev->ev_read)) {
+ event_del(&bev->ev_read);
+ event_del(&bev->ev_write);
+ }
+
+ event_assign(&bev->ev_read, bev->ev_base, fd,
+ EV_READ|EV_PERSIST|EV_FINALIZE,
+ be_openssl_handshakeeventcb, bev_ssl);
+ event_assign(&bev->ev_write, bev->ev_base, fd,
+ EV_WRITE|EV_PERSIST|EV_FINALIZE,
+ be_openssl_handshakeeventcb, bev_ssl);
+ if (fd >= 0)
+ bufferevent_enable(bev, bev->enabled);
+ return 0;
+ }
+}
+
+int
+bufferevent_ssl_renegotiate(struct bufferevent *bev)
+{
+ struct bufferevent_openssl *bev_ssl = upcast(bev);
+ if (!bev_ssl)
+ return -1;
+ if (SSL_renegotiate(bev_ssl->ssl) < 0)
+ return -1;
+ bev_ssl->state = BUFFEREVENT_SSL_CONNECTING;
+ if (set_handshake_callbacks(bev_ssl, be_openssl_auto_fd(bev_ssl, -1)) < 0)
+ return -1;
+ if (!bev_ssl->underlying)
+ return do_handshake(bev_ssl);
+ return 0;
+}
+
+static void
+be_openssl_outbuf_cb(struct evbuffer *buf,
+ const struct evbuffer_cb_info *cbinfo, void *arg)
+{
+ struct bufferevent_openssl *bev_ssl = arg;
+ int r = 0;
+ /* XXX need to hold a reference here. */
+
+ if (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN &&
+ cbinfo->orig_size == 0) {
+ r = bufferevent_add_event_(&bev_ssl->bev.bev.ev_write,
+ &bev_ssl->bev.bev.timeout_write);
+ }
+ /* XXX Handle r < 0 */
+ (void)r;
+}
+
+
+static int
+be_openssl_enable(struct bufferevent *bev, short events)
+{
+ struct bufferevent_openssl *bev_ssl = upcast(bev);
+ int r1 = 0, r2 = 0;
+
+ if (events & EV_READ)
+ r1 = start_reading(bev_ssl);
+ if (events & EV_WRITE)
+ r2 = start_writing(bev_ssl);
+
+ if (bev_ssl->underlying) {
+ if (events & EV_READ)
+ BEV_RESET_GENERIC_READ_TIMEOUT(bev);
+ if (events & EV_WRITE)
+ BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
+
+ if (events & EV_READ)
+ consider_reading(bev_ssl);
+ if (events & EV_WRITE)
+ consider_writing(bev_ssl);
+ }
+ return (r1 < 0 || r2 < 0) ? -1 : 0;
+}
+
+static int
+be_openssl_disable(struct bufferevent *bev, short events)
+{
+ struct bufferevent_openssl *bev_ssl = upcast(bev);
+
+ if (events & EV_READ)
+ stop_reading(bev_ssl);
+ if (events & EV_WRITE)
+ stop_writing(bev_ssl);
+
+ if (bev_ssl->underlying) {
+ if (events & EV_READ)
+ BEV_DEL_GENERIC_READ_TIMEOUT(bev);
+ if (events & EV_WRITE)
+ BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
+ }
+ return 0;
+}
+
+static void
+be_openssl_unlink(struct bufferevent *bev)
+{
+ struct bufferevent_openssl *bev_ssl = upcast(bev);
+
+ if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
+ if (bev_ssl->underlying) {
+ if (BEV_UPCAST(bev_ssl->underlying)->refcnt < 2) {
+ event_warnx("BEV_OPT_CLOSE_ON_FREE set on an "
+ "bufferevent with too few references");
+ } else {
+ bufferevent_free(bev_ssl->underlying);
+ /* We still have a reference to it, via our
+ * BIO. So we don't drop this. */
+ // bev_ssl->underlying = NULL;
+ }
+ }
+ } else {
+ if (bev_ssl->underlying) {
+ if (bev_ssl->underlying->errorcb == be_openssl_eventcb)
+ bufferevent_setcb(bev_ssl->underlying,
+ NULL,NULL,NULL,NULL);
+ bufferevent_unsuspend_read_(bev_ssl->underlying,
+ BEV_SUSPEND_FILT_READ);
+ }
+ }
+}
+
+static void
+be_openssl_destruct(struct bufferevent *bev)
+{
+ struct bufferevent_openssl *bev_ssl = upcast(bev);
+
+ if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
+ if (! bev_ssl->underlying) {
+ evutil_socket_t fd = -1;
+ BIO *bio = SSL_get_wbio(bev_ssl->ssl);
+ if (bio)
+ fd = BIO_get_fd(bio, NULL);
+ if (fd >= 0)
+ evutil_closesocket(fd);
+ }
+ SSL_free(bev_ssl->ssl);
+ }
+}
+
+static int
+be_openssl_adj_timeouts(struct bufferevent *bev)
+{
+ struct bufferevent_openssl *bev_ssl = upcast(bev);
+
+ if (bev_ssl->underlying) {
+ return bufferevent_generic_adj_timeouts_(bev);
+ } else {
+ return bufferevent_generic_adj_existing_timeouts_(bev);
+ }
+}
+
+static int
+be_openssl_flush(struct bufferevent *bufev,
+ short iotype, enum bufferevent_flush_mode mode)
+{
+ /* XXXX Implement this. */
+ return 0;
+}
+
+static int
+be_openssl_set_fd(struct bufferevent_openssl *bev_ssl,
+ enum bufferevent_ssl_state state, int fd)
+{
+ bev_ssl->state = state;
+
+ switch (state) {
+ case BUFFEREVENT_SSL_ACCEPTING:
+ SSL_set_accept_state(bev_ssl->ssl);
+ if (set_handshake_callbacks(bev_ssl, fd) < 0)
+ return -1;
+ break;
+ case BUFFEREVENT_SSL_CONNECTING:
+ SSL_set_connect_state(bev_ssl->ssl);
+ if (set_handshake_callbacks(bev_ssl, fd) < 0)
+ return -1;
+ break;
+ case BUFFEREVENT_SSL_OPEN:
+ if (set_open_callbacks(bev_ssl, fd) < 0)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+be_openssl_ctrl(struct bufferevent *bev,
+ enum bufferevent_ctrl_op op, union bufferevent_ctrl_data *data)
+{
+ struct bufferevent_openssl *bev_ssl = upcast(bev);
+ switch (op) {
+ case BEV_CTRL_SET_FD:
+ if (bev_ssl->underlying)
+ return -1;
+ {
+ BIO *bio;
+ bio = BIO_new_socket(data->fd, 0);
+ SSL_set_bio(bev_ssl->ssl, bio, bio);
+ }
+
+ return be_openssl_set_fd(bev_ssl, bev_ssl->old_state, data->fd);
+ case BEV_CTRL_GET_FD:
+ data->fd = event_get_fd(&bev->ev_read);
+ return 0;
+ case BEV_CTRL_GET_UNDERLYING:
+ data->ptr = bev_ssl->underlying;
+ return 0;
+ case BEV_CTRL_CANCEL_ALL:
+ default:
+ return -1;
+ }
+}
+
+SSL *
+bufferevent_openssl_get_ssl(struct bufferevent *bufev)
+{
+ struct bufferevent_openssl *bev_ssl = upcast(bufev);
+ if (!bev_ssl)
+ return NULL;
+ return bev_ssl->ssl;
+}
+
+static struct bufferevent *
+bufferevent_openssl_new_impl(struct event_base *base,
+ struct bufferevent *underlying,
+ evutil_socket_t fd,
+ SSL *ssl,
+ enum bufferevent_ssl_state state,
+ int options)
+{
+ struct bufferevent_openssl *bev_ssl = NULL;
+ struct bufferevent_private *bev_p = NULL;
+ int tmp_options = options & ~BEV_OPT_THREADSAFE;
+
+ if (underlying != NULL && fd >= 0)
+ return NULL; /* Only one can be set. */
+
+ if (!(bev_ssl = mm_calloc(1, sizeof(struct bufferevent_openssl))))
+ goto err;
+
+ bev_p = &bev_ssl->bev;
+
+ if (bufferevent_init_common_(bev_p, base,
+ &bufferevent_ops_openssl, tmp_options) < 0)
+ goto err;
+
+ /* Don't explode if we decide to realloc a chunk we're writing from in
+ * the output buffer. */
+ SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+ bev_ssl->underlying = underlying;
+ bev_ssl->ssl = ssl;
+
+ bev_ssl->outbuf_cb = evbuffer_add_cb(bev_p->bev.output,
+ be_openssl_outbuf_cb, bev_ssl);
+
+ if (options & BEV_OPT_THREADSAFE)
+ bufferevent_enable_locking_(&bev_ssl->bev.bev, NULL);
+
+ if (underlying) {
+ bufferevent_init_generic_timeout_cbs_(&bev_ssl->bev.bev);
+ bufferevent_incref_(underlying);
+ }
+
+ bev_ssl->old_state = state;
+ bev_ssl->last_write = -1;
+
+ init_bio_counts(bev_ssl);
+
+ fd = be_openssl_auto_fd(bev_ssl, fd);
+ if (be_openssl_set_fd(bev_ssl, state, fd))
+ goto err;
+
+ if (underlying) {
+ bufferevent_setwatermark(underlying, EV_READ, 0, 0);
+ bufferevent_enable(underlying, EV_READ|EV_WRITE);
+ if (state == BUFFEREVENT_SSL_OPEN)
+ bufferevent_suspend_read_(underlying,
+ BEV_SUSPEND_FILT_READ);
+ }
+
+ return &bev_ssl->bev.bev;
+err:
+ if (bev_ssl)
+ bufferevent_free(&bev_ssl->bev.bev);
+ return NULL;
+}
+
+struct bufferevent *
+bufferevent_openssl_filter_new(struct event_base *base,
+ struct bufferevent *underlying,
+ SSL *ssl,
+ enum bufferevent_ssl_state state,
+ int options)
+{
+ /* We don't tell the BIO to close the bufferevent; we do it ourselves
+ * on be_openssl_destruct */
+ int close_flag = 0; /* options & BEV_OPT_CLOSE_ON_FREE; */
+ BIO *bio;
+ if (!underlying)
+ return NULL;
+ if (!(bio = BIO_new_bufferevent(underlying, close_flag)))
+ return NULL;
+
+ SSL_set_bio(ssl, bio, bio);
+
+ return bufferevent_openssl_new_impl(
+ base, underlying, -1, ssl, state, options);
+}
+
+struct bufferevent *
+bufferevent_openssl_socket_new(struct event_base *base,
+ evutil_socket_t fd,
+ SSL *ssl,
+ enum bufferevent_ssl_state state,
+ int options)
+{
+ /* Does the SSL already have an fd? */
+ BIO *bio = SSL_get_wbio(ssl);
+ long have_fd = -1;
+
+ if (bio)
+ have_fd = BIO_get_fd(bio, NULL);
+
+ if (have_fd >= 0) {
+ /* The SSL is already configured with an fd. */
+ if (fd < 0) {
+ /* We should learn the fd from the SSL. */
+ fd = (evutil_socket_t) have_fd;
+ } else if (have_fd == (long)fd) {
+ /* We already know the fd from the SSL; do nothing */
+ } else {
+ /* We specified an fd different from that of the SSL.
+ This is probably an error on our part. Fail. */
+ return NULL;
+ }
+ (void) BIO_set_close(bio, 0);
+ } else {
+ /* The SSL isn't configured with a BIO with an fd. */
+ if (fd >= 0) {
+ /* ... and we have an fd we want to use. */
+ bio = BIO_new_socket(fd, 0);
+ SSL_set_bio(ssl, bio, bio);
+ } else {
+ /* Leave the fd unset. */
+ }
+ }
+
+ return bufferevent_openssl_new_impl(
+ base, NULL, fd, ssl, state, options);
+}
+
+int
+bufferevent_openssl_get_allow_dirty_shutdown(struct bufferevent *bev)
+{
+ int allow_dirty_shutdown = -1;
+ struct bufferevent_openssl *bev_ssl;
+ BEV_LOCK(bev);
+ bev_ssl = upcast(bev);
+ if (bev_ssl)
+ allow_dirty_shutdown = bev_ssl->allow_dirty_shutdown;
+ BEV_UNLOCK(bev);
+ return allow_dirty_shutdown;
+}
+
+void
+bufferevent_openssl_set_allow_dirty_shutdown(struct bufferevent *bev,
+ int allow_dirty_shutdown)
+{
+ struct bufferevent_openssl *bev_ssl;
+ BEV_LOCK(bev);
+ bev_ssl = upcast(bev);
+ if (bev_ssl)
+ bev_ssl->allow_dirty_shutdown = !!allow_dirty_shutdown;
+ BEV_UNLOCK(bev);
+}
+
+unsigned long
+bufferevent_get_openssl_error(struct bufferevent *bev)
+{
+ unsigned long err = 0;
+ struct bufferevent_openssl *bev_ssl;
+ BEV_LOCK(bev);
+ bev_ssl = upcast(bev);
+ if (bev_ssl && bev_ssl->n_errors) {
+ err = bev_ssl->errors[--bev_ssl->n_errors];
+ }
+ BEV_UNLOCK(bev);
+ return err;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_pair.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_pair.c
new file mode 100644
index 000000000..1e93f5729
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_pair.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+#include "event2/util.h"
+#include "event2/buffer.h"
+#include "event2/bufferevent.h"
+#include "event2/bufferevent_struct.h"
+#include "event2/event.h"
+#include "defer-internal.h"
+#include "bufferevent-internal.h"
+#include "mm-internal.h"
+#include "util-internal.h"
+
+struct bufferevent_pair {
+ struct bufferevent_private bev;
+ struct bufferevent_pair *partner;
+ /* For ->destruct() lock checking */
+ struct bufferevent_pair *unlinked_partner;
+};
+
+
+/* Given a bufferevent that's really a bev part of a bufferevent_pair,
+ * return that bufferevent_filtered. Returns NULL otherwise.*/
+static inline struct bufferevent_pair *
+upcast(struct bufferevent *bev)
+{
+ struct bufferevent_pair *bev_p;
+ if (bev->be_ops != &bufferevent_ops_pair)
+ return NULL;
+ bev_p = EVUTIL_UPCAST(bev, struct bufferevent_pair, bev.bev);
+ EVUTIL_ASSERT(bev_p->bev.bev.be_ops == &bufferevent_ops_pair);
+ return bev_p;
+}
+
+#define downcast(bev_pair) (&(bev_pair)->bev.bev)
+
+static inline void
+incref_and_lock(struct bufferevent *b)
+{
+ struct bufferevent_pair *bevp;
+ bufferevent_incref_and_lock_(b);
+ bevp = upcast(b);
+ if (bevp->partner)
+ bufferevent_incref_and_lock_(downcast(bevp->partner));
+}
+
+static inline void
+decref_and_unlock(struct bufferevent *b)
+{
+ struct bufferevent_pair *bevp = upcast(b);
+ if (bevp->partner)
+ bufferevent_decref_and_unlock_(downcast(bevp->partner));
+ bufferevent_decref_and_unlock_(b);
+}
+
+/* XXX Handle close */
+
+static void be_pair_outbuf_cb(struct evbuffer *,
+ const struct evbuffer_cb_info *, void *);
+
+static struct bufferevent_pair *
+bufferevent_pair_elt_new(struct event_base *base,
+ int options)
+{
+ struct bufferevent_pair *bufev;
+ if (! (bufev = mm_calloc(1, sizeof(struct bufferevent_pair))))
+ return NULL;
+ if (bufferevent_init_common_(&bufev->bev, base, &bufferevent_ops_pair,
+ options)) {
+ mm_free(bufev);
+ return NULL;
+ }
+ if (!evbuffer_add_cb(bufev->bev.bev.output, be_pair_outbuf_cb, bufev)) {
+ bufferevent_free(downcast(bufev));
+ return NULL;
+ }
+
+ bufferevent_init_generic_timeout_cbs_(&bufev->bev.bev);
+
+ return bufev;
+}
+
+int
+bufferevent_pair_new(struct event_base *base, int options,
+ struct bufferevent *pair[2])
+{
+ struct bufferevent_pair *bufev1 = NULL, *bufev2 = NULL;
+ int tmp_options;
+
+ options |= BEV_OPT_DEFER_CALLBACKS;
+ tmp_options = options & ~BEV_OPT_THREADSAFE;
+
+ bufev1 = bufferevent_pair_elt_new(base, options);
+ if (!bufev1)
+ return -1;
+ bufev2 = bufferevent_pair_elt_new(base, tmp_options);
+ if (!bufev2) {
+ bufferevent_free(downcast(bufev1));
+ return -1;
+ }
+
+ if (options & BEV_OPT_THREADSAFE) {
+ /*XXXX check return */
+ bufferevent_enable_locking_(downcast(bufev2), bufev1->bev.lock);
+ }
+
+ bufev1->partner = bufev2;
+ bufev2->partner = bufev1;
+
+ evbuffer_freeze(downcast(bufev1)->input, 0);
+ evbuffer_freeze(downcast(bufev1)->output, 1);
+ evbuffer_freeze(downcast(bufev2)->input, 0);
+ evbuffer_freeze(downcast(bufev2)->output, 1);
+
+ pair[0] = downcast(bufev1);
+ pair[1] = downcast(bufev2);
+
+ return 0;
+}
+
+static void
+be_pair_transfer(struct bufferevent *src, struct bufferevent *dst,
+ int ignore_wm)
+{
+ size_t dst_size;
+ size_t n;
+
+ evbuffer_unfreeze(src->output, 1);
+ evbuffer_unfreeze(dst->input, 0);
+
+ if (dst->wm_read.high) {
+ dst_size = evbuffer_get_length(dst->input);
+ if (dst_size < dst->wm_read.high) {
+ n = dst->wm_read.high - dst_size;
+ evbuffer_remove_buffer(src->output, dst->input, n);
+ } else {
+ if (!ignore_wm)
+ goto done;
+ n = evbuffer_get_length(src->output);
+ evbuffer_add_buffer(dst->input, src->output);
+ }
+ } else {
+ n = evbuffer_get_length(src->output);
+ evbuffer_add_buffer(dst->input, src->output);
+ }
+
+ if (n) {
+ BEV_RESET_GENERIC_READ_TIMEOUT(dst);
+
+ if (evbuffer_get_length(dst->output))
+ BEV_RESET_GENERIC_WRITE_TIMEOUT(dst);
+ else
+ BEV_DEL_GENERIC_WRITE_TIMEOUT(dst);
+ }
+
+ bufferevent_trigger_nolock_(dst, EV_READ, 0);
+ bufferevent_trigger_nolock_(src, EV_WRITE, 0);
+done:
+ evbuffer_freeze(src->output, 1);
+ evbuffer_freeze(dst->input, 0);
+}
+
+static inline int
+be_pair_wants_to_talk(struct bufferevent_pair *src,
+ struct bufferevent_pair *dst)
+{
+ return (downcast(src)->enabled & EV_WRITE) &&
+ (downcast(dst)->enabled & EV_READ) &&
+ !dst->bev.read_suspended &&
+ evbuffer_get_length(downcast(src)->output);
+}
+
+static void
+be_pair_outbuf_cb(struct evbuffer *outbuf,
+ const struct evbuffer_cb_info *info, void *arg)
+{
+ struct bufferevent_pair *bev_pair = arg;
+ struct bufferevent_pair *partner = bev_pair->partner;
+
+ incref_and_lock(downcast(bev_pair));
+
+ if (info->n_added > info->n_deleted && partner) {
+ /* We got more data. If the other side's reading, then
+ hand it over. */
+ if (be_pair_wants_to_talk(bev_pair, partner)) {
+ be_pair_transfer(downcast(bev_pair), downcast(partner), 0);
+ }
+ }
+
+ decref_and_unlock(downcast(bev_pair));
+}
+
+static int
+be_pair_enable(struct bufferevent *bufev, short events)
+{
+ struct bufferevent_pair *bev_p = upcast(bufev);
+ struct bufferevent_pair *partner = bev_p->partner;
+
+ incref_and_lock(bufev);
+
+ if (events & EV_READ) {
+ BEV_RESET_GENERIC_READ_TIMEOUT(bufev);
+ }
+ if ((events & EV_WRITE) && evbuffer_get_length(bufev->output))
+ BEV_RESET_GENERIC_WRITE_TIMEOUT(bufev);
+
+ /* We're starting to read! Does the other side have anything to write?*/
+ if ((events & EV_READ) && partner &&
+ be_pair_wants_to_talk(partner, bev_p)) {
+ be_pair_transfer(downcast(partner), bufev, 0);
+ }
+ /* We're starting to write! Does the other side want to read? */
+ if ((events & EV_WRITE) && partner &&
+ be_pair_wants_to_talk(bev_p, partner)) {
+ be_pair_transfer(bufev, downcast(partner), 0);
+ }
+ decref_and_unlock(bufev);
+ return 0;
+}
+
+static int
+be_pair_disable(struct bufferevent *bev, short events)
+{
+ if (events & EV_READ) {
+ BEV_DEL_GENERIC_READ_TIMEOUT(bev);
+ }
+ if (events & EV_WRITE) {
+ BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
+ }
+ return 0;
+}
+
+static void
+be_pair_unlink(struct bufferevent *bev)
+{
+ struct bufferevent_pair *bev_p = upcast(bev);
+
+ if (bev_p->partner) {
+ bev_p->unlinked_partner = bev_p->partner;
+ bev_p->partner->partner = NULL;
+ bev_p->partner = NULL;
+ }
+}
+
+/* Free *shared* lock in the latest be (since we share it between two of them). */
+static void
+be_pair_destruct(struct bufferevent *bev)
+{
+ struct bufferevent_pair *bev_p = upcast(bev);
+
+ /* Transfer ownership of the lock into partner, otherwise we will use
+ * already free'd lock during freeing second bev, see next example:
+ *
+ * bev1->own_lock = 1
+ * bev2->own_lock = 0
+ * bev2->lock = bev1->lock
+ *
+ * bufferevent_free(bev1) # refcnt == 0 -> unlink
+ * bufferevent_free(bev2) # refcnt == 0 -> unlink
+ *
+ * event_base_free() -> finilizers -> EVTHREAD_FREE_LOCK(bev1->lock)
+ * -> BEV_LOCK(bev2->lock) <-- already freed
+ *
+ * Where bev1 == pair[0], bev2 == pair[1].
+ */
+ if (bev_p->unlinked_partner && bev_p->bev.own_lock) {
+ bev_p->unlinked_partner->bev.own_lock = 1;
+ bev_p->bev.own_lock = 0;
+ }
+ bev_p->unlinked_partner = NULL;
+}
+
+static int
+be_pair_flush(struct bufferevent *bev, short iotype,
+ enum bufferevent_flush_mode mode)
+{
+ struct bufferevent_pair *bev_p = upcast(bev);
+ struct bufferevent *partner;
+
+ if (!bev_p->partner)
+ return -1;
+
+ if (mode == BEV_NORMAL)
+ return 0;
+
+ incref_and_lock(bev);
+
+ partner = downcast(bev_p->partner);
+
+ if ((iotype & EV_READ) != 0)
+ be_pair_transfer(partner, bev, 1);
+
+ if ((iotype & EV_WRITE) != 0)
+ be_pair_transfer(bev, partner, 1);
+
+ if (mode == BEV_FINISHED) {
+ short what = BEV_EVENT_EOF;
+ if (iotype & EV_READ)
+ what |= BEV_EVENT_WRITING;
+ if (iotype & EV_WRITE)
+ what |= BEV_EVENT_READING;
+ bufferevent_run_eventcb_(partner, what, 0);
+ }
+ decref_and_unlock(bev);
+ return 0;
+}
+
+struct bufferevent *
+bufferevent_pair_get_partner(struct bufferevent *bev)
+{
+ struct bufferevent_pair *bev_p;
+ struct bufferevent *partner = NULL;
+ bev_p = upcast(bev);
+ if (! bev_p)
+ return NULL;
+
+ incref_and_lock(bev);
+ if (bev_p->partner)
+ partner = downcast(bev_p->partner);
+ decref_and_unlock(bev);
+ return partner;
+}
+
+const struct bufferevent_ops bufferevent_ops_pair = {
+ "pair_elt",
+ evutil_offsetof(struct bufferevent_pair, bev.bev),
+ be_pair_enable,
+ be_pair_disable,
+ be_pair_unlink,
+ be_pair_destruct,
+ bufferevent_generic_adj_timeouts_,
+ be_pair_flush,
+ NULL, /* ctrl */
+};
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_ratelim.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_ratelim.c
new file mode 100644
index 000000000..bde192021
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_ratelim.c
@@ -0,0 +1,1092 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "evconfig-private.h"
+
+#include <sys/types.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/util.h"
+#include "event2/bufferevent.h"
+#include "event2/bufferevent_struct.h"
+#include "event2/buffer.h"
+
+#include "ratelim-internal.h"
+
+#include "bufferevent-internal.h"
+#include "mm-internal.h"
+#include "util-internal.h"
+#include "event-internal.h"
+
+int
+ev_token_bucket_init_(struct ev_token_bucket *bucket,
+ const struct ev_token_bucket_cfg *cfg,
+ ev_uint32_t current_tick,
+ int reinitialize)
+{
+ if (reinitialize) {
+ /* on reinitialization, we only clip downwards, since we've
+ already used who-knows-how-much bandwidth this tick. We
+ leave "last_updated" as it is; the next update will add the
+ appropriate amount of bandwidth to the bucket.
+ */
+ if (bucket->read_limit > (ev_int64_t) cfg->read_maximum)
+ bucket->read_limit = cfg->read_maximum;
+ if (bucket->write_limit > (ev_int64_t) cfg->write_maximum)
+ bucket->write_limit = cfg->write_maximum;
+ } else {
+ bucket->read_limit = cfg->read_rate;
+ bucket->write_limit = cfg->write_rate;
+ bucket->last_updated = current_tick;
+ }
+ return 0;
+}
+
+int
+ev_token_bucket_update_(struct ev_token_bucket *bucket,
+ const struct ev_token_bucket_cfg *cfg,
+ ev_uint32_t current_tick)
+{
+ /* It's okay if the tick number overflows, since we'll just
+ * wrap around when we do the unsigned substraction. */
+ unsigned n_ticks = current_tick - bucket->last_updated;
+
+ /* Make sure some ticks actually happened, and that time didn't
+ * roll back. */
+ if (n_ticks == 0 || n_ticks > INT_MAX)
+ return 0;
+
+ /* Naively, we would say
+ bucket->limit += n_ticks * cfg->rate;
+
+ if (bucket->limit > cfg->maximum)
+ bucket->limit = cfg->maximum;
+
+ But we're worried about overflow, so we do it like this:
+ */
+
+ if ((cfg->read_maximum - bucket->read_limit) / n_ticks < cfg->read_rate)
+ bucket->read_limit = cfg->read_maximum;
+ else
+ bucket->read_limit += n_ticks * cfg->read_rate;
+
+
+ if ((cfg->write_maximum - bucket->write_limit) / n_ticks < cfg->write_rate)
+ bucket->write_limit = cfg->write_maximum;
+ else
+ bucket->write_limit += n_ticks * cfg->write_rate;
+
+
+ bucket->last_updated = current_tick;
+
+ return 1;
+}
+
+static inline void
+bufferevent_update_buckets(struct bufferevent_private *bev)
+{
+ /* Must hold lock on bev. */
+ struct timeval now;
+ unsigned tick;
+ event_base_gettimeofday_cached(bev->bev.ev_base, &now);
+ tick = ev_token_bucket_get_tick_(&now, bev->rate_limiting->cfg);
+ if (tick != bev->rate_limiting->limit.last_updated)
+ ev_token_bucket_update_(&bev->rate_limiting->limit,
+ bev->rate_limiting->cfg, tick);
+}
+
+ev_uint32_t
+ev_token_bucket_get_tick_(const struct timeval *tv,
+ const struct ev_token_bucket_cfg *cfg)
+{
+ /* This computation uses two multiplies and a divide. We could do
+ * fewer if we knew that the tick length was an integer number of
+ * seconds, or if we knew it divided evenly into a second. We should
+ * investigate that more.
+ */
+
+ /* We cast to an ev_uint64_t first, since we don't want to overflow
+ * before we do the final divide. */
+ ev_uint64_t msec = (ev_uint64_t)tv->tv_sec * 1000 + tv->tv_usec / 1000;
+ return (unsigned)(msec / cfg->msec_per_tick);
+}
+
+struct ev_token_bucket_cfg *
+ev_token_bucket_cfg_new(size_t read_rate, size_t read_burst,
+ size_t write_rate, size_t write_burst,
+ const struct timeval *tick_len)
+{
+ struct ev_token_bucket_cfg *r;
+ struct timeval g;
+ if (! tick_len) {
+ g.tv_sec = 1;
+ g.tv_usec = 0;
+ tick_len = &g;
+ }
+ if (read_rate > read_burst || write_rate > write_burst ||
+ read_rate < 1 || write_rate < 1)
+ return NULL;
+ if (read_rate > EV_RATE_LIMIT_MAX ||
+ write_rate > EV_RATE_LIMIT_MAX ||
+ read_burst > EV_RATE_LIMIT_MAX ||
+ write_burst > EV_RATE_LIMIT_MAX)
+ return NULL;
+ r = mm_calloc(1, sizeof(struct ev_token_bucket_cfg));
+ if (!r)
+ return NULL;
+ r->read_rate = read_rate;
+ r->write_rate = write_rate;
+ r->read_maximum = read_burst;
+ r->write_maximum = write_burst;
+ memcpy(&r->tick_timeout, tick_len, sizeof(struct timeval));
+ r->msec_per_tick = (tick_len->tv_sec * 1000) +
+ (tick_len->tv_usec & COMMON_TIMEOUT_MICROSECONDS_MASK)/1000;
+ return r;
+}
+
+void
+ev_token_bucket_cfg_free(struct ev_token_bucket_cfg *cfg)
+{
+ mm_free(cfg);
+}
+
+/* Default values for max_single_read & max_single_write variables. */
+#define MAX_SINGLE_READ_DEFAULT 16384
+#define MAX_SINGLE_WRITE_DEFAULT 16384
+
+#define LOCK_GROUP(g) EVLOCK_LOCK((g)->lock, 0)
+#define UNLOCK_GROUP(g) EVLOCK_UNLOCK((g)->lock, 0)
+
+static int bev_group_suspend_reading_(struct bufferevent_rate_limit_group *g);
+static int bev_group_suspend_writing_(struct bufferevent_rate_limit_group *g);
+static void bev_group_unsuspend_reading_(struct bufferevent_rate_limit_group *g);
+static void bev_group_unsuspend_writing_(struct bufferevent_rate_limit_group *g);
+
+/** Helper: figure out the maximum amount we should write if is_write, or
+ the maximum amount we should read if is_read. Return that maximum, or
+ 0 if our bucket is wholly exhausted.
+ */
+static inline ev_ssize_t
+bufferevent_get_rlim_max_(struct bufferevent_private *bev, int is_write)
+{
+ /* needs lock on bev. */
+ ev_ssize_t max_so_far = is_write?bev->max_single_write:bev->max_single_read;
+
+#define LIM(x) \
+ (is_write ? (x).write_limit : (x).read_limit)
+
+#define GROUP_SUSPENDED(g) \
+ (is_write ? (g)->write_suspended : (g)->read_suspended)
+
+ /* Sets max_so_far to MIN(x, max_so_far) */
+#define CLAMPTO(x) \
+ do { \
+ if (max_so_far > (x)) \
+ max_so_far = (x); \
+ } while (0);
+
+ if (!bev->rate_limiting)
+ return max_so_far;
+
+ /* If rate-limiting is enabled at all, update the appropriate
+ bucket, and take the smaller of our rate limit and the group
+ rate limit.
+ */
+
+ if (bev->rate_limiting->cfg) {
+ bufferevent_update_buckets(bev);
+ max_so_far = LIM(bev->rate_limiting->limit);
+ }
+ if (bev->rate_limiting->group) {
+ struct bufferevent_rate_limit_group *g =
+ bev->rate_limiting->group;
+ ev_ssize_t share;
+ LOCK_GROUP(g);
+ if (GROUP_SUSPENDED(g)) {
+ /* We can get here if we failed to lock this
+ * particular bufferevent while suspending the whole
+ * group. */
+ if (is_write)
+ bufferevent_suspend_write_(&bev->bev,
+ BEV_SUSPEND_BW_GROUP);
+ else
+ bufferevent_suspend_read_(&bev->bev,
+ BEV_SUSPEND_BW_GROUP);
+ share = 0;
+ } else {
+ /* XXXX probably we should divide among the active
+ * members, not the total members. */
+ share = LIM(g->rate_limit) / g->n_members;
+ if (share < g->min_share)
+ share = g->min_share;
+ }
+ UNLOCK_GROUP(g);
+ CLAMPTO(share);
+ }
+
+ if (max_so_far < 0)
+ max_so_far = 0;
+ return max_so_far;
+}
+
+ev_ssize_t
+bufferevent_get_read_max_(struct bufferevent_private *bev)
+{
+ return bufferevent_get_rlim_max_(bev, 0);
+}
+
+ev_ssize_t
+bufferevent_get_write_max_(struct bufferevent_private *bev)
+{
+ return bufferevent_get_rlim_max_(bev, 1);
+}
+
+int
+bufferevent_decrement_read_buckets_(struct bufferevent_private *bev, ev_ssize_t bytes)
+{
+ /* XXXXX Make sure all users of this function check its return value */
+ int r = 0;
+ /* need to hold lock on bev */
+ if (!bev->rate_limiting)
+ return 0;
+
+ if (bev->rate_limiting->cfg) {
+ bev->rate_limiting->limit.read_limit -= bytes;
+ if (bev->rate_limiting->limit.read_limit <= 0) {
+ bufferevent_suspend_read_(&bev->bev, BEV_SUSPEND_BW);
+ if (event_add(&bev->rate_limiting->refill_bucket_event,
+ &bev->rate_limiting->cfg->tick_timeout) < 0)
+ r = -1;
+ } else if (bev->read_suspended & BEV_SUSPEND_BW) {
+ if (!(bev->write_suspended & BEV_SUSPEND_BW))
+ event_del(&bev->rate_limiting->refill_bucket_event);
+ bufferevent_unsuspend_read_(&bev->bev, BEV_SUSPEND_BW);
+ }
+ }
+
+ if (bev->rate_limiting->group) {
+ LOCK_GROUP(bev->rate_limiting->group);
+ bev->rate_limiting->group->rate_limit.read_limit -= bytes;
+ bev->rate_limiting->group->total_read += bytes;
+ if (bev->rate_limiting->group->rate_limit.read_limit <= 0) {
+ bev_group_suspend_reading_(bev->rate_limiting->group);
+ } else if (bev->rate_limiting->group->read_suspended) {
+ bev_group_unsuspend_reading_(bev->rate_limiting->group);
+ }
+ UNLOCK_GROUP(bev->rate_limiting->group);
+ }
+
+ return r;
+}
+
+int
+bufferevent_decrement_write_buckets_(struct bufferevent_private *bev, ev_ssize_t bytes)
+{
+ /* XXXXX Make sure all users of this function check its return value */
+ int r = 0;
+ /* need to hold lock */
+ if (!bev->rate_limiting)
+ return 0;
+
+ if (bev->rate_limiting->cfg) {
+ bev->rate_limiting->limit.write_limit -= bytes;
+ if (bev->rate_limiting->limit.write_limit <= 0) {
+ bufferevent_suspend_write_(&bev->bev, BEV_SUSPEND_BW);
+ if (event_add(&bev->rate_limiting->refill_bucket_event,
+ &bev->rate_limiting->cfg->tick_timeout) < 0)
+ r = -1;
+ } else if (bev->write_suspended & BEV_SUSPEND_BW) {
+ if (!(bev->read_suspended & BEV_SUSPEND_BW))
+ event_del(&bev->rate_limiting->refill_bucket_event);
+ bufferevent_unsuspend_write_(&bev->bev, BEV_SUSPEND_BW);
+ }
+ }
+
+ if (bev->rate_limiting->group) {
+ LOCK_GROUP(bev->rate_limiting->group);
+ bev->rate_limiting->group->rate_limit.write_limit -= bytes;
+ bev->rate_limiting->group->total_written += bytes;
+ if (bev->rate_limiting->group->rate_limit.write_limit <= 0) {
+ bev_group_suspend_writing_(bev->rate_limiting->group);
+ } else if (bev->rate_limiting->group->write_suspended) {
+ bev_group_unsuspend_writing_(bev->rate_limiting->group);
+ }
+ UNLOCK_GROUP(bev->rate_limiting->group);
+ }
+
+ return r;
+}
+
+/** Stop reading on every bufferevent in <b>g</b> */
+static int
+bev_group_suspend_reading_(struct bufferevent_rate_limit_group *g)
+{
+ /* Needs group lock */
+ struct bufferevent_private *bev;
+ g->read_suspended = 1;
+ g->pending_unsuspend_read = 0;
+
+ /* Note that in this loop we call EVLOCK_TRY_LOCK_ instead of BEV_LOCK,
+ to prevent a deadlock. (Ordinarily, the group lock nests inside
+ the bufferevent locks. If we are unable to lock any individual
+ bufferevent, it will find out later when it looks at its limit
+ and sees that its group is suspended.)
+ */
+ LIST_FOREACH(bev, &g->members, rate_limiting->next_in_group) {
+ if (EVLOCK_TRY_LOCK_(bev->lock)) {
+ bufferevent_suspend_read_(&bev->bev,
+ BEV_SUSPEND_BW_GROUP);
+ EVLOCK_UNLOCK(bev->lock, 0);
+ }
+ }
+ return 0;
+}
+
+/** Stop writing on every bufferevent in <b>g</b> */
+static int
+bev_group_suspend_writing_(struct bufferevent_rate_limit_group *g)
+{
+ /* Needs group lock */
+ struct bufferevent_private *bev;
+ g->write_suspended = 1;
+ g->pending_unsuspend_write = 0;
+ LIST_FOREACH(bev, &g->members, rate_limiting->next_in_group) {
+ if (EVLOCK_TRY_LOCK_(bev->lock)) {
+ bufferevent_suspend_write_(&bev->bev,
+ BEV_SUSPEND_BW_GROUP);
+ EVLOCK_UNLOCK(bev->lock, 0);
+ }
+ }
+ return 0;
+}
+
+/** Timer callback invoked on a single bufferevent with one or more exhausted
+ buckets when they are ready to refill. */
+static void
+bev_refill_callback_(evutil_socket_t fd, short what, void *arg)
+{
+ unsigned tick;
+ struct timeval now;
+ struct bufferevent_private *bev = arg;
+ int again = 0;
+ BEV_LOCK(&bev->bev);
+ if (!bev->rate_limiting || !bev->rate_limiting->cfg) {
+ BEV_UNLOCK(&bev->bev);
+ return;
+ }
+
+ /* First, update the bucket */
+ event_base_gettimeofday_cached(bev->bev.ev_base, &now);
+ tick = ev_token_bucket_get_tick_(&now,
+ bev->rate_limiting->cfg);
+ ev_token_bucket_update_(&bev->rate_limiting->limit,
+ bev->rate_limiting->cfg,
+ tick);
+
+ /* Now unsuspend any read/write operations as appropriate. */
+ if ((bev->read_suspended & BEV_SUSPEND_BW)) {
+ if (bev->rate_limiting->limit.read_limit > 0)
+ bufferevent_unsuspend_read_(&bev->bev, BEV_SUSPEND_BW);
+ else
+ again = 1;
+ }
+ if ((bev->write_suspended & BEV_SUSPEND_BW)) {
+ if (bev->rate_limiting->limit.write_limit > 0)
+ bufferevent_unsuspend_write_(&bev->bev, BEV_SUSPEND_BW);
+ else
+ again = 1;
+ }
+ if (again) {
+ /* One or more of the buckets may need another refill if they
+ started negative.
+
+ XXXX if we need to be quiet for more ticks, we should
+ maybe figure out what timeout we really want.
+ */
+ /* XXXX Handle event_add failure somehow */
+ event_add(&bev->rate_limiting->refill_bucket_event,
+ &bev->rate_limiting->cfg->tick_timeout);
+ }
+ BEV_UNLOCK(&bev->bev);
+}
+
+/** Helper: grab a random element from a bufferevent group.
+ *
+ * Requires that we hold the lock on the group.
+ */
+static struct bufferevent_private *
+bev_group_random_element_(struct bufferevent_rate_limit_group *group)
+{
+ int which;
+ struct bufferevent_private *bev;
+
+ /* requires group lock */
+
+ if (!group->n_members)
+ return NULL;
+
+ EVUTIL_ASSERT(! LIST_EMPTY(&group->members));
+
+ which = evutil_weakrand_range_(&group->weakrand_seed, group->n_members);
+
+ bev = LIST_FIRST(&group->members);
+ while (which--)
+ bev = LIST_NEXT(bev, rate_limiting->next_in_group);
+
+ return bev;
+}
+
+/** Iterate over the elements of a rate-limiting group 'g' with a random
+ starting point, assigning each to the variable 'bev', and executing the
+ block 'block'.
+
+ We do this in a half-baked effort to get fairness among group members.
+ XXX Round-robin or some kind of priority queue would be even more fair.
+ */
+#define FOREACH_RANDOM_ORDER(block) \
+ do { \
+ first = bev_group_random_element_(g); \
+ for (bev = first; bev != LIST_END(&g->members); \
+ bev = LIST_NEXT(bev, rate_limiting->next_in_group)) { \
+ block ; \
+ } \
+ for (bev = LIST_FIRST(&g->members); bev && bev != first; \
+ bev = LIST_NEXT(bev, rate_limiting->next_in_group)) { \
+ block ; \
+ } \
+ } while (0)
+
+static void
+bev_group_unsuspend_reading_(struct bufferevent_rate_limit_group *g)
+{
+ int again = 0;
+ struct bufferevent_private *bev, *first;
+
+ g->read_suspended = 0;
+ FOREACH_RANDOM_ORDER({
+ if (EVLOCK_TRY_LOCK_(bev->lock)) {
+ bufferevent_unsuspend_read_(&bev->bev,
+ BEV_SUSPEND_BW_GROUP);
+ EVLOCK_UNLOCK(bev->lock, 0);
+ } else {
+ again = 1;
+ }
+ });
+ g->pending_unsuspend_read = again;
+}
+
+static void
+bev_group_unsuspend_writing_(struct bufferevent_rate_limit_group *g)
+{
+ int again = 0;
+ struct bufferevent_private *bev, *first;
+ g->write_suspended = 0;
+
+ FOREACH_RANDOM_ORDER({
+ if (EVLOCK_TRY_LOCK_(bev->lock)) {
+ bufferevent_unsuspend_write_(&bev->bev,
+ BEV_SUSPEND_BW_GROUP);
+ EVLOCK_UNLOCK(bev->lock, 0);
+ } else {
+ again = 1;
+ }
+ });
+ g->pending_unsuspend_write = again;
+}
+
+/** Callback invoked every tick to add more elements to the group bucket
+ and unsuspend group members as needed.
+ */
+static void
+bev_group_refill_callback_(evutil_socket_t fd, short what, void *arg)
+{
+ struct bufferevent_rate_limit_group *g = arg;
+ unsigned tick;
+ struct timeval now;
+
+ event_base_gettimeofday_cached(event_get_base(&g->master_refill_event), &now);
+
+ LOCK_GROUP(g);
+
+ tick = ev_token_bucket_get_tick_(&now, &g->rate_limit_cfg);
+ ev_token_bucket_update_(&g->rate_limit, &g->rate_limit_cfg, tick);
+
+ if (g->pending_unsuspend_read ||
+ (g->read_suspended && (g->rate_limit.read_limit >= g->min_share))) {
+ bev_group_unsuspend_reading_(g);
+ }
+ if (g->pending_unsuspend_write ||
+ (g->write_suspended && (g->rate_limit.write_limit >= g->min_share))){
+ bev_group_unsuspend_writing_(g);
+ }
+
+ /* XXXX Rather than waiting to the next tick to unsuspend stuff
+ * with pending_unsuspend_write/read, we should do it on the
+ * next iteration of the mainloop.
+ */
+
+ UNLOCK_GROUP(g);
+}
+
+int
+bufferevent_set_rate_limit(struct bufferevent *bev,
+ struct ev_token_bucket_cfg *cfg)
+{
+ struct bufferevent_private *bevp =
+ EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+ int r = -1;
+ struct bufferevent_rate_limit *rlim;
+ struct timeval now;
+ ev_uint32_t tick;
+ int reinit = 0, suspended = 0;
+ /* XXX reference-count cfg */
+
+ BEV_LOCK(bev);
+
+ if (cfg == NULL) {
+ if (bevp->rate_limiting) {
+ rlim = bevp->rate_limiting;
+ rlim->cfg = NULL;
+ bufferevent_unsuspend_read_(bev, BEV_SUSPEND_BW);
+ bufferevent_unsuspend_write_(bev, BEV_SUSPEND_BW);
+ if (event_initialized(&rlim->refill_bucket_event))
+ event_del(&rlim->refill_bucket_event);
+ }
+ r = 0;
+ goto done;
+ }
+
+ event_base_gettimeofday_cached(bev->ev_base, &now);
+ tick = ev_token_bucket_get_tick_(&now, cfg);
+
+ if (bevp->rate_limiting && bevp->rate_limiting->cfg == cfg) {
+ /* no-op */
+ r = 0;
+ goto done;
+ }
+ if (bevp->rate_limiting == NULL) {
+ rlim = mm_calloc(1, sizeof(struct bufferevent_rate_limit));
+ if (!rlim)
+ goto done;
+ bevp->rate_limiting = rlim;
+ } else {
+ rlim = bevp->rate_limiting;
+ }
+ reinit = rlim->cfg != NULL;
+
+ rlim->cfg = cfg;
+ ev_token_bucket_init_(&rlim->limit, cfg, tick, reinit);
+
+ if (reinit) {
+ EVUTIL_ASSERT(event_initialized(&rlim->refill_bucket_event));
+ event_del(&rlim->refill_bucket_event);
+ }
+ event_assign(&rlim->refill_bucket_event, bev->ev_base,
+ -1, EV_FINALIZE, bev_refill_callback_, bevp);
+
+ if (rlim->limit.read_limit > 0) {
+ bufferevent_unsuspend_read_(bev, BEV_SUSPEND_BW);
+ } else {
+ bufferevent_suspend_read_(bev, BEV_SUSPEND_BW);
+ suspended=1;
+ }
+ if (rlim->limit.write_limit > 0) {
+ bufferevent_unsuspend_write_(bev, BEV_SUSPEND_BW);
+ } else {
+ bufferevent_suspend_write_(bev, BEV_SUSPEND_BW);
+ suspended = 1;
+ }
+
+ if (suspended)
+ event_add(&rlim->refill_bucket_event, &cfg->tick_timeout);
+
+ r = 0;
+
+done:
+ BEV_UNLOCK(bev);
+ return r;
+}
+
+struct bufferevent_rate_limit_group *
+bufferevent_rate_limit_group_new(struct event_base *base,
+ const struct ev_token_bucket_cfg *cfg)
+{
+ struct bufferevent_rate_limit_group *g;
+ struct timeval now;
+ ev_uint32_t tick;
+
+ event_base_gettimeofday_cached(base, &now);
+ tick = ev_token_bucket_get_tick_(&now, cfg);
+
+ g = mm_calloc(1, sizeof(struct bufferevent_rate_limit_group));
+ if (!g)
+ return NULL;
+ memcpy(&g->rate_limit_cfg, cfg, sizeof(g->rate_limit_cfg));
+ LIST_INIT(&g->members);
+
+ ev_token_bucket_init_(&g->rate_limit, cfg, tick, 0);
+
+ event_assign(&g->master_refill_event, base, -1, EV_PERSIST|EV_FINALIZE,
+ bev_group_refill_callback_, g);
+ /*XXXX handle event_add failure */
+ event_add(&g->master_refill_event, &cfg->tick_timeout);
+
+ EVTHREAD_ALLOC_LOCK(g->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+
+ bufferevent_rate_limit_group_set_min_share(g, 64);
+
+ evutil_weakrand_seed_(&g->weakrand_seed,
+ (ev_uint32_t) ((now.tv_sec + now.tv_usec) + (ev_intptr_t)g));
+
+ return g;
+}
+
+int
+bufferevent_rate_limit_group_set_cfg(
+ struct bufferevent_rate_limit_group *g,
+ const struct ev_token_bucket_cfg *cfg)
+{
+ int same_tick;
+ if (!g || !cfg)
+ return -1;
+
+ LOCK_GROUP(g);
+ same_tick = evutil_timercmp(
+ &g->rate_limit_cfg.tick_timeout, &cfg->tick_timeout, ==);
+ memcpy(&g->rate_limit_cfg, cfg, sizeof(g->rate_limit_cfg));
+
+ if (g->rate_limit.read_limit > (ev_ssize_t)cfg->read_maximum)
+ g->rate_limit.read_limit = cfg->read_maximum;
+ if (g->rate_limit.write_limit > (ev_ssize_t)cfg->write_maximum)
+ g->rate_limit.write_limit = cfg->write_maximum;
+
+ if (!same_tick) {
+ /* This can cause a hiccup in the schedule */
+ event_add(&g->master_refill_event, &cfg->tick_timeout);
+ }
+
+ /* The new limits might force us to adjust min_share differently. */
+ bufferevent_rate_limit_group_set_min_share(g, g->configured_min_share);
+
+ UNLOCK_GROUP(g);
+ return 0;
+}
+
+int
+bufferevent_rate_limit_group_set_min_share(
+ struct bufferevent_rate_limit_group *g,
+ size_t share)
+{
+ if (share > EV_SSIZE_MAX)
+ return -1;
+
+ g->configured_min_share = share;
+
+ /* Can't set share to less than the one-tick maximum. IOW, at steady
+ * state, at least one connection can go per tick. */
+ if (share > g->rate_limit_cfg.read_rate)
+ share = g->rate_limit_cfg.read_rate;
+ if (share > g->rate_limit_cfg.write_rate)
+ share = g->rate_limit_cfg.write_rate;
+
+ g->min_share = share;
+ return 0;
+}
+
+void
+bufferevent_rate_limit_group_free(struct bufferevent_rate_limit_group *g)
+{
+ LOCK_GROUP(g);
+ EVUTIL_ASSERT(0 == g->n_members);
+ event_del(&g->master_refill_event);
+ UNLOCK_GROUP(g);
+ EVTHREAD_FREE_LOCK(g->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ mm_free(g);
+}
+
+int
+bufferevent_add_to_rate_limit_group(struct bufferevent *bev,
+ struct bufferevent_rate_limit_group *g)
+{
+ int wsuspend, rsuspend;
+ struct bufferevent_private *bevp =
+ EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+ BEV_LOCK(bev);
+
+ if (!bevp->rate_limiting) {
+ struct bufferevent_rate_limit *rlim;
+ rlim = mm_calloc(1, sizeof(struct bufferevent_rate_limit));
+ if (!rlim) {
+ BEV_UNLOCK(bev);
+ return -1;
+ }
+ event_assign(&rlim->refill_bucket_event, bev->ev_base,
+ -1, EV_FINALIZE, bev_refill_callback_, bevp);
+ bevp->rate_limiting = rlim;
+ }
+
+ if (bevp->rate_limiting->group == g) {
+ BEV_UNLOCK(bev);
+ return 0;
+ }
+ if (bevp->rate_limiting->group)
+ bufferevent_remove_from_rate_limit_group(bev);
+
+ LOCK_GROUP(g);
+ bevp->rate_limiting->group = g;
+ ++g->n_members;
+ LIST_INSERT_HEAD(&g->members, bevp, rate_limiting->next_in_group);
+
+ rsuspend = g->read_suspended;
+ wsuspend = g->write_suspended;
+
+ UNLOCK_GROUP(g);
+
+ if (rsuspend)
+ bufferevent_suspend_read_(bev, BEV_SUSPEND_BW_GROUP);
+ if (wsuspend)
+ bufferevent_suspend_write_(bev, BEV_SUSPEND_BW_GROUP);
+
+ BEV_UNLOCK(bev);
+ return 0;
+}
+
+int
+bufferevent_remove_from_rate_limit_group(struct bufferevent *bev)
+{
+ return bufferevent_remove_from_rate_limit_group_internal_(bev, 1);
+}
+
+int
+bufferevent_remove_from_rate_limit_group_internal_(struct bufferevent *bev,
+ int unsuspend)
+{
+ struct bufferevent_private *bevp =
+ EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+ BEV_LOCK(bev);
+ if (bevp->rate_limiting && bevp->rate_limiting->group) {
+ struct bufferevent_rate_limit_group *g =
+ bevp->rate_limiting->group;
+ LOCK_GROUP(g);
+ bevp->rate_limiting->group = NULL;
+ --g->n_members;
+ LIST_REMOVE(bevp, rate_limiting->next_in_group);
+ UNLOCK_GROUP(g);
+ }
+ if (unsuspend) {
+ bufferevent_unsuspend_read_(bev, BEV_SUSPEND_BW_GROUP);
+ bufferevent_unsuspend_write_(bev, BEV_SUSPEND_BW_GROUP);
+ }
+ BEV_UNLOCK(bev);
+ return 0;
+}
+
+/* ===
+ * API functions to expose rate limits.
+ *
+ * Don't use these from inside Libevent; they're meant to be for use by
+ * the program.
+ * === */
+
+/* Mostly you don't want to use this function from inside libevent;
+ * bufferevent_get_read_max_() is more likely what you want*/
+ev_ssize_t
+bufferevent_get_read_limit(struct bufferevent *bev)
+{
+ ev_ssize_t r;
+ struct bufferevent_private *bevp;
+ BEV_LOCK(bev);
+ bevp = BEV_UPCAST(bev);
+ if (bevp->rate_limiting && bevp->rate_limiting->cfg) {
+ bufferevent_update_buckets(bevp);
+ r = bevp->rate_limiting->limit.read_limit;
+ } else {
+ r = EV_SSIZE_MAX;
+ }
+ BEV_UNLOCK(bev);
+ return r;
+}
+
+/* Mostly you don't want to use this function from inside libevent;
+ * bufferevent_get_write_max_() is more likely what you want*/
+ev_ssize_t
+bufferevent_get_write_limit(struct bufferevent *bev)
+{
+ ev_ssize_t r;
+ struct bufferevent_private *bevp;
+ BEV_LOCK(bev);
+ bevp = BEV_UPCAST(bev);
+ if (bevp->rate_limiting && bevp->rate_limiting->cfg) {
+ bufferevent_update_buckets(bevp);
+ r = bevp->rate_limiting->limit.write_limit;
+ } else {
+ r = EV_SSIZE_MAX;
+ }
+ BEV_UNLOCK(bev);
+ return r;
+}
+
+int
+bufferevent_set_max_single_read(struct bufferevent *bev, size_t size)
+{
+ struct bufferevent_private *bevp;
+ BEV_LOCK(bev);
+ bevp = BEV_UPCAST(bev);
+ if (size == 0 || size > EV_SSIZE_MAX)
+ bevp->max_single_read = MAX_SINGLE_READ_DEFAULT;
+ else
+ bevp->max_single_read = size;
+ BEV_UNLOCK(bev);
+ return 0;
+}
+
+int
+bufferevent_set_max_single_write(struct bufferevent *bev, size_t size)
+{
+ struct bufferevent_private *bevp;
+ BEV_LOCK(bev);
+ bevp = BEV_UPCAST(bev);
+ if (size == 0 || size > EV_SSIZE_MAX)
+ bevp->max_single_write = MAX_SINGLE_WRITE_DEFAULT;
+ else
+ bevp->max_single_write = size;
+ BEV_UNLOCK(bev);
+ return 0;
+}
+
+ev_ssize_t
+bufferevent_get_max_single_read(struct bufferevent *bev)
+{
+ ev_ssize_t r;
+
+ BEV_LOCK(bev);
+ r = BEV_UPCAST(bev)->max_single_read;
+ BEV_UNLOCK(bev);
+ return r;
+}
+
+ev_ssize_t
+bufferevent_get_max_single_write(struct bufferevent *bev)
+{
+ ev_ssize_t r;
+
+ BEV_LOCK(bev);
+ r = BEV_UPCAST(bev)->max_single_write;
+ BEV_UNLOCK(bev);
+ return r;
+}
+
+ev_ssize_t
+bufferevent_get_max_to_read(struct bufferevent *bev)
+{
+ ev_ssize_t r;
+ BEV_LOCK(bev);
+ r = bufferevent_get_read_max_(BEV_UPCAST(bev));
+ BEV_UNLOCK(bev);
+ return r;
+}
+
+ev_ssize_t
+bufferevent_get_max_to_write(struct bufferevent *bev)
+{
+ ev_ssize_t r;
+ BEV_LOCK(bev);
+ r = bufferevent_get_write_max_(BEV_UPCAST(bev));
+ BEV_UNLOCK(bev);
+ return r;
+}
+
+const struct ev_token_bucket_cfg *
+bufferevent_get_token_bucket_cfg(const struct bufferevent *bev) {
+ struct bufferevent_private *bufev_private = BEV_UPCAST(bev);
+ struct ev_token_bucket_cfg *cfg;
+
+ BEV_LOCK(bev);
+
+ if (bufev_private->rate_limiting) {
+ cfg = bufev_private->rate_limiting->cfg;
+ } else {
+ cfg = NULL;
+ }
+
+ BEV_UNLOCK(bev);
+
+ return cfg;
+}
+
+/* Mostly you don't want to use this function from inside libevent;
+ * bufferevent_get_read_max_() is more likely what you want*/
+ev_ssize_t
+bufferevent_rate_limit_group_get_read_limit(
+ struct bufferevent_rate_limit_group *grp)
+{
+ ev_ssize_t r;
+ LOCK_GROUP(grp);
+ r = grp->rate_limit.read_limit;
+ UNLOCK_GROUP(grp);
+ return r;
+}
+
+/* Mostly you don't want to use this function from inside libevent;
+ * bufferevent_get_write_max_() is more likely what you want. */
+ev_ssize_t
+bufferevent_rate_limit_group_get_write_limit(
+ struct bufferevent_rate_limit_group *grp)
+{
+ ev_ssize_t r;
+ LOCK_GROUP(grp);
+ r = grp->rate_limit.write_limit;
+ UNLOCK_GROUP(grp);
+ return r;
+}
+
+int
+bufferevent_decrement_read_limit(struct bufferevent *bev, ev_ssize_t decr)
+{
+ int r = 0;
+ ev_ssize_t old_limit, new_limit;
+ struct bufferevent_private *bevp;
+ BEV_LOCK(bev);
+ bevp = BEV_UPCAST(bev);
+ EVUTIL_ASSERT(bevp->rate_limiting && bevp->rate_limiting->cfg);
+ old_limit = bevp->rate_limiting->limit.read_limit;
+
+ new_limit = (bevp->rate_limiting->limit.read_limit -= decr);
+ if (old_limit > 0 && new_limit <= 0) {
+ bufferevent_suspend_read_(bev, BEV_SUSPEND_BW);
+ if (event_add(&bevp->rate_limiting->refill_bucket_event,
+ &bevp->rate_limiting->cfg->tick_timeout) < 0)
+ r = -1;
+ } else if (old_limit <= 0 && new_limit > 0) {
+ if (!(bevp->write_suspended & BEV_SUSPEND_BW))
+ event_del(&bevp->rate_limiting->refill_bucket_event);
+ bufferevent_unsuspend_read_(bev, BEV_SUSPEND_BW);
+ }
+
+ BEV_UNLOCK(bev);
+ return r;
+}
+
+int
+bufferevent_decrement_write_limit(struct bufferevent *bev, ev_ssize_t decr)
+{
+ /* XXXX this is mostly copy-and-paste from
+ * bufferevent_decrement_read_limit */
+ int r = 0;
+ ev_ssize_t old_limit, new_limit;
+ struct bufferevent_private *bevp;
+ BEV_LOCK(bev);
+ bevp = BEV_UPCAST(bev);
+ EVUTIL_ASSERT(bevp->rate_limiting && bevp->rate_limiting->cfg);
+ old_limit = bevp->rate_limiting->limit.write_limit;
+
+ new_limit = (bevp->rate_limiting->limit.write_limit -= decr);
+ if (old_limit > 0 && new_limit <= 0) {
+ bufferevent_suspend_write_(bev, BEV_SUSPEND_BW);
+ if (event_add(&bevp->rate_limiting->refill_bucket_event,
+ &bevp->rate_limiting->cfg->tick_timeout) < 0)
+ r = -1;
+ } else if (old_limit <= 0 && new_limit > 0) {
+ if (!(bevp->read_suspended & BEV_SUSPEND_BW))
+ event_del(&bevp->rate_limiting->refill_bucket_event);
+ bufferevent_unsuspend_write_(bev, BEV_SUSPEND_BW);
+ }
+
+ BEV_UNLOCK(bev);
+ return r;
+}
+
+int
+bufferevent_rate_limit_group_decrement_read(
+ struct bufferevent_rate_limit_group *grp, ev_ssize_t decr)
+{
+ int r = 0;
+ ev_ssize_t old_limit, new_limit;
+ LOCK_GROUP(grp);
+ old_limit = grp->rate_limit.read_limit;
+ new_limit = (grp->rate_limit.read_limit -= decr);
+
+ if (old_limit > 0 && new_limit <= 0) {
+ bev_group_suspend_reading_(grp);
+ } else if (old_limit <= 0 && new_limit > 0) {
+ bev_group_unsuspend_reading_(grp);
+ }
+
+ UNLOCK_GROUP(grp);
+ return r;
+}
+
+int
+bufferevent_rate_limit_group_decrement_write(
+ struct bufferevent_rate_limit_group *grp, ev_ssize_t decr)
+{
+ int r = 0;
+ ev_ssize_t old_limit, new_limit;
+ LOCK_GROUP(grp);
+ old_limit = grp->rate_limit.write_limit;
+ new_limit = (grp->rate_limit.write_limit -= decr);
+
+ if (old_limit > 0 && new_limit <= 0) {
+ bev_group_suspend_writing_(grp);
+ } else if (old_limit <= 0 && new_limit > 0) {
+ bev_group_unsuspend_writing_(grp);
+ }
+
+ UNLOCK_GROUP(grp);
+ return r;
+}
+
+void
+bufferevent_rate_limit_group_get_totals(struct bufferevent_rate_limit_group *grp,
+ ev_uint64_t *total_read_out, ev_uint64_t *total_written_out)
+{
+ EVUTIL_ASSERT(grp != NULL);
+ if (total_read_out)
+ *total_read_out = grp->total_read;
+ if (total_written_out)
+ *total_written_out = grp->total_written;
+}
+
+void
+bufferevent_rate_limit_group_reset_totals(struct bufferevent_rate_limit_group *grp)
+{
+ grp->total_read = grp->total_written = 0;
+}
+
+int
+bufferevent_ratelim_init_(struct bufferevent_private *bev)
+{
+ bev->rate_limiting = NULL;
+ bev->max_single_read = MAX_SINGLE_READ_DEFAULT;
+ bev->max_single_write = MAX_SINGLE_WRITE_DEFAULT;
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_sock.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_sock.c
new file mode 100644
index 000000000..58095f37d
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/bufferevent_sock.c
@@ -0,0 +1,720 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
+
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef EVENT__HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef EVENT__HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef EVENT__HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+
+#include "event2/util.h"
+#include "event2/bufferevent.h"
+#include "event2/buffer.h"
+#include "event2/bufferevent_struct.h"
+#include "event2/bufferevent_compat.h"
+#include "event2/event.h"
+#include "log-internal.h"
+#include "mm-internal.h"
+#include "bufferevent-internal.h"
+#include "util-internal.h"
+#ifdef _WIN32
+#include "iocp-internal.h"
+#endif
+
+/* prototypes */
+static int be_socket_enable(struct bufferevent *, short);
+static int be_socket_disable(struct bufferevent *, short);
+static void be_socket_destruct(struct bufferevent *);
+static int be_socket_flush(struct bufferevent *, short, enum bufferevent_flush_mode);
+static int be_socket_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
+
+static void be_socket_setfd(struct bufferevent *, evutil_socket_t);
+
+const struct bufferevent_ops bufferevent_ops_socket = {
+ "socket",
+ evutil_offsetof(struct bufferevent_private, bev),
+ be_socket_enable,
+ be_socket_disable,
+ NULL, /* unlink */
+ be_socket_destruct,
+ bufferevent_generic_adj_existing_timeouts_,
+ be_socket_flush,
+ be_socket_ctrl,
+};
+
+const struct sockaddr*
+bufferevent_socket_get_conn_address_(struct bufferevent *bev)
+{
+ struct bufferevent_private *bev_p =
+ EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+
+ return (struct sockaddr *)&bev_p->conn_address;
+}
+static void
+bufferevent_socket_set_conn_address_fd(struct bufferevent_private *bev_p, int fd)
+{
+ socklen_t len = sizeof(bev_p->conn_address);
+
+ struct sockaddr *addr = (struct sockaddr *)&bev_p->conn_address;
+ if (addr->sa_family != AF_UNSPEC)
+ getpeername(fd, addr, &len);
+}
+static void
+bufferevent_socket_set_conn_address(struct bufferevent_private *bev_p,
+ struct sockaddr *addr, size_t addrlen)
+{
+ EVUTIL_ASSERT(addrlen <= sizeof(bev_p->conn_address));
+ memcpy(&bev_p->conn_address, addr, addrlen);
+}
+
+static void
+bufferevent_socket_outbuf_cb(struct evbuffer *buf,
+ const struct evbuffer_cb_info *cbinfo,
+ void *arg)
+{
+ struct bufferevent *bufev = arg;
+ struct bufferevent_private *bufev_p =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+
+ if (cbinfo->n_added &&
+ (bufev->enabled & EV_WRITE) &&
+ !event_pending(&bufev->ev_write, EV_WRITE, NULL) &&
+ !bufev_p->write_suspended) {
+ /* Somebody added data to the buffer, and we would like to
+ * write, and we were not writing. So, start writing. */
+ if (bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1) {
+ /* Should we log this? */
+ }
+ }
+}
+
+static void
+bufferevent_readcb(evutil_socket_t fd, short event, void *arg)
+{
+ struct bufferevent *bufev = arg;
+ struct bufferevent_private *bufev_p =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+ struct evbuffer *input;
+ int res = 0;
+ short what = BEV_EVENT_READING;
+ ev_ssize_t howmuch = -1, readmax=-1;
+
+ bufferevent_incref_and_lock_(bufev);
+
+ if (event == EV_TIMEOUT) {
+ /* Note that we only check for event==EV_TIMEOUT. If
+ * event==EV_TIMEOUT|EV_READ, we can safely ignore the
+ * timeout, since a read has occurred */
+ what |= BEV_EVENT_TIMEOUT;
+ goto error;
+ }
+
+ input = bufev->input;
+
+ /*
+ * If we have a high watermark configured then we don't want to
+ * read more data than would make us reach the watermark.
+ */
+ if (bufev->wm_read.high != 0) {
+ howmuch = bufev->wm_read.high - evbuffer_get_length(input);
+ /* we somehow lowered the watermark, stop reading */
+ if (howmuch <= 0) {
+ bufferevent_wm_suspend_read(bufev);
+ goto done;
+ }
+ }
+ readmax = bufferevent_get_read_max_(bufev_p);
+ if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited"
+ * uglifies this code. XXXX */
+ howmuch = readmax;
+ if (bufev_p->read_suspended)
+ goto done;
+
+ evbuffer_unfreeze(input, 0);
+ res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */
+ evbuffer_freeze(input, 0);
+
+ if (res == -1) {
+ int err = evutil_socket_geterror(fd);
+ if (EVUTIL_ERR_RW_RETRIABLE(err))
+ goto reschedule;
+ if (EVUTIL_ERR_CONNECT_REFUSED(err)) {
+ bufev_p->connection_refused = 1;
+ goto done;
+ }
+ /* error case */
+ what |= BEV_EVENT_ERROR;
+ } else if (res == 0) {
+ /* eof case */
+ what |= BEV_EVENT_EOF;
+ }
+
+ if (res <= 0)
+ goto error;
+
+ bufferevent_decrement_read_buckets_(bufev_p, res);
+
+ /* Invoke the user callback - must always be called last */
+ bufferevent_trigger_nolock_(bufev, EV_READ, 0);
+
+ goto done;
+
+ reschedule:
+ goto done;
+
+ error:
+ bufferevent_disable(bufev, EV_READ);
+ bufferevent_run_eventcb_(bufev, what, 0);
+
+ done:
+ bufferevent_decref_and_unlock_(bufev);
+}
+
+static void
+bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
+{
+ struct bufferevent *bufev = arg;
+ struct bufferevent_private *bufev_p =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+ int res = 0;
+ short what = BEV_EVENT_WRITING;
+ int connected = 0;
+ ev_ssize_t atmost = -1;
+
+ bufferevent_incref_and_lock_(bufev);
+
+ if (event == EV_TIMEOUT) {
+ /* Note that we only check for event==EV_TIMEOUT. If
+ * event==EV_TIMEOUT|EV_WRITE, we can safely ignore the
+ * timeout, since a read has occurred */
+ what |= BEV_EVENT_TIMEOUT;
+ goto error;
+ }
+ if (bufev_p->connecting) {
+ int c = evutil_socket_finished_connecting_(fd);
+ /* we need to fake the error if the connection was refused
+ * immediately - usually connection to localhost on BSD */
+ if (bufev_p->connection_refused) {
+ bufev_p->connection_refused = 0;
+ c = -1;
+ }
+
+ if (c == 0)
+ goto done;
+
+ bufev_p->connecting = 0;
+ if (c < 0) {
+ event_del(&bufev->ev_write);
+ event_del(&bufev->ev_read);
+ bufferevent_run_eventcb_(bufev, BEV_EVENT_ERROR, 0);
+ goto done;
+ } else {
+ connected = 1;
+ bufferevent_socket_set_conn_address_fd(bufev_p, fd);
+#ifdef _WIN32
+ if (BEV_IS_ASYNC(bufev)) {
+ event_del(&bufev->ev_write);
+ bufferevent_async_set_connected_(bufev);
+ bufferevent_run_eventcb_(bufev,
+ BEV_EVENT_CONNECTED, 0);
+ goto done;
+ }
+#endif
+ bufferevent_run_eventcb_(bufev,
+ BEV_EVENT_CONNECTED, 0);
+ if (!(bufev->enabled & EV_WRITE) ||
+ bufev_p->write_suspended) {
+ event_del(&bufev->ev_write);
+ goto done;
+ }
+ }
+ }
+
+ atmost = bufferevent_get_write_max_(bufev_p);
+
+ if (bufev_p->write_suspended)
+ goto done;
+
+ if (evbuffer_get_length(bufev->output)) {
+ evbuffer_unfreeze(bufev->output, 1);
+ res = evbuffer_write_atmost(bufev->output, fd, atmost);
+ evbuffer_freeze(bufev->output, 1);
+ if (res == -1) {
+ int err = evutil_socket_geterror(fd);
+ if (EVUTIL_ERR_RW_RETRIABLE(err))
+ goto reschedule;
+ what |= BEV_EVENT_ERROR;
+ } else if (res == 0) {
+ /* eof case
+ XXXX Actually, a 0 on write doesn't indicate
+ an EOF. An ECONNRESET might be more typical.
+ */
+ what |= BEV_EVENT_EOF;
+ }
+ if (res <= 0)
+ goto error;
+
+ bufferevent_decrement_write_buckets_(bufev_p, res);
+ }
+
+ if (evbuffer_get_length(bufev->output) == 0) {
+ event_del(&bufev->ev_write);
+ }
+
+ /*
+ * Invoke the user callback if our buffer is drained or below the
+ * low watermark.
+ */
+ if (res || !connected) {
+ bufferevent_trigger_nolock_(bufev, EV_WRITE, 0);
+ }
+
+ goto done;
+
+ reschedule:
+ if (evbuffer_get_length(bufev->output) == 0) {
+ event_del(&bufev->ev_write);
+ }
+ goto done;
+
+ error:
+ bufferevent_disable(bufev, EV_WRITE);
+ bufferevent_run_eventcb_(bufev, what, 0);
+
+ done:
+ bufferevent_decref_and_unlock_(bufev);
+}
+
+struct bufferevent *
+bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,
+ int options)
+{
+ struct bufferevent_private *bufev_p;
+ struct bufferevent *bufev;
+
+#ifdef _WIN32
+ if (base && event_base_get_iocp_(base))
+ return bufferevent_async_new_(base, fd, options);
+#endif
+
+ if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL)
+ return NULL;
+
+ if (bufferevent_init_common_(bufev_p, base, &bufferevent_ops_socket,
+ options) < 0) {
+ mm_free(bufev_p);
+ return NULL;
+ }
+ bufev = &bufev_p->bev;
+ evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD);
+
+ event_assign(&bufev->ev_read, bufev->ev_base, fd,
+ EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev);
+ event_assign(&bufev->ev_write, bufev->ev_base, fd,
+ EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev);
+
+ evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev);
+
+ evbuffer_freeze(bufev->input, 0);
+ evbuffer_freeze(bufev->output, 1);
+
+ return bufev;
+}
+
+int
+bufferevent_socket_connect(struct bufferevent *bev,
+ const struct sockaddr *sa, int socklen)
+{
+ struct bufferevent_private *bufev_p =
+ EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+
+ evutil_socket_t fd;
+ int r = 0;
+ int result=-1;
+ int ownfd = 0;
+
+ bufferevent_incref_and_lock_(bev);
+
+ if (!bufev_p)
+ goto done;
+
+ fd = bufferevent_getfd(bev);
+ if (fd < 0) {
+ if (!sa)
+ goto done;
+ fd = evutil_socket_(sa->sa_family,
+ SOCK_STREAM|EVUTIL_SOCK_NONBLOCK, 0);
+ if (fd < 0)
+ goto done;
+ ownfd = 1;
+ }
+ if (sa) {
+#ifdef _WIN32
+ if (bufferevent_async_can_connect_(bev)) {
+ bufferevent_setfd(bev, fd);
+ r = bufferevent_async_connect_(bev, fd, sa, socklen);
+ if (r < 0)
+ goto freesock;
+ bufev_p->connecting = 1;
+ result = 0;
+ goto done;
+ } else
+#endif
+ r = evutil_socket_connect_(&fd, sa, socklen);
+ if (r < 0)
+ goto freesock;
+ }
+#ifdef _WIN32
+ /* ConnectEx() isn't always around, even when IOCP is enabled.
+ * Here, we borrow the socket object's write handler to fall back
+ * on a non-blocking connect() when ConnectEx() is unavailable. */
+ if (BEV_IS_ASYNC(bev)) {
+ event_assign(&bev->ev_write, bev->ev_base, fd,
+ EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bev);
+ }
+#endif
+ bufferevent_setfd(bev, fd);
+ if (r == 0) {
+ if (! be_socket_enable(bev, EV_WRITE)) {
+ bufev_p->connecting = 1;
+ result = 0;
+ goto done;
+ }
+ } else if (r == 1) {
+ /* The connect succeeded already. How very BSD of it. */
+ result = 0;
+ bufev_p->connecting = 1;
+ event_active(&bev->ev_write, EV_WRITE, 1);
+ } else {
+ /* The connect failed already. How very BSD of it. */
+ bufev_p->connection_refused = 1;
+ bufev_p->connecting = 1;
+ result = 0;
+ event_active(&bev->ev_write, EV_WRITE, 1);
+ }
+
+ goto done;
+
+freesock:
+ bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
+ if (ownfd)
+ evutil_closesocket(fd);
+ /* do something about the error? */
+done:
+ bufferevent_decref_and_unlock_(bev);
+ return result;
+}
+
+static void
+bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai,
+ void *arg)
+{
+ struct bufferevent *bev = arg;
+ struct bufferevent_private *bev_p =
+ EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+ int r;
+ BEV_LOCK(bev);
+
+ bufferevent_unsuspend_write_(bev, BEV_SUSPEND_LOOKUP);
+ bufferevent_unsuspend_read_(bev, BEV_SUSPEND_LOOKUP);
+
+ bev_p->dns_request = NULL;
+
+ if (result == EVUTIL_EAI_CANCEL) {
+ bev_p->dns_error = result;
+ bufferevent_decref_and_unlock_(bev);
+ return;
+ }
+ if (result != 0) {
+ bev_p->dns_error = result;
+ bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
+ bufferevent_decref_and_unlock_(bev);
+ if (ai)
+ evutil_freeaddrinfo(ai);
+ return;
+ }
+
+ /* XXX use the other addrinfos? */
+ /* XXX use this return value */
+ bufferevent_socket_set_conn_address(bev_p, ai->ai_addr, (int)ai->ai_addrlen);
+ r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen);
+ (void)r;
+ bufferevent_decref_and_unlock_(bev);
+ evutil_freeaddrinfo(ai);
+}
+
+int
+bufferevent_socket_connect_hostname(struct bufferevent *bev,
+ struct evdns_base *evdns_base, int family, const char *hostname, int port)
+{
+ char portbuf[10];
+ struct evutil_addrinfo hint;
+ struct bufferevent_private *bev_p =
+ EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+
+ if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC)
+ return -1;
+ if (port < 1 || port > 65535)
+ return -1;
+
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_family = family;
+ hint.ai_protocol = IPPROTO_TCP;
+ hint.ai_socktype = SOCK_STREAM;
+
+ evutil_snprintf(portbuf, sizeof(portbuf), "%d", port);
+
+ BEV_LOCK(bev);
+ bev_p->dns_error = 0;
+
+ bufferevent_suspend_write_(bev, BEV_SUSPEND_LOOKUP);
+ bufferevent_suspend_read_(bev, BEV_SUSPEND_LOOKUP);
+
+ bufferevent_incref_(bev);
+ bev_p->dns_request = evutil_getaddrinfo_async_(evdns_base, hostname,
+ portbuf, &hint, bufferevent_connect_getaddrinfo_cb, bev);
+ BEV_UNLOCK(bev);
+
+ return 0;
+}
+
+int
+bufferevent_socket_get_dns_error(struct bufferevent *bev)
+{
+ int rv;
+ struct bufferevent_private *bev_p =
+ EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+
+ BEV_LOCK(bev);
+ rv = bev_p->dns_error;
+ BEV_UNLOCK(bev);
+
+ return rv;
+}
+
+/*
+ * Create a new buffered event object.
+ *
+ * The read callback is invoked whenever we read new data.
+ * The write callback is invoked whenever the output buffer is drained.
+ * The error callback is invoked on a write/read error or on EOF.
+ *
+ * Both read and write callbacks maybe NULL. The error callback is not
+ * allowed to be NULL and have to be provided always.
+ */
+
+struct bufferevent *
+bufferevent_new(evutil_socket_t fd,
+ bufferevent_data_cb readcb, bufferevent_data_cb writecb,
+ bufferevent_event_cb eventcb, void *cbarg)
+{
+ struct bufferevent *bufev;
+
+ if (!(bufev = bufferevent_socket_new(NULL, fd, 0)))
+ return NULL;
+
+ bufferevent_setcb(bufev, readcb, writecb, eventcb, cbarg);
+
+ return bufev;
+}
+
+
+static int
+be_socket_enable(struct bufferevent *bufev, short event)
+{
+ if (event & EV_READ &&
+ bufferevent_add_event_(&bufev->ev_read, &bufev->timeout_read) == -1)
+ return -1;
+ if (event & EV_WRITE &&
+ bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1)
+ return -1;
+ return 0;
+}
+
+static int
+be_socket_disable(struct bufferevent *bufev, short event)
+{
+ struct bufferevent_private *bufev_p =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+ if (event & EV_READ) {
+ if (event_del(&bufev->ev_read) == -1)
+ return -1;
+ }
+ /* Don't actually disable the write if we are trying to connect. */
+ if ((event & EV_WRITE) && ! bufev_p->connecting) {
+ if (event_del(&bufev->ev_write) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+static void
+be_socket_destruct(struct bufferevent *bufev)
+{
+ struct bufferevent_private *bufev_p =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+ evutil_socket_t fd;
+ EVUTIL_ASSERT(bufev->be_ops == &bufferevent_ops_socket);
+
+ fd = event_get_fd(&bufev->ev_read);
+
+ if ((bufev_p->options & BEV_OPT_CLOSE_ON_FREE) && fd >= 0)
+ EVUTIL_CLOSESOCKET(fd);
+
+ evutil_getaddrinfo_cancel_async_(bufev_p->dns_request);
+}
+
+static int
+be_socket_flush(struct bufferevent *bev, short iotype,
+ enum bufferevent_flush_mode mode)
+{
+ return 0;
+}
+
+
+static void
+be_socket_setfd(struct bufferevent *bufev, evutil_socket_t fd)
+{
+ struct bufferevent_private *bufev_p =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+
+ BEV_LOCK(bufev);
+ EVUTIL_ASSERT(bufev->be_ops == &bufferevent_ops_socket);
+
+ event_del(&bufev->ev_read);
+ event_del(&bufev->ev_write);
+
+ evbuffer_unfreeze(bufev->input, 0);
+ evbuffer_unfreeze(bufev->output, 1);
+
+ event_assign(&bufev->ev_read, bufev->ev_base, fd,
+ EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev);
+ event_assign(&bufev->ev_write, bufev->ev_base, fd,
+ EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev);
+
+ if (fd >= 0)
+ bufferevent_enable(bufev, bufev->enabled);
+
+ evutil_getaddrinfo_cancel_async_(bufev_p->dns_request);
+
+ BEV_UNLOCK(bufev);
+}
+
+/* XXXX Should non-socket bufferevents support this? */
+int
+bufferevent_priority_set(struct bufferevent *bufev, int priority)
+{
+ int r = -1;
+ struct bufferevent_private *bufev_p =
+ EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+
+ BEV_LOCK(bufev);
+ if (bufev->be_ops != &bufferevent_ops_socket)
+ goto done;
+
+ if (event_priority_set(&bufev->ev_read, priority) == -1)
+ goto done;
+ if (event_priority_set(&bufev->ev_write, priority) == -1)
+ goto done;
+
+ event_deferred_cb_set_priority_(&bufev_p->deferred, priority);
+
+ r = 0;
+done:
+ BEV_UNLOCK(bufev);
+ return r;
+}
+
+/* XXXX Should non-socket bufferevents support this? */
+int
+bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
+{
+ int res = -1;
+
+ BEV_LOCK(bufev);
+ if (bufev->be_ops != &bufferevent_ops_socket)
+ goto done;
+
+ bufev->ev_base = base;
+
+ res = event_base_set(base, &bufev->ev_read);
+ if (res == -1)
+ goto done;
+
+ res = event_base_set(base, &bufev->ev_write);
+done:
+ BEV_UNLOCK(bufev);
+ return res;
+}
+
+static int
+be_socket_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
+ union bufferevent_ctrl_data *data)
+{
+ switch (op) {
+ case BEV_CTRL_SET_FD:
+ be_socket_setfd(bev, data->fd);
+ return 0;
+ case BEV_CTRL_GET_FD:
+ data->fd = event_get_fd(&bev->ev_read);
+ return 0;
+ case BEV_CTRL_GET_UNDERLYING:
+ case BEV_CTRL_CANCEL_ALL:
+ default:
+ return -1;
+ }
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/changelist-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/changelist-internal.h
new file mode 100644
index 000000000..98fc52aeb
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/changelist-internal.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef CHANGELIST_INTERNAL_H_INCLUDED_
+#define CHANGELIST_INTERNAL_H_INCLUDED_
+
+/*
+ A "changelist" is a list of all the fd status changes that should be made
+ between calls to the backend's dispatch function. There are a few reasons
+ that a backend would want to queue changes like this rather than processing
+ them immediately.
+
+ 1) Sometimes applications will add and delete the same event more than
+ once between calls to dispatch. Processing these changes immediately
+ is needless, and potentially expensive (especially if we're on a system
+ that makes one syscall per changed event).
+
+ 2) Sometimes we can coalesce multiple changes on the same fd into a single
+ syscall if we know about them in advance. For example, epoll can do an
+ add and a delete at the same time, but only if we have found out about
+ both of them before we tell epoll.
+
+ 3) Sometimes adding an event that we immediately delete can cause
+ unintended consequences: in kqueue, this makes pending events get
+ reported spuriously.
+ */
+
+#include "event2/util.h"
+
+/** Represents a */
+struct event_change {
+ /** The fd or signal whose events are to be changed */
+ evutil_socket_t fd;
+ /* The events that were enabled on the fd before any of these changes
+ were made. May include EV_READ or EV_WRITE. */
+ short old_events;
+
+ /* The changes that we want to make in reading and writing on this fd.
+ * If this is a signal, then read_change has EV_CHANGE_SIGNAL set,
+ * and write_change is unused. */
+ ev_uint8_t read_change;
+ ev_uint8_t write_change;
+ ev_uint8_t close_change;
+};
+
+/* Flags for read_change and write_change. */
+
+/* If set, add the event. */
+#define EV_CHANGE_ADD 0x01
+/* If set, delete the event. Exclusive with EV_CHANGE_ADD */
+#define EV_CHANGE_DEL 0x02
+/* If set, this event refers a signal, not an fd. */
+#define EV_CHANGE_SIGNAL EV_SIGNAL
+/* Set for persistent events. Currently not used. */
+#define EV_CHANGE_PERSIST EV_PERSIST
+/* Set for adding edge-triggered events. */
+#define EV_CHANGE_ET EV_ET
+
+/* The value of fdinfo_size that a backend should use if it is letting
+ * changelist handle its add and delete functions. */
+#define EVENT_CHANGELIST_FDINFO_SIZE sizeof(int)
+
+/** Set up the data fields in a changelist. */
+void event_changelist_init_(struct event_changelist *changelist);
+/** Remove every change in the changelist, and make corresponding changes
+ * in the event maps in the base. This function is generally used right
+ * after making all the changes in the changelist. */
+void event_changelist_remove_all_(struct event_changelist *changelist,
+ struct event_base *base);
+/** Free all memory held in a changelist. */
+void event_changelist_freemem_(struct event_changelist *changelist);
+
+/** Implementation of eventop_add that queues the event in a changelist. */
+int event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, short events,
+ void *p);
+/** Implementation of eventop_del that queues the event in a changelist. */
+int event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, short events,
+ void *p);
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/checkpatch.sh b/fluent-bit/lib/monkey/mk_core/deps/libevent/checkpatch.sh
new file mode 100755
index 000000000..6eaa19c46
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/checkpatch.sh
@@ -0,0 +1,299 @@
+#!/usr/bin/env bash
+
+# TODO:
+# - inline replace
+# - clang-format-diff replacement
+# - uncrustify for patches (not git refs)
+# - maybe integrate into travis-ci?
+
+function usage()
+{
+ cat <<EOL
+$0 [ OPTS ] [ file-or-gitref [ ... ] ]
+
+Example:
+ # Chech HEAD git ref
+ $ $0 -r
+ $ $0 -r HEAD
+
+ # Check patch
+ $ git format-patch --stdout -1 | $0 -p
+ $ git show -1 | $0 -p
+
+ # Or via regular files
+ $ git format-patch --stdout -2
+ $ $0 *.patch
+
+ # Over a file
+ $ $0 -d event.c
+ $ $0 -d < event.c
+
+ # And print the whole file not only summary
+ $ $0 -f event.c
+ $ $0 -f < event.c
+
+OPTS:
+ -p - treat as patch
+ -f - treat as regular file
+ -f - treat as regular file and print diff
+ -r - treat as git revision (default)
+ -C - check using clang-format (default)
+ -U - check with uncrustify
+ -c - config for clang-format/uncrustify
+ -h - print this message
+EOL
+}
+function cfg()
+{
+ [ -z "${options[cfg]}" ] || {
+ echo "${options[cfg]}"
+ return
+ }
+
+ local dir="$(dirname "${BASH_SOURCE[0]}")"
+ [ "${options[clang]}" -eq 0 ] || {
+ echo "$dir/.clang-format"
+ return
+ }
+ [ "${options[uncrustify]}" -eq 0 ] || {
+ echo "$dir/.uncrustify"
+ return
+ }
+}
+function abort()
+{
+ local msg="$1"
+ shift
+
+ printf "$msg\n" "$@" >&2
+ exit 1
+}
+function default_arg()
+{
+ if [ "${options[ref]}" -eq 1 ]; then
+ echo "HEAD"
+ else
+ [ ! -t 0 ] || abort "<stdin> is a tty"
+ echo "/dev/stdin"
+ fi
+}
+function parse_options()
+{
+ options[patch]=0
+ options[file]=0
+ options[file_diff]=0
+ options[ref]=1
+ options[clang]=1
+ options[uncrustify]=0
+ options[cfg]=
+
+ local OPTARG OPTIND c
+ while getopts "pfrdCUc:h?" c; do
+ case "$c" in
+ p)
+ options[patch]=1
+ options[ref]=0
+ options[file]=0
+ options[file_diff]=0
+ ;;
+ f)
+ options[file]=1
+ options[ref]=0
+ options[patch]=0
+ options[file_diff]=0
+ ;;
+ r)
+ options[ref]=1
+ options[file]=0
+ options[patch]=0
+ options[file_diff]=0
+ ;;
+ d)
+ options[file_diff]=1
+ options[file]=0
+ options[patch]=0
+ options[ref]=0
+ ;;
+ C)
+ options[clang]=1
+ options[uncrustify]=0
+ ;;
+ U)
+ options[uncrustify]=1
+ options[clang]=0
+ ;;
+ c) options[cfg]="$OPTIND" ;;
+ ?|h)
+ usage
+ exit 0
+ ;;
+ *)
+ usage
+ exit 1
+ ;;
+ esac
+ done
+
+ options[cfg]="$(cfg)"
+
+ [ -f "${options[cfg]}" ] || \
+ abort "Config '%s' does not exist" "${options[cfg]}"
+
+ shift $((OPTIND - 1))
+ args=( "$@" )
+
+ if [ ${#args[@]} -eq 0 ]; then
+ # exit on error globally, not only in subshell
+ default_arg > /dev/null
+ args=( "$(default_arg)" )
+ fi
+
+ if [ "${args[0]}" = "/dev/stdin" ]; then
+ TMP_FILE="/tmp/libevent.checkpatch.$RANDOM"
+ cat > "$TMP_FILE"
+ trap "rm '$TMP_FILE'" EXIT
+
+ args[0]="$TMP_FILE"
+ fi
+}
+
+function diff() { command diff --color=always "$@"; }
+
+function clang_style()
+{
+ local c="${options[cfg]}"
+ echo "{ $(sed -e 's/#.*//' -e '/---/d' -e '/\.\.\./d' "$c" | tr $'\n' ,) }"
+}
+function clang_format() { clang-format --style="$(clang_style)" "$@"; }
+function clang_format_diff() { clang-format-diff --style="$(clang_style)" "$@"; }
+# for non-bare repo will work
+function clang_format_git()
+{ git format-patch --stdout "$@" -1 | clang_format_diff; }
+
+function uncrustify() { command uncrustify -c "${options[cfg]}" "$@"; }
+function uncrustify_frag() { uncrustify -l C --frag "$@"; }
+function uncrustify_indent_off() { echo '/* *INDENT-OFF* */'; }
+function uncrustify_indent_on() { echo '/* *INDENT-ON* */'; }
+function git_hunk()
+{
+ local ref=$1 f=$2
+ shift 2
+ git cat-file -p $ref:$f
+}
+function uncrustify_git_indent_hunk()
+{
+ local start=$1 end=$2
+ shift 2
+
+ # Will be beatier with tee(1), but doh bash async substitution
+ { uncrustify_indent_off; git_hunk "$@" | head -n$((start - 1)); }
+ { uncrustify_indent_on; git_hunk "$@" | head -n$((end - 1)) | tail -n+$start; }
+ { uncrustify_indent_off; git_hunk "$@" | tail -n+$((end + 1)); }
+}
+function strip()
+{
+ local start=$1 end=$2
+ shift 2
+
+ # seek indent_{on,off}()
+ let start+=2
+ head -n$end | tail -n+$start
+}
+function patch_ranges()
+{
+ egrep -o '^@@ -[0-9]+(,[0-9]+|) \+[0-9]+(,[0-9]+|) @@' | \
+ cut -d' ' -f3
+}
+function git_ranges()
+{
+ local ref=$1 f=$2
+ shift 2
+
+ git diff -W $ref^..$ref -- $f | patch_ranges
+}
+function diff_substitute()
+{
+ local f="$1"
+ shift
+
+ sed \
+ -e "s#^--- /dev/fd.*\$#--- a/$f#" \
+ -e "s#^+++ /dev/fd.*\$#+++ b/$f#"
+}
+function uncrustify_git()
+{
+ local ref=$1 r f start end length
+ shift
+
+ local files=( $(git diff --name-only $ref^..$ref | egrep "\.(c|h)$") )
+ for f in "${files[@]}"; do
+ local ranges=( $(git_ranges $ref "$f") )
+ for r in "${ranges[@]}"; do
+ [[ ! "$r" =~ ^\+([0-9]+)(,([0-9]+)|)$ ]] && continue
+ start=${BASH_REMATCH[1]}
+ [ -n "${BASH_REMATCH[3]}" ] && \
+ length=${BASH_REMATCH[3]} || \
+ length=1
+ end=$((start + length))
+ echo "Range: $start:$end ($length)" >&2
+
+ diff -u \
+ <(uncrustify_git_indent_hunk $start $end $ref "$f" | strip $start $end) \
+ <(uncrustify_git_indent_hunk $start $end $ref "$f" | uncrustify_frag | strip $start $end) \
+ | diff_substitute "$f"
+ done
+ done
+}
+function uncrustify_diff() { abort "Not implemented"; }
+function uncrustify_file() { uncrustify -f "$@"; }
+
+function checker()
+{
+ local c=$1 u=$2
+ shift 2
+
+ [ "${options[clang]}" -eq 0 ] || {
+ $c "$@"
+ return
+ }
+ [ "${options[uncrustify]}" -eq 0 ] || {
+ $u "$@"
+ return
+ }
+}
+function check_patch() { checker clang_format_diff uncrustify_diff "$@"; }
+function check_file() { checker clang_format uncrustify_file "$@"; }
+function check_ref() { checker clang_format_git uncrustify_git "$@"; }
+
+function check_arg()
+{
+ [ "${options[patch]}" -eq 0 ] || {
+ check_patch "$@"
+ return
+ }
+ [ "${options[file]}" -eq 0 ] || {
+ check_file "$@"
+ return
+ }
+ [ "${options[file_diff]}" -eq 0 ] || {
+ diff -u "$@" <(check_file "$@") | diff_substitute "$@"
+ return
+ }
+ [ "${options[ref]}" -eq 0 ] || {
+ check_ref "$@"
+ return
+ }
+}
+
+function main()
+{
+ local a
+ for a in "${args}"; do
+ check_arg "$a"
+ done
+}
+
+declare -A options
+parse_options "$@"
+
+main "$@" | less -FRSX
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/AddCompilerFlags.cmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/AddCompilerFlags.cmake
new file mode 100644
index 000000000..9dc21d03a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/AddCompilerFlags.cmake
@@ -0,0 +1,13 @@
+include(CheckCCompilerFlag)
+
+macro(add_compiler_flags)
+ foreach(flag ${ARGN})
+ string(REGEX REPLACE "[-.+/:= ]" "_" _flag_esc "${flag}")
+
+ check_c_compiler_flag("${flag}" check_c_compiler_flag_${_flag_esc})
+
+ if (check_c_compiler_flag_${_flag_esc})
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}")
+ endif()
+ endforeach()
+endmacro()
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/COPYING-CMAKE-SCRIPTS b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/COPYING-CMAKE-SCRIPTS
new file mode 100644
index 000000000..ab3c4d25d
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/COPYING-CMAKE-SCRIPTS
@@ -0,0 +1,22 @@
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFileOffsetBits.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFileOffsetBits.c
new file mode 100644
index 000000000..d948fecf2
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFileOffsetBits.c
@@ -0,0 +1,14 @@
+#include <sys/types.h>
+
+#define KB ((off_t)1024)
+#define MB ((off_t)1024 * KB)
+#define GB ((off_t)1024 * MB)
+#define TB ((off_t)1024 * GB)
+int t2[(((64 * GB -1) % 671088649) == 268434537)
+ && (((TB - (64 * GB -1) + 255) % 1792151290) == 305159546)? 1: -1];
+
+int main()
+{
+ ;
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFileOffsetBits.cmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFileOffsetBits.cmake
new file mode 100644
index 000000000..125344016
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFileOffsetBits.cmake
@@ -0,0 +1,43 @@
+# - Check if _FILE_OFFSET_BITS macro needed for large files
+# CHECK_FILE_OFFSET_BITS ()
+#
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+# CMAKE_REQUIRED_FLAGS = string of compile command line flags
+# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+# CMAKE_REQUIRED_INCLUDES = list of include directories
+# Copyright (c) 2009, Michihiro NAKAJIMA
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+#INCLUDE(CheckCSourceCompiles)
+
+GET_FILENAME_COMPONENT(_selfdir_CheckFileOffsetBits
+ "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+MACRO (CHECK_FILE_OFFSET_BITS)
+ IF(NOT DEFINED _FILE_OFFSET_BITS)
+ MESSAGE(STATUS "Cheking _FILE_OFFSET_BITS for large files")
+ TRY_COMPILE(__WITHOUT_FILE_OFFSET_BITS_64
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${_selfdir_CheckFileOffsetBits}/CheckFileOffsetBits.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS})
+ IF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
+ TRY_COMPILE(__WITH_FILE_OFFSET_BITS_64
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${_selfdir_CheckFileOffsetBits}/CheckFileOffsetBits.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_FILE_OFFSET_BITS=64)
+ ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
+
+ IF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
+ SET(_FILE_OFFSET_BITS 64 CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files")
+ MESSAGE(STATUS "Cheking _FILE_OFFSET_BITS for large files - needed")
+ ELSE(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
+ SET(_FILE_OFFSET_BITS "" CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files")
+ MESSAGE(STATUS "Cheking _FILE_OFFSET_BITS for large files - not needed")
+ ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
+ ENDIF(NOT DEFINED _FILE_OFFSET_BITS)
+
+ENDMACRO (CHECK_FILE_OFFSET_BITS)
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFunctionExistsEx.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFunctionExistsEx.c
new file mode 100644
index 000000000..5ee3e5913
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFunctionExistsEx.c
@@ -0,0 +1,30 @@
+#ifdef CHECK_FUNCTION_EXISTS
+
+#ifndef _WIN32
+char CHECK_FUNCTION_EXISTS();
+#endif
+
+#ifdef __CLASSIC_C__
+int main(){
+ int ac;
+ char*av[];
+#else
+int main(int ac, char*av[]){
+#endif
+#ifdef _WIN32
+ void * p = &CHECK_FUNCTION_EXISTS;
+#else
+ CHECK_FUNCTION_EXISTS();
+#endif
+ if(ac > 1000)
+ {
+ return *av[0];
+ }
+ return 0;
+}
+
+#else /* CHECK_FUNCTION_EXISTS */
+
+# error "CHECK_FUNCTION_EXISTS has to specify the function"
+
+#endif /* CHECK_FUNCTION_EXISTS */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFunctionExistsEx.cmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFunctionExistsEx.cmake
new file mode 100644
index 000000000..78bc2ecc1
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFunctionExistsEx.cmake
@@ -0,0 +1,69 @@
+# - Check if a C function can be linked
+# CHECK_FUNCTION_EXISTS(<function> <variable>)
+#
+# Check that the <function> is provided by libraries on the system and
+# store the result in a <variable>. This does not verify that any
+# system header file declares the function, only that it can be found
+# at link time (considure using CheckSymbolExists).
+#
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+# CMAKE_REQUIRED_FLAGS = string of compile command line flags
+# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+# CMAKE_REQUIRED_INCLUDES = list of include directories
+# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+#=============================================================================
+# Copyright 2002-2011 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+MACRO(CHECK_FUNCTION_EXISTS_EX FUNCTION VARIABLE)
+ IF(${VARIABLE} MATCHES "^${VARIABLE}$")
+ SET(MACRO_CHECK_FUNCTION_DEFINITIONS
+ "-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}")
+ MESSAGE(STATUS "Looking for ${FUNCTION}")
+ IF(CMAKE_REQUIRED_LIBRARIES)
+ SET(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES
+ "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
+ ELSE(CMAKE_REQUIRED_LIBRARIES)
+ SET(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES)
+ ENDIF(CMAKE_REQUIRED_LIBRARIES)
+ IF(CMAKE_REQUIRED_INCLUDES)
+ SET(CHECK_FUNCTION_EXISTS_ADD_INCLUDES
+ "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+ ELSE(CMAKE_REQUIRED_INCLUDES)
+ SET(CHECK_FUNCTION_EXISTS_ADD_INCLUDES)
+ ENDIF(CMAKE_REQUIRED_INCLUDES)
+ TRY_COMPILE(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${PROJECT_SOURCE_DIR}/cmake/CheckFunctionExistsEx.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+ "${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES}"
+ "${CHECK_FUNCTION_EXISTS_ADD_INCLUDES}"
+ OUTPUT_VARIABLE OUTPUT)
+ IF(${VARIABLE})
+ SET(${VARIABLE} 1 CACHE INTERNAL "Have function ${FUNCTION}")
+ MESSAGE(STATUS "Looking for ${FUNCTION} - found")
+ FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the function ${FUNCTION} exists passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ ELSE(${VARIABLE})
+ MESSAGE(STATUS "Looking for ${FUNCTION} - not found")
+ SET(${VARIABLE} "" CACHE INTERNAL "Have function ${FUNCTION}")
+ FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the function ${FUNCTION} exists failed with the following output:\n"
+ "${OUTPUT}\n\n")
+ ENDIF(${VARIABLE})
+ ENDIF()
+ENDMACRO(CHECK_FUNCTION_EXISTS_EX)
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFunctionKeywords.cmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFunctionKeywords.cmake
new file mode 100644
index 000000000..3d968b8a6
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckFunctionKeywords.cmake
@@ -0,0 +1,14 @@
+include(CheckCSourceCompiles)
+
+macro(check_function_keywords _wordlist)
+ set(${_result} "")
+ foreach(flag ${_wordlist})
+ string(REGEX REPLACE "[-+/ ()]" "_" flagname "${flag}")
+ string(TOUPPER "${flagname}" flagname)
+ set(have_flag "HAVE_${flagname}")
+ check_c_source_compiles("${flag} void func(); void func() { } int main() { func(); return 0; }" ${have_flag})
+ if(${have_flag} AND NOT ${_result})
+ set(${_result} "${flag}")
+ endif(${have_flag} AND NOT ${_result})
+ endforeach(flag)
+endmacro(check_function_keywords)
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckPrototypeDefinition.c.in b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckPrototypeDefinition.c.in
new file mode 100644
index 000000000..a97344ac3
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckPrototypeDefinition.c.in
@@ -0,0 +1,29 @@
+@CHECK_PROTOTYPE_DEFINITION_HEADER@
+
+static void cmakeRequireSymbol(int dummy, ...) {
+ (void) dummy;
+}
+
+static void checkSymbol(void) {
+#ifndef @CHECK_PROTOTYPE_DEFINITION_SYMBOL@
+ cmakeRequireSymbol(0, &@CHECK_PROTOTYPE_DEFINITION_SYMBOL@);
+#endif
+}
+
+@CHECK_PROTOTYPE_DEFINITION_PROTO@ {
+ return @CHECK_PROTOTYPE_DEFINITION_RETURN@;
+}
+
+#ifdef __CLASSIC_C__
+int main() {
+ int ac;
+ char*av[];
+#else
+int main(int ac, char *av[]) {
+#endif
+ checkSymbol();
+ if (ac > 1000) {
+ return *av[0];
+ }
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckPrototypeDefinition.cmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckPrototypeDefinition.cmake
new file mode 100644
index 000000000..940d1ff0c
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckPrototypeDefinition.cmake
@@ -0,0 +1,82 @@
+# - Check if the protoype we expect is correct.
+# check_prototype_definition(FUNCTION PROTOTYPE RETURN HEADER VARIABLE)
+#
+# FUNCTION - The name of the function (used to check if prototype exists)
+# PROTOTYPE- The prototype to check.
+# RETURN - The return value of the function.
+# HEADER - The header files required.
+# VARIABLE - The variable to store the result.
+#
+# Example:
+#
+# check_prototype_definition(getpwent_r
+# "struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)"
+# "NULL"
+# "unistd.h;pwd.h"
+# SOLARIS_GETPWENT_R)
+#
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+# CMAKE_REQUIRED_FLAGS = string of compile command line flags
+# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+# CMAKE_REQUIRED_INCLUDES = list of include directories
+# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+
+function(CHECK_PROTOTYPE_DEFINITION _FUNCTION _PROTOTYPE _RETURN _HEADER _VARIABLE)
+ if (${_VARIABLE} MATCHES "^${_VARIABLE}$")
+ set(CHECK_PROTOTYPE_DEFINITION_CONTENT "/* */\n")
+
+ set(CHECK_PROTOTYPE_DEFINITION_FLAGS ${CMAKE_REQUIRED_FLAGS})
+ if (CMAKE_REQUIRED_LIBRARIES)
+ set(CHECK_PROTOTYPE_DEFINITION_LIBS
+ "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
+ else(CMAKE_REQUIRED_LIBRARIES)
+ set(CHECK_PROTOTYPE_DEFINITION_LIBS)
+ endif(CMAKE_REQUIRED_LIBRARIES)
+ if (CMAKE_REQUIRED_INCLUDES)
+ set(CMAKE_SYMBOL_EXISTS_INCLUDES
+ "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+ else(CMAKE_REQUIRED_INCLUDES)
+ set(CMAKE_SYMBOL_EXISTS_INCLUDES)
+ endif(CMAKE_REQUIRED_INCLUDES)
+
+ foreach(_FILE ${_HEADER})
+ set(CHECK_PROTOTYPE_DEFINITION_HEADER
+ "${CHECK_PROTOTYPE_DEFINITION_HEADER}#include <${_FILE}>\n")
+ endforeach(_FILE)
+
+ set(CHECK_PROTOTYPE_DEFINITION_SYMBOL ${_FUNCTION})
+ set(CHECK_PROTOTYPE_DEFINITION_PROTO ${_PROTOTYPE})
+ set(CHECK_PROTOTYPE_DEFINITION_RETURN ${_RETURN})
+
+ configure_file("${PROJECT_SOURCE_DIR}/cmake/CheckPrototypeDefinition.c.in"
+ "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c" @ONLY)
+
+ file(READ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c _SOURCE)
+
+ try_compile(${_VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${CHECK_PROTOTYPE_DEFINITION_FLAGS}
+ "${CHECK_PROTOTYPE_DEFINITION_LIBS}"
+ "${CMAKE_SYMBOL_EXISTS_INCLUDES}"
+ OUTPUT_VARIABLE OUTPUT)
+
+ if (${_VARIABLE})
+ set(${_VARIABLE} 1 CACHE INTERNAL "Have correct prototype for ${_FUNCTION}")
+ message(STATUS "Checking prototype ${_FUNCTION} for ${_VARIABLE} - True")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the prototype ${_FUNCTION} exists for ${_VARIABLE} passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ else (${_VARIABLE})
+ message(STATUS "Checking prototype ${_FUNCTION} for ${_VARIABLE} - False")
+ set(${_VARIABLE} 0 CACHE INTERNAL "Have correct prototype for ${_FUNCTION}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the prototype ${_FUNCTION} exists for ${_VARIABLE} failed with the following output:\n"
+ "${OUTPUT}\n\n${_SOURCE}\n\n")
+ endif (${_VARIABLE})
+ endif()
+endfunction(CHECK_PROTOTYPE_DEFINITION)
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckWaitpidSupportWNOWAIT.cmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckWaitpidSupportWNOWAIT.cmake
new file mode 100644
index 000000000..1a73db37b
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckWaitpidSupportWNOWAIT.cmake
@@ -0,0 +1,18 @@
+include(CheckCSourceRuns)
+
+check_c_source_runs(
+"
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+
+int
+main(int argc, char** argv)
+{
+ pid_t pid;
+ int status;
+ if ((pid = fork()) == 0) _exit(0);
+ _exit(waitpid(pid, &status, WNOWAIT) == -1);
+}"
+EVENT__HAVE_WAITPID_WITH_WNOWAIT)
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckWorkingKqueue.cmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckWorkingKqueue.cmake
new file mode 100644
index 000000000..47bf4e838
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CheckWorkingKqueue.cmake
@@ -0,0 +1,52 @@
+include(CheckCSourceRuns)
+
+check_c_source_runs(
+"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/event.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int
+main(int argc, char **argv)
+{
+ int kq;
+ int n;
+ int fd[2];
+ struct kevent ev;
+ struct timespec ts;
+ char buf[8000];
+
+ if (pipe(fd) == -1)
+ exit(1);
+ if (fcntl(fd[1], F_SETFL, O_NONBLOCK) == -1)
+ exit(1);
+
+ while ((n = write(fd[1], buf, sizeof(buf))) == sizeof(buf))
+ ;
+
+ if ((kq = kqueue()) == -1)
+ exit(1);
+
+ memset(&ev, 0, sizeof(ev));
+ ev.ident = fd[1];
+ ev.filter = EVFILT_WRITE;
+ ev.flags = EV_ADD | EV_ENABLE;
+ n = kevent(kq, &ev, 1, NULL, 0, NULL);
+ if (n == -1)
+ exit(1);
+
+ read(fd[0], buf, sizeof(buf));
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ n = kevent(kq, NULL, 0, &ev, 1, &ts);
+ if (n == -1 || n == 0)
+ exit(1);
+
+ exit(0);
+}
+
+" EVENT__HAVE_WORKING_KQUEUE) \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CodeCoverage.cmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CodeCoverage.cmake
new file mode 100644
index 000000000..eba85b3fb
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/CodeCoverage.cmake
@@ -0,0 +1,165 @@
+#
+# Boost Software License - Version 1.0 - August 17th, 2003
+#
+# Permission is hereby granted, free of charge, to any person or organization
+# obtaining a copy of the software and accompanying documentation covered by
+# this license (the "Software") to use, reproduce, display, distribute,
+# execute, and transmit the Software, and to prepare derivative works of the
+# Software, and to permit third-parties to whom the Software is furnished to
+# do so, all subject to the following:
+#
+# The copyright notices in the Software and this entire statement, including
+# the above license grant, this restriction and the following disclaimer,
+# must be included in all copies of the Software, in whole or in part, and
+# all derivative works of the Software, unless such copies or derivative
+# works are solely in the form of machine-executable object code generated by
+# a source language processor.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+# SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+# FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+# 2012-01-31, Lars Bilke
+# - Enable Code Coverage
+#
+# 2013-09-17, Joakim Söderberg
+# - Added support for Clang.
+# - Some additional usage instructions.
+#
+# 2016-11-02, Azat Khuzhin
+# - Adopt for C compiler only (libevent)
+#
+# USAGE:
+# 1. Copy this file into your cmake modules path.
+#
+# 2. Add the following line to your CMakeLists.txt:
+# INCLUDE(CodeCoverage)
+#
+# 3. Set compiler flags to turn off optimization and enable coverage:
+# SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
+# SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
+#
+# 3. Use the function SETUP_TARGET_FOR_COVERAGE to create a custom make target
+# which runs your test executable and produces a lcov code coverage report:
+# Example:
+# SETUP_TARGET_FOR_COVERAGE(
+# my_coverage_target # Name for custom target.
+# test_driver # Name of the test driver executable that runs the tests.
+# # NOTE! This should always have a ZERO as exit code
+# # otherwise the coverage generation will not complete.
+# coverage # Name of output directory.
+# )
+#
+# 4. Build a Debug build:
+# cmake -DCMAKE_BUILD_TYPE=Debug ..
+# make
+# make my_coverage_target
+#
+#
+
+# Check prereqs
+FIND_PROGRAM( GCOV_PATH gcov )
+FIND_PROGRAM( LCOV_PATH lcov )
+FIND_PROGRAM( GENHTML_PATH genhtml )
+FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests)
+
+IF(NOT GCOV_PATH)
+ MESSAGE(FATAL_ERROR "gcov not found! Aborting...")
+ENDIF() # NOT GCOV_PATH
+
+IF(NOT CMAKE_COMPILER_IS_GNUCC)
+ # Clang version 3.0.0 and greater now supports gcov as well.
+ MESSAGE(WARNING "Compiler is not GNU gcc! Clang Version 3.0.0 and greater supports gcov as well, but older versions don't.")
+
+ IF(NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
+ MESSAGE(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
+ ENDIF()
+ENDIF() # NOT CMAKE_COMPILER_IS_GNUCC
+
+IF ( NOT CMAKE_BUILD_TYPE STREQUAL "Debug" )
+ MESSAGE( WARNING "Code coverage results with an optimized (non-Debug) build may be misleading" )
+ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
+
+
+# Param _targetname The name of new the custom make target
+# Param _testrunner The name of the target which runs the tests.
+# MUST return ZERO always, even on errors.
+# If not, no coverage report will be created!
+# Param _outputname lcov output is generated as _outputname.info
+# HTML report is generated in _outputname/index.html
+# Optional fourth parameter is passed as arguments to _testrunner
+# Pass them in list form, e.g.: "-j;2" for -j 2
+FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _testrunner _outputname)
+
+ IF(NOT LCOV_PATH)
+ MESSAGE(FATAL_ERROR "lcov not found! Aborting...")
+ ENDIF() # NOT LCOV_PATH
+
+ IF(NOT GENHTML_PATH)
+ MESSAGE(FATAL_ERROR "genhtml not found! Aborting...")
+ ENDIF() # NOT GENHTML_PATH
+
+ # Setup target
+ ADD_CUSTOM_TARGET(${_targetname}
+
+ # Cleanup lcov
+ ${LCOV_PATH} --directory . --zerocounters
+
+ # Run tests
+ COMMAND ${_testrunner} ${ARGV3}
+
+ # Capturing lcov counters and generating report
+ COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info
+ COMMAND ${LCOV_PATH} --remove ${_outputname}.info 'tests/*' '/usr/*' --output-file ${_outputname}.info.cleaned
+ COMMAND ${GENHTML_PATH} -o ${_outputname} ${_outputname}.info.cleaned
+ COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned
+
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+ COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
+ )
+
+ # Show info where to find the report
+ ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD
+ COMMAND ;
+ COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report."
+ )
+
+ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE
+
+# Param _targetname The name of new the custom make target
+# Param _testrunner The name of the target which runs the tests
+# Param _outputname cobertura output is generated as _outputname.xml
+# Optional fourth parameter is passed as arguments to _testrunner
+# Pass them in list form, e.g.: "-j;2" for -j 2
+FUNCTION(SETUP_TARGET_FOR_COVERAGE_COBERTURA _targetname _testrunner _outputname)
+
+ IF(NOT PYTHON_EXECUTABLE)
+ MESSAGE(FATAL_ERROR "Python not found! Aborting...")
+ ENDIF() # NOT PYTHON_EXECUTABLE
+
+ IF(NOT GCOVR_PATH)
+ MESSAGE(FATAL_ERROR "gcovr not found! Aborting...")
+ ENDIF() # NOT GCOVR_PATH
+
+ ADD_CUSTOM_TARGET(${_targetname}
+
+ # Run tests
+ ${_testrunner} ${ARGV3}
+
+ # Running gcovr
+ COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} -e '${CMAKE_SOURCE_DIR}/tests/' -o ${_outputname}.xml
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+ COMMENT "Running gcovr to produce Cobertura code coverage report."
+ )
+
+ # Show info where to find the report
+ ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD
+ COMMAND ;
+ COMMENT "Cobertura code coverage report saved in ${_outputname}.xml."
+ )
+
+ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE_COBERTURA
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/Copyright.txt b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/Copyright.txt
new file mode 100644
index 000000000..813124f02
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/Copyright.txt
@@ -0,0 +1,57 @@
+CMake - Cross Platform Makefile Generator
+Copyright 2000-2013 Kitware, Inc.
+Copyright 2000-2011 Insight Software Consortium
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the names of Kitware, Inc., the Insight Software Consortium,
+ nor the names of their contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+------------------------------------------------------------------------------
+
+The above copyright and license notice applies to distributions of
+CMake in source and binary form. Some source files contain additional
+notices of original copyright by their contributors; see each source
+for details. Third-party software packages supplied with CMake under
+compatible licenses provide their own copyright notices documented in
+corresponding subdirectories.
+
+------------------------------------------------------------------------------
+
+CMake was initially developed by Kitware with the following sponsorship:
+
+ * National Library of Medicine at the National Institutes of Health
+ as part of the Insight Segmentation and Registration Toolkit (ITK).
+
+ * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
+ Visualization Initiative.
+
+ * National Alliance for Medical Image Computing (NAMIC) is funded by the
+ National Institutes of Health through the NIH Roadmap for Medical Research,
+ Grant U54 EB005149.
+
+ * Kitware, Inc. \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/FindGit.cmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/FindGit.cmake
new file mode 100644
index 000000000..2abbfe4e9
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/FindGit.cmake
@@ -0,0 +1,45 @@
+# The module defines the following variables:
+# GIT_EXECUTABLE - path to git command line client
+# GIT_FOUND - true if the command line client was found
+# Example usage:
+# find_package(Git)
+# if(GIT_FOUND)
+# message("git found: ${GIT_EXECUTABLE}")
+# endif()
+
+#=============================================================================
+# Copyright 2010 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distributed this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+# Look for 'git' or 'eg' (easy git)
+set(git_names git eg)
+
+# Prefer .cmd variants on Windows unless running in a Makefile
+# in the MSYS shell.
+if(WIN32)
+ if(NOT CMAKE_GENERATOR MATCHES "MSYS")
+ set(git_names git.cmd git eg.cmd eg)
+ endif()
+endif()
+
+find_program(GIT_EXECUTABLE
+ NAMES ${git_names}
+ DOC "git command line client")
+
+mark_as_advanced(GIT_EXECUTABLE)
+
+# Handle the QUIETLY and REQUIRED arguments and set GIT_FOUND to TRUE if
+# all listed variables are TRUE
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Git DEFAULT_MSG GIT_EXECUTABLE)
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/LibeventConfig.cmake.in b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/LibeventConfig.cmake.in
new file mode 100644
index 000000000..b28cacb5f
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/LibeventConfig.cmake.in
@@ -0,0 +1,17 @@
+# - Config file for the Libevent package
+# It defines the following variables
+# LIBEVENT_INCLUDE_DIRS - include directories for FooBar
+# LIBEVENT_LIBRARIES - libraries to link against
+
+# Get the path of the current file.
+get_filename_component(LIBEVENT_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+# Set the include directories.
+set(LIBEVENT_INCLUDE_DIRS "@EVENT_INSTALL_INCLUDE_DIR@")
+
+# Include the project Targets file, this contains definitions for IMPORTED targets.
+include(${LIBEVENT_CMAKE_DIR}/LibeventTargets.cmake)
+
+# IMPORTED targets from LibeventTargets.cmake
+set(LIBEVENT_LIBRARIES event event_core event_extra)
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/LibeventConfigBuildTree.cmake.in b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/LibeventConfigBuildTree.cmake.in
new file mode 100644
index 000000000..02edef32f
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/LibeventConfigBuildTree.cmake.in
@@ -0,0 +1,17 @@
+# - Config file for the Libevent package
+# It defines the following variables
+# LIBEVENT_INCLUDE_DIRS - include directories for FooBar
+# LIBEVENT_LIBRARIES - libraries to link against
+
+# Get the path of the current file.
+get_filename_component(LIBEVENT_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+# Set the include directories.
+set(LIBEVENT_INCLUDE_DIRS "@EVENT__INCLUDE_DIRS@")
+
+# Include the project Targets file, this contains definitions for IMPORTED targets.
+include(${LIBEVENT_CMAKE_DIR}/LibeventTargets.cmake)
+
+# IMPORTED targets from LibeventTargets.cmake
+set(LIBEVENT_LIBRARIES event event_core event_extra)
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/LibeventConfigVersion.cmake.in b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/LibeventConfigVersion.cmake.in
new file mode 100644
index 000000000..56371a8fe
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/LibeventConfigVersion.cmake.in
@@ -0,0 +1,11 @@
+set(PACKAGE_VERSION "@EVENT_PACKAGE_VERSION@")
+
+# Check whether the requested PACKAGE_FIND_VERSION is compatible
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/VersionViaGit.cmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/VersionViaGit.cmake
new file mode 100644
index 000000000..aedf16571
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/cmake/VersionViaGit.cmake
@@ -0,0 +1,66 @@
+# This module defines the following variables utilizing
+# git to determine the parent tag. And if found the macro
+# will attempt to parse them in the github tag fomat
+#
+# Useful for auto-versioning in our CMakeLists
+#
+# EVENT_GIT___VERSION_MAJOR - Major version.
+# EVENT_GIT___VERSION_MINOR - Minor version
+# EVENT_GIT___VERSION_STAGE - Stage version
+#
+# Example usage:
+#
+# event_fuzzy_version_from_git()
+# message("Libvent major=${EVENT_GIT___VERSION_MAJOR}")
+# message(" minor=${EVENT_GIT___VERSION_MINOR}")
+# message(" patch=${EVENT_GIT___VERSION_PATCH}")
+# message(" stage=${EVENT_GIT___VERSION_STAGE}")
+# endif()
+
+include(FindGit)
+
+macro(event_fuzzy_version_from_git)
+ # set our defaults.
+ set(EVENT_GIT___VERSION_MAJOR 2)
+ set(EVENT_GIT___VERSION_MINOR 2)
+ set(EVENT_GIT___VERSION_PATCH 0)
+ set(EVENT_GIT___VERSION_STAGE "alpha-dev")
+
+ find_package(Git)
+
+ if (GIT_FOUND)
+ execute_process(
+ COMMAND
+ ${GIT_EXECUTABLE} describe --abbrev=0 --always
+ WORKING_DIRECTORY
+ ${PROJECT_SOURCE_DIR}
+ RESULT_VARIABLE
+ GITRET
+ OUTPUT_VARIABLE
+ GITVERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+ string(REGEX REPLACE "[\\._-]" ";" VERSION_LIST "${GITVERSION}")
+ if(VERSION_LIST)
+ list(LENGTH VERSION_LIST VERSION_LIST_LENGTH)
+ endif()
+
+ if ((GITRET EQUAL 0) AND (VERSION_LIST_LENGTH EQUAL 5))
+ list(GET VERSION_LIST 1 _MAJOR)
+ list(GET VERSION_LIST 2 _MINOR)
+ list(GET VERSION_LIST 3 _PATCH)
+ list(GET VERSION_LIST 4 _STAGE)
+
+ set(_DEFAULT_VERSION "${EVENT_GIT___VERSION_MAJOR}.${EVENT_GIT___VERSION_MINOR}.${EVENT_GIT___VERSION_PATCH}-${EVENT_GIT___VERSION_STAGE}")
+ set(_GIT_VERSION "${_MAJOR}.${_MINOR}.${_PATCH}-${_STAGE}")
+
+ if (${_DEFAULT_VERSION} VERSION_LESS ${_GIT_VERSION})
+ set(EVENT_GIT___VERSION_MAJOR ${_MAJOR})
+ set(EVENT_GIT___VERSION_MINOR ${_MINOR})
+ set(EVENT_GIT___VERSION_PATCH ${_PATCH})
+ set(EVENT_GIT___VERSION_STAGE ${_STAGE})
+ endif()
+ endif()
+ endif()
+endmacro()
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/compat/sys/queue.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/compat/sys/queue.h
new file mode 100644
index 000000000..c387bdcf5
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/compat/sys/queue.h
@@ -0,0 +1,488 @@
+/* $OpenBSD: queue.h,v 1.16 2000/09/07 19:47:59 art Exp $ */
+/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef SYS_QUEUE_H__
+#define SYS_QUEUE_H__
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#ifndef _WIN32
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+#endif
+
+/*
+ * Singly-linked List access methods.
+ */
+#define SLIST_FIRST(head) ((head)->slh_first)
+#define SLIST_END(head) NULL
+#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for((var) = SLIST_FIRST(head); \
+ (var) != SLIST_END(head); \
+ (var) = SLIST_NEXT(var, field))
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_INIT(head) { \
+ SLIST_FIRST(head) = SLIST_END(head); \
+}
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
+ (slistelm)->field.sle_next = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.sle_next = (head)->slh_first; \
+ (head)->slh_first = (elm); \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ (head)->slh_first = (head)->slh_first->field.sle_next; \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List access methods
+ */
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_END(head) NULL
+#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field) \
+ for((var) = LIST_FIRST(head); \
+ (var)!= LIST_END(head); \
+ (var) = LIST_NEXT(var, field))
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) do { \
+ LIST_FIRST(head) = LIST_END(head); \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do { \
+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
+ (elm2)->field.le_next->field.le_prev = \
+ &(elm2)->field.le_next; \
+ (elm2)->field.le_prev = (elm)->field.le_prev; \
+ *(elm2)->field.le_prev = (elm2); \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqe_next; /* next element */ \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for((var) = SIMPLEQ_FIRST(head); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = SIMPLEQ_NEXT(var, field))
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \
+ if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * tail queue access methods
+ */
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) NULL
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define TAILQ_EMPTY(head) \
+ (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field) \
+ for((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_PREV(var, headname, field))
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
+ (elm2)->field.tqe_next->field.tqe_prev = \
+ &(elm2)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm2)->field.tqe_next; \
+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
+ *(elm2)->field.tqe_prev = (elm2); \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head) \
+ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+/*
+ * Circular queue access methods
+ */
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+#define CIRCLEQ_END(head) ((void *)(head))
+#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
+#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
+#define CIRCLEQ_EMPTY(head) \
+ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
+
+#define CIRCLEQ_FOREACH(var, head, field) \
+ for((var) = CIRCLEQ_FIRST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_NEXT(var, field))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
+ for((var) = CIRCLEQ_LAST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_PREV(var, field))
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_INIT(head) do { \
+ (head)->cqh_first = CIRCLEQ_END(head); \
+ (head)->cqh_last = CIRCLEQ_END(head); \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
+ (elm)->field.cqe_prev = (listelm); \
+ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
+ (listelm)->field.cqe_next = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm); \
+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
+ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
+ (listelm)->field.cqe_prev = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.cqe_next = (head)->cqh_first; \
+ (elm)->field.cqe_prev = CIRCLEQ_END(head); \
+ if ((head)->cqh_last == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (head)->cqh_first->field.cqe_prev = (elm); \
+ (head)->cqh_first = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.cqe_next = CIRCLEQ_END(head); \
+ (elm)->field.cqe_prev = (head)->cqh_last; \
+ if ((head)->cqh_first == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (head)->cqh_last->field.cqe_next = (elm); \
+ (head)->cqh_last = (elm); \
+} while (0)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do { \
+ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm)->field.cqe_prev; \
+ else \
+ (elm)->field.cqe_next->field.cqe_prev = \
+ (elm)->field.cqe_prev; \
+ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm)->field.cqe_next; \
+ else \
+ (elm)->field.cqe_prev->field.cqe_next = \
+ (elm)->field.cqe_next; \
+} while (0)
+
+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
+ CIRCLEQ_END(head)) \
+ (head).cqh_last = (elm2); \
+ else \
+ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
+ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
+ CIRCLEQ_END(head)) \
+ (head).cqh_first = (elm2); \
+ else \
+ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
+} while (0)
+
+#endif /* !SYS_QUEUE_H__ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/configure.ac b/fluent-bit/lib/monkey/mk_core/deps/libevent/configure.ac
new file mode 100644
index 000000000..78a4edcc7
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/configure.ac
@@ -0,0 +1,958 @@
+dnl Copyright 2000-2007 Niels Provos
+dnl Copyright 2007-2012 Niels Provos and Nick Mathewson
+dnl
+dnl See LICENSE for copying information.
+dnl
+dnl Original version Dug Song <dugsong@monkey.org>
+
+AC_INIT(libevent,2.1.7-beta)
+AC_PREREQ(2.59)
+AC_CONFIG_SRCDIR(event.c)
+
+AC_CONFIG_MACRO_DIR([m4])
+
+# 'foreign' means that we're not enforcing GNU package rules strictly.
+# '1.9' means that we need automake 1.9 or later (and we do).
+# serial-tests means that we don't need parallel test harness
+AM_INIT_AUTOMAKE(m4_esyscmd([echo foreign 1.9 subdir-objects
+ case `automake --version | head -n 1` in
+ *1.9*);;
+ *1.10*);;
+ *1.11*);;
+ *) echo serial-tests;;
+ esac]))
+
+dnl AM_SILENT_RULES req. automake 1.11. [no] defaults V=1
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+AC_CONFIG_HEADERS(config.h evconfig-private.h:evconfig-private.h.in)
+AC_DEFINE(NUMERIC_VERSION, 0x02010700, [Numeric representation of the version])
+
+dnl Initialize prefix.
+if test "$prefix" = "NONE"; then
+ prefix="/usr/local"
+fi
+
+dnl Try and get a full POSIX environment on obscure systems
+ifdef([AC_USE_SYSTEM_EXTENSIONS], [
+AC_USE_SYSTEM_EXTENSIONS
+], [
+AC_AIX
+AC_GNU_SOURCE
+AC_MINIX
+])
+
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+dnl the 'build' machine is where we run configure and compile
+dnl the 'host' machine is where the resulting stuff runs.
+
+#case "$host_os" in
+#
+# osf5*)
+# CFLAGS="$CFLAGS -D_OSF_SOURCE"
+# ;;
+#esac
+
+dnl Checks for programs.
+AM_PROG_CC_C_O
+AC_PROG_INSTALL
+AC_PROG_LN_S
+# AC_PROG_MKDIR_P - $(MKDIR_P) should be defined by AM_INIT_AUTOMAKE
+
+# AC_PROG_SED is only available in Autoconf >= 2.59b; workaround for older
+# versions
+ifdef([AC_PROG_SED], [AC_PROG_SED], [
+AC_CHECK_PROGS(SED, [gsed sed])
+])
+
+AC_PROG_GCC_TRADITIONAL
+
+# We need to test for at least gcc 2.95 here, because older versions don't
+# have -fno-strict-aliasing
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
+#if !defined(__GNUC__) || (__GNUC__ < 2) || (__GNUC__ == 2 && __GNUC_MINOR__ < 95)
+#error
+#endif])], have_gcc295=yes, have_gcc295=no)
+
+if test "$GCC" = "yes" ; then
+ # Enable many gcc warnings by default...
+ CFLAGS="$CFLAGS -Wall"
+ # And disable the strict-aliasing optimization, since it breaks
+ # our sockaddr-handling code in strange ways.
+ if test x$have_gcc295 = xyes; then
+ CFLAGS="$CFLAGS -fno-strict-aliasing"
+ fi
+fi
+
+# OS X Lion started deprecating the system openssl. Let's just disable
+# all deprecation warnings on OS X; but do so only for gcc...
+if test "$GCC" = "yes" ; then
+ case "$host_os" in
+ darwin*)
+ CFLAGS="$CFLAGS -Wno-deprecated-declarations"
+ ;;
+ esac
+fi
+
+AC_ARG_ENABLE(gcc-warnings,
+ AS_HELP_STRING(--disable-gcc-warnings, disable verbose warnings with GCC))
+
+AC_ARG_ENABLE(gcc-hardening,
+ AS_HELP_STRING(--enable-gcc-hardening, enable compiler security checks),
+[if test x$enableval = xyes; then
+ CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -fstack-protector-all"
+ CFLAGS="$CFLAGS -fwrapv -fPIE -Wstack-protector"
+ CFLAGS="$CFLAGS --param ssp-buffer-size=1"
+fi])
+
+AC_ARG_ENABLE(thread-support,
+ AS_HELP_STRING(--disable-thread-support, disable support for threading),
+ [], [enable_thread_support=yes])
+AC_ARG_ENABLE(malloc-replacement,
+ AS_HELP_STRING(--disable-malloc-replacement, disable support for replacing the memory mgt functions),
+ [], [enable_malloc_replacement=yes])
+AC_ARG_ENABLE(openssl,
+ AS_HELP_STRING(--disable-openssl, disable support for openssl encryption),
+ [], [enable_openssl=yes])
+AC_ARG_ENABLE(debug-mode,
+ AS_HELP_STRING(--disable-debug-mode, disable support for running in debug mode),
+ [], [enable_debug_mode=yes])
+AC_ARG_ENABLE([libevent-install],
+ AS_HELP_STRING([--disable-libevent-install, disable installation of libevent]),
+ [], [enable_libevent_install=yes])
+AC_ARG_ENABLE([libevent-regress],
+ AS_HELP_STRING([--disable-libevent-regress, skip regress in make check]),
+ [], [enable_libevent_regress=yes])
+AC_ARG_ENABLE([samples],
+ AS_HELP_STRING([--disable-samples, skip building of sample programs]),
+ [], [enable_samples=yes])
+AC_ARG_ENABLE([function-sections],
+ AS_HELP_STRING([--enable-function-sections, make static library allow smaller binaries with --gc-sections]),
+ [], [enable_function_sections=no])
+AC_ARG_ENABLE([verbose-debug],
+ AS_HELP_STRING([--enable-verbose-debug, verbose debug logging]),
+ [], [enable_verbose_debug=no])
+AC_ARG_ENABLE([clock-gettime],
+ AS_HELP_STRING(--disable-clock-gettime, do not use clock_gettime even if it is available),
+ [], [enable_clock_gettime=yes])
+
+
+AC_PROG_LIBTOOL
+
+dnl Uncomment "AC_DISABLE_SHARED" to make shared libraries not get
+dnl built by default. You can also turn shared libs on and off from
+dnl the command line with --enable-shared and --disable-shared.
+dnl AC_DISABLE_SHARED
+AC_SUBST(LIBTOOL_DEPS)
+
+AM_CONDITIONAL([BUILD_SAMPLES], [test "$enable_samples" = "yes"])
+AM_CONDITIONAL([BUILD_REGRESS], [test "$enable_libevent_regress" = "yes"])
+
+dnl Checks for libraries.
+AC_SEARCH_LIBS([inet_ntoa], [nsl])
+AC_SEARCH_LIBS([socket], [socket])
+AC_SEARCH_LIBS([inet_aton], [resolv])
+if test "x$enable_clock_gettime" = "xyes"; then
+ AC_SEARCH_LIBS([clock_gettime], [rt])
+ AC_CHECK_FUNCS([clock_gettime])
+fi
+AC_SEARCH_LIBS([sendfile], [sendfile])
+
+dnl - check if the macro _WIN32 is defined on this compiler.
+dnl - (this is how we check for a windows compiler)
+AC_MSG_CHECKING(for WIN32)
+AC_TRY_COMPILE(,
+ [
+#ifndef _WIN32
+die horribly
+#endif
+ ],
+ bwin32=true; AC_MSG_RESULT(yes),
+ bwin32=false; AC_MSG_RESULT(no),
+)
+
+dnl - check if the macro __CYGWIN__ is defined on this compiler.
+dnl - (this is how we check for a cygwin version of GCC)
+AC_MSG_CHECKING(for CYGWIN)
+AC_TRY_COMPILE(,
+ [
+#ifndef __CYGWIN__
+die horribly
+#endif
+ ],
+ cygwin=true; AC_MSG_RESULT(yes),
+ cygwin=false; AC_MSG_RESULT(no),
+)
+
+AC_CHECK_HEADERS([zlib.h])
+
+if test "x$ac_cv_header_zlib_h" = "xyes"; then
+dnl Determine if we have zlib for regression tests
+dnl Don't put this one in LIBS
+save_LIBS="$LIBS"
+LIBS=""
+ZLIB_LIBS=""
+have_zlib=no
+AC_SEARCH_LIBS([inflateEnd], [z],
+ [have_zlib=yes
+ ZLIB_LIBS="$LIBS"
+ AC_DEFINE(HAVE_LIBZ, 1, [Define if the system has zlib])])
+LIBS="$save_LIBS"
+AC_SUBST(ZLIB_LIBS)
+fi
+AM_CONDITIONAL(ZLIB_REGRESS, [test "$have_zlib" = "yes"])
+
+dnl See if we have openssl. This doesn't go in LIBS either.
+if test "$bwin32" = true; then
+ EV_LIB_WS32=-lws2_32
+ EV_LIB_GDI=-lgdi32
+else
+ EV_LIB_WS32=
+ EV_LIB_GDI=
+fi
+AC_SUBST(EV_LIB_WS32)
+AC_SUBST(EV_LIB_GDI)
+AC_SUBST(OPENSSL_LIBADD)
+
+AC_SYS_LARGEFILE
+
+LIBEVENT_OPENSSL
+
+dnl Checks for header files.
+AC_CHECK_HEADERS([ \
+ arpa/inet.h \
+ fcntl.h \
+ ifaddrs.h \
+ mach/mach_time.h \
+ netdb.h \
+ netinet/in.h \
+ netinet/in6.h \
+ netinet/tcp.h \
+ poll.h \
+ port.h \
+ stdarg.h \
+ stddef.h \
+ sys/devpoll.h \
+ sys/epoll.h \
+ sys/event.h \
+ sys/eventfd.h \
+ sys/ioctl.h \
+ sys/mman.h \
+ sys/param.h \
+ sys/queue.h \
+ sys/resource.h \
+ sys/select.h \
+ sys/sendfile.h \
+ sys/socket.h \
+ sys/stat.h \
+ sys/time.h \
+ sys/timerfd.h \
+ sys/uio.h \
+ sys/wait.h \
+ errno.h \
+])
+
+AC_CHECK_HEADERS(sys/sysctl.h, [], [], [
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+])
+if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
+ AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
+ AC_EGREP_CPP(yes,
+[
+#include <sys/queue.h>
+#ifdef TAILQ_FOREACH
+ yes
+#endif
+], [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_TAILQFOREACH, 1,
+ [Define if TAILQ_FOREACH is defined in <sys/queue.h>])],
+ AC_MSG_RESULT(no)
+ )
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+ AC_MSG_CHECKING(for timeradd in sys/time.h)
+ AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timeradd
+ yes
+#endif
+], [ AC_DEFINE(HAVE_TIMERADD, 1,
+ [Define if timeradd is defined in <sys/time.h>])
+ AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+ AC_MSG_CHECKING(for timercmp in sys/time.h)
+ AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timercmp
+ yes
+#endif
+], [ AC_DEFINE(HAVE_TIMERCMP, 1,
+ [Define if timercmp is defined in <sys/time.h>])
+ AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+ AC_MSG_CHECKING(for timerclear in sys/time.h)
+ AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timerclear
+ yes
+#endif
+], [ AC_DEFINE(HAVE_TIMERCLEAR, 1,
+ [Define if timerclear is defined in <sys/time.h>])
+ AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+ AC_MSG_CHECKING(for timerisset in sys/time.h)
+ AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timerisset
+ yes
+#endif
+], [ AC_DEFINE(HAVE_TIMERISSET, 1,
+ [Define if timerisset is defined in <sys/time.h>])
+ AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+if test "x$ac_cv_header_sys_sysctl_h" = "xyes"; then
+ AC_CHECK_DECLS([CTL_KERN, KERN_RANDOM, RANDOM_UUID, KERN_ARND], [], [],
+ [[#include <sys/types.h>
+ #include <sys/sysctl.h>]]
+ )
+fi
+
+AM_CONDITIONAL(BUILD_WIN32, test x$bwin32 = xtrue)
+AM_CONDITIONAL(BUILD_CYGWIN, test x$cygwin = xtrue)
+AM_CONDITIONAL(BUILD_WITH_NO_UNDEFINED, test x$bwin32 = xtrue || test x$cygwin = xtrue)
+
+if test x$bwin32 = xtrue; then
+ AC_SEARCH_LIBS([getservbyname],[ws2_32])
+fi
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_HEADER_TIME
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS([ \
+ accept4 \
+ arc4random \
+ arc4random_buf \
+ eventfd \
+ epoll_create1 \
+ fcntl \
+ getegid \
+ geteuid \
+ getifaddrs \
+ getnameinfo \
+ getprotobynumber \
+ gettimeofday \
+ inet_ntop \
+ inet_pton \
+ issetugid \
+ mach_absolute_time \
+ mmap \
+ nanosleep \
+ pipe \
+ pipe2 \
+ putenv \
+ sendfile \
+ setenv \
+ setrlimit \
+ sigaction \
+ signal \
+ splice \
+ strlcpy \
+ strsep \
+ strtok_r \
+ strtoll \
+ sysctl \
+ timerfd_create \
+ umask \
+ unsetenv \
+ usleep \
+ vasprintf \
+ getservbyname \
+])
+AM_CONDITIONAL(STRLCPY_IMPL, [test x"$ac_cv_func_strlcpy" = xno])
+
+AC_CACHE_CHECK(
+ [for getaddrinfo],
+ [libevent_cv_getaddrinfo],
+ [AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[
+ #ifdef HAVE_NETDB_H
+ #include <netdb.h>
+ #endif
+ ]],
+ [[
+ getaddrinfo;
+ ]]
+ )],
+ [libevent_cv_getaddrinfo=yes],
+ [libevent_cv_getaddrinfo=no]
+ )]
+)
+if test "$libevent_cv_getaddrinfo" = "yes" ; then
+ AC_DEFINE([HAVE_GETADDRINFO], [1], [Do we have getaddrinfo()?])
+else
+
+# Check for gethostbyname_r in all its glorious incompatible versions.
+# (This is cut-and-pasted from Tor, which based its logic on
+# Python's configure.in.)
+AH_TEMPLATE(HAVE_GETHOSTBYNAME_R,
+ [Define this if you have any gethostbyname_r()])
+
+AC_CHECK_FUNC(gethostbyname_r, [
+ AC_MSG_CHECKING([how many arguments gethostbyname_r() wants])
+ OLD_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS $MY_CPPFLAGS $MY_THREAD_CPPFLAGS $MY_CFLAGS"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
+#include <netdb.h>
+ ], [[
+ char *cp1, *cp2;
+ struct hostent *h1, *h2;
+ int i1, i2;
+ (void)gethostbyname_r(cp1,h1,cp2,i1,&h2,&i2);
+ ]])],[
+ AC_DEFINE(HAVE_GETHOSTBYNAME_R)
+ AC_DEFINE(HAVE_GETHOSTBYNAME_R_6_ARG, 1,
+ [Define this if gethostbyname_r takes 6 arguments])
+ AC_MSG_RESULT(6)
+ ], [
+ AC_TRY_COMPILE([
+#include <netdb.h>
+ ], [
+ char *cp1, *cp2;
+ struct hostent *h1;
+ int i1, i2;
+ (void)gethostbyname_r(cp1,h1,cp2,i1,&i2);
+ ], [
+ AC_DEFINE(HAVE_GETHOSTBYNAME_R)
+ AC_DEFINE(HAVE_GETHOSTBYNAME_R_5_ARG, 1,
+ [Define this if gethostbyname_r takes 5 arguments])
+ AC_MSG_RESULT(5)
+ ], [
+ AC_TRY_COMPILE([
+#include <netdb.h>
+ ], [
+ char *cp1;
+ struct hostent *h1;
+ struct hostent_data hd;
+ (void) gethostbyname_r(cp1,h1,&hd);
+ ], [
+ AC_DEFINE(HAVE_GETHOSTBYNAME_R)
+ AC_DEFINE(HAVE_GETHOSTBYNAME_R_3_ARG, 1,
+ [Define this if gethostbyname_r takes 3 arguments])
+ AC_MSG_RESULT(3)
+ ], [
+ AC_MSG_RESULT(0)
+ ])
+ ])
+ ])
+ CFLAGS=$OLD_CFLAGS
+])
+
+fi
+
+AC_MSG_CHECKING(for F_SETFD in fcntl.h)
+AC_EGREP_CPP(yes,
+[
+#define _GNU_SOURCE
+#include <fcntl.h>
+#ifdef F_SETFD
+yes
+#endif
+], [ AC_DEFINE(HAVE_SETFD, 1,
+ [Define if F_SETFD is defined in <fcntl.h>])
+ AC_MSG_RESULT(yes) ], AC_MSG_RESULT(no))
+
+needsignal=no
+haveselect=no
+if test x$bwin32 != xtrue; then
+ AC_CHECK_FUNCS(select, [haveselect=yes], )
+ if test "x$haveselect" = "xyes" ; then
+ needsignal=yes
+ fi
+fi
+AM_CONDITIONAL(SELECT_BACKEND, [test "x$haveselect" = "xyes"])
+
+havepoll=no
+AC_CHECK_FUNCS(poll, [havepoll=yes], )
+if test "x$havepoll" = "xyes" ; then
+ needsignal=yes
+fi
+AM_CONDITIONAL(POLL_BACKEND, [test "x$havepoll" = "xyes"])
+
+havedevpoll=no
+if test "x$ac_cv_header_sys_devpoll_h" = "xyes"; then
+ AC_DEFINE(HAVE_DEVPOLL, 1,
+ [Define if /dev/poll is available])
+fi
+AM_CONDITIONAL(DEVPOLL_BACKEND, [test "x$ac_cv_header_sys_devpoll_h" = "xyes"])
+
+havekqueue=no
+if test "x$ac_cv_header_sys_event_h" = "xyes"; then
+ AC_CHECK_FUNCS(kqueue, [havekqueue=yes], )
+ if test "x$havekqueue" = "xyes" ; then
+ AC_MSG_CHECKING(for working kqueue)
+ AC_TRY_RUN(
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/event.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int
+main(int argc, char **argv)
+{
+ int kq;
+ int n;
+ int fd[[2]];
+ struct kevent ev;
+ struct timespec ts;
+ char buf[[8000]];
+
+ if (pipe(fd) == -1)
+ exit(1);
+ if (fcntl(fd[[1]], F_SETFL, O_NONBLOCK) == -1)
+ exit(1);
+
+ while ((n = write(fd[[1]], buf, sizeof(buf))) == sizeof(buf))
+ ;
+
+ if ((kq = kqueue()) == -1)
+ exit(1);
+
+ memset(&ev, 0, sizeof(ev));
+ ev.ident = fd[[1]];
+ ev.filter = EVFILT_WRITE;
+ ev.flags = EV_ADD | EV_ENABLE;
+ n = kevent(kq, &ev, 1, NULL, 0, NULL);
+ if (n == -1)
+ exit(1);
+
+ read(fd[[0]], buf, sizeof(buf));
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ n = kevent(kq, NULL, 0, &ev, 1, &ts);
+ if (n == -1 || n == 0)
+ exit(1);
+
+ exit(0);
+}, [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_WORKING_KQUEUE, 1,
+ [Define if kqueue works correctly with pipes])
+ havekqueue=yes
+ ], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+ fi
+fi
+AM_CONDITIONAL(KQUEUE_BACKEND, [test "x$havekqueue" = "xyes"])
+
+haveepollsyscall=no
+haveepoll=no
+AC_CHECK_FUNCS(epoll_ctl, [haveepoll=yes], )
+if test "x$haveepoll" = "xyes" ; then
+ AC_DEFINE(HAVE_EPOLL, 1,
+ [Define if your system supports the epoll system calls])
+ needsignal=yes
+fi
+if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then
+ if test "x$haveepoll" = "xno" ; then
+ AC_MSG_CHECKING(for epoll system call)
+ AC_TRY_RUN(
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+int
+epoll_create(int size)
+{
+ return (syscall(__NR_epoll_create, size));
+}
+
+int
+main(int argc, char **argv)
+{
+ int epfd;
+
+ epfd = epoll_create(256);
+ exit (epfd == -1 ? 1 : 0);
+}, [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_EPOLL, 1,
+ [Define if your system supports the epoll system calls])
+ needsignal=yes
+ have_epoll=yes
+ AC_LIBOBJ(epoll_sub)
+ ], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+ fi
+fi
+AM_CONDITIONAL(EPOLL_BACKEND, [test "x$haveepoll" = "xyes"])
+
+AC_MSG_CHECKING(waitpid support WNOWAIT)
+AC_TRY_RUN(
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+
+int
+main(int argc, char** argv)
+{
+ pid_t pid;
+ int status;
+ if ((pid = fork()) == 0) _exit(0);
+ _exit(waitpid(pid, &status, WNOWAIT) == -1);
+}, [AC_MSG_RESULT(yes)
+AC_DEFINE(HAVE_WAITPID_WITH_WNOWAIT, 1,
+[Define if waitpid() supports WNOWAIT])
+], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+
+
+haveeventports=no
+AC_CHECK_FUNCS(port_create, [haveeventports=yes], )
+if test "x$haveeventports" = "xyes" ; then
+ AC_DEFINE(HAVE_EVENT_PORTS, 1,
+ [Define if your system supports event ports])
+ needsignal=yes
+fi
+AM_CONDITIONAL(EVPORT_BACKEND, [test "x$haveeventports" = "xyes"])
+
+if test "x$bwin32" = "xtrue"; then
+ needsignal=yes
+fi
+
+AM_CONDITIONAL(SIGNAL_SUPPORT, [test "x$needsignal" = "xyes"])
+
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
+
+AC_CHECK_TYPES([uint64_t, uint32_t, uint16_t, uint8_t, uintptr_t], , ,
+[#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+#include <inttypes.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif])
+
+AC_CHECK_TYPES([fd_mask], , ,
+[#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif])
+
+AC_CHECK_SIZEOF(long long)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(size_t)
+AC_CHECK_SIZEOF(void *)
+AC_CHECK_SIZEOF(off_t)
+
+AC_CHECK_TYPES([struct in6_addr, struct sockaddr_in6, sa_family_t, struct addrinfo, struct sockaddr_storage], , ,
+[#define _GNU_SOURCE
+#include <sys/types.h>
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef _WIN32
+#define WIN32_WINNT 0x400
+#define _WIN32_WINNT 0x400
+#define WIN32_LEAN_AND_MEAN
+#if defined(_MSC_VER) && (_MSC_VER < 1300)
+#include <winsock.h>
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+#endif
+])
+AC_CHECK_MEMBERS([struct in6_addr.s6_addr32, struct in6_addr.s6_addr16, struct sockaddr_in.sin_len, struct sockaddr_in6.sin6_len, struct sockaddr_storage.ss_family, struct sockaddr_storage.__ss_family], , ,
+[#include <sys/types.h>
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef _WIN32
+#define WIN32_WINNT 0x400
+#define _WIN32_WINNT 0x400
+#define WIN32_LEAN_AND_MEAN
+#if defined(_MSC_VER) && (_MSC_VER < 1300)
+#include <winsock.h>
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+#endif
+])
+
+AC_CHECK_TYPES([struct so_linger],
+[#define HAVE_SO_LINGER], ,
+[
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+])
+
+AC_MSG_CHECKING([for socklen_t])
+AC_TRY_COMPILE([
+ #include <sys/types.h>
+ #include <sys/socket.h>],
+ [socklen_t x;],
+ AC_MSG_RESULT([yes]),
+ [AC_MSG_RESULT([no])
+ AC_DEFINE(socklen_t, unsigned int,
+ [Define to unsigned int if you dont have it])]
+)
+
+AC_MSG_CHECKING([whether our compiler supports __func__])
+AC_TRY_COMPILE([],
+ [ const char *cp = __func__; ],
+ AC_MSG_RESULT([yes]),
+ AC_MSG_RESULT([no])
+ AC_MSG_CHECKING([whether our compiler supports __FUNCTION__])
+ AC_TRY_COMPILE([],
+ [ const char *cp = __FUNCTION__; ],
+ AC_MSG_RESULT([yes])
+ AC_DEFINE(__func__, __FUNCTION__,
+ [Define to appropriate substitue if compiler doesnt have __func__]),
+ AC_MSG_RESULT([no])
+ AC_DEFINE(__func__, __FILE__,
+ [Define to appropriate substitue if compiler doesnt have __func__])))
+
+
+# check if we can compile with pthreads
+have_pthreads=no
+if test x$bwin32 != xtrue && test "$enable_thread_support" != "no"; then
+ ACX_PTHREAD([
+ AC_DEFINE(HAVE_PTHREADS, 1,
+ [Define if we have pthreads on this system])
+ have_pthreads=yes])
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ AC_CHECK_SIZEOF(pthread_t, ,
+ [AC_INCLUDES_DEFAULT()
+ #include <pthread.h> ]
+ )
+fi
+AM_CONDITIONAL(THREADS, [test "$enable_thread_support" != "no"])
+AM_CONDITIONAL(PTHREADS, [test "$have_pthreads" != "no" && test "$enable_thread_support" != "no"])
+
+# check if we should compile locking into the library
+if test x$enable_thread_support = xno; then
+ AC_DEFINE(DISABLE_THREAD_SUPPORT, 1,
+ [Define if libevent should not be compiled with thread support])
+fi
+
+# check if we should hard-code the mm functions.
+if test x$enable_malloc_replacement = xno; then
+ AC_DEFINE(DISABLE_MM_REPLACEMENT, 1,
+ [Define if libevent should not allow replacing the mm functions])
+fi
+
+# check if we should hard-code debugging out
+if test x$enable_debug_mode = xno; then
+ AC_DEFINE(DISABLE_DEBUG_MODE, 1,
+ [Define if libevent should build without support for a debug mode])
+fi
+
+# check if we should enable verbose debugging
+if test x$enable_verbose_debug = xyes; then
+ CFLAGS="$CFLAGS -DUSE_DEBUG"
+fi
+
+# check if we have and should use openssl
+AM_CONDITIONAL(OPENSSL, [test "$enable_openssl" != "no" && test "$have_openssl" = "yes"])
+if test "x$enable_openssl" = "xyes"; then
+ AC_SEARCH_LIBS([ERR_remove_thread_state], [crypto eay32],
+ [AC_DEFINE(HAVE_ERR_REMOVE_THREAD_STATE, 1, [Define to 1 if you have ERR_remove_thread_stat().])])
+fi
+
+# Add some more warnings which we use in development but not in the
+# released versions. (Some relevant gcc versions can't handle these.)
+if test x$enable_gcc_warnings != xno && test "$GCC" = "yes"; then
+
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
+#if !defined(__GNUC__) || (__GNUC__ < 4)
+#error
+#endif])], have_gcc4=yes, have_gcc4=no)
+
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
+#if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)
+#error
+#endif])], have_gcc42=yes, have_gcc42=no)
+
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
+#if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+#error
+#endif])], have_gcc45=yes, have_gcc45=no)
+
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
+#if !defined(__clang__)
+#error
+#endif])], have_clang=yes, have_clang=no)
+
+ CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wchar-subscripts -Wcomment -Wformat -Wwrite-strings -Wmissing-declarations -Wredundant-decls -Wnested-externs -Wbad-function-cast -Wswitch"
+ if test x$enable_gcc_warnings = xyes; then
+ CFLAGS="$CFLAGS -Werror"
+ fi
+
+ CFLAGS="$CFLAGS -Wno-unused-parameter -Wstrict-aliasing"
+
+ if test x$have_gcc4 = xyes ; then
+ # These warnings break gcc 3.3.5 and work on gcc 4.0.2
+ CFLAGS="$CFLAGS -Winit-self -Wmissing-field-initializers -Wdeclaration-after-statement"
+ #CFLAGS="$CFLAGS -Wold-style-definition"
+ fi
+
+ if test x$have_gcc42 = xyes ; then
+ # These warnings break gcc 4.0.2 and work on gcc 4.2
+ CFLAGS="$CFLAGS -Waddress"
+ fi
+
+ if test x$have_gcc42 = xyes && test x$have_clang = xno; then
+ # These warnings break gcc 4.0.2 and clang, but work on gcc 4.2
+ CFLAGS="$CFLAGS -Wnormalized=id -Woverride-init"
+ fi
+
+ if test x$have_gcc45 = xyes ; then
+ # These warnings work on gcc 4.5
+ CFLAGS="$CFLAGS -Wlogical-op"
+ fi
+
+ if test x$have_clang = xyes; then
+ # Disable the unused-function warnings, because these trigger
+ # for minheap-internal.h related code.
+ CFLAGS="$CFLAGS -Wno-unused-function"
+
+ # clang on macosx emits warnigns for each directory specified which
+ # isn't "used" generating a lot of build noise (typically 3 warnings
+ # per file
+ case "$host_os" in
+ darwin*)
+ CFLAGS="$CFLAGS -Qunused-arguments"
+ ;;
+ esac
+ fi
+
+##This will break the world on some 64-bit architectures
+# CFLAGS="$CFLAGS -Winline"
+
+fi
+
+LIBEVENT_GC_SECTIONS=
+if test "$GCC" = yes && test "$enable_function_sections" = yes ; then
+ AC_CACHE_CHECK(
+ [if linker supports omitting unused code and data],
+ [libevent_cv_gc_sections_runs],
+ [
+ dnl NetBSD will link but likely not run with --gc-sections
+ dnl http://bugs.ntp.org/1844
+ dnl http://gnats.netbsd.org/40401
+ dnl --gc-sections causes attempt to load as linux elf, with
+ dnl wrong syscalls in place. Test a little gauntlet of
+ dnl simple stdio read code checking for errors, expecting
+ dnl enough syscall differences that the NetBSD code will
+ dnl fail even with Linux emulation working as designed.
+ dnl A shorter test could be refined by someone with access
+ dnl to a NetBSD host with Linux emulation working.
+ origCFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -Wl,--gc-sections"
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[
+ #include <stdlib.h>
+ #include <stdio.h>
+ ]],
+ [[
+ FILE * fpC;
+ char buf[32];
+ size_t cch;
+ int read_success_once;
+
+ fpC = fopen("conftest.c", "r");
+ if (NULL == fpC)
+ exit(1);
+ do {
+ cch = fread(buf, sizeof(buf), 1, fpC);
+ read_success_once |= (0 != cch);
+ } while (0 != cch);
+ if (!read_success_once)
+ exit(2);
+ if (!feof(fpC))
+ exit(3);
+ if (0 != fclose(fpC))
+ exit(4);
+
+ exit(EXIT_SUCCESS);
+ ]]
+ )],
+ [
+ dnl We have to do this invocation manually so that we can
+ dnl get the output of conftest.err to make sure it doesn't
+ dnl mention gc-sections.
+ if test "X$cross_compiling" = "Xyes" || grep gc-sections conftest.err ; then
+ libevent_cv_gc_sections_runs=no
+ else
+ libevent_cv_gc_sections_runs=no
+ ./conftest >/dev/null 2>&1 && libevent_cv_gc_sections_runs=yes
+ fi
+ ],
+ [libevent_cv_gc_sections_runs=no]
+ )
+ CFLAGS="$origCFLAGS"
+ AS_UNSET([origCFLAGS])
+ ]
+ )
+ case "$libevent_cv_gc_sections_runs" in
+ yes)
+ CFLAGS="-ffunction-sections -fdata-sections $CFLAGS"
+ LIBEVENT_GC_SECTIONS="-Wl,--gc-sections"
+ ;;
+ esac
+fi
+AC_SUBST([LIBEVENT_GC_SECTIONS])
+
+AM_CONDITIONAL([INSTALL_LIBEVENT], [test "$enable_libevent_install" = "yes"])
+
+AC_CONFIG_FILES( [libevent.pc libevent_openssl.pc libevent_pthreads.pc libevent_core.pc libevent_extra.pc] )
+AC_OUTPUT(Makefile)
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/defer-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/defer-internal.h
new file mode 100644
index 000000000..e3c7d7da5
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/defer-internal.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef DEFER_INTERNAL_H_INCLUDED_
+#define DEFER_INTERNAL_H_INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/queue.h>
+
+struct event_callback;
+typedef void (*deferred_cb_fn)(struct event_callback *, void *);
+
+/**
+ Initialize an empty, non-pending event_callback.
+
+ @param deferred The struct event_callback structure to initialize.
+ @param priority The priority that the callback should run at.
+ @param cb The function to run when the struct event_callback executes.
+ @param arg The function's second argument.
+ */
+void event_deferred_cb_init_(struct event_callback *, ev_uint8_t, deferred_cb_fn, void *);
+/**
+ Change the priority of a non-pending event_callback.
+ */
+void event_deferred_cb_set_priority_(struct event_callback *, ev_uint8_t);
+/**
+ Cancel a struct event_callback if it is currently scheduled in an event_base.
+ */
+void event_deferred_cb_cancel_(struct event_base *, struct event_callback *);
+/**
+ Activate a struct event_callback if it is not currently scheduled in an event_base.
+
+ Return true if it was not previously scheduled.
+ */
+int event_deferred_cb_schedule_(struct event_base *, struct event_callback *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT_INTERNAL_H_INCLUDED_ */
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/devpoll.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/devpoll.c
new file mode 100644
index 000000000..3a2f86d6f
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/devpoll.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2000-2009 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef EVENT__HAVE_DEVPOLL
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#include <sys/devpoll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/thread.h"
+#include "event-internal.h"
+#include "evsignal-internal.h"
+#include "log-internal.h"
+#include "evmap-internal.h"
+#include "evthread-internal.h"
+
+struct devpollop {
+ struct pollfd *events;
+ int nevents;
+ int dpfd;
+ struct pollfd *changes;
+ int nchanges;
+};
+
+static void *devpoll_init(struct event_base *);
+static int devpoll_add(struct event_base *, int fd, short old, short events, void *);
+static int devpoll_del(struct event_base *, int fd, short old, short events, void *);
+static int devpoll_dispatch(struct event_base *, struct timeval *);
+static void devpoll_dealloc(struct event_base *);
+
+const struct eventop devpollops = {
+ "devpoll",
+ devpoll_init,
+ devpoll_add,
+ devpoll_del,
+ devpoll_dispatch,
+ devpoll_dealloc,
+ 1, /* need reinit */
+ EV_FEATURE_FDS|EV_FEATURE_O1,
+ 0
+};
+
+#define NEVENT 32000
+
+static int
+devpoll_commit(struct devpollop *devpollop)
+{
+ /*
+ * Due to a bug in Solaris, we have to use pwrite with an offset of 0.
+ * Write is limited to 2GB of data, until it will fail.
+ */
+ if (pwrite(devpollop->dpfd, devpollop->changes,
+ sizeof(struct pollfd) * devpollop->nchanges, 0) == -1)
+ return (-1);
+
+ devpollop->nchanges = 0;
+ return (0);
+}
+
+static int
+devpoll_queue(struct devpollop *devpollop, int fd, int events) {
+ struct pollfd *pfd;
+
+ if (devpollop->nchanges >= devpollop->nevents) {
+ /*
+ * Change buffer is full, must commit it to /dev/poll before
+ * adding more
+ */
+ if (devpoll_commit(devpollop) != 0)
+ return (-1);
+ }
+
+ pfd = &devpollop->changes[devpollop->nchanges++];
+ pfd->fd = fd;
+ pfd->events = events;
+ pfd->revents = 0;
+
+ return (0);
+}
+
+static void *
+devpoll_init(struct event_base *base)
+{
+ int dpfd, nfiles = NEVENT;
+ struct rlimit rl;
+ struct devpollop *devpollop;
+
+ if (!(devpollop = mm_calloc(1, sizeof(struct devpollop))))
+ return (NULL);
+
+ if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
+ rl.rlim_cur != RLIM_INFINITY)
+ nfiles = rl.rlim_cur;
+
+ /* Initialize the kernel queue */
+ if ((dpfd = evutil_open_closeonexec_("/dev/poll", O_RDWR, 0)) == -1) {
+ event_warn("open: /dev/poll");
+ mm_free(devpollop);
+ return (NULL);
+ }
+
+ devpollop->dpfd = dpfd;
+
+ /* Initialize fields */
+ /* FIXME: allocating 'nfiles' worth of space here can be
+ * expensive and unnecessary. See how epoll.c does it instead. */
+ devpollop->events = mm_calloc(nfiles, sizeof(struct pollfd));
+ if (devpollop->events == NULL) {
+ mm_free(devpollop);
+ close(dpfd);
+ return (NULL);
+ }
+ devpollop->nevents = nfiles;
+
+ devpollop->changes = mm_calloc(nfiles, sizeof(struct pollfd));
+ if (devpollop->changes == NULL) {
+ mm_free(devpollop->events);
+ mm_free(devpollop);
+ close(dpfd);
+ return (NULL);
+ }
+
+ evsig_init_(base);
+
+ return (devpollop);
+}
+
+static int
+devpoll_dispatch(struct event_base *base, struct timeval *tv)
+{
+ struct devpollop *devpollop = base->evbase;
+ struct pollfd *events = devpollop->events;
+ struct dvpoll dvp;
+ int i, res, timeout = -1;
+
+ if (devpollop->nchanges)
+ devpoll_commit(devpollop);
+
+ if (tv != NULL)
+ timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
+
+ dvp.dp_fds = devpollop->events;
+ dvp.dp_nfds = devpollop->nevents;
+ dvp.dp_timeout = timeout;
+
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ res = ioctl(devpollop->dpfd, DP_POLL, &dvp);
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ if (res == -1) {
+ if (errno != EINTR) {
+ event_warn("ioctl: DP_POLL");
+ return (-1);
+ }
+
+ return (0);
+ }
+
+ event_debug(("%s: devpoll_wait reports %d", __func__, res));
+
+ for (i = 0; i < res; i++) {
+ int which = 0;
+ int what = events[i].revents;
+
+ if (what & POLLHUP)
+ what |= POLLIN | POLLOUT;
+ else if (what & POLLERR)
+ what |= POLLIN | POLLOUT;
+
+ if (what & POLLIN)
+ which |= EV_READ;
+ if (what & POLLOUT)
+ which |= EV_WRITE;
+
+ if (!which)
+ continue;
+
+ /* XXX(niels): not sure if this works for devpoll */
+ evmap_io_active_(base, events[i].fd, which);
+ }
+
+ return (0);
+}
+
+
+static int
+devpoll_add(struct event_base *base, int fd, short old, short events, void *p)
+{
+ struct devpollop *devpollop = base->evbase;
+ int res;
+ (void)p;
+
+ /*
+ * It's not necessary to OR the existing read/write events that we
+ * are currently interested in with the new event we are adding.
+ * The /dev/poll driver ORs any new events with the existing events
+ * that it has cached for the fd.
+ */
+
+ res = 0;
+ if (events & EV_READ)
+ res |= POLLIN;
+ if (events & EV_WRITE)
+ res |= POLLOUT;
+
+ if (devpoll_queue(devpollop, fd, res) != 0)
+ return (-1);
+
+ return (0);
+}
+
+static int
+devpoll_del(struct event_base *base, int fd, short old, short events, void *p)
+{
+ struct devpollop *devpollop = base->evbase;
+ int res;
+ (void)p;
+
+ res = 0;
+ if (events & EV_READ)
+ res |= POLLIN;
+ if (events & EV_WRITE)
+ res |= POLLOUT;
+
+ /*
+ * The only way to remove an fd from the /dev/poll monitored set is
+ * to use POLLREMOVE by itself. This removes ALL events for the fd
+ * provided so if we care about two events and are only removing one
+ * we must re-add the other event after POLLREMOVE.
+ */
+
+ if (devpoll_queue(devpollop, fd, POLLREMOVE) != 0)
+ return (-1);
+
+ if ((res & (POLLIN|POLLOUT)) != (POLLIN|POLLOUT)) {
+ /*
+ * We're not deleting all events, so we must resubmit the
+ * event that we are still interested in if one exists.
+ */
+
+ if ((res & POLLIN) && (old & EV_WRITE)) {
+ /* Deleting read, still care about write */
+ devpoll_queue(devpollop, fd, POLLOUT);
+ } else if ((res & POLLOUT) && (old & EV_READ)) {
+ /* Deleting write, still care about read */
+ devpoll_queue(devpollop, fd, POLLIN);
+ }
+ }
+
+ return (0);
+}
+
+static void
+devpoll_dealloc(struct event_base *base)
+{
+ struct devpollop *devpollop = base->evbase;
+
+ evsig_dealloc_(base);
+ if (devpollop->events)
+ mm_free(devpollop->events);
+ if (devpollop->changes)
+ mm_free(devpollop->changes);
+ if (devpollop->dpfd >= 0)
+ close(devpollop->dpfd);
+
+ memset(devpollop, 0, sizeof(struct devpollop));
+ mm_free(devpollop);
+}
+
+#endif /* EVENT__HAVE_DEVPOLL */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/epoll.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/epoll.c
new file mode 100644
index 000000000..bf730b23d
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/epoll.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2007-2012 Niels Provos, Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef EVENT__HAVE_EPOLL
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#include <sys/epoll.h>
+#include <signal.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef EVENT__HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIMERFD_H
+#include <sys/timerfd.h>
+#endif
+
+#include "event-internal.h"
+#include "evsignal-internal.h"
+#include "event2/thread.h"
+#include "evthread-internal.h"
+#include "log-internal.h"
+#include "evmap-internal.h"
+#include "changelist-internal.h"
+#include "time-internal.h"
+
+/* Since Linux 2.6.17, epoll is able to report about peer half-closed connection
+ using special EPOLLRDHUP flag on a read event.
+*/
+#if !defined(EPOLLRDHUP)
+#define EPOLLRDHUP 0
+#define EARLY_CLOSE_IF_HAVE_RDHUP 0
+#else
+#define EARLY_CLOSE_IF_HAVE_RDHUP EV_FEATURE_EARLY_CLOSE
+#endif
+
+#include "epolltable-internal.h"
+
+#if defined(EVENT__HAVE_SYS_TIMERFD_H) && \
+ defined(EVENT__HAVE_TIMERFD_CREATE) && \
+ defined(HAVE_POSIX_MONOTONIC) && defined(TFD_NONBLOCK) && \
+ defined(TFD_CLOEXEC)
+/* Note that we only use timerfd if TFD_NONBLOCK and TFD_CLOEXEC are available
+ and working. This means that we can't support it on 2.6.25 (where timerfd
+ was introduced) or 2.6.26, since 2.6.27 introduced those flags.
+ */
+#define USING_TIMERFD
+#endif
+
+struct epollop {
+ struct epoll_event *events;
+ int nevents;
+ int epfd;
+#ifdef USING_TIMERFD
+ int timerfd;
+#endif
+};
+
+static void *epoll_init(struct event_base *);
+static int epoll_dispatch(struct event_base *, struct timeval *);
+static void epoll_dealloc(struct event_base *);
+
+static const struct eventop epollops_changelist = {
+ "epoll (with changelist)",
+ epoll_init,
+ event_changelist_add_,
+ event_changelist_del_,
+ epoll_dispatch,
+ epoll_dealloc,
+ 1, /* need reinit */
+ EV_FEATURE_ET|EV_FEATURE_O1| EARLY_CLOSE_IF_HAVE_RDHUP,
+ EVENT_CHANGELIST_FDINFO_SIZE
+};
+
+
+static int epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
+ short old, short events, void *p);
+static int epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
+ short old, short events, void *p);
+
+const struct eventop epollops = {
+ "epoll",
+ epoll_init,
+ epoll_nochangelist_add,
+ epoll_nochangelist_del,
+ epoll_dispatch,
+ epoll_dealloc,
+ 1, /* need reinit */
+ EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_EARLY_CLOSE,
+ 0
+};
+
+#define INITIAL_NEVENT 32
+#define MAX_NEVENT 4096
+
+/* On Linux kernels at least up to 2.6.24.4, epoll can't handle timeout
+ * values bigger than (LONG_MAX - 999ULL)/HZ. HZ in the wild can be
+ * as big as 1000, and LONG_MAX can be as small as (1<<31)-1, so the
+ * largest number of msec we can support here is 2147482. Let's
+ * round that down by 47 seconds.
+ */
+#define MAX_EPOLL_TIMEOUT_MSEC (35*60*1000)
+
+static void *
+epoll_init(struct event_base *base)
+{
+ int epfd = -1;
+ struct epollop *epollop;
+
+#ifdef EVENT__HAVE_EPOLL_CREATE1
+ /* First, try the shiny new epoll_create1 interface, if we have it. */
+ epfd = epoll_create1(EPOLL_CLOEXEC);
+#endif
+ if (epfd == -1) {
+ /* Initialize the kernel queue using the old interface. (The
+ size field is ignored since 2.6.8.) */
+ if ((epfd = epoll_create(32000)) == -1) {
+ if (errno != ENOSYS)
+ event_warn("epoll_create");
+ return (NULL);
+ }
+ evutil_make_socket_closeonexec(epfd);
+ }
+
+ if (!(epollop = mm_calloc(1, sizeof(struct epollop)))) {
+ close(epfd);
+ return (NULL);
+ }
+
+ epollop->epfd = epfd;
+
+ /* Initialize fields */
+ epollop->events = mm_calloc(INITIAL_NEVENT, sizeof(struct epoll_event));
+ if (epollop->events == NULL) {
+ mm_free(epollop);
+ close(epfd);
+ return (NULL);
+ }
+ epollop->nevents = INITIAL_NEVENT;
+
+ if ((base->flags & EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST) != 0 ||
+ ((base->flags & EVENT_BASE_FLAG_IGNORE_ENV) == 0 &&
+ evutil_getenv_("EVENT_EPOLL_USE_CHANGELIST") != NULL)) {
+
+ base->evsel = &epollops_changelist;
+ }
+
+#ifdef USING_TIMERFD
+ /*
+ The epoll interface ordinarily gives us one-millisecond precision,
+ so on Linux it makes perfect sense to use the CLOCK_MONOTONIC_COARSE
+ timer. But when the user has set the new PRECISE_TIMER flag for an
+ event_base, we can try to use timerfd to give them finer granularity.
+ */
+ if ((base->flags & EVENT_BASE_FLAG_PRECISE_TIMER) &&
+ base->monotonic_timer.monotonic_clock == CLOCK_MONOTONIC) {
+ int fd;
+ fd = epollop->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
+ if (epollop->timerfd >= 0) {
+ struct epoll_event epev;
+ memset(&epev, 0, sizeof(epev));
+ epev.data.fd = epollop->timerfd;
+ epev.events = EPOLLIN;
+ if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, fd, &epev) < 0) {
+ event_warn("epoll_ctl(timerfd)");
+ close(fd);
+ epollop->timerfd = -1;
+ }
+ } else {
+ if (errno != EINVAL && errno != ENOSYS) {
+ /* These errors probably mean that we were
+ * compiled with timerfd/TFD_* support, but
+ * we're running on a kernel that lacks those.
+ */
+ event_warn("timerfd_create");
+ }
+ epollop->timerfd = -1;
+ }
+ } else {
+ epollop->timerfd = -1;
+ }
+#endif
+
+ evsig_init_(base);
+
+ return (epollop);
+}
+
+static const char *
+change_to_string(int change)
+{
+ change &= (EV_CHANGE_ADD|EV_CHANGE_DEL);
+ if (change == EV_CHANGE_ADD) {
+ return "add";
+ } else if (change == EV_CHANGE_DEL) {
+ return "del";
+ } else if (change == 0) {
+ return "none";
+ } else {
+ return "???";
+ }
+}
+
+static const char *
+epoll_op_to_string(int op)
+{
+ return op == EPOLL_CTL_ADD?"ADD":
+ op == EPOLL_CTL_DEL?"DEL":
+ op == EPOLL_CTL_MOD?"MOD":
+ "???";
+}
+
+#define PRINT_CHANGES(op, events, ch, status) \
+ "Epoll %s(%d) on fd %d " status ". " \
+ "Old events were %d; " \
+ "read change was %d (%s); " \
+ "write change was %d (%s); " \
+ "close change was %d (%s)", \
+ epoll_op_to_string(op), \
+ events, \
+ ch->fd, \
+ ch->old_events, \
+ ch->read_change, \
+ change_to_string(ch->read_change), \
+ ch->write_change, \
+ change_to_string(ch->write_change), \
+ ch->close_change, \
+ change_to_string(ch->close_change)
+
+static int
+epoll_apply_one_change(struct event_base *base,
+ struct epollop *epollop,
+ const struct event_change *ch)
+{
+ struct epoll_event epev;
+ int op, events = 0;
+ int idx;
+
+ idx = EPOLL_OP_TABLE_INDEX(ch);
+ op = epoll_op_table[idx].op;
+ events = epoll_op_table[idx].events;
+
+ if (!events) {
+ EVUTIL_ASSERT(op == 0);
+ return 0;
+ }
+
+ if ((ch->read_change|ch->write_change) & EV_CHANGE_ET)
+ events |= EPOLLET;
+
+ memset(&epev, 0, sizeof(epev));
+ epev.data.fd = ch->fd;
+ epev.events = events;
+ if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == 0) {
+ event_debug((PRINT_CHANGES(op, epev.events, ch, "okay")));
+ return 0;
+ }
+
+ switch (op) {
+ case EPOLL_CTL_MOD:
+ if (errno == ENOENT) {
+ /* If a MOD operation fails with ENOENT, the
+ * fd was probably closed and re-opened. We
+ * should retry the operation as an ADD.
+ */
+ if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, ch->fd, &epev) == -1) {
+ event_warn("Epoll MOD(%d) on %d retried as ADD; that failed too",
+ (int)epev.events, ch->fd);
+ return -1;
+ } else {
+ event_debug(("Epoll MOD(%d) on %d retried as ADD; succeeded.",
+ (int)epev.events,
+ ch->fd));
+ return 0;
+ }
+ }
+ break;
+ case EPOLL_CTL_ADD:
+ if (errno == EEXIST) {
+ /* If an ADD operation fails with EEXIST,
+ * either the operation was redundant (as with a
+ * precautionary add), or we ran into a fun
+ * kernel bug where using dup*() to duplicate the
+ * same file into the same fd gives you the same epitem
+ * rather than a fresh one. For the second case,
+ * we must retry with MOD. */
+ if (epoll_ctl(epollop->epfd, EPOLL_CTL_MOD, ch->fd, &epev) == -1) {
+ event_warn("Epoll ADD(%d) on %d retried as MOD; that failed too",
+ (int)epev.events, ch->fd);
+ return -1;
+ } else {
+ event_debug(("Epoll ADD(%d) on %d retried as MOD; succeeded.",
+ (int)epev.events,
+ ch->fd));
+ return 0;
+ }
+ }
+ break;
+ case EPOLL_CTL_DEL:
+ if (errno == ENOENT || errno == EBADF || errno == EPERM) {
+ /* If a delete fails with one of these errors,
+ * that's fine too: we closed the fd before we
+ * got around to calling epoll_dispatch. */
+ event_debug(("Epoll DEL(%d) on fd %d gave %s: DEL was unnecessary.",
+ (int)epev.events,
+ ch->fd,
+ strerror(errno)));
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+
+ event_warn(PRINT_CHANGES(op, epev.events, ch, "failed"));
+ return -1;
+}
+
+static int
+epoll_apply_changes(struct event_base *base)
+{
+ struct event_changelist *changelist = &base->changelist;
+ struct epollop *epollop = base->evbase;
+ struct event_change *ch;
+
+ int r = 0;
+ int i;
+
+ for (i = 0; i < changelist->n_changes; ++i) {
+ ch = &changelist->changes[i];
+ if (epoll_apply_one_change(base, epollop, ch) < 0)
+ r = -1;
+ }
+
+ return (r);
+}
+
+static int
+epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
+ short old, short events, void *p)
+{
+ struct event_change ch;
+ ch.fd = fd;
+ ch.old_events = old;
+ ch.read_change = ch.write_change = ch.close_change = 0;
+ if (events & EV_WRITE)
+ ch.write_change = EV_CHANGE_ADD |
+ (events & EV_ET);
+ if (events & EV_READ)
+ ch.read_change = EV_CHANGE_ADD |
+ (events & EV_ET);
+ if (events & EV_CLOSED)
+ ch.close_change = EV_CHANGE_ADD |
+ (events & EV_ET);
+
+ return epoll_apply_one_change(base, base->evbase, &ch);
+}
+
+static int
+epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
+ short old, short events, void *p)
+{
+ struct event_change ch;
+ ch.fd = fd;
+ ch.old_events = old;
+ ch.read_change = ch.write_change = ch.close_change = 0;
+ if (events & EV_WRITE)
+ ch.write_change = EV_CHANGE_DEL;
+ if (events & EV_READ)
+ ch.read_change = EV_CHANGE_DEL;
+ if (events & EV_CLOSED)
+ ch.close_change = EV_CHANGE_DEL;
+
+ return epoll_apply_one_change(base, base->evbase, &ch);
+}
+
+static int
+epoll_dispatch(struct event_base *base, struct timeval *tv)
+{
+ struct epollop *epollop = base->evbase;
+ struct epoll_event *events = epollop->events;
+ int i, res;
+ long timeout = -1;
+
+#ifdef USING_TIMERFD
+ if (epollop->timerfd >= 0) {
+ struct itimerspec is;
+ is.it_interval.tv_sec = 0;
+ is.it_interval.tv_nsec = 0;
+ if (tv == NULL) {
+ /* No timeout; disarm the timer. */
+ is.it_value.tv_sec = 0;
+ is.it_value.tv_nsec = 0;
+ } else {
+ if (tv->tv_sec == 0 && tv->tv_usec == 0) {
+ /* we need to exit immediately; timerfd can't
+ * do that. */
+ timeout = 0;
+ }
+ is.it_value.tv_sec = tv->tv_sec;
+ is.it_value.tv_nsec = tv->tv_usec * 1000;
+ }
+ /* TODO: we could avoid unnecessary syscalls here by only
+ calling timerfd_settime when the top timeout changes, or
+ when we're called with a different timeval.
+ */
+ if (timerfd_settime(epollop->timerfd, 0, &is, NULL) < 0) {
+ event_warn("timerfd_settime");
+ }
+ } else
+#endif
+ if (tv != NULL) {
+ timeout = evutil_tv_to_msec_(tv);
+ if (timeout < 0 || timeout > MAX_EPOLL_TIMEOUT_MSEC) {
+ /* Linux kernels can wait forever if the timeout is
+ * too big; see comment on MAX_EPOLL_TIMEOUT_MSEC. */
+ timeout = MAX_EPOLL_TIMEOUT_MSEC;
+ }
+ }
+
+ epoll_apply_changes(base);
+ event_changelist_remove_all_(&base->changelist, base);
+
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ if (res == -1) {
+ if (errno != EINTR) {
+ event_warn("epoll_wait");
+ return (-1);
+ }
+
+ return (0);
+ }
+
+ event_debug(("%s: epoll_wait reports %d", __func__, res));
+ EVUTIL_ASSERT(res <= epollop->nevents);
+
+ for (i = 0; i < res; i++) {
+ int what = events[i].events;
+ short ev = 0;
+#ifdef USING_TIMERFD
+ if (events[i].data.fd == epollop->timerfd)
+ continue;
+#endif
+
+ if (what & (EPOLLHUP|EPOLLERR)) {
+ ev = EV_READ | EV_WRITE;
+ } else {
+ if (what & EPOLLIN)
+ ev |= EV_READ;
+ if (what & EPOLLOUT)
+ ev |= EV_WRITE;
+ if (what & EPOLLRDHUP)
+ ev |= EV_CLOSED;
+ }
+
+ if (!ev)
+ continue;
+
+ evmap_io_active_(base, events[i].data.fd, ev | EV_ET);
+ }
+
+ if (res == epollop->nevents && epollop->nevents < MAX_NEVENT) {
+ /* We used all of the event space this time. We should
+ be ready for more events next time. */
+ int new_nevents = epollop->nevents * 2;
+ struct epoll_event *new_events;
+
+ new_events = mm_realloc(epollop->events,
+ new_nevents * sizeof(struct epoll_event));
+ if (new_events) {
+ epollop->events = new_events;
+ epollop->nevents = new_nevents;
+ }
+ }
+
+ return (0);
+}
+
+
+static void
+epoll_dealloc(struct event_base *base)
+{
+ struct epollop *epollop = base->evbase;
+
+ evsig_dealloc_(base);
+ if (epollop->events)
+ mm_free(epollop->events);
+ if (epollop->epfd >= 0)
+ close(epollop->epfd);
+#ifdef USING_TIMERFD
+ if (epollop->timerfd >= 0)
+ close(epollop->timerfd);
+#endif
+
+ memset(epollop, 0, sizeof(struct epollop));
+ mm_free(epollop);
+}
+
+#endif /* EVENT__HAVE_EPOLL */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/epoll_sub.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/epoll_sub.c
new file mode 100644
index 000000000..3f01f6a69
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/epoll_sub.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2003-2009 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "evconfig-private.h"
+#include <stdint.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+#include <errno.h>
+
+int
+epoll_create(int size)
+{
+#if !defined(__NR_epoll_create) && defined(__NR_epoll_create1)
+ if (size <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return (syscall(__NR_epoll_create1, 0));
+#else
+ return (syscall(__NR_epoll_create, size));
+#endif
+}
+
+int
+epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
+{
+
+ return (syscall(__NR_epoll_ctl, epfd, op, fd, event));
+}
+
+int
+epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
+{
+#if !defined(__NR_epoll_wait) && defined(__NR_epoll_pwait)
+ return (syscall(__NR_epoll_pwait, epfd, events, maxevents, timeout, NULL, 0));
+#else
+ return (syscall(__NR_epoll_wait, epfd, events, maxevents, timeout));
+#endif
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/epolltable-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/epolltable-internal.h
new file mode 100644
index 000000000..da30e0973
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/epolltable-internal.h
@@ -0,0 +1,1166 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EPOLLTABLE_INTERNAL_H_INCLUDED_
+#define EPOLLTABLE_INTERNAL_H_INCLUDED_
+
+/*
+ Here are the values we're masking off to decide what operations to do.
+ Note that since EV_READ|EV_WRITE.
+
+ Note also that this table is a little sparse, since ADD+DEL is
+ nonsensical ("xxx" in the list below.)
+
+ Note also also that we are shifting old_events by only 5 bits, since
+ EV_READ is 2 and EV_WRITE is 4.
+
+ The table was auto-generated with a python script, according to this
+ pseudocode:[*0]
+
+ If either the read or the write change is add+del:
+ This is impossible; Set op==-1, events=0.
+ Else, if either the read or the write change is add:
+ Set events to 0.
+ If the read change is add, or
+ (the read change is not del, and ev_read is in old_events):
+ Add EPOLLIN to events.
+ If the write change is add, or
+ (the write change is not del, and ev_write is in old_events):
+ Add EPOLLOUT to events.
+
+ If old_events is set:
+ Set op to EPOLL_CTL_MOD [*1,*2]
+ Else:
+ Set op to EPOLL_CTL_ADD [*3]
+
+ Else, if the read or the write change is del:
+ Set op to EPOLL_CTL_DEL.
+ If the read change is del:
+ If the write change is del:
+ Set events to EPOLLIN|EPOLLOUT
+ Else if ev_write is in old_events:
+ Set events to EPOLLOUT
+ Set op to EPOLL_CTL_MOD
+ Else
+ Set events to EPOLLIN
+ Else:
+ {The write change is del.}
+ If ev_read is in old_events:
+ Set events to EPOLLIN
+ Set op to EPOLL_CTL_MOD
+ Else:
+ Set the events to EPOLLOUT
+
+ Else:
+ There is no read or write change; set op to 0 and events to 0.
+
+ The logic is a little tricky, since we had no events set on the fd before,
+ we need to set op="ADD" and set events=the events we want to add. If we
+ had any events set on the fd before, and we want any events to remain on
+ the fd, we need to say op="MOD" and set events=the events we want to
+ remain. But if we want to delete the last event, we say op="DEL" and
+ set events=(any non-null pointer).
+
+ [*0] Actually, the Python script has gotten a bit more complicated, to
+ support EPOLLRDHUP.
+
+ [*1] This MOD is only a guess. MOD might fail with ENOENT if the file was
+ closed and a new file was opened with the same fd. If so, we'll retry
+ with ADD.
+
+ [*2] We can't replace this with a no-op even if old_events is the same as
+ the new events: if the file was closed and reopened, we need to retry
+ with an ADD. (We do a MOD in this case since "no change" is more
+ common than "close and reopen", so we'll usually wind up doing 1
+ syscalls instead of 2.)
+
+ [*3] This ADD is only a guess. There is a fun Linux kernel issue where if
+ you have two fds for the same file (via dup) and you ADD one to an
+ epfd, then close it, then re-create it with the same fd (via dup2 or an
+ unlucky dup), then try to ADD it again, you'll get an EEXIST, since the
+ struct epitem is not actually removed from the struct eventpoll until
+ the file itself is closed.
+
+ EV_CHANGE_ADD==1
+ EV_CHANGE_DEL==2
+ EV_READ ==2
+ EV_WRITE ==4
+ EV_CLOSED ==0x80
+
+ Bit 0: close change is add
+ Bit 1: close change is del
+ Bit 2: read change is add
+ Bit 3: read change is del
+ Bit 4: write change is add
+ Bit 5: write change is del
+ Bit 6: old events had EV_READ
+ Bit 7: old events had EV_WRITE
+ Bit 8: old events had EV_CLOSED
+*/
+
+#define EPOLL_OP_TABLE_INDEX(c) \
+ ( (((c)->close_change&(EV_CHANGE_ADD|EV_CHANGE_DEL))) | \
+ (((c)->read_change&(EV_CHANGE_ADD|EV_CHANGE_DEL)) << 2) | \
+ (((c)->write_change&(EV_CHANGE_ADD|EV_CHANGE_DEL)) << 4) | \
+ (((c)->old_events&(EV_READ|EV_WRITE)) << 5) | \
+ (((c)->old_events&(EV_CLOSED)) << 1) \
+ )
+
+#if EV_READ != 2 || EV_WRITE != 4 || EV_CLOSED != 0x80 || EV_CHANGE_ADD != 1 || EV_CHANGE_DEL != 2
+#error "Libevent's internals changed! Regenerate the op_table in epolltable-internal.h"
+#endif
+
+static const struct operation {
+ int events;
+ int op;
+} epoll_op_table[] = {
+ /* old= 0, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= 0, write: 0, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read: 0, close:del */
+ { EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= 0, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= 0, write: 0, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= 0, write: 0, read:del, close: 0 */
+ { EPOLLIN, EPOLL_CTL_DEL },
+ /* old= 0, write: 0, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read:del, close:del */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= 0, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= 0, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= 0, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= 0, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= 0, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:add, read: 0, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:add, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= 0, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= 0, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:del, read: 0, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= 0, write:del, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read: 0, close:del */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= 0, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:del, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:del, read:del, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= 0, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= 0, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= 0, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= 0, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= 0, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= 0, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= r, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= r, write: 0, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= r, write: 0, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= r, write: 0, read:del, close: 0 */
+ { EPOLLIN, EPOLL_CTL_DEL },
+ /* old= r, write: 0, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read:del, close:del */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= r, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= r, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= r, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= r, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= r, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= r, write:add, read: 0, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:add, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= r, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= r, write:add, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= r, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= r, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= r, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= r, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= r, write:del, read: 0, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write:del, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:del, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= r, write:del, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= r, write:del, read:del, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= r, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= r, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= r, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= r, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= r, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= r, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= r, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= r, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= r, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= r, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= r, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= r, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= r, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= r, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= r, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= r, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= r, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= r, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= r, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= r, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= r, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= r, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= w, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= w, write: 0, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= w, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= w, write: 0, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= w, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= w, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= w, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= w, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= w, write:add, read: 0, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:add, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= w, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= w, write:add, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= w, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= w, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= w, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= w, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= w, write:del, read: 0, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= w, write:del, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:del, read: 0, close:del */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= w, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= w, write:del, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= w, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= w, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= w, write:del, read:del, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= w, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= w, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= w, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= w, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= w, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= w, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= w, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= w, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= w, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= w, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= w, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= w, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= w, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= w, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= w, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= w, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= w, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= w, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= w, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= w, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= w, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= w, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= rw, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= rw, write: 0, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= rw, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= rw, write: 0, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= rw, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= rw, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= rw, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= rw, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:add, read: 0, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:add, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= rw, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= rw, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:del, read: 0, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:del, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:del, read:del, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= rw, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= rw, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= rw, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= rw, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= rw, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= rw, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= c, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= c, write: 0, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read: 0, close:del */
+ { EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= c, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= c, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= c, write: 0, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:del, close:del */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= c, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= c, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= c, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= c, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= c, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= c, write:add, read: 0, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= c, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= c, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= c, write:add, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= c, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= c, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= c, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= c, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= c, write:del, read: 0, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read: 0, close:del */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= c, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= c, write:del, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= c, write:del, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= c, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= c, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= c, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= c, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= c, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= c, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= c, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= c, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= c, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= c, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= c, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= c, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= c, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= c, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= c, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= c, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= c, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= c, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= c, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= c, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= c, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cr, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= cr, write: 0, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cr, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cr, write: 0, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:del, close:del */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= cr, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cr, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cr, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cr, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cr, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:add, read: 0, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:add, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cr, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cr, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:del, read: 0, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:del, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:del, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= cr, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cr, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cr, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= cr, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= cr, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cw, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= cw, write: 0, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cw, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cw, write: 0, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cw, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cw, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cw, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cw, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:add, read: 0, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:add, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cw, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cw, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:del, read: 0, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read: 0, close:del */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= cw, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:del, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:del, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= cw, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cw, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cw, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= cw, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= cw, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old=crw, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old=crw, write: 0, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old=crw, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old=crw, write: 0, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old=crw, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old=crw, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old=crw, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old=crw, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:add, read: 0, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:add, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old=crw, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old=crw, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:del, read: 0, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:del, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:del, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old=crw, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old=crw, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old=crw, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old=crw, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old=crw, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+};
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evbuffer-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/evbuffer-internal.h
new file mode 100644
index 000000000..cf4bddc80
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evbuffer-internal.h
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVBUFFER_INTERNAL_H_INCLUDED_
+#define EVBUFFER_INTERNAL_H_INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+#include "event2/util.h"
+#include "event2/event_struct.h"
+#include "util-internal.h"
+#include "defer-internal.h"
+
+/* Experimental cb flag: "never deferred." Implementation note:
+ * these callbacks may get an inaccurate view of n_del/n_added in their
+ * arguments. */
+#define EVBUFFER_CB_NODEFER 2
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+#include <sys/queue.h>
+
+/* Minimum allocation for a chain. We define this so that we're burning no
+ * more than 5% of each allocation on overhead. It would be nice to lose even
+ * less space, though. */
+#if EVENT__SIZEOF_VOID_P < 8
+#define MIN_BUFFER_SIZE 512
+#else
+#define MIN_BUFFER_SIZE 1024
+#endif
+
+/** A single evbuffer callback for an evbuffer. This function will be invoked
+ * when bytes are added to or removed from the evbuffer. */
+struct evbuffer_cb_entry {
+ /** Structures to implement a doubly-linked queue of callbacks */
+ LIST_ENTRY(evbuffer_cb_entry) next;
+ /** The callback function to invoke when this callback is called.
+ If EVBUFFER_CB_OBSOLETE is set in flags, the cb_obsolete field is
+ valid; otherwise, cb_func is valid. */
+ union {
+ evbuffer_cb_func cb_func;
+ evbuffer_cb cb_obsolete;
+ } cb;
+ /** Argument to pass to cb. */
+ void *cbarg;
+ /** Currently set flags on this callback. */
+ ev_uint32_t flags;
+};
+
+struct bufferevent;
+struct evbuffer_chain;
+struct evbuffer {
+ /** The first chain in this buffer's linked list of chains. */
+ struct evbuffer_chain *first;
+ /** The last chain in this buffer's linked list of chains. */
+ struct evbuffer_chain *last;
+
+ /** Pointer to the next pointer pointing at the 'last_with_data' chain.
+ *
+ * To unpack:
+ *
+ * The last_with_data chain is the last chain that has any data in it.
+ * If all chains in the buffer are empty, it is the first chain.
+ * If the buffer has no chains, it is NULL.
+ *
+ * The last_with_datap pointer points at _whatever 'next' pointer_
+ * points at the last_with_datap chain. If the last_with_data chain
+ * is the first chain, or it is NULL, then the last_with_datap pointer
+ * is &buf->first.
+ */
+ struct evbuffer_chain **last_with_datap;
+
+ /** Total amount of bytes stored in all chains.*/
+ size_t total_len;
+
+ /** Number of bytes we have added to the buffer since we last tried to
+ * invoke callbacks. */
+ size_t n_add_for_cb;
+ /** Number of bytes we have removed from the buffer since we last
+ * tried to invoke callbacks. */
+ size_t n_del_for_cb;
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ /** A lock used to mediate access to this buffer. */
+ void *lock;
+#endif
+ /** True iff we should free the lock field when we free this
+ * evbuffer. */
+ unsigned own_lock : 1;
+ /** True iff we should not allow changes to the front of the buffer
+ * (drains or prepends). */
+ unsigned freeze_start : 1;
+ /** True iff we should not allow changes to the end of the buffer
+ * (appends) */
+ unsigned freeze_end : 1;
+ /** True iff this evbuffer's callbacks are not invoked immediately
+ * upon a change in the buffer, but instead are deferred to be invoked
+ * from the event_base's loop. Useful for preventing enormous stack
+ * overflows when we have mutually recursive callbacks, and for
+ * serializing callbacks in a single thread. */
+ unsigned deferred_cbs : 1;
+#ifdef _WIN32
+ /** True iff this buffer is set up for overlapped IO. */
+ unsigned is_overlapped : 1;
+#endif
+ /** Zero or more EVBUFFER_FLAG_* bits */
+ ev_uint32_t flags;
+
+ /** Used to implement deferred callbacks. */
+ struct event_base *cb_queue;
+
+ /** A reference count on this evbuffer. When the reference count
+ * reaches 0, the buffer is destroyed. Manipulated with
+ * evbuffer_incref and evbuffer_decref_and_unlock and
+ * evbuffer_free. */
+ int refcnt;
+
+ /** A struct event_callback handle to make all of this buffer's callbacks
+ * invoked from the event loop. */
+ struct event_callback deferred;
+
+ /** A doubly-linked-list of callback functions */
+ LIST_HEAD(evbuffer_cb_queue, evbuffer_cb_entry) callbacks;
+
+ /** The parent bufferevent object this evbuffer belongs to.
+ * NULL if the evbuffer stands alone. */
+ struct bufferevent *parent;
+};
+
+#if EVENT__SIZEOF_OFF_T < EVENT__SIZEOF_SIZE_T
+typedef ev_ssize_t ev_misalign_t;
+#define EVBUFFER_CHAIN_MAX ((size_t)EV_SSIZE_MAX)
+#else
+typedef ev_off_t ev_misalign_t;
+#if EVENT__SIZEOF_OFF_T > EVENT__SIZEOF_SIZE_T
+#define EVBUFFER_CHAIN_MAX EV_SIZE_MAX
+#else
+#define EVBUFFER_CHAIN_MAX ((size_t)EV_SSIZE_MAX)
+#endif
+#endif
+
+/** A single item in an evbuffer. */
+struct evbuffer_chain {
+ /** points to next buffer in the chain */
+ struct evbuffer_chain *next;
+
+ /** total allocation available in the buffer field. */
+ size_t buffer_len;
+
+ /** unused space at the beginning of buffer or an offset into a
+ * file for sendfile buffers. */
+ ev_misalign_t misalign;
+
+ /** Offset into buffer + misalign at which to start writing.
+ * In other words, the total number of bytes actually stored
+ * in buffer. */
+ size_t off;
+
+ /** Set if special handling is required for this chain */
+ unsigned flags;
+#define EVBUFFER_FILESEGMENT 0x0001 /**< A chain used for a file segment */
+#define EVBUFFER_SENDFILE 0x0002 /**< a chain used with sendfile */
+#define EVBUFFER_REFERENCE 0x0004 /**< a chain with a mem reference */
+#define EVBUFFER_IMMUTABLE 0x0008 /**< read-only chain */
+ /** a chain that mustn't be reallocated or freed, or have its contents
+ * memmoved, until the chain is un-pinned. */
+#define EVBUFFER_MEM_PINNED_R 0x0010
+#define EVBUFFER_MEM_PINNED_W 0x0020
+#define EVBUFFER_MEM_PINNED_ANY (EVBUFFER_MEM_PINNED_R|EVBUFFER_MEM_PINNED_W)
+ /** a chain that should be freed, but can't be freed until it is
+ * un-pinned. */
+#define EVBUFFER_DANGLING 0x0040
+ /** a chain that is a referenced copy of another chain */
+#define EVBUFFER_MULTICAST 0x0080
+
+ /** number of references to this chain */
+ int refcnt;
+
+ /** Usually points to the read-write memory belonging to this
+ * buffer allocated as part of the evbuffer_chain allocation.
+ * For mmap, this can be a read-only buffer and
+ * EVBUFFER_IMMUTABLE will be set in flags. For sendfile, it
+ * may point to NULL.
+ */
+ unsigned char *buffer;
+};
+
+/** callback for a reference chain; lets us know what to do with it when
+ * we're done with it. Lives at the end of an evbuffer_chain with the
+ * EVBUFFER_REFERENCE flag set */
+struct evbuffer_chain_reference {
+ evbuffer_ref_cleanup_cb cleanupfn;
+ void *extra;
+};
+
+/** File segment for a file-segment chain. Lives at the end of an
+ * evbuffer_chain with the EVBUFFER_FILESEGMENT flag set. */
+struct evbuffer_chain_file_segment {
+ struct evbuffer_file_segment *segment;
+#ifdef _WIN32
+ /** If we're using CreateFileMapping, this is the handle to the view. */
+ HANDLE view_handle;
+#endif
+};
+
+/* Declared in event2/buffer.h; defined here. */
+struct evbuffer_file_segment {
+ void *lock; /**< lock prevent concurrent access to refcnt */
+ int refcnt; /**< Reference count for this file segment */
+ unsigned flags; /**< combination of EVBUF_FS_* flags */
+
+ /** What kind of file segment is this? */
+ unsigned can_sendfile : 1;
+ unsigned is_mapping : 1;
+
+ /** The fd that we read the data from. */
+ int fd;
+ /** If we're using mmap, this is the raw mapped memory. */
+ void *mapping;
+#ifdef _WIN32
+ /** If we're using CreateFileMapping, this is the mapping */
+ HANDLE mapping_handle;
+#endif
+ /** If we're using mmap or IO, this is the content of the file
+ * segment. */
+ char *contents;
+ /** Position of this segment within the file. */
+ ev_off_t file_offset;
+ /** If we're using mmap, this is the offset within 'mapping' where
+ * this data segment begins. */
+ ev_off_t mmap_offset;
+ /** The length of this segment. */
+ ev_off_t length;
+ /** Cleanup callback function */
+ evbuffer_file_segment_cleanup_cb cleanup_cb;
+ /** Argument to be pass to cleanup callback function */
+ void *cleanup_cb_arg;
+};
+
+/** Information about the multicast parent of a chain. Lives at the
+ * end of an evbuffer_chain with the EVBUFFER_MULTICAST flag set. */
+struct evbuffer_multicast_parent {
+ /** source buffer the multicast parent belongs to */
+ struct evbuffer *source;
+ /** multicast parent for this chain */
+ struct evbuffer_chain *parent;
+};
+
+#define EVBUFFER_CHAIN_SIZE sizeof(struct evbuffer_chain)
+/** Return a pointer to extra data allocated along with an evbuffer. */
+#define EVBUFFER_CHAIN_EXTRA(t, c) (t *)((struct evbuffer_chain *)(c) + 1)
+
+/** Assert that we are holding the lock on an evbuffer */
+#define ASSERT_EVBUFFER_LOCKED(buffer) \
+ EVLOCK_ASSERT_LOCKED((buffer)->lock)
+
+#define EVBUFFER_LOCK(buffer) \
+ do { \
+ EVLOCK_LOCK((buffer)->lock, 0); \
+ } while (0)
+#define EVBUFFER_UNLOCK(buffer) \
+ do { \
+ EVLOCK_UNLOCK((buffer)->lock, 0); \
+ } while (0)
+#define EVBUFFER_LOCK2(buffer1, buffer2) \
+ do { \
+ EVLOCK_LOCK2((buffer1)->lock, (buffer2)->lock, 0, 0); \
+ } while (0)
+#define EVBUFFER_UNLOCK2(buffer1, buffer2) \
+ do { \
+ EVLOCK_UNLOCK2((buffer1)->lock, (buffer2)->lock, 0, 0); \
+ } while (0)
+
+/** Increase the reference count of buf by one. */
+void evbuffer_incref_(struct evbuffer *buf);
+/** Increase the reference count of buf by one and acquire the lock. */
+void evbuffer_incref_and_lock_(struct evbuffer *buf);
+/** Pin a single buffer chain using a given flag. A pinned chunk may not be
+ * moved or freed until it is unpinned. */
+void evbuffer_chain_pin_(struct evbuffer_chain *chain, unsigned flag);
+/** Unpin a single buffer chain using a given flag. */
+void evbuffer_chain_unpin_(struct evbuffer_chain *chain, unsigned flag);
+/** As evbuffer_free, but requires that we hold a lock on the buffer, and
+ * releases the lock before freeing it and the buffer. */
+void evbuffer_decref_and_unlock_(struct evbuffer *buffer);
+
+/** As evbuffer_expand, but does not guarantee that the newly allocated memory
+ * is contiguous. Instead, it may be split across two or more chunks. */
+int evbuffer_expand_fast_(struct evbuffer *, size_t, int);
+
+/** Helper: prepares for a readv/WSARecv call by expanding the buffer to
+ * hold enough memory to read 'howmuch' bytes in possibly noncontiguous memory.
+ * Sets up the one or two iovecs in 'vecs' to point to the free memory and its
+ * extent, and *chainp to point to the first chain that we'll try to read into.
+ * Returns the number of vecs used.
+ */
+int evbuffer_read_setup_vecs_(struct evbuffer *buf, ev_ssize_t howmuch,
+ struct evbuffer_iovec *vecs, int n_vecs, struct evbuffer_chain ***chainp,
+ int exact);
+
+/* Helper macro: copies an evbuffer_iovec in ei to a win32 WSABUF in i. */
+#define WSABUF_FROM_EVBUFFER_IOV(i,ei) do { \
+ (i)->buf = (ei)->iov_base; \
+ (i)->len = (unsigned long)(ei)->iov_len; \
+ } while (0)
+/* XXXX the cast above is safe for now, but not if we allow mmaps on win64.
+ * See note in buffer_iocp's launch_write function */
+
+/** Set the parent bufferevent object for buf to bev */
+void evbuffer_set_parent_(struct evbuffer *buf, struct bufferevent *bev);
+
+void evbuffer_invoke_callbacks_(struct evbuffer *buf);
+
+
+int evbuffer_get_callbacks_(struct evbuffer *buffer,
+ struct event_callback **cbs,
+ int max_cbs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVBUFFER_INTERNAL_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evconfig-private.h.cmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/evconfig-private.h.cmake
new file mode 100644
index 000000000..32f04794d
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evconfig-private.h.cmake
@@ -0,0 +1,35 @@
+
+#ifndef EVCONFIG_PRIVATE_H_INCLUDED_
+#define EVCONFIG_PRIVATE_H_INCLUDED_
+
+/* Enable extensions on AIX 3, Interix. */
+#cmakedefine _ALL_SOURCE
+
+/* Enable GNU extensions on systems that have them. */
+#cmakedefine _GNU_SOURCE 1
+
+/* Enable threading extensions on Solaris. */
+#cmakedefine _POSIX_PTHREAD_SEMANTICS 1
+
+/* Enable extensions on HP NonStop. */
+#cmakedefine _TANDEM_SOURCE 1
+
+/* Enable general extensions on Solaris. */
+#cmakedefine __EXTENSIONS__
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#cmakedefine _FILE_OFFSET_BITS 1
+/* Define for large files, on AIX-style hosts. */
+#cmakedefine _LARGE_FILES 1
+
+/* Define to 1 if on MINIX. */
+#cmakedefine _MINIX 1
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#cmakedefine _POSIX_1_SOURCE 1
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#cmakedefine _POSIX_SOURCE 1
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evconfig-private.h.in b/fluent-bit/lib/monkey/mk_core/deps/libevent/evconfig-private.h.in
new file mode 100644
index 000000000..7b3dfdb10
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evconfig-private.h.in
@@ -0,0 +1,48 @@
+/* evconfig-private.h template - see "Configuration Header Templates" */
+/* in AC manual. Kevin Bowling <kevin.bowling@kev009.com */
+#ifndef EVCONFIG_PRIVATE_H_INCLUDED_
+#define EVCONFIG_PRIVATE_H_INCLUDED_
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#ifndef _MINIX
+#undef _MINIX
+#endif
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#ifndef _POSIX_1_SOURCE
+#undef _POSIX_1_SOURCE
+#endif
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#ifndef _POSIX_SOURCE
+#undef _POSIX_SOURCE
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evdns.3 b/fluent-bit/lib/monkey/mk_core/deps/libevent/evdns.3
new file mode 100644
index 000000000..10414fa2e
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evdns.3
@@ -0,0 +1,322 @@
+.\"
+.\" Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd October 7, 2006
+.Dt EVDNS 3
+.Os
+.Sh NAME
+.Nm evdns_init
+.Nm evdns_shutdown
+.Nm evdns_err_to_string
+.Nm evdns_nameserver_add
+.Nm evdns_count_nameservers
+.Nm evdns_clear_nameservers_and_suspend
+.Nm evdns_resume
+.Nm evdns_nameserver_ip_add
+.Nm evdns_resolve_ipv4
+.Nm evdns_resolve_reverse
+.Nm evdns_resolv_conf_parse
+.Nm evdns_config_windows_nameservers
+.Nm evdns_search_clear
+.Nm evdns_search_add
+.Nm evdns_search_ndots_set
+.Nm evdns_set_log_fn
+.Nd asynchronous functions for DNS resolution.
+.Sh SYNOPSIS
+.Fd #include <sys/time.h>
+.Fd #include <event.h>
+.Fd #include <evdns.h>
+.Ft int
+.Fn evdns_init
+.Ft void
+.Fn evdns_shutdown "int fail_requests"
+.Ft "const char *"
+.Fn evdns_err_to_string "int err"
+.Ft int
+.Fn evdns_nameserver_add "unsigned long int address"
+.Ft int
+.Fn evdns_count_nameservers
+.Ft int
+.Fn evdns_clear_nameservers_and_suspend
+.Ft int
+.Fn evdns_resume
+.Ft int
+.Fn evdns_nameserver_ip_add(const char *ip_as_string);
+.Ft int
+.Fn evdns_resolve_ipv4 "const char *name" "int flags" "evdns_callback_type callback" "void *ptr"
+.Ft int
+.Fn evdns_resolve_reverse "struct in_addr *in" "int flags" "evdns_callback_type callback" "void *ptr"
+.Ft int
+.Fn evdns_resolv_conf_parse "int flags" "const char *"
+.Ft void
+.Fn evdns_search_clear
+.Ft void
+.Fn evdns_search_add "const char *domain"
+.Ft void
+.Fn evdns_search_ndots_set "const int ndots"
+.Ft void
+.Fn evdns_set_log_fn "evdns_debug_log_fn_type fn"
+.Ft int
+.Fn evdns_config_windows_nameservers
+.Sh DESCRIPTION
+Welcome, gentle reader
+.Pp
+Async DNS lookups are really a whole lot harder than they should be,
+mostly stemming from the fact that the libc resolver has never been
+very good at them. Before you use this library you should see if libc
+can do the job for you with the modern async call getaddrinfo_a
+(see http://www.imperialviolet.org/page25.html#e498). Otherwise,
+please continue.
+.Pp
+This code is based on libevent and you must call event_init before
+any of the APIs in this file. You must also seed the OpenSSL random
+source if you are using OpenSSL for ids (see below).
+.Pp
+This library is designed to be included and shipped with your source
+code. You statically link with it. You should also test for the
+existence of strtok_r and define HAVE_STRTOK_R if you have it.
+.Pp
+The DNS protocol requires a good source of id numbers and these
+numbers should be unpredictable for spoofing reasons. There are
+three methods for generating them here and you must define exactly
+one of them. In increasing order of preference:
+.Pp
+.Bl -tag -width "DNS_USE_GETTIMEOFDAY_FOR_ID" -compact -offset indent
+.It DNS_USE_GETTIMEOFDAY_FOR_ID
+Using the bottom 16 bits of the usec result from gettimeofday. This
+is a pretty poor solution but should work anywhere.
+.It DNS_USE_CPU_CLOCK_FOR_ID
+Using the bottom 16 bits of the nsec result from the CPU's time
+counter. This is better, but may not work everywhere. Requires
+POSIX realtime support and you'll need to link against -lrt on
+glibc systems at least.
+.It DNS_USE_OPENSSL_FOR_ID
+Uses the OpenSSL RAND_bytes call to generate the data. You must
+have seeded the pool before making any calls to this library.
+.El
+.Pp
+The library keeps track of the state of nameservers and will avoid
+them when they go down. Otherwise it will round robin between them.
+.Pp
+Quick start guide:
+ #include "evdns.h"
+ void callback(int result, char type, int count, int ttl,
+ void *addresses, void *arg);
+ evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
+ evdns_resolve("www.hostname.com", 0, callback, NULL);
+.Pp
+When the lookup is complete the callback function is called. The
+first argument will be one of the DNS_ERR_* defines in evdns.h.
+Hopefully it will be DNS_ERR_NONE, in which case type will be
+DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
+which the data can be cached for (in seconds), addresses will point
+to an array of uint32_t's and arg will be whatever you passed to
+evdns_resolve.
+.Pp
+Searching:
+.Pp
+In order for this library to be a good replacement for glibc's resolver it
+supports searching. This involves setting a list of default domains, in
+which names will be queried for. The number of dots in the query name
+determines the order in which this list is used.
+.Pp
+Searching appears to be a single lookup from the point of view of the API,
+although many DNS queries may be generated from a single call to
+evdns_resolve. Searching can also drastically slow down the resolution
+of names.
+.Pp
+To disable searching:
+.Bl -enum -compact -offset indent
+.It
+Never set it up. If you never call
+.Fn evdns_resolv_conf_parse,
+.Fn evdns_init,
+or
+.Fn evdns_search_add
+then no searching will occur.
+.It
+If you do call
+.Fn evdns_resolv_conf_parse
+then don't pass
+.Va DNS_OPTION_SEARCH
+(or
+.Va DNS_OPTIONS_ALL,
+which implies it).
+.It
+When calling
+.Fn evdns_resolve,
+pass the
+.Va DNS_QUERY_NO_SEARCH
+flag.
+.El
+.Pp
+The order of searches depends on the number of dots in the name. If the
+number is greater than the ndots setting then the names is first tried
+globally. Otherwise each search domain is appended in turn.
+.Pp
+The ndots setting can either be set from a resolv.conf, or by calling
+evdns_search_ndots_set.
+.Pp
+For example, with ndots set to 1 (the default) and a search domain list of
+["myhome.net"]:
+ Query: www
+ Order: www.myhome.net, www.
+.Pp
+ Query: www.abc
+ Order: www.abc., www.abc.myhome.net
+.Pp
+.Sh API reference
+.Pp
+.Bl -tag -width 0123456
+.It Ft int Fn evdns_init
+Initializes support for non-blocking name resolution by calling
+.Fn evdns_resolv_conf_parse
+on UNIX and
+.Fn evdns_config_windows_nameservers
+on Windows.
+.It Ft int Fn evdns_nameserver_add "unsigned long int address"
+Add a nameserver. The address should be an IP address in
+network byte order. The type of address is chosen so that
+it matches in_addr.s_addr.
+Returns non-zero on error.
+.It Ft int Fn evdns_nameserver_ip_add "const char *ip_as_string"
+This wraps the above function by parsing a string as an IP
+address and adds it as a nameserver.
+Returns non-zero on error
+.It Ft int Fn evdns_resolve "const char *name" "int flags" "evdns_callback_type callback" "void *ptr"
+Resolve a name. The name parameter should be a DNS name.
+The flags parameter should be 0, or DNS_QUERY_NO_SEARCH
+which disables searching for this query. (see defn of
+searching above).
+.Pp
+The callback argument is a function which is called when
+this query completes and ptr is an argument which is passed
+to that callback function.
+.Pp
+Returns non-zero on error
+.It Ft void Fn evdns_search_clear
+Clears the list of search domains
+.It Ft void Fn evdns_search_add "const char *domain"
+Add a domain to the list of search domains
+.It Ft void Fn evdns_search_ndots_set "int ndots"
+Set the number of dots which, when found in a name, causes
+the first query to be without any search domain.
+.It Ft int Fn evdns_count_nameservers "void"
+Return the number of configured nameservers (not necessarily the
+number of running nameservers). This is useful for double-checking
+whether our calls to the various nameserver configuration functions
+have been successful.
+.It Ft int Fn evdns_clear_nameservers_and_suspend "void"
+Remove all currently configured nameservers, and suspend all pending
+resolves. Resolves will not necessarily be re-attempted until
+evdns_resume() is called.
+.It Ft int Fn evdns_resume "void"
+Re-attempt resolves left in limbo after an earlier call to
+evdns_clear_nameservers_and_suspend().
+.It Ft int Fn evdns_config_windows_nameservers "void"
+Attempt to configure a set of nameservers based on platform settings on
+a win32 host. Preferentially tries to use GetNetworkParams; if that fails,
+looks in the registry. Returns 0 on success, nonzero on failure.
+.It Ft int Fn evdns_resolv_conf_parse "int flags" "const char *filename"
+Parse a resolv.conf like file from the given filename.
+.Pp
+See the man page for resolv.conf for the format of this file.
+The flags argument determines what information is parsed from
+this file:
+.Bl -tag -width "DNS_OPTION_NAMESERVERS" -offset indent -compact -nested
+.It DNS_OPTION_SEARCH
+domain, search and ndots options
+.It DNS_OPTION_NAMESERVERS
+nameserver lines
+.It DNS_OPTION_MISC
+timeout and attempts options
+.It DNS_OPTIONS_ALL
+all of the above
+.El
+.Pp
+The following directives are not parsed from the file:
+ sortlist, rotate, no-check-names, inet6, debug
+.Pp
+Returns non-zero on error:
+.Bl -tag -width "0" -offset indent -compact -nested
+.It 0
+no errors
+.It 1
+failed to open file
+.It 2
+failed to stat file
+.It 3
+file too large
+.It 4
+out of memory
+.It 5
+short read from file
+.El
+.El
+.Sh Internals:
+Requests are kept in two queues. The first is the inflight queue. In
+this queue requests have an allocated transaction id and nameserver.
+They will soon be transmitted if they haven't already been.
+.Pp
+The second is the waiting queue. The size of the inflight ring is
+limited and all other requests wait in waiting queue for space. This
+bounds the number of concurrent requests so that we don't flood the
+nameserver. Several algorithms require a full walk of the inflight
+queue and so bounding its size keeps thing going nicely under huge
+(many thousands of requests) loads.
+.Pp
+If a nameserver loses too many requests it is considered down and we
+try not to use it. After a while we send a probe to that nameserver
+(a lookup for google.com) and, if it replies, we consider it working
+again. If the nameserver fails a probe we wait longer to try again
+with the next probe.
+.Sh SEE ALSO
+.Xr event 3 ,
+.Xr gethostbyname 3 ,
+.Xr resolv.conf 5
+.Sh HISTORY
+The
+.Nm evdns
+API was developed by Adam Langley on top of the
+.Nm libevent
+API.
+The code was integrate into
+.Nm Tor
+by Nick Mathewson and finally put into
+.Nm libevent
+itself by Niels Provos.
+.Sh AUTHORS
+The
+.Nm evdns
+API and code was written by Adam Langley with significant
+contributions by Nick Mathewson.
+.Sh BUGS
+This documentation is neither complete nor authoritative.
+If you are in doubt about the usage of this API then
+check the source code to find out how it works, write
+up the missing piece of documentation and send it to
+me for inclusion in this man page.
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evdns.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/evdns.c
new file mode 100644
index 000000000..e9dbc35c6
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evdns.c
@@ -0,0 +1,4767 @@
+/* Copyright 2006-2007 Niels Provos
+ * Copyright 2007-2012 Nick Mathewson and Niels Provos
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Based on software by Adam Langly. Adam's original message:
+ *
+ * Async DNS Library
+ * Adam Langley <agl@imperialviolet.org>
+ * http://www.imperialviolet.org/eventdns.html
+ * Public Domain code
+ *
+ * This software is Public Domain. To view a copy of the public domain dedication,
+ * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
+ * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *
+ * I ask and expect, but do not require, that all derivative works contain an
+ * attribution similar to:
+ * Parts developed by Adam Langley <agl@imperialviolet.org>
+ *
+ * You may wish to replace the word "Parts" with something else depending on
+ * the amount of original code.
+ *
+ * (Derivative works does not include programs which link against, run or include
+ * the source verbatim in their source distributions)
+ *
+ * Version: 0.1b
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
+
+#ifndef _FORTIFY_SOURCE
+#define _FORTIFY_SOURCE 3
+#endif
+
+#include <string.h>
+#include <fcntl.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef EVENT__HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <limits.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdarg.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#ifndef _WIN32_IE
+#define _WIN32_IE 0x400
+#endif
+#include <shlobj.h>
+#endif
+
+#include "event2/dns.h"
+#include "event2/dns_struct.h"
+#include "event2/dns_compat.h"
+#include "event2/util.h"
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/thread.h"
+
+#include "defer-internal.h"
+#include "log-internal.h"
+#include "mm-internal.h"
+#include "strlcpy-internal.h"
+#include "ipv6-internal.h"
+#include "util-internal.h"
+#include "evthread-internal.h"
+#ifdef _WIN32
+#include <ctype.h>
+#include <winsock2.h>
+#include <windows.h>
+#include <iphlpapi.h>
+#include <io.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#ifdef EVENT__HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+
+#define EVDNS_LOG_DEBUG EVENT_LOG_DEBUG
+#define EVDNS_LOG_WARN EVENT_LOG_WARN
+#define EVDNS_LOG_MSG EVENT_LOG_MSG
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+
+#include <stdio.h>
+
+#undef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+#define ASSERT_VALID_REQUEST(req) \
+ EVUTIL_ASSERT((req)->handle && (req)->handle->current_req == (req))
+
+#define u64 ev_uint64_t
+#define u32 ev_uint32_t
+#define u16 ev_uint16_t
+#define u8 ev_uint8_t
+
+/* maximum number of addresses from a single packet */
+/* that we bother recording */
+#define MAX_V4_ADDRS 32
+#define MAX_V6_ADDRS 32
+
+
+#define TYPE_A EVDNS_TYPE_A
+#define TYPE_CNAME 5
+#define TYPE_PTR EVDNS_TYPE_PTR
+#define TYPE_SOA EVDNS_TYPE_SOA
+#define TYPE_AAAA EVDNS_TYPE_AAAA
+
+#define CLASS_INET EVDNS_CLASS_INET
+
+/* Persistent handle. We keep this separate from 'struct request' since we
+ * need some object to last for as long as an evdns_request is outstanding so
+ * that it can be canceled, whereas a search request can lead to multiple
+ * 'struct request' instances being created over its lifetime. */
+struct evdns_request {
+ struct request *current_req;
+ struct evdns_base *base;
+
+ int pending_cb; /* Waiting for its callback to be invoked; not
+ * owned by event base any more. */
+
+ /* elements used by the searching code */
+ int search_index;
+ struct search_state *search_state;
+ char *search_origname; /* needs to be free()ed */
+ int search_flags;
+};
+
+struct request {
+ u8 *request; /* the dns packet data */
+ u8 request_type; /* TYPE_PTR or TYPE_A or TYPE_AAAA */
+ unsigned int request_len;
+ int reissue_count;
+ int tx_count; /* the number of times that this packet has been sent */
+ void *user_pointer; /* the pointer given to us for this request */
+ evdns_callback_type user_callback;
+ struct nameserver *ns; /* the server which we last sent it */
+
+ /* these objects are kept in a circular list */
+ /* XXX We could turn this into a CIRCLEQ. */
+ struct request *next, *prev;
+
+ struct event timeout_event;
+
+ u16 trans_id; /* the transaction id */
+ unsigned request_appended :1; /* true if the request pointer is data which follows this struct */
+ unsigned transmit_me :1; /* needs to be transmitted */
+
+ /* XXXX This is a horrible hack. */
+ char **put_cname_in_ptr; /* store the cname here if we get one. */
+
+ struct evdns_base *base;
+
+ struct evdns_request *handle;
+};
+
+struct reply {
+ unsigned int type;
+ unsigned int have_answer : 1;
+ union {
+ struct {
+ u32 addrcount;
+ u32 addresses[MAX_V4_ADDRS];
+ } a;
+ struct {
+ u32 addrcount;
+ struct in6_addr addresses[MAX_V6_ADDRS];
+ } aaaa;
+ struct {
+ char name[HOST_NAME_MAX];
+ } ptr;
+ } data;
+};
+
+struct nameserver {
+ evutil_socket_t socket; /* a connected UDP socket */
+ struct sockaddr_storage address;
+ ev_socklen_t addrlen;
+ int failed_times; /* number of times which we have given this server a chance */
+ int timedout; /* number of times in a row a request has timed out */
+ struct event event;
+ /* these objects are kept in a circular list */
+ struct nameserver *next, *prev;
+ struct event timeout_event; /* used to keep the timeout for */
+ /* when we next probe this server. */
+ /* Valid if state == 0 */
+ /* Outstanding probe request for this nameserver, if any */
+ struct evdns_request *probe_request;
+ char state; /* zero if we think that this server is down */
+ char choked; /* true if we have an EAGAIN from this server's socket */
+ char write_waiting; /* true if we are waiting for EV_WRITE events */
+ struct evdns_base *base;
+
+ /* Number of currently inflight requests: used
+ * to track when we should add/del the event. */
+ int requests_inflight;
+};
+
+
+/* Represents a local port where we're listening for DNS requests. Right now, */
+/* only UDP is supported. */
+struct evdns_server_port {
+ evutil_socket_t socket; /* socket we use to read queries and write replies. */
+ int refcnt; /* reference count. */
+ char choked; /* Are we currently blocked from writing? */
+ char closing; /* Are we trying to close this port, pending writes? */
+ evdns_request_callback_fn_type user_callback; /* Fn to handle requests */
+ void *user_data; /* Opaque pointer passed to user_callback */
+ struct event event; /* Read/write event */
+ /* circular list of replies that we want to write. */
+ struct server_request *pending_replies;
+ struct event_base *event_base;
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ void *lock;
+#endif
+};
+
+/* Represents part of a reply being built. (That is, a single RR.) */
+struct server_reply_item {
+ struct server_reply_item *next; /* next item in sequence. */
+ char *name; /* name part of the RR */
+ u16 type; /* The RR type */
+ u16 class; /* The RR class (usually CLASS_INET) */
+ u32 ttl; /* The RR TTL */
+ char is_name; /* True iff data is a label */
+ u16 datalen; /* Length of data; -1 if data is a label */
+ void *data; /* The contents of the RR */
+};
+
+/* Represents a request that we've received as a DNS server, and holds */
+/* the components of the reply as we're constructing it. */
+struct server_request {
+ /* Pointers to the next and previous entries on the list of replies */
+ /* that we're waiting to write. Only set if we have tried to respond */
+ /* and gotten EAGAIN. */
+ struct server_request *next_pending;
+ struct server_request *prev_pending;
+
+ u16 trans_id; /* Transaction id. */
+ struct evdns_server_port *port; /* Which port received this request on? */
+ struct sockaddr_storage addr; /* Where to send the response */
+ ev_socklen_t addrlen; /* length of addr */
+
+ int n_answer; /* how many answer RRs have been set? */
+ int n_authority; /* how many authority RRs have been set? */
+ int n_additional; /* how many additional RRs have been set? */
+
+ struct server_reply_item *answer; /* linked list of answer RRs */
+ struct server_reply_item *authority; /* linked list of authority RRs */
+ struct server_reply_item *additional; /* linked list of additional RRs */
+
+ /* Constructed response. Only set once we're ready to send a reply. */
+ /* Once this is set, the RR fields are cleared, and no more should be set. */
+ char *response;
+ size_t response_len;
+
+ /* Caller-visible fields: flags, questions. */
+ struct evdns_server_request base;
+};
+
+struct evdns_base {
+ /* An array of n_req_heads circular lists for inflight requests.
+ * Each inflight request req is in req_heads[req->trans_id % n_req_heads].
+ */
+ struct request **req_heads;
+ /* A circular list of requests that we're waiting to send, but haven't
+ * sent yet because there are too many requests inflight */
+ struct request *req_waiting_head;
+ /* A circular list of nameservers. */
+ struct nameserver *server_head;
+ int n_req_heads;
+
+ struct event_base *event_base;
+
+ /* The number of good nameservers that we have */
+ int global_good_nameservers;
+
+ /* inflight requests are contained in the req_head list */
+ /* and are actually going out across the network */
+ int global_requests_inflight;
+ /* requests which aren't inflight are in the waiting list */
+ /* and are counted here */
+ int global_requests_waiting;
+
+ int global_max_requests_inflight;
+
+ struct timeval global_timeout; /* 5 seconds by default */
+ int global_max_reissues; /* a reissue occurs when we get some errors from the server */
+ int global_max_retransmits; /* number of times we'll retransmit a request which timed out */
+ /* number of timeouts in a row before we consider this server to be down */
+ int global_max_nameserver_timeout;
+ /* true iff we will use the 0x20 hack to prevent poisoning attacks. */
+ int global_randomize_case;
+
+ /* The first time that a nameserver fails, how long do we wait before
+ * probing to see if it has returned? */
+ struct timeval global_nameserver_probe_initial_timeout;
+
+ /** Port to bind to for outgoing DNS packets. */
+ struct sockaddr_storage global_outgoing_address;
+ /** ev_socklen_t for global_outgoing_address. 0 if it isn't set. */
+ ev_socklen_t global_outgoing_addrlen;
+
+ struct timeval global_getaddrinfo_allow_skew;
+
+ int getaddrinfo_ipv4_timeouts;
+ int getaddrinfo_ipv6_timeouts;
+ int getaddrinfo_ipv4_answered;
+ int getaddrinfo_ipv6_answered;
+
+ struct search_state *global_search_state;
+
+ TAILQ_HEAD(hosts_list, hosts_entry) hostsdb;
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ void *lock;
+#endif
+
+ int disable_when_inactive;
+};
+
+struct hosts_entry {
+ TAILQ_ENTRY(hosts_entry) next;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } addr;
+ int addrlen;
+ char hostname[1];
+};
+
+static struct evdns_base *current_base = NULL;
+
+struct evdns_base *
+evdns_get_global_base(void)
+{
+ return current_base;
+}
+
+/* Given a pointer to an evdns_server_request, get the corresponding */
+/* server_request. */
+#define TO_SERVER_REQUEST(base_ptr) \
+ ((struct server_request*) \
+ (((char*)(base_ptr) - evutil_offsetof(struct server_request, base))))
+
+#define REQ_HEAD(base, id) ((base)->req_heads[id % (base)->n_req_heads])
+
+static struct nameserver *nameserver_pick(struct evdns_base *base);
+static void evdns_request_insert(struct request *req, struct request **head);
+static void evdns_request_remove(struct request *req, struct request **head);
+static void nameserver_ready_callback(evutil_socket_t fd, short events, void *arg);
+static int evdns_transmit(struct evdns_base *base);
+static int evdns_request_transmit(struct request *req);
+static void nameserver_send_probe(struct nameserver *const ns);
+static void search_request_finished(struct evdns_request *const);
+static int search_try_next(struct evdns_request *const req);
+static struct request *search_request_new(struct evdns_base *base, struct evdns_request *handle, int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg);
+static void evdns_requests_pump_waiting_queue(struct evdns_base *base);
+static u16 transaction_id_pick(struct evdns_base *base);
+static struct request *request_new(struct evdns_base *base, struct evdns_request *handle, int type, const char *name, int flags, evdns_callback_type callback, void *ptr);
+static void request_submit(struct request *const req);
+
+static int server_request_free(struct server_request *req);
+static void server_request_free_answers(struct server_request *req);
+static void server_port_free(struct evdns_server_port *port);
+static void server_port_ready_callback(evutil_socket_t fd, short events, void *arg);
+static int evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename);
+static int evdns_base_set_option_impl(struct evdns_base *base,
+ const char *option, const char *val, int flags);
+static void evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests);
+static void evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg);
+
+static int strtoint(const char *const str);
+
+#ifdef EVENT__DISABLE_THREAD_SUPPORT
+#define EVDNS_LOCK(base) EVUTIL_NIL_STMT_
+#define EVDNS_UNLOCK(base) EVUTIL_NIL_STMT_
+#define ASSERT_LOCKED(base) EVUTIL_NIL_STMT_
+#else
+#define EVDNS_LOCK(base) \
+ EVLOCK_LOCK((base)->lock, 0)
+#define EVDNS_UNLOCK(base) \
+ EVLOCK_UNLOCK((base)->lock, 0)
+#define ASSERT_LOCKED(base) \
+ EVLOCK_ASSERT_LOCKED((base)->lock)
+#endif
+
+static evdns_debug_log_fn_type evdns_log_fn = NULL;
+
+void
+evdns_set_log_fn(evdns_debug_log_fn_type fn)
+{
+ evdns_log_fn = fn;
+}
+
+#ifdef __GNUC__
+#define EVDNS_LOG_CHECK __attribute__ ((format(printf, 2, 3)))
+#else
+#define EVDNS_LOG_CHECK
+#endif
+
+static void evdns_log_(int severity, const char *fmt, ...) EVDNS_LOG_CHECK;
+static void
+evdns_log_(int severity, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args,fmt);
+ if (evdns_log_fn) {
+ char buf[512];
+ int is_warn = (severity == EVDNS_LOG_WARN);
+ evutil_vsnprintf(buf, sizeof(buf), fmt, args);
+ evdns_log_fn(is_warn, buf);
+ } else {
+ event_logv_(severity, NULL, fmt, args);
+ }
+ va_end(args);
+}
+
+#define log evdns_log_
+
+/* This walks the list of inflight requests to find the */
+/* one with a matching transaction id. Returns NULL on */
+/* failure */
+static struct request *
+request_find_from_trans_id(struct evdns_base *base, u16 trans_id) {
+ struct request *req = REQ_HEAD(base, trans_id);
+ struct request *const started_at = req;
+
+ ASSERT_LOCKED(base);
+
+ if (req) {
+ do {
+ if (req->trans_id == trans_id) return req;
+ req = req->next;
+ } while (req != started_at);
+ }
+
+ return NULL;
+}
+
+/* a libevent callback function which is called when a nameserver */
+/* has gone down and we want to test if it has came back to life yet */
+static void
+nameserver_prod_callback(evutil_socket_t fd, short events, void *arg) {
+ struct nameserver *const ns = (struct nameserver *) arg;
+ (void)fd;
+ (void)events;
+
+ EVDNS_LOCK(ns->base);
+ nameserver_send_probe(ns);
+ EVDNS_UNLOCK(ns->base);
+}
+
+/* a libevent callback which is called when a nameserver probe (to see if */
+/* it has come back to life) times out. We increment the count of failed_times */
+/* and wait longer to send the next probe packet. */
+static void
+nameserver_probe_failed(struct nameserver *const ns) {
+ struct timeval timeout;
+ int i;
+
+ ASSERT_LOCKED(ns->base);
+ (void) evtimer_del(&ns->timeout_event);
+ if (ns->state == 1) {
+ /* This can happen if the nameserver acts in a way which makes us mark */
+ /* it as bad and then starts sending good replies. */
+ return;
+ }
+
+#define MAX_PROBE_TIMEOUT 3600
+#define TIMEOUT_BACKOFF_FACTOR 3
+
+ memcpy(&timeout, &ns->base->global_nameserver_probe_initial_timeout,
+ sizeof(struct timeval));
+ for (i=ns->failed_times; i > 0 && timeout.tv_sec < MAX_PROBE_TIMEOUT; --i) {
+ timeout.tv_sec *= TIMEOUT_BACKOFF_FACTOR;
+ timeout.tv_usec *= TIMEOUT_BACKOFF_FACTOR;
+ if (timeout.tv_usec > 1000000) {
+ timeout.tv_sec += timeout.tv_usec / 1000000;
+ timeout.tv_usec %= 1000000;
+ }
+ }
+ if (timeout.tv_sec > MAX_PROBE_TIMEOUT) {
+ timeout.tv_sec = MAX_PROBE_TIMEOUT;
+ timeout.tv_usec = 0;
+ }
+
+ ns->failed_times++;
+
+ if (evtimer_add(&ns->timeout_event, &timeout) < 0) {
+ char addrbuf[128];
+ log(EVDNS_LOG_WARN,
+ "Error from libevent when adding timer event for %s",
+ evutil_format_sockaddr_port_(
+ (struct sockaddr *)&ns->address,
+ addrbuf, sizeof(addrbuf)));
+ }
+}
+
+static void
+request_swap_ns(struct request *req, struct nameserver *ns) {
+ if (ns && req->ns != ns) {
+ EVUTIL_ASSERT(req->ns->requests_inflight > 0);
+ req->ns->requests_inflight--;
+ ns->requests_inflight++;
+
+ req->ns = ns;
+ }
+}
+
+/* called when a nameserver has been deemed to have failed. For example, too */
+/* many packets have timed out etc */
+static void
+nameserver_failed(struct nameserver *const ns, const char *msg) {
+ struct request *req, *started_at;
+ struct evdns_base *base = ns->base;
+ int i;
+ char addrbuf[128];
+
+ ASSERT_LOCKED(base);
+ /* if this nameserver has already been marked as failed */
+ /* then don't do anything */
+ if (!ns->state) return;
+
+ log(EVDNS_LOG_MSG, "Nameserver %s has failed: %s",
+ evutil_format_sockaddr_port_(
+ (struct sockaddr *)&ns->address,
+ addrbuf, sizeof(addrbuf)),
+ msg);
+
+ base->global_good_nameservers--;
+ EVUTIL_ASSERT(base->global_good_nameservers >= 0);
+ if (base->global_good_nameservers == 0) {
+ log(EVDNS_LOG_MSG, "All nameservers have failed");
+ }
+
+ ns->state = 0;
+ ns->failed_times = 1;
+
+ if (evtimer_add(&ns->timeout_event,
+ &base->global_nameserver_probe_initial_timeout) < 0) {
+ log(EVDNS_LOG_WARN,
+ "Error from libevent when adding timer event for %s",
+ evutil_format_sockaddr_port_(
+ (struct sockaddr *)&ns->address,
+ addrbuf, sizeof(addrbuf)));
+ /* ???? Do more? */
+ }
+
+ /* walk the list of inflight requests to see if any can be reassigned to */
+ /* a different server. Requests in the waiting queue don't have a */
+ /* nameserver assigned yet */
+
+ /* if we don't have *any* good nameservers then there's no point */
+ /* trying to reassign requests to one */
+ if (!base->global_good_nameservers) return;
+
+ for (i = 0; i < base->n_req_heads; ++i) {
+ req = started_at = base->req_heads[i];
+ if (req) {
+ do {
+ if (req->tx_count == 0 && req->ns == ns) {
+ /* still waiting to go out, can be moved */
+ /* to another server */
+ request_swap_ns(req, nameserver_pick(base));
+ }
+ req = req->next;
+ } while (req != started_at);
+ }
+ }
+}
+
+static void
+nameserver_up(struct nameserver *const ns)
+{
+ char addrbuf[128];
+ ASSERT_LOCKED(ns->base);
+ if (ns->state) return;
+ log(EVDNS_LOG_MSG, "Nameserver %s is back up",
+ evutil_format_sockaddr_port_(
+ (struct sockaddr *)&ns->address,
+ addrbuf, sizeof(addrbuf)));
+ evtimer_del(&ns->timeout_event);
+ if (ns->probe_request) {
+ evdns_cancel_request(ns->base, ns->probe_request);
+ ns->probe_request = NULL;
+ }
+ ns->state = 1;
+ ns->failed_times = 0;
+ ns->timedout = 0;
+ ns->base->global_good_nameservers++;
+}
+
+static void
+request_trans_id_set(struct request *const req, const u16 trans_id) {
+ req->trans_id = trans_id;
+ *((u16 *) req->request) = htons(trans_id);
+}
+
+/* Called to remove a request from a list and dealloc it. */
+/* head is a pointer to the head of the list it should be */
+/* removed from or NULL if the request isn't in a list. */
+/* when free_handle is one, free the handle as well. */
+static void
+request_finished(struct request *const req, struct request **head, int free_handle) {
+ struct evdns_base *base = req->base;
+ int was_inflight = (head != &base->req_waiting_head);
+ EVDNS_LOCK(base);
+ ASSERT_VALID_REQUEST(req);
+
+ if (head)
+ evdns_request_remove(req, head);
+
+ log(EVDNS_LOG_DEBUG, "Removing timeout for request %p", req);
+ if (was_inflight) {
+ evtimer_del(&req->timeout_event);
+ base->global_requests_inflight--;
+ req->ns->requests_inflight--;
+ } else {
+ base->global_requests_waiting--;
+ }
+ /* it was initialized during request_new / evtimer_assign */
+ event_debug_unassign(&req->timeout_event);
+
+ if (req->ns &&
+ req->ns->requests_inflight == 0 &&
+ req->base->disable_when_inactive) {
+ event_del(&req->ns->event);
+ evtimer_del(&req->ns->timeout_event);
+ }
+
+ if (!req->request_appended) {
+ /* need to free the request data on it's own */
+ mm_free(req->request);
+ } else {
+ /* the request data is appended onto the header */
+ /* so everything gets free()ed when we: */
+ }
+
+ if (req->handle) {
+ EVUTIL_ASSERT(req->handle->current_req == req);
+
+ if (free_handle) {
+ search_request_finished(req->handle);
+ req->handle->current_req = NULL;
+ if (! req->handle->pending_cb) {
+ /* If we're planning to run the callback,
+ * don't free the handle until later. */
+ mm_free(req->handle);
+ }
+ req->handle = NULL; /* If we have a bug, let's crash
+ * early */
+ } else {
+ req->handle->current_req = NULL;
+ }
+ }
+
+ mm_free(req);
+
+ evdns_requests_pump_waiting_queue(base);
+ EVDNS_UNLOCK(base);
+}
+
+/* This is called when a server returns a funny error code. */
+/* We try the request again with another server. */
+/* */
+/* return: */
+/* 0 ok */
+/* 1 failed/reissue is pointless */
+static int
+request_reissue(struct request *req) {
+ const struct nameserver *const last_ns = req->ns;
+ ASSERT_LOCKED(req->base);
+ ASSERT_VALID_REQUEST(req);
+ /* the last nameserver should have been marked as failing */
+ /* by the caller of this function, therefore pick will try */
+ /* not to return it */
+ request_swap_ns(req, nameserver_pick(req->base));
+ if (req->ns == last_ns) {
+ /* ... but pick did return it */
+ /* not a lot of point in trying again with the */
+ /* same server */
+ return 1;
+ }
+
+ req->reissue_count++;
+ req->tx_count = 0;
+ req->transmit_me = 1;
+
+ return 0;
+}
+
+/* this function looks for space on the inflight queue and promotes */
+/* requests from the waiting queue if it can. */
+/* */
+/* TODO: */
+/* add return code, see at nameserver_pick() and other functions. */
+static void
+evdns_requests_pump_waiting_queue(struct evdns_base *base) {
+ ASSERT_LOCKED(base);
+ while (base->global_requests_inflight < base->global_max_requests_inflight &&
+ base->global_requests_waiting) {
+ struct request *req;
+
+ EVUTIL_ASSERT(base->req_waiting_head);
+ req = base->req_waiting_head;
+
+ req->ns = nameserver_pick(base);
+ if (!req->ns)
+ return;
+
+ /* move a request from the waiting queue to the inflight queue */
+ req->ns->requests_inflight++;
+
+ evdns_request_remove(req, &base->req_waiting_head);
+
+ base->global_requests_waiting--;
+ base->global_requests_inflight++;
+
+ request_trans_id_set(req, transaction_id_pick(base));
+
+ evdns_request_insert(req, &REQ_HEAD(base, req->trans_id));
+ evdns_request_transmit(req);
+ evdns_transmit(base);
+ }
+}
+
+/* TODO(nickm) document */
+struct deferred_reply_callback {
+ struct event_callback deferred;
+ struct evdns_request *handle;
+ u8 request_type;
+ u8 have_reply;
+ u32 ttl;
+ u32 err;
+ evdns_callback_type user_callback;
+ struct reply reply;
+};
+
+static void
+reply_run_callback(struct event_callback *d, void *user_pointer)
+{
+ struct deferred_reply_callback *cb =
+ EVUTIL_UPCAST(d, struct deferred_reply_callback, deferred);
+
+ switch (cb->request_type) {
+ case TYPE_A:
+ if (cb->have_reply)
+ cb->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
+ cb->reply.data.a.addrcount, cb->ttl,
+ cb->reply.data.a.addresses,
+ user_pointer);
+ else
+ cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
+ break;
+ case TYPE_PTR:
+ if (cb->have_reply) {
+ char *name = cb->reply.data.ptr.name;
+ cb->user_callback(DNS_ERR_NONE, DNS_PTR, 1, cb->ttl,
+ &name, user_pointer);
+ } else {
+ cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
+ }
+ break;
+ case TYPE_AAAA:
+ if (cb->have_reply)
+ cb->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA,
+ cb->reply.data.aaaa.addrcount, cb->ttl,
+ cb->reply.data.aaaa.addresses,
+ user_pointer);
+ else
+ cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
+ break;
+ default:
+ EVUTIL_ASSERT(0);
+ }
+
+ if (cb->handle && cb->handle->pending_cb) {
+ mm_free(cb->handle);
+ }
+
+ mm_free(cb);
+}
+
+static void
+reply_schedule_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply)
+{
+ struct deferred_reply_callback *d = mm_calloc(1, sizeof(*d));
+
+ if (!d) {
+ event_warn("%s: Couldn't allocate space for deferred callback.",
+ __func__);
+ return;
+ }
+
+ ASSERT_LOCKED(req->base);
+
+ d->request_type = req->request_type;
+ d->user_callback = req->user_callback;
+ d->ttl = ttl;
+ d->err = err;
+ if (reply) {
+ d->have_reply = 1;
+ memcpy(&d->reply, reply, sizeof(struct reply));
+ }
+
+ if (req->handle) {
+ req->handle->pending_cb = 1;
+ d->handle = req->handle;
+ }
+
+ event_deferred_cb_init_(
+ &d->deferred,
+ event_get_priority(&req->timeout_event),
+ reply_run_callback,
+ req->user_pointer);
+ event_deferred_cb_schedule_(
+ req->base->event_base,
+ &d->deferred);
+}
+
+/* this processes a parsed reply packet */
+static void
+reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) {
+ int error;
+ char addrbuf[128];
+ static const int error_codes[] = {
+ DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST,
+ DNS_ERR_NOTIMPL, DNS_ERR_REFUSED
+ };
+
+ ASSERT_LOCKED(req->base);
+ ASSERT_VALID_REQUEST(req);
+
+ if (flags & 0x020f || !reply || !reply->have_answer) {
+ /* there was an error */
+ if (flags & 0x0200) {
+ error = DNS_ERR_TRUNCATED;
+ } else if (flags & 0x000f) {
+ u16 error_code = (flags & 0x000f) - 1;
+ if (error_code > 4) {
+ error = DNS_ERR_UNKNOWN;
+ } else {
+ error = error_codes[error_code];
+ }
+ } else if (reply && !reply->have_answer) {
+ error = DNS_ERR_NODATA;
+ } else {
+ error = DNS_ERR_UNKNOWN;
+ }
+
+ switch (error) {
+ case DNS_ERR_NOTIMPL:
+ case DNS_ERR_REFUSED:
+ /* we regard these errors as marking a bad nameserver */
+ if (req->reissue_count < req->base->global_max_reissues) {
+ char msg[64];
+ evutil_snprintf(msg, sizeof(msg), "Bad response %d (%s)",
+ error, evdns_err_to_string(error));
+ nameserver_failed(req->ns, msg);
+ if (!request_reissue(req)) return;
+ }
+ break;
+ case DNS_ERR_SERVERFAILED:
+ /* rcode 2 (servfailed) sometimes means "we
+ * are broken" and sometimes (with some binds)
+ * means "that request was very confusing."
+ * Treat this as a timeout, not a failure.
+ */
+ log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver"
+ "at %s; will allow the request to time out.",
+ evutil_format_sockaddr_port_(
+ (struct sockaddr *)&req->ns->address,
+ addrbuf, sizeof(addrbuf)));
+ /* Call the timeout function */
+ evdns_request_timeout_callback(0, 0, req);
+ return;
+ default:
+ /* we got a good reply from the nameserver: it is up. */
+ if (req->handle == req->ns->probe_request) {
+ /* Avoid double-free */
+ req->ns->probe_request = NULL;
+ }
+
+ nameserver_up(req->ns);
+ }
+
+ if (req->handle->search_state &&
+ req->request_type != TYPE_PTR) {
+ /* if we have a list of domains to search in,
+ * try the next one */
+ if (!search_try_next(req->handle)) {
+ /* a new request was issued so this
+ * request is finished and */
+ /* the user callback will be made when
+ * that request (or a */
+ /* child of it) finishes. */
+ return;
+ }
+ }
+
+ /* all else failed. Pass the failure up */
+ reply_schedule_callback(req, ttl, error, NULL);
+ request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
+ } else {
+ /* all ok, tell the user */
+ reply_schedule_callback(req, ttl, 0, reply);
+ if (req->handle == req->ns->probe_request)
+ req->ns->probe_request = NULL; /* Avoid double-free */
+ nameserver_up(req->ns);
+ request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
+ }
+}
+
+static int
+name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
+ int name_end = -1;
+ int j = *idx;
+ int ptr_count = 0;
+#define GET32(x) do { if (j + 4 > length) goto err; memcpy(&t32_, packet + j, 4); j += 4; x = ntohl(t32_); } while (0)
+#define GET16(x) do { if (j + 2 > length) goto err; memcpy(&t_, packet + j, 2); j += 2; x = ntohs(t_); } while (0)
+#define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while (0)
+
+ char *cp = name_out;
+ const char *const end = name_out + name_out_len;
+
+ /* Normally, names are a series of length prefixed strings terminated */
+ /* with a length of 0 (the lengths are u8's < 63). */
+ /* However, the length can start with a pair of 1 bits and that */
+ /* means that the next 14 bits are a pointer within the current */
+ /* packet. */
+
+ for (;;) {
+ u8 label_len;
+ GET8(label_len);
+ if (!label_len) break;
+ if (label_len & 0xc0) {
+ u8 ptr_low;
+ GET8(ptr_low);
+ if (name_end < 0) name_end = j;
+ j = (((int)label_len & 0x3f) << 8) + ptr_low;
+ /* Make sure that the target offset is in-bounds. */
+ if (j < 0 || j >= length) return -1;
+ /* If we've jumped more times than there are characters in the
+ * message, we must have a loop. */
+ if (++ptr_count > length) return -1;
+ continue;
+ }
+ if (label_len > 63) return -1;
+ if (cp != name_out) {
+ if (cp + 1 >= end) return -1;
+ *cp++ = '.';
+ }
+ if (cp + label_len >= end) return -1;
+ if (j + label_len > length) return -1;
+ memcpy(cp, packet + j, label_len);
+ cp += label_len;
+ j += label_len;
+ }
+ if (cp >= end) return -1;
+ *cp = '\0';
+ if (name_end < 0)
+ *idx = j;
+ else
+ *idx = name_end;
+ return 0;
+ err:
+ return -1;
+}
+
+/* parses a raw request from a nameserver */
+static int
+reply_parse(struct evdns_base *base, u8 *packet, int length) {
+ int j = 0, k = 0; /* index into packet */
+ u16 t_; /* used by the macros */
+ u32 t32_; /* used by the macros */
+ char tmp_name[256], cmp_name[256]; /* used by the macros */
+ int name_matches = 0;
+
+ u16 trans_id, questions, answers, authority, additional, datalength;
+ u16 flags = 0;
+ u32 ttl, ttl_r = 0xffffffff;
+ struct reply reply;
+ struct request *req = NULL;
+ unsigned int i;
+
+ ASSERT_LOCKED(base);
+
+ GET16(trans_id);
+ GET16(flags);
+ GET16(questions);
+ GET16(answers);
+ GET16(authority);
+ GET16(additional);
+ (void) authority; /* suppress "unused variable" warnings. */
+ (void) additional; /* suppress "unused variable" warnings. */
+
+ req = request_find_from_trans_id(base, trans_id);
+ if (!req) return -1;
+ EVUTIL_ASSERT(req->base == base);
+
+ memset(&reply, 0, sizeof(reply));
+
+ /* If it's not an answer, it doesn't correspond to any request. */
+ if (!(flags & 0x8000)) return -1; /* must be an answer */
+ if ((flags & 0x020f) && (flags & 0x020f) != DNS_ERR_NOTEXIST) {
+ /* there was an error and it's not NXDOMAIN */
+ goto err;
+ }
+ /* if (!answers) return; */ /* must have an answer of some form */
+
+ /* This macro skips a name in the DNS reply. */
+#define SKIP_NAME \
+ do { tmp_name[0] = '\0'; \
+ if (name_parse(packet, length, &j, tmp_name, \
+ sizeof(tmp_name))<0) \
+ goto err; \
+ } while (0)
+
+ reply.type = req->request_type;
+
+ /* skip over each question in the reply */
+ for (i = 0; i < questions; ++i) {
+ /* the question looks like
+ * <label:name><u16:type><u16:class>
+ */
+ tmp_name[0] = '\0';
+ cmp_name[0] = '\0';
+ k = j;
+ if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name)) < 0)
+ goto err;
+ if (name_parse(req->request, req->request_len, &k,
+ cmp_name, sizeof(cmp_name))<0)
+ goto err;
+ if (!base->global_randomize_case) {
+ if (strcmp(tmp_name, cmp_name) == 0)
+ name_matches = 1;
+ } else {
+ if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0)
+ name_matches = 1;
+ }
+
+ j += 4;
+ if (j > length)
+ goto err;
+ }
+
+ if (!name_matches)
+ goto err;
+
+ /* now we have the answer section which looks like
+ * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
+ */
+
+ for (i = 0; i < answers; ++i) {
+ u16 type, class;
+
+ SKIP_NAME;
+ GET16(type);
+ GET16(class);
+ GET32(ttl);
+ GET16(datalength);
+
+ if (type == TYPE_A && class == CLASS_INET) {
+ int addrcount, addrtocopy;
+ if (req->request_type != TYPE_A) {
+ j += datalength; continue;
+ }
+ if ((datalength & 3) != 0) /* not an even number of As. */
+ goto err;
+ addrcount = datalength >> 2;
+ addrtocopy = MIN(MAX_V4_ADDRS - reply.data.a.addrcount, (unsigned)addrcount);
+
+ ttl_r = MIN(ttl_r, ttl);
+ /* we only bother with the first four addresses. */
+ if (j + 4*addrtocopy > length) goto err;
+ memcpy(&reply.data.a.addresses[reply.data.a.addrcount],
+ packet + j, 4*addrtocopy);
+ j += 4*addrtocopy;
+ reply.data.a.addrcount += addrtocopy;
+ reply.have_answer = 1;
+ if (reply.data.a.addrcount == MAX_V4_ADDRS) break;
+ } else if (type == TYPE_PTR && class == CLASS_INET) {
+ if (req->request_type != TYPE_PTR) {
+ j += datalength; continue;
+ }
+ if (name_parse(packet, length, &j, reply.data.ptr.name,
+ sizeof(reply.data.ptr.name))<0)
+ goto err;
+ ttl_r = MIN(ttl_r, ttl);
+ reply.have_answer = 1;
+ break;
+ } else if (type == TYPE_CNAME) {
+ char cname[HOST_NAME_MAX];
+ if (!req->put_cname_in_ptr || *req->put_cname_in_ptr) {
+ j += datalength; continue;
+ }
+ if (name_parse(packet, length, &j, cname,
+ sizeof(cname))<0)
+ goto err;
+ *req->put_cname_in_ptr = mm_strdup(cname);
+ } else if (type == TYPE_AAAA && class == CLASS_INET) {
+ int addrcount, addrtocopy;
+ if (req->request_type != TYPE_AAAA) {
+ j += datalength; continue;
+ }
+ if ((datalength & 15) != 0) /* not an even number of AAAAs. */
+ goto err;
+ addrcount = datalength >> 4; /* each address is 16 bytes long */
+ addrtocopy = MIN(MAX_V6_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount);
+ ttl_r = MIN(ttl_r, ttl);
+
+ /* we only bother with the first four addresses. */
+ if (j + 16*addrtocopy > length) goto err;
+ memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount],
+ packet + j, 16*addrtocopy);
+ reply.data.aaaa.addrcount += addrtocopy;
+ j += 16*addrtocopy;
+ reply.have_answer = 1;
+ if (reply.data.aaaa.addrcount == MAX_V6_ADDRS) break;
+ } else {
+ /* skip over any other type of resource */
+ j += datalength;
+ }
+ }
+
+ if (!reply.have_answer) {
+ for (i = 0; i < authority; ++i) {
+ u16 type, class;
+ SKIP_NAME;
+ GET16(type);
+ GET16(class);
+ GET32(ttl);
+ GET16(datalength);
+ if (type == TYPE_SOA && class == CLASS_INET) {
+ u32 serial, refresh, retry, expire, minimum;
+ SKIP_NAME;
+ SKIP_NAME;
+ GET32(serial);
+ GET32(refresh);
+ GET32(retry);
+ GET32(expire);
+ GET32(minimum);
+ (void)expire;
+ (void)retry;
+ (void)refresh;
+ (void)serial;
+ ttl_r = MIN(ttl_r, ttl);
+ ttl_r = MIN(ttl_r, minimum);
+ } else {
+ /* skip over any other type of resource */
+ j += datalength;
+ }
+ }
+ }
+
+ if (ttl_r == 0xffffffff)
+ ttl_r = 0;
+
+ reply_handle(req, flags, ttl_r, &reply);
+ return 0;
+ err:
+ if (req)
+ reply_handle(req, flags, 0, NULL);
+ return -1;
+}
+
+/* Parse a raw request (packet,length) sent to a nameserver port (port) from */
+/* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */
+/* callback. */
+static int
+request_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, ev_socklen_t addrlen)
+{
+ int j = 0; /* index into packet */
+ u16 t_; /* used by the macros */
+ char tmp_name[256]; /* used by the macros */
+
+ int i;
+ u16 trans_id, flags, questions, answers, authority, additional;
+ struct server_request *server_req = NULL;
+
+ ASSERT_LOCKED(port);
+
+ /* Get the header fields */
+ GET16(trans_id);
+ GET16(flags);
+ GET16(questions);
+ GET16(answers);
+ GET16(authority);
+ GET16(additional);
+ (void)answers;
+ (void)additional;
+ (void)authority;
+
+ if (flags & 0x8000) return -1; /* Must not be an answer. */
+ flags &= 0x0110; /* Only RD and CD get preserved. */
+
+ server_req = mm_malloc(sizeof(struct server_request));
+ if (server_req == NULL) return -1;
+ memset(server_req, 0, sizeof(struct server_request));
+
+ server_req->trans_id = trans_id;
+ memcpy(&server_req->addr, addr, addrlen);
+ server_req->addrlen = addrlen;
+
+ server_req->base.flags = flags;
+ server_req->base.nquestions = 0;
+ server_req->base.questions = mm_calloc(sizeof(struct evdns_server_question *), questions);
+ if (server_req->base.questions == NULL)
+ goto err;
+
+ for (i = 0; i < questions; ++i) {
+ u16 type, class;
+ struct evdns_server_question *q;
+ int namelen;
+ if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)
+ goto err;
+ GET16(type);
+ GET16(class);
+ namelen = (int)strlen(tmp_name);
+ q = mm_malloc(sizeof(struct evdns_server_question) + namelen);
+ if (!q)
+ goto err;
+ q->type = type;
+ q->dns_question_class = class;
+ memcpy(q->name, tmp_name, namelen+1);
+ server_req->base.questions[server_req->base.nquestions++] = q;
+ }
+
+ /* Ignore answers, authority, and additional. */
+
+ server_req->port = port;
+ port->refcnt++;
+
+ /* Only standard queries are supported. */
+ if (flags & 0x7800) {
+ evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
+ return -1;
+ }
+
+ port->user_callback(&(server_req->base), port->user_data);
+
+ return 0;
+err:
+ if (server_req) {
+ if (server_req->base.questions) {
+ for (i = 0; i < server_req->base.nquestions; ++i)
+ mm_free(server_req->base.questions[i]);
+ mm_free(server_req->base.questions);
+ }
+ mm_free(server_req);
+ }
+ return -1;
+
+#undef SKIP_NAME
+#undef GET32
+#undef GET16
+#undef GET8
+}
+
+
+void
+evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void))
+{
+}
+
+void
+evdns_set_random_bytes_fn(void (*fn)(char *, size_t))
+{
+}
+
+/* Try to choose a strong transaction id which isn't already in flight */
+static u16
+transaction_id_pick(struct evdns_base *base) {
+ ASSERT_LOCKED(base);
+ for (;;) {
+ u16 trans_id;
+ evutil_secure_rng_get_bytes(&trans_id, sizeof(trans_id));
+
+ if (trans_id == 0xffff) continue;
+ /* now check to see if that id is already inflight */
+ if (request_find_from_trans_id(base, trans_id) == NULL)
+ return trans_id;
+ }
+}
+
+/* choose a namesever to use. This function will try to ignore */
+/* nameservers which we think are down and load balance across the rest */
+/* by updating the server_head global each time. */
+static struct nameserver *
+nameserver_pick(struct evdns_base *base) {
+ struct nameserver *started_at = base->server_head, *picked;
+ ASSERT_LOCKED(base);
+ if (!base->server_head) return NULL;
+
+ /* if we don't have any good nameservers then there's no */
+ /* point in trying to find one. */
+ if (!base->global_good_nameservers) {
+ base->server_head = base->server_head->next;
+ return base->server_head;
+ }
+
+ /* remember that nameservers are in a circular list */
+ for (;;) {
+ if (base->server_head->state) {
+ /* we think this server is currently good */
+ picked = base->server_head;
+ base->server_head = base->server_head->next;
+ return picked;
+ }
+
+ base->server_head = base->server_head->next;
+ if (base->server_head == started_at) {
+ /* all the nameservers seem to be down */
+ /* so we just return this one and hope for the */
+ /* best */
+ EVUTIL_ASSERT(base->global_good_nameservers == 0);
+ picked = base->server_head;
+ base->server_head = base->server_head->next;
+ return picked;
+ }
+ }
+}
+
+/* this is called when a namesever socket is ready for reading */
+static void
+nameserver_read(struct nameserver *ns) {
+ struct sockaddr_storage ss;
+ ev_socklen_t addrlen = sizeof(ss);
+ u8 packet[1500];
+ char addrbuf[128];
+ ASSERT_LOCKED(ns->base);
+
+ for (;;) {
+ const int r = recvfrom(ns->socket, (void*)packet,
+ sizeof(packet), 0,
+ (struct sockaddr*)&ss, &addrlen);
+ if (r < 0) {
+ int err = evutil_socket_geterror(ns->socket);
+ if (EVUTIL_ERR_RW_RETRIABLE(err))
+ return;
+ nameserver_failed(ns,
+ evutil_socket_error_to_string(err));
+ return;
+ }
+ if (evutil_sockaddr_cmp((struct sockaddr*)&ss,
+ (struct sockaddr*)&ns->address, 0)) {
+ log(EVDNS_LOG_WARN, "Address mismatch on received "
+ "DNS packet. Apparent source was %s",
+ evutil_format_sockaddr_port_(
+ (struct sockaddr *)&ss,
+ addrbuf, sizeof(addrbuf)));
+ return;
+ }
+
+ ns->timedout = 0;
+ reply_parse(ns->base, packet, r);
+ }
+}
+
+/* Read a packet from a DNS client on a server port s, parse it, and */
+/* act accordingly. */
+static void
+server_port_read(struct evdns_server_port *s) {
+ u8 packet[1500];
+ struct sockaddr_storage addr;
+ ev_socklen_t addrlen;
+ int r;
+ ASSERT_LOCKED(s);
+
+ for (;;) {
+ addrlen = sizeof(struct sockaddr_storage);
+ r = recvfrom(s->socket, (void*)packet, sizeof(packet), 0,
+ (struct sockaddr*) &addr, &addrlen);
+ if (r < 0) {
+ int err = evutil_socket_geterror(s->socket);
+ if (EVUTIL_ERR_RW_RETRIABLE(err))
+ return;
+ log(EVDNS_LOG_WARN,
+ "Error %s (%d) while reading request.",
+ evutil_socket_error_to_string(err), err);
+ return;
+ }
+ request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen);
+ }
+}
+
+/* Try to write all pending replies on a given DNS server port. */
+static void
+server_port_flush(struct evdns_server_port *port)
+{
+ struct server_request *req = port->pending_replies;
+ ASSERT_LOCKED(port);
+ while (req) {
+ int r = sendto(port->socket, req->response, (int)req->response_len, 0,
+ (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen);
+ if (r < 0) {
+ int err = evutil_socket_geterror(port->socket);
+ if (EVUTIL_ERR_RW_RETRIABLE(err))
+ return;
+ log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", evutil_socket_error_to_string(err), err);
+ }
+ if (server_request_free(req)) {
+ /* we released the last reference to req->port. */
+ return;
+ } else {
+ EVUTIL_ASSERT(req != port->pending_replies);
+ req = port->pending_replies;
+ }
+ }
+
+ /* We have no more pending requests; stop listening for 'writeable' events. */
+ (void) event_del(&port->event);
+ event_assign(&port->event, port->event_base,
+ port->socket, EV_READ | EV_PERSIST,
+ server_port_ready_callback, port);
+
+ if (event_add(&port->event, NULL) < 0) {
+ log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
+ /* ???? Do more? */
+ }
+}
+
+/* set if we are waiting for the ability to write to this server. */
+/* if waiting is true then we ask libevent for EV_WRITE events, otherwise */
+/* we stop these events. */
+static void
+nameserver_write_waiting(struct nameserver *ns, char waiting) {
+ ASSERT_LOCKED(ns->base);
+ if (ns->write_waiting == waiting) return;
+
+ ns->write_waiting = waiting;
+ (void) event_del(&ns->event);
+ event_assign(&ns->event, ns->base->event_base,
+ ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
+ nameserver_ready_callback, ns);
+ if (event_add(&ns->event, NULL) < 0) {
+ char addrbuf[128];
+ log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
+ evutil_format_sockaddr_port_(
+ (struct sockaddr *)&ns->address,
+ addrbuf, sizeof(addrbuf)));
+ /* ???? Do more? */
+ }
+}
+
+/* a callback function. Called by libevent when the kernel says that */
+/* a nameserver socket is ready for writing or reading */
+static void
+nameserver_ready_callback(evutil_socket_t fd, short events, void *arg) {
+ struct nameserver *ns = (struct nameserver *) arg;
+ (void)fd;
+
+ EVDNS_LOCK(ns->base);
+ if (events & EV_WRITE) {
+ ns->choked = 0;
+ if (!evdns_transmit(ns->base)) {
+ nameserver_write_waiting(ns, 0);
+ }
+ }
+ if (events & EV_READ) {
+ nameserver_read(ns);
+ }
+ EVDNS_UNLOCK(ns->base);
+}
+
+/* a callback function. Called by libevent when the kernel says that */
+/* a server socket is ready for writing or reading. */
+static void
+server_port_ready_callback(evutil_socket_t fd, short events, void *arg) {
+ struct evdns_server_port *port = (struct evdns_server_port *) arg;
+ (void) fd;
+
+ EVDNS_LOCK(port);
+ if (events & EV_WRITE) {
+ port->choked = 0;
+ server_port_flush(port);
+ }
+ if (events & EV_READ) {
+ server_port_read(port);
+ }
+ EVDNS_UNLOCK(port);
+}
+
+/* This is an inefficient representation; only use it via the dnslabel_table_*
+ * functions, so that is can be safely replaced with something smarter later. */
+#define MAX_LABELS 128
+/* Structures used to implement name compression */
+struct dnslabel_entry { char *v; off_t pos; };
+struct dnslabel_table {
+ int n_labels; /* number of current entries */
+ /* map from name to position in message */
+ struct dnslabel_entry labels[MAX_LABELS];
+};
+
+/* Initialize dnslabel_table. */
+static void
+dnslabel_table_init(struct dnslabel_table *table)
+{
+ table->n_labels = 0;
+}
+
+/* Free all storage held by table, but not the table itself. */
+static void
+dnslabel_clear(struct dnslabel_table *table)
+{
+ int i;
+ for (i = 0; i < table->n_labels; ++i)
+ mm_free(table->labels[i].v);
+ table->n_labels = 0;
+}
+
+/* return the position of the label in the current message, or -1 if the label */
+/* hasn't been used yet. */
+static int
+dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label)
+{
+ int i;
+ for (i = 0; i < table->n_labels; ++i) {
+ if (!strcmp(label, table->labels[i].v))
+ return table->labels[i].pos;
+ }
+ return -1;
+}
+
+/* remember that we've used the label at position pos */
+static int
+dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos)
+{
+ char *v;
+ int p;
+ if (table->n_labels == MAX_LABELS)
+ return (-1);
+ v = mm_strdup(label);
+ if (v == NULL)
+ return (-1);
+ p = table->n_labels++;
+ table->labels[p].v = v;
+ table->labels[p].pos = pos;
+
+ return (0);
+}
+
+/* Converts a string to a length-prefixed set of DNS labels, starting */
+/* at buf[j]. name and buf must not overlap. name_len should be the length */
+/* of name. table is optional, and is used for compression. */
+/* */
+/* Input: abc.def */
+/* Output: <3>abc<3>def<0> */
+/* */
+/* Returns the first index after the encoded name, or negative on error. */
+/* -1 label was > 63 bytes */
+/* -2 name too long to fit in buffer. */
+/* */
+static off_t
+dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j,
+ const char *name, const size_t name_len,
+ struct dnslabel_table *table) {
+ const char *end = name + name_len;
+ int ref = 0;
+ u16 t_;
+
+#define APPEND16(x) do { \
+ if (j + 2 > (off_t)buf_len) \
+ goto overflow; \
+ t_ = htons(x); \
+ memcpy(buf + j, &t_, 2); \
+ j += 2; \
+ } while (0)
+#define APPEND32(x) do { \
+ if (j + 4 > (off_t)buf_len) \
+ goto overflow; \
+ t32_ = htonl(x); \
+ memcpy(buf + j, &t32_, 4); \
+ j += 4; \
+ } while (0)
+
+ if (name_len > 255) return -2;
+
+ for (;;) {
+ const char *const start = name;
+ if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) {
+ APPEND16(ref | 0xc000);
+ return j;
+ }
+ name = strchr(name, '.');
+ if (!name) {
+ const size_t label_len = end - start;
+ if (label_len > 63) return -1;
+ if ((size_t)(j+label_len+1) > buf_len) return -2;
+ if (table) dnslabel_table_add(table, start, j);
+ buf[j++] = (ev_uint8_t)label_len;
+
+ memcpy(buf + j, start, label_len);
+ j += (int) label_len;
+ break;
+ } else {
+ /* append length of the label. */
+ const size_t label_len = name - start;
+ if (label_len > 63) return -1;
+ if ((size_t)(j+label_len+1) > buf_len) return -2;
+ if (table) dnslabel_table_add(table, start, j);
+ buf[j++] = (ev_uint8_t)label_len;
+
+ memcpy(buf + j, start, label_len);
+ j += (int) label_len;
+ /* hop over the '.' */
+ name++;
+ }
+ }
+
+ /* the labels must be terminated by a 0. */
+ /* It's possible that the name ended in a . */
+ /* in which case the zero is already there */
+ if (!j || buf[j-1]) buf[j++] = 0;
+ return j;
+ overflow:
+ return (-2);
+}
+
+/* Finds the length of a dns request for a DNS name of the given */
+/* length. The actual request may be smaller than the value returned */
+/* here */
+static size_t
+evdns_request_len(const size_t name_len) {
+ return 96 + /* length of the DNS standard header */
+ name_len + 2 +
+ 4; /* space for the resource type */
+}
+
+/* build a dns request packet into buf. buf should be at least as long */
+/* as evdns_request_len told you it should be. */
+/* */
+/* Returns the amount of space used. Negative on error. */
+static int
+evdns_request_data_build(const char *const name, const size_t name_len,
+ const u16 trans_id, const u16 type, const u16 class,
+ u8 *const buf, size_t buf_len) {
+ off_t j = 0; /* current offset into buf */
+ u16 t_; /* used by the macros */
+
+ APPEND16(trans_id);
+ APPEND16(0x0100); /* standard query, recusion needed */
+ APPEND16(1); /* one question */
+ APPEND16(0); /* no answers */
+ APPEND16(0); /* no authority */
+ APPEND16(0); /* no additional */
+
+ j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL);
+ if (j < 0) {
+ return (int)j;
+ }
+
+ APPEND16(type);
+ APPEND16(class);
+
+ return (int)j;
+ overflow:
+ return (-1);
+}
+
+/* exported function */
+struct evdns_server_port *
+evdns_add_server_port_with_base(struct event_base *base, evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data)
+{
+ struct evdns_server_port *port;
+ if (flags)
+ return NULL; /* flags not yet implemented */
+ if (!(port = mm_malloc(sizeof(struct evdns_server_port))))
+ return NULL;
+ memset(port, 0, sizeof(struct evdns_server_port));
+
+
+ port->socket = socket;
+ port->refcnt = 1;
+ port->choked = 0;
+ port->closing = 0;
+ port->user_callback = cb;
+ port->user_data = user_data;
+ port->pending_replies = NULL;
+ port->event_base = base;
+
+ event_assign(&port->event, port->event_base,
+ port->socket, EV_READ | EV_PERSIST,
+ server_port_ready_callback, port);
+ if (event_add(&port->event, NULL) < 0) {
+ mm_free(port);
+ return NULL;
+ }
+ EVTHREAD_ALLOC_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ return port;
+}
+
+struct evdns_server_port *
+evdns_add_server_port(evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data)
+{
+ return evdns_add_server_port_with_base(NULL, socket, flags, cb, user_data);
+}
+
+/* exported function */
+void
+evdns_close_server_port(struct evdns_server_port *port)
+{
+ EVDNS_LOCK(port);
+ if (--port->refcnt == 0) {
+ EVDNS_UNLOCK(port);
+ server_port_free(port);
+ } else {
+ port->closing = 1;
+ }
+}
+
+/* exported function */
+int
+evdns_server_request_add_reply(struct evdns_server_request *req_, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data)
+{
+ struct server_request *req = TO_SERVER_REQUEST(req_);
+ struct server_reply_item **itemp, *item;
+ int *countp;
+ int result = -1;
+
+ EVDNS_LOCK(req->port);
+ if (req->response) /* have we already answered? */
+ goto done;
+
+ switch (section) {
+ case EVDNS_ANSWER_SECTION:
+ itemp = &req->answer;
+ countp = &req->n_answer;
+ break;
+ case EVDNS_AUTHORITY_SECTION:
+ itemp = &req->authority;
+ countp = &req->n_authority;
+ break;
+ case EVDNS_ADDITIONAL_SECTION:
+ itemp = &req->additional;
+ countp = &req->n_additional;
+ break;
+ default:
+ goto done;
+ }
+ while (*itemp) {
+ itemp = &((*itemp)->next);
+ }
+ item = mm_malloc(sizeof(struct server_reply_item));
+ if (!item)
+ goto done;
+ item->next = NULL;
+ if (!(item->name = mm_strdup(name))) {
+ mm_free(item);
+ goto done;
+ }
+ item->type = type;
+ item->dns_question_class = class;
+ item->ttl = ttl;
+ item->is_name = is_name != 0;
+ item->datalen = 0;
+ item->data = NULL;
+ if (data) {
+ if (item->is_name) {
+ if (!(item->data = mm_strdup(data))) {
+ mm_free(item->name);
+ mm_free(item);
+ goto done;
+ }
+ item->datalen = (u16)-1;
+ } else {
+ if (!(item->data = mm_malloc(datalen))) {
+ mm_free(item->name);
+ mm_free(item);
+ goto done;
+ }
+ item->datalen = datalen;
+ memcpy(item->data, data, datalen);
+ }
+ }
+
+ *itemp = item;
+ ++(*countp);
+ result = 0;
+done:
+ EVDNS_UNLOCK(req->port);
+ return result;
+}
+
+/* exported function */
+int
+evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
+{
+ return evdns_server_request_add_reply(
+ req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
+ ttl, n*4, 0, addrs);
+}
+
+/* exported function */
+int
+evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
+{
+ return evdns_server_request_add_reply(
+ req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET,
+ ttl, n*16, 0, addrs);
+}
+
+/* exported function */
+int
+evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl)
+{
+ u32 a;
+ char buf[32];
+ if (in && inaddr_name)
+ return -1;
+ else if (!in && !inaddr_name)
+ return -1;
+ if (in) {
+ a = ntohl(in->s_addr);
+ evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
+ (int)(u8)((a )&0xff),
+ (int)(u8)((a>>8 )&0xff),
+ (int)(u8)((a>>16)&0xff),
+ (int)(u8)((a>>24)&0xff));
+ inaddr_name = buf;
+ }
+ return evdns_server_request_add_reply(
+ req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET,
+ ttl, -1, 1, hostname);
+}
+
+/* exported function */
+int
+evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl)
+{
+ return evdns_server_request_add_reply(
+ req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET,
+ ttl, -1, 1, cname);
+}
+
+/* exported function */
+void
+evdns_server_request_set_flags(struct evdns_server_request *exreq, int flags)
+{
+ struct server_request *req = TO_SERVER_REQUEST(exreq);
+ req->base.flags &= ~(EVDNS_FLAGS_AA|EVDNS_FLAGS_RD);
+ req->base.flags |= flags;
+}
+
+static int
+evdns_server_request_format_response(struct server_request *req, int err)
+{
+ unsigned char buf[1500];
+ size_t buf_len = sizeof(buf);
+ off_t j = 0, r;
+ u16 t_;
+ u32 t32_;
+ int i;
+ u16 flags;
+ struct dnslabel_table table;
+
+ if (err < 0 || err > 15) return -1;
+
+ /* Set response bit and error code; copy OPCODE and RD fields from
+ * question; copy RA and AA if set by caller. */
+ flags = req->base.flags;
+ flags |= (0x8000 | err);
+
+ dnslabel_table_init(&table);
+ APPEND16(req->trans_id);
+ APPEND16(flags);
+ APPEND16(req->base.nquestions);
+ APPEND16(req->n_answer);
+ APPEND16(req->n_authority);
+ APPEND16(req->n_additional);
+
+ /* Add questions. */
+ for (i=0; i < req->base.nquestions; ++i) {
+ const char *s = req->base.questions[i]->name;
+ j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table);
+ if (j < 0) {
+ dnslabel_clear(&table);
+ return (int) j;
+ }
+ APPEND16(req->base.questions[i]->type);
+ APPEND16(req->base.questions[i]->dns_question_class);
+ }
+
+ /* Add answer, authority, and additional sections. */
+ for (i=0; i<3; ++i) {
+ struct server_reply_item *item;
+ if (i==0)
+ item = req->answer;
+ else if (i==1)
+ item = req->authority;
+ else
+ item = req->additional;
+ while (item) {
+ r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table);
+ if (r < 0)
+ goto overflow;
+ j = r;
+
+ APPEND16(item->type);
+ APPEND16(item->dns_question_class);
+ APPEND32(item->ttl);
+ if (item->is_name) {
+ off_t len_idx = j, name_start;
+ j += 2;
+ name_start = j;
+ r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table);
+ if (r < 0)
+ goto overflow;
+ j = r;
+ t_ = htons( (short) (j-name_start) );
+ memcpy(buf+len_idx, &t_, 2);
+ } else {
+ APPEND16(item->datalen);
+ if (j+item->datalen > (off_t)buf_len)
+ goto overflow;
+ memcpy(buf+j, item->data, item->datalen);
+ j += item->datalen;
+ }
+ item = item->next;
+ }
+ }
+
+ if (j > 512) {
+overflow:
+ j = 512;
+ buf[2] |= 0x02; /* set the truncated bit. */
+ }
+
+ req->response_len = j;
+
+ if (!(req->response = mm_malloc(req->response_len))) {
+ server_request_free_answers(req);
+ dnslabel_clear(&table);
+ return (-1);
+ }
+ memcpy(req->response, buf, req->response_len);
+ server_request_free_answers(req);
+ dnslabel_clear(&table);
+ return (0);
+}
+
+/* exported function */
+int
+evdns_server_request_respond(struct evdns_server_request *req_, int err)
+{
+ struct server_request *req = TO_SERVER_REQUEST(req_);
+ struct evdns_server_port *port = req->port;
+ int r = -1;
+
+ EVDNS_LOCK(port);
+ if (!req->response) {
+ if ((r = evdns_server_request_format_response(req, err))<0)
+ goto done;
+ }
+
+ r = sendto(port->socket, req->response, (int)req->response_len, 0,
+ (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen);
+ if (r<0) {
+ int sock_err = evutil_socket_geterror(port->socket);
+ if (EVUTIL_ERR_RW_RETRIABLE(sock_err))
+ goto done;
+
+ if (port->pending_replies) {
+ req->prev_pending = port->pending_replies->prev_pending;
+ req->next_pending = port->pending_replies;
+ req->prev_pending->next_pending =
+ req->next_pending->prev_pending = req;
+ } else {
+ req->prev_pending = req->next_pending = req;
+ port->pending_replies = req;
+ port->choked = 1;
+
+ (void) event_del(&port->event);
+ event_assign(&port->event, port->event_base, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port);
+
+ if (event_add(&port->event, NULL) < 0) {
+ log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server");
+ }
+
+ }
+
+ r = 1;
+ goto done;
+ }
+ if (server_request_free(req)) {
+ r = 0;
+ goto done;
+ }
+
+ if (port->pending_replies)
+ server_port_flush(port);
+
+ r = 0;
+done:
+ EVDNS_UNLOCK(port);
+ return r;
+}
+
+/* Free all storage held by RRs in req. */
+static void
+server_request_free_answers(struct server_request *req)
+{
+ struct server_reply_item *victim, *next, **list;
+ int i;
+ for (i = 0; i < 3; ++i) {
+ if (i==0)
+ list = &req->answer;
+ else if (i==1)
+ list = &req->authority;
+ else
+ list = &req->additional;
+
+ victim = *list;
+ while (victim) {
+ next = victim->next;
+ mm_free(victim->name);
+ if (victim->data)
+ mm_free(victim->data);
+ mm_free(victim);
+ victim = next;
+ }
+ *list = NULL;
+ }
+}
+
+/* Free all storage held by req, and remove links to it. */
+/* return true iff we just wound up freeing the server_port. */
+static int
+server_request_free(struct server_request *req)
+{
+ int i, rc=1, lock=0;
+ if (req->base.questions) {
+ for (i = 0; i < req->base.nquestions; ++i)
+ mm_free(req->base.questions[i]);
+ mm_free(req->base.questions);
+ }
+
+ if (req->port) {
+ EVDNS_LOCK(req->port);
+ lock=1;
+ if (req->port->pending_replies == req) {
+ if (req->next_pending && req->next_pending != req)
+ req->port->pending_replies = req->next_pending;
+ else
+ req->port->pending_replies = NULL;
+ }
+ rc = --req->port->refcnt;
+ }
+
+ if (req->response) {
+ mm_free(req->response);
+ }
+
+ server_request_free_answers(req);
+
+ if (req->next_pending && req->next_pending != req) {
+ req->next_pending->prev_pending = req->prev_pending;
+ req->prev_pending->next_pending = req->next_pending;
+ }
+
+ if (rc == 0) {
+ EVDNS_UNLOCK(req->port); /* ????? nickm */
+ server_port_free(req->port);
+ mm_free(req);
+ return (1);
+ }
+ if (lock)
+ EVDNS_UNLOCK(req->port);
+ mm_free(req);
+ return (0);
+}
+
+/* Free all storage held by an evdns_server_port. Only called when */
+static void
+server_port_free(struct evdns_server_port *port)
+{
+ EVUTIL_ASSERT(port);
+ EVUTIL_ASSERT(!port->refcnt);
+ EVUTIL_ASSERT(!port->pending_replies);
+ if (port->socket > 0) {
+ evutil_closesocket(port->socket);
+ port->socket = -1;
+ }
+ (void) event_del(&port->event);
+ event_debug_unassign(&port->event);
+ EVTHREAD_FREE_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ mm_free(port);
+}
+
+/* exported function */
+int
+evdns_server_request_drop(struct evdns_server_request *req_)
+{
+ struct server_request *req = TO_SERVER_REQUEST(req_);
+ server_request_free(req);
+ return 0;
+}
+
+/* exported function */
+int
+evdns_server_request_get_requesting_addr(struct evdns_server_request *req_, struct sockaddr *sa, int addr_len)
+{
+ struct server_request *req = TO_SERVER_REQUEST(req_);
+ if (addr_len < (int)req->addrlen)
+ return -1;
+ memcpy(sa, &(req->addr), req->addrlen);
+ return req->addrlen;
+}
+
+#undef APPEND16
+#undef APPEND32
+
+/* this is a libevent callback function which is called when a request */
+/* has timed out. */
+static void
+evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg) {
+ struct request *const req = (struct request *) arg;
+ struct evdns_base *base = req->base;
+
+ (void) fd;
+ (void) events;
+
+ log(EVDNS_LOG_DEBUG, "Request %p timed out", arg);
+ EVDNS_LOCK(base);
+
+ if (req->tx_count >= req->base->global_max_retransmits) {
+ struct nameserver *ns = req->ns;
+ /* this request has failed */
+ log(EVDNS_LOG_DEBUG, "Giving up on request %p; tx_count==%d",
+ arg, req->tx_count);
+ reply_schedule_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
+
+ request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
+ nameserver_failed(ns, "request timed out.");
+ } else {
+ /* retransmit it */
+ log(EVDNS_LOG_DEBUG, "Retransmitting request %p; tx_count==%d",
+ arg, req->tx_count);
+ (void) evtimer_del(&req->timeout_event);
+ request_swap_ns(req, nameserver_pick(base));
+ evdns_request_transmit(req);
+
+ req->ns->timedout++;
+ if (req->ns->timedout > req->base->global_max_nameserver_timeout) {
+ req->ns->timedout = 0;
+ nameserver_failed(req->ns, "request timed out.");
+ }
+ }
+
+ EVDNS_UNLOCK(base);
+}
+
+/* try to send a request to a given server. */
+/* */
+/* return: */
+/* 0 ok */
+/* 1 temporary failure */
+/* 2 other failure */
+static int
+evdns_request_transmit_to(struct request *req, struct nameserver *server) {
+ int r;
+ ASSERT_LOCKED(req->base);
+ ASSERT_VALID_REQUEST(req);
+
+ if (server->requests_inflight == 1 &&
+ req->base->disable_when_inactive &&
+ event_add(&server->event, NULL) < 0) {
+ return 1;
+ }
+
+ r = sendto(server->socket, (void*)req->request, req->request_len, 0,
+ (struct sockaddr *)&server->address, server->addrlen);
+ if (r < 0) {
+ int err = evutil_socket_geterror(server->socket);
+ if (EVUTIL_ERR_RW_RETRIABLE(err))
+ return 1;
+ nameserver_failed(req->ns, evutil_socket_error_to_string(err));
+ return 2;
+ } else if (r != (int)req->request_len) {
+ return 1; /* short write */
+ } else {
+ return 0;
+ }
+}
+
+/* try to send a request, updating the fields of the request */
+/* as needed */
+/* */
+/* return: */
+/* 0 ok */
+/* 1 failed */
+static int
+evdns_request_transmit(struct request *req) {
+ int retcode = 0, r;
+
+ ASSERT_LOCKED(req->base);
+ ASSERT_VALID_REQUEST(req);
+ /* if we fail to send this packet then this flag marks it */
+ /* for evdns_transmit */
+ req->transmit_me = 1;
+ EVUTIL_ASSERT(req->trans_id != 0xffff);
+
+ if (!req->ns)
+ {
+ /* unable to transmit request if no nameservers */
+ return 1;
+ }
+
+ if (req->ns->choked) {
+ /* don't bother trying to write to a socket */
+ /* which we have had EAGAIN from */
+ return 1;
+ }
+
+ r = evdns_request_transmit_to(req, req->ns);
+ switch (r) {
+ case 1:
+ /* temp failure */
+ req->ns->choked = 1;
+ nameserver_write_waiting(req->ns, 1);
+ return 1;
+ case 2:
+ /* failed to transmit the request entirely. */
+ retcode = 1;
+ /* fall through: we'll set a timeout, which will time out,
+ * and make us retransmit the request anyway. */
+ default:
+ /* all ok */
+ log(EVDNS_LOG_DEBUG,
+ "Setting timeout for request %p, sent to nameserver %p", req, req->ns);
+ if (evtimer_add(&req->timeout_event, &req->base->global_timeout) < 0) {
+ log(EVDNS_LOG_WARN,
+ "Error from libevent when adding timer for request %p",
+ req);
+ /* ???? Do more? */
+ }
+ req->tx_count++;
+ req->transmit_me = 0;
+ return retcode;
+ }
+}
+
+static void
+nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
+ struct nameserver *const ns = (struct nameserver *) arg;
+ (void) type;
+ (void) count;
+ (void) ttl;
+ (void) addresses;
+
+ if (result == DNS_ERR_CANCEL) {
+ /* We canceled this request because the nameserver came up
+ * for some other reason. Do not change our opinion about
+ * the nameserver. */
+ return;
+ }
+
+ EVDNS_LOCK(ns->base);
+ ns->probe_request = NULL;
+ if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
+ /* this is a good reply */
+ nameserver_up(ns);
+ } else {
+ nameserver_probe_failed(ns);
+ }
+ EVDNS_UNLOCK(ns->base);
+}
+
+static void
+nameserver_send_probe(struct nameserver *const ns) {
+ struct evdns_request *handle;
+ struct request *req;
+ char addrbuf[128];
+ /* here we need to send a probe to a given nameserver */
+ /* in the hope that it is up now. */
+
+ ASSERT_LOCKED(ns->base);
+ log(EVDNS_LOG_DEBUG, "Sending probe to %s",
+ evutil_format_sockaddr_port_(
+ (struct sockaddr *)&ns->address,
+ addrbuf, sizeof(addrbuf)));
+ handle = mm_calloc(1, sizeof(*handle));
+ if (!handle) return;
+ req = request_new(ns->base, handle, TYPE_A, "google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
+ if (!req) {
+ mm_free(handle);
+ return;
+ }
+ ns->probe_request = handle;
+ /* we force this into the inflight queue no matter what */
+ request_trans_id_set(req, transaction_id_pick(ns->base));
+ req->ns = ns;
+ request_submit(req);
+}
+
+/* returns: */
+/* 0 didn't try to transmit anything */
+/* 1 tried to transmit something */
+static int
+evdns_transmit(struct evdns_base *base) {
+ char did_try_to_transmit = 0;
+ int i;
+
+ ASSERT_LOCKED(base);
+ for (i = 0; i < base->n_req_heads; ++i) {
+ if (base->req_heads[i]) {
+ struct request *const started_at = base->req_heads[i], *req = started_at;
+ /* first transmit all the requests which are currently waiting */
+ do {
+ if (req->transmit_me) {
+ did_try_to_transmit = 1;
+ evdns_request_transmit(req);
+ }
+
+ req = req->next;
+ } while (req != started_at);
+ }
+ }
+
+ return did_try_to_transmit;
+}
+
+/* exported function */
+int
+evdns_base_count_nameservers(struct evdns_base *base)
+{
+ const struct nameserver *server;
+ int n = 0;
+
+ EVDNS_LOCK(base);
+ server = base->server_head;
+ if (!server)
+ goto done;
+ do {
+ ++n;
+ server = server->next;
+ } while (server != base->server_head);
+done:
+ EVDNS_UNLOCK(base);
+ return n;
+}
+
+int
+evdns_count_nameservers(void)
+{
+ return evdns_base_count_nameservers(current_base);
+}
+
+/* exported function */
+int
+evdns_base_clear_nameservers_and_suspend(struct evdns_base *base)
+{
+ struct nameserver *server, *started_at;
+ int i;
+
+ EVDNS_LOCK(base);
+ server = base->server_head;
+ started_at = base->server_head;
+ if (!server) {
+ EVDNS_UNLOCK(base);
+ return 0;
+ }
+ while (1) {
+ struct nameserver *next = server->next;
+ (void) event_del(&server->event);
+ if (evtimer_initialized(&server->timeout_event))
+ (void) evtimer_del(&server->timeout_event);
+ if (server->probe_request) {
+ evdns_cancel_request(server->base, server->probe_request);
+ server->probe_request = NULL;
+ }
+ if (server->socket >= 0)
+ evutil_closesocket(server->socket);
+ mm_free(server);
+ if (next == started_at)
+ break;
+ server = next;
+ }
+ base->server_head = NULL;
+ base->global_good_nameservers = 0;
+
+ for (i = 0; i < base->n_req_heads; ++i) {
+ struct request *req, *req_started_at;
+ req = req_started_at = base->req_heads[i];
+ while (req) {
+ struct request *next = req->next;
+ req->tx_count = req->reissue_count = 0;
+ req->ns = NULL;
+ /* ???? What to do about searches? */
+ (void) evtimer_del(&req->timeout_event);
+ req->trans_id = 0;
+ req->transmit_me = 0;
+
+ base->global_requests_waiting++;
+ evdns_request_insert(req, &base->req_waiting_head);
+ /* We want to insert these suspended elements at the front of
+ * the waiting queue, since they were pending before any of
+ * the waiting entries were added. This is a circular list,
+ * so we can just shift the start back by one.*/
+ base->req_waiting_head = base->req_waiting_head->prev;
+
+ if (next == req_started_at)
+ break;
+ req = next;
+ }
+ base->req_heads[i] = NULL;
+ }
+
+ base->global_requests_inflight = 0;
+
+ EVDNS_UNLOCK(base);
+ return 0;
+}
+
+int
+evdns_clear_nameservers_and_suspend(void)
+{
+ return evdns_base_clear_nameservers_and_suspend(current_base);
+}
+
+
+/* exported function */
+int
+evdns_base_resume(struct evdns_base *base)
+{
+ EVDNS_LOCK(base);
+ evdns_requests_pump_waiting_queue(base);
+ EVDNS_UNLOCK(base);
+
+ return 0;
+}
+
+int
+evdns_resume(void)
+{
+ return evdns_base_resume(current_base);
+}
+
+static int
+evdns_nameserver_add_impl_(struct evdns_base *base, const struct sockaddr *address, int addrlen) {
+ /* first check to see if we already have this nameserver */
+
+ const struct nameserver *server = base->server_head, *const started_at = base->server_head;
+ struct nameserver *ns;
+ int err = 0;
+ char addrbuf[128];
+
+ ASSERT_LOCKED(base);
+ if (server) {
+ do {
+ if (!evutil_sockaddr_cmp((struct sockaddr*)&server->address, address, 1)) return 3;
+ server = server->next;
+ } while (server != started_at);
+ }
+ if (addrlen > (int)sizeof(ns->address)) {
+ log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen);
+ return 2;
+ }
+
+ ns = (struct nameserver *) mm_malloc(sizeof(struct nameserver));
+ if (!ns) return -1;
+
+ memset(ns, 0, sizeof(struct nameserver));
+ ns->base = base;
+
+ evtimer_assign(&ns->timeout_event, ns->base->event_base, nameserver_prod_callback, ns);
+
+ ns->socket = evutil_socket_(address->sa_family,
+ SOCK_DGRAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0);
+ if (ns->socket < 0) { err = 1; goto out1; }
+
+ if (base->global_outgoing_addrlen &&
+ !evutil_sockaddr_is_loopback_(address)) {
+ if (bind(ns->socket,
+ (struct sockaddr*)&base->global_outgoing_address,
+ base->global_outgoing_addrlen) < 0) {
+ log(EVDNS_LOG_WARN,"Couldn't bind to outgoing address");
+ err = 2;
+ goto out2;
+ }
+ }
+
+ memcpy(&ns->address, address, addrlen);
+ ns->addrlen = addrlen;
+ ns->state = 1;
+ event_assign(&ns->event, ns->base->event_base, ns->socket,
+ EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
+ if (!base->disable_when_inactive && event_add(&ns->event, NULL) < 0) {
+ err = 2;
+ goto out2;
+ }
+
+ log(EVDNS_LOG_DEBUG, "Added nameserver %s as %p",
+ evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), ns);
+
+ /* insert this nameserver into the list of them */
+ if (!base->server_head) {
+ ns->next = ns->prev = ns;
+ base->server_head = ns;
+ } else {
+ ns->next = base->server_head->next;
+ ns->prev = base->server_head;
+ base->server_head->next = ns;
+ ns->next->prev = ns;
+ }
+
+ base->global_good_nameservers++;
+
+ return 0;
+
+out2:
+ evutil_closesocket(ns->socket);
+out1:
+ event_debug_unassign(&ns->event);
+ mm_free(ns);
+ log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d",
+ evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), err);
+ return err;
+}
+
+/* exported function */
+int
+evdns_base_nameserver_add(struct evdns_base *base, unsigned long int address)
+{
+ struct sockaddr_in sin;
+ int res;
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_addr.s_addr = address;
+ sin.sin_port = htons(53);
+ sin.sin_family = AF_INET;
+ EVDNS_LOCK(base);
+ res = evdns_nameserver_add_impl_(base, (struct sockaddr*)&sin, sizeof(sin));
+ EVDNS_UNLOCK(base);
+ return res;
+}
+
+int
+evdns_nameserver_add(unsigned long int address) {
+ if (!current_base)
+ current_base = evdns_base_new(NULL, 0);
+ return evdns_base_nameserver_add(current_base, address);
+}
+
+static void
+sockaddr_setport(struct sockaddr *sa, ev_uint16_t port)
+{
+ if (sa->sa_family == AF_INET) {
+ ((struct sockaddr_in *)sa)->sin_port = htons(port);
+ } else if (sa->sa_family == AF_INET6) {
+ ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
+ }
+}
+
+static ev_uint16_t
+sockaddr_getport(struct sockaddr *sa)
+{
+ if (sa->sa_family == AF_INET) {
+ return ntohs(((struct sockaddr_in *)sa)->sin_port);
+ } else if (sa->sa_family == AF_INET6) {
+ return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
+ } else {
+ return 0;
+ }
+}
+
+/* exported function */
+int
+evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string) {
+ struct sockaddr_storage ss;
+ struct sockaddr *sa;
+ int len = sizeof(ss);
+ int res;
+ if (evutil_parse_sockaddr_port(ip_as_string, (struct sockaddr *)&ss,
+ &len)) {
+ log(EVDNS_LOG_WARN, "Unable to parse nameserver address %s",
+ ip_as_string);
+ return 4;
+ }
+ sa = (struct sockaddr *) &ss;
+ if (sockaddr_getport(sa) == 0)
+ sockaddr_setport(sa, 53);
+
+ EVDNS_LOCK(base);
+ res = evdns_nameserver_add_impl_(base, sa, len);
+ EVDNS_UNLOCK(base);
+ return res;
+}
+
+int
+evdns_nameserver_ip_add(const char *ip_as_string) {
+ if (!current_base)
+ current_base = evdns_base_new(NULL, 0);
+ return evdns_base_nameserver_ip_add(current_base, ip_as_string);
+}
+
+int
+evdns_base_nameserver_sockaddr_add(struct evdns_base *base,
+ const struct sockaddr *sa, ev_socklen_t len, unsigned flags)
+{
+ int res;
+ EVUTIL_ASSERT(base);
+ EVDNS_LOCK(base);
+ res = evdns_nameserver_add_impl_(base, sa, len);
+ EVDNS_UNLOCK(base);
+ return res;
+}
+
+int
+evdns_base_get_nameserver_addr(struct evdns_base *base, int idx,
+ struct sockaddr *sa, ev_socklen_t len)
+{
+ int result = -1;
+ int i;
+ struct nameserver *server;
+ EVDNS_LOCK(base);
+ server = base->server_head;
+ for (i = 0; i < idx && server; ++i, server = server->next) {
+ if (server->next == base->server_head)
+ goto done;
+ }
+ if (! server)
+ goto done;
+
+ if (server->addrlen > len) {
+ result = (int) server->addrlen;
+ goto done;
+ }
+
+ memcpy(sa, &server->address, server->addrlen);
+ result = (int) server->addrlen;
+done:
+ EVDNS_UNLOCK(base);
+ return result;
+}
+
+/* remove from the queue */
+static void
+evdns_request_remove(struct request *req, struct request **head)
+{
+ ASSERT_LOCKED(req->base);
+ ASSERT_VALID_REQUEST(req);
+
+#if 0
+ {
+ struct request *ptr;
+ int found = 0;
+ EVUTIL_ASSERT(*head != NULL);
+
+ ptr = *head;
+ do {
+ if (ptr == req) {
+ found = 1;
+ break;
+ }
+ ptr = ptr->next;
+ } while (ptr != *head);
+ EVUTIL_ASSERT(found);
+
+ EVUTIL_ASSERT(req->next);
+ }
+#endif
+
+ if (req->next == req) {
+ /* only item in the list */
+ *head = NULL;
+ } else {
+ req->next->prev = req->prev;
+ req->prev->next = req->next;
+ if (*head == req) *head = req->next;
+ }
+ req->next = req->prev = NULL;
+}
+
+/* insert into the tail of the queue */
+static void
+evdns_request_insert(struct request *req, struct request **head) {
+ ASSERT_LOCKED(req->base);
+ ASSERT_VALID_REQUEST(req);
+ if (!*head) {
+ *head = req;
+ req->next = req->prev = req;
+ return;
+ }
+
+ req->prev = (*head)->prev;
+ req->prev->next = req;
+ req->next = *head;
+ (*head)->prev = req;
+}
+
+static int
+string_num_dots(const char *s) {
+ int count = 0;
+ while ((s = strchr(s, '.'))) {
+ s++;
+ count++;
+ }
+ return count;
+}
+
+static struct request *
+request_new(struct evdns_base *base, struct evdns_request *handle, int type,
+ const char *name, int flags, evdns_callback_type callback,
+ void *user_ptr) {
+
+ const char issuing_now =
+ (base->global_requests_inflight < base->global_max_requests_inflight) ? 1 : 0;
+
+ const size_t name_len = strlen(name);
+ const size_t request_max_len = evdns_request_len(name_len);
+ const u16 trans_id = issuing_now ? transaction_id_pick(base) : 0xffff;
+ /* the request data is alloced in a single block with the header */
+ struct request *const req =
+ mm_malloc(sizeof(struct request) + request_max_len);
+ int rlen;
+ char namebuf[256];
+ (void) flags;
+
+ ASSERT_LOCKED(base);
+
+ if (!req) return NULL;
+
+ if (name_len >= sizeof(namebuf)) {
+ mm_free(req);
+ return NULL;
+ }
+
+ memset(req, 0, sizeof(struct request));
+ req->base = base;
+
+ evtimer_assign(&req->timeout_event, req->base->event_base, evdns_request_timeout_callback, req);
+
+ if (base->global_randomize_case) {
+ unsigned i;
+ char randbits[(sizeof(namebuf)+7)/8];
+ strlcpy(namebuf, name, sizeof(namebuf));
+ evutil_secure_rng_get_bytes(randbits, (name_len+7)/8);
+ for (i = 0; i < name_len; ++i) {
+ if (EVUTIL_ISALPHA_(namebuf[i])) {
+ if ((randbits[i >> 3] & (1<<(i & 7))))
+ namebuf[i] |= 0x20;
+ else
+ namebuf[i] &= ~0x20;
+ }
+ }
+ name = namebuf;
+ }
+
+ /* request data lives just after the header */
+ req->request = ((u8 *) req) + sizeof(struct request);
+ /* denotes that the request data shouldn't be free()ed */
+ req->request_appended = 1;
+ rlen = evdns_request_data_build(name, name_len, trans_id,
+ type, CLASS_INET, req->request, request_max_len);
+ if (rlen < 0)
+ goto err1;
+
+ req->request_len = rlen;
+ req->trans_id = trans_id;
+ req->tx_count = 0;
+ req->request_type = type;
+ req->user_pointer = user_ptr;
+ req->user_callback = callback;
+ req->ns = issuing_now ? nameserver_pick(base) : NULL;
+ req->next = req->prev = NULL;
+ req->handle = handle;
+ if (handle) {
+ handle->current_req = req;
+ handle->base = base;
+ }
+
+ return req;
+err1:
+ mm_free(req);
+ return NULL;
+}
+
+static void
+request_submit(struct request *const req) {
+ struct evdns_base *base = req->base;
+ ASSERT_LOCKED(base);
+ ASSERT_VALID_REQUEST(req);
+ if (req->ns) {
+ /* if it has a nameserver assigned then this is going */
+ /* straight into the inflight queue */
+ evdns_request_insert(req, &REQ_HEAD(base, req->trans_id));
+
+ base->global_requests_inflight++;
+ req->ns->requests_inflight++;
+
+ evdns_request_transmit(req);
+ } else {
+ evdns_request_insert(req, &base->req_waiting_head);
+ base->global_requests_waiting++;
+ }
+}
+
+/* exported function */
+void
+evdns_cancel_request(struct evdns_base *base, struct evdns_request *handle)
+{
+ struct request *req;
+
+ if (!handle->current_req)
+ return;
+
+ if (!base) {
+ /* This redundancy is silly; can we fix it? (Not for 2.0) XXXX */
+ base = handle->base;
+ if (!base)
+ base = handle->current_req->base;
+ }
+
+ EVDNS_LOCK(base);
+ if (handle->pending_cb) {
+ EVDNS_UNLOCK(base);
+ return;
+ }
+
+ req = handle->current_req;
+ ASSERT_VALID_REQUEST(req);
+
+ reply_schedule_callback(req, 0, DNS_ERR_CANCEL, NULL);
+ if (req->ns) {
+ /* remove from inflight queue */
+ request_finished(req, &REQ_HEAD(base, req->trans_id), 1);
+ } else {
+ /* remove from global_waiting head */
+ request_finished(req, &base->req_waiting_head, 1);
+ }
+ EVDNS_UNLOCK(base);
+}
+
+/* exported function */
+struct evdns_request *
+evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags,
+ evdns_callback_type callback, void *ptr) {
+ struct evdns_request *handle;
+ struct request *req;
+ log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
+ handle = mm_calloc(1, sizeof(*handle));
+ if (handle == NULL)
+ return NULL;
+ EVDNS_LOCK(base);
+ if (flags & DNS_QUERY_NO_SEARCH) {
+ req =
+ request_new(base, handle, TYPE_A, name, flags,
+ callback, ptr);
+ if (req)
+ request_submit(req);
+ } else {
+ search_request_new(base, handle, TYPE_A, name, flags,
+ callback, ptr);
+ }
+ if (handle->current_req == NULL) {
+ mm_free(handle);
+ handle = NULL;
+ }
+ EVDNS_UNLOCK(base);
+ return handle;
+}
+
+int evdns_resolve_ipv4(const char *name, int flags,
+ evdns_callback_type callback, void *ptr)
+{
+ return evdns_base_resolve_ipv4(current_base, name, flags, callback, ptr)
+ ? 0 : -1;
+}
+
+
+/* exported function */
+struct evdns_request *
+evdns_base_resolve_ipv6(struct evdns_base *base,
+ const char *name, int flags,
+ evdns_callback_type callback, void *ptr)
+{
+ struct evdns_request *handle;
+ struct request *req;
+ log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
+ handle = mm_calloc(1, sizeof(*handle));
+ if (handle == NULL)
+ return NULL;
+ EVDNS_LOCK(base);
+ if (flags & DNS_QUERY_NO_SEARCH) {
+ req = request_new(base, handle, TYPE_AAAA, name, flags,
+ callback, ptr);
+ if (req)
+ request_submit(req);
+ } else {
+ search_request_new(base, handle, TYPE_AAAA, name, flags,
+ callback, ptr);
+ }
+ if (handle->current_req == NULL) {
+ mm_free(handle);
+ handle = NULL;
+ }
+ EVDNS_UNLOCK(base);
+ return handle;
+}
+
+int evdns_resolve_ipv6(const char *name, int flags,
+ evdns_callback_type callback, void *ptr) {
+ return evdns_base_resolve_ipv6(current_base, name, flags, callback, ptr)
+ ? 0 : -1;
+}
+
+struct evdns_request *
+evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
+ char buf[32];
+ struct evdns_request *handle;
+ struct request *req;
+ u32 a;
+ EVUTIL_ASSERT(in);
+ a = ntohl(in->s_addr);
+ evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
+ (int)(u8)((a )&0xff),
+ (int)(u8)((a>>8 )&0xff),
+ (int)(u8)((a>>16)&0xff),
+ (int)(u8)((a>>24)&0xff));
+ handle = mm_calloc(1, sizeof(*handle));
+ if (handle == NULL)
+ return NULL;
+ log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
+ EVDNS_LOCK(base);
+ req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
+ if (req)
+ request_submit(req);
+ if (handle->current_req == NULL) {
+ mm_free(handle);
+ handle = NULL;
+ }
+ EVDNS_UNLOCK(base);
+ return (handle);
+}
+
+int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
+ return evdns_base_resolve_reverse(current_base, in, flags, callback, ptr)
+ ? 0 : -1;
+}
+
+struct evdns_request *
+evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
+ /* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
+ char buf[73];
+ char *cp;
+ struct evdns_request *handle;
+ struct request *req;
+ int i;
+ EVUTIL_ASSERT(in);
+ cp = buf;
+ for (i=15; i >= 0; --i) {
+ u8 byte = in->s6_addr[i];
+ *cp++ = "0123456789abcdef"[byte & 0x0f];
+ *cp++ = '.';
+ *cp++ = "0123456789abcdef"[byte >> 4];
+ *cp++ = '.';
+ }
+ EVUTIL_ASSERT(cp + strlen("ip6.arpa") < buf+sizeof(buf));
+ memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
+ handle = mm_calloc(1, sizeof(*handle));
+ if (handle == NULL)
+ return NULL;
+ log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
+ EVDNS_LOCK(base);
+ req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
+ if (req)
+ request_submit(req);
+ if (handle->current_req == NULL) {
+ mm_free(handle);
+ handle = NULL;
+ }
+ EVDNS_UNLOCK(base);
+ return (handle);
+}
+
+int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
+ return evdns_base_resolve_reverse_ipv6(current_base, in, flags, callback, ptr)
+ ? 0 : -1;
+}
+
+/* ================================================================= */
+/* Search support */
+/* */
+/* the libc resolver has support for searching a number of domains */
+/* to find a name. If nothing else then it takes the single domain */
+/* from the gethostname() call. */
+/* */
+/* It can also be configured via the domain and search options in a */
+/* resolv.conf. */
+/* */
+/* The ndots option controls how many dots it takes for the resolver */
+/* to decide that a name is non-local and so try a raw lookup first. */
+
+struct search_domain {
+ int len;
+ struct search_domain *next;
+ /* the text string is appended to this structure */
+};
+
+struct search_state {
+ int refcount;
+ int ndots;
+ int num_domains;
+ struct search_domain *head;
+};
+
+static void
+search_state_decref(struct search_state *const state) {
+ if (!state) return;
+ state->refcount--;
+ if (!state->refcount) {
+ struct search_domain *next, *dom;
+ for (dom = state->head; dom; dom = next) {
+ next = dom->next;
+ mm_free(dom);
+ }
+ mm_free(state);
+ }
+}
+
+static struct search_state *
+search_state_new(void) {
+ struct search_state *state = (struct search_state *) mm_malloc(sizeof(struct search_state));
+ if (!state) return NULL;
+ memset(state, 0, sizeof(struct search_state));
+ state->refcount = 1;
+ state->ndots = 1;
+
+ return state;
+}
+
+static void
+search_postfix_clear(struct evdns_base *base) {
+ search_state_decref(base->global_search_state);
+
+ base->global_search_state = search_state_new();
+}
+
+/* exported function */
+void
+evdns_base_search_clear(struct evdns_base *base)
+{
+ EVDNS_LOCK(base);
+ search_postfix_clear(base);
+ EVDNS_UNLOCK(base);
+}
+
+void
+evdns_search_clear(void) {
+ evdns_base_search_clear(current_base);
+}
+
+static void
+search_postfix_add(struct evdns_base *base, const char *domain) {
+ size_t domain_len;
+ struct search_domain *sdomain;
+ while (domain[0] == '.') domain++;
+ domain_len = strlen(domain);
+
+ ASSERT_LOCKED(base);
+ if (!base->global_search_state) base->global_search_state = search_state_new();
+ if (!base->global_search_state) return;
+ base->global_search_state->num_domains++;
+
+ sdomain = (struct search_domain *) mm_malloc(sizeof(struct search_domain) + domain_len);
+ if (!sdomain) return;
+ memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len);
+ sdomain->next = base->global_search_state->head;
+ sdomain->len = (int) domain_len;
+
+ base->global_search_state->head = sdomain;
+}
+
+/* reverse the order of members in the postfix list. This is needed because, */
+/* when parsing resolv.conf we push elements in the wrong order */
+static void
+search_reverse(struct evdns_base *base) {
+ struct search_domain *cur, *prev = NULL, *next;
+ ASSERT_LOCKED(base);
+ cur = base->global_search_state->head;
+ while (cur) {
+ next = cur->next;
+ cur->next = prev;
+ prev = cur;
+ cur = next;
+ }
+
+ base->global_search_state->head = prev;
+}
+
+/* exported function */
+void
+evdns_base_search_add(struct evdns_base *base, const char *domain) {
+ EVDNS_LOCK(base);
+ search_postfix_add(base, domain);
+ EVDNS_UNLOCK(base);
+}
+void
+evdns_search_add(const char *domain) {
+ evdns_base_search_add(current_base, domain);
+}
+
+/* exported function */
+void
+evdns_base_search_ndots_set(struct evdns_base *base, const int ndots) {
+ EVDNS_LOCK(base);
+ if (!base->global_search_state) base->global_search_state = search_state_new();
+ if (base->global_search_state)
+ base->global_search_state->ndots = ndots;
+ EVDNS_UNLOCK(base);
+}
+void
+evdns_search_ndots_set(const int ndots) {
+ evdns_base_search_ndots_set(current_base, ndots);
+}
+
+static void
+search_set_from_hostname(struct evdns_base *base) {
+ char hostname[HOST_NAME_MAX + 1], *domainname;
+
+ ASSERT_LOCKED(base);
+ search_postfix_clear(base);
+ if (gethostname(hostname, sizeof(hostname))) return;
+ domainname = strchr(hostname, '.');
+ if (!domainname) return;
+ search_postfix_add(base, domainname);
+}
+
+/* warning: returns malloced string */
+static char *
+search_make_new(const struct search_state *const state, int n, const char *const base_name) {
+ const size_t base_len = strlen(base_name);
+ char need_to_append_dot;
+ struct search_domain *dom;
+
+ if (!base_len) return NULL;
+ need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
+
+ for (dom = state->head; dom; dom = dom->next) {
+ if (!n--) {
+ /* this is the postfix we want */
+ /* the actual postfix string is kept at the end of the structure */
+ const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain);
+ const int postfix_len = dom->len;
+ char *const newname = (char *) mm_malloc(base_len + need_to_append_dot + postfix_len + 1);
+ if (!newname) return NULL;
+ memcpy(newname, base_name, base_len);
+ if (need_to_append_dot) newname[base_len] = '.';
+ memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len);
+ newname[base_len + need_to_append_dot + postfix_len] = 0;
+ return newname;
+ }
+ }
+
+ /* we ran off the end of the list and still didn't find the requested string */
+ EVUTIL_ASSERT(0);
+ return NULL; /* unreachable; stops warnings in some compilers. */
+}
+
+static struct request *
+search_request_new(struct evdns_base *base, struct evdns_request *handle,
+ int type, const char *const name, int flags,
+ evdns_callback_type user_callback, void *user_arg) {
+ ASSERT_LOCKED(base);
+ EVUTIL_ASSERT(type == TYPE_A || type == TYPE_AAAA);
+ EVUTIL_ASSERT(handle->current_req == NULL);
+ if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
+ base->global_search_state &&
+ base->global_search_state->num_domains) {
+ /* we have some domains to search */
+ struct request *req;
+ if (string_num_dots(name) >= base->global_search_state->ndots) {
+ req = request_new(base, handle, type, name, flags, user_callback, user_arg);
+ if (!req) return NULL;
+ handle->search_index = -1;
+ } else {
+ char *const new_name = search_make_new(base->global_search_state, 0, name);
+ if (!new_name) return NULL;
+ req = request_new(base, handle, type, new_name, flags, user_callback, user_arg);
+ mm_free(new_name);
+ if (!req) return NULL;
+ handle->search_index = 0;
+ }
+ EVUTIL_ASSERT(handle->search_origname == NULL);
+ handle->search_origname = mm_strdup(name);
+ if (handle->search_origname == NULL) {
+ /* XXX Should we dealloc req? If yes, how? */
+ if (req)
+ mm_free(req);
+ return NULL;
+ }
+ handle->search_state = base->global_search_state;
+ handle->search_flags = flags;
+ base->global_search_state->refcount++;
+ request_submit(req);
+ return req;
+ } else {
+ struct request *const req = request_new(base, handle, type, name, flags, user_callback, user_arg);
+ if (!req) return NULL;
+ request_submit(req);
+ return req;
+ }
+}
+
+/* this is called when a request has failed to find a name. We need to check */
+/* if it is part of a search and, if so, try the next name in the list */
+/* returns: */
+/* 0 another request has been submitted */
+/* 1 no more requests needed */
+static int
+search_try_next(struct evdns_request *const handle) {
+ struct request *req = handle->current_req;
+ struct evdns_base *base = req->base;
+ struct request *newreq;
+ ASSERT_LOCKED(base);
+ if (handle->search_state) {
+ /* it is part of a search */
+ char *new_name;
+ handle->search_index++;
+ if (handle->search_index >= handle->search_state->num_domains) {
+ /* no more postfixes to try, however we may need to try */
+ /* this name without a postfix */
+ if (string_num_dots(handle->search_origname) < handle->search_state->ndots) {
+ /* yep, we need to try it raw */
+ newreq = request_new(base, NULL, req->request_type, handle->search_origname, handle->search_flags, req->user_callback, req->user_pointer);
+ log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", handle->search_origname);
+ if (newreq) {
+ search_request_finished(handle);
+ goto submit_next;
+ }
+ }
+ return 1;
+ }
+
+ new_name = search_make_new(handle->search_state, handle->search_index, handle->search_origname);
+ if (!new_name) return 1;
+ log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, handle->search_index);
+ newreq = request_new(base, NULL, req->request_type, new_name, handle->search_flags, req->user_callback, req->user_pointer);
+ mm_free(new_name);
+ if (!newreq) return 1;
+ goto submit_next;
+ }
+ return 1;
+
+submit_next:
+ request_finished(req, &REQ_HEAD(req->base, req->trans_id), 0);
+ handle->current_req = newreq;
+ newreq->handle = handle;
+ request_submit(newreq);
+ return 0;
+}
+
+static void
+search_request_finished(struct evdns_request *const handle) {
+ ASSERT_LOCKED(handle->current_req->base);
+ if (handle->search_state) {
+ search_state_decref(handle->search_state);
+ handle->search_state = NULL;
+ }
+ if (handle->search_origname) {
+ mm_free(handle->search_origname);
+ handle->search_origname = NULL;
+ }
+}
+
+/* ================================================================= */
+/* Parsing resolv.conf files */
+
+static void
+evdns_resolv_set_defaults(struct evdns_base *base, int flags) {
+ /* if the file isn't found then we assume a local resolver */
+ ASSERT_LOCKED(base);
+ if (flags & DNS_OPTION_SEARCH) search_set_from_hostname(base);
+ if (flags & DNS_OPTION_NAMESERVERS) evdns_base_nameserver_ip_add(base,"127.0.0.1");
+}
+
+#ifndef EVENT__HAVE_STRTOK_R
+static char *
+strtok_r(char *s, const char *delim, char **state) {
+ char *cp, *start;
+ start = cp = s ? s : *state;
+ if (!cp)
+ return NULL;
+ while (*cp && !strchr(delim, *cp))
+ ++cp;
+ if (!*cp) {
+ if (cp == start)
+ return NULL;
+ *state = NULL;
+ return start;
+ } else {
+ *cp++ = '\0';
+ *state = cp;
+ return start;
+ }
+}
+#endif
+
+/* helper version of atoi which returns -1 on error */
+static int
+strtoint(const char *const str)
+{
+ char *endptr;
+ const int r = strtol(str, &endptr, 10);
+ if (*endptr) return -1;
+ return r;
+}
+
+/* Parse a number of seconds into a timeval; return -1 on error. */
+static int
+evdns_strtotimeval(const char *const str, struct timeval *out)
+{
+ double d;
+ char *endptr;
+ d = strtod(str, &endptr);
+ if (*endptr) return -1;
+ if (d < 0) return -1;
+ out->tv_sec = (int) d;
+ out->tv_usec = (int) ((d - (int) d)*1000000);
+ if (out->tv_sec == 0 && out->tv_usec < 1000) /* less than 1 msec */
+ return -1;
+ return 0;
+}
+
+/* helper version of atoi that returns -1 on error and clips to bounds. */
+static int
+strtoint_clipped(const char *const str, int min, int max)
+{
+ int r = strtoint(str);
+ if (r == -1)
+ return r;
+ else if (r<min)
+ return min;
+ else if (r>max)
+ return max;
+ else
+ return r;
+}
+
+static int
+evdns_base_set_max_requests_inflight(struct evdns_base *base, int maxinflight)
+{
+ int old_n_heads = base->n_req_heads, n_heads;
+ struct request **old_heads = base->req_heads, **new_heads, *req;
+ int i;
+
+ ASSERT_LOCKED(base);
+ if (maxinflight < 1)
+ maxinflight = 1;
+ n_heads = (maxinflight+4) / 5;
+ EVUTIL_ASSERT(n_heads > 0);
+ new_heads = mm_calloc(n_heads, sizeof(struct request*));
+ if (!new_heads)
+ return (-1);
+ if (old_heads) {
+ for (i = 0; i < old_n_heads; ++i) {
+ while (old_heads[i]) {
+ req = old_heads[i];
+ evdns_request_remove(req, &old_heads[i]);
+ evdns_request_insert(req, &new_heads[req->trans_id % n_heads]);
+ }
+ }
+ mm_free(old_heads);
+ }
+ base->req_heads = new_heads;
+ base->n_req_heads = n_heads;
+ base->global_max_requests_inflight = maxinflight;
+ return (0);
+}
+
+/* exported function */
+int
+evdns_base_set_option(struct evdns_base *base,
+ const char *option, const char *val)
+{
+ int res;
+ EVDNS_LOCK(base);
+ res = evdns_base_set_option_impl(base, option, val, DNS_OPTIONS_ALL);
+ EVDNS_UNLOCK(base);
+ return res;
+}
+
+static inline int
+str_matches_option(const char *s1, const char *optionname)
+{
+ /* Option names are given as "option:" We accept either 'option' in
+ * s1, or 'option:randomjunk'. The latter form is to implement the
+ * resolv.conf parser. */
+ size_t optlen = strlen(optionname);
+ size_t slen = strlen(s1);
+ if (slen == optlen || slen == optlen - 1)
+ return !strncmp(s1, optionname, slen);
+ else if (slen > optlen)
+ return !strncmp(s1, optionname, optlen);
+ else
+ return 0;
+}
+
+static int
+evdns_base_set_option_impl(struct evdns_base *base,
+ const char *option, const char *val, int flags)
+{
+ ASSERT_LOCKED(base);
+ if (str_matches_option(option, "ndots:")) {
+ const int ndots = strtoint(val);
+ if (ndots == -1) return -1;
+ if (!(flags & DNS_OPTION_SEARCH)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
+ if (!base->global_search_state) base->global_search_state = search_state_new();
+ if (!base->global_search_state) return -1;
+ base->global_search_state->ndots = ndots;
+ } else if (str_matches_option(option, "timeout:")) {
+ struct timeval tv;
+ if (evdns_strtotimeval(val, &tv) == -1) return -1;
+ if (!(flags & DNS_OPTION_MISC)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting timeout to %s", val);
+ memcpy(&base->global_timeout, &tv, sizeof(struct timeval));
+ } else if (str_matches_option(option, "getaddrinfo-allow-skew:")) {
+ struct timeval tv;
+ if (evdns_strtotimeval(val, &tv) == -1) return -1;
+ if (!(flags & DNS_OPTION_MISC)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting getaddrinfo-allow-skew to %s",
+ val);
+ memcpy(&base->global_getaddrinfo_allow_skew, &tv,
+ sizeof(struct timeval));
+ } else if (str_matches_option(option, "max-timeouts:")) {
+ const int maxtimeout = strtoint_clipped(val, 1, 255);
+ if (maxtimeout == -1) return -1;
+ if (!(flags & DNS_OPTION_MISC)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
+ maxtimeout);
+ base->global_max_nameserver_timeout = maxtimeout;
+ } else if (str_matches_option(option, "max-inflight:")) {
+ const int maxinflight = strtoint_clipped(val, 1, 65000);
+ if (maxinflight == -1) return -1;
+ if (!(flags & DNS_OPTION_MISC)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
+ maxinflight);
+ evdns_base_set_max_requests_inflight(base, maxinflight);
+ } else if (str_matches_option(option, "attempts:")) {
+ int retries = strtoint(val);
+ if (retries == -1) return -1;
+ if (retries > 255) retries = 255;
+ if (!(flags & DNS_OPTION_MISC)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
+ base->global_max_retransmits = retries;
+ } else if (str_matches_option(option, "randomize-case:")) {
+ int randcase = strtoint(val);
+ if (!(flags & DNS_OPTION_MISC)) return 0;
+ base->global_randomize_case = randcase;
+ } else if (str_matches_option(option, "bind-to:")) {
+ /* XXX This only applies to successive nameservers, not
+ * to already-configured ones. We might want to fix that. */
+ int len = sizeof(base->global_outgoing_address);
+ if (!(flags & DNS_OPTION_NAMESERVERS)) return 0;
+ if (evutil_parse_sockaddr_port(val,
+ (struct sockaddr*)&base->global_outgoing_address, &len))
+ return -1;
+ base->global_outgoing_addrlen = len;
+ } else if (str_matches_option(option, "initial-probe-timeout:")) {
+ struct timeval tv;
+ if (evdns_strtotimeval(val, &tv) == -1) return -1;
+ if (tv.tv_sec > 3600)
+ tv.tv_sec = 3600;
+ if (!(flags & DNS_OPTION_MISC)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting initial probe timeout to %s",
+ val);
+ memcpy(&base->global_nameserver_probe_initial_timeout, &tv,
+ sizeof(tv));
+ }
+ return 0;
+}
+
+int
+evdns_set_option(const char *option, const char *val, int flags)
+{
+ if (!current_base)
+ current_base = evdns_base_new(NULL, 0);
+ return evdns_base_set_option(current_base, option, val);
+}
+
+static void
+resolv_conf_parse_line(struct evdns_base *base, char *const start, int flags) {
+ char *strtok_state;
+ static const char *const delims = " \t";
+#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
+
+
+ char *const first_token = strtok_r(start, delims, &strtok_state);
+ ASSERT_LOCKED(base);
+ if (!first_token) return;
+
+ if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
+ const char *const nameserver = NEXT_TOKEN;
+
+ if (nameserver)
+ evdns_base_nameserver_ip_add(base, nameserver);
+ } else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
+ const char *const domain = NEXT_TOKEN;
+ if (domain) {
+ search_postfix_clear(base);
+ search_postfix_add(base, domain);
+ }
+ } else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) {
+ const char *domain;
+ search_postfix_clear(base);
+
+ while ((domain = NEXT_TOKEN)) {
+ search_postfix_add(base, domain);
+ }
+ search_reverse(base);
+ } else if (!strcmp(first_token, "options")) {
+ const char *option;
+ while ((option = NEXT_TOKEN)) {
+ const char *val = strchr(option, ':');
+ evdns_base_set_option_impl(base, option, val ? val+1 : "", flags);
+ }
+ }
+#undef NEXT_TOKEN
+}
+
+/* exported function */
+/* returns: */
+/* 0 no errors */
+/* 1 failed to open file */
+/* 2 failed to stat file */
+/* 3 file too large */
+/* 4 out of memory */
+/* 5 short read from file */
+int
+evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename) {
+ int res;
+ EVDNS_LOCK(base);
+ res = evdns_base_resolv_conf_parse_impl(base, flags, filename);
+ EVDNS_UNLOCK(base);
+ return res;
+}
+
+static char *
+evdns_get_default_hosts_filename(void)
+{
+#ifdef _WIN32
+ /* Windows is a little coy about where it puts its configuration
+ * files. Sure, they're _usually_ in C:\windows\system32, but
+ * there's no reason in principle they couldn't be in
+ * W:\hoboken chicken emergency\
+ */
+ char path[MAX_PATH+1];
+ static const char hostfile[] = "\\drivers\\etc\\hosts";
+ char *path_out;
+ size_t len_out;
+
+ if (! SHGetSpecialFolderPathA(NULL, path, CSIDL_SYSTEM, 0))
+ return NULL;
+ len_out = strlen(path)+strlen(hostfile)+1;
+ path_out = mm_malloc(len_out);
+ evutil_snprintf(path_out, len_out, "%s%s", path, hostfile);
+ return path_out;
+#else
+ return mm_strdup("/etc/hosts");
+#endif
+}
+
+static int
+evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename) {
+ size_t n;
+ char *resolv;
+ char *start;
+ int err = 0;
+
+ log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
+
+ if (flags & DNS_OPTION_HOSTSFILE) {
+ char *fname = evdns_get_default_hosts_filename();
+ evdns_base_load_hosts(base, fname);
+ if (fname)
+ mm_free(fname);
+ }
+
+ if ((err = evutil_read_file_(filename, &resolv, &n, 0)) < 0) {
+ if (err == -1) {
+ /* No file. */
+ evdns_resolv_set_defaults(base, flags);
+ return 1;
+ } else {
+ return 2;
+ }
+ }
+
+ start = resolv;
+ for (;;) {
+ char *const newline = strchr(start, '\n');
+ if (!newline) {
+ resolv_conf_parse_line(base, start, flags);
+ break;
+ } else {
+ *newline = 0;
+ resolv_conf_parse_line(base, start, flags);
+ start = newline + 1;
+ }
+ }
+
+ if (!base->server_head && (flags & DNS_OPTION_NAMESERVERS)) {
+ /* no nameservers were configured. */
+ evdns_base_nameserver_ip_add(base, "127.0.0.1");
+ err = 6;
+ }
+ if (flags & DNS_OPTION_SEARCH && (!base->global_search_state || base->global_search_state->num_domains == 0)) {
+ search_set_from_hostname(base);
+ }
+
+ mm_free(resolv);
+ return err;
+}
+
+int
+evdns_resolv_conf_parse(int flags, const char *const filename) {
+ if (!current_base)
+ current_base = evdns_base_new(NULL, 0);
+ return evdns_base_resolv_conf_parse(current_base, flags, filename);
+}
+
+
+#ifdef _WIN32
+/* Add multiple nameservers from a space-or-comma-separated list. */
+static int
+evdns_nameserver_ip_add_line(struct evdns_base *base, const char *ips) {
+ const char *addr;
+ char *buf;
+ int r;
+ ASSERT_LOCKED(base);
+ while (*ips) {
+ while (isspace(*ips) || *ips == ',' || *ips == '\t')
+ ++ips;
+ addr = ips;
+ while (isdigit(*ips) || *ips == '.' || *ips == ':' ||
+ *ips=='[' || *ips==']')
+ ++ips;
+ buf = mm_malloc(ips-addr+1);
+ if (!buf) return 4;
+ memcpy(buf, addr, ips-addr);
+ buf[ips-addr] = '\0';
+ r = evdns_base_nameserver_ip_add(base, buf);
+ mm_free(buf);
+ if (r) return r;
+ }
+ return 0;
+}
+
+typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*);
+
+/* Use the windows GetNetworkParams interface in iphlpapi.dll to */
+/* figure out what our nameservers are. */
+static int
+load_nameservers_with_getnetworkparams(struct evdns_base *base)
+{
+ /* Based on MSDN examples and inspection of c-ares code. */
+ FIXED_INFO *fixed;
+ HMODULE handle = 0;
+ ULONG size = sizeof(FIXED_INFO);
+ void *buf = NULL;
+ int status = 0, r, added_any;
+ IP_ADDR_STRING *ns;
+ GetNetworkParams_fn_t fn;
+
+ ASSERT_LOCKED(base);
+ if (!(handle = evutil_load_windows_system_library_(
+ TEXT("iphlpapi.dll")))) {
+ log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
+ status = -1;
+ goto done;
+ }
+ if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) {
+ log(EVDNS_LOG_WARN, "Could not get address of function.");
+ status = -1;
+ goto done;
+ }
+
+ buf = mm_malloc(size);
+ if (!buf) { status = 4; goto done; }
+ fixed = buf;
+ r = fn(fixed, &size);
+ if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
+ status = -1;
+ goto done;
+ }
+ if (r != ERROR_SUCCESS) {
+ mm_free(buf);
+ buf = mm_malloc(size);
+ if (!buf) { status = 4; goto done; }
+ fixed = buf;
+ r = fn(fixed, &size);
+ if (r != ERROR_SUCCESS) {
+ log(EVDNS_LOG_DEBUG, "fn() failed.");
+ status = -1;
+ goto done;
+ }
+ }
+
+ EVUTIL_ASSERT(fixed);
+ added_any = 0;
+ ns = &(fixed->DnsServerList);
+ while (ns) {
+ r = evdns_nameserver_ip_add_line(base, ns->IpAddress.String);
+ if (r) {
+ log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d",
+ (ns->IpAddress.String),(int)GetLastError());
+ status = r;
+ } else {
+ ++added_any;
+ log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String);
+ }
+
+ ns = ns->Next;
+ }
+
+ if (!added_any) {
+ log(EVDNS_LOG_DEBUG, "No nameservers added.");
+ if (status == 0)
+ status = -1;
+ } else {
+ status = 0;
+ }
+
+ done:
+ if (buf)
+ mm_free(buf);
+ if (handle)
+ FreeLibrary(handle);
+ return status;
+}
+
+static int
+config_nameserver_from_reg_key(struct evdns_base *base, HKEY key, const TCHAR *subkey)
+{
+ char *buf;
+ DWORD bufsz = 0, type = 0;
+ int status = 0;
+
+ ASSERT_LOCKED(base);
+ if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz)
+ != ERROR_MORE_DATA)
+ return -1;
+ if (!(buf = mm_malloc(bufsz)))
+ return -1;
+
+ if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
+ == ERROR_SUCCESS && bufsz > 1) {
+ status = evdns_nameserver_ip_add_line(base,buf);
+ }
+
+ mm_free(buf);
+ return status;
+}
+
+#define SERVICES_KEY TEXT("System\\CurrentControlSet\\Services\\")
+#define WIN_NS_9X_KEY SERVICES_KEY TEXT("VxD\\MSTCP")
+#define WIN_NS_NT_KEY SERVICES_KEY TEXT("Tcpip\\Parameters")
+
+static int
+load_nameservers_from_registry(struct evdns_base *base)
+{
+ int found = 0;
+ int r;
+#define TRY(k, name) \
+ if (!found && config_nameserver_from_reg_key(base,k,TEXT(name)) == 0) { \
+ log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \
+ found = 1; \
+ } else if (!found) { \
+ log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \
+ #k,#name); \
+ }
+
+ ASSERT_LOCKED(base);
+
+ if (((int)GetVersion()) > 0) { /* NT */
+ HKEY nt_key = 0, interfaces_key = 0;
+
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
+ KEY_READ, &nt_key) != ERROR_SUCCESS) {
+ log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
+ return -1;
+ }
+ r = RegOpenKeyEx(nt_key, TEXT("Interfaces"), 0,
+ KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
+ &interfaces_key);
+ if (r != ERROR_SUCCESS) {
+ log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError());
+ return -1;
+ }
+ TRY(nt_key, "NameServer");
+ TRY(nt_key, "DhcpNameServer");
+ TRY(interfaces_key, "NameServer");
+ TRY(interfaces_key, "DhcpNameServer");
+ RegCloseKey(interfaces_key);
+ RegCloseKey(nt_key);
+ } else {
+ HKEY win_key = 0;
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
+ KEY_READ, &win_key) != ERROR_SUCCESS) {
+ log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError());
+ return -1;
+ }
+ TRY(win_key, "NameServer");
+ RegCloseKey(win_key);
+ }
+
+ if (found == 0) {
+ log(EVDNS_LOG_WARN,"Didn't find any nameservers.");
+ }
+
+ return found ? 0 : -1;
+#undef TRY
+}
+
+int
+evdns_base_config_windows_nameservers(struct evdns_base *base)
+{
+ int r;
+ char *fname;
+ if (base == NULL)
+ base = current_base;
+ if (base == NULL)
+ return -1;
+ EVDNS_LOCK(base);
+ fname = evdns_get_default_hosts_filename();
+ log(EVDNS_LOG_DEBUG, "Loading hosts entries from %s", fname);
+ evdns_base_load_hosts(base, fname);
+ if (fname)
+ mm_free(fname);
+
+ if (load_nameservers_with_getnetworkparams(base) == 0) {
+ EVDNS_UNLOCK(base);
+ return 0;
+ }
+ r = load_nameservers_from_registry(base);
+
+ EVDNS_UNLOCK(base);
+ return r;
+}
+
+int
+evdns_config_windows_nameservers(void)
+{
+ if (!current_base) {
+ current_base = evdns_base_new(NULL, 1);
+ return current_base == NULL ? -1 : 0;
+ } else {
+ return evdns_base_config_windows_nameservers(current_base);
+ }
+}
+#endif
+
+struct evdns_base *
+evdns_base_new(struct event_base *event_base, int flags)
+{
+ struct evdns_base *base;
+
+ if (evutil_secure_rng_init() < 0) {
+ log(EVDNS_LOG_WARN, "Unable to seed random number generator; "
+ "DNS can't run.");
+ return NULL;
+ }
+
+ /* Give the evutil library a hook into its evdns-enabled
+ * functionality. We can't just call evdns_getaddrinfo directly or
+ * else libevent-core will depend on libevent-extras. */
+ evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo);
+ evutil_set_evdns_getaddrinfo_cancel_fn_(evdns_getaddrinfo_cancel);
+
+ base = mm_malloc(sizeof(struct evdns_base));
+ if (base == NULL)
+ return (NULL);
+ memset(base, 0, sizeof(struct evdns_base));
+ base->req_waiting_head = NULL;
+
+ EVTHREAD_ALLOC_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ EVDNS_LOCK(base);
+
+ /* Set max requests inflight and allocate req_heads. */
+ base->req_heads = NULL;
+
+ evdns_base_set_max_requests_inflight(base, 64);
+
+ base->server_head = NULL;
+ base->event_base = event_base;
+ base->global_good_nameservers = base->global_requests_inflight =
+ base->global_requests_waiting = 0;
+
+ base->global_timeout.tv_sec = 5;
+ base->global_timeout.tv_usec = 0;
+ base->global_max_reissues = 1;
+ base->global_max_retransmits = 3;
+ base->global_max_nameserver_timeout = 3;
+ base->global_search_state = NULL;
+ base->global_randomize_case = 1;
+ base->global_getaddrinfo_allow_skew.tv_sec = 3;
+ base->global_getaddrinfo_allow_skew.tv_usec = 0;
+ base->global_nameserver_probe_initial_timeout.tv_sec = 10;
+ base->global_nameserver_probe_initial_timeout.tv_usec = 0;
+
+ TAILQ_INIT(&base->hostsdb);
+
+#define EVDNS_BASE_ALL_FLAGS (0x8001)
+ if (flags & ~EVDNS_BASE_ALL_FLAGS) {
+ flags = EVDNS_BASE_INITIALIZE_NAMESERVERS;
+ log(EVDNS_LOG_WARN,
+ "Unrecognized flag passed to evdns_base_new(). Assuming "
+ "you meant EVDNS_BASE_INITIALIZE_NAMESERVERS.");
+ }
+#undef EVDNS_BASE_ALL_FLAGS
+
+ if (flags & EVDNS_BASE_INITIALIZE_NAMESERVERS) {
+ int r;
+#ifdef _WIN32
+ r = evdns_base_config_windows_nameservers(base);
+#else
+ r = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf");
+#endif
+ if (r == -1) {
+ evdns_base_free_and_unlock(base, 0);
+ return NULL;
+ }
+ }
+ if (flags & EVDNS_BASE_DISABLE_WHEN_INACTIVE) {
+ base->disable_when_inactive = 1;
+ }
+
+ EVDNS_UNLOCK(base);
+ return base;
+}
+
+int
+evdns_init(void)
+{
+ struct evdns_base *base = evdns_base_new(NULL, 1);
+ if (base) {
+ current_base = base;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+const char *
+evdns_err_to_string(int err)
+{
+ switch (err) {
+ case DNS_ERR_NONE: return "no error";
+ case DNS_ERR_FORMAT: return "misformatted query";
+ case DNS_ERR_SERVERFAILED: return "server failed";
+ case DNS_ERR_NOTEXIST: return "name does not exist";
+ case DNS_ERR_NOTIMPL: return "query not implemented";
+ case DNS_ERR_REFUSED: return "refused";
+
+ case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed";
+ case DNS_ERR_UNKNOWN: return "unknown";
+ case DNS_ERR_TIMEOUT: return "request timed out";
+ case DNS_ERR_SHUTDOWN: return "dns subsystem shut down";
+ case DNS_ERR_CANCEL: return "dns request canceled";
+ case DNS_ERR_NODATA: return "no records in the reply";
+ default: return "[Unknown error code]";
+ }
+}
+
+static void
+evdns_nameserver_free(struct nameserver *server)
+{
+ if (server->socket >= 0)
+ evutil_closesocket(server->socket);
+ (void) event_del(&server->event);
+ event_debug_unassign(&server->event);
+ if (server->state == 0)
+ (void) event_del(&server->timeout_event);
+ if (server->probe_request) {
+ evdns_cancel_request(server->base, server->probe_request);
+ server->probe_request = NULL;
+ }
+ event_debug_unassign(&server->timeout_event);
+ mm_free(server);
+}
+
+static void
+evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
+{
+ struct nameserver *server, *server_next;
+ struct search_domain *dom, *dom_next;
+ int i;
+
+ /* Requires that we hold the lock. */
+
+ /* TODO(nickm) we might need to refcount here. */
+
+ for (i = 0; i < base->n_req_heads; ++i) {
+ while (base->req_heads[i]) {
+ if (fail_requests)
+ reply_schedule_callback(base->req_heads[i], 0, DNS_ERR_SHUTDOWN, NULL);
+ request_finished(base->req_heads[i], &REQ_HEAD(base, base->req_heads[i]->trans_id), 1);
+ }
+ }
+ while (base->req_waiting_head) {
+ if (fail_requests)
+ reply_schedule_callback(base->req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
+ request_finished(base->req_waiting_head, &base->req_waiting_head, 1);
+ }
+ base->global_requests_inflight = base->global_requests_waiting = 0;
+
+ for (server = base->server_head; server; server = server_next) {
+ server_next = server->next;
+ /** already done something before */
+ server->probe_request = NULL;
+ evdns_nameserver_free(server);
+ if (server_next == base->server_head)
+ break;
+ }
+ base->server_head = NULL;
+ base->global_good_nameservers = 0;
+
+ if (base->global_search_state) {
+ for (dom = base->global_search_state->head; dom; dom = dom_next) {
+ dom_next = dom->next;
+ mm_free(dom);
+ }
+ mm_free(base->global_search_state);
+ base->global_search_state = NULL;
+ }
+
+ {
+ struct hosts_entry *victim;
+ while ((victim = TAILQ_FIRST(&base->hostsdb))) {
+ TAILQ_REMOVE(&base->hostsdb, victim, next);
+ mm_free(victim);
+ }
+ }
+
+ mm_free(base->req_heads);
+
+ EVDNS_UNLOCK(base);
+ EVTHREAD_FREE_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+
+ mm_free(base);
+}
+
+void
+evdns_base_free(struct evdns_base *base, int fail_requests)
+{
+ EVDNS_LOCK(base);
+ evdns_base_free_and_unlock(base, fail_requests);
+}
+
+void
+evdns_base_clear_host_addresses(struct evdns_base *base)
+{
+ struct hosts_entry *victim;
+ EVDNS_LOCK(base);
+ while ((victim = TAILQ_FIRST(&base->hostsdb))) {
+ TAILQ_REMOVE(&base->hostsdb, victim, next);
+ mm_free(victim);
+ }
+ EVDNS_UNLOCK(base);
+}
+
+void
+evdns_shutdown(int fail_requests)
+{
+ if (current_base) {
+ struct evdns_base *b = current_base;
+ current_base = NULL;
+ evdns_base_free(b, fail_requests);
+ }
+ evdns_log_fn = NULL;
+}
+
+static int
+evdns_base_parse_hosts_line(struct evdns_base *base, char *line)
+{
+ char *strtok_state;
+ static const char *const delims = " \t";
+ char *const addr = strtok_r(line, delims, &strtok_state);
+ char *hostname, *hash;
+ struct sockaddr_storage ss;
+ int socklen = sizeof(ss);
+ ASSERT_LOCKED(base);
+
+#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
+
+ if (!addr || *addr == '#')
+ return 0;
+
+ memset(&ss, 0, sizeof(ss));
+ if (evutil_parse_sockaddr_port(addr, (struct sockaddr*)&ss, &socklen)<0)
+ return -1;
+ if (socklen > (int)sizeof(struct sockaddr_in6))
+ return -1;
+
+ if (sockaddr_getport((struct sockaddr*)&ss))
+ return -1;
+
+ while ((hostname = NEXT_TOKEN)) {
+ struct hosts_entry *he;
+ size_t namelen;
+ if ((hash = strchr(hostname, '#'))) {
+ if (hash == hostname)
+ return 0;
+ *hash = '\0';
+ }
+
+ namelen = strlen(hostname);
+
+ he = mm_calloc(1, sizeof(struct hosts_entry)+namelen);
+ if (!he)
+ return -1;
+ EVUTIL_ASSERT(socklen <= (int)sizeof(he->addr));
+ memcpy(&he->addr, &ss, socklen);
+ memcpy(he->hostname, hostname, namelen+1);
+ he->addrlen = socklen;
+
+ TAILQ_INSERT_TAIL(&base->hostsdb, he, next);
+
+ if (hash)
+ return 0;
+ }
+
+ return 0;
+#undef NEXT_TOKEN
+}
+
+static int
+evdns_base_load_hosts_impl(struct evdns_base *base, const char *hosts_fname)
+{
+ char *str=NULL, *cp, *eol;
+ size_t len;
+ int err=0;
+
+ ASSERT_LOCKED(base);
+
+ if (hosts_fname == NULL ||
+ (err = evutil_read_file_(hosts_fname, &str, &len, 0)) < 0) {
+ char tmp[64];
+ strlcpy(tmp, "127.0.0.1 localhost", sizeof(tmp));
+ evdns_base_parse_hosts_line(base, tmp);
+ strlcpy(tmp, "::1 localhost", sizeof(tmp));
+ evdns_base_parse_hosts_line(base, tmp);
+ return err ? -1 : 0;
+ }
+
+ /* This will break early if there is a NUL in the hosts file.
+ * Probably not a problem.*/
+ cp = str;
+ for (;;) {
+ eol = strchr(cp, '\n');
+
+ if (eol) {
+ *eol = '\0';
+ evdns_base_parse_hosts_line(base, cp);
+ cp = eol+1;
+ } else {
+ evdns_base_parse_hosts_line(base, cp);
+ break;
+ }
+ }
+
+ mm_free(str);
+ return 0;
+}
+
+int
+evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname)
+{
+ int res;
+ if (!base)
+ base = current_base;
+ EVDNS_LOCK(base);
+ res = evdns_base_load_hosts_impl(base, hosts_fname);
+ EVDNS_UNLOCK(base);
+ return res;
+}
+
+/* A single request for a getaddrinfo, either v4 or v6. */
+struct getaddrinfo_subrequest {
+ struct evdns_request *r;
+ ev_uint32_t type;
+};
+
+/* State data used to implement an in-progress getaddrinfo. */
+struct evdns_getaddrinfo_request {
+ struct evdns_base *evdns_base;
+ /* Copy of the modified 'hints' data that we'll use to build
+ * answers. */
+ struct evutil_addrinfo hints;
+ /* The callback to invoke when we're done */
+ evdns_getaddrinfo_cb user_cb;
+ /* User-supplied data to give to the callback. */
+ void *user_data;
+ /* The port to use when building sockaddrs. */
+ ev_uint16_t port;
+ /* The sub_request for an A record (if any) */
+ struct getaddrinfo_subrequest ipv4_request;
+ /* The sub_request for an AAAA record (if any) */
+ struct getaddrinfo_subrequest ipv6_request;
+
+ /* The cname result that we were told (if any) */
+ char *cname_result;
+
+ /* If we have one request answered and one request still inflight,
+ * then this field holds the answer from the first request... */
+ struct evutil_addrinfo *pending_result;
+ /* And this event is a timeout that will tell us to cancel the second
+ * request if it's taking a long time. */
+ struct event timeout;
+
+ /* And this field holds the error code from the first request... */
+ int pending_error;
+ /* If this is set, the user canceled this request. */
+ unsigned user_canceled : 1;
+ /* If this is set, the user can no longer cancel this request; we're
+ * just waiting for the free. */
+ unsigned request_done : 1;
+};
+
+/* Convert an evdns errors to the equivalent getaddrinfo error. */
+static int
+evdns_err_to_getaddrinfo_err(int e1)
+{
+ /* XXX Do this better! */
+ if (e1 == DNS_ERR_NONE)
+ return 0;
+ else if (e1 == DNS_ERR_NOTEXIST)
+ return EVUTIL_EAI_NONAME;
+ else
+ return EVUTIL_EAI_FAIL;
+}
+
+/* Return the more informative of two getaddrinfo errors. */
+static int
+getaddrinfo_merge_err(int e1, int e2)
+{
+ /* XXXX be cleverer here. */
+ if (e1 == 0)
+ return e2;
+ else
+ return e1;
+}
+
+static void
+free_getaddrinfo_request(struct evdns_getaddrinfo_request *data)
+{
+ /* DO NOT CALL this if either of the requests is pending. Only once
+ * both callbacks have been invoked is it safe to free the request */
+ if (data->pending_result)
+ evutil_freeaddrinfo(data->pending_result);
+ if (data->cname_result)
+ mm_free(data->cname_result);
+ event_del(&data->timeout);
+ mm_free(data);
+ return;
+}
+
+static void
+add_cname_to_reply(struct evdns_getaddrinfo_request *data,
+ struct evutil_addrinfo *ai)
+{
+ if (data->cname_result && ai) {
+ ai->ai_canonname = data->cname_result;
+ data->cname_result = NULL;
+ }
+}
+
+/* Callback: invoked when one request in a mixed-format A/AAAA getaddrinfo
+ * request has finished, but the other one took too long to answer. Pass
+ * along the answer we got, and cancel the other request.
+ */
+static void
+evdns_getaddrinfo_timeout_cb(evutil_socket_t fd, short what, void *ptr)
+{
+ int v4_timedout = 0, v6_timedout = 0;
+ struct evdns_getaddrinfo_request *data = ptr;
+
+ /* Cancel any pending requests, and note which one */
+ if (data->ipv4_request.r) {
+ /* XXXX This does nothing if the request's callback is already
+ * running (pending_cb is set). */
+ evdns_cancel_request(NULL, data->ipv4_request.r);
+ v4_timedout = 1;
+ EVDNS_LOCK(data->evdns_base);
+ ++data->evdns_base->getaddrinfo_ipv4_timeouts;
+ EVDNS_UNLOCK(data->evdns_base);
+ }
+ if (data->ipv6_request.r) {
+ /* XXXX This does nothing if the request's callback is already
+ * running (pending_cb is set). */
+ evdns_cancel_request(NULL, data->ipv6_request.r);
+ v6_timedout = 1;
+ EVDNS_LOCK(data->evdns_base);
+ ++data->evdns_base->getaddrinfo_ipv6_timeouts;
+ EVDNS_UNLOCK(data->evdns_base);
+ }
+
+ /* We only use this timeout callback when we have an answer for
+ * one address. */
+ EVUTIL_ASSERT(!v4_timedout || !v6_timedout);
+
+ /* Report the outcome of the other request that didn't time out. */
+ if (data->pending_result) {
+ add_cname_to_reply(data, data->pending_result);
+ data->user_cb(0, data->pending_result, data->user_data);
+ data->pending_result = NULL;
+ } else {
+ int e = data->pending_error;
+ if (!e)
+ e = EVUTIL_EAI_AGAIN;
+ data->user_cb(e, NULL, data->user_data);
+ }
+
+ data->user_cb = NULL; /* prevent double-call if evdns callbacks are
+ * in-progress. XXXX It would be better if this
+ * weren't necessary. */
+
+ if (!v4_timedout && !v6_timedout) {
+ /* should be impossible? XXXX */
+ free_getaddrinfo_request(data);
+ }
+}
+
+static int
+evdns_getaddrinfo_set_timeout(struct evdns_base *evdns_base,
+ struct evdns_getaddrinfo_request *data)
+{
+ return event_add(&data->timeout, &evdns_base->global_getaddrinfo_allow_skew);
+}
+
+static inline int
+evdns_result_is_answer(int result)
+{
+ return (result != DNS_ERR_NOTIMPL && result != DNS_ERR_REFUSED &&
+ result != DNS_ERR_SERVERFAILED && result != DNS_ERR_CANCEL);
+}
+
+static void
+evdns_getaddrinfo_gotresolve(int result, char type, int count,
+ int ttl, void *addresses, void *arg)
+{
+ int i;
+ struct getaddrinfo_subrequest *req = arg;
+ struct getaddrinfo_subrequest *other_req;
+ struct evdns_getaddrinfo_request *data;
+
+ struct evutil_addrinfo *res;
+
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr *sa;
+ int socklen, addrlen;
+ void *addrp;
+ int err;
+ int user_canceled;
+
+ EVUTIL_ASSERT(req->type == DNS_IPv4_A || req->type == DNS_IPv6_AAAA);
+ if (req->type == DNS_IPv4_A) {
+ data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv4_request);
+ other_req = &data->ipv6_request;
+ } else {
+ data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv6_request);
+ other_req = &data->ipv4_request;
+ }
+
+ /** Called from evdns_base_free() with @fail_requests == 1 */
+ if (result != DNS_ERR_SHUTDOWN) {
+ EVDNS_LOCK(data->evdns_base);
+ if (evdns_result_is_answer(result)) {
+ if (req->type == DNS_IPv4_A)
+ ++data->evdns_base->getaddrinfo_ipv4_answered;
+ else
+ ++data->evdns_base->getaddrinfo_ipv6_answered;
+ }
+ user_canceled = data->user_canceled;
+ if (other_req->r == NULL)
+ data->request_done = 1;
+ EVDNS_UNLOCK(data->evdns_base);
+ } else {
+ data->evdns_base = NULL;
+ user_canceled = data->user_canceled;
+ }
+
+ req->r = NULL;
+
+ if (result == DNS_ERR_CANCEL && ! user_canceled) {
+ /* Internal cancel request from timeout or internal error.
+ * we already answered the user. */
+ if (other_req->r == NULL)
+ free_getaddrinfo_request(data);
+ return;
+ }
+
+ if (data->user_cb == NULL) {
+ /* We already answered. XXXX This shouldn't be needed; see
+ * comments in evdns_getaddrinfo_timeout_cb */
+ free_getaddrinfo_request(data);
+ return;
+ }
+
+ if (result == DNS_ERR_NONE) {
+ if (count == 0)
+ err = EVUTIL_EAI_NODATA;
+ else
+ err = 0;
+ } else {
+ err = evdns_err_to_getaddrinfo_err(result);
+ }
+
+ if (err) {
+ /* Looks like we got an error. */
+ if (other_req->r) {
+ /* The other request is still working; maybe it will
+ * succeed. */
+ /* XXXX handle failure from set_timeout */
+ if (result != DNS_ERR_SHUTDOWN) {
+ evdns_getaddrinfo_set_timeout(data->evdns_base, data);
+ }
+ data->pending_error = err;
+ return;
+ }
+
+ if (user_canceled) {
+ data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data);
+ } else if (data->pending_result) {
+ /* If we have an answer waiting, and we weren't
+ * canceled, ignore this error. */
+ add_cname_to_reply(data, data->pending_result);
+ data->user_cb(0, data->pending_result, data->user_data);
+ data->pending_result = NULL;
+ } else {
+ if (data->pending_error)
+ err = getaddrinfo_merge_err(err,
+ data->pending_error);
+ data->user_cb(err, NULL, data->user_data);
+ }
+ free_getaddrinfo_request(data);
+ return;
+ } else if (user_canceled) {
+ if (other_req->r) {
+ /* The other request is still working; let it hit this
+ * callback with EVUTIL_EAI_CANCEL callback and report
+ * the failure. */
+ return;
+ }
+ data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data);
+ free_getaddrinfo_request(data);
+ return;
+ }
+
+ /* Looks like we got some answers. We should turn them into addrinfos
+ * and then either queue those or return them all. */
+ EVUTIL_ASSERT(type == DNS_IPv4_A || type == DNS_IPv6_AAAA);
+
+ if (type == DNS_IPv4_A) {
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(data->port);
+
+ sa = (struct sockaddr *)&sin;
+ socklen = sizeof(sin);
+ addrlen = 4;
+ addrp = &sin.sin_addr.s_addr;
+ } else {
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(data->port);
+
+ sa = (struct sockaddr *)&sin6;
+ socklen = sizeof(sin6);
+ addrlen = 16;
+ addrp = &sin6.sin6_addr.s6_addr;
+ }
+
+ res = NULL;
+ for (i=0; i < count; ++i) {
+ struct evutil_addrinfo *ai;
+ memcpy(addrp, ((char*)addresses)+i*addrlen, addrlen);
+ ai = evutil_new_addrinfo_(sa, socklen, &data->hints);
+ if (!ai) {
+ if (other_req->r) {
+ evdns_cancel_request(NULL, other_req->r);
+ }
+ data->user_cb(EVUTIL_EAI_MEMORY, NULL, data->user_data);
+ if (res)
+ evutil_freeaddrinfo(res);
+
+ if (other_req->r == NULL)
+ free_getaddrinfo_request(data);
+ return;
+ }
+ res = evutil_addrinfo_append_(res, ai);
+ }
+
+ if (other_req->r) {
+ /* The other request is still in progress; wait for it */
+ /* XXXX handle failure from set_timeout */
+ evdns_getaddrinfo_set_timeout(data->evdns_base, data);
+ data->pending_result = res;
+ return;
+ } else {
+ /* The other request is done or never started; append its
+ * results (if any) and return them. */
+ if (data->pending_result) {
+ if (req->type == DNS_IPv4_A)
+ res = evutil_addrinfo_append_(res,
+ data->pending_result);
+ else
+ res = evutil_addrinfo_append_(
+ data->pending_result, res);
+ data->pending_result = NULL;
+ }
+
+ /* Call the user callback. */
+ add_cname_to_reply(data, res);
+ data->user_cb(0, res, data->user_data);
+
+ /* Free data. */
+ free_getaddrinfo_request(data);
+ }
+}
+
+static struct hosts_entry *
+find_hosts_entry(struct evdns_base *base, const char *hostname,
+ struct hosts_entry *find_after)
+{
+ struct hosts_entry *e;
+
+ if (find_after)
+ e = TAILQ_NEXT(find_after, next);
+ else
+ e = TAILQ_FIRST(&base->hostsdb);
+
+ for (; e; e = TAILQ_NEXT(e, next)) {
+ if (!evutil_ascii_strcasecmp(e->hostname, hostname))
+ return e;
+ }
+ return NULL;
+}
+
+static int
+evdns_getaddrinfo_fromhosts(struct evdns_base *base,
+ const char *nodename, struct evutil_addrinfo *hints, ev_uint16_t port,
+ struct evutil_addrinfo **res)
+{
+ int n_found = 0;
+ struct hosts_entry *e;
+ struct evutil_addrinfo *ai=NULL;
+ int f = hints->ai_family;
+
+ EVDNS_LOCK(base);
+ for (e = find_hosts_entry(base, nodename, NULL); e;
+ e = find_hosts_entry(base, nodename, e)) {
+ struct evutil_addrinfo *ai_new;
+ ++n_found;
+ if ((e->addr.sa.sa_family == AF_INET && f == PF_INET6) ||
+ (e->addr.sa.sa_family == AF_INET6 && f == PF_INET))
+ continue;
+ ai_new = evutil_new_addrinfo_(&e->addr.sa, e->addrlen, hints);
+ if (!ai_new) {
+ n_found = 0;
+ goto out;
+ }
+ sockaddr_setport(ai_new->ai_addr, port);
+ ai = evutil_addrinfo_append_(ai, ai_new);
+ }
+ EVDNS_UNLOCK(base);
+out:
+ if (n_found) {
+ /* Note that we return an empty answer if we found entries for
+ * this hostname but none were of the right address type. */
+ *res = ai;
+ return 0;
+ } else {
+ if (ai)
+ evutil_freeaddrinfo(ai);
+ return -1;
+ }
+}
+
+struct evdns_getaddrinfo_request *
+evdns_getaddrinfo(struct evdns_base *dns_base,
+ const char *nodename, const char *servname,
+ const struct evutil_addrinfo *hints_in,
+ evdns_getaddrinfo_cb cb, void *arg)
+{
+ struct evdns_getaddrinfo_request *data;
+ struct evutil_addrinfo hints;
+ struct evutil_addrinfo *res = NULL;
+ int err;
+ int port = 0;
+ int want_cname = 0;
+
+ if (!dns_base) {
+ dns_base = current_base;
+ if (!dns_base) {
+ log(EVDNS_LOG_WARN,
+ "Call to getaddrinfo_async with no "
+ "evdns_base configured.");
+ cb(EVUTIL_EAI_FAIL, NULL, arg); /* ??? better error? */
+ return NULL;
+ }
+ }
+
+ /* If we _must_ answer this immediately, do so. */
+ if ((hints_in && (hints_in->ai_flags & EVUTIL_AI_NUMERICHOST))) {
+ res = NULL;
+ err = evutil_getaddrinfo(nodename, servname, hints_in, &res);
+ cb(err, res, arg);
+ return NULL;
+ }
+
+ if (hints_in) {
+ memcpy(&hints, hints_in, sizeof(hints));
+ } else {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ }
+
+ evutil_adjust_hints_for_addrconfig_(&hints);
+
+ /* Now try to see if we _can_ answer immediately. */
+ /* (It would be nice to do this by calling getaddrinfo directly, with
+ * AI_NUMERICHOST, on plaforms that have it, but we can't: there isn't
+ * a reliable way to distinguish the "that wasn't a numeric host!" case
+ * from any other EAI_NONAME cases.) */
+ err = evutil_getaddrinfo_common_(nodename, servname, &hints, &res, &port);
+ if (err != EVUTIL_EAI_NEED_RESOLVE) {
+ cb(err, res, arg);
+ return NULL;
+ }
+
+ /* If there is an entry in the hosts file, we should give it now. */
+ if (!evdns_getaddrinfo_fromhosts(dns_base, nodename, &hints, port, &res)) {
+ cb(0, res, arg);
+ return NULL;
+ }
+
+ /* Okay, things are serious now. We're going to need to actually
+ * launch a request.
+ */
+ data = mm_calloc(1,sizeof(struct evdns_getaddrinfo_request));
+ if (!data) {
+ cb(EVUTIL_EAI_MEMORY, NULL, arg);
+ return NULL;
+ }
+
+ memcpy(&data->hints, &hints, sizeof(data->hints));
+ data->port = (ev_uint16_t)port;
+ data->ipv4_request.type = DNS_IPv4_A;
+ data->ipv6_request.type = DNS_IPv6_AAAA;
+ data->user_cb = cb;
+ data->user_data = arg;
+ data->evdns_base = dns_base;
+
+ want_cname = (hints.ai_flags & EVUTIL_AI_CANONNAME);
+
+ /* If we are asked for a PF_UNSPEC address, we launch two requests in
+ * parallel: one for an A address and one for an AAAA address. We
+ * can't send just one request, since many servers only answer one
+ * question per DNS request.
+ *
+ * Once we have the answer to one request, we allow for a short
+ * timeout before we report it, to see if the other one arrives. If
+ * they both show up in time, then we report both the answers.
+ *
+ * If too many addresses of one type time out or fail, we should stop
+ * launching those requests. (XXX we don't do that yet.)
+ */
+
+ if (hints.ai_family != PF_INET6) {
+ log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv4 as %p",
+ nodename, &data->ipv4_request);
+
+ data->ipv4_request.r = evdns_base_resolve_ipv4(dns_base,
+ nodename, 0, evdns_getaddrinfo_gotresolve,
+ &data->ipv4_request);
+ if (want_cname && data->ipv4_request.r)
+ data->ipv4_request.r->current_req->put_cname_in_ptr =
+ &data->cname_result;
+ }
+ if (hints.ai_family != PF_INET) {
+ log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv6 as %p",
+ nodename, &data->ipv6_request);
+
+ data->ipv6_request.r = evdns_base_resolve_ipv6(dns_base,
+ nodename, 0, evdns_getaddrinfo_gotresolve,
+ &data->ipv6_request);
+ if (want_cname && data->ipv6_request.r)
+ data->ipv6_request.r->current_req->put_cname_in_ptr =
+ &data->cname_result;
+ }
+
+ evtimer_assign(&data->timeout, dns_base->event_base,
+ evdns_getaddrinfo_timeout_cb, data);
+
+ if (data->ipv4_request.r || data->ipv6_request.r) {
+ return data;
+ } else {
+ mm_free(data);
+ cb(EVUTIL_EAI_FAIL, NULL, arg);
+ return NULL;
+ }
+}
+
+void
+evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *data)
+{
+ EVDNS_LOCK(data->evdns_base);
+ if (data->request_done) {
+ EVDNS_UNLOCK(data->evdns_base);
+ return;
+ }
+ event_del(&data->timeout);
+ data->user_canceled = 1;
+ if (data->ipv4_request.r)
+ evdns_cancel_request(data->evdns_base, data->ipv4_request.r);
+ if (data->ipv6_request.r)
+ evdns_cancel_request(data->evdns_base, data->ipv6_request.r);
+ EVDNS_UNLOCK(data->evdns_base);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/event-config.h.cmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/event-config.h.cmake
new file mode 100644
index 000000000..c1355be91
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/event-config.h.cmake
@@ -0,0 +1,532 @@
+/* event-config.h
+ *
+ * This file was generated by cmake when the makefiles were generated.
+ *
+ * DO NOT EDIT THIS FILE.
+ *
+ * Do not rely on macros in this file existing in later versions.
+ */
+#ifndef EVENT2_EVENT_CONFIG_H_INCLUDED_
+#define EVENT2_EVENT_CONFIG_H_INCLUDED_
+
+/* Numeric representation of the version */
+#define EVENT__NUMERIC_VERSION @EVENT_NUMERIC_VERSION@
+#define EVENT__PACKAGE_VERSION "@EVENT_PACKAGE_VERSION@"
+
+#define EVENT__VERSION_MAJOR @EVENT_VERSION_MAJOR@
+#define EVENT__VERSION_MINOR @EVENT_VERSION_MINOR@
+#define EVENT__VERSION_PATCH @EVENT_VERSION_PATCH@
+
+/* Version number of package */
+#define EVENT__VERSION "@EVENT_VERSION@"
+
+/* Name of package */
+#define EVENT__PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define EVENT__PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define EVENT__PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define EVENT__PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define EVENT__PACKAGE_TARNAME ""
+
+/* Define if libevent should build without support for a debug mode */
+#cmakedefine EVENT__DISABLE_DEBUG_MODE
+
+/* Define if libevent should not allow replacing the mm functions */
+#cmakedefine EVENT__DISABLE_MM_REPLACEMENT
+
+/* Define if libevent should not be compiled with thread support */
+#cmakedefine EVENT__DISABLE_THREAD_SUPPORT
+
+/* Define to 1 if you have the `accept4' function. */
+#cmakedefine EVENT__HAVE_ACCEPT4
+
+/* Define to 1 if you have the `arc4random' function. */
+#cmakedefine EVENT__HAVE_ARC4RANDOM
+
+/* Define to 1 if you have the `arc4random_buf' function. */
+#cmakedefine EVENT__HAVE_ARC4RANDOM_BUF
+
+/* Define if clock_gettime is available in libc */
+#cmakedefine EVENT__DNS_USE_CPU_CLOCK_FOR_ID
+
+/* Define is no secure id variant is available */
+#cmakedefine EVENT__DNS_USE_GETTIMEOFDAY_FOR_ID
+#cmakedefine EVENT__DNS_USE_FTIME_FOR_ID
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#cmakedefine EVENT__HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#cmakedefine EVENT__HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you have the declaration of `CTL_KERN'. */
+#cmakedefine EVENT__HAVE_DECL_CTL_KERN
+
+/* Define to 1 if you have the declaration of `KERN_ARND'. */
+#cmakedefine EVENT__HAVE_DECL_KERN_ARND
+
+/* Define to 1 if you have the declaration of `KERN_RANDOM'. */
+#cmakedefine EVENT__HAVE_DECL_KERN_RANDOM
+
+/* Define if /dev/poll is available */
+#cmakedefine EVENT__HAVE_DEVPOLL
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#cmakedefine EVENT__HAVE_NETDB_H
+
+/* Define to 1 if fd_mask type is defined */
+#cmakedefine EVENT__HAVE_FD_MASK
+
+/* Define to 1 if the <sys/queue.h> header file defines TAILQ_FOREACH. */
+#cmakedefine EVENT__HAVE_TAILQFOREACH
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#cmakedefine EVENT__HAVE_DLFCN_H
+
+/* Define if your system supports the epoll system calls */
+#cmakedefine EVENT__HAVE_EPOLL
+
+/* Define to 1 if you have the `epoll_create1' function. */
+#cmakedefine EVENT__HAVE_EPOLL_CREATE1
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+#cmakedefine EVENT__HAVE_EPOLL_CTL
+
+/* Define to 1 if you have the `eventfd' function. */
+#cmakedefine EVENT__HAVE_EVENTFD
+
+/* Define if your system supports event ports */
+#cmakedefine EVENT__HAVE_EVENT_PORTS
+
+/* Define to 1 if you have the `fcntl' function. */
+#cmakedefine EVENT__HAVE_FCNTL
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#cmakedefine EVENT__HAVE_FCNTL_H
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#cmakedefine EVENT__HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getegid' function. */
+#cmakedefine EVENT__HAVE_GETEGID
+
+/* Define to 1 if you have the `geteuid' function. */
+#cmakedefine EVENT__HAVE_GETEUID
+
+/* TODO: Check for different gethostname argument counts. CheckPrototypeDefinition.cmake can be used. */
+/* Define this if you have any gethostbyname_r() */
+#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R
+
+/* Define this if gethostbyname_r takes 3 arguments */
+#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R_3_ARG
+
+/* Define this if gethostbyname_r takes 5 arguments */
+#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R_5_ARG
+
+/* Define this if gethostbyname_r takes 6 arguments */
+#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R_6_ARG
+
+/* Define to 1 if you have the `getifaddrs' function. */
+#cmakedefine EVENT__HAVE_GETIFADDRS
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#cmakedefine EVENT__HAVE_GETNAMEINFO
+
+/* Define to 1 if you have the `getprotobynumber' function. */
+#cmakedefine EVENT__HAVE_GETPROTOBYNUMBER
+
+/* Define to 1 if you have the `getservbyname' function. */
+#cmakedefine EVENT__HAVE_GETSERVBYNAME
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#cmakedefine EVENT__HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#cmakedefine EVENT__HAVE_IFADDRS_H
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#cmakedefine EVENT__HAVE_INET_NTOP
+
+/* Define to 1 if you have the `inet_pton' function. */
+#cmakedefine EVENT__HAVE_INET_PTON
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#cmakedefine EVENT__HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `issetugid' function. */
+#cmakedefine EVENT__HAVE_ISSETUGID
+
+/* Define to 1 if you have the `kqueue' function. */
+#cmakedefine EVENT__HAVE_KQUEUE
+
+/* Define if the system has zlib */
+#cmakedefine EVENT__HAVE_LIBZ
+
+/* Define to 1 if you have the `mach_absolute_time' function. */
+#cmakedefine EVENT__HAVE_MACH_ABSOLUTE_TIME
+
+/* Define to 1 if you have the <mach/mach_time.h> header file. */
+#cmakedefine EVENT__HAVE_MACH_MACH_TIME_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#cmakedefine EVENT__HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mmap' function. */
+#cmakedefine EVENT__HAVE_MMAP
+
+/* Define to 1 if you have the `nanosleep' function. */
+#cmakedefine EVENT__HAVE_NANOSLEEP
+
+/* Define to 1 if you have the `usleep' function. */
+#cmakedefine EVENT__HAVE_USLEEP
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+#cmakedefine EVENT__HAVE_NETINET_IN6_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#cmakedefine EVENT__HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#cmakedefine EVENT__HAVE_NETINET_TCP_H
+
+/* Define if the system has openssl */
+#cmakedefine EVENT__HAVE_OPENSSL
+
+/* Define to 1 if you have the `pipe' function. */
+#cmakedefine EVENT__HAVE_PIPE
+
+/* Define to 1 if you have the `pipe2' function. */
+#cmakedefine EVENT__HAVE_PIPE2
+
+/* Define to 1 if you have the `poll' function. */
+#cmakedefine EVENT__HAVE_POLL
+
+/* Define to 1 if you have the <poll.h> header file. */
+#cmakedefine EVENT__HAVE_POLL_H
+
+/* Define to 1 if you have the `port_create' function. */
+#cmakedefine EVENT__HAVE_PORT_CREATE
+
+/* Define to 1 if you have the <port.h> header file. */
+#cmakedefine EVENT__HAVE_PORT_H
+
+/* Define if we have pthreads on this system */
+#cmakedefine EVENT__HAVE_PTHREADS
+
+/* Define to 1 if you have the `putenv' function. */
+#cmakedefine EVENT__HAVE_PUTENV
+
+/* Define to 1 if the system has the type `sa_family_t'. */
+#cmakedefine EVENT__HAVE_SA_FAMILY_T
+
+/* Define to 1 if you have the `select' function. */
+#cmakedefine EVENT__HAVE_SELECT
+
+/* Define to 1 if you have the `setenv' function. */
+#cmakedefine EVENT__HAVE_SETENV
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#cmakedefine EVENT__HAVE_SETFD
+
+/* Define to 1 if you have the `setrlimit' function. */
+#cmakedefine EVENT__HAVE_SETRLIMIT
+
+/* Define to 1 if you have the `sendfile' function. */
+#cmakedefine EVENT__HAVE_SENDFILE
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#cmakedefine EVENT__HAVE_SETFD
+
+/* Define to 1 if you have the `sigaction' function. */
+#cmakedefine EVENT__HAVE_SIGACTION
+
+/* Define to 1 if you have the `signal' function. */
+#cmakedefine EVENT__HAVE_SIGNAL
+
+/* Define to 1 if you have the `splice' function. */
+#cmakedefine EVENT__HAVE_SPLICE
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#cmakedefine EVENT__HAVE_STDARG_H
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#cmakedefine EVENT__HAVE_STDDEF_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine EVENT__HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#cmakedefine EVENT__HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#cmakedefine EVENT__HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#cmakedefine EVENT__HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcpy' function. */
+#cmakedefine EVENT__HAVE_STRLCPY
+
+/* Define to 1 if you have the `strsep' function. */
+#cmakedefine EVENT__HAVE_STRSEP
+
+/* Define to 1 if you have the `strtok_r' function. */
+#cmakedefine EVENT__HAVE_STRTOK_R
+
+/* Define to 1 if you have the `strtoll' function. */
+#cmakedefine EVENT__HAVE_STRTOLL
+
+/* Define to 1 if the system has the type `struct addrinfo'. */
+#cmakedefine EVENT__HAVE_STRUCT_ADDRINFO
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#cmakedefine EVENT__HAVE_STRUCT_IN6_ADDR
+
+/* Define to 1 if `s6_addr16' is member of `struct in6_addr'. */
+#cmakedefine EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR16
+
+/* Define to 1 if `s6_addr32' is member of `struct in6_addr'. */
+#cmakedefine EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR32
+
+/* Define to 1 if the system has the type `struct sockaddr_in6'. */
+#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_IN6
+
+/* Define to 1 if `sin6_len' is member of `struct sockaddr_in6'. */
+#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
+
+/* Define to 1 if `sin_len' is member of `struct sockaddr_in'. */
+#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+
+/* Define to 1 if the system has the type `struct sockaddr_storage'. */
+#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_STORAGE
+
+/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */
+#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
+
+/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */
+#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY
+
+/* Define to 1 if you have the `sysctl' function. */
+#cmakedefine EVENT__HAVE_SYSCTL
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_DEVPOLL_H
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_EPOLL_H
+
+/* Define to 1 if you have the <sys/eventfd.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_EVENTFD_H
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_EVENT_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_QUEUE_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/sendfile.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_SENDFILE_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/sysctl.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_SYSCTL_H
+
+/* Define to 1 if you have the <sys/timerfd.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_TIMERFD_H */
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_UIO_H
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the <errno.h> header file. */
+#cmakedefine EVENT__HAVE_ERRNO_H
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#cmakedefine EVENT__HAVE_TAILQFOREACH
+
+/* Define if timeradd is defined in <sys/time.h> */
+#cmakedefine EVENT__HAVE_TIMERADD
+
+/* Define if timerclear is defined in <sys/time.h> */
+#cmakedefine EVENT__HAVE_TIMERCLEAR
+
+/* Define if timercmp is defined in <sys/time.h> */
+#cmakedefine EVENT__HAVE_TIMERCMP
+
+
+/* Define to 1 if you have the `timerfd_create' function. */
+#cmakedefine EVENT__HAVE_TIMERFD_CREATE
+
+/* Define if timerisset is defined in <sys/time.h> */
+#cmakedefine EVENT__HAVE_TIMERISSET
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#cmakedefine EVENT__HAVE_UINT8_T
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#cmakedefine EVENT__HAVE_UINT16_T
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#cmakedefine EVENT__HAVE_UINT32_T
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#cmakedefine EVENT__HAVE_UINT64_T
+
+/* Define to 1 if the system has the type `uintptr_t'. */
+#cmakedefine EVENT__HAVE_UINTPTR_T
+
+/* Define to 1 if you have the `umask' function. */
+#cmakedefine EVENT__HAVE_UMASK
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine EVENT__HAVE_UNISTD_H
+
+/* Define to 1 if you have the `unsetenv' function. */
+#cmakedefine EVENT__HAVE_UNSETENV
+
+/* Define to 1 if you have the `vasprintf' function. */
+#cmakedefine EVENT__HAVE_VASPRINTF
+
+/* Define if kqueue works correctly with pipes */
+#cmakedefine EVENT__HAVE_WORKING_KQUEUE
+
+#ifdef __USE_UNUSED_DEFINITIONS__
+/* Define to necessary symbol if this constant uses a non-standard name on your system. */
+/* XXX: Hello, this isn't even used, nor is it defined anywhere... - Ellzey */
+#define EVENT__PTHREAD_CREATE_JOINABLE ${EVENT__PTHREAD_CREATE_JOINABLE}
+#endif
+
+/* The size of `pthread_t', as computed by sizeof. */
+#define EVENT__SIZEOF_PTHREAD_T @EVENT__SIZEOF_PTHREAD_T@
+
+/* The size of a `int', as computed by sizeof. */
+#define EVENT__SIZEOF_INT @EVENT__SIZEOF_INT@
+
+/* The size of a `long', as computed by sizeof. */
+#define EVENT__SIZEOF_LONG @EVENT__SIZEOF_LONG@
+
+/* The size of a `long long', as computed by sizeof. */
+#define EVENT__SIZEOF_LONG_LONG @EVENT__SIZEOF_LONG_LONG@
+
+/* The size of `off_t', as computed by sizeof. */
+#define EVENT__SIZEOF_OFF_T @EVENT__SIZEOF_OFF_T@
+
+#define EVENT__SIZEOF_SSIZE_T @EVENT__SIZEOF_SSIZE_T@
+
+
+/* The size of a `short', as computed by sizeof. */
+#define EVENT__SIZEOF_SHORT @EVENT__SIZEOF_SHORT@
+
+/* The size of `size_t', as computed by sizeof. */
+#define EVENT__SIZEOF_SIZE_T @EVENT__SIZEOF_SIZE_T@
+
+/* Define to 1 if you have the ANSI C header files. */
+#cmakedefine EVENT__STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#cmakedefine EVENT__TIME_WITH_SYS_TIME
+
+/* The size of `socklen_t', as computed by sizeof. */
+#define EVENT__SIZEOF_SOCKLEN_T @EVENT__SIZEOF_SOCKLEN_T@
+
+/* The size of 'void *', as computer by sizeof */
+#define EVENT__SIZEOF_VOID_P @EVENT__SIZEOF_VOID_P@
+
+/* set an alias for whatever __func__ __FUNCTION__ is, what sillyness */
+#if defined (__func__)
+#define EVENT____func__ __func__
+#elif defined(__FUNCTION__)
+#define EVENT____func__ __FUNCTION__
+#else
+#define EVENT____func__ __FILE__
+#endif
+
+
+#ifdef __THESE_ARE_NOT_CONFIG_H_THINGS_THEY_ARE_DASH_D_THINGS__
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* Ellzey is not satisfied */
+#define EVENT___FILE_OFFSET_BITS @EVENT___FILE_OFFSET_BITS@
+
+/* Define for large files, on AIX-style hosts. */
+#define @_LARGE_FILES@
+#endif
+
+#ifdef _WhAT_DOES_THIS_EVEN_DO_
+/* Define to empty if `const' does not conform to ANSI C. */
+/* lolwut? - ellzey */
+#undef EVENT__const
+#endif
+
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* why not c++?
+ *
+ * and are we really expected to use EVENT__inline everywhere,
+ * shouldn't we just do:
+ * ifdef EVENT__inline
+ * define inline EVENT__inline
+ *
+ * - Ellzey
+ */
+
+#define EVENT__inline @EVENT__inline@
+#endif
+
+/* Define to `int' if <sys/tyes.h> does not define. */
+#define EVENT__pid_t @EVENT__pid_t@
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#define EVENT__size_t @EVENT__size_t@
+
+/* Define to unsigned int if you dont have it */
+#define EVENT__socklen_t @EVENT__socklen_t@
+
+/* Define to `int' if <sys/types.h> does not define. */
+#define EVENT__ssize_t @EVENT__ssize_t@
+
+#cmakedefine EVENT__NEED_DLLIMPORT
+
+/* Define to 1 if you have ERR_remove_thread_stat(). */
+#cmakedefine EVENT__HAVE_ERR_REMOVE_THREAD_STATE
+
+/* Define if waitpid() supports WNOWAIT */
+#cmakedefine EVENT__HAVE_WAITPID_WITH_WNOWAIT
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/event-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/event-internal.h
new file mode 100644
index 000000000..66dcfc329
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/event-internal.h
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT_INTERNAL_H_INCLUDED_
+#define EVENT_INTERNAL_H_INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <time.h>
+#include <sys/queue.h>
+#include "event2/event_struct.h"
+#include "minheap-internal.h"
+#include "evsignal-internal.h"
+#include "mm-internal.h"
+#include "defer-internal.h"
+
+/* map union members back */
+
+/* mutually exclusive */
+#define ev_signal_next ev_.ev_signal.ev_signal_next
+#define ev_io_next ev_.ev_io.ev_io_next
+#define ev_io_timeout ev_.ev_io.ev_timeout
+
+/* used only by signals */
+#define ev_ncalls ev_.ev_signal.ev_ncalls
+#define ev_pncalls ev_.ev_signal.ev_pncalls
+
+#define ev_pri ev_evcallback.evcb_pri
+#define ev_flags ev_evcallback.evcb_flags
+#define ev_closure ev_evcallback.evcb_closure
+#define ev_callback ev_evcallback.evcb_cb_union.evcb_callback
+#define ev_arg ev_evcallback.evcb_arg
+
+/** @name Event closure codes
+
+ Possible values for evcb_closure in struct event_callback
+
+ @{
+ */
+/** A regular event. Uses the evcb_callback callback */
+#define EV_CLOSURE_EVENT 0
+/** A signal event. Uses the evcb_callback callback */
+#define EV_CLOSURE_EVENT_SIGNAL 1
+/** A persistent non-signal event. Uses the evcb_callback callback */
+#define EV_CLOSURE_EVENT_PERSIST 2
+/** A simple callback. Uses the evcb_selfcb callback. */
+#define EV_CLOSURE_CB_SELF 3
+/** A finalizing callback. Uses the evcb_cbfinalize callback. */
+#define EV_CLOSURE_CB_FINALIZE 4
+/** A finalizing event. Uses the evcb_evfinalize callback. */
+#define EV_CLOSURE_EVENT_FINALIZE 5
+/** A finalizing event that should get freed after. Uses the evcb_evfinalize
+ * callback. */
+#define EV_CLOSURE_EVENT_FINALIZE_FREE 6
+/** @} */
+
+/** Structure to define the backend of a given event_base. */
+struct eventop {
+ /** The name of this backend. */
+ const char *name;
+ /** Function to set up an event_base to use this backend. It should
+ * create a new structure holding whatever information is needed to
+ * run the backend, and return it. The returned pointer will get
+ * stored by event_init into the event_base.evbase field. On failure,
+ * this function should return NULL. */
+ void *(*init)(struct event_base *);
+ /** Enable reading/writing on a given fd or signal. 'events' will be
+ * the events that we're trying to enable: one or more of EV_READ,
+ * EV_WRITE, EV_SIGNAL, and EV_ET. 'old' will be those events that
+ * were enabled on this fd previously. 'fdinfo' will be a structure
+ * associated with the fd by the evmap; its size is defined by the
+ * fdinfo field below. It will be set to 0 the first time the fd is
+ * added. The function should return 0 on success and -1 on error.
+ */
+ int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
+ /** As "add", except 'events' contains the events we mean to disable. */
+ int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
+ /** Function to implement the core of an event loop. It must see which
+ added events are ready, and cause event_active to be called for each
+ active event (usually via event_io_active or such). It should
+ return 0 on success and -1 on error.
+ */
+ int (*dispatch)(struct event_base *, struct timeval *);
+ /** Function to clean up and free our data from the event_base. */
+ void (*dealloc)(struct event_base *);
+ /** Flag: set if we need to reinitialize the event base after we fork.
+ */
+ int need_reinit;
+ /** Bit-array of supported event_method_features that this backend can
+ * provide. */
+ enum event_method_feature features;
+ /** Length of the extra information we should record for each fd that
+ has one or more active events. This information is recorded
+ as part of the evmap entry for each fd, and passed as an argument
+ to the add and del functions above.
+ */
+ size_t fdinfo_len;
+};
+
+#ifdef _WIN32
+/* If we're on win32, then file descriptors are not nice low densely packed
+ integers. Instead, they are pointer-like windows handles, and we want to
+ use a hashtable instead of an array to map fds to events.
+*/
+#define EVMAP_USE_HT
+#endif
+
+/* #define HT_CACHE_HASH_VALS */
+
+#ifdef EVMAP_USE_HT
+#define HT_NO_CACHE_HASH_VALUES
+#include "ht-internal.h"
+struct event_map_entry;
+HT_HEAD(event_io_map, event_map_entry);
+#else
+#define event_io_map event_signal_map
+#endif
+
+/* Used to map signal numbers to a list of events. If EVMAP_USE_HT is not
+ defined, this structure is also used as event_io_map, which maps fds to a
+ list of events.
+*/
+struct event_signal_map {
+ /* An array of evmap_io * or of evmap_signal *; empty entries are
+ * set to NULL. */
+ void **entries;
+ /* The number of entries available in entries */
+ int nentries;
+};
+
+/* A list of events waiting on a given 'common' timeout value. Ordinarily,
+ * events waiting for a timeout wait on a minheap. Sometimes, however, a
+ * queue can be faster.
+ **/
+struct common_timeout_list {
+ /* List of events currently waiting in the queue. */
+ struct event_list events;
+ /* 'magic' timeval used to indicate the duration of events in this
+ * queue. */
+ struct timeval duration;
+ /* Event that triggers whenever one of the events in the queue is
+ * ready to activate */
+ struct event timeout_event;
+ /* The event_base that this timeout list is part of */
+ struct event_base *base;
+};
+
+/** Mask used to get the real tv_usec value from a common timeout. */
+#define COMMON_TIMEOUT_MICROSECONDS_MASK 0x000fffff
+
+struct event_change;
+
+/* List of 'changes' since the last call to eventop.dispatch. Only maintained
+ * if the backend is using changesets. */
+struct event_changelist {
+ struct event_change *changes;
+ int n_changes;
+ int changes_size;
+};
+
+#ifndef EVENT__DISABLE_DEBUG_MODE
+/* Global internal flag: set to one if debug mode is on. */
+extern int event_debug_mode_on_;
+#define EVENT_DEBUG_MODE_IS_ON() (event_debug_mode_on_)
+#else
+#define EVENT_DEBUG_MODE_IS_ON() (0)
+#endif
+
+TAILQ_HEAD(evcallback_list, event_callback);
+
+/* Sets up an event for processing once */
+struct event_once {
+ LIST_ENTRY(event_once) next_once;
+ struct event ev;
+
+ void (*cb)(evutil_socket_t, short, void *);
+ void *arg;
+};
+
+struct event_base {
+ /** Function pointers and other data to describe this event_base's
+ * backend. */
+ const struct eventop *evsel;
+ /** Pointer to backend-specific data. */
+ void *evbase;
+
+ /** List of changes to tell backend about at next dispatch. Only used
+ * by the O(1) backends. */
+ struct event_changelist changelist;
+
+ /** Function pointers used to describe the backend that this event_base
+ * uses for signals */
+ const struct eventop *evsigsel;
+ /** Data to implement the common signal handelr code. */
+ struct evsig_info sig;
+
+ /** Number of virtual events */
+ int virtual_event_count;
+ /** Maximum number of virtual events active */
+ int virtual_event_count_max;
+ /** Number of total events added to this event_base */
+ int event_count;
+ /** Maximum number of total events added to this event_base */
+ int event_count_max;
+ /** Number of total events active in this event_base */
+ int event_count_active;
+ /** Maximum number of total events active in this event_base */
+ int event_count_active_max;
+
+ /** Set if we should terminate the loop once we're done processing
+ * events. */
+ int event_gotterm;
+ /** Set if we should terminate the loop immediately */
+ int event_break;
+ /** Set if we should start a new instance of the loop immediately. */
+ int event_continue;
+
+ /** The currently running priority of events */
+ int event_running_priority;
+
+ /** Set if we're running the event_base_loop function, to prevent
+ * reentrant invocation. */
+ int running_loop;
+
+ /** Set to the number of deferred_cbs we've made 'active' in the
+ * loop. This is a hack to prevent starvation; it would be smarter
+ * to just use event_config_set_max_dispatch_interval's max_callbacks
+ * feature */
+ int n_deferreds_queued;
+
+ /* Active event management. */
+ /** An array of nactivequeues queues for active event_callbacks (ones
+ * that have triggered, and whose callbacks need to be called). Low
+ * priority numbers are more important, and stall higher ones.
+ */
+ struct evcallback_list *activequeues;
+ /** The length of the activequeues array */
+ int nactivequeues;
+ /** A list of event_callbacks that should become active the next time
+ * we process events, but not this time. */
+ struct evcallback_list active_later_queue;
+
+ /* common timeout logic */
+
+ /** An array of common_timeout_list* for all of the common timeout
+ * values we know. */
+ struct common_timeout_list **common_timeout_queues;
+ /** The number of entries used in common_timeout_queues */
+ int n_common_timeouts;
+ /** The total size of common_timeout_queues. */
+ int n_common_timeouts_allocated;
+
+ /** Mapping from file descriptors to enabled (added) events */
+ struct event_io_map io;
+
+ /** Mapping from signal numbers to enabled (added) events. */
+ struct event_signal_map sigmap;
+
+ /** Priority queue of events with timeouts. */
+ struct min_heap timeheap;
+
+ /** Stored timeval: used to avoid calling gettimeofday/clock_gettime
+ * too often. */
+ struct timeval tv_cache;
+
+ struct evutil_monotonic_timer monotonic_timer;
+
+ /** Difference between internal time (maybe from clock_gettime) and
+ * gettimeofday. */
+ struct timeval tv_clock_diff;
+ /** Second in which we last updated tv_clock_diff, in monotonic time. */
+ time_t last_updated_clock_diff;
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ /* threading support */
+ /** The thread currently running the event_loop for this base */
+ unsigned long th_owner_id;
+ /** A lock to prevent conflicting accesses to this event_base */
+ void *th_base_lock;
+ /** A condition that gets signalled when we're done processing an
+ * event with waiters on it. */
+ void *current_event_cond;
+ /** Number of threads blocking on current_event_cond. */
+ int current_event_waiters;
+#endif
+ /** The event whose callback is executing right now */
+ struct event_callback *current_event;
+
+#ifdef _WIN32
+ /** IOCP support structure, if IOCP is enabled. */
+ struct event_iocp_port *iocp;
+#endif
+
+ /** Flags that this base was configured with */
+ enum event_base_config_flag flags;
+
+ struct timeval max_dispatch_time;
+ int max_dispatch_callbacks;
+ int limit_callbacks_after_prio;
+
+ /* Notify main thread to wake up break, etc. */
+ /** True if the base already has a pending notify, and we don't need
+ * to add any more. */
+ int is_notify_pending;
+ /** A socketpair used by some th_notify functions to wake up the main
+ * thread. */
+ evutil_socket_t th_notify_fd[2];
+ /** An event used by some th_notify functions to wake up the main
+ * thread. */
+ struct event th_notify;
+ /** A function used to wake up the main thread from another thread. */
+ int (*th_notify_fn)(struct event_base *base);
+
+ /** Saved seed for weak random number generator. Some backends use
+ * this to produce fairness among sockets. Protected by th_base_lock. */
+ struct evutil_weakrand_state weakrand_seed;
+
+ /** List of event_onces that have not yet fired. */
+ LIST_HEAD(once_event_list, event_once) once_events;
+
+};
+
+struct event_config_entry {
+ TAILQ_ENTRY(event_config_entry) next;
+
+ const char *avoid_method;
+};
+
+/** Internal structure: describes the configuration we want for an event_base
+ * that we're about to allocate. */
+struct event_config {
+ TAILQ_HEAD(event_configq, event_config_entry) entries;
+
+ int n_cpus_hint;
+ struct timeval max_dispatch_interval;
+ int max_dispatch_callbacks;
+ int limit_callbacks_after_prio;
+ enum event_method_feature require_features;
+ enum event_base_config_flag flags;
+};
+
+/* Internal use only: Functions that might be missing from <sys/queue.h> */
+#ifndef TAILQ_FIRST
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#endif
+#ifndef TAILQ_END
+#define TAILQ_END(head) NULL
+#endif
+#ifndef TAILQ_NEXT
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#endif
+
+#ifndef TAILQ_FOREACH
+#define TAILQ_FOREACH(var, head, field) \
+ for ((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_NEXT(var, field))
+#endif
+
+#ifndef TAILQ_INSERT_BEFORE
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+#endif
+
+#define N_ACTIVE_CALLBACKS(base) \
+ ((base)->event_count_active)
+
+int evsig_set_handler_(struct event_base *base, int evsignal,
+ void (*fn)(int));
+int evsig_restore_handler_(struct event_base *base, int evsignal);
+
+int event_add_nolock_(struct event *ev,
+ const struct timeval *tv, int tv_is_absolute);
+/** Argument for event_del_nolock_. Tells event_del not to block on the event
+ * if it's running in another thread. */
+#define EVENT_DEL_NOBLOCK 0
+/** Argument for event_del_nolock_. Tells event_del to block on the event
+ * if it's running in another thread, regardless of its value for EV_FINALIZE
+ */
+#define EVENT_DEL_BLOCK 1
+/** Argument for event_del_nolock_. Tells event_del to block on the event
+ * if it is running in another thread and it doesn't have EV_FINALIZE set.
+ */
+#define EVENT_DEL_AUTOBLOCK 2
+/** Argument for event_del_nolock_. Tells event_del to procede even if the
+ * event is set up for finalization rather for regular use.*/
+#define EVENT_DEL_EVEN_IF_FINALIZING 3
+int event_del_nolock_(struct event *ev, int blocking);
+int event_remove_timer_nolock_(struct event *ev);
+
+void event_active_nolock_(struct event *ev, int res, short count);
+int event_callback_activate_(struct event_base *, struct event_callback *);
+int event_callback_activate_nolock_(struct event_base *, struct event_callback *);
+int event_callback_cancel_(struct event_base *base,
+ struct event_callback *evcb);
+
+void event_callback_finalize_nolock_(struct event_base *base, unsigned flags, struct event_callback *evcb, void (*cb)(struct event_callback *, void *));
+void event_callback_finalize_(struct event_base *base, unsigned flags, struct event_callback *evcb, void (*cb)(struct event_callback *, void *));
+int event_callback_finalize_many_(struct event_base *base, int n_cbs, struct event_callback **evcb, void (*cb)(struct event_callback *, void *));
+
+
+void event_active_later_(struct event *ev, int res);
+void event_active_later_nolock_(struct event *ev, int res);
+int event_callback_activate_later_nolock_(struct event_base *base,
+ struct event_callback *evcb);
+int event_callback_cancel_nolock_(struct event_base *base,
+ struct event_callback *evcb, int even_if_finalizing);
+void event_callback_init_(struct event_base *base,
+ struct event_callback *cb);
+
+/* FIXME document. */
+void event_base_add_virtual_(struct event_base *base);
+void event_base_del_virtual_(struct event_base *base);
+
+/** For debugging: unless assertions are disabled, verify the referential
+ integrity of the internal data structures of 'base'. This operation can
+ be expensive.
+
+ Returns on success; aborts on failure.
+*/
+void event_base_assert_ok_(struct event_base *base);
+void event_base_assert_ok_nolock_(struct event_base *base);
+
+
+/* Helper function: Call 'fn' exactly once every inserted or active event in
+ * the event_base 'base'.
+ *
+ * If fn returns 0, continue on to the next event. Otherwise, return the same
+ * value that fn returned.
+ *
+ * Requires that 'base' be locked.
+ */
+int event_base_foreach_event_nolock_(struct event_base *base,
+ event_base_foreach_event_cb cb, void *arg);
+
+/* Cleanup function to reset debug mode during shutdown.
+ *
+ * Calling this function doesn't mean it'll be possible to re-enable
+ * debug mode if any events were added.
+ */
+void event_disable_debug_mode(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT_INTERNAL_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/event.3 b/fluent-bit/lib/monkey/mk_core/deps/libevent/event.3
new file mode 100644
index 000000000..655a823ef
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/event.3
@@ -0,0 +1,624 @@
+.\" $OpenBSD: event.3,v 1.4 2002/07/12 18:50:48 provos Exp $
+.\"
+.\" Copyright (c) 2000 Artur Grabowski <art@openbsd.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd August 8, 2000
+.Dt EVENT 3
+.Os
+.Sh NAME
+.Nm event_init ,
+.Nm event_dispatch ,
+.Nm event_loop ,
+.Nm event_loopexit ,
+.Nm event_loopbreak ,
+.Nm event_set ,
+.Nm event_base_dispatch ,
+.Nm event_base_loop ,
+.Nm event_base_loopexit ,
+.Nm event_base_loopbreak ,
+.Nm event_base_set ,
+.Nm event_base_free ,
+.Nm event_add ,
+.Nm event_del ,
+.Nm event_once ,
+.Nm event_base_once ,
+.Nm event_pending ,
+.Nm event_initialized ,
+.Nm event_priority_init ,
+.Nm event_priority_set ,
+.Nm evtimer_set ,
+.Nm evtimer_add ,
+.Nm evtimer_del ,
+.Nm evtimer_pending ,
+.Nm evtimer_initialized ,
+.Nm signal_set ,
+.Nm signal_add ,
+.Nm signal_del ,
+.Nm signal_pending ,
+.Nm signal_initialized ,
+.Nm bufferevent_new ,
+.Nm bufferevent_free ,
+.Nm bufferevent_write ,
+.Nm bufferevent_write_buffer ,
+.Nm bufferevent_read ,
+.Nm bufferevent_enable ,
+.Nm bufferevent_disable ,
+.Nm bufferevent_settimeout ,
+.Nm bufferevent_base_set ,
+.Nm evbuffer_new ,
+.Nm evbuffer_free ,
+.Nm evbuffer_add ,
+.Nm evbuffer_add_buffer ,
+.Nm evbuffer_add_printf ,
+.Nm evbuffer_add_vprintf ,
+.Nm evbuffer_drain ,
+.Nm evbuffer_write ,
+.Nm evbuffer_read ,
+.Nm evbuffer_find ,
+.Nm evbuffer_readline ,
+.Nm evhttp_new ,
+.Nm evhttp_bind_socket ,
+.Nm evhttp_free
+.Nd execute a function when a specific event occurs
+.Sh SYNOPSIS
+.Fd #include <sys/time.h>
+.Fd #include <event.h>
+.Ft "struct event_base *"
+.Fn "event_init" "void"
+.Ft int
+.Fn "event_dispatch" "void"
+.Ft int
+.Fn "event_loop" "int flags"
+.Ft int
+.Fn "event_loopexit" "struct timeval *tv"
+.Ft int
+.Fn "event_loopbreak" "void"
+.Ft void
+.Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg"
+.Ft int
+.Fn "event_base_dispatch" "struct event_base *base"
+.Ft int
+.Fn "event_base_loop" "struct event_base *base" "int flags"
+.Ft int
+.Fn "event_base_loopexit" "struct event_base *base" "struct timeval *tv"
+.Ft int
+.Fn "event_base_loopbreak" "struct event_base *base"
+.Ft int
+.Fn "event_base_set" "struct event_base *base" "struct event *"
+.Ft void
+.Fn "event_base_free" "struct event_base *base"
+.Ft int
+.Fn "event_add" "struct event *ev" "struct timeval *tv"
+.Ft int
+.Fn "event_del" "struct event *ev"
+.Ft int
+.Fn "event_once" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv"
+.Ft int
+.Fn "event_base_once" "struct event_base *base" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv"
+.Ft int
+.Fn "event_pending" "struct event *ev" "short event" "struct timeval *tv"
+.Ft int
+.Fn "event_initialized" "struct event *ev"
+.Ft int
+.Fn "event_priority_init" "int npriorities"
+.Ft int
+.Fn "event_priority_set" "struct event *ev" "int priority"
+.Ft void
+.Fn "evtimer_set" "struct event *ev" "void (*fn)(int, short, void *)" "void *arg"
+.Ft void
+.Fn "evtimer_add" "struct event *ev" "struct timeval *"
+.Ft void
+.Fn "evtimer_del" "struct event *ev"
+.Ft int
+.Fn "evtimer_pending" "struct event *ev" "struct timeval *tv"
+.Ft int
+.Fn "evtimer_initialized" "struct event *ev"
+.Ft void
+.Fn "signal_set" "struct event *ev" "int signal" "void (*fn)(int, short, void *)" "void *arg"
+.Ft void
+.Fn "signal_add" "struct event *ev" "struct timeval *"
+.Ft void
+.Fn "signal_del" "struct event *ev"
+.Ft int
+.Fn "signal_pending" "struct event *ev" "struct timeval *tv"
+.Ft int
+.Fn "signal_initialized" "struct event *ev"
+.Ft "struct bufferevent *"
+.Fn "bufferevent_new" "int fd" "evbuffercb readcb" "evbuffercb writecb" "everrorcb" "void *cbarg"
+.Ft void
+.Fn "bufferevent_free" "struct bufferevent *bufev"
+.Ft int
+.Fn "bufferevent_write" "struct bufferevent *bufev" "void *data" "size_t size"
+.Ft int
+.Fn "bufferevent_write_buffer" "struct bufferevent *bufev" "struct evbuffer *buf"
+.Ft size_t
+.Fn "bufferevent_read" "struct bufferevent *bufev" "void *data" "size_t size"
+.Ft int
+.Fn "bufferevent_enable" "struct bufferevent *bufev" "short event"
+.Ft int
+.Fn "bufferevent_disable" "struct bufferevent *bufev" "short event"
+.Ft void
+.Fn "bufferevent_settimeout" "struct bufferevent *bufev" "int timeout_read" "int timeout_write"
+.Ft int
+.Fn "bufferevent_base_set" "struct event_base *base" "struct bufferevent *bufev"
+.Ft "struct evbuffer *"
+.Fn "evbuffer_new" "void"
+.Ft void
+.Fn "evbuffer_free" "struct evbuffer *buf"
+.Ft int
+.Fn "evbuffer_add" "struct evbuffer *buf" "const void *data" "size_t size"
+.Ft int
+.Fn "evbuffer_add_buffer" "struct evbuffer *dst" "struct evbuffer *src"
+.Ft int
+.Fn "evbuffer_add_printf" "struct evbuffer *buf" "const char *fmt" "..."
+.Ft int
+.Fn "evbuffer_add_vprintf" "struct evbuffer *buf" "const char *fmt" "va_list ap"
+.Ft void
+.Fn "evbuffer_drain" "struct evbuffer *buf" "size_t size"
+.Ft int
+.Fn "evbuffer_write" "struct evbuffer *buf" "int fd"
+.Ft int
+.Fn "evbuffer_read" "struct evbuffer *buf" "int fd" "int size"
+.Ft "unsigned char *"
+.Fn "evbuffer_find" "struct evbuffer *buf" "const unsigned char *data" "size_t size"
+.Ft "char *"
+.Fn "evbuffer_readline" "struct evbuffer *buf"
+.Ft "struct evhttp *"
+.Fn "evhttp_new" "struct event_base *base"
+.Ft int
+.Fn "evhttp_bind_socket" "struct evhttp *http" "const char *address" "unsigned short port"
+.Ft "void"
+.Fn "evhttp_free" "struct evhttp *http"
+.Ft int
+.Fa (*event_sigcb)(void) ;
+.Ft volatile sig_atomic_t
+.Fa event_gotsig ;
+.Sh DESCRIPTION
+The
+.Nm event
+API provides a mechanism to execute a function when a specific event
+on a file descriptor occurs or after a given time has passed.
+.Pp
+The
+.Nm event
+API needs to be initialized with
+.Fn event_init
+before it can be used.
+.Pp
+In order to process events, an application needs to call
+.Fn event_dispatch .
+This function only returns on error, and should replace the event core
+of the application program.
+.Pp
+The function
+.Fn event_set
+prepares the event structure
+.Fa ev
+to be used in future calls to
+.Fn event_add
+and
+.Fn event_del .
+The event will be prepared to call the function specified by the
+.Fa fn
+argument with an
+.Fa int
+argument indicating the file descriptor, a
+.Fa short
+argument indicating the type of event, and a
+.Fa void *
+argument given in the
+.Fa arg
+argument.
+The
+.Fa fd
+indicates the file descriptor that should be monitored for events.
+The events can be either
+.Va EV_READ ,
+.Va EV_WRITE ,
+or both,
+indicating that an application can read or write from the file descriptor
+respectively without blocking.
+.Pp
+The function
+.Fa fn
+will be called with the file descriptor that triggered the event and
+the type of event which will be either
+.Va EV_TIMEOUT ,
+.Va EV_SIGNAL ,
+.Va EV_READ ,
+or
+.Va EV_WRITE .
+Additionally, an event which has registered interest in more than one of the
+preceeding events, via bitwise-OR to
+.Fn event_set ,
+can provide its callback function with a bitwise-OR of more than one triggered
+event.
+The additional flag
+.Va EV_PERSIST
+makes an
+.Fn event_add
+persistent until
+.Fn event_del
+has been called.
+.Pp
+Once initialized, the
+.Fa ev
+structure can be used repeatedly with
+.Fn event_add
+and
+.Fn event_del
+and does not need to be reinitialized unless the function called and/or
+the argument to it are to be changed.
+However, when an
+.Fa ev
+structure has been added to libevent using
+.Fn event_add
+the structure must persist until the event occurs (assuming
+.Fa EV_PERSIST
+is not set) or is removed
+using
+.Fn event_del .
+You may not reuse the same
+.Fa ev
+structure for multiple monitored descriptors; each descriptor
+needs its own
+.Fa ev .
+.Pp
+The function
+.Fn event_add
+schedules the execution of the
+.Fa ev
+event when the event specified in
+.Fn event_set
+occurs or in at least the time specified in the
+.Fa tv .
+If
+.Fa tv
+is
+.Dv NULL ,
+no timeout occurs and the function will only be called
+if a matching event occurs on the file descriptor.
+The event in the
+.Fa ev
+argument must be already initialized by
+.Fn event_set
+and may not be used in calls to
+.Fn event_set
+until it has timed out or been removed with
+.Fn event_del .
+If the event in the
+.Fa ev
+argument already has a scheduled timeout, the old timeout will be
+replaced by the new one.
+.Pp
+The function
+.Fn event_del
+will cancel the event in the argument
+.Fa ev .
+If the event has already executed or has never been added
+the call will have no effect.
+.Pp
+The functions
+.Fn evtimer_set ,
+.Fn evtimer_add ,
+.Fn evtimer_del ,
+.Fn evtimer_initialized ,
+and
+.Fn evtimer_pending
+are abbreviations for common situations where only a timeout is required.
+The file descriptor passed will be \-1, and the event type will be
+.Va EV_TIMEOUT .
+.Pp
+The functions
+.Fn signal_set ,
+.Fn signal_add ,
+.Fn signal_del ,
+.Fn signal_initialized ,
+and
+.Fn signal_pending
+are abbreviations.
+The event type will be a persistent
+.Va EV_SIGNAL .
+That means
+.Fn signal_set
+adds
+.Va EV_PERSIST .
+.Pp
+In order to avoid races in signal handlers, the
+.Nm event
+API provides two variables:
+.Va event_sigcb
+and
+.Va event_gotsig .
+A signal handler
+sets
+.Va event_gotsig
+to indicate that a signal has been received.
+The application sets
+.Va event_sigcb
+to a callback function.
+After the signal handler sets
+.Va event_gotsig ,
+.Nm event_dispatch
+will execute the callback function to process received signals.
+The callback returns 1 when no events are registered any more.
+It can return \-1 to indicate an error to the
+.Nm event
+library, causing
+.Fn event_dispatch
+to terminate with
+.Va errno
+set to
+.Er EINTR .
+.Pp
+The function
+.Fn event_once
+is similar to
+.Fn event_set .
+However, it schedules a callback to be called exactly once and does not
+require the caller to prepare an
+.Fa event
+structure.
+This function supports
+.Fa EV_TIMEOUT ,
+.Fa EV_READ ,
+and
+.Fa EV_WRITE .
+.Pp
+The
+.Fn event_pending
+function can be used to check if the event specified by
+.Fa event
+is pending to run.
+If
+.Va EV_TIMEOUT
+was specified and
+.Fa tv
+is not
+.Dv NULL ,
+the expiration time of the event will be returned in
+.Fa tv .
+.Pp
+The
+.Fn event_initialized
+macro can be used to check if an event has been initialized.
+.Pp
+The
+.Nm event_loop
+function provides an interface for single pass execution of pending
+events.
+The flags
+.Va EVLOOP_ONCE
+and
+.Va EVLOOP_NONBLOCK
+are recognized.
+The
+.Nm event_loopexit
+function exits from the event loop. The next
+.Fn event_loop
+iteration after the
+given timer expires will complete normally (handling all queued events) then
+exit without blocking for events again. Subsequent invocations of
+.Fn event_loop
+will proceed normally.
+The
+.Nm event_loopbreak
+function exits from the event loop immediately.
+.Fn event_loop
+will abort after the next event is completed;
+.Fn event_loopbreak
+is typically invoked from this event's callback. This behavior is analogous
+to the "break;" statement. Subsequent invocations of
+.Fn event_loop
+will proceed normally.
+.Pp
+It is the responsibility of the caller to provide these functions with
+pre-allocated event structures.
+.Pp
+.Sh EVENT PRIORITIES
+By default
+.Nm libevent
+schedules all active events with the same priority.
+However, sometimes it is desirable to process some events with a higher
+priority than others.
+For that reason,
+.Nm libevent
+supports strict priority queues.
+Active events with a lower priority are always processed before events
+with a higher priority.
+.Pp
+The number of different priorities can be set initially with the
+.Fn event_priority_init
+function.
+This function should be called before the first call to
+.Fn event_dispatch .
+The
+.Fn event_priority_set
+function can be used to assign a priority to an event.
+By default,
+.Nm libevent
+assigns the middle priority to all events unless their priority
+is explicitly set.
+.Sh THREAD SAFE EVENTS
+.Nm Libevent
+has experimental support for thread-safe events.
+When initializing the library via
+.Fn event_init ,
+an event base is returned.
+This event base can be used in conjunction with calls to
+.Fn event_base_set ,
+.Fn event_base_dispatch ,
+.Fn event_base_loop ,
+.Fn event_base_loopexit ,
+.Fn bufferevent_base_set
+and
+.Fn event_base_free .
+.Fn event_base_set
+should be called after preparing an event with
+.Fn event_set ,
+as
+.Fn event_set
+assigns the provided event to the most recently created event base.
+.Fn bufferevent_base_set
+should be called after preparing a bufferevent with
+.Fn bufferevent_new .
+.Fn event_base_free
+should be used to free memory associated with the event base
+when it is no longer needed.
+.Sh BUFFERED EVENTS
+.Nm libevent
+provides an abstraction on top of the regular event callbacks.
+This abstraction is called a
+.Va "buffered event" .
+A buffered event provides input and output buffers that get filled
+and drained automatically.
+The user of a buffered event no longer deals directly with the IO,
+but instead is reading from input and writing to output buffers.
+.Pp
+A new bufferevent is created by
+.Fn bufferevent_new .
+The parameter
+.Fa fd
+specifies the file descriptor from which data is read and written to.
+This file descriptor is not allowed to be a
+.Xr pipe 2 .
+The next three parameters are callbacks.
+The read and write callback have the following form:
+.Ft void
+.Fn "(*cb)" "struct bufferevent *bufev" "void *arg" .
+The error callback has the following form:
+.Ft void
+.Fn "(*cb)" "struct bufferevent *bufev" "short what" "void *arg" .
+The argument is specified by the fourth parameter
+.Fa "cbarg" .
+A
+.Fa bufferevent struct
+pointer is returned on success, NULL on error.
+Both the read and the write callback may be NULL.
+The error callback has to be always provided.
+.Pp
+Once initialized, the bufferevent structure can be used repeatedly with
+bufferevent_enable() and bufferevent_disable().
+The flags parameter can be a combination of
+.Va EV_READ
+and
+.Va EV_WRITE .
+When read enabled the bufferevent will try to read from the file
+descriptor and call the read callback.
+The write callback is executed
+whenever the output buffer is drained below the write low watermark,
+which is
+.Va 0
+by default.
+.Pp
+The
+.Fn bufferevent_write
+function can be used to write data to the file descriptor.
+The data is appended to the output buffer and written to the descriptor
+automatically as it becomes available for writing.
+.Fn bufferevent_write
+returns 0 on success or \-1 on failure.
+The
+.Fn bufferevent_read
+function is used to read data from the input buffer,
+returning the amount of data read.
+.Pp
+If multiple bases are in use, bufferevent_base_set() must be called before
+enabling the bufferevent for the first time.
+.Sh NON-BLOCKING HTTP SUPPORT
+.Nm libevent
+provides a very thin HTTP layer that can be used both to host an HTTP
+server and also to make HTTP requests.
+An HTTP server can be created by calling
+.Fn evhttp_new .
+It can be bound to any port and address with the
+.Fn evhttp_bind_socket
+function.
+When the HTTP server is no longer used, it can be freed via
+.Fn evhttp_free .
+.Pp
+To be notified of HTTP requests, a user needs to register callbacks with the
+HTTP server.
+This can be done by calling
+.Fn evhttp_set_cb .
+The second argument is the URI for which a callback is being registered.
+The corresponding callback will receive an
+.Va struct evhttp_request
+object that contains all information about the request.
+.Pp
+This section does not document all the possible function calls; please
+check
+.Va event.h
+for the public interfaces.
+.Sh ADDITIONAL NOTES
+It is possible to disable support for
+.Va epoll , kqueue , devpoll , poll
+or
+.Va select
+by setting the environment variable
+.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL , EVENT_NOPOLL
+or
+.Va EVENT_NOSELECT ,
+respectively.
+By setting the environment variable
+.Va EVENT_SHOW_METHOD ,
+.Nm libevent
+displays the kernel notification method that it uses.
+.Sh RETURN VALUES
+Upon successful completion
+.Fn event_add
+and
+.Fn event_del
+return 0.
+Otherwise, \-1 is returned and the global variable errno is
+set to indicate the error.
+.Sh SEE ALSO
+.Xr kqueue 2 ,
+.Xr poll 2 ,
+.Xr select 2 ,
+.Xr evdns 3 ,
+.Xr timeout 9
+.Sh HISTORY
+The
+.Nm event
+API manpage is based on the
+.Xr timeout 9
+manpage by Artur Grabowski.
+The port of
+.Nm libevent
+to Windows is due to Michael A. Davis.
+Support for real-time signals is due to Taral.
+.Sh AUTHORS
+The
+.Nm event
+library was written by Niels Provos.
+.Sh BUGS
+This documentation is neither complete nor authoritative.
+If you are in doubt about the usage of this API then
+check the source code to find out how it works, write
+up the missing piece of documentation and send it to
+me for inclusion in this man page.
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/event.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/event.c
new file mode 100644
index 000000000..503003e24
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/event.c
@@ -0,0 +1,3940 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+#include <sys/types.h>
+#if !defined(_WIN32) && defined(EVENT__HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+#include <limits.h>
+
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/event_compat.h"
+#include "event-internal.h"
+#include "defer-internal.h"
+#include "evthread-internal.h"
+#include "event2/thread.h"
+#include "event2/util.h"
+#include "log-internal.h"
+#include "evmap-internal.h"
+#include "iocp-internal.h"
+#include "changelist-internal.h"
+#define HT_NO_CACHE_HASH_VALUES
+#include "ht-internal.h"
+#include "util-internal.h"
+
+
+#ifdef EVENT__HAVE_WORKING_KQUEUE
+#include "kqueue-internal.h"
+#endif
+
+#ifdef EVENT__HAVE_EVENT_PORTS
+extern const struct eventop evportops;
+#endif
+#ifdef EVENT__HAVE_SELECT
+extern const struct eventop selectops;
+#endif
+#ifdef EVENT__HAVE_POLL
+extern const struct eventop pollops;
+#endif
+#ifdef EVENT__HAVE_EPOLL
+extern const struct eventop epollops;
+#endif
+#ifdef EVENT__HAVE_WORKING_KQUEUE
+extern const struct eventop kqops;
+#endif
+#ifdef EVENT__HAVE_DEVPOLL
+extern const struct eventop devpollops;
+#endif
+#ifdef _WIN32
+extern const struct eventop win32ops;
+#endif
+
+/* Array of backends in order of preference. */
+static const struct eventop *eventops[] = {
+#ifdef EVENT__HAVE_EVENT_PORTS
+ &evportops,
+#endif
+#ifdef EVENT__HAVE_WORKING_KQUEUE
+ &kqops,
+#endif
+#ifdef EVENT__HAVE_EPOLL
+ &epollops,
+#endif
+#ifdef EVENT__HAVE_DEVPOLL
+ &devpollops,
+#endif
+#ifdef EVENT__HAVE_POLL
+ &pollops,
+#endif
+#ifdef EVENT__HAVE_SELECT
+ &selectops,
+#endif
+#ifdef _WIN32
+ &win32ops,
+#endif
+ NULL
+};
+
+/* Global state; deprecated */
+struct event_base *event_global_current_base_ = NULL;
+#define current_base event_global_current_base_
+
+/* Global state */
+
+static void *event_self_cbarg_ptr_ = NULL;
+
+/* Prototypes */
+static void event_queue_insert_active(struct event_base *, struct event_callback *);
+static void event_queue_insert_active_later(struct event_base *, struct event_callback *);
+static void event_queue_insert_timeout(struct event_base *, struct event *);
+static void event_queue_insert_inserted(struct event_base *, struct event *);
+static void event_queue_remove_active(struct event_base *, struct event_callback *);
+static void event_queue_remove_active_later(struct event_base *, struct event_callback *);
+static void event_queue_remove_timeout(struct event_base *, struct event *);
+static void event_queue_remove_inserted(struct event_base *, struct event *);
+static void event_queue_make_later_events_active(struct event_base *base);
+
+static int evthread_make_base_notifiable_nolock_(struct event_base *base);
+static int event_del_(struct event *ev, int blocking);
+
+#ifdef USE_REINSERT_TIMEOUT
+/* This code seems buggy; only turn it on if we find out what the trouble is. */
+static void event_queue_reinsert_timeout(struct event_base *,struct event *, int was_common, int is_common, int old_timeout_idx);
+#endif
+
+static int event_haveevents(struct event_base *);
+
+static int event_process_active(struct event_base *);
+
+static int timeout_next(struct event_base *, struct timeval **);
+static void timeout_process(struct event_base *);
+
+static inline void event_signal_closure(struct event_base *, struct event *ev);
+static inline void event_persist_closure(struct event_base *, struct event *ev);
+
+static int evthread_notify_base(struct event_base *base);
+
+static void insert_common_timeout_inorder(struct common_timeout_list *ctl,
+ struct event *ev);
+
+#ifndef EVENT__DISABLE_DEBUG_MODE
+/* These functions implement a hashtable of which 'struct event *' structures
+ * have been setup or added. We don't want to trust the content of the struct
+ * event itself, since we're trying to work through cases where an event gets
+ * clobbered or freed. Instead, we keep a hashtable indexed by the pointer.
+ */
+
+struct event_debug_entry {
+ HT_ENTRY(event_debug_entry) node;
+ const struct event *ptr;
+ unsigned added : 1;
+};
+
+static inline unsigned
+hash_debug_entry(const struct event_debug_entry *e)
+{
+ /* We need to do this silliness to convince compilers that we
+ * honestly mean to cast e->ptr to an integer, and discard any
+ * part of it that doesn't fit in an unsigned.
+ */
+ unsigned u = (unsigned) ((ev_uintptr_t) e->ptr);
+ /* Our hashtable implementation is pretty sensitive to low bits,
+ * and every struct event is over 64 bytes in size, so we can
+ * just say >>6. */
+ return (u >> 6);
+}
+
+static inline int
+eq_debug_entry(const struct event_debug_entry *a,
+ const struct event_debug_entry *b)
+{
+ return a->ptr == b->ptr;
+}
+
+int event_debug_mode_on_ = 0;
+
+
+#if !defined(EVENT__DISABLE_THREAD_SUPPORT) && !defined(EVENT__DISABLE_DEBUG_MODE)
+/**
+ * @brief debug mode variable which is set for any function/structure that needs
+ * to be shared across threads (if thread support is enabled).
+ *
+ * When and if evthreads are initialized, this variable will be evaluated,
+ * and if set to something other than zero, this means the evthread setup
+ * functions were called out of order.
+ *
+ * See: "Locks and threading" in the documentation.
+ */
+int event_debug_created_threadable_ctx_ = 0;
+#endif
+
+/* Set if it's too late to enable event_debug_mode. */
+static int event_debug_mode_too_late = 0;
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+static void *event_debug_map_lock_ = NULL;
+#endif
+static HT_HEAD(event_debug_map, event_debug_entry) global_debug_map =
+ HT_INITIALIZER();
+
+HT_PROTOTYPE(event_debug_map, event_debug_entry, node, hash_debug_entry,
+ eq_debug_entry)
+HT_GENERATE(event_debug_map, event_debug_entry, node, hash_debug_entry,
+ eq_debug_entry, 0.5, mm_malloc, mm_realloc, mm_free)
+
+/* Macro: record that ev is now setup (that is, ready for an add) */
+#define event_debug_note_setup_(ev) do { \
+ if (event_debug_mode_on_) { \
+ struct event_debug_entry *dent,find; \
+ find.ptr = (ev); \
+ EVLOCK_LOCK(event_debug_map_lock_, 0); \
+ dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
+ if (dent) { \
+ dent->added = 0; \
+ } else { \
+ dent = mm_malloc(sizeof(*dent)); \
+ if (!dent) \
+ event_err(1, \
+ "Out of memory in debugging code"); \
+ dent->ptr = (ev); \
+ dent->added = 0; \
+ HT_INSERT(event_debug_map, &global_debug_map, dent); \
+ } \
+ EVLOCK_UNLOCK(event_debug_map_lock_, 0); \
+ } \
+ event_debug_mode_too_late = 1; \
+ } while (0)
+/* Macro: record that ev is no longer setup */
+#define event_debug_note_teardown_(ev) do { \
+ if (event_debug_mode_on_) { \
+ struct event_debug_entry *dent,find; \
+ find.ptr = (ev); \
+ EVLOCK_LOCK(event_debug_map_lock_, 0); \
+ dent = HT_REMOVE(event_debug_map, &global_debug_map, &find); \
+ if (dent) \
+ mm_free(dent); \
+ EVLOCK_UNLOCK(event_debug_map_lock_, 0); \
+ } \
+ event_debug_mode_too_late = 1; \
+ } while (0)
+/* Macro: record that ev is now added */
+#define event_debug_note_add_(ev) do { \
+ if (event_debug_mode_on_) { \
+ struct event_debug_entry *dent,find; \
+ find.ptr = (ev); \
+ EVLOCK_LOCK(event_debug_map_lock_, 0); \
+ dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
+ if (dent) { \
+ dent->added = 1; \
+ } else { \
+ event_errx(EVENT_ERR_ABORT_, \
+ "%s: noting an add on a non-setup event %p" \
+ " (events: 0x%x, fd: "EV_SOCK_FMT \
+ ", flags: 0x%x)", \
+ __func__, (ev), (ev)->ev_events, \
+ EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags); \
+ } \
+ EVLOCK_UNLOCK(event_debug_map_lock_, 0); \
+ } \
+ event_debug_mode_too_late = 1; \
+ } while (0)
+/* Macro: record that ev is no longer added */
+#define event_debug_note_del_(ev) do { \
+ if (event_debug_mode_on_) { \
+ struct event_debug_entry *dent,find; \
+ find.ptr = (ev); \
+ EVLOCK_LOCK(event_debug_map_lock_, 0); \
+ dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
+ if (dent) { \
+ dent->added = 0; \
+ } else { \
+ event_errx(EVENT_ERR_ABORT_, \
+ "%s: noting a del on a non-setup event %p" \
+ " (events: 0x%x, fd: "EV_SOCK_FMT \
+ ", flags: 0x%x)", \
+ __func__, (ev), (ev)->ev_events, \
+ EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags); \
+ } \
+ EVLOCK_UNLOCK(event_debug_map_lock_, 0); \
+ } \
+ event_debug_mode_too_late = 1; \
+ } while (0)
+/* Macro: assert that ev is setup (i.e., okay to add or inspect) */
+#define event_debug_assert_is_setup_(ev) do { \
+ if (event_debug_mode_on_) { \
+ struct event_debug_entry *dent,find; \
+ find.ptr = (ev); \
+ EVLOCK_LOCK(event_debug_map_lock_, 0); \
+ dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
+ if (!dent) { \
+ event_errx(EVENT_ERR_ABORT_, \
+ "%s called on a non-initialized event %p" \
+ " (events: 0x%x, fd: "EV_SOCK_FMT\
+ ", flags: 0x%x)", \
+ __func__, (ev), (ev)->ev_events, \
+ EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags); \
+ } \
+ EVLOCK_UNLOCK(event_debug_map_lock_, 0); \
+ } \
+ } while (0)
+/* Macro: assert that ev is not added (i.e., okay to tear down or set
+ * up again) */
+#define event_debug_assert_not_added_(ev) do { \
+ if (event_debug_mode_on_) { \
+ struct event_debug_entry *dent,find; \
+ find.ptr = (ev); \
+ EVLOCK_LOCK(event_debug_map_lock_, 0); \
+ dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
+ if (dent && dent->added) { \
+ event_errx(EVENT_ERR_ABORT_, \
+ "%s called on an already added event %p" \
+ " (events: 0x%x, fd: "EV_SOCK_FMT", " \
+ "flags: 0x%x)", \
+ __func__, (ev), (ev)->ev_events, \
+ EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags); \
+ } \
+ EVLOCK_UNLOCK(event_debug_map_lock_, 0); \
+ } \
+ } while (0)
+#else
+#define event_debug_note_setup_(ev) \
+ ((void)0)
+#define event_debug_note_teardown_(ev) \
+ ((void)0)
+#define event_debug_note_add_(ev) \
+ ((void)0)
+#define event_debug_note_del_(ev) \
+ ((void)0)
+#define event_debug_assert_is_setup_(ev) \
+ ((void)0)
+#define event_debug_assert_not_added_(ev) \
+ ((void)0)
+#endif
+
+#define EVENT_BASE_ASSERT_LOCKED(base) \
+ EVLOCK_ASSERT_LOCKED((base)->th_base_lock)
+
+/* How often (in seconds) do we check for changes in wall clock time relative
+ * to monotonic time? Set this to -1 for 'never.' */
+#define CLOCK_SYNC_INTERVAL 5
+
+/** Set 'tp' to the current time according to 'base'. We must hold the lock
+ * on 'base'. If there is a cached time, return it. Otherwise, use
+ * clock_gettime or gettimeofday as appropriate to find out the right time.
+ * Return 0 on success, -1 on failure.
+ */
+static int
+gettime(struct event_base *base, struct timeval *tp)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
+
+ if (base->tv_cache.tv_sec) {
+ *tp = base->tv_cache;
+ return (0);
+ }
+
+ if (evutil_gettime_monotonic_(&base->monotonic_timer, tp) == -1) {
+ return -1;
+ }
+
+ if (base->last_updated_clock_diff + CLOCK_SYNC_INTERVAL
+ < tp->tv_sec) {
+ struct timeval tv;
+ evutil_gettimeofday(&tv,NULL);
+ evutil_timersub(&tv, tp, &base->tv_clock_diff);
+ base->last_updated_clock_diff = tp->tv_sec;
+ }
+
+ return 0;
+}
+
+int
+event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv)
+{
+ int r;
+ if (!base) {
+ base = current_base;
+ if (!current_base)
+ return evutil_gettimeofday(tv, NULL);
+ }
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ if (base->tv_cache.tv_sec == 0) {
+ r = evutil_gettimeofday(tv, NULL);
+ } else {
+ evutil_timeradd(&base->tv_cache, &base->tv_clock_diff, tv);
+ r = 0;
+ }
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return r;
+}
+
+/** Make 'base' have no current cached time. */
+static inline void
+clear_time_cache(struct event_base *base)
+{
+ base->tv_cache.tv_sec = 0;
+}
+
+/** Replace the cached time in 'base' with the current time. */
+static inline void
+update_time_cache(struct event_base *base)
+{
+ base->tv_cache.tv_sec = 0;
+ if (!(base->flags & EVENT_BASE_FLAG_NO_CACHE_TIME))
+ gettime(base, &base->tv_cache);
+}
+
+int
+event_base_update_cache_time(struct event_base *base)
+{
+
+ if (!base) {
+ base = current_base;
+ if (!current_base)
+ return -1;
+ }
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ if (base->running_loop)
+ update_time_cache(base);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return 0;
+}
+
+static inline struct event *
+event_callback_to_event(struct event_callback *evcb)
+{
+ EVUTIL_ASSERT((evcb->evcb_flags & EVLIST_INIT));
+ return EVUTIL_UPCAST(evcb, struct event, ev_evcallback);
+}
+
+static inline struct event_callback *
+event_to_event_callback(struct event *ev)
+{
+ return &ev->ev_evcallback;
+}
+
+struct event_base *
+event_init(void)
+{
+ struct event_base *base = event_base_new_with_config(NULL);
+
+ if (base == NULL) {
+ event_errx(1, "%s: Unable to construct event_base", __func__);
+ return NULL;
+ }
+
+ current_base = base;
+
+ return (base);
+}
+
+struct event_base *
+event_base_new(void)
+{
+ struct event_base *base = NULL;
+ struct event_config *cfg = event_config_new();
+ if (cfg) {
+ base = event_base_new_with_config(cfg);
+ event_config_free(cfg);
+ }
+ return base;
+}
+
+/** Return true iff 'method' is the name of a method that 'cfg' tells us to
+ * avoid. */
+static int
+event_config_is_avoided_method(const struct event_config *cfg,
+ const char *method)
+{
+ struct event_config_entry *entry;
+
+ TAILQ_FOREACH(entry, &cfg->entries, next) {
+ if (entry->avoid_method != NULL &&
+ strcmp(entry->avoid_method, method) == 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+/** Return true iff 'method' is disabled according to the environment. */
+static int
+event_is_method_disabled(const char *name)
+{
+ char environment[64];
+ int i;
+
+ evutil_snprintf(environment, sizeof(environment), "EVENT_NO%s", name);
+ for (i = 8; environment[i] != '\0'; ++i)
+ environment[i] = EVUTIL_TOUPPER_(environment[i]);
+ /* Note that evutil_getenv_() ignores the environment entirely if
+ * we're setuid */
+ return (evutil_getenv_(environment) != NULL);
+}
+
+int
+event_base_get_features(const struct event_base *base)
+{
+ return base->evsel->features;
+}
+
+void
+event_enable_debug_mode(void)
+{
+#ifndef EVENT__DISABLE_DEBUG_MODE
+ if (event_debug_mode_on_)
+ event_errx(1, "%s was called twice!", __func__);
+ if (event_debug_mode_too_late)
+ event_errx(1, "%s must be called *before* creating any events "
+ "or event_bases",__func__);
+
+ event_debug_mode_on_ = 1;
+
+ HT_INIT(event_debug_map, &global_debug_map);
+#endif
+}
+
+void
+event_disable_debug_mode(void)
+{
+#ifndef EVENT__DISABLE_DEBUG_MODE
+ struct event_debug_entry **ent, *victim;
+
+ EVLOCK_LOCK(event_debug_map_lock_, 0);
+ for (ent = HT_START(event_debug_map, &global_debug_map); ent; ) {
+ victim = *ent;
+ ent = HT_NEXT_RMV(event_debug_map, &global_debug_map, ent);
+ mm_free(victim);
+ }
+ HT_CLEAR(event_debug_map, &global_debug_map);
+ EVLOCK_UNLOCK(event_debug_map_lock_ , 0);
+
+ event_debug_mode_on_ = 0;
+#endif
+}
+
+struct event_base *
+event_base_new_with_config(const struct event_config *cfg)
+{
+ int i;
+ struct event_base *base;
+ int should_check_environment;
+
+#ifndef EVENT__DISABLE_DEBUG_MODE
+ event_debug_mode_too_late = 1;
+#endif
+
+ if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) {
+ event_warn("%s: calloc", __func__);
+ return NULL;
+ }
+
+ if (cfg)
+ base->flags = cfg->flags;
+
+ should_check_environment =
+ !(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));
+
+ {
+ struct timeval tmp;
+ int precise_time =
+ cfg && (cfg->flags & EVENT_BASE_FLAG_PRECISE_TIMER);
+ int flags;
+ if (should_check_environment && !precise_time) {
+ precise_time = evutil_getenv_("EVENT_PRECISE_TIMER") != NULL;
+ base->flags |= EVENT_BASE_FLAG_PRECISE_TIMER;
+ }
+ flags = precise_time ? EV_MONOT_PRECISE : 0;
+ evutil_configure_monotonic_time_(&base->monotonic_timer, flags);
+
+ gettime(base, &tmp);
+ }
+
+ min_heap_ctor_(&base->timeheap);
+
+ base->sig.ev_signal_pair[0] = -1;
+ base->sig.ev_signal_pair[1] = -1;
+ base->th_notify_fd[0] = -1;
+ base->th_notify_fd[1] = -1;
+
+ TAILQ_INIT(&base->active_later_queue);
+
+ evmap_io_initmap_(&base->io);
+ evmap_signal_initmap_(&base->sigmap);
+ event_changelist_init_(&base->changelist);
+
+ base->evbase = NULL;
+
+ if (cfg) {
+ memcpy(&base->max_dispatch_time,
+ &cfg->max_dispatch_interval, sizeof(struct timeval));
+ base->limit_callbacks_after_prio =
+ cfg->limit_callbacks_after_prio;
+ } else {
+ base->max_dispatch_time.tv_sec = -1;
+ base->limit_callbacks_after_prio = 1;
+ }
+ if (cfg && cfg->max_dispatch_callbacks >= 0) {
+ base->max_dispatch_callbacks = cfg->max_dispatch_callbacks;
+ } else {
+ base->max_dispatch_callbacks = INT_MAX;
+ }
+ if (base->max_dispatch_callbacks == INT_MAX &&
+ base->max_dispatch_time.tv_sec == -1)
+ base->limit_callbacks_after_prio = INT_MAX;
+
+ for (i = 0; eventops[i] && !base->evbase; i++) {
+ if (cfg != NULL) {
+ /* determine if this backend should be avoided */
+ if (event_config_is_avoided_method(cfg,
+ eventops[i]->name))
+ continue;
+ if ((eventops[i]->features & cfg->require_features)
+ != cfg->require_features)
+ continue;
+ }
+
+ /* also obey the environment variables */
+ if (should_check_environment &&
+ event_is_method_disabled(eventops[i]->name))
+ continue;
+
+ base->evsel = eventops[i];
+
+ base->evbase = base->evsel->init(base);
+ }
+
+ if (base->evbase == NULL) {
+ event_warnx("%s: no event mechanism available",
+ __func__);
+ base->evsel = NULL;
+ event_base_free(base);
+ return NULL;
+ }
+
+ if (evutil_getenv_("EVENT_SHOW_METHOD"))
+ event_msgx("libevent using: %s", base->evsel->name);
+
+ /* allocate a single active event queue */
+ if (event_base_priority_init(base, 1) < 0) {
+ event_base_free(base);
+ return NULL;
+ }
+
+ /* prepare for threading */
+
+#if !defined(EVENT__DISABLE_THREAD_SUPPORT) && !defined(EVENT__DISABLE_DEBUG_MODE)
+ event_debug_created_threadable_ctx_ = 1;
+#endif
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ if (EVTHREAD_LOCKING_ENABLED() &&
+ (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) {
+ int r;
+ EVTHREAD_ALLOC_LOCK(base->th_base_lock, 0);
+ EVTHREAD_ALLOC_COND(base->current_event_cond);
+ r = evthread_make_base_notifiable(base);
+ if (r<0) {
+ event_warnx("%s: Unable to make base notifiable.", __func__);
+ event_base_free(base);
+ return NULL;
+ }
+ }
+#endif
+
+#ifdef _WIN32
+ if (cfg && (cfg->flags & EVENT_BASE_FLAG_STARTUP_IOCP))
+ event_base_start_iocp_(base, cfg->n_cpus_hint);
+#endif
+
+ return (base);
+}
+
+int
+event_base_start_iocp_(struct event_base *base, int n_cpus)
+{
+#ifdef _WIN32
+ if (base->iocp)
+ return 0;
+ base->iocp = event_iocp_port_launch_(n_cpus);
+ if (!base->iocp) {
+ event_warnx("%s: Couldn't launch IOCP", __func__);
+ return -1;
+ }
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+void
+event_base_stop_iocp_(struct event_base *base)
+{
+#ifdef _WIN32
+ int rv;
+
+ if (!base->iocp)
+ return;
+ rv = event_iocp_shutdown_(base->iocp, -1);
+ EVUTIL_ASSERT(rv >= 0);
+ base->iocp = NULL;
+#endif
+}
+
+static int
+event_base_cancel_single_callback_(struct event_base *base,
+ struct event_callback *evcb,
+ int run_finalizers)
+{
+ int result = 0;
+
+ if (evcb->evcb_flags & EVLIST_INIT) {
+ struct event *ev = event_callback_to_event(evcb);
+ if (!(ev->ev_flags & EVLIST_INTERNAL)) {
+ event_del_(ev, EVENT_DEL_EVEN_IF_FINALIZING);
+ result = 1;
+ }
+ } else {
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ event_callback_cancel_nolock_(base, evcb, 1);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ result = 1;
+ }
+
+ if (run_finalizers && (evcb->evcb_flags & EVLIST_FINALIZING)) {
+ switch (evcb->evcb_closure) {
+ case EV_CLOSURE_EVENT_FINALIZE:
+ case EV_CLOSURE_EVENT_FINALIZE_FREE: {
+ struct event *ev = event_callback_to_event(evcb);
+ ev->ev_evcallback.evcb_cb_union.evcb_evfinalize(ev, ev->ev_arg);
+ if (evcb->evcb_closure == EV_CLOSURE_EVENT_FINALIZE_FREE)
+ mm_free(ev);
+ break;
+ }
+ case EV_CLOSURE_CB_FINALIZE:
+ evcb->evcb_cb_union.evcb_cbfinalize(evcb, evcb->evcb_arg);
+ break;
+ default:
+ break;
+ }
+ }
+ return result;
+}
+
+static int event_base_free_queues_(struct event_base *base, int run_finalizers)
+{
+ int deleted = 0, i;
+
+ for (i = 0; i < base->nactivequeues; ++i) {
+ struct event_callback *evcb, *next;
+ for (evcb = TAILQ_FIRST(&base->activequeues[i]); evcb; ) {
+ next = TAILQ_NEXT(evcb, evcb_active_next);
+ deleted += event_base_cancel_single_callback_(base, evcb, run_finalizers);
+ evcb = next;
+ }
+ }
+
+ {
+ struct event_callback *evcb;
+ while ((evcb = TAILQ_FIRST(&base->active_later_queue))) {
+ deleted += event_base_cancel_single_callback_(base, evcb, run_finalizers);
+ }
+ }
+
+ return deleted;
+}
+
+static void
+event_base_free_(struct event_base *base, int run_finalizers)
+{
+ int i, n_deleted=0;
+ struct event *ev;
+ /* XXXX grab the lock? If there is contention when one thread frees
+ * the base, then the contending thread will be very sad soon. */
+
+ /* event_base_free(NULL) is how to free the current_base if we
+ * made it with event_init and forgot to hold a reference to it. */
+ if (base == NULL && current_base)
+ base = current_base;
+ /* Don't actually free NULL. */
+ if (base == NULL) {
+ event_warnx("%s: no base to free", __func__);
+ return;
+ }
+ /* XXX(niels) - check for internal events first */
+
+#ifdef _WIN32
+ event_base_stop_iocp_(base);
+#endif
+
+ /* threading fds if we have them */
+ if (base->th_notify_fd[0] != -1) {
+ event_del(&base->th_notify);
+ EVUTIL_CLOSESOCKET(base->th_notify_fd[0]);
+ if (base->th_notify_fd[1] != -1)
+ EVUTIL_CLOSESOCKET(base->th_notify_fd[1]);
+ base->th_notify_fd[0] = -1;
+ base->th_notify_fd[1] = -1;
+ event_debug_unassign(&base->th_notify);
+ }
+
+ /* Delete all non-internal events. */
+ evmap_delete_all_(base);
+
+ while ((ev = min_heap_top_(&base->timeheap)) != NULL) {
+ event_del(ev);
+ ++n_deleted;
+ }
+ for (i = 0; i < base->n_common_timeouts; ++i) {
+ struct common_timeout_list *ctl =
+ base->common_timeout_queues[i];
+ event_del(&ctl->timeout_event); /* Internal; doesn't count */
+ event_debug_unassign(&ctl->timeout_event);
+ for (ev = TAILQ_FIRST(&ctl->events); ev; ) {
+ struct event *next = TAILQ_NEXT(ev,
+ ev_timeout_pos.ev_next_with_common_timeout);
+ if (!(ev->ev_flags & EVLIST_INTERNAL)) {
+ event_del(ev);
+ ++n_deleted;
+ }
+ ev = next;
+ }
+ mm_free(ctl);
+ }
+ if (base->common_timeout_queues)
+ mm_free(base->common_timeout_queues);
+
+ for (;;) {
+ /* For finalizers we can register yet another finalizer out from
+ * finalizer, and iff finalizer will be in active_later_queue we can
+ * add finalizer to activequeues, and we will have events in
+ * activequeues after this function returns, which is not what we want
+ * (we even have an assertion for this).
+ *
+ * A simple case is bufferevent with underlying (i.e. filters).
+ */
+ int i = event_base_free_queues_(base, run_finalizers);
+ if (!i) {
+ break;
+ }
+ n_deleted += i;
+ }
+
+ if (n_deleted)
+ event_debug(("%s: %d events were still set in base",
+ __func__, n_deleted));
+
+ while (LIST_FIRST(&base->once_events)) {
+ struct event_once *eonce = LIST_FIRST(&base->once_events);
+ LIST_REMOVE(eonce, next_once);
+ mm_free(eonce);
+ }
+
+ if (base->evsel != NULL && base->evsel->dealloc != NULL)
+ base->evsel->dealloc(base);
+
+ for (i = 0; i < base->nactivequeues; ++i)
+ EVUTIL_ASSERT(TAILQ_EMPTY(&base->activequeues[i]));
+
+ EVUTIL_ASSERT(min_heap_empty_(&base->timeheap));
+ min_heap_dtor_(&base->timeheap);
+
+ mm_free(base->activequeues);
+
+ evmap_io_clear_(&base->io);
+ evmap_signal_clear_(&base->sigmap);
+ event_changelist_freemem_(&base->changelist);
+
+ EVTHREAD_FREE_LOCK(base->th_base_lock, 0);
+ EVTHREAD_FREE_COND(base->current_event_cond);
+
+ /* If we're freeing current_base, there won't be a current_base. */
+ if (base == current_base)
+ current_base = NULL;
+ mm_free(base);
+}
+
+void
+event_base_free_nofinalize(struct event_base *base)
+{
+ event_base_free_(base, 0);
+}
+
+void
+event_base_free(struct event_base *base)
+{
+ event_base_free_(base, 1);
+}
+
+/* Fake eventop; used to disable the backend temporarily inside event_reinit
+ * so that we can call event_del() on an event without telling the backend.
+ */
+static int
+nil_backend_del(struct event_base *b, evutil_socket_t fd, short old,
+ short events, void *fdinfo)
+{
+ return 0;
+}
+const struct eventop nil_eventop = {
+ "nil",
+ NULL, /* init: unused. */
+ NULL, /* add: unused. */
+ nil_backend_del, /* del: used, so needs to be killed. */
+ NULL, /* dispatch: unused. */
+ NULL, /* dealloc: unused. */
+ 0, 0, 0
+};
+
+/* reinitialize the event base after a fork */
+int
+event_reinit(struct event_base *base)
+{
+ const struct eventop *evsel;
+ int res = 0;
+ int was_notifiable = 0;
+ int had_signal_added = 0;
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ evsel = base->evsel;
+
+ /* check if this event mechanism requires reinit on the backend */
+ if (evsel->need_reinit) {
+ /* We're going to call event_del() on our notify events (the
+ * ones that tell about signals and wakeup events). But we
+ * don't actually want to tell the backend to change its
+ * state, since it might still share some resource (a kqueue,
+ * an epoll fd) with the parent process, and we don't want to
+ * delete the fds from _that_ backend, we temporarily stub out
+ * the evsel with a replacement.
+ */
+ base->evsel = &nil_eventop;
+ }
+
+ /* We need to re-create a new signal-notification fd and a new
+ * thread-notification fd. Otherwise, we'll still share those with
+ * the parent process, which would make any notification sent to them
+ * get received by one or both of the event loops, more or less at
+ * random.
+ */
+ if (base->sig.ev_signal_added) {
+ event_del_nolock_(&base->sig.ev_signal, EVENT_DEL_AUTOBLOCK);
+ event_debug_unassign(&base->sig.ev_signal);
+ memset(&base->sig.ev_signal, 0, sizeof(base->sig.ev_signal));
+ had_signal_added = 1;
+ base->sig.ev_signal_added = 0;
+ }
+ if (base->sig.ev_signal_pair[0] != -1)
+ EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]);
+ if (base->sig.ev_signal_pair[1] != -1)
+ EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]);
+ if (base->th_notify_fn != NULL) {
+ was_notifiable = 1;
+ base->th_notify_fn = NULL;
+ }
+ if (base->th_notify_fd[0] != -1) {
+ event_del_nolock_(&base->th_notify, EVENT_DEL_AUTOBLOCK);
+ EVUTIL_CLOSESOCKET(base->th_notify_fd[0]);
+ if (base->th_notify_fd[1] != -1)
+ EVUTIL_CLOSESOCKET(base->th_notify_fd[1]);
+ base->th_notify_fd[0] = -1;
+ base->th_notify_fd[1] = -1;
+ event_debug_unassign(&base->th_notify);
+ }
+
+ /* Replace the original evsel. */
+ base->evsel = evsel;
+
+ if (evsel->need_reinit) {
+ /* Reconstruct the backend through brute-force, so that we do
+ * not share any structures with the parent process. For some
+ * backends, this is necessary: epoll and kqueue, for
+ * instance, have events associated with a kernel
+ * structure. If didn't reinitialize, we'd share that
+ * structure with the parent process, and any changes made by
+ * the parent would affect our backend's behavior (and vice
+ * versa).
+ */
+ if (base->evsel->dealloc != NULL)
+ base->evsel->dealloc(base);
+ base->evbase = evsel->init(base);
+ if (base->evbase == NULL) {
+ event_errx(1,
+ "%s: could not reinitialize event mechanism",
+ __func__);
+ res = -1;
+ goto done;
+ }
+
+ /* Empty out the changelist (if any): we are starting from a
+ * blank slate. */
+ event_changelist_freemem_(&base->changelist);
+
+ /* Tell the event maps to re-inform the backend about all
+ * pending events. This will make the signal notification
+ * event get re-created if necessary. */
+ if (evmap_reinit_(base) < 0)
+ res = -1;
+ } else {
+ res = evsig_init_(base);
+ if (res == 0 && had_signal_added) {
+ res = event_add_nolock_(&base->sig.ev_signal, NULL, 0);
+ if (res == 0)
+ base->sig.ev_signal_added = 1;
+ }
+ }
+
+ /* If we were notifiable before, and nothing just exploded, become
+ * notifiable again. */
+ if (was_notifiable && res == 0)
+ res = evthread_make_base_notifiable_nolock_(base);
+
+done:
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return (res);
+}
+
+/* Get the monotonic time for this event_base' timer */
+int
+event_gettime_monotonic(struct event_base *base, struct timeval *tv)
+{
+ int rv = -1;
+
+ if (base && tv) {
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ rv = evutil_gettime_monotonic_(&(base->monotonic_timer), tv);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ }
+
+ return rv;
+}
+
+const char **
+event_get_supported_methods(void)
+{
+ static const char **methods = NULL;
+ const struct eventop **method;
+ const char **tmp;
+ int i = 0, k;
+
+ /* count all methods */
+ for (method = &eventops[0]; *method != NULL; ++method) {
+ ++i;
+ }
+
+ /* allocate one more than we need for the NULL pointer */
+ tmp = mm_calloc((i + 1), sizeof(char *));
+ if (tmp == NULL)
+ return (NULL);
+
+ /* populate the array with the supported methods */
+ for (k = 0, i = 0; eventops[k] != NULL; ++k) {
+ tmp[i++] = eventops[k]->name;
+ }
+ tmp[i] = NULL;
+
+ if (methods != NULL)
+ mm_free((char**)methods);
+
+ methods = tmp;
+
+ return (methods);
+}
+
+struct event_config *
+event_config_new(void)
+{
+ struct event_config *cfg = mm_calloc(1, sizeof(*cfg));
+
+ if (cfg == NULL)
+ return (NULL);
+
+ TAILQ_INIT(&cfg->entries);
+ cfg->max_dispatch_interval.tv_sec = -1;
+ cfg->max_dispatch_callbacks = INT_MAX;
+ cfg->limit_callbacks_after_prio = 1;
+
+ return (cfg);
+}
+
+static void
+event_config_entry_free(struct event_config_entry *entry)
+{
+ if (entry->avoid_method != NULL)
+ mm_free((char *)entry->avoid_method);
+ mm_free(entry);
+}
+
+void
+event_config_free(struct event_config *cfg)
+{
+ struct event_config_entry *entry;
+
+ while ((entry = TAILQ_FIRST(&cfg->entries)) != NULL) {
+ TAILQ_REMOVE(&cfg->entries, entry, next);
+ event_config_entry_free(entry);
+ }
+ mm_free(cfg);
+}
+
+int
+event_config_set_flag(struct event_config *cfg, int flag)
+{
+ if (!cfg)
+ return -1;
+ cfg->flags |= flag;
+ return 0;
+}
+
+int
+event_config_avoid_method(struct event_config *cfg, const char *method)
+{
+ struct event_config_entry *entry = mm_malloc(sizeof(*entry));
+ if (entry == NULL)
+ return (-1);
+
+ if ((entry->avoid_method = mm_strdup(method)) == NULL) {
+ mm_free(entry);
+ return (-1);
+ }
+
+ TAILQ_INSERT_TAIL(&cfg->entries, entry, next);
+
+ return (0);
+}
+
+int
+event_config_require_features(struct event_config *cfg,
+ int features)
+{
+ if (!cfg)
+ return (-1);
+ cfg->require_features = features;
+ return (0);
+}
+
+int
+event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)
+{
+ if (!cfg)
+ return (-1);
+ cfg->n_cpus_hint = cpus;
+ return (0);
+}
+
+int
+event_config_set_max_dispatch_interval(struct event_config *cfg,
+ const struct timeval *max_interval, int max_callbacks, int min_priority)
+{
+ if (max_interval)
+ memcpy(&cfg->max_dispatch_interval, max_interval,
+ sizeof(struct timeval));
+ else
+ cfg->max_dispatch_interval.tv_sec = -1;
+ cfg->max_dispatch_callbacks =
+ max_callbacks >= 0 ? max_callbacks : INT_MAX;
+ if (min_priority < 0)
+ min_priority = 0;
+ cfg->limit_callbacks_after_prio = min_priority;
+ return (0);
+}
+
+int
+event_priority_init(int npriorities)
+{
+ return event_base_priority_init(current_base, npriorities);
+}
+
+int
+event_base_priority_init(struct event_base *base, int npriorities)
+{
+ int i, r;
+ r = -1;
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ if (N_ACTIVE_CALLBACKS(base) || npriorities < 1
+ || npriorities >= EVENT_MAX_PRIORITIES)
+ goto err;
+
+ if (npriorities == base->nactivequeues)
+ goto ok;
+
+ if (base->nactivequeues) {
+ mm_free(base->activequeues);
+ base->nactivequeues = 0;
+ }
+
+ /* Allocate our priority queues */
+ base->activequeues = (struct evcallback_list *)
+ mm_calloc(npriorities, sizeof(struct evcallback_list));
+ if (base->activequeues == NULL) {
+ event_warn("%s: calloc", __func__);
+ goto err;
+ }
+ base->nactivequeues = npriorities;
+
+ for (i = 0; i < base->nactivequeues; ++i) {
+ TAILQ_INIT(&base->activequeues[i]);
+ }
+
+ok:
+ r = 0;
+err:
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return (r);
+}
+
+int
+event_base_get_npriorities(struct event_base *base)
+{
+
+ int n;
+ if (base == NULL)
+ base = current_base;
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ n = base->nactivequeues;
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return (n);
+}
+
+int
+event_base_get_num_events(struct event_base *base, unsigned int type)
+{
+ int r = 0;
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ if (type & EVENT_BASE_COUNT_ACTIVE)
+ r += base->event_count_active;
+
+ if (type & EVENT_BASE_COUNT_VIRTUAL)
+ r += base->virtual_event_count;
+
+ if (type & EVENT_BASE_COUNT_ADDED)
+ r += base->event_count;
+
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ return r;
+}
+
+int
+event_base_get_max_events(struct event_base *base, unsigned int type, int clear)
+{
+ int r = 0;
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ if (type & EVENT_BASE_COUNT_ACTIVE) {
+ r += base->event_count_active_max;
+ if (clear)
+ base->event_count_active_max = 0;
+ }
+
+ if (type & EVENT_BASE_COUNT_VIRTUAL) {
+ r += base->virtual_event_count_max;
+ if (clear)
+ base->virtual_event_count_max = 0;
+ }
+
+ if (type & EVENT_BASE_COUNT_ADDED) {
+ r += base->event_count_max;
+ if (clear)
+ base->event_count_max = 0;
+ }
+
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ return r;
+}
+
+/* Returns true iff we're currently watching any events. */
+static int
+event_haveevents(struct event_base *base)
+{
+ /* Caller must hold th_base_lock */
+ return (base->virtual_event_count > 0 || base->event_count > 0);
+}
+
+/* "closure" function called when processing active signal events */
+static inline void
+event_signal_closure(struct event_base *base, struct event *ev)
+{
+ short ncalls;
+ int should_break;
+
+ /* Allows deletes to work */
+ ncalls = ev->ev_ncalls;
+ if (ncalls != 0)
+ ev->ev_pncalls = &ncalls;
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ while (ncalls) {
+ ncalls--;
+ ev->ev_ncalls = ncalls;
+ if (ncalls == 0)
+ ev->ev_pncalls = NULL;
+ (*ev->ev_callback)(ev->ev_fd, ev->ev_res, ev->ev_arg);
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ should_break = base->event_break;
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ if (should_break) {
+ if (ncalls != 0)
+ ev->ev_pncalls = NULL;
+ return;
+ }
+ }
+}
+
+/* Common timeouts are special timeouts that are handled as queues rather than
+ * in the minheap. This is more efficient than the minheap if we happen to
+ * know that we're going to get several thousands of timeout events all with
+ * the same timeout value.
+ *
+ * Since all our timeout handling code assumes timevals can be copied,
+ * assigned, etc, we can't use "magic pointer" to encode these common
+ * timeouts. Searching through a list to see if every timeout is common could
+ * also get inefficient. Instead, we take advantage of the fact that tv_usec
+ * is 32 bits long, but only uses 20 of those bits (since it can never be over
+ * 999999.) We use the top bits to encode 4 bites of magic number, and 8 bits
+ * of index into the event_base's aray of common timeouts.
+ */
+
+#define MICROSECONDS_MASK COMMON_TIMEOUT_MICROSECONDS_MASK
+#define COMMON_TIMEOUT_IDX_MASK 0x0ff00000
+#define COMMON_TIMEOUT_IDX_SHIFT 20
+#define COMMON_TIMEOUT_MASK 0xf0000000
+#define COMMON_TIMEOUT_MAGIC 0x50000000
+
+#define COMMON_TIMEOUT_IDX(tv) \
+ (((tv)->tv_usec & COMMON_TIMEOUT_IDX_MASK)>>COMMON_TIMEOUT_IDX_SHIFT)
+
+/** Return true iff if 'tv' is a common timeout in 'base' */
+static inline int
+is_common_timeout(const struct timeval *tv,
+ const struct event_base *base)
+{
+ int idx;
+ if ((tv->tv_usec & COMMON_TIMEOUT_MASK) != COMMON_TIMEOUT_MAGIC)
+ return 0;
+ idx = COMMON_TIMEOUT_IDX(tv);
+ return idx < base->n_common_timeouts;
+}
+
+/* True iff tv1 and tv2 have the same common-timeout index, or if neither
+ * one is a common timeout. */
+static inline int
+is_same_common_timeout(const struct timeval *tv1, const struct timeval *tv2)
+{
+ return (tv1->tv_usec & ~MICROSECONDS_MASK) ==
+ (tv2->tv_usec & ~MICROSECONDS_MASK);
+}
+
+/** Requires that 'tv' is a common timeout. Return the corresponding
+ * common_timeout_list. */
+static inline struct common_timeout_list *
+get_common_timeout_list(struct event_base *base, const struct timeval *tv)
+{
+ return base->common_timeout_queues[COMMON_TIMEOUT_IDX(tv)];
+}
+
+#if 0
+static inline int
+common_timeout_ok(const struct timeval *tv,
+ struct event_base *base)
+{
+ const struct timeval *expect =
+ &get_common_timeout_list(base, tv)->duration;
+ return tv->tv_sec == expect->tv_sec &&
+ tv->tv_usec == expect->tv_usec;
+}
+#endif
+
+/* Add the timeout for the first event in given common timeout list to the
+ * event_base's minheap. */
+static void
+common_timeout_schedule(struct common_timeout_list *ctl,
+ const struct timeval *now, struct event *head)
+{
+ struct timeval timeout = head->ev_timeout;
+ timeout.tv_usec &= MICROSECONDS_MASK;
+ event_add_nolock_(&ctl->timeout_event, &timeout, 1);
+}
+
+/* Callback: invoked when the timeout for a common timeout queue triggers.
+ * This means that (at least) the first event in that queue should be run,
+ * and the timeout should be rescheduled if there are more events. */
+static void
+common_timeout_callback(evutil_socket_t fd, short what, void *arg)
+{
+ struct timeval now;
+ struct common_timeout_list *ctl = arg;
+ struct event_base *base = ctl->base;
+ struct event *ev = NULL;
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ gettime(base, &now);
+ while (1) {
+ ev = TAILQ_FIRST(&ctl->events);
+ if (!ev || ev->ev_timeout.tv_sec > now.tv_sec ||
+ (ev->ev_timeout.tv_sec == now.tv_sec &&
+ (ev->ev_timeout.tv_usec&MICROSECONDS_MASK) > now.tv_usec))
+ break;
+ event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
+ event_active_nolock_(ev, EV_TIMEOUT, 1);
+ }
+ if (ev)
+ common_timeout_schedule(ctl, &now, ev);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
+
+#define MAX_COMMON_TIMEOUTS 256
+
+const struct timeval *
+event_base_init_common_timeout(struct event_base *base,
+ const struct timeval *duration)
+{
+ int i;
+ struct timeval tv;
+ const struct timeval *result=NULL;
+ struct common_timeout_list *new_ctl;
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ if (duration->tv_usec > 1000000) {
+ memcpy(&tv, duration, sizeof(struct timeval));
+ if (is_common_timeout(duration, base))
+ tv.tv_usec &= MICROSECONDS_MASK;
+ tv.tv_sec += tv.tv_usec / 1000000;
+ tv.tv_usec %= 1000000;
+ duration = &tv;
+ }
+ for (i = 0; i < base->n_common_timeouts; ++i) {
+ const struct common_timeout_list *ctl =
+ base->common_timeout_queues[i];
+ if (duration->tv_sec == ctl->duration.tv_sec &&
+ duration->tv_usec ==
+ (ctl->duration.tv_usec & MICROSECONDS_MASK)) {
+ EVUTIL_ASSERT(is_common_timeout(&ctl->duration, base));
+ result = &ctl->duration;
+ goto done;
+ }
+ }
+ if (base->n_common_timeouts == MAX_COMMON_TIMEOUTS) {
+ event_warnx("%s: Too many common timeouts already in use; "
+ "we only support %d per event_base", __func__,
+ MAX_COMMON_TIMEOUTS);
+ goto done;
+ }
+ if (base->n_common_timeouts_allocated == base->n_common_timeouts) {
+ int n = base->n_common_timeouts < 16 ? 16 :
+ base->n_common_timeouts*2;
+ struct common_timeout_list **newqueues =
+ mm_realloc(base->common_timeout_queues,
+ n*sizeof(struct common_timeout_queue *));
+ if (!newqueues) {
+ event_warn("%s: realloc",__func__);
+ goto done;
+ }
+ base->n_common_timeouts_allocated = n;
+ base->common_timeout_queues = newqueues;
+ }
+ new_ctl = mm_calloc(1, sizeof(struct common_timeout_list));
+ if (!new_ctl) {
+ event_warn("%s: calloc",__func__);
+ goto done;
+ }
+ TAILQ_INIT(&new_ctl->events);
+ new_ctl->duration.tv_sec = duration->tv_sec;
+ new_ctl->duration.tv_usec =
+ duration->tv_usec | COMMON_TIMEOUT_MAGIC |
+ (base->n_common_timeouts << COMMON_TIMEOUT_IDX_SHIFT);
+ evtimer_assign(&new_ctl->timeout_event, base,
+ common_timeout_callback, new_ctl);
+ new_ctl->timeout_event.ev_flags |= EVLIST_INTERNAL;
+ event_priority_set(&new_ctl->timeout_event, 0);
+ new_ctl->base = base;
+ base->common_timeout_queues[base->n_common_timeouts++] = new_ctl;
+ result = &new_ctl->duration;
+
+done:
+ if (result)
+ EVUTIL_ASSERT(is_common_timeout(result, base));
+
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return result;
+}
+
+/* Closure function invoked when we're activating a persistent event. */
+static inline void
+event_persist_closure(struct event_base *base, struct event *ev)
+{
+ void (*evcb_callback)(evutil_socket_t, short, void *);
+
+ // Other fields of *ev that must be stored before executing
+ evutil_socket_t evcb_fd;
+ short evcb_res;
+ void *evcb_arg;
+
+ /* reschedule the persistent event if we have a timeout. */
+ if (ev->ev_io_timeout.tv_sec || ev->ev_io_timeout.tv_usec) {
+ /* If there was a timeout, we want it to run at an interval of
+ * ev_io_timeout after the last time it was _scheduled_ for,
+ * not ev_io_timeout after _now_. If it fired for another
+ * reason, though, the timeout ought to start ticking _now_. */
+ struct timeval run_at, relative_to, delay, now;
+ ev_uint32_t usec_mask = 0;
+ EVUTIL_ASSERT(is_same_common_timeout(&ev->ev_timeout,
+ &ev->ev_io_timeout));
+ gettime(base, &now);
+ if (is_common_timeout(&ev->ev_timeout, base)) {
+ delay = ev->ev_io_timeout;
+ usec_mask = delay.tv_usec & ~MICROSECONDS_MASK;
+ delay.tv_usec &= MICROSECONDS_MASK;
+ if (ev->ev_res & EV_TIMEOUT) {
+ relative_to = ev->ev_timeout;
+ relative_to.tv_usec &= MICROSECONDS_MASK;
+ } else {
+ relative_to = now;
+ }
+ } else {
+ delay = ev->ev_io_timeout;
+ if (ev->ev_res & EV_TIMEOUT) {
+ relative_to = ev->ev_timeout;
+ } else {
+ relative_to = now;
+ }
+ }
+ evutil_timeradd(&relative_to, &delay, &run_at);
+ if (evutil_timercmp(&run_at, &now, <)) {
+ /* Looks like we missed at least one invocation due to
+ * a clock jump, not running the event loop for a
+ * while, really slow callbacks, or
+ * something. Reschedule relative to now.
+ */
+ evutil_timeradd(&now, &delay, &run_at);
+ }
+ run_at.tv_usec |= usec_mask;
+ event_add_nolock_(ev, &run_at, 1);
+ }
+
+ // Save our callback before we release the lock
+ evcb_callback = ev->ev_callback;
+ evcb_fd = ev->ev_fd;
+ evcb_res = ev->ev_res;
+ evcb_arg = ev->ev_arg;
+
+ // Release the lock
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ // Execute the callback
+ (evcb_callback)(evcb_fd, evcb_res, evcb_arg);
+}
+
+/*
+ Helper for event_process_active to process all the events in a single queue,
+ releasing the lock as we go. This function requires that the lock be held
+ when it's invoked. Returns -1 if we get a signal or an event_break that
+ means we should stop processing any active events now. Otherwise returns
+ the number of non-internal event_callbacks that we processed.
+*/
+static int
+event_process_active_single_queue(struct event_base *base,
+ struct evcallback_list *activeq,
+ int max_to_process, const struct timeval *endtime)
+{
+ struct event_callback *evcb;
+ int count = 0;
+
+ EVUTIL_ASSERT(activeq != NULL);
+
+ for (evcb = TAILQ_FIRST(activeq); evcb; evcb = TAILQ_FIRST(activeq)) {
+ struct event *ev=NULL;
+ if (evcb->evcb_flags & EVLIST_INIT) {
+ ev = event_callback_to_event(evcb);
+
+ if (ev->ev_events & EV_PERSIST || ev->ev_flags & EVLIST_FINALIZING)
+ event_queue_remove_active(base, evcb);
+ else
+ event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
+ event_debug((
+ "event_process_active: event: %p, %s%s%scall %p",
+ ev,
+ ev->ev_res & EV_READ ? "EV_READ " : " ",
+ ev->ev_res & EV_WRITE ? "EV_WRITE " : " ",
+ ev->ev_res & EV_CLOSED ? "EV_CLOSED " : " ",
+ ev->ev_callback));
+ } else {
+ event_queue_remove_active(base, evcb);
+ event_debug(("event_process_active: event_callback %p, "
+ "closure %d, call %p",
+ evcb, evcb->evcb_closure, evcb->evcb_cb_union.evcb_callback));
+ }
+
+ if (!(evcb->evcb_flags & EVLIST_INTERNAL))
+ ++count;
+
+
+ base->current_event = evcb;
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ base->current_event_waiters = 0;
+#endif
+
+ switch (evcb->evcb_closure) {
+ case EV_CLOSURE_EVENT_SIGNAL:
+ EVUTIL_ASSERT(ev != NULL);
+ event_signal_closure(base, ev);
+ break;
+ case EV_CLOSURE_EVENT_PERSIST:
+ EVUTIL_ASSERT(ev != NULL);
+ event_persist_closure(base, ev);
+ break;
+ case EV_CLOSURE_EVENT: {
+ void (*evcb_callback)(evutil_socket_t, short, void *);
+ EVUTIL_ASSERT(ev != NULL);
+ evcb_callback = *ev->ev_callback;
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ evcb_callback(ev->ev_fd, ev->ev_res, ev->ev_arg);
+ }
+ break;
+ case EV_CLOSURE_CB_SELF: {
+ void (*evcb_selfcb)(struct event_callback *, void *) = evcb->evcb_cb_union.evcb_selfcb;
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ evcb_selfcb(evcb, evcb->evcb_arg);
+ }
+ break;
+ case EV_CLOSURE_EVENT_FINALIZE:
+ case EV_CLOSURE_EVENT_FINALIZE_FREE: {
+ void (*evcb_evfinalize)(struct event *, void *);
+ int evcb_closure = evcb->evcb_closure;
+ EVUTIL_ASSERT(ev != NULL);
+ base->current_event = NULL;
+ evcb_evfinalize = ev->ev_evcallback.evcb_cb_union.evcb_evfinalize;
+ EVUTIL_ASSERT((evcb->evcb_flags & EVLIST_FINALIZING));
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ evcb_evfinalize(ev, ev->ev_arg);
+ event_debug_note_teardown_(ev);
+ if (evcb_closure == EV_CLOSURE_EVENT_FINALIZE_FREE)
+ mm_free(ev);
+ }
+ break;
+ case EV_CLOSURE_CB_FINALIZE: {
+ void (*evcb_cbfinalize)(struct event_callback *, void *) = evcb->evcb_cb_union.evcb_cbfinalize;
+ base->current_event = NULL;
+ EVUTIL_ASSERT((evcb->evcb_flags & EVLIST_FINALIZING));
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ evcb_cbfinalize(evcb, evcb->evcb_arg);
+ }
+ break;
+ default:
+ EVUTIL_ASSERT(0);
+ }
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ base->current_event = NULL;
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ if (base->current_event_waiters) {
+ base->current_event_waiters = 0;
+ EVTHREAD_COND_BROADCAST(base->current_event_cond);
+ }
+#endif
+
+ if (base->event_break)
+ return -1;
+ if (count >= max_to_process)
+ return count;
+ if (count && endtime) {
+ struct timeval now;
+ update_time_cache(base);
+ gettime(base, &now);
+ if (evutil_timercmp(&now, endtime, >=))
+ return count;
+ }
+ if (base->event_continue)
+ break;
+ }
+ return count;
+}
+
+/*
+ * Active events are stored in priority queues. Lower priorities are always
+ * process before higher priorities. Low priority events can starve high
+ * priority ones.
+ */
+
+static int
+event_process_active(struct event_base *base)
+{
+ /* Caller must hold th_base_lock */
+ struct evcallback_list *activeq = NULL;
+ int i, c = 0;
+ const struct timeval *endtime;
+ struct timeval tv;
+ const int maxcb = base->max_dispatch_callbacks;
+ const int limit_after_prio = base->limit_callbacks_after_prio;
+ if (base->max_dispatch_time.tv_sec >= 0) {
+ update_time_cache(base);
+ gettime(base, &tv);
+ evutil_timeradd(&base->max_dispatch_time, &tv, &tv);
+ endtime = &tv;
+ } else {
+ endtime = NULL;
+ }
+
+ for (i = 0; i < base->nactivequeues; ++i) {
+ if (TAILQ_FIRST(&base->activequeues[i]) != NULL) {
+ base->event_running_priority = i;
+ activeq = &base->activequeues[i];
+ if (i < limit_after_prio)
+ c = event_process_active_single_queue(base, activeq,
+ INT_MAX, NULL);
+ else
+ c = event_process_active_single_queue(base, activeq,
+ maxcb, endtime);
+ if (c < 0) {
+ goto done;
+ } else if (c > 0)
+ break; /* Processed a real event; do not
+ * consider lower-priority events */
+ /* If we get here, all of the events we processed
+ * were internal. Continue. */
+ }
+ }
+
+done:
+ base->event_running_priority = -1;
+
+ return c;
+}
+
+/*
+ * Wait continuously for events. We exit only if no events are left.
+ */
+
+int
+event_dispatch(void)
+{
+ return (event_loop(0));
+}
+
+int
+event_base_dispatch(struct event_base *event_base)
+{
+ return (event_base_loop(event_base, 0));
+}
+
+const char *
+event_base_get_method(const struct event_base *base)
+{
+ EVUTIL_ASSERT(base);
+ return (base->evsel->name);
+}
+
+/** Callback: used to implement event_base_loopexit by telling the event_base
+ * that it's time to exit its loop. */
+static void
+event_loopexit_cb(evutil_socket_t fd, short what, void *arg)
+{
+ struct event_base *base = arg;
+ base->event_gotterm = 1;
+}
+
+int
+event_loopexit(const struct timeval *tv)
+{
+ return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
+ current_base, tv));
+}
+
+int
+event_base_loopexit(struct event_base *event_base, const struct timeval *tv)
+{
+ return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb,
+ event_base, tv));
+}
+
+int
+event_loopbreak(void)
+{
+ return (event_base_loopbreak(current_base));
+}
+
+int
+event_base_loopbreak(struct event_base *event_base)
+{
+ int r = 0;
+ if (event_base == NULL)
+ return (-1);
+
+ EVBASE_ACQUIRE_LOCK(event_base, th_base_lock);
+ event_base->event_break = 1;
+
+ if (EVBASE_NEED_NOTIFY(event_base)) {
+ r = evthread_notify_base(event_base);
+ } else {
+ r = (0);
+ }
+ EVBASE_RELEASE_LOCK(event_base, th_base_lock);
+ return r;
+}
+
+int
+event_base_loopcontinue(struct event_base *event_base)
+{
+ int r = 0;
+ if (event_base == NULL)
+ return (-1);
+
+ EVBASE_ACQUIRE_LOCK(event_base, th_base_lock);
+ event_base->event_continue = 1;
+
+ if (EVBASE_NEED_NOTIFY(event_base)) {
+ r = evthread_notify_base(event_base);
+ } else {
+ r = (0);
+ }
+ EVBASE_RELEASE_LOCK(event_base, th_base_lock);
+ return r;
+}
+
+int
+event_base_got_break(struct event_base *event_base)
+{
+ int res;
+ EVBASE_ACQUIRE_LOCK(event_base, th_base_lock);
+ res = event_base->event_break;
+ EVBASE_RELEASE_LOCK(event_base, th_base_lock);
+ return res;
+}
+
+int
+event_base_got_exit(struct event_base *event_base)
+{
+ int res;
+ EVBASE_ACQUIRE_LOCK(event_base, th_base_lock);
+ res = event_base->event_gotterm;
+ EVBASE_RELEASE_LOCK(event_base, th_base_lock);
+ return res;
+}
+
+/* not thread safe */
+
+int
+event_loop(int flags)
+{
+ return event_base_loop(current_base, flags);
+}
+
+int
+event_base_loop(struct event_base *base, int flags)
+{
+ const struct eventop *evsel = base->evsel;
+ struct timeval tv;
+ struct timeval *tv_p;
+ int res, done, retval = 0;
+
+ /* Grab the lock. We will release it inside evsel.dispatch, and again
+ * as we invoke user callbacks. */
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ if (base->running_loop) {
+ event_warnx("%s: reentrant invocation. Only one event_base_loop"
+ " can run on each event_base at once.", __func__);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return -1;
+ }
+
+ base->running_loop = 1;
+
+ clear_time_cache(base);
+
+ if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)
+ evsig_set_base_(base);
+
+ done = 0;
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ base->th_owner_id = EVTHREAD_GET_ID();
+#endif
+
+ base->event_gotterm = base->event_break = 0;
+
+ while (!done) {
+ base->event_continue = 0;
+ base->n_deferreds_queued = 0;
+
+ /* Terminate the loop if we have been asked to */
+ if (base->event_gotterm) {
+ break;
+ }
+
+ if (base->event_break) {
+ break;
+ }
+
+ tv_p = &tv;
+ if (!N_ACTIVE_CALLBACKS(base) && !(flags & EVLOOP_NONBLOCK)) {
+ timeout_next(base, &tv_p);
+ } else {
+ /*
+ * if we have active events, we just poll new events
+ * without waiting.
+ */
+ evutil_timerclear(&tv);
+ }
+
+ /* If we have no events, we just exit */
+ if (0==(flags&EVLOOP_NO_EXIT_ON_EMPTY) &&
+ !event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {
+ event_debug(("%s: no events registered.", __func__));
+ retval = 1;
+ goto done;
+ }
+
+ event_queue_make_later_events_active(base);
+
+ clear_time_cache(base);
+
+ res = evsel->dispatch(base, tv_p);
+
+ if (res == -1) {
+ event_debug(("%s: dispatch returned unsuccessfully.",
+ __func__));
+ retval = -1;
+ goto done;
+ }
+
+ update_time_cache(base);
+
+ timeout_process(base);
+
+ if (N_ACTIVE_CALLBACKS(base)) {
+ int n = event_process_active(base);
+ if ((flags & EVLOOP_ONCE)
+ && N_ACTIVE_CALLBACKS(base) == 0
+ && n != 0)
+ done = 1;
+ } else if (flags & EVLOOP_NONBLOCK)
+ done = 1;
+ }
+ event_debug(("%s: asked to terminate loop.", __func__));
+
+done:
+ clear_time_cache(base);
+ base->running_loop = 0;
+
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ return (retval);
+}
+
+/* One-time callback to implement event_base_once: invokes the user callback,
+ * then deletes the allocated storage */
+static void
+event_once_cb(evutil_socket_t fd, short events, void *arg)
+{
+ struct event_once *eonce = arg;
+
+ (*eonce->cb)(fd, events, eonce->arg);
+ EVBASE_ACQUIRE_LOCK(eonce->ev.ev_base, th_base_lock);
+ LIST_REMOVE(eonce, next_once);
+ EVBASE_RELEASE_LOCK(eonce->ev.ev_base, th_base_lock);
+ event_debug_unassign(&eonce->ev);
+ mm_free(eonce);
+}
+
+/* not threadsafe, event scheduled once. */
+int
+event_once(evutil_socket_t fd, short events,
+ void (*callback)(evutil_socket_t, short, void *),
+ void *arg, const struct timeval *tv)
+{
+ return event_base_once(current_base, fd, events, callback, arg, tv);
+}
+
+/* Schedules an event once */
+int
+event_base_once(struct event_base *base, evutil_socket_t fd, short events,
+ void (*callback)(evutil_socket_t, short, void *),
+ void *arg, const struct timeval *tv)
+{
+ struct event_once *eonce;
+ int res = 0;
+ int activate = 0;
+
+ /* We cannot support signals that just fire once, or persistent
+ * events. */
+ if (events & (EV_SIGNAL|EV_PERSIST))
+ return (-1);
+
+ if ((eonce = mm_calloc(1, sizeof(struct event_once))) == NULL)
+ return (-1);
+
+ eonce->cb = callback;
+ eonce->arg = arg;
+
+ if ((events & (EV_TIMEOUT|EV_SIGNAL|EV_READ|EV_WRITE|EV_CLOSED)) == EV_TIMEOUT) {
+ evtimer_assign(&eonce->ev, base, event_once_cb, eonce);
+
+ if (tv == NULL || ! evutil_timerisset(tv)) {
+ /* If the event is going to become active immediately,
+ * don't put it on the timeout queue. This is one
+ * idiom for scheduling a callback, so let's make
+ * it fast (and order-preserving). */
+ activate = 1;
+ }
+ } else if (events & (EV_READ|EV_WRITE|EV_CLOSED)) {
+ events &= EV_READ|EV_WRITE|EV_CLOSED;
+
+ event_assign(&eonce->ev, base, fd, events, event_once_cb, eonce);
+ } else {
+ /* Bad event combination */
+ mm_free(eonce);
+ return (-1);
+ }
+
+ if (res == 0) {
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ if (activate)
+ event_active_nolock_(&eonce->ev, EV_TIMEOUT, 1);
+ else
+ res = event_add_nolock_(&eonce->ev, tv, 0);
+
+ if (res != 0) {
+ mm_free(eonce);
+ return (res);
+ } else {
+ LIST_INSERT_HEAD(&base->once_events, eonce, next_once);
+ }
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ }
+
+ return (0);
+}
+
+int
+event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)
+{
+ if (!base)
+ base = current_base;
+ if (arg == &event_self_cbarg_ptr_)
+ arg = ev;
+
+ event_debug_assert_not_added_(ev);
+
+ ev->ev_base = base;
+
+ ev->ev_callback = callback;
+ ev->ev_arg = arg;
+ ev->ev_fd = fd;
+ ev->ev_events = events;
+ ev->ev_res = 0;
+ ev->ev_flags = EVLIST_INIT;
+ ev->ev_ncalls = 0;
+ ev->ev_pncalls = NULL;
+
+ if (events & EV_SIGNAL) {
+ if ((events & (EV_READ|EV_WRITE|EV_CLOSED)) != 0) {
+ event_warnx("%s: EV_SIGNAL is not compatible with "
+ "EV_READ, EV_WRITE or EV_CLOSED", __func__);
+ return -1;
+ }
+ ev->ev_closure = EV_CLOSURE_EVENT_SIGNAL;
+ } else {
+ if (events & EV_PERSIST) {
+ evutil_timerclear(&ev->ev_io_timeout);
+ ev->ev_closure = EV_CLOSURE_EVENT_PERSIST;
+ } else {
+ ev->ev_closure = EV_CLOSURE_EVENT;
+ }
+ }
+
+ min_heap_elem_init_(ev);
+
+ if (base != NULL) {
+ /* by default, we put new events into the middle priority */
+ ev->ev_pri = base->nactivequeues / 2;
+ }
+
+ event_debug_note_setup_(ev);
+
+ return 0;
+}
+
+int
+event_base_set(struct event_base *base, struct event *ev)
+{
+ /* Only innocent events may be assigned to a different base */
+ if (ev->ev_flags != EVLIST_INIT)
+ return (-1);
+
+ event_debug_assert_is_setup_(ev);
+
+ ev->ev_base = base;
+ ev->ev_pri = base->nactivequeues/2;
+
+ return (0);
+}
+
+void
+event_set(struct event *ev, evutil_socket_t fd, short events,
+ void (*callback)(evutil_socket_t, short, void *), void *arg)
+{
+ int r;
+ r = event_assign(ev, current_base, fd, events, callback, arg);
+ EVUTIL_ASSERT(r == 0);
+}
+
+void *
+event_self_cbarg(void)
+{
+ return &event_self_cbarg_ptr_;
+}
+
+struct event *
+event_base_get_running_event(struct event_base *base)
+{
+ struct event *ev = NULL;
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ if (EVBASE_IN_THREAD(base)) {
+ struct event_callback *evcb = base->current_event;
+ if (evcb->evcb_flags & EVLIST_INIT)
+ ev = event_callback_to_event(evcb);
+ }
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return ev;
+}
+
+struct event *
+event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg)
+{
+ struct event *ev;
+ ev = mm_malloc(sizeof(struct event));
+ if (ev == NULL)
+ return (NULL);
+ if (event_assign(ev, base, fd, events, cb, arg) < 0) {
+ mm_free(ev);
+ return (NULL);
+ }
+
+ return (ev);
+}
+
+void
+event_free(struct event *ev)
+{
+ /* This is disabled, so that events which have been finalized be a
+ * valid target for event_free(). That's */
+ // event_debug_assert_is_setup_(ev);
+
+ /* make sure that this event won't be coming back to haunt us. */
+ event_del(ev);
+ event_debug_note_teardown_(ev);
+ mm_free(ev);
+
+}
+
+void
+event_debug_unassign(struct event *ev)
+{
+ event_debug_assert_not_added_(ev);
+ event_debug_note_teardown_(ev);
+
+ ev->ev_flags &= ~EVLIST_INIT;
+}
+
+#define EVENT_FINALIZE_FREE_ 0x10000
+static int
+event_finalize_nolock_(struct event_base *base, unsigned flags, struct event *ev, event_finalize_callback_fn cb)
+{
+ ev_uint8_t closure = (flags & EVENT_FINALIZE_FREE_) ?
+ EV_CLOSURE_EVENT_FINALIZE_FREE : EV_CLOSURE_EVENT_FINALIZE;
+
+ event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
+ ev->ev_closure = closure;
+ ev->ev_evcallback.evcb_cb_union.evcb_evfinalize = cb;
+ event_active_nolock_(ev, EV_FINALIZE, 1);
+ ev->ev_flags |= EVLIST_FINALIZING;
+ return 0;
+}
+
+static int
+event_finalize_impl_(unsigned flags, struct event *ev, event_finalize_callback_fn cb)
+{
+ int r;
+ struct event_base *base = ev->ev_base;
+ if (EVUTIL_FAILURE_CHECK(!base)) {
+ event_warnx("%s: event has no event_base set.", __func__);
+ return -1;
+ }
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ r = event_finalize_nolock_(base, flags, ev, cb);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return r;
+}
+
+int
+event_finalize(unsigned flags, struct event *ev, event_finalize_callback_fn cb)
+{
+ return event_finalize_impl_(flags, ev, cb);
+}
+
+int
+event_free_finalize(unsigned flags, struct event *ev, event_finalize_callback_fn cb)
+{
+ return event_finalize_impl_(flags|EVENT_FINALIZE_FREE_, ev, cb);
+}
+
+void
+event_callback_finalize_nolock_(struct event_base *base, unsigned flags, struct event_callback *evcb, void (*cb)(struct event_callback *, void *))
+{
+ struct event *ev = NULL;
+ if (evcb->evcb_flags & EVLIST_INIT) {
+ ev = event_callback_to_event(evcb);
+ event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
+ } else {
+ event_callback_cancel_nolock_(base, evcb, 0); /*XXX can this fail?*/
+ }
+
+ evcb->evcb_closure = EV_CLOSURE_CB_FINALIZE;
+ evcb->evcb_cb_union.evcb_cbfinalize = cb;
+ event_callback_activate_nolock_(base, evcb); /* XXX can this really fail?*/
+ evcb->evcb_flags |= EVLIST_FINALIZING;
+}
+
+void
+event_callback_finalize_(struct event_base *base, unsigned flags, struct event_callback *evcb, void (*cb)(struct event_callback *, void *))
+{
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ event_callback_finalize_nolock_(base, flags, evcb, cb);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
+
+/** Internal: Finalize all of the n_cbs callbacks in evcbs. The provided
+ * callback will be invoked on *one of them*, after they have *all* been
+ * finalized. */
+int
+event_callback_finalize_many_(struct event_base *base, int n_cbs, struct event_callback **evcbs, void (*cb)(struct event_callback *, void *))
+{
+ int n_pending = 0, i;
+
+ if (base == NULL)
+ base = current_base;
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ event_debug(("%s: %d events finalizing", __func__, n_cbs));
+
+ /* At most one can be currently executing; the rest we just
+ * cancel... But we always make sure that the finalize callback
+ * runs. */
+ for (i = 0; i < n_cbs; ++i) {
+ struct event_callback *evcb = evcbs[i];
+ if (evcb == base->current_event) {
+ event_callback_finalize_nolock_(base, 0, evcb, cb);
+ ++n_pending;
+ } else {
+ event_callback_cancel_nolock_(base, evcb, 0);
+ }
+ }
+
+ if (n_pending == 0) {
+ /* Just do the first one. */
+ event_callback_finalize_nolock_(base, 0, evcbs[0], cb);
+ }
+
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return 0;
+}
+
+/*
+ * Set's the priority of an event - if an event is already scheduled
+ * changing the priority is going to fail.
+ */
+
+int
+event_priority_set(struct event *ev, int pri)
+{
+ event_debug_assert_is_setup_(ev);
+
+ if (ev->ev_flags & EVLIST_ACTIVE)
+ return (-1);
+ if (pri < 0 || pri >= ev->ev_base->nactivequeues)
+ return (-1);
+
+ ev->ev_pri = pri;
+
+ return (0);
+}
+
+/*
+ * Checks if a specific event is pending or scheduled.
+ */
+
+int
+event_pending(const struct event *ev, short event, struct timeval *tv)
+{
+ int flags = 0;
+
+ if (EVUTIL_FAILURE_CHECK(ev->ev_base == NULL)) {
+ event_warnx("%s: event has no event_base set.", __func__);
+ return 0;
+ }
+
+ EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
+ event_debug_assert_is_setup_(ev);
+
+ if (ev->ev_flags & EVLIST_INSERTED)
+ flags |= (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL));
+ if (ev->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))
+ flags |= ev->ev_res;
+ if (ev->ev_flags & EVLIST_TIMEOUT)
+ flags |= EV_TIMEOUT;
+
+ event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL);
+
+ /* See if there is a timeout that we should report */
+ if (tv != NULL && (flags & event & EV_TIMEOUT)) {
+ struct timeval tmp = ev->ev_timeout;
+ tmp.tv_usec &= MICROSECONDS_MASK;
+ /* correctly remamp to real time */
+ evutil_timeradd(&ev->ev_base->tv_clock_diff, &tmp, tv);
+ }
+
+ EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
+
+ return (flags & event);
+}
+
+int
+event_initialized(const struct event *ev)
+{
+ if (!(ev->ev_flags & EVLIST_INIT))
+ return 0;
+
+ return 1;
+}
+
+void
+event_get_assignment(const struct event *event, struct event_base **base_out, evutil_socket_t *fd_out, short *events_out, event_callback_fn *callback_out, void **arg_out)
+{
+ event_debug_assert_is_setup_(event);
+
+ if (base_out)
+ *base_out = event->ev_base;
+ if (fd_out)
+ *fd_out = event->ev_fd;
+ if (events_out)
+ *events_out = event->ev_events;
+ if (callback_out)
+ *callback_out = event->ev_callback;
+ if (arg_out)
+ *arg_out = event->ev_arg;
+}
+
+size_t
+event_get_struct_event_size(void)
+{
+ return sizeof(struct event);
+}
+
+evutil_socket_t
+event_get_fd(const struct event *ev)
+{
+ event_debug_assert_is_setup_(ev);
+ return ev->ev_fd;
+}
+
+struct event_base *
+event_get_base(const struct event *ev)
+{
+ event_debug_assert_is_setup_(ev);
+ return ev->ev_base;
+}
+
+short
+event_get_events(const struct event *ev)
+{
+ event_debug_assert_is_setup_(ev);
+ return ev->ev_events;
+}
+
+event_callback_fn
+event_get_callback(const struct event *ev)
+{
+ event_debug_assert_is_setup_(ev);
+ return ev->ev_callback;
+}
+
+void *
+event_get_callback_arg(const struct event *ev)
+{
+ event_debug_assert_is_setup_(ev);
+ return ev->ev_arg;
+}
+
+int
+event_get_priority(const struct event *ev)
+{
+ event_debug_assert_is_setup_(ev);
+ return ev->ev_pri;
+}
+
+int
+event_add(struct event *ev, const struct timeval *tv)
+{
+ int res;
+
+ if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
+ event_warnx("%s: event has no event_base set.", __func__);
+ return -1;
+ }
+
+ EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
+
+ res = event_add_nolock_(ev, tv, 0);
+
+ EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
+
+ return (res);
+}
+
+/* Helper callback: wake an event_base from another thread. This version
+ * works by writing a byte to one end of a socketpair, so that the event_base
+ * listening on the other end will wake up as the corresponding event
+ * triggers */
+static int
+evthread_notify_base_default(struct event_base *base)
+{
+ char buf[1];
+ int r;
+ buf[0] = (char) 0;
+#ifdef _WIN32
+ r = send(base->th_notify_fd[1], buf, 1, 0);
+#else
+ r = write(base->th_notify_fd[1], buf, 1);
+#endif
+ return (r < 0 && ! EVUTIL_ERR_IS_EAGAIN(errno)) ? -1 : 0;
+}
+
+#ifdef EVENT__HAVE_EVENTFD
+/* Helper callback: wake an event_base from another thread. This version
+ * assumes that you have a working eventfd() implementation. */
+static int
+evthread_notify_base_eventfd(struct event_base *base)
+{
+ ev_uint64_t msg = 1;
+ int r;
+ do {
+ r = write(base->th_notify_fd[0], (void*) &msg, sizeof(msg));
+ } while (r < 0 && errno == EAGAIN);
+
+ return (r < 0) ? -1 : 0;
+}
+#endif
+
+
+/** Tell the thread currently running the event_loop for base (if any) that it
+ * needs to stop waiting in its dispatch function (if it is) and process all
+ * active callbacks. */
+static int
+evthread_notify_base(struct event_base *base)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
+ if (!base->th_notify_fn)
+ return -1;
+ if (base->is_notify_pending)
+ return 0;
+ base->is_notify_pending = 1;
+ return base->th_notify_fn(base);
+}
+
+/* Implementation function to remove a timeout on a currently pending event.
+ */
+int
+event_remove_timer_nolock_(struct event *ev)
+{
+ struct event_base *base = ev->ev_base;
+
+ EVENT_BASE_ASSERT_LOCKED(base);
+ event_debug_assert_is_setup_(ev);
+
+ event_debug(("event_remove_timer_nolock: event: %p", ev));
+
+ /* If it's not pending on a timeout, we don't need to do anything. */
+ if (ev->ev_flags & EVLIST_TIMEOUT) {
+ event_queue_remove_timeout(base, ev);
+ evutil_timerclear(&ev->ev_.ev_io.ev_timeout);
+ }
+
+ return (0);
+}
+
+int
+event_remove_timer(struct event *ev)
+{
+ int res;
+
+ if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
+ event_warnx("%s: event has no event_base set.", __func__);
+ return -1;
+ }
+
+ EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
+
+ res = event_remove_timer_nolock_(ev);
+
+ EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
+
+ return (res);
+}
+
+/* Implementation function to add an event. Works just like event_add,
+ * except: 1) it requires that we have the lock. 2) if tv_is_absolute is set,
+ * we treat tv as an absolute time, not as an interval to add to the current
+ * time */
+int
+event_add_nolock_(struct event *ev, const struct timeval *tv,
+ int tv_is_absolute)
+{
+ struct event_base *base = ev->ev_base;
+ int res = 0;
+ int notify = 0;
+
+ EVENT_BASE_ASSERT_LOCKED(base);
+ event_debug_assert_is_setup_(ev);
+
+ event_debug((
+ "event_add: event: %p (fd "EV_SOCK_FMT"), %s%s%s%scall %p",
+ ev,
+ EV_SOCK_ARG(ev->ev_fd),
+ ev->ev_events & EV_READ ? "EV_READ " : " ",
+ ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
+ ev->ev_events & EV_CLOSED ? "EV_CLOSED " : " ",
+ tv ? "EV_TIMEOUT " : " ",
+ ev->ev_callback));
+
+ EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));
+
+ if (ev->ev_flags & EVLIST_FINALIZING) {
+ /* XXXX debug */
+ return (-1);
+ }
+
+ /*
+ * prepare for timeout insertion further below, if we get a
+ * failure on any step, we should not change any state.
+ */
+ if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
+ if (min_heap_reserve_(&base->timeheap,
+ 1 + min_heap_size_(&base->timeheap)) == -1)
+ return (-1); /* ENOMEM == errno */
+ }
+
+ /* If the main thread is currently executing a signal event's
+ * callback, and we are not the main thread, then we want to wait
+ * until the callback is done before we mess with the event, or else
+ * we can race on ev_ncalls and ev_pncalls below. */
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ if (base->current_event == event_to_event_callback(ev) &&
+ (ev->ev_events & EV_SIGNAL)
+ && !EVBASE_IN_THREAD(base)) {
+ ++base->current_event_waiters;
+ EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
+ }
+#endif
+
+ if ((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL)) &&
+ !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
+ if (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))
+ res = evmap_io_add_(base, ev->ev_fd, ev);
+ else if (ev->ev_events & EV_SIGNAL)
+ res = evmap_signal_add_(base, (int)ev->ev_fd, ev);
+ if (res != -1)
+ event_queue_insert_inserted(base, ev);
+ if (res == 1) {
+ /* evmap says we need to notify the main thread. */
+ notify = 1;
+ res = 0;
+ }
+ }
+
+ /*
+ * we should change the timeout state only if the previous event
+ * addition succeeded.
+ */
+ if (res != -1 && tv != NULL) {
+ struct timeval now;
+ int common_timeout;
+#ifdef USE_REINSERT_TIMEOUT
+ int was_common;
+ int old_timeout_idx;
+#endif
+
+ /*
+ * for persistent timeout events, we remember the
+ * timeout value and re-add the event.
+ *
+ * If tv_is_absolute, this was already set.
+ */
+ if (ev->ev_closure == EV_CLOSURE_EVENT_PERSIST && !tv_is_absolute)
+ ev->ev_io_timeout = *tv;
+
+#ifndef USE_REINSERT_TIMEOUT
+ if (ev->ev_flags & EVLIST_TIMEOUT) {
+ event_queue_remove_timeout(base, ev);
+ }
+#endif
+
+ /* Check if it is active due to a timeout. Rescheduling
+ * this timeout before the callback can be executed
+ * removes it from the active list. */
+ if ((ev->ev_flags & EVLIST_ACTIVE) &&
+ (ev->ev_res & EV_TIMEOUT)) {
+ if (ev->ev_events & EV_SIGNAL) {
+ /* See if we are just active executing
+ * this event in a loop
+ */
+ if (ev->ev_ncalls && ev->ev_pncalls) {
+ /* Abort loop */
+ *ev->ev_pncalls = 0;
+ }
+ }
+
+ event_queue_remove_active(base, event_to_event_callback(ev));
+ }
+
+ gettime(base, &now);
+
+ common_timeout = is_common_timeout(tv, base);
+#ifdef USE_REINSERT_TIMEOUT
+ was_common = is_common_timeout(&ev->ev_timeout, base);
+ old_timeout_idx = COMMON_TIMEOUT_IDX(&ev->ev_timeout);
+#endif
+
+ if (tv_is_absolute) {
+ ev->ev_timeout = *tv;
+ } else if (common_timeout) {
+ struct timeval tmp = *tv;
+ tmp.tv_usec &= MICROSECONDS_MASK;
+ evutil_timeradd(&now, &tmp, &ev->ev_timeout);
+ ev->ev_timeout.tv_usec |=
+ (tv->tv_usec & ~MICROSECONDS_MASK);
+ } else {
+ evutil_timeradd(&now, tv, &ev->ev_timeout);
+ }
+
+ event_debug((
+ "event_add: event %p, timeout in %d seconds %d useconds, call %p",
+ ev, (int)tv->tv_sec, (int)tv->tv_usec, ev->ev_callback));
+
+#ifdef USE_REINSERT_TIMEOUT
+ event_queue_reinsert_timeout(base, ev, was_common, common_timeout, old_timeout_idx);
+#else
+ event_queue_insert_timeout(base, ev);
+#endif
+
+ if (common_timeout) {
+ struct common_timeout_list *ctl =
+ get_common_timeout_list(base, &ev->ev_timeout);
+ if (ev == TAILQ_FIRST(&ctl->events)) {
+ common_timeout_schedule(ctl, &now, ev);
+ }
+ } else {
+ struct event* top = NULL;
+ /* See if the earliest timeout is now earlier than it
+ * was before: if so, we will need to tell the main
+ * thread to wake up earlier than it would otherwise.
+ * We double check the timeout of the top element to
+ * handle time distortions due to system suspension.
+ */
+ if (min_heap_elt_is_top_(ev))
+ notify = 1;
+ else if ((top = min_heap_top_(&base->timeheap)) != NULL &&
+ evutil_timercmp(&top->ev_timeout, &now, <))
+ notify = 1;
+ }
+ }
+
+ /* if we are not in the right thread, we need to wake up the loop */
+ if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
+ evthread_notify_base(base);
+
+ event_debug_note_add_(ev);
+
+ return (res);
+}
+
+static int
+event_del_(struct event *ev, int blocking)
+{
+ int res;
+
+ if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
+ event_warnx("%s: event has no event_base set.", __func__);
+ return -1;
+ }
+
+ EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
+
+ res = event_del_nolock_(ev, blocking);
+
+ EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
+
+ return (res);
+}
+
+int
+event_del(struct event *ev)
+{
+ return event_del_(ev, EVENT_DEL_AUTOBLOCK);
+}
+
+int
+event_del_block(struct event *ev)
+{
+ return event_del_(ev, EVENT_DEL_BLOCK);
+}
+
+int
+event_del_noblock(struct event *ev)
+{
+ return event_del_(ev, EVENT_DEL_NOBLOCK);
+}
+
+/** Helper for event_del: always called with th_base_lock held.
+ *
+ * "blocking" must be one of the EVENT_DEL_{BLOCK, NOBLOCK, AUTOBLOCK,
+ * EVEN_IF_FINALIZING} values. See those for more information.
+ */
+int
+event_del_nolock_(struct event *ev, int blocking)
+{
+ struct event_base *base;
+ int res = 0, notify = 0;
+
+ event_debug(("event_del: %p (fd "EV_SOCK_FMT"), callback %p",
+ ev, EV_SOCK_ARG(ev->ev_fd), ev->ev_callback));
+
+ /* An event without a base has not been added */
+ if (ev->ev_base == NULL)
+ return (-1);
+
+ EVENT_BASE_ASSERT_LOCKED(ev->ev_base);
+
+ if (blocking != EVENT_DEL_EVEN_IF_FINALIZING) {
+ if (ev->ev_flags & EVLIST_FINALIZING) {
+ /* XXXX Debug */
+ return 0;
+ }
+ }
+
+ /* If the main thread is currently executing this event's callback,
+ * and we are not the main thread, then we want to wait until the
+ * callback is done before we start removing the event. That way,
+ * when this function returns, it will be safe to free the
+ * user-supplied argument. */
+ base = ev->ev_base;
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ if (blocking != EVENT_DEL_NOBLOCK &&
+ base->current_event == event_to_event_callback(ev) &&
+ !EVBASE_IN_THREAD(base) &&
+ (blocking == EVENT_DEL_BLOCK || !(ev->ev_events & EV_FINALIZE))) {
+ ++base->current_event_waiters;
+ EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
+ }
+#endif
+
+ EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));
+
+ /* See if we are just active executing this event in a loop */
+ if (ev->ev_events & EV_SIGNAL) {
+ if (ev->ev_ncalls && ev->ev_pncalls) {
+ /* Abort loop */
+ *ev->ev_pncalls = 0;
+ }
+ }
+
+ if (ev->ev_flags & EVLIST_TIMEOUT) {
+ /* NOTE: We never need to notify the main thread because of a
+ * deleted timeout event: all that could happen if we don't is
+ * that the dispatch loop might wake up too early. But the
+ * point of notifying the main thread _is_ to wake up the
+ * dispatch loop early anyway, so we wouldn't gain anything by
+ * doing it.
+ */
+ event_queue_remove_timeout(base, ev);
+ }
+
+ if (ev->ev_flags & EVLIST_ACTIVE)
+ event_queue_remove_active(base, event_to_event_callback(ev));
+ else if (ev->ev_flags & EVLIST_ACTIVE_LATER)
+ event_queue_remove_active_later(base, event_to_event_callback(ev));
+
+ if (ev->ev_flags & EVLIST_INSERTED) {
+ event_queue_remove_inserted(base, ev);
+ if (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))
+ res = evmap_io_del_(base, ev->ev_fd, ev);
+ else
+ res = evmap_signal_del_(base, (int)ev->ev_fd, ev);
+ if (res == 1) {
+ /* evmap says we need to notify the main thread. */
+ notify = 1;
+ res = 0;
+ }
+ }
+
+ /* if we are not in the right thread, we need to wake up the loop */
+ if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
+ evthread_notify_base(base);
+
+ event_debug_note_del_(ev);
+
+ return (res);
+}
+
+void
+event_active(struct event *ev, int res, short ncalls)
+{
+ if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
+ event_warnx("%s: event has no event_base set.", __func__);
+ return;
+ }
+
+ EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
+
+ event_debug_assert_is_setup_(ev);
+
+ event_active_nolock_(ev, res, ncalls);
+
+ EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
+}
+
+
+void
+event_active_nolock_(struct event *ev, int res, short ncalls)
+{
+ struct event_base *base;
+
+ event_debug(("event_active: %p (fd "EV_SOCK_FMT"), res %d, callback %p",
+ ev, EV_SOCK_ARG(ev->ev_fd), (int)res, ev->ev_callback));
+
+ base = ev->ev_base;
+ EVENT_BASE_ASSERT_LOCKED(base);
+
+ if (ev->ev_flags & EVLIST_FINALIZING) {
+ /* XXXX debug */
+ return;
+ }
+
+ switch ((ev->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
+ default:
+ case EVLIST_ACTIVE|EVLIST_ACTIVE_LATER:
+ EVUTIL_ASSERT(0);
+ break;
+ case EVLIST_ACTIVE:
+ /* We get different kinds of events, add them together */
+ ev->ev_res |= res;
+ return;
+ case EVLIST_ACTIVE_LATER:
+ ev->ev_res |= res;
+ break;
+ case 0:
+ ev->ev_res = res;
+ break;
+ }
+
+ if (ev->ev_pri < base->event_running_priority)
+ base->event_continue = 1;
+
+ if (ev->ev_events & EV_SIGNAL) {
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ if (base->current_event == event_to_event_callback(ev) &&
+ !EVBASE_IN_THREAD(base)) {
+ ++base->current_event_waiters;
+ EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
+ }
+#endif
+ ev->ev_ncalls = ncalls;
+ ev->ev_pncalls = NULL;
+ }
+
+ event_callback_activate_nolock_(base, event_to_event_callback(ev));
+}
+
+void
+event_active_later_(struct event *ev, int res)
+{
+ EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
+ event_active_later_nolock_(ev, res);
+ EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
+}
+
+void
+event_active_later_nolock_(struct event *ev, int res)
+{
+ struct event_base *base = ev->ev_base;
+ EVENT_BASE_ASSERT_LOCKED(base);
+
+ if (ev->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)) {
+ /* We get different kinds of events, add them together */
+ ev->ev_res |= res;
+ return;
+ }
+
+ ev->ev_res = res;
+
+ event_callback_activate_later_nolock_(base, event_to_event_callback(ev));
+}
+
+int
+event_callback_activate_(struct event_base *base,
+ struct event_callback *evcb)
+{
+ int r;
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ r = event_callback_activate_nolock_(base, evcb);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return r;
+}
+
+int
+event_callback_activate_nolock_(struct event_base *base,
+ struct event_callback *evcb)
+{
+ int r = 1;
+
+ if (evcb->evcb_flags & EVLIST_FINALIZING)
+ return 0;
+
+ switch (evcb->evcb_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)) {
+ default:
+ EVUTIL_ASSERT(0);
+ case EVLIST_ACTIVE_LATER:
+ event_queue_remove_active_later(base, evcb);
+ r = 0;
+ break;
+ case EVLIST_ACTIVE:
+ return 0;
+ case 0:
+ break;
+ }
+
+ event_queue_insert_active(base, evcb);
+
+ if (EVBASE_NEED_NOTIFY(base))
+ evthread_notify_base(base);
+
+ return r;
+}
+
+int
+event_callback_activate_later_nolock_(struct event_base *base,
+ struct event_callback *evcb)
+{
+ if (evcb->evcb_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))
+ return 0;
+
+ event_queue_insert_active_later(base, evcb);
+ if (EVBASE_NEED_NOTIFY(base))
+ evthread_notify_base(base);
+ return 1;
+}
+
+void
+event_callback_init_(struct event_base *base,
+ struct event_callback *cb)
+{
+ memset(cb, 0, sizeof(*cb));
+ cb->evcb_pri = base->nactivequeues - 1;
+}
+
+int
+event_callback_cancel_(struct event_base *base,
+ struct event_callback *evcb)
+{
+ int r;
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ r = event_callback_cancel_nolock_(base, evcb, 0);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return r;
+}
+
+int
+event_callback_cancel_nolock_(struct event_base *base,
+ struct event_callback *evcb, int even_if_finalizing)
+{
+ if ((evcb->evcb_flags & EVLIST_FINALIZING) && !even_if_finalizing)
+ return 0;
+
+ if (evcb->evcb_flags & EVLIST_INIT)
+ return event_del_nolock_(event_callback_to_event(evcb),
+ even_if_finalizing ? EVENT_DEL_EVEN_IF_FINALIZING : EVENT_DEL_AUTOBLOCK);
+
+ switch ((evcb->evcb_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
+ default:
+ case EVLIST_ACTIVE|EVLIST_ACTIVE_LATER:
+ EVUTIL_ASSERT(0);
+ break;
+ case EVLIST_ACTIVE:
+ /* We get different kinds of events, add them together */
+ event_queue_remove_active(base, evcb);
+ return 0;
+ case EVLIST_ACTIVE_LATER:
+ event_queue_remove_active_later(base, evcb);
+ break;
+ case 0:
+ break;
+ }
+
+ return 0;
+}
+
+void
+event_deferred_cb_init_(struct event_callback *cb, ev_uint8_t priority, deferred_cb_fn fn, void *arg)
+{
+ memset(cb, 0, sizeof(*cb));
+ cb->evcb_cb_union.evcb_selfcb = fn;
+ cb->evcb_arg = arg;
+ cb->evcb_pri = priority;
+ cb->evcb_closure = EV_CLOSURE_CB_SELF;
+}
+
+void
+event_deferred_cb_set_priority_(struct event_callback *cb, ev_uint8_t priority)
+{
+ cb->evcb_pri = priority;
+}
+
+void
+event_deferred_cb_cancel_(struct event_base *base, struct event_callback *cb)
+{
+ if (!base)
+ base = current_base;
+ event_callback_cancel_(base, cb);
+}
+
+#define MAX_DEFERREDS_QUEUED 32
+int
+event_deferred_cb_schedule_(struct event_base *base, struct event_callback *cb)
+{
+ int r = 1;
+ if (!base)
+ base = current_base;
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ if (base->n_deferreds_queued > MAX_DEFERREDS_QUEUED) {
+ r = event_callback_activate_later_nolock_(base, cb);
+ } else {
+ r = event_callback_activate_nolock_(base, cb);
+ if (r) {
+ ++base->n_deferreds_queued;
+ }
+ }
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return r;
+}
+
+static int
+timeout_next(struct event_base *base, struct timeval **tv_p)
+{
+ /* Caller must hold th_base_lock */
+ struct timeval now;
+ struct event *ev;
+ struct timeval *tv = *tv_p;
+ int res = 0;
+
+ ev = min_heap_top_(&base->timeheap);
+
+ if (ev == NULL) {
+ /* if no time-based events are active wait for I/O */
+ *tv_p = NULL;
+ goto out;
+ }
+
+ if (gettime(base, &now) == -1) {
+ res = -1;
+ goto out;
+ }
+
+ if (evutil_timercmp(&ev->ev_timeout, &now, <=)) {
+ evutil_timerclear(tv);
+ goto out;
+ }
+
+ evutil_timersub(&ev->ev_timeout, &now, tv);
+
+ EVUTIL_ASSERT(tv->tv_sec >= 0);
+ EVUTIL_ASSERT(tv->tv_usec >= 0);
+ event_debug(("timeout_next: event: %p, in %d seconds, %d useconds", ev, (int)tv->tv_sec, (int)tv->tv_usec));
+
+out:
+ return (res);
+}
+
+/* Activate every event whose timeout has elapsed. */
+static void
+timeout_process(struct event_base *base)
+{
+ /* Caller must hold lock. */
+ struct timeval now;
+ struct event *ev;
+
+ if (min_heap_empty_(&base->timeheap)) {
+ return;
+ }
+
+ gettime(base, &now);
+
+ while ((ev = min_heap_top_(&base->timeheap))) {
+ if (evutil_timercmp(&ev->ev_timeout, &now, >))
+ break;
+
+ /* delete this event from the I/O queues */
+ event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
+
+ event_debug(("timeout_process: event: %p, call %p",
+ ev, ev->ev_callback));
+ event_active_nolock_(ev, EV_TIMEOUT, 1);
+ }
+}
+
+#if (EVLIST_INTERNAL >> 4) != 1
+#error "Mismatch for value of EVLIST_INTERNAL"
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#define MAX_EVENT_COUNT(var, v) var = MAX(var, v)
+
+/* These are a fancy way to spell
+ if (flags & EVLIST_INTERNAL)
+ base->event_count--/++;
+*/
+#define DECR_EVENT_COUNT(base,flags) \
+ ((base)->event_count -= (~((flags) >> 4) & 1))
+#define INCR_EVENT_COUNT(base,flags) do { \
+ ((base)->event_count += (~((flags) >> 4) & 1)); \
+ MAX_EVENT_COUNT((base)->event_count_max, (base)->event_count); \
+} while (0)
+
+static void
+event_queue_remove_inserted(struct event_base *base, struct event *ev)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
+ if (EVUTIL_FAILURE_CHECK(!(ev->ev_flags & EVLIST_INSERTED))) {
+ event_errx(1, "%s: %p(fd "EV_SOCK_FMT") not on queue %x", __func__,
+ ev, EV_SOCK_ARG(ev->ev_fd), EVLIST_INSERTED);
+ return;
+ }
+ DECR_EVENT_COUNT(base, ev->ev_flags);
+ ev->ev_flags &= ~EVLIST_INSERTED;
+}
+static void
+event_queue_remove_active(struct event_base *base, struct event_callback *evcb)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
+ if (EVUTIL_FAILURE_CHECK(!(evcb->evcb_flags & EVLIST_ACTIVE))) {
+ event_errx(1, "%s: %p not on queue %x", __func__,
+ evcb, EVLIST_ACTIVE);
+ return;
+ }
+ DECR_EVENT_COUNT(base, evcb->evcb_flags);
+ evcb->evcb_flags &= ~EVLIST_ACTIVE;
+ base->event_count_active--;
+
+ TAILQ_REMOVE(&base->activequeues[evcb->evcb_pri],
+ evcb, evcb_active_next);
+}
+static void
+event_queue_remove_active_later(struct event_base *base, struct event_callback *evcb)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
+ if (EVUTIL_FAILURE_CHECK(!(evcb->evcb_flags & EVLIST_ACTIVE_LATER))) {
+ event_errx(1, "%s: %p not on queue %x", __func__,
+ evcb, EVLIST_ACTIVE_LATER);
+ return;
+ }
+ DECR_EVENT_COUNT(base, evcb->evcb_flags);
+ evcb->evcb_flags &= ~EVLIST_ACTIVE_LATER;
+ base->event_count_active--;
+
+ TAILQ_REMOVE(&base->active_later_queue, evcb, evcb_active_next);
+}
+static void
+event_queue_remove_timeout(struct event_base *base, struct event *ev)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
+ if (EVUTIL_FAILURE_CHECK(!(ev->ev_flags & EVLIST_TIMEOUT))) {
+ event_errx(1, "%s: %p(fd "EV_SOCK_FMT") not on queue %x", __func__,
+ ev, EV_SOCK_ARG(ev->ev_fd), EVLIST_TIMEOUT);
+ return;
+ }
+ DECR_EVENT_COUNT(base, ev->ev_flags);
+ ev->ev_flags &= ~EVLIST_TIMEOUT;
+
+ if (is_common_timeout(&ev->ev_timeout, base)) {
+ struct common_timeout_list *ctl =
+ get_common_timeout_list(base, &ev->ev_timeout);
+ TAILQ_REMOVE(&ctl->events, ev,
+ ev_timeout_pos.ev_next_with_common_timeout);
+ } else {
+ min_heap_erase_(&base->timeheap, ev);
+ }
+}
+
+#ifdef USE_REINSERT_TIMEOUT
+/* Remove and reinsert 'ev' into the timeout queue. */
+static void
+event_queue_reinsert_timeout(struct event_base *base, struct event *ev,
+ int was_common, int is_common, int old_timeout_idx)
+{
+ struct common_timeout_list *ctl;
+ if (!(ev->ev_flags & EVLIST_TIMEOUT)) {
+ event_queue_insert_timeout(base, ev);
+ return;
+ }
+
+ switch ((was_common<<1) | is_common) {
+ case 3: /* Changing from one common timeout to another */
+ ctl = base->common_timeout_queues[old_timeout_idx];
+ TAILQ_REMOVE(&ctl->events, ev,
+ ev_timeout_pos.ev_next_with_common_timeout);
+ ctl = get_common_timeout_list(base, &ev->ev_timeout);
+ insert_common_timeout_inorder(ctl, ev);
+ break;
+ case 2: /* Was common; is no longer common */
+ ctl = base->common_timeout_queues[old_timeout_idx];
+ TAILQ_REMOVE(&ctl->events, ev,
+ ev_timeout_pos.ev_next_with_common_timeout);
+ min_heap_push_(&base->timeheap, ev);
+ break;
+ case 1: /* Wasn't common; has become common. */
+ min_heap_erase_(&base->timeheap, ev);
+ ctl = get_common_timeout_list(base, &ev->ev_timeout);
+ insert_common_timeout_inorder(ctl, ev);
+ break;
+ case 0: /* was in heap; is still on heap. */
+ min_heap_adjust_(&base->timeheap, ev);
+ break;
+ default:
+ EVUTIL_ASSERT(0); /* unreachable */
+ break;
+ }
+}
+#endif
+
+/* Add 'ev' to the common timeout list in 'ev'. */
+static void
+insert_common_timeout_inorder(struct common_timeout_list *ctl,
+ struct event *ev)
+{
+ struct event *e;
+ /* By all logic, we should just be able to append 'ev' to the end of
+ * ctl->events, since the timeout on each 'ev' is set to {the common
+ * timeout} + {the time when we add the event}, and so the events
+ * should arrive in order of their timeeouts. But just in case
+ * there's some wacky threading issue going on, we do a search from
+ * the end of 'ev' to find the right insertion point.
+ */
+ TAILQ_FOREACH_REVERSE(e, &ctl->events,
+ event_list, ev_timeout_pos.ev_next_with_common_timeout) {
+ /* This timercmp is a little sneaky, since both ev and e have
+ * magic values in tv_usec. Fortunately, they ought to have
+ * the _same_ magic values in tv_usec. Let's assert for that.
+ */
+ EVUTIL_ASSERT(
+ is_same_common_timeout(&e->ev_timeout, &ev->ev_timeout));
+ if (evutil_timercmp(&ev->ev_timeout, &e->ev_timeout, >=)) {
+ TAILQ_INSERT_AFTER(&ctl->events, e, ev,
+ ev_timeout_pos.ev_next_with_common_timeout);
+ return;
+ }
+ }
+ TAILQ_INSERT_HEAD(&ctl->events, ev,
+ ev_timeout_pos.ev_next_with_common_timeout);
+}
+
+static void
+event_queue_insert_inserted(struct event_base *base, struct event *ev)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
+
+ if (EVUTIL_FAILURE_CHECK(ev->ev_flags & EVLIST_INSERTED)) {
+ event_errx(1, "%s: %p(fd "EV_SOCK_FMT") already inserted", __func__,
+ ev, EV_SOCK_ARG(ev->ev_fd));
+ return;
+ }
+
+ INCR_EVENT_COUNT(base, ev->ev_flags);
+
+ ev->ev_flags |= EVLIST_INSERTED;
+}
+
+static void
+event_queue_insert_active(struct event_base *base, struct event_callback *evcb)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
+
+ if (evcb->evcb_flags & EVLIST_ACTIVE) {
+ /* Double insertion is possible for active events */
+ return;
+ }
+
+ INCR_EVENT_COUNT(base, evcb->evcb_flags);
+
+ evcb->evcb_flags |= EVLIST_ACTIVE;
+
+ base->event_count_active++;
+ MAX_EVENT_COUNT(base->event_count_active_max, base->event_count_active);
+ EVUTIL_ASSERT(evcb->evcb_pri < base->nactivequeues);
+ TAILQ_INSERT_TAIL(&base->activequeues[evcb->evcb_pri],
+ evcb, evcb_active_next);
+}
+
+static void
+event_queue_insert_active_later(struct event_base *base, struct event_callback *evcb)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
+ if (evcb->evcb_flags & (EVLIST_ACTIVE_LATER|EVLIST_ACTIVE)) {
+ /* Double insertion is possible */
+ return;
+ }
+
+ INCR_EVENT_COUNT(base, evcb->evcb_flags);
+ evcb->evcb_flags |= EVLIST_ACTIVE_LATER;
+ base->event_count_active++;
+ MAX_EVENT_COUNT(base->event_count_active_max, base->event_count_active);
+ EVUTIL_ASSERT(evcb->evcb_pri < base->nactivequeues);
+ TAILQ_INSERT_TAIL(&base->active_later_queue, evcb, evcb_active_next);
+}
+
+static void
+event_queue_insert_timeout(struct event_base *base, struct event *ev)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
+
+ if (EVUTIL_FAILURE_CHECK(ev->ev_flags & EVLIST_TIMEOUT)) {
+ event_errx(1, "%s: %p(fd "EV_SOCK_FMT") already on timeout", __func__,
+ ev, EV_SOCK_ARG(ev->ev_fd));
+ return;
+ }
+
+ INCR_EVENT_COUNT(base, ev->ev_flags);
+
+ ev->ev_flags |= EVLIST_TIMEOUT;
+
+ if (is_common_timeout(&ev->ev_timeout, base)) {
+ struct common_timeout_list *ctl =
+ get_common_timeout_list(base, &ev->ev_timeout);
+ insert_common_timeout_inorder(ctl, ev);
+ } else {
+ min_heap_push_(&base->timeheap, ev);
+ }
+}
+
+static void
+event_queue_make_later_events_active(struct event_base *base)
+{
+ struct event_callback *evcb;
+ EVENT_BASE_ASSERT_LOCKED(base);
+
+ while ((evcb = TAILQ_FIRST(&base->active_later_queue))) {
+ TAILQ_REMOVE(&base->active_later_queue, evcb, evcb_active_next);
+ evcb->evcb_flags = (evcb->evcb_flags & ~EVLIST_ACTIVE_LATER) | EVLIST_ACTIVE;
+ EVUTIL_ASSERT(evcb->evcb_pri < base->nactivequeues);
+ TAILQ_INSERT_TAIL(&base->activequeues[evcb->evcb_pri], evcb, evcb_active_next);
+ base->n_deferreds_queued += (evcb->evcb_closure == EV_CLOSURE_CB_SELF);
+ }
+}
+
+/* Functions for debugging */
+
+const char *
+event_get_version(void)
+{
+ return (EVENT__VERSION);
+}
+
+ev_uint32_t
+event_get_version_number(void)
+{
+ return (EVENT__NUMERIC_VERSION);
+}
+
+/*
+ * No thread-safe interface needed - the information should be the same
+ * for all threads.
+ */
+
+const char *
+event_get_method(void)
+{
+ return (current_base->evsel->name);
+}
+
+#ifndef EVENT__DISABLE_MM_REPLACEMENT
+static void *(*mm_malloc_fn_)(size_t sz) = NULL;
+static void *(*mm_realloc_fn_)(void *p, size_t sz) = NULL;
+static void (*mm_free_fn_)(void *p) = NULL;
+
+void *
+event_mm_malloc_(size_t sz)
+{
+ if (sz == 0)
+ return NULL;
+
+ if (mm_malloc_fn_)
+ return mm_malloc_fn_(sz);
+ else
+ return malloc(sz);
+}
+
+void *
+event_mm_calloc_(size_t count, size_t size)
+{
+ if (count == 0 || size == 0)
+ return NULL;
+
+ if (mm_malloc_fn_) {
+ size_t sz = count * size;
+ void *p = NULL;
+ if (count > EV_SIZE_MAX / size)
+ goto error;
+ p = mm_malloc_fn_(sz);
+ if (p)
+ return memset(p, 0, sz);
+ } else {
+ void *p = calloc(count, size);
+#ifdef _WIN32
+ /* Windows calloc doesn't reliably set ENOMEM */
+ if (p == NULL)
+ goto error;
+#endif
+ return p;
+ }
+
+error:
+ errno = ENOMEM;
+ return NULL;
+}
+
+char *
+event_mm_strdup_(const char *str)
+{
+ if (!str) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (mm_malloc_fn_) {
+ size_t ln = strlen(str);
+ void *p = NULL;
+ if (ln == EV_SIZE_MAX)
+ goto error;
+ p = mm_malloc_fn_(ln+1);
+ if (p)
+ return memcpy(p, str, ln+1);
+ } else
+#ifdef _WIN32
+ return _strdup(str);
+#else
+ return strdup(str);
+#endif
+
+error:
+ errno = ENOMEM;
+ return NULL;
+}
+
+void *
+event_mm_realloc_(void *ptr, size_t sz)
+{
+ if (mm_realloc_fn_)
+ return mm_realloc_fn_(ptr, sz);
+ else
+ return realloc(ptr, sz);
+}
+
+void
+event_mm_free_(void *ptr)
+{
+ if (mm_free_fn_)
+ mm_free_fn_(ptr);
+ else
+ free(ptr);
+}
+
+void
+event_set_mem_functions(void *(*malloc_fn)(size_t sz),
+ void *(*realloc_fn)(void *ptr, size_t sz),
+ void (*free_fn)(void *ptr))
+{
+ mm_malloc_fn_ = malloc_fn;
+ mm_realloc_fn_ = realloc_fn;
+ mm_free_fn_ = free_fn;
+}
+#endif
+
+#ifdef EVENT__HAVE_EVENTFD
+static void
+evthread_notify_drain_eventfd(evutil_socket_t fd, short what, void *arg)
+{
+ ev_uint64_t msg;
+ ev_ssize_t r;
+ struct event_base *base = arg;
+
+ r = read(fd, (void*) &msg, sizeof(msg));
+ if (r<0 && errno != EAGAIN) {
+ event_sock_warn(fd, "Error reading from eventfd");
+ }
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ base->is_notify_pending = 0;
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
+#endif
+
+static void
+evthread_notify_drain_default(evutil_socket_t fd, short what, void *arg)
+{
+ unsigned char buf[1024];
+ struct event_base *base = arg;
+#ifdef _WIN32
+ while (recv(fd, (char*)buf, sizeof(buf), 0) > 0)
+ ;
+#else
+ while (read(fd, (char*)buf, sizeof(buf)) > 0)
+ ;
+#endif
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ base->is_notify_pending = 0;
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
+
+int
+evthread_make_base_notifiable(struct event_base *base)
+{
+ int r;
+ if (!base)
+ return -1;
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ r = evthread_make_base_notifiable_nolock_(base);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return r;
+}
+
+static int
+evthread_make_base_notifiable_nolock_(struct event_base *base)
+{
+ void (*cb)(evutil_socket_t, short, void *);
+ int (*notify)(struct event_base *);
+
+ if (base->th_notify_fn != NULL) {
+ /* The base is already notifiable: we're doing fine. */
+ return 0;
+ }
+
+#if defined(EVENT__HAVE_WORKING_KQUEUE)
+ if (base->evsel == &kqops && event_kq_add_notify_event_(base) == 0) {
+ base->th_notify_fn = event_kq_notify_base_;
+ /* No need to add an event here; the backend can wake
+ * itself up just fine. */
+ return 0;
+ }
+#endif
+
+#ifdef EVENT__HAVE_EVENTFD
+ base->th_notify_fd[0] = evutil_eventfd_(0,
+ EVUTIL_EFD_CLOEXEC|EVUTIL_EFD_NONBLOCK);
+ if (base->th_notify_fd[0] >= 0) {
+ base->th_notify_fd[1] = -1;
+ notify = evthread_notify_base_eventfd;
+ cb = evthread_notify_drain_eventfd;
+ } else
+#endif
+ if (evutil_make_internal_pipe_(base->th_notify_fd) == 0) {
+ notify = evthread_notify_base_default;
+ cb = evthread_notify_drain_default;
+ } else {
+ return -1;
+ }
+
+ base->th_notify_fn = notify;
+
+ /* prepare an event that we can use for wakeup */
+ event_assign(&base->th_notify, base, base->th_notify_fd[0],
+ EV_READ|EV_PERSIST, cb, base);
+
+ /* we need to mark this as internal event */
+ base->th_notify.ev_flags |= EVLIST_INTERNAL;
+ event_priority_set(&base->th_notify, 0);
+
+ return event_add_nolock_(&base->th_notify, NULL, 0);
+}
+
+int
+event_base_foreach_event_nolock_(struct event_base *base,
+ event_base_foreach_event_cb fn, void *arg)
+{
+ int r, i;
+ unsigned u;
+ struct event *ev;
+
+ /* Start out with all the EVLIST_INSERTED events. */
+ if ((r = evmap_foreach_event_(base, fn, arg)))
+ return r;
+
+ /* Okay, now we deal with those events that have timeouts and are in
+ * the min-heap. */
+ for (u = 0; u < base->timeheap.n; ++u) {
+ ev = base->timeheap.p[u];
+ if (ev->ev_flags & EVLIST_INSERTED) {
+ /* we already processed this one */
+ continue;
+ }
+ if ((r = fn(base, ev, arg)))
+ return r;
+ }
+
+ /* Now for the events in one of the timeout queues.
+ * the min-heap. */
+ for (i = 0; i < base->n_common_timeouts; ++i) {
+ struct common_timeout_list *ctl =
+ base->common_timeout_queues[i];
+ TAILQ_FOREACH(ev, &ctl->events,
+ ev_timeout_pos.ev_next_with_common_timeout) {
+ if (ev->ev_flags & EVLIST_INSERTED) {
+ /* we already processed this one */
+ continue;
+ }
+ if ((r = fn(base, ev, arg)))
+ return r;
+ }
+ }
+
+ /* Finally, we deal wit all the active events that we haven't touched
+ * yet. */
+ for (i = 0; i < base->nactivequeues; ++i) {
+ struct event_callback *evcb;
+ TAILQ_FOREACH(evcb, &base->activequeues[i], evcb_active_next) {
+ if ((evcb->evcb_flags & (EVLIST_INIT|EVLIST_INSERTED|EVLIST_TIMEOUT)) != EVLIST_INIT) {
+ /* This isn't an event (evlist_init clear), or
+ * we already processed it. (inserted or
+ * timeout set */
+ continue;
+ }
+ ev = event_callback_to_event(evcb);
+ if ((r = fn(base, ev, arg)))
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+/* Helper for event_base_dump_events: called on each event in the event base;
+ * dumps only the inserted events. */
+static int
+dump_inserted_event_fn(const struct event_base *base, const struct event *e, void *arg)
+{
+ FILE *output = arg;
+ const char *gloss = (e->ev_events & EV_SIGNAL) ?
+ "sig" : "fd ";
+
+ if (! (e->ev_flags & (EVLIST_INSERTED|EVLIST_TIMEOUT)))
+ return 0;
+
+ fprintf(output, " %p [%s "EV_SOCK_FMT"]%s%s%s%s%s%s",
+ (void*)e, gloss, EV_SOCK_ARG(e->ev_fd),
+ (e->ev_events&EV_READ)?" Read":"",
+ (e->ev_events&EV_WRITE)?" Write":"",
+ (e->ev_events&EV_CLOSED)?" EOF":"",
+ (e->ev_events&EV_SIGNAL)?" Signal":"",
+ (e->ev_events&EV_PERSIST)?" Persist":"",
+ (e->ev_flags&EVLIST_INTERNAL)?" Internal":"");
+ if (e->ev_flags & EVLIST_TIMEOUT) {
+ struct timeval tv;
+ tv.tv_sec = e->ev_timeout.tv_sec;
+ tv.tv_usec = e->ev_timeout.tv_usec & MICROSECONDS_MASK;
+ evutil_timeradd(&tv, &base->tv_clock_diff, &tv);
+ fprintf(output, " Timeout=%ld.%06d",
+ (long)tv.tv_sec, (int)(tv.tv_usec & MICROSECONDS_MASK));
+ }
+ fputc('\n', output);
+
+ return 0;
+}
+
+/* Helper for event_base_dump_events: called on each event in the event base;
+ * dumps only the active events. */
+static int
+dump_active_event_fn(const struct event_base *base, const struct event *e, void *arg)
+{
+ FILE *output = arg;
+ const char *gloss = (e->ev_events & EV_SIGNAL) ?
+ "sig" : "fd ";
+
+ if (! (e->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)))
+ return 0;
+
+ fprintf(output, " %p [%s "EV_SOCK_FMT", priority=%d]%s%s%s%s%s active%s%s\n",
+ (void*)e, gloss, EV_SOCK_ARG(e->ev_fd), e->ev_pri,
+ (e->ev_res&EV_READ)?" Read":"",
+ (e->ev_res&EV_WRITE)?" Write":"",
+ (e->ev_res&EV_CLOSED)?" EOF":"",
+ (e->ev_res&EV_SIGNAL)?" Signal":"",
+ (e->ev_res&EV_TIMEOUT)?" Timeout":"",
+ (e->ev_flags&EVLIST_INTERNAL)?" [Internal]":"",
+ (e->ev_flags&EVLIST_ACTIVE_LATER)?" [NextTime]":"");
+
+ return 0;
+}
+
+int
+event_base_foreach_event(struct event_base *base,
+ event_base_foreach_event_cb fn, void *arg)
+{
+ int r;
+ if ((!fn) || (!base)) {
+ return -1;
+ }
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ r = event_base_foreach_event_nolock_(base, fn, arg);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return r;
+}
+
+
+void
+event_base_dump_events(struct event_base *base, FILE *output)
+{
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ fprintf(output, "Inserted events:\n");
+ event_base_foreach_event_nolock_(base, dump_inserted_event_fn, output);
+
+ fprintf(output, "Active events:\n");
+ event_base_foreach_event_nolock_(base, dump_active_event_fn, output);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
+
+void
+event_base_active_by_fd(struct event_base *base, evutil_socket_t fd, short events)
+{
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ evmap_io_active_(base, fd, events & (EV_READ|EV_WRITE|EV_CLOSED));
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
+
+void
+event_base_active_by_signal(struct event_base *base, int sig)
+{
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ evmap_signal_active_(base, sig, 1);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
+
+
+void
+event_base_add_virtual_(struct event_base *base)
+{
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ base->virtual_event_count++;
+ MAX_EVENT_COUNT(base->virtual_event_count_max, base->virtual_event_count);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
+
+void
+event_base_del_virtual_(struct event_base *base)
+{
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ EVUTIL_ASSERT(base->virtual_event_count > 0);
+ base->virtual_event_count--;
+ if (base->virtual_event_count == 0 && EVBASE_NEED_NOTIFY(base))
+ evthread_notify_base(base);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
+
+static void
+event_free_debug_globals_locks(void)
+{
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+#ifndef EVENT__DISABLE_DEBUG_MODE
+ if (event_debug_map_lock_ != NULL) {
+ EVTHREAD_FREE_LOCK(event_debug_map_lock_, 0);
+ event_debug_map_lock_ = NULL;
+ evthreadimpl_disable_lock_debugging_();
+ }
+#endif /* EVENT__DISABLE_DEBUG_MODE */
+#endif /* EVENT__DISABLE_THREAD_SUPPORT */
+ return;
+}
+
+static void
+event_free_debug_globals(void)
+{
+ event_free_debug_globals_locks();
+}
+
+static void
+event_free_evsig_globals(void)
+{
+ evsig_free_globals_();
+}
+
+static void
+event_free_evutil_globals(void)
+{
+ evutil_free_globals_();
+}
+
+static void
+event_free_globals(void)
+{
+ event_free_debug_globals();
+ event_free_evsig_globals();
+ event_free_evutil_globals();
+}
+
+void
+libevent_global_shutdown(void)
+{
+ event_disable_debug_mode();
+ event_free_globals();
+}
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+int
+event_global_setup_locks_(const int enable_locks)
+{
+#ifndef EVENT__DISABLE_DEBUG_MODE
+ EVTHREAD_SETUP_GLOBAL_LOCK(event_debug_map_lock_, 0);
+#endif
+ if (evsig_global_setup_locks_(enable_locks) < 0)
+ return -1;
+ if (evutil_global_setup_locks_(enable_locks) < 0)
+ return -1;
+ if (evutil_secure_rng_global_setup_locks_(enable_locks) < 0)
+ return -1;
+ return 0;
+}
+#endif
+
+void
+event_base_assert_ok_(struct event_base *base)
+{
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ event_base_assert_ok_nolock_(base);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
+
+void
+event_base_assert_ok_nolock_(struct event_base *base)
+{
+ int i;
+ int count;
+
+ /* First do checks on the per-fd and per-signal lists */
+ evmap_check_integrity_(base);
+
+ /* Check the heap property */
+ for (i = 1; i < (int)base->timeheap.n; ++i) {
+ int parent = (i - 1) / 2;
+ struct event *ev, *p_ev;
+ ev = base->timeheap.p[i];
+ p_ev = base->timeheap.p[parent];
+ EVUTIL_ASSERT(ev->ev_flags & EVLIST_TIMEOUT);
+ EVUTIL_ASSERT(evutil_timercmp(&p_ev->ev_timeout, &ev->ev_timeout, <=));
+ EVUTIL_ASSERT(ev->ev_timeout_pos.min_heap_idx == i);
+ }
+
+ /* Check that the common timeouts are fine */
+ for (i = 0; i < base->n_common_timeouts; ++i) {
+ struct common_timeout_list *ctl = base->common_timeout_queues[i];
+ struct event *last=NULL, *ev;
+
+ EVUTIL_ASSERT_TAILQ_OK(&ctl->events, event, ev_timeout_pos.ev_next_with_common_timeout);
+
+ TAILQ_FOREACH(ev, &ctl->events, ev_timeout_pos.ev_next_with_common_timeout) {
+ if (last)
+ EVUTIL_ASSERT(evutil_timercmp(&last->ev_timeout, &ev->ev_timeout, <=));
+ EVUTIL_ASSERT(ev->ev_flags & EVLIST_TIMEOUT);
+ EVUTIL_ASSERT(is_common_timeout(&ev->ev_timeout,base));
+ EVUTIL_ASSERT(COMMON_TIMEOUT_IDX(&ev->ev_timeout) == i);
+ last = ev;
+ }
+ }
+
+ /* Check the active queues. */
+ count = 0;
+ for (i = 0; i < base->nactivequeues; ++i) {
+ struct event_callback *evcb;
+ EVUTIL_ASSERT_TAILQ_OK(&base->activequeues[i], event_callback, evcb_active_next);
+ TAILQ_FOREACH(evcb, &base->activequeues[i], evcb_active_next) {
+ EVUTIL_ASSERT((evcb->evcb_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)) == EVLIST_ACTIVE);
+ EVUTIL_ASSERT(evcb->evcb_pri == i);
+ ++count;
+ }
+ }
+
+ {
+ struct event_callback *evcb;
+ TAILQ_FOREACH(evcb, &base->active_later_queue, evcb_active_next) {
+ EVUTIL_ASSERT((evcb->evcb_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)) == EVLIST_ACTIVE_LATER);
+ ++count;
+ }
+ }
+ EVUTIL_ASSERT(count == base->event_count_active);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/event_iocp.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/event_iocp.c
new file mode 100644
index 000000000..a9902fbc4
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/event_iocp.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "evconfig-private.h"
+
+#ifndef _WIN32_WINNT
+/* Minimum required for InitializeCriticalSectionAndSpinCount */
+#define _WIN32_WINNT 0x0403
+#endif
+#include <winsock2.h>
+#include <windows.h>
+#include <process.h>
+#include <stdio.h>
+#include <mswsock.h>
+
+#include "event2/util.h"
+#include "util-internal.h"
+#include "iocp-internal.h"
+#include "log-internal.h"
+#include "mm-internal.h"
+#include "event-internal.h"
+#include "evthread-internal.h"
+
+#define NOTIFICATION_KEY ((ULONG_PTR)-1)
+
+void
+event_overlapped_init_(struct event_overlapped *o, iocp_callback cb)
+{
+ memset(o, 0, sizeof(struct event_overlapped));
+ o->cb = cb;
+}
+
+static void
+handle_entry(OVERLAPPED *o, ULONG_PTR completion_key, DWORD nBytes, int ok)
+{
+ struct event_overlapped *eo =
+ EVUTIL_UPCAST(o, struct event_overlapped, overlapped);
+ eo->cb(eo, completion_key, nBytes, ok);
+}
+
+static void
+loop(void *port_)
+{
+ struct event_iocp_port *port = port_;
+ long ms = port->ms;
+ HANDLE p = port->port;
+
+ if (ms <= 0)
+ ms = INFINITE;
+
+ while (1) {
+ OVERLAPPED *overlapped=NULL;
+ ULONG_PTR key=0;
+ DWORD bytes=0;
+ int ok = GetQueuedCompletionStatus(p, &bytes, &key,
+ &overlapped, ms);
+ EnterCriticalSection(&port->lock);
+ if (port->shutdown) {
+ if (--port->n_live_threads == 0)
+ ReleaseSemaphore(port->shutdownSemaphore, 1,
+ NULL);
+ LeaveCriticalSection(&port->lock);
+ return;
+ }
+ LeaveCriticalSection(&port->lock);
+
+ if (key != NOTIFICATION_KEY && overlapped)
+ handle_entry(overlapped, key, bytes, ok);
+ else if (!overlapped)
+ break;
+ }
+ event_warnx("GetQueuedCompletionStatus exited with no event.");
+ EnterCriticalSection(&port->lock);
+ if (--port->n_live_threads == 0)
+ ReleaseSemaphore(port->shutdownSemaphore, 1, NULL);
+ LeaveCriticalSection(&port->lock);
+}
+
+int
+event_iocp_port_associate_(struct event_iocp_port *port, evutil_socket_t fd,
+ ev_uintptr_t key)
+{
+ HANDLE h;
+ h = CreateIoCompletionPort((HANDLE)fd, port->port, key, port->n_threads);
+ if (!h)
+ return -1;
+ return 0;
+}
+
+static void *
+get_extension_function(SOCKET s, const GUID *which_fn)
+{
+ void *ptr = NULL;
+ DWORD bytes=0;
+ WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ (GUID*)which_fn, sizeof(*which_fn),
+ &ptr, sizeof(ptr),
+ &bytes, NULL, NULL);
+
+ /* No need to detect errors here: if ptr is set, then we have a good
+ function pointer. Otherwise, we should behave as if we had no
+ function pointer.
+ */
+ return ptr;
+}
+
+/* Mingw doesn't have these in its mswsock.h. The values are copied from
+ wine.h. Perhaps if we copy them exactly, the cargo will come again.
+*/
+#ifndef WSAID_ACCEPTEX
+#define WSAID_ACCEPTEX \
+ {0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
+#endif
+#ifndef WSAID_CONNECTEX
+#define WSAID_CONNECTEX \
+ {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}}
+#endif
+#ifndef WSAID_GETACCEPTEXSOCKADDRS
+#define WSAID_GETACCEPTEXSOCKADDRS \
+ {0xb5367df2,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
+#endif
+
+static int extension_fns_initialized = 0;
+
+static void
+init_extension_functions(struct win32_extension_fns *ext)
+{
+ const GUID acceptex = WSAID_ACCEPTEX;
+ const GUID connectex = WSAID_CONNECTEX;
+ const GUID getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
+ SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s == INVALID_SOCKET)
+ return;
+ ext->AcceptEx = get_extension_function(s, &acceptex);
+ ext->ConnectEx = get_extension_function(s, &connectex);
+ ext->GetAcceptExSockaddrs = get_extension_function(s,
+ &getacceptexsockaddrs);
+ closesocket(s);
+
+ extension_fns_initialized = 1;
+}
+
+static struct win32_extension_fns the_extension_fns;
+
+const struct win32_extension_fns *
+event_get_win32_extension_fns_(void)
+{
+ return &the_extension_fns;
+}
+
+#define N_CPUS_DEFAULT 2
+
+struct event_iocp_port *
+event_iocp_port_launch_(int n_cpus)
+{
+ struct event_iocp_port *port;
+ int i;
+
+ if (!extension_fns_initialized)
+ init_extension_functions(&the_extension_fns);
+
+ if (!(port = mm_calloc(1, sizeof(struct event_iocp_port))))
+ return NULL;
+
+ if (n_cpus <= 0)
+ n_cpus = N_CPUS_DEFAULT;
+ port->n_threads = n_cpus * 2;
+ port->threads = mm_calloc(port->n_threads, sizeof(HANDLE));
+ if (!port->threads)
+ goto err;
+
+ port->port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0,
+ n_cpus);
+ port->ms = -1;
+ if (!port->port)
+ goto err;
+
+ port->shutdownSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
+ if (!port->shutdownSemaphore)
+ goto err;
+
+ for (i=0; i<port->n_threads; ++i) {
+ ev_uintptr_t th = _beginthread(loop, 0, port);
+ if (th == (ev_uintptr_t)-1)
+ goto err;
+ port->threads[i] = (HANDLE)th;
+ ++port->n_live_threads;
+ }
+
+ InitializeCriticalSectionAndSpinCount(&port->lock, 1000);
+
+ return port;
+err:
+ if (port->port)
+ CloseHandle(port->port);
+ if (port->threads)
+ mm_free(port->threads);
+ if (port->shutdownSemaphore)
+ CloseHandle(port->shutdownSemaphore);
+ mm_free(port);
+ return NULL;
+}
+
+static void
+event_iocp_port_unlock_and_free_(struct event_iocp_port *port)
+{
+ DeleteCriticalSection(&port->lock);
+ CloseHandle(port->port);
+ CloseHandle(port->shutdownSemaphore);
+ mm_free(port->threads);
+ mm_free(port);
+}
+
+static int
+event_iocp_notify_all(struct event_iocp_port *port)
+{
+ int i, r, ok=1;
+ for (i=0; i<port->n_threads; ++i) {
+ r = PostQueuedCompletionStatus(port->port, 0, NOTIFICATION_KEY,
+ NULL);
+ if (!r)
+ ok = 0;
+ }
+ return ok ? 0 : -1;
+}
+
+int
+event_iocp_shutdown_(struct event_iocp_port *port, long waitMsec)
+{
+ DWORD ms = INFINITE;
+ int n;
+
+ EnterCriticalSection(&port->lock);
+ port->shutdown = 1;
+ LeaveCriticalSection(&port->lock);
+ event_iocp_notify_all(port);
+
+ if (waitMsec >= 0)
+ ms = waitMsec;
+
+ WaitForSingleObject(port->shutdownSemaphore, ms);
+ EnterCriticalSection(&port->lock);
+ n = port->n_live_threads;
+ LeaveCriticalSection(&port->lock);
+ if (n == 0) {
+ event_iocp_port_unlock_and_free_(port);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int
+event_iocp_activate_overlapped_(
+ struct event_iocp_port *port, struct event_overlapped *o,
+ ev_uintptr_t key, ev_uint32_t n)
+{
+ BOOL r;
+
+ r = PostQueuedCompletionStatus(port->port, n, key, &o->overlapped);
+ return (r==0) ? -1 : 0;
+}
+
+struct event_iocp_port *
+event_base_get_iocp_(struct event_base *base)
+{
+#ifdef _WIN32
+ return base->iocp;
+#else
+ return NULL;
+#endif
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/event_rpcgen.py b/fluent-bit/lib/monkey/mk_core/deps/libevent/event_rpcgen.py
new file mode 100755
index 000000000..9baf73026
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/event_rpcgen.py
@@ -0,0 +1,1728 @@
+#!/usr/bin/env python2
+#
+# Copyright (c) 2005-2007 Niels Provos <provos@citi.umich.edu>
+# Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+# All rights reserved.
+#
+# Generates marshaling code based on libevent.
+
+# TODO:
+# 1) use optparse to allow the strategy shell to parse options, and
+# to allow the instantiated factory (for the specific output language)
+# to parse remaining options
+# 2) move the globals into a class that manages execution (including the
+# progress outputs that space stderr at the moment)
+# 3) emit other languages
+
+import sys
+import re
+
+_NAME = "event_rpcgen.py"
+_VERSION = "0.1"
+
+# Globals
+line_count = 0
+
+white = re.compile(r'\s+')
+cppcomment = re.compile(r'\/\/.*$')
+nonident = re.compile(r'[^a-zA-Z0-9_]')
+structref = re.compile(r'^struct\[([a-zA-Z_][a-zA-Z0-9_]*)\]$')
+structdef = re.compile(r'^struct +[a-zA-Z_][a-zA-Z0-9_]* *{$')
+
+headerdirect = []
+cppdirect = []
+
+QUIETLY = 0
+
+def declare(s):
+ if not QUIETLY:
+ print s
+
+def TranslateList(mylist, mydict):
+ return map(lambda x: x % mydict, mylist)
+
+# Exception class for parse errors
+class RpcGenError(Exception):
+ def __init__(self, why):
+ self.why = why
+ def __str__(self):
+ return str(self.why)
+
+# Holds everything that makes a struct
+class Struct:
+ def __init__(self, name):
+ self._name = name
+ self._entries = []
+ self._tags = {}
+ declare(' Created struct: %s' % name)
+
+ def AddEntry(self, entry):
+ if self._tags.has_key(entry.Tag()):
+ raise RpcGenError(
+ 'Entry "%s" duplicates tag number %d from "%s" '
+ 'around line %d' % (entry.Name(), entry.Tag(),
+ self._tags[entry.Tag()], line_count))
+ self._entries.append(entry)
+ self._tags[entry.Tag()] = entry.Name()
+ declare(' Added entry: %s' % entry.Name())
+
+ def Name(self):
+ return self._name
+
+ def EntryTagName(self, entry):
+ """Creates the name inside an enumeration for distinguishing data
+ types."""
+ name = "%s_%s" % (self._name, entry.Name())
+ return name.upper()
+
+ def PrintIndented(self, file, ident, code):
+ """Takes an array, add indentation to each entry and prints it."""
+ for entry in code:
+ print >>file, '%s%s' % (ident, entry)
+
+class StructCCode(Struct):
+ """ Knows how to generate C code for a struct """
+
+ def __init__(self, name):
+ Struct.__init__(self, name)
+
+ def PrintTags(self, file):
+ """Prints the tag definitions for a structure."""
+ print >>file, '/* Tag definition for %s */' % self._name
+ print >>file, 'enum %s_ {' % self._name.lower()
+ for entry in self._entries:
+ print >>file, ' %s=%d,' % (self.EntryTagName(entry),
+ entry.Tag())
+ print >>file, ' %s_MAX_TAGS' % (self._name.upper())
+ print >>file, '};\n'
+
+ def PrintForwardDeclaration(self, file):
+ print >>file, 'struct %s;' % self._name
+
+ def PrintDeclaration(self, file):
+ print >>file, '/* Structure declaration for %s */' % self._name
+ print >>file, 'struct %s_access_ {' % self._name
+ for entry in self._entries:
+ dcl = entry.AssignDeclaration('(*%s_assign)' % entry.Name())
+ dcl.extend(
+ entry.GetDeclaration('(*%s_get)' % entry.Name()))
+ if entry.Array():
+ dcl.extend(
+ entry.AddDeclaration('(*%s_add)' % entry.Name()))
+ self.PrintIndented(file, ' ', dcl)
+ print >>file, '};\n'
+
+ print >>file, 'struct %s {' % self._name
+ print >>file, ' struct %s_access_ *base;\n' % self._name
+ for entry in self._entries:
+ dcl = entry.Declaration()
+ self.PrintIndented(file, ' ', dcl)
+ print >>file, ''
+ for entry in self._entries:
+ print >>file, ' ev_uint8_t %s_set;' % entry.Name()
+ print >>file, '};\n'
+
+ print >>file, \
+"""struct %(name)s *%(name)s_new(void);
+struct %(name)s *%(name)s_new_with_arg(void *);
+void %(name)s_free(struct %(name)s *);
+void %(name)s_clear(struct %(name)s *);
+void %(name)s_marshal(struct evbuffer *, const struct %(name)s *);
+int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *);
+int %(name)s_complete(struct %(name)s *);
+void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t,
+ const struct %(name)s *);
+int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
+ struct %(name)s *);""" % { 'name' : self._name }
+
+
+ # Write a setting function of every variable
+ for entry in self._entries:
+ self.PrintIndented(file, '', entry.AssignDeclaration(
+ entry.AssignFuncName()))
+ self.PrintIndented(file, '', entry.GetDeclaration(
+ entry.GetFuncName()))
+ if entry.Array():
+ self.PrintIndented(file, '', entry.AddDeclaration(
+ entry.AddFuncName()))
+
+ print >>file, '/* --- %s done --- */\n' % self._name
+
+ def PrintCode(self, file):
+ print >>file, ('/*\n'
+ ' * Implementation of %s\n'
+ ' */\n') % self._name
+
+ print >>file, \
+ 'static struct %(name)s_access_ %(name)s_base__ = {' % \
+ { 'name' : self._name }
+ for entry in self._entries:
+ self.PrintIndented(file, ' ', entry.CodeBase())
+ print >>file, '};\n'
+
+ # Creation
+ print >>file, (
+ 'struct %(name)s *\n'
+ '%(name)s_new(void)\n'
+ '{\n'
+ ' return %(name)s_new_with_arg(NULL);\n'
+ '}\n'
+ '\n'
+ 'struct %(name)s *\n'
+ '%(name)s_new_with_arg(void *unused)\n'
+ '{\n'
+ ' struct %(name)s *tmp;\n'
+ ' if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {\n'
+ ' event_warn("%%s: malloc", __func__);\n'
+ ' return (NULL);\n'
+ ' }\n'
+ ' tmp->base = &%(name)s_base__;\n') % { 'name' : self._name }
+
+ for entry in self._entries:
+ self.PrintIndented(file, ' ', entry.CodeInitialize('tmp'))
+ print >>file, ' tmp->%s_set = 0;\n' % entry.Name()
+
+ print >>file, (
+ ' return (tmp);\n'
+ '}\n')
+
+ # Adding
+ for entry in self._entries:
+ if entry.Array():
+ self.PrintIndented(file, '', entry.CodeAdd())
+ print >>file, ''
+
+ # Assigning
+ for entry in self._entries:
+ self.PrintIndented(file, '', entry.CodeAssign())
+ print >>file, ''
+
+ # Getting
+ for entry in self._entries:
+ self.PrintIndented(file, '', entry.CodeGet())
+ print >>file, ''
+
+ # Clearing
+ print >>file, ( 'void\n'
+ '%(name)s_clear(struct %(name)s *tmp)\n'
+ '{'
+ ) % { 'name' : self._name }
+ for entry in self._entries:
+ self.PrintIndented(file, ' ', entry.CodeClear('tmp'))
+
+ print >>file, '}\n'
+
+ # Freeing
+ print >>file, ( 'void\n'
+ '%(name)s_free(struct %(name)s *tmp)\n'
+ '{'
+ ) % { 'name' : self._name }
+
+ for entry in self._entries:
+ self.PrintIndented(file, ' ', entry.CodeFree('tmp'))
+
+ print >>file, (' free(tmp);\n'
+ '}\n')
+
+ # Marshaling
+ print >>file, ('void\n'
+ '%(name)s_marshal(struct evbuffer *evbuf, '
+ 'const struct %(name)s *tmp)'
+ '{') % { 'name' : self._name }
+ for entry in self._entries:
+ indent = ' '
+ # Optional entries do not have to be set
+ if entry.Optional():
+ indent += ' '
+ print >>file, ' if (tmp->%s_set) {' % entry.Name()
+ self.PrintIndented(
+ file, indent,
+ entry.CodeMarshal('evbuf', self.EntryTagName(entry),
+ entry.GetVarName('tmp'),
+ entry.GetVarLen('tmp')))
+ if entry.Optional():
+ print >>file, ' }'
+
+ print >>file, '}\n'
+
+ # Unmarshaling
+ print >>file, ('int\n'
+ '%(name)s_unmarshal(struct %(name)s *tmp, '
+ ' struct evbuffer *evbuf)\n'
+ '{\n'
+ ' ev_uint32_t tag;\n'
+ ' while (evbuffer_get_length(evbuf) > 0) {\n'
+ ' if (evtag_peek(evbuf, &tag) == -1)\n'
+ ' return (-1);\n'
+ ' switch (tag) {\n'
+ ) % { 'name' : self._name }
+ for entry in self._entries:
+ print >>file, ' case %s:\n' % self.EntryTagName(entry)
+ if not entry.Array():
+ print >>file, (
+ ' if (tmp->%s_set)\n'
+ ' return (-1);'
+ ) % (entry.Name())
+
+ self.PrintIndented(
+ file, ' ',
+ entry.CodeUnmarshal('evbuf',
+ self.EntryTagName(entry),
+ entry.GetVarName('tmp'),
+ entry.GetVarLen('tmp')))
+
+ print >>file, ( ' tmp->%s_set = 1;\n' % entry.Name() +
+ ' break;\n' )
+ print >>file, ( ' default:\n'
+ ' return -1;\n'
+ ' }\n'
+ ' }\n' )
+ # Check if it was decoded completely
+ print >>file, ( ' if (%(name)s_complete(tmp) == -1)\n'
+ ' return (-1);'
+ ) % { 'name' : self._name }
+
+ # Successfully decoded
+ print >>file, ( ' return (0);\n'
+ '}\n')
+
+ # Checking if a structure has all the required data
+ print >>file, (
+ 'int\n'
+ '%(name)s_complete(struct %(name)s *msg)\n'
+ '{' ) % { 'name' : self._name }
+ for entry in self._entries:
+ if not entry.Optional():
+ code = [
+ 'if (!msg->%(name)s_set)',
+ ' return (-1);' ]
+ code = TranslateList(code, entry.GetTranslation())
+ self.PrintIndented(
+ file, ' ', code)
+
+ self.PrintIndented(
+ file, ' ',
+ entry.CodeComplete('msg', entry.GetVarName('msg')))
+ print >>file, (
+ ' return (0);\n'
+ '}\n' )
+
+ # Complete message unmarshaling
+ print >>file, (
+ 'int\n'
+ 'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, '
+ 'ev_uint32_t need_tag, struct %(name)s *msg)\n'
+ '{\n'
+ ' ev_uint32_t tag;\n'
+ ' int res = -1;\n'
+ '\n'
+ ' struct evbuffer *tmp = evbuffer_new();\n'
+ '\n'
+ ' if (evtag_unmarshal(evbuf, &tag, tmp) == -1'
+ ' || tag != need_tag)\n'
+ ' goto error;\n'
+ '\n'
+ ' if (%(name)s_unmarshal(msg, tmp) == -1)\n'
+ ' goto error;\n'
+ '\n'
+ ' res = 0;\n'
+ '\n'
+ ' error:\n'
+ ' evbuffer_free(tmp);\n'
+ ' return (res);\n'
+ '}\n' ) % { 'name' : self._name }
+
+ # Complete message marshaling
+ print >>file, (
+ 'void\n'
+ 'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, '
+ 'const struct %(name)s *msg)\n'
+ '{\n'
+ ' struct evbuffer *buf_ = evbuffer_new();\n'
+ ' assert(buf_ != NULL);\n'
+ ' %(name)s_marshal(buf_, msg);\n'
+ ' evtag_marshal_buffer(evbuf, tag, buf_);\n '
+ ' evbuffer_free(buf_);\n'
+ '}\n' ) % { 'name' : self._name }
+
+class Entry:
+ def __init__(self, type, name, tag):
+ self._type = type
+ self._name = name
+ self._tag = int(tag)
+ self._ctype = type
+ self._optional = 0
+ self._can_be_array = 0
+ self._array = 0
+ self._line_count = -1
+ self._struct = None
+ self._refname = None
+
+ self._optpointer = True
+ self._optaddarg = True
+
+ def GetInitializer(self):
+ assert 0, "Entry does not provide initializer"
+
+ def SetStruct(self, struct):
+ self._struct = struct
+
+ def LineCount(self):
+ assert self._line_count != -1
+ return self._line_count
+
+ def SetLineCount(self, number):
+ self._line_count = number
+
+ def Array(self):
+ return self._array
+
+ def Optional(self):
+ return self._optional
+
+ def Tag(self):
+ return self._tag
+
+ def Name(self):
+ return self._name
+
+ def Type(self):
+ return self._type
+
+ def MakeArray(self, yes=1):
+ self._array = yes
+
+ def MakeOptional(self):
+ self._optional = 1
+
+ def Verify(self):
+ if self.Array() and not self._can_be_array:
+ raise RpcGenError(
+ 'Entry "%s" cannot be created as an array '
+ 'around line %d' % (self._name, self.LineCount()))
+ if not self._struct:
+ raise RpcGenError(
+ 'Entry "%s" does not know which struct it belongs to '
+ 'around line %d' % (self._name, self.LineCount()))
+ if self._optional and self._array:
+ raise RpcGenError(
+ 'Entry "%s" has illegal combination of optional and array '
+ 'around line %d' % (self._name, self.LineCount()))
+
+ def GetTranslation(self, extradict = {}):
+ mapping = {
+ "parent_name" : self._struct.Name(),
+ "name" : self._name,
+ "ctype" : self._ctype,
+ "refname" : self._refname,
+ "optpointer" : self._optpointer and "*" or "",
+ "optreference" : self._optpointer and "&" or "",
+ "optaddarg" :
+ self._optaddarg and ", const %s value" % self._ctype or ""
+ }
+ for (k, v) in extradict.items():
+ mapping[k] = v
+
+ return mapping
+
+ def GetVarName(self, var):
+ return '%(var)s->%(name)s_data' % self.GetTranslation({ 'var' : var })
+
+ def GetVarLen(self, var):
+ return 'sizeof(%s)' % self._ctype
+
+ def GetFuncName(self):
+ return '%s_%s_get' % (self._struct.Name(), self._name)
+
+ def GetDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, %s *);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def CodeGet(self):
+ code = (
+ 'int',
+ '%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, '
+ '%(ctype)s *value)',
+ '{',
+ ' if (msg->%(name)s_set != 1)',
+ ' return (-1);',
+ ' *value = msg->%(name)s_data;',
+ ' return (0);',
+ '}' )
+ code = '\n'.join(code)
+ code = code % self.GetTranslation()
+ return code.split('\n')
+
+ def AssignFuncName(self):
+ return '%s_%s_assign' % (self._struct.Name(), self._name)
+
+ def AddFuncName(self):
+ return '%s_%s_add' % (self._struct.Name(), self._name)
+
+ def AssignDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, const %s);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def CodeAssign(self):
+ code = [ 'int',
+ '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,'
+ ' const %(ctype)s value)',
+ '{',
+ ' msg->%(name)s_set = 1;',
+ ' msg->%(name)s_data = value;',
+ ' return (0);',
+ '}' ]
+ code = '\n'.join(code)
+ code = code % self.GetTranslation()
+ return code.split('\n')
+
+ def CodeClear(self, structname):
+ code = [ '%s->%s_set = 0;' % (structname, self.Name()) ]
+
+ return code
+
+ def CodeComplete(self, structname, var_name):
+ return []
+
+ def CodeFree(self, name):
+ return []
+
+ def CodeBase(self):
+ code = [
+ '%(parent_name)s_%(name)s_assign,',
+ '%(parent_name)s_%(name)s_get,'
+ ]
+ if self.Array():
+ code.append('%(parent_name)s_%(name)s_add,')
+
+ code = '\n'.join(code)
+ code = code % self.GetTranslation()
+ return code.split('\n')
+
+class EntryBytes(Entry):
+ def __init__(self, type, name, tag, length):
+ # Init base class
+ Entry.__init__(self, type, name, tag)
+
+ self._length = length
+ self._ctype = 'ev_uint8_t'
+
+ def GetInitializer(self):
+ return "NULL"
+
+ def GetVarLen(self, var):
+ return '(%s)' % self._length
+
+ def CodeArrayAdd(self, varname, value):
+ # XXX: copy here
+ return [ '%(varname)s = NULL;' % { 'varname' : varname } ]
+
+ def GetDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, %s **);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def AssignDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, const %s *);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def Declaration(self):
+ dcl = ['ev_uint8_t %s_data[%s];' % (self._name, self._length)]
+
+ return dcl
+
+ def CodeGet(self):
+ name = self._name
+ code = [ 'int',
+ '%s_%s_get(struct %s *msg, %s **value)' % (
+ self._struct.Name(), name,
+ self._struct.Name(), self._ctype),
+ '{',
+ ' if (msg->%s_set != 1)' % name,
+ ' return (-1);',
+ ' *value = msg->%s_data;' % name,
+ ' return (0);',
+ '}' ]
+ return code
+
+ def CodeAssign(self):
+ name = self._name
+ code = [ 'int',
+ '%s_%s_assign(struct %s *msg, const %s *value)' % (
+ self._struct.Name(), name,
+ self._struct.Name(), self._ctype),
+ '{',
+ ' msg->%s_set = 1;' % name,
+ ' memcpy(msg->%s_data, value, %s);' % (
+ name, self._length),
+ ' return (0);',
+ '}' ]
+ return code
+
+ def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
+ code = [ 'if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, '
+ '%(var)s, %(varlen)s) == -1) {',
+ ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+ ' return (-1);',
+ '}'
+ ]
+ return TranslateList(code,
+ self.GetTranslation({
+ 'var' : var_name,
+ 'varlen' : var_len,
+ 'buf' : buf,
+ 'tag' : tag_name }))
+
+ def CodeMarshal(self, buf, tag_name, var_name, var_len):
+ code = ['evtag_marshal(%s, %s, %s, %s);' % (
+ buf, tag_name, var_name, var_len)]
+ return code
+
+ def CodeClear(self, structname):
+ code = [ '%s->%s_set = 0;' % (structname, self.Name()),
+ 'memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
+ structname, self._name, structname, self._name)]
+
+ return code
+
+ def CodeInitialize(self, name):
+ code = ['memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
+ name, self._name, name, self._name)]
+ return code
+
+ def Verify(self):
+ if not self._length:
+ raise RpcGenError(
+ 'Entry "%s" needs a length '
+ 'around line %d' % (self._name, self.LineCount()))
+
+ Entry.Verify(self)
+
+class EntryInt(Entry):
+ def __init__(self, type, name, tag, bits=32):
+ # Init base class
+ Entry.__init__(self, type, name, tag)
+
+ self._can_be_array = 1
+ if bits == 32:
+ self._ctype = 'ev_uint32_t'
+ self._marshal_type = 'int'
+ if bits == 64:
+ self._ctype = 'ev_uint64_t'
+ self._marshal_type = 'int64'
+
+ def GetInitializer(self):
+ return "0"
+
+ def CodeArrayFree(self, var):
+ return []
+
+ def CodeArrayAssign(self, varname, srcvar):
+ return [ '%(varname)s = %(srcvar)s;' % { 'varname' : varname,
+ 'srcvar' : srcvar } ]
+
+ def CodeArrayAdd(self, varname, value):
+ """Returns a new entry of this type."""
+ return [ '%(varname)s = %(value)s;' % { 'varname' : varname,
+ 'value' : value } ]
+
+ def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
+ code = [
+ 'if (evtag_unmarshal_%(ma)s(%(buf)s, %(tag)s, &%(var)s) == -1) {',
+ ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+ ' return (-1);',
+ '}' ]
+ code = '\n'.join(code) % self.GetTranslation({
+ 'ma' : self._marshal_type,
+ 'buf' : buf,
+ 'tag' : tag_name,
+ 'var' : var_name })
+ return code.split('\n')
+
+ def CodeMarshal(self, buf, tag_name, var_name, var_len):
+ code = [
+ 'evtag_marshal_%s(%s, %s, %s);' % (
+ self._marshal_type, buf, tag_name, var_name)]
+ return code
+
+ def Declaration(self):
+ dcl = ['%s %s_data;' % (self._ctype, self._name)]
+
+ return dcl
+
+ def CodeInitialize(self, name):
+ code = ['%s->%s_data = 0;' % (name, self._name)]
+ return code
+
+class EntryString(Entry):
+ def __init__(self, type, name, tag):
+ # Init base class
+ Entry.__init__(self, type, name, tag)
+
+ self._can_be_array = 1
+ self._ctype = 'char *'
+
+ def GetInitializer(self):
+ return "NULL"
+
+ def CodeArrayFree(self, varname):
+ code = [
+ 'if (%(var)s != NULL) free(%(var)s);' ]
+
+ return TranslateList(code, { 'var' : varname })
+
+ def CodeArrayAssign(self, varname, srcvar):
+ code = [
+ 'if (%(var)s != NULL)',
+ ' free(%(var)s);',
+ '%(var)s = strdup(%(srcvar)s);',
+ 'if (%(var)s == NULL) {',
+ ' event_warnx("%%s: strdup", __func__);',
+ ' return (-1);',
+ '}' ]
+
+ return TranslateList(code, { 'var' : varname,
+ 'srcvar' : srcvar })
+
+ def CodeArrayAdd(self, varname, value):
+ code = [
+ 'if (%(value)s != NULL) {',
+ ' %(var)s = strdup(%(value)s);',
+ ' if (%(var)s == NULL) {',
+ ' goto error;',
+ ' }',
+ '} else {',
+ ' %(var)s = NULL;',
+ '}' ]
+
+ return TranslateList(code, { 'var' : varname,
+ 'value' : value })
+
+ def GetVarLen(self, var):
+ return 'strlen(%s)' % self.GetVarName(var)
+
+ def CodeMakeInitalize(self, varname):
+ return '%(varname)s = NULL;' % { 'varname' : varname }
+
+ def CodeAssign(self):
+ name = self._name
+ code = """int
+%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
+ const %(ctype)s value)
+{
+ if (msg->%(name)s_data != NULL)
+ free(msg->%(name)s_data);
+ if ((msg->%(name)s_data = strdup(value)) == NULL)
+ return (-1);
+ msg->%(name)s_set = 1;
+ return (0);
+}""" % self.GetTranslation()
+
+ return code.split('\n')
+
+ def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
+ code = ['if (evtag_unmarshal_string(%(buf)s, %(tag)s, &%(var)s) == -1) {',
+ ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+ ' return (-1);',
+ '}'
+ ]
+ code = '\n'.join(code) % self.GetTranslation({
+ 'buf' : buf,
+ 'tag' : tag_name,
+ 'var' : var_name })
+ return code.split('\n')
+
+ def CodeMarshal(self, buf, tag_name, var_name, var_len):
+ code = ['evtag_marshal_string(%s, %s, %s);' % (
+ buf, tag_name, var_name)]
+ return code
+
+ def CodeClear(self, structname):
+ code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+ ' free(%s->%s_data);' % (structname, self.Name()),
+ ' %s->%s_data = NULL;' % (structname, self.Name()),
+ ' %s->%s_set = 0;' % (structname, self.Name()),
+ '}'
+ ]
+
+ return code
+
+ def CodeInitialize(self, name):
+ code = ['%s->%s_data = NULL;' % (name, self._name)]
+ return code
+
+ def CodeFree(self, name):
+ code = ['if (%s->%s_data != NULL)' % (name, self._name),
+ ' free (%s->%s_data);' % (name, self._name)]
+
+ return code
+
+ def Declaration(self):
+ dcl = ['char *%s_data;' % self._name]
+
+ return dcl
+
+class EntryStruct(Entry):
+ def __init__(self, type, name, tag, refname):
+ # Init base class
+ Entry.__init__(self, type, name, tag)
+
+ self._optpointer = False
+ self._can_be_array = 1
+ self._refname = refname
+ self._ctype = 'struct %s*' % refname
+ self._optaddarg = False
+
+ def GetInitializer(self):
+ return "NULL"
+
+ def GetVarLen(self, var):
+ return '-1'
+
+ def CodeArrayAdd(self, varname, value):
+ code = [
+ '%(varname)s = %(refname)s_new();',
+ 'if (%(varname)s == NULL)',
+ ' goto error;' ]
+
+ return TranslateList(code, self.GetTranslation({ 'varname' : varname }))
+
+ def CodeArrayFree(self, var):
+ code = [ '%(refname)s_free(%(var)s);' % self.GetTranslation(
+ { 'var' : var }) ]
+ return code
+
+ def CodeArrayAssign(self, var, srcvar):
+ code = [
+ 'int had_error = 0;',
+ 'struct evbuffer *tmp = NULL;',
+ '%(refname)s_clear(%(var)s);',
+ 'if ((tmp = evbuffer_new()) == NULL) {',
+ ' event_warn("%%s: evbuffer_new()", __func__);',
+ ' had_error = 1;',
+ ' goto done;',
+ '}',
+ '%(refname)s_marshal(tmp, %(srcvar)s);',
+ 'if (%(refname)s_unmarshal(%(var)s, tmp) == -1) {',
+ ' event_warnx("%%s: %(refname)s_unmarshal", __func__);',
+ ' had_error = 1;',
+ ' goto done;',
+ '}',
+ 'done:'
+ 'if (tmp != NULL)',
+ ' evbuffer_free(tmp);',
+ 'if (had_error) {',
+ ' %(refname)s_clear(%(var)s);',
+ ' return (-1);',
+ '}' ]
+
+ return TranslateList(code, self.GetTranslation({
+ 'var' : var,
+ 'srcvar' : srcvar}))
+
+ def CodeGet(self):
+ name = self._name
+ code = [ 'int',
+ '%s_%s_get(struct %s *msg, %s *value)' % (
+ self._struct.Name(), name,
+ self._struct.Name(), self._ctype),
+ '{',
+ ' if (msg->%s_set != 1) {' % name,
+ ' msg->%s_data = %s_new();' % (name, self._refname),
+ ' if (msg->%s_data == NULL)' % name,
+ ' return (-1);',
+ ' msg->%s_set = 1;' % name,
+ ' }',
+ ' *value = msg->%s_data;' % name,
+ ' return (0);',
+ '}' ]
+ return code
+
+ def CodeAssign(self):
+ name = self._name
+ code = """int
+%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
+ const %(ctype)s value)
+{
+ struct evbuffer *tmp = NULL;
+ if (msg->%(name)s_set) {
+ %(refname)s_clear(msg->%(name)s_data);
+ msg->%(name)s_set = 0;
+ } else {
+ msg->%(name)s_data = %(refname)s_new();
+ if (msg->%(name)s_data == NULL) {
+ event_warn("%%s: %(refname)s_new()", __func__);
+ goto error;
+ }
+ }
+ if ((tmp = evbuffer_new()) == NULL) {
+ event_warn("%%s: evbuffer_new()", __func__);
+ goto error;
+ }
+ %(refname)s_marshal(tmp, value);
+ if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) {
+ event_warnx("%%s: %(refname)s_unmarshal", __func__);
+ goto error;
+ }
+ msg->%(name)s_set = 1;
+ evbuffer_free(tmp);
+ return (0);
+ error:
+ if (tmp != NULL)
+ evbuffer_free(tmp);
+ if (msg->%(name)s_data != NULL) {
+ %(refname)s_free(msg->%(name)s_data);
+ msg->%(name)s_data = NULL;
+ }
+ return (-1);
+}""" % self.GetTranslation()
+ return code.split('\n')
+
+ def CodeComplete(self, structname, var_name):
+ code = [ 'if (%(structname)s->%(name)s_set && '
+ '%(refname)s_complete(%(var)s) == -1)',
+ ' return (-1);' ]
+
+ return TranslateList(code, self.GetTranslation({
+ 'structname' : structname,
+ 'var' : var_name }))
+
+ def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
+ code = ['%(var)s = %(refname)s_new();',
+ 'if (%(var)s == NULL)',
+ ' return (-1);',
+ 'if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag)s, '
+ '%(var)s) == -1) {',
+ ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+ ' return (-1);',
+ '}'
+ ]
+ code = '\n'.join(code) % self.GetTranslation({
+ 'buf' : buf,
+ 'tag' : tag_name,
+ 'var' : var_name })
+ return code.split('\n')
+
+ def CodeMarshal(self, buf, tag_name, var_name, var_len):
+ code = ['evtag_marshal_%s(%s, %s, %s);' % (
+ self._refname, buf, tag_name, var_name)]
+ return code
+
+ def CodeClear(self, structname):
+ code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+ ' %s_free(%s->%s_data);' % (
+ self._refname, structname, self.Name()),
+ ' %s->%s_data = NULL;' % (structname, self.Name()),
+ ' %s->%s_set = 0;' % (structname, self.Name()),
+ '}'
+ ]
+
+ return code
+
+ def CodeInitialize(self, name):
+ code = ['%s->%s_data = NULL;' % (name, self._name)]
+ return code
+
+ def CodeFree(self, name):
+ code = ['if (%s->%s_data != NULL)' % (name, self._name),
+ ' %s_free(%s->%s_data);' % (
+ self._refname, name, self._name)]
+
+ return code
+
+ def Declaration(self):
+ dcl = ['%s %s_data;' % (self._ctype, self._name)]
+
+ return dcl
+
+class EntryVarBytes(Entry):
+ def __init__(self, type, name, tag):
+ # Init base class
+ Entry.__init__(self, type, name, tag)
+
+ self._ctype = 'ev_uint8_t *'
+
+ def GetInitializer(self):
+ return "NULL"
+
+ def GetVarLen(self, var):
+ return '%(var)s->%(name)s_length' % self.GetTranslation({ 'var' : var })
+
+ def CodeArrayAdd(self, varname, value):
+ # xxx: copy
+ return [ '%(varname)s = NULL;' % { 'varname' : varname } ]
+
+ def GetDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, %s *, ev_uint32_t *);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def AssignDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, const %s, ev_uint32_t);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def CodeAssign(self):
+ name = self._name
+ code = [ 'int',
+ '%s_%s_assign(struct %s *msg, '
+ 'const %s value, ev_uint32_t len)' % (
+ self._struct.Name(), name,
+ self._struct.Name(), self._ctype),
+ '{',
+ ' if (msg->%s_data != NULL)' % name,
+ ' free (msg->%s_data);' % name,
+ ' msg->%s_data = malloc(len);' % name,
+ ' if (msg->%s_data == NULL)' % name,
+ ' return (-1);',
+ ' msg->%s_set = 1;' % name,
+ ' msg->%s_length = len;' % name,
+ ' memcpy(msg->%s_data, value, len);' % name,
+ ' return (0);',
+ '}' ]
+ return code
+
+ def CodeGet(self):
+ name = self._name
+ code = [ 'int',
+ '%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)' % (
+ self._struct.Name(), name,
+ self._struct.Name(), self._ctype),
+ '{',
+ ' if (msg->%s_set != 1)' % name,
+ ' return (-1);',
+ ' *value = msg->%s_data;' % name,
+ ' *plen = msg->%s_length;' % name,
+ ' return (0);',
+ '}' ]
+ return code
+
+ def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
+ code = ['if (evtag_payload_length(%(buf)s, &%(varlen)s) == -1)',
+ ' return (-1);',
+ # We do not want DoS opportunities
+ 'if (%(varlen)s > evbuffer_get_length(%(buf)s))',
+ ' return (-1);',
+ 'if ((%(var)s = malloc(%(varlen)s)) == NULL)',
+ ' return (-1);',
+ 'if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, %(var)s, '
+ '%(varlen)s) == -1) {',
+ ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+ ' return (-1);',
+ '}'
+ ]
+ code = '\n'.join(code) % self.GetTranslation({
+ 'buf' : buf,
+ 'tag' : tag_name,
+ 'var' : var_name,
+ 'varlen' : var_len })
+ return code.split('\n')
+
+ def CodeMarshal(self, buf, tag_name, var_name, var_len):
+ code = ['evtag_marshal(%s, %s, %s, %s);' % (
+ buf, tag_name, var_name, var_len)]
+ return code
+
+ def CodeClear(self, structname):
+ code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+ ' free (%s->%s_data);' % (structname, self.Name()),
+ ' %s->%s_data = NULL;' % (structname, self.Name()),
+ ' %s->%s_length = 0;' % (structname, self.Name()),
+ ' %s->%s_set = 0;' % (structname, self.Name()),
+ '}'
+ ]
+
+ return code
+
+ def CodeInitialize(self, name):
+ code = ['%s->%s_data = NULL;' % (name, self._name),
+ '%s->%s_length = 0;' % (name, self._name) ]
+ return code
+
+ def CodeFree(self, name):
+ code = ['if (%s->%s_data != NULL)' % (name, self._name),
+ ' free(%s->%s_data);' % (name, self._name)]
+
+ return code
+
+ def Declaration(self):
+ dcl = ['ev_uint8_t *%s_data;' % self._name,
+ 'ev_uint32_t %s_length;' % self._name]
+
+ return dcl
+
+class EntryArray(Entry):
+ def __init__(self, entry):
+ # Init base class
+ Entry.__init__(self, entry._type, entry._name, entry._tag)
+
+ self._entry = entry
+ self._refname = entry._refname
+ self._ctype = self._entry._ctype
+ self._optional = True
+ self._optpointer = self._entry._optpointer
+ self._optaddarg = self._entry._optaddarg
+
+ # provide a new function for accessing the variable name
+ def GetVarName(var_name):
+ return '%(var)s->%(name)s_data[%(index)s]' % \
+ self._entry.GetTranslation({'var' : var_name,
+ 'index' : self._index})
+ self._entry.GetVarName = GetVarName
+
+ def GetInitializer(self):
+ return "NULL"
+
+ def GetVarName(self, var_name):
+ return var_name
+
+ def GetVarLen(self, var_name):
+ return '-1'
+
+ def GetDeclaration(self, funcname):
+ """Allows direct access to elements of the array."""
+ code = [
+ 'int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);' %
+ self.GetTranslation({ 'funcname' : funcname }) ]
+ return code
+
+ def AssignDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, int, const %s);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def AddDeclaration(self, funcname):
+ code = [
+ '%(ctype)s %(optpointer)s '
+ '%(funcname)s(struct %(parent_name)s *msg%(optaddarg)s);' % \
+ self.GetTranslation({ 'funcname' : funcname }) ]
+ return code
+
+ def CodeGet(self):
+ code = """int
+%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset,
+ %(ctype)s *value)
+{
+ if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length)
+ return (-1);
+ *value = msg->%(name)s_data[offset];
+ return (0);
+}""" % self.GetTranslation()
+
+ return code.split('\n')
+
+ def CodeAssign(self):
+ code = [
+ 'int',
+ '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,',
+ ' const %(ctype)s value)',
+ '{',
+ ' if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)',
+ ' return (-1);\n',
+ ' {' ]
+ code = TranslateList(code, self.GetTranslation())
+
+ codearrayassign = self._entry.CodeArrayAssign(
+ 'msg->%(name)s_data[off]' % self.GetTranslation(), 'value')
+ code += map(lambda x: ' ' + x, codearrayassign)
+
+ code += TranslateList([
+ ' }',
+ ' return (0);',
+ '}' ], self.GetTranslation())
+
+ return code
+
+ def CodeAdd(self):
+ codearrayadd = self._entry.CodeArrayAdd(
+ 'msg->%(name)s_data[msg->%(name)s_length - 1]' % self.GetTranslation(),
+ 'value')
+ code = [
+ 'static int',
+ '%(parent_name)s_%(name)s_expand_to_hold_more('
+ 'struct %(parent_name)s *msg)',
+ '{',
+ ' int tobe_allocated = msg->%(name)s_num_allocated;',
+ ' %(ctype)s* new_data = NULL;',
+ ' tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;',
+ ' new_data = (%(ctype)s*) realloc(msg->%(name)s_data,',
+ ' tobe_allocated * sizeof(%(ctype)s));',
+ ' if (new_data == NULL)',
+ ' return -1;',
+ ' msg->%(name)s_data = new_data;',
+ ' msg->%(name)s_num_allocated = tobe_allocated;',
+ ' return 0;'
+ '}',
+ '',
+ '%(ctype)s %(optpointer)s',
+ '%(parent_name)s_%(name)s_add('
+ 'struct %(parent_name)s *msg%(optaddarg)s)',
+ '{',
+ ' if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {',
+ ' if (%(parent_name)s_%(name)s_expand_to_hold_more(msg)<0)',
+ ' goto error;',
+ ' }' ]
+
+ code = TranslateList(code, self.GetTranslation())
+
+ code += map(lambda x: ' ' + x, codearrayadd)
+
+ code += TranslateList([
+ ' msg->%(name)s_set = 1;',
+ ' return %(optreference)s(msg->%(name)s_data['
+ 'msg->%(name)s_length - 1]);',
+ 'error:',
+ ' --msg->%(name)s_length;',
+ ' return (NULL);',
+ '}' ], self.GetTranslation())
+
+ return code
+
+ def CodeComplete(self, structname, var_name):
+ self._index = 'i'
+ tmp = self._entry.CodeComplete(structname, self._entry.GetVarName(var_name))
+ # skip the whole loop if there is nothing to check
+ if not tmp:
+ return []
+
+ translate = self.GetTranslation({ 'structname' : structname })
+ code = [
+ '{',
+ ' int i;',
+ ' for (i = 0; i < %(structname)s->%(name)s_length; ++i) {' ]
+
+ code = TranslateList(code, translate)
+
+ code += map(lambda x: ' ' + x, tmp)
+
+ code += [
+ ' }',
+ '}' ]
+
+ return code
+
+ def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
+ translate = self.GetTranslation({ 'var' : var_name,
+ 'buf' : buf,
+ 'tag' : tag_name,
+ 'init' : self._entry.GetInitializer()})
+ code = [
+ 'if (%(var)s->%(name)s_length >= %(var)s->%(name)s_num_allocated &&',
+ ' %(parent_name)s_%(name)s_expand_to_hold_more(%(var)s) < 0) {',
+ ' puts("HEY NOW");',
+ ' return (-1);',
+ '}']
+
+ # the unmarshal code directly returns
+ code = TranslateList(code, translate)
+
+ self._index = '%(var)s->%(name)s_length' % translate
+ code += self._entry.CodeUnmarshal(buf, tag_name,
+ self._entry.GetVarName(var_name),
+ self._entry.GetVarLen(var_name))
+
+ code += [ '++%(var)s->%(name)s_length;' % translate ]
+
+ return code
+
+ def CodeMarshal(self, buf, tag_name, var_name, var_len):
+ code = ['{',
+ ' int i;',
+ ' for (i = 0; i < %(var)s->%(name)s_length; ++i) {' ]
+
+ self._index = 'i'
+ code += self._entry.CodeMarshal(buf, tag_name,
+ self._entry.GetVarName(var_name),
+ self._entry.GetVarLen(var_name))
+ code += [' }',
+ '}'
+ ]
+
+ code = "\n".join(code) % self.GetTranslation({ 'var' : var_name })
+
+ return code.split('\n')
+
+ def CodeClear(self, structname):
+ translate = self.GetTranslation({ 'structname' : structname })
+ codearrayfree = self._entry.CodeArrayFree(
+ '%(structname)s->%(name)s_data[i]' % self.GetTranslation(
+ { 'structname' : structname } ))
+
+ code = [ 'if (%(structname)s->%(name)s_set == 1) {' ]
+
+ if codearrayfree:
+ code += [
+ ' int i;',
+ ' for (i = 0; i < %(structname)s->%(name)s_length; ++i) {' ]
+
+ code = TranslateList(code, translate)
+
+ if codearrayfree:
+ code += map(lambda x: ' ' + x, codearrayfree)
+ code += [
+ ' }' ]
+
+ code += TranslateList([
+ ' free(%(structname)s->%(name)s_data);',
+ ' %(structname)s->%(name)s_data = NULL;',
+ ' %(structname)s->%(name)s_set = 0;',
+ ' %(structname)s->%(name)s_length = 0;',
+ ' %(structname)s->%(name)s_num_allocated = 0;',
+ '}'
+ ], translate)
+
+ return code
+
+ def CodeInitialize(self, name):
+ code = ['%s->%s_data = NULL;' % (name, self._name),
+ '%s->%s_length = 0;' % (name, self._name),
+ '%s->%s_num_allocated = 0;' % (name, self._name)]
+ return code
+
+ def CodeFree(self, structname):
+ code = self.CodeClear(structname);
+
+ code += TranslateList([
+ 'free(%(structname)s->%(name)s_data);' ],
+ self.GetTranslation({'structname' : structname }))
+
+ return code
+
+ def Declaration(self):
+ dcl = ['%s *%s_data;' % (self._ctype, self._name),
+ 'int %s_length;' % self._name,
+ 'int %s_num_allocated;' % self._name ]
+
+ return dcl
+
+def NormalizeLine(line):
+ global white
+ global cppcomment
+
+ line = cppcomment.sub('', line)
+ line = line.strip()
+ line = white.sub(' ', line)
+
+ return line
+
+def ProcessOneEntry(factory, newstruct, entry):
+ optional = 0
+ array = 0
+ entry_type = ''
+ name = ''
+ tag = ''
+ tag_set = None
+ separator = ''
+ fixed_length = ''
+
+ tokens = entry.split(' ')
+ while tokens:
+ token = tokens[0]
+ tokens = tokens[1:]
+
+ if not entry_type:
+ if not optional and token == 'optional':
+ optional = 1
+ continue
+
+ if not array and token == 'array':
+ array = 1
+ continue
+
+ if not entry_type:
+ entry_type = token
+ continue
+
+ if not name:
+ res = re.match(r'^([^\[\]]+)(\[.*\])?$', token)
+ if not res:
+ raise RpcGenError(
+ 'Cannot parse name: \"%s\" '
+ 'around line %d' % (entry, line_count))
+ name = res.group(1)
+ fixed_length = res.group(2)
+ if fixed_length:
+ fixed_length = fixed_length[1:-1]
+ continue
+
+ if not separator:
+ separator = token
+ if separator != '=':
+ raise RpcGenError('Expected "=" after name \"%s\" got %s'
+ % (name, token))
+ continue
+
+ if not tag_set:
+ tag_set = 1
+ if not re.match(r'^(0x)?[0-9]+$', token):
+ raise RpcGenError('Expected tag number: \"%s\"' % entry)
+ tag = int(token, 0)
+ continue
+
+ raise RpcGenError('Cannot parse \"%s\"' % entry)
+
+ if not tag_set:
+ raise RpcGenError('Need tag number: \"%s\"' % entry)
+
+ # Create the right entry
+ if entry_type == 'bytes':
+ if fixed_length:
+ newentry = factory.EntryBytes(entry_type, name, tag, fixed_length)
+ else:
+ newentry = factory.EntryVarBytes(entry_type, name, tag)
+ elif entry_type == 'int' and not fixed_length:
+ newentry = factory.EntryInt(entry_type, name, tag)
+ elif entry_type == 'int64' and not fixed_length:
+ newentry = factory.EntryInt(entry_type, name, tag, bits=64)
+ elif entry_type == 'string' and not fixed_length:
+ newentry = factory.EntryString(entry_type, name, tag)
+ else:
+ res = structref.match(entry_type)
+ if res:
+ # References another struct defined in our file
+ newentry = factory.EntryStruct(entry_type, name, tag, res.group(1))
+ else:
+ raise RpcGenError('Bad type: "%s" in "%s"' % (entry_type, entry))
+
+ structs = []
+
+ if optional:
+ newentry.MakeOptional()
+ if array:
+ newentry.MakeArray()
+
+ newentry.SetStruct(newstruct)
+ newentry.SetLineCount(line_count)
+ newentry.Verify()
+
+ if array:
+ # We need to encapsulate this entry into a struct
+ newname = newentry.Name()+ '_array'
+
+ # Now borgify the new entry.
+ newentry = factory.EntryArray(newentry)
+ newentry.SetStruct(newstruct)
+ newentry.SetLineCount(line_count)
+ newentry.MakeArray()
+
+ newstruct.AddEntry(newentry)
+
+ return structs
+
+def ProcessStruct(factory, data):
+ tokens = data.split(' ')
+
+ # First three tokens are: 'struct' 'name' '{'
+ newstruct = factory.Struct(tokens[1])
+
+ inside = ' '.join(tokens[3:-1])
+
+ tokens = inside.split(';')
+
+ structs = []
+
+ for entry in tokens:
+ entry = NormalizeLine(entry)
+ if not entry:
+ continue
+
+ # It's possible that new structs get defined in here
+ structs.extend(ProcessOneEntry(factory, newstruct, entry))
+
+ structs.append(newstruct)
+ return structs
+
+def GetNextStruct(file):
+ global line_count
+ global cppdirect
+
+ got_struct = 0
+
+ processed_lines = []
+
+ have_c_comment = 0
+ data = ''
+ while 1:
+ line = file.readline()
+ if not line:
+ break
+
+ line_count += 1
+ line = line[:-1]
+
+ if not have_c_comment and re.search(r'/\*', line):
+ if re.search(r'/\*.*?\*/', line):
+ line = re.sub(r'/\*.*?\*/', '', line)
+ else:
+ line = re.sub(r'/\*.*$', '', line)
+ have_c_comment = 1
+
+ if have_c_comment:
+ if not re.search(r'\*/', line):
+ continue
+ have_c_comment = 0
+ line = re.sub(r'^.*\*/', '', line)
+
+ line = NormalizeLine(line)
+
+ if not line:
+ continue
+
+ if not got_struct:
+ if re.match(r'#include ["<].*[>"]', line):
+ cppdirect.append(line)
+ continue
+
+ if re.match(r'^#(if( |def)|endif)', line):
+ cppdirect.append(line)
+ continue
+
+ if re.match(r'^#define', line):
+ headerdirect.append(line)
+ continue
+
+ if not structdef.match(line):
+ raise RpcGenError('Missing struct on line %d: %s'
+ % (line_count, line))
+ else:
+ got_struct = 1
+ data += line
+ continue
+
+ # We are inside the struct
+ tokens = line.split('}')
+ if len(tokens) == 1:
+ data += ' ' + line
+ continue
+
+ if len(tokens[1]):
+ raise RpcGenError('Trailing garbage after struct on line %d'
+ % line_count)
+
+ # We found the end of the struct
+ data += ' %s}' % tokens[0]
+ break
+
+ # Remove any comments, that might be in there
+ data = re.sub(r'/\*.*\*/', '', data)
+
+ return data
+
+
+def Parse(factory, file):
+ """
+ Parses the input file and returns C code and corresponding header file.
+ """
+
+ entities = []
+
+ while 1:
+ # Just gets the whole struct nicely formatted
+ data = GetNextStruct(file)
+
+ if not data:
+ break
+
+ entities.extend(ProcessStruct(factory, data))
+
+ return entities
+
+class CCodeGenerator:
+ def __init__(self):
+ pass
+
+ def GuardName(self, name):
+ # Use the complete provided path to the input file, with all
+ # non-identifier characters replaced with underscores, to
+ # reduce the chance of a collision between guard macros.
+ return 'EVENT_RPCOUT_' + nonident.sub('_', name).upper() + '_'
+
+ def HeaderPreamble(self, name):
+ guard = self.GuardName(name)
+ pre = (
+ '/*\n'
+ ' * Automatically generated from %s\n'
+ ' */\n\n'
+ '#ifndef %s\n'
+ '#define %s\n\n' ) % (
+ name, guard, guard)
+
+ for statement in headerdirect:
+ pre += '%s\n' % statement
+ if headerdirect:
+ pre += '\n'
+
+ pre += (
+ '#include <event2/util.h> /* for ev_uint*_t */\n'
+ '#include <event2/rpc.h>\n'
+ )
+
+ return pre
+
+ def HeaderPostamble(self, name):
+ guard = self.GuardName(name)
+ return '#endif /* %s */' % guard
+
+ def BodyPreamble(self, name, header_file):
+ global _NAME
+ global _VERSION
+
+ slash = header_file.rfind('/')
+ if slash != -1:
+ header_file = header_file[slash+1:]
+
+ pre = ( '/*\n'
+ ' * Automatically generated from %s\n'
+ ' * by %s/%s. DO NOT EDIT THIS FILE.\n'
+ ' */\n\n' ) % (name, _NAME, _VERSION)
+ pre += ( '#include <stdlib.h>\n'
+ '#include <string.h>\n'
+ '#include <assert.h>\n'
+ '#include <event2/event-config.h>\n'
+ '#include <event2/event.h>\n'
+ '#include <event2/buffer.h>\n'
+ '#include <event2/tag.h>\n\n'
+ '#if defined(EVENT____func__) && !defined(__func__)\n'
+ '#define __func__ EVENT____func__\n'
+ '#endif\n\n'
+ )
+
+ for statement in cppdirect:
+ pre += '%s\n' % statement
+
+ pre += '\n#include "%s"\n\n' % header_file
+
+ pre += 'void event_warn(const char *fmt, ...);\n'
+ pre += 'void event_warnx(const char *fmt, ...);\n\n'
+
+ return pre
+
+ def HeaderFilename(self, filename):
+ return '.'.join(filename.split('.')[:-1]) + '.h'
+
+ def CodeFilename(self, filename):
+ return '.'.join(filename.split('.')[:-1]) + '.gen.c'
+
+ def Struct(self, name):
+ return StructCCode(name)
+
+ def EntryBytes(self, entry_type, name, tag, fixed_length):
+ return EntryBytes(entry_type, name, tag, fixed_length)
+
+ def EntryVarBytes(self, entry_type, name, tag):
+ return EntryVarBytes(entry_type, name, tag)
+
+ def EntryInt(self, entry_type, name, tag, bits=32):
+ return EntryInt(entry_type, name, tag, bits)
+
+ def EntryString(self, entry_type, name, tag):
+ return EntryString(entry_type, name, tag)
+
+ def EntryStruct(self, entry_type, name, tag, struct_name):
+ return EntryStruct(entry_type, name, tag, struct_name)
+
+ def EntryArray(self, entry):
+ return EntryArray(entry)
+
+class Usage(RpcGenError):
+ def __init__(self, argv0):
+ RpcGenError.__init__("usage: %s input.rpc [[output.h] output.c]"
+ % argv0)
+
+class CommandLine:
+ def __init__(self, argv):
+ """Initialize a command-line to launch event_rpcgen, as if
+ from a command-line with CommandLine(sys.argv). If you're
+ calling this directly, remember to provide a dummy value
+ for sys.argv[0]
+ """
+ self.filename = None
+ self.header_file = None
+ self.impl_file = None
+ self.factory = CCodeGenerator()
+
+ if len(argv) >= 2 and argv[1] == '--quiet':
+ global QUIETLY
+ QUIETLY = 1
+ del argv[1]
+
+ if len(argv) < 2 or len(argv) > 4:
+ raise Usage(argv[0])
+
+ self.filename = argv[1].replace('\\', '/')
+ if len(argv) == 3:
+ self.impl_file = argv[2].replace('\\', '/')
+ if len(argv) == 4:
+ self.header_file = argv[2].replace('\\', '/')
+ self.impl_file = argv[3].replace('\\', '/')
+
+ if not self.filename:
+ raise Usage(argv[0])
+
+ if not self.impl_file:
+ self.impl_file = self.factory.CodeFilename(self.filename)
+
+ if not self.header_file:
+ self.header_file = self.factory.HeaderFilename(self.impl_file)
+
+ if not self.impl_file.endswith('.c'):
+ raise RpcGenError("can only generate C implementation files")
+ if not self.header_file.endswith('.h'):
+ raise RpcGenError("can only generate C header files")
+
+ def run(self):
+ filename = self.filename
+ header_file = self.header_file
+ impl_file = self.impl_file
+ factory = self.factory
+
+ declare('Reading \"%s\"' % filename)
+
+ fp = open(filename, 'r')
+ entities = Parse(factory, fp)
+ fp.close()
+
+ declare('... creating "%s"' % header_file)
+ header_fp = open(header_file, 'w')
+ print >>header_fp, factory.HeaderPreamble(filename)
+
+ # Create forward declarations: allows other structs to reference
+ # each other
+ for entry in entities:
+ entry.PrintForwardDeclaration(header_fp)
+ print >>header_fp, ''
+
+ for entry in entities:
+ entry.PrintTags(header_fp)
+ entry.PrintDeclaration(header_fp)
+ print >>header_fp, factory.HeaderPostamble(filename)
+ header_fp.close()
+
+ declare('... creating "%s"' % impl_file)
+ impl_fp = open(impl_file, 'w')
+ print >>impl_fp, factory.BodyPreamble(filename, header_file)
+ for entry in entities:
+ entry.PrintCode(impl_fp)
+ impl_fp.close()
+
+if __name__ == '__main__':
+ try:
+ CommandLine(sys.argv).run()
+ sys.exit(0)
+
+ except RpcGenError, e:
+ print >>sys.stderr, e
+ sys.exit(1)
+
+ except EnvironmentError, e:
+ if e.filename and e.strerror:
+ print >>sys.stderr, "%s: %s" % (e.filename, e.strerror)
+ sys.exit(1)
+ elif e.strerror:
+ print >> sys.stderr, e.strerror
+ sys.exit(1)
+ else:
+ raise
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/event_tagging.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/event_tagging.c
new file mode 100644
index 000000000..6459dfa72
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/event_tagging.c
@@ -0,0 +1,605 @@
+/*
+ * Copyright (c) 2003-2009 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+
+#ifdef EVENT__HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <sys/queue.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32
+#include <syslog.h>
+#endif
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <limits.h>
+
+#include "event2/event.h"
+#include "event2/tag.h"
+#include "event2/buffer.h"
+#include "log-internal.h"
+#include "mm-internal.h"
+#include "util-internal.h"
+
+/*
+ Here's our wire format:
+
+ Stream = TaggedData*
+
+ TaggedData = Tag Length Data
+ where the integer value of 'Length' is the length of 'data'.
+
+ Tag = HByte* LByte
+ where HByte is a byte with the high bit set, and LByte is a byte
+ with the high bit clear. The integer value of the tag is taken
+ by concatenating the lower 7 bits from all the tags. So for example,
+ the tag 0x66 is encoded as [66], whereas the tag 0x166 is encoded as
+ [82 66]
+
+ Length = Integer
+
+ Integer = NNibbles Nibble* Padding?
+ where NNibbles is a 4-bit value encoding the number of nibbles-1,
+ and each Nibble is 4 bits worth of encoded integer, in big-endian
+ order. If the total encoded integer size is an odd number of nibbles,
+ a final padding nibble with value 0 is appended.
+*/
+
+int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf);
+int evtag_decode_int64(ev_uint64_t *pnumber, struct evbuffer *evbuf);
+int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag);
+int evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf);
+
+void
+evtag_init(void)
+{
+}
+
+/*
+ * We encode integers by nibbles; the first nibble contains the number
+ * of significant nibbles - 1; this allows us to encode up to 64-bit
+ * integers. This function is byte-order independent.
+ *
+ * @param number a 32-bit unsigned integer to encode
+ * @param data a pointer to where the data should be written. Must
+ * have at least 5 bytes free.
+ * @return the number of bytes written into data.
+ */
+
+#define ENCODE_INT_INTERNAL(data, number) do { \
+ int off = 1, nibbles = 0; \
+ \
+ memset(data, 0, sizeof(number)+1); \
+ while (number) { \
+ if (off & 0x1) \
+ data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f); \
+ else \
+ data[off/2] = (data[off/2] & 0x0f) | \
+ ((number & 0x0f) << 4); \
+ number >>= 4; \
+ off++; \
+ } \
+ \
+ if (off > 2) \
+ nibbles = off - 2; \
+ \
+ /* Off - 1 is the number of encoded nibbles */ \
+ data[0] = (data[0] & 0x0f) | ((nibbles & 0x0f) << 4); \
+ \
+ return ((off + 1) / 2); \
+} while (0)
+
+static inline int
+encode_int_internal(ev_uint8_t *data, ev_uint32_t number)
+{
+ ENCODE_INT_INTERNAL(data, number);
+}
+
+static inline int
+encode_int64_internal(ev_uint8_t *data, ev_uint64_t number)
+{
+ ENCODE_INT_INTERNAL(data, number);
+}
+
+void
+evtag_encode_int(struct evbuffer *evbuf, ev_uint32_t number)
+{
+ ev_uint8_t data[5];
+ int len = encode_int_internal(data, number);
+ evbuffer_add(evbuf, data, len);
+}
+
+void
+evtag_encode_int64(struct evbuffer *evbuf, ev_uint64_t number)
+{
+ ev_uint8_t data[9];
+ int len = encode_int64_internal(data, number);
+ evbuffer_add(evbuf, data, len);
+}
+
+/*
+ * Support variable length encoding of tags; we use the high bit in each
+ * octet as a continuation signal.
+ */
+
+int
+evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag)
+{
+ int bytes = 0;
+ ev_uint8_t data[5];
+
+ memset(data, 0, sizeof(data));
+ do {
+ ev_uint8_t lower = tag & 0x7f;
+ tag >>= 7;
+
+ if (tag)
+ lower |= 0x80;
+
+ data[bytes++] = lower;
+ } while (tag);
+
+ if (evbuf != NULL)
+ evbuffer_add(evbuf, data, bytes);
+
+ return (bytes);
+}
+
+static int
+decode_tag_internal(ev_uint32_t *ptag, struct evbuffer *evbuf, int dodrain)
+{
+ ev_uint32_t number = 0;
+ size_t len = evbuffer_get_length(evbuf);
+ ev_uint8_t *data;
+ size_t count = 0;
+ int shift = 0, done = 0;
+
+ /*
+ * the encoding of a number is at most one byte more than its
+ * storage size. however, it may also be much smaller.
+ */
+ data = evbuffer_pullup(
+ evbuf, len < sizeof(number) + 1 ? len : sizeof(number) + 1);
+ if (!data)
+ return (-1);
+
+ while (count++ < len) {
+ ev_uint8_t lower = *data++;
+ if (shift >= 28) {
+ /* Make sure it fits into 32 bits */
+ if (shift > 28)
+ return (-1);
+ if ((lower & 0x7f) > 15)
+ return (-1);
+ }
+ number |= (lower & (unsigned)0x7f) << shift;
+ shift += 7;
+
+ if (!(lower & 0x80)) {
+ done = 1;
+ break;
+ }
+ }
+
+ if (!done)
+ return (-1);
+
+ if (dodrain)
+ evbuffer_drain(evbuf, count);
+
+ if (ptag != NULL)
+ *ptag = number;
+
+ return count > INT_MAX ? INT_MAX : (int)(count);
+}
+
+int
+evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf)
+{
+ return (decode_tag_internal(ptag, evbuf, 1 /* dodrain */));
+}
+
+/*
+ * Marshal a data type, the general format is as follows:
+ *
+ * tag number: one byte; length: var bytes; payload: var bytes
+ */
+
+void
+evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag,
+ const void *data, ev_uint32_t len)
+{
+ evtag_encode_tag(evbuf, tag);
+ evtag_encode_int(evbuf, len);
+ evbuffer_add(evbuf, (void *)data, len);
+}
+
+void
+evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag,
+ struct evbuffer *data)
+{
+ evtag_encode_tag(evbuf, tag);
+ /* XXX support more than UINT32_MAX data */
+ evtag_encode_int(evbuf, (ev_uint32_t)evbuffer_get_length(data));
+ evbuffer_add_buffer(evbuf, data);
+}
+
+/* Marshaling for integers */
+void
+evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer)
+{
+ ev_uint8_t data[5];
+ int len = encode_int_internal(data, integer);
+
+ evtag_encode_tag(evbuf, tag);
+ evtag_encode_int(evbuf, len);
+ evbuffer_add(evbuf, data, len);
+}
+
+void
+evtag_marshal_int64(struct evbuffer *evbuf, ev_uint32_t tag,
+ ev_uint64_t integer)
+{
+ ev_uint8_t data[9];
+ int len = encode_int64_internal(data, integer);
+
+ evtag_encode_tag(evbuf, tag);
+ evtag_encode_int(evbuf, len);
+ evbuffer_add(evbuf, data, len);
+}
+
+void
+evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string)
+{
+ /* TODO support strings longer than UINT32_MAX ? */
+ evtag_marshal(buf, tag, string, (ev_uint32_t)strlen(string));
+}
+
+void
+evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv)
+{
+ ev_uint8_t data[10];
+ int len = encode_int_internal(data, tv->tv_sec);
+ len += encode_int_internal(data + len, tv->tv_usec);
+ evtag_marshal(evbuf, tag, data, len);
+}
+
+#define DECODE_INT_INTERNAL(number, maxnibbles, pnumber, evbuf, offset) \
+do { \
+ ev_uint8_t *data; \
+ ev_ssize_t len = evbuffer_get_length(evbuf) - offset; \
+ int nibbles = 0; \
+ \
+ if (len <= 0) \
+ return (-1); \
+ \
+ /* XXX(niels): faster? */ \
+ data = evbuffer_pullup(evbuf, offset + 1) + offset; \
+ if (!data) \
+ return (-1); \
+ \
+ nibbles = ((data[0] & 0xf0) >> 4) + 1; \
+ if (nibbles > maxnibbles || (nibbles >> 1) + 1 > len) \
+ return (-1); \
+ len = (nibbles >> 1) + 1; \
+ \
+ data = evbuffer_pullup(evbuf, offset + len) + offset; \
+ if (!data) \
+ return (-1); \
+ \
+ while (nibbles > 0) { \
+ number <<= 4; \
+ if (nibbles & 0x1) \
+ number |= data[nibbles >> 1] & 0x0f; \
+ else \
+ number |= (data[nibbles >> 1] & 0xf0) >> 4; \
+ nibbles--; \
+ } \
+ \
+ *pnumber = number; \
+ \
+ return (int)(len); \
+} while (0)
+
+/* Internal: decode an integer from an evbuffer, without draining it.
+ * Only integers up to 32-bits are supported.
+ *
+ * @param evbuf the buffer to read from
+ * @param offset an index into the buffer at which we should start reading.
+ * @param pnumber a pointer to receive the integer.
+ * @return The length of the number as encoded, or -1 on error.
+ */
+
+static int
+decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int offset)
+{
+ ev_uint32_t number = 0;
+ DECODE_INT_INTERNAL(number, 8, pnumber, evbuf, offset);
+}
+
+static int
+decode_int64_internal(ev_uint64_t *pnumber, struct evbuffer *evbuf, int offset)
+{
+ ev_uint64_t number = 0;
+ DECODE_INT_INTERNAL(number, 16, pnumber, evbuf, offset);
+}
+
+int
+evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf)
+{
+ int res = decode_int_internal(pnumber, evbuf, 0);
+ if (res != -1)
+ evbuffer_drain(evbuf, res);
+
+ return (res == -1 ? -1 : 0);
+}
+
+int
+evtag_decode_int64(ev_uint64_t *pnumber, struct evbuffer *evbuf)
+{
+ int res = decode_int64_internal(pnumber, evbuf, 0);
+ if (res != -1)
+ evbuffer_drain(evbuf, res);
+
+ return (res == -1 ? -1 : 0);
+}
+
+int
+evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag)
+{
+ return (decode_tag_internal(ptag, evbuf, 0 /* dodrain */));
+}
+
+int
+evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength)
+{
+ int res, len;
+
+ len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
+ if (len == -1)
+ return (-1);
+
+ res = decode_int_internal(plength, evbuf, len);
+ if (res == -1)
+ return (-1);
+
+ *plength += res + len;
+
+ return (0);
+}
+
+int
+evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength)
+{
+ int res, len;
+
+ len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
+ if (len == -1)
+ return (-1);
+
+ res = decode_int_internal(plength, evbuf, len);
+ if (res == -1)
+ return (-1);
+
+ return (0);
+}
+
+/* just unmarshals the header and returns the length of the remaining data */
+
+int
+evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag)
+{
+ ev_uint32_t len;
+
+ if (decode_tag_internal(ptag, evbuf, 1 /* dodrain */) == -1)
+ return (-1);
+ if (evtag_decode_int(&len, evbuf) == -1)
+ return (-1);
+
+ if (evbuffer_get_length(evbuf) < len)
+ return (-1);
+
+ return (len);
+}
+
+int
+evtag_consume(struct evbuffer *evbuf)
+{
+ int len;
+ if ((len = evtag_unmarshal_header(evbuf, NULL)) == -1)
+ return (-1);
+ evbuffer_drain(evbuf, len);
+
+ return (0);
+}
+
+/* Reads the data type from an event buffer */
+
+int
+evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst)
+{
+ int len;
+
+ if ((len = evtag_unmarshal_header(src, ptag)) == -1)
+ return (-1);
+
+ if (evbuffer_add(dst, evbuffer_pullup(src, len), len) == -1)
+ return (-1);
+
+ evbuffer_drain(src, len);
+
+ return (len);
+}
+
+/* Marshaling for integers */
+
+int
+evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ ev_uint32_t *pinteger)
+{
+ ev_uint32_t tag;
+ ev_uint32_t len;
+ int result;
+
+ if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1)
+ return (-1);
+ if (need_tag != tag)
+ return (-1);
+ if (evtag_decode_int(&len, evbuf) == -1)
+ return (-1);
+
+ if (evbuffer_get_length(evbuf) < len)
+ return (-1);
+
+ result = decode_int_internal(pinteger, evbuf, 0);
+ evbuffer_drain(evbuf, len);
+ if (result < 0 || (size_t)result > len) /* XXX Should this be != rather than > ?*/
+ return (-1);
+ else
+ return result;
+}
+
+int
+evtag_unmarshal_int64(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ ev_uint64_t *pinteger)
+{
+ ev_uint32_t tag;
+ ev_uint32_t len;
+ int result;
+
+ if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1)
+ return (-1);
+ if (need_tag != tag)
+ return (-1);
+ if (evtag_decode_int(&len, evbuf) == -1)
+ return (-1);
+
+ if (evbuffer_get_length(evbuf) < len)
+ return (-1);
+
+ result = decode_int64_internal(pinteger, evbuf, 0);
+ evbuffer_drain(evbuf, len);
+ if (result < 0 || (size_t)result > len) /* XXX Should this be != rather than > ?*/
+ return (-1);
+ else
+ return result;
+}
+
+/* Unmarshal a fixed length tag */
+
+int
+evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data,
+ size_t len)
+{
+ ev_uint32_t tag;
+ int tag_len;
+
+ /* Now unmarshal a tag and check that it matches the tag we want */
+ if ((tag_len = evtag_unmarshal_header(src, &tag)) < 0 ||
+ tag != need_tag)
+ return (-1);
+
+ if ((size_t)tag_len != len)
+ return (-1);
+
+ evbuffer_remove(src, data, len);
+ return (0);
+}
+
+int
+evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ char **pstring)
+{
+ ev_uint32_t tag;
+ int tag_len;
+
+ if ((tag_len = evtag_unmarshal_header(evbuf, &tag)) == -1 ||
+ tag != need_tag)
+ return (-1);
+
+ *pstring = mm_malloc(tag_len + 1);
+ if (*pstring == NULL) {
+ event_warn("%s: malloc", __func__);
+ return -1;
+ }
+ evbuffer_remove(evbuf, *pstring, tag_len);
+ (*pstring)[tag_len] = '\0';
+
+ return (0);
+}
+
+int
+evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ struct timeval *ptv)
+{
+ ev_uint32_t tag;
+ ev_uint32_t integer;
+ int len, offset, offset2;
+ int result = -1;
+
+ if ((len = evtag_unmarshal_header(evbuf, &tag)) == -1)
+ return (-1);
+ if (tag != need_tag)
+ goto done;
+ if ((offset = decode_int_internal(&integer, evbuf, 0)) == -1)
+ goto done;
+ ptv->tv_sec = integer;
+ if ((offset2 = decode_int_internal(&integer, evbuf, offset)) == -1)
+ goto done;
+ ptv->tv_usec = integer;
+ if (offset + offset2 > len) /* XXX Should this be != instead of > ? */
+ goto done;
+
+ result = 0;
+ done:
+ evbuffer_drain(evbuf, len);
+ return result;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evmap-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/evmap-internal.h
new file mode 100644
index 000000000..dfc81d508
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evmap-internal.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVMAP_INTERNAL_H_INCLUDED_
+#define EVMAP_INTERNAL_H_INCLUDED_
+
+/** @file evmap-internal.h
+ *
+ * An event_map is a utility structure to map each fd or signal to zero or
+ * more events. Functions to manipulate event_maps should only be used from
+ * inside libevent. They generally need to hold the lock on the corresponding
+ * event_base.
+ **/
+
+struct event_base;
+struct event;
+
+/** Initialize an event_map for use.
+ */
+void evmap_io_initmap_(struct event_io_map* ctx);
+void evmap_signal_initmap_(struct event_signal_map* ctx);
+
+/** Remove all entries from an event_map.
+
+ @param ctx the map to clear.
+ */
+void evmap_io_clear_(struct event_io_map* ctx);
+void evmap_signal_clear_(struct event_signal_map* ctx);
+
+/** Add an IO event (some combination of EV_READ or EV_WRITE) to an
+ event_base's list of events on a given file descriptor, and tell the
+ underlying eventops about the fd if its state has changed.
+
+ Requires that ev is not already added.
+
+ @param base the event_base to operate on.
+ @param fd the file descriptor corresponding to ev.
+ @param ev the event to add.
+*/
+int evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev);
+/** Remove an IO event (some combination of EV_READ or EV_WRITE) to an
+ event_base's list of events on a given file descriptor, and tell the
+ underlying eventops about the fd if its state has changed.
+
+ @param base the event_base to operate on.
+ @param fd the file descriptor corresponding to ev.
+ @param ev the event to remove.
+ */
+int evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev);
+/** Active the set of events waiting on an event_base for a given fd.
+
+ @param base the event_base to operate on.
+ @param fd the file descriptor that has become active.
+ @param events a bitmask of EV_READ|EV_WRITE|EV_ET.
+*/
+void evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events);
+
+
+/* These functions behave in the same way as evmap_io_*, except they work on
+ * signals rather than fds. signals use a linear map everywhere; fds use
+ * either a linear map or a hashtable. */
+int evmap_signal_add_(struct event_base *base, int signum, struct event *ev);
+int evmap_signal_del_(struct event_base *base, int signum, struct event *ev);
+void evmap_signal_active_(struct event_base *base, evutil_socket_t signum, int ncalls);
+
+/* Return the fdinfo object associated with a given fd. If the fd has no
+ * events associated with it, the result may be NULL.
+ */
+void *evmap_io_get_fdinfo_(struct event_io_map *ctx, evutil_socket_t fd);
+
+/* Helper for event_reinit(): Tell the backend to re-add every fd and signal
+ * for which we have a pending event.
+ */
+int evmap_reinit_(struct event_base *base);
+
+/* Helper for event_base_free(): Call event_del() on every pending fd and
+ * signal event.
+ */
+void evmap_delete_all_(struct event_base *base);
+
+/* Helper for event_base_assert_ok_(): Check referential integrity of the
+ * evmaps.
+ */
+void evmap_check_integrity_(struct event_base *base);
+
+/* Helper: Call fn on every fd or signal event, passing as its arguments the
+ * provided event_base, the event, and arg. If fn returns 0, process the next
+ * event. If it returns any other value, return that value and process no
+ * more events.
+ */
+int evmap_foreach_event_(struct event_base *base,
+ event_base_foreach_event_cb fn,
+ void *arg);
+
+#endif /* EVMAP_INTERNAL_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evmap.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/evmap.c
new file mode 100644
index 000000000..3f76dd0ae
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evmap.c
@@ -0,0 +1,1055 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+#include <sys/types.h>
+#if !defined(_WIN32) && defined(EVENT__HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+
+#include "event-internal.h"
+#include "evmap-internal.h"
+#include "mm-internal.h"
+#include "changelist-internal.h"
+
+/** An entry for an evmap_io list: notes all the events that want to read or
+ write on a given fd, and the number of each.
+ */
+struct evmap_io {
+ struct event_dlist events;
+ ev_uint16_t nread;
+ ev_uint16_t nwrite;
+ ev_uint16_t nclose;
+};
+
+/* An entry for an evmap_signal list: notes all the events that want to know
+ when a signal triggers. */
+struct evmap_signal {
+ struct event_dlist events;
+};
+
+/* On some platforms, fds start at 0 and increment by 1 as they are
+ allocated, and old numbers get used. For these platforms, we
+ implement io maps just like signal maps: as an array of pointers to
+ struct evmap_io. But on other platforms (windows), sockets are not
+ 0-indexed, not necessarily consecutive, and not necessarily reused.
+ There, we use a hashtable to implement evmap_io.
+*/
+#ifdef EVMAP_USE_HT
+struct event_map_entry {
+ HT_ENTRY(event_map_entry) map_node;
+ evutil_socket_t fd;
+ union { /* This is a union in case we need to make more things that can
+ be in the hashtable. */
+ struct evmap_io evmap_io;
+ } ent;
+};
+
+/* Helper used by the event_io_map hashtable code; tries to return a good hash
+ * of the fd in e->fd. */
+static inline unsigned
+hashsocket(struct event_map_entry *e)
+{
+ /* On win32, in practice, the low 2-3 bits of a SOCKET seem not to
+ * matter. Our hashtable implementation really likes low-order bits,
+ * though, so let's do the rotate-and-add trick. */
+ unsigned h = (unsigned) e->fd;
+ h += (h >> 2) | (h << 30);
+ return h;
+}
+
+/* Helper used by the event_io_map hashtable code; returns true iff e1 and e2
+ * have the same e->fd. */
+static inline int
+eqsocket(struct event_map_entry *e1, struct event_map_entry *e2)
+{
+ return e1->fd == e2->fd;
+}
+
+HT_PROTOTYPE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket)
+HT_GENERATE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket,
+ 0.5, mm_malloc, mm_realloc, mm_free)
+
+#define GET_IO_SLOT(x, map, slot, type) \
+ do { \
+ struct event_map_entry key_, *ent_; \
+ key_.fd = slot; \
+ ent_ = HT_FIND(event_io_map, map, &key_); \
+ (x) = ent_ ? &ent_->ent.type : NULL; \
+ } while (0);
+
+#define GET_IO_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \
+ do { \
+ struct event_map_entry key_, *ent_; \
+ key_.fd = slot; \
+ HT_FIND_OR_INSERT_(event_io_map, map_node, hashsocket, map, \
+ event_map_entry, &key_, ptr, \
+ { \
+ ent_ = *ptr; \
+ }, \
+ { \
+ ent_ = mm_calloc(1,sizeof(struct event_map_entry)+fdinfo_len); \
+ if (EVUTIL_UNLIKELY(ent_ == NULL)) \
+ return (-1); \
+ ent_->fd = slot; \
+ (ctor)(&ent_->ent.type); \
+ HT_FOI_INSERT_(map_node, map, &key_, ent_, ptr) \
+ }); \
+ (x) = &ent_->ent.type; \
+ } while (0)
+
+void evmap_io_initmap_(struct event_io_map *ctx)
+{
+ HT_INIT(event_io_map, ctx);
+}
+
+void evmap_io_clear_(struct event_io_map *ctx)
+{
+ struct event_map_entry **ent, **next, *this;
+ for (ent = HT_START(event_io_map, ctx); ent; ent = next) {
+ this = *ent;
+ next = HT_NEXT_RMV(event_io_map, ctx, ent);
+ mm_free(this);
+ }
+ HT_CLEAR(event_io_map, ctx); /* remove all storage held by the ctx. */
+}
+#endif
+
+/* Set the variable 'x' to the field in event_map 'map' with fields of type
+ 'struct type *' corresponding to the fd or signal 'slot'. Set 'x' to NULL
+ if there are no entries for 'slot'. Does no bounds-checking. */
+#define GET_SIGNAL_SLOT(x, map, slot, type) \
+ (x) = (struct type *)((map)->entries[slot])
+/* As GET_SLOT, but construct the entry for 'slot' if it is not present,
+ by allocating enough memory for a 'struct type', and initializing the new
+ value by calling the function 'ctor' on it. Makes the function
+ return -1 on allocation failure.
+ */
+#define GET_SIGNAL_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \
+ do { \
+ if ((map)->entries[slot] == NULL) { \
+ (map)->entries[slot] = \
+ mm_calloc(1,sizeof(struct type)+fdinfo_len); \
+ if (EVUTIL_UNLIKELY((map)->entries[slot] == NULL)) \
+ return (-1); \
+ (ctor)((struct type *)(map)->entries[slot]); \
+ } \
+ (x) = (struct type *)((map)->entries[slot]); \
+ } while (0)
+
+/* If we aren't using hashtables, then define the IO_SLOT macros and functions
+ as thin aliases over the SIGNAL_SLOT versions. */
+#ifndef EVMAP_USE_HT
+#define GET_IO_SLOT(x,map,slot,type) GET_SIGNAL_SLOT(x,map,slot,type)
+#define GET_IO_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len) \
+ GET_SIGNAL_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)
+#define FDINFO_OFFSET sizeof(struct evmap_io)
+void
+evmap_io_initmap_(struct event_io_map* ctx)
+{
+ evmap_signal_initmap_(ctx);
+}
+void
+evmap_io_clear_(struct event_io_map* ctx)
+{
+ evmap_signal_clear_(ctx);
+}
+#endif
+
+
+/** Expand 'map' with new entries of width 'msize' until it is big enough
+ to store a value in 'slot'.
+ */
+static int
+evmap_make_space(struct event_signal_map *map, int slot, int msize)
+{
+ if (map->nentries <= slot) {
+ int nentries = map->nentries ? map->nentries : 32;
+ void **tmp;
+
+ while (nentries <= slot)
+ nentries <<= 1;
+
+ tmp = (void **)mm_realloc(map->entries, nentries * msize);
+ if (tmp == NULL)
+ return (-1);
+
+ memset(&tmp[map->nentries], 0,
+ (nentries - map->nentries) * msize);
+
+ map->nentries = nentries;
+ map->entries = tmp;
+ }
+
+ return (0);
+}
+
+void
+evmap_signal_initmap_(struct event_signal_map *ctx)
+{
+ ctx->nentries = 0;
+ ctx->entries = NULL;
+}
+
+void
+evmap_signal_clear_(struct event_signal_map *ctx)
+{
+ if (ctx->entries != NULL) {
+ int i;
+ for (i = 0; i < ctx->nentries; ++i) {
+ if (ctx->entries[i] != NULL)
+ mm_free(ctx->entries[i]);
+ }
+ mm_free(ctx->entries);
+ ctx->entries = NULL;
+ }
+ ctx->nentries = 0;
+}
+
+
+/* code specific to file descriptors */
+
+/** Constructor for struct evmap_io */
+static void
+evmap_io_init(struct evmap_io *entry)
+{
+ LIST_INIT(&entry->events);
+ entry->nread = 0;
+ entry->nwrite = 0;
+ entry->nclose = 0;
+}
+
+
+/* return -1 on error, 0 on success if nothing changed in the event backend,
+ * and 1 on success if something did. */
+int
+evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
+{
+ const struct eventop *evsel = base->evsel;
+ struct event_io_map *io = &base->io;
+ struct evmap_io *ctx = NULL;
+ int nread, nwrite, nclose, retval = 0;
+ short res = 0, old = 0;
+ struct event *old_ev;
+
+ EVUTIL_ASSERT(fd == ev->ev_fd);
+
+ if (fd < 0)
+ return 0;
+
+#ifndef EVMAP_USE_HT
+ if (fd >= io->nentries) {
+ if (evmap_make_space(io, fd, sizeof(struct evmap_io *)) == -1)
+ return (-1);
+ }
+#endif
+ GET_IO_SLOT_AND_CTOR(ctx, io, fd, evmap_io, evmap_io_init,
+ evsel->fdinfo_len);
+
+ nread = ctx->nread;
+ nwrite = ctx->nwrite;
+ nclose = ctx->nclose;
+
+ if (nread)
+ old |= EV_READ;
+ if (nwrite)
+ old |= EV_WRITE;
+ if (nclose)
+ old |= EV_CLOSED;
+
+ if (ev->ev_events & EV_READ) {
+ if (++nread == 1)
+ res |= EV_READ;
+ }
+ if (ev->ev_events & EV_WRITE) {
+ if (++nwrite == 1)
+ res |= EV_WRITE;
+ }
+ if (ev->ev_events & EV_CLOSED) {
+ if (++nclose == 1)
+ res |= EV_CLOSED;
+ }
+ if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff || nclose > 0xffff)) {
+ event_warnx("Too many events reading or writing on fd %d",
+ (int)fd);
+ return -1;
+ }
+ if (EVENT_DEBUG_MODE_IS_ON() &&
+ (old_ev = LIST_FIRST(&ctx->events)) &&
+ (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) {
+ event_warnx("Tried to mix edge-triggered and non-edge-triggered"
+ " events on fd %d", (int)fd);
+ return -1;
+ }
+
+ if (res) {
+ void *extra = ((char*)ctx) + sizeof(struct evmap_io);
+ /* XXX(niels): we cannot mix edge-triggered and
+ * level-triggered, we should probably assert on
+ * this. */
+ if (evsel->add(base, ev->ev_fd,
+ old, (ev->ev_events & EV_ET) | res, extra) == -1)
+ return (-1);
+ retval = 1;
+ }
+
+ ctx->nread = (ev_uint16_t) nread;
+ ctx->nwrite = (ev_uint16_t) nwrite;
+ ctx->nclose = (ev_uint16_t) nclose;
+ LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next);
+
+ return (retval);
+}
+
+/* return -1 on error, 0 on success if nothing changed in the event backend,
+ * and 1 on success if something did. */
+int
+evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
+{
+ const struct eventop *evsel = base->evsel;
+ struct event_io_map *io = &base->io;
+ struct evmap_io *ctx;
+ int nread, nwrite, nclose, retval = 0;
+ short res = 0, old = 0;
+
+ if (fd < 0)
+ return 0;
+
+ EVUTIL_ASSERT(fd == ev->ev_fd);
+
+#ifndef EVMAP_USE_HT
+ if (fd >= io->nentries)
+ return (-1);
+#endif
+
+ GET_IO_SLOT(ctx, io, fd, evmap_io);
+
+ nread = ctx->nread;
+ nwrite = ctx->nwrite;
+ nclose = ctx->nclose;
+
+ if (nread)
+ old |= EV_READ;
+ if (nwrite)
+ old |= EV_WRITE;
+ if (nclose)
+ old |= EV_CLOSED;
+
+ if (ev->ev_events & EV_READ) {
+ if (--nread == 0)
+ res |= EV_READ;
+ EVUTIL_ASSERT(nread >= 0);
+ }
+ if (ev->ev_events & EV_WRITE) {
+ if (--nwrite == 0)
+ res |= EV_WRITE;
+ EVUTIL_ASSERT(nwrite >= 0);
+ }
+ if (ev->ev_events & EV_CLOSED) {
+ if (--nclose == 0)
+ res |= EV_CLOSED;
+ EVUTIL_ASSERT(nclose >= 0);
+ }
+
+ if (res) {
+ void *extra = ((char*)ctx) + sizeof(struct evmap_io);
+ if (evsel->del(base, ev->ev_fd, old, res, extra) == -1) {
+ retval = -1;
+ } else {
+ retval = 1;
+ }
+ }
+
+ ctx->nread = nread;
+ ctx->nwrite = nwrite;
+ ctx->nclose = nclose;
+ LIST_REMOVE(ev, ev_io_next);
+
+ return (retval);
+}
+
+void
+evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events)
+{
+ struct event_io_map *io = &base->io;
+ struct evmap_io *ctx;
+ struct event *ev;
+
+#ifndef EVMAP_USE_HT
+ if (fd < 0 || fd >= io->nentries)
+ return;
+#endif
+ GET_IO_SLOT(ctx, io, fd, evmap_io);
+
+ if (NULL == ctx)
+ return;
+ LIST_FOREACH(ev, &ctx->events, ev_io_next) {
+ if (ev->ev_events & events)
+ event_active_nolock_(ev, ev->ev_events & events, 1);
+ }
+}
+
+/* code specific to signals */
+
+static void
+evmap_signal_init(struct evmap_signal *entry)
+{
+ LIST_INIT(&entry->events);
+}
+
+
+int
+evmap_signal_add_(struct event_base *base, int sig, struct event *ev)
+{
+ const struct eventop *evsel = base->evsigsel;
+ struct event_signal_map *map = &base->sigmap;
+ struct evmap_signal *ctx = NULL;
+
+ if (sig >= map->nentries) {
+ if (evmap_make_space(
+ map, sig, sizeof(struct evmap_signal *)) == -1)
+ return (-1);
+ }
+ GET_SIGNAL_SLOT_AND_CTOR(ctx, map, sig, evmap_signal, evmap_signal_init,
+ base->evsigsel->fdinfo_len);
+
+ if (LIST_EMPTY(&ctx->events)) {
+ if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL)
+ == -1)
+ return (-1);
+ }
+
+ LIST_INSERT_HEAD(&ctx->events, ev, ev_signal_next);
+
+ return (1);
+}
+
+int
+evmap_signal_del_(struct event_base *base, int sig, struct event *ev)
+{
+ const struct eventop *evsel = base->evsigsel;
+ struct event_signal_map *map = &base->sigmap;
+ struct evmap_signal *ctx;
+
+ if (sig >= map->nentries)
+ return (-1);
+
+ GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
+
+ LIST_REMOVE(ev, ev_signal_next);
+
+ if (LIST_FIRST(&ctx->events) == NULL) {
+ if (evsel->del(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1)
+ return (-1);
+ }
+
+ return (1);
+}
+
+void
+evmap_signal_active_(struct event_base *base, evutil_socket_t sig, int ncalls)
+{
+ struct event_signal_map *map = &base->sigmap;
+ struct evmap_signal *ctx;
+ struct event *ev;
+
+ if (sig < 0 || sig >= map->nentries)
+ return;
+ GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
+
+ if (!ctx)
+ return;
+ LIST_FOREACH(ev, &ctx->events, ev_signal_next)
+ event_active_nolock_(ev, EV_SIGNAL, ncalls);
+}
+
+void *
+evmap_io_get_fdinfo_(struct event_io_map *map, evutil_socket_t fd)
+{
+ struct evmap_io *ctx;
+ GET_IO_SLOT(ctx, map, fd, evmap_io);
+ if (ctx)
+ return ((char*)ctx) + sizeof(struct evmap_io);
+ else
+ return NULL;
+}
+
+/* Callback type for evmap_io_foreach_fd */
+typedef int (*evmap_io_foreach_fd_cb)(
+ struct event_base *, evutil_socket_t, struct evmap_io *, void *);
+
+/* Multipurpose helper function: Iterate over every file descriptor event_base
+ * for which we could have EV_READ or EV_WRITE events. For each such fd, call
+ * fn(base, signum, evmap_io, arg), where fn is the user-provided
+ * function, base is the event_base, signum is the signal number, evmap_io
+ * is an evmap_io structure containing a list of events pending on the
+ * file descriptor, and arg is the user-supplied argument.
+ *
+ * If fn returns 0, continue on to the next signal. Otherwise, return the same
+ * value that fn returned.
+ *
+ * Note that there is no guarantee that the file descriptors will be processed
+ * in any particular order.
+ */
+static int
+evmap_io_foreach_fd(struct event_base *base,
+ evmap_io_foreach_fd_cb fn,
+ void *arg)
+{
+ evutil_socket_t fd;
+ struct event_io_map *iomap = &base->io;
+ int r = 0;
+#ifdef EVMAP_USE_HT
+ struct event_map_entry **mapent;
+ HT_FOREACH(mapent, event_io_map, iomap) {
+ struct evmap_io *ctx = &(*mapent)->ent.evmap_io;
+ fd = (*mapent)->fd;
+#else
+ for (fd = 0; fd < iomap->nentries; ++fd) {
+ struct evmap_io *ctx = iomap->entries[fd];
+ if (!ctx)
+ continue;
+#endif
+ if ((r = fn(base, fd, ctx, arg)))
+ break;
+ }
+ return r;
+}
+
+/* Callback type for evmap_signal_foreach_signal */
+typedef int (*evmap_signal_foreach_signal_cb)(
+ struct event_base *, int, struct evmap_signal *, void *);
+
+/* Multipurpose helper function: Iterate over every signal number in the
+ * event_base for which we could have signal events. For each such signal,
+ * call fn(base, signum, evmap_signal, arg), where fn is the user-provided
+ * function, base is the event_base, signum is the signal number, evmap_signal
+ * is an evmap_signal structure containing a list of events pending on the
+ * signal, and arg is the user-supplied argument.
+ *
+ * If fn returns 0, continue on to the next signal. Otherwise, return the same
+ * value that fn returned.
+ */
+static int
+evmap_signal_foreach_signal(struct event_base *base,
+ evmap_signal_foreach_signal_cb fn,
+ void *arg)
+{
+ struct event_signal_map *sigmap = &base->sigmap;
+ int r = 0;
+ int signum;
+
+ for (signum = 0; signum < sigmap->nentries; ++signum) {
+ struct evmap_signal *ctx = sigmap->entries[signum];
+ if (!ctx)
+ continue;
+ if ((r = fn(base, signum, ctx, arg)))
+ break;
+ }
+ return r;
+}
+
+/* Helper for evmap_reinit_: tell the backend to add every fd for which we have
+ * pending events, with the appropriate combination of EV_READ, EV_WRITE, and
+ * EV_ET. */
+static int
+evmap_io_reinit_iter_fn(struct event_base *base, evutil_socket_t fd,
+ struct evmap_io *ctx, void *arg)
+{
+ const struct eventop *evsel = base->evsel;
+ void *extra;
+ int *result = arg;
+ short events = 0;
+ struct event *ev;
+ EVUTIL_ASSERT(ctx);
+
+ extra = ((char*)ctx) + sizeof(struct evmap_io);
+ if (ctx->nread)
+ events |= EV_READ;
+ if (ctx->nwrite)
+ events |= EV_WRITE;
+ if (ctx->nclose)
+ events |= EV_CLOSED;
+ if (evsel->fdinfo_len)
+ memset(extra, 0, evsel->fdinfo_len);
+ if (events &&
+ (ev = LIST_FIRST(&ctx->events)) &&
+ (ev->ev_events & EV_ET))
+ events |= EV_ET;
+ if (evsel->add(base, fd, 0, events, extra) == -1)
+ *result = -1;
+
+ return 0;
+}
+
+/* Helper for evmap_reinit_: tell the backend to add every signal for which we
+ * have pending events. */
+static int
+evmap_signal_reinit_iter_fn(struct event_base *base,
+ int signum, struct evmap_signal *ctx, void *arg)
+{
+ const struct eventop *evsel = base->evsigsel;
+ int *result = arg;
+
+ if (!LIST_EMPTY(&ctx->events)) {
+ if (evsel->add(base, signum, 0, EV_SIGNAL, NULL) == -1)
+ *result = -1;
+ }
+ return 0;
+}
+
+int
+evmap_reinit_(struct event_base *base)
+{
+ int result = 0;
+
+ evmap_io_foreach_fd(base, evmap_io_reinit_iter_fn, &result);
+ if (result < 0)
+ return -1;
+ evmap_signal_foreach_signal(base, evmap_signal_reinit_iter_fn, &result);
+ if (result < 0)
+ return -1;
+ return 0;
+}
+
+/* Helper for evmap_delete_all_: delete every event in an event_dlist. */
+static int
+delete_all_in_dlist(struct event_dlist *dlist)
+{
+ struct event *ev;
+ while ((ev = LIST_FIRST(dlist)))
+ event_del(ev);
+ return 0;
+}
+
+/* Helper for evmap_delete_all_: delete every event pending on an fd. */
+static int
+evmap_io_delete_all_iter_fn(struct event_base *base, evutil_socket_t fd,
+ struct evmap_io *io_info, void *arg)
+{
+ return delete_all_in_dlist(&io_info->events);
+}
+
+/* Helper for evmap_delete_all_: delete every event pending on a signal. */
+static int
+evmap_signal_delete_all_iter_fn(struct event_base *base, int signum,
+ struct evmap_signal *sig_info, void *arg)
+{
+ return delete_all_in_dlist(&sig_info->events);
+}
+
+void
+evmap_delete_all_(struct event_base *base)
+{
+ evmap_signal_foreach_signal(base, evmap_signal_delete_all_iter_fn, NULL);
+ evmap_io_foreach_fd(base, evmap_io_delete_all_iter_fn, NULL);
+}
+
+/** Per-fd structure for use with changelists. It keeps track, for each fd or
+ * signal using the changelist, of where its entry in the changelist is.
+ */
+struct event_changelist_fdinfo {
+ int idxplus1; /* this is the index +1, so that memset(0) will make it
+ * a no-such-element */
+};
+
+void
+event_changelist_init_(struct event_changelist *changelist)
+{
+ changelist->changes = NULL;
+ changelist->changes_size = 0;
+ changelist->n_changes = 0;
+}
+
+/** Helper: return the changelist_fdinfo corresponding to a given change. */
+static inline struct event_changelist_fdinfo *
+event_change_get_fdinfo(struct event_base *base,
+ const struct event_change *change)
+{
+ char *ptr;
+ if (change->read_change & EV_CHANGE_SIGNAL) {
+ struct evmap_signal *ctx;
+ GET_SIGNAL_SLOT(ctx, &base->sigmap, change->fd, evmap_signal);
+ ptr = ((char*)ctx) + sizeof(struct evmap_signal);
+ } else {
+ struct evmap_io *ctx;
+ GET_IO_SLOT(ctx, &base->io, change->fd, evmap_io);
+ ptr = ((char*)ctx) + sizeof(struct evmap_io);
+ }
+ return (void*)ptr;
+}
+
+/** Callback helper for event_changelist_assert_ok */
+static int
+event_changelist_assert_ok_foreach_iter_fn(
+ struct event_base *base,
+ evutil_socket_t fd, struct evmap_io *io, void *arg)
+{
+ struct event_changelist *changelist = &base->changelist;
+ struct event_changelist_fdinfo *f;
+ f = (void*)
+ ( ((char*)io) + sizeof(struct evmap_io) );
+ if (f->idxplus1) {
+ struct event_change *c = &changelist->changes[f->idxplus1 - 1];
+ EVUTIL_ASSERT(c->fd == fd);
+ }
+ return 0;
+}
+
+/** Make sure that the changelist is consistent with the evmap structures. */
+static void
+event_changelist_assert_ok(struct event_base *base)
+{
+ int i;
+ struct event_changelist *changelist = &base->changelist;
+
+ EVUTIL_ASSERT(changelist->changes_size >= changelist->n_changes);
+ for (i = 0; i < changelist->n_changes; ++i) {
+ struct event_change *c = &changelist->changes[i];
+ struct event_changelist_fdinfo *f;
+ EVUTIL_ASSERT(c->fd >= 0);
+ f = event_change_get_fdinfo(base, c);
+ EVUTIL_ASSERT(f);
+ EVUTIL_ASSERT(f->idxplus1 == i + 1);
+ }
+
+ evmap_io_foreach_fd(base,
+ event_changelist_assert_ok_foreach_iter_fn,
+ NULL);
+}
+
+#ifdef DEBUG_CHANGELIST
+#define event_changelist_check(base) event_changelist_assert_ok((base))
+#else
+#define event_changelist_check(base) ((void)0)
+#endif
+
+void
+event_changelist_remove_all_(struct event_changelist *changelist,
+ struct event_base *base)
+{
+ int i;
+
+ event_changelist_check(base);
+
+ for (i = 0; i < changelist->n_changes; ++i) {
+ struct event_change *ch = &changelist->changes[i];
+ struct event_changelist_fdinfo *fdinfo =
+ event_change_get_fdinfo(base, ch);
+ EVUTIL_ASSERT(fdinfo->idxplus1 == i + 1);
+ fdinfo->idxplus1 = 0;
+ }
+
+ changelist->n_changes = 0;
+
+ event_changelist_check(base);
+}
+
+void
+event_changelist_freemem_(struct event_changelist *changelist)
+{
+ if (changelist->changes)
+ mm_free(changelist->changes);
+ event_changelist_init_(changelist); /* zero it all out. */
+}
+
+/** Increase the size of 'changelist' to hold more changes. */
+static int
+event_changelist_grow(struct event_changelist *changelist)
+{
+ int new_size;
+ struct event_change *new_changes;
+ if (changelist->changes_size < 64)
+ new_size = 64;
+ else
+ new_size = changelist->changes_size * 2;
+
+ new_changes = mm_realloc(changelist->changes,
+ new_size * sizeof(struct event_change));
+
+ if (EVUTIL_UNLIKELY(new_changes == NULL))
+ return (-1);
+
+ changelist->changes = new_changes;
+ changelist->changes_size = new_size;
+
+ return (0);
+}
+
+/** Return a pointer to the changelist entry for the file descriptor or signal
+ * 'fd', whose fdinfo is 'fdinfo'. If none exists, construct it, setting its
+ * old_events field to old_events.
+ */
+static struct event_change *
+event_changelist_get_or_construct(struct event_changelist *changelist,
+ evutil_socket_t fd,
+ short old_events,
+ struct event_changelist_fdinfo *fdinfo)
+{
+ struct event_change *change;
+
+ if (fdinfo->idxplus1 == 0) {
+ int idx;
+ EVUTIL_ASSERT(changelist->n_changes <= changelist->changes_size);
+
+ if (changelist->n_changes == changelist->changes_size) {
+ if (event_changelist_grow(changelist) < 0)
+ return NULL;
+ }
+
+ idx = changelist->n_changes++;
+ change = &changelist->changes[idx];
+ fdinfo->idxplus1 = idx + 1;
+
+ memset(change, 0, sizeof(struct event_change));
+ change->fd = fd;
+ change->old_events = old_events;
+ } else {
+ change = &changelist->changes[fdinfo->idxplus1 - 1];
+ EVUTIL_ASSERT(change->fd == fd);
+ }
+ return change;
+}
+
+int
+event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, short events,
+ void *p)
+{
+ struct event_changelist *changelist = &base->changelist;
+ struct event_changelist_fdinfo *fdinfo = p;
+ struct event_change *change;
+
+ event_changelist_check(base);
+
+ change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
+ if (!change)
+ return -1;
+
+ /* An add replaces any previous delete, but doesn't result in a no-op,
+ * since the delete might fail (because the fd had been closed since
+ * the last add, for instance. */
+
+ if (events & (EV_READ|EV_SIGNAL)) {
+ change->read_change = EV_CHANGE_ADD |
+ (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
+ }
+ if (events & EV_WRITE) {
+ change->write_change = EV_CHANGE_ADD |
+ (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
+ }
+ if (events & EV_CLOSED) {
+ change->close_change = EV_CHANGE_ADD |
+ (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
+ }
+
+ event_changelist_check(base);
+ return (0);
+}
+
+int
+event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, short events,
+ void *p)
+{
+ struct event_changelist *changelist = &base->changelist;
+ struct event_changelist_fdinfo *fdinfo = p;
+ struct event_change *change;
+
+ event_changelist_check(base);
+ change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
+ event_changelist_check(base);
+ if (!change)
+ return -1;
+
+ /* A delete on an event set that doesn't contain the event to be
+ deleted produces a no-op. This effectively emoves any previous
+ uncommitted add, rather than replacing it: on those platforms where
+ "add, delete, dispatch" is not the same as "no-op, dispatch", we
+ want the no-op behavior.
+
+ If we have a no-op item, we could remove it it from the list
+ entirely, but really there's not much point: skipping the no-op
+ change when we do the dispatch later is far cheaper than rejuggling
+ the array now.
+
+ As this stands, it also lets through deletions of events that are
+ not currently set.
+ */
+
+ if (events & (EV_READ|EV_SIGNAL)) {
+ if (!(change->old_events & (EV_READ | EV_SIGNAL)))
+ change->read_change = 0;
+ else
+ change->read_change = EV_CHANGE_DEL;
+ }
+ if (events & EV_WRITE) {
+ if (!(change->old_events & EV_WRITE))
+ change->write_change = 0;
+ else
+ change->write_change = EV_CHANGE_DEL;
+ }
+ if (events & EV_CLOSED) {
+ if (!(change->old_events & EV_CLOSED))
+ change->close_change = 0;
+ else
+ change->close_change = EV_CHANGE_DEL;
+ }
+
+ event_changelist_check(base);
+ return (0);
+}
+
+/* Helper for evmap_check_integrity_: verify that all of the events pending on
+ * given fd are set up correctly, and that the nread and nwrite counts on that
+ * fd are correct. */
+static int
+evmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd,
+ struct evmap_io *io_info, void *arg)
+{
+ struct event *ev;
+ int n_read = 0, n_write = 0, n_close = 0;
+
+ /* First, make sure the list itself isn't corrupt. Otherwise,
+ * running LIST_FOREACH could be an exciting adventure. */
+ EVUTIL_ASSERT_LIST_OK(&io_info->events, event, ev_io_next);
+
+ LIST_FOREACH(ev, &io_info->events, ev_io_next) {
+ EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
+ EVUTIL_ASSERT(ev->ev_fd == fd);
+ EVUTIL_ASSERT(!(ev->ev_events & EV_SIGNAL));
+ EVUTIL_ASSERT((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
+ if (ev->ev_events & EV_READ)
+ ++n_read;
+ if (ev->ev_events & EV_WRITE)
+ ++n_write;
+ if (ev->ev_events & EV_CLOSED)
+ ++n_close;
+ }
+
+ EVUTIL_ASSERT(n_read == io_info->nread);
+ EVUTIL_ASSERT(n_write == io_info->nwrite);
+ EVUTIL_ASSERT(n_close == io_info->nclose);
+
+ return 0;
+}
+
+/* Helper for evmap_check_integrity_: verify that all of the events pending
+ * on given signal are set up correctly. */
+static int
+evmap_signal_check_integrity_fn(struct event_base *base,
+ int signum, struct evmap_signal *sig_info, void *arg)
+{
+ struct event *ev;
+ /* First, make sure the list itself isn't corrupt. */
+ EVUTIL_ASSERT_LIST_OK(&sig_info->events, event, ev_signal_next);
+
+ LIST_FOREACH(ev, &sig_info->events, ev_io_next) {
+ EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
+ EVUTIL_ASSERT(ev->ev_fd == signum);
+ EVUTIL_ASSERT((ev->ev_events & EV_SIGNAL));
+ EVUTIL_ASSERT(!(ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
+ }
+ return 0;
+}
+
+void
+evmap_check_integrity_(struct event_base *base)
+{
+ evmap_io_foreach_fd(base, evmap_io_check_integrity_fn, NULL);
+ evmap_signal_foreach_signal(base, evmap_signal_check_integrity_fn, NULL);
+
+ if (base->evsel->add == event_changelist_add_)
+ event_changelist_assert_ok(base);
+}
+
+/* Helper type for evmap_foreach_event_: Bundles a function to call on every
+ * event, and the user-provided void* to use as its third argument. */
+struct evmap_foreach_event_helper {
+ event_base_foreach_event_cb fn;
+ void *arg;
+};
+
+/* Helper for evmap_foreach_event_: calls a provided function on every event
+ * pending on a given fd. */
+static int
+evmap_io_foreach_event_fn(struct event_base *base, evutil_socket_t fd,
+ struct evmap_io *io_info, void *arg)
+{
+ struct evmap_foreach_event_helper *h = arg;
+ struct event *ev;
+ int r;
+ LIST_FOREACH(ev, &io_info->events, ev_io_next) {
+ if ((r = h->fn(base, ev, h->arg)))
+ return r;
+ }
+ return 0;
+}
+
+/* Helper for evmap_foreach_event_: calls a provided function on every event
+ * pending on a given signal. */
+static int
+evmap_signal_foreach_event_fn(struct event_base *base, int signum,
+ struct evmap_signal *sig_info, void *arg)
+{
+ struct event *ev;
+ struct evmap_foreach_event_helper *h = arg;
+ int r;
+ LIST_FOREACH(ev, &sig_info->events, ev_signal_next) {
+ if ((r = h->fn(base, ev, h->arg)))
+ return r;
+ }
+ return 0;
+}
+
+int
+evmap_foreach_event_(struct event_base *base,
+ event_base_foreach_event_cb fn, void *arg)
+{
+ struct evmap_foreach_event_helper h;
+ int r;
+ h.fn = fn;
+ h.arg = arg;
+ if ((r = evmap_io_foreach_fd(base, evmap_io_foreach_event_fn, &h)))
+ return r;
+ return evmap_signal_foreach_signal(base, evmap_signal_foreach_event_fn, &h);
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evport.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/evport.c
new file mode 100644
index 000000000..a014386bf
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evport.c
@@ -0,0 +1,451 @@
+/*
+ * Submitted by David Pacheco (dp.spambait@gmail.com)
+ *
+ * Copyright 2006-2007 Niels Provos
+ * Copyright 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2007 Sun Microsystems. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * evport.c: event backend using Solaris 10 event ports. See port_create(3C).
+ * This implementation is loosely modeled after the one used for select(2) (in
+ * select.c).
+ *
+ * The outstanding events are tracked in a data structure called evport_data.
+ * Each entry in the ed_fds array corresponds to a file descriptor, and contains
+ * pointers to the read and write events that correspond to that fd. (That is,
+ * when the file is readable, the "read" event should handle it, etc.)
+ *
+ * evport_add and evport_del update this data structure. evport_dispatch uses it
+ * to determine where to callback when an event occurs (which it gets from
+ * port_getn).
+ *
+ * Helper functions are used: grow() grows the file descriptor array as
+ * necessary when large fd's come in. reassociate() takes care of maintaining
+ * the proper file-descriptor/event-port associations.
+ *
+ * As in the select(2) implementation, signals are handled by evsignal.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef EVENT__HAVE_EVENT_PORTS
+
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <poll.h>
+#include <port.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "event2/thread.h"
+
+#include "evthread-internal.h"
+#include "event-internal.h"
+#include "log-internal.h"
+#include "evsignal-internal.h"
+#include "evmap-internal.h"
+
+#define INITIAL_EVENTS_PER_GETN 8
+#define MAX_EVENTS_PER_GETN 4096
+
+/*
+ * Per-file-descriptor information about what events we're subscribed to. These
+ * fields are NULL if no event is subscribed to either of them.
+ */
+
+struct fd_info {
+ /* combinations of EV_READ and EV_WRITE */
+ short fdi_what;
+ /* Index of this fd within ed_pending, plus 1. Zero if this fd is
+ * not in ed_pending. (The +1 is a hack so that memset(0) will set
+ * it to a nil index. */
+ int pending_idx_plus_1;
+};
+
+#define FDI_HAS_READ(fdi) ((fdi)->fdi_what & EV_READ)
+#define FDI_HAS_WRITE(fdi) ((fdi)->fdi_what & EV_WRITE)
+#define FDI_HAS_EVENTS(fdi) (FDI_HAS_READ(fdi) || FDI_HAS_WRITE(fdi))
+#define FDI_TO_SYSEVENTS(fdi) (FDI_HAS_READ(fdi) ? POLLIN : 0) | \
+ (FDI_HAS_WRITE(fdi) ? POLLOUT : 0)
+
+struct evport_data {
+ int ed_port; /* event port for system events */
+ /* How many elements of ed_pending should we look at? */
+ int ed_npending;
+ /* How many elements are allocated in ed_pending and pevtlist? */
+ int ed_maxevents;
+ /* fdi's that we need to reassoc */
+ int *ed_pending;
+ /* storage space for incoming events. */
+ port_event_t *ed_pevtlist;
+
+};
+
+static void* evport_init(struct event_base *);
+static int evport_add(struct event_base *, int fd, short old, short events, void *);
+static int evport_del(struct event_base *, int fd, short old, short events, void *);
+static int evport_dispatch(struct event_base *, struct timeval *);
+static void evport_dealloc(struct event_base *);
+static int grow(struct evport_data *, int min_events);
+
+const struct eventop evportops = {
+ "evport",
+ evport_init,
+ evport_add,
+ evport_del,
+ evport_dispatch,
+ evport_dealloc,
+ 1, /* need reinit */
+ 0, /* features */
+ sizeof(struct fd_info), /* fdinfo length */
+};
+
+/*
+ * Initialize the event port implementation.
+ */
+
+static void*
+evport_init(struct event_base *base)
+{
+ struct evport_data *evpd;
+
+ if (!(evpd = mm_calloc(1, sizeof(struct evport_data))))
+ return (NULL);
+
+ if ((evpd->ed_port = port_create()) == -1) {
+ mm_free(evpd);
+ return (NULL);
+ }
+
+ if (grow(evpd, INITIAL_EVENTS_PER_GETN) < 0) {
+ close(evpd->ed_port);
+ mm_free(evpd);
+ return NULL;
+ }
+
+ evpd->ed_npending = 0;
+
+ evsig_init_(base);
+
+ return (evpd);
+}
+
+static int
+grow(struct evport_data *data, int min_events)
+{
+ int newsize;
+ int *new_pending;
+ port_event_t *new_pevtlist;
+ if (data->ed_maxevents) {
+ newsize = data->ed_maxevents;
+ do {
+ newsize *= 2;
+ } while (newsize < min_events);
+ } else {
+ newsize = min_events;
+ }
+
+ new_pending = mm_realloc(data->ed_pending, sizeof(int)*newsize);
+ if (new_pending == NULL)
+ return -1;
+ data->ed_pending = new_pending;
+ new_pevtlist = mm_realloc(data->ed_pevtlist, sizeof(port_event_t)*newsize);
+ if (new_pevtlist == NULL)
+ return -1;
+ data->ed_pevtlist = new_pevtlist;
+
+ data->ed_maxevents = newsize;
+ return 0;
+}
+
+#ifdef CHECK_INVARIANTS
+/*
+ * Checks some basic properties about the evport_data structure. Because it
+ * checks all file descriptors, this function can be expensive when the maximum
+ * file descriptor ever used is rather large.
+ */
+
+static void
+check_evportop(struct evport_data *evpd)
+{
+ EVUTIL_ASSERT(evpd);
+ EVUTIL_ASSERT(evpd->ed_port > 0);
+}
+
+/*
+ * Verifies very basic integrity of a given port_event.
+ */
+static void
+check_event(port_event_t* pevt)
+{
+ /*
+ * We've only registered for PORT_SOURCE_FD events. The only
+ * other thing we can legitimately receive is PORT_SOURCE_ALERT,
+ * but since we're not using port_alert either, we can assume
+ * PORT_SOURCE_FD.
+ */
+ EVUTIL_ASSERT(pevt->portev_source == PORT_SOURCE_FD);
+}
+
+#else
+#define check_evportop(epop)
+#define check_event(pevt)
+#endif /* CHECK_INVARIANTS */
+
+/*
+ * (Re)associates the given file descriptor with the event port. The OS events
+ * are specified (implicitly) from the fd_info struct.
+ */
+static int
+reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd)
+{
+ int sysevents = FDI_TO_SYSEVENTS(fdip);
+
+ if (sysevents != 0) {
+ if (port_associate(epdp->ed_port, PORT_SOURCE_FD,
+ fd, sysevents, fdip) == -1) {
+ event_warn("port_associate");
+ return (-1);
+ }
+ }
+
+ check_evportop(epdp);
+
+ return (0);
+}
+
+/*
+ * Main event loop - polls port_getn for some number of events, and processes
+ * them.
+ */
+
+static int
+evport_dispatch(struct event_base *base, struct timeval *tv)
+{
+ int i, res;
+ struct evport_data *epdp = base->evbase;
+ port_event_t *pevtlist = epdp->ed_pevtlist;
+
+ /*
+ * port_getn will block until it has at least nevents events. It will
+ * also return how many it's given us (which may be more than we asked
+ * for, as long as it's less than our maximum (ed_maxevents)) in
+ * nevents.
+ */
+ int nevents = 1;
+
+ /*
+ * We have to convert a struct timeval to a struct timespec
+ * (only difference is nanoseconds vs. microseconds). If no time-based
+ * events are active, we should wait for I/O (and tv == NULL).
+ */
+ struct timespec ts;
+ struct timespec *ts_p = NULL;
+ if (tv != NULL) {
+ ts.tv_sec = tv->tv_sec;
+ ts.tv_nsec = tv->tv_usec * 1000;
+ ts_p = &ts;
+ }
+
+ /*
+ * Before doing anything else, we need to reassociate the events we hit
+ * last time which need reassociation. See comment at the end of the
+ * loop below.
+ */
+ for (i = 0; i < epdp->ed_npending; ++i) {
+ struct fd_info *fdi = NULL;
+ const int fd = epdp->ed_pending[i];
+ if (fd != -1) {
+ /* We might have cleared out this event; we need
+ * to be sure that it's still set. */
+ fdi = evmap_io_get_fdinfo_(&base->io, fd);
+ }
+
+ if (fdi != NULL && FDI_HAS_EVENTS(fdi)) {
+ reassociate(epdp, fdi, fd);
+ /* epdp->ed_pending[i] = -1; */
+ fdi->pending_idx_plus_1 = 0;
+ }
+ }
+
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ res = port_getn(epdp->ed_port, pevtlist, epdp->ed_maxevents,
+ (unsigned int *) &nevents, ts_p);
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ if (res == -1) {
+ if (errno == EINTR || errno == EAGAIN) {
+ return (0);
+ } else if (errno == ETIME) {
+ if (nevents == 0)
+ return (0);
+ } else {
+ event_warn("port_getn");
+ return (-1);
+ }
+ }
+
+ event_debug(("%s: port_getn reports %d events", __func__, nevents));
+
+ for (i = 0; i < nevents; ++i) {
+ port_event_t *pevt = &pevtlist[i];
+ int fd = (int) pevt->portev_object;
+ struct fd_info *fdi = pevt->portev_user;
+ /*EVUTIL_ASSERT(evmap_io_get_fdinfo_(&base->io, fd) == fdi);*/
+
+ check_evportop(epdp);
+ check_event(pevt);
+ epdp->ed_pending[i] = fd;
+ fdi->pending_idx_plus_1 = i + 1;
+
+ /*
+ * Figure out what kind of event it was
+ * (because we have to pass this to the callback)
+ */
+ res = 0;
+ if (pevt->portev_events & (POLLERR|POLLHUP)) {
+ res = EV_READ | EV_WRITE;
+ } else {
+ if (pevt->portev_events & POLLIN)
+ res |= EV_READ;
+ if (pevt->portev_events & POLLOUT)
+ res |= EV_WRITE;
+ }
+
+ /*
+ * Check for the error situations or a hangup situation
+ */
+ if (pevt->portev_events & (POLLERR|POLLHUP|POLLNVAL))
+ res |= EV_READ|EV_WRITE;
+
+ evmap_io_active_(base, fd, res);
+ } /* end of all events gotten */
+ epdp->ed_npending = nevents;
+
+ if (nevents == epdp->ed_maxevents &&
+ epdp->ed_maxevents < MAX_EVENTS_PER_GETN) {
+ /* we used all the space this time. We should be ready
+ * for more events next time around. */
+ grow(epdp, epdp->ed_maxevents * 2);
+ }
+
+ check_evportop(epdp);
+
+ return (0);
+}
+
+
+/*
+ * Adds the given event (so that you will be notified when it happens via
+ * the callback function).
+ */
+
+static int
+evport_add(struct event_base *base, int fd, short old, short events, void *p)
+{
+ struct evport_data *evpd = base->evbase;
+ struct fd_info *fdi = p;
+
+ check_evportop(evpd);
+
+ fdi->fdi_what |= events;
+
+ return reassociate(evpd, fdi, fd);
+}
+
+/*
+ * Removes the given event from the list of events to wait for.
+ */
+
+static int
+evport_del(struct event_base *base, int fd, short old, short events, void *p)
+{
+ struct evport_data *evpd = base->evbase;
+ struct fd_info *fdi = p;
+ int associated = ! fdi->pending_idx_plus_1;
+
+ check_evportop(evpd);
+
+ fdi->fdi_what &= ~(events &(EV_READ|EV_WRITE));
+
+ if (associated) {
+ if (!FDI_HAS_EVENTS(fdi) &&
+ port_dissociate(evpd->ed_port, PORT_SOURCE_FD, fd) == -1) {
+ /*
+ * Ignore EBADFD error the fd could have been closed
+ * before event_del() was called.
+ */
+ if (errno != EBADFD) {
+ event_warn("port_dissociate");
+ return (-1);
+ }
+ } else {
+ if (FDI_HAS_EVENTS(fdi)) {
+ return (reassociate(evpd, fdi, fd));
+ }
+ }
+ } else {
+ if ((fdi->fdi_what & (EV_READ|EV_WRITE)) == 0) {
+ const int i = fdi->pending_idx_plus_1 - 1;
+ EVUTIL_ASSERT(evpd->ed_pending[i] == fd);
+ evpd->ed_pending[i] = -1;
+ fdi->pending_idx_plus_1 = 0;
+ }
+ }
+ return 0;
+}
+
+
+static void
+evport_dealloc(struct event_base *base)
+{
+ struct evport_data *evpd = base->evbase;
+
+ evsig_dealloc_(base);
+
+ close(evpd->ed_port);
+
+ if (evpd->ed_pending)
+ mm_free(evpd->ed_pending);
+ if (evpd->ed_pevtlist)
+ mm_free(evpd->ed_pevtlist);
+
+ mm_free(evpd);
+}
+
+#endif /* EVENT__HAVE_EVENT_PORTS */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evrpc-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/evrpc-internal.h
new file mode 100644
index 000000000..9eb376386
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evrpc-internal.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2006-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVRPC_INTERNAL_H_INCLUDED_
+#define EVRPC_INTERNAL_H_INCLUDED_
+
+#include "event2/http.h"
+#include "http-internal.h"
+
+struct evrpc;
+struct evrpc_request_wrapper;
+
+#define EVRPC_URI_PREFIX "/.rpc."
+
+struct evrpc_hook {
+ TAILQ_ENTRY(evrpc_hook) next;
+
+ /* returns EVRPC_TERMINATE; if the rpc should be aborted.
+ * a hook is is allowed to rewrite the evbuffer
+ */
+ int (*process)(void *, struct evhttp_request *,
+ struct evbuffer *, void *);
+ void *process_arg;
+};
+
+TAILQ_HEAD(evrpc_hook_list, evrpc_hook);
+
+/*
+ * this is shared between the base and the pool, so that we can reuse
+ * the hook adding functions; we alias both evrpc_pool and evrpc_base
+ * to this common structure.
+ */
+
+struct evrpc_hook_ctx;
+TAILQ_HEAD(evrpc_pause_list, evrpc_hook_ctx);
+
+struct evrpc_hooks_ {
+ /* hooks for processing outbound and inbound rpcs */
+ struct evrpc_hook_list in_hooks;
+ struct evrpc_hook_list out_hooks;
+
+ struct evrpc_pause_list pause_requests;
+};
+
+#define input_hooks common.in_hooks
+#define output_hooks common.out_hooks
+#define paused_requests common.pause_requests
+
+struct evrpc_base {
+ struct evrpc_hooks_ common;
+
+ /* the HTTP server under which we register our RPC calls */
+ struct evhttp* http_server;
+
+ /* a list of all RPCs registered with us */
+ TAILQ_HEAD(evrpc_list, evrpc) registered_rpcs;
+};
+
+struct evrpc_req_generic;
+void evrpc_reqstate_free_(struct evrpc_req_generic* rpc_state);
+
+/* A pool for holding evhttp_connection objects */
+struct evrpc_pool {
+ struct evrpc_hooks_ common;
+
+ struct event_base *base;
+
+ struct evconq connections;
+
+ int timeout;
+
+ TAILQ_HEAD(evrpc_requestq, evrpc_request_wrapper) (requests);
+};
+
+struct evrpc_hook_ctx {
+ TAILQ_ENTRY(evrpc_hook_ctx) next;
+
+ void *ctx;
+ void (*cb)(void *, enum EVRPC_HOOK_RESULT);
+};
+
+struct evrpc_meta {
+ TAILQ_ENTRY(evrpc_meta) next;
+ char *key;
+
+ void *data;
+ size_t data_size;
+};
+
+TAILQ_HEAD(evrpc_meta_list, evrpc_meta);
+
+struct evrpc_hook_meta {
+ struct evrpc_meta_list meta_data;
+ struct evhttp_connection *evcon;
+};
+
+/* allows association of meta data with a request */
+static void evrpc_hook_associate_meta_(struct evrpc_hook_meta **pctx,
+ struct evhttp_connection *evcon);
+
+/* creates a new meta data store */
+static struct evrpc_hook_meta *evrpc_hook_meta_new_(void);
+
+/* frees the meta data associated with a request */
+static void evrpc_hook_context_free_(struct evrpc_hook_meta *ctx);
+
+/* the server side of an rpc */
+
+/* We alias the RPC specific structs to this voided one */
+struct evrpc_req_generic {
+ /*
+ * allows association of meta data via hooks - needs to be
+ * synchronized with evrpc_request_wrapper
+ */
+ struct evrpc_hook_meta *hook_meta;
+
+ /* the unmarshaled request object */
+ void *request;
+
+ /* the empty reply object that needs to be filled in */
+ void *reply;
+
+ /*
+ * the static structure for this rpc; that can be used to
+ * automatically unmarshal and marshal the http buffers.
+ */
+ struct evrpc *rpc;
+
+ /*
+ * the http request structure on which we need to answer.
+ */
+ struct evhttp_request* http_req;
+
+ /*
+ * Temporary data store for marshaled data
+ */
+ struct evbuffer* rpc_data;
+};
+
+/* the client side of an rpc request */
+struct evrpc_request_wrapper {
+ /*
+ * allows association of meta data via hooks - needs to be
+ * synchronized with evrpc_req_generic.
+ */
+ struct evrpc_hook_meta *hook_meta;
+
+ TAILQ_ENTRY(evrpc_request_wrapper) next;
+
+ /* pool on which this rpc request is being made */
+ struct evrpc_pool *pool;
+
+ /* connection on which the request is being sent */
+ struct evhttp_connection *evcon;
+
+ /* the actual request */
+ struct evhttp_request *req;
+
+ /* event for implementing request timeouts */
+ struct event ev_timeout;
+
+ /* the name of the rpc */
+ char *name;
+
+ /* callback */
+ void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg);
+ void *cb_arg;
+
+ void *request;
+ void *reply;
+
+ /* unmarshals the buffer into the proper request structure */
+ void (*request_marshal)(struct evbuffer *, void *);
+
+ /* removes all stored state in the reply */
+ void (*reply_clear)(void *);
+
+ /* marshals the reply into a buffer */
+ int (*reply_unmarshal)(void *, struct evbuffer*);
+};
+
+#endif /* EVRPC_INTERNAL_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evrpc.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/evrpc.c
new file mode 100644
index 000000000..2443ab279
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evrpc.c
@@ -0,0 +1,1171 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+
+#include <sys/queue.h>
+
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/rpc.h"
+#include "event2/rpc_struct.h"
+#include "evrpc-internal.h"
+#include "event2/http.h"
+#include "event2/buffer.h"
+#include "event2/tag.h"
+#include "event2/http_struct.h"
+#include "event2/http_compat.h"
+#include "event2/util.h"
+#include "util-internal.h"
+#include "log-internal.h"
+#include "mm-internal.h"
+
+struct evrpc_base *
+evrpc_init(struct evhttp *http_server)
+{
+ struct evrpc_base* base = mm_calloc(1, sizeof(struct evrpc_base));
+ if (base == NULL)
+ return (NULL);
+
+ /* we rely on the tagging sub system */
+ evtag_init();
+
+ TAILQ_INIT(&base->registered_rpcs);
+ TAILQ_INIT(&base->input_hooks);
+ TAILQ_INIT(&base->output_hooks);
+
+ TAILQ_INIT(&base->paused_requests);
+
+ base->http_server = http_server;
+
+ return (base);
+}
+
+void
+evrpc_free(struct evrpc_base *base)
+{
+ struct evrpc *rpc;
+ struct evrpc_hook *hook;
+ struct evrpc_hook_ctx *pause;
+ int r;
+
+ while ((rpc = TAILQ_FIRST(&base->registered_rpcs)) != NULL) {
+ r = evrpc_unregister_rpc(base, rpc->uri);
+ EVUTIL_ASSERT(r == 0);
+ }
+ while ((pause = TAILQ_FIRST(&base->paused_requests)) != NULL) {
+ TAILQ_REMOVE(&base->paused_requests, pause, next);
+ mm_free(pause);
+ }
+ while ((hook = TAILQ_FIRST(&base->input_hooks)) != NULL) {
+ r = evrpc_remove_hook(base, EVRPC_INPUT, hook);
+ EVUTIL_ASSERT(r);
+ }
+ while ((hook = TAILQ_FIRST(&base->output_hooks)) != NULL) {
+ r = evrpc_remove_hook(base, EVRPC_OUTPUT, hook);
+ EVUTIL_ASSERT(r);
+ }
+ mm_free(base);
+}
+
+void *
+evrpc_add_hook(void *vbase,
+ enum EVRPC_HOOK_TYPE hook_type,
+ int (*cb)(void *, struct evhttp_request *, struct evbuffer *, void *),
+ void *cb_arg)
+{
+ struct evrpc_hooks_ *base = vbase;
+ struct evrpc_hook_list *head = NULL;
+ struct evrpc_hook *hook = NULL;
+ switch (hook_type) {
+ case EVRPC_INPUT:
+ head = &base->in_hooks;
+ break;
+ case EVRPC_OUTPUT:
+ head = &base->out_hooks;
+ break;
+ default:
+ EVUTIL_ASSERT(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
+ }
+
+ hook = mm_calloc(1, sizeof(struct evrpc_hook));
+ EVUTIL_ASSERT(hook != NULL);
+
+ hook->process = cb;
+ hook->process_arg = cb_arg;
+ TAILQ_INSERT_TAIL(head, hook, next);
+
+ return (hook);
+}
+
+static int
+evrpc_remove_hook_internal(struct evrpc_hook_list *head, void *handle)
+{
+ struct evrpc_hook *hook = NULL;
+ TAILQ_FOREACH(hook, head, next) {
+ if (hook == handle) {
+ TAILQ_REMOVE(head, hook, next);
+ mm_free(hook);
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * remove the hook specified by the handle
+ */
+
+int
+evrpc_remove_hook(void *vbase, enum EVRPC_HOOK_TYPE hook_type, void *handle)
+{
+ struct evrpc_hooks_ *base = vbase;
+ struct evrpc_hook_list *head = NULL;
+ switch (hook_type) {
+ case EVRPC_INPUT:
+ head = &base->in_hooks;
+ break;
+ case EVRPC_OUTPUT:
+ head = &base->out_hooks;
+ break;
+ default:
+ EVUTIL_ASSERT(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
+ }
+
+ return (evrpc_remove_hook_internal(head, handle));
+}
+
+static int
+evrpc_process_hooks(struct evrpc_hook_list *head, void *ctx,
+ struct evhttp_request *req, struct evbuffer *evbuf)
+{
+ struct evrpc_hook *hook;
+ TAILQ_FOREACH(hook, head, next) {
+ int res = hook->process(ctx, req, evbuf, hook->process_arg);
+ if (res != EVRPC_CONTINUE)
+ return (res);
+ }
+
+ return (EVRPC_CONTINUE);
+}
+
+static void evrpc_pool_schedule(struct evrpc_pool *pool);
+static void evrpc_request_cb(struct evhttp_request *, void *);
+
+/*
+ * Registers a new RPC with the HTTP server. The evrpc object is expected
+ * to have been filled in via the EVRPC_REGISTER_OBJECT macro which in turn
+ * calls this function.
+ */
+
+static char *
+evrpc_construct_uri(const char *uri)
+{
+ char *constructed_uri;
+ size_t constructed_uri_len;
+
+ constructed_uri_len = strlen(EVRPC_URI_PREFIX) + strlen(uri) + 1;
+ if ((constructed_uri = mm_malloc(constructed_uri_len)) == NULL)
+ event_err(1, "%s: failed to register rpc at %s",
+ __func__, uri);
+ memcpy(constructed_uri, EVRPC_URI_PREFIX, strlen(EVRPC_URI_PREFIX));
+ memcpy(constructed_uri + strlen(EVRPC_URI_PREFIX), uri, strlen(uri));
+ constructed_uri[constructed_uri_len - 1] = '\0';
+
+ return (constructed_uri);
+}
+
+int
+evrpc_register_rpc(struct evrpc_base *base, struct evrpc *rpc,
+ void (*cb)(struct evrpc_req_generic *, void *), void *cb_arg)
+{
+ char *constructed_uri = evrpc_construct_uri(rpc->uri);
+
+ rpc->base = base;
+ rpc->cb = cb;
+ rpc->cb_arg = cb_arg;
+
+ TAILQ_INSERT_TAIL(&base->registered_rpcs, rpc, next);
+
+ evhttp_set_cb(base->http_server,
+ constructed_uri,
+ evrpc_request_cb,
+ rpc);
+
+ mm_free(constructed_uri);
+
+ return (0);
+}
+
+int
+evrpc_unregister_rpc(struct evrpc_base *base, const char *name)
+{
+ char *registered_uri = NULL;
+ struct evrpc *rpc;
+ int r;
+
+ /* find the right rpc; linear search might be slow */
+ TAILQ_FOREACH(rpc, &base->registered_rpcs, next) {
+ if (strcmp(rpc->uri, name) == 0)
+ break;
+ }
+ if (rpc == NULL) {
+ /* We did not find an RPC with this name */
+ return (-1);
+ }
+ TAILQ_REMOVE(&base->registered_rpcs, rpc, next);
+
+ registered_uri = evrpc_construct_uri(name);
+
+ /* remove the http server callback */
+ r = evhttp_del_cb(base->http_server, registered_uri);
+ EVUTIL_ASSERT(r == 0);
+
+ mm_free(registered_uri);
+
+ mm_free((char *)rpc->uri);
+ mm_free(rpc);
+ return (0);
+}
+
+static int evrpc_pause_request(void *vbase, void *ctx,
+ void (*cb)(void *, enum EVRPC_HOOK_RESULT));
+static void evrpc_request_cb_closure(void *, enum EVRPC_HOOK_RESULT);
+
+static void
+evrpc_request_cb(struct evhttp_request *req, void *arg)
+{
+ struct evrpc *rpc = arg;
+ struct evrpc_req_generic *rpc_state = NULL;
+
+ /* let's verify the outside parameters */
+ if (req->type != EVHTTP_REQ_POST ||
+ evbuffer_get_length(req->input_buffer) <= 0)
+ goto error;
+
+ rpc_state = mm_calloc(1, sizeof(struct evrpc_req_generic));
+ if (rpc_state == NULL)
+ goto error;
+ rpc_state->rpc = rpc;
+ rpc_state->http_req = req;
+ rpc_state->rpc_data = NULL;
+
+ if (TAILQ_FIRST(&rpc->base->input_hooks) != NULL) {
+ int hook_res;
+
+ evrpc_hook_associate_meta_(&rpc_state->hook_meta, req->evcon);
+
+ /*
+ * allow hooks to modify the outgoing request
+ */
+ hook_res = evrpc_process_hooks(&rpc->base->input_hooks,
+ rpc_state, req, req->input_buffer);
+ switch (hook_res) {
+ case EVRPC_TERMINATE:
+ goto error;
+ case EVRPC_PAUSE:
+ evrpc_pause_request(rpc->base, rpc_state,
+ evrpc_request_cb_closure);
+ return;
+ case EVRPC_CONTINUE:
+ break;
+ default:
+ EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
+ hook_res == EVRPC_CONTINUE ||
+ hook_res == EVRPC_PAUSE);
+ }
+ }
+
+ evrpc_request_cb_closure(rpc_state, EVRPC_CONTINUE);
+ return;
+
+error:
+ evrpc_reqstate_free_(rpc_state);
+ evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
+ return;
+}
+
+static void
+evrpc_request_cb_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
+{
+ struct evrpc_req_generic *rpc_state = arg;
+ struct evrpc *rpc;
+ struct evhttp_request *req;
+
+ EVUTIL_ASSERT(rpc_state);
+ rpc = rpc_state->rpc;
+ req = rpc_state->http_req;
+
+ if (hook_res == EVRPC_TERMINATE)
+ goto error;
+
+ /* let's check that we can parse the request */
+ rpc_state->request = rpc->request_new(rpc->request_new_arg);
+ if (rpc_state->request == NULL)
+ goto error;
+
+ if (rpc->request_unmarshal(
+ rpc_state->request, req->input_buffer) == -1) {
+ /* we failed to parse the request; that's a bummer */
+ goto error;
+ }
+
+ /* at this point, we have a well formed request, prepare the reply */
+
+ rpc_state->reply = rpc->reply_new(rpc->reply_new_arg);
+ if (rpc_state->reply == NULL)
+ goto error;
+
+ /* give the rpc to the user; they can deal with it */
+ rpc->cb(rpc_state, rpc->cb_arg);
+
+ return;
+
+error:
+ evrpc_reqstate_free_(rpc_state);
+ evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
+ return;
+}
+
+
+void
+evrpc_reqstate_free_(struct evrpc_req_generic* rpc_state)
+{
+ struct evrpc *rpc;
+ EVUTIL_ASSERT(rpc_state != NULL);
+ rpc = rpc_state->rpc;
+
+ /* clean up all memory */
+ if (rpc_state->hook_meta != NULL)
+ evrpc_hook_context_free_(rpc_state->hook_meta);
+ if (rpc_state->request != NULL)
+ rpc->request_free(rpc_state->request);
+ if (rpc_state->reply != NULL)
+ rpc->reply_free(rpc_state->reply);
+ if (rpc_state->rpc_data != NULL)
+ evbuffer_free(rpc_state->rpc_data);
+ mm_free(rpc_state);
+}
+
+static void
+evrpc_request_done_closure(void *, enum EVRPC_HOOK_RESULT);
+
+void
+evrpc_request_done(struct evrpc_req_generic *rpc_state)
+{
+ struct evhttp_request *req;
+ struct evrpc *rpc;
+
+ EVUTIL_ASSERT(rpc_state);
+
+ req = rpc_state->http_req;
+ rpc = rpc_state->rpc;
+
+ if (rpc->reply_complete(rpc_state->reply) == -1) {
+ /* the reply was not completely filled in. error out */
+ goto error;
+ }
+
+ if ((rpc_state->rpc_data = evbuffer_new()) == NULL) {
+ /* out of memory */
+ goto error;
+ }
+
+ /* serialize the reply */
+ rpc->reply_marshal(rpc_state->rpc_data, rpc_state->reply);
+
+ if (TAILQ_FIRST(&rpc->base->output_hooks) != NULL) {
+ int hook_res;
+
+ evrpc_hook_associate_meta_(&rpc_state->hook_meta, req->evcon);
+
+ /* do hook based tweaks to the request */
+ hook_res = evrpc_process_hooks(&rpc->base->output_hooks,
+ rpc_state, req, rpc_state->rpc_data);
+ switch (hook_res) {
+ case EVRPC_TERMINATE:
+ goto error;
+ case EVRPC_PAUSE:
+ if (evrpc_pause_request(rpc->base, rpc_state,
+ evrpc_request_done_closure) == -1)
+ goto error;
+ return;
+ case EVRPC_CONTINUE:
+ break;
+ default:
+ EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
+ hook_res == EVRPC_CONTINUE ||
+ hook_res == EVRPC_PAUSE);
+ }
+ }
+
+ evrpc_request_done_closure(rpc_state, EVRPC_CONTINUE);
+ return;
+
+error:
+ evrpc_reqstate_free_(rpc_state);
+ evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
+ return;
+}
+
+void *
+evrpc_get_request(struct evrpc_req_generic *req)
+{
+ return req->request;
+}
+
+void *
+evrpc_get_reply(struct evrpc_req_generic *req)
+{
+ return req->reply;
+}
+
+static void
+evrpc_request_done_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
+{
+ struct evrpc_req_generic *rpc_state = arg;
+ struct evhttp_request *req;
+ EVUTIL_ASSERT(rpc_state);
+ req = rpc_state->http_req;
+
+ if (hook_res == EVRPC_TERMINATE)
+ goto error;
+
+ /* on success, we are going to transmit marshaled binary data */
+ if (evhttp_find_header(req->output_headers, "Content-Type") == NULL) {
+ evhttp_add_header(req->output_headers,
+ "Content-Type", "application/octet-stream");
+ }
+ evhttp_send_reply(req, HTTP_OK, "OK", rpc_state->rpc_data);
+
+ evrpc_reqstate_free_(rpc_state);
+
+ return;
+
+error:
+ evrpc_reqstate_free_(rpc_state);
+ evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
+ return;
+}
+
+
+/* Client implementation of RPC site */
+
+static int evrpc_schedule_request(struct evhttp_connection *connection,
+ struct evrpc_request_wrapper *ctx);
+
+struct evrpc_pool *
+evrpc_pool_new(struct event_base *base)
+{
+ struct evrpc_pool *pool = mm_calloc(1, sizeof(struct evrpc_pool));
+ if (pool == NULL)
+ return (NULL);
+
+ TAILQ_INIT(&pool->connections);
+ TAILQ_INIT(&pool->requests);
+
+ TAILQ_INIT(&pool->paused_requests);
+
+ TAILQ_INIT(&pool->input_hooks);
+ TAILQ_INIT(&pool->output_hooks);
+
+ pool->base = base;
+ pool->timeout = -1;
+
+ return (pool);
+}
+
+static void
+evrpc_request_wrapper_free(struct evrpc_request_wrapper *request)
+{
+ if (request->hook_meta != NULL)
+ evrpc_hook_context_free_(request->hook_meta);
+ mm_free(request->name);
+ mm_free(request);
+}
+
+void
+evrpc_pool_free(struct evrpc_pool *pool)
+{
+ struct evhttp_connection *connection;
+ struct evrpc_request_wrapper *request;
+ struct evrpc_hook_ctx *pause;
+ struct evrpc_hook *hook;
+ int r;
+
+ while ((request = TAILQ_FIRST(&pool->requests)) != NULL) {
+ TAILQ_REMOVE(&pool->requests, request, next);
+ evrpc_request_wrapper_free(request);
+ }
+
+ while ((pause = TAILQ_FIRST(&pool->paused_requests)) != NULL) {
+ TAILQ_REMOVE(&pool->paused_requests, pause, next);
+ mm_free(pause);
+ }
+
+ while ((connection = TAILQ_FIRST(&pool->connections)) != NULL) {
+ TAILQ_REMOVE(&pool->connections, connection, next);
+ evhttp_connection_free(connection);
+ }
+
+ while ((hook = TAILQ_FIRST(&pool->input_hooks)) != NULL) {
+ r = evrpc_remove_hook(pool, EVRPC_INPUT, hook);
+ EVUTIL_ASSERT(r);
+ }
+
+ while ((hook = TAILQ_FIRST(&pool->output_hooks)) != NULL) {
+ r = evrpc_remove_hook(pool, EVRPC_OUTPUT, hook);
+ EVUTIL_ASSERT(r);
+ }
+
+ mm_free(pool);
+}
+
+/*
+ * Add a connection to the RPC pool. A request scheduled on the pool
+ * may use any available connection.
+ */
+
+void
+evrpc_pool_add_connection(struct evrpc_pool *pool,
+ struct evhttp_connection *connection)
+{
+ EVUTIL_ASSERT(connection->http_server == NULL);
+ TAILQ_INSERT_TAIL(&pool->connections, connection, next);
+
+ /*
+ * associate an event base with this connection
+ */
+ if (pool->base != NULL)
+ evhttp_connection_set_base(connection, pool->base);
+
+ /*
+ * unless a timeout was specifically set for a connection,
+ * the connection inherits the timeout from the pool.
+ */
+ if (!evutil_timerisset(&connection->timeout))
+ evhttp_connection_set_timeout(connection, pool->timeout);
+
+ /*
+ * if we have any requests pending, schedule them with the new
+ * connections.
+ */
+
+ if (TAILQ_FIRST(&pool->requests) != NULL) {
+ struct evrpc_request_wrapper *request =
+ TAILQ_FIRST(&pool->requests);
+ TAILQ_REMOVE(&pool->requests, request, next);
+ evrpc_schedule_request(connection, request);
+ }
+}
+
+void
+evrpc_pool_remove_connection(struct evrpc_pool *pool,
+ struct evhttp_connection *connection)
+{
+ TAILQ_REMOVE(&pool->connections, connection, next);
+}
+
+void
+evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs)
+{
+ struct evhttp_connection *evcon;
+ TAILQ_FOREACH(evcon, &pool->connections, next) {
+ evhttp_connection_set_timeout(evcon, timeout_in_secs);
+ }
+ pool->timeout = timeout_in_secs;
+}
+
+
+static void evrpc_reply_done(struct evhttp_request *, void *);
+static void evrpc_request_timeout(evutil_socket_t, short, void *);
+
+/*
+ * Finds a connection object associated with the pool that is currently
+ * idle and can be used to make a request.
+ */
+static struct evhttp_connection *
+evrpc_pool_find_connection(struct evrpc_pool *pool)
+{
+ struct evhttp_connection *connection;
+ TAILQ_FOREACH(connection, &pool->connections, next) {
+ if (TAILQ_FIRST(&connection->requests) == NULL)
+ return (connection);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Prototypes responsible for evrpc scheduling and hooking
+ */
+
+static void evrpc_schedule_request_closure(void *ctx, enum EVRPC_HOOK_RESULT);
+
+/*
+ * We assume that the ctx is no longer queued on the pool.
+ */
+static int
+evrpc_schedule_request(struct evhttp_connection *connection,
+ struct evrpc_request_wrapper *ctx)
+{
+ struct evhttp_request *req = NULL;
+ struct evrpc_pool *pool = ctx->pool;
+ struct evrpc_status status;
+
+ if ((req = evhttp_request_new(evrpc_reply_done, ctx)) == NULL)
+ goto error;
+
+ /* serialize the request data into the output buffer */
+ ctx->request_marshal(req->output_buffer, ctx->request);
+
+ /* we need to know the connection that we might have to abort */
+ ctx->evcon = connection;
+
+ /* if we get paused we also need to know the request */
+ ctx->req = req;
+
+ if (TAILQ_FIRST(&pool->output_hooks) != NULL) {
+ int hook_res;
+
+ evrpc_hook_associate_meta_(&ctx->hook_meta, connection);
+
+ /* apply hooks to the outgoing request */
+ hook_res = evrpc_process_hooks(&pool->output_hooks,
+ ctx, req, req->output_buffer);
+
+ switch (hook_res) {
+ case EVRPC_TERMINATE:
+ goto error;
+ case EVRPC_PAUSE:
+ /* we need to be explicitly resumed */
+ if (evrpc_pause_request(pool, ctx,
+ evrpc_schedule_request_closure) == -1)
+ goto error;
+ return (0);
+ case EVRPC_CONTINUE:
+ /* we can just continue */
+ break;
+ default:
+ EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
+ hook_res == EVRPC_CONTINUE ||
+ hook_res == EVRPC_PAUSE);
+ }
+ }
+
+ evrpc_schedule_request_closure(ctx, EVRPC_CONTINUE);
+ return (0);
+
+error:
+ memset(&status, 0, sizeof(status));
+ status.error = EVRPC_STATUS_ERR_UNSTARTED;
+ (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
+ evrpc_request_wrapper_free(ctx);
+ return (-1);
+}
+
+static void
+evrpc_schedule_request_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
+{
+ struct evrpc_request_wrapper *ctx = arg;
+ struct evhttp_connection *connection = ctx->evcon;
+ struct evhttp_request *req = ctx->req;
+ struct evrpc_pool *pool = ctx->pool;
+ struct evrpc_status status;
+ char *uri = NULL;
+ int res = 0;
+
+ if (hook_res == EVRPC_TERMINATE)
+ goto error;
+
+ uri = evrpc_construct_uri(ctx->name);
+ if (uri == NULL)
+ goto error;
+
+ if (pool->timeout > 0) {
+ /*
+ * a timeout after which the whole rpc is going to be aborted.
+ */
+ struct timeval tv;
+ evutil_timerclear(&tv);
+ tv.tv_sec = pool->timeout;
+ evtimer_add(&ctx->ev_timeout, &tv);
+ }
+
+ /* start the request over the connection */
+ res = evhttp_make_request(connection, req, EVHTTP_REQ_POST, uri);
+ mm_free(uri);
+
+ if (res == -1)
+ goto error;
+
+ return;
+
+error:
+ memset(&status, 0, sizeof(status));
+ status.error = EVRPC_STATUS_ERR_UNSTARTED;
+ (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
+ evrpc_request_wrapper_free(ctx);
+}
+
+/* we just queue the paused request on the pool under the req object */
+static int
+evrpc_pause_request(void *vbase, void *ctx,
+ void (*cb)(void *, enum EVRPC_HOOK_RESULT))
+{
+ struct evrpc_hooks_ *base = vbase;
+ struct evrpc_hook_ctx *pause = mm_malloc(sizeof(*pause));
+ if (pause == NULL)
+ return (-1);
+
+ pause->ctx = ctx;
+ pause->cb = cb;
+
+ TAILQ_INSERT_TAIL(&base->pause_requests, pause, next);
+ return (0);
+}
+
+int
+evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res)
+{
+ struct evrpc_hooks_ *base = vbase;
+ struct evrpc_pause_list *head = &base->pause_requests;
+ struct evrpc_hook_ctx *pause;
+
+ TAILQ_FOREACH(pause, head, next) {
+ if (pause->ctx == ctx)
+ break;
+ }
+
+ if (pause == NULL)
+ return (-1);
+
+ (*pause->cb)(pause->ctx, res);
+ TAILQ_REMOVE(head, pause, next);
+ mm_free(pause);
+ return (0);
+}
+
+int
+evrpc_make_request(struct evrpc_request_wrapper *ctx)
+{
+ struct evrpc_pool *pool = ctx->pool;
+
+ /* initialize the event structure for this rpc */
+ evtimer_assign(&ctx->ev_timeout, pool->base, evrpc_request_timeout, ctx);
+
+ /* we better have some available connections on the pool */
+ EVUTIL_ASSERT(TAILQ_FIRST(&pool->connections) != NULL);
+
+ /*
+ * if no connection is available, we queue the request on the pool,
+ * the next time a connection is empty, the rpc will be send on that.
+ */
+ TAILQ_INSERT_TAIL(&pool->requests, ctx, next);
+
+ evrpc_pool_schedule(pool);
+
+ return (0);
+}
+
+
+struct evrpc_request_wrapper *
+evrpc_make_request_ctx(
+ struct evrpc_pool *pool, void *request, void *reply,
+ const char *rpcname,
+ void (*req_marshal)(struct evbuffer*, void *),
+ void (*rpl_clear)(void *),
+ int (*rpl_unmarshal)(void *, struct evbuffer *),
+ void (*cb)(struct evrpc_status *, void *, void *, void *),
+ void *cbarg)
+{
+ struct evrpc_request_wrapper *ctx = (struct evrpc_request_wrapper *)
+ mm_malloc(sizeof(struct evrpc_request_wrapper));
+ if (ctx == NULL)
+ return (NULL);
+
+ ctx->pool = pool;
+ ctx->hook_meta = NULL;
+ ctx->evcon = NULL;
+ ctx->name = mm_strdup(rpcname);
+ if (ctx->name == NULL) {
+ mm_free(ctx);
+ return (NULL);
+ }
+ ctx->cb = cb;
+ ctx->cb_arg = cbarg;
+ ctx->request = request;
+ ctx->reply = reply;
+ ctx->request_marshal = req_marshal;
+ ctx->reply_clear = rpl_clear;
+ ctx->reply_unmarshal = rpl_unmarshal;
+
+ return (ctx);
+}
+
+static void
+evrpc_reply_done_closure(void *, enum EVRPC_HOOK_RESULT);
+
+static void
+evrpc_reply_done(struct evhttp_request *req, void *arg)
+{
+ struct evrpc_request_wrapper *ctx = arg;
+ struct evrpc_pool *pool = ctx->pool;
+ int hook_res = EVRPC_CONTINUE;
+
+ /* cancel any timeout we might have scheduled */
+ event_del(&ctx->ev_timeout);
+
+ ctx->req = req;
+
+ /* we need to get the reply now */
+ if (req == NULL) {
+ evrpc_reply_done_closure(ctx, EVRPC_CONTINUE);
+ return;
+ }
+
+ if (TAILQ_FIRST(&pool->input_hooks) != NULL) {
+ evrpc_hook_associate_meta_(&ctx->hook_meta, ctx->evcon);
+
+ /* apply hooks to the incoming request */
+ hook_res = evrpc_process_hooks(&pool->input_hooks,
+ ctx, req, req->input_buffer);
+
+ switch (hook_res) {
+ case EVRPC_TERMINATE:
+ case EVRPC_CONTINUE:
+ break;
+ case EVRPC_PAUSE:
+ /*
+ * if we get paused we also need to know the
+ * request. unfortunately, the underlying
+ * layer is going to free it. we need to
+ * request ownership explicitly
+ */
+ if (req != NULL)
+ evhttp_request_own(req);
+
+ evrpc_pause_request(pool, ctx,
+ evrpc_reply_done_closure);
+ return;
+ default:
+ EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
+ hook_res == EVRPC_CONTINUE ||
+ hook_res == EVRPC_PAUSE);
+ }
+ }
+
+ evrpc_reply_done_closure(ctx, hook_res);
+
+ /* http request is being freed by underlying layer */
+}
+
+static void
+evrpc_reply_done_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
+{
+ struct evrpc_request_wrapper *ctx = arg;
+ struct evhttp_request *req = ctx->req;
+ struct evrpc_pool *pool = ctx->pool;
+ struct evrpc_status status;
+ int res = -1;
+
+ memset(&status, 0, sizeof(status));
+ status.http_req = req;
+
+ /* we need to get the reply now */
+ if (req == NULL) {
+ status.error = EVRPC_STATUS_ERR_TIMEOUT;
+ } else if (hook_res == EVRPC_TERMINATE) {
+ status.error = EVRPC_STATUS_ERR_HOOKABORTED;
+ } else {
+ res = ctx->reply_unmarshal(ctx->reply, req->input_buffer);
+ if (res == -1)
+ status.error = EVRPC_STATUS_ERR_BADPAYLOAD;
+ }
+
+ if (res == -1) {
+ /* clear everything that we might have written previously */
+ ctx->reply_clear(ctx->reply);
+ }
+
+ (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
+
+ evrpc_request_wrapper_free(ctx);
+
+ /* the http layer owned the original request structure, but if we
+ * got paused, we asked for ownership and need to free it here. */
+ if (req != NULL && evhttp_request_is_owned(req))
+ evhttp_request_free(req);
+
+ /* see if we can schedule another request */
+ evrpc_pool_schedule(pool);
+}
+
+static void
+evrpc_pool_schedule(struct evrpc_pool *pool)
+{
+ struct evrpc_request_wrapper *ctx = TAILQ_FIRST(&pool->requests);
+ struct evhttp_connection *evcon;
+
+ /* if no requests are pending, we have no work */
+ if (ctx == NULL)
+ return;
+
+ if ((evcon = evrpc_pool_find_connection(pool)) != NULL) {
+ TAILQ_REMOVE(&pool->requests, ctx, next);
+ evrpc_schedule_request(evcon, ctx);
+ }
+}
+
+static void
+evrpc_request_timeout(evutil_socket_t fd, short what, void *arg)
+{
+ struct evrpc_request_wrapper *ctx = arg;
+ struct evhttp_connection *evcon = ctx->evcon;
+ EVUTIL_ASSERT(evcon != NULL);
+
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT);
+}
+
+/*
+ * frees potential meta data associated with a request.
+ */
+
+static void
+evrpc_meta_data_free(struct evrpc_meta_list *meta_data)
+{
+ struct evrpc_meta *entry;
+ EVUTIL_ASSERT(meta_data != NULL);
+
+ while ((entry = TAILQ_FIRST(meta_data)) != NULL) {
+ TAILQ_REMOVE(meta_data, entry, next);
+ mm_free(entry->key);
+ mm_free(entry->data);
+ mm_free(entry);
+ }
+}
+
+static struct evrpc_hook_meta *
+evrpc_hook_meta_new_(void)
+{
+ struct evrpc_hook_meta *ctx;
+ ctx = mm_malloc(sizeof(struct evrpc_hook_meta));
+ EVUTIL_ASSERT(ctx != NULL);
+
+ TAILQ_INIT(&ctx->meta_data);
+ ctx->evcon = NULL;
+
+ return (ctx);
+}
+
+static void
+evrpc_hook_associate_meta_(struct evrpc_hook_meta **pctx,
+ struct evhttp_connection *evcon)
+{
+ struct evrpc_hook_meta *ctx = *pctx;
+ if (ctx == NULL)
+ *pctx = ctx = evrpc_hook_meta_new_();
+ ctx->evcon = evcon;
+}
+
+static void
+evrpc_hook_context_free_(struct evrpc_hook_meta *ctx)
+{
+ evrpc_meta_data_free(&ctx->meta_data);
+ mm_free(ctx);
+}
+
+/* Adds meta data */
+void
+evrpc_hook_add_meta(void *ctx, const char *key,
+ const void *data, size_t data_size)
+{
+ struct evrpc_request_wrapper *req = ctx;
+ struct evrpc_hook_meta *store = NULL;
+ struct evrpc_meta *meta = NULL;
+
+ if ((store = req->hook_meta) == NULL)
+ store = req->hook_meta = evrpc_hook_meta_new_();
+
+ meta = mm_malloc(sizeof(struct evrpc_meta));
+ EVUTIL_ASSERT(meta != NULL);
+ meta->key = mm_strdup(key);
+ EVUTIL_ASSERT(meta->key != NULL);
+ meta->data_size = data_size;
+ meta->data = mm_malloc(data_size);
+ EVUTIL_ASSERT(meta->data != NULL);
+ memcpy(meta->data, data, data_size);
+
+ TAILQ_INSERT_TAIL(&store->meta_data, meta, next);
+}
+
+int
+evrpc_hook_find_meta(void *ctx, const char *key, void **data, size_t *data_size)
+{
+ struct evrpc_request_wrapper *req = ctx;
+ struct evrpc_meta *meta = NULL;
+
+ if (req->hook_meta == NULL)
+ return (-1);
+
+ TAILQ_FOREACH(meta, &req->hook_meta->meta_data, next) {
+ if (strcmp(meta->key, key) == 0) {
+ *data = meta->data;
+ *data_size = meta->data_size;
+ return (0);
+ }
+ }
+
+ return (-1);
+}
+
+struct evhttp_connection *
+evrpc_hook_get_connection(void *ctx)
+{
+ struct evrpc_request_wrapper *req = ctx;
+ return (req->hook_meta != NULL ? req->hook_meta->evcon : NULL);
+}
+
+int
+evrpc_send_request_generic(struct evrpc_pool *pool,
+ void *request, void *reply,
+ void (*cb)(struct evrpc_status *, void *, void *, void *),
+ void *cb_arg,
+ const char *rpcname,
+ void (*req_marshal)(struct evbuffer *, void *),
+ void (*rpl_clear)(void *),
+ int (*rpl_unmarshal)(void *, struct evbuffer *))
+{
+ struct evrpc_status status;
+ struct evrpc_request_wrapper *ctx;
+ ctx = evrpc_make_request_ctx(pool, request, reply,
+ rpcname, req_marshal, rpl_clear, rpl_unmarshal, cb, cb_arg);
+ if (ctx == NULL)
+ goto error;
+ return (evrpc_make_request(ctx));
+error:
+ memset(&status, 0, sizeof(status));
+ status.error = EVRPC_STATUS_ERR_UNSTARTED;
+ (*(cb))(&status, request, reply, cb_arg);
+ return (-1);
+}
+
+/** Takes a request object and fills it in with the right magic */
+static struct evrpc *
+evrpc_register_object(const char *name,
+ void *(*req_new)(void*), void *req_new_arg, void (*req_free)(void *),
+ int (*req_unmarshal)(void *, struct evbuffer *),
+ void *(*rpl_new)(void*), void *rpl_new_arg, void (*rpl_free)(void *),
+ int (*rpl_complete)(void *),
+ void (*rpl_marshal)(struct evbuffer *, void *))
+{
+ struct evrpc* rpc = (struct evrpc *)mm_calloc(1, sizeof(struct evrpc));
+ if (rpc == NULL)
+ return (NULL);
+ rpc->uri = mm_strdup(name);
+ if (rpc->uri == NULL) {
+ mm_free(rpc);
+ return (NULL);
+ }
+ rpc->request_new = req_new;
+ rpc->request_new_arg = req_new_arg;
+ rpc->request_free = req_free;
+ rpc->request_unmarshal = req_unmarshal;
+ rpc->reply_new = rpl_new;
+ rpc->reply_new_arg = rpl_new_arg;
+ rpc->reply_free = rpl_free;
+ rpc->reply_complete = rpl_complete;
+ rpc->reply_marshal = rpl_marshal;
+ return (rpc);
+}
+
+int
+evrpc_register_generic(struct evrpc_base *base, const char *name,
+ void (*callback)(struct evrpc_req_generic *, void *), void *cbarg,
+ void *(*req_new)(void *), void *req_new_arg, void (*req_free)(void *),
+ int (*req_unmarshal)(void *, struct evbuffer *),
+ void *(*rpl_new)(void *), void *rpl_new_arg, void (*rpl_free)(void *),
+ int (*rpl_complete)(void *),
+ void (*rpl_marshal)(struct evbuffer *, void *))
+{
+ struct evrpc* rpc =
+ evrpc_register_object(name, req_new, req_new_arg, req_free, req_unmarshal,
+ rpl_new, rpl_new_arg, rpl_free, rpl_complete, rpl_marshal);
+ if (rpc == NULL)
+ return (-1);
+ evrpc_register_rpc(base, rpc,
+ (void (*)(struct evrpc_req_generic*, void *))callback, cbarg);
+ return (0);
+}
+
+/** accessors for obscure and undocumented functionality */
+struct evrpc_pool *
+evrpc_request_get_pool(struct evrpc_request_wrapper *ctx)
+{
+ return (ctx->pool);
+}
+
+void
+evrpc_request_set_pool(struct evrpc_request_wrapper *ctx,
+ struct evrpc_pool *pool)
+{
+ ctx->pool = pool;
+}
+
+void
+evrpc_request_set_cb(struct evrpc_request_wrapper *ctx,
+ void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg),
+ void *cb_arg)
+{
+ ctx->cb = cb;
+ ctx->cb_arg = cb_arg;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evsignal-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/evsignal-internal.h
new file mode 100644
index 000000000..5cff03b52
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evsignal-internal.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVSIGNAL_INTERNAL_H_INCLUDED_
+#define EVSIGNAL_INTERNAL_H_INCLUDED_
+
+#ifndef evutil_socket_t
+#include "event2/util.h"
+#endif
+#include <signal.h>
+
+typedef void (*ev_sighandler_t)(int);
+
+/* Data structure for the default signal-handling implementation in signal.c
+ */
+struct evsig_info {
+ /* Event watching ev_signal_pair[1] */
+ struct event ev_signal;
+ /* Socketpair used to send notifications from the signal handler */
+ evutil_socket_t ev_signal_pair[2];
+ /* True iff we've added the ev_signal event yet. */
+ int ev_signal_added;
+ /* Count of the number of signals we're currently watching. */
+ int ev_n_signals_added;
+
+ /* Array of previous signal handler objects before Libevent started
+ * messing with them. Used to restore old signal handlers. */
+#ifdef EVENT__HAVE_SIGACTION
+ struct sigaction **sh_old;
+#else
+ ev_sighandler_t **sh_old;
+#endif
+ /* Size of sh_old. */
+ int sh_old_max;
+};
+int evsig_init_(struct event_base *);
+void evsig_dealloc_(struct event_base *);
+
+void evsig_set_base_(struct event_base *base);
+void evsig_free_globals_(void);
+
+#endif /* EVSIGNAL_INTERNAL_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evthread-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/evthread-internal.h
new file mode 100644
index 000000000..efdecf81e
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evthread-internal.h
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVTHREAD_INTERNAL_H_INCLUDED_
+#define EVTHREAD_INTERNAL_H_INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include "event2/thread.h"
+#include "util-internal.h"
+
+struct event_base;
+
+#ifndef _WIN32
+/* On Windows, the way we currently make DLLs, it's not allowed for us to
+ * have shared global structures. Thus, we only do the direct-call-to-function
+ * code path if we know that the local shared library system supports it.
+ */
+#define EVTHREAD_EXPOSE_STRUCTS
+#endif
+
+#if ! defined(EVENT__DISABLE_THREAD_SUPPORT) && defined(EVTHREAD_EXPOSE_STRUCTS)
+/* Global function pointers to lock-related functions. NULL if locking isn't
+ enabled. */
+extern struct evthread_lock_callbacks evthread_lock_fns_;
+extern struct evthread_condition_callbacks evthread_cond_fns_;
+extern unsigned long (*evthread_id_fn_)(void);
+extern int evthread_lock_debugging_enabled_;
+
+/** Return the ID of the current thread, or 1 if threading isn't enabled. */
+#define EVTHREAD_GET_ID() \
+ (evthread_id_fn_ ? evthread_id_fn_() : 1)
+
+/** Return true iff we're in the thread that is currently (or most recently)
+ * running a given event_base's loop. Requires lock. */
+#define EVBASE_IN_THREAD(base) \
+ (evthread_id_fn_ == NULL || \
+ (base)->th_owner_id == evthread_id_fn_())
+
+/** Return true iff we need to notify the base's main thread about changes to
+ * its state, because it's currently running the main loop in another
+ * thread. Requires lock. */
+#define EVBASE_NEED_NOTIFY(base) \
+ (evthread_id_fn_ != NULL && \
+ (base)->running_loop && \
+ (base)->th_owner_id != evthread_id_fn_())
+
+/** Allocate a new lock, and store it in lockvar, a void*. Sets lockvar to
+ NULL if locking is not enabled. */
+#define EVTHREAD_ALLOC_LOCK(lockvar, locktype) \
+ ((lockvar) = evthread_lock_fns_.alloc ? \
+ evthread_lock_fns_.alloc(locktype) : NULL)
+
+/** Free a given lock, if it is present and locking is enabled. */
+#define EVTHREAD_FREE_LOCK(lockvar, locktype) \
+ do { \
+ void *lock_tmp_ = (lockvar); \
+ if (lock_tmp_ && evthread_lock_fns_.free) \
+ evthread_lock_fns_.free(lock_tmp_, (locktype)); \
+ } while (0)
+
+/** Acquire a lock. */
+#define EVLOCK_LOCK(lockvar,mode) \
+ do { \
+ if (lockvar) \
+ evthread_lock_fns_.lock(mode, lockvar); \
+ } while (0)
+
+/** Release a lock */
+#define EVLOCK_UNLOCK(lockvar,mode) \
+ do { \
+ if (lockvar) \
+ evthread_lock_fns_.unlock(mode, lockvar); \
+ } while (0)
+
+/** Helper: put lockvar1 and lockvar2 into pointerwise ascending order. */
+#define EVLOCK_SORTLOCKS_(lockvar1, lockvar2) \
+ do { \
+ if (lockvar1 && lockvar2 && lockvar1 > lockvar2) { \
+ void *tmp = lockvar1; \
+ lockvar1 = lockvar2; \
+ lockvar2 = tmp; \
+ } \
+ } while (0)
+
+/** Lock an event_base, if it is set up for locking. Acquires the lock
+ in the base structure whose field is named 'lockvar'. */
+#define EVBASE_ACQUIRE_LOCK(base, lockvar) do { \
+ EVLOCK_LOCK((base)->lockvar, 0); \
+ } while (0)
+
+/** Unlock an event_base, if it is set up for locking. */
+#define EVBASE_RELEASE_LOCK(base, lockvar) do { \
+ EVLOCK_UNLOCK((base)->lockvar, 0); \
+ } while (0)
+
+/** If lock debugging is enabled, and lock is non-null, assert that 'lock' is
+ * locked and held by us. */
+#define EVLOCK_ASSERT_LOCKED(lock) \
+ do { \
+ if ((lock) && evthread_lock_debugging_enabled_) { \
+ EVUTIL_ASSERT(evthread_is_debug_lock_held_(lock)); \
+ } \
+ } while (0)
+
+/** Try to grab the lock for 'lockvar' without blocking, and return 1 if we
+ * manage to get it. */
+static inline int EVLOCK_TRY_LOCK_(void *lock);
+static inline int
+EVLOCK_TRY_LOCK_(void *lock)
+{
+ if (lock && evthread_lock_fns_.lock) {
+ int r = evthread_lock_fns_.lock(EVTHREAD_TRY, lock);
+ return !r;
+ } else {
+ /* Locking is disabled either globally or for this thing;
+ * of course we count as having the lock. */
+ return 1;
+ }
+}
+
+/** Allocate a new condition variable and store it in the void *, condvar */
+#define EVTHREAD_ALLOC_COND(condvar) \
+ do { \
+ (condvar) = evthread_cond_fns_.alloc_condition ? \
+ evthread_cond_fns_.alloc_condition(0) : NULL; \
+ } while (0)
+/** Deallocate and free a condition variable in condvar */
+#define EVTHREAD_FREE_COND(cond) \
+ do { \
+ if (cond) \
+ evthread_cond_fns_.free_condition((cond)); \
+ } while (0)
+/** Signal one thread waiting on cond */
+#define EVTHREAD_COND_SIGNAL(cond) \
+ ( (cond) ? evthread_cond_fns_.signal_condition((cond), 0) : 0 )
+/** Signal all threads waiting on cond */
+#define EVTHREAD_COND_BROADCAST(cond) \
+ ( (cond) ? evthread_cond_fns_.signal_condition((cond), 1) : 0 )
+/** Wait until the condition 'cond' is signalled. Must be called while
+ * holding 'lock'. The lock will be released until the condition is
+ * signalled, at which point it will be acquired again. Returns 0 for
+ * success, -1 for failure. */
+#define EVTHREAD_COND_WAIT(cond, lock) \
+ ( (cond) ? evthread_cond_fns_.wait_condition((cond), (lock), NULL) : 0 )
+/** As EVTHREAD_COND_WAIT, but gives up after 'tv' has elapsed. Returns 1
+ * on timeout. */
+#define EVTHREAD_COND_WAIT_TIMED(cond, lock, tv) \
+ ( (cond) ? evthread_cond_fns_.wait_condition((cond), (lock), (tv)) : 0 )
+
+/** True iff locking functions have been configured. */
+#define EVTHREAD_LOCKING_ENABLED() \
+ (evthread_lock_fns_.lock != NULL)
+
+#elif ! defined(EVENT__DISABLE_THREAD_SUPPORT)
+
+unsigned long evthreadimpl_get_id_(void);
+int evthreadimpl_is_lock_debugging_enabled_(void);
+void *evthreadimpl_lock_alloc_(unsigned locktype);
+void evthreadimpl_lock_free_(void *lock, unsigned locktype);
+int evthreadimpl_lock_lock_(unsigned mode, void *lock);
+int evthreadimpl_lock_unlock_(unsigned mode, void *lock);
+void *evthreadimpl_cond_alloc_(unsigned condtype);
+void evthreadimpl_cond_free_(void *cond);
+int evthreadimpl_cond_signal_(void *cond, int broadcast);
+int evthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv);
+int evthreadimpl_locking_enabled_(void);
+
+#define EVTHREAD_GET_ID() evthreadimpl_get_id_()
+#define EVBASE_IN_THREAD(base) \
+ ((base)->th_owner_id == evthreadimpl_get_id_())
+#define EVBASE_NEED_NOTIFY(base) \
+ ((base)->running_loop && \
+ ((base)->th_owner_id != evthreadimpl_get_id_()))
+
+#define EVTHREAD_ALLOC_LOCK(lockvar, locktype) \
+ ((lockvar) = evthreadimpl_lock_alloc_(locktype))
+
+#define EVTHREAD_FREE_LOCK(lockvar, locktype) \
+ do { \
+ void *lock_tmp_ = (lockvar); \
+ if (lock_tmp_) \
+ evthreadimpl_lock_free_(lock_tmp_, (locktype)); \
+ } while (0)
+
+/** Acquire a lock. */
+#define EVLOCK_LOCK(lockvar,mode) \
+ do { \
+ if (lockvar) \
+ evthreadimpl_lock_lock_(mode, lockvar); \
+ } while (0)
+
+/** Release a lock */
+#define EVLOCK_UNLOCK(lockvar,mode) \
+ do { \
+ if (lockvar) \
+ evthreadimpl_lock_unlock_(mode, lockvar); \
+ } while (0)
+
+/** Lock an event_base, if it is set up for locking. Acquires the lock
+ in the base structure whose field is named 'lockvar'. */
+#define EVBASE_ACQUIRE_LOCK(base, lockvar) do { \
+ EVLOCK_LOCK((base)->lockvar, 0); \
+ } while (0)
+
+/** Unlock an event_base, if it is set up for locking. */
+#define EVBASE_RELEASE_LOCK(base, lockvar) do { \
+ EVLOCK_UNLOCK((base)->lockvar, 0); \
+ } while (0)
+
+/** If lock debugging is enabled, and lock is non-null, assert that 'lock' is
+ * locked and held by us. */
+#define EVLOCK_ASSERT_LOCKED(lock) \
+ do { \
+ if ((lock) && evthreadimpl_is_lock_debugging_enabled_()) { \
+ EVUTIL_ASSERT(evthread_is_debug_lock_held_(lock)); \
+ } \
+ } while (0)
+
+/** Try to grab the lock for 'lockvar' without blocking, and return 1 if we
+ * manage to get it. */
+static inline int EVLOCK_TRY_LOCK_(void *lock);
+static inline int
+EVLOCK_TRY_LOCK_(void *lock)
+{
+ if (lock) {
+ int r = evthreadimpl_lock_lock_(EVTHREAD_TRY, lock);
+ return !r;
+ } else {
+ /* Locking is disabled either globally or for this thing;
+ * of course we count as having the lock. */
+ return 1;
+ }
+}
+
+/** Allocate a new condition variable and store it in the void *, condvar */
+#define EVTHREAD_ALLOC_COND(condvar) \
+ do { \
+ (condvar) = evthreadimpl_cond_alloc_(0); \
+ } while (0)
+/** Deallocate and free a condition variable in condvar */
+#define EVTHREAD_FREE_COND(cond) \
+ do { \
+ if (cond) \
+ evthreadimpl_cond_free_((cond)); \
+ } while (0)
+/** Signal one thread waiting on cond */
+#define EVTHREAD_COND_SIGNAL(cond) \
+ ( (cond) ? evthreadimpl_cond_signal_((cond), 0) : 0 )
+/** Signal all threads waiting on cond */
+#define EVTHREAD_COND_BROADCAST(cond) \
+ ( (cond) ? evthreadimpl_cond_signal_((cond), 1) : 0 )
+/** Wait until the condition 'cond' is signalled. Must be called while
+ * holding 'lock'. The lock will be released until the condition is
+ * signalled, at which point it will be acquired again. Returns 0 for
+ * success, -1 for failure. */
+#define EVTHREAD_COND_WAIT(cond, lock) \
+ ( (cond) ? evthreadimpl_cond_wait_((cond), (lock), NULL) : 0 )
+/** As EVTHREAD_COND_WAIT, but gives up after 'tv' has elapsed. Returns 1
+ * on timeout. */
+#define EVTHREAD_COND_WAIT_TIMED(cond, lock, tv) \
+ ( (cond) ? evthreadimpl_cond_wait_((cond), (lock), (tv)) : 0 )
+
+#define EVTHREAD_LOCKING_ENABLED() \
+ (evthreadimpl_locking_enabled_())
+
+#else /* EVENT__DISABLE_THREAD_SUPPORT */
+
+#define EVTHREAD_GET_ID() 1
+#define EVTHREAD_ALLOC_LOCK(lockvar, locktype) EVUTIL_NIL_STMT_
+#define EVTHREAD_FREE_LOCK(lockvar, locktype) EVUTIL_NIL_STMT_
+
+#define EVLOCK_LOCK(lockvar, mode) EVUTIL_NIL_STMT_
+#define EVLOCK_UNLOCK(lockvar, mode) EVUTIL_NIL_STMT_
+#define EVLOCK_LOCK2(lock1,lock2,mode1,mode2) EVUTIL_NIL_STMT_
+#define EVLOCK_UNLOCK2(lock1,lock2,mode1,mode2) EVUTIL_NIL_STMT_
+
+#define EVBASE_IN_THREAD(base) 1
+#define EVBASE_NEED_NOTIFY(base) 0
+#define EVBASE_ACQUIRE_LOCK(base, lock) EVUTIL_NIL_STMT_
+#define EVBASE_RELEASE_LOCK(base, lock) EVUTIL_NIL_STMT_
+#define EVLOCK_ASSERT_LOCKED(lock) EVUTIL_NIL_STMT_
+
+#define EVLOCK_TRY_LOCK_(lock) 1
+
+#define EVTHREAD_ALLOC_COND(condvar) EVUTIL_NIL_STMT_
+#define EVTHREAD_FREE_COND(cond) EVUTIL_NIL_STMT_
+#define EVTHREAD_COND_SIGNAL(cond) EVUTIL_NIL_STMT_
+#define EVTHREAD_COND_BROADCAST(cond) EVUTIL_NIL_STMT_
+#define EVTHREAD_COND_WAIT(cond, lock) EVUTIL_NIL_STMT_
+#define EVTHREAD_COND_WAIT_TIMED(cond, lock, howlong) EVUTIL_NIL_STMT_
+
+#define EVTHREAD_LOCKING_ENABLED() 0
+
+#endif
+
+/* This code is shared between both lock impls */
+#if ! defined(EVENT__DISABLE_THREAD_SUPPORT)
+/** Helper: put lockvar1 and lockvar2 into pointerwise ascending order. */
+#define EVLOCK_SORTLOCKS_(lockvar1, lockvar2) \
+ do { \
+ if (lockvar1 && lockvar2 && lockvar1 > lockvar2) { \
+ void *tmp = lockvar1; \
+ lockvar1 = lockvar2; \
+ lockvar2 = tmp; \
+ } \
+ } while (0)
+
+/** Acquire both lock1 and lock2. Always allocates locks in the same order,
+ * so that two threads locking two locks with LOCK2 will not deadlock. */
+#define EVLOCK_LOCK2(lock1,lock2,mode1,mode2) \
+ do { \
+ void *lock1_tmplock_ = (lock1); \
+ void *lock2_tmplock_ = (lock2); \
+ EVLOCK_SORTLOCKS_(lock1_tmplock_,lock2_tmplock_); \
+ EVLOCK_LOCK(lock1_tmplock_,mode1); \
+ if (lock2_tmplock_ != lock1_tmplock_) \
+ EVLOCK_LOCK(lock2_tmplock_,mode2); \
+ } while (0)
+/** Release both lock1 and lock2. */
+#define EVLOCK_UNLOCK2(lock1,lock2,mode1,mode2) \
+ do { \
+ void *lock1_tmplock_ = (lock1); \
+ void *lock2_tmplock_ = (lock2); \
+ EVLOCK_SORTLOCKS_(lock1_tmplock_,lock2_tmplock_); \
+ if (lock2_tmplock_ != lock1_tmplock_) \
+ EVLOCK_UNLOCK(lock2_tmplock_,mode2); \
+ EVLOCK_UNLOCK(lock1_tmplock_,mode1); \
+ } while (0)
+
+int evthread_is_debug_lock_held_(void *lock);
+void *evthread_debug_get_real_lock_(void *lock);
+
+void *evthread_setup_global_lock_(void *lock_, unsigned locktype,
+ int enable_locks);
+
+#define EVTHREAD_SETUP_GLOBAL_LOCK(lockvar, locktype) \
+ do { \
+ lockvar = evthread_setup_global_lock_(lockvar, \
+ (locktype), enable_locks); \
+ if (!lockvar) { \
+ event_warn("Couldn't allocate %s", #lockvar); \
+ return -1; \
+ } \
+ } while (0);
+
+int event_global_setup_locks_(const int enable_locks);
+int evsig_global_setup_locks_(const int enable_locks);
+int evutil_global_setup_locks_(const int enable_locks);
+int evutil_secure_rng_global_setup_locks_(const int enable_locks);
+
+/** Return current evthread_lock_callbacks */
+struct evthread_lock_callbacks *evthread_get_lock_callbacks(void);
+/** Return current evthread_condition_callbacks */
+struct evthread_condition_callbacks *evthread_get_condition_callbacks(void);
+/** Disable locking for internal usage (like global shutdown) */
+void evthreadimpl_disable_lock_debugging_(void);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVTHREAD_INTERNAL_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evthread.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/evthread.c
new file mode 100644
index 000000000..f3f1eddc8
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evthread.c
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+
+#include "event2/thread.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "log-internal.h"
+#include "mm-internal.h"
+#include "util-internal.h"
+#include "evthread-internal.h"
+
+#ifdef EVTHREAD_EXPOSE_STRUCTS
+#define GLOBAL
+#else
+#define GLOBAL static
+#endif
+
+#ifndef EVENT__DISABLE_DEBUG_MODE
+extern int event_debug_created_threadable_ctx_;
+extern int event_debug_mode_on_;
+#endif
+
+/* globals */
+GLOBAL int evthread_lock_debugging_enabled_ = 0;
+GLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = {
+ 0, 0, NULL, NULL, NULL, NULL
+};
+GLOBAL unsigned long (*evthread_id_fn_)(void) = NULL;
+GLOBAL struct evthread_condition_callbacks evthread_cond_fns_ = {
+ 0, NULL, NULL, NULL, NULL
+};
+
+/* Used for debugging */
+static struct evthread_lock_callbacks original_lock_fns_ = {
+ 0, 0, NULL, NULL, NULL, NULL
+};
+static struct evthread_condition_callbacks original_cond_fns_ = {
+ 0, NULL, NULL, NULL, NULL
+};
+
+void
+evthread_set_id_callback(unsigned long (*id_fn)(void))
+{
+ evthread_id_fn_ = id_fn;
+}
+
+struct evthread_lock_callbacks *evthread_get_lock_callbacks()
+{
+ return evthread_lock_debugging_enabled_
+ ? &original_lock_fns_ : &evthread_lock_fns_;
+}
+struct evthread_condition_callbacks *evthread_get_condition_callbacks()
+{
+ return evthread_lock_debugging_enabled_
+ ? &original_cond_fns_ : &evthread_cond_fns_;
+}
+void evthreadimpl_disable_lock_debugging_(void)
+{
+ evthread_lock_debugging_enabled_ = 0;
+}
+
+int
+evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs)
+{
+ struct evthread_lock_callbacks *target = evthread_get_lock_callbacks();
+
+#ifndef EVENT__DISABLE_DEBUG_MODE
+ if (event_debug_mode_on_) {
+ if (event_debug_created_threadable_ctx_) {
+ event_errx(1, "evthread initialization must be called BEFORE anything else!");
+ }
+ }
+#endif
+
+ if (!cbs) {
+ if (target->alloc)
+ event_warnx("Trying to disable lock functions after "
+ "they have been set up will probaby not work.");
+ memset(target, 0, sizeof(evthread_lock_fns_));
+ return 0;
+ }
+ if (target->alloc) {
+ /* Uh oh; we already had locking callbacks set up.*/
+ if (target->lock_api_version == cbs->lock_api_version &&
+ target->supported_locktypes == cbs->supported_locktypes &&
+ target->alloc == cbs->alloc &&
+ target->free == cbs->free &&
+ target->lock == cbs->lock &&
+ target->unlock == cbs->unlock) {
+ /* no change -- allow this. */
+ return 0;
+ }
+ event_warnx("Can't change lock callbacks once they have been "
+ "initialized.");
+ return -1;
+ }
+ if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) {
+ memcpy(target, cbs, sizeof(evthread_lock_fns_));
+ return event_global_setup_locks_(1);
+ } else {
+ return -1;
+ }
+}
+
+int
+evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs)
+{
+ struct evthread_condition_callbacks *target = evthread_get_condition_callbacks();
+
+#ifndef EVENT__DISABLE_DEBUG_MODE
+ if (event_debug_mode_on_) {
+ if (event_debug_created_threadable_ctx_) {
+ event_errx(1, "evthread initialization must be called BEFORE anything else!");
+ }
+ }
+#endif
+
+ if (!cbs) {
+ if (target->alloc_condition)
+ event_warnx("Trying to disable condition functions "
+ "after they have been set up will probaby not "
+ "work.");
+ memset(target, 0, sizeof(evthread_cond_fns_));
+ return 0;
+ }
+ if (target->alloc_condition) {
+ /* Uh oh; we already had condition callbacks set up.*/
+ if (target->condition_api_version == cbs->condition_api_version &&
+ target->alloc_condition == cbs->alloc_condition &&
+ target->free_condition == cbs->free_condition &&
+ target->signal_condition == cbs->signal_condition &&
+ target->wait_condition == cbs->wait_condition) {
+ /* no change -- allow this. */
+ return 0;
+ }
+ event_warnx("Can't change condition callbacks once they "
+ "have been initialized.");
+ return -1;
+ }
+ if (cbs->alloc_condition && cbs->free_condition &&
+ cbs->signal_condition && cbs->wait_condition) {
+ memcpy(target, cbs, sizeof(evthread_cond_fns_));
+ }
+ if (evthread_lock_debugging_enabled_) {
+ evthread_cond_fns_.alloc_condition = cbs->alloc_condition;
+ evthread_cond_fns_.free_condition = cbs->free_condition;
+ evthread_cond_fns_.signal_condition = cbs->signal_condition;
+ }
+ return 0;
+}
+
+#define DEBUG_LOCK_SIG 0xdeb0b10c
+
+struct debug_lock {
+ unsigned signature;
+ unsigned locktype;
+ unsigned long held_by;
+ /* XXXX if we ever use read-write locks, we will need a separate
+ * lock to protect count. */
+ int count;
+ void *lock;
+};
+
+static void *
+debug_lock_alloc(unsigned locktype)
+{
+ struct debug_lock *result = mm_malloc(sizeof(struct debug_lock));
+ if (!result)
+ return NULL;
+ if (original_lock_fns_.alloc) {
+ if (!(result->lock = original_lock_fns_.alloc(
+ locktype|EVTHREAD_LOCKTYPE_RECURSIVE))) {
+ mm_free(result);
+ return NULL;
+ }
+ } else {
+ result->lock = NULL;
+ }
+ result->signature = DEBUG_LOCK_SIG;
+ result->locktype = locktype;
+ result->count = 0;
+ result->held_by = 0;
+ return result;
+}
+
+static void
+debug_lock_free(void *lock_, unsigned locktype)
+{
+ struct debug_lock *lock = lock_;
+ EVUTIL_ASSERT(lock->count == 0);
+ EVUTIL_ASSERT(locktype == lock->locktype);
+ EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
+ if (original_lock_fns_.free) {
+ original_lock_fns_.free(lock->lock,
+ lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
+ }
+ lock->lock = NULL;
+ lock->count = -100;
+ lock->signature = 0x12300fda;
+ mm_free(lock);
+}
+
+static void
+evthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock)
+{
+ EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
+ ++lock->count;
+ if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE))
+ EVUTIL_ASSERT(lock->count == 1);
+ if (evthread_id_fn_) {
+ unsigned long me;
+ me = evthread_id_fn_();
+ if (lock->count > 1)
+ EVUTIL_ASSERT(lock->held_by == me);
+ lock->held_by = me;
+ }
+}
+
+static int
+debug_lock_lock(unsigned mode, void *lock_)
+{
+ struct debug_lock *lock = lock_;
+ int res = 0;
+ if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
+ EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
+ else
+ EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
+ if (original_lock_fns_.lock)
+ res = original_lock_fns_.lock(mode, lock->lock);
+ if (!res) {
+ evthread_debug_lock_mark_locked(mode, lock);
+ }
+ return res;
+}
+
+static void
+evthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock)
+{
+ EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
+ if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
+ EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
+ else
+ EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
+ if (evthread_id_fn_) {
+ unsigned long me;
+ me = evthread_id_fn_();
+ EVUTIL_ASSERT(lock->held_by == me);
+ if (lock->count == 1)
+ lock->held_by = 0;
+ }
+ --lock->count;
+ EVUTIL_ASSERT(lock->count >= 0);
+}
+
+static int
+debug_lock_unlock(unsigned mode, void *lock_)
+{
+ struct debug_lock *lock = lock_;
+ int res = 0;
+ evthread_debug_lock_mark_unlocked(mode, lock);
+ if (original_lock_fns_.unlock)
+ res = original_lock_fns_.unlock(mode, lock->lock);
+ return res;
+}
+
+static int
+debug_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
+{
+ int r;
+ struct debug_lock *lock = lock_;
+ EVUTIL_ASSERT(lock);
+ EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
+ EVLOCK_ASSERT_LOCKED(lock_);
+ evthread_debug_lock_mark_unlocked(0, lock);
+ r = original_cond_fns_.wait_condition(cond_, lock->lock, tv);
+ evthread_debug_lock_mark_locked(0, lock);
+ return r;
+}
+
+/* misspelled version for backward compatibility */
+void
+evthread_enable_lock_debuging(void)
+{
+ evthread_enable_lock_debugging();
+}
+
+void
+evthread_enable_lock_debugging(void)
+{
+ struct evthread_lock_callbacks cbs = {
+ EVTHREAD_LOCK_API_VERSION,
+ EVTHREAD_LOCKTYPE_RECURSIVE,
+ debug_lock_alloc,
+ debug_lock_free,
+ debug_lock_lock,
+ debug_lock_unlock
+ };
+ if (evthread_lock_debugging_enabled_)
+ return;
+ memcpy(&original_lock_fns_, &evthread_lock_fns_,
+ sizeof(struct evthread_lock_callbacks));
+ memcpy(&evthread_lock_fns_, &cbs,
+ sizeof(struct evthread_lock_callbacks));
+
+ memcpy(&original_cond_fns_, &evthread_cond_fns_,
+ sizeof(struct evthread_condition_callbacks));
+ evthread_cond_fns_.wait_condition = debug_cond_wait;
+ evthread_lock_debugging_enabled_ = 1;
+
+ /* XXX return value should get checked. */
+ event_global_setup_locks_(0);
+}
+
+int
+evthread_is_debug_lock_held_(void *lock_)
+{
+ struct debug_lock *lock = lock_;
+ if (! lock->count)
+ return 0;
+ if (evthread_id_fn_) {
+ unsigned long me = evthread_id_fn_();
+ if (lock->held_by != me)
+ return 0;
+ }
+ return 1;
+}
+
+void *
+evthread_debug_get_real_lock_(void *lock_)
+{
+ struct debug_lock *lock = lock_;
+ return lock->lock;
+}
+
+void *
+evthread_setup_global_lock_(void *lock_, unsigned locktype, int enable_locks)
+{
+ /* there are four cases here:
+ 1) we're turning on debugging; locking is not on.
+ 2) we're turning on debugging; locking is on.
+ 3) we're turning on locking; debugging is not on.
+ 4) we're turning on locking; debugging is on. */
+
+ if (!enable_locks && original_lock_fns_.alloc == NULL) {
+ /* Case 1: allocate a debug lock. */
+ EVUTIL_ASSERT(lock_ == NULL);
+ return debug_lock_alloc(locktype);
+ } else if (!enable_locks && original_lock_fns_.alloc != NULL) {
+ /* Case 2: wrap the lock in a debug lock. */
+ struct debug_lock *lock;
+ EVUTIL_ASSERT(lock_ != NULL);
+
+ if (!(locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) {
+ /* We can't wrap it: We need a recursive lock */
+ original_lock_fns_.free(lock_, locktype);
+ return debug_lock_alloc(locktype);
+ }
+ lock = mm_malloc(sizeof(struct debug_lock));
+ if (!lock) {
+ original_lock_fns_.free(lock_, locktype);
+ return NULL;
+ }
+ lock->lock = lock_;
+ lock->locktype = locktype;
+ lock->count = 0;
+ lock->held_by = 0;
+ return lock;
+ } else if (enable_locks && ! evthread_lock_debugging_enabled_) {
+ /* Case 3: allocate a regular lock */
+ EVUTIL_ASSERT(lock_ == NULL);
+ return evthread_lock_fns_.alloc(locktype);
+ } else {
+ /* Case 4: Fill in a debug lock with a real lock */
+ struct debug_lock *lock = lock_ ? lock_ : debug_lock_alloc(locktype);
+ EVUTIL_ASSERT(enable_locks &&
+ evthread_lock_debugging_enabled_);
+ EVUTIL_ASSERT(lock->locktype == locktype);
+ if (!lock->lock) {
+ lock->lock = original_lock_fns_.alloc(
+ locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
+ if (!lock->lock) {
+ lock->count = -200;
+ mm_free(lock);
+ return NULL;
+ }
+ }
+ return lock;
+ }
+}
+
+
+#ifndef EVTHREAD_EXPOSE_STRUCTS
+unsigned long
+evthreadimpl_get_id_()
+{
+ return evthread_id_fn_ ? evthread_id_fn_() : 1;
+}
+void *
+evthreadimpl_lock_alloc_(unsigned locktype)
+{
+#ifndef EVENT__DISABLE_DEBUG_MODE
+ if (event_debug_mode_on_) {
+ event_debug_created_threadable_ctx_ = 1;
+ }
+#endif
+
+ return evthread_lock_fns_.alloc ?
+ evthread_lock_fns_.alloc(locktype) : NULL;
+}
+void
+evthreadimpl_lock_free_(void *lock, unsigned locktype)
+{
+ if (evthread_lock_fns_.free)
+ evthread_lock_fns_.free(lock, locktype);
+}
+int
+evthreadimpl_lock_lock_(unsigned mode, void *lock)
+{
+ if (evthread_lock_fns_.lock)
+ return evthread_lock_fns_.lock(mode, lock);
+ else
+ return 0;
+}
+int
+evthreadimpl_lock_unlock_(unsigned mode, void *lock)
+{
+ if (evthread_lock_fns_.unlock)
+ return evthread_lock_fns_.unlock(mode, lock);
+ else
+ return 0;
+}
+void *
+evthreadimpl_cond_alloc_(unsigned condtype)
+{
+#ifndef EVENT__DISABLE_DEBUG_MODE
+ if (event_debug_mode_on_) {
+ event_debug_created_threadable_ctx_ = 1;
+ }
+#endif
+
+ return evthread_cond_fns_.alloc_condition ?
+ evthread_cond_fns_.alloc_condition(condtype) : NULL;
+}
+void
+evthreadimpl_cond_free_(void *cond)
+{
+ if (evthread_cond_fns_.free_condition)
+ evthread_cond_fns_.free_condition(cond);
+}
+int
+evthreadimpl_cond_signal_(void *cond, int broadcast)
+{
+ if (evthread_cond_fns_.signal_condition)
+ return evthread_cond_fns_.signal_condition(cond, broadcast);
+ else
+ return 0;
+}
+int
+evthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv)
+{
+ if (evthread_cond_fns_.wait_condition)
+ return evthread_cond_fns_.wait_condition(cond, lock, tv);
+ else
+ return 0;
+}
+int
+evthreadimpl_is_lock_debugging_enabled_(void)
+{
+ return evthread_lock_debugging_enabled_;
+}
+
+int
+evthreadimpl_locking_enabled_(void)
+{
+ return evthread_lock_fns_.lock != NULL;
+}
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evthread_pthread.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/evthread_pthread.c
new file mode 100644
index 000000000..4e11f7497
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evthread_pthread.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+/* With glibc we need to define _GNU_SOURCE to get PTHREAD_MUTEX_RECURSIVE.
+ * This comes from evconfig-private.h
+ */
+#include <pthread.h>
+
+struct event_base;
+#include "event2/thread.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include "mm-internal.h"
+#include "evthread-internal.h"
+
+static pthread_mutexattr_t attr_recursive;
+
+static void *
+evthread_posix_lock_alloc(unsigned locktype)
+{
+ pthread_mutexattr_t *attr = NULL;
+ pthread_mutex_t *lock = mm_malloc(sizeof(pthread_mutex_t));
+ if (!lock)
+ return NULL;
+ if (locktype & EVTHREAD_LOCKTYPE_RECURSIVE)
+ attr = &attr_recursive;
+ if (pthread_mutex_init(lock, attr)) {
+ mm_free(lock);
+ return NULL;
+ }
+ return lock;
+}
+
+static void
+evthread_posix_lock_free(void *lock_, unsigned locktype)
+{
+ pthread_mutex_t *lock = lock_;
+ pthread_mutex_destroy(lock);
+ mm_free(lock);
+}
+
+static int
+evthread_posix_lock(unsigned mode, void *lock_)
+{
+ pthread_mutex_t *lock = lock_;
+ if (mode & EVTHREAD_TRY)
+ return pthread_mutex_trylock(lock);
+ else
+ return pthread_mutex_lock(lock);
+}
+
+static int
+evthread_posix_unlock(unsigned mode, void *lock_)
+{
+ pthread_mutex_t *lock = lock_;
+ return pthread_mutex_unlock(lock);
+}
+
+static unsigned long
+evthread_posix_get_id(void)
+{
+ union {
+ pthread_t thr;
+#if EVENT__SIZEOF_PTHREAD_T > EVENT__SIZEOF_LONG
+ ev_uint64_t id;
+#else
+ unsigned long id;
+#endif
+ } r;
+#if EVENT__SIZEOF_PTHREAD_T < EVENT__SIZEOF_LONG
+ memset(&r, 0, sizeof(r));
+#endif
+ r.thr = pthread_self();
+ return (unsigned long)r.id;
+}
+
+static void *
+evthread_posix_cond_alloc(unsigned condflags)
+{
+ pthread_cond_t *cond = mm_malloc(sizeof(pthread_cond_t));
+ if (!cond)
+ return NULL;
+ if (pthread_cond_init(cond, NULL)) {
+ mm_free(cond);
+ return NULL;
+ }
+ return cond;
+}
+
+static void
+evthread_posix_cond_free(void *cond_)
+{
+ pthread_cond_t *cond = cond_;
+ pthread_cond_destroy(cond);
+ mm_free(cond);
+}
+
+static int
+evthread_posix_cond_signal(void *cond_, int broadcast)
+{
+ pthread_cond_t *cond = cond_;
+ int r;
+ if (broadcast)
+ r = pthread_cond_broadcast(cond);
+ else
+ r = pthread_cond_signal(cond);
+ return r ? -1 : 0;
+}
+
+static int
+evthread_posix_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
+{
+ int r;
+ pthread_cond_t *cond = cond_;
+ pthread_mutex_t *lock = lock_;
+
+ if (tv) {
+ struct timeval now, abstime;
+ struct timespec ts;
+ evutil_gettimeofday(&now, NULL);
+ evutil_timeradd(&now, tv, &abstime);
+ ts.tv_sec = abstime.tv_sec;
+ ts.tv_nsec = abstime.tv_usec*1000;
+ r = pthread_cond_timedwait(cond, lock, &ts);
+ if (r == ETIMEDOUT)
+ return 1;
+ else if (r)
+ return -1;
+ else
+ return 0;
+ } else {
+ r = pthread_cond_wait(cond, lock);
+ return r ? -1 : 0;
+ }
+}
+
+int
+evthread_use_pthreads(void)
+{
+ struct evthread_lock_callbacks cbs = {
+ EVTHREAD_LOCK_API_VERSION,
+ EVTHREAD_LOCKTYPE_RECURSIVE,
+ evthread_posix_lock_alloc,
+ evthread_posix_lock_free,
+ evthread_posix_lock,
+ evthread_posix_unlock
+ };
+ struct evthread_condition_callbacks cond_cbs = {
+ EVTHREAD_CONDITION_API_VERSION,
+ evthread_posix_cond_alloc,
+ evthread_posix_cond_free,
+ evthread_posix_cond_signal,
+ evthread_posix_cond_wait
+ };
+ /* Set ourselves up to get recursive locks. */
+ if (pthread_mutexattr_init(&attr_recursive))
+ return -1;
+ if (pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE))
+ return -1;
+
+ evthread_set_lock_callbacks(&cbs);
+ evthread_set_condition_callbacks(&cond_cbs);
+ evthread_set_id_callback(evthread_posix_get_id);
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evthread_win32.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/evthread_win32.c
new file mode 100644
index 000000000..2ec80560a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evthread_win32.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef _WIN32
+#ifndef _WIN32_WINNT
+/* Minimum required for InitializeCriticalSectionAndSpinCount */
+#define _WIN32_WINNT 0x0403
+#endif
+#include <winsock2.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <sys/locking.h>
+#endif
+
+struct event_base;
+#include "event2/thread.h"
+
+#include "mm-internal.h"
+#include "evthread-internal.h"
+#include "time-internal.h"
+
+#define SPIN_COUNT 2000
+
+static void *
+evthread_win32_lock_create(unsigned locktype)
+{
+ CRITICAL_SECTION *lock = mm_malloc(sizeof(CRITICAL_SECTION));
+ if (!lock)
+ return NULL;
+ if (InitializeCriticalSectionAndSpinCount(lock, SPIN_COUNT) == 0) {
+ mm_free(lock);
+ return NULL;
+ }
+ return lock;
+}
+
+static void
+evthread_win32_lock_free(void *lock_, unsigned locktype)
+{
+ CRITICAL_SECTION *lock = lock_;
+ DeleteCriticalSection(lock);
+ mm_free(lock);
+}
+
+static int
+evthread_win32_lock(unsigned mode, void *lock_)
+{
+ CRITICAL_SECTION *lock = lock_;
+ if ((mode & EVTHREAD_TRY)) {
+ return ! TryEnterCriticalSection(lock);
+ } else {
+ EnterCriticalSection(lock);
+ return 0;
+ }
+}
+
+static int
+evthread_win32_unlock(unsigned mode, void *lock_)
+{
+ CRITICAL_SECTION *lock = lock_;
+ LeaveCriticalSection(lock);
+ return 0;
+}
+
+static unsigned long
+evthread_win32_get_id(void)
+{
+ return (unsigned long) GetCurrentThreadId();
+}
+
+#ifdef WIN32_HAVE_CONDITION_VARIABLES
+static void WINAPI (*InitializeConditionVariable_fn)(PCONDITION_VARIABLE)
+ = NULL;
+static BOOL WINAPI (*SleepConditionVariableCS_fn)(
+ PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD) = NULL;
+static void WINAPI (*WakeAllConditionVariable_fn)(PCONDITION_VARIABLE) = NULL;
+static void WINAPI (*WakeConditionVariable_fn)(PCONDITION_VARIABLE) = NULL;
+
+static int
+evthread_win32_condvar_init(void)
+{
+ HANDLE lib;
+
+ lib = GetModuleHandle(TEXT("kernel32.dll"));
+ if (lib == NULL)
+ return 0;
+
+#define LOAD(name) \
+ name##_fn = GetProcAddress(lib, #name)
+ LOAD(InitializeConditionVariable);
+ LOAD(SleepConditionVariableCS);
+ LOAD(WakeAllConditionVariable);
+ LOAD(WakeConditionVariable);
+
+ return InitializeConditionVariable_fn && SleepConditionVariableCS_fn &&
+ WakeAllConditionVariable_fn && WakeConditionVariable_fn;
+}
+
+/* XXXX Even if we can build this, we don't necessarily want to: the functions
+ * in question didn't exist before Vista, so we'd better LoadProc them. */
+static void *
+evthread_win32_condvar_alloc(unsigned condflags)
+{
+ CONDITION_VARIABLE *cond = mm_malloc(sizeof(CONDITION_VARIABLE));
+ if (!cond)
+ return NULL;
+ InitializeConditionVariable_fn(cond);
+ return cond;
+}
+
+static void
+evthread_win32_condvar_free(void *cond_)
+{
+ CONDITION_VARIABLE *cond = cond_;
+ /* There doesn't _seem_ to be a cleaup fn here... */
+ mm_free(cond);
+}
+
+static int
+evthread_win32_condvar_signal(void *cond, int broadcast)
+{
+ CONDITION_VARIABLE *cond = cond_;
+ if (broadcast)
+ WakeAllConditionVariable_fn(cond);
+ else
+ WakeConditionVariable_fn(cond);
+ return 0;
+}
+
+static int
+evthread_win32_condvar_wait(void *cond_, void *lock_, const struct timeval *tv)
+{
+ CONDITION_VARIABLE *cond = cond_;
+ CRITICAL_SECTION *lock = lock_;
+ DWORD ms, err;
+ BOOL result;
+
+ if (tv)
+ ms = evutil_tv_to_msec_(tv);
+ else
+ ms = INFINITE;
+ result = SleepConditionVariableCS_fn(cond, lock, ms);
+ if (result) {
+ if (GetLastError() == WAIT_TIMEOUT)
+ return 1;
+ else
+ return -1;
+ } else {
+ return 0;
+ }
+}
+#endif
+
+struct evthread_win32_cond {
+ HANDLE event;
+
+ CRITICAL_SECTION lock;
+ int n_waiting;
+ int n_to_wake;
+ int generation;
+};
+
+static void *
+evthread_win32_cond_alloc(unsigned flags)
+{
+ struct evthread_win32_cond *cond;
+ if (!(cond = mm_malloc(sizeof(struct evthread_win32_cond))))
+ return NULL;
+ if (InitializeCriticalSectionAndSpinCount(&cond->lock, SPIN_COUNT)==0) {
+ mm_free(cond);
+ return NULL;
+ }
+ if ((cond->event = CreateEvent(NULL,TRUE,FALSE,NULL)) == NULL) {
+ DeleteCriticalSection(&cond->lock);
+ mm_free(cond);
+ return NULL;
+ }
+ cond->n_waiting = cond->n_to_wake = cond->generation = 0;
+ return cond;
+}
+
+static void
+evthread_win32_cond_free(void *cond_)
+{
+ struct evthread_win32_cond *cond = cond_;
+ DeleteCriticalSection(&cond->lock);
+ CloseHandle(cond->event);
+ mm_free(cond);
+}
+
+static int
+evthread_win32_cond_signal(void *cond_, int broadcast)
+{
+ struct evthread_win32_cond *cond = cond_;
+ EnterCriticalSection(&cond->lock);
+ if (broadcast)
+ cond->n_to_wake = cond->n_waiting;
+ else
+ ++cond->n_to_wake;
+ cond->generation++;
+ SetEvent(cond->event);
+ LeaveCriticalSection(&cond->lock);
+ return 0;
+}
+
+static int
+evthread_win32_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
+{
+ struct evthread_win32_cond *cond = cond_;
+ CRITICAL_SECTION *lock = lock_;
+ int generation_at_start;
+ int waiting = 1;
+ int result = -1;
+ DWORD ms = INFINITE, ms_orig = INFINITE, startTime, endTime;
+ if (tv)
+ ms_orig = ms = evutil_tv_to_msec_(tv);
+
+ EnterCriticalSection(&cond->lock);
+ ++cond->n_waiting;
+ generation_at_start = cond->generation;
+ LeaveCriticalSection(&cond->lock);
+
+ LeaveCriticalSection(lock);
+
+ startTime = GetTickCount();
+ do {
+ DWORD res;
+ res = WaitForSingleObject(cond->event, ms);
+ EnterCriticalSection(&cond->lock);
+ if (cond->n_to_wake &&
+ cond->generation != generation_at_start) {
+ --cond->n_to_wake;
+ --cond->n_waiting;
+ result = 0;
+ waiting = 0;
+ goto out;
+ } else if (res != WAIT_OBJECT_0) {
+ result = (res==WAIT_TIMEOUT) ? 1 : -1;
+ --cond->n_waiting;
+ waiting = 0;
+ goto out;
+ } else if (ms != INFINITE) {
+ endTime = GetTickCount();
+ if (startTime + ms_orig <= endTime) {
+ result = 1; /* Timeout */
+ --cond->n_waiting;
+ waiting = 0;
+ goto out;
+ } else {
+ ms = startTime + ms_orig - endTime;
+ }
+ }
+ /* If we make it here, we are still waiting. */
+ if (cond->n_to_wake == 0) {
+ /* There is nobody else who should wake up; reset
+ * the event. */
+ ResetEvent(cond->event);
+ }
+ out:
+ LeaveCriticalSection(&cond->lock);
+ } while (waiting);
+
+ EnterCriticalSection(lock);
+
+ EnterCriticalSection(&cond->lock);
+ if (!cond->n_waiting)
+ ResetEvent(cond->event);
+ LeaveCriticalSection(&cond->lock);
+
+ return result;
+}
+
+int
+evthread_use_windows_threads(void)
+{
+ struct evthread_lock_callbacks cbs = {
+ EVTHREAD_LOCK_API_VERSION,
+ EVTHREAD_LOCKTYPE_RECURSIVE,
+ evthread_win32_lock_create,
+ evthread_win32_lock_free,
+ evthread_win32_lock,
+ evthread_win32_unlock
+ };
+
+
+ struct evthread_condition_callbacks cond_cbs = {
+ EVTHREAD_CONDITION_API_VERSION,
+ evthread_win32_cond_alloc,
+ evthread_win32_cond_free,
+ evthread_win32_cond_signal,
+ evthread_win32_cond_wait
+ };
+#ifdef WIN32_HAVE_CONDITION_VARIABLES
+ struct evthread_condition_callbacks condvar_cbs = {
+ EVTHREAD_CONDITION_API_VERSION,
+ evthread_win32_condvar_alloc,
+ evthread_win32_condvar_free,
+ evthread_win32_condvar_signal,
+ evthread_win32_condvar_wait
+ };
+#endif
+
+ evthread_set_lock_callbacks(&cbs);
+ evthread_set_id_callback(evthread_win32_get_id);
+#ifdef WIN32_HAVE_CONDITION_VARIABLES
+ if (evthread_win32_condvar_init()) {
+ evthread_set_condition_callbacks(&condvar_cbs);
+ return 0;
+ }
+#endif
+ evthread_set_condition_callbacks(&cond_cbs);
+
+ return 0;
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evutil.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/evutil.c
new file mode 100644
index 000000000..1e8ef7bd3
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evutil.c
@@ -0,0 +1,2693 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <io.h>
+#include <tchar.h>
+#include <process.h>
+#undef _WIN32_WINNT
+/* For structs needed by GetAdaptersAddresses */
+#define _WIN32_WINNT 0x0501
+#include <iphlpapi.h>
+#endif
+
+#include <sys/types.h>
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef EVENT__HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef EVENT__HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef EVENT__HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef EVENT__HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef EVENT__HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#ifdef EVENT__HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <time.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#endif
+
+#include "event2/util.h"
+#include "util-internal.h"
+#include "log-internal.h"
+#include "mm-internal.h"
+#include "evthread-internal.h"
+
+#include "strlcpy-internal.h"
+#include "ipv6-internal.h"
+
+#ifdef _WIN32
+#define HT_NO_CACHE_HASH_VALUES
+#include "ht-internal.h"
+#define open _open
+#define read _read
+#define close _close
+#ifndef fstat
+#define fstat _fstati64
+#endif
+#ifndef stat
+#define stat _stati64
+#endif
+#define mode_t int
+#endif
+
+int
+evutil_open_closeonexec_(const char *pathname, int flags, unsigned mode)
+{
+ int fd;
+
+#ifdef O_CLOEXEC
+ fd = open(pathname, flags|O_CLOEXEC, (mode_t)mode);
+ if (fd >= 0 || errno == EINVAL)
+ return fd;
+ /* If we got an EINVAL, fall through and try without O_CLOEXEC */
+#endif
+ fd = open(pathname, flags, (mode_t)mode);
+ if (fd < 0)
+ return -1;
+
+#if defined(FD_CLOEXEC)
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
+ close(fd);
+ return -1;
+ }
+#endif
+
+ return fd;
+}
+
+/**
+ Read the contents of 'filename' into a newly allocated NUL-terminated
+ string. Set *content_out to hold this string, and *len_out to hold its
+ length (not including the appended NUL). If 'is_binary', open the file in
+ binary mode.
+
+ Returns 0 on success, -1 if the open fails, and -2 for all other failures.
+
+ Used internally only; may go away in a future version.
+ */
+int
+evutil_read_file_(const char *filename, char **content_out, size_t *len_out,
+ int is_binary)
+{
+ int fd, r;
+ struct stat st;
+ char *mem;
+ size_t read_so_far=0;
+ int mode = O_RDONLY;
+
+ EVUTIL_ASSERT(content_out);
+ EVUTIL_ASSERT(len_out);
+ *content_out = NULL;
+ *len_out = 0;
+
+#ifdef O_BINARY
+ if (is_binary)
+ mode |= O_BINARY;
+#endif
+
+ fd = evutil_open_closeonexec_(filename, mode, 0);
+ if (fd < 0)
+ return -1;
+ if (fstat(fd, &st) || st.st_size < 0 ||
+ st.st_size > EV_SSIZE_MAX-1 ) {
+ close(fd);
+ return -2;
+ }
+ mem = mm_malloc((size_t)st.st_size + 1);
+ if (!mem) {
+ close(fd);
+ return -2;
+ }
+ read_so_far = 0;
+#ifdef _WIN32
+#define N_TO_READ(x) ((x) > INT_MAX) ? INT_MAX : ((int)(x))
+#else
+#define N_TO_READ(x) (x)
+#endif
+ while ((r = read(fd, mem+read_so_far, N_TO_READ(st.st_size - read_so_far))) > 0) {
+ read_so_far += r;
+ if (read_so_far >= (size_t)st.st_size)
+ break;
+ EVUTIL_ASSERT(read_so_far < (size_t)st.st_size);
+ }
+ close(fd);
+ if (r < 0) {
+ mm_free(mem);
+ return -2;
+ }
+ mem[read_so_far] = 0;
+
+ *len_out = read_so_far;
+ *content_out = mem;
+ return 0;
+}
+
+int
+evutil_socketpair(int family, int type, int protocol, evutil_socket_t fd[2])
+{
+#ifndef _WIN32
+ return socketpair(family, type, protocol, fd);
+#else
+ return evutil_ersatz_socketpair_(family, type, protocol, fd);
+#endif
+}
+
+int
+evutil_ersatz_socketpair_(int family, int type, int protocol,
+ evutil_socket_t fd[2])
+{
+ /* This code is originally from Tor. Used with permission. */
+
+ /* This socketpair does not work when localhost is down. So
+ * it's really not the same thing at all. But it's close enough
+ * for now, and really, when localhost is down sometimes, we
+ * have other problems too.
+ */
+#ifdef _WIN32
+#define ERR(e) WSA##e
+#else
+#define ERR(e) e
+#endif
+ evutil_socket_t listener = -1;
+ evutil_socket_t connector = -1;
+ evutil_socket_t acceptor = -1;
+ struct sockaddr_in listen_addr;
+ struct sockaddr_in connect_addr;
+ ev_socklen_t size;
+ int saved_errno = -1;
+ int family_test;
+
+ family_test = family != AF_INET;
+#ifdef AF_UNIX
+ family_test = family_test && (family != AF_UNIX);
+#endif
+ if (protocol || family_test) {
+ EVUTIL_SET_SOCKET_ERROR(ERR(EAFNOSUPPORT));
+ return -1;
+ }
+
+ if (!fd) {
+ EVUTIL_SET_SOCKET_ERROR(ERR(EINVAL));
+ return -1;
+ }
+
+ listener = socket(AF_INET, type, 0);
+ if (listener < 0)
+ return -1;
+ memset(&listen_addr, 0, sizeof(listen_addr));
+ listen_addr.sin_family = AF_INET;
+ listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ listen_addr.sin_port = 0; /* kernel chooses port. */
+ if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr))
+ == -1)
+ goto tidy_up_and_fail;
+ if (listen(listener, 1) == -1)
+ goto tidy_up_and_fail;
+
+ connector = socket(AF_INET, type, 0);
+ if (connector < 0)
+ goto tidy_up_and_fail;
+
+ memset(&connect_addr, 0, sizeof(connect_addr));
+
+ /* We want to find out the port number to connect to. */
+ size = sizeof(connect_addr);
+ if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1)
+ goto tidy_up_and_fail;
+ if (size != sizeof (connect_addr))
+ goto abort_tidy_up_and_fail;
+ if (connect(connector, (struct sockaddr *) &connect_addr,
+ sizeof(connect_addr)) == -1)
+ goto tidy_up_and_fail;
+
+ size = sizeof(listen_addr);
+ acceptor = accept(listener, (struct sockaddr *) &listen_addr, &size);
+ if (acceptor < 0)
+ goto tidy_up_and_fail;
+ if (size != sizeof(listen_addr))
+ goto abort_tidy_up_and_fail;
+ /* Now check we are talking to ourself by matching port and host on the
+ two sockets. */
+ if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1)
+ goto tidy_up_and_fail;
+ if (size != sizeof (connect_addr)
+ || listen_addr.sin_family != connect_addr.sin_family
+ || listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr
+ || listen_addr.sin_port != connect_addr.sin_port)
+ goto abort_tidy_up_and_fail;
+ evutil_closesocket(listener);
+ fd[0] = connector;
+ fd[1] = acceptor;
+
+ return 0;
+
+ abort_tidy_up_and_fail:
+ saved_errno = ERR(ECONNABORTED);
+ tidy_up_and_fail:
+ if (saved_errno < 0)
+ saved_errno = EVUTIL_SOCKET_ERROR();
+ if (listener != -1)
+ evutil_closesocket(listener);
+ if (connector != -1)
+ evutil_closesocket(connector);
+ if (acceptor != -1)
+ evutil_closesocket(acceptor);
+
+ EVUTIL_SET_SOCKET_ERROR(saved_errno);
+ return -1;
+#undef ERR
+}
+
+int
+evutil_make_socket_nonblocking(evutil_socket_t fd)
+{
+#ifdef _WIN32
+ {
+ unsigned long nonblocking = 1;
+ if (ioctlsocket(fd, FIONBIO, &nonblocking) == SOCKET_ERROR) {
+ event_sock_warn(fd, "fcntl(%d, F_GETFL)", (int)fd);
+ return -1;
+ }
+ }
+#else
+ {
+ int flags;
+ if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) {
+ event_warn("fcntl(%d, F_GETFL)", fd);
+ return -1;
+ }
+ if (!(flags & O_NONBLOCK)) {
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+ event_warn("fcntl(%d, F_SETFL)", fd);
+ return -1;
+ }
+ }
+ }
+#endif
+ return 0;
+}
+
+/* Faster version of evutil_make_socket_nonblocking for internal use.
+ *
+ * Requires that no F_SETFL flags were previously set on the fd.
+ */
+static int
+evutil_fast_socket_nonblocking(evutil_socket_t fd)
+{
+#ifdef _WIN32
+ return evutil_make_socket_nonblocking(fd);
+#else
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+ event_warn("fcntl(%d, F_SETFL)", fd);
+ return -1;
+ }
+ return 0;
+#endif
+}
+
+int
+evutil_make_listen_socket_reuseable(evutil_socket_t sock)
+{
+#if defined(SO_REUSEADDR) && !defined(_WIN32)
+ int one = 1;
+ /* REUSEADDR on Unix means, "don't hang on to this address after the
+ * listener is closed." On Windows, though, it means "don't keep other
+ * processes from binding to this address while we're using it. */
+ return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one,
+ (ev_socklen_t)sizeof(one));
+#else
+ return 0;
+#endif
+}
+
+int
+evutil_make_listen_socket_reuseable_port(evutil_socket_t sock)
+{
+#if defined __linux__ && defined(SO_REUSEPORT)
+ int one = 1;
+ /* REUSEPORT on Linux 3.9+ means, "Multiple servers (processes or
+ * threads) can bind to the same port if they each set the option. */
+ return setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void*) &one,
+ (ev_socklen_t)sizeof(one));
+#else
+ return 0;
+#endif
+}
+
+int
+evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock)
+{
+#if defined(EVENT__HAVE_NETINET_TCP_H) && defined(TCP_DEFER_ACCEPT)
+ int one = 1;
+
+ /* TCP_DEFER_ACCEPT tells the kernel to call defer accept() only after data
+ * has arrived and ready to read */
+ return setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &one,
+ (ev_socklen_t)sizeof(one));
+#endif
+ return 0;
+}
+
+int
+evutil_make_socket_closeonexec(evutil_socket_t fd)
+{
+#if !defined(_WIN32) && defined(EVENT__HAVE_SETFD)
+ int flags;
+ if ((flags = fcntl(fd, F_GETFD, NULL)) < 0) {
+ event_warn("fcntl(%d, F_GETFD)", fd);
+ return -1;
+ }
+ if (!(flags & FD_CLOEXEC)) {
+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
+ event_warn("fcntl(%d, F_SETFD)", fd);
+ return -1;
+ }
+ }
+#endif
+ return 0;
+}
+
+/* Faster version of evutil_make_socket_closeonexec for internal use.
+ *
+ * Requires that no F_SETFD flags were previously set on the fd.
+ */
+static int
+evutil_fast_socket_closeonexec(evutil_socket_t fd)
+{
+#if !defined(_WIN32) && defined(EVENT__HAVE_SETFD)
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
+ event_warn("fcntl(%d, F_SETFD)", fd);
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+int
+evutil_closesocket(evutil_socket_t sock)
+{
+#ifndef _WIN32
+ return close(sock);
+#else
+ return closesocket(sock);
+#endif
+}
+
+ev_int64_t
+evutil_strtoll(const char *s, char **endptr, int base)
+{
+#ifdef EVENT__HAVE_STRTOLL
+ return (ev_int64_t)strtoll(s, endptr, base);
+#elif EVENT__SIZEOF_LONG == 8
+ return (ev_int64_t)strtol(s, endptr, base);
+#elif defined(_WIN32) && defined(_MSC_VER) && _MSC_VER < 1300
+ /* XXXX on old versions of MS APIs, we only support base
+ * 10. */
+ ev_int64_t r;
+ if (base != 10)
+ return 0;
+ r = (ev_int64_t) _atoi64(s);
+ while (isspace(*s))
+ ++s;
+ if (*s == '-')
+ ++s;
+ while (isdigit(*s))
+ ++s;
+ if (endptr)
+ *endptr = (char*) s;
+ return r;
+#elif defined(_WIN32)
+ return (ev_int64_t) _strtoi64(s, endptr, base);
+#elif defined(EVENT__SIZEOF_LONG_LONG) && EVENT__SIZEOF_LONG_LONG == 8
+ long long r;
+ int n;
+ if (base != 10 && base != 16)
+ return 0;
+ if (base == 10) {
+ n = sscanf(s, "%lld", &r);
+ } else {
+ unsigned long long ru=0;
+ n = sscanf(s, "%llx", &ru);
+ if (ru > EV_INT64_MAX)
+ return 0;
+ r = (long long) ru;
+ }
+ if (n != 1)
+ return 0;
+ while (EVUTIL_ISSPACE_(*s))
+ ++s;
+ if (*s == '-')
+ ++s;
+ if (base == 10) {
+ while (EVUTIL_ISDIGIT_(*s))
+ ++s;
+ } else {
+ while (EVUTIL_ISXDIGIT_(*s))
+ ++s;
+ }
+ if (endptr)
+ *endptr = (char*) s;
+ return r;
+#else
+#error "I don't know how to parse 64-bit integers."
+#endif
+}
+
+#ifdef _WIN32
+int
+evutil_socket_geterror(evutil_socket_t sock)
+{
+ int optval, optvallen=sizeof(optval);
+ int err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK && sock >= 0) {
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval,
+ &optvallen))
+ return err;
+ if (optval)
+ return optval;
+ }
+ return err;
+}
+#endif
+
+/* XXX we should use an enum here. */
+/* 2 for connection refused, 1 for connected, 0 for not yet, -1 for error. */
+int
+evutil_socket_connect_(evutil_socket_t *fd_ptr, const struct sockaddr *sa, int socklen)
+{
+ int made_fd = 0;
+
+ if (*fd_ptr < 0) {
+ if ((*fd_ptr = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
+ goto err;
+ made_fd = 1;
+ if (evutil_make_socket_nonblocking(*fd_ptr) < 0) {
+ goto err;
+ }
+ }
+
+ if (connect(*fd_ptr, sa, socklen) < 0) {
+ int e = evutil_socket_geterror(*fd_ptr);
+ if (EVUTIL_ERR_CONNECT_RETRIABLE(e))
+ return 0;
+ if (EVUTIL_ERR_CONNECT_REFUSED(e))
+ return 2;
+ goto err;
+ } else {
+ return 1;
+ }
+
+err:
+ if (made_fd) {
+ evutil_closesocket(*fd_ptr);
+ *fd_ptr = -1;
+ }
+ return -1;
+}
+
+/* Check whether a socket on which we called connect() is done
+ connecting. Return 1 for connected, 0 for not yet, -1 for error. In the
+ error case, set the current socket errno to the error that happened during
+ the connect operation. */
+int
+evutil_socket_finished_connecting_(evutil_socket_t fd)
+{
+ int e;
+ ev_socklen_t elen = sizeof(e);
+
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&e, &elen) < 0)
+ return -1;
+
+ if (e) {
+ if (EVUTIL_ERR_CONNECT_RETRIABLE(e))
+ return 0;
+ EVUTIL_SET_SOCKET_ERROR(e);
+ return -1;
+ }
+
+ return 1;
+}
+
+#if (EVUTIL_AI_PASSIVE|EVUTIL_AI_CANONNAME|EVUTIL_AI_NUMERICHOST| \
+ EVUTIL_AI_NUMERICSERV|EVUTIL_AI_V4MAPPED|EVUTIL_AI_ALL| \
+ EVUTIL_AI_ADDRCONFIG) != \
+ (EVUTIL_AI_PASSIVE^EVUTIL_AI_CANONNAME^EVUTIL_AI_NUMERICHOST^ \
+ EVUTIL_AI_NUMERICSERV^EVUTIL_AI_V4MAPPED^EVUTIL_AI_ALL^ \
+ EVUTIL_AI_ADDRCONFIG)
+#error "Some of our EVUTIL_AI_* flags seem to overlap with system AI_* flags"
+#endif
+
+/* We sometimes need to know whether we have an ipv4 address and whether we
+ have an ipv6 address. If 'have_checked_interfaces', then we've already done
+ the test. If 'had_ipv4_address', then it turns out we had an ipv4 address.
+ If 'had_ipv6_address', then it turns out we had an ipv6 address. These are
+ set by evutil_check_interfaces. */
+static int have_checked_interfaces, had_ipv4_address, had_ipv6_address;
+
+/* Macro: True iff the IPv4 address 'addr', in host order, is in 127.0.0.0/8
+ */
+#define EVUTIL_V4ADDR_IS_LOCALHOST(addr) (((addr)>>24) == 127)
+
+/* Macro: True iff the IPv4 address 'addr', in host order, is a class D
+ * (multiclass) address.
+ */
+#define EVUTIL_V4ADDR_IS_CLASSD(addr) ((((addr)>>24) & 0xf0) == 0xe0)
+
+static void
+evutil_found_ifaddr(const struct sockaddr *sa)
+{
+ const char ZEROES[] = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00";
+
+ if (sa->sa_family == AF_INET) {
+ const struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+ ev_uint32_t addr = ntohl(sin->sin_addr.s_addr);
+ if (addr == 0 ||
+ EVUTIL_V4ADDR_IS_LOCALHOST(addr) ||
+ EVUTIL_V4ADDR_IS_CLASSD(addr)) {
+ /* Not actually a usable external address. */
+ } else {
+ event_debug(("Detected an IPv4 interface"));
+ had_ipv4_address = 1;
+ }
+ } else if (sa->sa_family == AF_INET6) {
+ const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+ const unsigned char *addr =
+ (unsigned char*)sin6->sin6_addr.s6_addr;
+ if (!memcmp(addr, ZEROES, 8) ||
+ ((addr[0] & 0xfe) == 0xfc) ||
+ (addr[0] == 0xfe && (addr[1] & 0xc0) == 0x80) ||
+ (addr[0] == 0xfe && (addr[1] & 0xc0) == 0xc0) ||
+ (addr[0] == 0xff)) {
+ /* This is a reserved, ipv4compat, ipv4map, loopback,
+ * link-local, multicast, or unspecified address. */
+ } else {
+ event_debug(("Detected an IPv6 interface"));
+ had_ipv6_address = 1;
+ }
+ }
+}
+
+#ifdef _WIN32
+typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)(
+ ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
+#endif
+
+static int
+evutil_check_ifaddrs(void)
+{
+#if defined(EVENT__HAVE_GETIFADDRS)
+ /* Most free Unixy systems provide getifaddrs, which gives us a linked list
+ * of struct ifaddrs. */
+ struct ifaddrs *ifa = NULL;
+ const struct ifaddrs *i;
+ if (getifaddrs(&ifa) < 0) {
+ event_warn("Unable to call getifaddrs()");
+ return -1;
+ }
+
+ for (i = ifa; i; i = i->ifa_next) {
+ if (!i->ifa_addr)
+ continue;
+ evutil_found_ifaddr(i->ifa_addr);
+ }
+
+ freeifaddrs(ifa);
+ return 0;
+#elif defined(_WIN32)
+ /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a
+ "GetAdaptersInfo", but that's deprecated; let's just try
+ GetAdaptersAddresses and fall back to connect+getsockname.
+ */
+ HMODULE lib = evutil_load_windows_system_library_(TEXT("ihplapi.dll"));
+ GetAdaptersAddresses_fn_t fn;
+ ULONG size, res;
+ IP_ADAPTER_ADDRESSES *addresses = NULL, *address;
+ int result = -1;
+
+#define FLAGS (GAA_FLAG_SKIP_ANYCAST | \
+ GAA_FLAG_SKIP_MULTICAST | \
+ GAA_FLAG_SKIP_DNS_SERVER)
+
+ if (!lib)
+ goto done;
+
+ if (!(fn = (GetAdaptersAddresses_fn_t) GetProcAddress(lib, "GetAdaptersAddresses")))
+ goto done;
+
+ /* Guess how much space we need. */
+ size = 15*1024;
+ addresses = mm_malloc(size);
+ if (!addresses)
+ goto done;
+ res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
+ if (res == ERROR_BUFFER_OVERFLOW) {
+ /* we didn't guess that we needed enough space; try again */
+ mm_free(addresses);
+ addresses = mm_malloc(size);
+ if (!addresses)
+ goto done;
+ res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
+ }
+ if (res != NO_ERROR)
+ goto done;
+
+ for (address = addresses; address; address = address->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS *a;
+ for (a = address->FirstUnicastAddress; a; a = a->Next) {
+ /* Yes, it's a linked list inside a linked list */
+ struct sockaddr *sa = a->Address.lpSockaddr;
+ evutil_found_ifaddr(sa);
+ }
+ }
+
+ result = 0;
+done:
+ if (lib)
+ FreeLibrary(lib);
+ if (addresses)
+ mm_free(addresses);
+ return result;
+#else
+ return -1;
+#endif
+}
+
+/* Test whether we have an ipv4 interface and an ipv6 interface. Return 0 if
+ * the test seemed successful. */
+static int
+evutil_check_interfaces(int force_recheck)
+{
+ evutil_socket_t fd = -1;
+ struct sockaddr_in sin, sin_out;
+ struct sockaddr_in6 sin6, sin6_out;
+ ev_socklen_t sin_out_len = sizeof(sin_out);
+ ev_socklen_t sin6_out_len = sizeof(sin6_out);
+ int r;
+ if (have_checked_interfaces && !force_recheck)
+ return 0;
+
+ if (evutil_check_ifaddrs() == 0) {
+ /* Use a nice sane interface, if this system has one. */
+ return 0;
+ }
+
+ /* Ugh. There was no nice sane interface. So to check whether we have
+ * an interface open for a given protocol, will try to make a UDP
+ * 'connection' to a remote host on the internet. We don't actually
+ * use it, so the address doesn't matter, but we want to pick one that
+ * keep us from using a host- or link-local interface. */
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(53);
+ r = evutil_inet_pton(AF_INET, "18.244.0.188", &sin.sin_addr);
+ EVUTIL_ASSERT(r);
+
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(53);
+ r = evutil_inet_pton(AF_INET6, "2001:4860:b002::68", &sin6.sin6_addr);
+ EVUTIL_ASSERT(r);
+
+ memset(&sin_out, 0, sizeof(sin_out));
+ memset(&sin6_out, 0, sizeof(sin6_out));
+
+ /* XXX some errnos mean 'no address'; some mean 'not enough sockets'. */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0 &&
+ connect(fd, (struct sockaddr*)&sin, sizeof(sin)) == 0 &&
+ getsockname(fd, (struct sockaddr*)&sin_out, &sin_out_len) == 0) {
+ /* We might have an IPv4 interface. */
+ evutil_found_ifaddr((struct sockaddr*) &sin_out);
+ }
+ if (fd >= 0)
+ evutil_closesocket(fd);
+
+ if ((fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) >= 0 &&
+ connect(fd, (struct sockaddr*)&sin6, sizeof(sin6)) == 0 &&
+ getsockname(fd, (struct sockaddr*)&sin6_out, &sin6_out_len) == 0) {
+ /* We might have an IPv6 interface. */
+ evutil_found_ifaddr((struct sockaddr*) &sin6_out);
+ }
+
+ if (fd >= 0)
+ evutil_closesocket(fd);
+
+ return 0;
+}
+
+/* Internal addrinfo flag. This one is set when we allocate the addrinfo from
+ * inside libevent. Otherwise, the built-in getaddrinfo() function allocated
+ * it, and we should trust what they said.
+ **/
+#define EVUTIL_AI_LIBEVENT_ALLOCATED 0x80000000
+
+/* Helper: construct a new addrinfo containing the socket address in
+ * 'sa', which must be a sockaddr_in or a sockaddr_in6. Take the
+ * socktype and protocol info from hints. If they weren't set, then
+ * allocate both a TCP and a UDP addrinfo.
+ */
+struct evutil_addrinfo *
+evutil_new_addrinfo_(struct sockaddr *sa, ev_socklen_t socklen,
+ const struct evutil_addrinfo *hints)
+{
+ struct evutil_addrinfo *res;
+ EVUTIL_ASSERT(hints);
+
+ if (hints->ai_socktype == 0 && hints->ai_protocol == 0) {
+ /* Indecisive user! Give them a UDP and a TCP. */
+ struct evutil_addrinfo *r1, *r2;
+ struct evutil_addrinfo tmp;
+ memcpy(&tmp, hints, sizeof(tmp));
+ tmp.ai_socktype = SOCK_STREAM; tmp.ai_protocol = IPPROTO_TCP;
+ r1 = evutil_new_addrinfo_(sa, socklen, &tmp);
+ if (!r1)
+ return NULL;
+ tmp.ai_socktype = SOCK_DGRAM; tmp.ai_protocol = IPPROTO_UDP;
+ r2 = evutil_new_addrinfo_(sa, socklen, &tmp);
+ if (!r2) {
+ evutil_freeaddrinfo(r1);
+ return NULL;
+ }
+ r1->ai_next = r2;
+ return r1;
+ }
+
+ /* We're going to allocate extra space to hold the sockaddr. */
+ res = mm_calloc(1,sizeof(struct evutil_addrinfo)+socklen);
+ if (!res)
+ return NULL;
+ res->ai_addr = (struct sockaddr*)
+ (((char*)res) + sizeof(struct evutil_addrinfo));
+ memcpy(res->ai_addr, sa, socklen);
+ res->ai_addrlen = socklen;
+ res->ai_family = sa->sa_family; /* Same or not? XXX */
+ res->ai_flags = EVUTIL_AI_LIBEVENT_ALLOCATED;
+ res->ai_socktype = hints->ai_socktype;
+ res->ai_protocol = hints->ai_protocol;
+
+ return res;
+}
+
+/* Append the addrinfo 'append' to the end of 'first', and return the start of
+ * the list. Either element can be NULL, in which case we return the element
+ * that is not NULL. */
+struct evutil_addrinfo *
+evutil_addrinfo_append_(struct evutil_addrinfo *first,
+ struct evutil_addrinfo *append)
+{
+ struct evutil_addrinfo *ai = first;
+ if (!ai)
+ return append;
+ while (ai->ai_next)
+ ai = ai->ai_next;
+ ai->ai_next = append;
+
+ return first;
+}
+
+static int
+parse_numeric_servname(const char *servname)
+{
+ int n;
+ char *endptr=NULL;
+ n = (int) strtol(servname, &endptr, 10);
+ if (n>=0 && n <= 65535 && servname[0] && endptr && !endptr[0])
+ return n;
+ else
+ return -1;
+}
+
+/** Parse a service name in 'servname', which can be a decimal port.
+ * Return the port number, or -1 on error.
+ */
+static int
+evutil_parse_servname(const char *servname, const char *protocol,
+ const struct evutil_addrinfo *hints)
+{
+ int n = parse_numeric_servname(servname);
+ if (n>=0)
+ return n;
+#if defined(EVENT__HAVE_GETSERVBYNAME) || defined(_WIN32)
+ if (!(hints->ai_flags & EVUTIL_AI_NUMERICSERV)) {
+ struct servent *ent = getservbyname(servname, protocol);
+ if (ent) {
+ return ntohs(ent->s_port);
+ }
+ }
+#endif
+ return -1;
+}
+
+/* Return a string corresponding to a protocol number that we can pass to
+ * getservyname. */
+static const char *
+evutil_unparse_protoname(int proto)
+{
+ switch (proto) {
+ case 0:
+ return NULL;
+ case IPPROTO_TCP:
+ return "tcp";
+ case IPPROTO_UDP:
+ return "udp";
+#ifdef IPPROTO_SCTP
+ case IPPROTO_SCTP:
+ return "sctp";
+#endif
+ default:
+#ifdef EVENT__HAVE_GETPROTOBYNUMBER
+ {
+ struct protoent *ent = getprotobynumber(proto);
+ if (ent)
+ return ent->p_name;
+ }
+#endif
+ return NULL;
+ }
+}
+
+static void
+evutil_getaddrinfo_infer_protocols(struct evutil_addrinfo *hints)
+{
+ /* If we can guess the protocol from the socktype, do so. */
+ if (!hints->ai_protocol && hints->ai_socktype) {
+ if (hints->ai_socktype == SOCK_DGRAM)
+ hints->ai_protocol = IPPROTO_UDP;
+ else if (hints->ai_socktype == SOCK_STREAM)
+ hints->ai_protocol = IPPROTO_TCP;
+ }
+
+ /* Set the socktype if it isn't set. */
+ if (!hints->ai_socktype && hints->ai_protocol) {
+ if (hints->ai_protocol == IPPROTO_UDP)
+ hints->ai_socktype = SOCK_DGRAM;
+ else if (hints->ai_protocol == IPPROTO_TCP)
+ hints->ai_socktype = SOCK_STREAM;
+#ifdef IPPROTO_SCTP
+ else if (hints->ai_protocol == IPPROTO_SCTP)
+ hints->ai_socktype = SOCK_STREAM;
+#endif
+ }
+}
+
+#if AF_UNSPEC != PF_UNSPEC
+#error "I cannot build on a system where AF_UNSPEC != PF_UNSPEC"
+#endif
+
+/** Implements the part of looking up hosts by name that's common to both
+ * the blocking and nonblocking resolver:
+ * - Adjust 'hints' to have a reasonable socktype and protocol.
+ * - Look up the port based on 'servname', and store it in *portnum,
+ * - Handle the nodename==NULL case
+ * - Handle some invalid arguments cases.
+ * - Handle the cases where nodename is an IPv4 or IPv6 address.
+ *
+ * If we need the resolver to look up the hostname, we return
+ * EVUTIL_EAI_NEED_RESOLVE. Otherwise, we can completely implement
+ * getaddrinfo: we return 0 or an appropriate EVUTIL_EAI_* error, and
+ * set *res as getaddrinfo would.
+ */
+int
+evutil_getaddrinfo_common_(const char *nodename, const char *servname,
+ struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum)
+{
+ int port = 0;
+ const char *pname;
+
+ if (nodename == NULL && servname == NULL)
+ return EVUTIL_EAI_NONAME;
+
+ /* We only understand 3 families */
+ if (hints->ai_family != PF_UNSPEC && hints->ai_family != PF_INET &&
+ hints->ai_family != PF_INET6)
+ return EVUTIL_EAI_FAMILY;
+
+ evutil_getaddrinfo_infer_protocols(hints);
+
+ /* Look up the port number and protocol, if possible. */
+ pname = evutil_unparse_protoname(hints->ai_protocol);
+ if (servname) {
+ /* XXXX We could look at the protocol we got back from
+ * getservbyname, but it doesn't seem too useful. */
+ port = evutil_parse_servname(servname, pname, hints);
+ if (port < 0) {
+ return EVUTIL_EAI_NONAME;
+ }
+ }
+
+ /* If we have no node name, then we're supposed to bind to 'any' and
+ * connect to localhost. */
+ if (nodename == NULL) {
+ struct evutil_addrinfo *res4=NULL, *res6=NULL;
+ if (hints->ai_family != PF_INET) { /* INET6 or UNSPEC. */
+ struct sockaddr_in6 sin6;
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(port);
+ if (hints->ai_flags & EVUTIL_AI_PASSIVE) {
+ /* Bind to :: */
+ } else {
+ /* connect to ::1 */
+ sin6.sin6_addr.s6_addr[15] = 1;
+ }
+ res6 = evutil_new_addrinfo_((struct sockaddr*)&sin6,
+ sizeof(sin6), hints);
+ if (!res6)
+ return EVUTIL_EAI_MEMORY;
+ }
+
+ if (hints->ai_family != PF_INET6) { /* INET or UNSPEC */
+ struct sockaddr_in sin;
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ if (hints->ai_flags & EVUTIL_AI_PASSIVE) {
+ /* Bind to 0.0.0.0 */
+ } else {
+ /* connect to 127.0.0.1 */
+ sin.sin_addr.s_addr = htonl(0x7f000001);
+ }
+ res4 = evutil_new_addrinfo_((struct sockaddr*)&sin,
+ sizeof(sin), hints);
+ if (!res4) {
+ if (res6)
+ evutil_freeaddrinfo(res6);
+ return EVUTIL_EAI_MEMORY;
+ }
+ }
+ *res = evutil_addrinfo_append_(res4, res6);
+ return 0;
+ }
+
+ /* If we can, we should try to parse the hostname without resolving
+ * it. */
+ /* Try ipv6. */
+ if (hints->ai_family == PF_INET6 || hints->ai_family == PF_UNSPEC) {
+ struct sockaddr_in6 sin6;
+ memset(&sin6, 0, sizeof(sin6));
+ if (1==evutil_inet_pton(AF_INET6, nodename, &sin6.sin6_addr)) {
+ /* Got an ipv6 address. */
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(port);
+ *res = evutil_new_addrinfo_((struct sockaddr*)&sin6,
+ sizeof(sin6), hints);
+ if (!*res)
+ return EVUTIL_EAI_MEMORY;
+ return 0;
+ }
+ }
+
+ /* Try ipv4. */
+ if (hints->ai_family == PF_INET || hints->ai_family == PF_UNSPEC) {
+ struct sockaddr_in sin;
+ memset(&sin, 0, sizeof(sin));
+ if (1==evutil_inet_pton(AF_INET, nodename, &sin.sin_addr)) {
+ /* Got an ipv6 address. */
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ *res = evutil_new_addrinfo_((struct sockaddr*)&sin,
+ sizeof(sin), hints);
+ if (!*res)
+ return EVUTIL_EAI_MEMORY;
+ return 0;
+ }
+ }
+
+
+ /* If we have reached this point, we definitely need to do a DNS
+ * lookup. */
+ if ((hints->ai_flags & EVUTIL_AI_NUMERICHOST)) {
+ /* If we're not allowed to do one, then say so. */
+ return EVUTIL_EAI_NONAME;
+ }
+ *portnum = port;
+ return EVUTIL_EAI_NEED_RESOLVE;
+}
+
+#ifdef EVENT__HAVE_GETADDRINFO
+#define USE_NATIVE_GETADDRINFO
+#endif
+
+#ifdef USE_NATIVE_GETADDRINFO
+/* A mask of all the flags that we declare, so we can clear them before calling
+ * the native getaddrinfo */
+static const unsigned int ALL_NONNATIVE_AI_FLAGS =
+#ifndef AI_PASSIVE
+ EVUTIL_AI_PASSIVE |
+#endif
+#ifndef AI_CANONNAME
+ EVUTIL_AI_CANONNAME |
+#endif
+#ifndef AI_NUMERICHOST
+ EVUTIL_AI_NUMERICHOST |
+#endif
+#ifndef AI_NUMERICSERV
+ EVUTIL_AI_NUMERICSERV |
+#endif
+#ifndef AI_ADDRCONFIG
+ EVUTIL_AI_ADDRCONFIG |
+#endif
+#ifndef AI_ALL
+ EVUTIL_AI_ALL |
+#endif
+#ifndef AI_V4MAPPED
+ EVUTIL_AI_V4MAPPED |
+#endif
+ EVUTIL_AI_LIBEVENT_ALLOCATED;
+
+static const unsigned int ALL_NATIVE_AI_FLAGS =
+#ifdef AI_PASSIVE
+ AI_PASSIVE |
+#endif
+#ifdef AI_CANONNAME
+ AI_CANONNAME |
+#endif
+#ifdef AI_NUMERICHOST
+ AI_NUMERICHOST |
+#endif
+#ifdef AI_NUMERICSERV
+ AI_NUMERICSERV |
+#endif
+#ifdef AI_ADDRCONFIG
+ AI_ADDRCONFIG |
+#endif
+#ifdef AI_ALL
+ AI_ALL |
+#endif
+#ifdef AI_V4MAPPED
+ AI_V4MAPPED |
+#endif
+ 0;
+#endif
+
+#ifndef USE_NATIVE_GETADDRINFO
+/* Helper for systems with no getaddrinfo(): make one or more addrinfos out of
+ * a struct hostent.
+ */
+static struct evutil_addrinfo *
+addrinfo_from_hostent(const struct hostent *ent,
+ int port, const struct evutil_addrinfo *hints)
+{
+ int i;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr *sa;
+ int socklen;
+ struct evutil_addrinfo *res=NULL, *ai;
+ void *addrp;
+
+ if (ent->h_addrtype == PF_INET) {
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ sa = (struct sockaddr *)&sin;
+ socklen = sizeof(struct sockaddr_in);
+ addrp = &sin.sin_addr;
+ if (ent->h_length != sizeof(sin.sin_addr)) {
+ event_warnx("Weird h_length from gethostbyname");
+ return NULL;
+ }
+ } else if (ent->h_addrtype == PF_INET6) {
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(port);
+ sa = (struct sockaddr *)&sin6;
+ socklen = sizeof(struct sockaddr_in6);
+ addrp = &sin6.sin6_addr;
+ if (ent->h_length != sizeof(sin6.sin6_addr)) {
+ event_warnx("Weird h_length from gethostbyname");
+ return NULL;
+ }
+ } else
+ return NULL;
+
+ for (i = 0; ent->h_addr_list[i]; ++i) {
+ memcpy(addrp, ent->h_addr_list[i], ent->h_length);
+ ai = evutil_new_addrinfo_(sa, socklen, hints);
+ if (!ai) {
+ evutil_freeaddrinfo(res);
+ return NULL;
+ }
+ res = evutil_addrinfo_append_(res, ai);
+ }
+
+ if (res && ((hints->ai_flags & EVUTIL_AI_CANONNAME) && ent->h_name)) {
+ res->ai_canonname = mm_strdup(ent->h_name);
+ if (res->ai_canonname == NULL) {
+ evutil_freeaddrinfo(res);
+ return NULL;
+ }
+ }
+
+ return res;
+}
+#endif
+
+/* If the EVUTIL_AI_ADDRCONFIG flag is set on hints->ai_flags, and
+ * hints->ai_family is PF_UNSPEC, then revise the value of hints->ai_family so
+ * that we'll only get addresses we could maybe connect to.
+ */
+void
+evutil_adjust_hints_for_addrconfig_(struct evutil_addrinfo *hints)
+{
+ if (!(hints->ai_flags & EVUTIL_AI_ADDRCONFIG))
+ return;
+ if (hints->ai_family != PF_UNSPEC)
+ return;
+ if (!have_checked_interfaces)
+ evutil_check_interfaces(0);
+ if (had_ipv4_address && !had_ipv6_address) {
+ hints->ai_family = PF_INET;
+ } else if (!had_ipv4_address && had_ipv6_address) {
+ hints->ai_family = PF_INET6;
+ }
+}
+
+#ifdef USE_NATIVE_GETADDRINFO
+static int need_numeric_port_hack_=0;
+static int need_socktype_protocol_hack_=0;
+static int tested_for_getaddrinfo_hacks=0;
+
+/* Some older BSDs (like OpenBSD up to 4.6) used to believe that
+ giving a numeric port without giving an ai_socktype was verboten.
+ We test for this so we can apply an appropriate workaround. If it
+ turns out that the bug is present, then:
+
+ - If nodename==NULL and servname is numeric, we build an answer
+ ourselves using evutil_getaddrinfo_common_().
+
+ - If nodename!=NULL and servname is numeric, then we set
+ servname=NULL when calling getaddrinfo, and post-process the
+ result to set the ports on it.
+
+ We test for this bug at runtime, since otherwise we can't have the
+ same binary run on multiple BSD versions.
+
+ - Some versions of Solaris believe that it's nice to leave to protocol
+ field set to 0. We test for this so we can apply an appropriate
+ workaround.
+*/
+static struct evutil_addrinfo *ai_find_protocol(struct evutil_addrinfo *ai)
+{
+ while (ai) {
+ if (ai->ai_protocol)
+ return ai;
+ ai = ai->ai_next;
+ }
+ return NULL;
+}
+static void
+test_for_getaddrinfo_hacks(void)
+{
+ int r, r2;
+ struct evutil_addrinfo *ai=NULL, *ai2=NULL, *ai3=NULL;
+ struct evutil_addrinfo hints;
+
+ memset(&hints,0,sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags =
+#ifdef AI_NUMERICHOST
+ AI_NUMERICHOST |
+#endif
+#ifdef AI_NUMERICSERV
+ AI_NUMERICSERV |
+#endif
+ 0;
+ r = getaddrinfo("1.2.3.4", "80", &hints, &ai);
+ getaddrinfo("1.2.3.4", NULL, &hints, &ai3);
+ hints.ai_socktype = SOCK_STREAM;
+ r2 = getaddrinfo("1.2.3.4", "80", &hints, &ai2);
+ if (r2 == 0 && r != 0) {
+ need_numeric_port_hack_=1;
+ }
+ if (!ai_find_protocol(ai2) || !ai_find_protocol(ai3)) {
+ need_socktype_protocol_hack_=1;
+ }
+
+ if (ai)
+ freeaddrinfo(ai);
+ if (ai2)
+ freeaddrinfo(ai2);
+ if (ai3)
+ freeaddrinfo(ai3);
+ tested_for_getaddrinfo_hacks=1;
+}
+
+static inline int
+need_numeric_port_hack(void)
+{
+ if (!tested_for_getaddrinfo_hacks)
+ test_for_getaddrinfo_hacks();
+ return need_numeric_port_hack_;
+}
+
+static inline int
+need_socktype_protocol_hack(void)
+{
+ if (!tested_for_getaddrinfo_hacks)
+ test_for_getaddrinfo_hacks();
+ return need_socktype_protocol_hack_;
+}
+
+static void
+apply_numeric_port_hack(int port, struct evutil_addrinfo **ai)
+{
+ /* Now we run through the list and set the ports on all of the
+ * results where ports would make sense. */
+ for ( ; *ai; ai = &(*ai)->ai_next) {
+ struct sockaddr *sa = (*ai)->ai_addr;
+ if (sa && sa->sa_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in*)sa;
+ sin->sin_port = htons(port);
+ } else if (sa && sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
+ sin6->sin6_port = htons(port);
+ } else {
+ /* A numeric port makes no sense here; remove this one
+ * from the list. */
+ struct evutil_addrinfo *victim = *ai;
+ *ai = victim->ai_next;
+ victim->ai_next = NULL;
+ freeaddrinfo(victim);
+ }
+ }
+}
+
+static int
+apply_socktype_protocol_hack(struct evutil_addrinfo *ai)
+{
+ struct evutil_addrinfo *ai_new;
+ for (; ai; ai = ai->ai_next) {
+ evutil_getaddrinfo_infer_protocols(ai);
+ if (ai->ai_socktype || ai->ai_protocol)
+ continue;
+ ai_new = mm_malloc(sizeof(*ai_new));
+ if (!ai_new)
+ return -1;
+ memcpy(ai_new, ai, sizeof(*ai_new));
+ ai->ai_socktype = SOCK_STREAM;
+ ai->ai_protocol = IPPROTO_TCP;
+ ai_new->ai_socktype = SOCK_DGRAM;
+ ai_new->ai_protocol = IPPROTO_UDP;
+
+ ai_new->ai_next = ai->ai_next;
+ ai->ai_next = ai_new;
+ }
+ return 0;
+}
+#endif
+
+int
+evutil_getaddrinfo(const char *nodename, const char *servname,
+ const struct evutil_addrinfo *hints_in, struct evutil_addrinfo **res)
+{
+#ifdef USE_NATIVE_GETADDRINFO
+ struct evutil_addrinfo hints;
+ int portnum=-1, need_np_hack, err;
+
+ if (hints_in) {
+ memcpy(&hints, hints_in, sizeof(hints));
+ } else {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ }
+
+#ifndef AI_ADDRCONFIG
+ /* Not every system has AI_ADDRCONFIG, so fake it. */
+ if (hints.ai_family == PF_UNSPEC &&
+ (hints.ai_flags & EVUTIL_AI_ADDRCONFIG)) {
+ evutil_adjust_hints_for_addrconfig_(&hints);
+ }
+#endif
+
+#ifndef AI_NUMERICSERV
+ /* Not every system has AI_NUMERICSERV, so fake it. */
+ if (hints.ai_flags & EVUTIL_AI_NUMERICSERV) {
+ if (servname && parse_numeric_servname(servname)<0)
+ return EVUTIL_EAI_NONAME;
+ }
+#endif
+
+ /* Enough operating systems handle enough common non-resolve
+ * cases here weirdly enough that we are better off just
+ * overriding them. For example:
+ *
+ * - Windows doesn't like to infer the protocol from the
+ * socket type, or fill in socket or protocol types much at
+ * all. It also seems to do its own broken implicit
+ * always-on version of AI_ADDRCONFIG that keeps it from
+ * ever resolving even a literal IPv6 address when
+ * ai_addrtype is PF_UNSPEC.
+ */
+#ifdef _WIN32
+ {
+ int tmp_port;
+ err = evutil_getaddrinfo_common_(nodename,servname,&hints,
+ res, &tmp_port);
+ if (err == 0 ||
+ err == EVUTIL_EAI_MEMORY ||
+ err == EVUTIL_EAI_NONAME)
+ return err;
+ /* If we make it here, the system getaddrinfo can
+ * have a crack at it. */
+ }
+#endif
+
+ /* See documentation for need_numeric_port_hack above.*/
+ need_np_hack = need_numeric_port_hack() && servname && !hints.ai_socktype
+ && ((portnum=parse_numeric_servname(servname)) >= 0);
+ if (need_np_hack) {
+ if (!nodename)
+ return evutil_getaddrinfo_common_(
+ NULL,servname,&hints, res, &portnum);
+ servname = NULL;
+ }
+
+ if (need_socktype_protocol_hack()) {
+ evutil_getaddrinfo_infer_protocols(&hints);
+ }
+
+ /* Make sure that we didn't actually steal any AI_FLAGS values that
+ * the system is using. (This is a constant expression, and should ge
+ * optimized out.)
+ *
+ * XXXX Turn this into a compile-time failure rather than a run-time
+ * failure.
+ */
+ EVUTIL_ASSERT((ALL_NONNATIVE_AI_FLAGS & ALL_NATIVE_AI_FLAGS) == 0);
+
+ /* Clear any flags that only libevent understands. */
+ hints.ai_flags &= ~ALL_NONNATIVE_AI_FLAGS;
+
+ err = getaddrinfo(nodename, servname, &hints, res);
+ if (need_np_hack)
+ apply_numeric_port_hack(portnum, res);
+
+ if (need_socktype_protocol_hack()) {
+ if (apply_socktype_protocol_hack(*res) < 0) {
+ evutil_freeaddrinfo(*res);
+ *res = NULL;
+ return EVUTIL_EAI_MEMORY;
+ }
+ }
+ return err;
+#else
+ int port=0, err;
+ struct hostent *ent = NULL;
+ struct evutil_addrinfo hints;
+
+ if (hints_in) {
+ memcpy(&hints, hints_in, sizeof(hints));
+ } else {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ }
+
+ evutil_adjust_hints_for_addrconfig_(&hints);
+
+ err = evutil_getaddrinfo_common_(nodename, servname, &hints, res, &port);
+ if (err != EVUTIL_EAI_NEED_RESOLVE) {
+ /* We either succeeded or failed. No need to continue */
+ return err;
+ }
+
+ err = 0;
+ /* Use any of the various gethostbyname_r variants as available. */
+ {
+#ifdef EVENT__HAVE_GETHOSTBYNAME_R_6_ARG
+ /* This one is what glibc provides. */
+ char buf[2048];
+ struct hostent hostent;
+ int r;
+ r = gethostbyname_r(nodename, &hostent, buf, sizeof(buf), &ent,
+ &err);
+#elif defined(EVENT__HAVE_GETHOSTBYNAME_R_5_ARG)
+ char buf[2048];
+ struct hostent hostent;
+ ent = gethostbyname_r(nodename, &hostent, buf, sizeof(buf),
+ &err);
+#elif defined(EVENT__HAVE_GETHOSTBYNAME_R_3_ARG)
+ struct hostent_data data;
+ struct hostent hostent;
+ memset(&data, 0, sizeof(data));
+ err = gethostbyname_r(nodename, &hostent, &data);
+ ent = err ? NULL : &hostent;
+#else
+ /* fall back to gethostbyname. */
+ /* XXXX This needs a lock everywhere but Windows. */
+ ent = gethostbyname(nodename);
+#ifdef _WIN32
+ err = WSAGetLastError();
+#else
+ err = h_errno;
+#endif
+#endif
+
+ /* Now we have either ent or err set. */
+ if (!ent) {
+ /* XXX is this right for windows ? */
+ switch (err) {
+ case TRY_AGAIN:
+ return EVUTIL_EAI_AGAIN;
+ case NO_RECOVERY:
+ default:
+ return EVUTIL_EAI_FAIL;
+ case HOST_NOT_FOUND:
+ return EVUTIL_EAI_NONAME;
+ case NO_ADDRESS:
+#if NO_DATA != NO_ADDRESS
+ case NO_DATA:
+#endif
+ return EVUTIL_EAI_NODATA;
+ }
+ }
+
+ if (ent->h_addrtype != hints.ai_family &&
+ hints.ai_family != PF_UNSPEC) {
+ /* This wasn't the type we were hoping for. Too bad
+ * we never had a chance to ask gethostbyname for what
+ * we wanted. */
+ return EVUTIL_EAI_NONAME;
+ }
+
+ /* Make sure we got _some_ answers. */
+ if (ent->h_length == 0)
+ return EVUTIL_EAI_NODATA;
+
+ /* If we got an address type we don't know how to make a
+ sockaddr for, give up. */
+ if (ent->h_addrtype != PF_INET && ent->h_addrtype != PF_INET6)
+ return EVUTIL_EAI_FAMILY;
+
+ *res = addrinfo_from_hostent(ent, port, &hints);
+ if (! *res)
+ return EVUTIL_EAI_MEMORY;
+ }
+
+ return 0;
+#endif
+}
+
+void
+evutil_freeaddrinfo(struct evutil_addrinfo *ai)
+{
+#ifdef EVENT__HAVE_GETADDRINFO
+ if (!(ai->ai_flags & EVUTIL_AI_LIBEVENT_ALLOCATED)) {
+ freeaddrinfo(ai);
+ return;
+ }
+#endif
+ while (ai) {
+ struct evutil_addrinfo *next = ai->ai_next;
+ if (ai->ai_canonname)
+ mm_free(ai->ai_canonname);
+ mm_free(ai);
+ ai = next;
+ }
+}
+
+static evdns_getaddrinfo_fn evdns_getaddrinfo_impl = NULL;
+static evdns_getaddrinfo_cancel_fn evdns_getaddrinfo_cancel_impl = NULL;
+
+void
+evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo_fn fn)
+{
+ if (!evdns_getaddrinfo_impl)
+ evdns_getaddrinfo_impl = fn;
+}
+void
+evutil_set_evdns_getaddrinfo_cancel_fn_(evdns_getaddrinfo_cancel_fn fn)
+{
+ if (!evdns_getaddrinfo_cancel_impl)
+ evdns_getaddrinfo_cancel_impl = fn;
+}
+
+/* Internal helper function: act like evdns_getaddrinfo if dns_base is set;
+ * otherwise do a blocking resolve and pass the result to the callback in the
+ * way that evdns_getaddrinfo would.
+ */
+struct evdns_getaddrinfo_request *evutil_getaddrinfo_async_(
+ struct evdns_base *dns_base,
+ const char *nodename, const char *servname,
+ const struct evutil_addrinfo *hints_in,
+ void (*cb)(int, struct evutil_addrinfo *, void *), void *arg)
+{
+ if (dns_base && evdns_getaddrinfo_impl) {
+ return evdns_getaddrinfo_impl(
+ dns_base, nodename, servname, hints_in, cb, arg);
+ } else {
+ struct evutil_addrinfo *ai=NULL;
+ int err;
+ err = evutil_getaddrinfo(nodename, servname, hints_in, &ai);
+ cb(err, ai, arg);
+ return NULL;
+ }
+}
+
+void evutil_getaddrinfo_cancel_async_(struct evdns_getaddrinfo_request *data)
+{
+ if (evdns_getaddrinfo_cancel_impl && data) {
+ evdns_getaddrinfo_cancel_impl(data);
+ }
+}
+
+const char *
+evutil_gai_strerror(int err)
+{
+ /* As a sneaky side-benefit, this case statement will get most
+ * compilers to tell us if any of the error codes we defined
+ * conflict with the platform's native error codes. */
+ switch (err) {
+ case EVUTIL_EAI_CANCEL:
+ return "Request canceled";
+ case 0:
+ return "No error";
+
+ case EVUTIL_EAI_ADDRFAMILY:
+ return "address family for nodename not supported";
+ case EVUTIL_EAI_AGAIN:
+ return "temporary failure in name resolution";
+ case EVUTIL_EAI_BADFLAGS:
+ return "invalid value for ai_flags";
+ case EVUTIL_EAI_FAIL:
+ return "non-recoverable failure in name resolution";
+ case EVUTIL_EAI_FAMILY:
+ return "ai_family not supported";
+ case EVUTIL_EAI_MEMORY:
+ return "memory allocation failure";
+ case EVUTIL_EAI_NODATA:
+ return "no address associated with nodename";
+ case EVUTIL_EAI_NONAME:
+ return "nodename nor servname provided, or not known";
+ case EVUTIL_EAI_SERVICE:
+ return "servname not supported for ai_socktype";
+ case EVUTIL_EAI_SOCKTYPE:
+ return "ai_socktype not supported";
+ case EVUTIL_EAI_SYSTEM:
+ return "system error";
+ default:
+#if defined(USE_NATIVE_GETADDRINFO) && defined(_WIN32)
+ return gai_strerrorA(err);
+#elif defined(USE_NATIVE_GETADDRINFO)
+ return gai_strerror(err);
+#else
+ return "Unknown error code";
+#endif
+ }
+}
+
+#ifdef _WIN32
+/* destructively remove a trailing line terminator from s */
+static void
+chomp (char *s)
+{
+ size_t len;
+ if (s && (len = strlen (s)) > 0 && s[len - 1] == '\n') {
+ s[--len] = 0;
+ if (len > 0 && s[len - 1] == '\r')
+ s[--len] = 0;
+ }
+}
+
+/* FormatMessage returns allocated strings, but evutil_socket_error_to_string
+ * is supposed to return a string which is good indefinitely without having
+ * to be freed. To make this work without leaking memory, we cache the
+ * string the first time FormatMessage is called on a particular error
+ * code, and then return the cached string on subsequent calls with the
+ * same code. The strings aren't freed until libevent_global_shutdown
+ * (or never). We use a linked list to cache the errors, because we
+ * only expect there to be a few dozen, and that should be fast enough.
+ */
+
+struct cached_sock_errs_entry {
+ HT_ENTRY(cached_sock_errs_entry) node;
+ DWORD code;
+ char *msg; /* allocated with LocalAlloc; free with LocalFree */
+};
+
+static inline unsigned
+hash_cached_sock_errs(const struct cached_sock_errs_entry *e)
+{
+ /* Use Murmur3's 32-bit finalizer as an integer hash function */
+ DWORD h = e->code;
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+ return h;
+}
+
+static inline int
+eq_cached_sock_errs(const struct cached_sock_errs_entry *a,
+ const struct cached_sock_errs_entry *b)
+{
+ return a->code == b->code;
+}
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+static void *windows_socket_errors_lock_ = NULL;
+#endif
+
+static HT_HEAD(cached_sock_errs_map, cached_sock_errs_entry)
+ windows_socket_errors = HT_INITIALIZER();
+
+HT_PROTOTYPE(cached_sock_errs_map,
+ cached_sock_errs_entry,
+ node,
+ hash_cached_sock_errs,
+ eq_cached_sock_errs);
+
+HT_GENERATE(cached_sock_errs_map,
+ cached_sock_errs_entry,
+ node,
+ hash_cached_sock_errs,
+ eq_cached_sock_errs,
+ 0.5,
+ mm_malloc,
+ mm_realloc,
+ mm_free);
+
+/** Equivalent to strerror, but for windows socket errors. */
+const char *
+evutil_socket_error_to_string(int errcode)
+{
+ struct cached_sock_errs_entry *errs, *newerr, find;
+ char *msg = NULL;
+
+ EVLOCK_LOCK(windows_socket_errors_lock_, 0);
+
+ find.code = errcode;
+ errs = HT_FIND(cached_sock_errs_map, &windows_socket_errors, &find);
+ if (errs) {
+ msg = errs->msg;
+ goto done;
+ }
+
+ if (0 != FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL, errcode, 0, (char *)&msg, 0, NULL))
+ chomp (msg); /* because message has trailing newline */
+ else {
+ size_t len = 50;
+ /* use LocalAlloc because FormatMessage does */
+ msg = LocalAlloc(LMEM_FIXED, len);
+ if (!msg) {
+ msg = (char *)"LocalAlloc failed during Winsock error";
+ goto done;
+ }
+ evutil_snprintf(msg, len, "winsock error 0x%08x", errcode);
+ }
+
+ newerr = (struct cached_sock_errs_entry *)
+ mm_malloc(sizeof (struct cached_sock_errs_entry));
+
+ if (!newerr) {
+ LocalFree(msg);
+ msg = (char *)"malloc failed during Winsock error";
+ goto done;
+ }
+
+ newerr->code = errcode;
+ newerr->msg = msg;
+ HT_INSERT(cached_sock_errs_map, &windows_socket_errors, newerr);
+
+ done:
+ EVLOCK_UNLOCK(windows_socket_errors_lock_, 0);
+
+ return msg;
+}
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+int
+evutil_global_setup_locks_(const int enable_locks)
+{
+ EVTHREAD_SETUP_GLOBAL_LOCK(windows_socket_errors_lock_, 0);
+ return 0;
+}
+#endif
+
+static void
+evutil_free_sock_err_globals(void)
+{
+ struct cached_sock_errs_entry **errs, *tofree;
+
+ for (errs = HT_START(cached_sock_errs_map, &windows_socket_errors)
+ ; errs; ) {
+ tofree = *errs;
+ errs = HT_NEXT_RMV(cached_sock_errs_map,
+ &windows_socket_errors,
+ errs);
+ LocalFree(tofree->msg);
+ mm_free(tofree);
+ }
+
+ HT_CLEAR(cached_sock_errs_map, &windows_socket_errors);
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ if (windows_socket_errors_lock_ != NULL) {
+ EVTHREAD_FREE_LOCK(windows_socket_errors_lock_, 0);
+ windows_socket_errors_lock_ = NULL;
+ }
+#endif
+}
+
+#else
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+int
+evutil_global_setup_locks_(const int enable_locks)
+{
+ return 0;
+}
+#endif
+
+static void
+evutil_free_sock_err_globals(void)
+{
+}
+
+#endif
+
+int
+evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
+{
+ int r;
+ va_list ap;
+ va_start(ap, format);
+ r = evutil_vsnprintf(buf, buflen, format, ap);
+ va_end(ap);
+ return r;
+}
+
+int
+evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
+{
+ int r;
+ if (!buflen)
+ return 0;
+#if defined(_MSC_VER) || defined(_WIN32)
+ r = _vsnprintf(buf, buflen, format, ap);
+ if (r < 0)
+ r = _vscprintf(format, ap);
+#elif defined(sgi)
+ /* Make sure we always use the correct vsnprintf on IRIX */
+ extern int _xpg5_vsnprintf(char * __restrict,
+ __SGI_LIBC_NAMESPACE_QUALIFIER size_t,
+ const char * __restrict, /* va_list */ char *);
+
+ r = _xpg5_vsnprintf(buf, buflen, format, ap);
+#else
+ r = vsnprintf(buf, buflen, format, ap);
+#endif
+ buf[buflen-1] = '\0';
+ return r;
+}
+
+#define USE_INTERNAL_NTOP
+#define USE_INTERNAL_PTON
+
+const char *
+evutil_inet_ntop(int af, const void *src, char *dst, size_t len)
+{
+#if defined(EVENT__HAVE_INET_NTOP) && !defined(USE_INTERNAL_NTOP)
+ return inet_ntop(af, src, dst, len);
+#else
+ if (af == AF_INET) {
+ const struct in_addr *in = src;
+ const ev_uint32_t a = ntohl(in->s_addr);
+ int r;
+ r = evutil_snprintf(dst, len, "%d.%d.%d.%d",
+ (int)(ev_uint8_t)((a>>24)&0xff),
+ (int)(ev_uint8_t)((a>>16)&0xff),
+ (int)(ev_uint8_t)((a>>8 )&0xff),
+ (int)(ev_uint8_t)((a )&0xff));
+ if (r<0||(size_t)r>=len)
+ return NULL;
+ else
+ return dst;
+#ifdef AF_INET6
+ } else if (af == AF_INET6) {
+ const struct in6_addr *addr = src;
+ char buf[64], *cp;
+ int longestGapLen = 0, longestGapPos = -1, i,
+ curGapPos = -1, curGapLen = 0;
+ ev_uint16_t words[8];
+ for (i = 0; i < 8; ++i) {
+ words[i] =
+ (((ev_uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1];
+ }
+ if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
+ words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) ||
+ (words[5] == 0xffff))) {
+ /* This is an IPv4 address. */
+ if (words[5] == 0) {
+ evutil_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d",
+ addr->s6_addr[12], addr->s6_addr[13],
+ addr->s6_addr[14], addr->s6_addr[15]);
+ } else {
+ evutil_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5],
+ addr->s6_addr[12], addr->s6_addr[13],
+ addr->s6_addr[14], addr->s6_addr[15]);
+ }
+ if (strlen(buf) > len)
+ return NULL;
+ strlcpy(dst, buf, len);
+ return dst;
+ }
+ i = 0;
+ while (i < 8) {
+ if (words[i] == 0) {
+ curGapPos = i++;
+ curGapLen = 1;
+ while (i<8 && words[i] == 0) {
+ ++i; ++curGapLen;
+ }
+ if (curGapLen > longestGapLen) {
+ longestGapPos = curGapPos;
+ longestGapLen = curGapLen;
+ }
+ } else {
+ ++i;
+ }
+ }
+ if (longestGapLen<=1)
+ longestGapPos = -1;
+
+ cp = buf;
+ for (i = 0; i < 8; ++i) {
+ if (words[i] == 0 && longestGapPos == i) {
+ if (i == 0)
+ *cp++ = ':';
+ *cp++ = ':';
+ while (i < 8 && words[i] == 0)
+ ++i;
+ --i; /* to compensate for loop increment. */
+ } else {
+ evutil_snprintf(cp,
+ sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]);
+ cp += strlen(cp);
+ if (i != 7)
+ *cp++ = ':';
+ }
+ }
+ *cp = '\0';
+ if (strlen(buf) > len)
+ return NULL;
+ strlcpy(dst, buf, len);
+ return dst;
+#endif
+ } else {
+ return NULL;
+ }
+#endif
+}
+
+int
+evutil_inet_pton(int af, const char *src, void *dst)
+{
+#if defined(EVENT__HAVE_INET_PTON) && !defined(USE_INTERNAL_PTON)
+ return inet_pton(af, src, dst);
+#else
+ if (af == AF_INET) {
+ unsigned a,b,c,d;
+ char more;
+ struct in_addr *addr = dst;
+ if (sscanf(src, "%u.%u.%u.%u%c", &a,&b,&c,&d,&more) != 4)
+ return 0;
+ if (a > 255) return 0;
+ if (b > 255) return 0;
+ if (c > 255) return 0;
+ if (d > 255) return 0;
+ addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d);
+ return 1;
+#ifdef AF_INET6
+ } else if (af == AF_INET6) {
+ struct in6_addr *out = dst;
+ ev_uint16_t words[8];
+ int gapPos = -1, i, setWords=0;
+ const char *dot = strchr(src, '.');
+ const char *eow; /* end of words. */
+ if (dot == src)
+ return 0;
+ else if (!dot)
+ eow = src+strlen(src);
+ else {
+ unsigned byte1,byte2,byte3,byte4;
+ char more;
+ for (eow = dot-1; eow >= src && EVUTIL_ISDIGIT_(*eow); --eow)
+ ;
+ ++eow;
+
+ /* We use "scanf" because some platform inet_aton()s are too lax
+ * about IPv4 addresses of the form "1.2.3" */
+ if (sscanf(eow, "%u.%u.%u.%u%c",
+ &byte1,&byte2,&byte3,&byte4,&more) != 4)
+ return 0;
+
+ if (byte1 > 255 ||
+ byte2 > 255 ||
+ byte3 > 255 ||
+ byte4 > 255)
+ return 0;
+
+ words[6] = (byte1<<8) | byte2;
+ words[7] = (byte3<<8) | byte4;
+ setWords += 2;
+ }
+
+ i = 0;
+ while (src < eow) {
+ if (i > 7)
+ return 0;
+ if (EVUTIL_ISXDIGIT_(*src)) {
+ char *next;
+ long r = strtol(src, &next, 16);
+ if (next > 4+src)
+ return 0;
+ if (next == src)
+ return 0;
+ if (r<0 || r>65536)
+ return 0;
+
+ words[i++] = (ev_uint16_t)r;
+ setWords++;
+ src = next;
+ if (*src != ':' && src != eow)
+ return 0;
+ ++src;
+ } else if (*src == ':' && i > 0 && gapPos==-1) {
+ gapPos = i;
+ ++src;
+ } else if (*src == ':' && i == 0 && src[1] == ':' && gapPos==-1) {
+ gapPos = i;
+ src += 2;
+ } else {
+ return 0;
+ }
+ }
+
+ if (setWords > 8 ||
+ (setWords == 8 && gapPos != -1) ||
+ (setWords < 8 && gapPos == -1))
+ return 0;
+
+ if (gapPos >= 0) {
+ int nToMove = setWords - (dot ? 2 : 0) - gapPos;
+ int gapLen = 8 - setWords;
+ /* assert(nToMove >= 0); */
+ if (nToMove < 0)
+ return -1; /* should be impossible */
+ memmove(&words[gapPos+gapLen], &words[gapPos],
+ sizeof(ev_uint16_t)*nToMove);
+ memset(&words[gapPos], 0, sizeof(ev_uint16_t)*gapLen);
+ }
+ for (i = 0; i < 8; ++i) {
+ out->s6_addr[2*i ] = words[i] >> 8;
+ out->s6_addr[2*i+1] = words[i] & 0xff;
+ }
+
+ return 1;
+#endif
+ } else {
+ return -1;
+ }
+#endif
+}
+
+int
+evutil_parse_sockaddr_port(const char *ip_as_string, struct sockaddr *out, int *outlen)
+{
+ int port;
+ char buf[128];
+ const char *cp, *addr_part, *port_part;
+ int is_ipv6;
+ /* recognized formats are:
+ * [ipv6]:port
+ * ipv6
+ * [ipv6]
+ * ipv4:port
+ * ipv4
+ */
+
+ cp = strchr(ip_as_string, ':');
+ if (*ip_as_string == '[') {
+ size_t len;
+ if (!(cp = strchr(ip_as_string, ']'))) {
+ return -1;
+ }
+ len = ( cp-(ip_as_string + 1) );
+ if (len > sizeof(buf)-1) {
+ return -1;
+ }
+ memcpy(buf, ip_as_string+1, len);
+ buf[len] = '\0';
+ addr_part = buf;
+ if (cp[1] == ':')
+ port_part = cp+2;
+ else
+ port_part = NULL;
+ is_ipv6 = 1;
+ } else if (cp && strchr(cp+1, ':')) {
+ is_ipv6 = 1;
+ addr_part = ip_as_string;
+ port_part = NULL;
+ } else if (cp) {
+ is_ipv6 = 0;
+ if (cp - ip_as_string > (int)sizeof(buf)-1) {
+ return -1;
+ }
+ memcpy(buf, ip_as_string, cp-ip_as_string);
+ buf[cp-ip_as_string] = '\0';
+ addr_part = buf;
+ port_part = cp+1;
+ } else {
+ addr_part = ip_as_string;
+ port_part = NULL;
+ is_ipv6 = 0;
+ }
+
+ if (port_part == NULL) {
+ port = 0;
+ } else {
+ port = atoi(port_part);
+ if (port <= 0 || port > 65535) {
+ return -1;
+ }
+ }
+
+ if (!addr_part)
+ return -1; /* Should be impossible. */
+#ifdef AF_INET6
+ if (is_ipv6)
+ {
+ struct sockaddr_in6 sin6;
+ memset(&sin6, 0, sizeof(sin6));
+#ifdef EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
+ sin6.sin6_len = sizeof(sin6);
+#endif
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(port);
+ if (1 != evutil_inet_pton(AF_INET6, addr_part, &sin6.sin6_addr))
+ return -1;
+ if ((int)sizeof(sin6) > *outlen)
+ return -1;
+ memset(out, 0, *outlen);
+ memcpy(out, &sin6, sizeof(sin6));
+ *outlen = sizeof(sin6);
+ return 0;
+ }
+ else
+#endif
+ {
+ struct sockaddr_in sin;
+ memset(&sin, 0, sizeof(sin));
+#ifdef EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ sin.sin_len = sizeof(sin);
+#endif
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ if (1 != evutil_inet_pton(AF_INET, addr_part, &sin.sin_addr))
+ return -1;
+ if ((int)sizeof(sin) > *outlen)
+ return -1;
+ memset(out, 0, *outlen);
+ memcpy(out, &sin, sizeof(sin));
+ *outlen = sizeof(sin);
+ return 0;
+ }
+}
+
+const char *
+evutil_format_sockaddr_port_(const struct sockaddr *sa, char *out, size_t outlen)
+{
+ char b[128];
+ const char *res=NULL;
+ int port;
+ if (sa->sa_family == AF_INET) {
+ const struct sockaddr_in *sin = (const struct sockaddr_in*)sa;
+ res = evutil_inet_ntop(AF_INET, &sin->sin_addr,b,sizeof(b));
+ port = ntohs(sin->sin_port);
+ if (res) {
+ evutil_snprintf(out, outlen, "%s:%d", b, port);
+ return out;
+ }
+ } else if (sa->sa_family == AF_INET6) {
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6*)sa;
+ res = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr,b,sizeof(b));
+ port = ntohs(sin6->sin6_port);
+ if (res) {
+ evutil_snprintf(out, outlen, "[%s]:%d", b, port);
+ return out;
+ }
+ }
+
+ evutil_snprintf(out, outlen, "<addr with socktype %d>",
+ (int)sa->sa_family);
+ return out;
+}
+
+int
+evutil_sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2,
+ int include_port)
+{
+ int r;
+ if (0 != (r = (sa1->sa_family - sa2->sa_family)))
+ return r;
+
+ if (sa1->sa_family == AF_INET) {
+ const struct sockaddr_in *sin1, *sin2;
+ sin1 = (const struct sockaddr_in *)sa1;
+ sin2 = (const struct sockaddr_in *)sa2;
+ if (sin1->sin_addr.s_addr < sin2->sin_addr.s_addr)
+ return -1;
+ else if (sin1->sin_addr.s_addr > sin2->sin_addr.s_addr)
+ return 1;
+ else if (include_port &&
+ (r = ((int)sin1->sin_port - (int)sin2->sin_port)))
+ return r;
+ else
+ return 0;
+ }
+#ifdef AF_INET6
+ else if (sa1->sa_family == AF_INET6) {
+ const struct sockaddr_in6 *sin1, *sin2;
+ sin1 = (const struct sockaddr_in6 *)sa1;
+ sin2 = (const struct sockaddr_in6 *)sa2;
+ if ((r = memcmp(sin1->sin6_addr.s6_addr, sin2->sin6_addr.s6_addr, 16)))
+ return r;
+ else if (include_port &&
+ (r = ((int)sin1->sin6_port - (int)sin2->sin6_port)))
+ return r;
+ else
+ return 0;
+ }
+#endif
+ return 1;
+}
+
+/* Tables to implement ctypes-replacement EVUTIL_IS*() functions. Each table
+ * has 256 bits to look up whether a character is in some set or not. This
+ * fails on non-ASCII platforms, but so does every other place where we
+ * take a char and write it onto the network.
+ **/
+static const ev_uint32_t EVUTIL_ISALPHA_TABLE[8] =
+ { 0, 0, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 };
+static const ev_uint32_t EVUTIL_ISALNUM_TABLE[8] =
+ { 0, 0x3ff0000, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 };
+static const ev_uint32_t EVUTIL_ISSPACE_TABLE[8] = { 0x3e00, 0x1, 0, 0, 0, 0, 0, 0 };
+static const ev_uint32_t EVUTIL_ISXDIGIT_TABLE[8] =
+ { 0, 0x3ff0000, 0x7e, 0x7e, 0, 0, 0, 0 };
+static const ev_uint32_t EVUTIL_ISDIGIT_TABLE[8] = { 0, 0x3ff0000, 0, 0, 0, 0, 0, 0 };
+static const ev_uint32_t EVUTIL_ISPRINT_TABLE[8] =
+ { 0, 0xffffffff, 0xffffffff, 0x7fffffff, 0, 0, 0, 0x0 };
+static const ev_uint32_t EVUTIL_ISUPPER_TABLE[8] = { 0, 0, 0x7fffffe, 0, 0, 0, 0, 0 };
+static const ev_uint32_t EVUTIL_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 };
+/* Upper-casing and lowercasing tables to map characters to upper/lowercase
+ * equivalents. */
+static const unsigned char EVUTIL_TOUPPER_TABLE[256] = {
+ 0,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,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,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,195,196,197,198,199,200,201,202,203,204,205,206,207,
+ 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
+ 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
+ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
+};
+static const unsigned char EVUTIL_TOLOWER_TABLE[256] = {
+ 0,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,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,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,195,196,197,198,199,200,201,202,203,204,205,206,207,
+ 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
+ 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
+ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
+};
+
+#define IMPL_CTYPE_FN(name) \
+ int EVUTIL_##name##_(char c) { \
+ ev_uint8_t u = c; \
+ return !!(EVUTIL_##name##_TABLE[(u >> 5) & 7] & (1 << (u & 31))); \
+ }
+IMPL_CTYPE_FN(ISALPHA)
+IMPL_CTYPE_FN(ISALNUM)
+IMPL_CTYPE_FN(ISSPACE)
+IMPL_CTYPE_FN(ISDIGIT)
+IMPL_CTYPE_FN(ISXDIGIT)
+IMPL_CTYPE_FN(ISPRINT)
+IMPL_CTYPE_FN(ISLOWER)
+IMPL_CTYPE_FN(ISUPPER)
+
+char EVUTIL_TOLOWER_(char c)
+{
+ return ((char)EVUTIL_TOLOWER_TABLE[(ev_uint8_t)c]);
+}
+char EVUTIL_TOUPPER_(char c)
+{
+ return ((char)EVUTIL_TOUPPER_TABLE[(ev_uint8_t)c]);
+}
+int
+evutil_ascii_strcasecmp(const char *s1, const char *s2)
+{
+ char c1, c2;
+ while (1) {
+ c1 = EVUTIL_TOLOWER_(*s1++);
+ c2 = EVUTIL_TOLOWER_(*s2++);
+ if (c1 < c2)
+ return -1;
+ else if (c1 > c2)
+ return 1;
+ else if (c1 == 0)
+ return 0;
+ }
+}
+int evutil_ascii_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ char c1, c2;
+ while (n--) {
+ c1 = EVUTIL_TOLOWER_(*s1++);
+ c2 = EVUTIL_TOLOWER_(*s2++);
+ if (c1 < c2)
+ return -1;
+ else if (c1 > c2)
+ return 1;
+ else if (c1 == 0)
+ return 0;
+ }
+ return 0;
+}
+
+void
+evutil_rtrim_lws_(char *str)
+{
+ char *cp;
+
+ if (str == NULL)
+ return;
+
+ if ((cp = strchr(str, '\0')) == NULL || (cp == str))
+ return;
+
+ --cp;
+
+ while (*cp == ' ' || *cp == '\t') {
+ *cp = '\0';
+ if (cp == str)
+ break;
+ --cp;
+ }
+}
+
+static int
+evutil_issetugid(void)
+{
+#ifdef EVENT__HAVE_ISSETUGID
+ return issetugid();
+#else
+
+#ifdef EVENT__HAVE_GETEUID
+ if (getuid() != geteuid())
+ return 1;
+#endif
+#ifdef EVENT__HAVE_GETEGID
+ if (getgid() != getegid())
+ return 1;
+#endif
+ return 0;
+#endif
+}
+
+const char *
+evutil_getenv_(const char *varname)
+{
+ if (evutil_issetugid())
+ return NULL;
+
+ return getenv(varname);
+}
+
+ev_uint32_t
+evutil_weakrand_seed_(struct evutil_weakrand_state *state, ev_uint32_t seed)
+{
+ if (seed == 0) {
+ struct timeval tv;
+ evutil_gettimeofday(&tv, NULL);
+ seed = (ev_uint32_t)tv.tv_sec + (ev_uint32_t)tv.tv_usec;
+#ifdef _WIN32
+ seed += (ev_uint32_t) _getpid();
+#else
+ seed += (ev_uint32_t) getpid();
+#endif
+ }
+ state->seed = seed;
+ return seed;
+}
+
+ev_int32_t
+evutil_weakrand_(struct evutil_weakrand_state *state)
+{
+ /* This RNG implementation is a linear congruential generator, with
+ * modulus 2^31, multiplier 1103515245, and addend 12345. It's also
+ * used by OpenBSD, and by Glibc's TYPE_0 RNG.
+ *
+ * The linear congruential generator is not an industrial-strength
+ * RNG! It's fast, but it can have higher-order patterns. Notably,
+ * the low bits tend to have periodicity.
+ */
+ state->seed = ((state->seed) * 1103515245 + 12345) & 0x7fffffff;
+ return (ev_int32_t)(state->seed);
+}
+
+ev_int32_t
+evutil_weakrand_range_(struct evutil_weakrand_state *state, ev_int32_t top)
+{
+ ev_int32_t divisor, result;
+
+ /* We can't just do weakrand() % top, since the low bits of the LCG
+ * are less random than the high ones. (Specifically, since the LCG
+ * modulus is 2^N, every 2^m for m<N will divide the modulus, and so
+ * therefore the low m bits of the LCG will have period 2^m.) */
+ divisor = EVUTIL_WEAKRAND_MAX / top;
+ do {
+ result = evutil_weakrand_(state) / divisor;
+ } while (result >= top);
+ return result;
+}
+
+/**
+ * Volatile pointer to memset: we use this to keep the compiler from
+ * eliminating our call to memset.
+ */
+void * (*volatile evutil_memset_volatile_)(void *, int, size_t) = memset;
+
+void
+evutil_memclear_(void *mem, size_t len)
+{
+ evutil_memset_volatile_(mem, 0, len);
+}
+
+int
+evutil_sockaddr_is_loopback_(const struct sockaddr *addr)
+{
+ static const char LOOPBACK_S6[16] =
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1";
+ if (addr->sa_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+ return (ntohl(sin->sin_addr.s_addr) & 0xff000000) == 0x7f000000;
+ } else if (addr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
+ return !memcmp(sin6->sin6_addr.s6_addr, LOOPBACK_S6, 16);
+ }
+ return 0;
+}
+
+int
+evutil_hex_char_to_int_(char c)
+{
+ switch(c)
+ {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ case 'A': case 'a': return 10;
+ case 'B': case 'b': return 11;
+ case 'C': case 'c': return 12;
+ case 'D': case 'd': return 13;
+ case 'E': case 'e': return 14;
+ case 'F': case 'f': return 15;
+ }
+ return -1;
+}
+
+#ifdef _WIN32
+HMODULE
+evutil_load_windows_system_library_(const TCHAR *library_name)
+{
+ TCHAR path[MAX_PATH];
+ unsigned n;
+ n = GetSystemDirectory(path, MAX_PATH);
+ if (n == 0 || n + _tcslen(library_name) + 2 >= MAX_PATH)
+ return 0;
+ _tcscat(path, TEXT("\\"));
+ _tcscat(path, library_name);
+ return LoadLibrary(path);
+}
+#endif
+
+/* Internal wrapper around 'socket' to provide Linux-style support for
+ * syscall-saving methods where available.
+ *
+ * In addition to regular socket behavior, you can use a bitwise or to set the
+ * flags EVUTIL_SOCK_NONBLOCK and EVUTIL_SOCK_CLOEXEC in the 'type' argument,
+ * to make the socket nonblocking or close-on-exec with as few syscalls as
+ * possible.
+ */
+evutil_socket_t
+evutil_socket_(int domain, int type, int protocol)
+{
+ evutil_socket_t r;
+#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
+ r = socket(domain, type, protocol);
+ if (r >= 0)
+ return r;
+ else if ((type & (SOCK_NONBLOCK|SOCK_CLOEXEC)) == 0)
+ return -1;
+#endif
+#define SOCKET_TYPE_MASK (~(EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC))
+ r = socket(domain, type & SOCKET_TYPE_MASK, protocol);
+ if (r < 0)
+ return -1;
+ if (type & EVUTIL_SOCK_NONBLOCK) {
+ if (evutil_fast_socket_nonblocking(r) < 0) {
+ evutil_closesocket(r);
+ return -1;
+ }
+ }
+ if (type & EVUTIL_SOCK_CLOEXEC) {
+ if (evutil_fast_socket_closeonexec(r) < 0) {
+ evutil_closesocket(r);
+ return -1;
+ }
+ }
+ return r;
+}
+
+/* Internal wrapper around 'accept' or 'accept4' to provide Linux-style
+ * support for syscall-saving methods where available.
+ *
+ * In addition to regular accept behavior, you can set one or more of flags
+ * EVUTIL_SOCK_NONBLOCK and EVUTIL_SOCK_CLOEXEC in the 'flags' argument, to
+ * make the socket nonblocking or close-on-exec with as few syscalls as
+ * possible.
+ */
+evutil_socket_t
+evutil_accept4_(evutil_socket_t sockfd, struct sockaddr *addr,
+ ev_socklen_t *addrlen, int flags)
+{
+ evutil_socket_t result;
+#if defined(EVENT__HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
+ result = accept4(sockfd, addr, addrlen, flags);
+ if (result >= 0 || (errno != EINVAL && errno != ENOSYS)) {
+ /* A nonnegative result means that we succeeded, so return.
+ * Failing with EINVAL means that an option wasn't supported,
+ * and failing with ENOSYS means that the syscall wasn't
+ * there: in those cases we want to fall back. Otherwise, we
+ * got a real error, and we should return. */
+ return result;
+ }
+#endif
+ result = accept(sockfd, addr, addrlen);
+ if (result < 0)
+ return result;
+
+ if (flags & EVUTIL_SOCK_CLOEXEC) {
+ if (evutil_fast_socket_closeonexec(result) < 0) {
+ evutil_closesocket(result);
+ return -1;
+ }
+ }
+ if (flags & EVUTIL_SOCK_NONBLOCK) {
+ if (evutil_fast_socket_nonblocking(result) < 0) {
+ evutil_closesocket(result);
+ return -1;
+ }
+ }
+ return result;
+}
+
+/* Internal function: Set fd[0] and fd[1] to a pair of fds such that writes on
+ * fd[0] get read from fd[1]. Make both fds nonblocking and close-on-exec.
+ * Return 0 on success, -1 on failure.
+ */
+int
+evutil_make_internal_pipe_(evutil_socket_t fd[2])
+{
+ /*
+ Making the second socket nonblocking is a bit subtle, given that we
+ ignore any EAGAIN returns when writing to it, and you don't usally
+ do that for a nonblocking socket. But if the kernel gives us EAGAIN,
+ then there's no need to add any more data to the buffer, since
+ the main thread is already either about to wake up and drain it,
+ or woken up and in the process of draining it.
+ */
+
+#if defined(EVENT__HAVE_PIPE2)
+ if (pipe2(fd, O_NONBLOCK|O_CLOEXEC) == 0)
+ return 0;
+#endif
+#if defined(EVENT__HAVE_PIPE)
+ if (pipe(fd) == 0) {
+ if (evutil_fast_socket_nonblocking(fd[0]) < 0 ||
+ evutil_fast_socket_nonblocking(fd[1]) < 0 ||
+ evutil_fast_socket_closeonexec(fd[0]) < 0 ||
+ evutil_fast_socket_closeonexec(fd[1]) < 0) {
+ close(fd[0]);
+ close(fd[1]);
+ fd[0] = fd[1] = -1;
+ return -1;
+ }
+ return 0;
+ } else {
+ event_warn("%s: pipe", __func__);
+ }
+#endif
+
+#ifdef _WIN32
+#define LOCAL_SOCKETPAIR_AF AF_INET
+#else
+#define LOCAL_SOCKETPAIR_AF AF_UNIX
+#endif
+ if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, fd) == 0) {
+ if (evutil_fast_socket_nonblocking(fd[0]) < 0 ||
+ evutil_fast_socket_nonblocking(fd[1]) < 0 ||
+ evutil_fast_socket_closeonexec(fd[0]) < 0 ||
+ evutil_fast_socket_closeonexec(fd[1]) < 0) {
+ evutil_closesocket(fd[0]);
+ evutil_closesocket(fd[1]);
+ fd[0] = fd[1] = -1;
+ return -1;
+ }
+ return 0;
+ }
+ fd[0] = fd[1] = -1;
+ return -1;
+}
+
+/* Wrapper around eventfd on systems that provide it. Unlike the system
+ * eventfd, it always supports EVUTIL_EFD_CLOEXEC and EVUTIL_EFD_NONBLOCK as
+ * flags. Returns -1 on error or if eventfd is not supported.
+ */
+evutil_socket_t
+evutil_eventfd_(unsigned initval, int flags)
+{
+#if defined(EVENT__HAVE_EVENTFD) && defined(EVENT__HAVE_SYS_EVENTFD_H)
+ int r;
+#if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
+ r = eventfd(initval, flags);
+ if (r >= 0 || flags == 0)
+ return r;
+#endif
+ r = eventfd(initval, 0);
+ if (r < 0)
+ return r;
+ if (flags & EVUTIL_EFD_CLOEXEC) {
+ if (evutil_fast_socket_closeonexec(r) < 0) {
+ evutil_closesocket(r);
+ return -1;
+ }
+ }
+ if (flags & EVUTIL_EFD_NONBLOCK) {
+ if (evutil_fast_socket_nonblocking(r) < 0) {
+ evutil_closesocket(r);
+ return -1;
+ }
+ }
+ return r;
+#else
+ return -1;
+#endif
+}
+
+void
+evutil_free_globals_(void)
+{
+ evutil_free_secure_rng_globals_();
+ evutil_free_sock_err_globals();
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evutil_rand.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/evutil_rand.c
new file mode 100644
index 000000000..046a14b07
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evutil_rand.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* This file has our secure PRNG code. On platforms that have arc4random(),
+ * we just use that. Otherwise, we include arc4random.c as a bunch of static
+ * functions, and wrap it lightly. We don't expose the arc4random*() APIs
+ * because A) they aren't in our namespace, and B) it's not nice to name your
+ * APIs after their implementations. We keep them in a separate file
+ * so that other people can rip it out and use it for whatever.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <limits.h>
+
+#include "util-internal.h"
+#include "evthread-internal.h"
+
+#ifdef EVENT__HAVE_ARC4RANDOM
+#include <stdlib.h>
+#include <string.h>
+int
+evutil_secure_rng_set_urandom_device_file(char *fname)
+{
+ (void) fname;
+ return -1;
+}
+int
+evutil_secure_rng_init(void)
+{
+ /* call arc4random() now to force it to self-initialize */
+ (void) arc4random();
+ return 0;
+}
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+int
+evutil_secure_rng_global_setup_locks_(const int enable_locks)
+{
+ return 0;
+}
+#endif
+static void
+evutil_free_secure_rng_globals_locks(void)
+{
+}
+
+static void
+ev_arc4random_buf(void *buf, size_t n)
+{
+#if defined(EVENT__HAVE_ARC4RANDOM_BUF) && !defined(__APPLE__)
+ arc4random_buf(buf, n);
+ return;
+#else
+ unsigned char *b = buf;
+
+#if defined(EVENT__HAVE_ARC4RANDOM_BUF)
+ /* OSX 10.7 introducd arc4random_buf, so if you build your program
+ * there, you'll get surprised when older versions of OSX fail to run.
+ * To solve this, we can check whether the function pointer is set,
+ * and fall back otherwise. (OSX does this using some linker
+ * trickery.)
+ */
+ {
+ void (*tptr)(void *,size_t) =
+ (void (*)(void*,size_t))arc4random_buf;
+ if (tptr != NULL) {
+ arc4random_buf(buf, n);
+ return;
+ }
+ }
+#endif
+ /* Make sure that we start out with b at a 4-byte alignment; plenty
+ * of CPUs care about this for 32-bit access. */
+ if (n >= 4 && ((ev_uintptr_t)b) & 3) {
+ ev_uint32_t u = arc4random();
+ int n_bytes = 4 - (((ev_uintptr_t)b) & 3);
+ memcpy(b, &u, n_bytes);
+ b += n_bytes;
+ n -= n_bytes;
+ }
+ while (n >= 4) {
+ *(ev_uint32_t*)b = arc4random();
+ b += 4;
+ n -= 4;
+ }
+ if (n) {
+ ev_uint32_t u = arc4random();
+ memcpy(b, &u, n);
+ }
+#endif
+}
+
+#else /* !EVENT__HAVE_ARC4RANDOM { */
+
+#ifdef EVENT__ssize_t
+#define ssize_t EVENT__ssize_t
+#endif
+#define ARC4RANDOM_EXPORT static
+#define ARC4_LOCK_() EVLOCK_LOCK(arc4rand_lock, 0)
+#define ARC4_UNLOCK_() EVLOCK_UNLOCK(arc4rand_lock, 0)
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+static void *arc4rand_lock;
+#endif
+
+#define ARC4RANDOM_UINT32 ev_uint32_t
+#define ARC4RANDOM_NOSTIR
+#define ARC4RANDOM_NORANDOM
+#define ARC4RANDOM_NOUNIFORM
+
+#include "./arc4random.c"
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+int
+evutil_secure_rng_global_setup_locks_(const int enable_locks)
+{
+ EVTHREAD_SETUP_GLOBAL_LOCK(arc4rand_lock, 0);
+ return 0;
+}
+#endif
+
+static void
+evutil_free_secure_rng_globals_locks(void)
+{
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ if (arc4rand_lock != NULL) {
+ EVTHREAD_FREE_LOCK(arc4rand_lock, 0);
+ arc4rand_lock = NULL;
+ }
+#endif
+ return;
+}
+
+int
+evutil_secure_rng_set_urandom_device_file(char *fname)
+{
+#ifdef TRY_SEED_URANDOM
+ ARC4_LOCK_();
+ arc4random_urandom_filename = fname;
+ ARC4_UNLOCK_();
+#endif
+ return 0;
+}
+
+int
+evutil_secure_rng_init(void)
+{
+ int val;
+
+ ARC4_LOCK_();
+ if (!arc4_seeded_ok)
+ arc4_stir();
+ val = arc4_seeded_ok ? 0 : -1;
+ ARC4_UNLOCK_();
+ return val;
+}
+
+static void
+ev_arc4random_buf(void *buf, size_t n)
+{
+ arc4random_buf(buf, n);
+}
+
+#endif /* } !EVENT__HAVE_ARC4RANDOM */
+
+void
+evutil_secure_rng_get_bytes(void *buf, size_t n)
+{
+ ev_arc4random_buf(buf, n);
+}
+
+void
+evutil_secure_rng_add_bytes(const char *buf, size_t n)
+{
+ arc4random_addrandom((unsigned char*)buf,
+ n>(size_t)INT_MAX ? INT_MAX : (int)n);
+}
+
+void
+evutil_free_secure_rng_globals_(void)
+{
+ evutil_free_secure_rng_globals_locks();
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/evutil_time.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/evutil_time.c
new file mode 100644
index 000000000..3a8424ea3
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/evutil_time.c
@@ -0,0 +1,573 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+
+#include <sys/types.h>
+#ifdef EVENT__HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <errno.h>
+#include <limits.h>
+#ifndef EVENT__HAVE_GETTIMEOFDAY
+#include <sys/timeb.h>
+#endif
+#if !defined(EVENT__HAVE_NANOSLEEP) && !defined(EVENT_HAVE_USLEEP) && \
+ !defined(_WIN32)
+#include <sys/select.h>
+#endif
+#include <time.h>
+#include <sys/stat.h>
+#include <string.h>
+
+/** evutil_usleep_() */
+#if defined(_WIN32)
+#elif defined(EVENT__HAVE_NANOSLEEP)
+#elif defined(EVENT__HAVE_USLEEP)
+#include <unistd.h>
+#endif
+
+#include "event2/util.h"
+#include "util-internal.h"
+#include "log-internal.h"
+#include "mm-internal.h"
+
+#ifndef EVENT__HAVE_GETTIMEOFDAY
+/* No gettimeofday; this must be windows. */
+int
+evutil_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+#ifdef _MSC_VER
+#define U64_LITERAL(n) n##ui64
+#else
+#define U64_LITERAL(n) n##llu
+#endif
+
+ /* Conversion logic taken from Tor, which in turn took it
+ * from Perl. GetSystemTimeAsFileTime returns its value as
+ * an unaligned (!) 64-bit value containing the number of
+ * 100-nanosecond intervals since 1 January 1601 UTC. */
+#define EPOCH_BIAS U64_LITERAL(116444736000000000)
+#define UNITS_PER_SEC U64_LITERAL(10000000)
+#define USEC_PER_SEC U64_LITERAL(1000000)
+#define UNITS_PER_USEC U64_LITERAL(10)
+ union {
+ FILETIME ft_ft;
+ ev_uint64_t ft_64;
+ } ft;
+
+ if (tv == NULL)
+ return -1;
+
+ GetSystemTimeAsFileTime(&ft.ft_ft);
+
+ if (EVUTIL_UNLIKELY(ft.ft_64 < EPOCH_BIAS)) {
+ /* Time before the unix epoch. */
+ return -1;
+ }
+ ft.ft_64 -= EPOCH_BIAS;
+ tv->tv_sec = (long) (ft.ft_64 / UNITS_PER_SEC);
+ tv->tv_usec = (long) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC);
+ return 0;
+}
+#endif
+
+#define MAX_SECONDS_IN_MSEC_LONG \
+ (((LONG_MAX) - 999) / 1000)
+
+long
+evutil_tv_to_msec_(const struct timeval *tv)
+{
+ if (tv->tv_usec > 1000000 || tv->tv_sec > MAX_SECONDS_IN_MSEC_LONG)
+ return -1;
+
+ return (tv->tv_sec * 1000) + ((tv->tv_usec + 999) / 1000);
+}
+
+/*
+ Replacement for usleep on platforms that don't have one. Not guaranteed to
+ be any more finegrained than 1 msec.
+ */
+void
+evutil_usleep_(const struct timeval *tv)
+{
+ if (!tv)
+ return;
+#if defined(_WIN32)
+ {
+ long msec = evutil_tv_to_msec_(tv);
+ Sleep((DWORD)msec);
+ }
+#elif defined(EVENT__HAVE_NANOSLEEP)
+ {
+ struct timespec ts;
+ ts.tv_sec = tv->tv_sec;
+ ts.tv_nsec = tv->tv_usec*1000;
+ nanosleep(&ts, NULL);
+ }
+#elif defined(EVENT__HAVE_USLEEP)
+ /* Some systems don't like to usleep more than 999999 usec */
+ sleep(tv->tv_sec);
+ usleep(tv->tv_usec);
+#else
+ select(0, NULL, NULL, NULL, tv);
+#endif
+}
+
+int
+evutil_date_rfc1123(char *date, const size_t datelen, struct tm *cur_p) {
+ static const char *DAYS[] =
+ { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+ static const char *MONTHS[] =
+ { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+ time_t t = time(NULL);
+
+ /* If `cur_p` is null, set system's current time. */
+ if (cur_p == NULL) {
+#ifdef _WIN32
+ cur_p = gmtime(&t);
+#else
+ {
+ struct tm cur;
+ gmtime_r(&t, &cur);
+ cur_p = &cur;
+ }
+#endif
+ }
+
+ return evutil_snprintf(
+ date, datelen, "%s, %02d %s %4d %02d:%02d:%02d GMT",
+ DAYS[cur_p->tm_wday], cur_p->tm_mday, MONTHS[cur_p->tm_mon],
+ 1900+cur_p->tm_year, cur_p->tm_hour, cur_p->tm_min, cur_p->tm_sec);
+}
+
+/*
+ This function assumes it's called repeatedly with a
+ not-actually-so-monotonic time source whose outputs are in 'tv'. It
+ implements a trivial ratcheting mechanism so that the values never go
+ backwards.
+ */
+static void
+adjust_monotonic_time(struct evutil_monotonic_timer *base,
+ struct timeval *tv)
+{
+ evutil_timeradd(tv, &base->adjust_monotonic_clock, tv);
+
+ if (evutil_timercmp(tv, &base->last_time, <)) {
+ /* Guess it wasn't monotonic after all. */
+ struct timeval adjust;
+ evutil_timersub(&base->last_time, tv, &adjust);
+ evutil_timeradd(&adjust, &base->adjust_monotonic_clock,
+ &base->adjust_monotonic_clock);
+ *tv = base->last_time;
+ }
+ base->last_time = *tv;
+}
+
+/*
+ Allocate a new struct evutil_monotonic_timer
+ */
+struct evutil_monotonic_timer *
+evutil_monotonic_timer_new(void)
+{
+ struct evutil_monotonic_timer *p = NULL;
+
+ p = mm_malloc(sizeof(*p));
+ if (!p) goto done;
+
+ memset(p, 0, sizeof(*p));
+
+ done:
+ return p;
+}
+
+/*
+ Free a struct evutil_monotonic_timer
+ */
+void
+evutil_monotonic_timer_free(struct evutil_monotonic_timer *timer)
+{
+ if (timer) {
+ mm_free(timer);
+ }
+}
+
+/*
+ Set up a struct evutil_monotonic_timer for initial use
+ */
+int
+evutil_configure_monotonic_time(struct evutil_monotonic_timer *timer,
+ int flags)
+{
+ return evutil_configure_monotonic_time_(timer, flags);
+}
+
+/*
+ Query the current monotonic time
+ */
+int
+evutil_gettime_monotonic(struct evutil_monotonic_timer *timer,
+ struct timeval *tp)
+{
+ return evutil_gettime_monotonic_(timer, tp);
+}
+
+
+#if defined(HAVE_POSIX_MONOTONIC)
+/* =====
+ The POSIX clock_gettime() interface provides a few ways to get at a
+ monotonic clock. CLOCK_MONOTONIC is most widely supported. Linux also
+ provides a CLOCK_MONOTONIC_COARSE with accuracy of about 1-4 msec.
+
+ On all platforms I'm aware of, CLOCK_MONOTONIC really is monotonic.
+ Platforms don't agree about whether it should jump on a sleep/resume.
+ */
+
+int
+evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
+ int flags)
+{
+ /* CLOCK_MONOTONIC exists on FreeBSD, Linux, and Solaris. You need to
+ * check for it at runtime, because some older kernel versions won't
+ * have it working. */
+#ifdef CLOCK_MONOTONIC_COARSE
+ const int precise = flags & EV_MONOT_PRECISE;
+#endif
+ const int fallback = flags & EV_MONOT_FALLBACK;
+ struct timespec ts;
+
+#ifdef CLOCK_MONOTONIC_COARSE
+ if (CLOCK_MONOTONIC_COARSE < 0) {
+ /* Technically speaking, nothing keeps CLOCK_* from being
+ * negative (as far as I know). This check and the one below
+ * make sure that it's safe for us to use -1 as an "unset"
+ * value. */
+ event_errx(1,"I didn't expect CLOCK_MONOTONIC_COARSE to be < 0");
+ }
+ if (! precise && ! fallback) {
+ if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0) {
+ base->monotonic_clock = CLOCK_MONOTONIC_COARSE;
+ return 0;
+ }
+ }
+#endif
+ if (!fallback && clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ base->monotonic_clock = CLOCK_MONOTONIC;
+ return 0;
+ }
+
+ if (CLOCK_MONOTONIC < 0) {
+ event_errx(1,"I didn't expect CLOCK_MONOTONIC to be < 0");
+ }
+
+ base->monotonic_clock = -1;
+ return 0;
+}
+
+int
+evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
+ struct timeval *tp)
+{
+ struct timespec ts;
+
+ if (base->monotonic_clock < 0) {
+ if (evutil_gettimeofday(tp, NULL) < 0)
+ return -1;
+ adjust_monotonic_time(base, tp);
+ return 0;
+ }
+
+ if (clock_gettime(base->monotonic_clock, &ts) == -1)
+ return -1;
+ tp->tv_sec = ts.tv_sec;
+ tp->tv_usec = ts.tv_nsec / 1000;
+
+ return 0;
+}
+#endif
+
+#if defined(HAVE_MACH_MONOTONIC)
+/* ======
+ Apple is a little late to the POSIX party. And why not? Instead of
+ clock_gettime(), they provide mach_absolute_time(). Its units are not
+ fixed; we need to use mach_timebase_info() to get the right functions to
+ convert its units into nanoseconds.
+
+ To all appearances, mach_absolute_time() seems to be honest-to-goodness
+ monotonic. Whether it stops during sleep or not is unspecified in
+ principle, and dependent on CPU architecture in practice.
+ */
+
+int
+evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
+ int flags)
+{
+ const int fallback = flags & EV_MONOT_FALLBACK;
+ struct mach_timebase_info mi;
+ memset(base, 0, sizeof(*base));
+ /* OSX has mach_absolute_time() */
+ if (!fallback &&
+ mach_timebase_info(&mi) == 0 &&
+ mach_absolute_time() != 0) {
+ /* mach_timebase_info tells us how to convert
+ * mach_absolute_time() into nanoseconds, but we
+ * want to use microseconds instead. */
+ mi.denom *= 1000;
+ memcpy(&base->mach_timebase_units, &mi, sizeof(mi));
+ } else {
+ base->mach_timebase_units.numer = 0;
+ }
+ return 0;
+}
+
+int
+evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
+ struct timeval *tp)
+{
+ ev_uint64_t abstime, usec;
+ if (base->mach_timebase_units.numer == 0) {
+ if (evutil_gettimeofday(tp, NULL) < 0)
+ return -1;
+ adjust_monotonic_time(base, tp);
+ return 0;
+ }
+
+ abstime = mach_absolute_time();
+ usec = (abstime * base->mach_timebase_units.numer)
+ / (base->mach_timebase_units.denom);
+ tp->tv_sec = usec / 1000000;
+ tp->tv_usec = usec % 1000000;
+
+ return 0;
+}
+#endif
+
+#if defined(HAVE_WIN32_MONOTONIC)
+/* =====
+ Turn we now to Windows. Want monontonic time on Windows?
+
+ Windows has QueryPerformanceCounter(), which gives time most high-
+ resolution time. It's a pity it's not so monotonic in practice; it's
+ also got some fun bugs, especially: with older Windowses, under
+ virtualizations, with funny hardware, on multiprocessor systems, and so
+ on. PEP418 [1] has a nice roundup of the issues here.
+
+ There's GetTickCount64() on Vista and later, which gives a number of 1-msec
+ ticks since startup. The accuracy here might be as bad as 10-20 msec, I
+ hear. There's an undocumented function (NtSetTimerResolution) that
+ allegedly increases the accuracy. Good luck!
+
+ There's also GetTickCount(), which is only 32 bits, but seems to be
+ supported on pre-Vista versions of Windows. Apparently, you can coax
+ another 14 bits out of it, giving you 2231 years before rollover.
+
+ The less said about timeGetTime() the better.
+
+ "We don't care. We don't have to. We're the Phone Company."
+ -- Lily Tomlin, SNL
+
+ Our strategy, if precise timers are turned off, is to just use the best
+ GetTickCount equivalent available. If we've been asked for precise timing,
+ then we mostly[2] assume that GetTickCount is monotonic, and correct
+ GetPerformanceCounter to approximate it.
+
+ [1] http://www.python.org/dev/peps/pep-0418
+ [2] Of course, we feed the Windows stuff into adjust_monotonic_time()
+ anyway, just in case it isn't.
+
+ */
+/*
+ Parts of our logic in the win32 timer code here are closely based on
+ BitTorrent's libUTP library. That code is subject to the following
+ license:
+
+ Copyright (c) 2010 BitTorrent, Inc.
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+static ev_uint64_t
+evutil_GetTickCount_(struct evutil_monotonic_timer *base)
+{
+ if (base->GetTickCount64_fn) {
+ /* Let's just use GetTickCount64 if we can. */
+ return base->GetTickCount64_fn();
+ } else if (base->GetTickCount_fn) {
+ /* Greg Hazel assures me that this works, that BitTorrent has
+ * done it for years, and this it won't turn around and
+ * bite us. He says they found it on some game programmers'
+ * forum some time around 2007.
+ */
+ ev_uint64_t v = base->GetTickCount_fn();
+ return (DWORD)v | ((v >> 18) & 0xFFFFFFFF00000000);
+ } else {
+ /* Here's the fallback implementation. We have to use
+ * GetTickCount() with its given signature, so we only get
+ * 32 bits worth of milliseconds, which will roll ove every
+ * 49 days or so. */
+ DWORD ticks = GetTickCount();
+ if (ticks < base->last_tick_count) {
+ base->adjust_tick_count += ((ev_uint64_t)1) << 32;
+ }
+ base->last_tick_count = ticks;
+ return ticks + base->adjust_tick_count;
+ }
+}
+
+int
+evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
+ int flags)
+{
+ const int precise = flags & EV_MONOT_PRECISE;
+ const int fallback = flags & EV_MONOT_FALLBACK;
+ HANDLE h;
+ memset(base, 0, sizeof(*base));
+
+ h = evutil_load_windows_system_library_(TEXT("kernel32.dll"));
+ if (h != NULL && !fallback) {
+ base->GetTickCount64_fn = (ev_GetTickCount_func)GetProcAddress(h, "GetTickCount64");
+ base->GetTickCount_fn = (ev_GetTickCount_func)GetProcAddress(h, "GetTickCount");
+ }
+
+ base->first_tick = base->last_tick_count = evutil_GetTickCount_(base);
+ if (precise && !fallback) {
+ LARGE_INTEGER freq;
+ if (QueryPerformanceFrequency(&freq)) {
+ LARGE_INTEGER counter;
+ QueryPerformanceCounter(&counter);
+ base->first_counter = counter.QuadPart;
+ base->usec_per_count = 1.0e6 / freq.QuadPart;
+ base->use_performance_counter = 1;
+ }
+ }
+
+ return 0;
+}
+
+static inline ev_int64_t
+abs64(ev_int64_t i)
+{
+ return i < 0 ? -i : i;
+}
+
+
+int
+evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
+ struct timeval *tp)
+{
+ ev_uint64_t ticks = evutil_GetTickCount_(base);
+ if (base->use_performance_counter) {
+ /* Here's a trick we took from BitTorrent's libutp, at Greg
+ * Hazel's recommendation. We use QueryPerformanceCounter for
+ * our high-resolution timer, but use GetTickCount*() to keep
+ * it sane, and adjust_monotonic_time() to keep it monotonic.
+ */
+ LARGE_INTEGER counter;
+ ev_int64_t counter_elapsed, counter_usec_elapsed, ticks_elapsed;
+ QueryPerformanceCounter(&counter);
+ counter_elapsed = (ev_int64_t)
+ (counter.QuadPart - base->first_counter);
+ ticks_elapsed = ticks - base->first_tick;
+ /* TODO: This may upset VC6. If you need this to work with
+ * VC6, please supply an appropriate patch. */
+ counter_usec_elapsed = (ev_int64_t)
+ (counter_elapsed * base->usec_per_count);
+
+ if (abs64(ticks_elapsed*1000 - counter_usec_elapsed) > 1000000) {
+ /* It appears that the QueryPerformanceCounter()
+ * result is more than 1 second away from
+ * GetTickCount() result. Let's adjust it to be as
+ * accurate as we can; adjust_monotnonic_time() below
+ * will keep it monotonic. */
+ counter_usec_elapsed = ticks_elapsed * 1000;
+ base->first_counter = (ev_uint64_t) (counter.QuadPart - counter_usec_elapsed / base->usec_per_count);
+ }
+ tp->tv_sec = (time_t) (counter_usec_elapsed / 1000000);
+ tp->tv_usec = counter_usec_elapsed % 1000000;
+
+ } else {
+ /* We're just using GetTickCount(). */
+ tp->tv_sec = (time_t) (ticks / 1000);
+ tp->tv_usec = (ticks % 1000) * 1000;
+ }
+ adjust_monotonic_time(base, tp);
+
+ return 0;
+}
+#endif
+
+#if defined(HAVE_FALLBACK_MONOTONIC)
+/* =====
+ And if none of the other options work, let's just use gettimeofday(), and
+ ratchet it forward so that it acts like a monotonic timer, whether it
+ wants to or not.
+ */
+
+int
+evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
+ int precise)
+{
+ memset(base, 0, sizeof(*base));
+ return 0;
+}
+
+int
+evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
+ struct timeval *tp)
+{
+ if (evutil_gettimeofday(tp, NULL) < 0)
+ return -1;
+ adjust_monotonic_time(base, tp);
+ return 0;
+
+}
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/ht-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/ht-internal.h
new file mode 100644
index 000000000..50375bbaa
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/ht-internal.h
@@ -0,0 +1,487 @@
+/* Copyright 2002 Christopher Clark */
+/* Copyright 2005-2012 Nick Mathewson */
+/* Copyright 2009-2012 Niels Provos and Nick Mathewson */
+/* See license at end. */
+
+/* Based on ideas by Christopher Clark and interfaces from Niels Provos. */
+
+#ifndef HT_INTERNAL_H_INCLUDED_
+#define HT_INTERNAL_H_INCLUDED_
+
+#define HT_HEAD(name, type) \
+ struct name { \
+ /* The hash table itself. */ \
+ struct type **hth_table; \
+ /* How long is the hash table? */ \
+ unsigned hth_table_length; \
+ /* How many elements does the table contain? */ \
+ unsigned hth_n_entries; \
+ /* How many elements will we allow in the table before resizing it? */ \
+ unsigned hth_load_limit; \
+ /* Position of hth_table_length in the primes table. */ \
+ int hth_prime_idx; \
+ }
+
+#define HT_INITIALIZER() \
+ { NULL, 0, 0, 0, -1 }
+
+#ifdef HT_NO_CACHE_HASH_VALUES
+#define HT_ENTRY(type) \
+ struct { \
+ struct type *hte_next; \
+ }
+#else
+#define HT_ENTRY(type) \
+ struct { \
+ struct type *hte_next; \
+ unsigned hte_hash; \
+ }
+#endif
+
+#define HT_EMPTY(head) \
+ ((head)->hth_n_entries == 0)
+
+/* How many elements in 'head'? */
+#define HT_SIZE(head) \
+ ((head)->hth_n_entries)
+
+/* Return memory usage for a hashtable (not counting the entries themselves) */
+#define HT_MEM_USAGE(head) \
+ (sizeof(*head) + (head)->hth_table_length * sizeof(void*))
+
+#define HT_FIND(name, head, elm) name##_HT_FIND((head), (elm))
+#define HT_INSERT(name, head, elm) name##_HT_INSERT((head), (elm))
+#define HT_REPLACE(name, head, elm) name##_HT_REPLACE((head), (elm))
+#define HT_REMOVE(name, head, elm) name##_HT_REMOVE((head), (elm))
+#define HT_START(name, head) name##_HT_START(head)
+#define HT_NEXT(name, head, elm) name##_HT_NEXT((head), (elm))
+#define HT_NEXT_RMV(name, head, elm) name##_HT_NEXT_RMV((head), (elm))
+#define HT_CLEAR(name, head) name##_HT_CLEAR(head)
+#define HT_INIT(name, head) name##_HT_INIT(head)
+/* Helper: */
+static inline unsigned
+ht_improve_hash_(unsigned h)
+{
+ /* Aim to protect against poor hash functions by adding logic here
+ * - logic taken from java 1.4 hashtable source */
+ h += ~(h << 9);
+ h ^= ((h >> 14) | (h << 18)); /* >>> */
+ h += (h << 4);
+ h ^= ((h >> 10) | (h << 22)); /* >>> */
+ return h;
+}
+
+#if 0
+/** Basic string hash function, from Java standard String.hashCode(). */
+static inline unsigned
+ht_string_hash_(const char *s)
+{
+ unsigned h = 0;
+ int m = 1;
+ while (*s) {
+ h += ((signed char)*s++)*m;
+ m = (m<<5)-1; /* m *= 31 */
+ }
+ return h;
+}
+#endif
+
+/** Basic string hash function, from Python's str.__hash__() */
+static inline unsigned
+ht_string_hash_(const char *s)
+{
+ unsigned h;
+ const unsigned char *cp = (const unsigned char *)s;
+ h = *cp << 7;
+ while (*cp) {
+ h = (1000003*h) ^ *cp++;
+ }
+ /* This conversion truncates the length of the string, but that's ok. */
+ h ^= (unsigned)(cp-(const unsigned char*)s);
+ return h;
+}
+
+#ifndef HT_NO_CACHE_HASH_VALUES
+#define HT_SET_HASH_(elm, field, hashfn) \
+ do { (elm)->field.hte_hash = hashfn(elm); } while (0)
+#define HT_SET_HASHVAL_(elm, field, val) \
+ do { (elm)->field.hte_hash = (val); } while (0)
+#define HT_ELT_HASH_(elm, field, hashfn) \
+ ((elm)->field.hte_hash)
+#else
+#define HT_SET_HASH_(elm, field, hashfn) \
+ ((void)0)
+#define HT_ELT_HASH_(elm, field, hashfn) \
+ (hashfn(elm))
+#define HT_SET_HASHVAL_(elm, field, val) \
+ ((void)0)
+#endif
+
+/* Helper: alias for the bucket containing 'elm'. */
+#define HT_BUCKET_(head, field, elm, hashfn) \
+ ((head)->hth_table[HT_ELT_HASH_(elm,field,hashfn) % head->hth_table_length])
+
+#define HT_FOREACH(x, name, head) \
+ for ((x) = HT_START(name, head); \
+ (x) != NULL; \
+ (x) = HT_NEXT(name, head, x))
+
+#define HT_PROTOTYPE(name, type, field, hashfn, eqfn) \
+ int name##_HT_GROW(struct name *ht, unsigned min_capacity); \
+ void name##_HT_CLEAR(struct name *ht); \
+ int name##_HT_REP_IS_BAD_(const struct name *ht); \
+ static inline void \
+ name##_HT_INIT(struct name *head) { \
+ head->hth_table_length = 0; \
+ head->hth_table = NULL; \
+ head->hth_n_entries = 0; \
+ head->hth_load_limit = 0; \
+ head->hth_prime_idx = -1; \
+ } \
+ /* Helper: returns a pointer to the right location in the table \
+ * 'head' to find or insert the element 'elm'. */ \
+ static inline struct type ** \
+ name##_HT_FIND_P_(struct name *head, struct type *elm) \
+ { \
+ struct type **p; \
+ if (!head->hth_table) \
+ return NULL; \
+ p = &HT_BUCKET_(head, field, elm, hashfn); \
+ while (*p) { \
+ if (eqfn(*p, elm)) \
+ return p; \
+ p = &(*p)->field.hte_next; \
+ } \
+ return p; \
+ } \
+ /* Return a pointer to the element in the table 'head' matching 'elm', \
+ * or NULL if no such element exists */ \
+ static inline struct type * \
+ name##_HT_FIND(const struct name *head, struct type *elm) \
+ { \
+ struct type **p; \
+ struct name *h = (struct name *) head; \
+ HT_SET_HASH_(elm, field, hashfn); \
+ p = name##_HT_FIND_P_(h, elm); \
+ return p ? *p : NULL; \
+ } \
+ /* Insert the element 'elm' into the table 'head'. Do not call this \
+ * function if the table might already contain a matching element. */ \
+ static inline void \
+ name##_HT_INSERT(struct name *head, struct type *elm) \
+ { \
+ struct type **p; \
+ if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
+ name##_HT_GROW(head, head->hth_n_entries+1); \
+ ++head->hth_n_entries; \
+ HT_SET_HASH_(elm, field, hashfn); \
+ p = &HT_BUCKET_(head, field, elm, hashfn); \
+ elm->field.hte_next = *p; \
+ *p = elm; \
+ } \
+ /* Insert the element 'elm' into the table 'head'. If there already \
+ * a matching element in the table, replace that element and return \
+ * it. */ \
+ static inline struct type * \
+ name##_HT_REPLACE(struct name *head, struct type *elm) \
+ { \
+ struct type **p, *r; \
+ if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
+ name##_HT_GROW(head, head->hth_n_entries+1); \
+ HT_SET_HASH_(elm, field, hashfn); \
+ p = name##_HT_FIND_P_(head, elm); \
+ r = *p; \
+ *p = elm; \
+ if (r && (r!=elm)) { \
+ elm->field.hte_next = r->field.hte_next; \
+ r->field.hte_next = NULL; \
+ return r; \
+ } else { \
+ ++head->hth_n_entries; \
+ return NULL; \
+ } \
+ } \
+ /* Remove any element matching 'elm' from the table 'head'. If such \
+ * an element is found, return it; otherwise return NULL. */ \
+ static inline struct type * \
+ name##_HT_REMOVE(struct name *head, struct type *elm) \
+ { \
+ struct type **p, *r; \
+ HT_SET_HASH_(elm, field, hashfn); \
+ p = name##_HT_FIND_P_(head,elm); \
+ if (!p || !*p) \
+ return NULL; \
+ r = *p; \
+ *p = r->field.hte_next; \
+ r->field.hte_next = NULL; \
+ --head->hth_n_entries; \
+ return r; \
+ } \
+ /* Invoke the function 'fn' on every element of the table 'head', \
+ * using 'data' as its second argument. If the function returns \
+ * nonzero, remove the most recently examined element before invoking \
+ * the function again. */ \
+ static inline void \
+ name##_HT_FOREACH_FN(struct name *head, \
+ int (*fn)(struct type *, void *), \
+ void *data) \
+ { \
+ unsigned idx; \
+ struct type **p, **nextp, *next; \
+ if (!head->hth_table) \
+ return; \
+ for (idx=0; idx < head->hth_table_length; ++idx) { \
+ p = &head->hth_table[idx]; \
+ while (*p) { \
+ nextp = &(*p)->field.hte_next; \
+ next = *nextp; \
+ if (fn(*p, data)) { \
+ --head->hth_n_entries; \
+ *p = next; \
+ } else { \
+ p = nextp; \
+ } \
+ } \
+ } \
+ } \
+ /* Return a pointer to the first element in the table 'head', under \
+ * an arbitrary order. This order is stable under remove operations, \
+ * but not under others. If the table is empty, return NULL. */ \
+ static inline struct type ** \
+ name##_HT_START(struct name *head) \
+ { \
+ unsigned b = 0; \
+ while (b < head->hth_table_length) { \
+ if (head->hth_table[b]) \
+ return &head->hth_table[b]; \
+ ++b; \
+ } \
+ return NULL; \
+ } \
+ /* Return the next element in 'head' after 'elm', under the arbitrary \
+ * order used by HT_START. If there are no more elements, return \
+ * NULL. If 'elm' is to be removed from the table, you must call \
+ * this function for the next value before you remove it. \
+ */ \
+ static inline struct type ** \
+ name##_HT_NEXT(struct name *head, struct type **elm) \
+ { \
+ if ((*elm)->field.hte_next) { \
+ return &(*elm)->field.hte_next; \
+ } else { \
+ unsigned b = (HT_ELT_HASH_(*elm, field, hashfn) % head->hth_table_length)+1; \
+ while (b < head->hth_table_length) { \
+ if (head->hth_table[b]) \
+ return &head->hth_table[b]; \
+ ++b; \
+ } \
+ return NULL; \
+ } \
+ } \
+ static inline struct type ** \
+ name##_HT_NEXT_RMV(struct name *head, struct type **elm) \
+ { \
+ unsigned h = HT_ELT_HASH_(*elm, field, hashfn); \
+ *elm = (*elm)->field.hte_next; \
+ --head->hth_n_entries; \
+ if (*elm) { \
+ return elm; \
+ } else { \
+ unsigned b = (h % head->hth_table_length)+1; \
+ while (b < head->hth_table_length) { \
+ if (head->hth_table[b]) \
+ return &head->hth_table[b]; \
+ ++b; \
+ } \
+ return NULL; \
+ } \
+ }
+
+#define HT_GENERATE(name, type, field, hashfn, eqfn, load, mallocfn, \
+ reallocfn, freefn) \
+ static unsigned name##_PRIMES[] = { \
+ 53, 97, 193, 389, \
+ 769, 1543, 3079, 6151, \
+ 12289, 24593, 49157, 98317, \
+ 196613, 393241, 786433, 1572869, \
+ 3145739, 6291469, 12582917, 25165843, \
+ 50331653, 100663319, 201326611, 402653189, \
+ 805306457, 1610612741 \
+ }; \
+ static unsigned name##_N_PRIMES = \
+ (unsigned)(sizeof(name##_PRIMES)/sizeof(name##_PRIMES[0])); \
+ /* Expand the internal table of 'head' until it is large enough to \
+ * hold 'size' elements. Return 0 on success, -1 on allocation \
+ * failure. */ \
+ int \
+ name##_HT_GROW(struct name *head, unsigned size) \
+ { \
+ unsigned new_len, new_load_limit; \
+ int prime_idx; \
+ struct type **new_table; \
+ if (head->hth_prime_idx == (int)name##_N_PRIMES - 1) \
+ return 0; \
+ if (head->hth_load_limit > size) \
+ return 0; \
+ prime_idx = head->hth_prime_idx; \
+ do { \
+ new_len = name##_PRIMES[++prime_idx]; \
+ new_load_limit = (unsigned)(load*new_len); \
+ } while (new_load_limit <= size && \
+ prime_idx < (int)name##_N_PRIMES); \
+ if ((new_table = mallocfn(new_len*sizeof(struct type*)))) { \
+ unsigned b; \
+ memset(new_table, 0, new_len*sizeof(struct type*)); \
+ for (b = 0; b < head->hth_table_length; ++b) { \
+ struct type *elm, *next; \
+ unsigned b2; \
+ elm = head->hth_table[b]; \
+ while (elm) { \
+ next = elm->field.hte_next; \
+ b2 = HT_ELT_HASH_(elm, field, hashfn) % new_len; \
+ elm->field.hte_next = new_table[b2]; \
+ new_table[b2] = elm; \
+ elm = next; \
+ } \
+ } \
+ if (head->hth_table) \
+ freefn(head->hth_table); \
+ head->hth_table = new_table; \
+ } else { \
+ unsigned b, b2; \
+ new_table = reallocfn(head->hth_table, new_len*sizeof(struct type*)); \
+ if (!new_table) return -1; \
+ memset(new_table + head->hth_table_length, 0, \
+ (new_len - head->hth_table_length)*sizeof(struct type*)); \
+ for (b=0; b < head->hth_table_length; ++b) { \
+ struct type *e, **pE; \
+ for (pE = &new_table[b], e = *pE; e != NULL; e = *pE) { \
+ b2 = HT_ELT_HASH_(e, field, hashfn) % new_len; \
+ if (b2 == b) { \
+ pE = &e->field.hte_next; \
+ } else { \
+ *pE = e->field.hte_next; \
+ e->field.hte_next = new_table[b2]; \
+ new_table[b2] = e; \
+ } \
+ } \
+ } \
+ head->hth_table = new_table; \
+ } \
+ head->hth_table_length = new_len; \
+ head->hth_prime_idx = prime_idx; \
+ head->hth_load_limit = new_load_limit; \
+ return 0; \
+ } \
+ /* Free all storage held by 'head'. Does not free 'head' itself, or \
+ * individual elements. */ \
+ void \
+ name##_HT_CLEAR(struct name *head) \
+ { \
+ if (head->hth_table) \
+ freefn(head->hth_table); \
+ name##_HT_INIT(head); \
+ } \
+ /* Debugging helper: return false iff the representation of 'head' is \
+ * internally consistent. */ \
+ int \
+ name##_HT_REP_IS_BAD_(const struct name *head) \
+ { \
+ unsigned n, i; \
+ struct type *elm; \
+ if (!head->hth_table_length) { \
+ if (!head->hth_table && !head->hth_n_entries && \
+ !head->hth_load_limit && head->hth_prime_idx == -1) \
+ return 0; \
+ else \
+ return 1; \
+ } \
+ if (!head->hth_table || head->hth_prime_idx < 0 || \
+ !head->hth_load_limit) \
+ return 2; \
+ if (head->hth_n_entries > head->hth_load_limit) \
+ return 3; \
+ if (head->hth_table_length != name##_PRIMES[head->hth_prime_idx]) \
+ return 4; \
+ if (head->hth_load_limit != (unsigned)(load*head->hth_table_length)) \
+ return 5; \
+ for (n = i = 0; i < head->hth_table_length; ++i) { \
+ for (elm = head->hth_table[i]; elm; elm = elm->field.hte_next) { \
+ if (HT_ELT_HASH_(elm, field, hashfn) != hashfn(elm)) \
+ return 1000 + i; \
+ if ((HT_ELT_HASH_(elm, field, hashfn) % head->hth_table_length) != i) \
+ return 10000 + i; \
+ ++n; \
+ } \
+ } \
+ if (n != head->hth_n_entries) \
+ return 6; \
+ return 0; \
+ }
+
+/** Implements an over-optimized "find and insert if absent" block;
+ * not meant for direct usage by typical code, or usage outside the critical
+ * path.*/
+#define HT_FIND_OR_INSERT_(name, field, hashfn, head, eltype, elm, var, y, n) \
+ { \
+ struct name *var##_head_ = head; \
+ struct eltype **var; \
+ if (!var##_head_->hth_table || \
+ var##_head_->hth_n_entries >= var##_head_->hth_load_limit) \
+ name##_HT_GROW(var##_head_, var##_head_->hth_n_entries+1); \
+ HT_SET_HASH_((elm), field, hashfn); \
+ var = name##_HT_FIND_P_(var##_head_, (elm)); \
+ if (*var) { \
+ y; \
+ } else { \
+ n; \
+ } \
+ }
+#define HT_FOI_INSERT_(field, head, elm, newent, var) \
+ { \
+ HT_SET_HASHVAL_(newent, field, (elm)->field.hte_hash); \
+ newent->field.hte_next = NULL; \
+ *var = newent; \
+ ++((head)->hth_n_entries); \
+ }
+
+/*
+ * Copyright 2005, Nick Mathewson. Implementation logic is adapted from code
+ * by Christopher Clark, retrofit to allow drop-in memory management, and to
+ * use the same interface as Niels Provos's tree.h. This is probably still
+ * a derived work, so the original license below still applies.
+ *
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#endif
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/http-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/http-internal.h
new file mode 100644
index 000000000..45555171c
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/http-internal.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2001-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * This header file contains definitions for dealing with HTTP requests
+ * that are internal to libevent. As user of the library, you should not
+ * need to know about these.
+ */
+
+#ifndef HTTP_INTERNAL_H_INCLUDED_
+#define HTTP_INTERNAL_H_INCLUDED_
+
+#include "event2/event_struct.h"
+#include "util-internal.h"
+#include "defer-internal.h"
+
+#define HTTP_CONNECT_TIMEOUT 45
+#define HTTP_WRITE_TIMEOUT 50
+#define HTTP_READ_TIMEOUT 50
+
+#define HTTP_PREFIX "http://"
+#define HTTP_DEFAULTPORT 80
+
+enum message_read_status {
+ ALL_DATA_READ = 1,
+ MORE_DATA_EXPECTED = 0,
+ DATA_CORRUPTED = -1,
+ REQUEST_CANCELED = -2,
+ DATA_TOO_LONG = -3
+};
+
+struct evbuffer;
+struct addrinfo;
+struct evhttp_request;
+
+/* Indicates an unknown request method. */
+#define EVHTTP_REQ_UNKNOWN_ (1<<15)
+
+enum evhttp_connection_state {
+ EVCON_DISCONNECTED, /**< not currently connected not trying either*/
+ EVCON_CONNECTING, /**< tries to currently connect */
+ EVCON_IDLE, /**< connection is established */
+ EVCON_READING_FIRSTLINE,/**< reading Request-Line (incoming conn) or
+ **< Status-Line (outgoing conn) */
+ EVCON_READING_HEADERS, /**< reading request/response headers */
+ EVCON_READING_BODY, /**< reading request/response body */
+ EVCON_READING_TRAILER, /**< reading request/response chunked trailer */
+ EVCON_WRITING /**< writing request/response headers/body */
+};
+
+struct event_base;
+
+/* A client or server connection. */
+struct evhttp_connection {
+ /* we use this tailq only if this connection was created for an http
+ * server */
+ TAILQ_ENTRY(evhttp_connection) next;
+
+ evutil_socket_t fd;
+ struct bufferevent *bufev;
+
+ struct event retry_ev; /* for retrying connects */
+
+ char *bind_address; /* address to use for binding the src */
+ ev_uint16_t bind_port; /* local port for binding the src */
+
+ char *address; /* address to connect to */
+ ev_uint16_t port;
+
+ size_t max_headers_size;
+ ev_uint64_t max_body_size;
+
+ int flags;
+#define EVHTTP_CON_INCOMING 0x0001 /* only one request on it ever */
+#define EVHTTP_CON_OUTGOING 0x0002 /* multiple requests possible */
+#define EVHTTP_CON_CLOSEDETECT 0x0004 /* detecting if persistent close */
+/* set when we want to auto free the connection */
+#define EVHTTP_CON_AUTOFREE EVHTTP_CON_PUBLIC_FLAGS_END
+/* Installed when attempt to read HTTP error after write failed, see
+ * EVHTTP_CON_READ_ON_WRITE_ERROR */
+#define EVHTTP_CON_READING_ERROR (EVHTTP_CON_AUTOFREE << 1)
+
+ struct timeval timeout; /* timeout for events */
+ int retry_cnt; /* retry count */
+ int retry_max; /* maximum number of retries */
+ struct timeval initial_retry_timeout; /* Timeout for low long to wait
+ * after first failing attempt
+ * before retry */
+
+ enum evhttp_connection_state state;
+
+ /* for server connections, the http server they are connected with */
+ struct evhttp *http_server;
+
+ TAILQ_HEAD(evcon_requestq, evhttp_request) requests;
+
+ void (*cb)(struct evhttp_connection *, void *);
+ void *cb_arg;
+
+ void (*closecb)(struct evhttp_connection *, void *);
+ void *closecb_arg;
+
+ struct event_callback read_more_deferred_cb;
+
+ struct event_base *base;
+ struct evdns_base *dns_base;
+ int ai_family;
+};
+
+/* A callback for an http server */
+struct evhttp_cb {
+ TAILQ_ENTRY(evhttp_cb) next;
+
+ char *what;
+
+ void (*cb)(struct evhttp_request *req, void *);
+ void *cbarg;
+};
+
+/* both the http server as well as the rpc system need to queue connections */
+TAILQ_HEAD(evconq, evhttp_connection);
+
+/* each bound socket is stored in one of these */
+struct evhttp_bound_socket {
+ TAILQ_ENTRY(evhttp_bound_socket) next;
+
+ struct evconnlistener *listener;
+};
+
+/* server alias list item. */
+struct evhttp_server_alias {
+ TAILQ_ENTRY(evhttp_server_alias) next;
+
+ char *alias; /* the server alias. */
+};
+
+struct evhttp {
+ /* Next vhost, if this is a vhost. */
+ TAILQ_ENTRY(evhttp) next_vhost;
+
+ /* All listeners for this host */
+ TAILQ_HEAD(boundq, evhttp_bound_socket) sockets;
+
+ TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
+
+ /* All live connections on this host. */
+ struct evconq connections;
+
+ TAILQ_HEAD(vhostsq, evhttp) virtualhosts;
+
+ TAILQ_HEAD(aliasq, evhttp_server_alias) aliases;
+
+ /* NULL if this server is not a vhost */
+ char *vhost_pattern;
+
+ struct timeval timeout;
+
+ size_t default_max_headers_size;
+ ev_uint64_t default_max_body_size;
+ int flags;
+ const char *default_content_type;
+
+ /* Bitmask of all HTTP methods that we accept and pass to user
+ * callbacks. */
+ ev_uint16_t allowed_methods;
+
+ /* Fallback callback if all the other callbacks for this connection
+ don't match. */
+ void (*gencb)(struct evhttp_request *req, void *);
+ void *gencbarg;
+ struct bufferevent* (*bevcb)(struct event_base *, void *);
+ void *bevcbarg;
+
+ struct event_base *base;
+};
+
+/* XXX most of these functions could be static. */
+
+/* resets the connection; can be reused for more requests */
+void evhttp_connection_reset_(struct evhttp_connection *);
+
+/* connects if necessary */
+int evhttp_connection_connect_(struct evhttp_connection *);
+
+enum evhttp_request_error;
+/* notifies the current request that it failed; resets connection */
+void evhttp_connection_fail_(struct evhttp_connection *,
+ enum evhttp_request_error error);
+
+enum message_read_status;
+
+enum message_read_status evhttp_parse_firstline_(struct evhttp_request *, struct evbuffer*);
+enum message_read_status evhttp_parse_headers_(struct evhttp_request *, struct evbuffer*);
+
+void evhttp_start_read_(struct evhttp_connection *);
+void evhttp_start_write_(struct evhttp_connection *);
+
+/* response sending HTML the data in the buffer */
+void evhttp_response_code_(struct evhttp_request *, int, const char *);
+void evhttp_send_page_(struct evhttp_request *, struct evbuffer *);
+
+int evhttp_decode_uri_internal(const char *uri, size_t length,
+ char *ret, int decode_plus);
+
+#endif /* _HTTP_H */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/http.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/http.c
new file mode 100644
index 000000000..f5a2ef931
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/http.c
@@ -0,0 +1,5024 @@
+/*
+ * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef EVENT__HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_IOCCOM_H
+#include <sys/ioccom.h>
+#endif
+#ifdef EVENT__HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef EVENT__HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/stat.h>
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include <sys/queue.h>
+
+#ifdef EVENT__HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef EVENT__HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef EVENT__HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32
+#include <syslog.h>
+#endif
+#include <signal.h>
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef EVENT__HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#undef timeout_pending
+#undef timeout_initialized
+
+#include "strlcpy-internal.h"
+#include "event2/http.h"
+#include "event2/event.h"
+#include "event2/buffer.h"
+#include "event2/bufferevent.h"
+#include "event2/http_struct.h"
+#include "event2/http_compat.h"
+#include "event2/util.h"
+#include "event2/listener.h"
+#include "log-internal.h"
+#include "util-internal.h"
+#include "http-internal.h"
+#include "mm-internal.h"
+#include "bufferevent-internal.h"
+
+#ifndef EVENT__HAVE_GETNAMEINFO
+#define NI_MAXSERV 32
+#define NI_MAXHOST 1025
+
+#ifndef NI_NUMERICHOST
+#define NI_NUMERICHOST 1
+#endif
+
+#ifndef NI_NUMERICSERV
+#define NI_NUMERICSERV 2
+#endif
+
+static int
+fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
+ size_t hostlen, char *serv, size_t servlen, int flags)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+ if (serv != NULL) {
+ char tmpserv[16];
+ evutil_snprintf(tmpserv, sizeof(tmpserv),
+ "%d", ntohs(sin->sin_port));
+ if (strlcpy(serv, tmpserv, servlen) >= servlen)
+ return (-1);
+ }
+
+ if (host != NULL) {
+ if (flags & NI_NUMERICHOST) {
+ if (strlcpy(host, inet_ntoa(sin->sin_addr),
+ hostlen) >= hostlen)
+ return (-1);
+ else
+ return (0);
+ } else {
+ struct hostent *hp;
+ hp = gethostbyaddr((char *)&sin->sin_addr,
+ sizeof(struct in_addr), AF_INET);
+ if (hp == NULL)
+ return (-2);
+
+ if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
+ return (-1);
+ else
+ return (0);
+ }
+ }
+ return (0);
+}
+
+#endif
+
+#define REQ_VERSION_BEFORE(req, major_v, minor_v) \
+ ((req)->major < (major_v) || \
+ ((req)->major == (major_v) && (req)->minor < (minor_v)))
+
+#define REQ_VERSION_ATLEAST(req, major_v, minor_v) \
+ ((req)->major > (major_v) || \
+ ((req)->major == (major_v) && (req)->minor >= (minor_v)))
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+extern int debug;
+
+static evutil_socket_t bind_socket_ai(struct evutil_addrinfo *, int reuse);
+static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse);
+static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **);
+static int evhttp_associate_new_request_with_connection(
+ struct evhttp_connection *evcon);
+static void evhttp_connection_start_detectclose(
+ struct evhttp_connection *evcon);
+static void evhttp_connection_stop_detectclose(
+ struct evhttp_connection *evcon);
+static void evhttp_request_dispatch(struct evhttp_connection* evcon);
+static void evhttp_read_firstline(struct evhttp_connection *evcon,
+ struct evhttp_request *req);
+static void evhttp_read_header(struct evhttp_connection *evcon,
+ struct evhttp_request *req);
+static int evhttp_add_header_internal(struct evkeyvalq *headers,
+ const char *key, const char *value);
+static const char *evhttp_response_phrase_internal(int code);
+static void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t);
+static void evhttp_write_buffer(struct evhttp_connection *,
+ void (*)(struct evhttp_connection *, void *), void *);
+static void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
+
+/* callbacks for bufferevent */
+static void evhttp_read_cb(struct bufferevent *, void *);
+static void evhttp_write_cb(struct bufferevent *, void *);
+static void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg);
+static int evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp,
+ const char *hostname);
+
+#ifndef EVENT__HAVE_STRSEP
+/* strsep replacement for platforms that lack it. Only works if
+ * del is one character long. */
+static char *
+strsep(char **s, const char *del)
+{
+ char *d, *tok;
+ EVUTIL_ASSERT(strlen(del) == 1);
+ if (!s || !*s)
+ return NULL;
+ tok = *s;
+ d = strstr(tok, del);
+ if (d) {
+ *d = '\0';
+ *s = d + 1;
+ } else
+ *s = NULL;
+ return tok;
+}
+#endif
+
+static size_t
+html_replace(const char ch, const char **escaped)
+{
+ switch (ch) {
+ case '<':
+ *escaped = "&lt;";
+ return 4;
+ case '>':
+ *escaped = "&gt;";
+ return 4;
+ case '"':
+ *escaped = "&quot;";
+ return 6;
+ case '\'':
+ *escaped = "&#039;";
+ return 6;
+ case '&':
+ *escaped = "&amp;";
+ return 5;
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+/*
+ * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
+ * &#039; and &amp; correspondingly.
+ *
+ * The returned string needs to be freed by the caller.
+ */
+
+char *
+evhttp_htmlescape(const char *html)
+{
+ size_t i;
+ size_t new_size = 0, old_size = 0;
+ char *escaped_html, *p;
+
+ if (html == NULL)
+ return (NULL);
+
+ old_size = strlen(html);
+ for (i = 0; i < old_size; ++i) {
+ const char *replaced = NULL;
+ const size_t replace_size = html_replace(html[i], &replaced);
+ if (replace_size > EV_SIZE_MAX - new_size) {
+ event_warn("%s: html_replace overflow", __func__);
+ return (NULL);
+ }
+ new_size += replace_size;
+ }
+
+ if (new_size == EV_SIZE_MAX)
+ return (NULL);
+ p = escaped_html = mm_malloc(new_size + 1);
+ if (escaped_html == NULL) {
+ event_warn("%s: malloc(%lu)", __func__,
+ (unsigned long)(new_size + 1));
+ return (NULL);
+ }
+ for (i = 0; i < old_size; ++i) {
+ const char *replaced = &html[i];
+ const size_t len = html_replace(html[i], &replaced);
+ memcpy(p, replaced, len);
+ p += len;
+ }
+
+ *p = '\0';
+
+ return (escaped_html);
+}
+
+/** Given an evhttp_cmd_type, returns a constant string containing the
+ * equivalent HTTP command, or NULL if the evhttp_command_type is
+ * unrecognized. */
+static const char *
+evhttp_method(enum evhttp_cmd_type type)
+{
+ const char *method;
+
+ switch (type) {
+ case EVHTTP_REQ_GET:
+ method = "GET";
+ break;
+ case EVHTTP_REQ_POST:
+ method = "POST";
+ break;
+ case EVHTTP_REQ_HEAD:
+ method = "HEAD";
+ break;
+ case EVHTTP_REQ_PUT:
+ method = "PUT";
+ break;
+ case EVHTTP_REQ_DELETE:
+ method = "DELETE";
+ break;
+ case EVHTTP_REQ_OPTIONS:
+ method = "OPTIONS";
+ break;
+ case EVHTTP_REQ_TRACE:
+ method = "TRACE";
+ break;
+ case EVHTTP_REQ_CONNECT:
+ method = "CONNECT";
+ break;
+ case EVHTTP_REQ_PATCH:
+ method = "PATCH";
+ break;
+ default:
+ method = NULL;
+ break;
+ }
+
+ return (method);
+}
+
+/**
+ * Determines if a response should have a body.
+ * Follows the rules in RFC 2616 section 4.3.
+ * @return 1 if the response MUST have a body; 0 if the response MUST NOT have
+ * a body.
+ */
+static int
+evhttp_response_needs_body(struct evhttp_request *req)
+{
+ return (req->response_code != HTTP_NOCONTENT &&
+ req->response_code != HTTP_NOTMODIFIED &&
+ (req->response_code < 100 || req->response_code >= 200) &&
+ req->type != EVHTTP_REQ_HEAD);
+}
+
+/** Helper: called after we've added some data to an evcon's bufferevent's
+ * output buffer. Sets the evconn's writing-is-done callback, and puts
+ * the bufferevent into writing mode.
+ */
+static void
+evhttp_write_buffer(struct evhttp_connection *evcon,
+ void (*cb)(struct evhttp_connection *, void *), void *arg)
+{
+ event_debug(("%s: preparing to write buffer\n", __func__));
+
+ /* Set call back */
+ evcon->cb = cb;
+ evcon->cb_arg = arg;
+
+ /* Disable the read callback: we don't actually care about data;
+ * we only care about close detection. (We don't disable reading,
+ * since we *do* want to learn about any close events.) */
+ bufferevent_setcb(evcon->bufev,
+ NULL, /*read*/
+ evhttp_write_cb,
+ evhttp_error_cb,
+ evcon);
+
+ bufferevent_enable(evcon->bufev, EV_WRITE);
+}
+
+static void
+evhttp_send_continue_done(struct evhttp_connection *evcon, void *arg)
+{
+ bufferevent_disable(evcon->bufev, EV_WRITE);
+}
+
+static void
+evhttp_send_continue(struct evhttp_connection *evcon,
+ struct evhttp_request *req)
+{
+ bufferevent_enable(evcon->bufev, EV_WRITE);
+ evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
+ "HTTP/%d.%d 100 Continue\r\n\r\n",
+ req->major, req->minor);
+ evcon->cb = evhttp_send_continue_done;
+ evcon->cb_arg = NULL;
+ bufferevent_setcb(evcon->bufev,
+ evhttp_read_cb,
+ evhttp_write_cb,
+ evhttp_error_cb,
+ evcon);
+}
+
+/** Helper: returns true iff evconn is in any connected state. */
+static int
+evhttp_connected(struct evhttp_connection *evcon)
+{
+ switch (evcon->state) {
+ case EVCON_DISCONNECTED:
+ case EVCON_CONNECTING:
+ return (0);
+ case EVCON_IDLE:
+ case EVCON_READING_FIRSTLINE:
+ case EVCON_READING_HEADERS:
+ case EVCON_READING_BODY:
+ case EVCON_READING_TRAILER:
+ case EVCON_WRITING:
+ default:
+ return (1);
+ }
+}
+
+/* Create the headers needed for an outgoing HTTP request, adds them to
+ * the request's header list, and writes the request line to the
+ * connection's output buffer.
+ */
+static void
+evhttp_make_header_request(struct evhttp_connection *evcon,
+ struct evhttp_request *req)
+{
+ const char *method;
+
+ evhttp_remove_header(req->output_headers, "Proxy-Connection");
+
+ /* Generate request line */
+ if (!(method = evhttp_method(req->type))) {
+ method = "NULL";
+ }
+
+ evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
+ "%s %s HTTP/%d.%d\r\n",
+ method, req->uri, req->major, req->minor);
+
+ /* Add the content length on a post or put request if missing */
+ if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) &&
+ evhttp_find_header(req->output_headers, "Content-Length") == NULL){
+ char size[22];
+ evutil_snprintf(size, sizeof(size), EV_SIZE_FMT,
+ EV_SIZE_ARG(evbuffer_get_length(req->output_buffer)));
+ evhttp_add_header(req->output_headers, "Content-Length", size);
+ }
+}
+
+/** Return true if the list of headers in 'headers', intepreted with respect
+ * to flags, means that we should send a "connection: close" when the request
+ * is done. */
+static int
+evhttp_is_connection_close(int flags, struct evkeyvalq* headers)
+{
+ if (flags & EVHTTP_PROXY_REQUEST) {
+ /* proxy connection */
+ const char *connection = evhttp_find_header(headers, "Proxy-Connection");
+ return (connection == NULL || evutil_ascii_strcasecmp(connection, "keep-alive") != 0);
+ } else {
+ const char *connection = evhttp_find_header(headers, "Connection");
+ return (connection != NULL && evutil_ascii_strcasecmp(connection, "close") == 0);
+ }
+}
+static int
+evhttp_is_request_connection_close(struct evhttp_request *req)
+{
+ return
+ evhttp_is_connection_close(req->flags, req->input_headers) ||
+ evhttp_is_connection_close(req->flags, req->output_headers);
+}
+
+/* Return true iff 'headers' contains 'Connection: keep-alive' */
+static int
+evhttp_is_connection_keepalive(struct evkeyvalq* headers)
+{
+ const char *connection = evhttp_find_header(headers, "Connection");
+ return (connection != NULL
+ && evutil_ascii_strncasecmp(connection, "keep-alive", 10) == 0);
+}
+
+/* Add a correct "Date" header to headers, unless it already has one. */
+static void
+evhttp_maybe_add_date_header(struct evkeyvalq *headers)
+{
+ if (evhttp_find_header(headers, "Date") == NULL) {
+ char date[50];
+ if (sizeof(date) - evutil_date_rfc1123(date, sizeof(date), NULL) > 0) {
+ evhttp_add_header(headers, "Date", date);
+ }
+ }
+}
+
+/* Add a "Content-Length" header with value 'content_length' to headers,
+ * unless it already has a content-length or transfer-encoding header. */
+static void
+evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
+ size_t content_length)
+{
+ if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
+ evhttp_find_header(headers, "Content-Length") == NULL) {
+ char len[22];
+ evutil_snprintf(len, sizeof(len), EV_SIZE_FMT,
+ EV_SIZE_ARG(content_length));
+ evhttp_add_header(headers, "Content-Length", len);
+ }
+}
+
+/*
+ * Create the headers needed for an HTTP reply in req->output_headers,
+ * and write the first HTTP response for req line to evcon.
+ */
+static void
+evhttp_make_header_response(struct evhttp_connection *evcon,
+ struct evhttp_request *req)
+{
+ int is_keepalive = evhttp_is_connection_keepalive(req->input_headers);
+ evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
+ "HTTP/%d.%d %d %s\r\n",
+ req->major, req->minor, req->response_code,
+ req->response_code_line);
+
+ if (req->major == 1) {
+ if (req->minor >= 1)
+ evhttp_maybe_add_date_header(req->output_headers);
+
+ /*
+ * if the protocol is 1.0; and the connection was keep-alive
+ * we need to add a keep-alive header, too.
+ */
+ if (req->minor == 0 && is_keepalive)
+ evhttp_add_header(req->output_headers,
+ "Connection", "keep-alive");
+
+ if ((req->minor >= 1 || is_keepalive) &&
+ evhttp_response_needs_body(req)) {
+ /*
+ * we need to add the content length if the
+ * user did not give it, this is required for
+ * persistent connections to work.
+ */
+ evhttp_maybe_add_content_length_header(
+ req->output_headers,
+ evbuffer_get_length(req->output_buffer));
+ }
+ }
+
+ /* Potentially add headers for unidentified content. */
+ if (evhttp_response_needs_body(req)) {
+ if (evhttp_find_header(req->output_headers,
+ "Content-Type") == NULL
+ && evcon->http_server->default_content_type) {
+ evhttp_add_header(req->output_headers,
+ "Content-Type",
+ evcon->http_server->default_content_type);
+ }
+ }
+
+ /* if the request asked for a close, we send a close, too */
+ if (evhttp_is_connection_close(req->flags, req->input_headers)) {
+ evhttp_remove_header(req->output_headers, "Connection");
+ if (!(req->flags & EVHTTP_PROXY_REQUEST))
+ evhttp_add_header(req->output_headers, "Connection", "close");
+ evhttp_remove_header(req->output_headers, "Proxy-Connection");
+ }
+}
+
+enum expect { NO, CONTINUE, OTHER };
+static enum expect evhttp_have_expect(struct evhttp_request *req, int input)
+{
+ const char *expect;
+ struct evkeyvalq *h = input ? req->input_headers : req->output_headers;
+
+ if (!(req->kind == EVHTTP_REQUEST) || !REQ_VERSION_ATLEAST(req, 1, 1))
+ return NO;
+
+ expect = evhttp_find_header(h, "Expect");
+ if (!expect)
+ return NO;
+
+ return !evutil_ascii_strcasecmp(expect, "100-continue") ? CONTINUE : OTHER;
+}
+
+
+/** Generate all headers appropriate for sending the http request in req (or
+ * the response, if we're sending a response), and write them to evcon's
+ * bufferevent. Also writes all data from req->output_buffer */
+static void
+evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+ struct evkeyval *header;
+ struct evbuffer *output = bufferevent_get_output(evcon->bufev);
+
+ /*
+ * Depending if this is a HTTP request or response, we might need to
+ * add some new headers or remove existing headers.
+ */
+ if (req->kind == EVHTTP_REQUEST) {
+ evhttp_make_header_request(evcon, req);
+ } else {
+ evhttp_make_header_response(evcon, req);
+ }
+
+ TAILQ_FOREACH(header, req->output_headers, next) {
+ evbuffer_add_printf(output, "%s: %s\r\n",
+ header->key, header->value);
+ }
+ evbuffer_add(output, "\r\n", 2);
+
+ if (evhttp_have_expect(req, 0) != CONTINUE &&
+ evbuffer_get_length(req->output_buffer)) {
+ /*
+ * For a request, we add the POST data, for a reply, this
+ * is the regular data.
+ */
+ evbuffer_add_buffer(output, req->output_buffer);
+ }
+}
+
+void
+evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon,
+ ev_ssize_t new_max_headers_size)
+{
+ if (new_max_headers_size<0)
+ evcon->max_headers_size = EV_SIZE_MAX;
+ else
+ evcon->max_headers_size = new_max_headers_size;
+}
+void
+evhttp_connection_set_max_body_size(struct evhttp_connection* evcon,
+ ev_ssize_t new_max_body_size)
+{
+ if (new_max_body_size<0)
+ evcon->max_body_size = EV_UINT64_MAX;
+ else
+ evcon->max_body_size = new_max_body_size;
+}
+
+static int
+evhttp_connection_incoming_fail(struct evhttp_request *req,
+ enum evhttp_request_error error)
+{
+ switch (error) {
+ case EVREQ_HTTP_DATA_TOO_LONG:
+ req->response_code = HTTP_ENTITYTOOLARGE;
+ break;
+ default:
+ req->response_code = HTTP_BADREQUEST;
+ }
+
+ switch (error) {
+ case EVREQ_HTTP_TIMEOUT:
+ case EVREQ_HTTP_EOF:
+ /*
+ * these are cases in which we probably should just
+ * close the connection and not send a reply. this
+ * case may happen when a browser keeps a persistent
+ * connection open and we timeout on the read. when
+ * the request is still being used for sending, we
+ * need to disassociated it from the connection here.
+ */
+ if (!req->userdone) {
+ /* remove it so that it will not be freed */
+ TAILQ_REMOVE(&req->evcon->requests, req, next);
+ /* indicate that this request no longer has a
+ * connection object
+ */
+ req->evcon = NULL;
+ }
+ return (-1);
+ case EVREQ_HTTP_INVALID_HEADER:
+ case EVREQ_HTTP_BUFFER_ERROR:
+ case EVREQ_HTTP_REQUEST_CANCEL:
+ case EVREQ_HTTP_DATA_TOO_LONG:
+ default: /* xxx: probably should just error on default */
+ /* the callback looks at the uri to determine errors */
+ if (req->uri) {
+ mm_free(req->uri);
+ req->uri = NULL;
+ }
+ if (req->uri_elems) {
+ evhttp_uri_free(req->uri_elems);
+ req->uri_elems = NULL;
+ }
+
+ /*
+ * the callback needs to send a reply, once the reply has
+ * been send, the connection should get freed.
+ */
+ (*req->cb)(req, req->cb_arg);
+ }
+
+ return (0);
+}
+
+/* Free connection ownership of which can be acquired by user using
+ * evhttp_request_own(). */
+static inline void
+evhttp_request_free_auto(struct evhttp_request *req)
+{
+ if (!(req->flags & EVHTTP_USER_OWNED))
+ evhttp_request_free(req);
+}
+
+static void
+evhttp_request_free_(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+ TAILQ_REMOVE(&evcon->requests, req, next);
+ evhttp_request_free_auto(req);
+}
+
+/* Called when evcon has experienced a (non-recoverable? -NM) error, as
+ * given in error. If it's an outgoing connection, reset the connection,
+ * retry any pending requests, and inform the user. If it's incoming,
+ * delegates to evhttp_connection_incoming_fail(). */
+void
+evhttp_connection_fail_(struct evhttp_connection *evcon,
+ enum evhttp_request_error error)
+{
+ const int errsave = EVUTIL_SOCKET_ERROR();
+ struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
+ void (*cb)(struct evhttp_request *, void *);
+ void *cb_arg;
+ void (*error_cb)(enum evhttp_request_error, void *);
+ void *error_cb_arg;
+ EVUTIL_ASSERT(req != NULL);
+
+ bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
+
+ if (evcon->flags & EVHTTP_CON_INCOMING) {
+ /*
+ * for incoming requests, there are two different
+ * failure cases. it's either a network level error
+ * or an http layer error. for problems on the network
+ * layer like timeouts we just drop the connections.
+ * For HTTP problems, we might have to send back a
+ * reply before the connection can be freed.
+ */
+ if (evhttp_connection_incoming_fail(req, error) == -1)
+ evhttp_connection_free(evcon);
+ return;
+ }
+
+ error_cb = req->error_cb;
+ error_cb_arg = req->cb_arg;
+ /* when the request was canceled, the callback is not executed */
+ if (error != EVREQ_HTTP_REQUEST_CANCEL) {
+ /* save the callback for later; the cb might free our object */
+ cb = req->cb;
+ cb_arg = req->cb_arg;
+ } else {
+ cb = NULL;
+ cb_arg = NULL;
+ }
+
+ /* do not fail all requests; the next request is going to get
+ * send over a new connection. when a user cancels a request,
+ * all other pending requests should be processed as normal
+ */
+ evhttp_request_free_(evcon, req);
+
+ /* reset the connection */
+ evhttp_connection_reset_(evcon);
+
+ /* We are trying the next request that was queued on us */
+ if (TAILQ_FIRST(&evcon->requests) != NULL)
+ evhttp_connection_connect_(evcon);
+
+ /* The call to evhttp_connection_reset_ overwrote errno.
+ * Let's restore the original errno, so that the user's
+ * callback can have a better idea of what the error was.
+ */
+ EVUTIL_SET_SOCKET_ERROR(errsave);
+
+ /* inform the user */
+ if (error_cb != NULL)
+ error_cb(error, error_cb_arg);
+ if (cb != NULL)
+ (*cb)(NULL, cb_arg);
+}
+
+/* Bufferevent callback: invoked when any data has been written from an
+ * http connection's bufferevent */
+static void
+evhttp_write_cb(struct bufferevent *bufev, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+
+ /* Activate our call back */
+ if (evcon->cb != NULL)
+ (*evcon->cb)(evcon, evcon->cb_arg);
+}
+
+/**
+ * Advance the connection state.
+ * - If this is an outgoing connection, we've just processed the response;
+ * idle or close the connection.
+ * - If this is an incoming connection, we've just processed the request;
+ * respond.
+ */
+static void
+evhttp_connection_done(struct evhttp_connection *evcon)
+{
+ struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+ int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING;
+ int free_evcon = 0;
+
+ if (con_outgoing) {
+ /* idle or close the connection */
+ int need_close = evhttp_is_request_connection_close(req);
+ TAILQ_REMOVE(&evcon->requests, req, next);
+ req->evcon = NULL;
+
+ evcon->state = EVCON_IDLE;
+
+ /* check if we got asked to close the connection */
+ if (need_close)
+ evhttp_connection_reset_(evcon);
+
+ if (TAILQ_FIRST(&evcon->requests) != NULL) {
+ /*
+ * We have more requests; reset the connection
+ * and deal with the next request.
+ */
+ if (!evhttp_connected(evcon))
+ evhttp_connection_connect_(evcon);
+ else
+ evhttp_request_dispatch(evcon);
+ } else if (!need_close) {
+ /*
+ * The connection is going to be persistent, but we
+ * need to detect if the other side closes it.
+ */
+ evhttp_connection_start_detectclose(evcon);
+ } else if ((evcon->flags & EVHTTP_CON_AUTOFREE)) {
+ /*
+ * If we have no more requests that need completion
+ * and we're not waiting for the connection to close
+ */
+ free_evcon = 1;
+ }
+ } else {
+ /*
+ * incoming connection - we need to leave the request on the
+ * connection so that we can reply to it.
+ */
+ evcon->state = EVCON_WRITING;
+ }
+
+ /* notify the user of the request */
+ (*req->cb)(req, req->cb_arg);
+
+ /* if this was an outgoing request, we own and it's done. so free it. */
+ if (con_outgoing) {
+ evhttp_request_free_auto(req);
+ }
+
+ /* If this was the last request of an outgoing connection and we're
+ * not waiting to receive a connection close event and we want to
+ * automatically free the connection. We check to ensure our request
+ * list is empty one last time just in case our callback added a
+ * new request.
+ */
+ if (free_evcon && TAILQ_FIRST(&evcon->requests) == NULL) {
+ evhttp_connection_free(evcon);
+ }
+}
+
+/*
+ * Handles reading from a chunked request.
+ * return ALL_DATA_READ:
+ * all data has been read
+ * return MORE_DATA_EXPECTED:
+ * more data is expected
+ * return DATA_CORRUPTED:
+ * data is corrupted
+ * return REQUEST_CANCELED:
+ * request was canceled by the user calling evhttp_cancel_request
+ * return DATA_TOO_LONG:
+ * ran over the maximum limit
+ */
+
+static enum message_read_status
+evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
+{
+ if (req == NULL || buf == NULL) {
+ return DATA_CORRUPTED;
+ }
+
+ while (1) {
+ size_t buflen;
+
+ if ((buflen = evbuffer_get_length(buf)) == 0) {
+ break;
+ }
+
+ /* evbuffer_get_length returns size_t, but len variable is ssize_t,
+ * check for overflow conditions */
+ if (buflen > EV_SSIZE_MAX) {
+ return DATA_CORRUPTED;
+ }
+
+ if (req->ntoread < 0) {
+ /* Read chunk size */
+ ev_int64_t ntoread;
+ char *p = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF);
+ char *endp;
+ int error;
+ if (p == NULL)
+ break;
+ /* the last chunk is on a new line? */
+ if (strlen(p) == 0) {
+ mm_free(p);
+ continue;
+ }
+ ntoread = evutil_strtoll(p, &endp, 16);
+ error = (*p == '\0' ||
+ (*endp != '\0' && *endp != ' ') ||
+ ntoread < 0);
+ mm_free(p);
+ if (error) {
+ /* could not get chunk size */
+ return (DATA_CORRUPTED);
+ }
+
+ /* ntoread is signed int64, body_size is unsigned size_t, check for under/overflow conditions */
+ if ((ev_uint64_t)ntoread > EV_SIZE_MAX - req->body_size) {
+ return DATA_CORRUPTED;
+ }
+
+ if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) {
+ /* failed body length test */
+ event_debug(("Request body is too long"));
+ return (DATA_TOO_LONG);
+ }
+
+ req->body_size += (size_t)ntoread;
+ req->ntoread = ntoread;
+ if (req->ntoread == 0) {
+ /* Last chunk */
+ return (ALL_DATA_READ);
+ }
+ continue;
+ }
+
+ /* req->ntoread is signed int64, len is ssize_t, based on arch,
+ * ssize_t could only be 32b, check for these conditions */
+ if (req->ntoread > EV_SSIZE_MAX) {
+ return DATA_CORRUPTED;
+ }
+
+ /* don't have enough to complete a chunk; wait for more */
+ if (req->ntoread > 0 && buflen < (ev_uint64_t)req->ntoread)
+ return (MORE_DATA_EXPECTED);
+
+ /* Completed chunk */
+ evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread);
+ req->ntoread = -1;
+ if (req->chunk_cb != NULL) {
+ req->flags |= EVHTTP_REQ_DEFER_FREE;
+ (*req->chunk_cb)(req, req->cb_arg);
+ evbuffer_drain(req->input_buffer,
+ evbuffer_get_length(req->input_buffer));
+ req->flags &= ~EVHTTP_REQ_DEFER_FREE;
+ if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
+ return (REQUEST_CANCELED);
+ }
+ }
+ }
+
+ return (MORE_DATA_EXPECTED);
+}
+
+static void
+evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+ struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
+
+ switch (evhttp_parse_headers_(req, buf)) {
+ case DATA_CORRUPTED:
+ case DATA_TOO_LONG:
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
+ break;
+ case ALL_DATA_READ:
+ bufferevent_disable(evcon->bufev, EV_READ);
+ evhttp_connection_done(evcon);
+ break;
+ case MORE_DATA_EXPECTED:
+ case REQUEST_CANCELED: /* ??? */
+ default:
+ break;
+ }
+}
+
+static void
+evhttp_lingering_close(struct evhttp_connection *evcon,
+ struct evhttp_request *req)
+{
+ struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
+
+ size_t n = evbuffer_get_length(buf);
+ if (n > (size_t) req->ntoread)
+ n = (size_t) req->ntoread;
+ req->ntoread -= n;
+ req->body_size += n;
+
+ event_debug(("Request body is too long, left " EV_I64_FMT,
+ EV_I64_ARG(req->ntoread)));
+
+ evbuffer_drain(buf, n);
+ if (!req->ntoread)
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
+}
+static void
+evhttp_lingering_fail(struct evhttp_connection *evcon,
+ struct evhttp_request *req)
+{
+ if (evcon->flags & EVHTTP_CON_LINGERING_CLOSE)
+ evhttp_lingering_close(evcon, req);
+ else
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
+}
+
+static void
+evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+ struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
+
+ if (req->chunked) {
+ switch (evhttp_handle_chunked_read(req, buf)) {
+ case ALL_DATA_READ:
+ /* finished last chunk */
+ evcon->state = EVCON_READING_TRAILER;
+ evhttp_read_trailer(evcon, req);
+ return;
+ case DATA_CORRUPTED:
+ case DATA_TOO_LONG:
+ /* corrupted data */
+ evhttp_connection_fail_(evcon,
+ EVREQ_HTTP_DATA_TOO_LONG);
+ return;
+ case REQUEST_CANCELED:
+ /* request canceled */
+ evhttp_request_free_auto(req);
+ return;
+ case MORE_DATA_EXPECTED:
+ default:
+ break;
+ }
+ } else if (req->ntoread < 0) {
+ /* Read until connection close. */
+ if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) {
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
+ return;
+ }
+
+ req->body_size += evbuffer_get_length(buf);
+ evbuffer_add_buffer(req->input_buffer, buf);
+ } else if (req->chunk_cb != NULL || evbuffer_get_length(buf) >= (size_t)req->ntoread) {
+ /* XXX: the above get_length comparison has to be fixed for overflow conditions! */
+ /* We've postponed moving the data until now, but we're
+ * about to use it. */
+ size_t n = evbuffer_get_length(buf);
+
+ if (n > (size_t) req->ntoread)
+ n = (size_t) req->ntoread;
+ req->ntoread -= n;
+ req->body_size += n;
+ evbuffer_remove_buffer(buf, req->input_buffer, n);
+ }
+
+ if (req->body_size > req->evcon->max_body_size ||
+ (!req->chunked && req->ntoread >= 0 &&
+ (size_t)req->ntoread > req->evcon->max_body_size)) {
+ /* XXX: The above casted comparison must checked for overflow */
+ /* failed body length test */
+
+ evhttp_lingering_fail(evcon, req);
+ return;
+ }
+
+ if (evbuffer_get_length(req->input_buffer) > 0 && req->chunk_cb != NULL) {
+ req->flags |= EVHTTP_REQ_DEFER_FREE;
+ (*req->chunk_cb)(req, req->cb_arg);
+ req->flags &= ~EVHTTP_REQ_DEFER_FREE;
+ evbuffer_drain(req->input_buffer,
+ evbuffer_get_length(req->input_buffer));
+ if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
+ evhttp_request_free_auto(req);
+ return;
+ }
+ }
+
+ if (!req->ntoread) {
+ bufferevent_disable(evcon->bufev, EV_READ);
+ /* Completed content length */
+ evhttp_connection_done(evcon);
+ return;
+ }
+}
+
+#define get_deferred_queue(evcon) \
+ ((evcon)->base)
+
+/*
+ * Gets called when more data becomes available
+ */
+
+static void
+evhttp_read_cb(struct bufferevent *bufev, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+ struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+
+ /* Cancel if it's pending. */
+ event_deferred_cb_cancel_(get_deferred_queue(evcon),
+ &evcon->read_more_deferred_cb);
+
+ switch (evcon->state) {
+ case EVCON_READING_FIRSTLINE:
+ evhttp_read_firstline(evcon, req);
+ /* note the request may have been freed in
+ * evhttp_read_body */
+ break;
+ case EVCON_READING_HEADERS:
+ evhttp_read_header(evcon, req);
+ /* note the request may have been freed in
+ * evhttp_read_body */
+ break;
+ case EVCON_READING_BODY:
+ evhttp_read_body(evcon, req);
+ /* note the request may have been freed in
+ * evhttp_read_body */
+ break;
+ case EVCON_READING_TRAILER:
+ evhttp_read_trailer(evcon, req);
+ break;
+ case EVCON_IDLE:
+ {
+#ifdef USE_DEBUG
+ struct evbuffer *input;
+ size_t total_len;
+
+ input = bufferevent_get_input(evcon->bufev);
+ total_len = evbuffer_get_length(input);
+ event_debug(("%s: read "EV_SIZE_FMT
+ " bytes in EVCON_IDLE state,"
+ " resetting connection",
+ __func__, EV_SIZE_ARG(total_len)));
+#endif
+
+ evhttp_connection_reset_(evcon);
+ }
+ break;
+ case EVCON_DISCONNECTED:
+ case EVCON_CONNECTING:
+ case EVCON_WRITING:
+ default:
+ event_errx(1, "%s: illegal connection state %d",
+ __func__, evcon->state);
+ }
+}
+
+static void
+evhttp_deferred_read_cb(struct event_callback *cb, void *data)
+{
+ struct evhttp_connection *evcon = data;
+ evhttp_read_cb(evcon->bufev, evcon);
+}
+
+static void
+evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
+{
+ /* This is after writing the request to the server */
+ struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+ struct evbuffer *output = bufferevent_get_output(evcon->bufev);
+ EVUTIL_ASSERT(req != NULL);
+
+ EVUTIL_ASSERT(evcon->state == EVCON_WRITING);
+
+ /* We need to wait until we've written all of our output data before we can
+ * continue */
+ if (evbuffer_get_length(output) > 0)
+ return;
+
+ /* We are done writing our header and are now expecting the response */
+ req->kind = EVHTTP_RESPONSE;
+
+ evhttp_start_read_(evcon);
+}
+
+/*
+ * Clean up a connection object
+ */
+
+void
+evhttp_connection_free(struct evhttp_connection *evcon)
+{
+ struct evhttp_request *req;
+
+ /* notify interested parties that this connection is going down */
+ if (evcon->fd != -1) {
+ if (evhttp_connected(evcon) && evcon->closecb != NULL)
+ (*evcon->closecb)(evcon, evcon->closecb_arg);
+ }
+
+ /* remove all requests that might be queued on this
+ * connection. for server connections, this should be empty.
+ * because it gets dequeued either in evhttp_connection_done or
+ * evhttp_connection_fail_.
+ */
+ while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
+ evhttp_request_free_(evcon, req);
+ }
+
+ if (evcon->http_server != NULL) {
+ struct evhttp *http = evcon->http_server;
+ TAILQ_REMOVE(&http->connections, evcon, next);
+ }
+
+ if (event_initialized(&evcon->retry_ev)) {
+ event_del(&evcon->retry_ev);
+ event_debug_unassign(&evcon->retry_ev);
+ }
+
+ if (evcon->bufev != NULL)
+ bufferevent_free(evcon->bufev);
+
+ event_deferred_cb_cancel_(get_deferred_queue(evcon),
+ &evcon->read_more_deferred_cb);
+
+ if (evcon->fd == -1)
+ evcon->fd = bufferevent_getfd(evcon->bufev);
+
+ if (evcon->fd != -1) {
+ bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
+ shutdown(evcon->fd, EVUTIL_SHUT_WR);
+ if (!(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE)) {
+ evutil_closesocket(evcon->fd);
+ }
+ }
+
+ if (evcon->bind_address != NULL)
+ mm_free(evcon->bind_address);
+
+ if (evcon->address != NULL)
+ mm_free(evcon->address);
+
+ mm_free(evcon);
+}
+
+void
+evhttp_connection_free_on_completion(struct evhttp_connection *evcon) {
+ evcon->flags |= EVHTTP_CON_AUTOFREE;
+}
+
+void
+evhttp_connection_set_local_address(struct evhttp_connection *evcon,
+ const char *address)
+{
+ EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
+ if (evcon->bind_address)
+ mm_free(evcon->bind_address);
+ if ((evcon->bind_address = mm_strdup(address)) == NULL)
+ event_warn("%s: strdup", __func__);
+}
+
+void
+evhttp_connection_set_local_port(struct evhttp_connection *evcon,
+ ev_uint16_t port)
+{
+ EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
+ evcon->bind_port = port;
+}
+
+static void
+evhttp_request_dispatch(struct evhttp_connection* evcon)
+{
+ struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+
+ /* this should not usually happy but it's possible */
+ if (req == NULL)
+ return;
+
+ /* delete possible close detection events */
+ evhttp_connection_stop_detectclose(evcon);
+
+ /* we assume that the connection is connected already */
+ EVUTIL_ASSERT(evcon->state == EVCON_IDLE);
+
+ evcon->state = EVCON_WRITING;
+
+ /* Create the header from the store arguments */
+ evhttp_make_header(evcon, req);
+
+ evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
+}
+
+/* Reset our connection state: disables reading/writing, closes our fd (if
+* any), clears out buffers, and puts us in state DISCONNECTED. */
+void
+evhttp_connection_reset_(struct evhttp_connection *evcon)
+{
+ struct evbuffer *tmp;
+ int err;
+
+ /* XXXX This is not actually an optimal fix. Instead we ought to have
+ an API for "stop connecting", or use bufferevent_setfd to turn off
+ connecting. But for Libevent 2.0, this seems like a minimal change
+ least likely to disrupt the rest of the bufferevent and http code.
+
+ Why is this here? If the fd is set in the bufferevent, and the
+ bufferevent is connecting, then you can't actually stop the
+ bufferevent from trying to connect with bufferevent_disable(). The
+ connect will never trigger, since we close the fd, but the timeout
+ might. That caused an assertion failure in evhttp_connection_fail_.
+ */
+ bufferevent_disable_hard_(evcon->bufev, EV_READ|EV_WRITE);
+
+ if (evcon->fd == -1)
+ evcon->fd = bufferevent_getfd(evcon->bufev);
+
+ if (evcon->fd != -1) {
+ /* inform interested parties about connection close */
+ if (evhttp_connected(evcon) && evcon->closecb != NULL)
+ (*evcon->closecb)(evcon, evcon->closecb_arg);
+
+ shutdown(evcon->fd, EVUTIL_SHUT_WR);
+ evutil_closesocket(evcon->fd);
+ evcon->fd = -1;
+ }
+ bufferevent_setfd(evcon->bufev, -1);
+
+ /* we need to clean up any buffered data */
+ tmp = bufferevent_get_output(evcon->bufev);
+ err = evbuffer_drain(tmp, -1);
+ EVUTIL_ASSERT(!err && "drain output");
+ tmp = bufferevent_get_input(evcon->bufev);
+ err = evbuffer_drain(tmp, -1);
+ EVUTIL_ASSERT(!err && "drain input");
+
+ evcon->flags &= ~EVHTTP_CON_READING_ERROR;
+
+ evcon->state = EVCON_DISCONNECTED;
+}
+
+static void
+evhttp_connection_start_detectclose(struct evhttp_connection *evcon)
+{
+ evcon->flags |= EVHTTP_CON_CLOSEDETECT;
+
+ bufferevent_enable(evcon->bufev, EV_READ);
+}
+
+static void
+evhttp_connection_stop_detectclose(struct evhttp_connection *evcon)
+{
+ evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
+
+ bufferevent_disable(evcon->bufev, EV_READ);
+}
+
+static void
+evhttp_connection_retry(evutil_socket_t fd, short what, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+
+ evcon->state = EVCON_DISCONNECTED;
+ evhttp_connection_connect_(evcon);
+}
+
+static void
+evhttp_connection_cb_cleanup(struct evhttp_connection *evcon)
+{
+ struct evcon_requestq requests;
+
+ evhttp_connection_reset_(evcon);
+ if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) {
+ struct timeval tv_retry = evcon->initial_retry_timeout;
+ int i;
+ evtimer_assign(&evcon->retry_ev, evcon->base, evhttp_connection_retry, evcon);
+ /* XXXX handle failure from evhttp_add_event */
+ for (i=0; i < evcon->retry_cnt; ++i) {
+ tv_retry.tv_usec *= 2;
+ if (tv_retry.tv_usec > 1000000) {
+ tv_retry.tv_usec -= 1000000;
+ tv_retry.tv_sec += 1;
+ }
+ tv_retry.tv_sec *= 2;
+ if (tv_retry.tv_sec > 3600) {
+ tv_retry.tv_sec = 3600;
+ tv_retry.tv_usec = 0;
+ }
+ }
+ event_add(&evcon->retry_ev, &tv_retry);
+ evcon->retry_cnt++;
+ return;
+ }
+
+ /*
+ * User callback can do evhttp_make_request() on the same
+ * evcon so new request will be added to evcon->requests. To
+ * avoid freeing it prematurely we iterate over the copy of
+ * the queue.
+ */
+ TAILQ_INIT(&requests);
+ while (TAILQ_FIRST(&evcon->requests) != NULL) {
+ struct evhttp_request *request = TAILQ_FIRST(&evcon->requests);
+ TAILQ_REMOVE(&evcon->requests, request, next);
+ TAILQ_INSERT_TAIL(&requests, request, next);
+ }
+
+ /* for now, we just signal all requests by executing their callbacks */
+ while (TAILQ_FIRST(&requests) != NULL) {
+ struct evhttp_request *request = TAILQ_FIRST(&requests);
+ TAILQ_REMOVE(&requests, request, next);
+ request->evcon = NULL;
+
+ /* we might want to set an error here */
+ request->cb(request, request->cb_arg);
+ evhttp_request_free_auto(request);
+ }
+}
+
+static void
+evhttp_connection_read_on_write_error(struct evhttp_connection *evcon,
+ struct evhttp_request *req)
+{
+ struct evbuffer *buf;
+
+ /** Second time, we can't read anything */
+ if (evcon->flags & EVHTTP_CON_READING_ERROR) {
+ evcon->flags &= ~EVHTTP_CON_READING_ERROR;
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
+ return;
+ }
+
+ req->kind = EVHTTP_RESPONSE;
+
+ buf = bufferevent_get_output(evcon->bufev);
+ evbuffer_unfreeze(buf, 1);
+ evbuffer_drain(buf, evbuffer_get_length(buf));
+ evbuffer_freeze(buf, 1);
+
+ evhttp_start_read_(evcon);
+ evcon->flags |= EVHTTP_CON_READING_ERROR;
+}
+
+static void
+evhttp_error_cb(struct bufferevent *bufev, short what, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+ struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+
+ if (evcon->fd == -1)
+ evcon->fd = bufferevent_getfd(bufev);
+
+ switch (evcon->state) {
+ case EVCON_CONNECTING:
+ if (what & BEV_EVENT_TIMEOUT) {
+ event_debug(("%s: connection timeout for \"%s:%d\" on "
+ EV_SOCK_FMT,
+ __func__, evcon->address, evcon->port,
+ EV_SOCK_ARG(evcon->fd)));
+ evhttp_connection_cb_cleanup(evcon);
+ return;
+ }
+ break;
+
+ case EVCON_READING_BODY:
+ if (!req->chunked && req->ntoread < 0
+ && what == (BEV_EVENT_READING|BEV_EVENT_EOF)) {
+ /* EOF on read can be benign */
+ evhttp_connection_done(evcon);
+ return;
+ }
+ break;
+
+ case EVCON_DISCONNECTED:
+ case EVCON_IDLE:
+ case EVCON_READING_FIRSTLINE:
+ case EVCON_READING_HEADERS:
+ case EVCON_READING_TRAILER:
+ case EVCON_WRITING:
+ default:
+ break;
+ }
+
+ /* when we are in close detect mode, a read error means that
+ * the other side closed their connection.
+ */
+ if (evcon->flags & EVHTTP_CON_CLOSEDETECT) {
+ evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
+ EVUTIL_ASSERT(evcon->http_server == NULL);
+ /* For connections from the client, we just
+ * reset the connection so that it becomes
+ * disconnected.
+ */
+ EVUTIL_ASSERT(evcon->state == EVCON_IDLE);
+ evhttp_connection_reset_(evcon);
+
+ /*
+ * If we have no more requests that need completion
+ * and we want to auto-free the connection when all
+ * requests have been completed.
+ */
+ if (TAILQ_FIRST(&evcon->requests) == NULL
+ && (evcon->flags & EVHTTP_CON_OUTGOING)
+ && (evcon->flags & EVHTTP_CON_AUTOFREE)) {
+ evhttp_connection_free(evcon);
+ }
+ return;
+ }
+
+ if (what & BEV_EVENT_TIMEOUT) {
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT);
+ } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
+ if (what & BEV_EVENT_WRITING &&
+ evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR) {
+ evhttp_connection_read_on_write_error(evcon, req);
+ return;
+ }
+
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
+ } else if (what == BEV_EVENT_CONNECTED) {
+ } else {
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_BUFFER_ERROR);
+ }
+}
+
+/*
+ * Event callback for asynchronous connection attempt.
+ */
+static void
+evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+ int error;
+ ev_socklen_t errsz = sizeof(error);
+
+ if (evcon->fd == -1)
+ evcon->fd = bufferevent_getfd(bufev);
+
+ if (!(what & BEV_EVENT_CONNECTED)) {
+ /* some operating systems return ECONNREFUSED immediately
+ * when connecting to a local address. the cleanup is going
+ * to reschedule this function call.
+ */
+#ifndef _WIN32
+ if (errno == ECONNREFUSED)
+ goto cleanup;
+#endif
+ evhttp_error_cb(bufev, what, arg);
+ return;
+ }
+
+ if (evcon->fd == -1) {
+ event_debug(("%s: bufferevent_getfd returned -1",
+ __func__));
+ goto cleanup;
+ }
+
+ /* Check if the connection completed */
+ if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error,
+ &errsz) == -1) {
+ event_debug(("%s: getsockopt for \"%s:%d\" on "EV_SOCK_FMT,
+ __func__, evcon->address, evcon->port,
+ EV_SOCK_ARG(evcon->fd)));
+ goto cleanup;
+ }
+
+ if (error) {
+ event_debug(("%s: connect failed for \"%s:%d\" on "
+ EV_SOCK_FMT": %s",
+ __func__, evcon->address, evcon->port,
+ EV_SOCK_ARG(evcon->fd),
+ evutil_socket_error_to_string(error)));
+ goto cleanup;
+ }
+
+ /* We are connected to the server now */
+ event_debug(("%s: connected to \"%s:%d\" on "EV_SOCK_FMT"\n",
+ __func__, evcon->address, evcon->port,
+ EV_SOCK_ARG(evcon->fd)));
+
+ /* Reset the retry count as we were successful in connecting */
+ evcon->retry_cnt = 0;
+ evcon->state = EVCON_IDLE;
+
+ /* reset the bufferevent cbs */
+ bufferevent_setcb(evcon->bufev,
+ evhttp_read_cb,
+ evhttp_write_cb,
+ evhttp_error_cb,
+ evcon);
+
+ if (!evutil_timerisset(&evcon->timeout)) {
+ const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
+ const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
+ bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
+ } else {
+ bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
+ }
+
+ /* try to start requests that have queued up on this connection */
+ evhttp_request_dispatch(evcon);
+ return;
+
+ cleanup:
+ evhttp_connection_cb_cleanup(evcon);
+}
+
+/*
+ * Check if we got a valid response code.
+ */
+
+static int
+evhttp_valid_response_code(int code)
+{
+ if (code == 0)
+ return (0);
+
+ return (1);
+}
+
+static int
+evhttp_parse_http_version(const char *version, struct evhttp_request *req)
+{
+ int major, minor;
+ char ch;
+ int n = sscanf(version, "HTTP/%d.%d%c", &major, &minor, &ch);
+ if (n != 2 || major > 1) {
+ event_debug(("%s: bad version %s on message %p from %s",
+ __func__, version, req, req->remote_host));
+ return (-1);
+ }
+ req->major = major;
+ req->minor = minor;
+ return (0);
+}
+
+/* Parses the status line of a web server */
+
+static int
+evhttp_parse_response_line(struct evhttp_request *req, char *line)
+{
+ char *protocol;
+ char *number;
+ const char *readable = "";
+
+ protocol = strsep(&line, " ");
+ if (line == NULL)
+ return (-1);
+ number = strsep(&line, " ");
+ if (line != NULL)
+ readable = line;
+
+ if (evhttp_parse_http_version(protocol, req) < 0)
+ return (-1);
+
+ req->response_code = atoi(number);
+ if (!evhttp_valid_response_code(req->response_code)) {
+ event_debug(("%s: bad response code \"%s\"",
+ __func__, number));
+ return (-1);
+ }
+
+ if (req->response_code_line != NULL)
+ mm_free(req->response_code_line);
+ if ((req->response_code_line = mm_strdup(readable)) == NULL) {
+ event_warn("%s: strdup", __func__);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* Parse the first line of a HTTP request */
+
+static int
+evhttp_parse_request_line(struct evhttp_request *req, char *line)
+{
+ char *method;
+ char *uri;
+ char *version;
+ const char *hostname;
+ const char *scheme;
+ size_t method_len;
+ enum evhttp_cmd_type type;
+
+ /* Parse the request line */
+ method = strsep(&line, " ");
+ if (line == NULL)
+ return (-1);
+ uri = strsep(&line, " ");
+ if (line == NULL)
+ return (-1);
+ version = strsep(&line, " ");
+ if (line != NULL)
+ return (-1);
+
+ method_len = (uri - method) - 1;
+ type = EVHTTP_REQ_UNKNOWN_;
+
+ /* First line */
+ switch (method_len) {
+ case 3:
+ /* The length of the method string is 3, meaning it can only be one of two methods: GET or PUT */
+
+ /* Since both GET and PUT share the same character 'T' at the end,
+ * if the string doesn't have 'T', we can immediately determine this
+ * is an invalid HTTP method */
+
+ if (method[2] != 'T') {
+ break;
+ }
+
+ switch (*method) {
+ case 'G':
+ /* This first byte is 'G', so make sure the next byte is
+ * 'E', if it isn't then this isn't a valid method */
+
+ if (method[1] == 'E') {
+ type = EVHTTP_REQ_GET;
+ }
+
+ break;
+ case 'P':
+ /* First byte is P, check second byte for 'U', if not,
+ * we know it's an invalid method */
+ if (method[1] == 'U') {
+ type = EVHTTP_REQ_PUT;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ /* The method length is 4 bytes, leaving only the methods "POST" and "HEAD" */
+ switch (*method) {
+ case 'P':
+ if (method[3] == 'T' && method[2] == 'S' && method[1] == 'O') {
+ type = EVHTTP_REQ_POST;
+ }
+ break;
+ case 'H':
+ if (method[3] == 'D' && method[2] == 'A' && method[1] == 'E') {
+ type = EVHTTP_REQ_HEAD;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case 5:
+ /* Method length is 5 bytes, which can only encompass PATCH and TRACE */
+ switch (*method) {
+ case 'P':
+ if (method[4] == 'H' && method[3] == 'C' && method[2] == 'T' && method[1] == 'A') {
+ type = EVHTTP_REQ_PATCH;
+ }
+ break;
+ case 'T':
+ if (method[4] == 'E' && method[3] == 'C' && method[2] == 'A' && method[1] == 'R') {
+ type = EVHTTP_REQ_TRACE;
+ }
+
+ break;
+ default:
+ break;
+ }
+ break;
+ case 6:
+ /* Method length is 6, only valid method 6 bytes in length is DELEte */
+
+ /* If the first byte isn't 'D' then it's invalid */
+ if (*method != 'D') {
+ break;
+ }
+
+ if (method[5] == 'E' && method[4] == 'T' && method[3] == 'E' && method[2] == 'L' && method[1] == 'E') {
+ type = EVHTTP_REQ_DELETE;
+ }
+
+ break;
+ case 7:
+ /* Method length is 7, only valid methods are "OPTIONS" and "CONNECT" */
+ switch (*method) {
+ case 'O':
+ if (method[6] == 'S' && method[5] == 'N' && method[4] == 'O' &&
+ method[3] == 'I' && method[2] == 'T' && method[1] == 'P') {
+ type = EVHTTP_REQ_OPTIONS;
+ }
+
+ break;
+ case 'C':
+ if (method[6] == 'T' && method[5] == 'C' && method[4] == 'E' &&
+ method[3] == 'N' && method[2] == 'N' && method[1] == 'O') {
+ type = EVHTTP_REQ_CONNECT;
+ }
+
+ break;
+ default:
+ break;
+ }
+ break;
+ } /* switch */
+
+ if ((int)type == EVHTTP_REQ_UNKNOWN_) {
+ event_debug(("%s: bad method %s on request %p from %s",
+ __func__, method, req, req->remote_host));
+ /* No error yet; we'll give a better error later when
+ * we see that req->type is unsupported. */
+ }
+
+ req->type = type;
+
+ if (evhttp_parse_http_version(version, req) < 0)
+ return (-1);
+
+ if ((req->uri = mm_strdup(uri)) == NULL) {
+ event_debug(("%s: mm_strdup", __func__));
+ return (-1);
+ }
+
+ if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri,
+ EVHTTP_URI_NONCONFORMANT)) == NULL) {
+ return -1;
+ }
+
+ /* If we have an absolute-URI, check to see if it is an http request
+ for a known vhost or server alias. If we don't know about this
+ host, we consider it a proxy request. */
+ scheme = evhttp_uri_get_scheme(req->uri_elems);
+ hostname = evhttp_uri_get_host(req->uri_elems);
+ if (scheme && (!evutil_ascii_strcasecmp(scheme, "http") ||
+ !evutil_ascii_strcasecmp(scheme, "https")) &&
+ hostname &&
+ !evhttp_find_vhost(req->evcon->http_server, NULL, hostname))
+ req->flags |= EVHTTP_PROXY_REQUEST;
+
+ return (0);
+}
+
+const char *
+evhttp_find_header(const struct evkeyvalq *headers, const char *key)
+{
+ struct evkeyval *header;
+
+ TAILQ_FOREACH(header, headers, next) {
+ if (evutil_ascii_strcasecmp(header->key, key) == 0)
+ return (header->value);
+ }
+
+ return (NULL);
+}
+
+void
+evhttp_clear_headers(struct evkeyvalq *headers)
+{
+ struct evkeyval *header;
+
+ for (header = TAILQ_FIRST(headers);
+ header != NULL;
+ header = TAILQ_FIRST(headers)) {
+ TAILQ_REMOVE(headers, header, next);
+ mm_free(header->key);
+ mm_free(header->value);
+ mm_free(header);
+ }
+}
+
+/*
+ * Returns 0, if the header was successfully removed.
+ * Returns -1, if the header could not be found.
+ */
+
+int
+evhttp_remove_header(struct evkeyvalq *headers, const char *key)
+{
+ struct evkeyval *header;
+
+ TAILQ_FOREACH(header, headers, next) {
+ if (evutil_ascii_strcasecmp(header->key, key) == 0)
+ break;
+ }
+
+ if (header == NULL)
+ return (-1);
+
+ /* Free and remove the header that we found */
+ TAILQ_REMOVE(headers, header, next);
+ mm_free(header->key);
+ mm_free(header->value);
+ mm_free(header);
+
+ return (0);
+}
+
+static int
+evhttp_header_is_valid_value(const char *value)
+{
+ const char *p = value;
+
+ while ((p = strpbrk(p, "\r\n")) != NULL) {
+ /* we really expect only one new line */
+ p += strspn(p, "\r\n");
+ /* we expect a space or tab for continuation */
+ if (*p != ' ' && *p != '\t')
+ return (0);
+ }
+ return (1);
+}
+
+int
+evhttp_add_header(struct evkeyvalq *headers,
+ const char *key, const char *value)
+{
+ event_debug(("%s: key: %s val: %s\n", __func__, key, value));
+
+ if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
+ /* drop illegal headers */
+ event_debug(("%s: dropping illegal header key\n", __func__));
+ return (-1);
+ }
+
+ if (!evhttp_header_is_valid_value(value)) {
+ event_debug(("%s: dropping illegal header value\n", __func__));
+ return (-1);
+ }
+
+ return (evhttp_add_header_internal(headers, key, value));
+}
+
+static int
+evhttp_add_header_internal(struct evkeyvalq *headers,
+ const char *key, const char *value)
+{
+ struct evkeyval *header = mm_calloc(1, sizeof(struct evkeyval));
+ if (header == NULL) {
+ event_warn("%s: calloc", __func__);
+ return (-1);
+ }
+ if ((header->key = mm_strdup(key)) == NULL) {
+ mm_free(header);
+ event_warn("%s: strdup", __func__);
+ return (-1);
+ }
+ if ((header->value = mm_strdup(value)) == NULL) {
+ mm_free(header->key);
+ mm_free(header);
+ event_warn("%s: strdup", __func__);
+ return (-1);
+ }
+
+ TAILQ_INSERT_TAIL(headers, header, next);
+
+ return (0);
+}
+
+/*
+ * Parses header lines from a request or a response into the specified
+ * request object given an event buffer.
+ *
+ * Returns
+ * DATA_CORRUPTED on error
+ * MORE_DATA_EXPECTED when we need to read more headers
+ * ALL_DATA_READ when all headers have been read.
+ */
+
+enum message_read_status
+evhttp_parse_firstline_(struct evhttp_request *req, struct evbuffer *buffer)
+{
+ char *line;
+ enum message_read_status status = ALL_DATA_READ;
+
+ size_t line_length;
+ /* XXX try */
+ line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF);
+ if (line == NULL) {
+ if (req->evcon != NULL &&
+ evbuffer_get_length(buffer) > req->evcon->max_headers_size)
+ return (DATA_TOO_LONG);
+ else
+ return (MORE_DATA_EXPECTED);
+ }
+
+ if (req->evcon != NULL &&
+ line_length > req->evcon->max_headers_size) {
+ mm_free(line);
+ return (DATA_TOO_LONG);
+ }
+
+ req->headers_size = line_length;
+
+ switch (req->kind) {
+ case EVHTTP_REQUEST:
+ if (evhttp_parse_request_line(req, line) == -1)
+ status = DATA_CORRUPTED;
+ break;
+ case EVHTTP_RESPONSE:
+ if (evhttp_parse_response_line(req, line) == -1)
+ status = DATA_CORRUPTED;
+ break;
+ default:
+ status = DATA_CORRUPTED;
+ }
+
+ mm_free(line);
+ return (status);
+}
+
+static int
+evhttp_append_to_last_header(struct evkeyvalq *headers, char *line)
+{
+ struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq);
+ char *newval;
+ size_t old_len, line_len;
+
+ if (header == NULL)
+ return (-1);
+
+ old_len = strlen(header->value);
+
+ /* Strip space from start and end of line. */
+ while (*line == ' ' || *line == '\t')
+ ++line;
+ evutil_rtrim_lws_(line);
+
+ line_len = strlen(line);
+
+ newval = mm_realloc(header->value, old_len + line_len + 2);
+ if (newval == NULL)
+ return (-1);
+
+ newval[old_len] = ' ';
+ memcpy(newval + old_len + 1, line, line_len + 1);
+ header->value = newval;
+
+ return (0);
+}
+
+enum message_read_status
+evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer* buffer)
+{
+ enum message_read_status errcode = DATA_CORRUPTED;
+ char *line;
+ enum message_read_status status = MORE_DATA_EXPECTED;
+
+ struct evkeyvalq* headers = req->input_headers;
+ size_t line_length;
+ while ((line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF))
+ != NULL) {
+ char *skey, *svalue;
+
+ req->headers_size += line_length;
+
+ if (req->evcon != NULL &&
+ req->headers_size > req->evcon->max_headers_size) {
+ errcode = DATA_TOO_LONG;
+ goto error;
+ }
+
+ if (*line == '\0') { /* Last header - Done */
+ status = ALL_DATA_READ;
+ mm_free(line);
+ break;
+ }
+
+ /* Check if this is a continuation line */
+ if (*line == ' ' || *line == '\t') {
+ if (evhttp_append_to_last_header(headers, line) == -1)
+ goto error;
+ mm_free(line);
+ continue;
+ }
+
+ /* Processing of header lines */
+ svalue = line;
+ skey = strsep(&svalue, ":");
+ if (svalue == NULL)
+ goto error;
+
+ svalue += strspn(svalue, " ");
+ evutil_rtrim_lws_(svalue);
+
+ if (evhttp_add_header(headers, skey, svalue) == -1)
+ goto error;
+
+ mm_free(line);
+ }
+
+ if (status == MORE_DATA_EXPECTED) {
+ if (req->evcon != NULL &&
+ req->headers_size + evbuffer_get_length(buffer) > req->evcon->max_headers_size)
+ return (DATA_TOO_LONG);
+ }
+
+ return (status);
+
+ error:
+ mm_free(line);
+ return (errcode);
+}
+
+static int
+evhttp_get_body_length(struct evhttp_request *req)
+{
+ struct evkeyvalq *headers = req->input_headers;
+ const char *content_length;
+ const char *connection;
+
+ content_length = evhttp_find_header(headers, "Content-Length");
+ connection = evhttp_find_header(headers, "Connection");
+
+ if (content_length == NULL && connection == NULL)
+ req->ntoread = -1;
+ else if (content_length == NULL &&
+ evutil_ascii_strcasecmp(connection, "Close") != 0) {
+ /* Bad combination, we don't know when it will end */
+ event_warnx("%s: we got no content length, but the "
+ "server wants to keep the connection open: %s.",
+ __func__, connection);
+ return (-1);
+ } else if (content_length == NULL) {
+ req->ntoread = -1;
+ } else {
+ char *endp;
+ ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10);
+ if (*content_length == '\0' || *endp != '\0' || ntoread < 0) {
+ event_debug(("%s: illegal content length: %s",
+ __func__, content_length));
+ return (-1);
+ }
+ req->ntoread = ntoread;
+ }
+
+ event_debug(("%s: bytes to read: "EV_I64_FMT" (in buffer "EV_SIZE_FMT")\n",
+ __func__, EV_I64_ARG(req->ntoread),
+ EV_SIZE_ARG(evbuffer_get_length(bufferevent_get_input(req->evcon->bufev)))));
+
+ return (0);
+}
+
+static int
+evhttp_method_may_have_body(enum evhttp_cmd_type type)
+{
+ switch (type) {
+ case EVHTTP_REQ_POST:
+ case EVHTTP_REQ_PUT:
+ case EVHTTP_REQ_PATCH:
+ return 1;
+ case EVHTTP_REQ_TRACE:
+ return 0;
+ /* XXX May any of the below methods have a body? */
+ case EVHTTP_REQ_GET:
+ case EVHTTP_REQ_HEAD:
+ case EVHTTP_REQ_DELETE:
+ case EVHTTP_REQ_OPTIONS:
+ case EVHTTP_REQ_CONNECT:
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static void
+evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+ const char *xfer_enc;
+
+ /* If this is a request without a body, then we are done */
+ if (req->kind == EVHTTP_REQUEST &&
+ !evhttp_method_may_have_body(req->type)) {
+ evhttp_connection_done(evcon);
+ return;
+ }
+ evcon->state = EVCON_READING_BODY;
+ xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding");
+ if (xfer_enc != NULL && evutil_ascii_strcasecmp(xfer_enc, "chunked") == 0) {
+ req->chunked = 1;
+ req->ntoread = -1;
+ } else {
+ if (evhttp_get_body_length(req) == -1) {
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
+ return;
+ }
+ if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) {
+ /* An incoming request with no content-length and no
+ * transfer-encoding has no body. */
+ evhttp_connection_done(evcon);
+ return;
+ }
+ }
+
+ /* Should we send a 100 Continue status line? */
+ switch (evhttp_have_expect(req, 1)) {
+ case CONTINUE:
+ /* XXX It would be nice to do some sanity
+ checking here. Does the resource exist?
+ Should the resource accept post requests? If
+ no, we should respond with an error. For
+ now, just optimistically tell the client to
+ send their message body. */
+ if (req->ntoread > 0) {
+ /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */
+ if ((req->evcon->max_body_size <= EV_INT64_MAX) &&
+ (ev_uint64_t)req->ntoread > req->evcon->max_body_size) {
+ evhttp_lingering_fail(evcon, req);
+ return;
+ }
+ }
+ if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev)))
+ evhttp_send_continue(evcon, req);
+ break;
+ case OTHER:
+ evhttp_send_error(req, HTTP_EXPECTATIONFAILED, NULL);
+ return;
+ case NO: break;
+ }
+
+ evhttp_read_body(evcon, req);
+ /* note the request may have been freed in evhttp_read_body */
+}
+
+static void
+evhttp_read_firstline(struct evhttp_connection *evcon,
+ struct evhttp_request *req)
+{
+ enum message_read_status res;
+
+ res = evhttp_parse_firstline_(req, bufferevent_get_input(evcon->bufev));
+ if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) {
+ /* Error while reading, terminate */
+ event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
+ __func__, EV_SOCK_ARG(evcon->fd)));
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
+ return;
+ } else if (res == MORE_DATA_EXPECTED) {
+ /* Need more header lines */
+ return;
+ }
+
+ evcon->state = EVCON_READING_HEADERS;
+ evhttp_read_header(evcon, req);
+}
+
+static void
+evhttp_read_header(struct evhttp_connection *evcon,
+ struct evhttp_request *req)
+{
+ enum message_read_status res;
+ evutil_socket_t fd = evcon->fd;
+
+ res = evhttp_parse_headers_(req, bufferevent_get_input(evcon->bufev));
+ if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) {
+ /* Error while reading, terminate */
+ event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
+ __func__, EV_SOCK_ARG(fd)));
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
+ return;
+ } else if (res == MORE_DATA_EXPECTED) {
+ /* Need more header lines */
+ return;
+ }
+
+ /* Callback can shut down connection with negative return value */
+ if (req->header_cb != NULL) {
+ if ((*req->header_cb)(req, req->cb_arg) < 0) {
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
+ return;
+ }
+ }
+
+ /* Done reading headers, do the real work */
+ switch (req->kind) {
+ case EVHTTP_REQUEST:
+ event_debug(("%s: checking for post data on "EV_SOCK_FMT"\n",
+ __func__, EV_SOCK_ARG(fd)));
+ evhttp_get_body(evcon, req);
+ /* note the request may have been freed in evhttp_get_body */
+ break;
+
+ case EVHTTP_RESPONSE:
+ /* Start over if we got a 100 Continue response. */
+ if (req->response_code == 100) {
+ struct evbuffer *output = bufferevent_get_output(evcon->bufev);
+ evbuffer_add_buffer(output, req->output_buffer);
+ evhttp_start_write_(evcon);
+ return;
+ }
+ if (!evhttp_response_needs_body(req)) {
+ event_debug(("%s: skipping body for code %d\n",
+ __func__, req->response_code));
+ evhttp_connection_done(evcon);
+ } else {
+ event_debug(("%s: start of read body for %s on "
+ EV_SOCK_FMT"\n",
+ __func__, req->remote_host, EV_SOCK_ARG(fd)));
+ evhttp_get_body(evcon, req);
+ /* note the request may have been freed in
+ * evhttp_get_body */
+ }
+ break;
+
+ default:
+ event_warnx("%s: bad header on "EV_SOCK_FMT, __func__,
+ EV_SOCK_ARG(fd));
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
+ break;
+ }
+ /* request may have been freed above */
+}
+
+/*
+ * Creates a TCP connection to the specified port and executes a callback
+ * when finished. Failure or success is indicate by the passed connection
+ * object.
+ *
+ * Although this interface accepts a hostname, it is intended to take
+ * only numeric hostnames so that non-blocking DNS resolution can
+ * happen elsewhere.
+ */
+
+struct evhttp_connection *
+evhttp_connection_new(const char *address, ev_uint16_t port)
+{
+ return (evhttp_connection_base_new(NULL, NULL, address, port));
+}
+
+struct evhttp_connection *
+evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev,
+ const char *address, ev_uint16_t port)
+{
+ struct evhttp_connection *evcon = NULL;
+
+ event_debug(("Attempting connection to %s:%d\n", address, port));
+
+ if ((evcon = mm_calloc(1, sizeof(struct evhttp_connection))) == NULL) {
+ event_warn("%s: calloc failed", __func__);
+ goto error;
+ }
+
+ evcon->fd = -1;
+ evcon->port = port;
+
+ evcon->max_headers_size = EV_SIZE_MAX;
+ evcon->max_body_size = EV_SIZE_MAX;
+
+ evutil_timerclear(&evcon->timeout);
+ evcon->retry_cnt = evcon->retry_max = 0;
+
+ if ((evcon->address = mm_strdup(address)) == NULL) {
+ event_warn("%s: strdup failed", __func__);
+ goto error;
+ }
+
+ if (bev == NULL) {
+ if (!(bev = bufferevent_socket_new(base, -1, 0))) {
+ event_warn("%s: bufferevent_socket_new failed", __func__);
+ goto error;
+ }
+ }
+
+ bufferevent_setcb(bev, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon);
+ evcon->bufev = bev;
+
+ evcon->state = EVCON_DISCONNECTED;
+ TAILQ_INIT(&evcon->requests);
+
+ evcon->initial_retry_timeout.tv_sec = 2;
+ evcon->initial_retry_timeout.tv_usec = 0;
+
+ if (base != NULL) {
+ evcon->base = base;
+ if (bufferevent_get_base(bev) != base)
+ bufferevent_base_set(base, evcon->bufev);
+ }
+
+ event_deferred_cb_init_(
+ &evcon->read_more_deferred_cb,
+ bufferevent_get_priority(bev),
+ evhttp_deferred_read_cb, evcon);
+
+ evcon->dns_base = dnsbase;
+ evcon->ai_family = AF_UNSPEC;
+
+ return (evcon);
+
+ error:
+ if (evcon != NULL)
+ evhttp_connection_free(evcon);
+ return (NULL);
+}
+
+struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon)
+{
+ return evcon->bufev;
+}
+
+struct evhttp *
+evhttp_connection_get_server(struct evhttp_connection *evcon)
+{
+ return evcon->http_server;
+}
+
+struct evhttp_connection *
+evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase,
+ const char *address, ev_uint16_t port)
+{
+ return evhttp_connection_base_bufferevent_new(base, dnsbase, NULL, address, port);
+}
+
+void evhttp_connection_set_family(struct evhttp_connection *evcon,
+ int family)
+{
+ evcon->ai_family = family;
+}
+
+int evhttp_connection_set_flags(struct evhttp_connection *evcon,
+ int flags)
+{
+ int avail_flags = 0;
+ avail_flags |= EVHTTP_CON_REUSE_CONNECTED_ADDR;
+ avail_flags |= EVHTTP_CON_READ_ON_WRITE_ERROR;
+
+ if (flags & ~avail_flags || flags > EVHTTP_CON_PUBLIC_FLAGS_END)
+ return 1;
+ evcon->flags &= ~avail_flags;
+
+ evcon->flags |= flags;
+
+ return 0;
+}
+
+void
+evhttp_connection_set_base(struct evhttp_connection *evcon,
+ struct event_base *base)
+{
+ EVUTIL_ASSERT(evcon->base == NULL);
+ EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
+ evcon->base = base;
+ bufferevent_base_set(base, evcon->bufev);
+}
+
+void
+evhttp_connection_set_timeout(struct evhttp_connection *evcon,
+ int timeout_in_secs)
+{
+ if (timeout_in_secs == -1)
+ evhttp_connection_set_timeout_tv(evcon, NULL);
+ else {
+ struct timeval tv;
+ tv.tv_sec = timeout_in_secs;
+ tv.tv_usec = 0;
+ evhttp_connection_set_timeout_tv(evcon, &tv);
+ }
+}
+
+void
+evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon,
+ const struct timeval* tv)
+{
+ if (tv) {
+ evcon->timeout = *tv;
+ bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
+ } else {
+ const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
+ const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
+ evutil_timerclear(&evcon->timeout);
+ bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
+ }
+}
+
+void
+evhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon,
+ const struct timeval *tv)
+{
+ if (tv) {
+ evcon->initial_retry_timeout = *tv;
+ } else {
+ evutil_timerclear(&evcon->initial_retry_timeout);
+ evcon->initial_retry_timeout.tv_sec = 2;
+ }
+}
+
+void
+evhttp_connection_set_retries(struct evhttp_connection *evcon,
+ int retry_max)
+{
+ evcon->retry_max = retry_max;
+}
+
+void
+evhttp_connection_set_closecb(struct evhttp_connection *evcon,
+ void (*cb)(struct evhttp_connection *, void *), void *cbarg)
+{
+ evcon->closecb = cb;
+ evcon->closecb_arg = cbarg;
+}
+
+void
+evhttp_connection_get_peer(struct evhttp_connection *evcon,
+ char **address, ev_uint16_t *port)
+{
+ *address = evcon->address;
+ *port = evcon->port;
+}
+
+const struct sockaddr*
+evhttp_connection_get_addr(struct evhttp_connection *evcon)
+{
+ return bufferevent_socket_get_conn_address_(evcon->bufev);
+}
+
+int
+evhttp_connection_connect_(struct evhttp_connection *evcon)
+{
+ int old_state = evcon->state;
+ const char *address = evcon->address;
+ const struct sockaddr *sa = evhttp_connection_get_addr(evcon);
+ int ret;
+
+ if (evcon->state == EVCON_CONNECTING)
+ return (0);
+
+ evhttp_connection_reset_(evcon);
+
+ EVUTIL_ASSERT(!(evcon->flags & EVHTTP_CON_INCOMING));
+ evcon->flags |= EVHTTP_CON_OUTGOING;
+
+ if (evcon->bind_address || evcon->bind_port) {
+ evcon->fd = bind_socket(
+ evcon->bind_address, evcon->bind_port, 0 /*reuse*/);
+ if (evcon->fd == -1) {
+ event_debug(("%s: failed to bind to \"%s\"",
+ __func__, evcon->bind_address));
+ return (-1);
+ }
+
+ bufferevent_setfd(evcon->bufev, evcon->fd);
+ } else {
+ bufferevent_setfd(evcon->bufev, -1);
+ }
+
+ /* Set up a callback for successful connection setup */
+ bufferevent_setcb(evcon->bufev,
+ NULL /* evhttp_read_cb */,
+ NULL /* evhttp_write_cb */,
+ evhttp_connection_cb,
+ evcon);
+ if (!evutil_timerisset(&evcon->timeout)) {
+ const struct timeval conn_tv = { HTTP_CONNECT_TIMEOUT, 0 };
+ bufferevent_set_timeouts(evcon->bufev, &conn_tv, &conn_tv);
+ } else {
+ bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
+ }
+ /* make sure that we get a write callback */
+ bufferevent_enable(evcon->bufev, EV_WRITE);
+
+ evcon->state = EVCON_CONNECTING;
+
+ if (evcon->flags & EVHTTP_CON_REUSE_CONNECTED_ADDR &&
+ sa &&
+ (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)) {
+ int socklen = sizeof(struct sockaddr_in);
+ if (sa->sa_family == AF_INET6) {
+ socklen = sizeof(struct sockaddr_in6);
+ }
+ ret = bufferevent_socket_connect(evcon->bufev, sa, socklen);
+ } else {
+ ret = bufferevent_socket_connect_hostname(evcon->bufev,
+ evcon->dns_base, evcon->ai_family, address, evcon->port);
+ }
+
+ if (ret < 0) {
+ evcon->state = old_state;
+ event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed",
+ __func__, evcon->address);
+ /* some operating systems return ECONNREFUSED immediately
+ * when connecting to a local address. the cleanup is going
+ * to reschedule this function call.
+ */
+ evhttp_connection_cb_cleanup(evcon);
+ return (0);
+ }
+
+ return (0);
+}
+
+/*
+ * Starts an HTTP request on the provided evhttp_connection object.
+ * If the connection object is not connected to the web server already,
+ * this will start the connection.
+ */
+
+int
+evhttp_make_request(struct evhttp_connection *evcon,
+ struct evhttp_request *req,
+ enum evhttp_cmd_type type, const char *uri)
+{
+ /* We are making a request */
+ req->kind = EVHTTP_REQUEST;
+ req->type = type;
+ if (req->uri != NULL)
+ mm_free(req->uri);
+ if ((req->uri = mm_strdup(uri)) == NULL) {
+ event_warn("%s: strdup", __func__);
+ evhttp_request_free_auto(req);
+ return (-1);
+ }
+
+ /* Set the protocol version if it is not supplied */
+ if (!req->major && !req->minor) {
+ req->major = 1;
+ req->minor = 1;
+ }
+
+ EVUTIL_ASSERT(req->evcon == NULL);
+ req->evcon = evcon;
+ EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION));
+
+ TAILQ_INSERT_TAIL(&evcon->requests, req, next);
+
+ /* If the connection object is not connected; make it so */
+ if (!evhttp_connected(evcon)) {
+ int res = evhttp_connection_connect_(evcon);
+ /* evhttp_connection_fail_(), which is called through
+ * evhttp_connection_connect_(), assumes that req lies in
+ * evcon->requests. Thus, enqueue the request in advance and
+ * remove it in the error case. */
+ if (res != 0)
+ TAILQ_REMOVE(&evcon->requests, req, next);
+
+ return res;
+ }
+
+ /*
+ * If it's connected already and we are the first in the queue,
+ * then we can dispatch this request immediately. Otherwise, it
+ * will be dispatched once the pending requests are completed.
+ */
+ if (TAILQ_FIRST(&evcon->requests) == req)
+ evhttp_request_dispatch(evcon);
+
+ return (0);
+}
+
+void
+evhttp_cancel_request(struct evhttp_request *req)
+{
+ struct evhttp_connection *evcon = req->evcon;
+ if (evcon != NULL) {
+ /* We need to remove it from the connection */
+ if (TAILQ_FIRST(&evcon->requests) == req) {
+ /* it's currently being worked on, so reset
+ * the connection.
+ */
+ evhttp_connection_fail_(evcon,
+ EVREQ_HTTP_REQUEST_CANCEL);
+
+ /* connection fail freed the request */
+ return;
+ } else {
+ /* otherwise, we can just remove it from the
+ * queue
+ */
+ TAILQ_REMOVE(&evcon->requests, req, next);
+ }
+ }
+
+ evhttp_request_free_auto(req);
+}
+
+/*
+ * Reads data from file descriptor into request structure
+ * Request structure needs to be set up correctly.
+ */
+
+void
+evhttp_start_read_(struct evhttp_connection *evcon)
+{
+ bufferevent_disable(evcon->bufev, EV_WRITE);
+ bufferevent_enable(evcon->bufev, EV_READ);
+
+ evcon->state = EVCON_READING_FIRSTLINE;
+ /* Reset the bufferevent callbacks */
+ bufferevent_setcb(evcon->bufev,
+ evhttp_read_cb,
+ evhttp_write_cb,
+ evhttp_error_cb,
+ evcon);
+
+ /* If there's still data pending, process it next time through the
+ * loop. Don't do it now; that could get recusive. */
+ if (evbuffer_get_length(bufferevent_get_input(evcon->bufev))) {
+ event_deferred_cb_schedule_(get_deferred_queue(evcon),
+ &evcon->read_more_deferred_cb);
+ }
+}
+
+void
+evhttp_start_write_(struct evhttp_connection *evcon)
+{
+ bufferevent_disable(evcon->bufev, EV_WRITE);
+ bufferevent_enable(evcon->bufev, EV_READ);
+
+ evcon->state = EVCON_WRITING;
+ evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
+}
+
+static void
+evhttp_send_done(struct evhttp_connection *evcon, void *arg)
+{
+ int need_close;
+ struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+ TAILQ_REMOVE(&evcon->requests, req, next);
+
+ if (req->on_complete_cb != NULL) {
+ req->on_complete_cb(req, req->on_complete_cb_arg);
+ }
+
+ need_close =
+ (REQ_VERSION_BEFORE(req, 1, 1) &&
+ !evhttp_is_connection_keepalive(req->input_headers)) ||
+ evhttp_is_request_connection_close(req);
+
+ EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION);
+ evhttp_request_free(req);
+
+ if (need_close) {
+ evhttp_connection_free(evcon);
+ return;
+ }
+
+ /* we have a persistent connection; try to accept another request. */
+ if (evhttp_associate_new_request_with_connection(evcon) == -1) {
+ evhttp_connection_free(evcon);
+ }
+}
+
+/*
+ * Returns an error page.
+ */
+
+void
+evhttp_send_error(struct evhttp_request *req, int error, const char *reason)
+{
+
+#define ERR_FORMAT "<HTML><HEAD>\n" \
+ "<TITLE>%d %s</TITLE>\n" \
+ "</HEAD><BODY>\n" \
+ "<H1>%s</H1>\n" \
+ "</BODY></HTML>\n"
+
+ struct evbuffer *buf = evbuffer_new();
+ if (buf == NULL) {
+ /* if we cannot allocate memory; we just drop the connection */
+ evhttp_connection_free(req->evcon);
+ return;
+ }
+ if (reason == NULL) {
+ reason = evhttp_response_phrase_internal(error);
+ }
+
+ evhttp_response_code_(req, error, reason);
+
+ evbuffer_add_printf(buf, ERR_FORMAT, error, reason, reason);
+
+ evhttp_send_page_(req, buf);
+
+ evbuffer_free(buf);
+#undef ERR_FORMAT
+}
+
+/* Requires that headers and response code are already set up */
+
+static inline void
+evhttp_send(struct evhttp_request *req, struct evbuffer *databuf)
+{
+ struct evhttp_connection *evcon = req->evcon;
+
+ if (evcon == NULL) {
+ evhttp_request_free(req);
+ return;
+ }
+
+ EVUTIL_ASSERT(TAILQ_FIRST(&evcon->requests) == req);
+
+ /* we expect no more calls form the user on this request */
+ req->userdone = 1;
+
+ /* xxx: not sure if we really should expose the data buffer this way */
+ if (databuf != NULL)
+ evbuffer_add_buffer(req->output_buffer, databuf);
+
+ /* Adds headers to the response */
+ evhttp_make_header(evcon, req);
+
+ evhttp_write_buffer(evcon, evhttp_send_done, NULL);
+}
+
+void
+evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
+ struct evbuffer *databuf)
+{
+ evhttp_response_code_(req, code, reason);
+
+ evhttp_send(req, databuf);
+}
+
+void
+evhttp_send_reply_start(struct evhttp_request *req, int code,
+ const char *reason)
+{
+ evhttp_response_code_(req, code, reason);
+ if (evhttp_find_header(req->output_headers, "Content-Length") == NULL &&
+ REQ_VERSION_ATLEAST(req, 1, 1) &&
+ evhttp_response_needs_body(req)) {
+ /*
+ * prefer HTTP/1.1 chunked encoding to closing the connection;
+ * note RFC 2616 section 4.4 forbids it with Content-Length:
+ * and it's not necessary then anyway.
+ */
+ evhttp_add_header(req->output_headers, "Transfer-Encoding",
+ "chunked");
+ req->chunked = 1;
+ } else {
+ req->chunked = 0;
+ }
+ evhttp_make_header(req->evcon, req);
+ evhttp_write_buffer(req->evcon, NULL, NULL);
+}
+
+void
+evhttp_send_reply_chunk_with_cb(struct evhttp_request *req, struct evbuffer *databuf,
+ void (*cb)(struct evhttp_connection *, void *), void *arg)
+{
+ struct evhttp_connection *evcon = req->evcon;
+ struct evbuffer *output;
+
+ if (evcon == NULL)
+ return;
+
+ output = bufferevent_get_output(evcon->bufev);
+
+ if (evbuffer_get_length(databuf) == 0)
+ return;
+ if (!evhttp_response_needs_body(req))
+ return;
+ if (req->chunked) {
+ evbuffer_add_printf(output, "%x\r\n",
+ (unsigned)evbuffer_get_length(databuf));
+ }
+ evbuffer_add_buffer(output, databuf);
+ if (req->chunked) {
+ evbuffer_add(output, "\r\n", 2);
+ }
+ evhttp_write_buffer(evcon, cb, arg);
+}
+
+void
+evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
+{
+ evhttp_send_reply_chunk_with_cb(req, databuf, NULL, NULL);
+}
+void
+evhttp_send_reply_end(struct evhttp_request *req)
+{
+ struct evhttp_connection *evcon = req->evcon;
+ struct evbuffer *output;
+
+ if (evcon == NULL) {
+ evhttp_request_free(req);
+ return;
+ }
+
+ output = bufferevent_get_output(evcon->bufev);
+
+ /* we expect no more calls form the user on this request */
+ req->userdone = 1;
+
+ if (req->chunked) {
+ evbuffer_add(output, "0\r\n\r\n", 5);
+ evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
+ req->chunked = 0;
+ } else if (evbuffer_get_length(output) == 0) {
+ /* let the connection know that we are done with the request */
+ evhttp_send_done(evcon, NULL);
+ } else {
+ /* make the callback execute after all data has been written */
+ evcon->cb = evhttp_send_done;
+ evcon->cb_arg = NULL;
+ }
+}
+
+static const char *informational_phrases[] = {
+ /* 100 */ "Continue",
+ /* 101 */ "Switching Protocols"
+};
+
+static const char *success_phrases[] = {
+ /* 200 */ "OK",
+ /* 201 */ "Created",
+ /* 202 */ "Accepted",
+ /* 203 */ "Non-Authoritative Information",
+ /* 204 */ "No Content",
+ /* 205 */ "Reset Content",
+ /* 206 */ "Partial Content"
+};
+
+static const char *redirection_phrases[] = {
+ /* 300 */ "Multiple Choices",
+ /* 301 */ "Moved Permanently",
+ /* 302 */ "Found",
+ /* 303 */ "See Other",
+ /* 304 */ "Not Modified",
+ /* 305 */ "Use Proxy",
+ /* 307 */ "Temporary Redirect"
+};
+
+static const char *client_error_phrases[] = {
+ /* 400 */ "Bad Request",
+ /* 401 */ "Unauthorized",
+ /* 402 */ "Payment Required",
+ /* 403 */ "Forbidden",
+ /* 404 */ "Not Found",
+ /* 405 */ "Method Not Allowed",
+ /* 406 */ "Not Acceptable",
+ /* 407 */ "Proxy Authentication Required",
+ /* 408 */ "Request Time-out",
+ /* 409 */ "Conflict",
+ /* 410 */ "Gone",
+ /* 411 */ "Length Required",
+ /* 412 */ "Precondition Failed",
+ /* 413 */ "Request Entity Too Large",
+ /* 414 */ "Request-URI Too Large",
+ /* 415 */ "Unsupported Media Type",
+ /* 416 */ "Requested range not satisfiable",
+ /* 417 */ "Expectation Failed"
+};
+
+static const char *server_error_phrases[] = {
+ /* 500 */ "Internal Server Error",
+ /* 501 */ "Not Implemented",
+ /* 502 */ "Bad Gateway",
+ /* 503 */ "Service Unavailable",
+ /* 504 */ "Gateway Time-out",
+ /* 505 */ "HTTP Version not supported"
+};
+
+struct response_class {
+ const char *name;
+ size_t num_responses;
+ const char **responses;
+};
+
+#ifndef MEMBERSOF
+#define MEMBERSOF(x) (sizeof(x)/sizeof(x[0]))
+#endif
+
+static const struct response_class response_classes[] = {
+ /* 1xx */ { "Informational", MEMBERSOF(informational_phrases), informational_phrases },
+ /* 2xx */ { "Success", MEMBERSOF(success_phrases), success_phrases },
+ /* 3xx */ { "Redirection", MEMBERSOF(redirection_phrases), redirection_phrases },
+ /* 4xx */ { "Client Error", MEMBERSOF(client_error_phrases), client_error_phrases },
+ /* 5xx */ { "Server Error", MEMBERSOF(server_error_phrases), server_error_phrases }
+};
+
+static const char *
+evhttp_response_phrase_internal(int code)
+{
+ int klass = code / 100 - 1;
+ int subcode = code % 100;
+
+ /* Unknown class - can't do any better here */
+ if (klass < 0 || klass >= (int) MEMBERSOF(response_classes))
+ return "Unknown Status Class";
+
+ /* Unknown sub-code, return class name at least */
+ if (subcode >= (int) response_classes[klass].num_responses)
+ return response_classes[klass].name;
+
+ return response_classes[klass].responses[subcode];
+}
+
+void
+evhttp_response_code_(struct evhttp_request *req, int code, const char *reason)
+{
+ req->kind = EVHTTP_RESPONSE;
+ req->response_code = code;
+ if (req->response_code_line != NULL)
+ mm_free(req->response_code_line);
+ if (reason == NULL)
+ reason = evhttp_response_phrase_internal(code);
+ req->response_code_line = mm_strdup(reason);
+ if (req->response_code_line == NULL) {
+ event_warn("%s: strdup", __func__);
+ /* XXX what else can we do? */
+ }
+}
+
+void
+evhttp_send_page_(struct evhttp_request *req, struct evbuffer *databuf)
+{
+ if (!req->major || !req->minor) {
+ req->major = 1;
+ req->minor = 1;
+ }
+
+ if (req->kind != EVHTTP_RESPONSE)
+ evhttp_response_code_(req, 200, "OK");
+
+ evhttp_clear_headers(req->output_headers);
+ evhttp_add_header(req->output_headers, "Content-Type", "text/html");
+ evhttp_add_header(req->output_headers, "Connection", "close");
+
+ evhttp_send(req, databuf);
+}
+
+static const char uri_chars[256] = {
+ /* 0 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ /* 64 */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
+ /* 128 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 192 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+#define CHAR_IS_UNRESERVED(c) \
+ (uri_chars[(unsigned char)(c)])
+
+/*
+ * Helper functions to encode/decode a string for inclusion in a URI.
+ * The returned string must be freed by the caller.
+ */
+char *
+evhttp_uriencode(const char *uri, ev_ssize_t len, int space_as_plus)
+{
+ struct evbuffer *buf = evbuffer_new();
+ const char *p, *end;
+ char *result;
+
+ if (buf == NULL) {
+ return (NULL);
+ }
+
+
+ if (len >= 0) {
+ if (uri + len < uri) {
+ return (NULL);
+ }
+
+ end = uri + len;
+ } else {
+ size_t slen = strlen(uri);
+
+ if (slen >= EV_SSIZE_MAX) {
+ /* we don't want to mix signed and unsigned */
+ return (NULL);
+ }
+
+ if (uri + slen < uri) {
+ return (NULL);
+ }
+
+ end = uri + slen;
+ }
+
+ for (p = uri; p < end; p++) {
+ if (CHAR_IS_UNRESERVED(*p)) {
+ evbuffer_add(buf, p, 1);
+ } else if (*p == ' ' && space_as_plus) {
+ evbuffer_add(buf, "+", 1);
+ } else {
+ evbuffer_add_printf(buf, "%%%02X", (unsigned char)(*p));
+ }
+ }
+
+ evbuffer_add(buf, "", 1); /* NUL-terminator. */
+ result = mm_malloc(evbuffer_get_length(buf));
+
+ if (result)
+ evbuffer_remove(buf, result, evbuffer_get_length(buf));
+
+ evbuffer_free(buf);
+
+ return (result);
+}
+
+char *
+evhttp_encode_uri(const char *str)
+{
+ return evhttp_uriencode(str, -1, 0);
+}
+
+/*
+ * @param decode_plus_ctl: if 1, we decode plus into space. If 0, we don't.
+ * If -1, when true we transform plus to space only after we've seen
+ * a ?. -1 is deprecated.
+ * @return the number of bytes written to 'ret'.
+ */
+int
+evhttp_decode_uri_internal(
+ const char *uri, size_t length, char *ret, int decode_plus_ctl)
+{
+ char c;
+ int j;
+ int decode_plus = (decode_plus_ctl == 1) ? 1: 0;
+ unsigned i;
+
+ for (i = j = 0; i < length; i++) {
+ c = uri[i];
+ if (c == '?') {
+ if (decode_plus_ctl < 0)
+ decode_plus = 1;
+ } else if (c == '+' && decode_plus) {
+ c = ' ';
+ } else if ((i + 2) < length && c == '%' &&
+ EVUTIL_ISXDIGIT_(uri[i+1]) && EVUTIL_ISXDIGIT_(uri[i+2])) {
+ char tmp[3];
+ tmp[0] = uri[i+1];
+ tmp[1] = uri[i+2];
+ tmp[2] = '\0';
+ c = (char)strtol(tmp, NULL, 16);
+ i += 2;
+ }
+ ret[j++] = c;
+ }
+ ret[j] = '\0';
+
+ return (j);
+}
+
+/* deprecated */
+char *
+evhttp_decode_uri(const char *uri)
+{
+ char *ret;
+
+ if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) {
+ event_warn("%s: malloc(%lu)", __func__,
+ (unsigned long)(strlen(uri) + 1));
+ return (NULL);
+ }
+
+ evhttp_decode_uri_internal(uri, strlen(uri),
+ ret, -1 /*always_decode_plus*/);
+
+ return (ret);
+}
+
+char *
+evhttp_uridecode(const char *uri, int decode_plus, size_t *size_out)
+{
+ char *ret;
+ int n;
+
+ if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) {
+ event_warn("%s: malloc(%lu)", __func__,
+ (unsigned long)(strlen(uri) + 1));
+ return (NULL);
+ }
+
+ n = evhttp_decode_uri_internal(uri, strlen(uri),
+ ret, !!decode_plus/*always_decode_plus*/);
+
+ if (size_out) {
+ EVUTIL_ASSERT(n >= 0);
+ *size_out = (size_t)n;
+ }
+
+ return (ret);
+}
+
+/*
+ * Helper function to parse out arguments in a query.
+ * The arguments are separated by key and value.
+ */
+
+static int
+evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers,
+ int is_whole_uri)
+{
+ char *line=NULL;
+ char *argument;
+ char *p;
+ const char *query_part;
+ int result = -1;
+ struct evhttp_uri *uri=NULL;
+
+ TAILQ_INIT(headers);
+
+ if (is_whole_uri) {
+ uri = evhttp_uri_parse(str);
+ if (!uri)
+ goto error;
+ query_part = evhttp_uri_get_query(uri);
+ } else {
+ query_part = str;
+ }
+
+ /* No arguments - we are done */
+ if (!query_part || !strlen(query_part)) {
+ result = 0;
+ goto done;
+ }
+
+ if ((line = mm_strdup(query_part)) == NULL) {
+ event_warn("%s: strdup", __func__);
+ goto error;
+ }
+
+ p = argument = line;
+ while (p != NULL && *p != '\0') {
+ char *key, *value, *decoded_value;
+ argument = strsep(&p, "&");
+
+ value = argument;
+ key = strsep(&value, "=");
+ if (value == NULL || *key == '\0') {
+ goto error;
+ }
+
+ if ((decoded_value = mm_malloc(strlen(value) + 1)) == NULL) {
+ event_warn("%s: mm_malloc", __func__);
+ goto error;
+ }
+ evhttp_decode_uri_internal(value, strlen(value),
+ decoded_value, 1 /*always_decode_plus*/);
+ event_debug(("Query Param: %s -> %s\n", key, decoded_value));
+ evhttp_add_header_internal(headers, key, decoded_value);
+ mm_free(decoded_value);
+ }
+
+ result = 0;
+ goto done;
+error:
+ evhttp_clear_headers(headers);
+done:
+ if (line)
+ mm_free(line);
+ if (uri)
+ evhttp_uri_free(uri);
+ return result;
+}
+
+int
+evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
+{
+ return evhttp_parse_query_impl(uri, headers, 1);
+}
+int
+evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers)
+{
+ return evhttp_parse_query_impl(uri, headers, 0);
+}
+
+static struct evhttp_cb *
+evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req)
+{
+ struct evhttp_cb *cb;
+ size_t offset = 0;
+ char *translated;
+ const char *path;
+
+ /* Test for different URLs */
+ path = evhttp_uri_get_path(req->uri_elems);
+ offset = strlen(path);
+ if ((translated = mm_malloc(offset + 1)) == NULL)
+ return (NULL);
+ evhttp_decode_uri_internal(path, offset, translated,
+ 0 /* decode_plus */);
+
+ TAILQ_FOREACH(cb, callbacks, next) {
+ if (!strcmp(cb->what, translated)) {
+ mm_free(translated);
+ return (cb);
+ }
+ }
+
+ mm_free(translated);
+ return (NULL);
+}
+
+
+static int
+prefix_suffix_match(const char *pattern, const char *name, int ignorecase)
+{
+ char c;
+
+ while (1) {
+ switch (c = *pattern++) {
+ case '\0':
+ return *name == '\0';
+
+ case '*':
+ while (*name != '\0') {
+ if (prefix_suffix_match(pattern, name,
+ ignorecase))
+ return (1);
+ ++name;
+ }
+ return (0);
+ default:
+ if (c != *name) {
+ if (!ignorecase ||
+ EVUTIL_TOLOWER_(c) != EVUTIL_TOLOWER_(*name))
+ return (0);
+ }
+ ++name;
+ }
+ }
+ /* NOTREACHED */
+}
+
+/*
+ Search the vhost hierarchy beginning with http for a server alias
+ matching hostname. If a match is found, and outhttp is non-null,
+ outhttp is set to the matching http object and 1 is returned.
+*/
+
+static int
+evhttp_find_alias(struct evhttp *http, struct evhttp **outhttp,
+ const char *hostname)
+{
+ struct evhttp_server_alias *alias;
+ struct evhttp *vhost;
+
+ TAILQ_FOREACH(alias, &http->aliases, next) {
+ /* XXX Do we need to handle IP addresses? */
+ if (!evutil_ascii_strcasecmp(alias->alias, hostname)) {
+ if (outhttp)
+ *outhttp = http;
+ return 1;
+ }
+ }
+
+ /* XXX It might be good to avoid recursion here, but I don't
+ see a way to do that w/o a list. */
+ TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) {
+ if (evhttp_find_alias(vhost, outhttp, hostname))
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ Attempts to find the best http object to handle a request for a hostname.
+ All aliases for the root http object and vhosts are searched for an exact
+ match. Then, the vhost hierarchy is traversed again for a matching
+ pattern.
+
+ If an alias or vhost is matched, 1 is returned, and outhttp, if non-null,
+ is set with the best matching http object. If there are no matches, the
+ root http object is stored in outhttp and 0 is returned.
+*/
+
+static int
+evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp,
+ const char *hostname)
+{
+ struct evhttp *vhost;
+ struct evhttp *oldhttp;
+ int match_found = 0;
+
+ if (evhttp_find_alias(http, outhttp, hostname))
+ return 1;
+
+ do {
+ oldhttp = http;
+ TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) {
+ if (prefix_suffix_match(vhost->vhost_pattern,
+ hostname, 1 /* ignorecase */)) {
+ http = vhost;
+ match_found = 1;
+ break;
+ }
+ }
+ } while (oldhttp != http);
+
+ if (outhttp)
+ *outhttp = http;
+
+ return match_found;
+}
+
+static void
+evhttp_handle_request(struct evhttp_request *req, void *arg)
+{
+ struct evhttp *http = arg;
+ struct evhttp_cb *cb = NULL;
+ const char *hostname;
+
+ /* we have a new request on which the user needs to take action */
+ req->userdone = 0;
+
+ if (req->type == 0 || req->uri == NULL) {
+ evhttp_send_error(req, req->response_code, NULL);
+ return;
+ }
+
+ if ((http->allowed_methods & req->type) == 0) {
+ event_debug(("Rejecting disallowed method %x (allowed: %x)\n",
+ (unsigned)req->type, (unsigned)http->allowed_methods));
+ evhttp_send_error(req, HTTP_NOTIMPLEMENTED, NULL);
+ return;
+ }
+
+ /* handle potential virtual hosts */
+ hostname = evhttp_request_get_host(req);
+ if (hostname != NULL) {
+ evhttp_find_vhost(http, &http, hostname);
+ }
+
+ if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) {
+ (*cb->cb)(req, cb->cbarg);
+ return;
+ }
+
+ /* Generic call back */
+ if (http->gencb) {
+ (*http->gencb)(req, http->gencbarg);
+ return;
+ } else {
+ /* We need to send a 404 here */
+#define ERR_FORMAT "<html><head>" \
+ "<title>404 Not Found</title>" \
+ "</head><body>" \
+ "<h1>Not Found</h1>" \
+ "<p>The requested URL %s was not found on this server.</p>"\
+ "</body></html>\n"
+
+ char *escaped_html;
+ struct evbuffer *buf;
+
+ if ((escaped_html = evhttp_htmlescape(req->uri)) == NULL) {
+ evhttp_connection_free(req->evcon);
+ return;
+ }
+
+ if ((buf = evbuffer_new()) == NULL) {
+ mm_free(escaped_html);
+ evhttp_connection_free(req->evcon);
+ return;
+ }
+
+ evhttp_response_code_(req, HTTP_NOTFOUND, "Not Found");
+
+ evbuffer_add_printf(buf, ERR_FORMAT, escaped_html);
+
+ mm_free(escaped_html);
+
+ evhttp_send_page_(req, buf);
+
+ evbuffer_free(buf);
+#undef ERR_FORMAT
+ }
+}
+
+/* Listener callback when a connection arrives at a server. */
+static void
+accept_socket_cb(struct evconnlistener *listener, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, void *arg)
+{
+ struct evhttp *http = arg;
+
+ evhttp_get_request(http, nfd, peer_sa, peer_socklen);
+}
+
+int
+evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port)
+{
+ struct evhttp_bound_socket *bound =
+ evhttp_bind_socket_with_handle(http, address, port);
+ if (bound == NULL)
+ return (-1);
+ return (0);
+}
+
+struct evhttp_bound_socket *
+evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port)
+{
+ evutil_socket_t fd;
+ struct evhttp_bound_socket *bound;
+
+ if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
+ return (NULL);
+
+ if (listen(fd, 128) == -1) {
+ event_sock_warn(fd, "%s: listen", __func__);
+ evutil_closesocket(fd);
+ return (NULL);
+ }
+
+ bound = evhttp_accept_socket_with_handle(http, fd);
+
+ if (bound != NULL) {
+ event_debug(("Bound to port %d - Awaiting connections ... ",
+ port));
+ return (bound);
+ }
+
+ return (NULL);
+}
+
+int
+evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd)
+{
+ struct evhttp_bound_socket *bound =
+ evhttp_accept_socket_with_handle(http, fd);
+ if (bound == NULL)
+ return (-1);
+ return (0);
+}
+
+void
+evhttp_foreach_bound_socket(struct evhttp *http,
+ evhttp_bound_socket_foreach_fn *function,
+ void *argument)
+{
+ struct evhttp_bound_socket *bound;
+
+ TAILQ_FOREACH(bound, &http->sockets, next)
+ function(bound, argument);
+}
+
+struct evhttp_bound_socket *
+evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd)
+{
+ struct evhttp_bound_socket *bound;
+ struct evconnlistener *listener;
+ const int flags =
+ LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE;
+
+ listener = evconnlistener_new(http->base, NULL, NULL,
+ flags,
+ 0, /* Backlog is '0' because we already said 'listen' */
+ fd);
+ if (!listener)
+ return (NULL);
+
+ bound = evhttp_bind_listener(http, listener);
+ if (!bound) {
+ evconnlistener_free(listener);
+ return (NULL);
+ }
+ return (bound);
+}
+
+struct evhttp_bound_socket *
+evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener)
+{
+ struct evhttp_bound_socket *bound;
+
+ bound = mm_malloc(sizeof(struct evhttp_bound_socket));
+ if (bound == NULL)
+ return (NULL);
+
+ bound->listener = listener;
+ TAILQ_INSERT_TAIL(&http->sockets, bound, next);
+
+ evconnlistener_set_cb(listener, accept_socket_cb, http);
+ return bound;
+}
+
+evutil_socket_t
+evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound)
+{
+ return evconnlistener_get_fd(bound->listener);
+}
+
+struct evconnlistener *
+evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound)
+{
+ return bound->listener;
+}
+
+void
+evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound)
+{
+ TAILQ_REMOVE(&http->sockets, bound, next);
+ evconnlistener_free(bound->listener);
+ mm_free(bound);
+}
+
+static struct evhttp*
+evhttp_new_object(void)
+{
+ struct evhttp *http = NULL;
+
+ if ((http = mm_calloc(1, sizeof(struct evhttp))) == NULL) {
+ event_warn("%s: calloc", __func__);
+ return (NULL);
+ }
+
+ evutil_timerclear(&http->timeout);
+ evhttp_set_max_headers_size(http, EV_SIZE_MAX);
+ evhttp_set_max_body_size(http, EV_SIZE_MAX);
+ evhttp_set_default_content_type(http, "text/html; charset=ISO-8859-1");
+ evhttp_set_allowed_methods(http,
+ EVHTTP_REQ_GET |
+ EVHTTP_REQ_POST |
+ EVHTTP_REQ_HEAD |
+ EVHTTP_REQ_PUT |
+ EVHTTP_REQ_DELETE);
+
+ TAILQ_INIT(&http->sockets);
+ TAILQ_INIT(&http->callbacks);
+ TAILQ_INIT(&http->connections);
+ TAILQ_INIT(&http->virtualhosts);
+ TAILQ_INIT(&http->aliases);
+
+ return (http);
+}
+
+struct evhttp *
+evhttp_new(struct event_base *base)
+{
+ struct evhttp *http = NULL;
+
+ http = evhttp_new_object();
+ if (http == NULL)
+ return (NULL);
+ http->base = base;
+
+ return (http);
+}
+
+/*
+ * Start a web server on the specified address and port.
+ */
+
+struct evhttp *
+evhttp_start(const char *address, ev_uint16_t port)
+{
+ struct evhttp *http = NULL;
+
+ http = evhttp_new_object();
+ if (http == NULL)
+ return (NULL);
+ if (evhttp_bind_socket(http, address, port) == -1) {
+ mm_free(http);
+ return (NULL);
+ }
+
+ return (http);
+}
+
+void
+evhttp_free(struct evhttp* http)
+{
+ struct evhttp_cb *http_cb;
+ struct evhttp_connection *evcon;
+ struct evhttp_bound_socket *bound;
+ struct evhttp* vhost;
+ struct evhttp_server_alias *alias;
+
+ /* Remove the accepting part */
+ while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) {
+ TAILQ_REMOVE(&http->sockets, bound, next);
+
+ evconnlistener_free(bound->listener);
+
+ mm_free(bound);
+ }
+
+ while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) {
+ /* evhttp_connection_free removes the connection */
+ evhttp_connection_free(evcon);
+ }
+
+ while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) {
+ TAILQ_REMOVE(&http->callbacks, http_cb, next);
+ mm_free(http_cb->what);
+ mm_free(http_cb);
+ }
+
+ while ((vhost = TAILQ_FIRST(&http->virtualhosts)) != NULL) {
+ TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
+
+ evhttp_free(vhost);
+ }
+
+ if (http->vhost_pattern != NULL)
+ mm_free(http->vhost_pattern);
+
+ while ((alias = TAILQ_FIRST(&http->aliases)) != NULL) {
+ TAILQ_REMOVE(&http->aliases, alias, next);
+ mm_free(alias->alias);
+ mm_free(alias);
+ }
+
+ mm_free(http);
+}
+
+int
+evhttp_add_virtual_host(struct evhttp* http, const char *pattern,
+ struct evhttp* vhost)
+{
+ /* a vhost can only be a vhost once and should not have bound sockets */
+ if (vhost->vhost_pattern != NULL ||
+ TAILQ_FIRST(&vhost->sockets) != NULL)
+ return (-1);
+
+ vhost->vhost_pattern = mm_strdup(pattern);
+ if (vhost->vhost_pattern == NULL)
+ return (-1);
+
+ TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next_vhost);
+
+ return (0);
+}
+
+int
+evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost)
+{
+ if (vhost->vhost_pattern == NULL)
+ return (-1);
+
+ TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
+
+ mm_free(vhost->vhost_pattern);
+ vhost->vhost_pattern = NULL;
+
+ return (0);
+}
+
+int
+evhttp_add_server_alias(struct evhttp *http, const char *alias)
+{
+ struct evhttp_server_alias *evalias;
+
+ evalias = mm_calloc(1, sizeof(*evalias));
+ if (!evalias)
+ return -1;
+
+ evalias->alias = mm_strdup(alias);
+ if (!evalias->alias) {
+ mm_free(evalias);
+ return -1;
+ }
+
+ TAILQ_INSERT_TAIL(&http->aliases, evalias, next);
+
+ return 0;
+}
+
+int
+evhttp_remove_server_alias(struct evhttp *http, const char *alias)
+{
+ struct evhttp_server_alias *evalias;
+
+ TAILQ_FOREACH(evalias, &http->aliases, next) {
+ if (evutil_ascii_strcasecmp(evalias->alias, alias) == 0) {
+ TAILQ_REMOVE(&http->aliases, evalias, next);
+ mm_free(evalias->alias);
+ mm_free(evalias);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+void
+evhttp_set_timeout(struct evhttp* http, int timeout_in_secs)
+{
+ if (timeout_in_secs == -1) {
+ evhttp_set_timeout_tv(http, NULL);
+ } else {
+ struct timeval tv;
+ tv.tv_sec = timeout_in_secs;
+ tv.tv_usec = 0;
+ evhttp_set_timeout_tv(http, &tv);
+ }
+}
+
+void
+evhttp_set_timeout_tv(struct evhttp* http, const struct timeval* tv)
+{
+ if (tv) {
+ http->timeout = *tv;
+ } else {
+ evutil_timerclear(&http->timeout);
+ }
+}
+
+int evhttp_set_flags(struct evhttp *http, int flags)
+{
+ int avail_flags = 0;
+ avail_flags |= EVHTTP_SERVER_LINGERING_CLOSE;
+
+ if (flags & ~avail_flags)
+ return 1;
+ http->flags &= ~avail_flags;
+
+ http->flags |= flags;
+
+ return 0;
+}
+
+void
+evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size)
+{
+ if (max_headers_size < 0)
+ http->default_max_headers_size = EV_SIZE_MAX;
+ else
+ http->default_max_headers_size = max_headers_size;
+}
+
+void
+evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size)
+{
+ if (max_body_size < 0)
+ http->default_max_body_size = EV_UINT64_MAX;
+ else
+ http->default_max_body_size = max_body_size;
+}
+
+void
+evhttp_set_default_content_type(struct evhttp *http,
+ const char *content_type) {
+ http->default_content_type = content_type;
+}
+
+void
+evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods)
+{
+ http->allowed_methods = methods;
+}
+
+int
+evhttp_set_cb(struct evhttp *http, const char *uri,
+ void (*cb)(struct evhttp_request *, void *), void *cbarg)
+{
+ struct evhttp_cb *http_cb;
+
+ TAILQ_FOREACH(http_cb, &http->callbacks, next) {
+ if (strcmp(http_cb->what, uri) == 0)
+ return (-1);
+ }
+
+ if ((http_cb = mm_calloc(1, sizeof(struct evhttp_cb))) == NULL) {
+ event_warn("%s: calloc", __func__);
+ return (-2);
+ }
+
+ http_cb->what = mm_strdup(uri);
+ if (http_cb->what == NULL) {
+ event_warn("%s: strdup", __func__);
+ mm_free(http_cb);
+ return (-3);
+ }
+ http_cb->cb = cb;
+ http_cb->cbarg = cbarg;
+
+ TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next);
+
+ return (0);
+}
+
+int
+evhttp_del_cb(struct evhttp *http, const char *uri)
+{
+ struct evhttp_cb *http_cb;
+
+ TAILQ_FOREACH(http_cb, &http->callbacks, next) {
+ if (strcmp(http_cb->what, uri) == 0)
+ break;
+ }
+ if (http_cb == NULL)
+ return (-1);
+
+ TAILQ_REMOVE(&http->callbacks, http_cb, next);
+ mm_free(http_cb->what);
+ mm_free(http_cb);
+
+ return (0);
+}
+
+void
+evhttp_set_gencb(struct evhttp *http,
+ void (*cb)(struct evhttp_request *, void *), void *cbarg)
+{
+ http->gencb = cb;
+ http->gencbarg = cbarg;
+}
+
+void
+evhttp_set_bevcb(struct evhttp *http,
+ struct bufferevent* (*cb)(struct event_base *, void *), void *cbarg)
+{
+ http->bevcb = cb;
+ http->bevcbarg = cbarg;
+}
+
+/*
+ * Request related functions
+ */
+
+struct evhttp_request *
+evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg)
+{
+ struct evhttp_request *req = NULL;
+
+ /* Allocate request structure */
+ if ((req = mm_calloc(1, sizeof(struct evhttp_request))) == NULL) {
+ event_warn("%s: calloc", __func__);
+ goto error;
+ }
+
+ req->headers_size = 0;
+ req->body_size = 0;
+
+ req->kind = EVHTTP_RESPONSE;
+ req->input_headers = mm_calloc(1, sizeof(struct evkeyvalq));
+ if (req->input_headers == NULL) {
+ event_warn("%s: calloc", __func__);
+ goto error;
+ }
+ TAILQ_INIT(req->input_headers);
+
+ req->output_headers = mm_calloc(1, sizeof(struct evkeyvalq));
+ if (req->output_headers == NULL) {
+ event_warn("%s: calloc", __func__);
+ goto error;
+ }
+ TAILQ_INIT(req->output_headers);
+
+ if ((req->input_buffer = evbuffer_new()) == NULL) {
+ event_warn("%s: evbuffer_new", __func__);
+ goto error;
+ }
+
+ if ((req->output_buffer = evbuffer_new()) == NULL) {
+ event_warn("%s: evbuffer_new", __func__);
+ goto error;
+ }
+
+ req->cb = cb;
+ req->cb_arg = arg;
+
+ return (req);
+
+ error:
+ if (req != NULL)
+ evhttp_request_free(req);
+ return (NULL);
+}
+
+void
+evhttp_request_free(struct evhttp_request *req)
+{
+ if ((req->flags & EVHTTP_REQ_DEFER_FREE) != 0) {
+ req->flags |= EVHTTP_REQ_NEEDS_FREE;
+ return;
+ }
+
+ if (req->remote_host != NULL)
+ mm_free(req->remote_host);
+ if (req->uri != NULL)
+ mm_free(req->uri);
+ if (req->uri_elems != NULL)
+ evhttp_uri_free(req->uri_elems);
+ if (req->response_code_line != NULL)
+ mm_free(req->response_code_line);
+ if (req->host_cache != NULL)
+ mm_free(req->host_cache);
+
+ evhttp_clear_headers(req->input_headers);
+ mm_free(req->input_headers);
+
+ evhttp_clear_headers(req->output_headers);
+ mm_free(req->output_headers);
+
+ if (req->input_buffer != NULL)
+ evbuffer_free(req->input_buffer);
+
+ if (req->output_buffer != NULL)
+ evbuffer_free(req->output_buffer);
+
+ mm_free(req);
+}
+
+void
+evhttp_request_own(struct evhttp_request *req)
+{
+ req->flags |= EVHTTP_USER_OWNED;
+}
+
+int
+evhttp_request_is_owned(struct evhttp_request *req)
+{
+ return (req->flags & EVHTTP_USER_OWNED) != 0;
+}
+
+struct evhttp_connection *
+evhttp_request_get_connection(struct evhttp_request *req)
+{
+ return req->evcon;
+}
+
+struct event_base *
+evhttp_connection_get_base(struct evhttp_connection *conn)
+{
+ return conn->base;
+}
+
+void
+evhttp_request_set_chunked_cb(struct evhttp_request *req,
+ void (*cb)(struct evhttp_request *, void *))
+{
+ req->chunk_cb = cb;
+}
+
+void
+evhttp_request_set_header_cb(struct evhttp_request *req,
+ int (*cb)(struct evhttp_request *, void *))
+{
+ req->header_cb = cb;
+}
+
+void
+evhttp_request_set_error_cb(struct evhttp_request *req,
+ void (*cb)(enum evhttp_request_error, void *))
+{
+ req->error_cb = cb;
+}
+
+void
+evhttp_request_set_on_complete_cb(struct evhttp_request *req,
+ void (*cb)(struct evhttp_request *, void *), void *cb_arg)
+{
+ req->on_complete_cb = cb;
+ req->on_complete_cb_arg = cb_arg;
+}
+
+/*
+ * Allows for inspection of the request URI
+ */
+
+const char *
+evhttp_request_get_uri(const struct evhttp_request *req) {
+ if (req->uri == NULL)
+ event_debug(("%s: request %p has no uri\n", __func__, req));
+ return (req->uri);
+}
+
+const struct evhttp_uri *
+evhttp_request_get_evhttp_uri(const struct evhttp_request *req) {
+ if (req->uri_elems == NULL)
+ event_debug(("%s: request %p has no uri elems\n",
+ __func__, req));
+ return (req->uri_elems);
+}
+
+const char *
+evhttp_request_get_host(struct evhttp_request *req)
+{
+ const char *host = NULL;
+
+ if (req->host_cache)
+ return req->host_cache;
+
+ if (req->uri_elems)
+ host = evhttp_uri_get_host(req->uri_elems);
+ if (!host && req->input_headers) {
+ const char *p;
+ size_t len;
+
+ host = evhttp_find_header(req->input_headers, "Host");
+ /* The Host: header may include a port. Remove it here
+ to be consistent with uri_elems case above. */
+ if (host) {
+ p = host + strlen(host) - 1;
+ while (p > host && EVUTIL_ISDIGIT_(*p))
+ --p;
+ if (p > host && *p == ':') {
+ len = p - host;
+ req->host_cache = mm_malloc(len + 1);
+ if (!req->host_cache) {
+ event_warn("%s: malloc", __func__);
+ return NULL;
+ }
+ memcpy(req->host_cache, host, len);
+ req->host_cache[len] = '\0';
+ host = req->host_cache;
+ }
+ }
+ }
+
+ return host;
+}
+
+enum evhttp_cmd_type
+evhttp_request_get_command(const struct evhttp_request *req) {
+ return (req->type);
+}
+
+int
+evhttp_request_get_response_code(const struct evhttp_request *req)
+{
+ return req->response_code;
+}
+
+const char *
+evhttp_request_get_response_code_line(const struct evhttp_request *req)
+{
+ return req->response_code_line;
+}
+
+/** Returns the input headers */
+struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req)
+{
+ return (req->input_headers);
+}
+
+/** Returns the output headers */
+struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req)
+{
+ return (req->output_headers);
+}
+
+/** Returns the input buffer */
+struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req)
+{
+ return (req->input_buffer);
+}
+
+/** Returns the output buffer */
+struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req)
+{
+ return (req->output_buffer);
+}
+
+
+/*
+ * Takes a file descriptor to read a request from.
+ * The callback is executed once the whole request has been read.
+ */
+
+static struct evhttp_connection*
+evhttp_get_request_connection(
+ struct evhttp* http,
+ evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen)
+{
+ struct evhttp_connection *evcon;
+ char *hostname = NULL, *portname = NULL;
+ struct bufferevent* bev = NULL;
+
+ name_from_addr(sa, salen, &hostname, &portname);
+ if (hostname == NULL || portname == NULL) {
+ if (hostname) mm_free(hostname);
+ if (portname) mm_free(portname);
+ return (NULL);
+ }
+
+ event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n",
+ __func__, hostname, portname, EV_SOCK_ARG(fd)));
+
+ /* we need a connection object to put the http request on */
+ if (http->bevcb != NULL) {
+ bev = (*http->bevcb)(http->base, http->bevcbarg);
+ }
+ evcon = evhttp_connection_base_bufferevent_new(
+ http->base, NULL, bev, hostname, atoi(portname));
+ mm_free(hostname);
+ mm_free(portname);
+ if (evcon == NULL)
+ return (NULL);
+
+ evcon->max_headers_size = http->default_max_headers_size;
+ evcon->max_body_size = http->default_max_body_size;
+ if (http->flags & EVHTTP_SERVER_LINGERING_CLOSE)
+ evcon->flags |= EVHTTP_CON_LINGERING_CLOSE;
+
+ evcon->flags |= EVHTTP_CON_INCOMING;
+ evcon->state = EVCON_READING_FIRSTLINE;
+
+ evcon->fd = fd;
+
+ bufferevent_enable(evcon->bufev, EV_READ);
+ bufferevent_disable(evcon->bufev, EV_WRITE);
+ bufferevent_setfd(evcon->bufev, fd);
+
+ return (evcon);
+}
+
+static int
+evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
+{
+ struct evhttp *http = evcon->http_server;
+ struct evhttp_request *req;
+ if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL)
+ return (-1);
+
+ if ((req->remote_host = mm_strdup(evcon->address)) == NULL) {
+ event_warn("%s: strdup", __func__);
+ evhttp_request_free(req);
+ return (-1);
+ }
+ req->remote_port = evcon->port;
+
+ req->evcon = evcon; /* the request ends up owning the connection */
+ req->flags |= EVHTTP_REQ_OWN_CONNECTION;
+
+ /* We did not present the request to the user user yet, so treat it as
+ * if the user was done with the request. This allows us to free the
+ * request on a persistent connection if the client drops it without
+ * sending a request.
+ */
+ req->userdone = 1;
+
+ TAILQ_INSERT_TAIL(&evcon->requests, req, next);
+
+ req->kind = EVHTTP_REQUEST;
+
+
+ evhttp_start_read_(evcon);
+
+ return (0);
+}
+
+static void
+evhttp_get_request(struct evhttp *http, evutil_socket_t fd,
+ struct sockaddr *sa, ev_socklen_t salen)
+{
+ struct evhttp_connection *evcon;
+
+ evcon = evhttp_get_request_connection(http, fd, sa, salen);
+ if (evcon == NULL) {
+ event_sock_warn(fd, "%s: cannot get connection on "EV_SOCK_FMT,
+ __func__, EV_SOCK_ARG(fd));
+ evutil_closesocket(fd);
+ return;
+ }
+
+ /* the timeout can be used by the server to close idle connections */
+ if (evutil_timerisset(&http->timeout))
+ evhttp_connection_set_timeout_tv(evcon, &http->timeout);
+
+ /*
+ * if we want to accept more than one request on a connection,
+ * we need to know which http server it belongs to.
+ */
+ evcon->http_server = http;
+ TAILQ_INSERT_TAIL(&http->connections, evcon, next);
+
+ if (evhttp_associate_new_request_with_connection(evcon) == -1)
+ evhttp_connection_free(evcon);
+}
+
+
+/*
+ * Network helper functions that we do not want to export to the rest of
+ * the world.
+ */
+
+static void
+name_from_addr(struct sockaddr *sa, ev_socklen_t salen,
+ char **phost, char **pport)
+{
+ char ntop[NI_MAXHOST];
+ char strport[NI_MAXSERV];
+ int ni_result;
+
+#ifdef EVENT__HAVE_GETNAMEINFO
+ ni_result = getnameinfo(sa, salen,
+ ntop, sizeof(ntop), strport, sizeof(strport),
+ NI_NUMERICHOST|NI_NUMERICSERV);
+
+ if (ni_result != 0) {
+#ifdef EAI_SYSTEM
+ /* Windows doesn't have an EAI_SYSTEM. */
+ if (ni_result == EAI_SYSTEM)
+ event_err(1, "getnameinfo failed");
+ else
+#endif
+ event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result));
+ return;
+ }
+#else
+ ni_result = fake_getnameinfo(sa, salen,
+ ntop, sizeof(ntop), strport, sizeof(strport),
+ NI_NUMERICHOST|NI_NUMERICSERV);
+ if (ni_result != 0)
+ return;
+#endif
+
+ *phost = mm_strdup(ntop);
+ *pport = mm_strdup(strport);
+}
+
+/* Create a non-blocking socket and bind it */
+/* todo: rename this function */
+static evutil_socket_t
+bind_socket_ai(struct evutil_addrinfo *ai, int reuse)
+{
+ evutil_socket_t fd;
+
+ int on = 1, r;
+ int serrno;
+
+ /* Create listen socket */
+ fd = evutil_socket_(ai ? ai->ai_family : AF_INET,
+ SOCK_STREAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0);
+ if (fd == -1) {
+ event_sock_warn(-1, "socket");
+ return (-1);
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on))<0)
+ goto out;
+ if (reuse) {
+ if (evutil_make_listen_socket_reuseable(fd) < 0)
+ goto out;
+ }
+
+ if (ai != NULL) {
+ r = bind(fd, ai->ai_addr, (ev_socklen_t)ai->ai_addrlen);
+ if (r == -1)
+ goto out;
+ }
+
+ return (fd);
+
+ out:
+ serrno = EVUTIL_SOCKET_ERROR();
+ evutil_closesocket(fd);
+ EVUTIL_SET_SOCKET_ERROR(serrno);
+ return (-1);
+}
+
+static struct evutil_addrinfo *
+make_addrinfo(const char *address, ev_uint16_t port)
+{
+ struct evutil_addrinfo *ai = NULL;
+
+ struct evutil_addrinfo hints;
+ char strport[NI_MAXSERV];
+ int ai_result;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ /* turn NULL hostname into INADDR_ANY, and skip looking up any address
+ * types we don't have an interface to connect to. */
+ hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG;
+ evutil_snprintf(strport, sizeof(strport), "%d", port);
+ if ((ai_result = evutil_getaddrinfo(address, strport, &hints, &ai))
+ != 0) {
+ if (ai_result == EVUTIL_EAI_SYSTEM)
+ event_warn("getaddrinfo");
+ else
+ event_warnx("getaddrinfo: %s",
+ evutil_gai_strerror(ai_result));
+ return (NULL);
+ }
+
+ return (ai);
+}
+
+static evutil_socket_t
+bind_socket(const char *address, ev_uint16_t port, int reuse)
+{
+ evutil_socket_t fd;
+ struct evutil_addrinfo *aitop = NULL;
+
+ /* just create an unbound socket */
+ if (address == NULL && port == 0)
+ return bind_socket_ai(NULL, 0);
+
+ aitop = make_addrinfo(address, port);
+
+ if (aitop == NULL)
+ return (-1);
+
+ fd = bind_socket_ai(aitop, reuse);
+
+ evutil_freeaddrinfo(aitop);
+
+ return (fd);
+}
+
+struct evhttp_uri {
+ unsigned flags;
+ char *scheme; /* scheme; e.g http, ftp etc */
+ char *userinfo; /* userinfo (typically username:pass), or NULL */
+ char *host; /* hostname, IP address, or NULL */
+ int port; /* port, or zero */
+ char *path; /* path, or "". */
+ char *query; /* query, or NULL */
+ char *fragment; /* fragment or NULL */
+};
+
+struct evhttp_uri *
+evhttp_uri_new(void)
+{
+ struct evhttp_uri *uri = mm_calloc(sizeof(struct evhttp_uri), 1);
+ if (uri)
+ uri->port = -1;
+ return uri;
+}
+
+void
+evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags)
+{
+ uri->flags = flags;
+}
+
+/* Return true if the string starting at s and ending immediately before eos
+ * is a valid URI scheme according to RFC3986
+ */
+static int
+scheme_ok(const char *s, const char *eos)
+{
+ /* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */
+ EVUTIL_ASSERT(eos >= s);
+ if (s == eos)
+ return 0;
+ if (!EVUTIL_ISALPHA_(*s))
+ return 0;
+ while (++s < eos) {
+ if (! EVUTIL_ISALNUM_(*s) &&
+ *s != '+' && *s != '-' && *s != '.')
+ return 0;
+ }
+ return 1;
+}
+
+#define SUBDELIMS "!$&'()*+,;="
+
+/* Return true iff [s..eos) is a valid userinfo */
+static int
+userinfo_ok(const char *s, const char *eos)
+{
+ while (s < eos) {
+ if (CHAR_IS_UNRESERVED(*s) ||
+ strchr(SUBDELIMS, *s) ||
+ *s == ':')
+ ++s;
+ else if (*s == '%' && s+2 < eos &&
+ EVUTIL_ISXDIGIT_(s[1]) &&
+ EVUTIL_ISXDIGIT_(s[2]))
+ s += 3;
+ else
+ return 0;
+ }
+ return 1;
+}
+
+static int
+regname_ok(const char *s, const char *eos)
+{
+ while (s && s<eos) {
+ if (CHAR_IS_UNRESERVED(*s) ||
+ strchr(SUBDELIMS, *s))
+ ++s;
+ else if (*s == '%' &&
+ EVUTIL_ISXDIGIT_(s[1]) &&
+ EVUTIL_ISXDIGIT_(s[2]))
+ s += 3;
+ else
+ return 0;
+ }
+ return 1;
+}
+
+static int
+parse_port(const char *s, const char *eos)
+{
+ int portnum = 0;
+ while (s < eos) {
+ if (! EVUTIL_ISDIGIT_(*s))
+ return -1;
+ portnum = (portnum * 10) + (*s - '0');
+ if (portnum < 0)
+ return -1;
+ if (portnum > 65535)
+ return -1;
+ ++s;
+ }
+ return portnum;
+}
+
+/* returns 0 for bad, 1 for ipv6, 2 for IPvFuture */
+static int
+bracket_addr_ok(const char *s, const char *eos)
+{
+ if (s + 3 > eos || *s != '[' || *(eos-1) != ']')
+ return 0;
+ if (s[1] == 'v') {
+ /* IPvFuture, or junk.
+ "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+ */
+ s += 2; /* skip [v */
+ --eos;
+ if (!EVUTIL_ISXDIGIT_(*s)) /*require at least one*/
+ return 0;
+ while (s < eos && *s != '.') {
+ if (EVUTIL_ISXDIGIT_(*s))
+ ++s;
+ else
+ return 0;
+ }
+ if (*s != '.')
+ return 0;
+ ++s;
+ while (s < eos) {
+ if (CHAR_IS_UNRESERVED(*s) ||
+ strchr(SUBDELIMS, *s) ||
+ *s == ':')
+ ++s;
+ else
+ return 0;
+ }
+ return 2;
+ } else {
+ /* IPv6, or junk */
+ char buf[64];
+ ev_ssize_t n_chars = eos-s-2;
+ struct in6_addr in6;
+ if (n_chars >= 64) /* way too long */
+ return 0;
+ memcpy(buf, s+1, n_chars);
+ buf[n_chars]='\0';
+ return (evutil_inet_pton(AF_INET6,buf,&in6)==1) ? 1 : 0;
+ }
+}
+
+static int
+parse_authority(struct evhttp_uri *uri, char *s, char *eos)
+{
+ char *cp, *port;
+ EVUTIL_ASSERT(eos);
+ if (eos == s) {
+ uri->host = mm_strdup("");
+ if (uri->host == NULL) {
+ event_warn("%s: strdup", __func__);
+ return -1;
+ }
+ return 0;
+ }
+
+ /* Optionally, we start with "userinfo@" */
+
+ cp = strchr(s, '@');
+ if (cp && cp < eos) {
+ if (! userinfo_ok(s,cp))
+ return -1;
+ *cp++ = '\0';
+ uri->userinfo = mm_strdup(s);
+ if (uri->userinfo == NULL) {
+ event_warn("%s: strdup", __func__);
+ return -1;
+ }
+ } else {
+ cp = s;
+ }
+ /* Optionally, we end with ":port" */
+ for (port=eos-1; port >= cp && EVUTIL_ISDIGIT_(*port); --port)
+ ;
+ if (port >= cp && *port == ':') {
+ if (port+1 == eos) /* Leave port unspecified; the RFC allows a
+ * nil port */
+ uri->port = -1;
+ else if ((uri->port = parse_port(port+1, eos))<0)
+ return -1;
+ eos = port;
+ }
+ /* Now, cp..eos holds the "host" port, which can be an IPv4Address,
+ * an IP-Literal, or a reg-name */
+ EVUTIL_ASSERT(eos >= cp);
+ if (*cp == '[' && eos >= cp+2 && *(eos-1) == ']') {
+ /* IPv6address, IP-Literal, or junk. */
+ if (! bracket_addr_ok(cp, eos))
+ return -1;
+ } else {
+ /* Make sure the host part is ok. */
+ if (! regname_ok(cp,eos)) /* Match IPv4Address or reg-name */
+ return -1;
+ }
+ uri->host = mm_malloc(eos-cp+1);
+ if (uri->host == NULL) {
+ event_warn("%s: malloc", __func__);
+ return -1;
+ }
+ memcpy(uri->host, cp, eos-cp);
+ uri->host[eos-cp] = '\0';
+ return 0;
+
+}
+
+static char *
+end_of_authority(char *cp)
+{
+ while (*cp) {
+ if (*cp == '?' || *cp == '#' || *cp == '/')
+ return cp;
+ ++cp;
+ }
+ return cp;
+}
+
+enum uri_part {
+ PART_PATH,
+ PART_QUERY,
+ PART_FRAGMENT
+};
+
+/* Return the character after the longest prefix of 'cp' that matches...
+ * *pchar / "/" if allow_qchars is false, or
+ * *(pchar / "/" / "?") if allow_qchars is true.
+ */
+static char *
+end_of_path(char *cp, enum uri_part part, unsigned flags)
+{
+ if (flags & EVHTTP_URI_NONCONFORMANT) {
+ /* If NONCONFORMANT:
+ * Path is everything up to a # or ? or nul.
+ * Query is everything up a # or nul
+ * Fragment is everything up to a nul.
+ */
+ switch (part) {
+ case PART_PATH:
+ while (*cp && *cp != '#' && *cp != '?')
+ ++cp;
+ break;
+ case PART_QUERY:
+ while (*cp && *cp != '#')
+ ++cp;
+ break;
+ case PART_FRAGMENT:
+ cp += strlen(cp);
+ break;
+ };
+ return cp;
+ }
+
+ while (*cp) {
+ if (CHAR_IS_UNRESERVED(*cp) ||
+ strchr(SUBDELIMS, *cp) ||
+ *cp == ':' || *cp == '@' || *cp == '/')
+ ++cp;
+ else if (*cp == '%' && EVUTIL_ISXDIGIT_(cp[1]) &&
+ EVUTIL_ISXDIGIT_(cp[2]))
+ cp += 3;
+ else if (*cp == '?' && part != PART_PATH)
+ ++cp;
+ else
+ return cp;
+ }
+ return cp;
+}
+
+static int
+path_matches_noscheme(const char *cp)
+{
+ while (*cp) {
+ if (*cp == ':')
+ return 0;
+ else if (*cp == '/')
+ return 1;
+ ++cp;
+ }
+ return 1;
+}
+
+struct evhttp_uri *
+evhttp_uri_parse(const char *source_uri)
+{
+ return evhttp_uri_parse_with_flags(source_uri, 0);
+}
+
+struct evhttp_uri *
+evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags)
+{
+ char *readbuf = NULL, *readp = NULL, *token = NULL, *query = NULL;
+ char *path = NULL, *fragment = NULL;
+ int got_authority = 0;
+
+ struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri));
+ if (uri == NULL) {
+ event_warn("%s: calloc", __func__);
+ goto err;
+ }
+ uri->port = -1;
+ uri->flags = flags;
+
+ readbuf = mm_strdup(source_uri);
+ if (readbuf == NULL) {
+ event_warn("%s: strdup", __func__);
+ goto err;
+ }
+
+ readp = readbuf;
+ token = NULL;
+
+ /* We try to follow RFC3986 here as much as we can, and match
+ the productions
+
+ URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+
+ relative-ref = relative-part [ "?" query ] [ "#" fragment ]
+ */
+
+ /* 1. scheme: */
+ token = strchr(readp, ':');
+ if (token && scheme_ok(readp,token)) {
+ *token = '\0';
+ uri->scheme = mm_strdup(readp);
+ if (uri->scheme == NULL) {
+ event_warn("%s: strdup", __func__);
+ goto err;
+ }
+ readp = token+1; /* eat : */
+ }
+
+ /* 2. Optionally, "//" then an 'authority' part. */
+ if (readp[0]=='/' && readp[1] == '/') {
+ char *authority;
+ readp += 2;
+ authority = readp;
+ path = end_of_authority(readp);
+ if (parse_authority(uri, authority, path) < 0)
+ goto err;
+ readp = path;
+ got_authority = 1;
+ }
+
+ /* 3. Query: path-abempty, path-absolute, path-rootless, or path-empty
+ */
+ path = readp;
+ readp = end_of_path(path, PART_PATH, flags);
+
+ /* Query */
+ if (*readp == '?') {
+ *readp = '\0';
+ ++readp;
+ query = readp;
+ readp = end_of_path(readp, PART_QUERY, flags);
+ }
+ /* fragment */
+ if (*readp == '#') {
+ *readp = '\0';
+ ++readp;
+ fragment = readp;
+ readp = end_of_path(readp, PART_FRAGMENT, flags);
+ }
+ if (*readp != '\0') {
+ goto err;
+ }
+
+ /* These next two cases may be unreachable; I'm leaving them
+ * in to be defensive. */
+ /* If you didn't get an authority, the path can't begin with "//" */
+ if (!got_authority && path[0]=='/' && path[1]=='/')
+ goto err;
+ /* If you did get an authority, the path must begin with "/" or be
+ * empty. */
+ if (got_authority && path[0] != '/' && path[0] != '\0')
+ goto err;
+ /* (End of maybe-unreachable cases) */
+
+ /* If there was no scheme, the first part of the path (if any) must
+ * have no colon in it. */
+ if (! uri->scheme && !path_matches_noscheme(path))
+ goto err;
+
+ EVUTIL_ASSERT(path);
+ uri->path = mm_strdup(path);
+ if (uri->path == NULL) {
+ event_warn("%s: strdup", __func__);
+ goto err;
+ }
+
+ if (query) {
+ uri->query = mm_strdup(query);
+ if (uri->query == NULL) {
+ event_warn("%s: strdup", __func__);
+ goto err;
+ }
+ }
+ if (fragment) {
+ uri->fragment = mm_strdup(fragment);
+ if (uri->fragment == NULL) {
+ event_warn("%s: strdup", __func__);
+ goto err;
+ }
+ }
+
+ mm_free(readbuf);
+
+ return uri;
+err:
+ if (uri)
+ evhttp_uri_free(uri);
+ if (readbuf)
+ mm_free(readbuf);
+ return NULL;
+}
+
+void
+evhttp_uri_free(struct evhttp_uri *uri)
+{
+#define URI_FREE_STR_(f) \
+ if (uri->f) { \
+ mm_free(uri->f); \
+ }
+
+ URI_FREE_STR_(scheme);
+ URI_FREE_STR_(userinfo);
+ URI_FREE_STR_(host);
+ URI_FREE_STR_(path);
+ URI_FREE_STR_(query);
+ URI_FREE_STR_(fragment);
+
+ mm_free(uri);
+#undef URI_FREE_STR_
+}
+
+char *
+evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit)
+{
+ struct evbuffer *tmp = 0;
+ size_t joined_size = 0;
+ char *output = NULL;
+
+#define URI_ADD_(f) evbuffer_add(tmp, uri->f, strlen(uri->f))
+
+ if (!uri || !buf || !limit)
+ return NULL;
+
+ tmp = evbuffer_new();
+ if (!tmp)
+ return NULL;
+
+ if (uri->scheme) {
+ URI_ADD_(scheme);
+ evbuffer_add(tmp, ":", 1);
+ }
+ if (uri->host) {
+ evbuffer_add(tmp, "//", 2);
+ if (uri->userinfo)
+ evbuffer_add_printf(tmp,"%s@", uri->userinfo);
+ URI_ADD_(host);
+ if (uri->port >= 0)
+ evbuffer_add_printf(tmp,":%d", uri->port);
+
+ if (uri->path && uri->path[0] != '/' && uri->path[0] != '\0')
+ goto err;
+ }
+
+ if (uri->path)
+ URI_ADD_(path);
+
+ if (uri->query) {
+ evbuffer_add(tmp, "?", 1);
+ URI_ADD_(query);
+ }
+
+ if (uri->fragment) {
+ evbuffer_add(tmp, "#", 1);
+ URI_ADD_(fragment);
+ }
+
+ evbuffer_add(tmp, "\0", 1); /* NUL */
+
+ joined_size = evbuffer_get_length(tmp);
+
+ if (joined_size > limit) {
+ /* It doesn't fit. */
+ evbuffer_free(tmp);
+ return NULL;
+ }
+ evbuffer_remove(tmp, buf, joined_size);
+
+ output = buf;
+err:
+ evbuffer_free(tmp);
+
+ return output;
+#undef URI_ADD_
+}
+
+const char *
+evhttp_uri_get_scheme(const struct evhttp_uri *uri)
+{
+ return uri->scheme;
+}
+const char *
+evhttp_uri_get_userinfo(const struct evhttp_uri *uri)
+{
+ return uri->userinfo;
+}
+const char *
+evhttp_uri_get_host(const struct evhttp_uri *uri)
+{
+ return uri->host;
+}
+int
+evhttp_uri_get_port(const struct evhttp_uri *uri)
+{
+ return uri->port;
+}
+const char *
+evhttp_uri_get_path(const struct evhttp_uri *uri)
+{
+ return uri->path;
+}
+const char *
+evhttp_uri_get_query(const struct evhttp_uri *uri)
+{
+ return uri->query;
+}
+const char *
+evhttp_uri_get_fragment(const struct evhttp_uri *uri)
+{
+ return uri->fragment;
+}
+
+#define URI_SET_STR_(f) do { \
+ if (uri->f) \
+ mm_free(uri->f); \
+ if (f) { \
+ if ((uri->f = mm_strdup(f)) == NULL) { \
+ event_warn("%s: strdup()", __func__); \
+ return -1; \
+ } \
+ } else { \
+ uri->f = NULL; \
+ } \
+ } while(0)
+
+int
+evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme)
+{
+ if (scheme && !scheme_ok(scheme, scheme+strlen(scheme)))
+ return -1;
+
+ URI_SET_STR_(scheme);
+ return 0;
+}
+int
+evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo)
+{
+ if (userinfo && !userinfo_ok(userinfo, userinfo+strlen(userinfo)))
+ return -1;
+ URI_SET_STR_(userinfo);
+ return 0;
+}
+int
+evhttp_uri_set_host(struct evhttp_uri *uri, const char *host)
+{
+ if (host) {
+ if (host[0] == '[') {
+ if (! bracket_addr_ok(host, host+strlen(host)))
+ return -1;
+ } else {
+ if (! regname_ok(host, host+strlen(host)))
+ return -1;
+ }
+ }
+
+ URI_SET_STR_(host);
+ return 0;
+}
+int
+evhttp_uri_set_port(struct evhttp_uri *uri, int port)
+{
+ if (port < -1)
+ return -1;
+ uri->port = port;
+ return 0;
+}
+#define end_of_cpath(cp,p,f) \
+ ((const char*)(end_of_path(((char*)(cp)), (p), (f))))
+
+int
+evhttp_uri_set_path(struct evhttp_uri *uri, const char *path)
+{
+ if (path && end_of_cpath(path, PART_PATH, uri->flags) != path+strlen(path))
+ return -1;
+
+ URI_SET_STR_(path);
+ return 0;
+}
+int
+evhttp_uri_set_query(struct evhttp_uri *uri, const char *query)
+{
+ if (query && end_of_cpath(query, PART_QUERY, uri->flags) != query+strlen(query))
+ return -1;
+ URI_SET_STR_(query);
+ return 0;
+}
+int
+evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment)
+{
+ if (fragment && end_of_cpath(fragment, PART_FRAGMENT, uri->flags) != fragment+strlen(fragment))
+ return -1;
+ URI_SET_STR_(fragment);
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/evdns.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/evdns.h
new file mode 100644
index 000000000..8672db036
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/evdns.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT1_EVDNS_H_INCLUDED_
+#define EVENT1_EVDNS_H_INCLUDED_
+
+/** @file evdns.h
+
+ A dns subsystem for Libevent.
+
+ The <evdns.h> header is deprecated in Libevent 2.0 and later; please
+ use <event2/evdns.h> instead. Depending on what functionality you
+ need, you may also want to include more of the other <event2/...>
+ headers.
+ */
+
+#include <event.h>
+#include <event2/dns.h>
+#include <event2/dns_compat.h>
+#include <event2/dns_struct.h>
+
+#endif /* EVENT1_EVDNS_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event.h
new file mode 100644
index 000000000..ba5186713
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT1_EVENT_H_INCLUDED_
+#define EVENT1_EVENT_H_INCLUDED_
+
+/** @file event.h
+
+ A library for writing event-driven network servers.
+
+ The <event.h> header is deprecated in Libevent 2.0 and later; please
+ use <event2/event.h> instead. Depending on what functionality you
+ need, you may also want to include more of the other event2/
+ headers.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef EVENT__HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdarg.h>
+
+/* For int types. */
+#include <evutil.h>
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+
+#include <event2/event_struct.h>
+#include <event2/event.h>
+#include <event2/event_compat.h>
+#include <event2/buffer.h>
+#include <event2/buffer_compat.h>
+#include <event2/bufferevent.h>
+#include <event2/bufferevent_struct.h>
+#include <event2/bufferevent_compat.h>
+#include <event2/tag.h>
+#include <event2/tag_compat.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT1_EVENT_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/buffer.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/buffer.h
new file mode 100644
index 000000000..468588b9f
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/buffer.h
@@ -0,0 +1,1076 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_BUFFER_H_INCLUDED_
+#define EVENT2_BUFFER_H_INCLUDED_
+
+/** @file event2/buffer.h
+
+ Functions for buffering data for network sending or receiving.
+
+ An evbuffer can be used for preparing data before sending it to
+ the network or conversely for reading data from the network.
+ Evbuffers try to avoid memory copies as much as possible. As a
+ result, evbuffers can be used to pass data around without actually
+ incurring the overhead of copying the data.
+
+ A new evbuffer can be allocated with evbuffer_new(), and can be
+ freed with evbuffer_free(). Most users will be using evbuffers via
+ the bufferevent interface. To access a bufferevent's evbuffers, use
+ bufferevent_get_input() and bufferevent_get_output().
+
+ There are several guidelines for using evbuffers.
+
+ - if you already know how much data you are going to add as a result
+ of calling evbuffer_add() multiple times, it makes sense to use
+ evbuffer_expand() first to make sure that enough memory is allocated
+ before hand.
+
+ - evbuffer_add_buffer() adds the contents of one buffer to the other
+ without incurring any unnecessary memory copies.
+
+ - evbuffer_add() and evbuffer_add_buffer() do not mix very well:
+ if you use them, you will wind up with fragmented memory in your
+ buffer.
+
+ - For high-performance code, you may want to avoid copying data into and out
+ of buffers. You can skip the copy step by using
+ evbuffer_reserve_space()/evbuffer_commit_space() when writing into a
+ buffer, and evbuffer_peek() when reading.
+
+ In Libevent 2.0 and later, evbuffers are represented using a linked
+ list of memory chunks, with pointers to the first and last chunk in
+ the chain.
+
+ As the contents of an evbuffer can be stored in multiple different
+ memory blocks, it cannot be accessed directly. Instead, evbuffer_pullup()
+ can be used to force a specified number of bytes to be contiguous. This
+ will cause memory reallocation and memory copies if the data is split
+ across multiple blocks. It is more efficient, however, to use
+ evbuffer_peek() if you don't require that the memory to be contiguous.
+ */
+
+#include <event2/visibility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+#include <stdarg.h>
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+#include <event2/util.h>
+
+/**
+ An evbuffer is an opaque data type for efficiently buffering data to be
+ sent or received on the network.
+
+ @see event2/event.h for more information
+*/
+struct evbuffer
+#ifdef EVENT_IN_DOXYGEN_
+{}
+#endif
+;
+
+/**
+ Pointer to a position within an evbuffer.
+
+ Used when repeatedly searching through a buffer. Calling any function
+ that modifies or re-packs the buffer contents may invalidate all
+ evbuffer_ptrs for that buffer. Do not modify or contruct these values
+ except with evbuffer_ptr_set.
+
+ An evbuffer_ptr can represent any position from the start of a buffer up
+ to a position immediately after the end of a buffer.
+
+ @see evbuffer_ptr_set()
+ */
+struct evbuffer_ptr {
+ ev_ssize_t pos;
+
+ /* Do not alter or rely on the values of fields: they are for internal
+ * use */
+ struct {
+ void *chain;
+ size_t pos_in_chain;
+ } internal_;
+};
+
+/** Describes a single extent of memory inside an evbuffer. Used for
+ direct-access functions.
+
+ @see evbuffer_reserve_space, evbuffer_commit_space, evbuffer_peek
+ */
+#ifdef EVENT__HAVE_SYS_UIO_H
+#define evbuffer_iovec iovec
+/* Internal use -- defined only if we are using the native struct iovec */
+#define EVBUFFER_IOVEC_IS_NATIVE_
+#else
+struct evbuffer_iovec {
+ /** The start of the extent of memory. */
+ void *iov_base;
+ /** The length of the extent of memory. */
+ size_t iov_len;
+};
+#endif
+
+/**
+ Allocate storage for a new evbuffer.
+
+ @return a pointer to a newly allocated evbuffer struct, or NULL if an error
+ occurred
+ */
+EVENT2_EXPORT_SYMBOL
+struct evbuffer *evbuffer_new(void);
+/**
+ Deallocate storage for an evbuffer.
+
+ @param buf pointer to the evbuffer to be freed
+ */
+EVENT2_EXPORT_SYMBOL
+void evbuffer_free(struct evbuffer *buf);
+
+/**
+ Enable locking on an evbuffer so that it can safely be used by multiple
+ threads at the same time.
+
+ NOTE: when locking is enabled, the lock will be held when callbacks are
+ invoked. This could result in deadlock if you aren't careful. Plan
+ accordingly!
+
+ @param buf An evbuffer to make lockable.
+ @param lock A lock object, or NULL if we should allocate our own.
+ @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_enable_locking(struct evbuffer *buf, void *lock);
+
+/**
+ Acquire the lock on an evbuffer. Has no effect if locking was not enabled
+ with evbuffer_enable_locking.
+*/
+EVENT2_EXPORT_SYMBOL
+void evbuffer_lock(struct evbuffer *buf);
+
+/**
+ Release the lock on an evbuffer. Has no effect if locking was not enabled
+ with evbuffer_enable_locking.
+*/
+EVENT2_EXPORT_SYMBOL
+void evbuffer_unlock(struct evbuffer *buf);
+
+
+/** If this flag is set, then we will not use evbuffer_peek(),
+ * evbuffer_remove(), evbuffer_remove_buffer(), and so on to read bytes
+ * from this buffer: we'll only take bytes out of this buffer by
+ * writing them to the network (as with evbuffer_write_atmost), by
+ * removing them without observing them (as with evbuffer_drain),
+ * or by copying them all out at once (as with evbuffer_add_buffer).
+ *
+ * Using this option allows the implementation to use sendfile-based
+ * operations for evbuffer_add_file(); see that function for more
+ * information.
+ *
+ * This flag is on by default for bufferevents that can take advantage
+ * of it; you should never actually need to set it on a bufferevent's
+ * output buffer.
+ */
+#define EVBUFFER_FLAG_DRAINS_TO_FD 1
+
+/** Change the flags that are set for an evbuffer by adding more.
+ *
+ * @param buffer the evbuffer that the callback is watching.
+ * @param cb the callback whose status we want to change.
+ * @param flags One or more EVBUFFER_FLAG_* options
+ * @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_set_flags(struct evbuffer *buf, ev_uint64_t flags);
+/** Change the flags that are set for an evbuffer by removing some.
+ *
+ * @param buffer the evbuffer that the callback is watching.
+ * @param cb the callback whose status we want to change.
+ * @param flags One or more EVBUFFER_FLAG_* options
+ * @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_clear_flags(struct evbuffer *buf, ev_uint64_t flags);
+
+/**
+ Returns the total number of bytes stored in the evbuffer
+
+ @param buf pointer to the evbuffer
+ @return the number of bytes stored in the evbuffer
+*/
+EVENT2_EXPORT_SYMBOL
+size_t evbuffer_get_length(const struct evbuffer *buf);
+
+/**
+ Returns the number of contiguous available bytes in the first buffer chain.
+
+ This is useful when processing data that might be split into multiple
+ chains, or that might all be in the first chain. Calls to
+ evbuffer_pullup() that cause reallocation and copying of data can thus be
+ avoided.
+
+ @param buf pointer to the evbuffer
+ @return 0 if no data is available, otherwise the number of available bytes
+ in the first buffer chain.
+*/
+EVENT2_EXPORT_SYMBOL
+size_t evbuffer_get_contiguous_space(const struct evbuffer *buf);
+
+/**
+ Expands the available space in an evbuffer.
+
+ Expands the available space in the evbuffer to at least datlen, so that
+ appending datlen additional bytes will not require any new allocations.
+
+ @param buf the evbuffer to be expanded
+ @param datlen the new minimum length requirement
+ @return 0 if successful, or -1 if an error occurred
+*/
+EVENT2_EXPORT_SYMBOL
+int evbuffer_expand(struct evbuffer *buf, size_t datlen);
+
+/**
+ Reserves space in the last chain or chains of an evbuffer.
+
+ Makes space available in the last chain or chains of an evbuffer that can
+ be arbitrarily written to by a user. The space does not become
+ available for reading until it has been committed with
+ evbuffer_commit_space().
+
+ The space is made available as one or more extents, represented by
+ an initial pointer and a length. You can force the memory to be
+ available as only one extent. Allowing more extents, however, makes the
+ function more efficient.
+
+ Multiple subsequent calls to this function will make the same space
+ available until evbuffer_commit_space() has been called.
+
+ It is an error to do anything that moves around the buffer's internal
+ memory structures before committing the space.
+
+ NOTE: The code currently does not ever use more than two extents.
+ This may change in future versions.
+
+ @param buf the evbuffer in which to reserve space.
+ @param size how much space to make available, at minimum. The
+ total length of the extents may be greater than the requested
+ length.
+ @param vec an array of one or more evbuffer_iovec structures to
+ hold pointers to the reserved extents of memory.
+ @param n_vec The length of the vec array. Must be at least 1;
+ 2 is more efficient.
+ @return the number of provided extents, or -1 on error.
+ @see evbuffer_commit_space()
+*/
+EVENT2_EXPORT_SYMBOL
+int
+evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
+ struct evbuffer_iovec *vec, int n_vec);
+
+/**
+ Commits previously reserved space.
+
+ Commits some of the space previously reserved with
+ evbuffer_reserve_space(). It then becomes available for reading.
+
+ This function may return an error if the pointer in the extents do
+ not match those returned from evbuffer_reserve_space, or if data
+ has been added to the buffer since the space was reserved.
+
+ If you want to commit less data than you got reserved space for,
+ modify the iov_len pointer of the appropriate extent to a smaller
+ value. Note that you may have received more space than you
+ requested if it was available!
+
+ @param buf the evbuffer in which to reserve space.
+ @param vec one or two extents returned by evbuffer_reserve_space.
+ @param n_vecs the number of extents.
+ @return 0 on success, -1 on error
+ @see evbuffer_reserve_space()
+*/
+EVENT2_EXPORT_SYMBOL
+int evbuffer_commit_space(struct evbuffer *buf,
+ struct evbuffer_iovec *vec, int n_vecs);
+
+/**
+ Append data to the end of an evbuffer.
+
+ @param buf the evbuffer to be appended to
+ @param data pointer to the beginning of the data buffer
+ @param datlen the number of bytes to be copied from the data buffer
+ @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen);
+
+
+/**
+ Read data from an evbuffer and drain the bytes read.
+
+ If more bytes are requested than are available in the evbuffer, we
+ only extract as many bytes as were available.
+
+ @param buf the evbuffer to be read from
+ @param data the destination buffer to store the result
+ @param datlen the maximum size of the destination buffer
+ @return the number of bytes read, or -1 if we can't drain the buffer.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen);
+
+/**
+ Read data from an evbuffer, and leave the buffer unchanged.
+
+ If more bytes are requested than are available in the evbuffer, we
+ only extract as many bytes as were available.
+
+ @param buf the evbuffer to be read from
+ @param data_out the destination buffer to store the result
+ @param datlen the maximum size of the destination buffer
+ @return the number of bytes read, or -1 if we can't drain the buffer.
+ */
+EVENT2_EXPORT_SYMBOL
+ev_ssize_t evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen);
+
+/**
+ Read data from the middle of an evbuffer, and leave the buffer unchanged.
+
+ If more bytes are requested than are available in the evbuffer, we
+ only extract as many bytes as were available.
+
+ @param buf the evbuffer to be read from
+ @param pos the position to start reading from
+ @param data_out the destination buffer to store the result
+ @param datlen the maximum size of the destination buffer
+ @return the number of bytes read, or -1 if we can't drain the buffer.
+ */
+EVENT2_EXPORT_SYMBOL
+ev_ssize_t evbuffer_copyout_from(struct evbuffer *buf, const struct evbuffer_ptr *pos, void *data_out, size_t datlen);
+
+/**
+ Read data from an evbuffer into another evbuffer, draining
+ the bytes from the source buffer. This function avoids copy
+ operations to the extent possible.
+
+ If more bytes are requested than are available in src, the src
+ buffer is drained completely.
+
+ @param src the evbuffer to be read from
+ @param dst the destination evbuffer to store the result into
+ @param datlen the maximum numbers of bytes to transfer
+ @return the number of bytes read
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
+ size_t datlen);
+
+/** Used to tell evbuffer_readln what kind of line-ending to look for.
+ */
+enum evbuffer_eol_style {
+ /** Any sequence of CR and LF characters is acceptable as an
+ * EOL.
+ *
+ * Note that this style can produce ambiguous results: the
+ * sequence "CRLF" will be treated as a single EOL if it is
+ * all in the buffer at once, but if you first read a CR from
+ * the network and later read an LF from the network, it will
+ * be treated as two EOLs.
+ */
+ EVBUFFER_EOL_ANY,
+ /** An EOL is an LF, optionally preceded by a CR. This style is
+ * most useful for implementing text-based internet protocols. */
+ EVBUFFER_EOL_CRLF,
+ /** An EOL is a CR followed by an LF. */
+ EVBUFFER_EOL_CRLF_STRICT,
+ /** An EOL is a LF. */
+ EVBUFFER_EOL_LF,
+ /** An EOL is a NUL character (that is, a single byte with value 0) */
+ EVBUFFER_EOL_NUL
+};
+
+/**
+ * Read a single line from an evbuffer.
+ *
+ * Reads a line terminated by an EOL as determined by the evbuffer_eol_style
+ * argument. Returns a newly allocated nul-terminated string; the caller must
+ * free the returned value. The EOL is not included in the returned string.
+ *
+ * @param buffer the evbuffer to read from
+ * @param n_read_out if non-NULL, points to a size_t that is set to the
+ * number of characters in the returned string. This is useful for
+ * strings that can contain NUL characters.
+ * @param eol_style the style of line-ending to use.
+ * @return pointer to a single line, or NULL if an error occurred
+ */
+EVENT2_EXPORT_SYMBOL
+char *evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
+ enum evbuffer_eol_style eol_style);
+
+/**
+ Move all data from one evbuffer into another evbuffer.
+
+ This is a destructive add. The data from one buffer moves into
+ the other buffer. However, no unnecessary memory copies occur.
+
+ @param outbuf the output buffer
+ @param inbuf the input buffer
+ @return 0 if successful, or -1 if an error occurred
+
+ @see evbuffer_remove_buffer()
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf);
+
+/**
+ Copy data from one evbuffer into another evbuffer.
+
+ This is a non-destructive add. The data from one buffer is copied
+ into the other buffer. However, no unnecessary memory copies occur.
+
+ Note that buffers already containing buffer references can't be added
+ to other buffers.
+
+ @param outbuf the output buffer
+ @param inbuf the input buffer
+ @return 0 if successful, or -1 if an error occurred
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_add_buffer_reference(struct evbuffer *outbuf,
+ struct evbuffer *inbuf);
+
+/**
+ A cleanup function for a piece of memory added to an evbuffer by
+ reference.
+
+ @see evbuffer_add_reference()
+ */
+typedef void (*evbuffer_ref_cleanup_cb)(const void *data,
+ size_t datalen, void *extra);
+
+/**
+ Reference memory into an evbuffer without copying.
+
+ The memory needs to remain valid until all the added data has been
+ read. This function keeps just a reference to the memory without
+ actually incurring the overhead of a copy.
+
+ @param outbuf the output buffer
+ @param data the memory to reference
+ @param datlen how memory to reference
+ @param cleanupfn callback to be invoked when the memory is no longer
+ referenced by this evbuffer.
+ @param cleanupfn_arg optional argument to the cleanup callback
+ @return 0 if successful, or -1 if an error occurred
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_add_reference(struct evbuffer *outbuf,
+ const void *data, size_t datlen,
+ evbuffer_ref_cleanup_cb cleanupfn, void *cleanupfn_arg);
+
+/**
+ Copy data from a file into the evbuffer for writing to a socket.
+
+ This function avoids unnecessary data copies between userland and
+ kernel. If sendfile is available and the EVBUFFER_FLAG_DRAINS_TO_FD
+ flag is set, it uses those functions. Otherwise, it tries to use
+ mmap (or CreateFileMapping on Windows).
+
+ The function owns the resulting file descriptor and will close it
+ when finished transferring data.
+
+ The results of using evbuffer_remove() or evbuffer_pullup() on
+ evbuffers whose data was added using this function are undefined.
+
+ For more fine-grained control, use evbuffer_add_file_segment.
+
+ @param outbuf the output buffer
+ @param fd the file descriptor
+ @param offset the offset from which to read data
+ @param length how much data to read, or -1 to read as much as possible.
+ (-1 requires that 'fd' support fstat.)
+ @return 0 if successful, or -1 if an error occurred
+*/
+
+EVENT2_EXPORT_SYMBOL
+int evbuffer_add_file(struct evbuffer *outbuf, int fd, ev_off_t offset,
+ ev_off_t length);
+
+/**
+ An evbuffer_file_segment holds a reference to a range of a file --
+ possibly the whole file! -- for use in writing from an evbuffer to a
+ socket. It could be implemented with mmap, sendfile, splice, or (if all
+ else fails) by just pulling all the data into RAM. A single
+ evbuffer_file_segment can be added more than once, and to more than one
+ evbuffer.
+ */
+struct evbuffer_file_segment;
+
+/**
+ Flag for creating evbuffer_file_segment: If this flag is set, then when
+ the evbuffer_file_segment is freed and no longer in use by any
+ evbuffer, the underlying fd is closed.
+ */
+#define EVBUF_FS_CLOSE_ON_FREE 0x01
+/**
+ Flag for creating evbuffer_file_segment: Disable memory-map based
+ implementations.
+ */
+#define EVBUF_FS_DISABLE_MMAP 0x02
+/**
+ Flag for creating evbuffer_file_segment: Disable direct fd-to-fd
+ implementations (including sendfile and splice).
+
+ You might want to use this option if data needs to be taken from the
+ evbuffer by any means other than writing it to the network: the sendfile
+ backend is fast, but it only works for sending files directly to the
+ network.
+ */
+#define EVBUF_FS_DISABLE_SENDFILE 0x04
+/**
+ Flag for creating evbuffer_file_segment: Do not allocate a lock for this
+ segment. If this option is set, then neither the segment nor any
+ evbuffer it is added to may ever be accessed from more than one thread
+ at a time.
+ */
+#define EVBUF_FS_DISABLE_LOCKING 0x08
+
+/**
+ A cleanup function for a evbuffer_file_segment added to an evbuffer
+ for reference.
+ */
+typedef void (*evbuffer_file_segment_cleanup_cb)(
+ struct evbuffer_file_segment const* seg, int flags, void* arg);
+
+/**
+ Create and return a new evbuffer_file_segment for reading data from a
+ file and sending it out via an evbuffer.
+
+ This function avoids unnecessary data copies between userland and
+ kernel. Where available, it uses sendfile or splice.
+
+ The file descriptor must not be closed so long as any evbuffer is using
+ this segment.
+
+ The results of using evbuffer_remove() or evbuffer_pullup() or any other
+ function that reads bytes from an evbuffer on any evbuffer containing
+ the newly returned segment are undefined, unless you pass the
+ EVBUF_FS_DISABLE_SENDFILE flag to this function.
+
+ @param fd an open file to read from.
+ @param offset an index within the file at which to start reading
+ @param length how much data to read, or -1 to read as much as possible.
+ (-1 requires that 'fd' support fstat.)
+ @param flags any number of the EVBUF_FS_* flags
+ @return a new evbuffer_file_segment, or NULL on failure.
+ **/
+EVENT2_EXPORT_SYMBOL
+struct evbuffer_file_segment *evbuffer_file_segment_new(
+ int fd, ev_off_t offset, ev_off_t length, unsigned flags);
+
+/**
+ Free an evbuffer_file_segment
+
+ It is safe to call this function even if the segment has been added to
+ one or more evbuffers. The evbuffer_file_segment will not be freed
+ until no more references to it exist.
+ */
+EVENT2_EXPORT_SYMBOL
+void evbuffer_file_segment_free(struct evbuffer_file_segment *seg);
+
+/**
+ Add cleanup callback and argument for the callback to an
+ evbuffer_file_segment.
+
+ The cleanup callback will be invoked when no more references to the
+ evbuffer_file_segment exist.
+ **/
+EVENT2_EXPORT_SYMBOL
+void evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment *seg,
+ evbuffer_file_segment_cleanup_cb cb, void* arg);
+
+/**
+ Insert some or all of an evbuffer_file_segment at the end of an evbuffer
+
+ Note that the offset and length parameters of this function have a
+ different meaning from those provided to evbuffer_file_segment_new: When
+ you create the segment, the offset is the offset _within the file_, and
+ the length is the length _of the segment_, whereas when you add a
+ segment to an evbuffer, the offset is _within the segment_ and the
+ length is the length of the _part of the segment you want to use.
+
+ In other words, if you have a 10 KiB file, and you create an
+ evbuffer_file_segment for it with offset 20 and length 1000, it will
+ refer to bytes 20..1019 inclusive. If you then pass this segment to
+ evbuffer_add_file_segment and specify an offset of 20 and a length of
+ 50, you will be adding bytes 40..99 inclusive.
+
+ @param buf the evbuffer to append to
+ @param seg the segment to add
+ @param offset the offset within the segment to start from
+ @param length the amount of data to add, or -1 to add it all.
+ @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_add_file_segment(struct evbuffer *buf,
+ struct evbuffer_file_segment *seg, ev_off_t offset, ev_off_t length);
+
+/**
+ Append a formatted string to the end of an evbuffer.
+
+ The string is formated as printf.
+
+ @param buf the evbuffer that will be appended to
+ @param fmt a format string
+ @param ... arguments that will be passed to printf(3)
+ @return The number of bytes added if successful, or -1 if an error occurred.
+
+ @see evutil_printf(), evbuffer_add_vprintf()
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
+#ifdef __GNUC__
+ __attribute__((format(printf, 2, 3)))
+#endif
+;
+
+/**
+ Append a va_list formatted string to the end of an evbuffer.
+
+ @param buf the evbuffer that will be appended to
+ @param fmt a format string
+ @param ap a varargs va_list argument array that will be passed to vprintf(3)
+ @return The number of bytes added if successful, or -1 if an error occurred.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
+#ifdef __GNUC__
+ __attribute__((format(printf, 2, 0)))
+#endif
+;
+
+
+/**
+ Remove a specified number of bytes data from the beginning of an evbuffer.
+
+ @param buf the evbuffer to be drained
+ @param len the number of bytes to drain from the beginning of the buffer
+ @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_drain(struct evbuffer *buf, size_t len);
+
+
+/**
+ Write the contents of an evbuffer to a file descriptor.
+
+ The evbuffer will be drained after the bytes have been successfully written.
+
+ @param buffer the evbuffer to be written and drained
+ @param fd the file descriptor to be written to
+ @return the number of bytes written, or -1 if an error occurred
+ @see evbuffer_read()
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_write(struct evbuffer *buffer, evutil_socket_t fd);
+
+/**
+ Write some of the contents of an evbuffer to a file descriptor.
+
+ The evbuffer will be drained after the bytes have been successfully written.
+
+ @param buffer the evbuffer to be written and drained
+ @param fd the file descriptor to be written to
+ @param howmuch the largest allowable number of bytes to write, or -1
+ to write as many bytes as we can.
+ @return the number of bytes written, or -1 if an error occurred
+ @see evbuffer_read()
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd,
+ ev_ssize_t howmuch);
+
+/**
+ Read from a file descriptor and store the result in an evbuffer.
+
+ @param buffer the evbuffer to store the result
+ @param fd the file descriptor to read from
+ @param howmuch the number of bytes to be read
+ @return the number of bytes read, or -1 if an error occurred
+ @see evbuffer_write()
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_read(struct evbuffer *buffer, evutil_socket_t fd, int howmuch);
+
+/**
+ Search for a string within an evbuffer.
+
+ @param buffer the evbuffer to be searched
+ @param what the string to be searched for
+ @param len the length of the search string
+ @param start NULL or a pointer to a valid struct evbuffer_ptr.
+ @return a struct evbuffer_ptr whose 'pos' field has the offset of the
+ first occurrence of the string in the buffer after 'start'. The 'pos'
+ field of the result is -1 if the string was not found.
+ */
+EVENT2_EXPORT_SYMBOL
+struct evbuffer_ptr evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start);
+
+/**
+ Search for a string within part of an evbuffer.
+
+ @param buffer the evbuffer to be searched
+ @param what the string to be searched for
+ @param len the length of the search string
+ @param start NULL or a pointer to a valid struct evbuffer_ptr that
+ indicates where we should start searching.
+ @param end NULL or a pointer to a valid struct evbuffer_ptr that
+ indicates where we should stop searching.
+ @return a struct evbuffer_ptr whose 'pos' field has the offset of the
+ first occurrence of the string in the buffer after 'start'. The 'pos'
+ field of the result is -1 if the string was not found.
+ */
+EVENT2_EXPORT_SYMBOL
+struct evbuffer_ptr evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start, const struct evbuffer_ptr *end);
+
+/**
+ Defines how to adjust an evbuffer_ptr by evbuffer_ptr_set()
+
+ @see evbuffer_ptr_set() */
+enum evbuffer_ptr_how {
+ /** Sets the pointer to the position; can be called on with an
+ uninitialized evbuffer_ptr. */
+ EVBUFFER_PTR_SET,
+ /** Advances the pointer by adding to the current position. */
+ EVBUFFER_PTR_ADD
+};
+
+/**
+ Sets the search pointer in the buffer to position.
+
+ There are two ways to use this function: you can call
+ evbuffer_ptr_set(buf, &pos, N, EVBUFFER_PTR_SET)
+ to move 'pos' to a position 'N' bytes after the start of the buffer, or
+ evbuffer_ptr_set(buf, &pos, N, EVBUFFER_PTR_ADD)
+ to move 'pos' forward by 'N' bytes.
+
+ If evbuffer_ptr is not initialized, this function can only be called
+ with EVBUFFER_PTR_SET.
+
+ An evbuffer_ptr can represent any position from the start of the buffer to
+ a position immediately after the end of the buffer.
+
+ @param buffer the evbuffer to be search
+ @param ptr a pointer to a struct evbuffer_ptr
+ @param position the position at which to start the next search
+ @param how determines how the pointer should be manipulated.
+ @returns 0 on success or -1 otherwise
+*/
+EVENT2_EXPORT_SYMBOL
+int
+evbuffer_ptr_set(struct evbuffer *buffer, struct evbuffer_ptr *ptr,
+ size_t position, enum evbuffer_ptr_how how);
+
+/**
+ Search for an end-of-line string within an evbuffer.
+
+ @param buffer the evbuffer to be searched
+ @param start NULL or a pointer to a valid struct evbuffer_ptr to start
+ searching at.
+ @param eol_len_out If non-NULL, the pointed-to value will be set to
+ the length of the end-of-line string.
+ @param eol_style The kind of EOL to look for; see evbuffer_readln() for
+ more information
+ @return a struct evbuffer_ptr whose 'pos' field has the offset of the
+ first occurrence EOL in the buffer after 'start'. The 'pos'
+ field of the result is -1 if the string was not found.
+ */
+EVENT2_EXPORT_SYMBOL
+struct evbuffer_ptr evbuffer_search_eol(struct evbuffer *buffer,
+ struct evbuffer_ptr *start, size_t *eol_len_out,
+ enum evbuffer_eol_style eol_style);
+
+/** Function to peek at data inside an evbuffer without removing it or
+ copying it out.
+
+ Pointers to the data are returned by filling the 'vec_out' array
+ with pointers to one or more extents of data inside the buffer.
+
+ The total data in the extents that you get back may be more than
+ you requested (if there is more data last extent than you asked
+ for), or less (if you do not provide enough evbuffer_iovecs, or if
+ the buffer does not have as much data as you asked to see).
+
+ @param buffer the evbuffer to peek into,
+ @param len the number of bytes to try to peek. If len is negative, we
+ will try to fill as much of vec_out as we can. If len is negative
+ and vec_out is not provided, we return the number of evbuffer_iovecs
+ that would be needed to get all the data in the buffer.
+ @param start_at an evbuffer_ptr indicating the point at which we
+ should start looking for data. NULL means, "At the start of the
+ buffer."
+ @param vec_out an array of evbuffer_iovec
+ @param n_vec the length of vec_out. If 0, we only count how many
+ extents would be necessary to point to the requested amount of
+ data.
+ @return The number of extents needed. This may be less than n_vec
+ if we didn't need all the evbuffer_iovecs we were given, or more
+ than n_vec if we would need more to return all the data that was
+ requested.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len,
+ struct evbuffer_ptr *start_at,
+ struct evbuffer_iovec *vec_out, int n_vec);
+
+
+/** Structure passed to an evbuffer_cb_func evbuffer callback
+
+ @see evbuffer_cb_func, evbuffer_add_cb()
+ */
+struct evbuffer_cb_info {
+ /** The number of bytes in this evbuffer when callbacks were last
+ * invoked. */
+ size_t orig_size;
+ /** The number of bytes added since callbacks were last invoked. */
+ size_t n_added;
+ /** The number of bytes removed since callbacks were last invoked. */
+ size_t n_deleted;
+};
+
+/** Type definition for a callback that is invoked whenever data is added or
+ removed from an evbuffer.
+
+ An evbuffer may have one or more callbacks set at a time. The order
+ in which they are executed is undefined.
+
+ A callback function may add more callbacks, or remove itself from the
+ list of callbacks, or add or remove data from the buffer. It may not
+ remove another callback from the list.
+
+ If a callback adds or removes data from the buffer or from another
+ buffer, this can cause a recursive invocation of your callback or
+ other callbacks. If you ask for an infinite loop, you might just get
+ one: watch out!
+
+ @param buffer the buffer whose size has changed
+ @param info a structure describing how the buffer changed.
+ @param arg a pointer to user data
+*/
+typedef void (*evbuffer_cb_func)(struct evbuffer *buffer, const struct evbuffer_cb_info *info, void *arg);
+
+struct evbuffer_cb_entry;
+/** Add a new callback to an evbuffer.
+
+ Subsequent calls to evbuffer_add_cb() add new callbacks. To remove this
+ callback, call evbuffer_remove_cb or evbuffer_remove_cb_entry.
+
+ @param buffer the evbuffer to be monitored
+ @param cb the callback function to invoke when the evbuffer is modified,
+ or NULL to remove all callbacks.
+ @param cbarg an argument to be provided to the callback function
+ @return a handle to the callback on success, or NULL on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+struct evbuffer_cb_entry *evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg);
+
+/** Remove a callback from an evbuffer, given a handle returned from
+ evbuffer_add_cb.
+
+ Calling this function invalidates the handle.
+
+ @return 0 if a callback was removed, or -1 if no matching callback was
+ found.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_remove_cb_entry(struct evbuffer *buffer,
+ struct evbuffer_cb_entry *ent);
+
+/** Remove a callback from an evbuffer, given the function and argument
+ used to add it.
+
+ @return 0 if a callback was removed, or -1 if no matching callback was
+ found.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg);
+
+/** If this flag is not set, then a callback is temporarily disabled, and
+ * should not be invoked.
+ *
+ * @see evbuffer_cb_set_flags(), evbuffer_cb_clear_flags()
+ */
+#define EVBUFFER_CB_ENABLED 1
+
+/** Change the flags that are set for a callback on a buffer by adding more.
+
+ @param buffer the evbuffer that the callback is watching.
+ @param cb the callback whose status we want to change.
+ @param flags EVBUFFER_CB_ENABLED to re-enable the callback.
+ @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_cb_set_flags(struct evbuffer *buffer,
+ struct evbuffer_cb_entry *cb, ev_uint32_t flags);
+
+/** Change the flags that are set for a callback on a buffer by removing some
+
+ @param buffer the evbuffer that the callback is watching.
+ @param cb the callback whose status we want to change.
+ @param flags EVBUFFER_CB_ENABLED to disable the callback.
+ @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_cb_clear_flags(struct evbuffer *buffer,
+ struct evbuffer_cb_entry *cb, ev_uint32_t flags);
+
+#if 0
+/** Postpone calling a given callback until unsuspend is called later.
+
+ This is different from disabling the callback, since the callback will get
+ invoked later if the buffer size changes between now and when we unsuspend
+ it.
+
+ @param the buffer that the callback is watching.
+ @param cb the callback we want to suspend.
+ */
+EVENT2_EXPORT_SYMBOL
+void evbuffer_cb_suspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb);
+/** Stop postponing a callback that we postponed with evbuffer_cb_suspend.
+
+ If data was added to or removed from the buffer while the callback was
+ suspended, the callback will get called once now.
+
+ @param the buffer that the callback is watching.
+ @param cb the callback we want to stop suspending.
+ */
+EVENT2_EXPORT_SYMBOL
+void evbuffer_cb_unsuspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb);
+#endif
+
+/**
+ Makes the data at the beginning of an evbuffer contiguous.
+
+ @param buf the evbuffer to make contiguous
+ @param size the number of bytes to make contiguous, or -1 to make the
+ entire buffer contiguous.
+ @return a pointer to the contiguous memory array, or NULL if param size
+ requested more data than is present in the buffer.
+*/
+
+EVENT2_EXPORT_SYMBOL
+unsigned char *evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size);
+
+/**
+ Prepends data to the beginning of the evbuffer
+
+ @param buf the evbuffer to which to prepend data
+ @param data a pointer to the memory to prepend
+ @param size the number of bytes to prepend
+ @return 0 if successful, or -1 otherwise
+*/
+
+EVENT2_EXPORT_SYMBOL
+int evbuffer_prepend(struct evbuffer *buf, const void *data, size_t size);
+
+/**
+ Prepends all data from the src evbuffer to the beginning of the dst
+ evbuffer.
+
+ @param dst the evbuffer to which to prepend data
+ @param src the evbuffer to prepend; it will be emptied as a result
+ @return 0 if successful, or -1 otherwise
+*/
+EVENT2_EXPORT_SYMBOL
+int evbuffer_prepend_buffer(struct evbuffer *dst, struct evbuffer* src);
+
+/**
+ Prevent calls that modify an evbuffer from succeeding. A buffer may
+ frozen at the front, at the back, or at both the front and the back.
+
+ If the front of a buffer is frozen, operations that drain data from
+ the front of the buffer, or that prepend data to the buffer, will
+ fail until it is unfrozen. If the back a buffer is frozen, operations
+ that append data from the buffer will fail until it is unfrozen.
+
+ @param buf The buffer to freeze
+ @param at_front If true, we freeze the front of the buffer. If false,
+ we freeze the back.
+ @return 0 on success, -1 on failure.
+*/
+EVENT2_EXPORT_SYMBOL
+int evbuffer_freeze(struct evbuffer *buf, int at_front);
+/**
+ Re-enable calls that modify an evbuffer.
+
+ @param buf The buffer to un-freeze
+ @param at_front If true, we unfreeze the front of the buffer. If false,
+ we unfreeze the back.
+ @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_unfreeze(struct evbuffer *buf, int at_front);
+
+struct event_base;
+/**
+ Force all the callbacks on an evbuffer to be run, not immediately after
+ the evbuffer is altered, but instead from inside the event loop.
+
+ This can be used to serialize all the callbacks to a single thread
+ of execution.
+ */
+EVENT2_EXPORT_SYMBOL
+int evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base);
+
+/**
+ Append data from 1 or more iovec's to an evbuffer
+
+ Calculates the number of bytes needed for an iovec structure and guarantees
+ all data will fit into a single chain. Can be used in lieu of functionality
+ which calls evbuffer_add() constantly before being used to increase
+ performance.
+
+ @param buffer the destination buffer
+ @param vec the source iovec
+ @param n_vec the number of iovec structures.
+ @return the number of bytes successfully written to the output buffer.
+*/
+EVENT2_EXPORT_SYMBOL
+size_t evbuffer_add_iovec(struct evbuffer * buffer, struct evbuffer_iovec * vec, int n_vec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_BUFFER_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/buffer_compat.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/buffer_compat.h
new file mode 100644
index 000000000..24f828c21
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/buffer_compat.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef EVENT2_BUFFER_COMPAT_H_INCLUDED_
+#define EVENT2_BUFFER_COMPAT_H_INCLUDED_
+
+#include <event2/visibility.h>
+
+/** @file event2/buffer_compat.h
+
+ Obsolete and deprecated versions of the functions in buffer.h: provided
+ only for backward compatibility.
+ */
+
+
+/**
+ Obsolete alias for evbuffer_readln(buffer, NULL, EVBUFFER_EOL_ANY).
+
+ @deprecated This function is deprecated because its behavior is not correct
+ for almost any protocol, and also because it's wholly subsumed by
+ evbuffer_readln().
+
+ @param buffer the evbuffer to read from
+ @return pointer to a single line, or NULL if an error occurred
+
+*/
+EVENT2_EXPORT_SYMBOL
+char *evbuffer_readline(struct evbuffer *buffer);
+
+/** Type definition for a callback that is invoked whenever data is added or
+ removed from an evbuffer.
+
+ An evbuffer may have one or more callbacks set at a time. The order
+ in which they are executed is undefined.
+
+ A callback function may add more callbacks, or remove itself from the
+ list of callbacks, or add or remove data from the buffer. It may not
+ remove another callback from the list.
+
+ If a callback adds or removes data from the buffer or from another
+ buffer, this can cause a recursive invocation of your callback or
+ other callbacks. If you ask for an infinite loop, you might just get
+ one: watch out!
+
+ @param buffer the buffer whose size has changed
+ @param old_len the previous length of the buffer
+ @param new_len the current length of the buffer
+ @param arg a pointer to user data
+*/
+typedef void (*evbuffer_cb)(struct evbuffer *buffer, size_t old_len, size_t new_len, void *arg);
+
+/**
+ Replace all callbacks on an evbuffer with a single new callback, or
+ remove them.
+
+ Subsequent calls to evbuffer_setcb() replace callbacks set by previous
+ calls. Setting the callback to NULL removes any previously set callback.
+
+ @deprecated This function is deprecated because it clears all previous
+ callbacks set on the evbuffer, which can cause confusing behavior if
+ multiple parts of the code all want to add their own callbacks on a
+ buffer. Instead, use evbuffer_add(), evbuffer_del(), and
+ evbuffer_setflags() to manage your own evbuffer callbacks without
+ interfering with callbacks set by others.
+
+ @param buffer the evbuffer to be monitored
+ @param cb the callback function to invoke when the evbuffer is modified,
+ or NULL to remove all callbacks.
+ @param cbarg an argument to be provided to the callback function
+ */
+EVENT2_EXPORT_SYMBOL
+void evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg);
+
+
+/**
+ Find a string within an evbuffer.
+
+ @param buffer the evbuffer to be searched
+ @param what the string to be searched for
+ @param len the length of the search string
+ @return a pointer to the beginning of the search string, or NULL if the search failed.
+ */
+EVENT2_EXPORT_SYMBOL
+unsigned char *evbuffer_find(struct evbuffer *buffer, const unsigned char *what, size_t len);
+
+/** deprecated in favor of calling the functions directly */
+#define EVBUFFER_LENGTH(x) evbuffer_get_length(x)
+/** deprecated in favor of calling the functions directly */
+#define EVBUFFER_DATA(x) evbuffer_pullup((x), -1)
+
+#endif
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent.h
new file mode 100644
index 000000000..825918e3a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent.h
@@ -0,0 +1,1021 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_BUFFEREVENT_H_INCLUDED_
+#define EVENT2_BUFFEREVENT_H_INCLUDED_
+
+/**
+ @file event2/bufferevent.h
+
+ Functions for buffering data for network sending or receiving. Bufferevents
+ are higher level than evbuffers: each has an underlying evbuffer for reading
+ and one for writing, and callbacks that are invoked under certain
+ circumstances.
+
+ A bufferevent provides input and output buffers that get filled and
+ drained automatically. The user of a bufferevent no longer deals
+ directly with the I/O, but instead is reading from input and writing
+ to output buffers.
+
+ Once initialized, the bufferevent structure can be used repeatedly
+ with bufferevent_enable() and bufferevent_disable().
+
+ When reading is enabled, the bufferevent will try to read from the
+ file descriptor onto its input buffer, and call the read callback.
+ When writing is enabled, the bufferevent will try to write data onto its
+ file descriptor when the output buffer has enough data, and call the write
+ callback when the output buffer is sufficiently drained.
+
+ Bufferevents come in several flavors, including:
+
+ <dl>
+ <dt>Socket-based bufferevents</dt>
+ <dd>A bufferevent that reads and writes data onto a network
+ socket. Created with bufferevent_socket_new().</dd>
+
+ <dt>Paired bufferevents</dt>
+ <dd>A pair of bufferevents that send and receive data to one
+ another without touching the network. Created with
+ bufferevent_pair_new().</dd>
+
+ <dt>Filtering bufferevents</dt>
+ <dd>A bufferevent that transforms data, and sends or receives it
+ over another underlying bufferevent. Created with
+ bufferevent_filter_new().</dd>
+
+ <dt>SSL-backed bufferevents</dt>
+ <dd>A bufferevent that uses the openssl library to send and
+ receive data over an encrypted connection. Created with
+ bufferevent_openssl_socket_new() or
+ bufferevent_openssl_filter_new().</dd>
+ </dl>
+ */
+
+#include <event2/visibility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/* For int types. */
+#include <event2/util.h>
+
+/** @name Bufferevent event codes
+
+ These flags are passed as arguments to a bufferevent's event callback.
+
+ @{
+*/
+#define BEV_EVENT_READING 0x01 /**< error encountered while reading */
+#define BEV_EVENT_WRITING 0x02 /**< error encountered while writing */
+#define BEV_EVENT_EOF 0x10 /**< eof file reached */
+#define BEV_EVENT_ERROR 0x20 /**< unrecoverable error encountered */
+#define BEV_EVENT_TIMEOUT 0x40 /**< user-specified timeout reached */
+#define BEV_EVENT_CONNECTED 0x80 /**< connect operation finished. */
+/**@}*/
+
+/**
+ An opaque type for handling buffered IO
+
+ @see event2/bufferevent.h
+ */
+struct bufferevent
+#ifdef EVENT_IN_DOXYGEN_
+{}
+#endif
+;
+struct event_base;
+struct evbuffer;
+struct sockaddr;
+
+/**
+ A read or write callback for a bufferevent.
+
+ The read callback is triggered when new data arrives in the input
+ buffer and the amount of readable data exceed the low watermark
+ which is 0 by default.
+
+ The write callback is triggered if the write buffer has been
+ exhausted or fell below its low watermark.
+
+ @param bev the bufferevent that triggered the callback
+ @param ctx the user-specified context for this bufferevent
+ */
+typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
+
+/**
+ An event/error callback for a bufferevent.
+
+ The event callback is triggered if either an EOF condition or another
+ unrecoverable error was encountered.
+
+ For bufferevents with deferred callbacks, this is a bitwise OR of all errors
+ that have happened on the bufferevent since the last callback invocation.
+
+ @param bev the bufferevent for which the error condition was reached
+ @param what a conjunction of flags: BEV_EVENT_READING or BEV_EVENT_WRITING
+ to indicate if the error was encountered on the read or write path,
+ and one of the following flags: BEV_EVENT_EOF, BEV_EVENT_ERROR,
+ BEV_EVENT_TIMEOUT, BEV_EVENT_CONNECTED.
+
+ @param ctx the user-specified context for this bufferevent
+*/
+typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx);
+
+/** Options that can be specified when creating a bufferevent */
+enum bufferevent_options {
+ /** If set, we close the underlying file
+ * descriptor/bufferevent/whatever when this bufferevent is freed. */
+ BEV_OPT_CLOSE_ON_FREE = (1<<0),
+
+ /** If set, and threading is enabled, operations on this bufferevent
+ * are protected by a lock */
+ BEV_OPT_THREADSAFE = (1<<1),
+
+ /** If set, callbacks are run deferred in the event loop. */
+ BEV_OPT_DEFER_CALLBACKS = (1<<2),
+
+ /** If set, callbacks are executed without locks being held on the
+ * bufferevent. This option currently requires that
+ * BEV_OPT_DEFER_CALLBACKS also be set; a future version of Libevent
+ * might remove the requirement.*/
+ BEV_OPT_UNLOCK_CALLBACKS = (1<<3)
+};
+
+/**
+ Create a new socket bufferevent over an existing socket.
+
+ @param base the event base to associate with the new bufferevent.
+ @param fd the file descriptor from which data is read and written to.
+ This file descriptor is not allowed to be a pipe(2).
+ It is safe to set the fd to -1, so long as you later
+ set it with bufferevent_setfd or bufferevent_socket_connect().
+ @param options Zero or more BEV_OPT_* flags
+ @return a pointer to a newly allocated bufferevent struct, or NULL if an
+ error occurred
+ @see bufferevent_free()
+ */
+EVENT2_EXPORT_SYMBOL
+struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options);
+
+/**
+ Launch a connect() attempt with a socket-based bufferevent.
+
+ When the connect succeeds, the eventcb will be invoked with
+ BEV_EVENT_CONNECTED set.
+
+ If the bufferevent does not already have a socket set, we allocate a new
+ socket here and make it nonblocking before we begin.
+
+ If no address is provided, we assume that the socket is already connecting,
+ and configure the bufferevent so that a BEV_EVENT_CONNECTED event will be
+ yielded when it is done connecting.
+
+ @param bufev an existing bufferevent allocated with
+ bufferevent_socket_new().
+ @param addr the address we should connect to
+ @param socklen The length of the address
+ @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_socket_connect(struct bufferevent *, const struct sockaddr *, int);
+
+struct evdns_base;
+/**
+ Resolve the hostname 'hostname' and connect to it as with
+ bufferevent_socket_connect().
+
+ @param bufev An existing bufferevent allocated with bufferevent_socket_new()
+ @param evdns_base Optionally, an evdns_base to use for resolving hostnames
+ asynchronously. May be set to NULL for a blocking resolve.
+ @param family A preferred address family to resolve addresses to, or
+ AF_UNSPEC for no preference. Only AF_INET, AF_INET6, and AF_UNSPEC are
+ supported.
+ @param hostname The hostname to resolve; see below for notes on recognized
+ formats
+ @param port The port to connect to on the resolved address.
+ @return 0 if successful, -1 on failure.
+
+ Recognized hostname formats are:
+
+ www.example.com (hostname)
+ 1.2.3.4 (ipv4address)
+ ::1 (ipv6address)
+ [::1] ([ipv6address])
+
+ Performance note: If you do not provide an evdns_base, this function
+ may block while it waits for a DNS response. This is probably not
+ what you want.
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_socket_connect_hostname(struct bufferevent *,
+ struct evdns_base *, int, const char *, int);
+
+/**
+ Return the error code for the last failed DNS lookup attempt made by
+ bufferevent_socket_connect_hostname().
+
+ @param bev The bufferevent object.
+ @return DNS error code.
+ @see evutil_gai_strerror()
+*/
+EVENT2_EXPORT_SYMBOL
+int bufferevent_socket_get_dns_error(struct bufferevent *bev);
+
+/**
+ Assign a bufferevent to a specific event_base.
+
+ NOTE that only socket bufferevents support this function.
+
+ @param base an event_base returned by event_init()
+ @param bufev a bufferevent struct returned by bufferevent_new()
+ or bufferevent_socket_new()
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_new()
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev);
+
+/**
+ Return the event_base used by a bufferevent
+*/
+EVENT2_EXPORT_SYMBOL
+struct event_base *bufferevent_get_base(struct bufferevent *bev);
+
+/**
+ Assign a priority to a bufferevent.
+
+ Only supported for socket bufferevents.
+
+ @param bufev a bufferevent struct
+ @param pri the priority to be assigned
+ @return 0 if successful, or -1 if an error occurred
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_priority_set(struct bufferevent *bufev, int pri);
+
+/**
+ Return the priority of a bufferevent.
+
+ Only supported for socket bufferevents
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_get_priority(const struct bufferevent *bufev);
+
+/**
+ Deallocate the storage associated with a bufferevent structure.
+
+ If there is pending data to write on the bufferevent, it probably won't be
+ flushed before the bufferevent is freed.
+
+ @param bufev the bufferevent structure to be freed.
+ */
+EVENT2_EXPORT_SYMBOL
+void bufferevent_free(struct bufferevent *bufev);
+
+
+/**
+ Changes the callbacks for a bufferevent.
+
+ @param bufev the bufferevent object for which to change callbacks
+ @param readcb callback to invoke when there is data to be read, or NULL if
+ no callback is desired
+ @param writecb callback to invoke when the file descriptor is ready for
+ writing, or NULL if no callback is desired
+ @param eventcb callback to invoke when there is an event on the file
+ descriptor
+ @param cbarg an argument that will be supplied to each of the callbacks
+ (readcb, writecb, and errorcb)
+ @see bufferevent_new()
+ */
+EVENT2_EXPORT_SYMBOL
+void bufferevent_setcb(struct bufferevent *bufev,
+ bufferevent_data_cb readcb, bufferevent_data_cb writecb,
+ bufferevent_event_cb eventcb, void *cbarg);
+
+/**
+ Retrieves the callbacks for a bufferevent.
+
+ @param bufev the bufferevent to examine.
+ @param readcb_ptr if readcb_ptr is nonnull, *readcb_ptr is set to the current
+ read callback for the bufferevent.
+ @param writecb_ptr if writecb_ptr is nonnull, *writecb_ptr is set to the
+ current write callback for the bufferevent.
+ @param eventcb_ptr if eventcb_ptr is nonnull, *eventcb_ptr is set to the
+ current event callback for the bufferevent.
+ @param cbarg_ptr if cbarg_ptr is nonnull, *cbarg_ptr is set to the current
+ callback argument for the bufferevent.
+ @see buffervent_setcb()
+*/
+EVENT2_EXPORT_SYMBOL
+void bufferevent_getcb(struct bufferevent *bufev,
+ bufferevent_data_cb *readcb_ptr,
+ bufferevent_data_cb *writecb_ptr,
+ bufferevent_event_cb *eventcb_ptr,
+ void **cbarg_ptr);
+
+/**
+ Changes the file descriptor on which the bufferevent operates.
+ Not supported for all bufferevent types.
+
+ @param bufev the bufferevent object for which to change the file descriptor
+ @param fd the file descriptor to operate on
+*/
+EVENT2_EXPORT_SYMBOL
+int bufferevent_setfd(struct bufferevent *bufev, evutil_socket_t fd);
+
+/**
+ Returns the file descriptor associated with a bufferevent, or -1 if
+ no file descriptor is associated with the bufferevent.
+ */
+EVENT2_EXPORT_SYMBOL
+evutil_socket_t bufferevent_getfd(struct bufferevent *bufev);
+
+/**
+ Returns the underlying bufferevent associated with a bufferevent (if
+ the bufferevent is a wrapper), or NULL if there is no underlying bufferevent.
+ */
+EVENT2_EXPORT_SYMBOL
+struct bufferevent *bufferevent_get_underlying(struct bufferevent *bufev);
+
+/**
+ Write data to a bufferevent buffer.
+
+ The bufferevent_write() function can be used to write data to the file
+ descriptor. The data is appended to the output buffer and written to the
+ descriptor automatically as it becomes available for writing.
+
+ @param bufev the bufferevent to be written to
+ @param data a pointer to the data to be written
+ @param size the length of the data, in bytes
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_write_buffer()
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_write(struct bufferevent *bufev,
+ const void *data, size_t size);
+
+
+/**
+ Write data from an evbuffer to a bufferevent buffer. The evbuffer is
+ being drained as a result.
+
+ @param bufev the bufferevent to be written to
+ @param buf the evbuffer to be written
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_write()
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf);
+
+
+/**
+ Read data from a bufferevent buffer.
+
+ The bufferevent_read() function is used to read data from the input buffer.
+
+ @param bufev the bufferevent to be read from
+ @param data pointer to a buffer that will store the data
+ @param size the size of the data buffer, in bytes
+ @return the amount of data read, in bytes.
+ */
+EVENT2_EXPORT_SYMBOL
+size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
+
+/**
+ Read data from a bufferevent buffer into an evbuffer. This avoids
+ memory copies.
+
+ @param bufev the bufferevent to be read from
+ @param buf the evbuffer to which to add data
+ @return 0 if successful, or -1 if an error occurred.
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_read_buffer(struct bufferevent *bufev, struct evbuffer *buf);
+
+/**
+ Returns the input buffer.
+
+ The user MUST NOT set the callback on this buffer.
+
+ @param bufev the bufferevent from which to get the evbuffer
+ @return the evbuffer object for the input buffer
+ */
+
+EVENT2_EXPORT_SYMBOL
+struct evbuffer *bufferevent_get_input(struct bufferevent *bufev);
+
+/**
+ Returns the output buffer.
+
+ The user MUST NOT set the callback on this buffer.
+
+ When filters are being used, the filters need to be manually
+ triggered if the output buffer was manipulated.
+
+ @param bufev the bufferevent from which to get the evbuffer
+ @return the evbuffer object for the output buffer
+ */
+
+EVENT2_EXPORT_SYMBOL
+struct evbuffer *bufferevent_get_output(struct bufferevent *bufev);
+
+/**
+ Enable a bufferevent.
+
+ @param bufev the bufferevent to be enabled
+ @param event any combination of EV_READ | EV_WRITE.
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_disable()
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_enable(struct bufferevent *bufev, short event);
+
+/**
+ Disable a bufferevent.
+
+ @param bufev the bufferevent to be disabled
+ @param event any combination of EV_READ | EV_WRITE.
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_enable()
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_disable(struct bufferevent *bufev, short event);
+
+/**
+ Return the events that are enabled on a given bufferevent.
+
+ @param bufev the bufferevent to inspect
+ @return A combination of EV_READ | EV_WRITE
+ */
+EVENT2_EXPORT_SYMBOL
+short bufferevent_get_enabled(struct bufferevent *bufev);
+
+/**
+ Set the read and write timeout for a bufferevent.
+
+ A bufferevent's timeout will fire the first time that the indicated
+ amount of time has elapsed since a successful read or write operation,
+ during which the bufferevent was trying to read or write.
+
+ (In other words, if reading or writing is disabled, or if the
+ bufferevent's read or write operation has been suspended because
+ there's no data to write, or not enough banwidth, or so on, the
+ timeout isn't active. The timeout only becomes active when we we're
+ willing to actually read or write.)
+
+ Calling bufferevent_enable or setting a timeout for a bufferevent
+ whose timeout is already pending resets its timeout.
+
+ If the timeout elapses, the corresponding operation (EV_READ or
+ EV_WRITE) becomes disabled until you re-enable it again. The
+ bufferevent's event callback is called with the
+ BEV_EVENT_TIMEOUT|BEV_EVENT_READING or
+ BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING.
+
+ @param bufev the bufferevent to be modified
+ @param timeout_read the read timeout, or NULL
+ @param timeout_write the write timeout, or NULL
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_set_timeouts(struct bufferevent *bufev,
+ const struct timeval *timeout_read, const struct timeval *timeout_write);
+
+/**
+ Sets the watermarks for read and write events.
+
+ On input, a bufferevent does not invoke the user read callback unless
+ there is at least low watermark data in the buffer. If the read buffer
+ is beyond the high watermark, the bufferevent stops reading from the network.
+
+ On output, the user write callback is invoked whenever the buffered data
+ falls below the low watermark. Filters that write to this bufev will try
+ not to write more bytes to this buffer than the high watermark would allow,
+ except when flushing.
+
+ @param bufev the bufferevent to be modified
+ @param events EV_READ, EV_WRITE or both
+ @param lowmark the lower watermark to set
+ @param highmark the high watermark to set
+*/
+
+EVENT2_EXPORT_SYMBOL
+void bufferevent_setwatermark(struct bufferevent *bufev, short events,
+ size_t lowmark, size_t highmark);
+
+/**
+ Retrieves the watermarks for read or write events.
+ Returns non-zero if events contains not only EV_READ or EV_WRITE.
+ Returns zero if events equal EV_READ or EV_WRITE
+
+ @param bufev the bufferevent to be examined
+ @param events EV_READ or EV_WRITE
+ @param lowmark receives the lower watermark if not NULL
+ @param highmark receives the high watermark if not NULL
+*/
+EVENT2_EXPORT_SYMBOL
+int bufferevent_getwatermark(struct bufferevent *bufev, short events,
+ size_t *lowmark, size_t *highmark);
+
+/**
+ Acquire the lock on a bufferevent. Has no effect if locking was not
+ enabled with BEV_OPT_THREADSAFE.
+ */
+EVENT2_EXPORT_SYMBOL
+void bufferevent_lock(struct bufferevent *bufev);
+
+/**
+ Release the lock on a bufferevent. Has no effect if locking was not
+ enabled with BEV_OPT_THREADSAFE.
+ */
+EVENT2_EXPORT_SYMBOL
+void bufferevent_unlock(struct bufferevent *bufev);
+
+
+/**
+ * Public interface to manually increase the reference count of a bufferevent
+ * this is useful in situations where a user may reference the bufferevent
+ * somewhere eles (unknown to libevent)
+ *
+ * @param bufev the bufferevent to increase the refcount on
+ *
+ */
+EVENT2_EXPORT_SYMBOL
+void bufferevent_incref(struct bufferevent *bufev);
+
+/**
+ * Public interface to manually decrement the reference count of a bufferevent
+ *
+ * Warning: make sure you know what you're doing. This is mainly used in
+ * conjunction with bufferevent_incref(). This will free up all data associated
+ * with a bufferevent if the reference count hits 0.
+ *
+ * @param bufev the bufferevent to decrement the refcount on
+ *
+ * @return 1 if the bufferevent was freed, otherwise 0 (still referenced)
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_decref(struct bufferevent *bufev);
+
+/**
+ Flags that can be passed into filters to let them know how to
+ deal with the incoming data.
+*/
+enum bufferevent_flush_mode {
+ /** usually set when processing data */
+ BEV_NORMAL = 0,
+
+ /** want to checkpoint all data sent. */
+ BEV_FLUSH = 1,
+
+ /** encountered EOF on read or done sending data */
+ BEV_FINISHED = 2
+};
+
+/**
+ Triggers the bufferevent to produce more data if possible.
+
+ @param bufev the bufferevent object
+ @param iotype either EV_READ or EV_WRITE or both.
+ @param mode either BEV_NORMAL or BEV_FLUSH or BEV_FINISHED
+ @return -1 on failure, 0 if no data was produces, 1 if data was produced
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_flush(struct bufferevent *bufev,
+ short iotype,
+ enum bufferevent_flush_mode mode);
+
+/**
+ Flags for bufferevent_trigger(_event) that modify when and how to trigger
+ the callback.
+*/
+enum bufferevent_trigger_options {
+ /** trigger the callback regardless of the watermarks */
+ BEV_TRIG_IGNORE_WATERMARKS = (1<<16),
+
+ /** defer even if the callbacks are not */
+ BEV_TRIG_DEFER_CALLBACKS = BEV_OPT_DEFER_CALLBACKS
+
+ /* (Note: for internal reasons, these need to be disjoint from
+ * bufferevent_options, except when they mean the same thing. */
+};
+
+/**
+ Triggers bufferevent data callbacks.
+
+ The function will honor watermarks unless options contain
+ BEV_TRIG_IGNORE_WATERMARKS. If the options contain BEV_OPT_DEFER_CALLBACKS,
+ the callbacks are deferred.
+
+ @param bufev the bufferevent object
+ @param iotype either EV_READ or EV_WRITE or both.
+ @param options
+ */
+EVENT2_EXPORT_SYMBOL
+void bufferevent_trigger(struct bufferevent *bufev, short iotype,
+ int options);
+
+/**
+ Triggers the bufferevent event callback.
+
+ If the options contain BEV_OPT_DEFER_CALLBACKS, the callbacks are deferred.
+
+ @param bufev the bufferevent object
+ @param what the flags to pass onto the event callback
+ @param options
+ */
+EVENT2_EXPORT_SYMBOL
+void bufferevent_trigger_event(struct bufferevent *bufev, short what,
+ int options);
+
+/**
+ @name Filtering support
+
+ @{
+*/
+/**
+ Values that filters can return.
+ */
+enum bufferevent_filter_result {
+ /** everything is okay */
+ BEV_OK = 0,
+
+ /** the filter needs to read more data before output */
+ BEV_NEED_MORE = 1,
+
+ /** the filter encountered a critical error, no further data
+ can be processed. */
+ BEV_ERROR = 2
+};
+
+/** A callback function to implement a filter for a bufferevent.
+
+ @param src An evbuffer to drain data from.
+ @param dst An evbuffer to add data to.
+ @param limit A suggested upper bound of bytes to write to dst.
+ The filter may ignore this value, but doing so means that
+ it will overflow the high-water mark associated with dst.
+ -1 means "no limit".
+ @param mode Whether we should write data as may be convenient
+ (BEV_NORMAL), or flush as much data as we can (BEV_FLUSH),
+ or flush as much as we can, possibly including an end-of-stream
+ marker (BEV_FINISH).
+ @param ctx A user-supplied pointer.
+
+ @return BEV_OK if we wrote some data; BEV_NEED_MORE if we can't
+ produce any more output until we get some input; and BEV_ERROR
+ on an error.
+ */
+typedef enum bufferevent_filter_result (*bufferevent_filter_cb)(
+ struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit,
+ enum bufferevent_flush_mode mode, void *ctx);
+
+/**
+ Allocate a new filtering bufferevent on top of an existing bufferevent.
+
+ @param underlying the underlying bufferevent.
+ @param input_filter The filter to apply to data we read from the underlying
+ bufferevent
+ @param output_filter The filer to apply to data we write to the underlying
+ bufferevent
+ @param options A bitfield of bufferevent options.
+ @param free_context A function to use to free the filter context when
+ this bufferevent is freed.
+ @param ctx A context pointer to pass to the filter functions.
+ */
+EVENT2_EXPORT_SYMBOL
+struct bufferevent *
+bufferevent_filter_new(struct bufferevent *underlying,
+ bufferevent_filter_cb input_filter,
+ bufferevent_filter_cb output_filter,
+ int options,
+ void (*free_context)(void *),
+ void *ctx);
+/**@}*/
+
+/**
+ Allocate a pair of linked bufferevents. The bufferevents behave as would
+ two bufferevent_sock instances connected to opposite ends of a
+ socketpair(), except that no internal socketpair is allocated.
+
+ @param base The event base to associate with the socketpair.
+ @param options A set of options for this bufferevent
+ @param pair A pointer to an array to hold the two new bufferevent objects.
+ @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_pair_new(struct event_base *base, int options,
+ struct bufferevent *pair[2]);
+
+/**
+ Given one bufferevent returned by bufferevent_pair_new(), returns the
+ other one if it still exists. Otherwise returns NULL.
+ */
+EVENT2_EXPORT_SYMBOL
+struct bufferevent *bufferevent_pair_get_partner(struct bufferevent *bev);
+
+/**
+ Abstract type used to configure rate-limiting on a bufferevent or a group
+ of bufferevents.
+ */
+struct ev_token_bucket_cfg;
+
+/**
+ A group of bufferevents which are configured to respect the same rate
+ limit.
+*/
+struct bufferevent_rate_limit_group;
+
+/** Maximum configurable rate- or burst-limit. */
+#define EV_RATE_LIMIT_MAX EV_SSIZE_MAX
+
+/**
+ Initialize and return a new object to configure the rate-limiting behavior
+ of bufferevents.
+
+ @param read_rate The maximum number of bytes to read per tick on
+ average.
+ @param read_burst The maximum number of bytes to read in any single tick.
+ @param write_rate The maximum number of bytes to write per tick on
+ average.
+ @param write_burst The maximum number of bytes to write in any single tick.
+ @param tick_len The length of a single tick. Defaults to one second.
+ Any fractions of a millisecond are ignored.
+
+ Note that all rate-limits hare are currently best-effort: future versions
+ of Libevent may implement them more tightly.
+ */
+EVENT2_EXPORT_SYMBOL
+struct ev_token_bucket_cfg *ev_token_bucket_cfg_new(
+ size_t read_rate, size_t read_burst,
+ size_t write_rate, size_t write_burst,
+ const struct timeval *tick_len);
+
+/** Free all storage held in 'cfg'.
+
+ Note: 'cfg' is not currently reference-counted; it is not safe to free it
+ until no bufferevent is using it.
+ */
+EVENT2_EXPORT_SYMBOL
+void ev_token_bucket_cfg_free(struct ev_token_bucket_cfg *cfg);
+
+/**
+ Set the rate-limit of a the bufferevent 'bev' to the one specified in
+ 'cfg'. If 'cfg' is NULL, disable any per-bufferevent rate-limiting on
+ 'bev'.
+
+ Note that only some bufferevent types currently respect rate-limiting.
+ They are: socket-based bufferevents (normal and IOCP-based), and SSL-based
+ bufferevents.
+
+ Return 0 on sucess, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_set_rate_limit(struct bufferevent *bev,
+ struct ev_token_bucket_cfg *cfg);
+
+/**
+ Create a new rate-limit group for bufferevents. A rate-limit group
+ constrains the maximum number of bytes sent and received, in toto,
+ by all of its bufferevents.
+
+ @param base An event_base to run any necessary timeouts for the group.
+ Note that all bufferevents in the group do not necessarily need to share
+ this event_base.
+ @param cfg The rate-limit for this group.
+
+ Note that all rate-limits hare are currently best-effort: future versions
+ of Libevent may implement them more tightly.
+
+ Note also that only some bufferevent types currently respect rate-limiting.
+ They are: socket-based bufferevents (normal and IOCP-based), and SSL-based
+ bufferevents.
+ */
+EVENT2_EXPORT_SYMBOL
+struct bufferevent_rate_limit_group *bufferevent_rate_limit_group_new(
+ struct event_base *base,
+ const struct ev_token_bucket_cfg *cfg);
+/**
+ Change the rate-limiting settings for a given rate-limiting group.
+
+ Return 0 on success, -1 on failure.
+*/
+EVENT2_EXPORT_SYMBOL
+int bufferevent_rate_limit_group_set_cfg(
+ struct bufferevent_rate_limit_group *,
+ const struct ev_token_bucket_cfg *);
+
+/**
+ Change the smallest quantum we're willing to allocate to any single
+ bufferevent in a group for reading or writing at a time.
+
+ The rationale is that, because of TCP/IP protocol overheads and kernel
+ behavior, if a rate-limiting group is so tight on bandwidth that you're
+ only willing to send 1 byte per tick per bufferevent, you might instead
+ want to batch up the reads and writes so that you send N bytes per
+ 1/N of the bufferevents (chosen at random) each tick, so you still wind
+ up send 1 byte per tick per bufferevent on average, but you don't send
+ so many tiny packets.
+
+ The default min-share is currently 64 bytes.
+
+ Returns 0 on success, -1 on faulre.
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_rate_limit_group_set_min_share(
+ struct bufferevent_rate_limit_group *, size_t);
+
+/**
+ Free a rate-limiting group. The group must have no members when
+ this function is called.
+*/
+EVENT2_EXPORT_SYMBOL
+void bufferevent_rate_limit_group_free(struct bufferevent_rate_limit_group *);
+
+/**
+ Add 'bev' to the list of bufferevents whose aggregate reading and writing
+ is restricted by 'g'. If 'g' is NULL, remove 'bev' from its current group.
+
+ A bufferevent may belong to no more than one rate-limit group at a time.
+ If 'bev' is already a member of a group, it will be removed from its old
+ group before being added to 'g'.
+
+ Return 0 on success and -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_add_to_rate_limit_group(struct bufferevent *bev,
+ struct bufferevent_rate_limit_group *g);
+
+/** Remove 'bev' from its current rate-limit group (if any). */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_remove_from_rate_limit_group(struct bufferevent *bev);
+
+/**
+ Set the size limit for single read operation.
+
+ Set to 0 for a reasonable default.
+
+ Return 0 on success and -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_set_max_single_read(struct bufferevent *bev, size_t size);
+
+/**
+ Set the size limit for single write operation.
+
+ Set to 0 for a reasonable default.
+
+ Return 0 on success and -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_set_max_single_write(struct bufferevent *bev, size_t size);
+
+/** Get the current size limit for single read operation. */
+EVENT2_EXPORT_SYMBOL
+ev_ssize_t bufferevent_get_max_single_read(struct bufferevent *bev);
+
+/** Get the current size limit for single write operation. */
+EVENT2_EXPORT_SYMBOL
+ev_ssize_t bufferevent_get_max_single_write(struct bufferevent *bev);
+
+/**
+ @name Rate limit inspection
+
+ Return the current read or write bucket size for a bufferevent.
+ If it is not configured with a per-bufferevent ratelimit, return
+ EV_SSIZE_MAX. This function does not inspect the group limit, if any.
+ Note that it can return a negative value if the bufferevent has been
+ made to read or write more than its limit.
+
+ @{
+ */
+EVENT2_EXPORT_SYMBOL
+ev_ssize_t bufferevent_get_read_limit(struct bufferevent *bev);
+EVENT2_EXPORT_SYMBOL
+ev_ssize_t bufferevent_get_write_limit(struct bufferevent *bev);
+/*@}*/
+
+EVENT2_EXPORT_SYMBOL
+ev_ssize_t bufferevent_get_max_to_read(struct bufferevent *bev);
+EVENT2_EXPORT_SYMBOL
+ev_ssize_t bufferevent_get_max_to_write(struct bufferevent *bev);
+
+EVENT2_EXPORT_SYMBOL
+const struct ev_token_bucket_cfg *bufferevent_get_token_bucket_cfg(const struct bufferevent * bev);
+
+/**
+ @name Group Rate limit inspection
+
+ Return the read or write bucket size for a bufferevent rate limit
+ group. Note that it can return a negative value if bufferevents in
+ the group have been made to read or write more than their limits.
+
+ @{
+ */
+EVENT2_EXPORT_SYMBOL
+ev_ssize_t bufferevent_rate_limit_group_get_read_limit(
+ struct bufferevent_rate_limit_group *);
+EVENT2_EXPORT_SYMBOL
+ev_ssize_t bufferevent_rate_limit_group_get_write_limit(
+ struct bufferevent_rate_limit_group *);
+/*@}*/
+
+/**
+ @name Rate limit manipulation
+
+ Subtract a number of bytes from a bufferevent's read or write bucket.
+ The decrement value can be negative, if you want to manually refill
+ the bucket. If the change puts the bucket above or below zero, the
+ bufferevent will resume or suspend reading writing as appropriate.
+ These functions make no change in the buckets for the bufferevent's
+ group, if any.
+
+ Returns 0 on success, -1 on internal error.
+
+ @{
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_decrement_read_limit(struct bufferevent *bev, ev_ssize_t decr);
+EVENT2_EXPORT_SYMBOL
+int bufferevent_decrement_write_limit(struct bufferevent *bev, ev_ssize_t decr);
+/*@}*/
+
+/**
+ @name Group rate limit manipulation
+
+ Subtract a number of bytes from a bufferevent rate-limiting group's
+ read or write bucket. The decrement value can be negative, if you
+ want to manually refill the bucket. If the change puts the bucket
+ above or below zero, the bufferevents in the group will resume or
+ suspend reading writing as appropriate.
+
+ Returns 0 on success, -1 on internal error.
+
+ @{
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_rate_limit_group_decrement_read(
+ struct bufferevent_rate_limit_group *, ev_ssize_t);
+EVENT2_EXPORT_SYMBOL
+int bufferevent_rate_limit_group_decrement_write(
+ struct bufferevent_rate_limit_group *, ev_ssize_t);
+/*@}*/
+
+
+/**
+ * Inspect the total bytes read/written on a group.
+ *
+ * Set the variable pointed to by total_read_out to the total number of bytes
+ * ever read on grp, and the variable pointed to by total_written_out to the
+ * total number of bytes ever written on grp. */
+EVENT2_EXPORT_SYMBOL
+void bufferevent_rate_limit_group_get_totals(
+ struct bufferevent_rate_limit_group *grp,
+ ev_uint64_t *total_read_out, ev_uint64_t *total_written_out);
+
+/**
+ * Reset the total bytes read/written on a group.
+ *
+ * Reset the number of bytes read or written on grp as given by
+ * bufferevent_rate_limit_group_reset_totals(). */
+EVENT2_EXPORT_SYMBOL
+void
+bufferevent_rate_limit_group_reset_totals(
+ struct bufferevent_rate_limit_group *grp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_BUFFEREVENT_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent_compat.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent_compat.h
new file mode 100644
index 000000000..65482042f
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent_compat.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos, Nick Mathewson
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_BUFFEREVENT_COMPAT_H_INCLUDED_
+#define EVENT2_BUFFEREVENT_COMPAT_H_INCLUDED_
+
+#define evbuffercb bufferevent_data_cb
+#define everrorcb bufferevent_event_cb
+
+/**
+ Create a new bufferevent for an fd.
+
+ This function is deprecated. Use bufferevent_socket_new and
+ bufferevent_set_callbacks instead.
+
+ Libevent provides an abstraction on top of the regular event callbacks.
+ This abstraction is called a buffered event. A buffered event provides
+ input and output buffers that get filled and drained automatically. The
+ user of a buffered event no longer deals directly with the I/O, but
+ instead is reading from input and writing to output buffers.
+
+ Once initialized, the bufferevent structure can be used repeatedly with
+ bufferevent_enable() and bufferevent_disable().
+
+ When read enabled the bufferevent will try to read from the file descriptor
+ and call the read callback. The write callback is executed whenever the
+ output buffer is drained below the write low watermark, which is 0 by
+ default.
+
+ If multiple bases are in use, bufferevent_base_set() must be called before
+ enabling the bufferevent for the first time.
+
+ @deprecated This function is deprecated because it uses the current
+ event base, and as such can be error prone for multithreaded programs.
+ Use bufferevent_socket_new() instead.
+
+ @param fd the file descriptor from which data is read and written to.
+ This file descriptor is not allowed to be a pipe(2).
+ @param readcb callback to invoke when there is data to be read, or NULL if
+ no callback is desired
+ @param writecb callback to invoke when the file descriptor is ready for
+ writing, or NULL if no callback is desired
+ @param errorcb callback to invoke when there is an error on the file
+ descriptor
+ @param cbarg an argument that will be supplied to each of the callbacks
+ (readcb, writecb, and errorcb)
+ @return a pointer to a newly allocated bufferevent struct, or NULL if an
+ error occurred
+ @see bufferevent_base_set(), bufferevent_free()
+ */
+struct bufferevent *bufferevent_new(evutil_socket_t fd,
+ evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
+
+
+/**
+ Set the read and write timeout for a buffered event.
+
+ @param bufev the bufferevent to be modified
+ @param timeout_read the read timeout
+ @param timeout_write the write timeout
+ */
+void bufferevent_settimeout(struct bufferevent *bufev,
+ int timeout_read, int timeout_write);
+
+#define EVBUFFER_READ BEV_EVENT_READING
+#define EVBUFFER_WRITE BEV_EVENT_WRITING
+#define EVBUFFER_EOF BEV_EVENT_EOF
+#define EVBUFFER_ERROR BEV_EVENT_ERROR
+#define EVBUFFER_TIMEOUT BEV_EVENT_TIMEOUT
+
+/** macro for getting access to the input buffer of a bufferevent */
+#define EVBUFFER_INPUT(x) bufferevent_get_input(x)
+/** macro for getting access to the output buffer of a bufferevent */
+#define EVBUFFER_OUTPUT(x) bufferevent_get_output(x)
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent_ssl.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent_ssl.h
new file mode 100644
index 000000000..bf39b844a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent_ssl.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_BUFFEREVENT_SSL_H_INCLUDED_
+#define EVENT2_BUFFEREVENT_SSL_H_INCLUDED_
+
+/** @file event2/bufferevent_ssl.h
+
+ OpenSSL support for bufferevents.
+ */
+#include <event2/visibility.h>
+#include <event2/event-config.h>
+#include <event2/bufferevent.h>
+#include <event2/util.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This is what openssl's SSL objects are underneath. */
+struct ssl_st;
+
+/**
+ The state of an SSL object to be used when creating a new
+ SSL bufferevent.
+ */
+enum bufferevent_ssl_state {
+ BUFFEREVENT_SSL_OPEN = 0,
+ BUFFEREVENT_SSL_CONNECTING = 1,
+ BUFFEREVENT_SSL_ACCEPTING = 2
+};
+
+#if defined(EVENT__HAVE_OPENSSL) || defined(EVENT_IN_DOXYGEN_)
+/**
+ Create a new SSL bufferevent to send its data over another bufferevent.
+
+ @param base An event_base to use to detect reading and writing. It
+ must also be the base for the underlying bufferevent.
+ @param underlying A socket to use for this SSL
+ @param ssl A SSL* object from openssl.
+ @param state The current state of the SSL connection
+ @param options One or more bufferevent_options
+ @return A new bufferevent on success, or NULL on failure
+*/
+EVENT2_EXPORT_SYMBOL
+struct bufferevent *
+bufferevent_openssl_filter_new(struct event_base *base,
+ struct bufferevent *underlying,
+ struct ssl_st *ssl,
+ enum bufferevent_ssl_state state,
+ int options);
+
+/**
+ Create a new SSL bufferevent to send its data over an SSL * on a socket.
+
+ @param base An event_base to use to detect reading and writing
+ @param fd A socket to use for this SSL
+ @param ssl A SSL* object from openssl.
+ @param state The current state of the SSL connection
+ @param options One or more bufferevent_options
+ @return A new bufferevent on success, or NULL on failure.
+*/
+EVENT2_EXPORT_SYMBOL
+struct bufferevent *
+bufferevent_openssl_socket_new(struct event_base *base,
+ evutil_socket_t fd,
+ struct ssl_st *ssl,
+ enum bufferevent_ssl_state state,
+ int options);
+
+/** Control how to report dirty SSL shutdowns.
+
+ If the peer (or the network, or an attacker) closes the TCP
+ connection before closing the SSL channel, and the protocol is SSL >= v3,
+ this is a "dirty" shutdown. If allow_dirty_shutdown is 0 (default),
+ this is reported as BEV_EVENT_ERROR.
+
+ If instead allow_dirty_shutdown=1, a dirty shutdown is reported as
+ BEV_EVENT_EOF.
+
+ (Note that if the protocol is < SSLv3, you will always receive
+ BEV_EVENT_EOF, since SSL 2 and earlier cannot distinguish a secure
+ connection close from a dirty one. This is one reason (among many)
+ not to use SSL 2.)
+*/
+
+EVENT2_EXPORT_SYMBOL
+int bufferevent_openssl_get_allow_dirty_shutdown(struct bufferevent *bev);
+EVENT2_EXPORT_SYMBOL
+void bufferevent_openssl_set_allow_dirty_shutdown(struct bufferevent *bev,
+ int allow_dirty_shutdown);
+
+/** Return the underlying openssl SSL * object for an SSL bufferevent. */
+EVENT2_EXPORT_SYMBOL
+struct ssl_st *
+bufferevent_openssl_get_ssl(struct bufferevent *bufev);
+
+/** Tells a bufferevent to begin SSL renegotiation. */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_ssl_renegotiate(struct bufferevent *bev);
+
+/** Return the most recent OpenSSL error reported on an SSL bufferevent. */
+EVENT2_EXPORT_SYMBOL
+unsigned long bufferevent_get_openssl_error(struct bufferevent *bev);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_BUFFEREVENT_SSL_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent_struct.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent_struct.h
new file mode 100644
index 000000000..e84c082c3
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/bufferevent_struct.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_
+#define EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_
+
+/** @file event2/bufferevent_struct.h
+
+ Data structures for bufferevents. Using these structures may hurt forward
+ compatibility with later versions of Libevent: be careful!
+
+ @deprecated Use of bufferevent_struct.h is completely deprecated; these
+ structures are only exposed for backward compatibility with programs
+ written before Libevent 2.0 that used them.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/* For int types. */
+#include <event2/util.h>
+/* For struct event */
+#include <event2/event_struct.h>
+
+struct event_watermark {
+ size_t low;
+ size_t high;
+};
+
+/**
+ Shared implementation of a bufferevent.
+
+ This type is exposed only because it was exposed in previous versions,
+ and some people's code may rely on manipulating it. Otherwise, you
+ should really not rely on the layout, size, or contents of this structure:
+ it is fairly volatile, and WILL change in future versions of the code.
+**/
+struct bufferevent {
+ /** Event base for which this bufferevent was created. */
+ struct event_base *ev_base;
+ /** Pointer to a table of function pointers to set up how this
+ bufferevent behaves. */
+ const struct bufferevent_ops *be_ops;
+
+ /** A read event that triggers when a timeout has happened or a socket
+ is ready to read data. Only used by some subtypes of
+ bufferevent. */
+ struct event ev_read;
+ /** A write event that triggers when a timeout has happened or a socket
+ is ready to write data. Only used by some subtypes of
+ bufferevent. */
+ struct event ev_write;
+
+ /** An input buffer. Only the bufferevent is allowed to add data to
+ this buffer, though the user is allowed to drain it. */
+ struct evbuffer *input;
+
+ /** An input buffer. Only the bufferevent is allowed to drain data
+ from this buffer, though the user is allowed to add it. */
+ struct evbuffer *output;
+
+ struct event_watermark wm_read;
+ struct event_watermark wm_write;
+
+ bufferevent_data_cb readcb;
+ bufferevent_data_cb writecb;
+ /* This should be called 'eventcb', but renaming it would break
+ * backward compatibility */
+ bufferevent_event_cb errorcb;
+ void *cbarg;
+
+ struct timeval timeout_read;
+ struct timeval timeout_write;
+
+ /** Events that are currently enabled: currently EV_READ and EV_WRITE
+ are supported. */
+ short enabled;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/dns.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/dns.h
new file mode 100644
index 000000000..17cd86a2e
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/dns.h
@@ -0,0 +1,717 @@
+/*
+ * Copyright (c) 2006-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The original DNS code is due to Adam Langley with heavy
+ * modifications by Nick Mathewson. Adam put his DNS software in the
+ * public domain. You can find his original copyright below. Please,
+ * aware that the code as part of Libevent is governed by the 3-clause
+ * BSD license above.
+ *
+ * This software is Public Domain. To view a copy of the public domain dedication,
+ * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
+ * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *
+ * I ask and expect, but do not require, that all derivative works contain an
+ * attribution similar to:
+ * Parts developed by Adam Langley <agl@imperialviolet.org>
+ *
+ * You may wish to replace the word "Parts" with something else depending on
+ * the amount of original code.
+ *
+ * (Derivative works does not include programs which link against, run or include
+ * the source verbatim in their source distributions)
+ */
+
+/** @file event2/dns.h
+ *
+ * Welcome, gentle reader
+ *
+ * Async DNS lookups are really a whole lot harder than they should be,
+ * mostly stemming from the fact that the libc resolver has never been
+ * very good at them. Before you use this library you should see if libc
+ * can do the job for you with the modern async call getaddrinfo_a
+ * (see http://www.imperialviolet.org/page25.html#e498). Otherwise,
+ * please continue.
+ *
+ * The library keeps track of the state of nameservers and will avoid
+ * them when they go down. Otherwise it will round robin between them.
+ *
+ * Quick start guide:
+ * #include "evdns.h"
+ * void callback(int result, char type, int count, int ttl,
+ * void *addresses, void *arg);
+ * evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
+ * evdns_resolve("www.hostname.com", 0, callback, NULL);
+ *
+ * When the lookup is complete the callback function is called. The
+ * first argument will be one of the DNS_ERR_* defines in evdns.h.
+ * Hopefully it will be DNS_ERR_NONE, in which case type will be
+ * DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
+ * which the data can be cached for (in seconds), addresses will point
+ * to an array of uint32_t's and arg will be whatever you passed to
+ * evdns_resolve.
+ *
+ * Searching:
+ *
+ * In order for this library to be a good replacement for glibc's resolver it
+ * supports searching. This involves setting a list of default domains, in
+ * which names will be queried for. The number of dots in the query name
+ * determines the order in which this list is used.
+ *
+ * Searching appears to be a single lookup from the point of view of the API,
+ * although many DNS queries may be generated from a single call to
+ * evdns_resolve. Searching can also drastically slow down the resolution
+ * of names.
+ *
+ * To disable searching:
+ * 1. Never set it up. If you never call evdns_resolv_conf_parse or
+ * evdns_search_add then no searching will occur.
+ *
+ * 2. If you do call evdns_resolv_conf_parse then don't pass
+ * DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it).
+ *
+ * 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag.
+ *
+ * The order of searches depends on the number of dots in the name. If the
+ * number is greater than the ndots setting then the names is first tried
+ * globally. Otherwise each search domain is appended in turn.
+ *
+ * The ndots setting can either be set from a resolv.conf, or by calling
+ * evdns_search_ndots_set.
+ *
+ * For example, with ndots set to 1 (the default) and a search domain list of
+ * ["myhome.net"]:
+ * Query: www
+ * Order: www.myhome.net, www.
+ *
+ * Query: www.abc
+ * Order: www.abc., www.abc.myhome.net
+ *
+ * Internals:
+ *
+ * Requests are kept in two queues. The first is the inflight queue. In
+ * this queue requests have an allocated transaction id and nameserver.
+ * They will soon be transmitted if they haven't already been.
+ *
+ * The second is the waiting queue. The size of the inflight ring is
+ * limited and all other requests wait in waiting queue for space. This
+ * bounds the number of concurrent requests so that we don't flood the
+ * nameserver. Several algorithms require a full walk of the inflight
+ * queue and so bounding its size keeps thing going nicely under huge
+ * (many thousands of requests) loads.
+ *
+ * If a nameserver loses too many requests it is considered down and we
+ * try not to use it. After a while we send a probe to that nameserver
+ * (a lookup for google.com) and, if it replies, we consider it working
+ * again. If the nameserver fails a probe we wait longer to try again
+ * with the next probe.
+ */
+
+#ifndef EVENT2_DNS_H_INCLUDED_
+#define EVENT2_DNS_H_INCLUDED_
+
+#include <event2/visibility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For integer types. */
+#include <event2/util.h>
+
+/** Error codes 0-5 are as described in RFC 1035. */
+#define DNS_ERR_NONE 0
+/** The name server was unable to interpret the query */
+#define DNS_ERR_FORMAT 1
+/** The name server was unable to process this query due to a problem with the
+ * name server */
+#define DNS_ERR_SERVERFAILED 2
+/** The domain name does not exist */
+#define DNS_ERR_NOTEXIST 3
+/** The name server does not support the requested kind of query */
+#define DNS_ERR_NOTIMPL 4
+/** The name server refuses to reform the specified operation for policy
+ * reasons */
+#define DNS_ERR_REFUSED 5
+/** The reply was truncated or ill-formatted */
+#define DNS_ERR_TRUNCATED 65
+/** An unknown error occurred */
+#define DNS_ERR_UNKNOWN 66
+/** Communication with the server timed out */
+#define DNS_ERR_TIMEOUT 67
+/** The request was canceled because the DNS subsystem was shut down. */
+#define DNS_ERR_SHUTDOWN 68
+/** The request was canceled via a call to evdns_cancel_request */
+#define DNS_ERR_CANCEL 69
+/** There were no answers and no error condition in the DNS packet.
+ * This can happen when you ask for an address that exists, but a record
+ * type that doesn't. */
+#define DNS_ERR_NODATA 70
+
+#define DNS_IPv4_A 1
+#define DNS_PTR 2
+#define DNS_IPv6_AAAA 3
+
+#define DNS_QUERY_NO_SEARCH 1
+
+#define DNS_OPTION_SEARCH 1
+#define DNS_OPTION_NAMESERVERS 2
+#define DNS_OPTION_MISC 4
+#define DNS_OPTION_HOSTSFILE 8
+#define DNS_OPTIONS_ALL 15
+
+/* Obsolete name for DNS_QUERY_NO_SEARCH */
+#define DNS_NO_SEARCH DNS_QUERY_NO_SEARCH
+
+/**
+ * The callback that contains the results from a lookup.
+ * - result is one of the DNS_ERR_* values (DNS_ERR_NONE for success)
+ * - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA
+ * - count contains the number of addresses of form type
+ * - ttl is the number of seconds the resolution may be cached for.
+ * - addresses needs to be cast according to type. It will be an array of
+ * 4-byte sequences for ipv4, or an array of 16-byte sequences for ipv6,
+ * or a nul-terminated string for PTR.
+ */
+typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg);
+
+struct evdns_base;
+struct event_base;
+
+/** Flag for evdns_base_new: process resolv.conf. */
+#define EVDNS_BASE_INITIALIZE_NAMESERVERS 1
+/** Flag for evdns_base_new: Do not prevent the libevent event loop from
+ * exiting when we have no active dns requests. */
+#define EVDNS_BASE_DISABLE_WHEN_INACTIVE 0x8000
+
+/**
+ Initialize the asynchronous DNS library.
+
+ This function initializes support for non-blocking name resolution by
+ calling evdns_resolv_conf_parse() on UNIX and
+ evdns_config_windows_nameservers() on Windows.
+
+ @param event_base the event base to associate the dns client with
+ @param flags any of EVDNS_BASE_INITIALIZE_NAMESERVERS|
+ EVDNS_BASE_DISABLE_WHEN_INACTIVE
+ @return evdns_base object if successful, or NULL if an error occurred.
+ @see evdns_base_free()
+ */
+EVENT2_EXPORT_SYMBOL
+struct evdns_base * evdns_base_new(struct event_base *event_base, int initialize_nameservers);
+
+
+/**
+ Shut down the asynchronous DNS resolver and terminate all active requests.
+
+ If the 'fail_requests' option is enabled, all active requests will return
+ an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise,
+ the requests will be silently discarded.
+
+ @param evdns_base the evdns base to free
+ @param fail_requests if zero, active requests will be aborted; if non-zero,
+ active requests will return DNS_ERR_SHUTDOWN.
+ @see evdns_base_new()
+ */
+EVENT2_EXPORT_SYMBOL
+void evdns_base_free(struct evdns_base *base, int fail_requests);
+
+/**
+ Remove all hosts entries that have been loaded into the event_base via
+ evdns_base_load_hosts or via event_base_resolv_conf_parse.
+
+ @param evdns_base the evdns base to remove outdated host addresses from
+ */
+EVENT2_EXPORT_SYMBOL
+void evdns_base_clear_host_addresses(struct evdns_base *base);
+
+/**
+ Convert a DNS error code to a string.
+
+ @param err the DNS error code
+ @return a string containing an explanation of the error code
+*/
+EVENT2_EXPORT_SYMBOL
+const char *evdns_err_to_string(int err);
+
+
+/**
+ Add a nameserver.
+
+ The address should be an IPv4 address in network byte order.
+ The type of address is chosen so that it matches in_addr.s_addr.
+
+ @param base the evdns_base to which to add the name server
+ @param address an IP address in network byte order
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_base_nameserver_ip_add()
+ */
+EVENT2_EXPORT_SYMBOL
+int evdns_base_nameserver_add(struct evdns_base *base,
+ unsigned long int address);
+
+/**
+ Get the number of configured nameservers.
+
+ This returns the number of configured nameservers (not necessarily the
+ number of running nameservers). This is useful for double-checking
+ whether our calls to the various nameserver configuration functions
+ have been successful.
+
+ @param base the evdns_base to which to apply this operation
+ @return the number of configured nameservers
+ @see evdns_base_nameserver_add()
+ */
+EVENT2_EXPORT_SYMBOL
+int evdns_base_count_nameservers(struct evdns_base *base);
+
+/**
+ Remove all configured nameservers, and suspend all pending resolves.
+
+ Resolves will not necessarily be re-attempted until evdns_base_resume() is called.
+
+ @param base the evdns_base to which to apply this operation
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_base_resume()
+ */
+EVENT2_EXPORT_SYMBOL
+int evdns_base_clear_nameservers_and_suspend(struct evdns_base *base);
+
+
+/**
+ Resume normal operation and continue any suspended resolve requests.
+
+ Re-attempt resolves left in limbo after an earlier call to
+ evdns_base_clear_nameservers_and_suspend().
+
+ @param base the evdns_base to which to apply this operation
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_base_clear_nameservers_and_suspend()
+ */
+EVENT2_EXPORT_SYMBOL
+int evdns_base_resume(struct evdns_base *base);
+
+/**
+ Add a nameserver by string address.
+
+ This function parses a n IPv4 or IPv6 address from a string and adds it as a
+ nameserver. It supports the following formats:
+ - [IPv6Address]:port
+ - [IPv6Address]
+ - IPv6Address
+ - IPv4Address:port
+ - IPv4Address
+
+ If no port is specified, it defaults to 53.
+
+ @param base the evdns_base to which to apply this operation
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_base_nameserver_add()
+ */
+EVENT2_EXPORT_SYMBOL
+int evdns_base_nameserver_ip_add(struct evdns_base *base,
+ const char *ip_as_string);
+
+/**
+ Add a nameserver by sockaddr.
+ **/
+EVENT2_EXPORT_SYMBOL
+int
+evdns_base_nameserver_sockaddr_add(struct evdns_base *base,
+ const struct sockaddr *sa, ev_socklen_t len, unsigned flags);
+
+struct evdns_request;
+
+/**
+ Lookup an A record for a given name.
+
+ @param base the evdns_base to which to apply this operation
+ @param name a DNS hostname
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return an evdns_request object if successful, or NULL if an error occurred.
+ @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6(), evdns_cancel_request()
+ */
+EVENT2_EXPORT_SYMBOL
+struct evdns_request *evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr);
+
+/**
+ Lookup an AAAA record for a given name.
+
+ @param base the evdns_base to which to apply this operation
+ @param name a DNS hostname
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return an evdns_request object if successful, or NULL if an error occurred.
+ @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6(), evdns_cancel_request()
+ */
+EVENT2_EXPORT_SYMBOL
+struct evdns_request *evdns_base_resolve_ipv6(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr);
+
+struct in_addr;
+struct in6_addr;
+
+/**
+ Lookup a PTR record for a given IP address.
+
+ @param base the evdns_base to which to apply this operation
+ @param in an IPv4 address
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return an evdns_request object if successful, or NULL if an error occurred.
+ @see evdns_resolve_reverse_ipv6(), evdns_cancel_request()
+ */
+EVENT2_EXPORT_SYMBOL
+struct evdns_request *evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
+
+
+/**
+ Lookup a PTR record for a given IPv6 address.
+
+ @param base the evdns_base to which to apply this operation
+ @param in an IPv6 address
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return an evdns_request object if successful, or NULL if an error occurred.
+ @see evdns_resolve_reverse_ipv6(), evdns_cancel_request()
+ */
+EVENT2_EXPORT_SYMBOL
+struct evdns_request *evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
+
+/**
+ Cancels a pending DNS resolution request.
+
+ @param base the evdns_base that was used to make the request
+ @param req the evdns_request that was returned by calling a resolve function
+ @see evdns_base_resolve_ipv4(), evdns_base_resolve_ipv6, evdns_base_resolve_reverse
+*/
+EVENT2_EXPORT_SYMBOL
+void evdns_cancel_request(struct evdns_base *base, struct evdns_request *req);
+
+/**
+ Set the value of a configuration option.
+
+ The currently available configuration options are:
+
+ ndots, timeout, max-timeouts, max-inflight, attempts, randomize-case,
+ bind-to, initial-probe-timeout, getaddrinfo-allow-skew.
+
+ In versions before Libevent 2.0.3-alpha, the option name needed to end with
+ a colon.
+
+ @param base the evdns_base to which to apply this operation
+ @param option the name of the configuration option to be modified
+ @param val the value to be set
+ @return 0 if successful, or -1 if an error occurred
+ */
+EVENT2_EXPORT_SYMBOL
+int evdns_base_set_option(struct evdns_base *base, const char *option, const char *val);
+
+
+/**
+ Parse a resolv.conf file.
+
+ The 'flags' parameter determines what information is parsed from the
+ resolv.conf file. See the man page for resolv.conf for the format of this
+ file.
+
+ The following directives are not parsed from the file: sortlist, rotate,
+ no-check-names, inet6, debug.
+
+ If this function encounters an error, the possible return values are: 1 =
+ failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of
+ memory, 5 = short read from file, 6 = no nameservers listed in the file
+
+ @param base the evdns_base to which to apply this operation
+ @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC|
+ DNS_OPTION_HOSTSFILE|DNS_OPTIONS_ALL
+ @param filename the path to the resolv.conf file
+ @return 0 if successful, or various positive error codes if an error
+ occurred (see above)
+ @see resolv.conf(3), evdns_config_windows_nameservers()
+ */
+EVENT2_EXPORT_SYMBOL
+int evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename);
+
+/**
+ Load an /etc/hosts-style file from 'hosts_fname' into 'base'.
+
+ If hosts_fname is NULL, add minimal entries for localhost, and nothing
+ else.
+
+ Note that only evdns_getaddrinfo uses the /etc/hosts entries.
+
+ This function does not replace previously loaded hosts entries; to do that,
+ call evdns_base_clear_host_addresses first.
+
+ Return 0 on success, negative on failure.
+*/
+EVENT2_EXPORT_SYMBOL
+int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname);
+
+/**
+ Obtain nameserver information using the Windows API.
+
+ Attempt to configure a set of nameservers based on platform settings on
+ a win32 host. Preferentially tries to use GetNetworkParams; if that fails,
+ looks in the registry.
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolv_conf_parse()
+ */
+#ifdef _WIN32
+EVENT2_EXPORT_SYMBOL
+int evdns_base_config_windows_nameservers(struct evdns_base *);
+#define EVDNS_BASE_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED
+#endif
+
+
+/**
+ Clear the list of search domains.
+ */
+EVENT2_EXPORT_SYMBOL
+void evdns_base_search_clear(struct evdns_base *base);
+
+
+/**
+ Add a domain to the list of search domains
+
+ @param domain the domain to be added to the search list
+ */
+EVENT2_EXPORT_SYMBOL
+void evdns_base_search_add(struct evdns_base *base, const char *domain);
+
+
+/**
+ Set the 'ndots' parameter for searches.
+
+ Sets the number of dots which, when found in a name, causes
+ the first query to be without any search domain.
+
+ @param ndots the new ndots parameter
+ */
+EVENT2_EXPORT_SYMBOL
+void evdns_base_search_ndots_set(struct evdns_base *base, const int ndots);
+
+/**
+ A callback that is invoked when a log message is generated
+
+ @param is_warning indicates if the log message is a 'warning'
+ @param msg the content of the log message
+ */
+typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg);
+
+
+/**
+ Set the callback function to handle DNS log messages. If this
+ callback is not set, evdns log messages are handled with the regular
+ Libevent logging system.
+
+ @param fn the callback to be invoked when a log message is generated
+ */
+EVENT2_EXPORT_SYMBOL
+void evdns_set_log_fn(evdns_debug_log_fn_type fn);
+
+/**
+ Set a callback that will be invoked to generate transaction IDs. By
+ default, we pick transaction IDs based on the current clock time, which
+ is bad for security.
+
+ @param fn the new callback, or NULL to use the default.
+
+ NOTE: This function has no effect in Libevent 2.0.4-alpha and later,
+ since Libevent now provides its own secure RNG.
+ */
+EVENT2_EXPORT_SYMBOL
+void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void));
+
+/**
+ Set a callback used to generate random bytes. By default, we use
+ the same function as passed to evdns_set_transaction_id_fn to generate
+ bytes two at a time. If a function is provided here, it's also used
+ to generate transaction IDs.
+
+ NOTE: This function has no effect in Libevent 2.0.4-alpha and later,
+ since Libevent now provides its own secure RNG.
+*/
+EVENT2_EXPORT_SYMBOL
+void evdns_set_random_bytes_fn(void (*fn)(char *, size_t));
+
+/*
+ * Functions used to implement a DNS server.
+ */
+
+struct evdns_server_request;
+struct evdns_server_question;
+
+/**
+ A callback to implement a DNS server. The callback function receives a DNS
+ request. It should then optionally add a number of answers to the reply
+ using the evdns_server_request_add_*_reply functions, before calling either
+ evdns_server_request_respond to send the reply back, or
+ evdns_server_request_drop to decline to answer the request.
+
+ @param req A newly received request
+ @param user_data A pointer that was passed to
+ evdns_add_server_port_with_base().
+ */
+typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *);
+#define EVDNS_ANSWER_SECTION 0
+#define EVDNS_AUTHORITY_SECTION 1
+#define EVDNS_ADDITIONAL_SECTION 2
+
+#define EVDNS_TYPE_A 1
+#define EVDNS_TYPE_NS 2
+#define EVDNS_TYPE_CNAME 5
+#define EVDNS_TYPE_SOA 6
+#define EVDNS_TYPE_PTR 12
+#define EVDNS_TYPE_MX 15
+#define EVDNS_TYPE_TXT 16
+#define EVDNS_TYPE_AAAA 28
+
+#define EVDNS_QTYPE_AXFR 252
+#define EVDNS_QTYPE_ALL 255
+
+#define EVDNS_CLASS_INET 1
+
+/* flags that can be set in answers; as part of the err parameter */
+#define EVDNS_FLAGS_AA 0x400
+#define EVDNS_FLAGS_RD 0x080
+
+/** Create a new DNS server port.
+
+ @param base The event base to handle events for the server port.
+ @param socket A UDP socket to accept DNS requests.
+ @param flags Always 0 for now.
+ @param callback A function to invoke whenever we get a DNS request
+ on the socket.
+ @param user_data Data to pass to the callback.
+ @return an evdns_server_port structure for this server port.
+ */
+EVENT2_EXPORT_SYMBOL
+struct evdns_server_port *evdns_add_server_port_with_base(struct event_base *base, evutil_socket_t socket, int flags, evdns_request_callback_fn_type callback, void *user_data);
+/** Close down a DNS server port, and free associated structures. */
+EVENT2_EXPORT_SYMBOL
+void evdns_close_server_port(struct evdns_server_port *port);
+
+/** Sets some flags in a reply we're building.
+ Allows setting of the AA or RD flags
+ */
+EVENT2_EXPORT_SYMBOL
+void evdns_server_request_set_flags(struct evdns_server_request *req, int flags);
+
+/* Functions to add an answer to an in-progress DNS reply.
+ */
+EVENT2_EXPORT_SYMBOL
+int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data);
+EVENT2_EXPORT_SYMBOL
+int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl);
+EVENT2_EXPORT_SYMBOL
+int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl);
+EVENT2_EXPORT_SYMBOL
+int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl);
+EVENT2_EXPORT_SYMBOL
+int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl);
+
+/**
+ Send back a response to a DNS request, and free the request structure.
+*/
+EVENT2_EXPORT_SYMBOL
+int evdns_server_request_respond(struct evdns_server_request *req, int err);
+/**
+ Free a DNS request without sending back a reply.
+*/
+EVENT2_EXPORT_SYMBOL
+int evdns_server_request_drop(struct evdns_server_request *req);
+struct sockaddr;
+/**
+ Get the address that made a DNS request.
+ */
+EVENT2_EXPORT_SYMBOL
+int evdns_server_request_get_requesting_addr(struct evdns_server_request *req, struct sockaddr *sa, int addr_len);
+
+/** Callback for evdns_getaddrinfo. */
+typedef void (*evdns_getaddrinfo_cb)(int result, struct evutil_addrinfo *res, void *arg);
+
+struct evdns_base;
+struct evdns_getaddrinfo_request;
+/** Make a non-blocking getaddrinfo request using the dns_base in 'dns_base'.
+ *
+ * If we can answer the request immediately (with an error or not!), then we
+ * invoke cb immediately and return NULL. Otherwise we return
+ * an evdns_getaddrinfo_request and invoke cb later.
+ *
+ * When the callback is invoked, we pass as its first argument the error code
+ * that getaddrinfo would return (or 0 for no error). As its second argument,
+ * we pass the evutil_addrinfo structures we found (or NULL on error). We
+ * pass 'arg' as the third argument.
+ *
+ * Limitations:
+ *
+ * - The AI_V4MAPPED and AI_ALL flags are not currently implemented.
+ * - For ai_socktype, we only handle SOCKTYPE_STREAM, SOCKTYPE_UDP, and 0.
+ * - For ai_protocol, we only handle IPPROTO_TCP, IPPROTO_UDP, and 0.
+ */
+EVENT2_EXPORT_SYMBOL
+struct evdns_getaddrinfo_request *evdns_getaddrinfo(
+ struct evdns_base *dns_base,
+ const char *nodename, const char *servname,
+ const struct evutil_addrinfo *hints_in,
+ evdns_getaddrinfo_cb cb, void *arg);
+
+/* Cancel an in-progress evdns_getaddrinfo. This MUST NOT be called after the
+ * getaddrinfo's callback has been invoked. The resolves will be canceled,
+ * and the callback will be invoked with the error EVUTIL_EAI_CANCEL. */
+EVENT2_EXPORT_SYMBOL
+void evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *req);
+
+/**
+ Retrieve the address of the 'idx'th configured nameserver.
+
+ @param base The evdns_base to examine.
+ @param idx The index of the nameserver to get the address of.
+ @param sa A location to receive the server's address.
+ @param len The number of bytes available at sa.
+
+ @return the number of bytes written into sa on success. On failure, returns
+ -1 if idx is greater than the number of configured nameservers, or a
+ value greater than 'len' if len was not high enough.
+ */
+EVENT2_EXPORT_SYMBOL
+int evdns_base_get_nameserver_addr(struct evdns_base *base, int idx,
+ struct sockaddr *sa, ev_socklen_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !EVENT2_DNS_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/dns_compat.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/dns_compat.h
new file mode 100644
index 000000000..965fd6544
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/dns_compat.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2006-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_DNS_COMPAT_H_INCLUDED_
+#define EVENT2_DNS_COMPAT_H_INCLUDED_
+
+/** @file event2/dns_compat.h
+
+ Potentially non-threadsafe versions of the functions in dns.h: provided
+ only for backwards compatibility.
+
+
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/* For int types. */
+#include <event2/util.h>
+
+/**
+ Initialize the asynchronous DNS library.
+
+ This function initializes support for non-blocking name resolution by
+ calling evdns_resolv_conf_parse() on UNIX and
+ evdns_config_windows_nameservers() on Windows.
+
+ @deprecated This function is deprecated because it always uses the current
+ event base, and is easily confused by multiple calls to event_init(), and
+ so is not safe for multithreaded use. Additionally, it allocates a global
+ structure that only one thread can use. The replacement is
+ evdns_base_new().
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_shutdown()
+ */
+int evdns_init(void);
+
+struct evdns_base;
+/**
+ Return the global evdns_base created by event_init() and used by the other
+ deprecated functions.
+
+ @deprecated This function is deprecated because use of the global
+ evdns_base is error-prone.
+ */
+struct evdns_base *evdns_get_global_base(void);
+
+/**
+ Shut down the asynchronous DNS resolver and terminate all active requests.
+
+ If the 'fail_requests' option is enabled, all active requests will return
+ an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise,
+ the requests will be silently discarded.
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_shutdown().
+
+ @param fail_requests if zero, active requests will be aborted; if non-zero,
+ active requests will return DNS_ERR_SHUTDOWN.
+ @see evdns_init()
+ */
+void evdns_shutdown(int fail_requests);
+
+/**
+ Add a nameserver.
+
+ The address should be an IPv4 address in network byte order.
+ The type of address is chosen so that it matches in_addr.s_addr.
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_nameserver_add().
+
+ @param address an IP address in network byte order
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_nameserver_ip_add()
+ */
+int evdns_nameserver_add(unsigned long int address);
+
+/**
+ Get the number of configured nameservers.
+
+ This returns the number of configured nameservers (not necessarily the
+ number of running nameservers). This is useful for double-checking
+ whether our calls to the various nameserver configuration functions
+ have been successful.
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_count_nameservers().
+
+ @return the number of configured nameservers
+ @see evdns_nameserver_add()
+ */
+int evdns_count_nameservers(void);
+
+/**
+ Remove all configured nameservers, and suspend all pending resolves.
+
+ Resolves will not necessarily be re-attempted until evdns_resume() is called.
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_clear_nameservers_and_suspend().
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resume()
+ */
+int evdns_clear_nameservers_and_suspend(void);
+
+/**
+ Resume normal operation and continue any suspended resolve requests.
+
+ Re-attempt resolves left in limbo after an earlier call to
+ evdns_clear_nameservers_and_suspend().
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_resume().
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_clear_nameservers_and_suspend()
+ */
+int evdns_resume(void);
+
+/**
+ Add a nameserver.
+
+ This wraps the evdns_nameserver_add() function by parsing a string as an IP
+ address and adds it as a nameserver.
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_nameserver_ip_add().
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_nameserver_add()
+ */
+int evdns_nameserver_ip_add(const char *ip_as_string);
+
+/**
+ Lookup an A record for a given name.
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_resolve_ipv4().
+
+ @param name a DNS hostname
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
+ */
+int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr);
+
+/**
+ Lookup an AAAA record for a given name.
+
+ @param name a DNS hostname
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
+ */
+int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr);
+
+struct in_addr;
+struct in6_addr;
+
+/**
+ Lookup a PTR record for a given IP address.
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_resolve_reverse().
+
+ @param in an IPv4 address
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolve_reverse_ipv6()
+ */
+int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
+
+/**
+ Lookup a PTR record for a given IPv6 address.
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_resolve_reverse_ipv6().
+
+ @param in an IPv6 address
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolve_reverse_ipv6()
+ */
+int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
+
+/**
+ Set the value of a configuration option.
+
+ The currently available configuration options are:
+
+ ndots, timeout, max-timeouts, max-inflight, and attempts
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_set_option().
+
+ @param option the name of the configuration option to be modified
+ @param val the value to be set
+ @param flags Ignored.
+ @return 0 if successful, or -1 if an error occurred
+ */
+int evdns_set_option(const char *option, const char *val, int flags);
+
+/**
+ Parse a resolv.conf file.
+
+ The 'flags' parameter determines what information is parsed from the
+ resolv.conf file. See the man page for resolv.conf for the format of this
+ file.
+
+ The following directives are not parsed from the file: sortlist, rotate,
+ no-check-names, inet6, debug.
+
+ If this function encounters an error, the possible return values are: 1 =
+ failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of
+ memory, 5 = short read from file, 6 = no nameservers listed in the file
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_resolv_conf_parse().
+
+ @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC|
+ DNS_OPTIONS_ALL
+ @param filename the path to the resolv.conf file
+ @return 0 if successful, or various positive error codes if an error
+ occurred (see above)
+ @see resolv.conf(3), evdns_config_windows_nameservers()
+ */
+int evdns_resolv_conf_parse(int flags, const char *const filename);
+
+/**
+ Clear the list of search domains.
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_search_clear().
+ */
+void evdns_search_clear(void);
+
+/**
+ Add a domain to the list of search domains
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_search_add().
+
+ @param domain the domain to be added to the search list
+ */
+void evdns_search_add(const char *domain);
+
+/**
+ Set the 'ndots' parameter for searches.
+
+ Sets the number of dots which, when found in a name, causes
+ the first query to be without any search domain.
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which evdns_base it applies to. The recommended
+ function is evdns_base_search_ndots_set().
+
+ @param ndots the new ndots parameter
+ */
+void evdns_search_ndots_set(const int ndots);
+
+/**
+ As evdns_server_new_with_base.
+
+ @deprecated This function is deprecated because it does not allow the
+ caller to specify which even_base it uses. The recommended
+ function is evdns_add_server_port_with_base().
+
+*/
+struct evdns_server_port *evdns_add_server_port(evutil_socket_t socket, int flags, evdns_request_callback_fn_type callback, void *user_data);
+
+#ifdef _WIN32
+int evdns_config_windows_nameservers(void);
+#define EVDNS_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/dns_struct.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/dns_struct.h
new file mode 100644
index 000000000..593a8a70b
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/dns_struct.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_DNS_STRUCT_H_INCLUDED_
+#define EVENT2_DNS_STRUCT_H_INCLUDED_
+
+/** @file event2/dns_struct.h
+
+ Data structures for dns. Using these structures may hurt forward
+ compatibility with later versions of Libevent: be careful!
+
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/* For int types. */
+#include <event2/util.h>
+
+/*
+ * Structures used to implement a DNS server.
+ */
+
+struct evdns_server_request {
+ int flags;
+ int nquestions;
+ struct evdns_server_question **questions;
+};
+struct evdns_server_question {
+ int type;
+#ifdef __cplusplus
+ int dns_question_class;
+#else
+ /* You should refer to this field as "dns_question_class". The
+ * name "class" works in C for backward compatibility, and will be
+ * removed in a future version. (1.5 or later). */
+ int class;
+#define dns_question_class class
+#endif
+ char name[1];
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_DNS_STRUCT_H_INCLUDED_ */
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/event.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/event.h
new file mode 100644
index 000000000..6e0a4f04c
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/event.h
@@ -0,0 +1,1675 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_EVENT_H_INCLUDED_
+#define EVENT2_EVENT_H_INCLUDED_
+
+/**
+ @mainpage
+
+ @section intro Introduction
+
+ Libevent is an event notification library for developing scalable network
+ servers. The Libevent API provides a mechanism to execute a callback
+ function when a specific event occurs on a file descriptor or after a
+ timeout has been reached. Furthermore, Libevent also support callbacks due
+ to signals or regular timeouts.
+
+ Libevent is meant to replace the event loop found in event driven network
+ servers. An application just needs to call event_base_dispatch() and then add or
+ remove events dynamically without having to change the event loop.
+
+
+ Currently, Libevent supports /dev/poll, kqueue(2), select(2), poll(2),
+ epoll(4), and evports. The internal event mechanism is completely
+ independent of the exposed event API, and a simple update of Libevent can
+ provide new functionality without having to redesign the applications. As a
+ result, Libevent allows for portable application development and provides
+ the most scalable event notification mechanism available on an operating
+ system. Libevent can also be used for multithreaded programs. Libevent
+ should compile on Linux, *BSD, Mac OS X, Solaris and, Windows.
+
+ @section usage Standard usage
+
+ Every program that uses Libevent must include the <event2/event.h>
+ header, and pass the -levent flag to the linker. (You can instead link
+ -levent_core if you only want the main event and buffered IO-based code,
+ and don't want to link any protocol code.)
+
+ @section setup Library setup
+
+ Before you call any other Libevent functions, you need to set up the
+ library. If you're going to use Libevent from multiple threads in a
+ multithreaded application, you need to initialize thread support --
+ typically by using evthread_use_pthreads() or
+ evthread_use_windows_threads(). See <event2/thread.h> for more
+ information.
+
+ This is also the point where you can replace Libevent's memory
+ management functions with event_set_mem_functions, and enable debug mode
+ with event_enable_debug_mode().
+
+ @section base Creating an event base
+
+ Next, you need to create an event_base structure, using event_base_new()
+ or event_base_new_with_config(). The event_base is responsible for
+ keeping track of which events are "pending" (that is to say, being
+ watched to see if they become active) and which events are "active".
+ Every event is associated with a single event_base.
+
+ @section event Event notification
+
+ For each file descriptor that you wish to monitor, you must create an
+ event structure with event_new(). (You may also declare an event
+ structure and call event_assign() to initialize the members of the
+ structure.) To enable notification, you add the structure to the list
+ of monitored events by calling event_add(). The event structure must
+ remain allocated as long as it is active, so it should generally be
+ allocated on the heap.
+
+ @section loop Dispatching events.
+
+ Finally, you call event_base_dispatch() to loop and dispatch events.
+ You can also use event_base_loop() for more fine-grained control.
+
+ Currently, only one thread can be dispatching a given event_base at a
+ time. If you want to run events in multiple threads at once, you can
+ either have a single event_base whose events add work to a work queue,
+ or you can create multiple event_base objects.
+
+ @section bufferevent I/O Buffers
+
+ Libevent provides a buffered I/O abstraction on top of the regular event
+ callbacks. This abstraction is called a bufferevent. A bufferevent
+ provides input and output buffers that get filled and drained
+ automatically. The user of a buffered event no longer deals directly
+ with the I/O, but instead is reading from input and writing to output
+ buffers.
+
+ Once initialized via bufferevent_socket_new(), the bufferevent structure
+ can be used repeatedly with bufferevent_enable() and
+ bufferevent_disable(). Instead of reading and writing directly to a
+ socket, you would call bufferevent_read() and bufferevent_write().
+
+ When read enabled the bufferevent will try to read from the file descriptor
+ and call the read callback. The write callback is executed whenever the
+ output buffer is drained below the write low watermark, which is 0 by
+ default.
+
+ See <event2/bufferevent*.h> for more information.
+
+ @section timers Timers
+
+ Libevent can also be used to create timers that invoke a callback after a
+ certain amount of time has expired. The evtimer_new() macro returns
+ an event struct to use as a timer. To activate the timer, call
+ evtimer_add(). Timers can be deactivated by calling evtimer_del().
+ (These macros are thin wrappers around event_new(), event_add(),
+ and event_del(); you can also use those instead.)
+
+ @section evdns Asynchronous DNS resolution
+
+ Libevent provides an asynchronous DNS resolver that should be used instead
+ of the standard DNS resolver functions. See the <event2/dns.h>
+ functions for more detail.
+
+ @section evhttp Event-driven HTTP servers
+
+ Libevent provides a very simple event-driven HTTP server that can be
+ embedded in your program and used to service HTTP requests.
+
+ To use this capability, you need to include the <event2/http.h> header in your
+ program. See that header for more information.
+
+ @section evrpc A framework for RPC servers and clients
+
+ Libevent provides a framework for creating RPC servers and clients. It
+ takes care of marshaling and unmarshaling all data structures.
+
+ @section api API Reference
+
+ To browse the complete documentation of the libevent API, click on any of
+ the following links.
+
+ event2/event.h
+ The primary libevent header
+
+ event2/thread.h
+ Functions for use by multithreaded programs
+
+ event2/buffer.h and event2/bufferevent.h
+ Buffer management for network reading and writing
+
+ event2/util.h
+ Utility functions for portable nonblocking network code
+
+ event2/dns.h
+ Asynchronous DNS resolution
+
+ event2/http.h
+ An embedded libevent-based HTTP server
+
+ event2/rpc.h
+ A framework for creating RPC servers and clients
+
+ */
+
+/** @file event2/event.h
+
+ Core functions for waiting for and receiving events, and using event bases.
+*/
+
+#include <event2/visibility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <stdio.h>
+
+/* For int types. */
+#include <event2/util.h>
+
+/**
+ * Structure to hold information and state for a Libevent dispatch loop.
+ *
+ * The event_base lies at the center of Libevent; every application will
+ * have one. It keeps track of all pending and active events, and
+ * notifies your application of the active ones.
+ *
+ * This is an opaque structure; you can allocate one using
+ * event_base_new() or event_base_new_with_config().
+ *
+ * @see event_base_new(), event_base_free(), event_base_loop(),
+ * event_base_new_with_config()
+ */
+struct event_base
+#ifdef EVENT_IN_DOXYGEN_
+{/*Empty body so that doxygen will generate documentation here.*/}
+#endif
+;
+
+/**
+ * @struct event
+ *
+ * Structure to represent a single event.
+ *
+ * An event can have some underlying condition it represents: a socket
+ * becoming readable or writeable (or both), or a signal becoming raised.
+ * (An event that represents no underlying condition is still useful: you
+ * can use one to implement a timer, or to communicate between threads.)
+ *
+ * Generally, you can create events with event_new(), then make them
+ * pending with event_add(). As your event_base runs, it will run the
+ * callbacks of an events whose conditions are triggered. When you
+ * longer want the event, free it with event_free().
+ *
+ * In more depth:
+ *
+ * An event may be "pending" (one whose condition we are watching),
+ * "active" (one whose condition has triggered and whose callback is about
+ * to run), neither, or both. Events come into existence via
+ * event_assign() or event_new(), and are then neither active nor pending.
+ *
+ * To make an event pending, pass it to event_add(). When doing so, you
+ * can also set a timeout for the event.
+ *
+ * Events become active during an event_base_loop() call when either their
+ * condition has triggered, or when their timeout has elapsed. You can
+ * also activate an event manually using event_active(). The even_base
+ * loop will run the callbacks of active events; after it has done so, it
+ * marks them as no longer active.
+ *
+ * You can make an event non-pending by passing it to event_del(). This
+ * also makes the event non-active.
+ *
+ * Events can be "persistent" or "non-persistent". A non-persistent event
+ * becomes non-pending as soon as it is triggered: thus, it only runs at
+ * most once per call to event_add(). A persistent event remains pending
+ * even when it becomes active: you'll need to event_del() it manually in
+ * order to make it non-pending. When a persistent event with a timeout
+ * becomes active, its timeout is reset: this means you can use persistent
+ * events to implement periodic timeouts.
+ *
+ * This should be treated as an opaque structure; you should never read or
+ * write any of its fields directly. For backward compatibility with old
+ * code, it is defined in the event2/event_struct.h header; including this
+ * header may make your code incompatible with other versions of Libevent.
+ *
+ * @see event_new(), event_free(), event_assign(), event_get_assignment(),
+ * event_add(), event_del(), event_active(), event_pending(),
+ * event_get_fd(), event_get_base(), event_get_events(),
+ * event_get_callback(), event_get_callback_arg(),
+ * event_priority_set()
+ */
+struct event
+#ifdef EVENT_IN_DOXYGEN_
+{/*Empty body so that doxygen will generate documentation here.*/}
+#endif
+;
+
+/**
+ * Configuration for an event_base.
+ *
+ * There are many options that can be used to alter the behavior and
+ * implementation of an event_base. To avoid having to pass them all in a
+ * complex many-argument constructor, we provide an abstract data type
+ * wrhere you set up configation information before passing it to
+ * event_base_new_with_config().
+ *
+ * @see event_config_new(), event_config_free(), event_base_new_with_config(),
+ * event_config_avoid_method(), event_config_require_features(),
+ * event_config_set_flag(), event_config_set_num_cpus_hint()
+ */
+struct event_config
+#ifdef EVENT_IN_DOXYGEN_
+{/*Empty body so that doxygen will generate documentation here.*/}
+#endif
+;
+
+/**
+ * Enable some relatively expensive debugging checks in Libevent that
+ * would normally be turned off. Generally, these checks cause code that
+ * would otherwise crash mysteriously to fail earlier with an assertion
+ * failure. Note that this method MUST be called before any events or
+ * event_bases have been created.
+ *
+ * Debug mode can currently catch the following errors:
+ * An event is re-assigned while it is added
+ * Any function is called on a non-assigned event
+ *
+ * Note that debugging mode uses memory to track every event that has been
+ * initialized (via event_assign, event_set, or event_new) but not yet
+ * released (via event_free or event_debug_unassign). If you want to use
+ * debug mode, and you find yourself running out of memory, you will need
+ * to use event_debug_unassign to explicitly stop tracking events that
+ * are no longer considered set-up.
+ *
+ * @see event_debug_unassign()
+ */
+EVENT2_EXPORT_SYMBOL
+void event_enable_debug_mode(void);
+
+/**
+ * When debugging mode is enabled, informs Libevent that an event should no
+ * longer be considered as assigned. When debugging mode is not enabled, does
+ * nothing.
+ *
+ * This function must only be called on a non-added event.
+ *
+ * @see event_enable_debug_mode()
+ */
+EVENT2_EXPORT_SYMBOL
+void event_debug_unassign(struct event *);
+
+/**
+ * Create and return a new event_base to use with the rest of Libevent.
+ *
+ * @return a new event_base on success, or NULL on failure.
+ *
+ * @see event_base_free(), event_base_new_with_config()
+ */
+EVENT2_EXPORT_SYMBOL
+struct event_base *event_base_new(void);
+
+/**
+ Reinitialize the event base after a fork
+
+ Some event mechanisms do not survive across fork. The event base needs
+ to be reinitialized with the event_reinit() function.
+
+ @param base the event base that needs to be re-initialized
+ @return 0 if successful, or -1 if some events could not be re-added.
+ @see event_base_new()
+*/
+EVENT2_EXPORT_SYMBOL
+int event_reinit(struct event_base *base);
+
+/**
+ Event dispatching loop
+
+ This loop will run the event base until either there are no more pending or
+ active, or until something calls event_base_loopbreak() or
+ event_base_loopexit().
+
+ @param base the event_base structure returned by event_base_new() or
+ event_base_new_with_config()
+ @return 0 if successful, -1 if an error occurred, or 1 if we exited because
+ no events were pending or active.
+ @see event_base_loop()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_dispatch(struct event_base *);
+
+/**
+ Get the kernel event notification mechanism used by Libevent.
+
+ @param eb the event_base structure returned by event_base_new()
+ @return a string identifying the kernel event mechanism (kqueue, epoll, etc.)
+ */
+EVENT2_EXPORT_SYMBOL
+const char *event_base_get_method(const struct event_base *);
+
+/**
+ Gets all event notification mechanisms supported by Libevent.
+
+ This functions returns the event mechanism in order preferred by
+ Libevent. Note that this list will include all backends that
+ Libevent has compiled-in support for, and will not necessarily check
+ your OS to see whether it has the required resources.
+
+ @return an array with pointers to the names of support methods.
+ The end of the array is indicated by a NULL pointer. If an
+ error is encountered NULL is returned.
+*/
+EVENT2_EXPORT_SYMBOL
+const char **event_get_supported_methods(void);
+
+/** Query the current monotonic time from a the timer for a struct
+ * event_base.
+ */
+EVENT2_EXPORT_SYMBOL
+int event_gettime_monotonic(struct event_base *base, struct timeval *tp);
+
+/**
+ @name event type flag
+
+ Flags to pass to event_base_get_num_events() to specify the kinds of events
+ we want to aggregate counts for
+*/
+/**@{*/
+/** count the number of active events, which have been triggered.*/
+#define EVENT_BASE_COUNT_ACTIVE 1U
+/** count the number of virtual events, which is used to represent an internal
+ * condition, other than a pending event, that keeps the loop from exiting. */
+#define EVENT_BASE_COUNT_VIRTUAL 2U
+/** count the number of events which have been added to event base, including
+ * internal events. */
+#define EVENT_BASE_COUNT_ADDED 4U
+/**@}*/
+
+/**
+ Gets the number of events in event_base, as specified in the flags.
+
+ Since event base has some internal events added to make some of its
+ functionalities work, EVENT_BASE_COUNT_ADDED may return more than the
+ number of events you added using event_add().
+
+ If you pass EVENT_BASE_COUNT_ACTIVE and EVENT_BASE_COUNT_ADDED together, an
+ active event will be counted twice. However, this might not be the case in
+ future libevent versions. The return value is an indication of the work
+ load, but the user shouldn't rely on the exact value as this may change in
+ the future.
+
+ @param eb the event_base structure returned by event_base_new()
+ @param flags a bitwise combination of the kinds of events to aggregate
+ counts for
+ @return the number of events specified in the flags
+*/
+EVENT2_EXPORT_SYMBOL
+int event_base_get_num_events(struct event_base *, unsigned int);
+
+/**
+ Get the maximum number of events in a given event_base as specified in the
+ flags.
+
+ @param eb the event_base structure returned by event_base_new()
+ @param flags a bitwise combination of the kinds of events to aggregate
+ counts for
+ @param clear option used to reset the maximum count.
+ @return the number of events specified in the flags
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_get_max_events(struct event_base *, unsigned int, int);
+
+/**
+ Allocates a new event configuration object.
+
+ The event configuration object can be used to change the behavior of
+ an event base.
+
+ @return an event_config object that can be used to store configuration, or
+ NULL if an error is encountered.
+ @see event_base_new_with_config(), event_config_free(), event_config
+*/
+EVENT2_EXPORT_SYMBOL
+struct event_config *event_config_new(void);
+
+/**
+ Deallocates all memory associated with an event configuration object
+
+ @param cfg the event configuration object to be freed.
+*/
+EVENT2_EXPORT_SYMBOL
+void event_config_free(struct event_config *cfg);
+
+/**
+ Enters an event method that should be avoided into the configuration.
+
+ This can be used to avoid event mechanisms that do not support certain
+ file descriptor types, or for debugging to avoid certain event
+ mechanisms. An application can make use of multiple event bases to
+ accommodate incompatible file descriptor types.
+
+ @param cfg the event configuration object
+ @param method the name of the event method to avoid
+ @return 0 on success, -1 on failure.
+*/
+EVENT2_EXPORT_SYMBOL
+int event_config_avoid_method(struct event_config *cfg, const char *method);
+
+/**
+ A flag used to describe which features an event_base (must) provide.
+
+ Because of OS limitations, not every Libevent backend supports every
+ possible feature. You can use this type with
+ event_config_require_features() to tell Libevent to only proceed if your
+ event_base implements a given feature, and you can receive this type from
+ event_base_get_features() to see which features are available.
+*/
+enum event_method_feature {
+ /** Require an event method that allows edge-triggered events with EV_ET. */
+ EV_FEATURE_ET = 0x01,
+ /** Require an event method where having one event triggered among
+ * many is [approximately] an O(1) operation. This excludes (for
+ * example) select and poll, which are approximately O(N) for N
+ * equal to the total number of possible events. */
+ EV_FEATURE_O1 = 0x02,
+ /** Require an event method that allows file descriptors as well as
+ * sockets. */
+ EV_FEATURE_FDS = 0x04,
+ /** Require an event method that allows you to use EV_CLOSED to detect
+ * connection close without the necessity of reading all the pending data.
+ *
+ * Methods that do support EV_CLOSED may not be able to provide support on
+ * all kernel versions.
+ **/
+ EV_FEATURE_EARLY_CLOSE = 0x08
+};
+
+/**
+ A flag passed to event_config_set_flag().
+
+ These flags change the behavior of an allocated event_base.
+
+ @see event_config_set_flag(), event_base_new_with_config(),
+ event_method_feature
+ */
+enum event_base_config_flag {
+ /** Do not allocate a lock for the event base, even if we have
+ locking set up.
+
+ Setting this option will make it unsafe and nonfunctional to call
+ functions on the base concurrently from multiple threads.
+ */
+ EVENT_BASE_FLAG_NOLOCK = 0x01,
+ /** Do not check the EVENT_* environment variables when configuring
+ an event_base */
+ EVENT_BASE_FLAG_IGNORE_ENV = 0x02,
+ /** Windows only: enable the IOCP dispatcher at startup
+
+ If this flag is set then bufferevent_socket_new() and
+ evconn_listener_new() will use IOCP-backed implementations
+ instead of the usual select-based one on Windows.
+ */
+ EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,
+ /** Instead of checking the current time every time the event loop is
+ ready to run timeout callbacks, check after each timeout callback.
+ */
+ EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,
+
+ /** If we are using the epoll backend, this flag says that it is
+ safe to use Libevent's internal change-list code to batch up
+ adds and deletes in order to try to do as few syscalls as
+ possible. Setting this flag can make your code run faster, but
+ it may trigger a Linux bug: it is not safe to use this flag
+ if you have any fds cloned by dup() or its variants. Doing so
+ will produce strange and hard-to-diagnose bugs.
+
+ This flag can also be activated by setting the
+ EVENT_EPOLL_USE_CHANGELIST environment variable.
+
+ This flag has no effect if you wind up using a backend other than
+ epoll.
+ */
+ EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,
+
+ /** Ordinarily, Libevent implements its time and timeout code using
+ the fastest monotonic timer that we have. If this flag is set,
+ however, we use less efficient more precise timer, assuming one is
+ present.
+ */
+ EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
+};
+
+/**
+ Return a bitmask of the features implemented by an event base. This
+ will be a bitwise OR of one or more of the values of
+ event_method_feature
+
+ @see event_method_feature
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_get_features(const struct event_base *base);
+
+/**
+ Enters a required event method feature that the application demands.
+
+ Note that not every feature or combination of features is supported
+ on every platform. Code that requests features should be prepared
+ to handle the case where event_base_new_with_config() returns NULL, as in:
+ <pre>
+ event_config_require_features(cfg, EV_FEATURE_ET);
+ base = event_base_new_with_config(cfg);
+ if (base == NULL) {
+ // We can't get edge-triggered behavior here.
+ event_config_require_features(cfg, 0);
+ base = event_base_new_with_config(cfg);
+ }
+ </pre>
+
+ @param cfg the event configuration object
+ @param feature a bitfield of one or more event_method_feature values.
+ Replaces values from previous calls to this function.
+ @return 0 on success, -1 on failure.
+ @see event_method_feature, event_base_new_with_config()
+*/
+EVENT2_EXPORT_SYMBOL
+int event_config_require_features(struct event_config *cfg, int feature);
+
+/**
+ * Sets one or more flags to configure what parts of the eventual event_base
+ * will be initialized, and how they'll work.
+ *
+ * @see event_base_config_flags, event_base_new_with_config()
+ **/
+EVENT2_EXPORT_SYMBOL
+int event_config_set_flag(struct event_config *cfg, int flag);
+
+/**
+ * Records a hint for the number of CPUs in the system. This is used for
+ * tuning thread pools, etc, for optimal performance. In Libevent 2.0,
+ * it is only on Windows, and only when IOCP is in use.
+ *
+ * @param cfg the event configuration object
+ * @param cpus the number of cpus
+ * @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus);
+
+/**
+ * Record an interval and/or a number of callbacks after which the event base
+ * should check for new events. By default, the event base will run as many
+ * events are as activated at the higest activated priority before checking
+ * for new events. If you configure it by setting max_interval, it will check
+ * the time after each callback, and not allow more than max_interval to
+ * elapse before checking for new events. If you configure it by setting
+ * max_callbacks to a value >= 0, it will run no more than max_callbacks
+ * callbacks before checking for new events.
+ *
+ * This option can decrease the latency of high-priority events, and
+ * avoid priority inversions where multiple low-priority events keep us from
+ * polling for high-priority events, but at the expense of slightly decreasing
+ * the throughput. Use it with caution!
+ *
+ * @param cfg The event_base configuration object.
+ * @param max_interval An interval after which Libevent should stop running
+ * callbacks and check for more events, or NULL if there should be
+ * no such interval.
+ * @param max_callbacks A number of callbacks after which Libevent should
+ * stop running callbacks and check for more events, or -1 if there
+ * should be no such limit.
+ * @param min_priority A priority below which max_interval and max_callbacks
+ * should not be enforced. If this is set to 0, they are enforced
+ * for events of every priority; if it's set to 1, they're enforced
+ * for events of priority 1 and above, and so on.
+ * @return 0 on success, -1 on failure.
+ **/
+EVENT2_EXPORT_SYMBOL
+int event_config_set_max_dispatch_interval(struct event_config *cfg,
+ const struct timeval *max_interval, int max_callbacks,
+ int min_priority);
+
+/**
+ Initialize the event API.
+
+ Use event_base_new_with_config() to initialize a new event base, taking
+ the specified configuration under consideration. The configuration object
+ can currently be used to avoid certain event notification mechanisms.
+
+ @param cfg the event configuration object
+ @return an initialized event_base that can be used to registering events,
+ or NULL if no event base can be created with the requested event_config.
+ @see event_base_new(), event_base_free(), event_init(), event_assign()
+*/
+EVENT2_EXPORT_SYMBOL
+struct event_base *event_base_new_with_config(const struct event_config *);
+
+/**
+ Deallocate all memory associated with an event_base, and free the base.
+
+ Note that this function will not close any fds or free any memory passed
+ to event_new as the argument to callback.
+
+ If there are any pending finalizer callbacks, this function will invoke
+ them.
+
+ @param eb an event_base to be freed
+ */
+EVENT2_EXPORT_SYMBOL
+void event_base_free(struct event_base *);
+
+/**
+ As event_free, but do not run finalizers.
+
+ THIS IS AN EXPERIMENTAL API. IT MIGHT CHANGE BEFORE THE LIBEVENT 2.1 SERIES
+ BECOMES STABLE.
+ */
+EVENT2_EXPORT_SYMBOL
+void event_base_free_nofinalize(struct event_base *);
+
+/** @name Log severities
+ */
+/**@{*/
+#define EVENT_LOG_DEBUG 0
+#define EVENT_LOG_MSG 1
+#define EVENT_LOG_WARN 2
+#define EVENT_LOG_ERR 3
+/**@}*/
+
+/* Obsolete names: these are deprecated, but older programs might use them.
+ * They violate the reserved-identifier namespace. */
+#define _EVENT_LOG_DEBUG EVENT_LOG_DEBUG
+#define _EVENT_LOG_MSG EVENT_LOG_MSG
+#define _EVENT_LOG_WARN EVENT_LOG_WARN
+#define _EVENT_LOG_ERR EVENT_LOG_ERR
+
+/**
+ A callback function used to intercept Libevent's log messages.
+
+ @see event_set_log_callback
+ */
+typedef void (*event_log_cb)(int severity, const char *msg);
+/**
+ Redirect Libevent's log messages.
+
+ @param cb a function taking two arguments: an integer severity between
+ EVENT_LOG_DEBUG and EVENT_LOG_ERR, and a string. If cb is NULL,
+ then the default log is used.
+
+ NOTE: The function you provide *must not* call any other libevent
+ functionality. Doing so can produce undefined behavior.
+ */
+EVENT2_EXPORT_SYMBOL
+void event_set_log_callback(event_log_cb cb);
+
+/**
+ A function to be called if Libevent encounters a fatal internal error.
+
+ @see event_set_fatal_callback
+ */
+typedef void (*event_fatal_cb)(int err);
+
+/**
+ Override Libevent's behavior in the event of a fatal internal error.
+
+ By default, Libevent will call exit(1) if a programming error makes it
+ impossible to continue correct operation. This function allows you to supply
+ another callback instead. Note that if the function is ever invoked,
+ something is wrong with your program, or with Libevent: any subsequent calls
+ to Libevent may result in undefined behavior.
+
+ Libevent will (almost) always log an EVENT_LOG_ERR message before calling
+ this function; look at the last log message to see why Libevent has died.
+ */
+EVENT2_EXPORT_SYMBOL
+void event_set_fatal_callback(event_fatal_cb cb);
+
+#define EVENT_DBG_ALL 0xffffffffu
+#define EVENT_DBG_NONE 0
+
+/**
+ Turn on debugging logs and have them sent to the default log handler.
+
+ This is a global setting; if you are going to call it, you must call this
+ before any calls that create an event-base. You must call it before any
+ multithreaded use of Libevent.
+
+ Debug logs are verbose.
+
+ @param which Controls which debug messages are turned on. This option is
+ unused for now; for forward compatibility, you must pass in the constant
+ "EVENT_DBG_ALL" to turn debugging logs on, or "EVENT_DBG_NONE" to turn
+ debugging logs off.
+ */
+EVENT2_EXPORT_SYMBOL
+void event_enable_debug_logging(ev_uint32_t which);
+
+/**
+ Associate a different event base with an event.
+
+ The event to be associated must not be currently active or pending.
+
+ @param eb the event base
+ @param ev the event
+ @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_set(struct event_base *, struct event *);
+
+/** @name Loop flags
+
+ These flags control the behavior of event_base_loop().
+ */
+/**@{*/
+/** Block until we have an active event, then exit once all active events
+ * have had their callbacks run. */
+#define EVLOOP_ONCE 0x01
+/** Do not block: see which events are ready now, run the callbacks
+ * of the highest-priority ones, then exit. */
+#define EVLOOP_NONBLOCK 0x02
+/** Do not exit the loop because we have no pending events. Instead, keep
+ * running until event_base_loopexit() or event_base_loopbreak() makes us
+ * stop.
+ */
+#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
+/**@}*/
+
+/**
+ Wait for events to become active, and run their callbacks.
+
+ This is a more flexible version of event_base_dispatch().
+
+ By default, this loop will run the event base until either there are no more
+ pending or active events, or until something calls event_base_loopbreak() or
+ event_base_loopexit(). You can override this behavior with the 'flags'
+ argument.
+
+ @param eb the event_base structure returned by event_base_new() or
+ event_base_new_with_config()
+ @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
+ @return 0 if successful, -1 if an error occurred, or 1 if we exited because
+ no events were pending or active.
+ @see event_base_loopexit(), event_base_dispatch(), EVLOOP_ONCE,
+ EVLOOP_NONBLOCK
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_loop(struct event_base *, int);
+
+/**
+ Exit the event loop after the specified time
+
+ The next event_base_loop() iteration after the given timer expires will
+ complete normally (handling all queued events) then exit without
+ blocking for events again.
+
+ Subsequent invocations of event_base_loop() will proceed normally.
+
+ @param eb the event_base structure returned by event_init()
+ @param tv the amount of time after which the loop should terminate,
+ or NULL to exit after running all currently active events.
+ @return 0 if successful, or -1 if an error occurred
+ @see event_base_loopbreak()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_loopexit(struct event_base *, const struct timeval *);
+
+/**
+ Abort the active event_base_loop() immediately.
+
+ event_base_loop() will abort the loop after the next event is completed;
+ event_base_loopbreak() is typically invoked from this event's callback.
+ This behavior is analogous to the "break;" statement.
+
+ Subsequent invocations of event_base_loop() will proceed normally.
+
+ @param eb the event_base structure returned by event_init()
+ @return 0 if successful, or -1 if an error occurred
+ @see event_base_loopexit()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_loopbreak(struct event_base *);
+
+/**
+ Tell the active event_base_loop() to scan for new events immediately.
+
+ Calling this function makes the currently active event_base_loop()
+ start the loop over again (scanning for new events) after the current
+ event callback finishes. If the event loop is not running, this
+ function has no effect.
+
+ event_base_loopbreak() is typically invoked from this event's callback.
+ This behavior is analogous to the "continue;" statement.
+
+ Subsequent invocations of event loop will proceed normally.
+
+ @param eb the event_base structure returned by event_init()
+ @return 0 if successful, or -1 if an error occurred
+ @see event_base_loopbreak()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_loopcontinue(struct event_base *);
+
+/**
+ Checks if the event loop was told to exit by event_base_loopexit().
+
+ This function will return true for an event_base at every point after
+ event_loopexit() is called, until the event loop is next entered.
+
+ @param eb the event_base structure returned by event_init()
+ @return true if event_base_loopexit() was called on this event base,
+ or 0 otherwise
+ @see event_base_loopexit()
+ @see event_base_got_break()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_got_exit(struct event_base *);
+
+/**
+ Checks if the event loop was told to abort immediately by event_base_loopbreak().
+
+ This function will return true for an event_base at every point after
+ event_base_loopbreak() is called, until the event loop is next entered.
+
+ @param eb the event_base structure returned by event_init()
+ @return true if event_base_loopbreak() was called on this event base,
+ or 0 otherwise
+ @see event_base_loopbreak()
+ @see event_base_got_exit()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_got_break(struct event_base *);
+
+/**
+ * @name event flags
+ *
+ * Flags to pass to event_new(), event_assign(), event_pending(), and
+ * anything else with an argument of the form "short events"
+ */
+/**@{*/
+/** Indicates that a timeout has occurred. It's not necessary to pass
+ * this flag to event_for new()/event_assign() to get a timeout. */
+#define EV_TIMEOUT 0x01
+/** Wait for a socket or FD to become readable */
+#define EV_READ 0x02
+/** Wait for a socket or FD to become writeable */
+#define EV_WRITE 0x04
+/** Wait for a POSIX signal to be raised*/
+#define EV_SIGNAL 0x08
+/**
+ * Persistent event: won't get removed automatically when activated.
+ *
+ * When a persistent event with a timeout becomes activated, its timeout
+ * is reset to 0.
+ */
+#define EV_PERSIST 0x10
+/** Select edge-triggered behavior, if supported by the backend. */
+#define EV_ET 0x20
+/**
+ * If this option is provided, then event_del() will not block in one thread
+ * while waiting for the event callback to complete in another thread.
+ *
+ * To use this option safely, you may need to use event_finalize() or
+ * event_free_finalize() in order to safely tear down an event in a
+ * multithreaded application. See those functions for more information.
+ *
+ * THIS IS AN EXPERIMENTAL API. IT MIGHT CHANGE BEFORE THE LIBEVENT 2.1 SERIES
+ * BECOMES STABLE.
+ **/
+#define EV_FINALIZE 0x40
+/**
+ * Detects connection close events. You can use this to detect when a
+ * connection has been closed, without having to read all the pending data
+ * from a connection.
+ *
+ * Not all backends support EV_CLOSED. To detect or require it, use the
+ * feature flag EV_FEATURE_EARLY_CLOSE.
+ **/
+#define EV_CLOSED 0x80
+/**@}*/
+
+/**
+ @name evtimer_* macros
+
+ Aliases for working with one-shot timer events */
+/**@{*/
+#define evtimer_assign(ev, b, cb, arg) \
+ event_assign((ev), (b), -1, 0, (cb), (arg))
+#define evtimer_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg))
+#define evtimer_add(ev, tv) event_add((ev), (tv))
+#define evtimer_del(ev) event_del(ev)
+#define evtimer_pending(ev, tv) event_pending((ev), EV_TIMEOUT, (tv))
+#define evtimer_initialized(ev) event_initialized(ev)
+/**@}*/
+
+/**
+ @name evsignal_* macros
+
+ Aliases for working with signal events
+ */
+/**@{*/
+#define evsignal_add(ev, tv) event_add((ev), (tv))
+#define evsignal_assign(ev, b, x, cb, arg) \
+ event_assign((ev), (b), (x), EV_SIGNAL|EV_PERSIST, cb, (arg))
+#define evsignal_new(b, x, cb, arg) \
+ event_new((b), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg))
+#define evsignal_del(ev) event_del(ev)
+#define evsignal_pending(ev, tv) event_pending((ev), EV_SIGNAL, (tv))
+#define evsignal_initialized(ev) event_initialized(ev)
+/**@}*/
+
+/**
+ A callback function for an event.
+
+ It receives three arguments:
+
+ @param fd An fd or signal
+ @param events One or more EV_* flags
+ @param arg A user-supplied argument.
+
+ @see event_new()
+ */
+typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
+
+/**
+ Return a value used to specify that the event itself must be used as the callback argument.
+
+ The function event_new() takes a callback argument which is passed
+ to the event's callback function. To specify that the argument to be
+ passed to the callback function is the event that event_new() returns,
+ pass in the return value of event_self_cbarg() as the callback argument
+ for event_new().
+
+ For example:
+ <pre>
+ struct event *ev = event_new(base, sock, events, callback, %event_self_cbarg());
+ </pre>
+
+ For consistency with event_new(), it is possible to pass the return value
+ of this function as the callback argument for event_assign() &ndash; this
+ achieves the same result as passing the event in directly.
+
+ @return a value to be passed as the callback argument to event_new() or
+ event_assign().
+ @see event_new(), event_assign()
+ */
+EVENT2_EXPORT_SYMBOL
+void *event_self_cbarg(void);
+
+/**
+ Allocate and asssign a new event structure, ready to be added.
+
+ The function event_new() returns a new event that can be used in
+ future calls to event_add() and event_del(). The fd and events
+ arguments determine which conditions will trigger the event; the
+ callback and callback_arg arguments tell Libevent what to do when the
+ event becomes active.
+
+ If events contains one of EV_READ, EV_WRITE, or EV_READ|EV_WRITE, then
+ fd is a file descriptor or socket that should get monitored for
+ readiness to read, readiness to write, or readiness for either operation
+ (respectively). If events contains EV_SIGNAL, then fd is a signal
+ number to wait for. If events contains none of those flags, then the
+ event can be triggered only by a timeout or by manual activation with
+ event_active(): In this case, fd must be -1.
+
+ The EV_PERSIST flag can also be passed in the events argument: it makes
+ event_add() persistent until event_del() is called.
+
+ The EV_ET flag is compatible with EV_READ and EV_WRITE, and supported
+ only by certain backends. It tells Libevent to use edge-triggered
+ events.
+
+ The EV_TIMEOUT flag has no effect here.
+
+ It is okay to have multiple events all listening on the same fds; but
+ they must either all be edge-triggered, or all not be edge triggerd.
+
+ When the event becomes active, the event loop will run the provided
+ callbuck function, with three arguments. The first will be the provided
+ fd value. The second will be a bitfield of the events that triggered:
+ EV_READ, EV_WRITE, or EV_SIGNAL. Here the EV_TIMEOUT flag indicates
+ that a timeout occurred, and EV_ET indicates that an edge-triggered
+ event occurred. The third event will be the callback_arg pointer that
+ you provide.
+
+ @param base the event base to which the event should be attached.
+ @param fd the file descriptor or signal to be monitored, or -1.
+ @param events desired events to monitor: bitfield of EV_READ, EV_WRITE,
+ EV_SIGNAL, EV_PERSIST, EV_ET.
+ @param callback callback function to be invoked when the event occurs
+ @param callback_arg an argument to be passed to the callback function
+
+ @return a newly allocated struct event that must later be freed with
+ event_free().
+ @see event_free(), event_add(), event_del(), event_assign()
+ */
+EVENT2_EXPORT_SYMBOL
+struct event *event_new(struct event_base *, evutil_socket_t, short, event_callback_fn, void *);
+
+
+/**
+ Prepare a new, already-allocated event structure to be added.
+
+ The function event_assign() prepares the event structure ev to be used
+ in future calls to event_add() and event_del(). Unlike event_new(), it
+ doesn't allocate memory itself: it requires that you have already
+ allocated a struct event, probably on the heap. Doing this will
+ typically make your code depend on the size of the event structure, and
+ thereby create incompatibility with future versions of Libevent.
+
+ The easiest way to avoid this problem is just to use event_new() and
+ event_free() instead.
+
+ A slightly harder way to future-proof your code is to use
+ event_get_struct_event_size() to determine the required size of an event
+ at runtime.
+
+ Note that it is NOT safe to call this function on an event that is
+ active or pending. Doing so WILL corrupt internal data structures in
+ Libevent, and lead to strange, hard-to-diagnose bugs. You _can_ use
+ event_assign to change an existing event, but only if it is not active
+ or pending!
+
+ The arguments for this function, and the behavior of the events that it
+ makes, are as for event_new().
+
+ @param ev an event struct to be modified
+ @param base the event base to which ev should be attached.
+ @param fd the file descriptor to be monitored
+ @param events desired events to monitor; can be EV_READ and/or EV_WRITE
+ @param callback callback function to be invoked when the event occurs
+ @param callback_arg an argument to be passed to the callback function
+
+ @return 0 if success, or -1 on invalid arguments.
+
+ @see event_new(), event_add(), event_del(), event_base_once(),
+ event_get_struct_event_size()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_assign(struct event *, struct event_base *, evutil_socket_t, short, event_callback_fn, void *);
+
+/**
+ Deallocate a struct event * returned by event_new().
+
+ If the event is pending or active, first make it non-pending and
+ non-active.
+ */
+EVENT2_EXPORT_SYMBOL
+void event_free(struct event *);
+
+/**
+ * Callback type for event_finalize and event_free_finalize().
+ *
+ * THIS IS AN EXPERIMENTAL API. IT MIGHT CHANGE BEFORE THE LIBEVENT 2.1 SERIES
+ * BECOMES STABLE.
+ *
+ **/
+typedef void (*event_finalize_callback_fn)(struct event *, void *);
+/**
+ @name Finalization functions
+
+ These functions are used to safely tear down an event in a multithreaded
+ application. If you construct your events with EV_FINALIZE to avoid
+ deadlocks, you will need a way to remove an event in the certainty that
+ it will definitely not be running its callback when you deallocate it
+ and its callback argument.
+
+ To do this, call one of event_finalize() or event_free_finalize with
+ 0 for its first argument, the event to tear down as its second argument,
+ and a callback function as its third argument. The callback will be
+ invoked as part of the event loop, with the event's priority.
+
+ After you call a finalizer function, event_add() and event_active() will
+ no longer work on the event, and event_del() will produce a no-op. You
+ must not try to change the event's fields with event_assign() or
+ event_set() while the finalize callback is in progress. Once the
+ callback has been invoked, you should treat the event structure as
+ containing uninitialized memory.
+
+ The event_free_finalize() function frees the event after it's finalized;
+ event_finalize() does not.
+
+ A finalizer callback must not make events pending or active. It must not
+ add events, activate events, or attempt to "resucitate" the event being
+ finalized in any way.
+
+ THIS IS AN EXPERIMENTAL API. IT MIGHT CHANGE BEFORE THE LIBEVENT 2.1 SERIES
+ BECOMES STABLE.
+
+ @return 0 on succes, -1 on failure.
+ */
+/**@{*/
+EVENT2_EXPORT_SYMBOL
+int event_finalize(unsigned, struct event *, event_finalize_callback_fn);
+EVENT2_EXPORT_SYMBOL
+int event_free_finalize(unsigned, struct event *, event_finalize_callback_fn);
+/**@}*/
+
+/**
+ Schedule a one-time event
+
+ The function event_base_once() is similar to event_new(). However, it
+ schedules a callback to be called exactly once, and does not require the
+ caller to prepare an event structure.
+
+ Note that in Libevent 2.0 and earlier, if the event is never triggered, the
+ internal memory used to hold it will never be freed. In Libevent 2.1,
+ the internal memory will get freed by event_base_free() if the event
+ is never triggered. The 'arg' value, however, will not get freed in either
+ case--you'll need to free that on your own if you want it to go away.
+
+ @param base an event_base
+ @param fd a file descriptor to monitor, or -1 for no fd.
+ @param events event(s) to monitor; can be any of EV_READ |
+ EV_WRITE, or EV_TIMEOUT
+ @param callback callback function to be invoked when the event occurs
+ @param arg an argument to be passed to the callback function
+ @param timeout the maximum amount of time to wait for the event. NULL
+ makes an EV_READ/EV_WRITE event make forever; NULL makes an
+ EV_TIMEOUT event succees immediately.
+ @return 0 if successful, or -1 if an error occurred
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_once(struct event_base *, evutil_socket_t, short, event_callback_fn, void *, const struct timeval *);
+
+/**
+ Add an event to the set of pending events.
+
+ The function event_add() schedules the execution of the event 'ev' when the
+ condition specified by event_assign() or event_new() occurs, or when the time
+ specified in timeout has elapesed. If atimeout is NULL, no timeout
+ occurs and the function will only be
+ called if a matching event occurs. The event in the
+ ev argument must be already initialized by event_assign() or event_new()
+ and may not be used
+ in calls to event_assign() until it is no longer pending.
+
+ If the event in the ev argument already has a scheduled timeout, calling
+ event_add() replaces the old timeout with the new one if tv is non-NULL.
+
+ @param ev an event struct initialized via event_assign() or event_new()
+ @param timeout the maximum amount of time to wait for the event, or NULL
+ to wait forever
+ @return 0 if successful, or -1 if an error occurred
+ @see event_del(), event_assign(), event_new()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_add(struct event *ev, const struct timeval *timeout);
+
+/**
+ Remove a timer from a pending event without removing the event itself.
+
+ If the event has a scheduled timeout, this function unschedules it but
+ leaves the event otherwise pending.
+
+ @param ev an event struct initialized via event_assign() or event_new()
+ @return 0 on success, or -1 if an error occurrect.
+*/
+EVENT2_EXPORT_SYMBOL
+int event_remove_timer(struct event *ev);
+
+/**
+ Remove an event from the set of monitored events.
+
+ The function event_del() will cancel the event in the argument ev. If the
+ event has already executed or has never been added the call will have no
+ effect.
+
+ @param ev an event struct to be removed from the working set
+ @return 0 if successful, or -1 if an error occurred
+ @see event_add()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_del(struct event *);
+
+/**
+ As event_del(), but never blocks while the event's callback is running
+ in another thread, even if the event was constructed without the
+ EV_FINALIZE flag.
+
+ THIS IS AN EXPERIMENTAL API. IT MIGHT CHANGE BEFORE THE LIBEVENT 2.1 SERIES
+ BECOMES STABLE.
+ */
+EVENT2_EXPORT_SYMBOL
+int event_del_noblock(struct event *ev);
+/**
+ As event_del(), but always blocks while the event's callback is running
+ in another thread, even if the event was constructed with the
+ EV_FINALIZE flag.
+
+ THIS IS AN EXPERIMENTAL API. IT MIGHT CHANGE BEFORE THE LIBEVENT 2.1 SERIES
+ BECOMES STABLE.
+ */
+EVENT2_EXPORT_SYMBOL
+int event_del_block(struct event *ev);
+
+/**
+ Make an event active.
+
+ You can use this function on a pending or a non-pending event to make it
+ active, so that its callback will be run by event_base_dispatch() or
+ event_base_loop().
+
+ One common use in multithreaded programs is to wake the thread running
+ event_base_loop() from another thread.
+
+ @param ev an event to make active.
+ @param res a set of flags to pass to the event's callback.
+ @param ncalls an obsolete argument: this is ignored.
+ **/
+EVENT2_EXPORT_SYMBOL
+void event_active(struct event *ev, int res, short ncalls);
+
+/**
+ Checks if a specific event is pending or scheduled.
+
+ @param ev an event struct previously passed to event_add()
+ @param events the requested event type; any of EV_TIMEOUT|EV_READ|
+ EV_WRITE|EV_SIGNAL
+ @param tv if this field is not NULL, and the event has a timeout,
+ this field is set to hold the time at which the timeout will
+ expire.
+
+ @return true if the event is pending on any of the events in 'what', (that
+ is to say, it has been added), or 0 if the event is not added.
+ */
+EVENT2_EXPORT_SYMBOL
+int event_pending(const struct event *ev, short events, struct timeval *tv);
+
+/**
+ If called from within the callback for an event, returns that event.
+
+ The behavior of this function is not defined when called from outside the
+ callback function for an event.
+ */
+EVENT2_EXPORT_SYMBOL
+struct event *event_base_get_running_event(struct event_base *base);
+
+/**
+ Test if an event structure might be initialized.
+
+ The event_initialized() function can be used to check if an event has been
+ initialized.
+
+ Warning: This function is only useful for distinguishing a a zeroed-out
+ piece of memory from an initialized event, it can easily be confused by
+ uninitialized memory. Thus, it should ONLY be used to distinguish an
+ initialized event from zero.
+
+ @param ev an event structure to be tested
+ @return 1 if the structure might be initialized, or 0 if it has not been
+ initialized
+ */
+EVENT2_EXPORT_SYMBOL
+int event_initialized(const struct event *ev);
+
+/**
+ Get the signal number assigned to a signal event
+*/
+#define event_get_signal(ev) ((int)event_get_fd(ev))
+
+/**
+ Get the socket or signal assigned to an event, or -1 if the event has
+ no socket.
+*/
+EVENT2_EXPORT_SYMBOL
+evutil_socket_t event_get_fd(const struct event *ev);
+
+/**
+ Get the event_base associated with an event.
+*/
+EVENT2_EXPORT_SYMBOL
+struct event_base *event_get_base(const struct event *ev);
+
+/**
+ Return the events (EV_READ, EV_WRITE, etc) assigned to an event.
+*/
+EVENT2_EXPORT_SYMBOL
+short event_get_events(const struct event *ev);
+
+/**
+ Return the callback assigned to an event.
+*/
+EVENT2_EXPORT_SYMBOL
+event_callback_fn event_get_callback(const struct event *ev);
+
+/**
+ Return the callback argument assigned to an event.
+*/
+EVENT2_EXPORT_SYMBOL
+void *event_get_callback_arg(const struct event *ev);
+
+/**
+ Return the priority of an event.
+ @see event_priority_init(), event_get_priority()
+*/
+EVENT2_EXPORT_SYMBOL
+int event_get_priority(const struct event *ev);
+
+/**
+ Extract _all_ of arguments given to construct a given event. The
+ event_base is copied into *base_out, the fd is copied into *fd_out, and so
+ on.
+
+ If any of the "_out" arguments is NULL, it will be ignored.
+ */
+EVENT2_EXPORT_SYMBOL
+void event_get_assignment(const struct event *event,
+ struct event_base **base_out, evutil_socket_t *fd_out, short *events_out,
+ event_callback_fn *callback_out, void **arg_out);
+
+/**
+ Return the size of struct event that the Libevent library was compiled
+ with.
+
+ This will be NO GREATER than sizeof(struct event) if you're running with
+ the same version of Libevent that your application was built with, but
+ otherwise might not.
+
+ Note that it might be SMALLER than sizeof(struct event) if some future
+ version of Libevent adds extra padding to the end of struct event.
+ We might do this to help ensure ABI-compatibility between different
+ versions of Libevent.
+ */
+EVENT2_EXPORT_SYMBOL
+size_t event_get_struct_event_size(void);
+
+/**
+ Get the Libevent version.
+
+ Note that this will give you the version of the library that you're
+ currently linked against, not the version of the headers that you've
+ compiled against.
+
+ @return a string containing the version number of Libevent
+*/
+EVENT2_EXPORT_SYMBOL
+const char *event_get_version(void);
+
+/**
+ Return a numeric representation of Libevent's version.
+
+ Note that this will give you the version of the library that you're
+ currently linked against, not the version of the headers you've used to
+ compile.
+
+ The format uses one byte each for the major, minor, and patchlevel parts of
+ the version number. The low-order byte is unused. For example, version
+ 2.0.1-alpha has a numeric representation of 0x02000100
+*/
+EVENT2_EXPORT_SYMBOL
+ev_uint32_t event_get_version_number(void);
+
+/** As event_get_version, but gives the version of Libevent's headers. */
+#define LIBEVENT_VERSION EVENT__VERSION
+/** As event_get_version_number, but gives the version number of Libevent's
+ * headers. */
+#define LIBEVENT_VERSION_NUMBER EVENT__NUMERIC_VERSION
+
+/** Largest number of priorities that Libevent can support. */
+#define EVENT_MAX_PRIORITIES 256
+/**
+ Set the number of different event priorities
+
+ By default Libevent schedules all active events with the same priority.
+ However, some time it is desirable to process some events with a higher
+ priority than others. For that reason, Libevent supports strict priority
+ queues. Active events with a lower priority are always processed before
+ events with a higher priority.
+
+ The number of different priorities can be set initially with the
+ event_base_priority_init() function. This function should be called
+ before the first call to event_base_dispatch(). The
+ event_priority_set() function can be used to assign a priority to an
+ event. By default, Libevent assigns the middle priority to all events
+ unless their priority is explicitly set.
+
+ Note that urgent-priority events can starve less-urgent events: after
+ running all urgent-priority callbacks, Libevent checks for more urgent
+ events again, before running less-urgent events. Less-urgent events
+ will not have their callbacks run until there are no events more urgent
+ than them that want to be active.
+
+ @param eb the event_base structure returned by event_base_new()
+ @param npriorities the maximum number of priorities
+ @return 0 if successful, or -1 if an error occurred
+ @see event_priority_set()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_priority_init(struct event_base *, int);
+
+/**
+ Get the number of different event priorities.
+
+ @param eb the event_base structure returned by event_base_new()
+ @return Number of different event priorities
+ @see event_base_priority_init()
+*/
+EVENT2_EXPORT_SYMBOL
+int event_base_get_npriorities(struct event_base *eb);
+
+/**
+ Assign a priority to an event.
+
+ @param ev an event struct
+ @param priority the new priority to be assigned
+ @return 0 if successful, or -1 if an error occurred
+ @see event_priority_init(), event_get_priority()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_priority_set(struct event *, int);
+
+/**
+ Prepare an event_base to use a large number of timeouts with the same
+ duration.
+
+ Libevent's default scheduling algorithm is optimized for having a large
+ number of timeouts with their durations more or less randomly
+ distributed. But if you have a large number of timeouts that all have
+ the same duration (for example, if you have a large number of
+ connections that all have a 10-second timeout), then you can improve
+ Libevent's performance by telling Libevent about it.
+
+ To do this, call this function with the common duration. It will return a
+ pointer to a different, opaque timeout value. (Don't depend on its actual
+ contents!) When you use this timeout value in event_add(), Libevent will
+ schedule the event more efficiently.
+
+ (This optimization probably will not be worthwhile until you have thousands
+ or tens of thousands of events with the same timeout.)
+ */
+EVENT2_EXPORT_SYMBOL
+const struct timeval *event_base_init_common_timeout(struct event_base *base,
+ const struct timeval *duration);
+
+#if !defined(EVENT__DISABLE_MM_REPLACEMENT) || defined(EVENT_IN_DOXYGEN_)
+/**
+ Override the functions that Libevent uses for memory management.
+
+ Usually, Libevent uses the standard libc functions malloc, realloc, and
+ free to allocate memory. Passing replacements for those functions to
+ event_set_mem_functions() overrides this behavior.
+
+ Note that all memory returned from Libevent will be allocated by the
+ replacement functions rather than by malloc() and realloc(). Thus, if you
+ have replaced those functions, it will not be appropriate to free() memory
+ that you get from Libevent. Instead, you must use the free_fn replacement
+ that you provided.
+
+ Note also that if you are going to call this function, you should do so
+ before any call to any Libevent function that does allocation.
+ Otherwise, those funtions will allocate their memory using malloc(), but
+ then later free it using your provided free_fn.
+
+ @param malloc_fn A replacement for malloc.
+ @param realloc_fn A replacement for realloc
+ @param free_fn A replacement for free.
+ **/
+EVENT2_EXPORT_SYMBOL
+void event_set_mem_functions(
+ void *(*malloc_fn)(size_t sz),
+ void *(*realloc_fn)(void *ptr, size_t sz),
+ void (*free_fn)(void *ptr));
+/** This definition is present if Libevent was built with support for
+ event_set_mem_functions() */
+#define EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
+#endif
+
+/**
+ Writes a human-readable description of all inserted and/or active
+ events to a provided stdio stream.
+
+ This is intended for debugging; its format is not guaranteed to be the same
+ between libevent versions.
+
+ @param base An event_base on which to scan the events.
+ @param output A stdio file to write on.
+ */
+EVENT2_EXPORT_SYMBOL
+void event_base_dump_events(struct event_base *, FILE *);
+
+
+/**
+ Activates all pending events for the given fd and event mask.
+
+ This function activates pending events only. Events which have not been
+ added will not become active.
+
+ @param base the event_base on which to activate the events.
+ @param fd An fd to active events on.
+ @param events One or more of EV_{READ,WRITE}.
+ */
+EVENT2_EXPORT_SYMBOL
+void event_base_active_by_fd(struct event_base *base, evutil_socket_t fd, short events);
+
+/**
+ Activates all pending signals with a given signal number
+
+ This function activates pending events only. Events which have not been
+ added will not become active.
+
+ @param base the event_base on which to activate the events.
+ @param fd The signal to active events on.
+ */
+EVENT2_EXPORT_SYMBOL
+void event_base_active_by_signal(struct event_base *base, int sig);
+
+/**
+ * Callback for iterating events in an event base via event_base_foreach_event
+ */
+typedef int (*event_base_foreach_event_cb)(const struct event_base *, const struct event *, void *);
+
+/**
+ Iterate over all added or active events events in an event loop, and invoke
+ a given callback on each one.
+
+ The callback must not call any function that modifies the event base, that
+ modifies any event in the event base, or that adds or removes any event to
+ the event base. Doing so is unsupported and will lead to undefined
+ behavior -- likely, to crashes.
+
+ event_base_foreach_event() holds a lock on the event_base() for the whole
+ time it's running: slow callbacks are not advisable.
+
+ Note that Libevent adds some events of its own to make pieces of its
+ functionality work. You must not assume that the only events you'll
+ encounter will be the ones you added yourself.
+
+ The callback function must return 0 to continue iteration, or some other
+ integer to stop iterating.
+
+ @param base An event_base on which to scan the events.
+ @param fn A callback function to receive the events.
+ @param arg An argument passed to the callback function.
+ @return 0 if we iterated over every event, or the value returned by the
+ callback function if the loop exited early.
+*/
+EVENT2_EXPORT_SYMBOL
+int event_base_foreach_event(struct event_base *base, event_base_foreach_event_cb fn, void *arg);
+
+
+/** Sets 'tv' to the current time (as returned by gettimeofday()),
+ looking at the cached value in 'base' if possible, and calling
+ gettimeofday() or clock_gettime() as appropriate if there is no
+ cached time.
+
+ Generally, this value will only be cached while actually
+ processing event callbacks, and may be very inaccuate if your
+ callbacks take a long time to execute.
+
+ Returns 0 on success, negative on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_gettimeofday_cached(struct event_base *base,
+ struct timeval *tv);
+
+/** Update cached_tv in the 'base' to the current time
+ *
+ * You can use this function is useful for selectively increasing
+ * the accuracy of the cached time value in 'base' during callbacks
+ * that take a long time to execute.
+ *
+ * This function has no effect if the base is currently not in its
+ * event loop, or if timeval caching is disabled via
+ * EVENT_BASE_FLAG_NO_CACHE_TIME.
+ *
+ * @return 0 on success, -1 on failure
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_update_cache_time(struct event_base *base);
+
+/** Release up all globally-allocated resources allocated by Libevent.
+
+ This function does not free developer-controlled resources like
+ event_bases, events, bufferevents, listeners, and so on. It only releases
+ resources like global locks that there is no other way to free.
+
+ It is not actually necessary to call this function before exit: every
+ resource that it frees would be released anyway on exit. It mainly exists
+ so that resource-leak debugging tools don't see Libevent as holding
+ resources at exit.
+
+ You should only call this function when no other Libevent functions will
+ be invoked -- e.g., when cleanly exiting a program.
+ */
+EVENT2_EXPORT_SYMBOL
+void libevent_global_shutdown(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_EVENT_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/event_compat.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/event_compat.h
new file mode 100644
index 000000000..5110175a1
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/event_compat.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_EVENT_COMPAT_H_INCLUDED_
+#define EVENT2_EVENT_COMPAT_H_INCLUDED_
+
+/** @file event2/event_compat.h
+
+ Potentially non-threadsafe versions of the functions in event.h: provided
+ only for backwards compatibility.
+
+ In the oldest versions of Libevent, event_base was not a first-class
+ structure. Instead, there was a single event base that every function
+ manipulated. Later, when separate event bases were added, the old functions
+ that didn't take an event_base argument needed to work by manipulating the
+ "current" event base. This could lead to thread-safety issues, and obscure,
+ hard-to-diagnose bugs.
+
+ @deprecated All functions in this file are by definition deprecated.
+ */
+#include <event2/visibility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/* For int types. */
+#include <event2/util.h>
+
+/**
+ Initialize the event API.
+
+ The event API needs to be initialized with event_init() before it can be
+ used. Sets the global current base that gets used for events that have no
+ base associated with them.
+
+ @deprecated This function is deprecated because it replaces the "current"
+ event_base, and is totally unsafe for multithreaded use. The replacement
+ is event_base_new().
+
+ @see event_base_set(), event_base_new()
+ */
+EVENT2_EXPORT_SYMBOL
+struct event_base *event_init(void);
+
+/**
+ Loop to process events.
+
+ Like event_base_dispatch(), but uses the "current" base.
+
+ @deprecated This function is deprecated because it is easily confused by
+ multiple calls to event_init(), and because it is not safe for
+ multithreaded use. The replacement is event_base_dispatch().
+
+ @see event_base_dispatch(), event_init()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_dispatch(void);
+
+/**
+ Handle events.
+
+ This function behaves like event_base_loop(), but uses the "current" base
+
+ @deprecated This function is deprecated because it uses the event base from
+ the last call to event_init, and is therefore not safe for multithreaded
+ use. The replacement is event_base_loop().
+
+ @see event_base_loop(), event_init()
+*/
+EVENT2_EXPORT_SYMBOL
+int event_loop(int);
+
+
+/**
+ Exit the event loop after the specified time.
+
+ This function behaves like event_base_loopexit(), except that it uses the
+ "current" base.
+
+ @deprecated This function is deprecated because it uses the event base from
+ the last call to event_init, and is therefore not safe for multithreaded
+ use. The replacement is event_base_loopexit().
+
+ @see event_init, event_base_loopexit()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_loopexit(const struct timeval *);
+
+
+/**
+ Abort the active event_loop() immediately.
+
+ This function behaves like event_base_loopbreakt(), except that it uses the
+ "current" base.
+
+ @deprecated This function is deprecated because it uses the event base from
+ the last call to event_init, and is therefore not safe for multithreaded
+ use. The replacement is event_base_loopbreak().
+
+ @see event_base_loopbreak(), event_init()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_loopbreak(void);
+
+/**
+ Schedule a one-time event to occur.
+
+ @deprecated This function is obsolete, and has been replaced by
+ event_base_once(). Its use is deprecated because it relies on the
+ "current" base configured by event_init().
+
+ @see event_base_once()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_once(evutil_socket_t , short,
+ void (*)(evutil_socket_t, short, void *), void *, const struct timeval *);
+
+
+/**
+ Get the kernel event notification mechanism used by Libevent.
+
+ @deprecated This function is obsolete, and has been replaced by
+ event_base_get_method(). Its use is deprecated because it relies on the
+ "current" base configured by event_init().
+
+ @see event_base_get_method()
+ */
+EVENT2_EXPORT_SYMBOL
+const char *event_get_method(void);
+
+
+/**
+ Set the number of different event priorities.
+
+ @deprecated This function is deprecated because it is easily confused by
+ multiple calls to event_init(), and because it is not safe for
+ multithreaded use. The replacement is event_base_priority_init().
+
+ @see event_base_priority_init()
+ */
+EVENT2_EXPORT_SYMBOL
+int event_priority_init(int);
+
+/**
+ Prepare an event structure to be added.
+
+ @deprecated event_set() is not recommended for new code, because it requires
+ a subsequent call to event_base_set() to be safe under most circumstances.
+ Use event_assign() or event_new() instead.
+ */
+EVENT2_EXPORT_SYMBOL
+void event_set(struct event *, evutil_socket_t, short, void (*)(evutil_socket_t, short, void *), void *);
+
+#define evtimer_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg))
+#define evsignal_set(ev, x, cb, arg) \
+ event_set((ev), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg))
+
+
+/**
+ @name timeout_* macros
+
+ @deprecated These macros are deprecated because their naming is inconsistent
+ with the rest of Libevent. Use the evtimer_* macros instead.
+ @{
+ */
+#define timeout_add(ev, tv) event_add((ev), (tv))
+#define timeout_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg))
+#define timeout_del(ev) event_del(ev)
+#define timeout_pending(ev, tv) event_pending((ev), EV_TIMEOUT, (tv))
+#define timeout_initialized(ev) event_initialized(ev)
+/**@}*/
+
+/**
+ @name signal_* macros
+
+ @deprecated These macros are deprecated because their naming is inconsistent
+ with the rest of Libevent. Use the evsignal_* macros instead.
+ @{
+ */
+#define signal_add(ev, tv) event_add((ev), (tv))
+#define signal_set(ev, x, cb, arg) \
+ event_set((ev), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg))
+#define signal_del(ev) event_del(ev)
+#define signal_pending(ev, tv) event_pending((ev), EV_SIGNAL, (tv))
+#define signal_initialized(ev) event_initialized(ev)
+/**@}*/
+
+#ifndef EVENT_FD
+/* These macros are obsolete; use event_get_fd and event_get_signal instead. */
+#define EVENT_FD(ev) ((int)event_get_fd(ev))
+#define EVENT_SIGNAL(ev) event_get_signal(ev)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/event_struct.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/event_struct.h
new file mode 100644
index 000000000..1c8b71b6b
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/event_struct.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_EVENT_STRUCT_H_INCLUDED_
+#define EVENT2_EVENT_STRUCT_H_INCLUDED_
+
+/** @file event2/event_struct.h
+
+ Structures used by event.h. Using these structures directly WILL harm
+ forward compatibility: be careful.
+
+ No field declared in this file should be used directly in user code. Except
+ for historical reasons, these fields would not be exposed at all.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/* For int types. */
+#include <event2/util.h>
+
+/* For evkeyvalq */
+#include <event2/keyvalq_struct.h>
+
+#define EVLIST_TIMEOUT 0x01
+#define EVLIST_INSERTED 0x02
+#define EVLIST_SIGNAL 0x04
+#define EVLIST_ACTIVE 0x08
+#define EVLIST_INTERNAL 0x10
+#define EVLIST_ACTIVE_LATER 0x20
+#define EVLIST_FINALIZING 0x40
+#define EVLIST_INIT 0x80
+
+#define EVLIST_ALL 0xff
+
+/* Fix so that people don't have to run with <sys/queue.h> */
+#ifndef TAILQ_ENTRY
+#define EVENT_DEFINED_TQENTRY_
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+#endif /* !TAILQ_ENTRY */
+
+#ifndef TAILQ_HEAD
+#define EVENT_DEFINED_TQHEAD_
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; \
+ struct type **tqh_last; \
+}
+#endif
+
+/* Fix so that people don't have to run with <sys/queue.h> */
+#ifndef LIST_ENTRY
+#define EVENT_DEFINED_LISTENTRY_
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+#endif /* !LIST_ENTRY */
+
+#ifndef LIST_HEAD
+#define EVENT_DEFINED_LISTHEAD_
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+ }
+#endif /* !LIST_HEAD */
+
+struct event;
+
+struct event_callback {
+ TAILQ_ENTRY(event_callback) evcb_active_next;
+ short evcb_flags;
+ ev_uint8_t evcb_pri; /* smaller numbers are higher priority */
+ ev_uint8_t evcb_closure;
+ /* allows us to adopt for different types of events */
+ union {
+ void (*evcb_callback)(evutil_socket_t, short, void *);
+ void (*evcb_selfcb)(struct event_callback *, void *);
+ void (*evcb_evfinalize)(struct event *, void *);
+ void (*evcb_cbfinalize)(struct event_callback *, void *);
+ } evcb_cb_union;
+ void *evcb_arg;
+};
+
+struct event_base;
+struct event {
+ struct event_callback ev_evcallback;
+
+ /* for managing timeouts */
+ union {
+ TAILQ_ENTRY(event) ev_next_with_common_timeout;
+ int min_heap_idx;
+ } ev_timeout_pos;
+ evutil_socket_t ev_fd;
+
+ struct event_base *ev_base;
+
+ union {
+ /* used for io events */
+ struct {
+ LIST_ENTRY (event) ev_io_next;
+ struct timeval ev_timeout;
+ } ev_io;
+
+ /* used by signal events */
+ struct {
+ LIST_ENTRY (event) ev_signal_next;
+ short ev_ncalls;
+ /* Allows deletes in callback */
+ short *ev_pncalls;
+ } ev_signal;
+ } ev_;
+
+ short ev_events;
+ short ev_res; /* result passed to event callback */
+ struct timeval ev_timeout;
+};
+
+TAILQ_HEAD (event_list, event);
+
+#ifdef EVENT_DEFINED_TQENTRY_
+#undef TAILQ_ENTRY
+#endif
+
+#ifdef EVENT_DEFINED_TQHEAD_
+#undef TAILQ_HEAD
+#endif
+
+LIST_HEAD (event_dlist, event);
+
+#ifdef EVENT_DEFINED_LISTENTRY_
+#undef LIST_ENTRY
+#endif
+
+#ifdef EVENT_DEFINED_LISTHEAD_
+#undef LIST_HEAD
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_EVENT_STRUCT_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/http.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/http.h
new file mode 100644
index 000000000..8fb5642f7
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/http.h
@@ -0,0 +1,1189 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_HTTP_H_INCLUDED_
+#define EVENT2_HTTP_H_INCLUDED_
+
+/* For int types. */
+#include <event2/util.h>
+#include <event2/visibility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* In case we haven't included the right headers yet. */
+struct evbuffer;
+struct event_base;
+struct bufferevent;
+struct evhttp_connection;
+
+/** @file event2/http.h
+ *
+ * Basic support for HTTP serving.
+ *
+ * As Libevent is a library for dealing with event notification and most
+ * interesting applications are networked today, I have often found the
+ * need to write HTTP code. The following prototypes and definitions provide
+ * an application with a minimal interface for making HTTP requests and for
+ * creating a very simple HTTP server.
+ */
+
+/* Response codes */
+#define HTTP_OK 200 /**< request completed ok */
+#define HTTP_NOCONTENT 204 /**< request does not have content */
+#define HTTP_MOVEPERM 301 /**< the uri moved permanently */
+#define HTTP_MOVETEMP 302 /**< the uri moved temporarily */
+#define HTTP_NOTMODIFIED 304 /**< page was not modified from last */
+#define HTTP_BADREQUEST 400 /**< invalid http request was made */
+#define HTTP_NOTFOUND 404 /**< could not find content for uri */
+#define HTTP_BADMETHOD 405 /**< method not allowed for this uri */
+#define HTTP_ENTITYTOOLARGE 413 /**< */
+#define HTTP_EXPECTATIONFAILED 417 /**< we can't handle this expectation */
+#define HTTP_INTERNAL 500 /**< internal error */
+#define HTTP_NOTIMPLEMENTED 501 /**< not implemented */
+#define HTTP_SERVUNAVAIL 503 /**< the server is not available */
+
+struct evhttp;
+struct evhttp_request;
+struct evkeyvalq;
+struct evhttp_bound_socket;
+struct evconnlistener;
+struct evdns_base;
+
+/**
+ * Create a new HTTP server.
+ *
+ * @param base (optional) the event base to receive the HTTP events
+ * @return a pointer to a newly initialized evhttp server structure
+ * @see evhttp_free()
+ */
+EVENT2_EXPORT_SYMBOL
+struct evhttp *evhttp_new(struct event_base *base);
+
+/**
+ * Binds an HTTP server on the specified address and port.
+ *
+ * Can be called multiple times to bind the same http server
+ * to multiple different ports.
+ *
+ * @param http a pointer to an evhttp object
+ * @param address a string containing the IP address to listen(2) on
+ * @param port the port number to listen on
+ * @return 0 on success, -1 on failure.
+ * @see evhttp_accept_socket()
+ */
+EVENT2_EXPORT_SYMBOL
+int evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port);
+
+/**
+ * Like evhttp_bind_socket(), but returns a handle for referencing the socket.
+ *
+ * The returned pointer is not valid after \a http is freed.
+ *
+ * @param http a pointer to an evhttp object
+ * @param address a string containing the IP address to listen(2) on
+ * @param port the port number to listen on
+ * @return Handle for the socket on success, NULL on failure.
+ * @see evhttp_bind_socket(), evhttp_del_accept_socket()
+ */
+EVENT2_EXPORT_SYMBOL
+struct evhttp_bound_socket *evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port);
+
+/**
+ * Makes an HTTP server accept connections on the specified socket.
+ *
+ * This may be useful to create a socket and then fork multiple instances
+ * of an http server, or when a socket has been communicated via file
+ * descriptor passing in situations where an http servers does not have
+ * permissions to bind to a low-numbered port.
+ *
+ * Can be called multiple times to have the http server listen to
+ * multiple different sockets.
+ *
+ * @param http a pointer to an evhttp object
+ * @param fd a socket fd that is ready for accepting connections
+ * @return 0 on success, -1 on failure.
+ * @see evhttp_bind_socket()
+ */
+EVENT2_EXPORT_SYMBOL
+int evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd);
+
+/**
+ * Like evhttp_accept_socket(), but returns a handle for referencing the socket.
+ *
+ * The returned pointer is not valid after \a http is freed.
+ *
+ * @param http a pointer to an evhttp object
+ * @param fd a socket fd that is ready for accepting connections
+ * @return Handle for the socket on success, NULL on failure.
+ * @see evhttp_accept_socket(), evhttp_del_accept_socket()
+ */
+EVENT2_EXPORT_SYMBOL
+struct evhttp_bound_socket *evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd);
+
+/**
+ * The most low-level evhttp_bind/accept method: takes an evconnlistener, and
+ * returns an evhttp_bound_socket. The listener will be freed when the bound
+ * socket is freed.
+ */
+EVENT2_EXPORT_SYMBOL
+struct evhttp_bound_socket *evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener);
+
+/**
+ * Return the listener used to implement a bound socket.
+ */
+EVENT2_EXPORT_SYMBOL
+struct evconnlistener *evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound);
+
+typedef void evhttp_bound_socket_foreach_fn(struct evhttp_bound_socket *, void *);
+/**
+ * Applies the function specified in the first argument to all
+ * evhttp_bound_sockets associated with "http". The user must not
+ * attempt to free or remove any connections, sockets or listeners
+ * in the callback "function".
+ *
+ * @param http pointer to an evhttp object
+ * @param function function to apply to every bound socket
+ * @param argument pointer value passed to function for every socket iterated
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_foreach_bound_socket(struct evhttp *http, evhttp_bound_socket_foreach_fn *function, void *argument);
+
+/**
+ * Makes an HTTP server stop accepting connections on the specified socket
+ *
+ * This may be useful when a socket has been sent via file descriptor passing
+ * and is no longer needed by the current process.
+ *
+ * If you created this bound socket with evhttp_bind_socket_with_handle or
+ * evhttp_accept_socket_with_handle, this function closes the fd you provided.
+ * If you created this bound socket with evhttp_bind_listener, this function
+ * frees the listener you provided.
+ *
+ * \a bound_socket is an invalid pointer after this call returns.
+ *
+ * @param http a pointer to an evhttp object
+ * @param bound_socket a handle returned by evhttp_{bind,accept}_socket_with_handle
+ * @see evhttp_bind_socket_with_handle(), evhttp_accept_socket_with_handle()
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound_socket);
+
+/**
+ * Get the raw file descriptor referenced by an evhttp_bound_socket.
+ *
+ * @param bound_socket a handle returned by evhttp_{bind,accept}_socket_with_handle
+ * @return the file descriptor used by the bound socket
+ * @see evhttp_bind_socket_with_handle(), evhttp_accept_socket_with_handle()
+ */
+EVENT2_EXPORT_SYMBOL
+evutil_socket_t evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound_socket);
+
+/**
+ * Free the previously created HTTP server.
+ *
+ * Works only if no requests are currently being served.
+ *
+ * @param http the evhttp server object to be freed
+ * @see evhttp_start()
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_free(struct evhttp* http);
+
+/** XXX Document. */
+EVENT2_EXPORT_SYMBOL
+void evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size);
+/** XXX Document. */
+EVENT2_EXPORT_SYMBOL
+void evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size);
+
+/**
+ Set the value to use for the Content-Type header when none was provided. If
+ the content type string is NULL, the Content-Type header will not be
+ automatically added.
+
+ @param http the http server on which to set the default content type
+ @param content_type the value for the Content-Type header
+*/
+EVENT2_EXPORT_SYMBOL
+void evhttp_set_default_content_type(struct evhttp *http,
+ const char *content_type);
+
+/**
+ Sets the what HTTP methods are supported in requests accepted by this
+ server, and passed to user callbacks.
+
+ If not supported they will generate a "405 Method not allowed" response.
+
+ By default this includes the following methods: GET, POST, HEAD, PUT, DELETE
+
+ @param http the http server on which to set the methods
+ @param methods bit mask constructed from evhttp_cmd_type values
+*/
+EVENT2_EXPORT_SYMBOL
+void evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods);
+
+/**
+ Set a callback for a specified URI
+
+ @param http the http sever on which to set the callback
+ @param path the path for which to invoke the callback
+ @param cb the callback function that gets invoked on requesting path
+ @param cb_arg an additional context argument for the callback
+ @return 0 on success, -1 if the callback existed already, -2 on failure
+*/
+EVENT2_EXPORT_SYMBOL
+int evhttp_set_cb(struct evhttp *http, const char *path,
+ void (*cb)(struct evhttp_request *, void *), void *cb_arg);
+
+/** Removes the callback for a specified URI */
+EVENT2_EXPORT_SYMBOL
+int evhttp_del_cb(struct evhttp *, const char *);
+
+/**
+ Set a callback for all requests that are not caught by specific callbacks
+
+ Invokes the specified callback for all requests that do not match any of
+ the previously specified request paths. This is catchall for requests not
+ specifically configured with evhttp_set_cb().
+
+ @param http the evhttp server object for which to set the callback
+ @param cb the callback to invoke for any unmatched requests
+ @param arg an context argument for the callback
+*/
+EVENT2_EXPORT_SYMBOL
+void evhttp_set_gencb(struct evhttp *http,
+ void (*cb)(struct evhttp_request *, void *), void *arg);
+
+/**
+ Set a callback used to create new bufferevents for connections
+ to a given evhttp object.
+
+ You can use this to override the default bufferevent type -- for example,
+ to make this evhttp object use SSL bufferevents rather than unencrypted
+ ones.
+
+ New bufferevents must be allocated with no fd set on them.
+
+ @param http the evhttp server object for which to set the callback
+ @param cb the callback to invoke for incoming connections
+ @param arg an context argument for the callback
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_set_bevcb(struct evhttp *http,
+ struct bufferevent *(*cb)(struct event_base *, void *), void *arg);
+
+/**
+ Adds a virtual host to the http server.
+
+ A virtual host is a newly initialized evhttp object that has request
+ callbacks set on it via evhttp_set_cb() or evhttp_set_gencb(). It
+ most not have any listing sockets associated with it.
+
+ If the virtual host has not been removed by the time that evhttp_free()
+ is called on the main http server, it will be automatically freed, too.
+
+ It is possible to have hierarchical vhosts. For example: A vhost
+ with the pattern *.example.com may have other vhosts with patterns
+ foo.example.com and bar.example.com associated with it.
+
+ @param http the evhttp object to which to add a virtual host
+ @param pattern the glob pattern against which the hostname is matched.
+ The match is case insensitive and follows otherwise regular shell
+ matching.
+ @param vhost the virtual host to add the regular http server.
+ @return 0 on success, -1 on failure
+ @see evhttp_remove_virtual_host()
+*/
+EVENT2_EXPORT_SYMBOL
+int evhttp_add_virtual_host(struct evhttp* http, const char *pattern,
+ struct evhttp* vhost);
+
+/**
+ Removes a virtual host from the http server.
+
+ @param http the evhttp object from which to remove the virtual host
+ @param vhost the virtual host to remove from the regular http server.
+ @return 0 on success, -1 on failure
+ @see evhttp_add_virtual_host()
+*/
+EVENT2_EXPORT_SYMBOL
+int evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost);
+
+/**
+ Add a server alias to an http object. The http object can be a virtual
+ host or the main server.
+
+ @param http the evhttp object
+ @param alias the alias to add
+ @see evhttp_add_remove_alias()
+*/
+EVENT2_EXPORT_SYMBOL
+int evhttp_add_server_alias(struct evhttp *http, const char *alias);
+
+/**
+ Remove a server alias from an http object.
+
+ @param http the evhttp object
+ @param alias the alias to remove
+ @see evhttp_add_server_alias()
+*/
+EVENT2_EXPORT_SYMBOL
+int evhttp_remove_server_alias(struct evhttp *http, const char *alias);
+
+/**
+ * Set the timeout for an HTTP request.
+ *
+ * @param http an evhttp object
+ * @param timeout_in_secs the timeout, in seconds
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_set_timeout(struct evhttp *http, int timeout_in_secs);
+
+/**
+ * Set the timeout for an HTTP request.
+ *
+ * @param http an evhttp object
+ * @param tv the timeout, or NULL
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_set_timeout_tv(struct evhttp *http, const struct timeval* tv);
+
+/* Read all the clients body, and only after this respond with an error if the
+ * clients body exceed max_body_size */
+#define EVHTTP_SERVER_LINGERING_CLOSE 0x0001
+/**
+ * Set connection flags for HTTP server.
+ *
+ * @see EVHTTP_SERVER_*
+ * @return 0 on success, otherwise non zero (for example if flag doesn't
+ * supported).
+ */
+EVENT2_EXPORT_SYMBOL
+int evhttp_set_flags(struct evhttp *http, int flags);
+
+/* Request/Response functionality */
+
+/**
+ * Send an HTML error message to the client.
+ *
+ * @param req a request object
+ * @param error the HTTP error code
+ * @param reason a brief explanation of the error. If this is NULL, we'll
+ * just use the standard meaning of the error code.
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_send_error(struct evhttp_request *req, int error,
+ const char *reason);
+
+/**
+ * Send an HTML reply to the client.
+ *
+ * The body of the reply consists of the data in databuf. After calling
+ * evhttp_send_reply() databuf will be empty, but the buffer is still
+ * owned by the caller and needs to be deallocated by the caller if
+ * necessary.
+ *
+ * @param req a request object
+ * @param code the HTTP response code to send
+ * @param reason a brief message to send with the response code
+ * @param databuf the body of the response
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_send_reply(struct evhttp_request *req, int code,
+ const char *reason, struct evbuffer *databuf);
+
+/* Low-level response interface, for streaming/chunked replies */
+
+/**
+ Initiate a reply that uses Transfer-Encoding chunked.
+
+ This allows the caller to stream the reply back to the client and is
+ useful when either not all of the reply data is immediately available
+ or when sending very large replies.
+
+ The caller needs to supply data chunks with evhttp_send_reply_chunk()
+ and complete the reply by calling evhttp_send_reply_end().
+
+ @param req a request object
+ @param code the HTTP response code to send
+ @param reason a brief message to send with the response code
+*/
+EVENT2_EXPORT_SYMBOL
+void evhttp_send_reply_start(struct evhttp_request *req, int code,
+ const char *reason);
+
+/**
+ Send another data chunk as part of an ongoing chunked reply.
+
+ The reply chunk consists of the data in databuf. After calling
+ evhttp_send_reply_chunk() databuf will be empty, but the buffer is
+ still owned by the caller and needs to be deallocated by the caller
+ if necessary.
+
+ @param req a request object
+ @param databuf the data chunk to send as part of the reply.
+*/
+EVENT2_EXPORT_SYMBOL
+void evhttp_send_reply_chunk(struct evhttp_request *req,
+ struct evbuffer *databuf);
+
+/**
+ Send another data chunk as part of an ongoing chunked reply.
+
+ The reply chunk consists of the data in databuf. After calling
+ evhttp_send_reply_chunk() databuf will be empty, but the buffer is
+ still owned by the caller and needs to be deallocated by the caller
+ if necessary.
+
+ @param req a request object
+ @param databuf the data chunk to send as part of the reply.
+ @param cb callback funcion
+ @param call back's argument.
+*/
+EVENT2_EXPORT_SYMBOL
+void evhttp_send_reply_chunk_with_cb(struct evhttp_request *, struct evbuffer *,
+ void (*cb)(struct evhttp_connection *, void *), void *arg);
+
+/**
+ Complete a chunked reply, freeing the request as appropriate.
+
+ @param req a request object
+*/
+EVENT2_EXPORT_SYMBOL
+void evhttp_send_reply_end(struct evhttp_request *req);
+
+/*
+ * Interfaces for making requests
+ */
+
+/** The different request types supported by evhttp. These are as specified
+ * in RFC2616, except for PATCH which is specified by RFC5789.
+ *
+ * By default, only some of these methods are accepted and passed to user
+ * callbacks; use evhttp_set_allowed_methods() to change which methods
+ * are allowed.
+ */
+enum evhttp_cmd_type {
+ EVHTTP_REQ_GET = 1 << 0,
+ EVHTTP_REQ_POST = 1 << 1,
+ EVHTTP_REQ_HEAD = 1 << 2,
+ EVHTTP_REQ_PUT = 1 << 3,
+ EVHTTP_REQ_DELETE = 1 << 4,
+ EVHTTP_REQ_OPTIONS = 1 << 5,
+ EVHTTP_REQ_TRACE = 1 << 6,
+ EVHTTP_REQ_CONNECT = 1 << 7,
+ EVHTTP_REQ_PATCH = 1 << 8
+};
+
+/** a request object can represent either a request or a reply */
+enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE };
+
+/**
+ * Create and return a connection object that can be used to for making HTTP
+ * requests. The connection object tries to resolve address and establish the
+ * connection when it is given an http request object.
+ *
+ * @param base the event_base to use for handling the connection
+ * @param dnsbase the dns_base to use for resolving host names; if not
+ * specified host name resolution will block.
+ * @param bev a bufferevent to use for connecting to the server; if NULL, a
+ * socket-based bufferevent will be created. This buffrevent will be freed
+ * when the connection closes. It must have no fd set on it.
+ * @param address the address to which to connect
+ * @param port the port to connect to
+ * @return an evhttp_connection object that can be used for making requests
+ */
+EVENT2_EXPORT_SYMBOL
+struct evhttp_connection *evhttp_connection_base_bufferevent_new(
+ struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev, const char *address, ev_uint16_t port);
+
+/**
+ * Return the bufferevent that an evhttp_connection is using.
+ */
+EVENT2_EXPORT_SYMBOL
+struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon);
+
+/**
+ * Return the HTTP server associated with this connection, or NULL.
+ */
+EVENT2_EXPORT_SYMBOL
+struct evhttp *evhttp_connection_get_server(struct evhttp_connection *evcon);
+
+/**
+ * Creates a new request object that needs to be filled in with the request
+ * parameters. The callback is executed when the request completed or an
+ * error occurred.
+ */
+EVENT2_EXPORT_SYMBOL
+struct evhttp_request *evhttp_request_new(
+ void (*cb)(struct evhttp_request *, void *), void *arg);
+
+/**
+ * Enable delivery of chunks to requestor.
+ * @param cb will be called after every read of data with the same argument
+ * as the completion callback. Will never be called on an empty
+ * response. May drain the input buffer; it will be drained
+ * automatically on return.
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_request_set_chunked_cb(struct evhttp_request *,
+ void (*cb)(struct evhttp_request *, void *));
+
+/**
+ * Register callback for additional parsing of request headers.
+ * @param cb will be called after receiving and parsing the full header.
+ * It allows analyzing the header and possibly closing the connection
+ * by returning a value < 0.
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_request_set_header_cb(struct evhttp_request *,
+ int (*cb)(struct evhttp_request *, void *));
+
+/**
+ * The different error types supported by evhttp
+ *
+ * @see evhttp_request_set_error_cb()
+ */
+enum evhttp_request_error {
+ /**
+ * Timeout reached, also @see evhttp_connection_set_timeout()
+ */
+ EVREQ_HTTP_TIMEOUT,
+ /**
+ * EOF reached
+ */
+ EVREQ_HTTP_EOF,
+ /**
+ * Error while reading header, or invalid header
+ */
+ EVREQ_HTTP_INVALID_HEADER,
+ /**
+ * Error encountered while reading or writing
+ */
+ EVREQ_HTTP_BUFFER_ERROR,
+ /**
+ * The evhttp_cancel_request() called on this request.
+ */
+ EVREQ_HTTP_REQUEST_CANCEL,
+ /**
+ * Body is greater then evhttp_connection_set_max_body_size()
+ */
+ EVREQ_HTTP_DATA_TOO_LONG
+};
+/**
+ * Set a callback for errors
+ * @see evhttp_request_error for error types.
+ *
+ * On error, both the error callback and the regular callback will be called,
+ * error callback is called before the regular callback.
+ **/
+EVENT2_EXPORT_SYMBOL
+void evhttp_request_set_error_cb(struct evhttp_request *,
+ void (*)(enum evhttp_request_error, void *));
+
+/**
+ * Set a callback to be called on request completion of evhttp_send_* function.
+ *
+ * The callback function will be called on the completion of the request after
+ * the output data has been written and before the evhttp_request object
+ * is destroyed. This can be useful for tracking resources associated with a
+ * request (ex: timing metrics).
+ *
+ * @param req a request object
+ * @param cb callback function that will be called on request completion
+ * @param cb_arg an additional context argument for the callback
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_request_set_on_complete_cb(struct evhttp_request *req,
+ void (*cb)(struct evhttp_request *, void *), void *cb_arg);
+
+/** Frees the request object and removes associated events. */
+EVENT2_EXPORT_SYMBOL
+void evhttp_request_free(struct evhttp_request *req);
+
+/**
+ * Create and return a connection object that can be used to for making HTTP
+ * requests. The connection object tries to resolve address and establish the
+ * connection when it is given an http request object.
+ *
+ * @param base the event_base to use for handling the connection
+ * @param dnsbase the dns_base to use for resolving host names; if not
+ * specified host name resolution will block.
+ * @param address the address to which to connect
+ * @param port the port to connect to
+ * @return an evhttp_connection object that can be used for making requests
+ */
+EVENT2_EXPORT_SYMBOL
+struct evhttp_connection *evhttp_connection_base_new(
+ struct event_base *base, struct evdns_base *dnsbase,
+ const char *address, ev_uint16_t port);
+
+/**
+ * Set family hint for DNS requests.
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_connection_set_family(struct evhttp_connection *evcon,
+ int family);
+
+/* reuse connection address on retry */
+#define EVHTTP_CON_REUSE_CONNECTED_ADDR 0x0008
+/* Try to read error, since server may already send and close
+ * connection, but if at that time we have some data to send then we
+ * can send get EPIPE and fail, while we can read that HTTP error. */
+#define EVHTTP_CON_READ_ON_WRITE_ERROR 0x0010
+/* @see EVHTTP_SERVER_LINGERING_CLOSE */
+#define EVHTTP_CON_LINGERING_CLOSE 0x0020
+/* Padding for public flags, @see EVHTTP_CON_* in http-internal.h */
+#define EVHTTP_CON_PUBLIC_FLAGS_END 0x100000
+/**
+ * Set connection flags.
+ *
+ * @see EVHTTP_CON_*
+ * @return 0 on success, otherwise non zero (for example if flag doesn't
+ * supported).
+ */
+EVENT2_EXPORT_SYMBOL
+int evhttp_connection_set_flags(struct evhttp_connection *evcon,
+ int flags);
+
+/** Takes ownership of the request object
+ *
+ * Can be used in a request callback to keep onto the request until
+ * evhttp_request_free() is explicitly called by the user.
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_request_own(struct evhttp_request *req);
+
+/** Returns 1 if the request is owned by the user */
+EVENT2_EXPORT_SYMBOL
+int evhttp_request_is_owned(struct evhttp_request *req);
+
+/**
+ * Returns the connection object associated with the request or NULL
+ *
+ * The user needs to either free the request explicitly or call
+ * evhttp_send_reply_end().
+ */
+EVENT2_EXPORT_SYMBOL
+struct evhttp_connection *evhttp_request_get_connection(struct evhttp_request *req);
+
+/**
+ * Returns the underlying event_base for this connection
+ */
+EVENT2_EXPORT_SYMBOL
+struct event_base *evhttp_connection_get_base(struct evhttp_connection *req);
+
+EVENT2_EXPORT_SYMBOL
+void evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon,
+ ev_ssize_t new_max_headers_size);
+
+EVENT2_EXPORT_SYMBOL
+void evhttp_connection_set_max_body_size(struct evhttp_connection* evcon,
+ ev_ssize_t new_max_body_size);
+
+/** Frees an http connection */
+EVENT2_EXPORT_SYMBOL
+void evhttp_connection_free(struct evhttp_connection *evcon);
+
+/** Disowns a given connection object
+ *
+ * Can be used to tell libevent to free the connection object after
+ * the last request has completed or failed.
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_connection_free_on_completion(struct evhttp_connection *evcon);
+
+/** sets the ip address from which http connections are made */
+EVENT2_EXPORT_SYMBOL
+void evhttp_connection_set_local_address(struct evhttp_connection *evcon,
+ const char *address);
+
+/** sets the local port from which http connections are made */
+EVENT2_EXPORT_SYMBOL
+void evhttp_connection_set_local_port(struct evhttp_connection *evcon,
+ ev_uint16_t port);
+
+/** Sets the timeout in seconds for events related to this connection */
+EVENT2_EXPORT_SYMBOL
+void evhttp_connection_set_timeout(struct evhttp_connection *evcon,
+ int timeout_in_secs);
+
+/** Sets the timeout for events related to this connection. Takes a struct
+ * timeval. */
+EVENT2_EXPORT_SYMBOL
+void evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon,
+ const struct timeval *tv);
+
+/** Sets the delay before retrying requests on this connection. This is only
+ * used if evhttp_connection_set_retries is used to make the number of retries
+ * at least one. Each retry after the first is twice as long as the one before
+ * it. */
+EVENT2_EXPORT_SYMBOL
+void evhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon,
+ const struct timeval *tv);
+
+/** Sets the retry limit for this connection - -1 repeats indefinitely */
+EVENT2_EXPORT_SYMBOL
+void evhttp_connection_set_retries(struct evhttp_connection *evcon,
+ int retry_max);
+
+/** Set a callback for connection close. */
+EVENT2_EXPORT_SYMBOL
+void evhttp_connection_set_closecb(struct evhttp_connection *evcon,
+ void (*)(struct evhttp_connection *, void *), void *);
+
+/** Get the remote address and port associated with this connection. */
+EVENT2_EXPORT_SYMBOL
+void evhttp_connection_get_peer(struct evhttp_connection *evcon,
+ char **address, ev_uint16_t *port);
+
+/** Get the remote address associated with this connection.
+ * extracted from getpeername() OR from nameserver.
+ *
+ * @return NULL if getpeername() return non success,
+ * or connection is not connected,
+ * otherwise it return pointer to struct sockaddr_storage */
+EVENT2_EXPORT_SYMBOL
+const struct sockaddr*
+evhttp_connection_get_addr(struct evhttp_connection *evcon);
+
+/**
+ Make an HTTP request over the specified connection.
+
+ The connection gets ownership of the request. On failure, the
+ request object is no longer valid as it has been freed.
+
+ @param evcon the evhttp_connection object over which to send the request
+ @param req the previously created and configured request object
+ @param type the request type EVHTTP_REQ_GET, EVHTTP_REQ_POST, etc.
+ @param uri the URI associated with the request
+ @return 0 on success, -1 on failure
+ @see evhttp_cancel_request()
+*/
+EVENT2_EXPORT_SYMBOL
+int evhttp_make_request(struct evhttp_connection *evcon,
+ struct evhttp_request *req,
+ enum evhttp_cmd_type type, const char *uri);
+
+/**
+ Cancels a pending HTTP request.
+
+ Cancels an ongoing HTTP request. The callback associated with this request
+ is not executed and the request object is freed. If the request is
+ currently being processed, e.g. it is ongoing, the corresponding
+ evhttp_connection object is going to get reset.
+
+ A request cannot be canceled if its callback has executed already. A request
+ may be canceled reentrantly from its chunked callback.
+
+ @param req the evhttp_request to cancel; req becomes invalid after this call.
+*/
+EVENT2_EXPORT_SYMBOL
+void evhttp_cancel_request(struct evhttp_request *req);
+
+/**
+ * A structure to hold a parsed URI or Relative-Ref conforming to RFC3986.
+ */
+struct evhttp_uri;
+
+/** Returns the request URI */
+EVENT2_EXPORT_SYMBOL
+const char *evhttp_request_get_uri(const struct evhttp_request *req);
+/** Returns the request URI (parsed) */
+EVENT2_EXPORT_SYMBOL
+const struct evhttp_uri *evhttp_request_get_evhttp_uri(const struct evhttp_request *req);
+/** Returns the request command */
+EVENT2_EXPORT_SYMBOL
+enum evhttp_cmd_type evhttp_request_get_command(const struct evhttp_request *req);
+
+EVENT2_EXPORT_SYMBOL
+int evhttp_request_get_response_code(const struct evhttp_request *req);
+EVENT2_EXPORT_SYMBOL
+const char * evhttp_request_get_response_code_line(const struct evhttp_request *req);
+
+/** Returns the input headers */
+EVENT2_EXPORT_SYMBOL
+struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req);
+/** Returns the output headers */
+EVENT2_EXPORT_SYMBOL
+struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req);
+/** Returns the input buffer */
+EVENT2_EXPORT_SYMBOL
+struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req);
+/** Returns the output buffer */
+EVENT2_EXPORT_SYMBOL
+struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req);
+/** Returns the host associated with the request. If a client sends an absolute
+ URI, the host part of that is preferred. Otherwise, the input headers are
+ searched for a Host: header. NULL is returned if no absolute URI or Host:
+ header is provided. */
+EVENT2_EXPORT_SYMBOL
+const char *evhttp_request_get_host(struct evhttp_request *req);
+
+/* Interfaces for dealing with HTTP headers */
+
+/**
+ Finds the value belonging to a header.
+
+ @param headers the evkeyvalq object in which to find the header
+ @param key the name of the header to find
+ @returns a pointer to the value for the header or NULL if the header
+ could not be found.
+ @see evhttp_add_header(), evhttp_remove_header()
+*/
+EVENT2_EXPORT_SYMBOL
+const char *evhttp_find_header(const struct evkeyvalq *headers,
+ const char *key);
+
+/**
+ Removes a header from a list of existing headers.
+
+ @param headers the evkeyvalq object from which to remove a header
+ @param key the name of the header to remove
+ @returns 0 if the header was removed, -1 otherwise.
+ @see evhttp_find_header(), evhttp_add_header()
+*/
+EVENT2_EXPORT_SYMBOL
+int evhttp_remove_header(struct evkeyvalq *headers, const char *key);
+
+/**
+ Adds a header to a list of existing headers.
+
+ @param headers the evkeyvalq object to which to add a header
+ @param key the name of the header
+ @param value the value belonging to the header
+ @returns 0 on success, -1 otherwise.
+ @see evhttp_find_header(), evhttp_clear_headers()
+*/
+EVENT2_EXPORT_SYMBOL
+int evhttp_add_header(struct evkeyvalq *headers, const char *key, const char *value);
+
+/**
+ Removes all headers from the header list.
+
+ @param headers the evkeyvalq object from which to remove all headers
+*/
+EVENT2_EXPORT_SYMBOL
+void evhttp_clear_headers(struct evkeyvalq *headers);
+
+/* Miscellaneous utility functions */
+
+
+/**
+ Helper function to encode a string for inclusion in a URI. All
+ characters are replaced by their hex-escaped (%22) equivalents,
+ except for characters explicitly unreserved by RFC3986 -- that is,
+ ASCII alphanumeric characters, hyphen, dot, underscore, and tilde.
+
+ The returned string must be freed by the caller.
+
+ @param str an unencoded string
+ @return a newly allocated URI-encoded string or NULL on failure
+ */
+EVENT2_EXPORT_SYMBOL
+char *evhttp_encode_uri(const char *str);
+
+/**
+ As evhttp_encode_uri, but if 'size' is nonnegative, treat the string
+ as being 'size' bytes long. This allows you to encode strings that
+ may contain 0-valued bytes.
+
+ The returned string must be freed by the caller.
+
+ @param str an unencoded string
+ @param size the length of the string to encode, or -1 if the string
+ is NUL-terminated
+ @param space_to_plus if true, space characters in 'str' are encoded
+ as +, not %20.
+ @return a newly allocate URI-encoded string, or NULL on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+char *evhttp_uriencode(const char *str, ev_ssize_t size, int space_to_plus);
+
+/**
+ Helper function to sort of decode a URI-encoded string. Unlike
+ evhttp_get_decoded_uri, it decodes all plus characters that appear
+ _after_ the first question mark character, but no plusses that occur
+ before. This is not a good way to decode URIs in whole or in part.
+
+ The returned string must be freed by the caller
+
+ @deprecated This function is deprecated; you probably want to use
+ evhttp_get_decoded_uri instead.
+
+ @param uri an encoded URI
+ @return a newly allocated unencoded URI or NULL on failure
+ */
+EVENT2_EXPORT_SYMBOL
+char *evhttp_decode_uri(const char *uri);
+
+/**
+ Helper function to decode a URI-escaped string or HTTP parameter.
+
+ If 'decode_plus' is 1, then we decode the string as an HTTP parameter
+ value, and convert all plus ('+') characters to spaces. If
+ 'decode_plus' is 0, we leave all plus characters unchanged.
+
+ The returned string must be freed by the caller.
+
+ @param uri a URI-encode encoded URI
+ @param decode_plus determines whether we convert '+' to space.
+ @param size_out if size_out is not NULL, *size_out is set to the size of the
+ returned string
+ @return a newly allocated unencoded URI or NULL on failure
+ */
+EVENT2_EXPORT_SYMBOL
+char *evhttp_uridecode(const char *uri, int decode_plus,
+ size_t *size_out);
+
+/**
+ Helper function to parse out arguments in a query.
+
+ Parsing a URI like
+
+ http://foo.com/?q=test&s=some+thing
+
+ will result in two entries in the key value queue.
+
+ The first entry is: key="q", value="test"
+ The second entry is: key="s", value="some thing"
+
+ @deprecated This function is deprecated as of Libevent 2.0.9. Use
+ evhttp_uri_parse and evhttp_parse_query_str instead.
+
+ @param uri the request URI
+ @param headers the head of the evkeyval queue
+ @return 0 on success, -1 on failure
+ */
+EVENT2_EXPORT_SYMBOL
+int evhttp_parse_query(const char *uri, struct evkeyvalq *headers);
+
+/**
+ Helper function to parse out arguments from the query portion of an
+ HTTP URI.
+
+ Parsing a query string like
+
+ q=test&s=some+thing
+
+ will result in two entries in the key value queue.
+
+ The first entry is: key="q", value="test"
+ The second entry is: key="s", value="some thing"
+
+ @param query_parse the query portion of the URI
+ @param headers the head of the evkeyval queue
+ @return 0 on success, -1 on failure
+ */
+EVENT2_EXPORT_SYMBOL
+int evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers);
+
+/**
+ * Escape HTML character entities in a string.
+ *
+ * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
+ * &#039; and &amp; correspondingly.
+ *
+ * The returned string needs to be freed by the caller.
+ *
+ * @param html an unescaped HTML string
+ * @return an escaped HTML string or NULL on error
+ */
+EVENT2_EXPORT_SYMBOL
+char *evhttp_htmlescape(const char *html);
+
+/**
+ * Return a new empty evhttp_uri with no fields set.
+ */
+EVENT2_EXPORT_SYMBOL
+struct evhttp_uri *evhttp_uri_new(void);
+
+/**
+ * Changes the flags set on a given URI. See EVHTTP_URI_* for
+ * a list of flags.
+ **/
+EVENT2_EXPORT_SYMBOL
+void evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags);
+
+/** Return the scheme of an evhttp_uri, or NULL if there is no scheme has
+ * been set and the evhttp_uri contains a Relative-Ref. */
+EVENT2_EXPORT_SYMBOL
+const char *evhttp_uri_get_scheme(const struct evhttp_uri *uri);
+/**
+ * Return the userinfo part of an evhttp_uri, or NULL if it has no userinfo
+ * set.
+ */
+EVENT2_EXPORT_SYMBOL
+const char *evhttp_uri_get_userinfo(const struct evhttp_uri *uri);
+/**
+ * Return the host part of an evhttp_uri, or NULL if it has no host set.
+ * The host may either be a regular hostname (conforming to the RFC 3986
+ * "regname" production), or an IPv4 address, or the empty string, or a
+ * bracketed IPv6 address, or a bracketed 'IP-Future' address.
+ *
+ * Note that having a NULL host means that the URI has no authority
+ * section, but having an empty-string host means that the URI has an
+ * authority section with no host part. For example,
+ * "mailto:user@example.com" has a host of NULL, but "file:///etc/motd"
+ * has a host of "".
+ */
+EVENT2_EXPORT_SYMBOL
+const char *evhttp_uri_get_host(const struct evhttp_uri *uri);
+/** Return the port part of an evhttp_uri, or -1 if there is no port set. */
+EVENT2_EXPORT_SYMBOL
+int evhttp_uri_get_port(const struct evhttp_uri *uri);
+/** Return the path part of an evhttp_uri, or NULL if it has no path set */
+EVENT2_EXPORT_SYMBOL
+const char *evhttp_uri_get_path(const struct evhttp_uri *uri);
+/** Return the query part of an evhttp_uri (excluding the leading "?"), or
+ * NULL if it has no query set */
+EVENT2_EXPORT_SYMBOL
+const char *evhttp_uri_get_query(const struct evhttp_uri *uri);
+/** Return the fragment part of an evhttp_uri (excluding the leading "#"),
+ * or NULL if it has no fragment set */
+EVENT2_EXPORT_SYMBOL
+const char *evhttp_uri_get_fragment(const struct evhttp_uri *uri);
+
+/** Set the scheme of an evhttp_uri, or clear the scheme if scheme==NULL.
+ * Returns 0 on success, -1 if scheme is not well-formed. */
+EVENT2_EXPORT_SYMBOL
+int evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme);
+/** Set the userinfo of an evhttp_uri, or clear the userinfo if userinfo==NULL.
+ * Returns 0 on success, -1 if userinfo is not well-formed. */
+EVENT2_EXPORT_SYMBOL
+int evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo);
+/** Set the host of an evhttp_uri, or clear the host if host==NULL.
+ * Returns 0 on success, -1 if host is not well-formed. */
+EVENT2_EXPORT_SYMBOL
+int evhttp_uri_set_host(struct evhttp_uri *uri, const char *host);
+/** Set the port of an evhttp_uri, or clear the port if port==-1.
+ * Returns 0 on success, -1 if port is not well-formed. */
+EVENT2_EXPORT_SYMBOL
+int evhttp_uri_set_port(struct evhttp_uri *uri, int port);
+/** Set the path of an evhttp_uri, or clear the path if path==NULL.
+ * Returns 0 on success, -1 if path is not well-formed. */
+EVENT2_EXPORT_SYMBOL
+int evhttp_uri_set_path(struct evhttp_uri *uri, const char *path);
+/** Set the query of an evhttp_uri, or clear the query if query==NULL.
+ * The query should not include a leading "?".
+ * Returns 0 on success, -1 if query is not well-formed. */
+EVENT2_EXPORT_SYMBOL
+int evhttp_uri_set_query(struct evhttp_uri *uri, const char *query);
+/** Set the fragment of an evhttp_uri, or clear the fragment if fragment==NULL.
+ * The fragment should not include a leading "#".
+ * Returns 0 on success, -1 if fragment is not well-formed. */
+EVENT2_EXPORT_SYMBOL
+int evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment);
+
+/**
+ * Helper function to parse a URI-Reference as specified by RFC3986.
+ *
+ * This function matches the URI-Reference production from RFC3986,
+ * which includes both URIs like
+ *
+ * scheme://[[userinfo]@]foo.com[:port]]/[path][?query][#fragment]
+ *
+ * and relative-refs like
+ *
+ * [path][?query][#fragment]
+ *
+ * Any optional elements portions not present in the original URI are
+ * left set to NULL in the resulting evhttp_uri. If no port is
+ * specified, the port is set to -1.
+ *
+ * Note that no decoding is performed on percent-escaped characters in
+ * the string; if you want to parse them, use evhttp_uridecode or
+ * evhttp_parse_query_str as appropriate.
+ *
+ * Note also that most URI schemes will have additional constraints that
+ * this function does not know about, and cannot check. For example,
+ * mailto://www.example.com/cgi-bin/fortune.pl is not a reasonable
+ * mailto url, http://www.example.com:99999/ is not a reasonable HTTP
+ * URL, and ftp:username@example.com is not a reasonable FTP URL.
+ * Nevertheless, all of these URLs conform to RFC3986, and this function
+ * accepts all of them as valid.
+ *
+ * @param source_uri the request URI
+ * @param flags Zero or more EVHTTP_URI_* flags to affect the behavior
+ * of the parser.
+ * @return uri container to hold parsed data, or NULL if there is error
+ * @see evhttp_uri_free()
+ */
+EVENT2_EXPORT_SYMBOL
+struct evhttp_uri *evhttp_uri_parse_with_flags(const char *source_uri,
+ unsigned flags);
+
+/** Tolerate URIs that do not conform to RFC3986.
+ *
+ * Unfortunately, some HTTP clients generate URIs that, according to RFC3986,
+ * are not conformant URIs. If you need to support these URIs, you can
+ * do so by passing this flag to evhttp_uri_parse_with_flags.
+ *
+ * Currently, these changes are:
+ * <ul>
+ * <li> Nonconformant URIs are allowed to contain otherwise unreasonable
+ * characters in their path, query, and fragment components.
+ * </ul>
+ */
+#define EVHTTP_URI_NONCONFORMANT 0x01
+
+/** Alias for evhttp_uri_parse_with_flags(source_uri, 0) */
+EVENT2_EXPORT_SYMBOL
+struct evhttp_uri *evhttp_uri_parse(const char *source_uri);
+
+/**
+ * Free all memory allocated for a parsed uri. Only use this for URIs
+ * generated by evhttp_uri_parse.
+ *
+ * @param uri container with parsed data
+ * @see evhttp_uri_parse()
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_uri_free(struct evhttp_uri *uri);
+
+/**
+ * Join together the uri parts from parsed data to form a URI-Reference.
+ *
+ * Note that no escaping of reserved characters is done on the members
+ * of the evhttp_uri, so the generated string might not be a valid URI
+ * unless the members of evhttp_uri are themselves valid.
+ *
+ * @param uri container with parsed data
+ * @param buf destination buffer
+ * @param limit destination buffer size
+ * @return an joined uri as string or NULL on error
+ * @see evhttp_uri_parse()
+ */
+EVENT2_EXPORT_SYMBOL
+char *evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_HTTP_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/http_compat.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/http_compat.h
new file mode 100644
index 000000000..43c2c43e4
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/http_compat.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_HTTP_COMPAT_H_INCLUDED_
+#define EVENT2_HTTP_COMPAT_H_INCLUDED_
+
+/** @file event2/http_compat.h
+
+ Potentially non-threadsafe versions of the functions in http.h: provided
+ only for backwards compatibility.
+
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/* For int types. */
+#include <event2/util.h>
+
+/**
+ * Start an HTTP server on the specified address and port
+ *
+ * @deprecated It does not allow an event base to be specified
+ *
+ * @param address the address to which the HTTP server should be bound
+ * @param port the port number on which the HTTP server should listen
+ * @return an struct evhttp object
+ */
+struct evhttp *evhttp_start(const char *address, ev_uint16_t port);
+
+/**
+ * A connection object that can be used to for making HTTP requests. The
+ * connection object tries to establish the connection when it is given an
+ * http request object.
+ *
+ * @deprecated It does not allow an event base to be specified
+ */
+struct evhttp_connection *evhttp_connection_new(
+ const char *address, ev_uint16_t port);
+
+/**
+ * Associates an event base with the connection - can only be called
+ * on a freshly created connection object that has not been used yet.
+ *
+ * @deprecated XXXX Why?
+ */
+void evhttp_connection_set_base(struct evhttp_connection *evcon,
+ struct event_base *base);
+
+
+/** Returns the request URI */
+#define evhttp_request_uri evhttp_request_get_uri
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/http_struct.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/http_struct.h
new file mode 100644
index 000000000..4bf5b1ff6
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/http_struct.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_HTTP_STRUCT_H_INCLUDED_
+#define EVENT2_HTTP_STRUCT_H_INCLUDED_
+
+/** @file event2/http_struct.h
+
+ Data structures for http. Using these structures may hurt forward
+ compatibility with later versions of Libevent: be careful!
+
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/* For int types. */
+#include <event2/util.h>
+
+/**
+ * the request structure that a server receives.
+ * WARNING: expect this structure to change. I will try to provide
+ * reasonable accessors.
+ */
+struct evhttp_request {
+#if defined(TAILQ_ENTRY)
+ TAILQ_ENTRY(evhttp_request) next;
+#else
+struct {
+ struct evhttp_request *tqe_next;
+ struct evhttp_request **tqe_prev;
+} next;
+#endif
+
+ /* the connection object that this request belongs to */
+ struct evhttp_connection *evcon;
+ int flags;
+/** The request obj owns the evhttp connection and needs to free it */
+#define EVHTTP_REQ_OWN_CONNECTION 0x0001
+/** Request was made via a proxy */
+#define EVHTTP_PROXY_REQUEST 0x0002
+/** The request object is owned by the user; the user must free it */
+#define EVHTTP_USER_OWNED 0x0004
+/** The request will be used again upstack; freeing must be deferred */
+#define EVHTTP_REQ_DEFER_FREE 0x0008
+/** The request should be freed upstack */
+#define EVHTTP_REQ_NEEDS_FREE 0x0010
+
+ struct evkeyvalq *input_headers;
+ struct evkeyvalq *output_headers;
+
+ /* address of the remote host and the port connection came from */
+ char *remote_host;
+ ev_uint16_t remote_port;
+
+ /* cache of the hostname for evhttp_request_get_host */
+ char *host_cache;
+
+ enum evhttp_request_kind kind;
+ enum evhttp_cmd_type type;
+
+ size_t headers_size;
+ size_t body_size;
+
+ char *uri; /* uri after HTTP request was parsed */
+ struct evhttp_uri *uri_elems; /* uri elements */
+
+ char major; /* HTTP Major number */
+ char minor; /* HTTP Minor number */
+
+ int response_code; /* HTTP Response code */
+ char *response_code_line; /* Readable response */
+
+ struct evbuffer *input_buffer; /* read data */
+ ev_int64_t ntoread;
+ unsigned chunked:1, /* a chunked request */
+ userdone:1; /* the user has sent all data */
+
+ struct evbuffer *output_buffer; /* outgoing post or data */
+
+ /* Callback */
+ void (*cb)(struct evhttp_request *, void *);
+ void *cb_arg;
+
+ /*
+ * Chunked data callback - call for each completed chunk if
+ * specified. If not specified, all the data is delivered via
+ * the regular callback.
+ */
+ void (*chunk_cb)(struct evhttp_request *, void *);
+
+ /*
+ * Callback added for forked-daapd so they can collect ICY
+ * (shoutcast) metadata from the http header. If return
+ * int is negative the connection will be closed.
+ */
+ int (*header_cb)(struct evhttp_request *, void *);
+
+ /*
+ * Error callback - called when error is occured.
+ * @see evhttp_request_error for error types.
+ *
+ * @see evhttp_request_set_error_cb()
+ */
+ void (*error_cb)(enum evhttp_request_error, void *);
+
+ /*
+ * Send complete callback - called when the request is actually
+ * sent and completed.
+ */
+ void (*on_complete_cb)(struct evhttp_request *, void *);
+ void *on_complete_cb_arg;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_HTTP_STRUCT_H_INCLUDED_ */
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/keyvalq_struct.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/keyvalq_struct.h
new file mode 100644
index 000000000..bffa54b3a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/keyvalq_struct.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_KEYVALQ_STRUCT_H_INCLUDED_
+#define EVENT2_KEYVALQ_STRUCT_H_INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Fix so that people don't have to run with <sys/queue.h> */
+/* XXXX This code is duplicated with event_struct.h */
+#ifndef TAILQ_ENTRY
+#define EVENT_DEFINED_TQENTRY_
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+#endif /* !TAILQ_ENTRY */
+
+#ifndef TAILQ_HEAD
+#define EVENT_DEFINED_TQHEAD_
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; \
+ struct type **tqh_last; \
+}
+#endif
+
+/*
+ * Key-Value pairs. Can be used for HTTP headers but also for
+ * query argument parsing.
+ */
+struct evkeyval {
+ TAILQ_ENTRY(evkeyval) next;
+
+ char *key;
+ char *value;
+};
+
+TAILQ_HEAD (evkeyvalq, evkeyval);
+
+/* XXXX This code is duplicated with event_struct.h */
+#ifdef EVENT_DEFINED_TQENTRY_
+#undef TAILQ_ENTRY
+#endif
+
+#ifdef EVENT_DEFINED_TQHEAD_
+#undef TAILQ_HEAD
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/listener.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/listener.h
new file mode 100644
index 000000000..84b4da055
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/listener.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_LISTENER_H_INCLUDED_
+#define EVENT2_LISTENER_H_INCLUDED_
+
+#include <event2/visibility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event.h>
+
+struct sockaddr;
+struct evconnlistener;
+
+/**
+ A callback that we invoke when a listener has a new connection.
+
+ @param listener The evconnlistener
+ @param fd The new file descriptor
+ @param addr The source address of the connection
+ @param socklen The length of addr
+ @param user_arg the pointer passed to evconnlistener_new()
+ */
+typedef void (*evconnlistener_cb)(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *);
+
+/**
+ A callback that we invoke when a listener encounters a non-retriable error.
+
+ @param listener The evconnlistener
+ @param user_arg the pointer passed to evconnlistener_new()
+ */
+typedef void (*evconnlistener_errorcb)(struct evconnlistener *, void *);
+
+/** Flag: Indicates that we should not make incoming sockets nonblocking
+ * before passing them to the callback. */
+#define LEV_OPT_LEAVE_SOCKETS_BLOCKING (1u<<0)
+/** Flag: Indicates that freeing the listener should close the underlying
+ * socket. */
+#define LEV_OPT_CLOSE_ON_FREE (1u<<1)
+/** Flag: Indicates that we should set the close-on-exec flag, if possible */
+#define LEV_OPT_CLOSE_ON_EXEC (1u<<2)
+/** Flag: Indicates that we should disable the timeout (if any) between when
+ * this socket is closed and when we can listen again on the same port. */
+#define LEV_OPT_REUSEABLE (1u<<3)
+/** Flag: Indicates that the listener should be locked so it's safe to use
+ * from multiple threadcs at once. */
+#define LEV_OPT_THREADSAFE (1u<<4)
+/** Flag: Indicates that the listener should be created in disabled
+ * state. Use evconnlistener_enable() to enable it later. */
+#define LEV_OPT_DISABLED (1u<<5)
+/** Flag: Indicates that the listener should defer accept() until data is
+ * available, if possible. Ignored on platforms that do not support this.
+ *
+ * This option can help performance for protocols where the client transmits
+ * immediately after connecting. Do not use this option if your protocol
+ * _doesn't_ start out with the client transmitting data, since in that case
+ * this option will sometimes cause the kernel to never tell you about the
+ * connection.
+ *
+ * This option is only supported by evconnlistener_new_bind(): it can't
+ * work with evconnlistener_new_fd(), since the listener needs to be told
+ * to use the option before it is actually bound.
+ */
+#define LEV_OPT_DEFERRED_ACCEPT (1u<<6)
+/** Flag: Indicates that we ask to allow multiple servers (processes or
+ * threads) to bind to the same port if they each set the option.
+ *
+ * SO_REUSEPORT is what most people would expect SO_REUSEADDR to be, however
+ * SO_REUSEPORT does not imply SO_REUSEADDR.
+ *
+ * This is only available on Linux and kernel 3.9+
+ */
+#define LEV_OPT_REUSEABLE_PORT (1u<<7)
+
+/**
+ Allocate a new evconnlistener object to listen for incoming TCP connections
+ on a given file descriptor.
+
+ @param base The event base to associate the listener with.
+ @param cb A callback to be invoked when a new connection arrives. If the
+ callback is NULL, the listener will be treated as disabled until the
+ callback is set.
+ @param ptr A user-supplied pointer to give to the callback.
+ @param flags Any number of LEV_OPT_* flags
+ @param backlog Passed to the listen() call to determine the length of the
+ acceptable connection backlog. Set to -1 for a reasonable default.
+ Set to 0 if the socket is already listening.
+ @param fd The file descriptor to listen on. It must be a nonblocking
+ file descriptor, and it should already be bound to an appropriate
+ port and address.
+*/
+EVENT2_EXPORT_SYMBOL
+struct evconnlistener *evconnlistener_new(struct event_base *base,
+ evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
+ evutil_socket_t fd);
+/**
+ Allocate a new evconnlistener object to listen for incoming TCP connections
+ on a given address.
+
+ @param base The event base to associate the listener with.
+ @param cb A callback to be invoked when a new connection arrives. If the
+ callback is NULL, the listener will be treated as disabled until the
+ callback is set.
+ @param ptr A user-supplied pointer to give to the callback.
+ @param flags Any number of LEV_OPT_* flags
+ @param backlog Passed to the listen() call to determine the length of the
+ acceptable connection backlog. Set to -1 for a reasonable default.
+ @param addr The address to listen for connections on.
+ @param socklen The length of the address.
+ */
+EVENT2_EXPORT_SYMBOL
+struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
+ evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
+ const struct sockaddr *sa, int socklen);
+/**
+ Disable and deallocate an evconnlistener.
+ */
+EVENT2_EXPORT_SYMBOL
+void evconnlistener_free(struct evconnlistener *lev);
+/**
+ Re-enable an evconnlistener that has been disabled.
+ */
+EVENT2_EXPORT_SYMBOL
+int evconnlistener_enable(struct evconnlistener *lev);
+/**
+ Stop listening for connections on an evconnlistener.
+ */
+EVENT2_EXPORT_SYMBOL
+int evconnlistener_disable(struct evconnlistener *lev);
+
+/** Return an evconnlistener's associated event_base. */
+EVENT2_EXPORT_SYMBOL
+struct event_base *evconnlistener_get_base(struct evconnlistener *lev);
+
+/** Return the socket that an evconnlistner is listening on. */
+EVENT2_EXPORT_SYMBOL
+evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev);
+
+/** Change the callback on the listener to cb and its user_data to arg.
+ */
+EVENT2_EXPORT_SYMBOL
+void evconnlistener_set_cb(struct evconnlistener *lev,
+ evconnlistener_cb cb, void *arg);
+
+/** Set an evconnlistener's error callback. */
+EVENT2_EXPORT_SYMBOL
+void evconnlistener_set_error_cb(struct evconnlistener *lev,
+ evconnlistener_errorcb errorcb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/rpc.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/rpc.h
new file mode 100644
index 000000000..dd43df266
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/rpc.h
@@ -0,0 +1,596 @@
+/*
+ * Copyright (c) 2006-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_RPC_H_INCLUDED_
+#define EVENT2_RPC_H_INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @file rpc.h
+ *
+ * This header files provides basic support for an RPC server and client.
+ *
+ * To support RPCs in a server, every supported RPC command needs to be
+ * defined and registered.
+ *
+ * EVRPC_HEADER(SendCommand, Request, Reply);
+ *
+ * SendCommand is the name of the RPC command.
+ * Request is the name of a structure generated by event_rpcgen.py.
+ * It contains all parameters relating to the SendCommand RPC. The
+ * server needs to fill in the Reply structure.
+ * Reply is the name of a structure generated by event_rpcgen.py. It
+ * contains the answer to the RPC.
+ *
+ * To register an RPC with an HTTP server, you need to first create an RPC
+ * base with:
+ *
+ * struct evrpc_base *base = evrpc_init(http);
+ *
+ * A specific RPC can then be registered with
+ *
+ * EVRPC_REGISTER(base, SendCommand, Request, Reply, FunctionCB, arg);
+ *
+ * when the server receives an appropriately formatted RPC, the user callback
+ * is invoked. The callback needs to fill in the reply structure.
+ *
+ * void FunctionCB(EVRPC_STRUCT(SendCommand)* rpc, void *arg);
+ *
+ * To send the reply, call EVRPC_REQUEST_DONE(rpc);
+ *
+ * See the regression test for an example.
+ */
+
+/**
+ Determines if the member has been set in the message
+
+ @param msg the message to inspect
+ @param member the member variable to test for presences
+ @return 1 if it's present or 0 otherwise.
+*/
+#define EVTAG_HAS(msg, member) \
+ ((msg)->member##_set == 1)
+
+#ifndef EVENT2_RPC_COMPAT_H_INCLUDED_
+
+/**
+ Assigns a value to the member in the message.
+
+ @param msg the message to which to assign a value
+ @param member the name of the member variable
+ @param value the value to assign
+*/
+#define EVTAG_ASSIGN(msg, member, value) \
+ (*(msg)->base->member##_assign)((msg), (value))
+/**
+ Assigns a value to the member in the message.
+
+ @param msg the message to which to assign a value
+ @param member the name of the member variable
+ @param value the value to assign
+ @param len the length of the value
+*/
+#define EVTAG_ASSIGN_WITH_LEN(msg, member, value, len) \
+ (*(msg)->base->member##_assign)((msg), (value), (len))
+/**
+ Returns the value for a member.
+
+ @param msg the message from which to get the value
+ @param member the name of the member variable
+ @param pvalue a pointer to the variable to hold the value
+ @return 0 on success, -1 otherwise.
+*/
+#define EVTAG_GET(msg, member, pvalue) \
+ (*(msg)->base->member##_get)((msg), (pvalue))
+/**
+ Returns the value for a member.
+
+ @param msg the message from which to get the value
+ @param member the name of the member variable
+ @param pvalue a pointer to the variable to hold the value
+ @param plen a pointer to the length of the value
+ @return 0 on success, -1 otherwise.
+*/
+#define EVTAG_GET_WITH_LEN(msg, member, pvalue, plen) \
+ (*(msg)->base->member##_get)((msg), (pvalue), (plen))
+
+#endif /* EVENT2_RPC_COMPAT_H_INCLUDED_ */
+
+/**
+ Adds a value to an array.
+*/
+#define EVTAG_ARRAY_ADD_VALUE(msg, member, value) \
+ (*(msg)->base->member##_add)((msg), (value))
+/**
+ Allocates a new entry in the array and returns it.
+*/
+#define EVTAG_ARRAY_ADD(msg, member) \
+ (*(msg)->base->member##_add)(msg)
+/**
+ Gets a variable at the specified offset from the array.
+*/
+#define EVTAG_ARRAY_GET(msg, member, offset, pvalue) \
+ (*(msg)->base->member##_get)((msg), (offset), (pvalue))
+/**
+ Returns the number of entries in the array.
+*/
+#define EVTAG_ARRAY_LEN(msg, member) ((msg)->member##_length)
+
+
+struct evbuffer;
+struct event_base;
+struct evrpc_req_generic;
+struct evrpc_request_wrapper;
+struct evrpc;
+
+/** The type of a specific RPC Message
+ *
+ * @param rpcname the name of the RPC message
+ */
+#define EVRPC_STRUCT(rpcname) struct evrpc_req__##rpcname
+
+struct evhttp_request;
+struct evrpc_status;
+struct evrpc_hook_meta;
+
+/** Creates the definitions and prototypes for an RPC
+ *
+ * You need to use EVRPC_HEADER to create structures and function prototypes
+ * needed by the server and client implementation. The structures have to be
+ * defined in an .rpc file and converted to source code via event_rpcgen.py
+ *
+ * @param rpcname the name of the RPC
+ * @param reqstruct the name of the RPC request structure
+ * @param replystruct the name of the RPC reply structure
+ * @see EVRPC_GENERATE()
+ */
+#define EVRPC_HEADER(rpcname, reqstruct, rplystruct) \
+EVRPC_STRUCT(rpcname) { \
+ struct evrpc_hook_meta *hook_meta; \
+ struct reqstruct* request; \
+ struct rplystruct* reply; \
+ struct evrpc* rpc; \
+ struct evhttp_request* http_req; \
+ struct evbuffer* rpc_data; \
+}; \
+int evrpc_send_request_##rpcname(struct evrpc_pool *, \
+ struct reqstruct *, struct rplystruct *, \
+ void (*)(struct evrpc_status *, \
+ struct reqstruct *, struct rplystruct *, void *cbarg), \
+ void *);
+
+struct evrpc_pool;
+
+/** use EVRPC_GENERATE instead */
+struct evrpc_request_wrapper *evrpc_make_request_ctx(
+ struct evrpc_pool *pool, void *request, void *reply,
+ const char *rpcname,
+ void (*req_marshal)(struct evbuffer*, void *),
+ void (*rpl_clear)(void *),
+ int (*rpl_unmarshal)(void *, struct evbuffer *),
+ void (*cb)(struct evrpc_status *, void *, void *, void *),
+ void *cbarg);
+
+/** Creates a context structure that contains rpc specific information.
+ *
+ * EVRPC_MAKE_CTX is used to populate a RPC specific context that
+ * contains information about marshaling the RPC data types.
+ *
+ * @param rpcname the name of the RPC
+ * @param reqstruct the name of the RPC request structure
+ * @param replystruct the name of the RPC reply structure
+ * @param pool the evrpc_pool over which to make the request
+ * @param request a pointer to the RPC request structure object
+ * @param reply a pointer to the RPC reply structure object
+ * @param cb the callback function to call when the RPC has completed
+ * @param cbarg the argument to supply to the callback
+ */
+#define EVRPC_MAKE_CTX(rpcname, reqstruct, rplystruct, \
+ pool, request, reply, cb, cbarg) \
+ evrpc_make_request_ctx(pool, request, reply, \
+ #rpcname, \
+ (void (*)(struct evbuffer *, void *))reqstruct##_marshal, \
+ (void (*)(void *))rplystruct##_clear, \
+ (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal, \
+ (void (*)(struct evrpc_status *, void *, void *, void *))cb, \
+ cbarg)
+
+/** Generates the code for receiving and sending an RPC message
+ *
+ * EVRPC_GENERATE is used to create the code corresponding to sending
+ * and receiving a particular RPC message
+ *
+ * @param rpcname the name of the RPC
+ * @param reqstruct the name of the RPC request structure
+ * @param replystruct the name of the RPC reply structure
+ * @see EVRPC_HEADER()
+ */
+#define EVRPC_GENERATE(rpcname, reqstruct, rplystruct) \
+ int evrpc_send_request_##rpcname(struct evrpc_pool *pool, \
+ struct reqstruct *request, struct rplystruct *reply, \
+ void (*cb)(struct evrpc_status *, \
+ struct reqstruct *, struct rplystruct *, void *cbarg), \
+ void *cbarg) { \
+ return evrpc_send_request_generic(pool, request, reply, \
+ (void (*)(struct evrpc_status *, void *, void *, void *))cb, \
+ cbarg, \
+ #rpcname, \
+ (void (*)(struct evbuffer *, void *))reqstruct##_marshal, \
+ (void (*)(void *))rplystruct##_clear, \
+ (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal); \
+}
+
+/** Provides access to the HTTP request object underlying an RPC
+ *
+ * Access to the underlying http object; can be used to look at headers or
+ * for getting the remote ip address
+ *
+ * @param rpc_req the rpc request structure provided to the server callback
+ * @return an struct evhttp_request object that can be inspected for
+ * HTTP headers or sender information.
+ */
+#define EVRPC_REQUEST_HTTP(rpc_req) (rpc_req)->http_req
+
+/** completes the server response to an rpc request */
+void evrpc_request_done(struct evrpc_req_generic *req);
+
+/** accessors for request and reply */
+void *evrpc_get_request(struct evrpc_req_generic *req);
+void *evrpc_get_reply(struct evrpc_req_generic *req);
+
+/** Creates the reply to an RPC request
+ *
+ * EVRPC_REQUEST_DONE is used to answer a request; the reply is expected
+ * to have been filled in. The request and reply pointers become invalid
+ * after this call has finished.
+ *
+ * @param rpc_req the rpc request structure provided to the server callback
+ */
+#define EVRPC_REQUEST_DONE(rpc_req) do { \
+ struct evrpc_req_generic *req_ = (struct evrpc_req_generic *)(rpc_req); \
+ evrpc_request_done(req_); \
+} while (0)
+
+
+struct evrpc_base;
+struct evhttp;
+
+/* functions to start up the rpc system */
+
+/** Creates a new rpc base from which RPC requests can be received
+ *
+ * @param server a pointer to an existing HTTP server
+ * @return a newly allocated evrpc_base struct
+ * @see evrpc_free()
+ */
+struct evrpc_base *evrpc_init(struct evhttp *server);
+
+/**
+ * Frees the evrpc base
+ *
+ * For now, you are responsible for making sure that no rpcs are ongoing.
+ *
+ * @param base the evrpc_base object to be freed
+ * @see evrpc_init
+ */
+void evrpc_free(struct evrpc_base *base);
+
+/** register RPCs with the HTTP Server
+ *
+ * registers a new RPC with the HTTP server, each RPC needs to have
+ * a unique name under which it can be identified.
+ *
+ * @param base the evrpc_base structure in which the RPC should be
+ * registered.
+ * @param name the name of the RPC
+ * @param request the name of the RPC request structure
+ * @param reply the name of the RPC reply structure
+ * @param callback the callback that should be invoked when the RPC
+ * is received. The callback has the following prototype
+ * void (*callback)(EVRPC_STRUCT(Message)* rpc, void *arg)
+ * @param cbarg an additional parameter that can be passed to the callback.
+ * The parameter can be used to carry around state.
+ */
+#define EVRPC_REGISTER(base, name, request, reply, callback, cbarg) \
+ evrpc_register_generic(base, #name, \
+ (void (*)(struct evrpc_req_generic *, void *))callback, cbarg, \
+ (void *(*)(void *))request##_new, NULL, \
+ (void (*)(void *))request##_free, \
+ (int (*)(void *, struct evbuffer *))request##_unmarshal, \
+ (void *(*)(void *))reply##_new, NULL, \
+ (void (*)(void *))reply##_free, \
+ (int (*)(void *))reply##_complete, \
+ (void (*)(struct evbuffer *, void *))reply##_marshal)
+
+/**
+ Low level function for registering an RPC with a server.
+
+ Use EVRPC_REGISTER() instead.
+
+ @see EVRPC_REGISTER()
+*/
+int evrpc_register_rpc(struct evrpc_base *, struct evrpc *,
+ void (*)(struct evrpc_req_generic*, void *), void *);
+
+/**
+ * Unregisters an already registered RPC
+ *
+ * @param base the evrpc_base object from which to unregister an RPC
+ * @param name the name of the rpc to unregister
+ * @return -1 on error or 0 when successful.
+ * @see EVRPC_REGISTER()
+ */
+#define EVRPC_UNREGISTER(base, name) evrpc_unregister_rpc((base), #name)
+
+int evrpc_unregister_rpc(struct evrpc_base *base, const char *name);
+
+/*
+ * Client-side RPC support
+ */
+
+struct evhttp_connection;
+struct evrpc_status;
+
+/** launches an RPC and sends it to the server
+ *
+ * EVRPC_MAKE_REQUEST() is used by the client to send an RPC to the server.
+ *
+ * @param name the name of the RPC
+ * @param pool the evrpc_pool that contains the connection objects over which
+ * the request should be sent.
+ * @param request a pointer to the RPC request structure - it contains the
+ * data to be sent to the server.
+ * @param reply a pointer to the RPC reply structure. It is going to be filled
+ * if the request was answered successfully
+ * @param cb the callback to invoke when the RPC request has been answered
+ * @param cbarg an additional argument to be passed to the client
+ * @return 0 on success, -1 on failure
+ */
+#define EVRPC_MAKE_REQUEST(name, pool, request, reply, cb, cbarg) \
+ evrpc_send_request_##name((pool), (request), (reply), (cb), (cbarg))
+
+/**
+ Makes an RPC request based on the provided context.
+
+ This is a low-level function and should not be used directly
+ unless a custom context object is provided. Use EVRPC_MAKE_REQUEST()
+ instead.
+
+ @param ctx a context from EVRPC_MAKE_CTX()
+ @returns 0 on success, -1 otherwise.
+ @see EVRPC_MAKE_REQUEST(), EVRPC_MAKE_CTX()
+*/
+int evrpc_make_request(struct evrpc_request_wrapper *ctx);
+
+/** creates an rpc connection pool
+ *
+ * a pool has a number of connections associated with it.
+ * rpc requests are always made via a pool.
+ *
+ * @param base a pointer to an struct event_based object; can be left NULL
+ * in singled-threaded applications
+ * @return a newly allocated struct evrpc_pool object
+ * @see evrpc_pool_free()
+ */
+struct evrpc_pool *evrpc_pool_new(struct event_base *base);
+/** frees an rpc connection pool
+ *
+ * @param pool a pointer to an evrpc_pool allocated via evrpc_pool_new()
+ * @see evrpc_pool_new()
+ */
+void evrpc_pool_free(struct evrpc_pool *pool);
+
+/**
+ * Adds a connection over which rpc can be dispatched to the pool.
+ *
+ * The connection object must have been newly created.
+ *
+ * @param pool the pool to which to add the connection
+ * @param evcon the connection to add to the pool.
+ */
+void evrpc_pool_add_connection(struct evrpc_pool *pool,
+ struct evhttp_connection *evcon);
+
+/**
+ * Removes a connection from the pool.
+ *
+ * The connection object must have been newly created.
+ *
+ * @param pool the pool from which to remove the connection
+ * @param evcon the connection to remove from the pool.
+ */
+void evrpc_pool_remove_connection(struct evrpc_pool *pool,
+ struct evhttp_connection *evcon);
+
+/**
+ * Sets the timeout in secs after which a request has to complete. The
+ * RPC is completely aborted if it does not complete by then. Setting
+ * the timeout to 0 means that it never timeouts and can be used to
+ * implement callback type RPCs.
+ *
+ * Any connection already in the pool will be updated with the new
+ * timeout. Connections added to the pool after set_timeout has be
+ * called receive the pool timeout only if no timeout has been set
+ * for the connection itself.
+ *
+ * @param pool a pointer to a struct evrpc_pool object
+ * @param timeout_in_secs the number of seconds after which a request should
+ * timeout and a failure be returned to the callback.
+ */
+void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs);
+
+/**
+ * Hooks for changing the input and output of RPCs; this can be used to
+ * implement compression, authentication, encryption, ...
+ */
+
+enum EVRPC_HOOK_TYPE {
+ EVRPC_INPUT, /**< apply the function to an input hook */
+ EVRPC_OUTPUT /**< apply the function to an output hook */
+};
+
+#ifndef _WIN32
+/** Deprecated alias for EVRPC_INPUT. Not available on windows, where it
+ * conflicts with platform headers. */
+#define INPUT EVRPC_INPUT
+/** Deprecated alias for EVRPC_OUTPUT. Not available on windows, where it
+ * conflicts with platform headers. */
+#define OUTPUT EVRPC_OUTPUT
+#endif
+
+/**
+ * Return value from hook processing functions
+ */
+
+enum EVRPC_HOOK_RESULT {
+ EVRPC_TERMINATE = -1, /**< indicates the rpc should be terminated */
+ EVRPC_CONTINUE = 0, /**< continue processing the rpc */
+ EVRPC_PAUSE = 1 /**< pause processing request until resumed */
+};
+
+/** adds a processing hook to either an rpc base or rpc pool
+ *
+ * If a hook returns TERMINATE, the processing is aborted. On CONTINUE,
+ * the request is immediately processed after the hook returns. If the
+ * hook returns PAUSE, request processing stops until evrpc_resume_request()
+ * has been called.
+ *
+ * The add functions return handles that can be used for removing hooks.
+ *
+ * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
+ * @param hook_type either INPUT or OUTPUT
+ * @param cb the callback to call when the hook is activated
+ * @param cb_arg an additional argument for the callback
+ * @return a handle to the hook so it can be removed later
+ * @see evrpc_remove_hook()
+ */
+void *evrpc_add_hook(void *vbase,
+ enum EVRPC_HOOK_TYPE hook_type,
+ int (*cb)(void *, struct evhttp_request *, struct evbuffer *, void *),
+ void *cb_arg);
+
+/** removes a previously added hook
+ *
+ * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
+ * @param hook_type either INPUT or OUTPUT
+ * @param handle a handle returned by evrpc_add_hook()
+ * @return 1 on success or 0 on failure
+ * @see evrpc_add_hook()
+ */
+int evrpc_remove_hook(void *vbase,
+ enum EVRPC_HOOK_TYPE hook_type,
+ void *handle);
+
+/** resume a paused request
+ *
+ * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
+ * @param ctx the context pointer provided to the original hook call
+ */
+int
+evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res);
+
+/** adds meta data to request
+ *
+ * evrpc_hook_add_meta() allows hooks to add meta data to a request. for
+ * a client request, the meta data can be inserted by an outgoing request hook
+ * and retrieved by the incoming request hook.
+ *
+ * @param ctx the context provided to the hook call
+ * @param key a NUL-terminated c-string
+ * @param data the data to be associated with the key
+ * @param data_size the size of the data
+ */
+void evrpc_hook_add_meta(void *ctx, const char *key,
+ const void *data, size_t data_size);
+
+/** retrieves meta data previously associated
+ *
+ * evrpc_hook_find_meta() can be used to retrieve meta data associated to a
+ * request by a previous hook.
+ * @param ctx the context provided to the hook call
+ * @param key a NUL-terminated c-string
+ * @param data pointer to a data pointer that will contain the retrieved data
+ * @param data_size pointer to the size of the data
+ * @return 0 on success or -1 on failure
+ */
+int evrpc_hook_find_meta(void *ctx, const char *key,
+ void **data, size_t *data_size);
+
+/**
+ * returns the connection object associated with the request
+ *
+ * @param ctx the context provided to the hook call
+ * @return a pointer to the evhttp_connection object
+ */
+struct evhttp_connection *evrpc_hook_get_connection(void *ctx);
+
+/**
+ Function for sending a generic RPC request.
+
+ Do not call this function directly, use EVRPC_MAKE_REQUEST() instead.
+
+ @see EVRPC_MAKE_REQUEST()
+ */
+int evrpc_send_request_generic(struct evrpc_pool *pool,
+ void *request, void *reply,
+ void (*cb)(struct evrpc_status *, void *, void *, void *),
+ void *cb_arg,
+ const char *rpcname,
+ void (*req_marshal)(struct evbuffer *, void *),
+ void (*rpl_clear)(void *),
+ int (*rpl_unmarshal)(void *, struct evbuffer *));
+
+/**
+ Function for registering a generic RPC with the RPC base.
+
+ Do not call this function directly, use EVRPC_REGISTER() instead.
+
+ @see EVRPC_REGISTER()
+ */
+int
+evrpc_register_generic(struct evrpc_base *base, const char *name,
+ void (*callback)(struct evrpc_req_generic *, void *), void *cbarg,
+ void *(*req_new)(void *), void *req_new_arg, void (*req_free)(void *),
+ int (*req_unmarshal)(void *, struct evbuffer *),
+ void *(*rpl_new)(void *), void *rpl_new_arg, void (*rpl_free)(void *),
+ int (*rpl_complete)(void *),
+ void (*rpl_marshal)(struct evbuffer *, void *));
+
+/** accessors for obscure and undocumented functionality */
+struct evrpc_pool* evrpc_request_get_pool(struct evrpc_request_wrapper *ctx);
+void evrpc_request_set_pool(struct evrpc_request_wrapper *ctx,
+ struct evrpc_pool *pool);
+void evrpc_request_set_cb(struct evrpc_request_wrapper *ctx,
+ void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg),
+ void *cb_arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_RPC_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/rpc_compat.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/rpc_compat.h
new file mode 100644
index 000000000..8d8334d25
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/rpc_compat.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2006-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_RPC_COMPAT_H_INCLUDED_
+#define EVENT2_RPC_COMPAT_H_INCLUDED_
+
+/** @file event2/rpc_compat.h
+
+ Deprecated versions of the functions in rpc.h: provided only for
+ backwards compatibility.
+
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** backwards compatible accessors that work only with gcc */
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+
+#undef EVTAG_ASSIGN
+#undef EVTAG_GET
+#undef EVTAG_ADD
+
+#define EVTAG_ASSIGN(msg, member, args...) \
+ (*(msg)->base->member##_assign)(msg, ## args)
+#define EVTAG_GET(msg, member, args...) \
+ (*(msg)->base->member##_get)(msg, ## args)
+#define EVTAG_ADD(msg, member, args...) \
+ (*(msg)->base->member##_add)(msg, ## args)
+#endif
+#define EVTAG_LEN(msg, member) ((msg)->member##_length)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/rpc_struct.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/rpc_struct.h
new file mode 100644
index 000000000..8f691f49f
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/rpc_struct.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2006-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_RPC_STRUCT_H_INCLUDED_
+#define EVENT2_RPC_STRUCT_H_INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @file event2/rpc_struct.h
+
+ Structures used by rpc.h. Using these structures directly may harm
+ forward compatibility: be careful!
+
+ */
+
+/**
+ * provides information about the completed RPC request.
+ */
+struct evrpc_status {
+#define EVRPC_STATUS_ERR_NONE 0
+#define EVRPC_STATUS_ERR_TIMEOUT 1
+#define EVRPC_STATUS_ERR_BADPAYLOAD 2
+#define EVRPC_STATUS_ERR_UNSTARTED 3
+#define EVRPC_STATUS_ERR_HOOKABORTED 4
+ int error;
+
+ /* for looking at headers or other information */
+ struct evhttp_request *http_req;
+};
+
+/* the structure below needs to be synchronized with evrpc_req_generic */
+
+/* Encapsulates a request */
+struct evrpc {
+ TAILQ_ENTRY(evrpc) next;
+
+ /* the URI at which the request handler lives */
+ const char* uri;
+
+ /* creates a new request structure */
+ void *(*request_new)(void *);
+ void *request_new_arg;
+
+ /* frees the request structure */
+ void (*request_free)(void *);
+
+ /* unmarshals the buffer into the proper request structure */
+ int (*request_unmarshal)(void *, struct evbuffer *);
+
+ /* creates a new reply structure */
+ void *(*reply_new)(void *);
+ void *reply_new_arg;
+
+ /* frees the reply structure */
+ void (*reply_free)(void *);
+
+ /* verifies that the reply is valid */
+ int (*reply_complete)(void *);
+
+ /* marshals the reply into a buffer */
+ void (*reply_marshal)(struct evbuffer*, void *);
+
+ /* the callback invoked for each received rpc */
+ void (*cb)(struct evrpc_req_generic *, void *);
+ void *cb_arg;
+
+ /* reference for further configuration */
+ struct evrpc_base *base;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_RPC_STRUCT_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/tag.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/tag.h
new file mode 100644
index 000000000..2f73bfc00
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/tag.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_TAG_H_INCLUDED_
+#define EVENT2_TAG_H_INCLUDED_
+
+/** @file event2/tag.h
+
+ Helper functions for reading and writing tagged data onto buffers.
+
+ */
+
+#include <event2/visibility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/* For int types. */
+#include <event2/util.h>
+
+struct evbuffer;
+
+/*
+ * Marshaling tagged data - We assume that all tags are inserted in their
+ * numeric order - so that unknown tags will always be higher than the
+ * known ones - and we can just ignore the end of an event buffer.
+ */
+
+EVENT2_EXPORT_SYMBOL
+void evtag_init(void);
+
+/**
+ Unmarshals the header and returns the length of the payload
+
+ @param evbuf the buffer from which to unmarshal data
+ @param ptag a pointer in which the tag id is being stored
+ @returns -1 on failure or the number of bytes in the remaining payload.
+*/
+EVENT2_EXPORT_SYMBOL
+int evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag);
+
+EVENT2_EXPORT_SYMBOL
+void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data,
+ ev_uint32_t len);
+EVENT2_EXPORT_SYMBOL
+void evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag,
+ struct evbuffer *data);
+
+/**
+ Encode an integer and store it in an evbuffer.
+
+ We encode integers by nybbles; the first nibble contains the number
+ of significant nibbles - 1; this allows us to encode up to 64-bit
+ integers. This function is byte-order independent.
+
+ @param evbuf evbuffer to store the encoded number
+ @param number a 32-bit integer
+ */
+EVENT2_EXPORT_SYMBOL
+void evtag_encode_int(struct evbuffer *evbuf, ev_uint32_t number);
+EVENT2_EXPORT_SYMBOL
+void evtag_encode_int64(struct evbuffer *evbuf, ev_uint64_t number);
+
+EVENT2_EXPORT_SYMBOL
+void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag,
+ ev_uint32_t integer);
+EVENT2_EXPORT_SYMBOL
+void evtag_marshal_int64(struct evbuffer *evbuf, ev_uint32_t tag,
+ ev_uint64_t integer);
+
+EVENT2_EXPORT_SYMBOL
+void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag,
+ const char *string);
+
+EVENT2_EXPORT_SYMBOL
+void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag,
+ struct timeval *tv);
+
+EVENT2_EXPORT_SYMBOL
+int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag,
+ struct evbuffer *dst);
+EVENT2_EXPORT_SYMBOL
+int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag);
+EVENT2_EXPORT_SYMBOL
+int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength);
+EVENT2_EXPORT_SYMBOL
+int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength);
+EVENT2_EXPORT_SYMBOL
+int evtag_consume(struct evbuffer *evbuf);
+
+EVENT2_EXPORT_SYMBOL
+int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ ev_uint32_t *pinteger);
+EVENT2_EXPORT_SYMBOL
+int evtag_unmarshal_int64(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ ev_uint64_t *pinteger);
+
+EVENT2_EXPORT_SYMBOL
+int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag,
+ void *data, size_t len);
+
+EVENT2_EXPORT_SYMBOL
+int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ char **pstring);
+
+EVENT2_EXPORT_SYMBOL
+int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ struct timeval *ptv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_TAG_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/tag_compat.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/tag_compat.h
new file mode 100644
index 000000000..a276c0d35
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/tag_compat.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_TAG_COMPAT_H_INCLUDED_
+#define EVENT2_TAG_COMPAT_H_INCLUDED_
+
+/** @file event2/tag_compat.h
+
+ Obsolete/deprecated functions from tag.h; provided only for backwards
+ compatibility.
+ */
+
+/**
+ @name Misnamed functions
+
+ @deprecated These macros are deprecated because their names don't follow
+ Libevent's naming conventions. Use evtag_encode_int and
+ evtag_encode_int64 instead.
+
+ @{
+*/
+#define encode_int(evbuf, number) evtag_encode_int((evbuf), (number))
+#define encode_int64(evbuf, number) evtag_encode_int64((evbuf), (number))
+/**@}*/
+
+#endif /* EVENT2_TAG_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/thread.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/thread.h
new file mode 100644
index 000000000..b51998631
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/thread.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2008-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_THREAD_H_INCLUDED_
+#define EVENT2_THREAD_H_INCLUDED_
+
+/** @file event2/thread.h
+
+ Functions for multi-threaded applications using Libevent.
+
+ When using a multi-threaded application in which multiple threads
+ add and delete events from a single event base, Libevent needs to
+ lock its data structures.
+
+ Like the memory-management function hooks, all of the threading functions
+ _must_ be set up before an event_base is created if you want the base to
+ use them.
+
+ Most programs will either be using Windows threads or Posix threads. You
+ can configure Libevent to use one of these event_use_windows_threads() or
+ event_use_pthreads() respectively. If you're using another threading
+ library, you'll need to configure threading functions manually using
+ evthread_set_lock_callbacks() and evthread_set_condition_callbacks().
+
+ */
+
+#include <event2/visibility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+
+/**
+ @name Flags passed to lock functions
+
+ @{
+*/
+/** A flag passed to a locking callback when the lock was allocated as a
+ * read-write lock, and we want to acquire or release the lock for writing. */
+#define EVTHREAD_WRITE 0x04
+/** A flag passed to a locking callback when the lock was allocated as a
+ * read-write lock, and we want to acquire or release the lock for reading. */
+#define EVTHREAD_READ 0x08
+/** A flag passed to a locking callback when we don't want to block waiting
+ * for the lock; if we can't get the lock immediately, we will instead
+ * return nonzero from the locking callback. */
+#define EVTHREAD_TRY 0x10
+/**@}*/
+
+#if !defined(EVENT__DISABLE_THREAD_SUPPORT) || defined(EVENT_IN_DOXYGEN_)
+
+#define EVTHREAD_LOCK_API_VERSION 1
+
+/**
+ @name Types of locks
+
+ @{*/
+/** A recursive lock is one that can be acquired multiple times at once by the
+ * same thread. No other process can allocate the lock until the thread that
+ * has been holding it has unlocked it as many times as it locked it. */
+#define EVTHREAD_LOCKTYPE_RECURSIVE 1
+/* A read-write lock is one that allows multiple simultaneous readers, but
+ * where any one writer excludes all other writers and readers. */
+#define EVTHREAD_LOCKTYPE_READWRITE 2
+/**@}*/
+
+/** This structure describes the interface a threading library uses for
+ * locking. It's used to tell evthread_set_lock_callbacks() how to use
+ * locking on this platform.
+ */
+struct evthread_lock_callbacks {
+ /** The current version of the locking API. Set this to
+ * EVTHREAD_LOCK_API_VERSION */
+ int lock_api_version;
+ /** Which kinds of locks does this version of the locking API
+ * support? A bitfield of EVTHREAD_LOCKTYPE_RECURSIVE and
+ * EVTHREAD_LOCKTYPE_READWRITE.
+ *
+ * (Note that RECURSIVE locks are currently mandatory, and
+ * READWRITE locks are not currently used.)
+ **/
+ unsigned supported_locktypes;
+ /** Function to allocate and initialize new lock of type 'locktype'.
+ * Returns NULL on failure. */
+ void *(*alloc)(unsigned locktype);
+ /** Funtion to release all storage held in 'lock', which was created
+ * with type 'locktype'. */
+ void (*free)(void *lock, unsigned locktype);
+ /** Acquire an already-allocated lock at 'lock' with mode 'mode'.
+ * Returns 0 on success, and nonzero on failure. */
+ int (*lock)(unsigned mode, void *lock);
+ /** Release a lock at 'lock' using mode 'mode'. Returns 0 on success,
+ * and nonzero on failure. */
+ int (*unlock)(unsigned mode, void *lock);
+};
+
+/** Sets a group of functions that Libevent should use for locking.
+ * For full information on the required callback API, see the
+ * documentation for the individual members of evthread_lock_callbacks.
+ *
+ * Note that if you're using Windows or the Pthreads threading library, you
+ * probably shouldn't call this function; instead, use
+ * evthread_use_windows_threads() or evthread_use_posix_threads() if you can.
+ */
+EVENT2_EXPORT_SYMBOL
+int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *);
+
+#define EVTHREAD_CONDITION_API_VERSION 1
+
+struct timeval;
+
+/** This structure describes the interface a threading library uses for
+ * condition variables. It's used to tell evthread_set_condition_callbacks
+ * how to use locking on this platform.
+ */
+struct evthread_condition_callbacks {
+ /** The current version of the conditions API. Set this to
+ * EVTHREAD_CONDITION_API_VERSION */
+ int condition_api_version;
+ /** Function to allocate and initialize a new condition variable.
+ * Returns the condition variable on success, and NULL on failure.
+ * The 'condtype' argument will be 0 with this API version.
+ */
+ void *(*alloc_condition)(unsigned condtype);
+ /** Function to free a condition variable. */
+ void (*free_condition)(void *cond);
+ /** Function to signal a condition variable. If 'broadcast' is 1, all
+ * threads waiting on 'cond' should be woken; otherwise, only on one
+ * thread is worken. Should return 0 on success, -1 on failure.
+ * This function will only be called while holding the associated
+ * lock for the condition.
+ */
+ int (*signal_condition)(void *cond, int broadcast);
+ /** Function to wait for a condition variable. The lock 'lock'
+ * will be held when this function is called; should be released
+ * while waiting for the condition to be come signalled, and
+ * should be held again when this function returns.
+ * If timeout is provided, it is interval of seconds to wait for
+ * the event to become signalled; if it is NULL, the function
+ * should wait indefinitely.
+ *
+ * The function should return -1 on error; 0 if the condition
+ * was signalled, or 1 on a timeout. */
+ int (*wait_condition)(void *cond, void *lock,
+ const struct timeval *timeout);
+};
+
+/** Sets a group of functions that Libevent should use for condition variables.
+ * For full information on the required callback API, see the
+ * documentation for the individual members of evthread_condition_callbacks.
+ *
+ * Note that if you're using Windows or the Pthreads threading library, you
+ * probably shouldn't call this function; instead, use
+ * evthread_use_windows_threads() or evthread_use_pthreads() if you can.
+ */
+EVENT2_EXPORT_SYMBOL
+int evthread_set_condition_callbacks(
+ const struct evthread_condition_callbacks *);
+
+/**
+ Sets the function for determining the thread id.
+
+ @param base the event base for which to set the id function
+ @param id_fn the identify function Libevent should invoke to
+ determine the identity of a thread.
+*/
+EVENT2_EXPORT_SYMBOL
+void evthread_set_id_callback(
+ unsigned long (*id_fn)(void));
+
+#if (defined(_WIN32) && !defined(EVENT__DISABLE_THREAD_SUPPORT)) || defined(EVENT_IN_DOXYGEN_)
+/** Sets up Libevent for use with Windows builtin locking and thread ID
+ functions. Unavailable if Libevent is not built for Windows.
+
+ @return 0 on success, -1 on failure. */
+EVENT2_EXPORT_SYMBOL
+int evthread_use_windows_threads(void);
+/**
+ Defined if Libevent was built with support for evthread_use_windows_threads()
+*/
+#define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED 1
+#endif
+
+#if defined(EVENT__HAVE_PTHREADS) || defined(EVENT_IN_DOXYGEN_)
+/** Sets up Libevent for use with Pthreads locking and thread ID functions.
+ Unavailable if Libevent is not build for use with pthreads. Requires
+ libraries to link against Libevent_pthreads as well as Libevent.
+
+ @return 0 on success, -1 on failure. */
+EVENT2_EXPORT_SYMBOL
+int evthread_use_pthreads(void);
+/** Defined if Libevent was built with support for evthread_use_pthreads() */
+#define EVTHREAD_USE_PTHREADS_IMPLEMENTED 1
+
+#endif
+
+/** Enable debugging wrappers around the current lock callbacks. If Libevent
+ * makes one of several common locking errors, exit with an assertion failure.
+ *
+ * If you're going to call this function, you must do so before any locks are
+ * allocated.
+ **/
+EVENT2_EXPORT_SYMBOL
+void evthread_enable_lock_debugging(void);
+
+/* Old (misspelled) version: This is deprecated; use
+ * evthread_enable_log_debugging instead. */
+EVENT2_EXPORT_SYMBOL
+void evthread_enable_lock_debuging(void);
+
+#endif /* EVENT__DISABLE_THREAD_SUPPORT */
+
+struct event_base;
+/** Make sure it's safe to tell an event base to wake up from another thread
+ or a signal handler.
+
+ You shouldn't need to call this by hand; configuring the base with thread
+ support should be necessary and sufficient.
+
+ @return 0 on success, -1 on failure.
+ */
+EVENT2_EXPORT_SYMBOL
+int evthread_make_base_notifiable(struct event_base *base);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT2_THREAD_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/util.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/util.h
new file mode 100644
index 000000000..defe00a3a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/util.h
@@ -0,0 +1,866 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_UTIL_H_INCLUDED_
+#define EVENT2_UTIL_H_INCLUDED_
+
+/** @file event2/util.h
+
+ Common convenience functions for cross-platform portability and
+ related socket manipulations.
+
+ */
+#include <event2/visibility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event2/event-config.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef EVENT__HAVE_STDINT_H
+#include <stdint.h>
+#elif defined(EVENT__HAVE_INTTYPES_H)
+#include <inttypes.h>
+#endif
+#ifdef EVENT__HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef EVENT__HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+#ifdef _MSC_VER
+#include <BaseTsd.h>
+#endif
+#include <stdarg.h>
+#ifdef EVENT__HAVE_NETDB_H
+#if !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+#include <netdb.h>
+#endif
+
+#ifdef _WIN32
+#include <winsock2.h>
+#ifdef EVENT__HAVE_GETADDRINFO
+/* for EAI_* definitions. */
+#include <ws2tcpip.h>
+#endif
+#else
+#ifdef EVENT__HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <sys/socket.h>
+#endif
+
+#include <time.h>
+
+/* Some openbsd autoconf versions get the name of this macro wrong. */
+#if defined(EVENT__SIZEOF_VOID__) && !defined(EVENT__SIZEOF_VOID_P)
+#define EVENT__SIZEOF_VOID_P EVENT__SIZEOF_VOID__
+#endif
+
+/**
+ * @name Standard integer types.
+ *
+ * Integer type definitions for types that are supposed to be defined in the
+ * C99-specified stdint.h. Shamefully, some platforms do not include
+ * stdint.h, so we need to replace it. (If you are on a platform like this,
+ * your C headers are now over 10 years out of date. You should bug them to
+ * do something about this.)
+ *
+ * We define:
+ *
+ * <dl>
+ * <dt>ev_uint64_t, ev_uint32_t, ev_uint16_t, ev_uint8_t</dt>
+ * <dd>unsigned integer types of exactly 64, 32, 16, and 8 bits
+ * respectively.</dd>
+ * <dt>ev_int64_t, ev_int32_t, ev_int16_t, ev_int8_t</dt>
+ * <dd>signed integer types of exactly 64, 32, 16, and 8 bits
+ * respectively.</dd>
+ * <dt>ev_uintptr_t, ev_intptr_t</dt>
+ * <dd>unsigned/signed integers large enough
+ * to hold a pointer without loss of bits.</dd>
+ * <dt>ev_ssize_t</dt>
+ * <dd>A signed type of the same size as size_t</dd>
+ * <dt>ev_off_t</dt>
+ * <dd>A signed type typically used to represent offsets within a
+ * (potentially large) file</dd>
+ *
+ * @{
+ */
+#ifdef EVENT__HAVE_UINT64_T
+#define ev_uint64_t uint64_t
+#define ev_int64_t int64_t
+#elif defined(_WIN32)
+#define ev_uint64_t unsigned __int64
+#define ev_int64_t signed __int64
+#elif EVENT__SIZEOF_LONG_LONG == 8
+#define ev_uint64_t unsigned long long
+#define ev_int64_t long long
+#elif EVENT__SIZEOF_LONG == 8
+#define ev_uint64_t unsigned long
+#define ev_int64_t long
+#elif defined(EVENT_IN_DOXYGEN_)
+#define ev_uint64_t ...
+#define ev_int64_t ...
+#else
+#error "No way to define ev_uint64_t"
+#endif
+
+#ifdef EVENT__HAVE_UINT32_T
+#define ev_uint32_t uint32_t
+#define ev_int32_t int32_t
+#elif defined(_WIN32)
+#define ev_uint32_t unsigned int
+#define ev_int32_t signed int
+#elif EVENT__SIZEOF_LONG == 4
+#define ev_uint32_t unsigned long
+#define ev_int32_t signed long
+#elif EVENT__SIZEOF_INT == 4
+#define ev_uint32_t unsigned int
+#define ev_int32_t signed int
+#elif defined(EVENT_IN_DOXYGEN_)
+#define ev_uint32_t ...
+#define ev_int32_t ...
+#else
+#error "No way to define ev_uint32_t"
+#endif
+
+#ifdef EVENT__HAVE_UINT16_T
+#define ev_uint16_t uint16_t
+#define ev_int16_t int16_t
+#elif defined(_WIN32)
+#define ev_uint16_t unsigned short
+#define ev_int16_t signed short
+#elif EVENT__SIZEOF_INT == 2
+#define ev_uint16_t unsigned int
+#define ev_int16_t signed int
+#elif EVENT__SIZEOF_SHORT == 2
+#define ev_uint16_t unsigned short
+#define ev_int16_t signed short
+#elif defined(EVENT_IN_DOXYGEN_)
+#define ev_uint16_t ...
+#define ev_int16_t ...
+#else
+#error "No way to define ev_uint16_t"
+#endif
+
+#ifdef EVENT__HAVE_UINT8_T
+#define ev_uint8_t uint8_t
+#define ev_int8_t int8_t
+#elif defined(EVENT_IN_DOXYGEN_)
+#define ev_uint8_t ...
+#define ev_int8_t ...
+#else
+#define ev_uint8_t unsigned char
+#define ev_int8_t signed char
+#endif
+
+#ifdef EVENT__HAVE_UINTPTR_T
+#define ev_uintptr_t uintptr_t
+#define ev_intptr_t intptr_t
+#elif EVENT__SIZEOF_VOID_P <= 4
+#define ev_uintptr_t ev_uint32_t
+#define ev_intptr_t ev_int32_t
+#elif EVENT__SIZEOF_VOID_P <= 8
+#define ev_uintptr_t ev_uint64_t
+#define ev_intptr_t ev_int64_t
+#elif defined(EVENT_IN_DOXYGEN_)
+#define ev_uintptr_t ...
+#define ev_intptr_t ...
+#else
+#error "No way to define ev_uintptr_t"
+#endif
+
+#ifdef EVENT__ssize_t
+#define ev_ssize_t EVENT__ssize_t
+#else
+#define ev_ssize_t ssize_t
+#endif
+
+/* Note that we define ev_off_t based on the compile-time size of off_t that
+ * we used to build Libevent, and not based on the current size of off_t.
+ * (For example, we don't define ev_off_t to off_t.). We do this because
+ * some systems let you build your software with different off_t sizes
+ * at runtime, and so putting in any dependency on off_t would risk API
+ * mismatch.
+ */
+#ifdef _WIN32
+#define ev_off_t ev_int64_t
+#elif EVENT__SIZEOF_OFF_T == 8
+#define ev_off_t ev_int64_t
+#elif EVENT__SIZEOF_OFF_T == 4
+#define ev_off_t ev_int32_t
+#elif defined(EVENT_IN_DOXYGEN_)
+#define ev_off_t ...
+#else
+#define ev_off_t off_t
+#endif
+/**@}*/
+
+/* Limits for integer types.
+
+ We're making two assumptions here:
+ - The compiler does constant folding properly.
+ - The platform does signed arithmetic in two's complement.
+*/
+
+/**
+ @name Limits for integer types
+
+ These macros hold the largest or smallest values possible for the
+ ev_[u]int*_t types.
+
+ @{
+*/
+#ifndef EVENT__HAVE_STDINT_H
+#define EV_UINT64_MAX ((((ev_uint64_t)0xffffffffUL) << 32) | 0xffffffffUL)
+#define EV_INT64_MAX ((((ev_int64_t) 0x7fffffffL) << 32) | 0xffffffffL)
+#define EV_INT64_MIN ((-EV_INT64_MAX) - 1)
+#define EV_UINT32_MAX ((ev_uint32_t)0xffffffffUL)
+#define EV_INT32_MAX ((ev_int32_t) 0x7fffffffL)
+#define EV_INT32_MIN ((-EV_INT32_MAX) - 1)
+#define EV_UINT16_MAX ((ev_uint16_t)0xffffUL)
+#define EV_INT16_MAX ((ev_int16_t) 0x7fffL)
+#define EV_INT16_MIN ((-EV_INT16_MAX) - 1)
+#define EV_UINT8_MAX 255
+#define EV_INT8_MAX 127
+#define EV_INT8_MIN ((-EV_INT8_MAX) - 1)
+#else
+#define EV_UINT64_MAX UINT64_MAX
+#define EV_INT64_MAX INT64_MAX
+#define EV_INT64_MIN INT64_MIN
+#define EV_UINT32_MAX UINT32_MAX
+#define EV_INT32_MAX INT32_MAX
+#define EV_INT32_MIN INT32_MIN
+#define EV_UINT16_MAX UINT16_MAX
+#define EV_INT16_MAX INT16_MAX
+#define EV_UINT8_MAX UINT8_MAX
+#define EV_INT8_MAX INT8_MAX
+#define EV_INT8_MIN INT8_MIN
+/** @} */
+#endif
+
+
+/**
+ @name Limits for SIZE_T and SSIZE_T
+
+ @{
+*/
+#if EVENT__SIZEOF_SIZE_T == 8
+#define EV_SIZE_MAX EV_UINT64_MAX
+#define EV_SSIZE_MAX EV_INT64_MAX
+#elif EVENT__SIZEOF_SIZE_T == 4
+#define EV_SIZE_MAX EV_UINT32_MAX
+#define EV_SSIZE_MAX EV_INT32_MAX
+#elif defined(EVENT_IN_DOXYGEN_)
+#define EV_SIZE_MAX ...
+#define EV_SSIZE_MAX ...
+#else
+#error "No way to define SIZE_MAX"
+#endif
+
+#define EV_SSIZE_MIN ((-EV_SSIZE_MAX) - 1)
+/**@}*/
+
+#ifdef _WIN32
+#define ev_socklen_t int
+#elif defined(EVENT__socklen_t)
+#define ev_socklen_t EVENT__socklen_t
+#else
+#define ev_socklen_t socklen_t
+#endif
+
+#ifdef EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY
+#if !defined(EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY) \
+ && !defined(ss_family)
+#define ss_family __ss_family
+#endif
+#endif
+
+/**
+ * A type wide enough to hold the output of "socket()" or "accept()". On
+ * Windows, this is an intptr_t; elsewhere, it is an int. */
+#ifdef _WIN32
+#define evutil_socket_t intptr_t
+#else
+#define evutil_socket_t int
+#endif
+
+/**
+ * Structure to hold information about a monotonic timer
+ *
+ * Use this with evutil_configure_monotonic_time() and
+ * evutil_gettime_monotonic().
+ *
+ * This is an opaque structure; you can allocate one using
+ * evutil_monotonic_timer_new().
+ *
+ * @see evutil_monotonic_timer_new(), evutil_monotonic_timer_free(),
+ * evutil_configure_monotonic_time(), evutil_gettime_monotonic()
+ */
+struct evutil_monotonic_timer
+#ifdef EVENT_IN_DOXYGEN_
+{/*Empty body so that doxygen will generate documentation here.*/}
+#endif
+;
+
+#define EV_MONOT_PRECISE 1
+#define EV_MONOT_FALLBACK 2
+
+/** Format a date string using RFC 1123 format (used in HTTP).
+ * If `cur_p` is NULL, current system's time will be used.
+ * The number of characters written will be returned.
+ * One should check if the return value is smaller than `datelen` to check if
+ * the result is truncated or not.
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_date_rfc1123(char *date, const size_t datelen, struct tm *cur_p);
+
+/** Allocate a new struct evutil_monotonic_timer for use with the
+ * evutil_configure_monotonic_time() and evutil_gettime_monotonic()
+ * functions. You must configure the timer with
+ * evutil_configure_monotonic_time() before using it.
+ */
+EVENT2_EXPORT_SYMBOL
+struct evutil_monotonic_timer * evutil_monotonic_timer_new(void);
+
+/** Free a struct evutil_monotonic_timer that was allocated using
+ * evutil_monotonic_timer_new().
+ */
+EVENT2_EXPORT_SYMBOL
+void evutil_monotonic_timer_free(struct evutil_monotonic_timer *timer);
+
+/** Set up a struct evutil_monotonic_timer; flags can include
+ * EV_MONOT_PRECISE and EV_MONOT_FALLBACK.
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_configure_monotonic_time(struct evutil_monotonic_timer *timer,
+ int flags);
+
+/** Query the current monotonic time from a struct evutil_monotonic_timer
+ * previously configured with evutil_configure_monotonic_time(). Monotonic
+ * time is guaranteed never to run in reverse, but is not necessarily epoch-
+ * based, or relative to any other definite point. Use it to make reliable
+ * measurements of elapsed time between events even when the system time
+ * may be changed.
+ *
+ * It is not safe to use this funtion on the same timer from multiple
+ * threads.
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_gettime_monotonic(struct evutil_monotonic_timer *timer,
+ struct timeval *tp);
+
+/** Create two new sockets that are connected to each other.
+
+ On Unix, this simply calls socketpair(). On Windows, it uses the
+ loopback network interface on 127.0.0.1, and only
+ AF_INET,SOCK_STREAM are supported.
+
+ (This may fail on some Windows hosts where firewall software has cleverly
+ decided to keep 127.0.0.1 from talking to itself.)
+
+ Parameters and return values are as for socketpair()
+*/
+EVENT2_EXPORT_SYMBOL
+int evutil_socketpair(int d, int type, int protocol, evutil_socket_t sv[2]);
+/** Do platform-specific operations as needed to make a socket nonblocking.
+
+ @param sock The socket to make nonblocking
+ @return 0 on success, -1 on failure
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_make_socket_nonblocking(evutil_socket_t sock);
+
+/** Do platform-specific operations to make a listener socket reusable.
+
+ Specifically, we want to make sure that another program will be able
+ to bind this address right after we've closed the listener.
+
+ This differs from Windows's interpretation of "reusable", which
+ allows multiple listeners to bind the same address at the same time.
+
+ @param sock The socket to make reusable
+ @return 0 on success, -1 on failure
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_make_listen_socket_reuseable(evutil_socket_t sock);
+
+/** Do platform-specific operations to make a listener port reusable.
+
+ Specifically, we want to make sure that multiple programs which also
+ set the same socket option will be able to bind, listen at the same time.
+
+ This is a feature available only to Linux 3.9+
+
+ @param sock The socket to make reusable
+ @return 0 on success, -1 on failure
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_make_listen_socket_reuseable_port(evutil_socket_t sock);
+
+/** Do platform-specific operations as needed to close a socket upon a
+ successful execution of one of the exec*() functions.
+
+ @param sock The socket to be closed
+ @return 0 on success, -1 on failure
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_make_socket_closeonexec(evutil_socket_t sock);
+
+/** Do the platform-specific call needed to close a socket returned from
+ socket() or accept().
+
+ @param sock The socket to be closed
+ @return 0 on success, -1 on failure
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_closesocket(evutil_socket_t sock);
+#define EVUTIL_CLOSESOCKET(s) evutil_closesocket(s)
+
+/** Do platform-specific operations, if possible, to make a tcp listener
+ * socket defer accept()s until there is data to read.
+ *
+ * Not all platforms support this. You don't want to do this for every
+ * listener socket: only the ones that implement a protocol where the
+ * client transmits before the server needs to respond.
+ *
+ * @param sock The listening socket to to make deferred
+ * @return 0 on success (whether the operation is supported or not),
+ * -1 on failure
+*/
+EVENT2_EXPORT_SYMBOL
+int evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock);
+
+#ifdef _WIN32
+/** Return the most recent socket error. Not idempotent on all platforms. */
+#define EVUTIL_SOCKET_ERROR() WSAGetLastError()
+/** Replace the most recent socket error with errcode */
+#define EVUTIL_SET_SOCKET_ERROR(errcode) \
+ do { WSASetLastError(errcode); } while (0)
+/** Return the most recent socket error to occur on sock. */
+EVENT2_EXPORT_SYMBOL
+int evutil_socket_geterror(evutil_socket_t sock);
+/** Convert a socket error to a string. */
+EVENT2_EXPORT_SYMBOL
+const char *evutil_socket_error_to_string(int errcode);
+#elif defined(EVENT_IN_DOXYGEN_)
+/**
+ @name Socket error functions
+
+ These functions are needed for making programs compatible between
+ Windows and Unix-like platforms.
+
+ You see, Winsock handles socket errors differently from the rest of
+ the world. Elsewhere, a socket error is like any other error and is
+ stored in errno. But winsock functions require you to retrieve the
+ error with a special function, and don't let you use strerror for
+ the error codes. And handling EWOULDBLOCK is ... different.
+
+ @{
+*/
+/** Return the most recent socket error. Not idempotent on all platforms. */
+#define EVUTIL_SOCKET_ERROR() ...
+/** Replace the most recent socket error with errcode */
+#define EVUTIL_SET_SOCKET_ERROR(errcode) ...
+/** Return the most recent socket error to occur on sock. */
+#define evutil_socket_geterror(sock) ...
+/** Convert a socket error to a string. */
+#define evutil_socket_error_to_string(errcode) ...
+/**@}*/
+#else
+#define EVUTIL_SOCKET_ERROR() (errno)
+#define EVUTIL_SET_SOCKET_ERROR(errcode) \
+ do { errno = (errcode); } while (0)
+#define evutil_socket_geterror(sock) (errno)
+#define evutil_socket_error_to_string(errcode) (strerror(errcode))
+#endif
+
+
+/**
+ * @name Manipulation macros for struct timeval.
+ *
+ * We define replacements
+ * for timeradd, timersub, timerclear, timercmp, and timerisset.
+ *
+ * @{
+ */
+#ifdef EVENT__HAVE_TIMERADD
+#define evutil_timeradd(tvp, uvp, vvp) timeradd((tvp), (uvp), (vvp))
+#define evutil_timersub(tvp, uvp, vvp) timersub((tvp), (uvp), (vvp))
+#else
+#define evutil_timeradd(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
+ if ((vvp)->tv_usec >= 1000000) { \
+ (vvp)->tv_sec++; \
+ (vvp)->tv_usec -= 1000000; \
+ } \
+ } while (0)
+#define evutil_timersub(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif /* !EVENT__HAVE_TIMERADD */
+
+#ifdef EVENT__HAVE_TIMERCLEAR
+#define evutil_timerclear(tvp) timerclear(tvp)
+#else
+#define evutil_timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
+#endif
+/**@}*/
+
+/** Return true iff the tvp is related to uvp according to the relational
+ * operator cmp. Recognized values for cmp are ==, <=, <, >=, and >. */
+#define evutil_timercmp(tvp, uvp, cmp) \
+ (((tvp)->tv_sec == (uvp)->tv_sec) ? \
+ ((tvp)->tv_usec cmp (uvp)->tv_usec) : \
+ ((tvp)->tv_sec cmp (uvp)->tv_sec))
+
+#ifdef EVENT__HAVE_TIMERISSET
+#define evutil_timerisset(tvp) timerisset(tvp)
+#else
+#define evutil_timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
+#endif
+
+/** Replacement for offsetof on platforms that don't define it. */
+#ifdef offsetof
+#define evutil_offsetof(type, field) offsetof(type, field)
+#else
+#define evutil_offsetof(type, field) ((off_t)(&((type *)0)->field))
+#endif
+
+/* big-int related functions */
+/** Parse a 64-bit value from a string. Arguments are as for strtol. */
+EVENT2_EXPORT_SYMBOL
+ev_int64_t evutil_strtoll(const char *s, char **endptr, int base);
+
+/** Replacement for gettimeofday on platforms that lack it. */
+#ifdef EVENT__HAVE_GETTIMEOFDAY
+#define evutil_gettimeofday(tv, tz) gettimeofday((tv), (tz))
+#else
+struct timezone;
+EVENT2_EXPORT_SYMBOL
+int evutil_gettimeofday(struct timeval *tv, struct timezone *tz);
+#endif
+
+/** Replacement for snprintf to get consistent behavior on platforms for
+ which the return value of snprintf does not conform to C99.
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
+#ifdef __GNUC__
+ __attribute__((format(printf, 3, 4)))
+#endif
+;
+/** Replacement for vsnprintf to get consistent behavior on platforms for
+ which the return value of snprintf does not conform to C99.
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
+#ifdef __GNUC__
+ __attribute__((format(printf, 3, 0)))
+#endif
+;
+
+/** Replacement for inet_ntop for platforms which lack it. */
+EVENT2_EXPORT_SYMBOL
+const char *evutil_inet_ntop(int af, const void *src, char *dst, size_t len);
+/** Replacement for inet_pton for platforms which lack it. */
+EVENT2_EXPORT_SYMBOL
+int evutil_inet_pton(int af, const char *src, void *dst);
+struct sockaddr;
+
+/** Parse an IPv4 or IPv6 address, with optional port, from a string.
+
+ Recognized formats are:
+ - [IPv6Address]:port
+ - [IPv6Address]
+ - IPv6Address
+ - IPv4Address:port
+ - IPv4Address
+
+ If no port is specified, the port in the output is set to 0.
+
+ @param str The string to parse.
+ @param out A struct sockaddr to hold the result. This should probably be
+ a struct sockaddr_storage.
+ @param outlen A pointer to the number of bytes that that 'out' can safely
+ hold. Set to the number of bytes used in 'out' on success.
+ @return -1 if the address is not well-formed, if the port is out of range,
+ or if out is not large enough to hold the result. Otherwise returns
+ 0 on success.
+*/
+EVENT2_EXPORT_SYMBOL
+int evutil_parse_sockaddr_port(const char *str, struct sockaddr *out, int *outlen);
+
+/** Compare two sockaddrs; return 0 if they are equal, or less than 0 if sa1
+ * preceeds sa2, or greater than 0 if sa1 follows sa2. If include_port is
+ * true, consider the port as well as the address. Only implemented for
+ * AF_INET and AF_INET6 addresses. The ordering is not guaranteed to remain
+ * the same between Libevent versions. */
+EVENT2_EXPORT_SYMBOL
+int evutil_sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2,
+ int include_port);
+
+/** As strcasecmp, but always compares the characters in locale-independent
+ ASCII. That's useful if you're handling data in ASCII-based protocols.
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_ascii_strcasecmp(const char *str1, const char *str2);
+/** As strncasecmp, but always compares the characters in locale-independent
+ ASCII. That's useful if you're handling data in ASCII-based protocols.
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_ascii_strncasecmp(const char *str1, const char *str2, size_t n);
+
+/* Here we define evutil_addrinfo to the native addrinfo type, or redefine it
+ * if this system has no getaddrinfo(). */
+#ifdef EVENT__HAVE_STRUCT_ADDRINFO
+#define evutil_addrinfo addrinfo
+#else
+/** A definition of struct addrinfo for systems that lack it.
+
+ (This is just an alias for struct addrinfo if the system defines
+ struct addrinfo.)
+*/
+struct evutil_addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for nodename */
+ struct sockaddr *ai_addr; /* binary address */
+ struct evutil_addrinfo *ai_next; /* next structure in linked list */
+};
+#endif
+/** @name evutil_getaddrinfo() error codes
+
+ These values are possible error codes for evutil_getaddrinfo() and
+ related functions.
+
+ @{
+*/
+#if defined(EAI_ADDRFAMILY) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_EAI_ADDRFAMILY EAI_ADDRFAMILY
+#else
+#define EVUTIL_EAI_ADDRFAMILY -901
+#endif
+#if defined(EAI_AGAIN) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_EAI_AGAIN EAI_AGAIN
+#else
+#define EVUTIL_EAI_AGAIN -902
+#endif
+#if defined(EAI_BADFLAGS) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_EAI_BADFLAGS EAI_BADFLAGS
+#else
+#define EVUTIL_EAI_BADFLAGS -903
+#endif
+#if defined(EAI_FAIL) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_EAI_FAIL EAI_FAIL
+#else
+#define EVUTIL_EAI_FAIL -904
+#endif
+#if defined(EAI_FAMILY) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_EAI_FAMILY EAI_FAMILY
+#else
+#define EVUTIL_EAI_FAMILY -905
+#endif
+#if defined(EAI_MEMORY) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_EAI_MEMORY EAI_MEMORY
+#else
+#define EVUTIL_EAI_MEMORY -906
+#endif
+/* This test is a bit complicated, since some MS SDKs decide to
+ * remove NODATA or redefine it to be the same as NONAME, in a
+ * fun interpretation of RFC 2553 and RFC 3493. */
+#if defined(EAI_NODATA) && defined(EVENT__HAVE_GETADDRINFO) && (!defined(EAI_NONAME) || EAI_NODATA != EAI_NONAME)
+#define EVUTIL_EAI_NODATA EAI_NODATA
+#else
+#define EVUTIL_EAI_NODATA -907
+#endif
+#if defined(EAI_NONAME) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_EAI_NONAME EAI_NONAME
+#else
+#define EVUTIL_EAI_NONAME -908
+#endif
+#if defined(EAI_SERVICE) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_EAI_SERVICE EAI_SERVICE
+#else
+#define EVUTIL_EAI_SERVICE -909
+#endif
+#if defined(EAI_SOCKTYPE) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_EAI_SOCKTYPE EAI_SOCKTYPE
+#else
+#define EVUTIL_EAI_SOCKTYPE -910
+#endif
+#if defined(EAI_SYSTEM) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_EAI_SYSTEM EAI_SYSTEM
+#else
+#define EVUTIL_EAI_SYSTEM -911
+#endif
+
+#define EVUTIL_EAI_CANCEL -90001
+
+#if defined(AI_PASSIVE) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_AI_PASSIVE AI_PASSIVE
+#else
+#define EVUTIL_AI_PASSIVE 0x1000
+#endif
+#if defined(AI_CANONNAME) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_AI_CANONNAME AI_CANONNAME
+#else
+#define EVUTIL_AI_CANONNAME 0x2000
+#endif
+#if defined(AI_NUMERICHOST) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_AI_NUMERICHOST AI_NUMERICHOST
+#else
+#define EVUTIL_AI_NUMERICHOST 0x4000
+#endif
+#if defined(AI_NUMERICSERV) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_AI_NUMERICSERV AI_NUMERICSERV
+#else
+#define EVUTIL_AI_NUMERICSERV 0x8000
+#endif
+#if defined(AI_V4MAPPED) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_AI_V4MAPPED AI_V4MAPPED
+#else
+#define EVUTIL_AI_V4MAPPED 0x10000
+#endif
+#if defined(AI_ALL) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_AI_ALL AI_ALL
+#else
+#define EVUTIL_AI_ALL 0x20000
+#endif
+#if defined(AI_ADDRCONFIG) && defined(EVENT__HAVE_GETADDRINFO)
+#define EVUTIL_AI_ADDRCONFIG AI_ADDRCONFIG
+#else
+#define EVUTIL_AI_ADDRCONFIG 0x40000
+#endif
+/**@}*/
+
+struct evutil_addrinfo;
+/**
+ * This function clones getaddrinfo for systems that don't have it. For full
+ * details, see RFC 3493, section 6.1.
+ *
+ * Limitations:
+ * - When the system has no getaddrinfo, we fall back to gethostbyname_r or
+ * gethostbyname, with their attendant issues.
+ * - The AI_V4MAPPED and AI_ALL flags are not currently implemented.
+ *
+ * For a nonblocking variant, see evdns_getaddrinfo.
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_getaddrinfo(const char *nodename, const char *servname,
+ const struct evutil_addrinfo *hints_in, struct evutil_addrinfo **res);
+
+/** Release storage allocated by evutil_getaddrinfo or evdns_getaddrinfo. */
+EVENT2_EXPORT_SYMBOL
+void evutil_freeaddrinfo(struct evutil_addrinfo *ai);
+
+EVENT2_EXPORT_SYMBOL
+const char *evutil_gai_strerror(int err);
+
+/** Generate n bytes of secure pseudorandom data, and store them in buf.
+ *
+ * Current versions of Libevent use an ARC4-based random number generator,
+ * seeded using the platform's entropy source (/dev/urandom on Unix-like
+ * systems; CryptGenRandom on Windows). This is not actually as secure as it
+ * should be: ARC4 is a pretty lousy cipher, and the current implementation
+ * provides only rudimentary prediction- and backtracking-resistance. Don't
+ * use this for serious cryptographic applications.
+ */
+EVENT2_EXPORT_SYMBOL
+void evutil_secure_rng_get_bytes(void *buf, size_t n);
+
+/**
+ * Seed the secure random number generator if needed, and return 0 on
+ * success or -1 on failure.
+ *
+ * It is okay to call this function more than once; it will still return
+ * 0 if the RNG has been successfully seeded and -1 if it can't be
+ * seeded.
+ *
+ * Ordinarily you don't need to call this function from your own code;
+ * Libevent will seed the RNG itself the first time it needs good random
+ * numbers. You only need to call it if (a) you want to double-check
+ * that one of the seeding methods did succeed, or (b) you plan to drop
+ * the capability to seed (by chrooting, or dropping capabilities, or
+ * whatever), and you want to make sure that seeding happens before your
+ * program loses the ability to do it.
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_secure_rng_init(void);
+
+/**
+ * Set a filename to use in place of /dev/urandom for seeding the secure
+ * PRNG. Return 0 on success, -1 on failure.
+ *
+ * Call this function BEFORE calling any other initialization or RNG
+ * functions.
+ *
+ * (This string will _NOT_ be copied internally. Do not free it while any
+ * user of the secure RNG might be running. Don't pass anything other than a
+ * real /dev/...random device file here, or you might lose security.)
+ *
+ * This API is unstable, and might change in a future libevent version.
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_secure_rng_set_urandom_device_file(char *fname);
+
+/** Seed the random number generator with extra random bytes.
+
+ You should almost never need to call this function; it should be
+ sufficient to invoke evutil_secure_rng_init(), or let Libevent take
+ care of calling evutil_secure_rng_init() on its own.
+
+ If you call this function as a _replacement_ for the regular
+ entropy sources, then you need to be sure that your input
+ contains a fairly large amount of strong entropy. Doing so is
+ notoriously hard: most people who try get it wrong. Watch out!
+
+ @param dat a buffer full of a strong source of random numbers
+ @param datlen the number of bytes to read from datlen
+ */
+EVENT2_EXPORT_SYMBOL
+void evutil_secure_rng_add_bytes(const char *dat, size_t datlen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT1_EVUTIL_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/visibility.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/visibility.h
new file mode 100644
index 000000000..fb16dbeed
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/event2/visibility.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_VISIBILITY_H_INCLUDED_
+#define EVENT2_VISIBILITY_H_INCLUDED_
+
+#include <event2/event-config.h>
+
+#if defined(event_EXPORTS) || defined(event_extra_EXPORTS) || defined(event_core_EXPORTS)
+# if defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+# define EVENT2_EXPORT_SYMBOL __global
+# elif defined __GNUC__
+# define EVENT2_EXPORT_SYMBOL __attribute__ ((visibility("default")))
+# elif defined(_MSC_VER)
+# define EVENT2_EXPORT_SYMBOL extern __declspec(dllexport)
+# else
+# define EVENT2_EXPORT_SYMBOL /* unknown compiler */
+# endif
+#else
+# if defined(EVENT__NEED_DLLIMPORT) && defined(_MSC_VER) && !defined(EVENT_BUILDING_REGRESS_TEST)
+# define EVENT2_EXPORT_SYMBOL extern __declspec(dllimport)
+# else
+# define EVENT2_EXPORT_SYMBOL
+# endif
+#endif
+
+#endif /* EVENT2_VISIBILITY_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/evhttp.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/evhttp.h
new file mode 100644
index 000000000..549bc9b14
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/evhttp.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT1_EVHTTP_H_INCLUDED_
+#define EVENT1_EVHTTP_H_INCLUDED_
+
+/** @file evhttp.h
+
+ An http implementation subsystem for Libevent.
+
+ The <evhttp.h> header is deprecated in Libevent 2.0 and later; please
+ use <event2/http.h> instead. Depending on what functionality you
+ need, you may also want to include more of the other <event2/...>
+ headers.
+ */
+
+#include <event.h>
+#include <event2/http.h>
+#include <event2/http_struct.h>
+#include <event2/http_compat.h>
+
+#endif /* EVENT1_EVHTTP_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/evrpc.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/evrpc.h
new file mode 100644
index 000000000..7e986f7da
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/evrpc.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT1_EVRPC_H_INCLUDED_
+#define EVENT1_EVRPC_H_INCLUDED_
+
+/** @file evrpc.h
+
+ An RPC system for Libevent.
+
+ The <evrpc.h> header is deprecated in Libevent 2.0 and later; please
+ use <event2/rpc.h> instead. Depending on what functionality you
+ need, you may also want to include more of the other <event2/...>
+ headers.
+ */
+
+#include <event.h>
+#include <event2/rpc.h>
+#include <event2/rpc_struct.h>
+#include <event2/rpc_compat.h>
+
+#endif /* EVENT1_EVRPC_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/evutil.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/evutil.h
new file mode 100644
index 000000000..12c137d74
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/evutil.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT1_EVUTIL_H_INCLUDED_
+#define EVENT1_EVUTIL_H_INCLUDED_
+
+/** @file evutil.h
+
+ Utility and compatibility functions for Libevent.
+
+ The <evutil.h> header is deprecated in Libevent 2.0 and later; please
+ use <event2/util.h> instead.
+*/
+
+#include <event2/util.h>
+
+#endif /* EVENT1_EVUTIL_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/include/include.am b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/include.am
new file mode 100644
index 000000000..9aad2dba4
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/include/include.am
@@ -0,0 +1,46 @@
+# include/Makefile.am for libevent
+# Copyright 2000-2007 Niels Provos
+# Copyright 2007-2012 Niels Provos and Nick Mathewson
+#
+# See LICENSE for copying information.
+
+include_event2dir = $(includedir)/event2
+
+EVENT2_EXPORT = \
+ include/event2/buffer.h \
+ include/event2/buffer_compat.h \
+ include/event2/bufferevent.h \
+ include/event2/bufferevent_compat.h \
+ include/event2/bufferevent_ssl.h \
+ include/event2/bufferevent_struct.h \
+ include/event2/dns.h \
+ include/event2/dns_compat.h \
+ include/event2/dns_struct.h \
+ include/event2/event.h \
+ include/event2/event_compat.h \
+ include/event2/event_struct.h \
+ include/event2/http.h \
+ include/event2/http_compat.h \
+ include/event2/http_struct.h \
+ include/event2/keyvalq_struct.h \
+ include/event2/listener.h \
+ include/event2/rpc.h \
+ include/event2/rpc_compat.h \
+ include/event2/rpc_struct.h \
+ include/event2/tag.h \
+ include/event2/tag_compat.h \
+ include/event2/thread.h \
+ include/event2/util.h \
+ include/event2/visibility.h
+
+## Without the nobase_ prefixing, Automake would strip "include/event2/" from
+## the source header filename to derive the installed header filename.
+## With nobase_ the installed path is $(includedir)/include/event2/ev*.h.
+
+if INSTALL_LIBEVENT
+include_event2_HEADERS = $(EVENT2_EXPORT)
+nodist_include_event2_HEADERS = include/event2/event-config.h
+else
+noinst_HEADERS += $(EVENT2_EXPORT)
+nodist_noinst_HEADERS = include/event2/event-config.h
+endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/iocp-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/iocp-internal.h
new file mode 100644
index 000000000..93dbe2b1a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/iocp-internal.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IOCP_INTERNAL_H_INCLUDED_
+#define IOCP_INTERNAL_H_INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct event_overlapped;
+struct event_iocp_port;
+struct evbuffer;
+typedef void (*iocp_callback)(struct event_overlapped *, ev_uintptr_t, ev_ssize_t, int success);
+
+/* This whole file is actually win32 only. We wrap the structures in a win32
+ * ifdef so that we can test-compile code that uses these interfaces on
+ * non-win32 platforms. */
+#ifdef _WIN32
+
+/**
+ Internal use only. Wraps an OVERLAPPED that we're using for libevent
+ functionality. Whenever an event_iocp_port gets an event for a given
+ OVERLAPPED*, it upcasts the pointer to an event_overlapped, and calls the
+ iocp_callback function with the event_overlapped, the iocp key, and the
+ number of bytes transferred as arguments.
+ */
+struct event_overlapped {
+ OVERLAPPED overlapped;
+ iocp_callback cb;
+};
+
+/* Mingw's headers don't define LPFN_ACCEPTEX. */
+
+typedef BOOL (WINAPI *AcceptExPtr)(SOCKET, SOCKET, PVOID, DWORD, DWORD, DWORD, LPDWORD, LPOVERLAPPED);
+typedef BOOL (WINAPI *ConnectExPtr)(SOCKET, const struct sockaddr *, int, PVOID, DWORD, LPDWORD, LPOVERLAPPED);
+typedef void (WINAPI *GetAcceptExSockaddrsPtr)(PVOID, DWORD, DWORD, DWORD, LPSOCKADDR *, LPINT, LPSOCKADDR *, LPINT);
+
+/** Internal use only. Holds pointers to functions that only some versions of
+ Windows provide.
+ */
+struct win32_extension_fns {
+ AcceptExPtr AcceptEx;
+ ConnectExPtr ConnectEx;
+ GetAcceptExSockaddrsPtr GetAcceptExSockaddrs;
+};
+
+/**
+ Internal use only. Stores a Windows IO Completion port, along with
+ related data.
+ */
+struct event_iocp_port {
+ /** The port itself */
+ HANDLE port;
+ /* A lock to cover internal structures. */
+ CRITICAL_SECTION lock;
+ /** Number of threads ever open on the port. */
+ short n_threads;
+ /** True iff we're shutting down all the threads on this port */
+ short shutdown;
+ /** How often the threads on this port check for shutdown and other
+ * conditions */
+ long ms;
+ /* The threads that are waiting for events. */
+ HANDLE *threads;
+ /** Number of threads currently open on this port. */
+ short n_live_threads;
+ /** A semaphore to signal when we are done shutting down. */
+ HANDLE *shutdownSemaphore;
+};
+
+const struct win32_extension_fns *event_get_win32_extension_fns_(void);
+#else
+/* Dummy definition so we can test-compile more things on unix. */
+struct event_overlapped {
+ iocp_callback cb;
+};
+#endif
+
+/** Initialize the fields in an event_overlapped.
+
+ @param overlapped The struct event_overlapped to initialize
+ @param cb The callback that should be invoked once the IO operation has
+ finished.
+ */
+void event_overlapped_init_(struct event_overlapped *, iocp_callback cb);
+
+/** Allocate and return a new evbuffer that supports overlapped IO on a given
+ socket. The socket must be associated with an IO completion port using
+ event_iocp_port_associate_.
+*/
+struct evbuffer *evbuffer_overlapped_new_(evutil_socket_t fd);
+
+/** XXXX Document (nickm) */
+evutil_socket_t evbuffer_overlapped_get_fd_(struct evbuffer *buf);
+
+void evbuffer_overlapped_set_fd_(struct evbuffer *buf, evutil_socket_t fd);
+
+/** Start reading data onto the end of an overlapped evbuffer.
+
+ An evbuffer can only have one read pending at a time. While the read
+ is in progress, no other data may be added to the end of the buffer.
+ The buffer must be created with event_overlapped_init_().
+ evbuffer_commit_read_() must be called in the completion callback.
+
+ @param buf The buffer to read onto
+ @param n The number of bytes to try to read.
+ @param ol Overlapped object with associated completion callback.
+ @return 0 on success, -1 on error.
+ */
+int evbuffer_launch_read_(struct evbuffer *buf, size_t n, struct event_overlapped *ol);
+
+/** Start writing data from the start of an evbuffer.
+
+ An evbuffer can only have one write pending at a time. While the write is
+ in progress, no other data may be removed from the front of the buffer.
+ The buffer must be created with event_overlapped_init_().
+ evbuffer_commit_write_() must be called in the completion callback.
+
+ @param buf The buffer to read onto
+ @param n The number of bytes to try to read.
+ @param ol Overlapped object with associated completion callback.
+ @return 0 on success, -1 on error.
+ */
+int evbuffer_launch_write_(struct evbuffer *buf, ev_ssize_t n, struct event_overlapped *ol);
+
+/** XXX document */
+void evbuffer_commit_read_(struct evbuffer *, ev_ssize_t);
+void evbuffer_commit_write_(struct evbuffer *, ev_ssize_t);
+
+/** Create an IOCP, and launch its worker threads. Internal use only.
+
+ This interface is unstable, and will change.
+ */
+struct event_iocp_port *event_iocp_port_launch_(int n_cpus);
+
+/** Associate a file descriptor with an iocp, such that overlapped IO on the
+ fd will happen on one of the iocp's worker threads.
+*/
+int event_iocp_port_associate_(struct event_iocp_port *port, evutil_socket_t fd,
+ ev_uintptr_t key);
+
+/** Tell all threads serving an iocp to stop. Wait for up to waitMsec for all
+ the threads to finish whatever they're doing. If waitMsec is -1, wait
+ as long as required. If all the threads are done, free the port and return
+ 0. Otherwise, return -1. If you get a -1 return value, it is safe to call
+ this function again.
+*/
+int event_iocp_shutdown_(struct event_iocp_port *port, long waitMsec);
+
+/* FIXME document. */
+int event_iocp_activate_overlapped_(struct event_iocp_port *port,
+ struct event_overlapped *o,
+ ev_uintptr_t key, ev_uint32_t n_bytes);
+
+struct event_base;
+/* FIXME document. */
+struct event_iocp_port *event_base_get_iocp_(struct event_base *base);
+
+/* FIXME document. */
+int event_base_start_iocp_(struct event_base *base, int n_cpus);
+void event_base_stop_iocp_(struct event_base *base);
+
+/* FIXME document. */
+struct bufferevent *bufferevent_async_new_(struct event_base *base,
+ evutil_socket_t fd, int options);
+
+/* FIXME document. */
+void bufferevent_async_set_connected_(struct bufferevent *bev);
+int bufferevent_async_can_connect_(struct bufferevent *bev);
+int bufferevent_async_connect_(struct bufferevent *bev, evutil_socket_t fd,
+ const struct sockaddr *sa, int socklen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/ipv6-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/ipv6-internal.h
new file mode 100644
index 000000000..0c207377b
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/ipv6-internal.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Internal use only: Fake IPv6 structures and values on platforms that
+ * do not have them */
+
+#ifndef IPV6_INTERNAL_H_INCLUDED_
+#define IPV6_INTERNAL_H_INCLUDED_
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include "event2/util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @file ipv6-internal.h
+ *
+ * Replacement types and functions for platforms that don't support ipv6
+ * properly.
+ */
+
+#ifndef EVENT__HAVE_STRUCT_IN6_ADDR
+struct in6_addr {
+ ev_uint8_t s6_addr[16];
+};
+#endif
+
+#ifndef EVENT__HAVE_SA_FAMILY_T
+typedef int sa_family_t;
+#endif
+
+#ifndef EVENT__HAVE_STRUCT_SOCKADDR_IN6
+struct sockaddr_in6 {
+ /* This will fail if we find a struct sockaddr that doesn't have
+ * sa_family as the first element. */
+ sa_family_t sin6_family;
+ ev_uint16_t sin6_port;
+ struct in6_addr sin6_addr;
+};
+#endif
+
+#ifndef AF_INET6
+#define AF_INET6 3333
+#endif
+#ifndef PF_INET6
+#define PF_INET6 AF_INET6
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/kqueue-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/kqueue-internal.h
new file mode 100644
index 000000000..02c5a3606
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/kqueue-internal.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef KQUEUE_INTERNAL_H_INCLUDED_
+#define KQUEUE_INTERNAL_H_INCLUDED_
+
+/** Notification function, used to tell an event base to wake up from another
+ * thread. Only works when event_kq_add_notify_event_() has previously been
+ * called successfully on that base. */
+int event_kq_notify_base_(struct event_base *base);
+
+/** Prepare a kqueue-using event base to receive notifications via an internal
+ * EVFILT_USER event. Return 0 on sucess, -1 on failure.
+ */
+int event_kq_add_notify_event_(struct event_base *base);
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/kqueue.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/kqueue.c
new file mode 100644
index 000000000..a959c58af
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/kqueue.c
@@ -0,0 +1,567 @@
+/* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */
+
+/*
+ * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef EVENT__HAVE_KQUEUE
+
+#include <sys/types.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#include <sys/event.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef EVENT__HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+/* Some platforms apparently define the udata field of struct kevent as
+ * intptr_t, whereas others define it as void*. There doesn't seem to be an
+ * easy way to tell them apart via autoconf, so we need to use OS macros. */
+#if defined(EVENT__HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__) && !defined(__CloudABI__)
+#define PTR_TO_UDATA(x) ((intptr_t)(x))
+#define INT_TO_UDATA(x) ((intptr_t)(x))
+#else
+#define PTR_TO_UDATA(x) (x)
+#define INT_TO_UDATA(x) ((void*)(x))
+#endif
+
+#include "event-internal.h"
+#include "log-internal.h"
+#include "evmap-internal.h"
+#include "event2/thread.h"
+#include "evthread-internal.h"
+#include "changelist-internal.h"
+
+#include "kqueue-internal.h"
+
+#define NEVENT 64
+
+struct kqop {
+ struct kevent *changes;
+ int changes_size;
+
+ struct kevent *events;
+ int events_size;
+ int kq;
+ int notify_event_added;
+ pid_t pid;
+};
+
+static void kqop_free(struct kqop *kqop);
+
+static void *kq_init(struct event_base *);
+static int kq_sig_add(struct event_base *, int, short, short, void *);
+static int kq_sig_del(struct event_base *, int, short, short, void *);
+static int kq_dispatch(struct event_base *, struct timeval *);
+static void kq_dealloc(struct event_base *);
+
+const struct eventop kqops = {
+ "kqueue",
+ kq_init,
+ event_changelist_add_,
+ event_changelist_del_,
+ kq_dispatch,
+ kq_dealloc,
+ 1 /* need reinit */,
+ EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_FDS,
+ EVENT_CHANGELIST_FDINFO_SIZE
+};
+
+static const struct eventop kqsigops = {
+ "kqueue_signal",
+ NULL,
+ kq_sig_add,
+ kq_sig_del,
+ NULL,
+ NULL,
+ 1 /* need reinit */,
+ 0,
+ 0
+};
+
+static void *
+kq_init(struct event_base *base)
+{
+ int kq = -1;
+ struct kqop *kqueueop = NULL;
+
+ if (!(kqueueop = mm_calloc(1, sizeof(struct kqop))))
+ return (NULL);
+
+/* Initialize the kernel queue */
+
+ if ((kq = kqueue()) == -1) {
+ event_warn("kqueue");
+ goto err;
+ }
+
+ kqueueop->kq = kq;
+
+ kqueueop->pid = getpid();
+
+ /* Initialize fields */
+ kqueueop->changes = mm_calloc(NEVENT, sizeof(struct kevent));
+ if (kqueueop->changes == NULL)
+ goto err;
+ kqueueop->events = mm_calloc(NEVENT, sizeof(struct kevent));
+ if (kqueueop->events == NULL)
+ goto err;
+ kqueueop->events_size = kqueueop->changes_size = NEVENT;
+
+ /* Check for Mac OS X kqueue bug. */
+ memset(&kqueueop->changes[0], 0, sizeof kqueueop->changes[0]);
+ kqueueop->changes[0].ident = -1;
+ kqueueop->changes[0].filter = EVFILT_READ;
+ kqueueop->changes[0].flags = EV_ADD;
+ /*
+ * If kqueue works, then kevent will succeed, and it will
+ * stick an error in events[0]. If kqueue is broken, then
+ * kevent will fail.
+ */
+ if (kevent(kq,
+ kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
+ (int)kqueueop->events[0].ident != -1 ||
+ !(kqueueop->events[0].flags & EV_ERROR)) {
+ event_warn("%s: detected broken kqueue; not using.", __func__);
+ goto err;
+ }
+
+ base->evsigsel = &kqsigops;
+
+ return (kqueueop);
+err:
+ if (kqueueop)
+ kqop_free(kqueueop);
+
+ return (NULL);
+}
+
+#define ADD_UDATA 0x30303
+
+static void
+kq_setup_kevent(struct kevent *out, evutil_socket_t fd, int filter, short change)
+{
+ memset(out, 0, sizeof(struct kevent));
+ out->ident = fd;
+ out->filter = filter;
+
+ if (change & EV_CHANGE_ADD) {
+ out->flags = EV_ADD;
+ /* We set a magic number here so that we can tell 'add'
+ * errors from 'del' errors. */
+ out->udata = INT_TO_UDATA(ADD_UDATA);
+ if (change & EV_ET)
+ out->flags |= EV_CLEAR;
+#ifdef NOTE_EOF
+ /* Make it behave like select() and poll() */
+ if (filter == EVFILT_READ)
+ out->fflags = NOTE_EOF;
+#endif
+ } else {
+ EVUTIL_ASSERT(change & EV_CHANGE_DEL);
+ out->flags = EV_DELETE;
+ }
+}
+
+static int
+kq_build_changes_list(const struct event_changelist *changelist,
+ struct kqop *kqop)
+{
+ int i;
+ int n_changes = 0;
+
+ for (i = 0; i < changelist->n_changes; ++i) {
+ struct event_change *in_ch = &changelist->changes[i];
+ struct kevent *out_ch;
+ if (n_changes >= kqop->changes_size - 1) {
+ int newsize = kqop->changes_size * 2;
+ struct kevent *newchanges;
+
+ newchanges = mm_realloc(kqop->changes,
+ newsize * sizeof(struct kevent));
+ if (newchanges == NULL) {
+ event_warn("%s: realloc", __func__);
+ return (-1);
+ }
+ kqop->changes = newchanges;
+ kqop->changes_size = newsize;
+ }
+ if (in_ch->read_change) {
+ out_ch = &kqop->changes[n_changes++];
+ kq_setup_kevent(out_ch, in_ch->fd, EVFILT_READ,
+ in_ch->read_change);
+ }
+ if (in_ch->write_change) {
+ out_ch = &kqop->changes[n_changes++];
+ kq_setup_kevent(out_ch, in_ch->fd, EVFILT_WRITE,
+ in_ch->write_change);
+ }
+ }
+ return n_changes;
+}
+
+static int
+kq_grow_events(struct kqop *kqop, size_t new_size)
+{
+ struct kevent *newresult;
+
+ newresult = mm_realloc(kqop->events,
+ new_size * sizeof(struct kevent));
+
+ if (newresult) {
+ kqop->events = newresult;
+ kqop->events_size = new_size;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+static int
+kq_dispatch(struct event_base *base, struct timeval *tv)
+{
+ struct kqop *kqop = base->evbase;
+ struct kevent *events = kqop->events;
+ struct kevent *changes;
+ struct timespec ts, *ts_p = NULL;
+ int i, n_changes, res;
+
+ if (tv != NULL) {
+ ts.tv_sec = tv->tv_sec;
+ ts.tv_nsec = tv->tv_usec * 1000;
+ ts_p = &ts;
+ }
+
+ /* Build "changes" from "base->changes" */
+ EVUTIL_ASSERT(kqop->changes);
+ n_changes = kq_build_changes_list(&base->changelist, kqop);
+ if (n_changes < 0)
+ return -1;
+
+ event_changelist_remove_all_(&base->changelist, base);
+
+ /* steal the changes array in case some broken code tries to call
+ * dispatch twice at once. */
+ changes = kqop->changes;
+ kqop->changes = NULL;
+
+ /* Make sure that 'events' is at least as long as the list of changes:
+ * otherwise errors in the changes can get reported as a -1 return
+ * value from kevent() rather than as EV_ERROR events in the events
+ * array.
+ *
+ * (We could instead handle -1 return values from kevent() by
+ * retrying with a smaller changes array or a larger events array,
+ * but this approach seems less risky for now.)
+ */
+ if (kqop->events_size < n_changes) {
+ int new_size = kqop->events_size;
+ do {
+ new_size *= 2;
+ } while (new_size < n_changes);
+
+ kq_grow_events(kqop, new_size);
+ events = kqop->events;
+ }
+
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ res = kevent(kqop->kq, changes, n_changes,
+ events, kqop->events_size, ts_p);
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ EVUTIL_ASSERT(kqop->changes == NULL);
+ kqop->changes = changes;
+
+ if (res == -1) {
+ if (errno != EINTR) {
+ event_warn("kevent");
+ return (-1);
+ }
+
+ return (0);
+ }
+
+ event_debug(("%s: kevent reports %d", __func__, res));
+
+ for (i = 0; i < res; i++) {
+ int which = 0;
+
+ if (events[i].flags & EV_ERROR) {
+ switch (events[i].data) {
+
+ /* Can occur on delete if we are not currently
+ * watching any events on this fd. That can
+ * happen when the fd was closed and another
+ * file was opened with that fd. */
+ case ENOENT:
+ /* Can occur for reasons not fully understood
+ * on FreeBSD. */
+ case EINVAL:
+ continue;
+#if defined(__FreeBSD__)
+ /*
+ * This currently occurs if an FD is closed
+ * before the EV_DELETE makes it out via kevent().
+ * The FreeBSD capabilities code sees the blank
+ * capability set and rejects the request to
+ * modify an event.
+ *
+ * To be strictly correct - when an FD is closed,
+ * all the registered events are also removed.
+ * Queuing EV_DELETE to a closed FD is wrong.
+ * The event(s) should just be deleted from
+ * the pending changelist.
+ */
+ case ENOTCAPABLE:
+ continue;
+#endif
+
+ /* Can occur on a delete if the fd is closed. */
+ case EBADF:
+ /* XXXX On NetBSD, we can also get EBADF if we
+ * try to add the write side of a pipe, but
+ * the read side has already been closed.
+ * Other BSDs call this situation 'EPIPE'. It
+ * would be good if we had a way to report
+ * this situation. */
+ continue;
+ /* These two can occur on an add if the fd was one side
+ * of a pipe, and the other side was closed. */
+ case EPERM:
+ case EPIPE:
+ /* Report read events, if we're listening for
+ * them, so that the user can learn about any
+ * add errors. (If the operation was a
+ * delete, then udata should be cleared.) */
+ if (events[i].udata) {
+ /* The operation was an add:
+ * report the error as a read. */
+ which |= EV_READ;
+ break;
+ } else {
+ /* The operation was a del:
+ * report nothing. */
+ continue;
+ }
+
+ /* Other errors shouldn't occur. */
+ default:
+ errno = events[i].data;
+ return (-1);
+ }
+ } else if (events[i].filter == EVFILT_READ) {
+ which |= EV_READ;
+ } else if (events[i].filter == EVFILT_WRITE) {
+ which |= EV_WRITE;
+ } else if (events[i].filter == EVFILT_SIGNAL) {
+ which |= EV_SIGNAL;
+#ifdef EVFILT_USER
+ } else if (events[i].filter == EVFILT_USER) {
+ base->is_notify_pending = 0;
+#endif
+ }
+
+ if (!which)
+ continue;
+
+ if (events[i].filter == EVFILT_SIGNAL) {
+ evmap_signal_active_(base, events[i].ident, 1);
+ } else {
+ evmap_io_active_(base, events[i].ident, which | EV_ET);
+ }
+ }
+
+ if (res == kqop->events_size) {
+ /* We used all the events space that we have. Maybe we should
+ make it bigger. */
+ kq_grow_events(kqop, kqop->events_size * 2);
+ }
+
+ return (0);
+}
+
+static void
+kqop_free(struct kqop *kqop)
+{
+ if (kqop->changes)
+ mm_free(kqop->changes);
+ if (kqop->events)
+ mm_free(kqop->events);
+ if (kqop->kq >= 0 && kqop->pid == getpid())
+ close(kqop->kq);
+ memset(kqop, 0, sizeof(struct kqop));
+ mm_free(kqop);
+}
+
+static void
+kq_dealloc(struct event_base *base)
+{
+ struct kqop *kqop = base->evbase;
+ evsig_dealloc_(base);
+ kqop_free(kqop);
+}
+
+/* signal handling */
+static int
+kq_sig_add(struct event_base *base, int nsignal, short old, short events, void *p)
+{
+ struct kqop *kqop = base->evbase;
+ struct kevent kev;
+ struct timespec timeout = { 0, 0 };
+ (void)p;
+
+ EVUTIL_ASSERT(nsignal >= 0 && nsignal < NSIG);
+
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = nsignal;
+ kev.filter = EVFILT_SIGNAL;
+ kev.flags = EV_ADD;
+
+ /* Be ready for the signal if it is sent any
+ * time between now and the next call to
+ * kq_dispatch. */
+ if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
+ return (-1);
+
+ /* We can set the handler for most signals to SIG_IGN and
+ * still have them reported to us in the queue. However,
+ * if the handler for SIGCHLD is SIG_IGN, the system reaps
+ * zombie processes for us, and we don't get any notification.
+ * This appears to be the only signal with this quirk. */
+ if (evsig_set_handler_(base, nsignal,
+ nsignal == SIGCHLD ? SIG_DFL : SIG_IGN) == -1)
+ return (-1);
+
+ return (0);
+}
+
+static int
+kq_sig_del(struct event_base *base, int nsignal, short old, short events, void *p)
+{
+ struct kqop *kqop = base->evbase;
+ struct kevent kev;
+
+ struct timespec timeout = { 0, 0 };
+ (void)p;
+
+ EVUTIL_ASSERT(nsignal >= 0 && nsignal < NSIG);
+
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = nsignal;
+ kev.filter = EVFILT_SIGNAL;
+ kev.flags = EV_DELETE;
+
+ /* Because we insert signal events
+ * immediately, we need to delete them
+ * immediately, too */
+ if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
+ return (-1);
+
+ if (evsig_restore_handler_(base, nsignal) == -1)
+ return (-1);
+
+ return (0);
+}
+
+
+/* OSX 10.6 and FreeBSD 8.1 add support for EVFILT_USER, which we can use
+ * to wake up the event loop from another thread. */
+
+/* Magic number we use for our filter ID. */
+#define NOTIFY_IDENT 42
+
+int
+event_kq_add_notify_event_(struct event_base *base)
+{
+ struct kqop *kqop = base->evbase;
+#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
+ struct kevent kev;
+ struct timespec timeout = { 0, 0 };
+#endif
+
+ if (kqop->notify_event_added)
+ return 0;
+
+#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = NOTIFY_IDENT;
+ kev.filter = EVFILT_USER;
+ kev.flags = EV_ADD | EV_CLEAR;
+
+ if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) {
+ event_warn("kevent: adding EVFILT_USER event");
+ return -1;
+ }
+
+ kqop->notify_event_added = 1;
+
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+int
+event_kq_notify_base_(struct event_base *base)
+{
+ struct kqop *kqop = base->evbase;
+#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
+ struct kevent kev;
+ struct timespec timeout = { 0, 0 };
+#endif
+ if (! kqop->notify_event_added)
+ return -1;
+
+#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = NOTIFY_IDENT;
+ kev.filter = EVFILT_USER;
+ kev.fflags = NOTE_TRIGGER;
+
+ if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) {
+ event_warn("kevent: triggering EVFILT_USER event");
+ return -1;
+ }
+
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+#endif /* EVENT__HAVE_KQUEUE */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent.pc.in b/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent.pc.in
new file mode 100644
index 000000000..7030884ee
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent.pc.in
@@ -0,0 +1,16 @@
+#libevent pkg-config source file
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libevent
+Description: libevent is an asynchronous notification event loop library
+Version: @VERSION@
+Requires:
+Conflicts:
+Libs: -L${libdir} -levent
+Libs.private: @LIBS@
+Cflags: -I${includedir}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_core.pc.in b/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_core.pc.in
new file mode 100644
index 000000000..98ab1efe7
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_core.pc.in
@@ -0,0 +1,16 @@
+#libevent pkg-config source file
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libevent_core
+Description: libevent_core
+Version: @VERSION@
+Requires:
+Conflicts:
+Libs: -L${libdir} -levent_core
+Libs.private: @LIBS@
+Cflags: -I${includedir}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_extra.pc.in b/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_extra.pc.in
new file mode 100644
index 000000000..b9633998d
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_extra.pc.in
@@ -0,0 +1,16 @@
+#libevent pkg-config source file
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libevent_extra
+Description: libevent_extra
+Version: @VERSION@
+Requires:
+Conflicts:
+Libs: -L${libdir} -levent_extra
+Libs.private: @LIBS@
+Cflags: -I${includedir}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_openssl.pc.in b/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_openssl.pc.in
new file mode 100644
index 000000000..a65d1e066
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_openssl.pc.in
@@ -0,0 +1,16 @@
+#libevent pkg-config source file
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libevent_openssl
+Description: libevent_openssl adds openssl-based TLS support to libevent
+Version: @VERSION@
+Requires: libevent
+Conflicts:
+Libs: -L${libdir} -levent_openssl
+Libs.private: @LIBS@ @OPENSSL_LIBS@
+Cflags: -I${includedir} @OPENSSL_INCS@
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_pthreads.pc.in b/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_pthreads.pc.in
new file mode 100644
index 000000000..9bc2392b3
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/libevent_pthreads.pc.in
@@ -0,0 +1,16 @@
+#libevent pkg-config source file
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libevent_pthreads
+Description: libevent_pthreads adds pthreads-based threading support to libevent
+Version: @VERSION@
+Requires: libevent
+Conflicts:
+Libs: -L${libdir} -levent_pthreads
+Libs.private: @LIBS@ @PTHREAD_LIBS@
+Cflags: -I${includedir} @PTHREAD_CFLAGS@
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/listener.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/listener.c
new file mode 100644
index 000000000..2862d32e3
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/listener.c
@@ -0,0 +1,890 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
+
+#ifdef _WIN32
+#ifndef _WIN32_WINNT
+/* Minimum required for InitializeCriticalSectionAndSpinCount */
+#define _WIN32_WINNT 0x0403
+#endif
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <mswsock.h>
+#endif
+#include <errno.h>
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef EVENT__HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "event2/listener.h"
+#include "event2/util.h"
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "mm-internal.h"
+#include "util-internal.h"
+#include "log-internal.h"
+#include "evthread-internal.h"
+#ifdef _WIN32
+#include "iocp-internal.h"
+#include "defer-internal.h"
+#include "event-internal.h"
+#endif
+
+struct evconnlistener_ops {
+ int (*enable)(struct evconnlistener *);
+ int (*disable)(struct evconnlistener *);
+ void (*destroy)(struct evconnlistener *);
+ void (*shutdown)(struct evconnlistener *);
+ evutil_socket_t (*getfd)(struct evconnlistener *);
+ struct event_base *(*getbase)(struct evconnlistener *);
+};
+
+struct evconnlistener {
+ const struct evconnlistener_ops *ops;
+ void *lock;
+ evconnlistener_cb cb;
+ evconnlistener_errorcb errorcb;
+ void *user_data;
+ unsigned flags;
+ short refcnt;
+ int accept4_flags;
+ unsigned enabled : 1;
+};
+
+struct evconnlistener_event {
+ struct evconnlistener base;
+ struct event listener;
+};
+
+#ifdef _WIN32
+struct evconnlistener_iocp {
+ struct evconnlistener base;
+ evutil_socket_t fd;
+ struct event_base *event_base;
+ struct event_iocp_port *port;
+ short n_accepting;
+ unsigned shutting_down : 1;
+ unsigned event_added : 1;
+ struct accepting_socket **accepting;
+};
+#endif
+
+#define LOCK(listener) EVLOCK_LOCK((listener)->lock, 0)
+#define UNLOCK(listener) EVLOCK_UNLOCK((listener)->lock, 0)
+
+struct evconnlistener *
+evconnlistener_new_async(struct event_base *base,
+ evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
+ evutil_socket_t fd); /* XXXX export this? */
+
+static int event_listener_enable(struct evconnlistener *);
+static int event_listener_disable(struct evconnlistener *);
+static void event_listener_destroy(struct evconnlistener *);
+static evutil_socket_t event_listener_getfd(struct evconnlistener *);
+static struct event_base *event_listener_getbase(struct evconnlistener *);
+
+#if 0
+static void
+listener_incref_and_lock(struct evconnlistener *listener)
+{
+ LOCK(listener);
+ ++listener->refcnt;
+}
+#endif
+
+static int
+listener_decref_and_unlock(struct evconnlistener *listener)
+{
+ int refcnt = --listener->refcnt;
+ if (refcnt == 0) {
+ listener->ops->destroy(listener);
+ UNLOCK(listener);
+ EVTHREAD_FREE_LOCK(listener->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ mm_free(listener);
+ return 1;
+ } else {
+ UNLOCK(listener);
+ return 0;
+ }
+}
+
+static const struct evconnlistener_ops evconnlistener_event_ops = {
+ event_listener_enable,
+ event_listener_disable,
+ event_listener_destroy,
+ NULL, /* shutdown */
+ event_listener_getfd,
+ event_listener_getbase
+};
+
+static void listener_read_cb(evutil_socket_t, short, void *);
+
+struct evconnlistener *
+evconnlistener_new(struct event_base *base,
+ evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
+ evutil_socket_t fd)
+{
+ struct evconnlistener_event *lev;
+
+#ifdef _WIN32
+ if (base && event_base_get_iocp_(base)) {
+ const struct win32_extension_fns *ext =
+ event_get_win32_extension_fns_();
+ if (ext->AcceptEx && ext->GetAcceptExSockaddrs)
+ return evconnlistener_new_async(base, cb, ptr, flags,
+ backlog, fd);
+ }
+#endif
+
+ if (backlog > 0) {
+ if (listen(fd, backlog) < 0)
+ return NULL;
+ } else if (backlog < 0) {
+ if (listen(fd, 128) < 0)
+ return NULL;
+ }
+
+ lev = mm_calloc(1, sizeof(struct evconnlistener_event));
+ if (!lev)
+ return NULL;
+
+ lev->base.ops = &evconnlistener_event_ops;
+ lev->base.cb = cb;
+ lev->base.user_data = ptr;
+ lev->base.flags = flags;
+ lev->base.refcnt = 1;
+
+ lev->base.accept4_flags = 0;
+ if (!(flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
+ lev->base.accept4_flags |= EVUTIL_SOCK_NONBLOCK;
+ if (flags & LEV_OPT_CLOSE_ON_EXEC)
+ lev->base.accept4_flags |= EVUTIL_SOCK_CLOEXEC;
+
+ if (flags & LEV_OPT_THREADSAFE) {
+ EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ }
+
+ event_assign(&lev->listener, base, fd, EV_READ|EV_PERSIST,
+ listener_read_cb, lev);
+
+ if (!(flags & LEV_OPT_DISABLED))
+ evconnlistener_enable(&lev->base);
+
+ return &lev->base;
+}
+
+struct evconnlistener *
+evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,
+ void *ptr, unsigned flags, int backlog, const struct sockaddr *sa,
+ int socklen)
+{
+ struct evconnlistener *listener;
+ evutil_socket_t fd;
+ int on = 1;
+ int family = sa ? sa->sa_family : AF_UNSPEC;
+ int socktype = SOCK_STREAM | EVUTIL_SOCK_NONBLOCK;
+
+ if (backlog == 0)
+ return NULL;
+
+ if (flags & LEV_OPT_CLOSE_ON_EXEC)
+ socktype |= EVUTIL_SOCK_CLOEXEC;
+
+ fd = evutil_socket_(family, socktype, 0);
+ if (fd == -1)
+ return NULL;
+
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))<0)
+ goto err;
+
+ if (flags & LEV_OPT_REUSEABLE) {
+ if (evutil_make_listen_socket_reuseable(fd) < 0)
+ goto err;
+ }
+
+ if (flags & LEV_OPT_REUSEABLE_PORT) {
+ if (evutil_make_listen_socket_reuseable_port(fd) < 0)
+ goto err;
+ }
+
+ if (flags & LEV_OPT_DEFERRED_ACCEPT) {
+ if (evutil_make_tcp_listen_socket_deferred(fd) < 0)
+ goto err;
+ }
+
+ if (sa) {
+ if (bind(fd, sa, socklen)<0)
+ goto err;
+ }
+
+ listener = evconnlistener_new(base, cb, ptr, flags, backlog, fd);
+ if (!listener)
+ goto err;
+
+ return listener;
+err:
+ evutil_closesocket(fd);
+ return NULL;
+}
+
+void
+evconnlistener_free(struct evconnlistener *lev)
+{
+ LOCK(lev);
+ lev->cb = NULL;
+ lev->errorcb = NULL;
+ if (lev->ops->shutdown)
+ lev->ops->shutdown(lev);
+ listener_decref_and_unlock(lev);
+}
+
+static void
+event_listener_destroy(struct evconnlistener *lev)
+{
+ struct evconnlistener_event *lev_e =
+ EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
+
+ event_del(&lev_e->listener);
+ if (lev->flags & LEV_OPT_CLOSE_ON_FREE)
+ evutil_closesocket(event_get_fd(&lev_e->listener));
+ event_debug_unassign(&lev_e->listener);
+}
+
+int
+evconnlistener_enable(struct evconnlistener *lev)
+{
+ int r;
+ LOCK(lev);
+ lev->enabled = 1;
+ if (lev->cb)
+ r = lev->ops->enable(lev);
+ else
+ r = 0;
+ UNLOCK(lev);
+ return r;
+}
+
+int
+evconnlistener_disable(struct evconnlistener *lev)
+{
+ int r;
+ LOCK(lev);
+ lev->enabled = 0;
+ r = lev->ops->disable(lev);
+ UNLOCK(lev);
+ return r;
+}
+
+static int
+event_listener_enable(struct evconnlistener *lev)
+{
+ struct evconnlistener_event *lev_e =
+ EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
+ return event_add(&lev_e->listener, NULL);
+}
+
+static int
+event_listener_disable(struct evconnlistener *lev)
+{
+ struct evconnlistener_event *lev_e =
+ EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
+ return event_del(&lev_e->listener);
+}
+
+evutil_socket_t
+evconnlistener_get_fd(struct evconnlistener *lev)
+{
+ evutil_socket_t fd;
+ LOCK(lev);
+ fd = lev->ops->getfd(lev);
+ UNLOCK(lev);
+ return fd;
+}
+
+static evutil_socket_t
+event_listener_getfd(struct evconnlistener *lev)
+{
+ struct evconnlistener_event *lev_e =
+ EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
+ return event_get_fd(&lev_e->listener);
+}
+
+struct event_base *
+evconnlistener_get_base(struct evconnlistener *lev)
+{
+ struct event_base *base;
+ LOCK(lev);
+ base = lev->ops->getbase(lev);
+ UNLOCK(lev);
+ return base;
+}
+
+static struct event_base *
+event_listener_getbase(struct evconnlistener *lev)
+{
+ struct evconnlistener_event *lev_e =
+ EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
+ return event_get_base(&lev_e->listener);
+}
+
+void
+evconnlistener_set_cb(struct evconnlistener *lev,
+ evconnlistener_cb cb, void *arg)
+{
+ int enable = 0;
+ LOCK(lev);
+ if (lev->enabled && !lev->cb)
+ enable = 1;
+ lev->cb = cb;
+ lev->user_data = arg;
+ if (enable)
+ evconnlistener_enable(lev);
+ UNLOCK(lev);
+}
+
+void
+evconnlistener_set_error_cb(struct evconnlistener *lev,
+ evconnlistener_errorcb errorcb)
+{
+ LOCK(lev);
+ lev->errorcb = errorcb;
+ UNLOCK(lev);
+}
+
+static void
+listener_read_cb(evutil_socket_t fd, short what, void *p)
+{
+ struct evconnlistener *lev = p;
+ int err;
+ evconnlistener_cb cb;
+ evconnlistener_errorcb errorcb;
+ void *user_data;
+ LOCK(lev);
+ while (1) {
+ struct sockaddr_storage ss;
+ ev_socklen_t socklen = sizeof(ss);
+ evutil_socket_t new_fd = evutil_accept4_(fd, (struct sockaddr*)&ss, &socklen, lev->accept4_flags);
+ if (new_fd < 0)
+ break;
+ if (socklen == 0) {
+ /* This can happen with some older linux kernels in
+ * response to nmap. */
+ evutil_closesocket(new_fd);
+ continue;
+ }
+
+ if (lev->cb == NULL) {
+ evutil_closesocket(new_fd);
+ UNLOCK(lev);
+ return;
+ }
+ ++lev->refcnt;
+ cb = lev->cb;
+ user_data = lev->user_data;
+ UNLOCK(lev);
+ cb(lev, new_fd, (struct sockaddr*)&ss, (int)socklen,
+ user_data);
+ LOCK(lev);
+ if (lev->refcnt == 1) {
+ int freed = listener_decref_and_unlock(lev);
+ EVUTIL_ASSERT(freed);
+
+ evutil_closesocket(new_fd);
+ return;
+ }
+ --lev->refcnt;
+ }
+ err = evutil_socket_geterror(fd);
+ if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) {
+ UNLOCK(lev);
+ return;
+ }
+ if (lev->errorcb != NULL) {
+ ++lev->refcnt;
+ errorcb = lev->errorcb;
+ user_data = lev->user_data;
+ UNLOCK(lev);
+ errorcb(lev, user_data);
+ LOCK(lev);
+ listener_decref_and_unlock(lev);
+ } else {
+ event_sock_warn(fd, "Error from accept() call");
+ UNLOCK(lev);
+ }
+}
+
+#ifdef _WIN32
+struct accepting_socket {
+ CRITICAL_SECTION lock;
+ struct event_overlapped overlapped;
+ SOCKET s;
+ int error;
+ struct event_callback deferred;
+ struct evconnlistener_iocp *lev;
+ ev_uint8_t buflen;
+ ev_uint8_t family;
+ unsigned free_on_cb:1;
+ char addrbuf[1];
+};
+
+static void accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key,
+ ev_ssize_t n, int ok);
+static void accepted_socket_invoke_user_cb(struct event_callback *cb, void *arg);
+
+static void
+iocp_listener_event_add(struct evconnlistener_iocp *lev)
+{
+ if (lev->event_added)
+ return;
+
+ lev->event_added = 1;
+ event_base_add_virtual_(lev->event_base);
+}
+
+static void
+iocp_listener_event_del(struct evconnlistener_iocp *lev)
+{
+ if (!lev->event_added)
+ return;
+
+ lev->event_added = 0;
+ event_base_del_virtual_(lev->event_base);
+}
+
+static struct accepting_socket *
+new_accepting_socket(struct evconnlistener_iocp *lev, int family)
+{
+ struct accepting_socket *res;
+ int addrlen;
+ int buflen;
+
+ if (family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return NULL;
+ buflen = (addrlen+16)*2;
+
+ res = mm_calloc(1,sizeof(struct accepting_socket)-1+buflen);
+ if (!res)
+ return NULL;
+
+ event_overlapped_init_(&res->overlapped, accepted_socket_cb);
+ res->s = INVALID_SOCKET;
+ res->lev = lev;
+ res->buflen = buflen;
+ res->family = family;
+
+ event_deferred_cb_init_(&res->deferred,
+ event_base_get_npriorities(lev->event_base) / 2,
+ accepted_socket_invoke_user_cb, res);
+
+ InitializeCriticalSectionAndSpinCount(&res->lock, 1000);
+
+ return res;
+}
+
+static void
+free_and_unlock_accepting_socket(struct accepting_socket *as)
+{
+ /* requires lock. */
+ if (as->s != INVALID_SOCKET)
+ closesocket(as->s);
+
+ LeaveCriticalSection(&as->lock);
+ DeleteCriticalSection(&as->lock);
+ mm_free(as);
+}
+
+static int
+start_accepting(struct accepting_socket *as)
+{
+ /* requires lock */
+ const struct win32_extension_fns *ext = event_get_win32_extension_fns_();
+ DWORD pending = 0;
+ SOCKET s = socket(as->family, SOCK_STREAM, 0);
+ int error = 0;
+
+ if (!as->lev->base.enabled)
+ return 0;
+
+ if (s == INVALID_SOCKET) {
+ error = WSAGetLastError();
+ goto report_err;
+ }
+
+ /* XXXX It turns out we need to do this again later. Does this call
+ * have any effect? */
+ setsockopt(s, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+ (char *)&as->lev->fd, sizeof(&as->lev->fd));
+
+ if (!(as->lev->base.flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
+ evutil_make_socket_nonblocking(s);
+
+ if (event_iocp_port_associate_(as->lev->port, s, 1) < 0) {
+ closesocket(s);
+ return -1;
+ }
+
+ as->s = s;
+
+ if (ext->AcceptEx(as->lev->fd, s, as->addrbuf, 0,
+ as->buflen/2, as->buflen/2, &pending, &as->overlapped.overlapped))
+ {
+ /* Immediate success! */
+ accepted_socket_cb(&as->overlapped, 1, 0, 1);
+ } else {
+ error = WSAGetLastError();
+ if (error != ERROR_IO_PENDING) {
+ goto report_err;
+ }
+ }
+
+ return 0;
+
+report_err:
+ as->error = error;
+ event_deferred_cb_schedule_(
+ as->lev->event_base,
+ &as->deferred);
+ return 0;
+}
+
+static void
+stop_accepting(struct accepting_socket *as)
+{
+ /* requires lock. */
+ SOCKET s = as->s;
+ as->s = INVALID_SOCKET;
+ closesocket(s);
+}
+
+static void
+accepted_socket_invoke_user_cb(struct event_callback *dcb, void *arg)
+{
+ struct accepting_socket *as = arg;
+
+ struct sockaddr *sa_local=NULL, *sa_remote=NULL;
+ int socklen_local=0, socklen_remote=0;
+ const struct win32_extension_fns *ext = event_get_win32_extension_fns_();
+ struct evconnlistener *lev = &as->lev->base;
+ evutil_socket_t sock=-1;
+ void *data;
+ evconnlistener_cb cb=NULL;
+ evconnlistener_errorcb errorcb=NULL;
+ int error;
+
+ EVUTIL_ASSERT(ext->GetAcceptExSockaddrs);
+
+ LOCK(lev);
+ EnterCriticalSection(&as->lock);
+ if (as->free_on_cb) {
+ free_and_unlock_accepting_socket(as);
+ listener_decref_and_unlock(lev);
+ return;
+ }
+
+ ++lev->refcnt;
+
+ error = as->error;
+ if (error) {
+ as->error = 0;
+ errorcb = lev->errorcb;
+ } else {
+ ext->GetAcceptExSockaddrs(
+ as->addrbuf, 0, as->buflen/2, as->buflen/2,
+ &sa_local, &socklen_local, &sa_remote,
+ &socklen_remote);
+ sock = as->s;
+ cb = lev->cb;
+ as->s = INVALID_SOCKET;
+
+ /* We need to call this so getsockname, getpeername, and
+ * shutdown work correctly on the accepted socket. */
+ /* XXXX handle error? */
+ setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+ (char *)&as->lev->fd, sizeof(&as->lev->fd));
+ }
+ data = lev->user_data;
+
+ LeaveCriticalSection(&as->lock);
+ UNLOCK(lev);
+
+ if (errorcb) {
+ WSASetLastError(error);
+ errorcb(lev, data);
+ } else if (cb) {
+ cb(lev, sock, sa_remote, socklen_remote, data);
+ }
+
+ LOCK(lev);
+ if (listener_decref_and_unlock(lev))
+ return;
+
+ EnterCriticalSection(&as->lock);
+ start_accepting(as);
+ LeaveCriticalSection(&as->lock);
+}
+
+static void
+accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key, ev_ssize_t n, int ok)
+{
+ struct accepting_socket *as =
+ EVUTIL_UPCAST(o, struct accepting_socket, overlapped);
+
+ LOCK(&as->lev->base);
+ EnterCriticalSection(&as->lock);
+ if (ok) {
+ /* XXXX Don't do this if some EV_MT flag is set. */
+ event_deferred_cb_schedule_(
+ as->lev->event_base,
+ &as->deferred);
+ LeaveCriticalSection(&as->lock);
+ } else if (as->free_on_cb) {
+ struct evconnlistener *lev = &as->lev->base;
+ free_and_unlock_accepting_socket(as);
+ listener_decref_and_unlock(lev);
+ return;
+ } else if (as->s == INVALID_SOCKET) {
+ /* This is okay; we were disabled by iocp_listener_disable. */
+ LeaveCriticalSection(&as->lock);
+ } else {
+ /* Some error on accept that we couldn't actually handle. */
+ BOOL ok;
+ DWORD transfer = 0, flags=0;
+ event_sock_warn(as->s, "Unexpected error on AcceptEx");
+ ok = WSAGetOverlappedResult(as->s, &o->overlapped,
+ &transfer, FALSE, &flags);
+ if (ok) {
+ /* well, that was confusing! */
+ as->error = 1;
+ } else {
+ as->error = WSAGetLastError();
+ }
+ event_deferred_cb_schedule_(
+ as->lev->event_base,
+ &as->deferred);
+ LeaveCriticalSection(&as->lock);
+ }
+ UNLOCK(&as->lev->base);
+}
+
+static int
+iocp_listener_enable(struct evconnlistener *lev)
+{
+ int i;
+ struct evconnlistener_iocp *lev_iocp =
+ EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
+
+ LOCK(lev);
+ iocp_listener_event_add(lev_iocp);
+ for (i = 0; i < lev_iocp->n_accepting; ++i) {
+ struct accepting_socket *as = lev_iocp->accepting[i];
+ if (!as)
+ continue;
+ EnterCriticalSection(&as->lock);
+ if (!as->free_on_cb && as->s == INVALID_SOCKET)
+ start_accepting(as);
+ LeaveCriticalSection(&as->lock);
+ }
+ UNLOCK(lev);
+ return 0;
+}
+
+static int
+iocp_listener_disable_impl(struct evconnlistener *lev, int shutdown)
+{
+ int i;
+ struct evconnlistener_iocp *lev_iocp =
+ EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
+
+ LOCK(lev);
+ iocp_listener_event_del(lev_iocp);
+ for (i = 0; i < lev_iocp->n_accepting; ++i) {
+ struct accepting_socket *as = lev_iocp->accepting[i];
+ if (!as)
+ continue;
+ EnterCriticalSection(&as->lock);
+ if (!as->free_on_cb && as->s != INVALID_SOCKET) {
+ if (shutdown)
+ as->free_on_cb = 1;
+ stop_accepting(as);
+ }
+ LeaveCriticalSection(&as->lock);
+ }
+
+ if (shutdown && lev->flags & LEV_OPT_CLOSE_ON_FREE)
+ evutil_closesocket(lev_iocp->fd);
+
+ UNLOCK(lev);
+ return 0;
+}
+
+static int
+iocp_listener_disable(struct evconnlistener *lev)
+{
+ return iocp_listener_disable_impl(lev,0);
+}
+
+static void
+iocp_listener_destroy(struct evconnlistener *lev)
+{
+ struct evconnlistener_iocp *lev_iocp =
+ EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
+
+ if (! lev_iocp->shutting_down) {
+ lev_iocp->shutting_down = 1;
+ iocp_listener_disable_impl(lev,1);
+ }
+
+}
+
+static evutil_socket_t
+iocp_listener_getfd(struct evconnlistener *lev)
+{
+ struct evconnlistener_iocp *lev_iocp =
+ EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
+ return lev_iocp->fd;
+}
+static struct event_base *
+iocp_listener_getbase(struct evconnlistener *lev)
+{
+ struct evconnlistener_iocp *lev_iocp =
+ EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
+ return lev_iocp->event_base;
+}
+
+static const struct evconnlistener_ops evconnlistener_iocp_ops = {
+ iocp_listener_enable,
+ iocp_listener_disable,
+ iocp_listener_destroy,
+ iocp_listener_destroy, /* shutdown */
+ iocp_listener_getfd,
+ iocp_listener_getbase
+};
+
+/* XXX define some way to override this. */
+#define N_SOCKETS_PER_LISTENER 4
+
+struct evconnlistener *
+evconnlistener_new_async(struct event_base *base,
+ evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
+ evutil_socket_t fd)
+{
+ struct sockaddr_storage ss;
+ int socklen = sizeof(ss);
+ struct evconnlistener_iocp *lev;
+ int i;
+
+ flags |= LEV_OPT_THREADSAFE;
+
+ if (!base || !event_base_get_iocp_(base))
+ goto err;
+
+ /* XXXX duplicate code */
+ if (backlog > 0) {
+ if (listen(fd, backlog) < 0)
+ goto err;
+ } else if (backlog < 0) {
+ if (listen(fd, 128) < 0)
+ goto err;
+ }
+ if (getsockname(fd, (struct sockaddr*)&ss, &socklen)) {
+ event_sock_warn(fd, "getsockname");
+ goto err;
+ }
+ lev = mm_calloc(1, sizeof(struct evconnlistener_iocp));
+ if (!lev) {
+ event_warn("calloc");
+ goto err;
+ }
+ lev->base.ops = &evconnlistener_iocp_ops;
+ lev->base.cb = cb;
+ lev->base.user_data = ptr;
+ lev->base.flags = flags;
+ lev->base.refcnt = 1;
+ lev->base.enabled = 1;
+
+ lev->port = event_base_get_iocp_(base);
+ lev->fd = fd;
+ lev->event_base = base;
+
+
+ if (event_iocp_port_associate_(lev->port, fd, 1) < 0)
+ goto err_free_lev;
+
+ EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+
+ lev->n_accepting = N_SOCKETS_PER_LISTENER;
+ lev->accepting = mm_calloc(lev->n_accepting,
+ sizeof(struct accepting_socket *));
+ if (!lev->accepting) {
+ event_warn("calloc");
+ goto err_delete_lock;
+ }
+ for (i = 0; i < lev->n_accepting; ++i) {
+ lev->accepting[i] = new_accepting_socket(lev, ss.ss_family);
+ if (!lev->accepting[i]) {
+ event_warnx("Couldn't create accepting socket");
+ goto err_free_accepting;
+ }
+ if (cb && start_accepting(lev->accepting[i]) < 0) {
+ event_warnx("Couldn't start accepting on socket");
+ EnterCriticalSection(&lev->accepting[i]->lock);
+ free_and_unlock_accepting_socket(lev->accepting[i]);
+ goto err_free_accepting;
+ }
+ ++lev->base.refcnt;
+ }
+
+ iocp_listener_event_add(lev);
+
+ return &lev->base;
+
+err_free_accepting:
+ mm_free(lev->accepting);
+ /* XXXX free the other elements. */
+err_delete_lock:
+ EVTHREAD_FREE_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+err_free_lev:
+ mm_free(lev);
+err:
+ /* Don't close the fd, it is caller's responsibility. */
+ return NULL;
+}
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/log-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/log-internal.h
new file mode 100644
index 000000000..330478a9e
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/log-internal.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef LOG_INTERNAL_H_INCLUDED_
+#define LOG_INTERNAL_H_INCLUDED_
+
+#include "event2/util.h"
+
+#ifdef __GNUC__
+#define EV_CHECK_FMT(a,b) __attribute__((format(printf, a, b)))
+#define EV_NORETURN __attribute__((noreturn))
+#else
+#define EV_CHECK_FMT(a,b)
+#define EV_NORETURN
+#endif
+
+#define EVENT_ERR_ABORT_ ((int)0xdeaddead)
+
+#define USE_GLOBAL_FOR_DEBUG_LOGGING
+
+#if !defined(EVENT__DISABLE_DEBUG_MODE) || defined(USE_DEBUG)
+#define EVENT_DEBUG_LOGGING_ENABLED
+#endif
+
+#ifdef EVENT_DEBUG_LOGGING_ENABLED
+#ifdef USE_GLOBAL_FOR_DEBUG_LOGGING
+extern ev_uint32_t event_debug_logging_mask_;
+#define event_debug_get_logging_mask_() (event_debug_logging_mask_)
+#else
+ev_uint32_t event_debug_get_logging_mask_(void);
+#endif
+#else
+#define event_debug_get_logging_mask_() (0)
+#endif
+
+void event_err(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3) EV_NORETURN;
+void event_warn(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void event_sock_err(int eval, evutil_socket_t sock, const char *fmt, ...) EV_CHECK_FMT(3,4) EV_NORETURN;
+void event_sock_warn(evutil_socket_t sock, const char *fmt, ...) EV_CHECK_FMT(2,3);
+void event_errx(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3) EV_NORETURN;
+void event_warnx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void event_msgx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void event_debugx_(const char *fmt, ...) EV_CHECK_FMT(1,2);
+
+void event_logv_(int severity, const char *errstr, const char *fmt, va_list ap)
+ EV_CHECK_FMT(3,0);
+
+#ifdef EVENT_DEBUG_LOGGING_ENABLED
+#define event_debug(x) do { \
+ if (event_debug_get_logging_mask_()) { \
+ event_debugx_ x; \
+ } \
+ } while (0)
+#else
+#define event_debug(x) ((void)0)
+#endif
+
+#undef EV_CHECK_FMT
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/log.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/log.c
new file mode 100644
index 000000000..e8ae9fdc3
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/log.c
@@ -0,0 +1,253 @@
+/* $OpenBSD: err.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
+
+/*
+ * log.c
+ *
+ * Based on err.c, which was adapted from OpenBSD libc *err* *warn* code.
+ *
+ * Copyright (c) 2005-2012 Niels Provos and Nick Mathewson
+ *
+ * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
+ *
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include "event2/event.h"
+#include "event2/util.h"
+
+#include "log-internal.h"
+
+static void event_log(int severity, const char *msg);
+static void event_exit(int errcode) EV_NORETURN;
+
+static event_fatal_cb fatal_fn = NULL;
+
+#ifdef EVENT_DEBUG_LOGGING_ENABLED
+#ifdef USE_DEBUG
+#define DEFAULT_MASK EVENT_DBG_ALL
+#else
+#define DEFAULT_MASK 0
+#endif
+
+#ifdef USE_GLOBAL_FOR_DEBUG_LOGGING
+ev_uint32_t event_debug_logging_mask_ = DEFAULT_MASK;
+#else
+static ev_uint32_t event_debug_logging_mask_ = DEFAULT_MASK;
+ev_uint32_t
+event_debug_get_logging_mask_(void)
+{
+ return event_debug_logging_mask_;
+}
+#endif
+#endif /* EVENT_DEBUG_LOGGING_ENABLED */
+
+void
+event_enable_debug_logging(ev_uint32_t which)
+{
+#ifdef EVENT_DEBUG_LOGGING_ENABLED
+ event_debug_logging_mask_ = which;
+#endif
+}
+
+void
+event_set_fatal_callback(event_fatal_cb cb)
+{
+ fatal_fn = cb;
+}
+
+static void
+event_exit(int errcode)
+{
+ if (fatal_fn) {
+ fatal_fn(errcode);
+ exit(errcode); /* should never be reached */
+ } else if (errcode == EVENT_ERR_ABORT_)
+ abort();
+ else
+ exit(errcode);
+}
+
+void
+event_err(int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ event_logv_(EVENT_LOG_ERR, strerror(errno), fmt, ap);
+ va_end(ap);
+ event_exit(eval);
+}
+
+void
+event_warn(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ event_logv_(EVENT_LOG_WARN, strerror(errno), fmt, ap);
+ va_end(ap);
+}
+
+void
+event_sock_err(int eval, evutil_socket_t sock, const char *fmt, ...)
+{
+ va_list ap;
+ int err = evutil_socket_geterror(sock);
+
+ va_start(ap, fmt);
+ event_logv_(EVENT_LOG_ERR, evutil_socket_error_to_string(err), fmt, ap);
+ va_end(ap);
+ event_exit(eval);
+}
+
+void
+event_sock_warn(evutil_socket_t sock, const char *fmt, ...)
+{
+ va_list ap;
+ int err = evutil_socket_geterror(sock);
+
+ va_start(ap, fmt);
+ event_logv_(EVENT_LOG_WARN, evutil_socket_error_to_string(err), fmt, ap);
+ va_end(ap);
+}
+
+void
+event_errx(int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ event_logv_(EVENT_LOG_ERR, NULL, fmt, ap);
+ va_end(ap);
+ event_exit(eval);
+}
+
+void
+event_warnx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ event_logv_(EVENT_LOG_WARN, NULL, fmt, ap);
+ va_end(ap);
+}
+
+void
+event_msgx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ event_logv_(EVENT_LOG_MSG, NULL, fmt, ap);
+ va_end(ap);
+}
+
+void
+event_debugx_(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ event_logv_(EVENT_LOG_DEBUG, NULL, fmt, ap);
+ va_end(ap);
+}
+
+void
+event_logv_(int severity, const char *errstr, const char *fmt, va_list ap)
+{
+ char buf[1024];
+ size_t len;
+
+ if (severity == EVENT_LOG_DEBUG && !event_debug_get_logging_mask_())
+ return;
+
+ if (fmt != NULL)
+ evutil_vsnprintf(buf, sizeof(buf), fmt, ap);
+ else
+ buf[0] = '\0';
+
+ if (errstr) {
+ len = strlen(buf);
+ if (len < sizeof(buf) - 3) {
+ evutil_snprintf(buf + len, sizeof(buf) - len, ": %s", errstr);
+ }
+ }
+
+ event_log(severity, buf);
+}
+
+static event_log_cb log_fn = NULL;
+
+void
+event_set_log_callback(event_log_cb cb)
+{
+ log_fn = cb;
+}
+
+static void
+event_log(int severity, const char *msg)
+{
+ if (log_fn)
+ log_fn(severity, msg);
+ else {
+ const char *severity_str;
+ switch (severity) {
+ case EVENT_LOG_DEBUG:
+ severity_str = "debug";
+ break;
+ case EVENT_LOG_MSG:
+ severity_str = "msg";
+ break;
+ case EVENT_LOG_WARN:
+ severity_str = "warn";
+ break;
+ case EVENT_LOG_ERR:
+ severity_str = "err";
+ break;
+ default:
+ severity_str = "???";
+ break;
+ }
+ (void)fprintf(stderr, "[%s] %s\n", severity_str, msg);
+ }
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/m4/ac_backport_259_ssizet.m4 b/fluent-bit/lib/monkey/mk_core/deps/libevent/m4/ac_backport_259_ssizet.m4
new file mode 100644
index 000000000..75fde386c
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/m4/ac_backport_259_ssizet.m4
@@ -0,0 +1,3 @@
+AN_IDENTIFIER([ssize_t], [AC_TYPE_SSIZE_T])
+AC_DEFUN([AC_TYPE_SSIZE_T], [AC_CHECK_TYPE(ssize_t, int)])
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/m4/acx_pthread.m4 b/fluent-bit/lib/monkey/mk_core/deps/libevent/m4/acx_pthread.m4
new file mode 100644
index 000000000..d2b116945
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/m4/acx_pthread.m4
@@ -0,0 +1,279 @@
+##### http://autoconf-archive.cryp.to/acx_pthread.html
+#
+# SYNOPSIS
+#
+# ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+#
+# DESCRIPTION
+#
+# This macro figures out how to build C programs using POSIX threads.
+# It sets the PTHREAD_LIBS output variable to the threads library and
+# linker flags, and the PTHREAD_CFLAGS output variable to any special
+# C compiler flags that are needed. (The user can also force certain
+# compiler flags/libs to be tested by setting these environment
+# variables.)
+#
+# Also sets PTHREAD_CC to any special C compiler that is needed for
+# multi-threaded programs (defaults to the value of CC otherwise).
+# (This is necessary on AIX to use the special cc_r compiler alias.)
+#
+# NOTE: You are assumed to not only compile your program with these
+# flags, but also link it with them as well. e.g. you should link
+# with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
+# $LIBS
+#
+# If you are only building threads programs, you may wish to use
+# these variables in your default LIBS, CFLAGS, and CC:
+#
+# LIBS="$PTHREAD_LIBS $LIBS"
+# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+# CC="$PTHREAD_CC"
+#
+# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
+# constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
+# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#
+# ACTION-IF-FOUND is a list of shell commands to run if a threads
+# library is found, and ACTION-IF-NOT-FOUND is a list of commands to
+# run it if it is not found. If ACTION-IF-FOUND is not specified, the
+# default action will define HAVE_PTHREAD.
+#
+# Please let the authors know if this macro fails on any platform, or
+# if you have any other suggestions or comments. This macro was based
+# on work by SGJ on autoconf scripts for FFTW (http://www.fftw.org/)
+# (with help from M. Frigo), as well as ac_pthread and hb_pthread
+# macros posted by Alejandro Forero Cuervo to the autoconf macro
+# repository. We are also grateful for the helpful feedback of
+# numerous users.
+#
+# LAST MODIFICATION
+#
+# 2007-07-29
+#
+# COPYLEFT
+#
+# Copyright (c) 2007 Steven G. Johnson <stevenj@alum.mit.edu>
+#
+# This program is free software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright
+# owner gives unlimited permission to copy, distribute and modify the
+# configure scripts that are the output of Autoconf when processing
+# the Macro. You need not follow the terms of the GNU General Public
+# License when using or distributing such scripts, even though
+# portions of the text of the Macro appear in them. The GNU General
+# Public License (GPL) does govern all other use of the material that
+# constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the
+# Autoconf Macro released by the Autoconf Macro Archive. When you
+# make and distribute a modified version of the Autoconf Macro, you
+# may extend this special exception to the GPL to apply to your
+# modified version as well.
+
+AC_DEFUN([ACX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+ AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test x"$acx_pthread_ok" = xno; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads too;
+# also defines -D_REENTRANT)
+# ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+ *solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthreads/-mt/
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+
+ acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
+ ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+ case $flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $flag])
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ pthread-config)
+ AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+ if test x"$acx_pthread_config" = xno; then continue; fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$flag])
+ PTHREAD_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [acx_pthread_ok=yes])
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test "x$acx_pthread_ok" = xyes; then
+ break;
+ fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ AC_MSG_CHECKING([for joinable pthread attribute])
+ attr_name=unknown
+ for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
+ [attr_name=$attr; break])
+ done
+ AC_MSG_RESULT($attr_name)
+ if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+ AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+ [Define to necessary symbol if this constant
+ uses a non-standard name on your system.])
+ fi
+
+ AC_MSG_CHECKING([if more special flags are required for pthreads])
+ flag=no
+ case "${host_cpu}-${host_os}" in
+ *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+ *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+ esac
+ AC_MSG_RESULT(${flag})
+ if test "x$flag" != xno; then
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+ fi
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ # More AIX lossage: must compile with xlc_r or cc_r
+ if test x"$GCC" != xyes; then
+ AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+ else
+ PTHREAD_CC=$CC
+ fi
+else
+ PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+ :
+else
+ acx_pthread_ok=no
+ $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/m4/libevent_openssl.m4 b/fluent-bit/lib/monkey/mk_core/deps/libevent/m4/libevent_openssl.m4
new file mode 100644
index 000000000..c20405950
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/m4/libevent_openssl.m4
@@ -0,0 +1,52 @@
+dnl ######################################################################
+dnl OpenSSL support
+AC_DEFUN([LIBEVENT_OPENSSL], [
+AC_REQUIRE([NTP_PKG_CONFIG])dnl
+
+case "$enable_openssl" in
+ yes)
+ have_openssl=no
+ case "$PKG_CONFIG" in
+ '')
+ ;;
+ *)
+ OPENSSL_LIBS=`$PKG_CONFIG --libs openssl 2>/dev/null`
+ case "$OPENSSL_LIBS" in
+ '') ;;
+ *) OPENSSL_LIBS="$OPENSSL_LIBS $EV_LIB_GDI $EV_LIB_WS32 $OPENSSL_LIBADD"
+ have_openssl=yes
+ ;;
+ esac
+ OPENSSL_INCS=`$PKG_CONFIG --cflags openssl 2>/dev/null`
+ ;;
+ esac
+ case "$have_openssl" in
+ yes) ;;
+ *)
+ save_LIBS="$LIBS"
+ LIBS=""
+ OPENSSL_LIBS=""
+ for lib in crypto eay32; do
+ # clear cache
+ unset ac_cv_search_SSL_new
+ AC_SEARCH_LIBS([SSL_new], [ssl ssl32],
+ [have_openssl=yes
+ OPENSSL_LIBS="$LIBS -l$lib $EV_LIB_GDI $EV_LIB_WS32 $OPENSSL_LIBADD"],
+ [have_openssl=no],
+ [-l$lib $EV_LIB_GDI $EV_LIB_WS32 $OPENSSL_LIBADD])
+ LIBS="$save_LIBS"
+ test "$have_openssl" = "yes" && break
+ done
+ ;;
+ esac
+ AC_SUBST(OPENSSL_INCS)
+ AC_SUBST(OPENSSL_LIBS)
+ case "$have_openssl" in
+ yes) AC_DEFINE(HAVE_OPENSSL, 1, [Define if the system has openssl]) ;;
+ esac
+ ;;
+esac
+
+# check if we have and should use openssl
+AM_CONDITIONAL(OPENSSL, [test "$enable_openssl" != "no" && test "$have_openssl" = "yes"])
+])
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/m4/ntp_pkg_config.m4 b/fluent-bit/lib/monkey/mk_core/deps/libevent/m4/ntp_pkg_config.m4
new file mode 100644
index 000000000..1bce8a6e4
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/m4/ntp_pkg_config.m4
@@ -0,0 +1,27 @@
+dnl NTP_PKG_CONFIG -*- Autoconf -*-
+dnl
+dnl Look for pkg-config, which must be at least
+dnl $ntp_pkgconfig_min_version.
+dnl
+AC_DEFUN([NTP_PKG_CONFIG], [
+
+dnl lower the minimum version if you find an earlier one works
+ntp_pkgconfig_min_version='0.15.0'
+AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+AS_UNSET([ac_cv_path_PKG_CONFIG])
+AS_UNSET([ac_cv_path_ac_pt_PKG_CONFIG])
+
+case "$PKG_CONFIG" in
+ /*)
+ AC_MSG_CHECKING([if pkg-config is at least version $ntp_pkgconfig_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $ntp_pkgconfig_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+ ;;
+esac
+
+]) dnl NTP_PKG_CONFIG
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/make-event-config.sed b/fluent-bit/lib/monkey/mk_core/deps/libevent/make-event-config.sed
new file mode 100644
index 000000000..e31018a2d
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/make-event-config.sed
@@ -0,0 +1,23 @@
+# Sed script to postprocess config.h into event-config.h.
+
+1i\
+/* event2/event-config.h\
+ *\
+ * This file was generated by autoconf when libevent was built, and post-\
+ * processed by Libevent so that its macros would have a uniform prefix.\
+ *\
+ * DO NOT EDIT THIS FILE.\
+ *\
+ * Do not rely on macros in this file existing in later versions.\
+ */\
+\
+#ifndef EVENT2_EVENT_CONFIG_H_INCLUDED_\
+#define EVENT2_EVENT_CONFIG_H_INCLUDED_\
+
+$a\
+\
+#endif /* event2/event-config.h */
+
+s/#\( *\)define /#\1define EVENT__/
+s/#\( *\)undef /#\1undef EVENT__/
+s/#\( *\)if\(n*\)def /#\1if\2def EVENT__/
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/make_epoll_table.py b/fluent-bit/lib/monkey/mk_core/deps/libevent/make_epoll_table.py
new file mode 100755
index 000000000..1b15a91a6
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/make_epoll_table.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python2
+
+def get(old,wc,rc,cc):
+ if ('xxx' in (rc, wc, cc)):
+ return "0",255
+
+ if ('add' in (rc, wc, cc)):
+ events = []
+ if rc == 'add' or (rc != 'del' and 'r' in old):
+ events.append("EPOLLIN")
+ if wc == 'add' or (wc != 'del' and 'w' in old):
+ events.append("EPOLLOUT")
+ if cc == 'add' or (cc != 'del' and 'c' in old):
+ events.append("EPOLLRDHUP")
+
+ if old == "0":
+ op = "EPOLL_CTL_ADD"
+ else:
+ op = "EPOLL_CTL_MOD"
+ return "|".join(events), op
+
+ if ('del' in (rc, wc, cc)):
+ delevents = []
+ modevents = []
+ op = "EPOLL_CTL_DEL"
+
+ if 'r' in old:
+ modevents.append("EPOLLIN")
+ if 'w' in old:
+ modevents.append("EPOLLOUT")
+ if 'c' in old:
+ modevents.append("EPOLLRDHUP")
+
+ for item, event in [(rc,"EPOLLIN"),
+ (wc,"EPOLLOUT"),
+ (cc,"EPOLLRDHUP")]:
+ if item == 'del':
+ delevents.append(event)
+ if event in modevents:
+ modevents.remove(event)
+
+ if modevents:
+ return "|".join(modevents), "EPOLL_CTL_MOD"
+ else:
+ return "|".join(delevents), "EPOLL_CTL_DEL"
+
+ return 0, 0
+
+
+def fmt(op, ev, old, wc, rc, cc):
+ entry = "{ %s, %s },"%(op, ev)
+ print "\t/* old=%3s, write:%3s, read:%3s, close:%3s */\n\t%s" % (
+ old, wc, rc, cc, entry)
+ return len(entry)
+
+for old in ('0','r','w','rw','c','cr','cw','crw'):
+ for wc in ('0', 'add', 'del', 'xxx'):
+ for rc in ('0', 'add', 'del', 'xxx'):
+ for cc in ('0', 'add', 'del', 'xxx'):
+
+ op,ev = get(old,wc,rc,cc)
+
+ fmt(op, ev, old, wc, rc, cc)
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/minheap-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/minheap-internal.h
new file mode 100644
index 000000000..b3b6f1fd4
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/minheap-internal.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef MINHEAP_INTERNAL_H_INCLUDED_
+#define MINHEAP_INTERNAL_H_INCLUDED_
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/util.h"
+#include "util-internal.h"
+#include "mm-internal.h"
+
+typedef struct min_heap
+{
+ struct event** p;
+ unsigned n, a;
+} min_heap_t;
+
+static inline void min_heap_ctor_(min_heap_t* s);
+static inline void min_heap_dtor_(min_heap_t* s);
+static inline void min_heap_elem_init_(struct event* e);
+static inline int min_heap_elt_is_top_(const struct event *e);
+static inline int min_heap_empty_(min_heap_t* s);
+static inline unsigned min_heap_size_(min_heap_t* s);
+static inline struct event* min_heap_top_(min_heap_t* s);
+static inline int min_heap_reserve_(min_heap_t* s, unsigned n);
+static inline int min_heap_push_(min_heap_t* s, struct event* e);
+static inline struct event* min_heap_pop_(min_heap_t* s);
+static inline int min_heap_adjust_(min_heap_t *s, struct event* e);
+static inline int min_heap_erase_(min_heap_t* s, struct event* e);
+static inline void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e);
+static inline void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e);
+static inline void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e);
+
+#define min_heap_elem_greater(a, b) \
+ (evutil_timercmp(&(a)->ev_timeout, &(b)->ev_timeout, >))
+
+void min_heap_ctor_(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; }
+void min_heap_dtor_(min_heap_t* s) { if (s->p) mm_free(s->p); }
+void min_heap_elem_init_(struct event* e) { e->ev_timeout_pos.min_heap_idx = -1; }
+int min_heap_empty_(min_heap_t* s) { return 0u == s->n; }
+unsigned min_heap_size_(min_heap_t* s) { return s->n; }
+struct event* min_heap_top_(min_heap_t* s) { return s->n ? *s->p : 0; }
+
+int min_heap_push_(min_heap_t* s, struct event* e)
+{
+ if (min_heap_reserve_(s, s->n + 1))
+ return -1;
+ min_heap_shift_up_(s, s->n++, e);
+ return 0;
+}
+
+struct event* min_heap_pop_(min_heap_t* s)
+{
+ if (s->n)
+ {
+ struct event* e = *s->p;
+ min_heap_shift_down_(s, 0u, s->p[--s->n]);
+ e->ev_timeout_pos.min_heap_idx = -1;
+ return e;
+ }
+ return 0;
+}
+
+int min_heap_elt_is_top_(const struct event *e)
+{
+ return e->ev_timeout_pos.min_heap_idx == 0;
+}
+
+int min_heap_erase_(min_heap_t* s, struct event* e)
+{
+ if (-1 != e->ev_timeout_pos.min_heap_idx)
+ {
+ struct event *last = s->p[--s->n];
+ unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2;
+ /* we replace e with the last element in the heap. We might need to
+ shift it upward if it is less than its parent, or downward if it is
+ greater than one or both its children. Since the children are known
+ to be less than the parent, it can't need to shift both up and
+ down. */
+ if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
+ min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, last);
+ else
+ min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, last);
+ e->ev_timeout_pos.min_heap_idx = -1;
+ return 0;
+ }
+ return -1;
+}
+
+int min_heap_adjust_(min_heap_t *s, struct event *e)
+{
+ if (-1 == e->ev_timeout_pos.min_heap_idx) {
+ return min_heap_push_(s, e);
+ } else {
+ unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2;
+ /* The position of e has changed; we shift it up or down
+ * as needed. We can't need to do both. */
+ if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], e))
+ min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, e);
+ else
+ min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, e);
+ return 0;
+ }
+}
+
+int min_heap_reserve_(min_heap_t* s, unsigned n)
+{
+ if (s->a < n)
+ {
+ struct event** p;
+ unsigned a = s->a ? s->a * 2 : 8;
+ if (a < n)
+ a = n;
+ if (!(p = (struct event**)mm_realloc(s->p, a * sizeof *p)))
+ return -1;
+ s->p = p;
+ s->a = a;
+ }
+ return 0;
+}
+
+void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e)
+{
+ unsigned parent = (hole_index - 1) / 2;
+ do
+ {
+ (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index;
+ hole_index = parent;
+ parent = (hole_index - 1) / 2;
+ } while (hole_index && min_heap_elem_greater(s->p[parent], e));
+ (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
+}
+
+void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
+{
+ unsigned parent = (hole_index - 1) / 2;
+ while (hole_index && min_heap_elem_greater(s->p[parent], e))
+ {
+ (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index;
+ hole_index = parent;
+ parent = (hole_index - 1) / 2;
+ }
+ (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
+}
+
+void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
+{
+ unsigned min_child = 2 * (hole_index + 1);
+ while (min_child <= s->n)
+ {
+ min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
+ if (!(min_heap_elem_greater(e, s->p[min_child])))
+ break;
+ (s->p[hole_index] = s->p[min_child])->ev_timeout_pos.min_heap_idx = hole_index;
+ hole_index = min_child;
+ min_child = 2 * (hole_index + 1);
+ }
+ (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
+}
+
+#endif /* MINHEAP_INTERNAL_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/mm-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/mm-internal.h
new file mode 100644
index 000000000..4ba6fce4a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/mm-internal.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef MM_INTERNAL_H_INCLUDED_
+#define MM_INTERNAL_H_INCLUDED_
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef EVENT__DISABLE_MM_REPLACEMENT
+/* Internal use only: Memory allocation functions. We give them nice short
+ * mm_names for our own use, but make sure that the symbols have longer names
+ * so they don't conflict with other libraries (like, say, libmm). */
+
+/** Allocate uninitialized memory.
+ *
+ * @return On success, return a pointer to sz newly allocated bytes.
+ * On failure, set errno to ENOMEM and return NULL.
+ * If the argument sz is 0, simply return NULL.
+ */
+void *event_mm_malloc_(size_t sz);
+
+/** Allocate memory initialized to zero.
+ *
+ * @return On success, return a pointer to (count * size) newly allocated
+ * bytes, initialized to zero.
+ * On failure, or if the product would result in an integer overflow,
+ * set errno to ENOMEM and return NULL.
+ * If either arguments are 0, simply return NULL.
+ */
+void *event_mm_calloc_(size_t count, size_t size);
+
+/** Duplicate a string.
+ *
+ * @return On success, return a pointer to a newly allocated duplicate
+ * of a string.
+ * Set errno to ENOMEM and return NULL if a memory allocation error
+ * occurs (or would occur) in the process.
+ * If the argument str is NULL, set errno to EINVAL and return NULL.
+ */
+char *event_mm_strdup_(const char *str);
+
+void *event_mm_realloc_(void *p, size_t sz);
+void event_mm_free_(void *p);
+#define mm_malloc(sz) event_mm_malloc_(sz)
+#define mm_calloc(count, size) event_mm_calloc_((count), (size))
+#define mm_strdup(s) event_mm_strdup_(s)
+#define mm_realloc(p, sz) event_mm_realloc_((p), (sz))
+#define mm_free(p) event_mm_free_(p)
+#else
+#define mm_malloc(sz) malloc(sz)
+#define mm_calloc(n, sz) calloc((n), (sz))
+#define mm_strdup(s) strdup(s)
+#define mm_realloc(p, sz) realloc((p), (sz))
+#define mm_free(p) free(p)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/openssl-compat.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/openssl-compat.h
new file mode 100644
index 000000000..69afc716e
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/openssl-compat.h
@@ -0,0 +1,35 @@
+#ifndef OPENSSL_COMPAT_H
+#define OPENSSL_COMPAT_H
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+static inline BIO_METHOD *BIO_meth_new(int type, const char *name)
+{
+ BIO_METHOD *biom = calloc(1, sizeof(BIO_METHOD));
+
+ if (biom != NULL) {
+ biom->type = type;
+ biom->name = name;
+ }
+ return biom;
+}
+
+#define BIO_meth_set_write(b, f) (b)->bwrite = (f)
+#define BIO_meth_set_read(b, f) (b)->bread = (f)
+#define BIO_meth_set_puts(b, f) (b)->bputs = (f)
+#define BIO_meth_set_ctrl(b, f) (b)->ctrl = (f)
+#define BIO_meth_set_create(b, f) (b)->create = (f)
+#define BIO_meth_set_destroy(b, f) (b)->destroy = (f)
+
+#define BIO_set_init(b, val) (b)->init = (val)
+#define BIO_set_data(b, val) (b)->ptr = (val)
+#define BIO_set_shutdown(b, val) (b)->shutdown = (val)
+#define BIO_get_init(b) (b)->init
+#define BIO_get_data(b) (b)->ptr
+#define BIO_get_shutdown(b) (b)->shutdown
+
+#define TLS_method SSLv23_method
+
+#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
+
+#endif /* OPENSSL_COMPAT_H */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/poll.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/poll.c
new file mode 100644
index 000000000..fe4407117
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/poll.c
@@ -0,0 +1,341 @@
+/* $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
+
+/*
+ * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef EVENT__HAVE_POLL
+
+#include <sys/types.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#include <poll.h>
+#include <signal.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "event-internal.h"
+#include "evsignal-internal.h"
+#include "log-internal.h"
+#include "evmap-internal.h"
+#include "event2/thread.h"
+#include "evthread-internal.h"
+#include "time-internal.h"
+
+struct pollidx {
+ int idxplus1;
+};
+
+struct pollop {
+ int event_count; /* Highest number alloc */
+ int nfds; /* Highest number used */
+ int realloc_copy; /* True iff we must realloc
+ * event_set_copy */
+ struct pollfd *event_set;
+ struct pollfd *event_set_copy;
+};
+
+static void *poll_init(struct event_base *);
+static int poll_add(struct event_base *, int, short old, short events, void *idx);
+static int poll_del(struct event_base *, int, short old, short events, void *idx);
+static int poll_dispatch(struct event_base *, struct timeval *);
+static void poll_dealloc(struct event_base *);
+
+const struct eventop pollops = {
+ "poll",
+ poll_init,
+ poll_add,
+ poll_del,
+ poll_dispatch,
+ poll_dealloc,
+ 0, /* doesn't need_reinit */
+ EV_FEATURE_FDS,
+ sizeof(struct pollidx),
+};
+
+static void *
+poll_init(struct event_base *base)
+{
+ struct pollop *pollop;
+
+ if (!(pollop = mm_calloc(1, sizeof(struct pollop))))
+ return (NULL);
+
+ evsig_init_(base);
+
+ evutil_weakrand_seed_(&base->weakrand_seed, 0);
+
+ return (pollop);
+}
+
+#ifdef CHECK_INVARIANTS
+static void
+poll_check_ok(struct pollop *pop)
+{
+ int i, idx;
+ struct event *ev;
+
+ for (i = 0; i < pop->fd_count; ++i) {
+ idx = pop->idxplus1_by_fd[i]-1;
+ if (idx < 0)
+ continue;
+ EVUTIL_ASSERT(pop->event_set[idx].fd == i);
+ }
+ for (i = 0; i < pop->nfds; ++i) {
+ struct pollfd *pfd = &pop->event_set[i];
+ EVUTIL_ASSERT(pop->idxplus1_by_fd[pfd->fd] == i+1);
+ }
+}
+#else
+#define poll_check_ok(pop)
+#endif
+
+static int
+poll_dispatch(struct event_base *base, struct timeval *tv)
+{
+ int res, i, j, nfds;
+ long msec = -1;
+ struct pollop *pop = base->evbase;
+ struct pollfd *event_set;
+
+ poll_check_ok(pop);
+
+ nfds = pop->nfds;
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ if (base->th_base_lock) {
+ /* If we're using this backend in a multithreaded setting,
+ * then we need to work on a copy of event_set, so that we can
+ * let other threads modify the main event_set while we're
+ * polling. If we're not multithreaded, then we'll skip the
+ * copy step here to save memory and time. */
+ if (pop->realloc_copy) {
+ struct pollfd *tmp = mm_realloc(pop->event_set_copy,
+ pop->event_count * sizeof(struct pollfd));
+ if (tmp == NULL) {
+ event_warn("realloc");
+ return -1;
+ }
+ pop->event_set_copy = tmp;
+ pop->realloc_copy = 0;
+ }
+ memcpy(pop->event_set_copy, pop->event_set,
+ sizeof(struct pollfd)*nfds);
+ event_set = pop->event_set_copy;
+ } else {
+ event_set = pop->event_set;
+ }
+#else
+ event_set = pop->event_set;
+#endif
+
+ if (tv != NULL) {
+ msec = evutil_tv_to_msec_(tv);
+ if (msec < 0 || msec > INT_MAX)
+ msec = INT_MAX;
+ }
+
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ res = poll(event_set, nfds, msec);
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ if (res == -1) {
+ if (errno != EINTR) {
+ event_warn("poll");
+ return (-1);
+ }
+
+ return (0);
+ }
+
+ event_debug(("%s: poll reports %d", __func__, res));
+
+ if (res == 0 || nfds == 0)
+ return (0);
+
+ i = evutil_weakrand_range_(&base->weakrand_seed, nfds);
+ for (j = 0; j < nfds; j++) {
+ int what;
+ if (++i == nfds)
+ i = 0;
+ what = event_set[i].revents;
+ if (!what)
+ continue;
+
+ res = 0;
+
+ /* If the file gets closed notify */
+ if (what & (POLLHUP|POLLERR|POLLNVAL))
+ what |= POLLIN|POLLOUT;
+ if (what & POLLIN)
+ res |= EV_READ;
+ if (what & POLLOUT)
+ res |= EV_WRITE;
+ if (res == 0)
+ continue;
+
+ evmap_io_active_(base, event_set[i].fd, res);
+ }
+
+ return (0);
+}
+
+static int
+poll_add(struct event_base *base, int fd, short old, short events, void *idx_)
+{
+ struct pollop *pop = base->evbase;
+ struct pollfd *pfd = NULL;
+ struct pollidx *idx = idx_;
+ int i;
+
+ EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
+ if (!(events & (EV_READ|EV_WRITE)))
+ return (0);
+
+ poll_check_ok(pop);
+ if (pop->nfds + 1 >= pop->event_count) {
+ struct pollfd *tmp_event_set;
+ int tmp_event_count;
+
+ if (pop->event_count < 32)
+ tmp_event_count = 32;
+ else
+ tmp_event_count = pop->event_count * 2;
+
+ /* We need more file descriptors */
+ tmp_event_set = mm_realloc(pop->event_set,
+ tmp_event_count * sizeof(struct pollfd));
+ if (tmp_event_set == NULL) {
+ event_warn("realloc");
+ return (-1);
+ }
+ pop->event_set = tmp_event_set;
+
+ pop->event_count = tmp_event_count;
+ pop->realloc_copy = 1;
+ }
+
+ i = idx->idxplus1 - 1;
+
+ if (i >= 0) {
+ pfd = &pop->event_set[i];
+ } else {
+ i = pop->nfds++;
+ pfd = &pop->event_set[i];
+ pfd->events = 0;
+ pfd->fd = fd;
+ idx->idxplus1 = i + 1;
+ }
+
+ pfd->revents = 0;
+ if (events & EV_WRITE)
+ pfd->events |= POLLOUT;
+ if (events & EV_READ)
+ pfd->events |= POLLIN;
+ poll_check_ok(pop);
+
+ return (0);
+}
+
+/*
+ * Nothing to be done here.
+ */
+
+static int
+poll_del(struct event_base *base, int fd, short old, short events, void *idx_)
+{
+ struct pollop *pop = base->evbase;
+ struct pollfd *pfd = NULL;
+ struct pollidx *idx = idx_;
+ int i;
+
+ EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
+ if (!(events & (EV_READ|EV_WRITE)))
+ return (0);
+
+ poll_check_ok(pop);
+ i = idx->idxplus1 - 1;
+ if (i < 0)
+ return (-1);
+
+ /* Do we still want to read or write? */
+ pfd = &pop->event_set[i];
+ if (events & EV_READ)
+ pfd->events &= ~POLLIN;
+ if (events & EV_WRITE)
+ pfd->events &= ~POLLOUT;
+ poll_check_ok(pop);
+ if (pfd->events)
+ /* Another event cares about that fd. */
+ return (0);
+
+ /* Okay, so we aren't interested in that fd anymore. */
+ idx->idxplus1 = 0;
+
+ --pop->nfds;
+ if (i != pop->nfds) {
+ /*
+ * Shift the last pollfd down into the now-unoccupied
+ * position.
+ */
+ memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
+ sizeof(struct pollfd));
+ idx = evmap_io_get_fdinfo_(&base->io, pop->event_set[i].fd);
+ EVUTIL_ASSERT(idx);
+ EVUTIL_ASSERT(idx->idxplus1 == pop->nfds + 1);
+ idx->idxplus1 = i + 1;
+ }
+
+ poll_check_ok(pop);
+ return (0);
+}
+
+static void
+poll_dealloc(struct event_base *base)
+{
+ struct pollop *pop = base->evbase;
+
+ evsig_dealloc_(base);
+ if (pop->event_set)
+ mm_free(pop->event_set);
+ if (pop->event_set_copy)
+ mm_free(pop->event_set_copy);
+
+ memset(pop, 0, sizeof(struct pollop));
+ mm_free(pop);
+}
+
+#endif /* EVENT__HAVE_POLL */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/ratelim-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/ratelim-internal.h
new file mode 100644
index 000000000..6cc1cdde2
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/ratelim-internal.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef RATELIM_INTERNAL_H_INCLUDED_
+#define RATELIM_INTERNAL_H_INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "event2/util.h"
+
+/** A token bucket is an internal structure that tracks how many bytes we are
+ * currently willing to read or write on a given bufferevent or group of
+ * bufferevents */
+struct ev_token_bucket {
+ /** How many bytes are we willing to read or write right now? These
+ * values are signed so that we can do "defecit spending" */
+ ev_ssize_t read_limit, write_limit;
+ /** When was this bucket last updated? Measured in abstract 'ticks'
+ * relative to the token bucket configuration. */
+ ev_uint32_t last_updated;
+};
+
+/** Configuration info for a token bucket or set of token buckets. */
+struct ev_token_bucket_cfg {
+ /** How many bytes are we willing to read on average per tick? */
+ size_t read_rate;
+ /** How many bytes are we willing to read at most in any one tick? */
+ size_t read_maximum;
+ /** How many bytes are we willing to write on average per tick? */
+ size_t write_rate;
+ /** How many bytes are we willing to write at most in any one tick? */
+ size_t write_maximum;
+
+ /* How long is a tick? Note that fractions of a millisecond are
+ * ignored. */
+ struct timeval tick_timeout;
+
+ /* How long is a tick, in milliseconds? Derived from tick_timeout. */
+ unsigned msec_per_tick;
+};
+
+/** The current tick is 'current_tick': add bytes to 'bucket' as specified in
+ * 'cfg'. */
+int ev_token_bucket_update_(struct ev_token_bucket *bucket,
+ const struct ev_token_bucket_cfg *cfg,
+ ev_uint32_t current_tick);
+
+/** In which tick does 'tv' fall according to 'cfg'? Note that ticks can
+ * overflow easily; your code needs to handle this. */
+ev_uint32_t ev_token_bucket_get_tick_(const struct timeval *tv,
+ const struct ev_token_bucket_cfg *cfg);
+
+/** Adjust 'bucket' to respect 'cfg', and note that it was last updated in
+ * 'current_tick'. If 'reinitialize' is true, we are changing the
+ * configuration of 'bucket'; otherwise, we are setting it up for the first
+ * time.
+ */
+int ev_token_bucket_init_(struct ev_token_bucket *bucket,
+ const struct ev_token_bucket_cfg *cfg,
+ ev_uint32_t current_tick,
+ int reinitialize);
+
+int bufferevent_remove_from_rate_limit_group_internal_(struct bufferevent *bev,
+ int unsuspend);
+
+/** Decrease the read limit of 'b' by 'n' bytes */
+#define ev_token_bucket_decrement_read(b,n) \
+ do { \
+ (b)->read_limit -= (n); \
+ } while (0)
+/** Decrease the write limit of 'b' by 'n' bytes */
+#define ev_token_bucket_decrement_write(b,n) \
+ do { \
+ (b)->write_limit -= (n); \
+ } while (0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/dns-example.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/dns-example.c
new file mode 100644
index 000000000..fb705664a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/dns-example.c
@@ -0,0 +1,257 @@
+/*
+ This example code shows how to use the high-level, low-level, and
+ server-level interfaces of evdns.
+
+ XXX It's pretty ugly and should probably be cleaned up.
+ */
+
+#include <event2/event-config.h>
+
+/* Compatibility for possible missing IPv6 declarations */
+#include "../ipv6-internal.h"
+
+#include <sys/types.h>
+
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <getopt.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include <event2/event.h>
+#include <event2/dns.h>
+#include <event2/dns_struct.h>
+#include <event2/util.h>
+
+#ifdef EVENT__HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define u32 ev_uint32_t
+#define u8 ev_uint8_t
+
+static const char *
+debug_ntoa(u32 address)
+{
+ static char buf[32];
+ u32 a = ntohl(address);
+ evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
+ (int)(u8)((a>>24)&0xff),
+ (int)(u8)((a>>16)&0xff),
+ (int)(u8)((a>>8 )&0xff),
+ (int)(u8)((a )&0xff));
+ return buf;
+}
+
+static void
+main_callback(int result, char type, int count, int ttl,
+ void *addrs, void *orig) {
+ char *n = (char*)orig;
+ int i;
+ for (i = 0; i < count; ++i) {
+ if (type == DNS_IPv4_A) {
+ printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i]));
+ } else if (type == DNS_PTR) {
+ printf("%s: %s\n", n, ((char**)addrs)[i]);
+ }
+ }
+ if (!count) {
+ printf("%s: No answer (%d)\n", n, result);
+ }
+ fflush(stdout);
+}
+
+static void
+gai_callback(int err, struct evutil_addrinfo *ai, void *arg)
+{
+ const char *name = arg;
+ int i;
+ if (err) {
+ printf("%s: %s\n", name, evutil_gai_strerror(err));
+ }
+ if (ai && ai->ai_canonname)
+ printf(" %s ==> %s\n", name, ai->ai_canonname);
+ for (i=0; ai; ai = ai->ai_next, ++i) {
+ char buf[128];
+ if (ai->ai_family == PF_INET) {
+ struct sockaddr_in *sin =
+ (struct sockaddr_in*)ai->ai_addr;
+ evutil_inet_ntop(AF_INET, &sin->sin_addr, buf,
+ sizeof(buf));
+ printf("[%d] %s: %s\n",i,name,buf);
+ } else {
+ struct sockaddr_in6 *sin6 =
+ (struct sockaddr_in6*)ai->ai_addr;
+ evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf,
+ sizeof(buf));
+ printf("[%d] %s: %s\n",i,name,buf);
+ }
+ }
+}
+
+static void
+evdns_server_callback(struct evdns_server_request *req, void *data)
+{
+ int i, r;
+ (void)data;
+ /* dummy; give 192.168.11.11 as an answer for all A questions,
+ * give foo.bar.example.com as an answer for all PTR questions. */
+ for (i = 0; i < req->nquestions; ++i) {
+ u32 ans = htonl(0xc0a80b0bUL);
+ if (req->questions[i]->type == EVDNS_TYPE_A &&
+ req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
+ printf(" -- replying for %s (A)\n", req->questions[i]->name);
+ r = evdns_server_request_add_a_reply(req, req->questions[i]->name,
+ 1, &ans, 10);
+ if (r<0)
+ printf("eeep, didn't work.\n");
+ } else if (req->questions[i]->type == EVDNS_TYPE_PTR &&
+ req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
+ printf(" -- replying for %s (PTR)\n", req->questions[i]->name);
+ r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name,
+ "foo.bar.example.com", 10);
+ if (r<0)
+ printf("ugh, no luck");
+ } else {
+ printf(" -- skipping %s [%d %d]\n", req->questions[i]->name,
+ req->questions[i]->type, req->questions[i]->dns_question_class);
+ }
+ }
+
+ r = evdns_server_request_respond(req, 0);
+ if (r<0)
+ printf("eeek, couldn't send reply.\n");
+}
+
+static int verbose = 0;
+
+static void
+logfn(int is_warn, const char *msg) {
+ if (!is_warn && !verbose)
+ return;
+ fprintf(stderr, "%s: %s\n", is_warn?"WARN":"INFO", msg);
+}
+
+int
+main(int c, char **v) {
+ struct options {
+ int reverse;
+ int use_getaddrinfo;
+ int servertest;
+ const char *resolv_conf;
+ const char *ns;
+ };
+ struct options o;
+ char opt;
+ struct event_base *event_base = NULL;
+ struct evdns_base *evdns_base = NULL;
+
+ memset(&o, 0, sizeof(o));
+
+ if (c < 2) {
+ fprintf(stderr, "syntax: %s [-x] [-v] [-c resolv.conf] [-s ns] hostname\n", v[0]);
+ fprintf(stderr, "syntax: %s [-T]\n", v[0]);
+ return 1;
+ }
+
+ while ((opt = getopt(c, v, "xvc:Ts:")) != -1) {
+ switch (opt) {
+ case 'x': o.reverse = 1; break;
+ case 'v': ++verbose; break;
+ case 'g': o.use_getaddrinfo = 1; break;
+ case 'T': o.servertest = 1; break;
+ case 'c': o.resolv_conf = optarg; break;
+ case 's': o.ns = optarg; break;
+ default : fprintf(stderr, "Unknown option %c\n", opt); break;
+ }
+ }
+
+#ifdef _WIN32
+ {
+ WSADATA WSAData;
+ WSAStartup(0x101, &WSAData);
+ }
+#endif
+
+ event_base = event_base_new();
+ evdns_base = evdns_base_new(event_base, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
+ evdns_set_log_fn(logfn);
+
+ if (o.servertest) {
+ evutil_socket_t sock;
+ struct sockaddr_in my_addr;
+ sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sock == -1) {
+ perror("socket");
+ exit(1);
+ }
+ evutil_make_socket_nonblocking(sock);
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_port = htons(10053);
+ my_addr.sin_addr.s_addr = INADDR_ANY;
+ if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr))<0) {
+ perror("bind");
+ exit(1);
+ }
+ evdns_add_server_port_with_base(event_base, sock, 0, evdns_server_callback, NULL);
+ }
+ if (optind < c) {
+ int res;
+#ifdef _WIN32
+ if (o.resolv_conf == NULL && !o.ns)
+ res = evdns_base_config_windows_nameservers(evdns_base);
+ else
+#endif
+ if (o.ns)
+ res = evdns_base_nameserver_ip_add(evdns_base, o.ns);
+ else
+ res = evdns_base_resolv_conf_parse(evdns_base,
+ DNS_OPTION_NAMESERVERS, o.resolv_conf);
+
+ if (res < 0) {
+ fprintf(stderr, "Couldn't configure nameservers");
+ return 1;
+ }
+ }
+
+ printf("EVUTIL_AI_CANONNAME in example = %d\n", EVUTIL_AI_CANONNAME);
+ for (; optind < c; ++optind) {
+ if (o.reverse) {
+ struct in_addr addr;
+ if (evutil_inet_pton(AF_INET, v[optind], &addr)!=1) {
+ fprintf(stderr, "Skipping non-IP %s\n", v[optind]);
+ continue;
+ }
+ fprintf(stderr, "resolving %s...\n",v[optind]);
+ evdns_base_resolve_reverse(evdns_base, &addr, 0, main_callback, v[optind]);
+ } else if (o.use_getaddrinfo) {
+ struct evutil_addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_flags = EVUTIL_AI_CANONNAME;
+ fprintf(stderr, "resolving (fwd) %s...\n",v[optind]);
+ evdns_getaddrinfo(evdns_base, v[optind], NULL, &hints,
+ gai_callback, v[optind]);
+ } else {
+ fprintf(stderr, "resolving (fwd) %s...\n",v[optind]);
+ evdns_base_resolve_ipv4(evdns_base, v[optind], 0, main_callback, v[optind]);
+ }
+ }
+ fflush(stdout);
+ event_base_dispatch(event_base);
+ return 0;
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/event-read-fifo.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/event-read-fifo.c
new file mode 100644
index 000000000..27b0b530d
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/event-read-fifo.c
@@ -0,0 +1,162 @@
+/*
+ * This sample code shows how to use Libevent to read from a named pipe.
+ * XXX This code could make better use of the Libevent interfaces.
+ *
+ * XXX This does not work on Windows; ignore everything inside the _WIN32 block.
+ *
+ * On UNIX, compile with:
+ * cc -I/usr/local/include -o event-read-fifo event-read-fifo.c \
+ * -L/usr/local/lib -levent
+ */
+
+#include <event2/event-config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef _WIN32
+#include <sys/queue.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <signal.h>
+#else
+#include <winsock2.h>
+#include <windows.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event2/event.h>
+
+static void
+fifo_read(evutil_socket_t fd, short event, void *arg)
+{
+ char buf[255];
+ int len;
+ struct event *ev = arg;
+#ifdef _WIN32
+ DWORD dwBytesRead;
+#endif
+
+ fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n",
+ (int)fd, event, arg);
+#ifdef _WIN32
+ len = ReadFile((HANDLE)fd, buf, sizeof(buf) - 1, &dwBytesRead, NULL);
+
+ /* Check for end of file. */
+ if (len && dwBytesRead == 0) {
+ fprintf(stderr, "End Of File");
+ event_del(ev);
+ return;
+ }
+
+ buf[dwBytesRead] = '\0';
+#else
+ len = read(fd, buf, sizeof(buf) - 1);
+
+ if (len <= 0) {
+ if (len == -1)
+ perror("read");
+ else if (len == 0)
+ fprintf(stderr, "Connection closed\n");
+ event_del(ev);
+ event_base_loopbreak(event_get_base(ev));
+ return;
+ }
+
+ buf[len] = '\0';
+#endif
+ fprintf(stdout, "Read: %s\n", buf);
+}
+
+/* On Unix, cleanup event.fifo if SIGINT is received. */
+#ifndef _WIN32
+static void
+signal_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct event_base *base = arg;
+ event_base_loopbreak(base);
+}
+#endif
+
+int
+main(int argc, char **argv)
+{
+ struct event *evfifo;
+ struct event_base* base;
+#ifdef _WIN32
+ HANDLE socket;
+ /* Open a file. */
+ socket = CreateFileA("test.txt", /* open File */
+ GENERIC_READ, /* open for reading */
+ 0, /* do not share */
+ NULL, /* no security */
+ OPEN_EXISTING, /* existing file only */
+ FILE_ATTRIBUTE_NORMAL, /* normal file */
+ NULL); /* no attr. template */
+
+ if (socket == INVALID_HANDLE_VALUE)
+ return 1;
+
+#else
+ struct event *signal_int;
+ struct stat st;
+ const char *fifo = "event.fifo";
+ int socket;
+
+ if (lstat(fifo, &st) == 0) {
+ if ((st.st_mode & S_IFMT) == S_IFREG) {
+ errno = EEXIST;
+ perror("lstat");
+ exit(1);
+ }
+ }
+
+ unlink(fifo);
+ if (mkfifo(fifo, 0600) == -1) {
+ perror("mkfifo");
+ exit(1);
+ }
+
+ socket = open(fifo, O_RDONLY | O_NONBLOCK, 0);
+
+ if (socket == -1) {
+ perror("open");
+ exit(1);
+ }
+
+ fprintf(stderr, "Write data to %s\n", fifo);
+#endif
+ /* Initalize the event library */
+ base = event_base_new();
+
+ /* Initalize one event */
+#ifdef _WIN32
+ evfifo = event_new(base, (evutil_socket_t)socket, EV_READ|EV_PERSIST, fifo_read,
+ event_self_cbarg());
+#else
+ /* catch SIGINT so that event.fifo can be cleaned up */
+ signal_int = evsignal_new(base, SIGINT, signal_cb, base);
+ event_add(signal_int, NULL);
+
+ evfifo = event_new(base, socket, EV_READ|EV_PERSIST, fifo_read,
+ event_self_cbarg());
+#endif
+
+ /* Add it to the active events, without a timeout */
+ event_add(evfifo, NULL);
+
+ event_base_dispatch(base);
+ event_base_free(base);
+#ifdef _WIN32
+ CloseHandle(socket);
+#else
+ close(socket);
+ unlink(fifo);
+#endif
+ libevent_global_shutdown();
+ return (0);
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/hello-world.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/hello-world.c
new file mode 100644
index 000000000..2023cd6c6
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/hello-world.c
@@ -0,0 +1,141 @@
+/*
+ This example program provides a trivial server program that listens for TCP
+ connections on port 9995. When they arrive, it writes a short message to
+ each client connection, and closes each connection once it is flushed.
+
+ Where possible, it exits cleanly in response to a SIGINT (ctrl-c).
+*/
+
+
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <signal.h>
+#ifndef _WIN32
+#include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
+#include <sys/socket.h>
+#endif
+
+#include <event2/bufferevent.h>
+#include <event2/buffer.h>
+#include <event2/listener.h>
+#include <event2/util.h>
+#include <event2/event.h>
+
+static const char MESSAGE[] = "Hello, World!\n";
+
+static const int PORT = 9995;
+
+static void listener_cb(struct evconnlistener *, evutil_socket_t,
+ struct sockaddr *, int socklen, void *);
+static void conn_writecb(struct bufferevent *, void *);
+static void conn_eventcb(struct bufferevent *, short, void *);
+static void signal_cb(evutil_socket_t, short, void *);
+
+int
+main(int argc, char **argv)
+{
+ struct event_base *base;
+ struct evconnlistener *listener;
+ struct event *signal_event;
+
+ struct sockaddr_in sin;
+#ifdef _WIN32
+ WSADATA wsa_data;
+ WSAStartup(0x0201, &wsa_data);
+#endif
+
+ base = event_base_new();
+ if (!base) {
+ fprintf(stderr, "Could not initialize libevent!\n");
+ return 1;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(PORT);
+
+ listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
+ LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1,
+ (struct sockaddr*)&sin,
+ sizeof(sin));
+
+ if (!listener) {
+ fprintf(stderr, "Could not create a listener!\n");
+ return 1;
+ }
+
+ signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
+
+ if (!signal_event || event_add(signal_event, NULL)<0) {
+ fprintf(stderr, "Could not create/add a signal event!\n");
+ return 1;
+ }
+
+ event_base_dispatch(base);
+
+ evconnlistener_free(listener);
+ event_free(signal_event);
+ event_base_free(base);
+
+ printf("done\n");
+ return 0;
+}
+
+static void
+listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
+ struct sockaddr *sa, int socklen, void *user_data)
+{
+ struct event_base *base = user_data;
+ struct bufferevent *bev;
+
+ bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
+ if (!bev) {
+ fprintf(stderr, "Error constructing bufferevent!");
+ event_base_loopbreak(base);
+ return;
+ }
+ bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);
+ bufferevent_enable(bev, EV_WRITE);
+ bufferevent_disable(bev, EV_READ);
+
+ bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
+}
+
+static void
+conn_writecb(struct bufferevent *bev, void *user_data)
+{
+ struct evbuffer *output = bufferevent_get_output(bev);
+ if (evbuffer_get_length(output) == 0) {
+ printf("flushed answer\n");
+ bufferevent_free(bev);
+ }
+}
+
+static void
+conn_eventcb(struct bufferevent *bev, short events, void *user_data)
+{
+ if (events & BEV_EVENT_EOF) {
+ printf("Connection closed.\n");
+ } else if (events & BEV_EVENT_ERROR) {
+ printf("Got an error on the connection: %s\n",
+ strerror(errno));/*XXX win32*/
+ }
+ /* None of the other events can happen here, since we haven't enabled
+ * timeouts */
+ bufferevent_free(bev);
+}
+
+static void
+signal_cb(evutil_socket_t sig, short events, void *user_data)
+{
+ struct event_base *base = user_data;
+ struct timeval delay = { 2, 0 };
+
+ printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");
+
+ event_base_loopexit(base, &delay);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/hostcheck.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/hostcheck.c
new file mode 100644
index 000000000..50709369c
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/hostcheck.c
@@ -0,0 +1,217 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* This file is an amalgamation of hostcheck.c and most of rawstr.c
+ from cURL. The contents of the COPYING file mentioned above are:
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1996 - 2013, Daniel Stenberg, <daniel@haxx.se>.
+
+All rights reserved.
+
+Permission to use, copy, modify, and distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright
+notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
+NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall not
+be used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization of the copyright holder.
+*/
+
+#include "hostcheck.h"
+#include <string.h>
+
+/* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because
+ its behavior is altered by the current locale. */
+static char Curl_raw_toupper(char in)
+{
+ switch (in) {
+ case 'a':
+ return 'A';
+ case 'b':
+ return 'B';
+ case 'c':
+ return 'C';
+ case 'd':
+ return 'D';
+ case 'e':
+ return 'E';
+ case 'f':
+ return 'F';
+ case 'g':
+ return 'G';
+ case 'h':
+ return 'H';
+ case 'i':
+ return 'I';
+ case 'j':
+ return 'J';
+ case 'k':
+ return 'K';
+ case 'l':
+ return 'L';
+ case 'm':
+ return 'M';
+ case 'n':
+ return 'N';
+ case 'o':
+ return 'O';
+ case 'p':
+ return 'P';
+ case 'q':
+ return 'Q';
+ case 'r':
+ return 'R';
+ case 's':
+ return 'S';
+ case 't':
+ return 'T';
+ case 'u':
+ return 'U';
+ case 'v':
+ return 'V';
+ case 'w':
+ return 'W';
+ case 'x':
+ return 'X';
+ case 'y':
+ return 'Y';
+ case 'z':
+ return 'Z';
+ }
+ return in;
+}
+
+/*
+ * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant
+ * to be locale independent and only compare strings we know are safe for
+ * this. See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
+ * some further explanation to why this function is necessary.
+ *
+ * The function is capable of comparing a-z case insensitively even for
+ * non-ascii.
+ */
+
+static int Curl_raw_equal(const char *first, const char *second)
+{
+ while(*first && *second) {
+ if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
+ /* get out of the loop as soon as they don't match */
+ break;
+ first++;
+ second++;
+ }
+ /* we do the comparison here (possibly again), just to make sure that if the
+ loop above is skipped because one of the strings reached zero, we must not
+ return this as a successful match */
+ return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second));
+}
+
+static int Curl_raw_nequal(const char *first, const char *second, size_t max)
+{
+ while(*first && *second && max) {
+ if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) {
+ break;
+ }
+ max--;
+ first++;
+ second++;
+ }
+ if(0 == max)
+ return 1; /* they are equal this far */
+
+ return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
+}
+
+/*
+ * Match a hostname against a wildcard pattern.
+ * E.g.
+ * "foo.host.com" matches "*.host.com".
+ *
+ * We use the matching rule described in RFC6125, section 6.4.3.
+ * http://tools.ietf.org/html/rfc6125#section-6.4.3
+ */
+
+static int hostmatch(const char *hostname, const char *pattern)
+{
+ const char *pattern_label_end, *pattern_wildcard, *hostname_label_end;
+ int wildcard_enabled;
+ size_t prefixlen, suffixlen;
+ pattern_wildcard = strchr(pattern, '*');
+ if(pattern_wildcard == NULL)
+ return Curl_raw_equal(pattern, hostname) ?
+ CURL_HOST_MATCH : CURL_HOST_NOMATCH;
+
+ /* We require at least 2 dots in pattern to avoid too wide wildcard
+ match. */
+ wildcard_enabled = 1;
+ pattern_label_end = strchr(pattern, '.');
+ if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL ||
+ pattern_wildcard > pattern_label_end ||
+ Curl_raw_nequal(pattern, "xn--", 4)) {
+ wildcard_enabled = 0;
+ }
+ if(!wildcard_enabled)
+ return Curl_raw_equal(pattern, hostname) ?
+ CURL_HOST_MATCH : CURL_HOST_NOMATCH;
+
+ hostname_label_end = strchr(hostname, '.');
+ if(hostname_label_end == NULL ||
+ !Curl_raw_equal(pattern_label_end, hostname_label_end))
+ return CURL_HOST_NOMATCH;
+
+ /* The wildcard must match at least one character, so the left-most
+ label of the hostname is at least as large as the left-most label
+ of the pattern. */
+ if(hostname_label_end - hostname < pattern_label_end - pattern)
+ return CURL_HOST_NOMATCH;
+
+ prefixlen = pattern_wildcard - pattern;
+ suffixlen = pattern_label_end - (pattern_wildcard+1);
+ return Curl_raw_nequal(pattern, hostname, prefixlen) &&
+ Curl_raw_nequal(pattern_wildcard+1, hostname_label_end - suffixlen,
+ suffixlen) ?
+ CURL_HOST_MATCH : CURL_HOST_NOMATCH;
+}
+
+int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
+{
+ if(!match_pattern || !*match_pattern ||
+ !hostname || !*hostname) /* sanity check */
+ return 0;
+
+ if(Curl_raw_equal(hostname, match_pattern)) /* trivial case */
+ return 1;
+
+ if(hostmatch(hostname,match_pattern) == CURL_HOST_MATCH)
+ return 1;
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/hostcheck.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/hostcheck.h
new file mode 100644
index 000000000..f40bc4343
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/hostcheck.h
@@ -0,0 +1,30 @@
+#ifndef HEADER_CURL_HOSTCHECK_H
+#define HEADER_CURL_HOSTCHECK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#define CURL_HOST_NOMATCH 0
+#define CURL_HOST_MATCH 1
+int Curl_cert_hostcheck(const char *match_pattern, const char *hostname);
+
+#endif /* HEADER_CURL_HOSTCHECK_H */
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/http-connect.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/http-connect.c
new file mode 100644
index 000000000..a44d001ac
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/http-connect.c
@@ -0,0 +1,117 @@
+#include "event2/event-config.h"
+
+#include <event2/event.h>
+#include <event2/http.h>
+#include <event2/http_struct.h>
+#include <event2/buffer.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+
+#define VERIFY(cond) do { \
+ if (!(cond)) { \
+ fprintf(stderr, "[error] %s\n", #cond); \
+ } \
+} while (0); \
+
+#define URL_MAX 4096
+
+struct connect_base
+{
+ struct evhttp_connection *evcon;
+ struct evhttp_uri *location;
+};
+
+static void get_cb(struct evhttp_request *req, void *arg)
+{
+ ev_ssize_t len;
+ struct evbuffer *evbuf;
+
+ VERIFY(req);
+
+ evbuf = evhttp_request_get_input_buffer(req);
+ len = evbuffer_get_length(evbuf);
+ fwrite(evbuffer_pullup(evbuf, len), len, 1, stdout);
+ evbuffer_drain(evbuf, len);
+}
+
+static void connect_cb(struct evhttp_request *proxy_req, void *arg)
+{
+ char buffer[URL_MAX];
+
+ struct connect_base *base = arg;
+ struct evhttp_connection *evcon = base->evcon;
+ struct evhttp_uri *location = base->location;
+
+ VERIFY(proxy_req);
+ if (evcon) {
+ struct evhttp_request *req = evhttp_request_new(get_cb, NULL);
+ evhttp_add_header(req->output_headers, "Connection", "close");
+ VERIFY(!evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ evhttp_uri_join(location, buffer, URL_MAX)));
+ }
+}
+
+int main(int argc, const char **argv)
+{
+ char buffer[URL_MAX];
+
+ struct evhttp_uri *host_port;
+ struct evhttp_uri *location;
+ struct evhttp_uri *proxy;
+
+ struct event_base *base;
+ struct evhttp_connection *evcon;
+ struct evhttp_request *req;
+
+ struct connect_base connect_base;
+
+ if (argc != 3) {
+ printf("Usage: %s proxy url\n", argv[0]);
+ return 1;
+ }
+
+ {
+ proxy = evhttp_uri_parse(argv[1]);
+ VERIFY(evhttp_uri_get_host(proxy));
+ VERIFY(evhttp_uri_get_port(proxy) > 0);
+ }
+ {
+ host_port = evhttp_uri_parse(argv[2]);
+ evhttp_uri_set_scheme(host_port, NULL);
+ evhttp_uri_set_userinfo(host_port, NULL);
+ evhttp_uri_set_path(host_port, NULL);
+ evhttp_uri_set_query(host_port, NULL);
+ evhttp_uri_set_fragment(host_port, NULL);
+ VERIFY(evhttp_uri_get_host(host_port));
+ VERIFY(evhttp_uri_get_port(host_port) > 0);
+ }
+ {
+ location = evhttp_uri_parse(argv[2]);
+ evhttp_uri_set_scheme(location, NULL);
+ evhttp_uri_set_userinfo(location, 0);
+ evhttp_uri_set_host(location, NULL);
+ evhttp_uri_set_port(location, -1);
+ }
+
+ VERIFY(base = event_base_new());
+ VERIFY(evcon = evhttp_connection_base_new(base, NULL,
+ evhttp_uri_get_host(proxy), evhttp_uri_get_port(proxy)));
+ connect_base.evcon = evcon;
+ connect_base.location = location;
+ VERIFY(req = evhttp_request_new(connect_cb, &connect_base));
+
+ evhttp_add_header(req->output_headers, "Connection", "keep-alive");
+ evhttp_add_header(req->output_headers, "Proxy-Connection", "keep-alive");
+ evutil_snprintf(buffer, URL_MAX, "%s:%d",
+ evhttp_uri_get_host(host_port), evhttp_uri_get_port(host_port));
+ evhttp_make_request(evcon, req, EVHTTP_REQ_CONNECT, buffer);
+
+ event_base_dispatch(base);
+ evhttp_connection_free(evcon);
+ event_base_free(base);
+ evhttp_uri_free(proxy);
+ evhttp_uri_free(host_port);
+ evhttp_uri_free(location);
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/http-server.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/http-server.c
new file mode 100644
index 000000000..579feea6e
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/http-server.c
@@ -0,0 +1,418 @@
+/*
+ A trivial static http webserver using Libevent's evhttp.
+
+ This is not the best code in the world, and it does some fairly stupid stuff
+ that you would never want to do in a production webserver. Caveat hackor!
+
+ */
+
+/* Compatibility for possible missing IPv6 declarations */
+#include "../util-internal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+#include <io.h>
+#include <fcntl.h>
+#ifndef S_ISDIR
+#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
+#endif
+#else
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#endif
+
+#include <event2/event.h>
+#include <event2/http.h>
+#include <event2/buffer.h>
+#include <event2/util.h>
+#include <event2/keyvalq_struct.h>
+
+#ifdef EVENT__HAVE_NETINET_IN_H
+#include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
+#endif
+
+#ifdef _WIN32
+#ifndef stat
+#define stat _stat
+#endif
+#ifndef fstat
+#define fstat _fstat
+#endif
+#ifndef open
+#define open _open
+#endif
+#ifndef close
+#define close _close
+#endif
+#ifndef O_RDONLY
+#define O_RDONLY _O_RDONLY
+#endif
+#endif
+
+char uri_root[512];
+
+static const struct table_entry {
+ const char *extension;
+ const char *content_type;
+} content_type_table[] = {
+ { "txt", "text/plain" },
+ { "c", "text/plain" },
+ { "h", "text/plain" },
+ { "html", "text/html" },
+ { "htm", "text/htm" },
+ { "css", "text/css" },
+ { "gif", "image/gif" },
+ { "jpg", "image/jpeg" },
+ { "jpeg", "image/jpeg" },
+ { "png", "image/png" },
+ { "pdf", "application/pdf" },
+ { "ps", "application/postscript" },
+ { NULL, NULL },
+};
+
+/* Try to guess a good content-type for 'path' */
+static const char *
+guess_content_type(const char *path)
+{
+ const char *last_period, *extension;
+ const struct table_entry *ent;
+ last_period = strrchr(path, '.');
+ if (!last_period || strchr(last_period, '/'))
+ goto not_found; /* no exension */
+ extension = last_period + 1;
+ for (ent = &content_type_table[0]; ent->extension; ++ent) {
+ if (!evutil_ascii_strcasecmp(ent->extension, extension))
+ return ent->content_type;
+ }
+
+not_found:
+ return "application/misc";
+}
+
+/* Callback used for the /dump URI, and for every non-GET request:
+ * dumps all information to stdout and gives back a trivial 200 ok */
+static void
+dump_request_cb(struct evhttp_request *req, void *arg)
+{
+ const char *cmdtype;
+ struct evkeyvalq *headers;
+ struct evkeyval *header;
+ struct evbuffer *buf;
+
+ switch (evhttp_request_get_command(req)) {
+ case EVHTTP_REQ_GET: cmdtype = "GET"; break;
+ case EVHTTP_REQ_POST: cmdtype = "POST"; break;
+ case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break;
+ case EVHTTP_REQ_PUT: cmdtype = "PUT"; break;
+ case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break;
+ case EVHTTP_REQ_OPTIONS: cmdtype = "OPTIONS"; break;
+ case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break;
+ case EVHTTP_REQ_CONNECT: cmdtype = "CONNECT"; break;
+ case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break;
+ default: cmdtype = "unknown"; break;
+ }
+
+ printf("Received a %s request for %s\nHeaders:\n",
+ cmdtype, evhttp_request_get_uri(req));
+
+ headers = evhttp_request_get_input_headers(req);
+ for (header = headers->tqh_first; header;
+ header = header->next.tqe_next) {
+ printf(" %s: %s\n", header->key, header->value);
+ }
+
+ buf = evhttp_request_get_input_buffer(req);
+ puts("Input data: <<<");
+ while (evbuffer_get_length(buf)) {
+ int n;
+ char cbuf[128];
+ n = evbuffer_remove(buf, cbuf, sizeof(cbuf));
+ if (n > 0)
+ (void) fwrite(cbuf, 1, n, stdout);
+ }
+ puts(">>>");
+
+ evhttp_send_reply(req, 200, "OK", NULL);
+}
+
+/* This callback gets invoked when we get any http request that doesn't match
+ * any other callback. Like any evhttp server callback, it has a simple job:
+ * it must eventually call evhttp_send_error() or evhttp_send_reply().
+ */
+static void
+send_document_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb = NULL;
+ const char *docroot = arg;
+ const char *uri = evhttp_request_get_uri(req);
+ struct evhttp_uri *decoded = NULL;
+ const char *path;
+ char *decoded_path;
+ char *whole_path = NULL;
+ size_t len;
+ int fd = -1;
+ struct stat st;
+
+ if (evhttp_request_get_command(req) != EVHTTP_REQ_GET) {
+ dump_request_cb(req, arg);
+ return;
+ }
+
+ printf("Got a GET request for <%s>\n", uri);
+
+ /* Decode the URI */
+ decoded = evhttp_uri_parse(uri);
+ if (!decoded) {
+ printf("It's not a good URI. Sending BADREQUEST\n");
+ evhttp_send_error(req, HTTP_BADREQUEST, 0);
+ return;
+ }
+
+ /* Let's see what path the user asked for. */
+ path = evhttp_uri_get_path(decoded);
+ if (!path) path = "/";
+
+ /* We need to decode it, to see what path the user really wanted. */
+ decoded_path = evhttp_uridecode(path, 0, NULL);
+ if (decoded_path == NULL)
+ goto err;
+ /* Don't allow any ".."s in the path, to avoid exposing stuff outside
+ * of the docroot. This test is both overzealous and underzealous:
+ * it forbids aceptable paths like "/this/one..here", but it doesn't
+ * do anything to prevent symlink following." */
+ if (strstr(decoded_path, ".."))
+ goto err;
+
+ len = strlen(decoded_path)+strlen(docroot)+2;
+ if (!(whole_path = malloc(len))) {
+ perror("malloc");
+ goto err;
+ }
+ evutil_snprintf(whole_path, len, "%s/%s", docroot, decoded_path);
+
+ if (stat(whole_path, &st)<0) {
+ goto err;
+ }
+
+ /* This holds the content we're sending. */
+ evb = evbuffer_new();
+
+ if (S_ISDIR(st.st_mode)) {
+ /* If it's a directory, read the comments and make a little
+ * index page */
+#ifdef _WIN32
+ HANDLE d;
+ WIN32_FIND_DATAA ent;
+ char *pattern;
+ size_t dirlen;
+#else
+ DIR *d;
+ struct dirent *ent;
+#endif
+ const char *trailing_slash = "";
+
+ if (!strlen(path) || path[strlen(path)-1] != '/')
+ trailing_slash = "/";
+
+#ifdef _WIN32
+ dirlen = strlen(whole_path);
+ pattern = malloc(dirlen+3);
+ memcpy(pattern, whole_path, dirlen);
+ pattern[dirlen] = '\\';
+ pattern[dirlen+1] = '*';
+ pattern[dirlen+2] = '\0';
+ d = FindFirstFileA(pattern, &ent);
+ free(pattern);
+ if (d == INVALID_HANDLE_VALUE)
+ goto err;
+#else
+ if (!(d = opendir(whole_path)))
+ goto err;
+#endif
+
+ evbuffer_add_printf(evb,
+ "<!DOCTYPE html>\n"
+ "<html>\n <head>\n"
+ " <meta charset='utf-8'>\n"
+ " <title>%s</title>\n"
+ " <base href='%s%s'>\n"
+ " </head>\n"
+ " <body>\n"
+ " <h1>%s</h1>\n"
+ " <ul>\n",
+ decoded_path, /* XXX html-escape this. */
+ path, /* XXX html-escape this? */
+ trailing_slash,
+ decoded_path /* XXX html-escape this */);
+#ifdef _WIN32
+ do {
+ const char *name = ent.cFileName;
+#else
+ while ((ent = readdir(d))) {
+ const char *name = ent->d_name;
+#endif
+ evbuffer_add_printf(evb,
+ " <li><a href=\"%s\">%s</a>\n",
+ name, name);/* XXX escape this */
+#ifdef _WIN32
+ } while (FindNextFileA(d, &ent));
+#else
+ }
+#endif
+ evbuffer_add_printf(evb, "</ul></body></html>\n");
+#ifdef _WIN32
+ FindClose(d);
+#else
+ closedir(d);
+#endif
+ evhttp_add_header(evhttp_request_get_output_headers(req),
+ "Content-Type", "text/html");
+ } else {
+ /* Otherwise it's a file; add it to the buffer to get
+ * sent via sendfile */
+ const char *type = guess_content_type(decoded_path);
+ if ((fd = open(whole_path, O_RDONLY)) < 0) {
+ perror("open");
+ goto err;
+ }
+
+ if (fstat(fd, &st)<0) {
+ /* Make sure the length still matches, now that we
+ * opened the file :/ */
+ perror("fstat");
+ goto err;
+ }
+ evhttp_add_header(evhttp_request_get_output_headers(req),
+ "Content-Type", type);
+ evbuffer_add_file(evb, fd, 0, st.st_size);
+ }
+
+ evhttp_send_reply(req, 200, "OK", evb);
+ goto done;
+err:
+ evhttp_send_error(req, 404, "Document was not found");
+ if (fd>=0)
+ close(fd);
+done:
+ if (decoded)
+ evhttp_uri_free(decoded);
+ if (decoded_path)
+ free(decoded_path);
+ if (whole_path)
+ free(whole_path);
+ if (evb)
+ evbuffer_free(evb);
+}
+
+static void
+syntax(void)
+{
+ fprintf(stdout, "Syntax: http-server <docroot>\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ struct event_base *base;
+ struct evhttp *http;
+ struct evhttp_bound_socket *handle;
+
+ ev_uint16_t port = 0;
+#ifdef _WIN32
+ WSADATA WSAData;
+ WSAStartup(0x101, &WSAData);
+#else
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+ return (1);
+#endif
+ if (argc < 2) {
+ syntax();
+ return 1;
+ }
+
+ base = event_base_new();
+ if (!base) {
+ fprintf(stderr, "Couldn't create an event_base: exiting\n");
+ return 1;
+ }
+
+ /* Create a new evhttp object to handle requests. */
+ http = evhttp_new(base);
+ if (!http) {
+ fprintf(stderr, "couldn't create evhttp. Exiting.\n");
+ return 1;
+ }
+
+ /* The /dump URI will dump all requests to stdout and say 200 ok. */
+ evhttp_set_cb(http, "/dump", dump_request_cb, NULL);
+
+ /* We want to accept arbitrary requests, so we need to set a "generic"
+ * cb. We can also add callbacks for specific paths. */
+ evhttp_set_gencb(http, send_document_cb, argv[1]);
+
+ /* Now we tell the evhttp what port to listen on */
+ handle = evhttp_bind_socket_with_handle(http, "0.0.0.0", port);
+ if (!handle) {
+ fprintf(stderr, "couldn't bind to port %d. Exiting.\n",
+ (int)port);
+ return 1;
+ }
+
+ {
+ /* Extract and display the address we're listening on. */
+ struct sockaddr_storage ss;
+ evutil_socket_t fd;
+ ev_socklen_t socklen = sizeof(ss);
+ char addrbuf[128];
+ void *inaddr;
+ const char *addr;
+ int got_port = -1;
+ fd = evhttp_bound_socket_get_fd(handle);
+ memset(&ss, 0, sizeof(ss));
+ if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) {
+ perror("getsockname() failed");
+ return 1;
+ }
+ if (ss.ss_family == AF_INET) {
+ got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
+ inaddr = &((struct sockaddr_in*)&ss)->sin_addr;
+ } else if (ss.ss_family == AF_INET6) {
+ got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
+ inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr;
+ } else {
+ fprintf(stderr, "Weird address family %d\n",
+ ss.ss_family);
+ return 1;
+ }
+ addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf,
+ sizeof(addrbuf));
+ if (addr) {
+ printf("Listening on %s:%d\n", addr, got_port);
+ evutil_snprintf(uri_root, sizeof(uri_root),
+ "http://%s:%d",addr,got_port);
+ } else {
+ fprintf(stderr, "evutil_inet_ntop failed\n");
+ return 1;
+ }
+ }
+
+ event_base_dispatch(base);
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/https-client.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/https-client.c
new file mode 100644
index 000000000..748395656
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/https-client.c
@@ -0,0 +1,502 @@
+/*
+ This is an example of how to hook up evhttp with bufferevent_ssl
+
+ It just GETs an https URL given on the command-line and prints the response
+ body to stdout.
+
+ Actually, it also accepts plain http URLs to make it easy to compare http vs
+ https code paths.
+
+ Loosely based on le-proxy.c.
+ */
+
+// Get rid of OSX 10.7 and greater deprecation warnings.
+#if defined(__APPLE__) && defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#define snprintf _snprintf
+#define strcasecmp _stricmp
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#include <event2/bufferevent_ssl.h>
+#include <event2/bufferevent.h>
+#include <event2/buffer.h>
+#include <event2/listener.h>
+#include <event2/util.h>
+#include <event2/http.h>
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#include "openssl_hostname_validation.h"
+
+static struct event_base *base;
+static int ignore_cert = 0;
+
+static void
+http_request_done(struct evhttp_request *req, void *ctx)
+{
+ char buffer[256];
+ int nread;
+
+ if (req == NULL) {
+ /* If req is NULL, it means an error occurred, but
+ * sadly we are mostly left guessing what the error
+ * might have been. We'll do our best... */
+ struct bufferevent *bev = (struct bufferevent *) ctx;
+ unsigned long oslerr;
+ int printed_err = 0;
+ int errcode = EVUTIL_SOCKET_ERROR();
+ fprintf(stderr, "some request failed - no idea which one though!\n");
+ /* Print out the OpenSSL error queue that libevent
+ * squirreled away for us, if any. */
+ while ((oslerr = bufferevent_get_openssl_error(bev))) {
+ ERR_error_string_n(oslerr, buffer, sizeof(buffer));
+ fprintf(stderr, "%s\n", buffer);
+ printed_err = 1;
+ }
+ /* If the OpenSSL error queue was empty, maybe it was a
+ * socket error; let's try printing that. */
+ if (! printed_err)
+ fprintf(stderr, "socket error = %s (%d)\n",
+ evutil_socket_error_to_string(errcode),
+ errcode);
+ return;
+ }
+
+ fprintf(stderr, "Response line: %d %s\n",
+ evhttp_request_get_response_code(req),
+ evhttp_request_get_response_code_line(req));
+
+ while ((nread = evbuffer_remove(evhttp_request_get_input_buffer(req),
+ buffer, sizeof(buffer)))
+ > 0) {
+ /* These are just arbitrary chunks of 256 bytes.
+ * They are not lines, so we can't treat them as such. */
+ fwrite(buffer, nread, 1, stdout);
+ }
+}
+
+static void
+syntax(void)
+{
+ fputs("Syntax:\n", stderr);
+ fputs(" https-client -url <https-url> [-data data-file.bin] [-ignore-cert] [-retries num] [-timeout sec] [-crt crt]\n", stderr);
+ fputs("Example:\n", stderr);
+ fputs(" https-client -url https://ip.appspot.com/\n", stderr);
+}
+
+static void
+err(const char *msg)
+{
+ fputs(msg, stderr);
+}
+
+static void
+err_openssl(const char *func)
+{
+ fprintf (stderr, "%s failed:\n", func);
+
+ /* This is the OpenSSL function that prints the contents of the
+ * error stack to the specified file handle. */
+ ERR_print_errors_fp (stderr);
+
+ exit(1);
+}
+
+#ifndef _WIN32
+/* See http://archives.seul.org/libevent/users/Jan-2013/msg00039.html */
+static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg)
+{
+ char cert_str[256];
+ const char *host = (const char *) arg;
+ const char *res_str = "X509_verify_cert failed";
+ HostnameValidationResult res = Error;
+
+ /* This is the function that OpenSSL would call if we hadn't called
+ * SSL_CTX_set_cert_verify_callback(). Therefore, we are "wrapping"
+ * the default functionality, rather than replacing it. */
+ int ok_so_far = 0;
+
+ X509 *server_cert = NULL;
+
+ if (ignore_cert) {
+ return 1;
+ }
+
+ ok_so_far = X509_verify_cert(x509_ctx);
+
+ server_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+
+ if (ok_so_far) {
+ res = validate_hostname(host, server_cert);
+
+ switch (res) {
+ case MatchFound:
+ res_str = "MatchFound";
+ break;
+ case MatchNotFound:
+ res_str = "MatchNotFound";
+ break;
+ case NoSANPresent:
+ res_str = "NoSANPresent";
+ break;
+ case MalformedCertificate:
+ res_str = "MalformedCertificate";
+ break;
+ case Error:
+ res_str = "Error";
+ break;
+ default:
+ res_str = "WTF!";
+ break;
+ }
+ }
+
+ X509_NAME_oneline(X509_get_subject_name (server_cert),
+ cert_str, sizeof (cert_str));
+
+ if (res == MatchFound) {
+ printf("https server '%s' has this certificate, "
+ "which looks good to me:\n%s\n",
+ host, cert_str);
+ return 1;
+ } else {
+ printf("Got '%s' for hostname '%s' and certificate:\n%s\n",
+ res_str, host, cert_str);
+ return 0;
+ }
+}
+#endif
+
+int
+main(int argc, char **argv)
+{
+ int r;
+
+ struct evhttp_uri *http_uri = NULL;
+ const char *url = NULL, *data_file = NULL;
+ const char *crt = "/etc/ssl/certs/ca-certificates.crt";
+ const char *scheme, *host, *path, *query;
+ char uri[256];
+ int port;
+ int retries = 0;
+ int timeout = -1;
+
+ SSL_CTX *ssl_ctx = NULL;
+ SSL *ssl = NULL;
+ struct bufferevent *bev;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req;
+ struct evkeyvalq *output_headers;
+ struct evbuffer *output_buffer;
+
+ int i;
+ int ret = 0;
+ enum { HTTP, HTTPS } type = HTTP;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp("-url", argv[i])) {
+ if (i < argc - 1) {
+ url = argv[i + 1];
+ } else {
+ syntax();
+ goto error;
+ }
+ } else if (!strcmp("-crt", argv[i])) {
+ if (i < argc - 1) {
+ crt = argv[i + 1];
+ } else {
+ syntax();
+ goto error;
+ }
+ } else if (!strcmp("-ignore-cert", argv[i])) {
+ ignore_cert = 1;
+ } else if (!strcmp("-data", argv[i])) {
+ if (i < argc - 1) {
+ data_file = argv[i + 1];
+ } else {
+ syntax();
+ goto error;
+ }
+ } else if (!strcmp("-retries", argv[i])) {
+ if (i < argc - 1) {
+ retries = atoi(argv[i + 1]);
+ } else {
+ syntax();
+ goto error;
+ }
+ } else if (!strcmp("-timeout", argv[i])) {
+ if (i < argc - 1) {
+ timeout = atoi(argv[i + 1]);
+ } else {
+ syntax();
+ goto error;
+ }
+ } else if (!strcmp("-help", argv[i])) {
+ syntax();
+ goto error;
+ }
+ }
+
+ if (!url) {
+ syntax();
+ goto error;
+ }
+
+#ifdef _WIN32
+ {
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+ if (err != 0) {
+ printf("WSAStartup failed with error: %d\n", err);
+ goto error;
+ }
+ }
+#endif // _WIN32
+
+ http_uri = evhttp_uri_parse(url);
+ if (http_uri == NULL) {
+ err("malformed url");
+ goto error;
+ }
+
+ scheme = evhttp_uri_get_scheme(http_uri);
+ if (scheme == NULL || (strcasecmp(scheme, "https") != 0 &&
+ strcasecmp(scheme, "http") != 0)) {
+ err("url must be http or https");
+ goto error;
+ }
+
+ host = evhttp_uri_get_host(http_uri);
+ if (host == NULL) {
+ err("url must have a host");
+ goto error;
+ }
+
+ port = evhttp_uri_get_port(http_uri);
+ if (port == -1) {
+ port = (strcasecmp(scheme, "http") == 0) ? 80 : 443;
+ }
+
+ path = evhttp_uri_get_path(http_uri);
+ if (strlen(path) == 0) {
+ path = "/";
+ }
+
+ query = evhttp_uri_get_query(http_uri);
+ if (query == NULL) {
+ snprintf(uri, sizeof(uri) - 1, "%s", path);
+ } else {
+ snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query);
+ }
+ uri[sizeof(uri) - 1] = '\0';
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ // Initialize OpenSSL
+ SSL_library_init();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+#endif
+
+ /* This isn't strictly necessary... OpenSSL performs RAND_poll
+ * automatically on first use of random number generator. */
+ r = RAND_poll();
+ if (r == 0) {
+ err_openssl("RAND_poll");
+ goto error;
+ }
+
+ /* Create a new OpenSSL context */
+ ssl_ctx = SSL_CTX_new(SSLv23_method());
+ if (!ssl_ctx) {
+ err_openssl("SSL_CTX_new");
+ goto error;
+ }
+
+#ifndef _WIN32
+ /* TODO: Add certificate loading on Windows as well */
+
+ /* Attempt to use the system's trusted root certificates.
+ * (This path is only valid for Debian-based systems.) */
+ if (1 != SSL_CTX_load_verify_locations(ssl_ctx, crt, NULL)) {
+ err_openssl("SSL_CTX_load_verify_locations");
+ goto error;
+ }
+ /* Ask OpenSSL to verify the server certificate. Note that this
+ * does NOT include verifying that the hostname is correct.
+ * So, by itself, this means anyone with any legitimate
+ * CA-issued certificate for any website, can impersonate any
+ * other website in the world. This is not good. See "The
+ * Most Dangerous Code in the World" article at
+ * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html
+ */
+ SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
+ /* This is how we solve the problem mentioned in the previous
+ * comment. We "wrap" OpenSSL's validation routine in our
+ * own routine, which also validates the hostname by calling
+ * the code provided by iSECPartners. Note that even though
+ * the "Everything You've Always Wanted to Know About
+ * Certificate Validation With OpenSSL (But Were Afraid to
+ * Ask)" paper from iSECPartners says very explicitly not to
+ * call SSL_CTX_set_cert_verify_callback (at the bottom of
+ * page 2), what we're doing here is safe because our
+ * cert_verify_callback() calls X509_verify_cert(), which is
+ * OpenSSL's built-in routine which would have been called if
+ * we hadn't set the callback. Therefore, we're just
+ * "wrapping" OpenSSL's routine, not replacing it. */
+ SSL_CTX_set_cert_verify_callback(ssl_ctx, cert_verify_callback,
+ (void *) host);
+#else // _WIN32
+ (void)crt;
+#endif // _WIN32
+
+ // Create event base
+ base = event_base_new();
+ if (!base) {
+ perror("event_base_new()");
+ goto error;
+ }
+
+ // Create OpenSSL bufferevent and stack evhttp on top of it
+ ssl = SSL_new(ssl_ctx);
+ if (ssl == NULL) {
+ err_openssl("SSL_new()");
+ goto error;
+ }
+
+ #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ // Set hostname for SNI extension
+ SSL_set_tlsext_host_name(ssl, host);
+ #endif
+
+ if (strcasecmp(scheme, "http") == 0) {
+ bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
+ } else {
+ type = HTTPS;
+ bev = bufferevent_openssl_socket_new(base, -1, ssl,
+ BUFFEREVENT_SSL_CONNECTING,
+ BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
+ }
+
+ if (bev == NULL) {
+ fprintf(stderr, "bufferevent_openssl_socket_new() failed\n");
+ goto error;
+ }
+
+ bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
+
+ // For simplicity, we let DNS resolution block. Everything else should be
+ // asynchronous though.
+ evcon = evhttp_connection_base_bufferevent_new(base, NULL, bev,
+ host, port);
+ if (evcon == NULL) {
+ fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n");
+ goto error;
+ }
+
+ if (retries > 0) {
+ evhttp_connection_set_retries(evcon, retries);
+ }
+ if (timeout >= 0) {
+ evhttp_connection_set_timeout(evcon, timeout);
+ }
+
+ // Fire off the request
+ req = evhttp_request_new(http_request_done, bev);
+ if (req == NULL) {
+ fprintf(stderr, "evhttp_request_new() failed\n");
+ goto error;
+ }
+
+ output_headers = evhttp_request_get_output_headers(req);
+ evhttp_add_header(output_headers, "Host", host);
+ evhttp_add_header(output_headers, "Connection", "close");
+
+ if (data_file) {
+ /* NOTE: In production code, you'd probably want to use
+ * evbuffer_add_file() or evbuffer_add_file_segment(), to
+ * avoid needless copying. */
+ FILE * f = fopen(data_file, "rb");
+ char buf[1024];
+ size_t s;
+ size_t bytes = 0;
+
+ if (!f) {
+ syntax();
+ goto error;
+ }
+
+ output_buffer = evhttp_request_get_output_buffer(req);
+ while ((s = fread(buf, 1, sizeof(buf), f)) > 0) {
+ evbuffer_add(output_buffer, buf, s);
+ bytes += s;
+ }
+ evutil_snprintf(buf, sizeof(buf)-1, "%lu", (unsigned long)bytes);
+ evhttp_add_header(output_headers, "Content-Length", buf);
+ fclose(f);
+ }
+
+ r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri);
+ if (r != 0) {
+ fprintf(stderr, "evhttp_make_request() failed\n");
+ goto error;
+ }
+
+ event_base_dispatch(base);
+ goto cleanup;
+
+error:
+ ret = 1;
+cleanup:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http_uri)
+ evhttp_uri_free(http_uri);
+ event_base_free(base);
+
+ if (ssl_ctx)
+ SSL_CTX_free(ssl_ctx);
+ if (type == HTTP && ssl)
+ SSL_free(ssl);
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ EVP_cleanup();
+ ERR_free_strings();
+
+#ifdef EVENT__HAVE_ERR_REMOVE_THREAD_STATE
+ ERR_remove_thread_state(NULL);
+#else
+ ERR_remove_state(0);
+#endif
+ CRYPTO_cleanup_all_ex_data();
+
+ sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
+#endif /*OPENSSL_VERSION_NUMBER < 0x10100000L */
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
+ return ret;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/include.am b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/include.am
new file mode 100644
index 000000000..d1a7242f7
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/include.am
@@ -0,0 +1,53 @@
+# sample/include.am for libevent
+# Copyright 2000-2007 Niels Provos
+# Copyright 2007-2012 Niels Provos and Nick Mathewson
+#
+# See LICENSE for copying information.
+
+SAMPLES = \
+ sample/dns-example \
+ sample/event-read-fifo \
+ sample/hello-world \
+ sample/http-server \
+ sample/http-connect \
+ sample/signal-test \
+ sample/time-test
+
+if OPENSSL
+SAMPLES += sample/le-proxy
+sample_le_proxy_SOURCES = sample/le-proxy.c
+sample_le_proxy_LDADD = libevent.la libevent_openssl.la ${OPENSSL_LIBS} ${OPENSSL_LIBADD}
+sample_le_proxy_INCLUDES = $(OPENSSL_INCS)
+
+SAMPLES += sample/https-client
+sample_https_client_SOURCES = \
+ sample/https-client.c \
+ sample/hostcheck.c \
+ sample/openssl_hostname_validation.c
+sample_https_client_LDADD = libevent.la libevent_openssl.la ${OPENSSL_LIBS} ${OPENSSL_LIBADD}
+sample_https_client_INCLUDES = $(OPENSSL_INCS)
+noinst_HEADERS += \
+ sample/hostcheck.h \
+ sample/openssl_hostname_validation.h
+endif
+
+if BUILD_SAMPLES
+noinst_PROGRAMS += $(SAMPLES)
+endif
+
+$(SAMPLES) : libevent.la
+
+sample_event_read_fifo_SOURCES = sample/event-read-fifo.c
+sample_event_read_fifo_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
+sample_time_test_SOURCES = sample/time-test.c
+sample_time_test_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
+sample_signal_test_SOURCES = sample/signal-test.c
+sample_signal_test_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
+sample_dns_example_SOURCES = sample/dns-example.c
+sample_dns_example_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
+sample_hello_world_SOURCES = sample/hello-world.c
+sample_hello_world_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
+sample_http_server_SOURCES = sample/http-server.c
+sample_http_server_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
+sample_http_connect_SOURCES = sample/http-connect.c
+sample_http_connect_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/le-proxy.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/le-proxy.c
new file mode 100644
index 000000000..8d9b529ee
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/le-proxy.c
@@ -0,0 +1,291 @@
+/*
+ This example code shows how to write an (optionally encrypting) SSL proxy
+ with Libevent's bufferevent layer.
+
+ XXX It's a little ugly and should probably be cleaned up.
+ */
+
+// Get rid of OSX 10.7 and greater deprecation warnings.
+#if defined(__APPLE__) && defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#include <event2/bufferevent_ssl.h>
+#include <event2/bufferevent.h>
+#include <event2/buffer.h>
+#include <event2/listener.h>
+#include <event2/util.h>
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include "openssl-compat.h"
+
+static struct event_base *base;
+static struct sockaddr_storage listen_on_addr;
+static struct sockaddr_storage connect_to_addr;
+static int connect_to_addrlen;
+static int use_wrapper = 1;
+
+static SSL_CTX *ssl_ctx = NULL;
+
+#define MAX_OUTPUT (512*1024)
+
+static void drained_writecb(struct bufferevent *bev, void *ctx);
+static void eventcb(struct bufferevent *bev, short what, void *ctx);
+
+static void
+readcb(struct bufferevent *bev, void *ctx)
+{
+ struct bufferevent *partner = ctx;
+ struct evbuffer *src, *dst;
+ size_t len;
+ src = bufferevent_get_input(bev);
+ len = evbuffer_get_length(src);
+ if (!partner) {
+ evbuffer_drain(src, len);
+ return;
+ }
+ dst = bufferevent_get_output(partner);
+ evbuffer_add_buffer(dst, src);
+
+ if (evbuffer_get_length(dst) >= MAX_OUTPUT) {
+ /* We're giving the other side data faster than it can
+ * pass it on. Stop reading here until we have drained the
+ * other side to MAX_OUTPUT/2 bytes. */
+ bufferevent_setcb(partner, readcb, drained_writecb,
+ eventcb, bev);
+ bufferevent_setwatermark(partner, EV_WRITE, MAX_OUTPUT/2,
+ MAX_OUTPUT);
+ bufferevent_disable(bev, EV_READ);
+ }
+}
+
+static void
+drained_writecb(struct bufferevent *bev, void *ctx)
+{
+ struct bufferevent *partner = ctx;
+
+ /* We were choking the other side until we drained our outbuf a bit.
+ * Now it seems drained. */
+ bufferevent_setcb(bev, readcb, NULL, eventcb, partner);
+ bufferevent_setwatermark(bev, EV_WRITE, 0, 0);
+ if (partner)
+ bufferevent_enable(partner, EV_READ);
+}
+
+static void
+close_on_finished_writecb(struct bufferevent *bev, void *ctx)
+{
+ struct evbuffer *b = bufferevent_get_output(bev);
+
+ if (evbuffer_get_length(b) == 0) {
+ bufferevent_free(bev);
+ }
+}
+
+static void
+eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+ struct bufferevent *partner = ctx;
+
+ if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
+ if (what & BEV_EVENT_ERROR) {
+ unsigned long err;
+ while ((err = (bufferevent_get_openssl_error(bev)))) {
+ const char *msg = (const char*)
+ ERR_reason_error_string(err);
+ const char *lib = (const char*)
+ ERR_lib_error_string(err);
+ const char *func = (const char*)
+ ERR_func_error_string(err);
+ fprintf(stderr,
+ "%s in %s %s\n", msg, lib, func);
+ }
+ if (errno)
+ perror("connection error");
+ }
+
+ if (partner) {
+ /* Flush all pending data */
+ readcb(bev, ctx);
+
+ if (evbuffer_get_length(
+ bufferevent_get_output(partner))) {
+ /* We still have to flush data from the other
+ * side, but when that's done, close the other
+ * side. */
+ bufferevent_setcb(partner,
+ NULL, close_on_finished_writecb,
+ eventcb, NULL);
+ bufferevent_disable(partner, EV_READ);
+ } else {
+ /* We have nothing left to say to the other
+ * side; close it. */
+ bufferevent_free(partner);
+ }
+ }
+ bufferevent_free(bev);
+ }
+}
+
+static void
+syntax(void)
+{
+ fputs("Syntax:\n", stderr);
+ fputs(" le-proxy [-s] [-W] <listen-on-addr> <connect-to-addr>\n", stderr);
+ fputs("Example:\n", stderr);
+ fputs(" le-proxy 127.0.0.1:8888 1.2.3.4:80\n", stderr);
+
+ exit(1);
+}
+
+static void
+accept_cb(struct evconnlistener *listener, evutil_socket_t fd,
+ struct sockaddr *a, int slen, void *p)
+{
+ struct bufferevent *b_out, *b_in;
+ /* Create two linked bufferevent objects: one to connect, one for the
+ * new connection */
+ b_in = bufferevent_socket_new(base, fd,
+ BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
+
+ if (!ssl_ctx || use_wrapper)
+ b_out = bufferevent_socket_new(base, -1,
+ BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
+ else {
+ SSL *ssl = SSL_new(ssl_ctx);
+ b_out = bufferevent_openssl_socket_new(base, -1, ssl,
+ BUFFEREVENT_SSL_CONNECTING,
+ BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
+ }
+
+ assert(b_in && b_out);
+
+ if (bufferevent_socket_connect(b_out,
+ (struct sockaddr*)&connect_to_addr, connect_to_addrlen)<0) {
+ perror("bufferevent_socket_connect");
+ bufferevent_free(b_out);
+ bufferevent_free(b_in);
+ return;
+ }
+
+ if (ssl_ctx && use_wrapper) {
+ struct bufferevent *b_ssl;
+ SSL *ssl = SSL_new(ssl_ctx);
+ b_ssl = bufferevent_openssl_filter_new(base,
+ b_out, ssl, BUFFEREVENT_SSL_CONNECTING,
+ BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
+ if (!b_ssl) {
+ perror("Bufferevent_openssl_new");
+ bufferevent_free(b_out);
+ bufferevent_free(b_in);
+ }
+ b_out = b_ssl;
+ }
+
+ bufferevent_setcb(b_in, readcb, NULL, eventcb, b_out);
+ bufferevent_setcb(b_out, readcb, NULL, eventcb, b_in);
+
+ bufferevent_enable(b_in, EV_READ|EV_WRITE);
+ bufferevent_enable(b_out, EV_READ|EV_WRITE);
+}
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ int socklen;
+
+ int use_ssl = 0;
+ struct evconnlistener *listener;
+
+ if (argc < 3)
+ syntax();
+
+ for (i=1; i < argc; ++i) {
+ if (!strcmp(argv[i], "-s")) {
+ use_ssl = 1;
+ } else if (!strcmp(argv[i], "-W")) {
+ use_wrapper = 0;
+ } else if (argv[i][0] == '-') {
+ syntax();
+ } else
+ break;
+ }
+
+ if (i+2 != argc)
+ syntax();
+
+ memset(&listen_on_addr, 0, sizeof(listen_on_addr));
+ socklen = sizeof(listen_on_addr);
+ if (evutil_parse_sockaddr_port(argv[i],
+ (struct sockaddr*)&listen_on_addr, &socklen)<0) {
+ int p = atoi(argv[i]);
+ struct sockaddr_in *sin = (struct sockaddr_in*)&listen_on_addr;
+ if (p < 1 || p > 65535)
+ syntax();
+ sin->sin_port = htons(p);
+ sin->sin_addr.s_addr = htonl(0x7f000001);
+ sin->sin_family = AF_INET;
+ socklen = sizeof(struct sockaddr_in);
+ }
+
+ memset(&connect_to_addr, 0, sizeof(connect_to_addr));
+ connect_to_addrlen = sizeof(connect_to_addr);
+ if (evutil_parse_sockaddr_port(argv[i+1],
+ (struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0)
+ syntax();
+
+ base = event_base_new();
+ if (!base) {
+ perror("event_base_new()");
+ return 1;
+ }
+
+ if (use_ssl) {
+ int r;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ SSL_library_init();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+#endif
+ r = RAND_poll();
+ if (r == 0) {
+ fprintf(stderr, "RAND_poll() failed.\n");
+ return 1;
+ }
+ ssl_ctx = SSL_CTX_new(TLS_method());
+ }
+
+ listener = evconnlistener_new_bind(base, accept_cb, NULL,
+ LEV_OPT_CLOSE_ON_FREE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_REUSEABLE,
+ -1, (struct sockaddr*)&listen_on_addr, socklen);
+
+ if (! listener) {
+ fprintf(stderr, "Couldn't open listener.\n");
+ event_base_free(base);
+ return 1;
+ }
+ event_base_dispatch(base);
+
+ evconnlistener_free(listener);
+ event_base_free(base);
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/openssl_hostname_validation.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/openssl_hostname_validation.c
new file mode 100644
index 000000000..40312f2e9
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/openssl_hostname_validation.c
@@ -0,0 +1,177 @@
+/* Obtained from: https://github.com/iSECPartners/ssl-conservatory */
+
+/*
+Copyright (C) 2012, iSEC Partners.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+
+/*
+ * Helper functions to perform basic hostname validation using OpenSSL.
+ *
+ * Please read "everything-you-wanted-to-know-about-openssl.pdf" before
+ * attempting to use this code. This whitepaper describes how the code works,
+ * how it should be used, and what its limitations are.
+ *
+ * Author: Alban Diquet
+ * License: See LICENSE
+ *
+ */
+
+// Get rid of OSX 10.7 and greater deprecation warnings.
+#if defined(__APPLE__) && defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+#include <openssl/x509v3.h>
+#include <openssl/ssl.h>
+#include <string.h>
+
+#include "openssl_hostname_validation.h"
+#include "hostcheck.h"
+
+#define HOSTNAME_MAX_SIZE 255
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#define ASN1_STRING_get0_data ASN1_STRING_data
+#endif
+
+/**
+* Tries to find a match for hostname in the certificate's Common Name field.
+*
+* Returns MatchFound if a match was found.
+* Returns MatchNotFound if no matches were found.
+* Returns MalformedCertificate if the Common Name had a NUL character embedded in it.
+* Returns Error if the Common Name could not be extracted.
+*/
+static HostnameValidationResult matches_common_name(const char *hostname, const X509 *server_cert) {
+ int common_name_loc = -1;
+ X509_NAME_ENTRY *common_name_entry = NULL;
+ ASN1_STRING *common_name_asn1 = NULL;
+ const char *common_name_str = NULL;
+
+ // Find the position of the CN field in the Subject field of the certificate
+ common_name_loc = X509_NAME_get_index_by_NID(X509_get_subject_name((X509 *) server_cert), NID_commonName, -1);
+ if (common_name_loc < 0) {
+ return Error;
+ }
+
+ // Extract the CN field
+ common_name_entry = X509_NAME_get_entry(X509_get_subject_name((X509 *) server_cert), common_name_loc);
+ if (common_name_entry == NULL) {
+ return Error;
+ }
+
+ // Convert the CN field to a C string
+ common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
+ if (common_name_asn1 == NULL) {
+ return Error;
+ }
+ common_name_str = (char *) ASN1_STRING_get0_data(common_name_asn1);
+
+ // Make sure there isn't an embedded NUL character in the CN
+ if ((size_t)ASN1_STRING_length(common_name_asn1) != strlen(common_name_str)) {
+ return MalformedCertificate;
+ }
+
+ // Compare expected hostname with the CN
+ if (Curl_cert_hostcheck(common_name_str, hostname) == CURL_HOST_MATCH) {
+ return MatchFound;
+ }
+ else {
+ return MatchNotFound;
+ }
+}
+
+
+/**
+* Tries to find a match for hostname in the certificate's Subject Alternative Name extension.
+*
+* Returns MatchFound if a match was found.
+* Returns MatchNotFound if no matches were found.
+* Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it.
+* Returns NoSANPresent if the SAN extension was not present in the certificate.
+*/
+static HostnameValidationResult matches_subject_alternative_name(const char *hostname, const X509 *server_cert) {
+ HostnameValidationResult result = MatchNotFound;
+ int i;
+ int san_names_nb = -1;
+ STACK_OF(GENERAL_NAME) *san_names = NULL;
+
+ // Try to extract the names within the SAN extension from the certificate
+ san_names = X509_get_ext_d2i((X509 *) server_cert, NID_subject_alt_name, NULL, NULL);
+ if (san_names == NULL) {
+ return NoSANPresent;
+ }
+ san_names_nb = sk_GENERAL_NAME_num(san_names);
+
+ // Check each name within the extension
+ for (i=0; i<san_names_nb; i++) {
+ const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i);
+
+ if (current_name->type == GEN_DNS) {
+ // Current name is a DNS name, let's check it
+ const char *dns_name = (char *) ASN1_STRING_get0_data(current_name->d.dNSName);
+
+ // Make sure there isn't an embedded NUL character in the DNS name
+ if ((size_t)ASN1_STRING_length(current_name->d.dNSName) != strlen(dns_name)) {
+ result = MalformedCertificate;
+ break;
+ }
+ else { // Compare expected hostname with the DNS name
+ if (Curl_cert_hostcheck(dns_name, hostname)
+ == CURL_HOST_MATCH) {
+ result = MatchFound;
+ break;
+ }
+ }
+ }
+ }
+ sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
+
+ return result;
+}
+
+
+/**
+* Validates the server's identity by looking for the expected hostname in the
+* server's certificate. As described in RFC 6125, it first tries to find a match
+* in the Subject Alternative Name extension. If the extension is not present in
+* the certificate, it checks the Common Name instead.
+*
+* Returns MatchFound if a match was found.
+* Returns MatchNotFound if no matches were found.
+* Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it.
+* Returns Error if there was an error.
+*/
+HostnameValidationResult validate_hostname(const char *hostname, const X509 *server_cert) {
+ HostnameValidationResult result;
+
+ if((hostname == NULL) || (server_cert == NULL))
+ return Error;
+
+ // First try the Subject Alternative Names extension
+ result = matches_subject_alternative_name(hostname, server_cert);
+ if (result == NoSANPresent) {
+ // Extension was not found: try the Common Name
+ result = matches_common_name(hostname, server_cert);
+ }
+
+ return result;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/openssl_hostname_validation.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/openssl_hostname_validation.h
new file mode 100644
index 000000000..54aa1c436
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/openssl_hostname_validation.h
@@ -0,0 +1,56 @@
+/* Obtained from: https://github.com/iSECPartners/ssl-conservatory */
+
+/*
+Copyright (C) 2012, iSEC Partners.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+
+/*
+ * Helper functions to perform basic hostname validation using OpenSSL.
+ *
+ * Please read "everything-you-wanted-to-know-about-openssl.pdf" before
+ * attempting to use this code. This whitepaper describes how the code works,
+ * how it should be used, and what its limitations are.
+ *
+ * Author: Alban Diquet
+ * License: See LICENSE
+ *
+ */
+
+typedef enum {
+ MatchFound,
+ MatchNotFound,
+ NoSANPresent,
+ MalformedCertificate,
+ Error
+} HostnameValidationResult;
+
+/**
+* Validates the server's identity by looking for the expected hostname in the
+* server's certificate. As described in RFC 6125, it first tries to find a match
+* in the Subject Alternative Name extension. If the extension is not present in
+* the certificate, it checks the Common Name instead.
+*
+* Returns MatchFound if a match was found.
+* Returns MatchNotFound if no matches were found.
+* Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it.
+* Returns Error if there was an error.
+*/
+HostnameValidationResult validate_hostname(const char *hostname, const X509 *server_cert);
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/signal-test.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/signal-test.c
new file mode 100644
index 000000000..18668350b
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/signal-test.c
@@ -0,0 +1,72 @@
+/*
+ * Compile with:
+ * cc -I/usr/local/include -o signal-test \
+ * signal-test.c -L/usr/local/lib -levent
+ */
+
+#include <sys/types.h>
+
+#include <event2/event-config.h>
+
+#include <sys/stat.h>
+#ifndef _WIN32
+#include <sys/queue.h>
+#include <unistd.h>
+#include <sys/time.h>
+#else
+#include <winsock2.h>
+#include <windows.h>
+#endif
+#include <signal.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event2/event.h>
+
+int called = 0;
+
+static void
+signal_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct event *signal = arg;
+
+ printf("signal_cb: got signal %d\n", event_get_signal(signal));
+
+ if (called >= 2)
+ event_del(signal);
+
+ called++;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct event *signal_int;
+ struct event_base* base;
+#ifdef _WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ (void) WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+ /* Initalize the event library */
+ base = event_base_new();
+
+ /* Initalize one event */
+ signal_int = evsignal_new(base, SIGINT, signal_cb, event_self_cbarg());
+
+ event_add(signal_int, NULL);
+
+ event_base_dispatch(base);
+ event_free(signal_int);
+ event_base_free(base);
+
+ return (0);
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/time-test.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/time-test.c
new file mode 100644
index 000000000..c94c18a50
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/sample/time-test.c
@@ -0,0 +1,107 @@
+/*
+ * XXX This sample code was once meant to show how to use the basic Libevent
+ * interfaces, but it never worked on non-Unix platforms, and some of the
+ * interfaces have changed since it was first written. It should probably
+ * be removed or replaced with something better.
+ *
+ * Compile with:
+ * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
+ */
+
+#include <sys/types.h>
+
+#include <event2/event-config.h>
+
+#include <sys/stat.h>
+#ifndef _WIN32
+#include <sys/queue.h>
+#include <unistd.h>
+#endif
+#include <time.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event2/event.h>
+#include <event2/event_struct.h>
+#include <event2/util.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+struct timeval lasttime;
+
+int event_is_persistent;
+
+static void
+timeout_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct timeval newtime, difference;
+ struct event *timeout = arg;
+ double elapsed;
+
+ evutil_gettimeofday(&newtime, NULL);
+ evutil_timersub(&newtime, &lasttime, &difference);
+ elapsed = difference.tv_sec +
+ (difference.tv_usec / 1.0e6);
+
+ printf("timeout_cb called at %d: %.3f seconds elapsed.\n",
+ (int)newtime.tv_sec, elapsed);
+ lasttime = newtime;
+
+ if (! event_is_persistent) {
+ struct timeval tv;
+ evutil_timerclear(&tv);
+ tv.tv_sec = 2;
+ event_add(timeout, &tv);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ struct event timeout;
+ struct timeval tv;
+ struct event_base *base;
+ int flags;
+
+#ifdef _WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ (void)WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+ if (argc == 2 && !strcmp(argv[1], "-p")) {
+ event_is_persistent = 1;
+ flags = EV_PERSIST;
+ } else {
+ event_is_persistent = 0;
+ flags = 0;
+ }
+
+ /* Initalize the event library */
+ base = event_base_new();
+
+ /* Initalize one event */
+ event_assign(&timeout, base, -1, flags, timeout_cb, (void*) &timeout);
+
+ evutil_timerclear(&tv);
+ tv.tv_sec = 2;
+ event_add(&timeout, &tv);
+
+ evutil_gettimeofday(&lasttime, NULL);
+
+ event_base_dispatch(base);
+
+ return (0);
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/select.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/select.c
new file mode 100644
index 000000000..8ae53cc11
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/select.c
@@ -0,0 +1,346 @@
+/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
+
+/*
+ * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef EVENT__HAVE_SELECT
+
+#ifdef __APPLE__
+/* Apple wants us to define this if we might ever pass more than
+ * FD_SETSIZE bits to select(). */
+#define _DARWIN_UNLIMITED_SELECT
+#endif
+
+#include <sys/types.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef EVENT__HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/queue.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "event-internal.h"
+#include "evsignal-internal.h"
+#include "event2/thread.h"
+#include "evthread-internal.h"
+#include "log-internal.h"
+#include "evmap-internal.h"
+
+#ifndef EVENT__HAVE_FD_MASK
+/* This type is mandatory, but Android doesn't define it. */
+typedef unsigned long fd_mask;
+#endif
+
+#ifndef NFDBITS
+#define NFDBITS (sizeof(fd_mask)*8)
+#endif
+
+/* Divide positive x by y, rounding up. */
+#define DIV_ROUNDUP(x, y) (((x)+((y)-1))/(y))
+
+/* How many bytes to allocate for N fds? */
+#define SELECT_ALLOC_SIZE(n) \
+ (DIV_ROUNDUP(n, NFDBITS) * sizeof(fd_mask))
+
+struct selectop {
+ int event_fds; /* Highest fd in fd set */
+ int event_fdsz;
+ int resize_out_sets;
+ fd_set *event_readset_in;
+ fd_set *event_writeset_in;
+ fd_set *event_readset_out;
+ fd_set *event_writeset_out;
+};
+
+static void *select_init(struct event_base *);
+static int select_add(struct event_base *, int, short old, short events, void*);
+static int select_del(struct event_base *, int, short old, short events, void*);
+static int select_dispatch(struct event_base *, struct timeval *);
+static void select_dealloc(struct event_base *);
+
+const struct eventop selectops = {
+ "select",
+ select_init,
+ select_add,
+ select_del,
+ select_dispatch,
+ select_dealloc,
+ 0, /* doesn't need reinit. */
+ EV_FEATURE_FDS,
+ 0,
+};
+
+static int select_resize(struct selectop *sop, int fdsz);
+static void select_free_selectop(struct selectop *sop);
+
+static void *
+select_init(struct event_base *base)
+{
+ struct selectop *sop;
+
+ if (!(sop = mm_calloc(1, sizeof(struct selectop))))
+ return (NULL);
+
+ if (select_resize(sop, SELECT_ALLOC_SIZE(32 + 1))) {
+ select_free_selectop(sop);
+ return (NULL);
+ }
+
+ evsig_init_(base);
+
+ evutil_weakrand_seed_(&base->weakrand_seed, 0);
+
+ return (sop);
+}
+
+#ifdef CHECK_INVARIANTS
+static void
+check_selectop(struct selectop *sop)
+{
+ /* nothing to be done here */
+}
+#else
+#define check_selectop(sop) do { (void) sop; } while (0)
+#endif
+
+static int
+select_dispatch(struct event_base *base, struct timeval *tv)
+{
+ int res=0, i, j, nfds;
+ struct selectop *sop = base->evbase;
+
+ check_selectop(sop);
+ if (sop->resize_out_sets) {
+ fd_set *readset_out=NULL, *writeset_out=NULL;
+ size_t sz = sop->event_fdsz;
+ if (!(readset_out = mm_realloc(sop->event_readset_out, sz)))
+ return (-1);
+ sop->event_readset_out = readset_out;
+ if (!(writeset_out = mm_realloc(sop->event_writeset_out, sz))) {
+ /* We don't free readset_out here, since it was
+ * already successfully reallocated. The next time
+ * we call select_dispatch, the realloc will be a
+ * no-op. */
+ return (-1);
+ }
+ sop->event_writeset_out = writeset_out;
+ sop->resize_out_sets = 0;
+ }
+
+ memcpy(sop->event_readset_out, sop->event_readset_in,
+ sop->event_fdsz);
+ memcpy(sop->event_writeset_out, sop->event_writeset_in,
+ sop->event_fdsz);
+
+ nfds = sop->event_fds+1;
+
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ res = select(nfds, sop->event_readset_out,
+ sop->event_writeset_out, NULL, tv);
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ check_selectop(sop);
+
+ if (res == -1) {
+ if (errno != EINTR) {
+ event_warn("select");
+ return (-1);
+ }
+
+ return (0);
+ }
+
+ event_debug(("%s: select reports %d", __func__, res));
+
+ check_selectop(sop);
+ i = evutil_weakrand_range_(&base->weakrand_seed, nfds);
+ for (j = 0; j < nfds; ++j) {
+ if (++i >= nfds)
+ i = 0;
+ res = 0;
+ if (FD_ISSET(i, sop->event_readset_out))
+ res |= EV_READ;
+ if (FD_ISSET(i, sop->event_writeset_out))
+ res |= EV_WRITE;
+
+ if (res == 0)
+ continue;
+
+ evmap_io_active_(base, i, res);
+ }
+ check_selectop(sop);
+
+ return (0);
+}
+
+static int
+select_resize(struct selectop *sop, int fdsz)
+{
+ fd_set *readset_in = NULL;
+ fd_set *writeset_in = NULL;
+
+ if (sop->event_readset_in)
+ check_selectop(sop);
+
+ if ((readset_in = mm_realloc(sop->event_readset_in, fdsz)) == NULL)
+ goto error;
+ sop->event_readset_in = readset_in;
+ if ((writeset_in = mm_realloc(sop->event_writeset_in, fdsz)) == NULL) {
+ /* Note that this will leave event_readset_in expanded.
+ * That's okay; we wouldn't want to free it, since that would
+ * change the semantics of select_resize from "expand the
+ * readset_in and writeset_in, or return -1" to "expand the
+ * *set_in members, or trash them and return -1."
+ */
+ goto error;
+ }
+ sop->event_writeset_in = writeset_in;
+ sop->resize_out_sets = 1;
+
+ memset((char *)sop->event_readset_in + sop->event_fdsz, 0,
+ fdsz - sop->event_fdsz);
+ memset((char *)sop->event_writeset_in + sop->event_fdsz, 0,
+ fdsz - sop->event_fdsz);
+
+ sop->event_fdsz = fdsz;
+ check_selectop(sop);
+
+ return (0);
+
+ error:
+ event_warn("malloc");
+ return (-1);
+}
+
+
+static int
+select_add(struct event_base *base, int fd, short old, short events, void *p)
+{
+ struct selectop *sop = base->evbase;
+ (void) p;
+
+ EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
+ check_selectop(sop);
+ /*
+ * Keep track of the highest fd, so that we can calculate the size
+ * of the fd_sets for select(2)
+ */
+ if (sop->event_fds < fd) {
+ int fdsz = sop->event_fdsz;
+
+ if (fdsz < (int)sizeof(fd_mask))
+ fdsz = (int)sizeof(fd_mask);
+
+ /* In theory we should worry about overflow here. In
+ * reality, though, the highest fd on a unixy system will
+ * not overflow here. XXXX */
+ while (fdsz < (int) SELECT_ALLOC_SIZE(fd + 1))
+ fdsz *= 2;
+
+ if (fdsz != sop->event_fdsz) {
+ if (select_resize(sop, fdsz)) {
+ check_selectop(sop);
+ return (-1);
+ }
+ }
+
+ sop->event_fds = fd;
+ }
+
+ if (events & EV_READ)
+ FD_SET(fd, sop->event_readset_in);
+ if (events & EV_WRITE)
+ FD_SET(fd, sop->event_writeset_in);
+ check_selectop(sop);
+
+ return (0);
+}
+
+/*
+ * Nothing to be done here.
+ */
+
+static int
+select_del(struct event_base *base, int fd, short old, short events, void *p)
+{
+ struct selectop *sop = base->evbase;
+ (void)p;
+
+ EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
+ check_selectop(sop);
+
+ if (sop->event_fds < fd) {
+ check_selectop(sop);
+ return (0);
+ }
+
+ if (events & EV_READ)
+ FD_CLR(fd, sop->event_readset_in);
+
+ if (events & EV_WRITE)
+ FD_CLR(fd, sop->event_writeset_in);
+
+ check_selectop(sop);
+ return (0);
+}
+
+static void
+select_free_selectop(struct selectop *sop)
+{
+ if (sop->event_readset_in)
+ mm_free(sop->event_readset_in);
+ if (sop->event_writeset_in)
+ mm_free(sop->event_writeset_in);
+ if (sop->event_readset_out)
+ mm_free(sop->event_readset_out);
+ if (sop->event_writeset_out)
+ mm_free(sop->event_writeset_out);
+
+ memset(sop, 0, sizeof(struct selectop));
+ mm_free(sop);
+}
+
+static void
+select_dealloc(struct event_base *base)
+{
+ evsig_dealloc_(base);
+
+ select_free_selectop(base->evbase);
+}
+
+#endif /* EVENT__HAVE_SELECT */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/signal.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/signal.c
new file mode 100644
index 000000000..3f4629502
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/signal.c
@@ -0,0 +1,479 @@
+/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
+
+/*
+ * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+#include <sys/types.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#ifdef EVENT__HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event-internal.h"
+#include "event2/util.h"
+#include "evsignal-internal.h"
+#include "log-internal.h"
+#include "evmap-internal.h"
+#include "evthread-internal.h"
+
+/*
+ signal.c
+
+ This is the signal-handling implementation we use for backends that don't
+ have a better way to do signal handling. It uses sigaction() or signal()
+ to set a signal handler, and a socket pair to tell the event base when
+
+ Note that I said "the event base" : only one event base can be set up to use
+ this at a time. For historical reasons and backward compatibility, if you
+ add an event for a signal to event_base A, then add an event for a signal
+ (any signal!) to event_base B, event_base B will get informed about the
+ signal, but event_base A won't.
+
+ It would be neat to change this behavior in some future version of Libevent.
+ kqueue already does something far more sensible. We can make all backends
+ on Linux do a reasonable thing using signalfd.
+*/
+
+#ifndef _WIN32
+/* Windows wants us to call our signal handlers as __cdecl. Nobody else
+ * expects you to do anything crazy like this. */
+#define __cdecl
+#endif
+
+static int evsig_add(struct event_base *, evutil_socket_t, short, short, void *);
+static int evsig_del(struct event_base *, evutil_socket_t, short, short, void *);
+
+static const struct eventop evsigops = {
+ "signal",
+ NULL,
+ evsig_add,
+ evsig_del,
+ NULL,
+ NULL,
+ 0, 0, 0
+};
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+/* Lock for evsig_base and evsig_base_n_signals_added fields. */
+static void *evsig_base_lock = NULL;
+#endif
+/* The event base that's currently getting informed about signals. */
+static struct event_base *evsig_base = NULL;
+/* A copy of evsig_base->sigev_n_signals_added. */
+static int evsig_base_n_signals_added = 0;
+static evutil_socket_t evsig_base_fd = -1;
+
+static void __cdecl evsig_handler(int sig);
+
+#define EVSIGBASE_LOCK() EVLOCK_LOCK(evsig_base_lock, 0)
+#define EVSIGBASE_UNLOCK() EVLOCK_UNLOCK(evsig_base_lock, 0)
+
+void
+evsig_set_base_(struct event_base *base)
+{
+ EVSIGBASE_LOCK();
+ evsig_base = base;
+ evsig_base_n_signals_added = base->sig.ev_n_signals_added;
+ evsig_base_fd = base->sig.ev_signal_pair[1];
+ EVSIGBASE_UNLOCK();
+}
+
+/* Callback for when the signal handler write a byte to our signaling socket */
+static void
+evsig_cb(evutil_socket_t fd, short what, void *arg)
+{
+ static char signals[1024];
+ ev_ssize_t n;
+ int i;
+ int ncaught[NSIG];
+ struct event_base *base;
+
+ base = arg;
+
+ memset(&ncaught, 0, sizeof(ncaught));
+
+ while (1) {
+#ifdef _WIN32
+ n = recv(fd, signals, sizeof(signals), 0);
+#else
+ n = read(fd, signals, sizeof(signals));
+#endif
+ if (n == -1) {
+ int err = evutil_socket_geterror(fd);
+ if (! EVUTIL_ERR_RW_RETRIABLE(err))
+ event_sock_err(1, fd, "%s: recv", __func__);
+ break;
+ } else if (n == 0) {
+ /* XXX warn? */
+ break;
+ }
+ for (i = 0; i < n; ++i) {
+ ev_uint8_t sig = signals[i];
+ if (sig < NSIG)
+ ncaught[sig]++;
+ }
+ }
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ for (i = 0; i < NSIG; ++i) {
+ if (ncaught[i])
+ evmap_signal_active_(base, i, ncaught[i]);
+ }
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
+
+int
+evsig_init_(struct event_base *base)
+{
+ /*
+ * Our signal handler is going to write to one end of the socket
+ * pair to wake up our event loop. The event loop then scans for
+ * signals that got delivered.
+ */
+ if (evutil_make_internal_pipe_(base->sig.ev_signal_pair) == -1) {
+#ifdef _WIN32
+ /* Make this nonfatal on win32, where sometimes people
+ have localhost firewalled. */
+ event_sock_warn(-1, "%s: socketpair", __func__);
+#else
+ event_sock_err(1, -1, "%s: socketpair", __func__);
+#endif
+ return -1;
+ }
+
+ if (base->sig.sh_old) {
+ mm_free(base->sig.sh_old);
+ }
+ base->sig.sh_old = NULL;
+ base->sig.sh_old_max = 0;
+
+ event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[0],
+ EV_READ | EV_PERSIST, evsig_cb, base);
+
+ base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
+ event_priority_set(&base->sig.ev_signal, 0);
+
+ base->evsigsel = &evsigops;
+
+ return 0;
+}
+
+/* Helper: set the signal handler for evsignal to handler in base, so that
+ * we can restore the original handler when we clear the current one. */
+int
+evsig_set_handler_(struct event_base *base,
+ int evsignal, void (__cdecl *handler)(int))
+{
+#ifdef EVENT__HAVE_SIGACTION
+ struct sigaction sa;
+#else
+ ev_sighandler_t sh;
+#endif
+ struct evsig_info *sig = &base->sig;
+ void *p;
+
+ /*
+ * resize saved signal handler array up to the highest signal number.
+ * a dynamic array is used to keep footprint on the low side.
+ */
+ if (evsignal >= sig->sh_old_max) {
+ int new_max = evsignal + 1;
+ event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
+ __func__, evsignal, sig->sh_old_max));
+ p = mm_realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
+ if (p == NULL) {
+ event_warn("realloc");
+ return (-1);
+ }
+
+ memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
+ 0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
+
+ sig->sh_old_max = new_max;
+ sig->sh_old = p;
+ }
+
+ /* allocate space for previous handler out of dynamic array */
+ sig->sh_old[evsignal] = mm_malloc(sizeof *sig->sh_old[evsignal]);
+ if (sig->sh_old[evsignal] == NULL) {
+ event_warn("malloc");
+ return (-1);
+ }
+
+ /* save previous handler and setup new handler */
+#ifdef EVENT__HAVE_SIGACTION
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = handler;
+ sa.sa_flags |= SA_RESTART;
+ sigfillset(&sa.sa_mask);
+
+ if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
+ event_warn("sigaction");
+ mm_free(sig->sh_old[evsignal]);
+ sig->sh_old[evsignal] = NULL;
+ return (-1);
+ }
+#else
+ if ((sh = signal(evsignal, handler)) == SIG_ERR) {
+ event_warn("signal");
+ mm_free(sig->sh_old[evsignal]);
+ sig->sh_old[evsignal] = NULL;
+ return (-1);
+ }
+ *sig->sh_old[evsignal] = sh;
+#endif
+
+ return (0);
+}
+
+static int
+evsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
+{
+ struct evsig_info *sig = &base->sig;
+ (void)p;
+
+ EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
+
+ /* catch signals if they happen quickly */
+ EVSIGBASE_LOCK();
+ if (evsig_base != base && evsig_base_n_signals_added) {
+ event_warnx("Added a signal to event base %p with signals "
+ "already added to event_base %p. Only one can have "
+ "signals at a time with the %s backend. The base with "
+ "the most recently added signal or the most recent "
+ "event_base_loop() call gets preference; do "
+ "not rely on this behavior in future Libevent versions.",
+ base, evsig_base, base->evsel->name);
+ }
+ evsig_base = base;
+ evsig_base_n_signals_added = ++sig->ev_n_signals_added;
+ evsig_base_fd = base->sig.ev_signal_pair[1];
+ EVSIGBASE_UNLOCK();
+
+ event_debug(("%s: %d: changing signal handler", __func__, (int)evsignal));
+ if (evsig_set_handler_(base, (int)evsignal, evsig_handler) == -1) {
+ goto err;
+ }
+
+
+ if (!sig->ev_signal_added) {
+ if (event_add_nolock_(&sig->ev_signal, NULL, 0))
+ goto err;
+ sig->ev_signal_added = 1;
+ }
+
+ return (0);
+
+err:
+ EVSIGBASE_LOCK();
+ --evsig_base_n_signals_added;
+ --sig->ev_n_signals_added;
+ EVSIGBASE_UNLOCK();
+ return (-1);
+}
+
+int
+evsig_restore_handler_(struct event_base *base, int evsignal)
+{
+ int ret = 0;
+ struct evsig_info *sig = &base->sig;
+#ifdef EVENT__HAVE_SIGACTION
+ struct sigaction *sh;
+#else
+ ev_sighandler_t *sh;
+#endif
+
+ if (evsignal >= sig->sh_old_max) {
+ /* Can't actually restore. */
+ /* XXXX.*/
+ return 0;
+ }
+
+ /* restore previous handler */
+ sh = sig->sh_old[evsignal];
+ sig->sh_old[evsignal] = NULL;
+#ifdef EVENT__HAVE_SIGACTION
+ if (sigaction(evsignal, sh, NULL) == -1) {
+ event_warn("sigaction");
+ ret = -1;
+ }
+#else
+ if (signal(evsignal, *sh) == SIG_ERR) {
+ event_warn("signal");
+ ret = -1;
+ }
+#endif
+
+ mm_free(sh);
+
+ return ret;
+}
+
+static int
+evsig_del(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
+{
+ EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
+
+ event_debug(("%s: "EV_SOCK_FMT": restoring signal handler",
+ __func__, EV_SOCK_ARG(evsignal)));
+
+ EVSIGBASE_LOCK();
+ --evsig_base_n_signals_added;
+ --base->sig.ev_n_signals_added;
+ EVSIGBASE_UNLOCK();
+
+ return (evsig_restore_handler_(base, (int)evsignal));
+}
+
+static void __cdecl
+evsig_handler(int sig)
+{
+ int save_errno = errno;
+#ifdef _WIN32
+ int socket_errno = EVUTIL_SOCKET_ERROR();
+#endif
+ ev_uint8_t msg;
+
+ if (evsig_base == NULL) {
+ event_warnx(
+ "%s: received signal %d, but have no base configured",
+ __func__, sig);
+ return;
+ }
+
+#ifndef EVENT__HAVE_SIGACTION
+ signal(sig, evsig_handler);
+#endif
+
+ /* Wake up our notification mechanism */
+ msg = sig;
+#ifdef _WIN32
+ send(evsig_base_fd, (char*)&msg, 1, 0);
+#else
+ {
+ int r = write(evsig_base_fd, (char*)&msg, 1);
+ (void)r; /* Suppress 'unused return value' and 'unused var' */
+ }
+#endif
+ errno = save_errno;
+#ifdef _WIN32
+ EVUTIL_SET_SOCKET_ERROR(socket_errno);
+#endif
+}
+
+void
+evsig_dealloc_(struct event_base *base)
+{
+ int i = 0;
+ if (base->sig.ev_signal_added) {
+ event_del(&base->sig.ev_signal);
+ base->sig.ev_signal_added = 0;
+ }
+ /* debug event is created in evsig_init_/event_assign even when
+ * ev_signal_added == 0, so unassign is required */
+ event_debug_unassign(&base->sig.ev_signal);
+
+ for (i = 0; i < NSIG; ++i) {
+ if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
+ evsig_restore_handler_(base, i);
+ }
+ EVSIGBASE_LOCK();
+ if (base == evsig_base) {
+ evsig_base = NULL;
+ evsig_base_n_signals_added = 0;
+ evsig_base_fd = -1;
+ }
+ EVSIGBASE_UNLOCK();
+
+ if (base->sig.ev_signal_pair[0] != -1) {
+ evutil_closesocket(base->sig.ev_signal_pair[0]);
+ base->sig.ev_signal_pair[0] = -1;
+ }
+ if (base->sig.ev_signal_pair[1] != -1) {
+ evutil_closesocket(base->sig.ev_signal_pair[1]);
+ base->sig.ev_signal_pair[1] = -1;
+ }
+ base->sig.sh_old_max = 0;
+
+ /* per index frees are handled in evsig_del() */
+ if (base->sig.sh_old) {
+ mm_free(base->sig.sh_old);
+ base->sig.sh_old = NULL;
+ }
+}
+
+static void
+evsig_free_globals_locks(void)
+{
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ if (evsig_base_lock != NULL) {
+ EVTHREAD_FREE_LOCK(evsig_base_lock, 0);
+ evsig_base_lock = NULL;
+ }
+#endif
+ return;
+}
+
+void
+evsig_free_globals_(void)
+{
+ evsig_free_globals_locks();
+}
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+int
+evsig_global_setup_locks_(const int enable_locks)
+{
+ EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock, 0);
+ return 0;
+}
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/strlcpy-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/strlcpy-internal.h
new file mode 100644
index 000000000..cfc27ec66
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/strlcpy-internal.h
@@ -0,0 +1,22 @@
+#ifndef STRLCPY_INTERNAL_H_INCLUDED_
+#define STRLCPY_INTERNAL_H_INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifndef EVENT__HAVE_STRLCPY
+#include <string.h>
+size_t event_strlcpy_(char *dst, const char *src, size_t siz);
+#define strlcpy event_strlcpy_
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/strlcpy.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/strlcpy.c
new file mode 100644
index 000000000..3876475f5
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/strlcpy.c
@@ -0,0 +1,75 @@
+/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
+
+#ifndef EVENT__HAVE_STRLCPY
+#include "strlcpy-internal.h"
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+event_strlcpy_(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return (s - src - 1); /* count does not include NUL */
+}
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/Makefile.nmake b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/Makefile.nmake
new file mode 100644
index 000000000..30c3eb792
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/Makefile.nmake
@@ -0,0 +1,79 @@
+# WATCH OUT! This makefile is a work in progress. -*- makefile -*-
+
+!IFDEF OPENSSL_DIR
+SSL_CFLAGS=/I$(OPENSSL_DIR)\include /DEVENT__HAVE_OPENSSL
+SSL_OBJS=regress_ssl.obj
+SSL_LIBS=..\libevent_openssl.lib $(OPENSSL_DIR)\lib\libeay32.lib $(OPENSSL_DIR)\lib\ssleay32.lib gdi32.lib User32.lib
+!ELSE
+SSL_CFLAGS=
+SSL_OBJS=
+SSL_LIBS=
+!ENDIF
+
+CFLAGS=/I.. /I../WIN32-Code /I../WIN32-Code/nmake /I../include /I../compat /DHAVE_CONFIG_H /DTINYTEST_LOCAL $(SSL_CFLAGS)
+
+CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo
+
+REGRESS_OBJS=regress.obj regress_buffer.obj regress_http.obj regress_dns.obj \
+ regress_testutils.obj \
+ regress_rpc.obj regress.gen.obj \
+ regress_et.obj regress_bufferevent.obj \
+ regress_listener.obj regress_util.obj tinytest.obj \
+ regress_main.obj regress_minheap.obj regress_iocp.obj \
+ regress_thread.obj regress_finalize.obj $(SSL_OBJS)
+
+OTHER_OBJS=test-init.obj test-eof.obj test-closed.obj test-weof.obj test-time.obj \
+ bench.obj bench_cascade.obj bench_http.obj bench_httpclient.obj \
+ test-changelist.obj \
+ print-winsock-errors.obj
+
+PROGRAMS=regress.exe \
+ test-init.exe test-eof.exe test-closed.exe test-weof.exe test-time.exe \
+ test-changelist.exe \
+ print-winsock-errors.exe
+
+# Disabled for now:
+# bench.exe bench_cascade.exe bench_http.exe bench_httpclient.exe
+
+
+LIBS=..\libevent.lib ws2_32.lib shell32.lib advapi32.lib
+
+all: $(PROGRAMS)
+
+regress.exe: $(REGRESS_OBJS)
+ $(CC) $(CFLAGS) $(LIBS) $(SSL_LIBS) $(REGRESS_OBJS)
+
+test-init.exe: test-init.obj
+ $(CC) $(CFLAGS) $(LIBS) test-init.obj
+test-eof.exe: test-eof.obj
+ $(CC) $(CFLAGS) $(LIBS) test-eof.obj
+test-closed.exe: test-closed.obj
+ $(CC) $(CFLAGS) $(LIBS) test-closed.obj
+test-changelist.exe: test-changelist.obj
+ $(CC) $(CFLAGS) $(LIBS) test-changelist.obj
+test-weof.exe: test-weof.obj
+ $(CC) $(CFLAGS) $(LIBS) test-weof.obj
+test-time.exe: test-time.obj
+ $(CC) $(CFLAGS) $(LIBS) test-time.obj
+
+print-winsock-errors.exe: print-winsock-errors.obj
+ $(CC) $(CFLAGS) $(LIBS) print-winsock-errors.obj
+
+bench.exe: bench.obj
+ $(CC) $(CFLAGS) $(LIBS) bench.obj
+bench_cascade.exe: bench_cascade.obj
+ $(CC) $(CFLAGS) $(LIBS) bench_cascade.obj
+bench_http.exe: bench_http.obj
+ $(CC) $(CFLAGS) $(LIBS) bench_http.obj
+bench_httpclient.exe: bench_httpclient.obj
+ $(CC) $(CFLAGS) $(LIBS) bench_httpclient.obj
+
+regress.gen.c regress.gen.h: regress.rpc ../event_rpcgen.py
+ echo // > regress.gen.c
+ echo #define NO_PYTHON_EXISTS > regress.gen.h
+ -python ..\event_rpcgen.py regress.rpc
+
+clean:
+ -del $(REGRESS_OBJS)
+ -del $(OTHER_OBJS)
+ -del $(PROGRAMS)
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench.c
new file mode 100644
index 000000000..214479c1f
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * Mon 03/10/2003 - Modified by Davide Libenzi <davidel@xmailserver.org>
+ *
+ * Added chain event propagation to improve the sensitivity of
+ * the measure respect to the event loop efficency.
+ *
+ *
+ */
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else
+#include <sys/socket.h>
+#include <signal.h>
+#include <sys/resource.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#ifdef _WIN32
+#include <getopt.h>
+#endif
+
+#include <event.h>
+#include <evutil.h>
+
+static int count, writes, fired, failures;
+static evutil_socket_t *pipes;
+static int num_pipes, num_active, num_writes;
+static struct event *events;
+
+
+static void
+read_cb(evutil_socket_t fd, short which, void *arg)
+{
+ ev_intptr_t idx = (ev_intptr_t) arg, widx = idx + 1;
+ unsigned char ch;
+ ev_ssize_t n;
+
+ n = recv(fd, (char*)&ch, sizeof(ch), 0);
+ if (n >= 0)
+ count += n;
+ else
+ failures++;
+ if (writes) {
+ if (widx >= num_pipes)
+ widx -= num_pipes;
+ n = send(pipes[2 * widx + 1], "e", 1, 0);
+ if (n != 1)
+ failures++;
+ writes--;
+ fired++;
+ }
+}
+
+static struct timeval *
+run_once(void)
+{
+ evutil_socket_t *cp, space;
+ long i;
+ static struct timeval ts, te;
+
+ for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
+ if (event_initialized(&events[i]))
+ event_del(&events[i]);
+ event_set(&events[i], cp[0], EV_READ | EV_PERSIST, read_cb, (void *)(ev_intptr_t) i);
+ event_add(&events[i], NULL);
+ }
+
+ event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK);
+
+ fired = 0;
+ space = num_pipes / num_active;
+ space = space * 2;
+ for (i = 0; i < num_active; i++, fired++)
+ (void) send(pipes[i * space + 1], "e", 1, 0);
+
+ count = 0;
+ writes = num_writes;
+ { int xcount = 0;
+ evutil_gettimeofday(&ts, NULL);
+ do {
+ event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK);
+ xcount++;
+ } while (count != fired);
+ evutil_gettimeofday(&te, NULL);
+
+ if (xcount != count) fprintf(stderr, "Xcount: %d, Rcount: %d\n", xcount, count);
+ }
+
+ evutil_timersub(&te, &ts, &te);
+
+ return (&te);
+}
+
+int
+main(int argc, char **argv)
+{
+#ifdef HAVE_SETRLIMIT
+ struct rlimit rl;
+#endif
+ int i, c;
+ struct timeval *tv;
+ evutil_socket_t *cp;
+
+#ifdef _WIN32
+ WSADATA WSAData;
+ WSAStartup(0x101, &WSAData);
+#endif
+ num_pipes = 100;
+ num_active = 1;
+ num_writes = num_pipes;
+ while ((c = getopt(argc, argv, "n:a:w:")) != -1) {
+ switch (c) {
+ case 'n':
+ num_pipes = atoi(optarg);
+ break;
+ case 'a':
+ num_active = atoi(optarg);
+ break;
+ case 'w':
+ num_writes = atoi(optarg);
+ break;
+ default:
+ fprintf(stderr, "Illegal argument \"%c\"\n", c);
+ exit(1);
+ }
+ }
+
+#ifdef HAVE_SETRLIMIT
+ rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
+ if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
+ perror("setrlimit");
+ exit(1);
+ }
+#endif
+
+ events = calloc(num_pipes, sizeof(struct event));
+ pipes = calloc(num_pipes * 2, sizeof(evutil_socket_t));
+ if (events == NULL || pipes == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ event_init();
+
+ for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
+#ifdef USE_PIPES
+ if (pipe(cp) == -1) {
+#else
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) {
+#endif
+ perror("pipe");
+ exit(1);
+ }
+ }
+
+ for (i = 0; i < 25; i++) {
+ tv = run_once();
+ if (tv == NULL)
+ exit(1);
+ fprintf(stdout, "%ld\n",
+ tv->tv_sec * 1000000L + tv->tv_usec);
+ }
+
+ exit(0);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench_cascade.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench_cascade.c
new file mode 100644
index 000000000..2d85cc1f1
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench_cascade.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else
+#include <sys/socket.h>
+#include <sys/resource.h>
+#endif
+#include <signal.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <getopt.h>
+#include <event.h>
+#include <evutil.h>
+
+/*
+ * This benchmark tests how quickly we can propagate a write down a chain
+ * of socket pairs. We start by writing to the first socket pair and all
+ * events will fire subsequently until the last socket pair has been reached
+ * and the benchmark terminates.
+ */
+
+static int fired;
+static evutil_socket_t *pipes;
+static struct event *events;
+
+static void
+read_cb(evutil_socket_t fd, short which, void *arg)
+{
+ char ch;
+ evutil_socket_t sock = (evutil_socket_t)(ev_intptr_t)arg;
+
+ (void) recv(fd, &ch, sizeof(ch), 0);
+ if (sock >= 0) {
+ if (send(sock, "e", 1, 0) < 0)
+ perror("send");
+ }
+ fired++;
+}
+
+static struct timeval *
+run_once(int num_pipes)
+{
+ int i;
+ evutil_socket_t *cp;
+ static struct timeval ts, te, tv_timeout;
+
+ events = (struct event *)calloc(num_pipes, sizeof(struct event));
+ pipes = (evutil_socket_t *)calloc(num_pipes * 2, sizeof(evutil_socket_t));
+
+ if (events == NULL || pipes == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) {
+ perror("socketpair");
+ exit(1);
+ }
+ }
+
+ /* measurements includes event setup */
+ evutil_gettimeofday(&ts, NULL);
+
+ /* provide a default timeout for events */
+ evutil_timerclear(&tv_timeout);
+ tv_timeout.tv_sec = 60;
+
+ for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
+ evutil_socket_t fd = i < num_pipes - 1 ? cp[3] : -1;
+ event_set(&events[i], cp[0], EV_READ, read_cb,
+ (void *)(ev_intptr_t)fd);
+ event_add(&events[i], &tv_timeout);
+ }
+
+ fired = 0;
+
+ /* kick everything off with a single write */
+ if (send(pipes[1], "e", 1, 0) < 0)
+ perror("send");
+
+ event_dispatch();
+
+ evutil_gettimeofday(&te, NULL);
+ evutil_timersub(&te, &ts, &te);
+
+ for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
+ event_del(&events[i]);
+ evutil_closesocket(cp[0]);
+ evutil_closesocket(cp[1]);
+ }
+
+ free(pipes);
+ free(events);
+
+ return (&te);
+}
+
+int
+main(int argc, char **argv)
+{
+#ifdef HAVE_SETRLIMIT
+ struct rlimit rl;
+#endif
+ int i, c;
+ struct timeval *tv;
+
+ int num_pipes = 100;
+#ifdef _WIN32
+ WSADATA WSAData;
+ WSAStartup(0x101, &WSAData);
+#endif
+
+ while ((c = getopt(argc, argv, "n:")) != -1) {
+ switch (c) {
+ case 'n':
+ num_pipes = atoi(optarg);
+ break;
+ default:
+ fprintf(stderr, "Illegal argument \"%c\"\n", c);
+ exit(1);
+ }
+ }
+
+#ifdef HAVE_SETRLIMIT
+ rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
+ if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
+ perror("setrlimit");
+ exit(1);
+ }
+#endif
+
+ event_init();
+
+ for (i = 0; i < 25; i++) {
+ tv = run_once(num_pipes);
+ if (tv == NULL)
+ exit(1);
+ fprintf(stdout, "%ld\n",
+ tv->tv_sec * 1000000L + tv->tv_usec);
+ }
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
+ exit(0);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench_http.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench_http.c
new file mode 100644
index 000000000..d20d3bc79
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench_http.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2008-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event2/event.h"
+#include "event2/buffer.h"
+#include "event2/util.h"
+#include "event2/http.h"
+#include "event2/thread.h"
+
+static void http_basic_cb(struct evhttp_request *req, void *arg);
+
+static char *content;
+static size_t content_len = 0;
+
+static void
+http_basic_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb = evbuffer_new();
+
+ evbuffer_add(evb, content, content_len);
+
+ /* allow sending of an empty reply */
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+ evbuffer_free(evb);
+}
+
+#if LIBEVENT_VERSION_NUMBER >= 0x02000200
+static void
+http_ref_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb = evbuffer_new();
+
+ evbuffer_add_reference(evb, content, content_len, NULL, NULL);
+
+ /* allow sending of an empty reply */
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+ evbuffer_free(evb);
+}
+#endif
+
+int
+main(int argc, char **argv)
+{
+ struct event_config *cfg = event_config_new();
+ struct event_base *base;
+ struct evhttp *http;
+ int i;
+ int c;
+ int use_iocp = 0;
+ ev_uint16_t port = 8080;
+ char *endptr = NULL;
+
+#ifdef _WIN32
+ WSADATA WSAData;
+ WSAStartup(0x101, &WSAData);
+#else
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+ return (1);
+#endif
+
+ for (i = 1; i < argc; ++i) {
+ if (*argv[i] != '-')
+ continue;
+
+ c = argv[i][1];
+
+ if ((c == 'p' || c == 'l') && i + 1 >= argc) {
+ fprintf(stderr, "-%c requires argument.\n", c);
+ exit(1);
+ }
+
+ switch (c) {
+ case 'p':
+ if (i+1 >= argc || !argv[i+1]) {
+ fprintf(stderr, "Missing port\n");
+ exit(1);
+ }
+ port = (int)strtol(argv[i+1], &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Bad port\n");
+ exit(1);
+ }
+ break;
+ case 'l':
+ if (i+1 >= argc || !argv[i+1]) {
+ fprintf(stderr, "Missing content length\n");
+ exit(1);
+ }
+ content_len = (size_t)strtol(argv[i+1], &endptr, 10);
+ if (*endptr != '\0' || content_len == 0) {
+ fprintf(stderr, "Bad content length\n");
+ exit(1);
+ }
+ break;
+#ifdef _WIN32
+ case 'i':
+ use_iocp = 1;
+#ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
+ evthread_use_windows_threads();
+#endif
+ event_config_set_flag(cfg,EVENT_BASE_FLAG_STARTUP_IOCP);
+ break;
+#endif
+ default:
+ fprintf(stderr, "Illegal argument \"%c\"\n", c);
+ exit(1);
+ }
+ }
+
+ base = event_base_new_with_config(cfg);
+ if (!base) {
+ fprintf(stderr, "creating event_base failed. Exiting.\n");
+ return 1;
+ }
+
+ http = evhttp_new(base);
+
+ content = malloc(content_len);
+ if (content == NULL) {
+ fprintf(stderr, "Cannot allocate content\n");
+ exit(1);
+ } else {
+ int i = 0;
+ for (i = 0; i < (int)content_len; ++i)
+ content[i] = (i & 255);
+ }
+
+ evhttp_set_cb(http, "/ind", http_basic_cb, NULL);
+ fprintf(stderr, "/ind - basic content (memory copy)\n");
+
+ evhttp_set_cb(http, "/ref", http_ref_cb, NULL);
+ fprintf(stderr, "/ref - basic content (reference)\n");
+
+ fprintf(stderr, "Serving %d bytes on port %d using %s\n",
+ (int)content_len, port,
+ use_iocp? "IOCP" : event_base_get_method(base));
+
+ evhttp_bind_socket(http, "0.0.0.0", port);
+
+#ifdef _WIN32
+ if (use_iocp) {
+ struct timeval tv={99999999,0};
+ event_base_loopexit(base, &tv);
+ }
+#endif
+ event_base_dispatch(base);
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
+ /* NOTREACHED */
+ return (0);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench_httpclient.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench_httpclient.c
new file mode 100644
index 000000000..e15929519
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/bench_httpclient.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* for EVUTIL_ERR_CONNECT_RETRIABLE macro */
+#include "util-internal.h"
+
+#include <sys/types.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event2/event.h"
+#include "event2/bufferevent.h"
+#include "event2/buffer.h"
+#include "event2/util.h"
+
+const char *resource = NULL;
+struct event_base *base = NULL;
+
+int total_n_handled = 0;
+int total_n_errors = 0;
+int total_n_launched = 0;
+size_t total_n_bytes = 0;
+struct timeval total_time = {0,0};
+int n_errors = 0;
+
+const int PARALLELISM = 200;
+const int N_REQUESTS = 20000;
+
+struct request_info {
+ size_t n_read;
+ struct timeval started;
+};
+
+static int launch_request(void);
+static void readcb(struct bufferevent *b, void *arg);
+static void errorcb(struct bufferevent *b, short what, void *arg);
+
+static void
+readcb(struct bufferevent *b, void *arg)
+{
+ struct request_info *ri = arg;
+ struct evbuffer *input = bufferevent_get_input(b);
+ size_t n = evbuffer_get_length(input);
+
+ ri->n_read += n;
+ evbuffer_drain(input, n);
+}
+
+static void
+errorcb(struct bufferevent *b, short what, void *arg)
+{
+ struct request_info *ri = arg;
+ struct timeval now, diff;
+ if (what & BEV_EVENT_EOF) {
+ ++total_n_handled;
+ total_n_bytes += ri->n_read;
+ evutil_gettimeofday(&now, NULL);
+ evutil_timersub(&now, &ri->started, &diff);
+ evutil_timeradd(&diff, &total_time, &total_time);
+
+ if (total_n_handled && (total_n_handled%1000)==0)
+ printf("%d requests done\n",total_n_handled);
+
+ if (total_n_launched < N_REQUESTS) {
+ if (launch_request() < 0)
+ perror("Can't launch");
+ }
+ } else {
+ ++total_n_errors;
+ perror("Unexpected error");
+ }
+
+ bufferevent_setcb(b, NULL, NULL, NULL, NULL);
+ free(ri);
+ bufferevent_disable(b, EV_READ|EV_WRITE);
+ bufferevent_free(b);
+}
+
+static void
+frob_socket(evutil_socket_t sock)
+{
+#ifdef HAVE_SO_LINGER
+ struct linger l;
+#endif
+ int one = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one))<0)
+ perror("setsockopt(SO_REUSEADDR)");
+#ifdef HAVE_SO_LINGER
+ l.l_onoff = 1;
+ l.l_linger = 0;
+ if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&l, sizeof(l))<0)
+ perror("setsockopt(SO_LINGER)");
+#endif
+}
+
+static int
+launch_request(void)
+{
+ evutil_socket_t sock;
+ struct sockaddr_in sin;
+ struct bufferevent *b;
+
+ struct request_info *ri;
+
+ memset(&sin, 0, sizeof(sin));
+
+ ++total_n_launched;
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(0x7f000001);
+ sin.sin_port = htons(8080);
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ return -1;
+ if (evutil_make_socket_nonblocking(sock) < 0) {
+ evutil_closesocket(sock);
+ return -1;
+ }
+ frob_socket(sock);
+ if (connect(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
+ int e = evutil_socket_geterror(sock);
+ if (! EVUTIL_ERR_CONNECT_RETRIABLE(e)) {
+ evutil_closesocket(sock);
+ return -1;
+ }
+ }
+
+ ri = malloc(sizeof(*ri));
+ ri->n_read = 0;
+ evutil_gettimeofday(&ri->started, NULL);
+
+ b = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE);
+
+ bufferevent_setcb(b, readcb, NULL, errorcb, ri);
+ bufferevent_enable(b, EV_READ|EV_WRITE);
+
+ evbuffer_add_printf(bufferevent_get_output(b),
+ "GET %s HTTP/1.0\r\n\r\n", resource);
+
+ return 0;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ struct timeval start, end, total;
+ long long usec;
+ double throughput;
+
+#ifdef _WIN32
+ WSADATA WSAData;
+ WSAStartup(0x101, &WSAData);
+#endif
+
+ resource = "/ref";
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ base = event_base_new();
+
+ for (i=0; i < PARALLELISM; ++i) {
+ if (launch_request() < 0)
+ perror("launch");
+ }
+
+ evutil_gettimeofday(&start, NULL);
+
+ event_base_dispatch(base);
+
+ evutil_gettimeofday(&end, NULL);
+ evutil_timersub(&end, &start, &total);
+ usec = total_time.tv_sec * (long long)1000000 + total_time.tv_usec;
+
+ if (!total_n_handled) {
+ puts("Nothing worked. You probably did something dumb.");
+ return 0;
+ }
+
+
+ throughput = total_n_handled /
+ (total.tv_sec+ ((double)total.tv_usec)/1000000.0);
+
+#ifdef _WIN32
+#define I64_FMT "%I64d"
+#define I64_TYP __int64
+#else
+#define I64_FMT "%lld"
+#define I64_TYP long long int
+#endif
+
+ printf("\n%d requests in %d.%06d sec. (%.2f throughput)\n"
+ "Each took about %.02f msec latency\n"
+ I64_FMT "bytes read. %d errors.\n",
+ total_n_handled,
+ (int)total.tv_sec, (int)total.tv_usec,
+ throughput,
+ (double)(usec/1000) / total_n_handled,
+ (I64_TYP)total_n_bytes, n_errors);
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/check-dumpevents.py b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/check-dumpevents.py
new file mode 100755
index 000000000..16fe9bc92
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/check-dumpevents.py
@@ -0,0 +1,54 @@
+#!/usr/bin/python2
+#
+# Post-process the output of test-dumpevents and check it for correctness.
+#
+
+import math
+import re
+import sys
+
+text = sys.stdin.readlines()
+
+try:
+ expect_inserted_pos = text.index("Inserted:\n")
+ expect_active_pos = text.index("Active:\n")
+ got_inserted_pos = text.index("Inserted events:\n")
+ got_active_pos = text.index("Active events:\n")
+except ValueError:
+ print >>sys.stderr, "Missing expected dividing line in dumpevents output"
+ sys.exit(1)
+
+if not (expect_inserted_pos < expect_active_pos <
+ got_inserted_pos < got_active_pos):
+ print >>sys.stderr, "Sections out of order in dumpevents output"
+ sys.exit(1)
+
+now,T= text[1].split()
+T = float(T)
+
+want_inserted = set(text[expect_inserted_pos+1:expect_active_pos])
+want_active = set(text[expect_active_pos+1:got_inserted_pos-1])
+got_inserted = set(text[got_inserted_pos+1:got_active_pos])
+got_active = set(text[got_active_pos+1:])
+
+pat = re.compile(r'Timeout=([0-9\.]+)')
+def replace_time(m):
+ t = float(m.group(1))
+ if .9 < abs(t-T) < 1.1:
+ return "Timeout=T+1"
+ elif 2.4 < abs(t-T) < 2.6:
+ return "Timeout=T+2.5"
+ else:
+ return m.group(0)
+
+cleaned_inserted = set( pat.sub(replace_time, s) for s in got_inserted
+ if "Internal" not in s)
+
+if cleaned_inserted != want_inserted:
+ print >>sys.stderr, "Inserted event lists were not as expected!"
+ sys.exit(1)
+
+if set(got_active) != set(want_active):
+ print >>sys.stderr, "Active event lists were not as expected!"
+ sys.exit(1)
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/include.am b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/include.am
new file mode 100644
index 000000000..308813cd2
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/include.am
@@ -0,0 +1,148 @@
+# test/Makefile.am for libevent
+# Copyright 2000-2007 Niels Provos
+# Copyright 2007-2012 Niels Provos and Nick Mathewson
+#
+# See LICENSE for copying information.
+
+regress_CPPFLAGS = -DTINYTEST_LOCAL
+
+EXTRA_DIST+= \
+ test/check-dumpevents.py \
+ test/regress.gen.c \
+ test/regress.gen.h \
+ test/regress.rpc \
+ test/rpcgen_wrapper.sh \
+ test/test.sh
+
+TESTPROGRAMS = \
+ test/bench \
+ test/bench_cascade \
+ test/bench_http \
+ test/bench_httpclient \
+ test/test-changelist \
+ test/test-dumpevents \
+ test/test-eof \
+ test/test-closed \
+ test/test-fdleak \
+ test/test-init \
+ test/test-ratelim \
+ test/test-time \
+ test/test-weof \
+ test/regress
+
+if BUILD_REGRESS
+noinst_PROGRAMS += $(TESTPROGRAMS)
+EXTRA_PROGRAMS+= test/regress
+endif
+
+noinst_HEADERS+= \
+ test/regress.h \
+ test/regress_thread.h \
+ test/tinytest.h \
+ test/tinytest_local.h \
+ test/tinytest_macros.h
+
+# We need to copy this file, since automake doesn't want us to use top_srcdir
+# in TESTS.
+TESTS = test/test-script.sh
+
+test/test-script.sh: test/test.sh
+ cp $(top_srcdir)/test/test.sh $@
+
+DISTCLEANFILES += test/test-script.sh
+DISTCLEANFILES += test/regress.gen.c test/regress.gen.h
+
+if BUILD_REGRESS
+BUILT_SOURCES += test/regress.gen.c test/regress.gen.h
+endif
+
+test_test_init_SOURCES = test/test-init.c
+test_test_init_LDADD = libevent_core.la
+test_test_dumpevents_SOURCES = test/test-dumpevents.c
+test_test_dumpevents_LDADD = libevent_core.la
+test_test_eof_SOURCES = test/test-eof.c
+test_test_eof_LDADD = libevent_core.la
+test_test_closed_SOURCES = test/test-closed.c
+test_test_closed_LDADD = libevent_core.la
+test_test_changelist_SOURCES = test/test-changelist.c
+test_test_changelist_LDADD = libevent_core.la
+test_test_weof_SOURCES = test/test-weof.c
+test_test_weof_LDADD = libevent_core.la
+test_test_time_SOURCES = test/test-time.c
+test_test_time_LDADD = libevent_core.la
+test_test_ratelim_SOURCES = test/test-ratelim.c
+test_test_ratelim_LDADD = libevent_core.la -lm
+test_test_fdleak_SOURCES = test/test-fdleak.c
+test_test_fdleak_LDADD = libevent_core.la
+
+test_regress_SOURCES = \
+ test/regress.c \
+ test/regress.gen.c \
+ test/regress.gen.h \
+ test/regress_buffer.c \
+ test/regress_bufferevent.c \
+ test/regress_dns.c \
+ test/regress_et.c \
+ test/regress_finalize.c \
+ test/regress_http.c \
+ test/regress_listener.c \
+ test/regress_main.c \
+ test/regress_minheap.c \
+ test/regress_rpc.c \
+ test/regress_testutils.c \
+ test/regress_testutils.h \
+ test/regress_util.c \
+ test/tinytest.c \
+ $(regress_thread_SOURCES) \
+ $(regress_zlib_SOURCES)
+
+if PTHREADS
+regress_thread_SOURCES = test/regress_thread.c
+PTHREAD_LIBS += libevent_pthreads.la
+endif
+if BUILD_WIN32
+if THREADS
+regress_thread_SOURCES = test/regress_thread.c
+endif
+endif
+if ZLIB_REGRESS
+regress_zlib_SOURCES = test/regress_zlib.c
+endif
+if BUILD_WIN32
+test_regress_SOURCES += test/regress_iocp.c
+endif
+
+test_regress_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la $(PTHREAD_LIBS) $(ZLIB_LIBS)
+test_regress_CPPFLAGS = $(AM_CPPFLAGS) $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS) -Itest
+test_regress_LDFLAGS = $(PTHREAD_CFLAGS)
+
+if OPENSSL
+test_regress_SOURCES += test/regress_ssl.c
+test_regress_CPPFLAGS += $(OPENSSL_INCS)
+test_regress_LDADD += libevent_openssl.la $(OPENSSL_LIBS) ${OPENSSL_LIBADD}
+endif
+
+test_bench_SOURCES = test/bench.c
+test_bench_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
+test_bench_cascade_SOURCES = test/bench_cascade.c
+test_bench_cascade_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
+test_bench_http_SOURCES = test/bench_http.c
+test_bench_http_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
+test_bench_httpclient_SOURCES = test/bench_httpclient.c
+test_bench_httpclient_LDADD = $(LIBEVENT_GC_SECTIONS) libevent_core.la
+
+test/regress.gen.c test/regress.gen.h: test/rpcgen-attempted
+
+test/rpcgen-attempted: test/regress.rpc event_rpcgen.py test/rpcgen_wrapper.sh
+ $(AM_V_GEN)date -u > $@
+ $(AM_V_at)if $(srcdir)/test/rpcgen_wrapper.sh $(srcdir)/test; then \
+ true; \
+ else \
+ echo "No Python installed; stubbing out RPC test." >&2; \
+ echo " "> test/regress.gen.c; \
+ echo "#define NO_PYTHON_EXISTS" > test/regress.gen.h; \
+ fi
+
+CLEANFILES += test/rpcgen-attempted
+
+$(TESTPROGRAMS) : libevent.la
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/print-winsock-errors.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/print-winsock-errors.c
new file mode 100644
index 000000000..64d6b0e70
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/print-winsock-errors.c
@@ -0,0 +1,86 @@
+#include <winsock2.h>
+#include <windows.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "event2/event.h"
+#include "event2/util.h"
+#include "event2/thread.h"
+
+#define E(x) printf (#x " -> \"%s\"\n", evutil_socket_error_to_string (x));
+
+int main (int argc, char **argv)
+{
+ int i, j;
+ const char *s1, *s2;
+
+#ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
+ evthread_use_windows_threads ();
+#endif
+
+ s1 = evutil_socket_error_to_string (WSAEINTR);
+
+ for (i = 0; i < 3; i++) {
+ printf ("\niteration %d:\n\n", i);
+ E(WSAEINTR);
+ E(WSAEACCES);
+ E(WSAEFAULT);
+ E(WSAEINVAL);
+ E(WSAEMFILE);
+ E(WSAEWOULDBLOCK);
+ E(WSAEINPROGRESS);
+ E(WSAEALREADY);
+ E(WSAENOTSOCK);
+ E(WSAEDESTADDRREQ);
+ E(WSAEMSGSIZE);
+ E(WSAEPROTOTYPE);
+ E(WSAENOPROTOOPT);
+ E(WSAEPROTONOSUPPORT);
+ E(WSAESOCKTNOSUPPORT);
+ E(WSAEOPNOTSUPP);
+ E(WSAEPFNOSUPPORT);
+ E(WSAEAFNOSUPPORT);
+ E(WSAEADDRINUSE);
+ E(WSAEADDRNOTAVAIL);
+ E(WSAENETDOWN);
+ E(WSAENETUNREACH);
+ E(WSAENETRESET);
+ E(WSAECONNABORTED);
+ E(WSAECONNRESET);
+ E(WSAENOBUFS);
+ E(WSAEISCONN);
+ E(WSAENOTCONN);
+ E(WSAESHUTDOWN);
+ E(WSAETIMEDOUT);
+ E(WSAECONNREFUSED);
+ E(WSAEHOSTDOWN);
+ E(WSAEHOSTUNREACH);
+ E(WSAEPROCLIM);
+ E(WSASYSNOTREADY);
+ E(WSAVERNOTSUPPORTED);
+ E(WSANOTINITIALISED);
+ E(WSAEDISCON);
+ E(WSATYPE_NOT_FOUND);
+ E(WSAHOST_NOT_FOUND);
+ E(WSATRY_AGAIN);
+ E(WSANO_RECOVERY);
+ E(WSANO_DATA);
+ E(0xdeadbeef); /* test the case where no message is available */
+
+ /* fill up the hash table a bit to make sure it grows properly */
+ for (j = 0; j < 50; j++) {
+ int err;
+ evutil_secure_rng_get_bytes(&err, sizeof(err));
+ evutil_socket_error_to_string(err);
+ }
+ }
+
+ s2 = evutil_socket_error_to_string (WSAEINTR);
+ if (s1 != s2)
+ printf ("caching failed!\n");
+
+ libevent_global_shutdown ();
+
+ return EXIT_SUCCESS;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress.c
new file mode 100644
index 000000000..d8a6b9b85
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress.c
@@ -0,0 +1,3473 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util-internal.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#ifdef EVENT__HAVE_PTHREADS
+#include <pthread.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/event_compat.h"
+#include "event2/tag.h"
+#include "event2/buffer.h"
+#include "event2/buffer_compat.h"
+#include "event2/util.h"
+#include "event-internal.h"
+#include "evthread-internal.h"
+#include "log-internal.h"
+#include "time-internal.h"
+
+#include "regress.h"
+
+#ifndef _WIN32
+#include "regress.gen.h"
+#endif
+
+evutil_socket_t pair[2];
+int test_ok;
+int called;
+struct event_base *global_base;
+
+static char wbuf[4096];
+static char rbuf[4096];
+static int woff;
+static int roff;
+static int usepersist;
+static struct timeval tset;
+static struct timeval tcalled;
+
+
+#define TEST1 "this is a test"
+
+#ifdef _WIN32
+#define write(fd,buf,len) send((fd),(buf),(int)(len),0)
+#define read(fd,buf,len) recv((fd),(buf),(int)(len),0)
+#endif
+
+struct basic_cb_args
+{
+ struct event_base *eb;
+ struct event *ev;
+ unsigned int callcount;
+};
+
+static void
+simple_read_cb(evutil_socket_t fd, short event, void *arg)
+{
+ char buf[256];
+ int len;
+
+ len = read(fd, buf, sizeof(buf));
+
+ if (len) {
+ if (!called) {
+ if (event_add(arg, NULL) == -1)
+ exit(1);
+ }
+ } else if (called == 1)
+ test_ok = 1;
+
+ called++;
+}
+
+static void
+basic_read_cb(evutil_socket_t fd, short event, void *data)
+{
+ char buf[256];
+ int len;
+ struct basic_cb_args *arg = data;
+
+ len = read(fd, buf, sizeof(buf));
+
+ if (len < 0) {
+ tt_fail_perror("read (callback)");
+ } else {
+ switch (arg->callcount++) {
+ case 0: /* first call: expect to read data; cycle */
+ if (len > 0)
+ return;
+
+ tt_fail_msg("EOF before data read");
+ break;
+
+ case 1: /* second call: expect EOF; stop */
+ if (len > 0)
+ tt_fail_msg("not all data read on first cycle");
+ break;
+
+ default: /* third call: should not happen */
+ tt_fail_msg("too many cycles");
+ }
+ }
+
+ event_del(arg->ev);
+ event_base_loopexit(arg->eb, NULL);
+}
+
+static void
+dummy_read_cb(evutil_socket_t fd, short event, void *arg)
+{
+}
+
+static void
+simple_write_cb(evutil_socket_t fd, short event, void *arg)
+{
+ int len;
+
+ len = write(fd, TEST1, strlen(TEST1) + 1);
+ if (len == -1)
+ test_ok = 0;
+ else
+ test_ok = 1;
+}
+
+static void
+multiple_write_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct event *ev = arg;
+ int len;
+
+ len = 128;
+ if (woff + len >= (int)sizeof(wbuf))
+ len = sizeof(wbuf) - woff;
+
+ len = write(fd, wbuf + woff, len);
+ if (len == -1) {
+ fprintf(stderr, "%s: write\n", __func__);
+ if (usepersist)
+ event_del(ev);
+ return;
+ }
+
+ woff += len;
+
+ if (woff >= (int)sizeof(wbuf)) {
+ shutdown(fd, EVUTIL_SHUT_WR);
+ if (usepersist)
+ event_del(ev);
+ return;
+ }
+
+ if (!usepersist) {
+ if (event_add(ev, NULL) == -1)
+ exit(1);
+ }
+}
+
+static void
+multiple_read_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct event *ev = arg;
+ int len;
+
+ len = read(fd, rbuf + roff, sizeof(rbuf) - roff);
+ if (len == -1)
+ fprintf(stderr, "%s: read\n", __func__);
+ if (len <= 0) {
+ if (usepersist)
+ event_del(ev);
+ return;
+ }
+
+ roff += len;
+ if (!usepersist) {
+ if (event_add(ev, NULL) == -1)
+ exit(1);
+ }
+}
+
+static void
+timeout_cb(evutil_socket_t fd, short event, void *arg)
+{
+ evutil_gettimeofday(&tcalled, NULL);
+}
+
+struct both {
+ struct event ev;
+ int nread;
+};
+
+static void
+combined_read_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct both *both = arg;
+ char buf[128];
+ int len;
+
+ len = read(fd, buf, sizeof(buf));
+ if (len == -1)
+ fprintf(stderr, "%s: read\n", __func__);
+ if (len <= 0)
+ return;
+
+ both->nread += len;
+ if (event_add(&both->ev, NULL) == -1)
+ exit(1);
+}
+
+static void
+combined_write_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct both *both = arg;
+ char buf[128];
+ int len;
+
+ len = sizeof(buf);
+ if (len > both->nread)
+ len = both->nread;
+
+ memset(buf, 'q', len);
+
+ len = write(fd, buf, len);
+ if (len == -1)
+ fprintf(stderr, "%s: write\n", __func__);
+ if (len <= 0) {
+ shutdown(fd, EVUTIL_SHUT_WR);
+ return;
+ }
+
+ both->nread -= len;
+ if (event_add(&both->ev, NULL) == -1)
+ exit(1);
+}
+
+/* These macros used to replicate the work of the legacy test wrapper code */
+#define setup_test(x) do { \
+ if (!in_legacy_test_wrapper) { \
+ TT_FAIL(("Legacy test %s not wrapped properly", x)); \
+ return; \
+ } \
+ } while (0)
+#define cleanup_test() setup_test("cleanup")
+
+static void
+test_simpleread(void)
+{
+ struct event ev;
+
+ /* Very simple read test */
+ setup_test("Simple read: ");
+
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ shutdown(pair[0], EVUTIL_SHUT_WR);
+
+ event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev);
+ if (event_add(&ev, NULL) == -1)
+ exit(1);
+ event_dispatch();
+
+ cleanup_test();
+}
+
+static void
+test_simplewrite(void)
+{
+ struct event ev;
+
+ /* Very simple write test */
+ setup_test("Simple write: ");
+
+ event_set(&ev, pair[0], EV_WRITE, simple_write_cb, &ev);
+ if (event_add(&ev, NULL) == -1)
+ exit(1);
+ event_dispatch();
+
+ cleanup_test();
+}
+
+static void
+simpleread_multiple_cb(evutil_socket_t fd, short event, void *arg)
+{
+ if (++called == 2)
+ test_ok = 1;
+}
+
+static void
+test_simpleread_multiple(void)
+{
+ struct event one, two;
+
+ /* Very simple read test */
+ setup_test("Simple read to multiple evens: ");
+
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ shutdown(pair[0], EVUTIL_SHUT_WR);
+
+ event_set(&one, pair[1], EV_READ, simpleread_multiple_cb, NULL);
+ if (event_add(&one, NULL) == -1)
+ exit(1);
+ event_set(&two, pair[1], EV_READ, simpleread_multiple_cb, NULL);
+ if (event_add(&two, NULL) == -1)
+ exit(1);
+ event_dispatch();
+
+ cleanup_test();
+}
+
+static int have_closed = 0;
+static int premature_event = 0;
+static void
+simpleclose_close_fd_cb(evutil_socket_t s, short what, void *ptr)
+{
+ evutil_socket_t **fds = ptr;
+ TT_BLATHER(("Closing"));
+ evutil_closesocket(*fds[0]);
+ evutil_closesocket(*fds[1]);
+ *fds[0] = -1;
+ *fds[1] = -1;
+ have_closed = 1;
+}
+
+static void
+record_event_cb(evutil_socket_t s, short what, void *ptr)
+{
+ short *whatp = ptr;
+ if (!have_closed)
+ premature_event = 1;
+ *whatp = what;
+ TT_BLATHER(("Recorded %d on socket %d", (int)what, (int)s));
+}
+
+static void
+test_simpleclose(void *ptr)
+{
+ /* Test that a close of FD is detected as a read and as a write. */
+ struct event_base *base = event_base_new();
+ evutil_socket_t pair1[2]={-1,-1}, pair2[2] = {-1, -1};
+ evutil_socket_t *to_close[2];
+ struct event *rev=NULL, *wev=NULL, *closeev=NULL;
+ struct timeval tv;
+ short got_read_on_close = 0, got_write_on_close = 0;
+ char buf[1024];
+ memset(buf, 99, sizeof(buf));
+#ifdef _WIN32
+#define LOCAL_SOCKETPAIR_AF AF_INET
+#else
+#define LOCAL_SOCKETPAIR_AF AF_UNIX
+#endif
+ if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair1)<0)
+ TT_DIE(("socketpair: %s", strerror(errno)));
+ if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair2)<0)
+ TT_DIE(("socketpair: %s", strerror(errno)));
+ if (evutil_make_socket_nonblocking(pair1[1]) < 0)
+ TT_DIE(("make_socket_nonblocking"));
+ if (evutil_make_socket_nonblocking(pair2[1]) < 0)
+ TT_DIE(("make_socket_nonblocking"));
+
+ /** Stuff pair2[1] full of data, until write fails */
+ while (1) {
+ int r = write(pair2[1], buf, sizeof(buf));
+ if (r<0) {
+ int err = evutil_socket_geterror(pair2[1]);
+ if (! EVUTIL_ERR_RW_RETRIABLE(err))
+ TT_DIE(("write failed strangely: %s",
+ evutil_socket_error_to_string(err)));
+ break;
+ }
+ }
+ to_close[0] = &pair1[0];
+ to_close[1] = &pair2[0];
+
+ closeev = event_new(base, -1, EV_TIMEOUT, simpleclose_close_fd_cb,
+ to_close);
+ rev = event_new(base, pair1[1], EV_READ, record_event_cb,
+ &got_read_on_close);
+ TT_BLATHER(("Waiting for read on %d", (int)pair1[1]));
+ wev = event_new(base, pair2[1], EV_WRITE, record_event_cb,
+ &got_write_on_close);
+ TT_BLATHER(("Waiting for write on %d", (int)pair2[1]));
+ tv.tv_sec = 0;
+ tv.tv_usec = 100*1000; /* Close pair1[0] after a little while, and make
+ * sure we get a read event. */
+ event_add(closeev, &tv);
+ event_add(rev, NULL);
+ event_add(wev, NULL);
+ /* Don't let the test go on too long. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 200*1000;
+ event_base_loopexit(base, &tv);
+ event_base_loop(base, 0);
+
+ tt_int_op(got_read_on_close, ==, EV_READ);
+ tt_int_op(got_write_on_close, ==, EV_WRITE);
+ tt_int_op(premature_event, ==, 0);
+
+end:
+ if (pair1[0] >= 0)
+ evutil_closesocket(pair1[0]);
+ if (pair1[1] >= 0)
+ evutil_closesocket(pair1[1]);
+ if (pair2[0] >= 0)
+ evutil_closesocket(pair2[0]);
+ if (pair2[1] >= 0)
+ evutil_closesocket(pair2[1]);
+ if (rev)
+ event_free(rev);
+ if (wev)
+ event_free(wev);
+ if (closeev)
+ event_free(closeev);
+ if (base)
+ event_base_free(base);
+}
+
+
+static void
+test_multiple(void)
+{
+ struct event ev, ev2;
+ int i;
+
+ /* Multiple read and write test */
+ setup_test("Multiple read/write: ");
+ memset(rbuf, 0, sizeof(rbuf));
+ for (i = 0; i < (int)sizeof(wbuf); i++)
+ wbuf[i] = i;
+
+ roff = woff = 0;
+ usepersist = 0;
+
+ event_set(&ev, pair[0], EV_WRITE, multiple_write_cb, &ev);
+ if (event_add(&ev, NULL) == -1)
+ exit(1);
+ event_set(&ev2, pair[1], EV_READ, multiple_read_cb, &ev2);
+ if (event_add(&ev2, NULL) == -1)
+ exit(1);
+ event_dispatch();
+
+ if (roff == woff)
+ test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0;
+
+ cleanup_test();
+}
+
+static void
+test_persistent(void)
+{
+ struct event ev, ev2;
+ int i;
+
+ /* Multiple read and write test with persist */
+ setup_test("Persist read/write: ");
+ memset(rbuf, 0, sizeof(rbuf));
+ for (i = 0; i < (int)sizeof(wbuf); i++)
+ wbuf[i] = i;
+
+ roff = woff = 0;
+ usepersist = 1;
+
+ event_set(&ev, pair[0], EV_WRITE|EV_PERSIST, multiple_write_cb, &ev);
+ if (event_add(&ev, NULL) == -1)
+ exit(1);
+ event_set(&ev2, pair[1], EV_READ|EV_PERSIST, multiple_read_cb, &ev2);
+ if (event_add(&ev2, NULL) == -1)
+ exit(1);
+ event_dispatch();
+
+ if (roff == woff)
+ test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0;
+
+ cleanup_test();
+}
+
+static void
+test_combined(void)
+{
+ struct both r1, r2, w1, w2;
+
+ setup_test("Combined read/write: ");
+ memset(&r1, 0, sizeof(r1));
+ memset(&r2, 0, sizeof(r2));
+ memset(&w1, 0, sizeof(w1));
+ memset(&w2, 0, sizeof(w2));
+
+ w1.nread = 4096;
+ w2.nread = 8192;
+
+ event_set(&r1.ev, pair[0], EV_READ, combined_read_cb, &r1);
+ event_set(&w1.ev, pair[0], EV_WRITE, combined_write_cb, &w1);
+ event_set(&r2.ev, pair[1], EV_READ, combined_read_cb, &r2);
+ event_set(&w2.ev, pair[1], EV_WRITE, combined_write_cb, &w2);
+ tt_assert(event_add(&r1.ev, NULL) != -1);
+ tt_assert(!event_add(&w1.ev, NULL));
+ tt_assert(!event_add(&r2.ev, NULL));
+ tt_assert(!event_add(&w2.ev, NULL));
+ event_dispatch();
+
+ if (r1.nread == 8192 && r2.nread == 4096)
+ test_ok = 1;
+
+end:
+ cleanup_test();
+}
+
+static void
+test_simpletimeout(void)
+{
+ struct timeval tv;
+ struct event ev;
+
+ setup_test("Simple timeout: ");
+
+ tv.tv_usec = 200*1000;
+ tv.tv_sec = 0;
+ evutil_timerclear(&tcalled);
+ evtimer_set(&ev, timeout_cb, NULL);
+ evtimer_add(&ev, &tv);
+
+ evutil_gettimeofday(&tset, NULL);
+ event_dispatch();
+ test_timeval_diff_eq(&tset, &tcalled, 200);
+
+ test_ok = 1;
+end:
+ cleanup_test();
+}
+
+static void
+periodic_timeout_cb(evutil_socket_t fd, short event, void *arg)
+{
+ int *count = arg;
+
+ (*count)++;
+ if (*count == 6) {
+ /* call loopexit only once - on slow machines(?), it is
+ * apparently possible for this to get called twice. */
+ test_ok = 1;
+ event_base_loopexit(global_base, NULL);
+ }
+}
+
+static void
+test_persistent_timeout(void)
+{
+ struct timeval tv;
+ struct event ev;
+ int count = 0;
+
+ evutil_timerclear(&tv);
+ tv.tv_usec = 10000;
+
+ event_assign(&ev, global_base, -1, EV_TIMEOUT|EV_PERSIST,
+ periodic_timeout_cb, &count);
+ event_add(&ev, &tv);
+
+ event_dispatch();
+
+ event_del(&ev);
+}
+
+static void
+test_persistent_timeout_jump(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event ev;
+ int count = 0;
+ struct timeval msec100 = { 0, 100 * 1000 };
+ struct timeval msec50 = { 0, 50 * 1000 };
+ struct timeval msec300 = { 0, 300 * 1000 };
+
+ event_assign(&ev, data->base, -1, EV_PERSIST, periodic_timeout_cb, &count);
+ event_add(&ev, &msec100);
+ /* Wait for a bit */
+ evutil_usleep_(&msec300);
+ event_base_loopexit(data->base, &msec50);
+ event_base_dispatch(data->base);
+ tt_int_op(count, ==, 1);
+
+end:
+ event_del(&ev);
+}
+
+struct persist_active_timeout_called {
+ int n;
+ short events[16];
+ struct timeval tvs[16];
+};
+
+static void
+activate_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct event *ev = arg;
+ event_active(ev, EV_READ, 1);
+}
+
+static void
+persist_active_timeout_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct persist_active_timeout_called *c = arg;
+ if (c->n < 15) {
+ c->events[c->n] = event;
+ evutil_gettimeofday(&c->tvs[c->n], NULL);
+ ++c->n;
+ }
+}
+
+static void
+test_persistent_active_timeout(void *ptr)
+{
+ struct timeval tv, tv2, tv_exit, start;
+ struct event ev;
+ struct persist_active_timeout_called res;
+
+ struct basic_test_data *data = ptr;
+ struct event_base *base = data->base;
+
+ memset(&res, 0, sizeof(res));
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 200 * 1000;
+ event_assign(&ev, base, -1, EV_TIMEOUT|EV_PERSIST,
+ persist_active_timeout_cb, &res);
+ event_add(&ev, &tv);
+
+ tv2.tv_sec = 0;
+ tv2.tv_usec = 100 * 1000;
+ event_base_once(base, -1, EV_TIMEOUT, activate_cb, &ev, &tv2);
+
+ tv_exit.tv_sec = 0;
+ tv_exit.tv_usec = 600 * 1000;
+ event_base_loopexit(base, &tv_exit);
+
+ event_base_assert_ok_(base);
+ evutil_gettimeofday(&start, NULL);
+
+ event_base_dispatch(base);
+ event_base_assert_ok_(base);
+
+ tt_int_op(res.n, ==, 3);
+ tt_int_op(res.events[0], ==, EV_READ);
+ tt_int_op(res.events[1], ==, EV_TIMEOUT);
+ tt_int_op(res.events[2], ==, EV_TIMEOUT);
+ test_timeval_diff_eq(&start, &res.tvs[0], 100);
+ test_timeval_diff_eq(&start, &res.tvs[1], 300);
+ test_timeval_diff_eq(&start, &res.tvs[2], 500);
+end:
+ event_del(&ev);
+}
+
+struct common_timeout_info {
+ struct event ev;
+ struct timeval called_at;
+ int which;
+ int count;
+};
+
+static void
+common_timeout_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct common_timeout_info *ti = arg;
+ ++ti->count;
+ evutil_gettimeofday(&ti->called_at, NULL);
+ if (ti->count >= 4)
+ event_del(&ti->ev);
+}
+
+static void
+test_common_timeout(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+
+ struct event_base *base = data->base;
+ int i;
+ struct common_timeout_info info[100];
+
+ struct timeval start;
+ struct timeval tmp_100_ms = { 0, 100*1000 };
+ struct timeval tmp_200_ms = { 0, 200*1000 };
+ struct timeval tmp_5_sec = { 5, 0 };
+ struct timeval tmp_5M_usec = { 0, 5*1000*1000 };
+
+ const struct timeval *ms_100, *ms_200, *sec_5;
+
+ ms_100 = event_base_init_common_timeout(base, &tmp_100_ms);
+ ms_200 = event_base_init_common_timeout(base, &tmp_200_ms);
+ sec_5 = event_base_init_common_timeout(base, &tmp_5_sec);
+ tt_assert(ms_100);
+ tt_assert(ms_200);
+ tt_assert(sec_5);
+ tt_ptr_op(event_base_init_common_timeout(base, &tmp_200_ms),
+ ==, ms_200);
+ tt_ptr_op(event_base_init_common_timeout(base, ms_200), ==, ms_200);
+ tt_ptr_op(event_base_init_common_timeout(base, &tmp_5M_usec), ==, sec_5);
+ tt_int_op(ms_100->tv_sec, ==, 0);
+ tt_int_op(ms_200->tv_sec, ==, 0);
+ tt_int_op(sec_5->tv_sec, ==, 5);
+ tt_int_op(ms_100->tv_usec, ==, 100000|0x50000000);
+ tt_int_op(ms_200->tv_usec, ==, 200000|0x50100000);
+ tt_int_op(sec_5->tv_usec, ==, 0|0x50200000);
+
+ memset(info, 0, sizeof(info));
+
+ for (i=0; i<100; ++i) {
+ info[i].which = i;
+ event_assign(&info[i].ev, base, -1, EV_TIMEOUT|EV_PERSIST,
+ common_timeout_cb, &info[i]);
+ if (i % 2) {
+ if ((i%20)==1) {
+ /* Glass-box test: Make sure we survive the
+ * transition to non-common timeouts. It's
+ * a little tricky. */
+ event_add(&info[i].ev, ms_200);
+ event_add(&info[i].ev, &tmp_100_ms);
+ } else if ((i%20)==3) {
+ /* Check heap-to-common too. */
+ event_add(&info[i].ev, &tmp_200_ms);
+ event_add(&info[i].ev, ms_100);
+ } else if ((i%20)==5) {
+ /* Also check common-to-common. */
+ event_add(&info[i].ev, ms_200);
+ event_add(&info[i].ev, ms_100);
+ } else {
+ event_add(&info[i].ev, ms_100);
+ }
+ } else {
+ event_add(&info[i].ev, ms_200);
+ }
+ }
+
+ event_base_assert_ok_(base);
+ evutil_gettimeofday(&start, NULL);
+ event_base_dispatch(base);
+
+ event_base_assert_ok_(base);
+
+ for (i=0; i<10; ++i) {
+ tt_int_op(info[i].count, ==, 4);
+ if (i % 2) {
+ test_timeval_diff_eq(&start, &info[i].called_at, 400);
+ } else {
+ test_timeval_diff_eq(&start, &info[i].called_at, 800);
+ }
+ }
+
+ /* Make sure we can free the base with some events in. */
+ for (i=0; i<100; ++i) {
+ if (i % 2) {
+ event_add(&info[i].ev, ms_100);
+ } else {
+ event_add(&info[i].ev, ms_200);
+ }
+ }
+
+end:
+ event_base_free(data->base); /* need to do this here before info is
+ * out-of-scope */
+ data->base = NULL;
+}
+
+#ifndef _WIN32
+
+#define current_base event_global_current_base_
+extern struct event_base *current_base;
+
+static void
+fork_signal_cb(evutil_socket_t fd, short events, void *arg)
+{
+ event_del(arg);
+}
+
+int child_pair[2] = { -1, -1 };
+static void
+simple_child_read_cb(evutil_socket_t fd, short event, void *arg)
+{
+ char buf[256];
+ int len;
+
+ len = read(fd, buf, sizeof(buf));
+ if (write(child_pair[0], "", 1) < 0)
+ tt_fail_perror("write");
+
+ if (len) {
+ if (!called) {
+ if (event_add(arg, NULL) == -1)
+ exit(1);
+ }
+ } else if (called == 1)
+ test_ok = 1;
+
+ called++;
+}
+static void
+test_fork(void)
+{
+ char c;
+ int status;
+ struct event ev, sig_ev, usr_ev, existing_ev;
+ pid_t pid;
+ int wait_flags = 0;
+
+#ifdef EVENT__HAVE_WAITPID_WITH_WNOWAIT
+ wait_flags |= WNOWAIT;
+#endif
+
+ setup_test("After fork: ");
+
+ {
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, child_pair) == -1) {
+ fprintf(stderr, "%s: socketpair\n", __func__);
+ exit(1);
+ }
+
+ if (evutil_make_socket_nonblocking(child_pair[0]) == -1) {
+ fprintf(stderr, "fcntl(O_NONBLOCK)");
+ exit(1);
+ }
+ }
+
+ tt_assert(current_base);
+ evthread_make_base_notifiable(current_base);
+
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ event_set(&ev, pair[1], EV_READ, simple_child_read_cb, &ev);
+ if (event_add(&ev, NULL) == -1)
+ exit(1);
+
+ evsignal_set(&sig_ev, SIGCHLD, fork_signal_cb, &sig_ev);
+ evsignal_add(&sig_ev, NULL);
+
+ evsignal_set(&existing_ev, SIGUSR2, fork_signal_cb, &existing_ev);
+ evsignal_add(&existing_ev, NULL);
+
+ event_base_assert_ok_(current_base);
+ TT_BLATHER(("Before fork"));
+ if ((pid = regress_fork()) == 0) {
+ /* in the child */
+ TT_BLATHER(("In child, before reinit"));
+ event_base_assert_ok_(current_base);
+ if (event_reinit(current_base) == -1) {
+ fprintf(stdout, "FAILED (reinit)\n");
+ exit(1);
+ }
+ TT_BLATHER(("After reinit"));
+ event_base_assert_ok_(current_base);
+ TT_BLATHER(("After assert-ok"));
+
+ evsignal_del(&sig_ev);
+
+ evsignal_set(&usr_ev, SIGUSR1, fork_signal_cb, &usr_ev);
+ evsignal_add(&usr_ev, NULL);
+ raise(SIGUSR1);
+ raise(SIGUSR2);
+
+ called = 0;
+
+ event_dispatch();
+
+ event_base_free(current_base);
+
+ /* we do not send an EOF; simple_read_cb requires an EOF
+ * to set test_ok. we just verify that the callback was
+ * called. */
+ exit(test_ok != 0 || called != 2 ? -2 : 76);
+ }
+
+ /** wait until client read first message */
+ if (read(child_pair[1], &c, 1) < 0) {
+ tt_fail_perror("read");
+ }
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ TT_BLATHER(("Before waitpid"));
+ if (waitpid(pid, &status, wait_flags) == -1) {
+ perror("waitpid");
+ exit(1);
+ }
+ TT_BLATHER(("After waitpid"));
+
+ if (WEXITSTATUS(status) != 76) {
+ fprintf(stdout, "FAILED (exit): %d\n", WEXITSTATUS(status));
+ exit(1);
+ }
+
+ /* test that the current event loop still works */
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ fprintf(stderr, "%s: write\n", __func__);
+ }
+
+ shutdown(pair[0], EVUTIL_SHUT_WR);
+
+ evsignal_set(&usr_ev, SIGUSR1, fork_signal_cb, &usr_ev);
+ evsignal_add(&usr_ev, NULL);
+ raise(SIGUSR1);
+ raise(SIGUSR2);
+
+ event_dispatch();
+
+ evsignal_del(&sig_ev);
+ tt_int_op(test_ok, ==, 1);
+
+ end:
+ cleanup_test();
+ if (child_pair[0] != -1)
+ evutil_closesocket(child_pair[0]);
+ if (child_pair[1] != -1)
+ evutil_closesocket(child_pair[1]);
+}
+
+#ifdef EVENT__HAVE_PTHREADS
+static void* del_wait_thread(void *arg)
+{
+ struct timeval tv_start, tv_end;
+
+ evutil_gettimeofday(&tv_start, NULL);
+ event_dispatch();
+ evutil_gettimeofday(&tv_end, NULL);
+
+ test_timeval_diff_eq(&tv_start, &tv_end, 300);
+
+ end:
+ return NULL;
+}
+
+static void
+del_wait_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct timeval delay = { 0, 300*1000 };
+ TT_BLATHER(("Sleeping"));
+ evutil_usleep_(&delay);
+ test_ok = 1;
+}
+
+static void
+test_del_wait(void)
+{
+ struct event ev;
+ pthread_t thread;
+
+ setup_test("event_del will wait: ");
+
+ event_set(&ev, pair[1], EV_READ, del_wait_cb, &ev);
+ event_add(&ev, NULL);
+
+ pthread_create(&thread, NULL, del_wait_thread, NULL);
+
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ {
+ struct timeval delay = { 0, 30*1000 };
+ evutil_usleep_(&delay);
+ }
+
+ {
+ struct timeval tv_start, tv_end;
+ evutil_gettimeofday(&tv_start, NULL);
+ event_del(&ev);
+ evutil_gettimeofday(&tv_end, NULL);
+ test_timeval_diff_eq(&tv_start, &tv_end, 270);
+ }
+
+ pthread_join(thread, NULL);
+
+ end:
+ ;
+}
+#endif
+
+static void
+signal_cb_sa(int sig)
+{
+ test_ok = 2;
+}
+
+static void
+signal_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct event *ev = arg;
+
+ evsignal_del(ev);
+ test_ok = 1;
+}
+
+static void
+test_simplesignal_impl(int find_reorder)
+{
+ struct event ev;
+ struct itimerval itv;
+
+ evsignal_set(&ev, SIGALRM, signal_cb, &ev);
+ evsignal_add(&ev, NULL);
+ /* find bugs in which operations are re-ordered */
+ if (find_reorder) {
+ evsignal_del(&ev);
+ evsignal_add(&ev, NULL);
+ }
+
+ memset(&itv, 0, sizeof(itv));
+ itv.it_value.tv_sec = 0;
+ itv.it_value.tv_usec = 100000;
+ if (setitimer(ITIMER_REAL, &itv, NULL) == -1)
+ goto skip_simplesignal;
+
+ event_dispatch();
+ skip_simplesignal:
+ if (evsignal_del(&ev) == -1)
+ test_ok = 0;
+
+ cleanup_test();
+}
+
+static void
+test_simplestsignal(void)
+{
+ setup_test("Simplest one signal: ");
+ test_simplesignal_impl(0);
+}
+
+static void
+test_simplesignal(void)
+{
+ setup_test("Simple signal: ");
+ test_simplesignal_impl(1);
+}
+
+static void
+test_multiplesignal(void)
+{
+ struct event ev_one, ev_two;
+ struct itimerval itv;
+
+ setup_test("Multiple signal: ");
+
+ evsignal_set(&ev_one, SIGALRM, signal_cb, &ev_one);
+ evsignal_add(&ev_one, NULL);
+
+ evsignal_set(&ev_two, SIGALRM, signal_cb, &ev_two);
+ evsignal_add(&ev_two, NULL);
+
+ memset(&itv, 0, sizeof(itv));
+ itv.it_value.tv_sec = 0;
+ itv.it_value.tv_usec = 100000;
+ if (setitimer(ITIMER_REAL, &itv, NULL) == -1)
+ goto skip_simplesignal;
+
+ event_dispatch();
+
+ skip_simplesignal:
+ if (evsignal_del(&ev_one) == -1)
+ test_ok = 0;
+ if (evsignal_del(&ev_two) == -1)
+ test_ok = 0;
+
+ cleanup_test();
+}
+
+static void
+test_immediatesignal(void)
+{
+ struct event ev;
+
+ test_ok = 0;
+ evsignal_set(&ev, SIGUSR1, signal_cb, &ev);
+ evsignal_add(&ev, NULL);
+ raise(SIGUSR1);
+ event_loop(EVLOOP_NONBLOCK);
+ evsignal_del(&ev);
+ cleanup_test();
+}
+
+static void
+test_signal_dealloc(void)
+{
+ /* make sure that evsignal_event is event_del'ed and pipe closed */
+ struct event ev;
+ struct event_base *base = event_init();
+ evsignal_set(&ev, SIGUSR1, signal_cb, &ev);
+ evsignal_add(&ev, NULL);
+ evsignal_del(&ev);
+ event_base_free(base);
+ /* If we got here without asserting, we're fine. */
+ test_ok = 1;
+ cleanup_test();
+}
+
+static void
+test_signal_pipeloss(void)
+{
+ /* make sure that the base1 pipe is closed correctly. */
+ struct event_base *base1, *base2;
+ int pipe1;
+ test_ok = 0;
+ base1 = event_init();
+ pipe1 = base1->sig.ev_signal_pair[0];
+ base2 = event_init();
+ event_base_free(base2);
+ event_base_free(base1);
+ if (close(pipe1) != -1 || errno!=EBADF) {
+ /* fd must be closed, so second close gives -1, EBADF */
+ printf("signal pipe not closed. ");
+ test_ok = 0;
+ } else {
+ test_ok = 1;
+ }
+ cleanup_test();
+}
+
+/*
+ * make two bases to catch signals, use both of them. this only works
+ * for event mechanisms that use our signal pipe trick. kqueue handles
+ * signals internally, and all interested kqueues get all the signals.
+ */
+static void
+test_signal_switchbase(void)
+{
+ struct event ev1, ev2;
+ struct event_base *base1, *base2;
+ int is_kqueue;
+ test_ok = 0;
+ base1 = event_init();
+ base2 = event_init();
+ is_kqueue = !strcmp(event_get_method(),"kqueue");
+ evsignal_set(&ev1, SIGUSR1, signal_cb, &ev1);
+ evsignal_set(&ev2, SIGUSR1, signal_cb, &ev2);
+ if (event_base_set(base1, &ev1) ||
+ event_base_set(base2, &ev2) ||
+ event_add(&ev1, NULL) ||
+ event_add(&ev2, NULL)) {
+ fprintf(stderr, "%s: cannot set base, add\n", __func__);
+ exit(1);
+ }
+
+ tt_ptr_op(event_get_base(&ev1), ==, base1);
+ tt_ptr_op(event_get_base(&ev2), ==, base2);
+
+ test_ok = 0;
+ /* can handle signal before loop is called */
+ raise(SIGUSR1);
+ event_base_loop(base2, EVLOOP_NONBLOCK);
+ if (is_kqueue) {
+ if (!test_ok)
+ goto end;
+ test_ok = 0;
+ }
+ event_base_loop(base1, EVLOOP_NONBLOCK);
+ if (test_ok && !is_kqueue) {
+ test_ok = 0;
+
+ /* set base1 to handle signals */
+ event_base_loop(base1, EVLOOP_NONBLOCK);
+ raise(SIGUSR1);
+ event_base_loop(base1, EVLOOP_NONBLOCK);
+ event_base_loop(base2, EVLOOP_NONBLOCK);
+ }
+end:
+ event_base_free(base1);
+ event_base_free(base2);
+ cleanup_test();
+}
+
+/*
+ * assert that a signal event removed from the event queue really is
+ * removed - with no possibility of it's parent handler being fired.
+ */
+static void
+test_signal_assert(void)
+{
+ struct event ev;
+ struct event_base *base = event_init();
+ test_ok = 0;
+ /* use SIGCONT so we don't kill ourselves when we signal to nowhere */
+ evsignal_set(&ev, SIGCONT, signal_cb, &ev);
+ evsignal_add(&ev, NULL);
+ /*
+ * if evsignal_del() fails to reset the handler, it's current handler
+ * will still point to evsig_handler().
+ */
+ evsignal_del(&ev);
+
+ raise(SIGCONT);
+#if 0
+ /* only way to verify we were in evsig_handler() */
+ /* XXXX Now there's no longer a good way. */
+ if (base->sig.evsig_caught)
+ test_ok = 0;
+ else
+ test_ok = 1;
+#else
+ test_ok = 1;
+#endif
+
+ event_base_free(base);
+ cleanup_test();
+ return;
+}
+
+/*
+ * assert that we restore our previous signal handler properly.
+ */
+static void
+test_signal_restore(void)
+{
+ struct event ev;
+ struct event_base *base = event_init();
+#ifdef EVENT__HAVE_SIGACTION
+ struct sigaction sa;
+#endif
+
+ test_ok = 0;
+#ifdef EVENT__HAVE_SIGACTION
+ sa.sa_handler = signal_cb_sa;
+ sa.sa_flags = 0x0;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(SIGUSR1, &sa, NULL) == -1)
+ goto out;
+#else
+ if (signal(SIGUSR1, signal_cb_sa) == SIG_ERR)
+ goto out;
+#endif
+ evsignal_set(&ev, SIGUSR1, signal_cb, &ev);
+ evsignal_add(&ev, NULL);
+ evsignal_del(&ev);
+
+ raise(SIGUSR1);
+ /* 1 == signal_cb, 2 == signal_cb_sa, we want our previous handler */
+ if (test_ok != 2)
+ test_ok = 0;
+out:
+ event_base_free(base);
+ cleanup_test();
+ return;
+}
+
+static void
+signal_cb_swp(int sig, short event, void *arg)
+{
+ called++;
+ if (called < 5)
+ raise(sig);
+ else
+ event_loopexit(NULL);
+}
+static void
+timeout_cb_swp(evutil_socket_t fd, short event, void *arg)
+{
+ if (called == -1) {
+ struct timeval tv = {5, 0};
+
+ called = 0;
+ evtimer_add((struct event *)arg, &tv);
+ raise(SIGUSR1);
+ return;
+ }
+ test_ok = 0;
+ event_loopexit(NULL);
+}
+
+static void
+test_signal_while_processing(void)
+{
+ struct event_base *base = event_init();
+ struct event ev, ev_timer;
+ struct timeval tv = {0, 0};
+
+ setup_test("Receiving a signal while processing other signal: ");
+
+ called = -1;
+ test_ok = 1;
+ signal_set(&ev, SIGUSR1, signal_cb_swp, NULL);
+ signal_add(&ev, NULL);
+ evtimer_set(&ev_timer, timeout_cb_swp, &ev_timer);
+ evtimer_add(&ev_timer, &tv);
+ event_dispatch();
+
+ event_base_free(base);
+ cleanup_test();
+ return;
+}
+#endif
+
+static void
+test_free_active_base(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base1;
+ struct event ev1;
+
+ base1 = event_init();
+ if (base1) {
+ event_assign(&ev1, base1, data->pair[1], EV_READ,
+ dummy_read_cb, NULL);
+ event_add(&ev1, NULL);
+ event_base_free(base1); /* should not crash */
+ } else {
+ tt_fail_msg("failed to create event_base for test");
+ }
+
+ base1 = event_init();
+ tt_assert(base1);
+ event_assign(&ev1, base1, 0, 0, dummy_read_cb, NULL);
+ event_active(&ev1, EV_READ, 1);
+ event_base_free(base1);
+end:
+ ;
+}
+
+static void
+test_manipulate_active_events(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base = data->base;
+ struct event ev1;
+
+ event_assign(&ev1, base, -1, EV_TIMEOUT, dummy_read_cb, NULL);
+
+ /* Make sure an active event is pending. */
+ event_active(&ev1, EV_READ, 1);
+ tt_int_op(event_pending(&ev1, EV_READ|EV_TIMEOUT|EV_WRITE, NULL),
+ ==, EV_READ);
+
+ /* Make sure that activating an event twice works. */
+ event_active(&ev1, EV_WRITE, 1);
+ tt_int_op(event_pending(&ev1, EV_READ|EV_TIMEOUT|EV_WRITE, NULL),
+ ==, EV_READ|EV_WRITE);
+
+end:
+ event_del(&ev1);
+}
+
+static void
+event_selfarg_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct event *ev = arg;
+ struct event_base *base = event_get_base(ev);
+ event_base_assert_ok_(base);
+ event_base_loopexit(base, NULL);
+ tt_want(ev == event_base_get_running_event(base));
+}
+
+static void
+test_event_new_selfarg(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base = data->base;
+ struct event *ev = event_new(base, -1, EV_READ, event_selfarg_cb,
+ event_self_cbarg());
+
+ event_active(ev, EV_READ, 1);
+ event_base_dispatch(base);
+
+ event_free(ev);
+}
+
+static void
+test_event_assign_selfarg(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base = data->base;
+ struct event ev;
+
+ event_assign(&ev, base, -1, EV_READ, event_selfarg_cb,
+ event_self_cbarg());
+ event_active(&ev, EV_READ, 1);
+ event_base_dispatch(base);
+}
+
+static void
+test_event_base_get_num_events(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base = data->base;
+ struct event ev;
+ int event_count_active;
+ int event_count_virtual;
+ int event_count_added;
+ int event_count_active_virtual;
+ int event_count_active_added;
+ int event_count_virtual_added;
+ int event_count_active_added_virtual;
+
+ struct timeval qsec = {0, 100000};
+
+ event_assign(&ev, base, -1, EV_READ, event_selfarg_cb,
+ event_self_cbarg());
+
+ event_add(&ev, &qsec);
+ event_count_active = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE);
+ event_count_virtual = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_VIRTUAL);
+ event_count_added = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ADDED);
+ event_count_active_virtual = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_VIRTUAL);
+ event_count_active_added = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_ADDED);
+ event_count_virtual_added = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_VIRTUAL|EVENT_BASE_COUNT_ADDED);
+ event_count_active_added_virtual = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE|
+ EVENT_BASE_COUNT_ADDED|
+ EVENT_BASE_COUNT_VIRTUAL);
+ tt_int_op(event_count_active, ==, 0);
+ tt_int_op(event_count_virtual, ==, 0);
+ /* libevent itself adds a timeout event, so the event_count is 2 here */
+ tt_int_op(event_count_added, ==, 2);
+ tt_int_op(event_count_active_virtual, ==, 0);
+ tt_int_op(event_count_active_added, ==, 2);
+ tt_int_op(event_count_virtual_added, ==, 2);
+ tt_int_op(event_count_active_added_virtual, ==, 2);
+
+ event_active(&ev, EV_READ, 1);
+ event_count_active = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE);
+ event_count_virtual = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_VIRTUAL);
+ event_count_added = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ADDED);
+ event_count_active_virtual = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_VIRTUAL);
+ event_count_active_added = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_ADDED);
+ event_count_virtual_added = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_VIRTUAL|EVENT_BASE_COUNT_ADDED);
+ event_count_active_added_virtual = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE|
+ EVENT_BASE_COUNT_ADDED|
+ EVENT_BASE_COUNT_VIRTUAL);
+ tt_int_op(event_count_active, ==, 1);
+ tt_int_op(event_count_virtual, ==, 0);
+ tt_int_op(event_count_added, ==, 3);
+ tt_int_op(event_count_active_virtual, ==, 1);
+ tt_int_op(event_count_active_added, ==, 4);
+ tt_int_op(event_count_virtual_added, ==, 3);
+ tt_int_op(event_count_active_added_virtual, ==, 4);
+
+ event_base_loop(base, 0);
+ event_count_active = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE);
+ event_count_virtual = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_VIRTUAL);
+ event_count_added = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ADDED);
+ event_count_active_virtual = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_VIRTUAL);
+ event_count_active_added = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_ADDED);
+ event_count_virtual_added = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_VIRTUAL|EVENT_BASE_COUNT_ADDED);
+ event_count_active_added_virtual = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE|
+ EVENT_BASE_COUNT_ADDED|
+ EVENT_BASE_COUNT_VIRTUAL);
+ tt_int_op(event_count_active, ==, 0);
+ tt_int_op(event_count_virtual, ==, 0);
+ tt_int_op(event_count_added, ==, 0);
+ tt_int_op(event_count_active_virtual, ==, 0);
+ tt_int_op(event_count_active_added, ==, 0);
+ tt_int_op(event_count_virtual_added, ==, 0);
+ tt_int_op(event_count_active_added_virtual, ==, 0);
+
+ event_base_add_virtual_(base);
+ event_count_active = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE);
+ event_count_virtual = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_VIRTUAL);
+ event_count_added = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ADDED);
+ event_count_active_virtual = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_VIRTUAL);
+ event_count_active_added = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_ADDED);
+ event_count_virtual_added = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_VIRTUAL|EVENT_BASE_COUNT_ADDED);
+ event_count_active_added_virtual = event_base_get_num_events(base,
+ EVENT_BASE_COUNT_ACTIVE|
+ EVENT_BASE_COUNT_ADDED|
+ EVENT_BASE_COUNT_VIRTUAL);
+ tt_int_op(event_count_active, ==, 0);
+ tt_int_op(event_count_virtual, ==, 1);
+ tt_int_op(event_count_added, ==, 0);
+ tt_int_op(event_count_active_virtual, ==, 1);
+ tt_int_op(event_count_active_added, ==, 0);
+ tt_int_op(event_count_virtual_added, ==, 1);
+ tt_int_op(event_count_active_added_virtual, ==, 1);
+
+end:
+ ;
+}
+
+static void
+test_event_base_get_max_events(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base = data->base;
+ struct event ev;
+ struct event ev2;
+ int event_count_active;
+ int event_count_virtual;
+ int event_count_added;
+ int event_count_active_virtual;
+ int event_count_active_added;
+ int event_count_virtual_added;
+ int event_count_active_added_virtual;
+
+ struct timeval qsec = {0, 100000};
+
+ event_assign(&ev, base, -1, EV_READ, event_selfarg_cb,
+ event_self_cbarg());
+ event_assign(&ev2, base, -1, EV_READ, event_selfarg_cb,
+ event_self_cbarg());
+
+ event_add(&ev, &qsec);
+ event_add(&ev2, &qsec);
+ event_del(&ev2);
+
+ event_count_active = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE, 0);
+ event_count_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_active_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_virtual_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_added_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE |
+ EVENT_BASE_COUNT_ADDED |
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+
+ tt_int_op(event_count_active, ==, 0);
+ tt_int_op(event_count_virtual, ==, 0);
+ /* libevent itself adds a timeout event, so the event_count is 4 here */
+ tt_int_op(event_count_added, ==, 4);
+ tt_int_op(event_count_active_virtual, ==, 0);
+ tt_int_op(event_count_active_added, ==, 4);
+ tt_int_op(event_count_virtual_added, ==, 4);
+ tt_int_op(event_count_active_added_virtual, ==, 4);
+
+ event_active(&ev, EV_READ, 1);
+ event_count_active = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE, 0);
+ event_count_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_active_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_virtual_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_added_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE |
+ EVENT_BASE_COUNT_ADDED |
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+
+ tt_int_op(event_count_active, ==, 1);
+ tt_int_op(event_count_virtual, ==, 0);
+ tt_int_op(event_count_added, ==, 4);
+ tt_int_op(event_count_active_virtual, ==, 1);
+ tt_int_op(event_count_active_added, ==, 5);
+ tt_int_op(event_count_virtual_added, ==, 4);
+ tt_int_op(event_count_active_added_virtual, ==, 5);
+
+ event_base_loop(base, 0);
+ event_count_active = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE, 1);
+ event_count_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL, 1);
+ event_count_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ADDED, 1);
+ event_count_active_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_active_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_virtual_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_added_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE |
+ EVENT_BASE_COUNT_ADDED |
+ EVENT_BASE_COUNT_VIRTUAL, 1);
+
+ tt_int_op(event_count_active, ==, 1);
+ tt_int_op(event_count_virtual, ==, 0);
+ tt_int_op(event_count_added, ==, 4);
+ tt_int_op(event_count_active_virtual, ==, 0);
+ tt_int_op(event_count_active_added, ==, 0);
+ tt_int_op(event_count_virtual_added, ==, 0);
+ tt_int_op(event_count_active_added_virtual, ==, 0);
+
+ event_count_active = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE, 0);
+ event_count_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ADDED, 0);
+ tt_int_op(event_count_active, ==, 0);
+ tt_int_op(event_count_virtual, ==, 0);
+ tt_int_op(event_count_added, ==, 0);
+
+ event_base_add_virtual_(base);
+ event_count_active = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE, 0);
+ event_count_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_active_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_virtual_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_added_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE |
+ EVENT_BASE_COUNT_ADDED |
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+
+ tt_int_op(event_count_active, ==, 0);
+ tt_int_op(event_count_virtual, ==, 1);
+ tt_int_op(event_count_added, ==, 0);
+ tt_int_op(event_count_active_virtual, ==, 1);
+ tt_int_op(event_count_active_added, ==, 0);
+ tt_int_op(event_count_virtual_added, ==, 1);
+ tt_int_op(event_count_active_added_virtual, ==, 1);
+
+end:
+ ;
+}
+
+static void
+test_bad_assign(void *ptr)
+{
+ struct event ev;
+ int r;
+ /* READ|SIGNAL is not allowed */
+ r = event_assign(&ev, NULL, -1, EV_SIGNAL|EV_READ, dummy_read_cb, NULL);
+ tt_int_op(r,==,-1);
+
+end:
+ ;
+}
+
+static int reentrant_cb_run = 0;
+
+static void
+bad_reentrant_run_loop_cb(evutil_socket_t fd, short what, void *ptr)
+{
+ struct event_base *base = ptr;
+ int r;
+ reentrant_cb_run = 1;
+ /* This reentrant call to event_base_loop should be detected and
+ * should fail */
+ r = event_base_loop(base, 0);
+ tt_int_op(r, ==, -1);
+end:
+ ;
+}
+
+static void
+test_bad_reentrant(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base = data->base;
+ struct event ev;
+ int r;
+ event_assign(&ev, base, -1,
+ 0, bad_reentrant_run_loop_cb, base);
+
+ event_active(&ev, EV_WRITE, 1);
+ r = event_base_loop(base, 0);
+ tt_int_op(r, ==, 1);
+ tt_int_op(reentrant_cb_run, ==, 1);
+end:
+ ;
+}
+
+static int n_write_a_byte_cb=0;
+static int n_read_and_drain_cb=0;
+static int n_activate_other_event_cb=0;
+static void
+write_a_byte_cb(evutil_socket_t fd, short what, void *arg)
+{
+ char buf[] = "x";
+ if (write(fd, buf, 1) == 1)
+ ++n_write_a_byte_cb;
+}
+static void
+read_and_drain_cb(evutil_socket_t fd, short what, void *arg)
+{
+ char buf[128];
+ int n;
+ ++n_read_and_drain_cb;
+ while ((n = read(fd, buf, sizeof(buf))) > 0)
+ ;
+}
+
+static void
+activate_other_event_cb(evutil_socket_t fd, short what, void *other_)
+{
+ struct event *ev_activate = other_;
+ ++n_activate_other_event_cb;
+ event_active_later_(ev_activate, EV_READ);
+}
+
+static void
+test_active_later(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event *ev1 = NULL, *ev2 = NULL;
+ struct event ev3, ev4;
+ struct timeval qsec = {0, 100000};
+ ev1 = event_new(data->base, data->pair[0], EV_READ|EV_PERSIST, read_and_drain_cb, NULL);
+ ev2 = event_new(data->base, data->pair[1], EV_WRITE|EV_PERSIST, write_a_byte_cb, NULL);
+ event_assign(&ev3, data->base, -1, 0, activate_other_event_cb, &ev4);
+ event_assign(&ev4, data->base, -1, 0, activate_other_event_cb, &ev3);
+ event_add(ev1, NULL);
+ event_add(ev2, NULL);
+ event_active_later_(&ev3, EV_READ);
+
+ event_base_loopexit(data->base, &qsec);
+
+ event_base_loop(data->base, 0);
+
+ TT_BLATHER(("%d write calls, %d read calls, %d activate-other calls.",
+ n_write_a_byte_cb, n_read_and_drain_cb, n_activate_other_event_cb));
+ event_del(&ev3);
+ event_del(&ev4);
+
+ tt_int_op(n_write_a_byte_cb, ==, n_activate_other_event_cb);
+ tt_int_op(n_write_a_byte_cb, >, 100);
+ tt_int_op(n_read_and_drain_cb, >, 100);
+ tt_int_op(n_activate_other_event_cb, >, 100);
+
+ event_active_later_(&ev4, EV_READ);
+ event_active(&ev4, EV_READ, 1); /* This should make the event
+ active immediately. */
+ tt_assert((ev4.ev_flags & EVLIST_ACTIVE) != 0);
+ tt_assert((ev4.ev_flags & EVLIST_ACTIVE_LATER) == 0);
+
+ /* Now leave this one around, so that event_free sees it and removes
+ * it. */
+ event_active_later_(&ev3, EV_READ);
+ event_base_assert_ok_(data->base);
+
+end:
+ if (ev1)
+ event_free(ev1);
+ if (ev2)
+ event_free(ev2);
+
+ event_base_free(data->base);
+ data->base = NULL;
+}
+
+
+static void incr_arg_cb(evutil_socket_t fd, short what, void *arg)
+{
+ int *intptr = arg;
+ (void) fd; (void) what;
+ ++*intptr;
+}
+static void remove_timers_cb(evutil_socket_t fd, short what, void *arg)
+{
+ struct event **ep = arg;
+ (void) fd; (void) what;
+ event_remove_timer(ep[0]);
+ event_remove_timer(ep[1]);
+}
+static void send_a_byte_cb(evutil_socket_t fd, short what, void *arg)
+{
+ evutil_socket_t *sockp = arg;
+ (void) fd; (void) what;
+ (void) write(*sockp, "A", 1);
+}
+struct read_not_timeout_param
+{
+ struct event **ev;
+ int events;
+ int count;
+};
+static void read_not_timeout_cb(evutil_socket_t fd, short what, void *arg)
+{
+ struct read_not_timeout_param *rntp = arg;
+ char c;
+ ev_ssize_t n;
+ (void) fd; (void) what;
+ n = read(fd, &c, 1);
+ tt_int_op(n, ==, 1);
+ rntp->events |= what;
+ ++rntp->count;
+ if(2 == rntp->count) event_del(rntp->ev[0]);
+end:
+ ;
+}
+
+static void
+test_event_remove_timeout(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base = data->base;
+ struct event *ev[5];
+ int ev1_fired=0;
+ struct timeval ms25 = { 0, 25*1000 },
+ ms40 = { 0, 40*1000 },
+ ms75 = { 0, 75*1000 },
+ ms125 = { 0, 125*1000 };
+ struct read_not_timeout_param rntp = { ev, 0, 0 };
+
+ event_base_assert_ok_(base);
+
+ ev[0] = event_new(base, data->pair[0], EV_READ|EV_PERSIST,
+ read_not_timeout_cb, &rntp);
+ ev[1] = evtimer_new(base, incr_arg_cb, &ev1_fired);
+ ev[2] = evtimer_new(base, remove_timers_cb, ev);
+ ev[3] = evtimer_new(base, send_a_byte_cb, &data->pair[1]);
+ ev[4] = evtimer_new(base, send_a_byte_cb, &data->pair[1]);
+ tt_assert(base);
+ event_add(ev[2], &ms25); /* remove timers */
+ event_add(ev[4], &ms40); /* write to test if timer re-activates */
+ event_add(ev[0], &ms75); /* read */
+ event_add(ev[1], &ms75); /* timer */
+ event_add(ev[3], &ms125); /* timeout. */
+ event_base_assert_ok_(base);
+
+ event_base_dispatch(base);
+
+ tt_int_op(ev1_fired, ==, 0);
+ tt_int_op(rntp.events, ==, EV_READ);
+
+ event_base_assert_ok_(base);
+end:
+ event_free(ev[0]);
+ event_free(ev[1]);
+ event_free(ev[2]);
+ event_free(ev[3]);
+ event_free(ev[4]);
+}
+
+static void
+test_event_base_new(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base = 0;
+ struct event ev1;
+ struct basic_cb_args args;
+
+ int towrite = (int)strlen(TEST1)+1;
+ int len = write(data->pair[0], TEST1, towrite);
+
+ if (len < 0)
+ tt_abort_perror("initial write");
+ else if (len != towrite)
+ tt_abort_printf(("initial write fell short (%d of %d bytes)",
+ len, towrite));
+
+ if (shutdown(data->pair[0], EVUTIL_SHUT_WR))
+ tt_abort_perror("initial write shutdown");
+
+ base = event_base_new();
+ if (!base)
+ tt_abort_msg("failed to create event base");
+
+ args.eb = base;
+ args.ev = &ev1;
+ args.callcount = 0;
+ event_assign(&ev1, base, data->pair[1],
+ EV_READ|EV_PERSIST, basic_read_cb, &args);
+
+ if (event_add(&ev1, NULL))
+ tt_abort_perror("initial event_add");
+
+ if (event_base_loop(base, 0))
+ tt_abort_msg("unsuccessful exit from event loop");
+
+end:
+ if (base)
+ event_base_free(base);
+}
+
+static void
+test_loopexit(void)
+{
+ struct timeval tv, tv_start, tv_end;
+ struct event ev;
+
+ setup_test("Loop exit: ");
+
+ tv.tv_usec = 0;
+ tv.tv_sec = 60*60*24;
+ evtimer_set(&ev, timeout_cb, NULL);
+ evtimer_add(&ev, &tv);
+
+ tv.tv_usec = 300*1000;
+ tv.tv_sec = 0;
+ event_loopexit(&tv);
+
+ evutil_gettimeofday(&tv_start, NULL);
+ event_dispatch();
+ evutil_gettimeofday(&tv_end, NULL);
+
+ evtimer_del(&ev);
+
+ tt_assert(event_base_got_exit(global_base));
+ tt_assert(!event_base_got_break(global_base));
+
+ test_timeval_diff_eq(&tv_start, &tv_end, 300);
+
+ test_ok = 1;
+end:
+ cleanup_test();
+}
+
+static void
+test_loopexit_multiple(void)
+{
+ struct timeval tv, tv_start, tv_end;
+ struct event_base *base;
+
+ setup_test("Loop Multiple exit: ");
+
+ base = event_base_new();
+
+ tv.tv_usec = 200*1000;
+ tv.tv_sec = 0;
+ event_base_loopexit(base, &tv);
+
+ tv.tv_usec = 0;
+ tv.tv_sec = 3;
+ event_base_loopexit(base, &tv);
+
+ evutil_gettimeofday(&tv_start, NULL);
+ event_base_dispatch(base);
+ evutil_gettimeofday(&tv_end, NULL);
+
+ tt_assert(event_base_got_exit(base));
+ tt_assert(!event_base_got_break(base));
+
+ event_base_free(base);
+
+ test_timeval_diff_eq(&tv_start, &tv_end, 200);
+
+ test_ok = 1;
+
+end:
+ cleanup_test();
+}
+
+static void
+break_cb(evutil_socket_t fd, short events, void *arg)
+{
+ test_ok = 1;
+ event_loopbreak();
+}
+
+static void
+fail_cb(evutil_socket_t fd, short events, void *arg)
+{
+ test_ok = 0;
+}
+
+static void
+test_loopbreak(void)
+{
+ struct event ev1, ev2;
+ struct timeval tv;
+
+ setup_test("Loop break: ");
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ evtimer_set(&ev1, break_cb, NULL);
+ evtimer_add(&ev1, &tv);
+ evtimer_set(&ev2, fail_cb, NULL);
+ evtimer_add(&ev2, &tv);
+
+ event_dispatch();
+
+ tt_assert(!event_base_got_exit(global_base));
+ tt_assert(event_base_got_break(global_base));
+
+ evtimer_del(&ev1);
+ evtimer_del(&ev2);
+
+end:
+ cleanup_test();
+}
+
+static struct event *readd_test_event_last_added = NULL;
+static void
+re_add_read_cb(evutil_socket_t fd, short event, void *arg)
+{
+ char buf[256];
+ struct event *ev_other = arg;
+ ev_ssize_t n_read;
+
+ readd_test_event_last_added = ev_other;
+
+ n_read = read(fd, buf, sizeof(buf));
+
+ if (n_read < 0) {
+ tt_fail_perror("read");
+ event_base_loopbreak(event_get_base(ev_other));
+ return;
+ } else {
+ event_add(ev_other, NULL);
+ ++test_ok;
+ }
+}
+
+static void
+test_nonpersist_readd(void)
+{
+ struct event ev1, ev2;
+
+ setup_test("Re-add nonpersistent events: ");
+ event_set(&ev1, pair[0], EV_READ, re_add_read_cb, &ev2);
+ event_set(&ev2, pair[1], EV_READ, re_add_read_cb, &ev1);
+
+ if (write(pair[0], "Hello", 5) < 0) {
+ tt_fail_perror("write(pair[0])");
+ }
+
+ if (write(pair[1], "Hello", 5) < 0) {
+ tt_fail_perror("write(pair[1])\n");
+ }
+
+ if (event_add(&ev1, NULL) == -1 ||
+ event_add(&ev2, NULL) == -1) {
+ test_ok = 0;
+ }
+ if (test_ok != 0)
+ exit(1);
+ event_loop(EVLOOP_ONCE);
+ if (test_ok != 2)
+ exit(1);
+ /* At this point, we executed both callbacks. Whichever one got
+ * called first added the second, but the second then immediately got
+ * deleted before its callback was called. At this point, though, it
+ * re-added the first.
+ */
+ if (!readd_test_event_last_added) {
+ test_ok = 0;
+ } else if (readd_test_event_last_added == &ev1) {
+ if (!event_pending(&ev1, EV_READ, NULL) ||
+ event_pending(&ev2, EV_READ, NULL))
+ test_ok = 0;
+ } else {
+ if (event_pending(&ev1, EV_READ, NULL) ||
+ !event_pending(&ev2, EV_READ, NULL))
+ test_ok = 0;
+ }
+
+ event_del(&ev1);
+ event_del(&ev2);
+
+ cleanup_test();
+}
+
+struct test_pri_event {
+ struct event ev;
+ int count;
+};
+
+static void
+test_priorities_cb(evutil_socket_t fd, short what, void *arg)
+{
+ struct test_pri_event *pri = arg;
+ struct timeval tv;
+
+ if (pri->count == 3) {
+ event_loopexit(NULL);
+ return;
+ }
+
+ pri->count++;
+
+ evutil_timerclear(&tv);
+ event_add(&pri->ev, &tv);
+}
+
+static void
+test_priorities_impl(int npriorities)
+{
+ struct test_pri_event one, two;
+ struct timeval tv;
+
+ TT_BLATHER(("Testing Priorities %d: ", npriorities));
+
+ event_base_priority_init(global_base, npriorities);
+
+ memset(&one, 0, sizeof(one));
+ memset(&two, 0, sizeof(two));
+
+ timeout_set(&one.ev, test_priorities_cb, &one);
+ if (event_priority_set(&one.ev, 0) == -1) {
+ fprintf(stderr, "%s: failed to set priority", __func__);
+ exit(1);
+ }
+
+ timeout_set(&two.ev, test_priorities_cb, &two);
+ if (event_priority_set(&two.ev, npriorities - 1) == -1) {
+ fprintf(stderr, "%s: failed to set priority", __func__);
+ exit(1);
+ }
+
+ evutil_timerclear(&tv);
+
+ if (event_add(&one.ev, &tv) == -1)
+ exit(1);
+ if (event_add(&two.ev, &tv) == -1)
+ exit(1);
+
+ event_dispatch();
+
+ event_del(&one.ev);
+ event_del(&two.ev);
+
+ if (npriorities == 1) {
+ if (one.count == 3 && two.count == 3)
+ test_ok = 1;
+ } else if (npriorities == 2) {
+ /* Two is called once because event_loopexit is priority 1 */
+ if (one.count == 3 && two.count == 1)
+ test_ok = 1;
+ } else {
+ if (one.count == 3 && two.count == 0)
+ test_ok = 1;
+ }
+}
+
+static void
+test_priorities(void)
+{
+ test_priorities_impl(1);
+ if (test_ok)
+ test_priorities_impl(2);
+ if (test_ok)
+ test_priorities_impl(3);
+}
+
+/* priority-active-inversion: activate a higher-priority event, and make sure
+ * it keeps us from running a lower-priority event first. */
+static int n_pai_calls = 0;
+static struct event pai_events[3];
+
+static void
+prio_active_inversion_cb(evutil_socket_t fd, short what, void *arg)
+{
+ int *call_order = arg;
+ *call_order = n_pai_calls++;
+ if (n_pai_calls == 1) {
+ /* This should activate later, even though it shares a
+ priority with us. */
+ event_active(&pai_events[1], EV_READ, 1);
+ /* This should activate next, since its priority is higher,
+ even though we activated it second. */
+ event_active(&pai_events[2], EV_TIMEOUT, 1);
+ }
+}
+
+static void
+test_priority_active_inversion(void *data_)
+{
+ struct basic_test_data *data = data_;
+ struct event_base *base = data->base;
+ int call_order[3];
+ int i;
+ tt_int_op(event_base_priority_init(base, 8), ==, 0);
+
+ n_pai_calls = 0;
+ memset(call_order, 0, sizeof(call_order));
+
+ for (i=0;i<3;++i) {
+ event_assign(&pai_events[i], data->base, -1, 0,
+ prio_active_inversion_cb, &call_order[i]);
+ }
+
+ event_priority_set(&pai_events[0], 4);
+ event_priority_set(&pai_events[1], 4);
+ event_priority_set(&pai_events[2], 0);
+
+ event_active(&pai_events[0], EV_WRITE, 1);
+
+ event_base_dispatch(base);
+ tt_int_op(n_pai_calls, ==, 3);
+ tt_int_op(call_order[0], ==, 0);
+ tt_int_op(call_order[1], ==, 2);
+ tt_int_op(call_order[2], ==, 1);
+end:
+ ;
+}
+
+
+static void
+test_multiple_cb(evutil_socket_t fd, short event, void *arg)
+{
+ if (event & EV_READ)
+ test_ok |= 1;
+ else if (event & EV_WRITE)
+ test_ok |= 2;
+}
+
+static void
+test_multiple_events_for_same_fd(void)
+{
+ struct event e1, e2;
+
+ setup_test("Multiple events for same fd: ");
+
+ event_set(&e1, pair[0], EV_READ, test_multiple_cb, NULL);
+ event_add(&e1, NULL);
+ event_set(&e2, pair[0], EV_WRITE, test_multiple_cb, NULL);
+ event_add(&e2, NULL);
+ event_loop(EVLOOP_ONCE);
+ event_del(&e2);
+
+ if (write(pair[1], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ event_loop(EVLOOP_ONCE);
+ event_del(&e1);
+
+ if (test_ok != 3)
+ test_ok = 0;
+
+ cleanup_test();
+}
+
+int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf);
+int evtag_decode_int64(ev_uint64_t *pnumber, struct evbuffer *evbuf);
+int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t number);
+int evtag_decode_tag(ev_uint32_t *pnumber, struct evbuffer *evbuf);
+
+static void
+read_once_cb(evutil_socket_t fd, short event, void *arg)
+{
+ char buf[256];
+ int len;
+
+ len = read(fd, buf, sizeof(buf));
+
+ if (called) {
+ test_ok = 0;
+ } else if (len) {
+ /* Assumes global pair[0] can be used for writing */
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ test_ok = 0;
+ } else {
+ test_ok = 1;
+ }
+ }
+
+ called++;
+}
+
+static void
+test_want_only_once(void)
+{
+ struct event ev;
+ struct timeval tv;
+
+ /* Very simple read test */
+ setup_test("Want read only once: ");
+
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ /* Setup the loop termination */
+ evutil_timerclear(&tv);
+ tv.tv_usec = 300*1000;
+ event_loopexit(&tv);
+
+ event_set(&ev, pair[1], EV_READ, read_once_cb, &ev);
+ if (event_add(&ev, NULL) == -1)
+ exit(1);
+ event_dispatch();
+
+ cleanup_test();
+}
+
+#define TEST_MAX_INT 6
+
+static void
+evtag_int_test(void *ptr)
+{
+ struct evbuffer *tmp = evbuffer_new();
+ ev_uint32_t integers[TEST_MAX_INT] = {
+ 0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000
+ };
+ ev_uint32_t integer;
+ ev_uint64_t big_int;
+ int i;
+
+ evtag_init();
+
+ for (i = 0; i < TEST_MAX_INT; i++) {
+ int oldlen, newlen;
+ oldlen = (int)EVBUFFER_LENGTH(tmp);
+ evtag_encode_int(tmp, integers[i]);
+ newlen = (int)EVBUFFER_LENGTH(tmp);
+ TT_BLATHER(("encoded 0x%08x with %d bytes",
+ (unsigned)integers[i], newlen - oldlen));
+ big_int = integers[i];
+ big_int *= 1000000000; /* 1 billion */
+ evtag_encode_int64(tmp, big_int);
+ }
+
+ for (i = 0; i < TEST_MAX_INT; i++) {
+ tt_int_op(evtag_decode_int(&integer, tmp), !=, -1);
+ tt_uint_op(integer, ==, integers[i]);
+ tt_int_op(evtag_decode_int64(&big_int, tmp), !=, -1);
+ tt_assert((big_int / 1000000000) == integers[i]);
+ }
+
+ tt_uint_op(EVBUFFER_LENGTH(tmp), ==, 0);
+end:
+ evbuffer_free(tmp);
+}
+
+static void
+evtag_fuzz(void *ptr)
+{
+ unsigned char buffer[4096];
+ struct evbuffer *tmp = evbuffer_new();
+ struct timeval tv;
+ int i, j;
+
+ int not_failed = 0;
+
+ evtag_init();
+
+ for (j = 0; j < 100; j++) {
+ for (i = 0; i < (int)sizeof(buffer); i++)
+ buffer[i] = test_weakrand();
+ evbuffer_drain(tmp, -1);
+ evbuffer_add(tmp, buffer, sizeof(buffer));
+
+ if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1)
+ not_failed++;
+ }
+
+ /* The majority of decodes should fail */
+ tt_int_op(not_failed, <, 10);
+
+ /* Now insert some corruption into the tag length field */
+ evbuffer_drain(tmp, -1);
+ evutil_timerclear(&tv);
+ tv.tv_sec = 1;
+ evtag_marshal_timeval(tmp, 0, &tv);
+ evbuffer_add(tmp, buffer, sizeof(buffer));
+
+ ((char *)EVBUFFER_DATA(tmp))[1] = '\xff';
+ if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1) {
+ tt_abort_msg("evtag_unmarshal_timeval should have failed");
+ }
+
+end:
+ evbuffer_free(tmp);
+}
+
+static void
+evtag_tag_encoding(void *ptr)
+{
+ struct evbuffer *tmp = evbuffer_new();
+ ev_uint32_t integers[TEST_MAX_INT] = {
+ 0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000
+ };
+ ev_uint32_t integer;
+ int i;
+
+ evtag_init();
+
+ for (i = 0; i < TEST_MAX_INT; i++) {
+ int oldlen, newlen;
+ oldlen = (int)EVBUFFER_LENGTH(tmp);
+ evtag_encode_tag(tmp, integers[i]);
+ newlen = (int)EVBUFFER_LENGTH(tmp);
+ TT_BLATHER(("encoded 0x%08x with %d bytes",
+ (unsigned)integers[i], newlen - oldlen));
+ }
+
+ for (i = 0; i < TEST_MAX_INT; i++) {
+ tt_int_op(evtag_decode_tag(&integer, tmp), !=, -1);
+ tt_uint_op(integer, ==, integers[i]);
+ }
+
+ tt_uint_op(EVBUFFER_LENGTH(tmp), ==, 0);
+
+end:
+ evbuffer_free(tmp);
+}
+
+static void
+evtag_test_peek(void *ptr)
+{
+ struct evbuffer *tmp = evbuffer_new();
+ ev_uint32_t u32;
+
+ evtag_marshal_int(tmp, 30, 0);
+ evtag_marshal_string(tmp, 40, "Hello world");
+
+ tt_int_op(evtag_peek(tmp, &u32), ==, 1);
+ tt_int_op(u32, ==, 30);
+ tt_int_op(evtag_peek_length(tmp, &u32), ==, 0);
+ tt_int_op(u32, ==, 1+1+1);
+ tt_int_op(evtag_consume(tmp), ==, 0);
+
+ tt_int_op(evtag_peek(tmp, &u32), ==, 1);
+ tt_int_op(u32, ==, 40);
+ tt_int_op(evtag_peek_length(tmp, &u32), ==, 0);
+ tt_int_op(u32, ==, 1+1+11);
+ tt_int_op(evtag_payload_length(tmp, &u32), ==, 0);
+ tt_int_op(u32, ==, 11);
+
+end:
+ evbuffer_free(tmp);
+}
+
+
+static void
+test_methods(void *ptr)
+{
+ const char **methods = event_get_supported_methods();
+ struct event_config *cfg = NULL;
+ struct event_base *base = NULL;
+ const char *backend;
+ int n_methods = 0;
+
+ tt_assert(methods);
+
+ backend = methods[0];
+ while (*methods != NULL) {
+ TT_BLATHER(("Support method: %s", *methods));
+ ++methods;
+ ++n_methods;
+ }
+
+ cfg = event_config_new();
+ assert(cfg != NULL);
+
+ tt_int_op(event_config_avoid_method(cfg, backend), ==, 0);
+ event_config_set_flag(cfg, EVENT_BASE_FLAG_IGNORE_ENV);
+
+ base = event_base_new_with_config(cfg);
+ if (n_methods > 1) {
+ tt_assert(base);
+ tt_str_op(backend, !=, event_base_get_method(base));
+ } else {
+ tt_assert(base == NULL);
+ }
+
+end:
+ if (base)
+ event_base_free(base);
+ if (cfg)
+ event_config_free(cfg);
+}
+
+static void
+test_version(void *arg)
+{
+ const char *vstr;
+ ev_uint32_t vint;
+ int major, minor, patch, n;
+
+ vstr = event_get_version();
+ vint = event_get_version_number();
+
+ tt_assert(vstr);
+ tt_assert(vint);
+
+ tt_str_op(vstr, ==, LIBEVENT_VERSION);
+ tt_int_op(vint, ==, LIBEVENT_VERSION_NUMBER);
+
+ n = sscanf(vstr, "%d.%d.%d", &major, &minor, &patch);
+ tt_assert(3 == n);
+ tt_int_op((vint&0xffffff00), ==, ((major<<24)|(minor<<16)|(patch<<8)));
+end:
+ ;
+}
+
+static void
+test_base_features(void *arg)
+{
+ struct event_base *base = NULL;
+ struct event_config *cfg = NULL;
+
+ cfg = event_config_new();
+
+ tt_assert(0 == event_config_require_features(cfg, EV_FEATURE_ET));
+
+ base = event_base_new_with_config(cfg);
+ if (base) {
+ tt_int_op(EV_FEATURE_ET, ==,
+ event_base_get_features(base) & EV_FEATURE_ET);
+ } else {
+ base = event_base_new();
+ tt_int_op(0, ==, event_base_get_features(base) & EV_FEATURE_ET);
+ }
+
+end:
+ if (base)
+ event_base_free(base);
+ if (cfg)
+ event_config_free(cfg);
+}
+
+#ifdef EVENT__HAVE_SETENV
+#define SETENV_OK
+#elif !defined(EVENT__HAVE_SETENV) && defined(EVENT__HAVE_PUTENV)
+static void setenv(const char *k, const char *v, int o_)
+{
+ char b[256];
+ evutil_snprintf(b, sizeof(b), "%s=%s",k,v);
+ putenv(b);
+}
+#define SETENV_OK
+#endif
+
+#ifdef EVENT__HAVE_UNSETENV
+#define UNSETENV_OK
+#elif !defined(EVENT__HAVE_UNSETENV) && defined(EVENT__HAVE_PUTENV)
+static void unsetenv(const char *k)
+{
+ char b[256];
+ evutil_snprintf(b, sizeof(b), "%s=",k);
+ putenv(b);
+}
+#define UNSETENV_OK
+#endif
+
+#if defined(SETENV_OK) && defined(UNSETENV_OK)
+static void
+methodname_to_envvar(const char *mname, char *buf, size_t buflen)
+{
+ char *cp;
+ evutil_snprintf(buf, buflen, "EVENT_NO%s", mname);
+ for (cp = buf; *cp; ++cp) {
+ *cp = EVUTIL_TOUPPER_(*cp);
+ }
+}
+#endif
+
+static void
+test_base_environ(void *arg)
+{
+ struct event_base *base = NULL;
+ struct event_config *cfg = NULL;
+
+#if defined(SETENV_OK) && defined(UNSETENV_OK)
+ const char **basenames;
+ int i, n_methods=0;
+ char varbuf[128];
+ const char *defaultname, *ignoreenvname;
+
+ /* See if unsetenv works before we rely on it. */
+ setenv("EVENT_NOWAFFLES", "1", 1);
+ unsetenv("EVENT_NOWAFFLES");
+ if (getenv("EVENT_NOWAFFLES") != NULL) {
+#ifndef EVENT__HAVE_UNSETENV
+ TT_DECLARE("NOTE", ("Can't fake unsetenv; skipping test"));
+#else
+ TT_DECLARE("NOTE", ("unsetenv doesn't work; skipping test"));
+#endif
+ tt_skip();
+ }
+
+ basenames = event_get_supported_methods();
+ for (i = 0; basenames[i]; ++i) {
+ methodname_to_envvar(basenames[i], varbuf, sizeof(varbuf));
+ unsetenv(varbuf);
+ ++n_methods;
+ }
+
+ base = event_base_new();
+ tt_assert(base);
+
+ defaultname = event_base_get_method(base);
+ TT_BLATHER(("default is <%s>", defaultname));
+ event_base_free(base);
+ base = NULL;
+
+ /* Can we disable the method with EVENT_NOfoo ? */
+ if (!strcmp(defaultname, "epoll (with changelist)")) {
+ setenv("EVENT_NOEPOLL", "1", 1);
+ ignoreenvname = "epoll";
+ } else {
+ methodname_to_envvar(defaultname, varbuf, sizeof(varbuf));
+ setenv(varbuf, "1", 1);
+ ignoreenvname = defaultname;
+ }
+
+ /* Use an empty cfg rather than NULL so a failure doesn't exit() */
+ cfg = event_config_new();
+ base = event_base_new_with_config(cfg);
+ event_config_free(cfg);
+ cfg = NULL;
+ if (n_methods == 1) {
+ tt_assert(!base);
+ } else {
+ tt_assert(base);
+ tt_str_op(defaultname, !=, event_base_get_method(base));
+ event_base_free(base);
+ base = NULL;
+ }
+
+ /* Can we disable looking at the environment with IGNORE_ENV ? */
+ cfg = event_config_new();
+ event_config_set_flag(cfg, EVENT_BASE_FLAG_IGNORE_ENV);
+ base = event_base_new_with_config(cfg);
+ tt_assert(base);
+ tt_str_op(ignoreenvname, ==, event_base_get_method(base));
+#else
+ tt_skip();
+#endif
+
+end:
+ if (base)
+ event_base_free(base);
+ if (cfg)
+ event_config_free(cfg);
+}
+
+static void
+read_called_once_cb(evutil_socket_t fd, short event, void *arg)
+{
+ tt_int_op(event, ==, EV_READ);
+ called += 1;
+end:
+ ;
+}
+
+static void
+timeout_called_once_cb(evutil_socket_t fd, short event, void *arg)
+{
+ tt_int_op(event, ==, EV_TIMEOUT);
+ called += 100;
+end:
+ ;
+}
+
+static void
+immediate_called_twice_cb(evutil_socket_t fd, short event, void *arg)
+{
+ tt_int_op(event, ==, EV_TIMEOUT);
+ called += 1000;
+end:
+ ;
+}
+
+static void
+test_event_once(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct timeval tv;
+ int r;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 50*1000;
+ called = 0;
+ r = event_base_once(data->base, data->pair[0], EV_READ,
+ read_called_once_cb, NULL, NULL);
+ tt_int_op(r, ==, 0);
+ r = event_base_once(data->base, -1, EV_TIMEOUT,
+ timeout_called_once_cb, NULL, &tv);
+ tt_int_op(r, ==, 0);
+ r = event_base_once(data->base, -1, 0, NULL, NULL, NULL);
+ tt_int_op(r, <, 0);
+ r = event_base_once(data->base, -1, EV_TIMEOUT,
+ immediate_called_twice_cb, NULL, NULL);
+ tt_int_op(r, ==, 0);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ r = event_base_once(data->base, -1, EV_TIMEOUT,
+ immediate_called_twice_cb, NULL, &tv);
+ tt_int_op(r, ==, 0);
+
+ if (write(data->pair[1], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ shutdown(data->pair[1], EVUTIL_SHUT_WR);
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(called, ==, 2101);
+end:
+ ;
+}
+
+static void
+test_event_once_never(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct timeval tv;
+
+ /* Have one trigger in 10 seconds (don't worry, because) */
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+ called = 0;
+ event_base_once(data->base, -1, EV_TIMEOUT,
+ timeout_called_once_cb, NULL, &tv);
+
+ /* But shut down the base in 75 msec. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 75*1000;
+ event_base_loopexit(data->base, &tv);
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(called, ==, 0);
+end:
+ ;
+}
+
+static void
+test_event_pending(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event *r=NULL, *w=NULL, *t=NULL;
+ struct timeval tv, now, tv2;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 500 * 1000;
+ r = event_new(data->base, data->pair[0], EV_READ, simple_read_cb,
+ NULL);
+ w = event_new(data->base, data->pair[1], EV_WRITE, simple_write_cb,
+ NULL);
+ t = evtimer_new(data->base, timeout_cb, NULL);
+
+ tt_assert(r);
+ tt_assert(w);
+ tt_assert(t);
+
+ evutil_gettimeofday(&now, NULL);
+ event_add(r, NULL);
+ event_add(t, &tv);
+
+ tt_assert( event_pending(r, EV_READ, NULL));
+ tt_assert(!event_pending(w, EV_WRITE, NULL));
+ tt_assert(!event_pending(r, EV_WRITE, NULL));
+ tt_assert( event_pending(r, EV_READ|EV_WRITE, NULL));
+ tt_assert(!event_pending(r, EV_TIMEOUT, NULL));
+ tt_assert( event_pending(t, EV_TIMEOUT, NULL));
+ tt_assert( event_pending(t, EV_TIMEOUT, &tv2));
+
+ tt_assert(evutil_timercmp(&tv2, &now, >));
+
+ test_timeval_diff_eq(&now, &tv2, 500);
+
+end:
+ if (r) {
+ event_del(r);
+ event_free(r);
+ }
+ if (w) {
+ event_del(w);
+ event_free(w);
+ }
+ if (t) {
+ event_del(t);
+ event_free(t);
+ }
+}
+
+static void
+dfd_cb(evutil_socket_t fd, short e, void *data)
+{
+ *(int*)data = (int)e;
+}
+
+static void
+test_event_closed_fd_poll(void *arg)
+{
+ struct timeval tv;
+ struct event *e;
+ struct basic_test_data *data = (struct basic_test_data *)arg;
+ int i = 0;
+
+ if (strcmp(event_base_get_method(data->base), "poll")) {
+ tinytest_set_test_skipped_();
+ return;
+ }
+
+ e = event_new(data->base, data->pair[0], EV_READ, dfd_cb, &i);
+ tt_assert(e);
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 500 * 1000;
+ event_add(e, &tv);
+ tt_assert(event_pending(e, EV_READ, NULL));
+ close(data->pair[0]);
+ data->pair[0] = -1; /** avoids double-close */
+ event_base_loop(data->base, EVLOOP_ONCE);
+ tt_int_op(i, ==, EV_READ);
+
+end:
+ if (e) {
+ event_del(e);
+ event_free(e);
+ }
+}
+
+#ifndef _WIN32
+/* You can't do this test on windows, since dup2 doesn't work on sockets */
+
+/* Regression test for our workaround for a fun epoll/linux related bug
+ * where fd2 = dup(fd1); add(fd2); close(fd2); dup2(fd1,fd2); add(fd2)
+ * will get you an EEXIST */
+static void
+test_dup_fd(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct event *ev1=NULL, *ev2=NULL;
+ int fd, dfd=-1;
+ int ev1_got, ev2_got;
+
+ tt_int_op(write(data->pair[0], "Hello world",
+ strlen("Hello world")), >, 0);
+ fd = data->pair[1];
+
+ dfd = dup(fd);
+ tt_int_op(dfd, >=, 0);
+
+ ev1 = event_new(base, fd, EV_READ|EV_PERSIST, dfd_cb, &ev1_got);
+ ev2 = event_new(base, dfd, EV_READ|EV_PERSIST, dfd_cb, &ev2_got);
+ ev1_got = ev2_got = 0;
+ event_add(ev1, NULL);
+ event_add(ev2, NULL);
+ event_base_loop(base, EVLOOP_ONCE);
+ tt_int_op(ev1_got, ==, EV_READ);
+ tt_int_op(ev2_got, ==, EV_READ);
+
+ /* Now close and delete dfd then dispatch. We need to do the
+ * dispatch here so that when we add it later, we think there
+ * was an intermediate delete. */
+ close(dfd);
+ event_del(ev2);
+ ev1_got = ev2_got = 0;
+ event_base_loop(base, EVLOOP_ONCE);
+ tt_want_int_op(ev1_got, ==, EV_READ);
+ tt_int_op(ev2_got, ==, 0);
+
+ /* Re-duplicate the fd. We need to get the same duplicated
+ * value that we closed to provoke the epoll quirk. Also, we
+ * need to change the events to write, or else the old lingering
+ * read event will make the test pass whether the change was
+ * successful or not. */
+ tt_int_op(dup2(fd, dfd), ==, dfd);
+ event_free(ev2);
+ ev2 = event_new(base, dfd, EV_WRITE|EV_PERSIST, dfd_cb, &ev2_got);
+ event_add(ev2, NULL);
+ ev1_got = ev2_got = 0;
+ event_base_loop(base, EVLOOP_ONCE);
+ tt_want_int_op(ev1_got, ==, EV_READ);
+ tt_int_op(ev2_got, ==, EV_WRITE);
+
+end:
+ if (ev1)
+ event_free(ev1);
+ if (ev2)
+ event_free(ev2);
+ if (dfd >= 0)
+ close(dfd);
+}
+#endif
+
+#ifdef EVENT__DISABLE_MM_REPLACEMENT
+static void
+test_mm_functions(void *arg)
+{
+ tinytest_set_test_skipped_();
+}
+#else
+static int
+check_dummy_mem_ok(void *mem_)
+{
+ char *mem = mem_;
+ mem -= 16;
+ return !memcmp(mem, "{[<guardedram>]}", 16);
+}
+
+static void *
+dummy_malloc(size_t len)
+{
+ char *mem = malloc(len+16);
+ memcpy(mem, "{[<guardedram>]}", 16);
+ return mem+16;
+}
+
+static void *
+dummy_realloc(void *mem_, size_t len)
+{
+ char *mem = mem_;
+ if (!mem)
+ return dummy_malloc(len);
+ tt_want(check_dummy_mem_ok(mem_));
+ mem -= 16;
+ mem = realloc(mem, len+16);
+ return mem+16;
+}
+
+static void
+dummy_free(void *mem_)
+{
+ char *mem = mem_;
+ tt_want(check_dummy_mem_ok(mem_));
+ mem -= 16;
+ free(mem);
+}
+
+static void
+test_mm_functions(void *arg)
+{
+ struct event_base *b = NULL;
+ struct event_config *cfg = NULL;
+ event_set_mem_functions(dummy_malloc, dummy_realloc, dummy_free);
+ cfg = event_config_new();
+ event_config_avoid_method(cfg, "Nonesuch");
+ b = event_base_new_with_config(cfg);
+ tt_assert(b);
+ tt_assert(check_dummy_mem_ok(b));
+end:
+ if (cfg)
+ event_config_free(cfg);
+ if (b)
+ event_base_free(b);
+}
+#endif
+
+static void
+many_event_cb(evutil_socket_t fd, short event, void *arg)
+{
+ int *calledp = arg;
+ *calledp += 1;
+}
+
+static void
+test_many_events(void *arg)
+{
+ /* Try 70 events that should all be ready at once. This will
+ * exercise the "resize" code on most of the backends, and will make
+ * sure that we can get past the 64-handle limit of some windows
+ * functions. */
+#define MANY 70
+
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ int one_at_a_time = data->setup_data != NULL;
+ evutil_socket_t sock[MANY];
+ struct event *ev[MANY];
+ int called[MANY];
+ int i;
+ int loopflags = EVLOOP_NONBLOCK, evflags=0;
+ if (one_at_a_time) {
+ loopflags |= EVLOOP_ONCE;
+ evflags = EV_PERSIST;
+ }
+
+ memset(sock, 0xff, sizeof(sock));
+ memset(ev, 0, sizeof(ev));
+ memset(called, 0, sizeof(called));
+
+ for (i = 0; i < MANY; ++i) {
+ /* We need an event that will hit the backend, and that will
+ * be ready immediately. "Send a datagram" is an easy
+ * instance of that. */
+ sock[i] = socket(AF_INET, SOCK_DGRAM, 0);
+ tt_assert(sock[i] >= 0);
+ called[i] = 0;
+ ev[i] = event_new(base, sock[i], EV_WRITE|evflags,
+ many_event_cb, &called[i]);
+ event_add(ev[i], NULL);
+ if (one_at_a_time)
+ event_base_loop(base, EVLOOP_NONBLOCK|EVLOOP_ONCE);
+ }
+
+ event_base_loop(base, loopflags);
+
+ for (i = 0; i < MANY; ++i) {
+ if (one_at_a_time)
+ tt_int_op(called[i], ==, MANY - i + 1);
+ else
+ tt_int_op(called[i], ==, 1);
+ }
+
+end:
+ for (i = 0; i < MANY; ++i) {
+ if (ev[i])
+ event_free(ev[i]);
+ if (sock[i] >= 0)
+ evutil_closesocket(sock[i]);
+ }
+#undef MANY
+}
+
+static void
+test_struct_event_size(void *arg)
+{
+ tt_int_op(event_get_struct_event_size(), <=, sizeof(struct event));
+end:
+ ;
+}
+
+static void
+test_get_assignment(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct event *ev1 = NULL;
+ const char *str = "foo";
+
+ struct event_base *b;
+ evutil_socket_t s;
+ short what;
+ event_callback_fn cb;
+ void *cb_arg;
+
+ ev1 = event_new(base, data->pair[1], EV_READ, dummy_read_cb, (void*)str);
+ event_get_assignment(ev1, &b, &s, &what, &cb, &cb_arg);
+
+ tt_ptr_op(b, ==, base);
+ tt_int_op(s, ==, data->pair[1]);
+ tt_int_op(what, ==, EV_READ);
+ tt_ptr_op(cb, ==, dummy_read_cb);
+ tt_ptr_op(cb_arg, ==, str);
+
+ /* Now make sure this doesn't crash. */
+ event_get_assignment(ev1, NULL, NULL, NULL, NULL, NULL);
+
+end:
+ if (ev1)
+ event_free(ev1);
+}
+
+struct foreach_helper {
+ int count;
+ const struct event *ev;
+};
+
+static int
+foreach_count_cb(const struct event_base *base, const struct event *ev, void *arg)
+{
+ struct foreach_helper *h = event_get_callback_arg(ev);
+ struct timeval *tv = arg;
+ if (event_get_callback(ev) != timeout_cb)
+ return 0;
+ tt_ptr_op(event_get_base(ev), ==, base);
+ tt_int_op(tv->tv_sec, ==, 10);
+ h->ev = ev;
+ h->count++;
+ return 0;
+end:
+ return -1;
+}
+
+static int
+foreach_find_cb(const struct event_base *base, const struct event *ev, void *arg)
+{
+ const struct event **ev_out = arg;
+ struct foreach_helper *h = event_get_callback_arg(ev);
+ if (event_get_callback(ev) != timeout_cb)
+ return 0;
+ if (h->count == 99) {
+ *ev_out = ev;
+ return 101;
+ }
+ return 0;
+}
+
+static void
+test_event_foreach(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct event *ev[5];
+ struct foreach_helper visited[5];
+ int i;
+ struct timeval ten_sec = {10,0};
+ const struct event *ev_found = NULL;
+
+ for (i = 0; i < 5; ++i) {
+ visited[i].count = 0;
+ visited[i].ev = NULL;
+ ev[i] = event_new(base, -1, 0, timeout_cb, &visited[i]);
+ }
+
+ tt_int_op(-1, ==, event_base_foreach_event(NULL, foreach_count_cb, NULL));
+ tt_int_op(-1, ==, event_base_foreach_event(base, NULL, NULL));
+
+ event_add(ev[0], &ten_sec);
+ event_add(ev[1], &ten_sec);
+ event_active(ev[1], EV_TIMEOUT, 1);
+ event_active(ev[2], EV_TIMEOUT, 1);
+ event_add(ev[3], &ten_sec);
+ /* Don't touch ev[4]. */
+
+ tt_int_op(0, ==, event_base_foreach_event(base, foreach_count_cb,
+ &ten_sec));
+ tt_int_op(1, ==, visited[0].count);
+ tt_int_op(1, ==, visited[1].count);
+ tt_int_op(1, ==, visited[2].count);
+ tt_int_op(1, ==, visited[3].count);
+ tt_ptr_op(ev[0], ==, visited[0].ev);
+ tt_ptr_op(ev[1], ==, visited[1].ev);
+ tt_ptr_op(ev[2], ==, visited[2].ev);
+ tt_ptr_op(ev[3], ==, visited[3].ev);
+
+ visited[2].count = 99;
+ tt_int_op(101, ==, event_base_foreach_event(base, foreach_find_cb,
+ &ev_found));
+ tt_ptr_op(ev_found, ==, ev[2]);
+
+end:
+ for (i=0; i<5; ++i) {
+ event_free(ev[i]);
+ }
+}
+
+static struct event_base *cached_time_base = NULL;
+static int cached_time_reset = 0;
+static int cached_time_sleep = 0;
+static void
+cache_time_cb(evutil_socket_t fd, short what, void *arg)
+{
+ struct timeval *tv = arg;
+ tt_int_op(0, ==, event_base_gettimeofday_cached(cached_time_base, tv));
+ if (cached_time_sleep) {
+ struct timeval delay = { 0, 30*1000 };
+ evutil_usleep_(&delay);
+ }
+ if (cached_time_reset) {
+ event_base_update_cache_time(cached_time_base);
+ }
+end:
+ ;
+}
+
+static void
+test_gettimeofday_cached(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_config *cfg = NULL;
+ struct event_base *base = NULL;
+ struct timeval tv1, tv2, tv3, now;
+ struct event *ev1=NULL, *ev2=NULL, *ev3=NULL;
+ int cached_time_disable = strstr(data->setup_data, "disable") != NULL;
+
+ cfg = event_config_new();
+ if (cached_time_disable) {
+ event_config_set_flag(cfg, EVENT_BASE_FLAG_NO_CACHE_TIME);
+ }
+ cached_time_base = base = event_base_new_with_config(cfg);
+ tt_assert(base);
+
+ /* Try gettimeofday_cached outside of an event loop. */
+ evutil_gettimeofday(&now, NULL);
+ tt_int_op(0, ==, event_base_gettimeofday_cached(NULL, &tv1));
+ tt_int_op(0, ==, event_base_gettimeofday_cached(base, &tv2));
+ tt_int_op(timeval_msec_diff(&tv1, &tv2), <, 10);
+ tt_int_op(timeval_msec_diff(&tv1, &now), <, 10);
+
+ cached_time_reset = strstr(data->setup_data, "reset") != NULL;
+ cached_time_sleep = strstr(data->setup_data, "sleep") != NULL;
+
+ ev1 = event_new(base, -1, 0, cache_time_cb, &tv1);
+ ev2 = event_new(base, -1, 0, cache_time_cb, &tv2);
+ ev3 = event_new(base, -1, 0, cache_time_cb, &tv3);
+
+ event_active(ev1, EV_TIMEOUT, 1);
+ event_active(ev2, EV_TIMEOUT, 1);
+ event_active(ev3, EV_TIMEOUT, 1);
+
+ event_base_dispatch(base);
+
+ if (cached_time_reset && cached_time_sleep) {
+ tt_int_op(labs(timeval_msec_diff(&tv1,&tv2)), >, 10);
+ tt_int_op(labs(timeval_msec_diff(&tv2,&tv3)), >, 10);
+ } else if (cached_time_disable && cached_time_sleep) {
+ tt_int_op(labs(timeval_msec_diff(&tv1,&tv2)), >, 10);
+ tt_int_op(labs(timeval_msec_diff(&tv2,&tv3)), >, 10);
+ } else if (! cached_time_disable) {
+ tt_assert(evutil_timercmp(&tv1, &tv2, ==));
+ tt_assert(evutil_timercmp(&tv2, &tv3, ==));
+ }
+
+end:
+ if (ev1)
+ event_free(ev1);
+ if (ev2)
+ event_free(ev2);
+ if (ev3)
+ event_free(ev3);
+ if (base)
+ event_base_free(base);
+ if (cfg)
+ event_config_free(cfg);
+}
+
+static void
+tabf_cb(evutil_socket_t fd, short what, void *arg)
+{
+ int *ptr = arg;
+ *ptr = what;
+ *ptr += 0x10000;
+}
+
+static void
+test_active_by_fd(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct event *ev1 = NULL, *ev2 = NULL, *ev3 = NULL, *ev4 = NULL;
+ int e1,e2,e3,e4;
+#ifndef _WIN32
+ struct event *evsig = NULL;
+ int es;
+#endif
+ struct timeval tenmin = { 600, 0 };
+
+ /* Ensure no crash on nonexistent FD. */
+ event_base_active_by_fd(base, 1000, EV_READ);
+
+ /* Ensure no crash on bogus FD. */
+ event_base_active_by_fd(base, -1, EV_READ);
+
+ /* Ensure no crash on nonexistent/bogus signal. */
+ event_base_active_by_signal(base, 1000);
+ event_base_active_by_signal(base, -1);
+
+ event_base_assert_ok_(base);
+
+ e1 = e2 = e3 = e4 = 0;
+ ev1 = event_new(base, data->pair[0], EV_READ, tabf_cb, &e1);
+ ev2 = event_new(base, data->pair[0], EV_WRITE, tabf_cb, &e2);
+ ev3 = event_new(base, data->pair[1], EV_READ, tabf_cb, &e3);
+ ev4 = event_new(base, data->pair[1], EV_READ, tabf_cb, &e4);
+ tt_assert(ev1);
+ tt_assert(ev2);
+ tt_assert(ev3);
+ tt_assert(ev4);
+#ifndef _WIN32
+ evsig = event_new(base, SIGHUP, EV_SIGNAL, tabf_cb, &es);
+ tt_assert(evsig);
+ event_add(evsig, &tenmin);
+#endif
+
+ event_add(ev1, &tenmin);
+ event_add(ev2, NULL);
+ event_add(ev3, NULL);
+ event_add(ev4, &tenmin);
+
+
+ event_base_assert_ok_(base);
+
+ /* Trigger 2, 3, 4 */
+ event_base_active_by_fd(base, data->pair[0], EV_WRITE);
+ event_base_active_by_fd(base, data->pair[1], EV_READ);
+#ifndef _WIN32
+ event_base_active_by_signal(base, SIGHUP);
+#endif
+
+ event_base_assert_ok_(base);
+
+ event_base_loop(base, EVLOOP_ONCE);
+
+ tt_int_op(e1, ==, 0);
+ tt_int_op(e2, ==, EV_WRITE | 0x10000);
+ tt_int_op(e3, ==, EV_READ | 0x10000);
+ /* Mask out EV_WRITE here, since it could be genuinely writeable. */
+ tt_int_op((e4 & ~EV_WRITE), ==, EV_READ | 0x10000);
+#ifndef _WIN32
+ tt_int_op(es, ==, EV_SIGNAL | 0x10000);
+#endif
+
+end:
+ if (ev1)
+ event_free(ev1);
+ if (ev2)
+ event_free(ev2);
+ if (ev3)
+ event_free(ev3);
+ if (ev4)
+ event_free(ev4);
+#ifndef _WIN32
+ if (evsig)
+ event_free(evsig);
+#endif
+}
+
+struct testcase_t main_testcases[] = {
+ /* Some converted-over tests */
+ { "methods", test_methods, TT_FORK, NULL, NULL },
+ { "version", test_version, 0, NULL, NULL },
+ BASIC(base_features, TT_FORK|TT_NO_LOGS),
+ { "base_environ", test_base_environ, TT_FORK, NULL, NULL },
+
+ BASIC(event_base_new, TT_FORK|TT_NEED_SOCKETPAIR),
+ BASIC(free_active_base, TT_FORK|TT_NEED_SOCKETPAIR),
+
+ BASIC(manipulate_active_events, TT_FORK|TT_NEED_BASE),
+ BASIC(event_new_selfarg, TT_FORK|TT_NEED_BASE),
+ BASIC(event_assign_selfarg, TT_FORK|TT_NEED_BASE),
+ BASIC(event_base_get_num_events, TT_FORK|TT_NEED_BASE),
+ BASIC(event_base_get_max_events, TT_FORK|TT_NEED_BASE),
+
+ BASIC(bad_assign, TT_FORK|TT_NEED_BASE|TT_NO_LOGS),
+ BASIC(bad_reentrant, TT_FORK|TT_NEED_BASE|TT_NO_LOGS),
+ BASIC(active_later, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR),
+ BASIC(event_remove_timeout, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR),
+
+ /* These are still using the old API */
+ LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE),
+ { "persistent_timeout_jump", test_persistent_timeout_jump, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "persistent_active_timeout", test_persistent_active_timeout,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ LEGACY(priorities, TT_FORK|TT_NEED_BASE),
+ BASIC(priority_active_inversion, TT_FORK|TT_NEED_BASE),
+ { "common_timeout", test_common_timeout, TT_FORK|TT_NEED_BASE,
+ &basic_setup, NULL },
+
+ /* These legacy tests may not all need all of these flags. */
+ LEGACY(simpleread, TT_ISOLATED),
+ LEGACY(simpleread_multiple, TT_ISOLATED),
+ LEGACY(simplewrite, TT_ISOLATED),
+ { "simpleclose", test_simpleclose, TT_FORK, &basic_setup,
+ NULL },
+ LEGACY(multiple, TT_ISOLATED),
+ LEGACY(persistent, TT_ISOLATED),
+ LEGACY(combined, TT_ISOLATED),
+ LEGACY(simpletimeout, TT_ISOLATED),
+ LEGACY(loopbreak, TT_ISOLATED),
+ LEGACY(loopexit, TT_ISOLATED),
+ LEGACY(loopexit_multiple, TT_ISOLATED),
+ LEGACY(nonpersist_readd, TT_ISOLATED),
+ LEGACY(multiple_events_for_same_fd, TT_ISOLATED),
+ LEGACY(want_only_once, TT_ISOLATED),
+ { "event_once", test_event_once, TT_ISOLATED, &basic_setup, NULL },
+ { "event_once_never", test_event_once_never, TT_ISOLATED, &basic_setup, NULL },
+ { "event_pending", test_event_pending, TT_ISOLATED, &basic_setup,
+ NULL },
+ { "event_closed_fd_poll", test_event_closed_fd_poll, TT_ISOLATED, &basic_setup,
+ NULL },
+
+#ifndef _WIN32
+ { "dup_fd", test_dup_fd, TT_ISOLATED, &basic_setup, NULL },
+#endif
+ { "mm_functions", test_mm_functions, TT_FORK, NULL, NULL },
+ { "many_events", test_many_events, TT_ISOLATED, &basic_setup, NULL },
+ { "many_events_slow_add", test_many_events, TT_ISOLATED, &basic_setup, (void*)1 },
+
+ { "struct_event_size", test_struct_event_size, 0, NULL, NULL },
+ BASIC(get_assignment, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR),
+
+ BASIC(event_foreach, TT_FORK|TT_NEED_BASE),
+ { "gettimeofday_cached", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"" },
+ { "gettimeofday_cached_sleep", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"sleep" },
+ { "gettimeofday_cached_reset", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"sleep reset" },
+ { "gettimeofday_cached_disabled", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"sleep disable" },
+ { "gettimeofday_cached_disabled_nosleep", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"disable" },
+
+ BASIC(active_by_fd, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR),
+
+#ifndef _WIN32
+ LEGACY(fork, TT_ISOLATED),
+#endif
+#ifdef EVENT__HAVE_PTHREADS
+ /** TODO: support win32 */
+ LEGACY(del_wait, TT_ISOLATED|TT_NEED_THREADS),
+#endif
+
+ END_OF_TESTCASES
+};
+
+struct testcase_t evtag_testcases[] = {
+ { "int", evtag_int_test, TT_FORK, NULL, NULL },
+ { "fuzz", evtag_fuzz, TT_FORK, NULL, NULL },
+ { "encoding", evtag_tag_encoding, TT_FORK, NULL, NULL },
+ { "peek", evtag_test_peek, 0, NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
+struct testcase_t signal_testcases[] = {
+#ifndef _WIN32
+ LEGACY(simplestsignal, TT_ISOLATED),
+ LEGACY(simplesignal, TT_ISOLATED),
+ LEGACY(multiplesignal, TT_ISOLATED),
+ LEGACY(immediatesignal, TT_ISOLATED),
+ LEGACY(signal_dealloc, TT_ISOLATED),
+ LEGACY(signal_pipeloss, TT_ISOLATED),
+ LEGACY(signal_switchbase, TT_ISOLATED|TT_NO_LOGS),
+ LEGACY(signal_restore, TT_ISOLATED),
+ LEGACY(signal_assert, TT_ISOLATED),
+ LEGACY(signal_while_processing, TT_ISOLATED),
+#endif
+ END_OF_TESTCASES
+};
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress.h
new file mode 100644
index 000000000..de1aed308
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef REGRESS_H_INCLUDED_
+#define REGRESS_H_INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "tinytest.h"
+#include "tinytest_macros.h"
+
+extern struct testcase_t main_testcases[];
+extern struct testcase_t evtag_testcases[];
+extern struct testcase_t evbuffer_testcases[];
+extern struct testcase_t finalize_testcases[];
+extern struct testcase_t bufferevent_testcases[];
+extern struct testcase_t bufferevent_iocp_testcases[];
+extern struct testcase_t util_testcases[];
+extern struct testcase_t signal_testcases[];
+extern struct testcase_t http_testcases[];
+extern struct testcase_t dns_testcases[];
+extern struct testcase_t rpc_testcases[];
+extern struct testcase_t edgetriggered_testcases[];
+extern struct testcase_t minheap_testcases[];
+extern struct testcase_t iocp_testcases[];
+extern struct testcase_t ssl_testcases[];
+extern struct testcase_t listener_testcases[];
+extern struct testcase_t listener_iocp_testcases[];
+extern struct testcase_t thread_testcases[];
+
+extern struct evutil_weakrand_state test_weakrand_state;
+
+#define test_weakrand() (evutil_weakrand_(&test_weakrand_state))
+
+void regress_threads(void *);
+void test_bufferevent_zlib(void *);
+
+/* Helpers to wrap old testcases */
+extern evutil_socket_t pair[2];
+extern int test_ok;
+extern int called;
+extern struct event_base *global_base;
+extern int in_legacy_test_wrapper;
+
+int regress_make_tmpfile(const void *data, size_t datalen, char **filename_out);
+
+struct basic_test_data {
+ struct event_base *base;
+ evutil_socket_t pair[2];
+
+ void (*legacy_test_fn)(void);
+
+ void *setup_data;
+};
+extern const struct testcase_setup_t basic_setup;
+
+
+extern const struct testcase_setup_t legacy_setup;
+void run_legacy_test_fn(void *ptr);
+
+extern int libevent_tests_running_in_debug_mode;
+
+/* A couple of flags that basic/legacy_setup can support. */
+#define TT_NEED_SOCKETPAIR TT_FIRST_USER_FLAG
+#define TT_NEED_BASE (TT_FIRST_USER_FLAG<<1)
+#define TT_NEED_DNS (TT_FIRST_USER_FLAG<<2)
+#define TT_LEGACY (TT_FIRST_USER_FLAG<<3)
+#define TT_NEED_THREADS (TT_FIRST_USER_FLAG<<4)
+#define TT_NO_LOGS (TT_FIRST_USER_FLAG<<5)
+#define TT_ENABLE_IOCP_FLAG (TT_FIRST_USER_FLAG<<6)
+#define TT_ENABLE_IOCP (TT_ENABLE_IOCP_FLAG|TT_NEED_THREADS)
+
+/* All the flags that a legacy test needs. */
+#define TT_ISOLATED TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE
+
+
+#define BASIC(name,flags) \
+ { #name, test_## name, flags, &basic_setup, NULL }
+
+#define LEGACY(name,flags) \
+ { #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup, \
+ test_## name }
+
+struct evutil_addrinfo;
+struct evutil_addrinfo *ai_find_by_family(struct evutil_addrinfo *ai, int f);
+struct evutil_addrinfo *ai_find_by_protocol(struct evutil_addrinfo *ai, int p);
+int test_ai_eq_(const struct evutil_addrinfo *ai, const char *sockaddr_port,
+ int socktype, int protocol, int line);
+
+#define test_ai_eq(ai, str, s, p) do { \
+ if (test_ai_eq_((ai), (str), (s), (p), __LINE__)<0) \
+ goto end; \
+ } while (0)
+
+#define test_timeval_diff_leq(tv1, tv2, diff, tolerance) \
+ tt_int_op(labs(timeval_msec_diff((tv1), (tv2)) - diff), <=, tolerance)
+
+#define test_timeval_diff_eq(tv1, tv2, diff) \
+ test_timeval_diff_leq((tv1), (tv2), (diff), 50)
+
+long timeval_msec_diff(const struct timeval *start, const struct timeval *end);
+
+#ifndef _WIN32
+pid_t regress_fork(void);
+#endif
+
+#ifdef EVENT__HAVE_OPENSSL
+#include <openssl/ssl.h>
+EVP_PKEY *ssl_getkey(void);
+X509 *ssl_getcert(void);
+SSL_CTX *get_ssl_ctx(void);
+void init_ssl(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* REGRESS_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress.rpc b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress.rpc
new file mode 100644
index 000000000..0ee904e91
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress.rpc
@@ -0,0 +1,25 @@
+/* tests data packing and unpacking */
+
+struct msg {
+ string /* sender */ from_name = 1; /* be verbose */
+ string to_name = 2;
+ optional struct[kill] attack = 3;
+ array struct[run] run = 4;
+}
+
+struct kill {
+ string weapon = 0x10121;
+ string action = 2;
+ array int how_often = 3;
+}
+
+struct run {
+ string how = 1;
+ optional bytes some_bytes = 2;
+
+ bytes fixed_bytes[24] = 3;
+ array string notes = 4;
+
+ optional int64 large_number = 5;
+ array int other_numbers = 6;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_buffer.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_buffer.c
new file mode 100644
index 000000000..1af75f537
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_buffer.c
@@ -0,0 +1,2563 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util-internal.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "event2/event.h"
+#include "event2/buffer.h"
+#include "event2/buffer_compat.h"
+#include "event2/util.h"
+
+#include "defer-internal.h"
+#include "evbuffer-internal.h"
+#include "log-internal.h"
+
+#include "regress.h"
+
+/* Validates that an evbuffer is good. Returns false if it isn't, true if it
+ * is*/
+static int
+evbuffer_validate_(struct evbuffer *buf)
+{
+ struct evbuffer_chain *chain;
+ size_t sum = 0;
+ int found_last_with_datap = 0;
+
+ if (buf->first == NULL) {
+ tt_assert(buf->last == NULL);
+ tt_assert(buf->total_len == 0);
+ }
+
+ chain = buf->first;
+
+ tt_assert(buf->last_with_datap);
+ if (buf->last_with_datap == &buf->first)
+ found_last_with_datap = 1;
+
+ while (chain != NULL) {
+ if (&chain->next == buf->last_with_datap)
+ found_last_with_datap = 1;
+ sum += chain->off;
+ if (chain->next == NULL) {
+ tt_assert(buf->last == chain);
+ }
+ tt_assert(chain->buffer_len >= chain->misalign + chain->off);
+ chain = chain->next;
+ }
+
+ if (buf->first)
+ tt_assert(*buf->last_with_datap);
+
+ if (*buf->last_with_datap) {
+ chain = *buf->last_with_datap;
+ if (chain->off == 0 || buf->total_len == 0) {
+ tt_assert(chain->off == 0)
+ tt_assert(chain == buf->first);
+ tt_assert(buf->total_len == 0);
+ }
+ chain = chain->next;
+ while (chain != NULL) {
+ tt_assert(chain->off == 0);
+ chain = chain->next;
+ }
+ } else {
+ tt_assert(buf->last_with_datap == &buf->first);
+ }
+ tt_assert(found_last_with_datap);
+
+ tt_assert(sum == buf->total_len);
+ return 1;
+ end:
+ return 0;
+}
+
+static void
+evbuffer_get_waste(struct evbuffer *buf, size_t *allocatedp, size_t *wastedp, size_t *usedp)
+{
+ struct evbuffer_chain *chain;
+ size_t a, w, u;
+ int n = 0;
+ u = a = w = 0;
+
+ chain = buf->first;
+ /* skip empty at start */
+ while (chain && chain->off==0) {
+ ++n;
+ a += chain->buffer_len;
+ chain = chain->next;
+ }
+ /* first nonempty chain: stuff at the end only is wasted. */
+ if (chain) {
+ ++n;
+ a += chain->buffer_len;
+ u += chain->off;
+ if (chain->next && chain->next->off)
+ w += (size_t)(chain->buffer_len - (chain->misalign + chain->off));
+ chain = chain->next;
+ }
+ /* subsequent nonempty chains */
+ while (chain && chain->off) {
+ ++n;
+ a += chain->buffer_len;
+ w += (size_t)chain->misalign;
+ u += chain->off;
+ if (chain->next && chain->next->off)
+ w += (size_t) (chain->buffer_len - (chain->misalign + chain->off));
+ chain = chain->next;
+ }
+ /* subsequent empty chains */
+ while (chain) {
+ ++n;
+ a += chain->buffer_len;
+ }
+ *allocatedp = a;
+ *wastedp = w;
+ *usedp = u;
+}
+
+#define evbuffer_validate(buf) \
+ TT_STMT_BEGIN if (!evbuffer_validate_(buf)) TT_DIE(("Buffer format invalid")); TT_STMT_END
+
+static void
+test_evbuffer(void *ptr)
+{
+ static char buffer[512], *tmp;
+ struct evbuffer *evb = evbuffer_new();
+ struct evbuffer *evb_two = evbuffer_new();
+ size_t sz_tmp;
+ int i;
+
+ evbuffer_validate(evb);
+ evbuffer_add_printf(evb, "%s/%d", "hello", 1);
+ evbuffer_validate(evb);
+
+ tt_assert(evbuffer_get_length(evb) == 7);
+ tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "hello/1", 1));
+
+ evbuffer_add_buffer(evb, evb_two);
+ evbuffer_validate(evb);
+
+ evbuffer_drain(evb, strlen("hello/"));
+ evbuffer_validate(evb);
+ tt_assert(evbuffer_get_length(evb) == 1);
+ tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1", 1));
+
+ evbuffer_add_printf(evb_two, "%s", "/hello");
+ evbuffer_validate(evb);
+ evbuffer_add_buffer(evb, evb_two);
+ evbuffer_validate(evb);
+
+ tt_assert(evbuffer_get_length(evb_two) == 0);
+ tt_assert(evbuffer_get_length(evb) == 7);
+ tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1/hello", 7));
+
+ memset(buffer, 0, sizeof(buffer));
+ evbuffer_add(evb, buffer, sizeof(buffer));
+ evbuffer_validate(evb);
+ tt_assert(evbuffer_get_length(evb) == 7 + 512);
+
+ tmp = (char *)evbuffer_pullup(evb, 7 + 512);
+ tt_assert(tmp);
+ tt_assert(!strncmp(tmp, "1/hello", 7));
+ tt_assert(!memcmp(tmp + 7, buffer, sizeof(buffer)));
+ evbuffer_validate(evb);
+
+ evbuffer_prepend(evb, "something", 9);
+ evbuffer_validate(evb);
+ evbuffer_prepend(evb, "else", 4);
+ evbuffer_validate(evb);
+
+ tmp = (char *)evbuffer_pullup(evb, 4 + 9 + 7);
+ tt_assert(!strncmp(tmp, "elsesomething1/hello", 4 + 9 + 7));
+ evbuffer_validate(evb);
+
+ evbuffer_drain(evb, -1);
+ evbuffer_validate(evb);
+ evbuffer_drain(evb_two, -1);
+ evbuffer_validate(evb);
+
+ for (i = 0; i < 3; ++i) {
+ evbuffer_add(evb_two, buffer, sizeof(buffer));
+ evbuffer_validate(evb_two);
+ evbuffer_add_buffer(evb, evb_two);
+ evbuffer_validate(evb);
+ evbuffer_validate(evb_two);
+ }
+
+ tt_assert(evbuffer_get_length(evb_two) == 0);
+ tt_assert(evbuffer_get_length(evb) == i * sizeof(buffer));
+
+ /* test remove buffer */
+ sz_tmp = (size_t)(sizeof(buffer)*2.5);
+ evbuffer_remove_buffer(evb, evb_two, sz_tmp);
+ tt_assert(evbuffer_get_length(evb_two) == sz_tmp);
+ tt_assert(evbuffer_get_length(evb) == sizeof(buffer) / 2);
+ evbuffer_validate(evb);
+
+ if (memcmp(evbuffer_pullup(
+ evb, -1), buffer, sizeof(buffer) / 2) != 0 ||
+ memcmp(evbuffer_pullup(
+ evb_two, -1), buffer, sizeof(buffer)) != 0)
+ tt_abort_msg("Pullup did not preserve content");
+
+ evbuffer_validate(evb);
+
+
+ /* testing one-vector reserve and commit */
+ {
+ struct evbuffer_iovec v[1];
+ char *buf;
+ int i, j, r;
+
+ for (i = 0; i < 3; ++i) {
+ r = evbuffer_reserve_space(evb, 10000, v, 1);
+ tt_int_op(r, ==, 1);
+ tt_assert(v[0].iov_len >= 10000);
+ tt_assert(v[0].iov_base != NULL);
+
+ evbuffer_validate(evb);
+ buf = v[0].iov_base;
+ for (j = 0; j < 10000; ++j) {
+ buf[j] = j;
+ }
+ evbuffer_validate(evb);
+
+ tt_int_op(evbuffer_commit_space(evb, v, 1), ==, 0);
+ evbuffer_validate(evb);
+
+ tt_assert(evbuffer_get_length(evb) >= 10000);
+
+ evbuffer_drain(evb, j * 5000);
+ evbuffer_validate(evb);
+ }
+ }
+
+ end:
+ evbuffer_free(evb);
+ evbuffer_free(evb_two);
+}
+
+static void
+no_cleanup(const void *data, size_t datalen, void *extra)
+{
+}
+
+static void
+test_evbuffer_remove_buffer_with_empty(void *ptr)
+{
+ struct evbuffer *src = evbuffer_new();
+ struct evbuffer *dst = evbuffer_new();
+ char buf[2];
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ /* setup the buffers */
+ /* we need more data in src than we will move later */
+ evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
+ evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
+ /* we need one buffer in dst and one empty buffer at the end */
+ evbuffer_add(dst, buf, sizeof(buf));
+ evbuffer_add_reference(dst, buf, 0, no_cleanup, NULL);
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ /* move three bytes over */
+ evbuffer_remove_buffer(src, dst, 3);
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+end:
+ evbuffer_free(src);
+ evbuffer_free(dst);
+}
+
+static void
+test_evbuffer_remove_buffer_with_empty2(void *ptr)
+{
+ struct evbuffer *src = evbuffer_new();
+ struct evbuffer *dst = evbuffer_new();
+ struct evbuffer *buf = evbuffer_new();
+
+ evbuffer_add(buf, "foo", 3);
+ evbuffer_add_reference(buf, "foo", 3, NULL, NULL);
+
+ evbuffer_add_reference(src, "foo", 3, NULL, NULL);
+ evbuffer_add_reference(src, NULL, 0, NULL, NULL);
+ evbuffer_add_buffer(src, buf);
+
+ evbuffer_add(buf, "foo", 3);
+ evbuffer_add_reference(buf, "foo", 3, NULL, NULL);
+
+ evbuffer_add_reference(dst, "foo", 3, NULL, NULL);
+ evbuffer_add_reference(dst, NULL, 0, NULL, NULL);
+ evbuffer_add_buffer(dst, buf);
+
+ tt_int_op(evbuffer_get_length(src), ==, 9);
+ tt_int_op(evbuffer_get_length(dst), ==, 9);
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ evbuffer_remove_buffer(src, dst, 8);
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ tt_int_op(evbuffer_get_length(src), ==, 1);
+ tt_int_op(evbuffer_get_length(dst), ==, 17);
+
+ end:
+ evbuffer_free(src);
+ evbuffer_free(dst);
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_remove_buffer_with_empty3(void *ptr)
+{
+ struct evbuffer *src = evbuffer_new();
+ struct evbuffer *dst = evbuffer_new();
+ struct evbuffer *buf = evbuffer_new();
+
+ evbuffer_add(buf, "foo", 3);
+ evbuffer_add_reference(buf, NULL, 0, NULL, NULL);
+
+ evbuffer_add_reference(src, "foo", 3, NULL, NULL);
+ evbuffer_add_reference(src, NULL, 0, NULL, NULL);
+ evbuffer_prepend_buffer(src, buf);
+
+ evbuffer_add(buf, "foo", 3);
+ evbuffer_add_reference(buf, NULL, 0, NULL, NULL);
+
+ evbuffer_add_reference(dst, "foo", 3, NULL, NULL);
+ evbuffer_add_reference(dst, NULL, 0, NULL, NULL);
+ evbuffer_prepend_buffer(dst, buf);
+
+ tt_int_op(evbuffer_get_length(src), ==, 6);
+ tt_int_op(evbuffer_get_length(dst), ==, 6);
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ evbuffer_remove_buffer(src, dst, 5);
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ tt_int_op(evbuffer_get_length(src), ==, 1);
+ tt_int_op(evbuffer_get_length(dst), ==, 11);
+
+ end:
+ evbuffer_free(src);
+ evbuffer_free(dst);
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_add_buffer_with_empty(void *ptr)
+{
+ struct evbuffer *src = evbuffer_new();
+ struct evbuffer *dst = evbuffer_new();
+ struct evbuffer *buf = evbuffer_new();
+
+ evbuffer_add(buf, "foo", 3);
+
+ evbuffer_add_reference(src, "foo", 3, NULL, NULL);
+ evbuffer_add_reference(src, NULL, 0, NULL, NULL);
+ evbuffer_add_buffer(src, buf);
+
+ evbuffer_add(buf, "foo", 3);
+
+ evbuffer_add_reference(dst, "foo", 3, NULL, NULL);
+ evbuffer_add_reference(dst, NULL, 0, NULL, NULL);
+ evbuffer_add_buffer(dst, buf);
+
+ tt_int_op(evbuffer_get_length(src), ==, 6);
+ tt_int_op(evbuffer_get_length(dst), ==, 6);
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ end:
+ evbuffer_free(src);
+ evbuffer_free(dst);
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_add_buffer_with_empty2(void *ptr)
+{
+ struct evbuffer *src = evbuffer_new();
+ struct evbuffer *dst = evbuffer_new();
+ struct evbuffer *buf = evbuffer_new();
+
+ evbuffer_add(buf, "foo", 3);
+
+ evbuffer_add_reference(src, NULL, 0, NULL, NULL);
+ evbuffer_add_buffer(src, buf);
+
+ evbuffer_add(buf, "foo", 3);
+
+ evbuffer_add_reference(dst, NULL, 0, NULL, NULL);
+ evbuffer_add_buffer(dst, buf);
+
+ tt_int_op(evbuffer_get_length(src), ==, 3);
+ tt_int_op(evbuffer_get_length(dst), ==, 3);
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ end:
+ evbuffer_free(src);
+ evbuffer_free(dst);
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_reserve2(void *ptr)
+{
+ /* Test the two-vector cases of reserve/commit. */
+ struct evbuffer *buf = evbuffer_new();
+ int n, i;
+ struct evbuffer_iovec v[2];
+ size_t remaining;
+ char *cp, *cp2;
+
+ /* First chunk will necessarily be one chunk. Use 512 bytes of it.*/
+ n = evbuffer_reserve_space(buf, 1024, v, 2);
+ tt_int_op(n, ==, 1);
+ tt_int_op(evbuffer_get_length(buf), ==, 0);
+ tt_assert(v[0].iov_base != NULL);
+ tt_int_op(v[0].iov_len, >=, 1024);
+ memset(v[0].iov_base, 'X', 512);
+ cp = v[0].iov_base;
+ remaining = v[0].iov_len - 512;
+ v[0].iov_len = 512;
+ evbuffer_validate(buf);
+ tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
+ tt_int_op(evbuffer_get_length(buf), ==, 512);
+ evbuffer_validate(buf);
+
+ /* Ask for another same-chunk request, in an existing chunk. Use 8
+ * bytes of it. */
+ n = evbuffer_reserve_space(buf, 32, v, 2);
+ tt_int_op(n, ==, 1);
+ tt_assert(cp + 512 == v[0].iov_base);
+ tt_int_op(remaining, ==, v[0].iov_len);
+ memset(v[0].iov_base, 'Y', 8);
+ v[0].iov_len = 8;
+ tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
+ tt_int_op(evbuffer_get_length(buf), ==, 520);
+ remaining -= 8;
+ evbuffer_validate(buf);
+
+ /* Now ask for a request that will be split. Use only one byte of it,
+ though. */
+ n = evbuffer_reserve_space(buf, remaining+64, v, 2);
+ tt_int_op(n, ==, 2);
+ tt_assert(cp + 520 == v[0].iov_base);
+ tt_int_op(remaining, ==, v[0].iov_len);
+ tt_assert(v[1].iov_base);
+ tt_assert(v[1].iov_len >= 64);
+ cp2 = v[1].iov_base;
+ memset(v[0].iov_base, 'Z', 1);
+ v[0].iov_len = 1;
+ tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
+ tt_int_op(evbuffer_get_length(buf), ==, 521);
+ remaining -= 1;
+ evbuffer_validate(buf);
+
+ /* Now ask for a request that will be split. Use some of the first
+ * part and some of the second. */
+ n = evbuffer_reserve_space(buf, remaining+64, v, 2);
+ evbuffer_validate(buf);
+ tt_int_op(n, ==, 2);
+ tt_assert(cp + 521 == v[0].iov_base);
+ tt_int_op(remaining, ==, v[0].iov_len);
+ tt_assert(v[1].iov_base == cp2);
+ tt_assert(v[1].iov_len >= 64);
+ memset(v[0].iov_base, 'W', 400);
+ v[0].iov_len = 400;
+ memset(v[1].iov_base, 'x', 60);
+ v[1].iov_len = 60;
+ tt_int_op(0, ==, evbuffer_commit_space(buf, v, 2));
+ tt_int_op(evbuffer_get_length(buf), ==, 981);
+ evbuffer_validate(buf);
+
+ /* Now peek to make sure stuff got made how we like. */
+ memset(v,0,sizeof(v));
+ n = evbuffer_peek(buf, -1, NULL, v, 2);
+ tt_int_op(n, ==, 2);
+ tt_int_op(v[0].iov_len, ==, 921);
+ tt_int_op(v[1].iov_len, ==, 60);
+
+ cp = v[0].iov_base;
+ for (i=0; i<512; ++i)
+ tt_int_op(cp[i], ==, 'X');
+ for (i=512; i<520; ++i)
+ tt_int_op(cp[i], ==, 'Y');
+ for (i=520; i<521; ++i)
+ tt_int_op(cp[i], ==, 'Z');
+ for (i=521; i<921; ++i)
+ tt_int_op(cp[i], ==, 'W');
+
+ cp = v[1].iov_base;
+ for (i=0; i<60; ++i)
+ tt_int_op(cp[i], ==, 'x');
+
+end:
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_reserve_many(void *ptr)
+{
+ /* This is a glass-box test to handle expanding a buffer with more
+ * chunks and reallocating chunks as needed */
+ struct evbuffer *buf = evbuffer_new();
+ struct evbuffer_iovec v[8];
+ int n;
+ size_t sz;
+ int add_data = ptr && !strcmp(ptr, "add");
+ int fill_first = ptr && !strcmp(ptr, "fill");
+ char *cp1, *cp2;
+
+ /* When reserving the the first chunk, we just allocate it */
+ n = evbuffer_reserve_space(buf, 128, v, 2);
+ evbuffer_validate(buf);
+ tt_int_op(n, ==, 1);
+ tt_assert(v[0].iov_len >= 128);
+ sz = v[0].iov_len;
+ cp1 = v[0].iov_base;
+ if (add_data) {
+ *(char*)v[0].iov_base = 'X';
+ v[0].iov_len = 1;
+ n = evbuffer_commit_space(buf, v, 1);
+ tt_int_op(n, ==, 0);
+ } else if (fill_first) {
+ memset(v[0].iov_base, 'X', v[0].iov_len);
+ n = evbuffer_commit_space(buf, v, 1);
+ tt_int_op(n, ==, 0);
+ n = evbuffer_reserve_space(buf, 128, v, 2);
+ tt_int_op(n, ==, 1);
+ sz = v[0].iov_len;
+ tt_assert(v[0].iov_base != cp1);
+ cp1 = v[0].iov_base;
+ }
+
+ /* Make another chunk get added. */
+ n = evbuffer_reserve_space(buf, sz+128, v, 2);
+ evbuffer_validate(buf);
+ tt_int_op(n, ==, 2);
+ sz = v[0].iov_len + v[1].iov_len;
+ tt_int_op(sz, >=, v[0].iov_len+128);
+ if (add_data) {
+ tt_assert(v[0].iov_base == cp1 + 1);
+ } else {
+ tt_assert(v[0].iov_base == cp1);
+ }
+ cp1 = v[0].iov_base;
+ cp2 = v[1].iov_base;
+
+ /* And a third chunk. */
+ n = evbuffer_reserve_space(buf, sz+128, v, 3);
+ evbuffer_validate(buf);
+ tt_int_op(n, ==, 3);
+ tt_assert(cp1 == v[0].iov_base);
+ tt_assert(cp2 == v[1].iov_base);
+ sz = v[0].iov_len + v[1].iov_len + v[2].iov_len;
+
+ /* Now force a reallocation by asking for more space in only 2
+ * buffers. */
+ n = evbuffer_reserve_space(buf, sz+128, v, 2);
+ evbuffer_validate(buf);
+ if (add_data) {
+ tt_int_op(n, ==, 2);
+ tt_assert(cp1 == v[0].iov_base);
+ } else {
+ tt_int_op(n, ==, 1);
+ }
+
+end:
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_expand(void *ptr)
+{
+ char data[4096];
+ struct evbuffer *buf;
+ size_t a,w,u;
+ void *buffer;
+
+ memset(data, 'X', sizeof(data));
+
+ /* Make sure that expand() works on an empty buffer */
+ buf = evbuffer_new();
+ tt_int_op(evbuffer_expand(buf, 20000), ==, 0);
+ evbuffer_validate(buf);
+ a=w=u=0;
+ evbuffer_get_waste(buf, &a,&w,&u);
+ tt_assert(w == 0);
+ tt_assert(u == 0);
+ tt_assert(a >= 20000);
+ tt_assert(buf->first);
+ tt_assert(buf->first == buf->last);
+ tt_assert(buf->first->off == 0);
+ tt_assert(buf->first->buffer_len >= 20000);
+
+ /* Make sure that expand() works as a no-op when there's enough
+ * contiguous space already. */
+ buffer = buf->first->buffer;
+ evbuffer_add(buf, data, 1024);
+ tt_int_op(evbuffer_expand(buf, 1024), ==, 0);
+ tt_assert(buf->first->buffer == buffer);
+ evbuffer_validate(buf);
+ evbuffer_free(buf);
+
+ /* Make sure that expand() can work by moving misaligned data
+ * when it makes sense to do so. */
+ buf = evbuffer_new();
+ evbuffer_add(buf, data, 400);
+ {
+ int n = (int)(buf->first->buffer_len - buf->first->off - 1);
+ tt_assert(n < (int)sizeof(data));
+ evbuffer_add(buf, data, n);
+ }
+ tt_assert(buf->first == buf->last);
+ tt_assert(buf->first->off == buf->first->buffer_len - 1);
+ evbuffer_drain(buf, buf->first->off - 1);
+ tt_assert(1 == evbuffer_get_length(buf));
+ tt_assert(buf->first->misalign > 0);
+ tt_assert(buf->first->off == 1);
+ buffer = buf->first->buffer;
+ tt_assert(evbuffer_expand(buf, 40) == 0);
+ tt_assert(buf->first == buf->last);
+ tt_assert(buf->first->off == 1);
+ tt_assert(buf->first->buffer == buffer);
+ tt_assert(buf->first->misalign == 0);
+ evbuffer_validate(buf);
+ evbuffer_free(buf);
+
+ /* add, expand, pull-up: This used to crash libevent. */
+ buf = evbuffer_new();
+
+ evbuffer_add(buf, data, sizeof(data));
+ evbuffer_add(buf, data, sizeof(data));
+ evbuffer_add(buf, data, sizeof(data));
+
+ evbuffer_validate(buf);
+ evbuffer_expand(buf, 1024);
+ evbuffer_validate(buf);
+ evbuffer_pullup(buf, -1);
+ evbuffer_validate(buf);
+
+end:
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_expand_overflow(void *ptr)
+{
+ struct evbuffer *buf;
+
+ buf = evbuffer_new();
+ evbuffer_add(buf, "1", 1);
+ evbuffer_expand(buf, EVBUFFER_CHAIN_MAX);
+ evbuffer_validate(buf);
+
+ evbuffer_expand(buf, EV_SIZE_MAX);
+ evbuffer_validate(buf);
+
+end:
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_add1(void *ptr)
+{
+ struct evbuffer *buf;
+ char *str;
+
+ buf = evbuffer_new();
+ evbuffer_add(buf, "1", 1);
+ evbuffer_validate(buf);
+ evbuffer_expand(buf, 2048);
+ evbuffer_validate(buf);
+ evbuffer_add(buf, "2", 1);
+ evbuffer_validate(buf);
+ evbuffer_add_printf(buf, "3");
+ evbuffer_validate(buf);
+
+ tt_assert(evbuffer_get_length(buf) == 3);
+ str = (char *)evbuffer_pullup(buf, -1);
+ tt_assert(str[0] == '1');
+ tt_assert(str[1] == '2');
+ tt_assert(str[2] == '3');
+end:
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_add2(void *ptr)
+{
+ struct evbuffer *buf;
+ static char data[4096];
+ int data_len = MIN_BUFFER_SIZE-EVBUFFER_CHAIN_SIZE-10;
+ char *str;
+ int len;
+
+ memset(data, 'P', sizeof(data));
+ buf = evbuffer_new();
+ evbuffer_add(buf, data, data_len);
+ evbuffer_validate(buf);
+ evbuffer_expand(buf, 100);
+ evbuffer_validate(buf);
+ evbuffer_add(buf, "2", 1);
+ evbuffer_validate(buf);
+ evbuffer_add_printf(buf, "3");
+ evbuffer_validate(buf);
+
+ len = evbuffer_get_length(buf);
+ tt_assert(len == data_len+2);
+ str = (char *)evbuffer_pullup(buf, -1);
+ tt_assert(str[len-3] == 'P');
+ tt_assert(str[len-2] == '2');
+ tt_assert(str[len-1] == '3');
+end:
+ evbuffer_free(buf);
+}
+
+static int reference_cb_called;
+static void
+reference_cb(const void *data, size_t len, void *extra)
+{
+ tt_str_op(data, ==, "this is what we add as read-only memory.");
+ tt_int_op(len, ==, strlen(data));
+ tt_want(extra == (void *)0xdeadaffe);
+ ++reference_cb_called;
+end:
+ ;
+}
+
+static void
+test_evbuffer_reference(void *ptr)
+{
+ struct evbuffer *src = evbuffer_new();
+ struct evbuffer *dst = evbuffer_new();
+ struct evbuffer_iovec v[1];
+ const char *data = "this is what we add as read-only memory.";
+ reference_cb_called = 0;
+
+ tt_assert(evbuffer_add_reference(src, data, strlen(data),
+ reference_cb, (void *)0xdeadaffe) != -1);
+
+ evbuffer_reserve_space(dst, strlen(data), v, 1);
+ tt_assert(evbuffer_remove(src, v[0].iov_base, 10) != -1);
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ /* make sure that we don't write data at the beginning */
+ evbuffer_prepend(src, "aaaaa", 5);
+ evbuffer_validate(src);
+ evbuffer_drain(src, 5);
+
+ tt_assert(evbuffer_remove(src, ((char*)(v[0].iov_base)) + 10,
+ strlen(data) - 10) != -1);
+
+ v[0].iov_len = strlen(data);
+
+ evbuffer_commit_space(dst, v, 1);
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ tt_int_op(reference_cb_called, ==, 1);
+
+ tt_assert(!memcmp(evbuffer_pullup(dst, strlen(data)),
+ data, strlen(data)));
+ evbuffer_validate(dst);
+
+ end:
+ evbuffer_free(dst);
+ evbuffer_free(src);
+}
+
+static void
+test_evbuffer_reference2(void *ptr)
+{
+ struct evbuffer *buf;
+ static char data[4096];
+ int data_len = MIN_BUFFER_SIZE-EVBUFFER_CHAIN_SIZE-10;
+ char *str;
+ int len;
+
+ memset(data, 'P', sizeof(data));
+ buf = evbuffer_new();
+ evbuffer_add(buf, data, data_len);
+ evbuffer_validate(buf);
+ evbuffer_expand(buf, 100);
+ evbuffer_validate(buf);
+ evbuffer_add_reference(buf, "2", 1, no_cleanup, NULL);
+ evbuffer_validate(buf);
+ evbuffer_add_printf(buf, "3");
+ evbuffer_validate(buf);
+
+ len = evbuffer_get_length(buf);
+ tt_assert(len == data_len+2);
+ str = (char *)evbuffer_pullup(buf, -1);
+ tt_assert(str[len-3] == 'P');
+ tt_assert(str[len-2] == '2');
+ tt_assert(str[len-1] == '3');
+end:
+ evbuffer_free(buf);
+}
+
+static struct event_base *addfile_test_event_base;
+static int addfile_test_done_writing;
+static int addfile_test_total_written;
+static int addfile_test_total_read;
+
+static void
+addfile_test_writecb(evutil_socket_t fd, short what, void *arg)
+{
+ struct evbuffer *b = arg;
+ int r;
+ evbuffer_validate(b);
+ while (evbuffer_get_length(b)) {
+ r = evbuffer_write(b, fd);
+ if (r > 0) {
+ addfile_test_total_written += r;
+ TT_BLATHER(("Wrote %d/%d bytes", r, addfile_test_total_written));
+ } else {
+ int e = evutil_socket_geterror(fd);
+ if (EVUTIL_ERR_RW_RETRIABLE(e))
+ return;
+ tt_fail_perror("write");
+ event_base_loopexit(addfile_test_event_base,NULL);
+ }
+ evbuffer_validate(b);
+ }
+ addfile_test_done_writing = 1;
+ return;
+end:
+ event_base_loopexit(addfile_test_event_base,NULL);
+}
+
+static void
+addfile_test_readcb(evutil_socket_t fd, short what, void *arg)
+{
+ struct evbuffer *b = arg;
+ int e, r = 0;
+ do {
+ r = evbuffer_read(b, fd, 1024);
+ if (r > 0) {
+ addfile_test_total_read += r;
+ TT_BLATHER(("Read %d/%d bytes", r, addfile_test_total_read));
+ }
+ } while (r > 0);
+ if (r < 0) {
+ e = evutil_socket_geterror(fd);
+ if (! EVUTIL_ERR_RW_RETRIABLE(e)) {
+ tt_fail_perror("read");
+ event_base_loopexit(addfile_test_event_base,NULL);
+ }
+ }
+ if (addfile_test_done_writing &&
+ addfile_test_total_read >= addfile_test_total_written) {
+ event_base_loopexit(addfile_test_event_base,NULL);
+ }
+}
+
+static void
+test_evbuffer_add_file(void *ptr)
+{
+ struct basic_test_data *testdata = ptr;
+ const char *impl = testdata->setup_data;
+ struct evbuffer *src = evbuffer_new(), *dest = evbuffer_new();
+ char *tmpfilename = NULL;
+ char *data = NULL;
+ const char *expect_data;
+ size_t datalen, expect_len;
+ const char *compare;
+ int fd = -1;
+ int want_ismapping = -1, want_cansendfile = -1;
+ unsigned flags = 0;
+ int use_segment = 1, use_bigfile = 0, map_from_offset = 0,
+ view_from_offset = 0;
+ struct evbuffer_file_segment *seg = NULL;
+ ev_off_t starting_offset = 0, mapping_len = -1;
+ ev_off_t segment_offset = 0, segment_len = -1;
+ struct event *rev=NULL, *wev=NULL;
+ struct event_base *base = testdata->base;
+ evutil_socket_t pair[2] = {-1, -1};
+ struct evutil_weakrand_state seed = { 123456789U };
+
+ /* This test is highly parameterized based on substrings of its
+ * argument. The strings are: */
+ tt_assert(impl);
+ if (strstr(impl, "nosegment")) {
+ /* If nosegment is set, use the older evbuffer_add_file
+ * interface */
+ use_segment = 0;
+ }
+ if (strstr(impl, "bigfile")) {
+ /* If bigfile is set, use a 512K file. Else use a smaller
+ * one. */
+ use_bigfile = 1;
+ }
+ if (strstr(impl, "map_offset")) {
+ /* If map_offset is set, we build the file segment starting
+ * from a point other than byte 0 and ending somewhere other
+ * than the last byte. Otherwise we map the whole thing */
+ map_from_offset = 1;
+ }
+ if (strstr(impl, "offset_in_segment")) {
+ /* If offset_in_segment is set, we add a subsection of the
+ * file semgment starting from a point other than byte 0 of
+ * the segment. */
+ view_from_offset = 1;
+ }
+ if (strstr(impl, "sendfile")) {
+ /* If sendfile is set, we try to use a sendfile/splice style
+ * backend. */
+ flags = EVBUF_FS_DISABLE_MMAP;
+ want_cansendfile = 1;
+ want_ismapping = 0;
+ } else if (strstr(impl, "mmap")) {
+ /* If sendfile is set, we try to use a mmap/CreateFileMapping
+ * style backend. */
+ flags = EVBUF_FS_DISABLE_SENDFILE;
+ want_ismapping = 1;
+ want_cansendfile = 0;
+ } else if (strstr(impl, "linear")) {
+ /* If linear is set, we try to use a read-the-whole-thing
+ * backend. */
+ flags = EVBUF_FS_DISABLE_SENDFILE|EVBUF_FS_DISABLE_MMAP;
+ want_ismapping = 0;
+ want_cansendfile = 0;
+ } else if (strstr(impl, "default")) {
+ /* The caller doesn't care which backend we use. */
+ ;
+ } else {
+ /* The caller must choose a backend. */
+ TT_DIE(("Didn't recognize the implementation"));
+ }
+
+ if (use_bigfile) {
+ unsigned int i;
+ datalen = 1024*512;
+ data = malloc(1024*512);
+ tt_assert(data);
+ for (i = 0; i < datalen; ++i)
+ data[i] = (char)evutil_weakrand_(&seed);
+ } else {
+ data = strdup("here is a relatively small string.");
+ tt_assert(data);
+ datalen = strlen(data);
+ }
+
+ fd = regress_make_tmpfile(data, datalen, &tmpfilename);
+
+ if (map_from_offset) {
+ starting_offset = datalen/4 + 1;
+ mapping_len = datalen / 2 - 1;
+ expect_data = data + starting_offset;
+ expect_len = mapping_len;
+ } else {
+ expect_data = data;
+ expect_len = datalen;
+ }
+ if (view_from_offset) {
+ tt_assert(use_segment); /* Can't do this with add_file*/
+ segment_offset = expect_len / 3;
+ segment_len = expect_len / 2;
+ expect_data = expect_data + segment_offset;
+ expect_len = segment_len;
+ }
+
+ if (use_segment) {
+ seg = evbuffer_file_segment_new(fd, starting_offset,
+ mapping_len, flags);
+ tt_assert(seg);
+ if (want_ismapping >= 0) {
+ if (seg->is_mapping != (unsigned)want_ismapping)
+ tt_skip();
+ }
+ if (want_cansendfile >= 0) {
+ if (seg->can_sendfile != (unsigned)want_cansendfile)
+ tt_skip();
+ }
+ }
+
+ /* Say that it drains to a fd so that we can use sendfile. */
+ evbuffer_set_flags(src, EVBUFFER_FLAG_DRAINS_TO_FD);
+
+#if defined(EVENT__HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__)
+ /* We need to use a pair of AF_INET sockets, since Solaris
+ doesn't support sendfile() over AF_UNIX. */
+ if (evutil_ersatz_socketpair_(AF_INET, SOCK_STREAM, 0, pair) == -1)
+ tt_abort_msg("ersatz_socketpair failed");
+#else
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+ tt_abort_msg("socketpair failed");
+#endif
+ evutil_make_socket_nonblocking(pair[0]);
+ evutil_make_socket_nonblocking(pair[1]);
+
+ tt_assert(fd != -1);
+
+ if (use_segment) {
+ tt_assert(evbuffer_add_file_segment(src, seg,
+ segment_offset, segment_len)!=-1);
+ } else {
+ tt_assert(evbuffer_add_file(src, fd, starting_offset,
+ mapping_len) != -1);
+ }
+
+ evbuffer_validate(src);
+
+ addfile_test_event_base = base;
+ addfile_test_done_writing = 0;
+ addfile_test_total_written = 0;
+ addfile_test_total_read = 0;
+
+ wev = event_new(base, pair[0], EV_WRITE|EV_PERSIST,
+ addfile_test_writecb, src);
+ rev = event_new(base, pair[1], EV_READ|EV_PERSIST,
+ addfile_test_readcb, dest);
+
+ event_add(wev, NULL);
+ event_add(rev, NULL);
+ event_base_dispatch(base);
+
+ evbuffer_validate(src);
+ evbuffer_validate(dest);
+
+ tt_assert(addfile_test_done_writing);
+ tt_int_op(addfile_test_total_written, ==, expect_len);
+ tt_int_op(addfile_test_total_read, ==, expect_len);
+
+ compare = (char *)evbuffer_pullup(dest, expect_len);
+ tt_assert(compare != NULL);
+ if (memcmp(compare, expect_data, expect_len)) {
+ tt_abort_msg("Data from add_file differs.");
+ }
+
+ evbuffer_validate(dest);
+ end:
+ if (data)
+ free(data);
+ if (seg)
+ evbuffer_file_segment_free(seg);
+ if (src)
+ evbuffer_free(src);
+ if (dest)
+ evbuffer_free(dest);
+ if (pair[0] >= 0)
+ evutil_closesocket(pair[0]);
+ if (pair[1] >= 0)
+ evutil_closesocket(pair[1]);
+ if (wev)
+ event_free(wev);
+ if (rev)
+ event_free(rev);
+ if (tmpfilename) {
+ unlink(tmpfilename);
+ free(tmpfilename);
+ }
+}
+
+static int file_segment_cleanup_cb_called_count = 0;
+static struct evbuffer_file_segment const* file_segment_cleanup_cb_called_with = NULL;
+static int file_segment_cleanup_cb_called_with_flags = 0;
+static void* file_segment_cleanup_cb_called_with_arg = NULL;
+static void
+file_segment_cleanup_cp(struct evbuffer_file_segment const* seg, int flags, void* arg)
+{
+ ++file_segment_cleanup_cb_called_count;
+ file_segment_cleanup_cb_called_with = seg;
+ file_segment_cleanup_cb_called_with_flags = flags;
+ file_segment_cleanup_cb_called_with_arg = arg;
+}
+
+static void
+test_evbuffer_file_segment_add_cleanup_cb(void* ptr)
+{
+ char *tmpfilename = NULL;
+ int fd = -1;
+ struct evbuffer *evb = NULL;
+ struct evbuffer_file_segment *seg = NULL, *segptr;
+ char const* arg = "token";
+
+ fd = regress_make_tmpfile("file_segment_test_file", 22, &tmpfilename);
+ tt_int_op(fd, >=, 0);
+
+ evb = evbuffer_new();
+ tt_assert(evb);
+
+ segptr = seg = evbuffer_file_segment_new(fd, 0, -1, 0);
+ tt_assert(seg);
+
+ evbuffer_file_segment_add_cleanup_cb(
+ seg, &file_segment_cleanup_cp, (void*)arg);
+
+ tt_assert(fd != -1);
+
+ tt_assert(evbuffer_add_file_segment(evb, seg, 0, -1)!=-1);
+
+ evbuffer_validate(evb);
+
+ tt_int_op(file_segment_cleanup_cb_called_count, ==, 0);
+ evbuffer_file_segment_free(seg);
+ seg = NULL; /* Prevent double-free. */
+
+ tt_int_op(file_segment_cleanup_cb_called_count, ==, 0);
+ evbuffer_free(evb);
+ evb = NULL; /* pevent double-free */
+
+ tt_int_op(file_segment_cleanup_cb_called_count, ==, 1);
+ tt_assert(file_segment_cleanup_cb_called_with == segptr);
+ tt_assert(file_segment_cleanup_cb_called_with_flags == 0);
+ tt_assert(file_segment_cleanup_cb_called_with_arg == (void*)arg);
+
+end:
+ if (evb)
+ evbuffer_free(evb);
+ if (seg)
+ evbuffer_file_segment_free(seg);
+ if (tmpfilename) {
+ unlink(tmpfilename);
+ free(tmpfilename);
+ }
+}
+
+#ifndef EVENT__DISABLE_MM_REPLACEMENT
+static void *
+failing_malloc(size_t how_much)
+{
+ errno = ENOMEM;
+ return NULL;
+}
+#endif
+
+static void
+test_evbuffer_readln(void *ptr)
+{
+ struct evbuffer *evb = evbuffer_new();
+ struct evbuffer *evb_tmp = evbuffer_new();
+ const char *s;
+ char *cp = NULL;
+ size_t sz;
+
+#define tt_line_eq(content) \
+ TT_STMT_BEGIN \
+ if (!cp || sz != strlen(content) || strcmp(cp, content)) { \
+ TT_DIE(("Wanted %s; got %s [%d]", content, cp, (int)sz)); \
+ } \
+ TT_STMT_END
+
+ /* Test EOL_ANY. */
+ s = "complex silly newline\r\n\n\r\n\n\rmore\0\n";
+ evbuffer_add(evb, s, strlen(s)+2);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
+ tt_line_eq("complex silly newline");
+ free(cp);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
+ if (!cp || sz != 5 || memcmp(cp, "more\0\0", 6))
+ tt_abort_msg("Not as expected");
+ tt_uint_op(evbuffer_get_length(evb), ==, 0);
+ evbuffer_validate(evb);
+ s = "\nno newline";
+ evbuffer_add(evb, s, strlen(s));
+ free(cp);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
+ tt_line_eq("");
+ free(cp);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
+ tt_assert(!cp);
+ evbuffer_validate(evb);
+ evbuffer_drain(evb, evbuffer_get_length(evb));
+ tt_assert(evbuffer_get_length(evb) == 0);
+ evbuffer_validate(evb);
+
+ /* Test EOL_CRLF */
+ s = "Line with\rin the middle\nLine with good crlf\r\n\nfinal\n";
+ evbuffer_add(evb, s, strlen(s));
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+ tt_line_eq("Line with\rin the middle");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+ tt_line_eq("Line with good crlf");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+ tt_line_eq("");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+ tt_line_eq("final");
+ s = "x";
+ evbuffer_validate(evb);
+ evbuffer_add(evb, s, 1);
+ evbuffer_validate(evb);
+ free(cp);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+ tt_assert(!cp);
+ evbuffer_validate(evb);
+
+ /* Test CRLF_STRICT */
+ s = " and a bad crlf\nand a good one\r\n\r\nMore\r";
+ evbuffer_add(evb, s, strlen(s));
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("x and a bad crlf\nand a good one");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_assert(!cp);
+ evbuffer_validate(evb);
+ evbuffer_add(evb, "\n", 1);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("More");
+ free(cp);
+ tt_assert(evbuffer_get_length(evb) == 0);
+ evbuffer_validate(evb);
+
+ s = "An internal CR\r is not an eol\r\nNor is a lack of one";
+ evbuffer_add(evb, s, strlen(s));
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("An internal CR\r is not an eol");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_assert(!cp);
+ evbuffer_validate(evb);
+
+ evbuffer_add(evb, "\r\n", 2);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("Nor is a lack of one");
+ free(cp);
+ tt_assert(evbuffer_get_length(evb) == 0);
+ evbuffer_validate(evb);
+
+ /* Test LF */
+ s = "An\rand a nl\n\nText";
+ evbuffer_add(evb, s, strlen(s));
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_line_eq("An\rand a nl");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_line_eq("");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_assert(!cp);
+ free(cp);
+ evbuffer_add(evb, "\n", 1);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_line_eq("Text");
+ free(cp);
+ evbuffer_validate(evb);
+
+ /* Test NUL */
+ tt_int_op(evbuffer_get_length(evb), ==, 0);
+ {
+ char x[] =
+ "NUL\n\0\0"
+ "The all-zeros character which may serve\0"
+ "to accomplish time fill\0and media fill";
+ /* Add all but the final NUL of x. */
+ evbuffer_add(evb, x, sizeof(x)-1);
+ }
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL);
+ tt_line_eq("NUL\n");
+ free(cp);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL);
+ tt_line_eq("");
+ free(cp);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL);
+ tt_line_eq("The all-zeros character which may serve");
+ free(cp);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL);
+ tt_line_eq("to accomplish time fill");
+ free(cp);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL);
+ tt_ptr_op(cp, ==, NULL);
+ evbuffer_drain(evb, -1);
+
+ /* Test CRLF_STRICT - across boundaries*/
+ s = " and a bad crlf\nand a good one\r";
+ evbuffer_add(evb_tmp, s, strlen(s));
+ evbuffer_validate(evb);
+ evbuffer_add_buffer(evb, evb_tmp);
+ evbuffer_validate(evb);
+ s = "\n\r";
+ evbuffer_add(evb_tmp, s, strlen(s));
+ evbuffer_validate(evb);
+ evbuffer_add_buffer(evb, evb_tmp);
+ evbuffer_validate(evb);
+ s = "\nMore\r";
+ evbuffer_add(evb_tmp, s, strlen(s));
+ evbuffer_validate(evb);
+ evbuffer_add_buffer(evb, evb_tmp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq(" and a bad crlf\nand a good one");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_assert(!cp);
+ free(cp);
+ evbuffer_validate(evb);
+ evbuffer_add(evb, "\n", 1);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("More");
+ free(cp); cp = NULL;
+ evbuffer_validate(evb);
+ tt_assert(evbuffer_get_length(evb) == 0);
+
+ /* Test memory problem*/
+ s = "one line\ntwo line\nblue line";
+ evbuffer_add(evb_tmp, s, strlen(s));
+ evbuffer_validate(evb);
+ evbuffer_add_buffer(evb, evb_tmp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_line_eq("one line");
+ free(cp); cp = NULL;
+ evbuffer_validate(evb);
+
+ /* the next call to readline should fail */
+#ifndef EVENT__DISABLE_MM_REPLACEMENT
+ event_set_mem_functions(failing_malloc, realloc, free);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_assert(cp == NULL);
+ evbuffer_validate(evb);
+
+ /* now we should get the next line back */
+ event_set_mem_functions(malloc, realloc, free);
+#endif
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_line_eq("two line");
+ free(cp); cp = NULL;
+ evbuffer_validate(evb);
+
+ end:
+ evbuffer_free(evb);
+ evbuffer_free(evb_tmp);
+ if (cp) free(cp);
+}
+
+static void
+test_evbuffer_search_eol(void *ptr)
+{
+ struct evbuffer *buf = evbuffer_new();
+ struct evbuffer_ptr ptr1, ptr2;
+ const char *s;
+ size_t eol_len;
+
+ s = "string! \r\n\r\nx\n";
+ evbuffer_add(buf, s, strlen(s));
+ eol_len = -1;
+ ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_CRLF);
+ tt_int_op(ptr1.pos, ==, 8);
+ tt_int_op(eol_len, ==, 2);
+
+ eol_len = -1;
+ ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF);
+ tt_int_op(ptr2.pos, ==, 8);
+ tt_int_op(eol_len, ==, 2);
+
+ evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD);
+ eol_len = -1;
+ ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF);
+ tt_int_op(ptr2.pos, ==, 9);
+ tt_int_op(eol_len, ==, 1);
+
+ eol_len = -1;
+ ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF_STRICT);
+ tt_int_op(ptr2.pos, ==, 10);
+ tt_int_op(eol_len, ==, 2);
+
+ eol_len = -1;
+ ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_LF);
+ tt_int_op(ptr1.pos, ==, 9);
+ tt_int_op(eol_len, ==, 1);
+
+ eol_len = -1;
+ ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF);
+ tt_int_op(ptr2.pos, ==, 9);
+ tt_int_op(eol_len, ==, 1);
+
+ evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD);
+ eol_len = -1;
+ ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF);
+ tt_int_op(ptr2.pos, ==, 11);
+ tt_int_op(eol_len, ==, 1);
+
+ tt_assert(evbuffer_ptr_set(buf, &ptr1, evbuffer_get_length(buf), EVBUFFER_PTR_SET) == 0);
+ eol_len = -1;
+ ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF);
+ tt_int_op(ptr2.pos, ==, -1);
+ tt_int_op(eol_len, ==, 0);
+
+end:
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_iterative(void *ptr)
+{
+ struct evbuffer *buf = evbuffer_new();
+ const char *abc = "abcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyz";
+ unsigned i, j, sum, n;
+
+ sum = 0;
+ n = 0;
+ for (i = 0; i < 1000; ++i) {
+ for (j = 1; j < strlen(abc); ++j) {
+ char format[32];
+ evutil_snprintf(format, sizeof(format), "%%%u.%us", j, j);
+ evbuffer_add_printf(buf, format, abc);
+
+ /* Only check for rep violations every so often.
+ Walking over the whole list of chains can get
+ pretty expensive as it gets long.
+ */
+ if ((n % 337) == 0)
+ evbuffer_validate(buf);
+
+ sum += j;
+ n++;
+ }
+ }
+ evbuffer_validate(buf);
+
+ tt_uint_op(sum, ==, evbuffer_get_length(buf));
+
+ {
+ size_t a,w,u;
+ a=w=u=0;
+ evbuffer_get_waste(buf, &a, &w, &u);
+ if (0)
+ printf("Allocated: %u.\nWasted: %u.\nUsed: %u.",
+ (unsigned)a, (unsigned)w, (unsigned)u);
+ tt_assert( ((double)w)/a < .125);
+ }
+ end:
+ evbuffer_free(buf);
+
+}
+
+static void
+test_evbuffer_find(void *ptr)
+{
+ unsigned char* p;
+ const char* test1 = "1234567890\r\n";
+ const char* test2 = "1234567890\r";
+#define EVBUFFER_INITIAL_LENGTH 256
+ char test3[EVBUFFER_INITIAL_LENGTH];
+ unsigned int i;
+ struct evbuffer * buf = evbuffer_new();
+
+ tt_assert(buf);
+
+ /* make sure evbuffer_find doesn't match past the end of the buffer */
+ evbuffer_add(buf, (unsigned char*)test1, strlen(test1));
+ evbuffer_validate(buf);
+ evbuffer_drain(buf, strlen(test1));
+ evbuffer_validate(buf);
+ evbuffer_add(buf, (unsigned char*)test2, strlen(test2));
+ evbuffer_validate(buf);
+ p = evbuffer_find(buf, (unsigned char*)"\r\n", 2);
+ tt_want(p == NULL);
+
+ /*
+ * drain the buffer and do another find; in r309 this would
+ * read past the allocated buffer causing a valgrind error.
+ */
+ evbuffer_drain(buf, strlen(test2));
+ evbuffer_validate(buf);
+ for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i)
+ test3[i] = 'a';
+ test3[EVBUFFER_INITIAL_LENGTH - 1] = 'x';
+ evbuffer_add(buf, (unsigned char *)test3, EVBUFFER_INITIAL_LENGTH);
+ evbuffer_validate(buf);
+ p = evbuffer_find(buf, (unsigned char *)"xy", 2);
+ tt_want(p == NULL);
+
+ /* simple test for match at end of allocated buffer */
+ p = evbuffer_find(buf, (unsigned char *)"ax", 2);
+ tt_assert(p != NULL);
+ tt_want(strncmp((char*)p, "ax", 2) == 0);
+
+end:
+ if (buf)
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_ptr_set(void *ptr)
+{
+ struct evbuffer *buf = evbuffer_new();
+ struct evbuffer_ptr pos;
+ struct evbuffer_iovec v[1];
+
+ tt_assert(buf);
+
+ tt_int_op(evbuffer_get_length(buf), ==, 0);
+
+ tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
+ tt_assert(pos.pos == 0);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 1, EVBUFFER_PTR_ADD) == -1);
+ tt_assert(pos.pos == -1);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 1, EVBUFFER_PTR_SET) == -1);
+ tt_assert(pos.pos == -1);
+
+ /* create some chains */
+ evbuffer_reserve_space(buf, 5000, v, 1);
+ v[0].iov_len = 5000;
+ memset(v[0].iov_base, 1, v[0].iov_len);
+ evbuffer_commit_space(buf, v, 1);
+ evbuffer_validate(buf);
+
+ evbuffer_reserve_space(buf, 4000, v, 1);
+ v[0].iov_len = 4000;
+ memset(v[0].iov_base, 2, v[0].iov_len);
+ evbuffer_commit_space(buf, v, 1);
+
+ evbuffer_reserve_space(buf, 3000, v, 1);
+ v[0].iov_len = 3000;
+ memset(v[0].iov_base, 3, v[0].iov_len);
+ evbuffer_commit_space(buf, v, 1);
+ evbuffer_validate(buf);
+
+ tt_int_op(evbuffer_get_length(buf), ==, 12000);
+
+ tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_SET) == -1);
+ tt_assert(pos.pos == -1);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
+ tt_assert(pos.pos == 0);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_ADD) == -1);
+
+ tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
+ tt_assert(pos.pos == 0);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 10000, EVBUFFER_PTR_ADD) == 0);
+ tt_assert(pos.pos == 10000);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0);
+ tt_assert(pos.pos == 11000);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0);
+ tt_assert(pos.pos == 12000);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == -1);
+ tt_assert(pos.pos == -1);
+
+end:
+ if (buf)
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_search(void *ptr)
+{
+ struct evbuffer *buf = evbuffer_new();
+ struct evbuffer *tmp = evbuffer_new();
+ struct evbuffer_ptr pos, end;
+
+ tt_assert(buf);
+ tt_assert(tmp);
+
+ pos = evbuffer_search(buf, "x", 1, NULL);
+ tt_int_op(pos.pos, ==, -1);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
+ pos = evbuffer_search(buf, "x", 1, &pos);
+ tt_int_op(pos.pos, ==, -1);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
+ pos = evbuffer_search_range(buf, "x", 1, &pos, &pos);
+ tt_int_op(pos.pos, ==, -1);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
+ pos = evbuffer_search_range(buf, "x", 1, &pos, NULL);
+ tt_int_op(pos.pos, ==, -1);
+
+ /* set up our chains */
+ evbuffer_add_printf(tmp, "hello"); /* 5 chars */
+ evbuffer_add_buffer(buf, tmp);
+ evbuffer_add_printf(tmp, "foo"); /* 3 chars */
+ evbuffer_add_buffer(buf, tmp);
+ evbuffer_add_printf(tmp, "cat"); /* 3 chars */
+ evbuffer_add_buffer(buf, tmp);
+ evbuffer_add_printf(tmp, "attack");
+ evbuffer_add_buffer(buf, tmp);
+
+ pos = evbuffer_search(buf, "attack", 6, NULL);
+ tt_int_op(pos.pos, ==, 11);
+ pos = evbuffer_search(buf, "attacker", 8, NULL);
+ tt_int_op(pos.pos, ==, -1);
+
+ /* test continuing search */
+ pos = evbuffer_search(buf, "oc", 2, NULL);
+ tt_int_op(pos.pos, ==, 7);
+ pos = evbuffer_search(buf, "cat", 3, &pos);
+ tt_int_op(pos.pos, ==, 8);
+ pos = evbuffer_search(buf, "tacking", 7, &pos);
+ tt_int_op(pos.pos, ==, -1);
+
+ evbuffer_ptr_set(buf, &pos, 5, EVBUFFER_PTR_SET);
+ pos = evbuffer_search(buf, "foo", 3, &pos);
+ tt_int_op(pos.pos, ==, 5);
+
+ evbuffer_ptr_set(buf, &pos, 2, EVBUFFER_PTR_ADD);
+ pos = evbuffer_search(buf, "tat", 3, &pos);
+ tt_int_op(pos.pos, ==, 10);
+
+ /* test bounded search. */
+ /* Set "end" to the first t in "attack". */
+ evbuffer_ptr_set(buf, &end, 12, EVBUFFER_PTR_SET);
+ pos = evbuffer_search_range(buf, "foo", 3, NULL, &end);
+ tt_int_op(pos.pos, ==, 5);
+ pos = evbuffer_search_range(buf, "foocata", 7, NULL, &end);
+ tt_int_op(pos.pos, ==, 5);
+ pos = evbuffer_search_range(buf, "foocatat", 8, NULL, &end);
+ tt_int_op(pos.pos, ==, -1);
+ pos = evbuffer_search_range(buf, "ack", 3, NULL, &end);
+ tt_int_op(pos.pos, ==, -1);
+
+ /* Set "end" after the last byte in the buffer. */
+ tt_assert(evbuffer_ptr_set(buf, &end, 17, EVBUFFER_PTR_SET) == 0);
+
+ pos = evbuffer_search_range(buf, "attack", 6, NULL, &end);
+ tt_int_op(pos.pos, ==, 11);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 11, EVBUFFER_PTR_SET) == 0);
+ pos = evbuffer_search_range(buf, "attack", 6, &pos, &end);
+ tt_int_op(pos.pos, ==, 11);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 17, EVBUFFER_PTR_SET) == 0);
+ pos = evbuffer_search_range(buf, "attack", 6, &pos, &end);
+ tt_int_op(pos.pos, ==, -1);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 17, EVBUFFER_PTR_SET) == 0);
+ pos = evbuffer_search_range(buf, "attack", 6, &pos, NULL);
+ tt_int_op(pos.pos, ==, -1);
+
+end:
+ if (buf)
+ evbuffer_free(buf);
+ if (tmp)
+ evbuffer_free(tmp);
+}
+
+static void
+log_change_callback(struct evbuffer *buffer,
+ const struct evbuffer_cb_info *cbinfo,
+ void *arg)
+{
+
+ size_t old_len = cbinfo->orig_size;
+ size_t new_len = old_len + cbinfo->n_added - cbinfo->n_deleted;
+ struct evbuffer *out = arg;
+ evbuffer_add_printf(out, "%lu->%lu; ", (unsigned long)old_len,
+ (unsigned long)new_len);
+}
+static void
+self_draining_callback(struct evbuffer *evbuffer, size_t old_len,
+ size_t new_len, void *arg)
+{
+ if (new_len > old_len)
+ evbuffer_drain(evbuffer, new_len);
+}
+
+static void
+test_evbuffer_callbacks(void *ptr)
+{
+ struct evbuffer *buf = evbuffer_new();
+ struct evbuffer *buf_out1 = evbuffer_new();
+ struct evbuffer *buf_out2 = evbuffer_new();
+ struct evbuffer_cb_entry *cb1, *cb2;
+
+ tt_assert(buf);
+ tt_assert(buf_out1);
+ tt_assert(buf_out2);
+
+ cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
+ cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
+
+ /* Let's run through adding and deleting some stuff from the buffer
+ * and turning the callbacks on and off and removing them. The callback
+ * adds a summary of length changes to buf_out1/buf_out2 when called. */
+ /* size: 0-> 36. */
+ evbuffer_add_printf(buf, "The %d magic words are spotty pudding", 2);
+ evbuffer_validate(buf);
+ evbuffer_cb_clear_flags(buf, cb2, EVBUFFER_CB_ENABLED);
+ evbuffer_drain(buf, 10); /*36->26*/
+ evbuffer_validate(buf);
+ evbuffer_prepend(buf, "Hello", 5);/*26->31*/
+ evbuffer_cb_set_flags(buf, cb2, EVBUFFER_CB_ENABLED);
+ evbuffer_add_reference(buf, "Goodbye", 7, NULL, NULL); /*31->38*/
+ evbuffer_remove_cb_entry(buf, cb1);
+ evbuffer_validate(buf);
+ evbuffer_drain(buf, evbuffer_get_length(buf)); /*38->0*/;
+ tt_assert(-1 == evbuffer_remove_cb(buf, log_change_callback, NULL));
+ evbuffer_add(buf, "X", 1); /* 0->1 */
+ tt_assert(!evbuffer_remove_cb(buf, log_change_callback, buf_out2));
+ evbuffer_validate(buf);
+
+ tt_str_op((const char *) evbuffer_pullup(buf_out1, -1), ==,
+ "0->36; 36->26; 26->31; 31->38; ");
+ tt_str_op((const char *) evbuffer_pullup(buf_out2, -1), ==,
+ "0->36; 31->38; 38->0; 0->1; ");
+ evbuffer_drain(buf_out1, evbuffer_get_length(buf_out1));
+ evbuffer_drain(buf_out2, evbuffer_get_length(buf_out2));
+ /* Let's test the obsolete buffer_setcb function too. */
+ cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
+ tt_assert(cb1 != NULL);
+ cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
+ tt_assert(cb2 != NULL);
+ evbuffer_setcb(buf, self_draining_callback, NULL);
+ evbuffer_add_printf(buf, "This should get drained right away.");
+ tt_uint_op(evbuffer_get_length(buf), ==, 0);
+ tt_uint_op(evbuffer_get_length(buf_out1), ==, 0);
+ tt_uint_op(evbuffer_get_length(buf_out2), ==, 0);
+ evbuffer_setcb(buf, NULL, NULL);
+ evbuffer_add_printf(buf, "This will not.");
+ tt_str_op((const char *) evbuffer_pullup(buf, -1), ==, "This will not.");
+ evbuffer_validate(buf);
+ evbuffer_drain(buf, evbuffer_get_length(buf));
+ evbuffer_validate(buf);
+#if 0
+ /* Now let's try a suspended callback. */
+ cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
+ cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
+ evbuffer_cb_suspend(buf,cb2);
+ evbuffer_prepend(buf,"Hello world",11); /*0->11*/
+ evbuffer_validate(buf);
+ evbuffer_cb_suspend(buf,cb1);
+ evbuffer_add(buf,"more",4); /* 11->15 */
+ evbuffer_cb_unsuspend(buf,cb2);
+ evbuffer_drain(buf, 4); /* 15->11 */
+ evbuffer_cb_unsuspend(buf,cb1);
+ evbuffer_drain(buf, evbuffer_get_length(buf)); /* 11->0 */
+
+ tt_str_op(evbuffer_pullup(buf_out1, -1), ==,
+ "0->11; 11->11; 11->0; ");
+ tt_str_op(evbuffer_pullup(buf_out2, -1), ==,
+ "0->15; 15->11; 11->0; ");
+#endif
+
+ end:
+ if (buf)
+ evbuffer_free(buf);
+ if (buf_out1)
+ evbuffer_free(buf_out1);
+ if (buf_out2)
+ evbuffer_free(buf_out2);
+}
+
+static int ref_done_cb_called_count = 0;
+static void *ref_done_cb_called_with = NULL;
+static const void *ref_done_cb_called_with_data = NULL;
+static size_t ref_done_cb_called_with_len = 0;
+static void ref_done_cb(const void *data, size_t len, void *info)
+{
+ ++ref_done_cb_called_count;
+ ref_done_cb_called_with = info;
+ ref_done_cb_called_with_data = data;
+ ref_done_cb_called_with_len = len;
+}
+
+static void
+test_evbuffer_add_reference(void *ptr)
+{
+ const char chunk1[] = "If you have found the answer to such a problem";
+ const char chunk2[] = "you ought to write it up for publication";
+ /* -- Knuth's "Notes on the Exercises" from TAOCP */
+ char tmp[16];
+ size_t len1 = strlen(chunk1), len2=strlen(chunk2);
+
+ struct evbuffer *buf1 = NULL, *buf2 = NULL;
+
+ buf1 = evbuffer_new();
+ tt_assert(buf1);
+
+ evbuffer_add_reference(buf1, chunk1, len1, ref_done_cb, (void*)111);
+ evbuffer_add(buf1, ", ", 2);
+ evbuffer_add_reference(buf1, chunk2, len2, ref_done_cb, (void*)222);
+ tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2);
+
+ /* Make sure we can drain a little from a reference. */
+ tt_int_op(evbuffer_remove(buf1, tmp, 6), ==, 6);
+ tt_int_op(memcmp(tmp, "If you", 6), ==, 0);
+ tt_int_op(evbuffer_remove(buf1, tmp, 5), ==, 5);
+ tt_int_op(memcmp(tmp, " have", 5), ==, 0);
+
+ /* Make sure that prepending does not meddle with immutable data */
+ tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0);
+ tt_int_op(memcmp(chunk1, "If you", 6), ==, 0);
+ evbuffer_validate(buf1);
+
+ /* Make sure that when the chunk is over, the callback is invoked. */
+ evbuffer_drain(buf1, 7); /* Remove prepended stuff. */
+ evbuffer_drain(buf1, len1-11-1); /* remove all but one byte of chunk1 */
+ tt_int_op(ref_done_cb_called_count, ==, 0);
+ evbuffer_remove(buf1, tmp, 1);
+ tt_int_op(tmp[0], ==, 'm');
+ tt_assert(ref_done_cb_called_with == (void*)111);
+ tt_assert(ref_done_cb_called_with_data == chunk1);
+ tt_assert(ref_done_cb_called_with_len == len1);
+ tt_int_op(ref_done_cb_called_count, ==, 1);
+ evbuffer_validate(buf1);
+
+ /* Drain some of the remaining chunk, then add it to another buffer */
+ evbuffer_drain(buf1, 6); /* Remove the ", you ". */
+ buf2 = evbuffer_new();
+ tt_assert(buf2);
+ tt_int_op(ref_done_cb_called_count, ==, 1);
+ evbuffer_add(buf2, "I ", 2);
+
+ evbuffer_add_buffer(buf2, buf1);
+ tt_int_op(ref_done_cb_called_count, ==, 1);
+ evbuffer_remove(buf2, tmp, 16);
+ tt_int_op(memcmp("I ought to write", tmp, 16), ==, 0);
+ evbuffer_drain(buf2, evbuffer_get_length(buf2));
+ tt_int_op(ref_done_cb_called_count, ==, 2);
+ tt_assert(ref_done_cb_called_with == (void*)222);
+ evbuffer_validate(buf2);
+
+ /* Now add more stuff to buf1 and make sure that it gets removed on
+ * free. */
+ evbuffer_add(buf1, "You shake and shake the ", 24);
+ evbuffer_add_reference(buf1, "ketchup bottle", 14, ref_done_cb,
+ (void*)3333);
+ evbuffer_add(buf1, ". Nothing comes and then a lot'll.", 35);
+ evbuffer_free(buf1);
+ buf1 = NULL;
+ tt_int_op(ref_done_cb_called_count, ==, 3);
+ tt_assert(ref_done_cb_called_with == (void*)3333);
+
+end:
+ if (buf1)
+ evbuffer_free(buf1);
+ if (buf2)
+ evbuffer_free(buf2);
+}
+
+static void
+test_evbuffer_multicast(void *ptr)
+{
+ const char chunk1[] = "If you have found the answer to such a problem";
+ const char chunk2[] = "you ought to write it up for publication";
+ /* -- Knuth's "Notes on the Exercises" from TAOCP */
+ char tmp[16];
+ size_t len1 = strlen(chunk1), len2=strlen(chunk2);
+
+ struct evbuffer *buf1 = NULL, *buf2 = NULL;
+
+ buf1 = evbuffer_new();
+ tt_assert(buf1);
+
+ evbuffer_add(buf1, chunk1, len1);
+ evbuffer_add(buf1, ", ", 2);
+ evbuffer_add(buf1, chunk2, len2);
+ tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2);
+
+ buf2 = evbuffer_new();
+ tt_assert(buf2);
+
+ tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0);
+ /* nested references are not allowed */
+ tt_int_op(evbuffer_add_buffer_reference(buf2, buf2), ==, -1);
+ tt_int_op(evbuffer_add_buffer_reference(buf1, buf2), ==, -1);
+
+ /* both buffers contain the same amount of data */
+ tt_int_op(evbuffer_get_length(buf1), ==, evbuffer_get_length(buf1));
+
+ /* Make sure we can drain a little from the first buffer. */
+ tt_int_op(evbuffer_remove(buf1, tmp, 6), ==, 6);
+ tt_int_op(memcmp(tmp, "If you", 6), ==, 0);
+ tt_int_op(evbuffer_remove(buf1, tmp, 5), ==, 5);
+ tt_int_op(memcmp(tmp, " have", 5), ==, 0);
+
+ /* Make sure that prepending does not meddle with immutable data */
+ tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0);
+ tt_int_op(memcmp(chunk1, "If you", 6), ==, 0);
+ evbuffer_validate(buf1);
+
+ /* Make sure we can drain a little from the second buffer. */
+ tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6);
+ tt_int_op(memcmp(tmp, "If you", 6), ==, 0);
+ tt_int_op(evbuffer_remove(buf2, tmp, 5), ==, 5);
+ tt_int_op(memcmp(tmp, " have", 5), ==, 0);
+
+ /* Make sure that prepending does not meddle with immutable data */
+ tt_int_op(evbuffer_prepend(buf2, "I have ", 7), ==, 0);
+ tt_int_op(memcmp(chunk1, "If you", 6), ==, 0);
+ evbuffer_validate(buf2);
+
+ /* Make sure the data can be read from the second buffer when the first is freed */
+ evbuffer_free(buf1);
+ buf1 = NULL;
+
+ tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6);
+ tt_int_op(memcmp(tmp, "I have", 6), ==, 0);
+
+ tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6);
+ tt_int_op(memcmp(tmp, " foun", 6), ==, 0);
+
+end:
+ if (buf1)
+ evbuffer_free(buf1);
+ if (buf2)
+ evbuffer_free(buf2);
+}
+
+static void
+test_evbuffer_multicast_drain(void *ptr)
+{
+ const char chunk1[] = "If you have found the answer to such a problem";
+ const char chunk2[] = "you ought to write it up for publication";
+ /* -- Knuth's "Notes on the Exercises" from TAOCP */
+ size_t len1 = strlen(chunk1), len2=strlen(chunk2);
+
+ struct evbuffer *buf1 = NULL, *buf2 = NULL;
+
+ buf1 = evbuffer_new();
+ tt_assert(buf1);
+
+ evbuffer_add(buf1, chunk1, len1);
+ evbuffer_add(buf1, ", ", 2);
+ evbuffer_add(buf1, chunk2, len2);
+ tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2);
+
+ buf2 = evbuffer_new();
+ tt_assert(buf2);
+
+ tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0);
+ tt_int_op(evbuffer_get_length(buf2), ==, len1+len2+2);
+ tt_int_op(evbuffer_drain(buf1, evbuffer_get_length(buf1)), ==, 0);
+ tt_int_op(evbuffer_get_length(buf2), ==, len1+len2+2);
+ tt_int_op(evbuffer_drain(buf2, evbuffer_get_length(buf2)), ==, 0);
+ evbuffer_validate(buf1);
+ evbuffer_validate(buf2);
+
+end:
+ if (buf1)
+ evbuffer_free(buf1);
+ if (buf2)
+ evbuffer_free(buf2);
+}
+
+static void
+check_prepend(struct evbuffer *buffer,
+ const struct evbuffer_cb_info *cbinfo,
+ void *arg)
+{
+ tt_int_op(cbinfo->orig_size, ==, 3);
+ tt_int_op(cbinfo->n_added, ==, 8096);
+ tt_int_op(cbinfo->n_deleted, ==, 0);
+end:
+ ;
+}
+/* Some cases that we didn't get in test_evbuffer() above, for more coverage. */
+static void
+test_evbuffer_prepend(void *ptr)
+{
+ struct evbuffer *buf1 = NULL, *buf2 = NULL;
+ char tmp[128], *buffer = malloc(8096);
+ int n;
+
+ buf1 = evbuffer_new();
+ tt_assert(buf1);
+
+ /* Case 0: The evbuffer is entirely empty. */
+ evbuffer_prepend(buf1, "This string has 29 characters", 29);
+ evbuffer_validate(buf1);
+
+ /* Case 1: Prepend goes entirely in new chunk. */
+ evbuffer_prepend(buf1, "Short.", 6);
+ evbuffer_validate(buf1);
+
+ /* Case 2: prepend goes entirely in first chunk. */
+ evbuffer_drain(buf1, 6+11);
+ evbuffer_prepend(buf1, "it", 2);
+ evbuffer_validate(buf1);
+ tt_assert(!memcmp(buf1->first->buffer+buf1->first->misalign,
+ "it has", 6));
+
+ /* Case 3: prepend is split over multiple chunks. */
+ evbuffer_prepend(buf1, "It is no longer true to say ", 28);
+ evbuffer_validate(buf1);
+ n = evbuffer_remove(buf1, tmp, sizeof(tmp)-1);
+ tt_int_op(n, >=, 0);
+ tmp[n]='\0';
+ tt_str_op(tmp,==,"It is no longer true to say it has 29 characters");
+
+ buf2 = evbuffer_new();
+ tt_assert(buf2);
+
+ /* Case 4: prepend a buffer to an empty buffer. */
+ n = 999;
+ evbuffer_add_printf(buf1, "Here is string %d. ", n++);
+ evbuffer_prepend_buffer(buf2, buf1);
+ evbuffer_validate(buf2);
+
+ /* Case 5: prepend a buffer to a nonempty buffer. */
+ evbuffer_add_printf(buf1, "Here is string %d. ", n++);
+ evbuffer_prepend_buffer(buf2, buf1);
+ evbuffer_validate(buf2);
+ evbuffer_validate(buf1);
+ n = evbuffer_remove(buf2, tmp, sizeof(tmp)-1);
+ tt_int_op(n, >=, 0);
+ tmp[n]='\0';
+ tt_str_op(tmp,==,"Here is string 1000. Here is string 999. ");
+
+ /* Case 5: evbuffer_prepend() will need a new buffer, with callbacks */
+ memset(buffer, 'A', 8096);
+ evbuffer_free(buf2);
+ buf2 = evbuffer_new();
+ tt_assert(buf2);
+ evbuffer_prepend(buf2, "foo", 3);
+ evbuffer_add_cb(buf2, check_prepend, NULL);
+ evbuffer_prepend(buf2, buffer, 8096);
+ evbuffer_remove_cb(buf2, check_prepend, NULL);
+ evbuffer_validate(buf2);
+ tt_nstr_op(8096,(char *)evbuffer_pullup(buf2, 8096),==,buffer);
+ evbuffer_drain(buf2, 8096);
+ tt_nstr_op(3,(char *)evbuffer_pullup(buf2, 3),==,"foo");
+ evbuffer_drain(buf2, 3);
+
+end:
+ free(buffer);
+ if (buf1)
+ evbuffer_free(buf1);
+ if (buf2)
+ evbuffer_free(buf2);
+
+}
+
+static void
+test_evbuffer_peek_first_gt(void *info)
+{
+ struct evbuffer *buf = NULL, *tmp_buf = NULL;
+ struct evbuffer_ptr ptr;
+ struct evbuffer_iovec v[2];
+
+ buf = evbuffer_new();
+ tmp_buf = evbuffer_new();
+ evbuffer_add_printf(tmp_buf, "Contents of chunk 100\n");
+ evbuffer_add_buffer(buf, tmp_buf);
+ evbuffer_add_printf(tmp_buf, "Contents of chunk 1\n");
+ evbuffer_add_buffer(buf, tmp_buf);
+
+ evbuffer_ptr_set(buf, &ptr, 0, EVBUFFER_PTR_SET);
+
+ /** The only case that matters*/
+ tt_int_op(evbuffer_peek(buf, -1, &ptr, NULL, 0), ==, 2);
+ /** Just in case */
+ tt_int_op(evbuffer_peek(buf, -1, &ptr, v, 2), ==, 2);
+
+ evbuffer_ptr_set(buf, &ptr, 20, EVBUFFER_PTR_ADD);
+ tt_int_op(evbuffer_peek(buf, -1, &ptr, NULL, 0), ==, 2);
+ tt_int_op(evbuffer_peek(buf, -1, &ptr, v, 2), ==, 2);
+ tt_int_op(evbuffer_peek(buf, 2, &ptr, NULL, 0), ==, 1);
+ tt_int_op(evbuffer_peek(buf, 2, &ptr, v, 2), ==, 1);
+ tt_int_op(evbuffer_peek(buf, 3, &ptr, NULL, 0), ==, 2);
+ tt_int_op(evbuffer_peek(buf, 3, &ptr, v, 2), ==, 2);
+
+end:
+ if (buf)
+ evbuffer_free(buf);
+ if (tmp_buf)
+ evbuffer_free(tmp_buf);
+}
+
+static void
+test_evbuffer_peek(void *info)
+{
+ struct evbuffer *buf = NULL, *tmp_buf = NULL;
+ int i;
+ struct evbuffer_iovec v[20];
+ struct evbuffer_ptr ptr;
+
+#define tt_iov_eq(v, s) \
+ tt_int_op((v)->iov_len, ==, strlen(s)); \
+ tt_assert(!memcmp((v)->iov_base, (s), strlen(s)))
+
+ /* Let's make a very fragmented buffer. */
+ buf = evbuffer_new();
+ tmp_buf = evbuffer_new();
+ for (i = 0; i < 16; ++i) {
+ evbuffer_add_printf(tmp_buf, "Contents of chunk [%d]\n", i);
+ evbuffer_add_buffer(buf, tmp_buf);
+ }
+
+ /* How many chunks do we need for everything? */
+ i = evbuffer_peek(buf, -1, NULL, NULL, 0);
+ tt_int_op(i, ==, 16);
+
+ /* Simple peek: get everything. */
+ i = evbuffer_peek(buf, -1, NULL, v, 20);
+ tt_int_op(i, ==, 16); /* we used only 16 chunks. */
+ tt_iov_eq(&v[0], "Contents of chunk [0]\n");
+ tt_iov_eq(&v[3], "Contents of chunk [3]\n");
+ tt_iov_eq(&v[12], "Contents of chunk [12]\n");
+ tt_iov_eq(&v[15], "Contents of chunk [15]\n");
+
+ /* Just get one chunk worth. */
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(buf, -1, NULL, v, 1);
+ tt_int_op(i, ==, 1);
+ tt_iov_eq(&v[0], "Contents of chunk [0]\n");
+ tt_assert(v[1].iov_base == NULL);
+
+ /* Suppose we want at least the first 40 bytes. */
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(buf, 40, NULL, v, 16);
+ tt_int_op(i, ==, 2);
+ tt_iov_eq(&v[0], "Contents of chunk [0]\n");
+ tt_iov_eq(&v[1], "Contents of chunk [1]\n");
+ tt_assert(v[2].iov_base == NULL);
+
+ /* How many chunks do we need for 100 bytes? */
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(buf, 100, NULL, NULL, 0);
+ tt_int_op(i, ==, 5);
+ tt_assert(v[0].iov_base == NULL);
+
+ /* Now we ask for more bytes than we provide chunks for */
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(buf, 60, NULL, v, 1);
+ tt_int_op(i, ==, 3);
+ tt_iov_eq(&v[0], "Contents of chunk [0]\n");
+ tt_assert(v[1].iov_base == NULL);
+
+ /* Now we ask for more bytes than the buffer has. */
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(buf, 65536, NULL, v, 20);
+ tt_int_op(i, ==, 16); /* we used only 16 chunks. */
+ tt_iov_eq(&v[0], "Contents of chunk [0]\n");
+ tt_iov_eq(&v[3], "Contents of chunk [3]\n");
+ tt_iov_eq(&v[12], "Contents of chunk [12]\n");
+ tt_iov_eq(&v[15], "Contents of chunk [15]\n");
+ tt_assert(v[16].iov_base == NULL);
+
+ /* What happens if we try an empty buffer? */
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(tmp_buf, -1, NULL, v, 20);
+ tt_int_op(i, ==, 0);
+ tt_assert(v[0].iov_base == NULL);
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(tmp_buf, 50, NULL, v, 20);
+ tt_int_op(i, ==, 0);
+ tt_assert(v[0].iov_base == NULL);
+
+ /* Okay, now time to have fun with pointers. */
+ memset(v, 0, sizeof(v));
+ evbuffer_ptr_set(buf, &ptr, 30, EVBUFFER_PTR_SET);
+ i = evbuffer_peek(buf, 50, &ptr, v, 20);
+ tt_int_op(i, ==, 3);
+ tt_iov_eq(&v[0], " of chunk [1]\n");
+ tt_iov_eq(&v[1], "Contents of chunk [2]\n");
+ tt_iov_eq(&v[2], "Contents of chunk [3]\n"); /*more than we asked for*/
+
+ /* advance to the start of another chain. */
+ memset(v, 0, sizeof(v));
+ evbuffer_ptr_set(buf, &ptr, 14, EVBUFFER_PTR_ADD);
+ i = evbuffer_peek(buf, 44, &ptr, v, 20);
+ tt_int_op(i, ==, 2);
+ tt_iov_eq(&v[0], "Contents of chunk [2]\n");
+ tt_iov_eq(&v[1], "Contents of chunk [3]\n"); /*more than we asked for*/
+
+ /* peek at the end of the buffer */
+ memset(v, 0, sizeof(v));
+ tt_assert(evbuffer_ptr_set(buf, &ptr, evbuffer_get_length(buf), EVBUFFER_PTR_SET) == 0);
+ i = evbuffer_peek(buf, 44, &ptr, v, 20);
+ tt_int_op(i, ==, 0);
+ tt_assert(v[0].iov_base == NULL);
+
+end:
+ if (buf)
+ evbuffer_free(buf);
+ if (tmp_buf)
+ evbuffer_free(tmp_buf);
+}
+
+/* Check whether evbuffer freezing works right. This is called twice,
+ once with the argument "start" and once with the argument "end".
+ When we test "start", we freeze the start of an evbuffer and make sure
+ that modifying the start of the buffer doesn't work. When we test
+ "end", we freeze the end of an evbuffer and make sure that modifying
+ the end of the buffer doesn't work.
+ */
+static void
+test_evbuffer_freeze(void *ptr)
+{
+ struct evbuffer *buf = NULL, *tmp_buf=NULL;
+ const char string[] = /* Year's End, Richard Wilbur */
+ "I've known the wind by water banks to shake\n"
+ "The late leaves down, which frozen where they fell\n"
+ "And held in ice as dancers in a spell\n"
+ "Fluttered all winter long into a lake...";
+ const int start = !strcmp(ptr, "start");
+ char *cp;
+ char charbuf[128];
+ int r;
+ size_t orig_length;
+ struct evbuffer_iovec v[1];
+
+ if (!start)
+ tt_str_op(ptr, ==, "end");
+
+ buf = evbuffer_new();
+ tmp_buf = evbuffer_new();
+ tt_assert(tmp_buf);
+
+ evbuffer_add(buf, string, strlen(string));
+ evbuffer_freeze(buf, start); /* Freeze the start or the end.*/
+
+#define FREEZE_EQ(a, startcase, endcase) \
+ do { \
+ if (start) { \
+ tt_int_op((a), ==, (startcase)); \
+ } else { \
+ tt_int_op((a), ==, (endcase)); \
+ } \
+ } while (0)
+
+
+ orig_length = evbuffer_get_length(buf);
+
+ /* These functions all manipulate the end of buf. */
+ r = evbuffer_add(buf, "abc", 0);
+ FREEZE_EQ(r, 0, -1);
+ r = evbuffer_reserve_space(buf, 10, v, 1);
+ FREEZE_EQ(r, 1, -1);
+ if (r == 1) {
+ memset(v[0].iov_base, 'X', 10);
+ v[0].iov_len = 10;
+ }
+ r = evbuffer_commit_space(buf, v, 1);
+ FREEZE_EQ(r, 0, -1);
+ r = evbuffer_add_reference(buf, string, 5, NULL, NULL);
+ FREEZE_EQ(r, 0, -1);
+ r = evbuffer_add_printf(buf, "Hello %s", "world");
+ FREEZE_EQ(r, 11, -1);
+ /* TODO: test add_buffer, add_file, read */
+
+ if (!start)
+ tt_int_op(orig_length, ==, evbuffer_get_length(buf));
+
+ orig_length = evbuffer_get_length(buf);
+
+ /* These functions all manipulate the start of buf. */
+ r = evbuffer_remove(buf, charbuf, 1);
+ FREEZE_EQ(r, -1, 1);
+ r = evbuffer_drain(buf, 3);
+ FREEZE_EQ(r, -1, 0);
+ r = evbuffer_prepend(buf, "dummy", 5);
+ FREEZE_EQ(r, -1, 0);
+ cp = evbuffer_readln(buf, NULL, EVBUFFER_EOL_LF);
+ FREEZE_EQ(cp==NULL, 1, 0);
+ if (cp)
+ free(cp);
+ /* TODO: Test remove_buffer, add_buffer, write, prepend_buffer */
+
+ if (start)
+ tt_int_op(orig_length, ==, evbuffer_get_length(buf));
+
+end:
+ if (buf)
+ evbuffer_free(buf);
+
+ if (tmp_buf)
+ evbuffer_free(tmp_buf);
+}
+
+static void
+test_evbuffer_add_iovec(void * ptr)
+{
+ struct evbuffer * buf = NULL;
+ struct evbuffer_iovec vec[4];
+ const char * data[] = {
+ "Guilt resembles a sword with two edges.",
+ "On the one hand, it cuts for Justice, imposing practical morality upon those who fear it.",
+ "Conscience does not always adhere to rational judgment.",
+ "Guilt is always a self-imposed burden, but it is not always rightly imposed."
+ /* -- R.A. Salvatore, _Sojurn_ */
+ };
+ size_t expected_length = 0;
+ size_t returned_length = 0;
+ int i;
+
+ buf = evbuffer_new();
+
+ tt_assert(buf);
+
+ for (i = 0; i < 4; i++) {
+ vec[i].iov_len = strlen(data[i]);
+ vec[i].iov_base = (char*) data[i];
+ expected_length += vec[i].iov_len;
+ }
+
+ returned_length = evbuffer_add_iovec(buf, vec, 4);
+
+ tt_int_op(returned_length, ==, evbuffer_get_length(buf));
+ tt_int_op(evbuffer_get_length(buf), ==, expected_length);
+
+ for (i = 0; i < 4; i++) {
+ char charbuf[1024];
+
+ memset(charbuf, 0, 1024);
+ evbuffer_remove(buf, charbuf, strlen(data[i]));
+ tt_assert(strcmp(charbuf, data[i]) == 0);
+ }
+
+ tt_assert(evbuffer_get_length(buf) == 0);
+end:
+ if (buf) {
+ evbuffer_free(buf);
+ }
+}
+
+static void
+test_evbuffer_copyout(void *dummy)
+{
+ const char string[] =
+ "Still they skirmish to and fro, men my messmates on the snow "
+ "When we headed off the aurochs turn for turn; "
+ "When the rich Allobrogenses never kept amanuenses, "
+ "And our only plots were piled in lakes at Berne.";
+ /* -- Kipling, "In The Neolithic Age" */
+ char tmp[1024];
+ struct evbuffer_ptr ptr;
+ struct evbuffer *buf;
+
+ (void)dummy;
+
+ buf = evbuffer_new();
+ tt_assert(buf);
+
+ tt_int_op(strlen(string), ==, 206);
+
+ /* Ensure separate chains */
+ evbuffer_add_reference(buf, string, 80, no_cleanup, NULL);
+ evbuffer_add_reference(buf, string+80, 80, no_cleanup, NULL);
+ evbuffer_add(buf, string+160, strlen(string)-160);
+
+ tt_int_op(206, ==, evbuffer_get_length(buf));
+
+ /* First, let's test plain old copyout. */
+
+ /* Copy a little from the beginning. */
+ tt_int_op(10, ==, evbuffer_copyout(buf, tmp, 10));
+ tt_int_op(0, ==, memcmp(tmp, "Still they", 10));
+
+ /* Now copy more than a little from the beginning */
+ memset(tmp, 0, sizeof(tmp));
+ tt_int_op(100, ==, evbuffer_copyout(buf, tmp, 100));
+ tt_int_op(0, ==, memcmp(tmp, string, 100));
+
+ /* Copy too much; ensure truncation. */
+ memset(tmp, 0, sizeof(tmp));
+ tt_int_op(206, ==, evbuffer_copyout(buf, tmp, 230));
+ tt_int_op(0, ==, memcmp(tmp, string, 206));
+
+ /* That was supposed to be nondestructive, btw */
+ tt_int_op(206, ==, evbuffer_get_length(buf));
+
+ /* Now it's time to test copyout_from! First, let's start in the
+ * first chain. */
+ evbuffer_ptr_set(buf, &ptr, 15, EVBUFFER_PTR_SET);
+ memset(tmp, 0, sizeof(tmp));
+ tt_int_op(10, ==, evbuffer_copyout_from(buf, &ptr, tmp, 10));
+ tt_int_op(0, ==, memcmp(tmp, "mish to an", 10));
+
+ /* Right up to the end of the first chain */
+ memset(tmp, 0, sizeof(tmp));
+ tt_int_op(65, ==, evbuffer_copyout_from(buf, &ptr, tmp, 65));
+ tt_int_op(0, ==, memcmp(tmp, string+15, 65));
+
+ /* Span into the second chain */
+ memset(tmp, 0, sizeof(tmp));
+ tt_int_op(90, ==, evbuffer_copyout_from(buf, &ptr, tmp, 90));
+ tt_int_op(0, ==, memcmp(tmp, string+15, 90));
+
+ /* Span into the third chain */
+ memset(tmp, 0, sizeof(tmp));
+ tt_int_op(160, ==, evbuffer_copyout_from(buf, &ptr, tmp, 160));
+ tt_int_op(0, ==, memcmp(tmp, string+15, 160));
+
+ /* Overrun */
+ memset(tmp, 0, sizeof(tmp));
+ tt_int_op(206-15, ==, evbuffer_copyout_from(buf, &ptr, tmp, 999));
+ tt_int_op(0, ==, memcmp(tmp, string+15, 206-15));
+
+ /* That was supposed to be nondestructive, too */
+ tt_int_op(206, ==, evbuffer_get_length(buf));
+
+end:
+ if (buf)
+ evbuffer_free(buf);
+}
+
+static void *
+setup_passthrough(const struct testcase_t *testcase)
+{
+ return testcase->setup_data;
+}
+static int
+cleanup_passthrough(const struct testcase_t *testcase, void *ptr)
+{
+ (void) ptr;
+ return 1;
+}
+
+static const struct testcase_setup_t nil_setup = {
+ setup_passthrough,
+ cleanup_passthrough
+};
+
+struct testcase_t evbuffer_testcases[] = {
+ { "evbuffer", test_evbuffer, 0, NULL, NULL },
+ { "remove_buffer_with_empty", test_evbuffer_remove_buffer_with_empty, 0, NULL, NULL },
+ { "remove_buffer_with_empty2", test_evbuffer_remove_buffer_with_empty2, 0, NULL, NULL },
+ { "remove_buffer_with_empty3", test_evbuffer_remove_buffer_with_empty3, 0, NULL, NULL },
+ { "add_buffer_with_empty", test_evbuffer_add_buffer_with_empty, 0, NULL, NULL },
+ { "add_buffer_with_empty2", test_evbuffer_add_buffer_with_empty2, 0, NULL, NULL },
+ { "reserve2", test_evbuffer_reserve2, 0, NULL, NULL },
+ { "reserve_many", test_evbuffer_reserve_many, 0, NULL, NULL },
+ { "reserve_many2", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"add" },
+ { "reserve_many3", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"fill" },
+ { "expand", test_evbuffer_expand, 0, NULL, NULL },
+ { "expand_overflow", test_evbuffer_expand_overflow, 0, NULL, NULL },
+ { "add1", test_evbuffer_add1, 0, NULL, NULL },
+ { "add2", test_evbuffer_add2, 0, NULL, NULL },
+ { "reference", test_evbuffer_reference, 0, NULL, NULL },
+ { "reference2", test_evbuffer_reference2, 0, NULL, NULL },
+ { "iterative", test_evbuffer_iterative, 0, NULL, NULL },
+ { "readln", test_evbuffer_readln, TT_NO_LOGS, &basic_setup, NULL },
+ { "search_eol", test_evbuffer_search_eol, 0, NULL, NULL },
+ { "find", test_evbuffer_find, 0, NULL, NULL },
+ { "ptr_set", test_evbuffer_ptr_set, 0, NULL, NULL },
+ { "search", test_evbuffer_search, 0, NULL, NULL },
+ { "callbacks", test_evbuffer_callbacks, 0, NULL, NULL },
+ { "add_reference", test_evbuffer_add_reference, 0, NULL, NULL },
+ { "multicast", test_evbuffer_multicast, 0, NULL, NULL },
+ { "multicast_drain", test_evbuffer_multicast_drain, 0, NULL, NULL },
+ { "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL },
+ { "peek", test_evbuffer_peek, 0, NULL, NULL },
+ { "peek_first_gt", test_evbuffer_peek_first_gt, 0, NULL, NULL },
+ { "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" },
+ { "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" },
+ { "add_iovec", test_evbuffer_add_iovec, 0, NULL, NULL},
+ { "copyout", test_evbuffer_copyout, 0, NULL, NULL},
+ { "file_segment_add_cleanup_cb", test_evbuffer_file_segment_add_cleanup_cb, 0, NULL, NULL },
+
+#define ADDFILE_TEST(name, parameters) \
+ { name, test_evbuffer_add_file, TT_FORK|TT_NEED_BASE, \
+ &basic_setup, (void*)(parameters) }
+
+#define ADDFILE_TEST_GROUP(name, parameters) \
+ ADDFILE_TEST(name "_sendfile", "sendfile " parameters), \
+ ADDFILE_TEST(name "_mmap", "mmap " parameters), \
+ ADDFILE_TEST(name "_linear", "linear " parameters)
+
+ ADDFILE_TEST_GROUP("add_file", ""),
+ ADDFILE_TEST("add_file_nosegment", "default nosegment"),
+
+ ADDFILE_TEST_GROUP("add_big_file", "bigfile"),
+ ADDFILE_TEST("add_big_file_nosegment", "default nosegment bigfile"),
+
+ ADDFILE_TEST_GROUP("add_file_offset", "bigfile map_offset"),
+ ADDFILE_TEST("add_file_offset_nosegment",
+ "default nosegment bigfile map_offset"),
+
+ ADDFILE_TEST_GROUP("add_file_offset2", "bigfile offset_in_segment"),
+
+ ADDFILE_TEST_GROUP("add_file_offset3",
+ "bigfile offset_in_segment map_offset"),
+
+ END_OF_TESTCASES
+};
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_bufferevent.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_bufferevent.c
new file mode 100644
index 000000000..249985e99
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_bufferevent.c
@@ -0,0 +1,1443 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util-internal.h"
+
+/* The old tests here need assertions to work. */
+#undef NDEBUG
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#endif
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#ifdef EVENT__HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "event2/event-config.h"
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/event_compat.h"
+#include "event2/tag.h"
+#include "event2/buffer.h"
+#include "event2/bufferevent.h"
+#include "event2/bufferevent_compat.h"
+#include "event2/bufferevent_struct.h"
+#include "event2/listener.h"
+#include "event2/util.h"
+
+#include "bufferevent-internal.h"
+#include "evthread-internal.h"
+#include "util-internal.h"
+#ifdef _WIN32
+#include "iocp-internal.h"
+#endif
+
+#include "regress.h"
+#include "regress_testutils.h"
+
+/*
+ * simple bufferevent test
+ */
+
+static void
+readcb(struct bufferevent *bev, void *arg)
+{
+ if (evbuffer_get_length(bev->input) == 8333) {
+ struct evbuffer *evbuf = evbuffer_new();
+ assert(evbuf != NULL);
+
+ /* gratuitous test of bufferevent_read_buffer */
+ bufferevent_read_buffer(bev, evbuf);
+
+ bufferevent_disable(bev, EV_READ);
+
+ if (evbuffer_get_length(evbuf) == 8333) {
+ test_ok++;
+ }
+
+ evbuffer_free(evbuf);
+ }
+}
+
+static void
+writecb(struct bufferevent *bev, void *arg)
+{
+ if (evbuffer_get_length(bev->output) == 0) {
+ test_ok++;
+ }
+}
+
+static void
+errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ test_ok = -2;
+}
+
+static void
+test_bufferevent_impl(int use_pair, int flush)
+{
+ struct bufferevent *bev1 = NULL, *bev2 = NULL;
+ char buffer[8333];
+ int i;
+ int expected = 2;
+
+ if (use_pair) {
+ struct bufferevent *pair[2];
+ tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
+ bev1 = pair[0];
+ bev2 = pair[1];
+ bufferevent_setcb(bev1, readcb, writecb, errorcb, bev1);
+ bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL);
+ tt_int_op(bufferevent_getfd(bev1), ==, -1);
+ tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL);
+ tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, bev2);
+ tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, bev1);
+ } else {
+ bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL);
+ bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL);
+ tt_int_op(bufferevent_getfd(bev1), ==, pair[0]);
+ tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL);
+ tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL);
+ tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL);
+ }
+
+ {
+ /* Test getcb. */
+ bufferevent_data_cb r, w;
+ bufferevent_event_cb e;
+ void *a;
+ bufferevent_getcb(bev1, &r, &w, &e, &a);
+ tt_ptr_op(r, ==, readcb);
+ tt_ptr_op(w, ==, writecb);
+ tt_ptr_op(e, ==, errorcb);
+ tt_ptr_op(a, ==, use_pair ? bev1 : NULL);
+ }
+
+ bufferevent_disable(bev1, EV_READ);
+ bufferevent_enable(bev2, EV_READ);
+
+ tt_int_op(bufferevent_get_enabled(bev1), ==, EV_WRITE);
+ tt_int_op(bufferevent_get_enabled(bev2), ==, EV_WRITE|EV_READ);
+
+ for (i = 0; i < (int)sizeof(buffer); i++)
+ buffer[i] = i;
+
+ bufferevent_write(bev1, buffer, sizeof(buffer));
+ if (flush >= 0) {
+ tt_int_op(bufferevent_flush(bev1, EV_WRITE, flush), >=, 0);
+ }
+
+ event_dispatch();
+
+ bufferevent_free(bev2);
+ tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL);
+ bufferevent_free(bev1);
+
+ /** Only pair call errorcb for BEV_FINISHED */
+ if (use_pair && flush == BEV_FINISHED) {
+ expected = -1;
+ }
+ if (test_ok != expected)
+ test_ok = 0;
+end:
+ ;
+}
+
+static void test_bufferevent(void) { test_bufferevent_impl(0, -1); }
+static void test_bufferevent_pair(void) { test_bufferevent_impl(1, -1); }
+
+static void test_bufferevent_flush_normal(void) { test_bufferevent_impl(0, BEV_NORMAL); }
+static void test_bufferevent_flush_flush(void) { test_bufferevent_impl(0, BEV_FLUSH); }
+static void test_bufferevent_flush_finished(void) { test_bufferevent_impl(0, BEV_FINISHED); }
+
+static void test_bufferevent_pair_flush_normal(void) { test_bufferevent_impl(1, BEV_NORMAL); }
+static void test_bufferevent_pair_flush_flush(void) { test_bufferevent_impl(1, BEV_FLUSH); }
+static void test_bufferevent_pair_flush_finished(void) { test_bufferevent_impl(1, BEV_FINISHED); }
+
+#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
+/**
+ * Trace lock/unlock/alloc/free for locks.
+ * (More heavier then evthread_debug*)
+ */
+typedef struct
+{
+ void *lock;
+ enum {
+ ALLOC, FREE,
+ } status;
+ size_t locked /** allow recursive locking */;
+} lock_wrapper;
+struct lock_unlock_base
+{
+ /* Original callbacks */
+ struct evthread_lock_callbacks cbs;
+ /* Map of locks */
+ lock_wrapper *locks;
+ size_t nr_locks;
+} lu_base = {
+ .locks = NULL,
+};
+
+static lock_wrapper *lu_find(void *lock_)
+{
+ size_t i;
+ for (i = 0; i < lu_base.nr_locks; ++i) {
+ lock_wrapper *lock = &lu_base.locks[i];
+ if (lock->lock == lock_)
+ return lock;
+ }
+ return NULL;
+}
+
+static void *trace_lock_alloc(unsigned locktype)
+{
+ void *lock;
+ ++lu_base.nr_locks;
+ lu_base.locks = realloc(lu_base.locks,
+ sizeof(lock_wrapper) * lu_base.nr_locks);
+ lock = lu_base.cbs.alloc(locktype);
+ lu_base.locks[lu_base.nr_locks - 1] = (lock_wrapper){ lock, ALLOC, 0 };
+ return lock;
+}
+static void trace_lock_free(void *lock_, unsigned locktype)
+{
+ lock_wrapper *lock = lu_find(lock_);
+ if (!lock || lock->status == FREE || lock->locked) {
+ TT_FAIL(("lock: free error"));
+ } else {
+ lock->status = FREE;
+ lu_base.cbs.free(lock_, locktype);
+ }
+}
+static int trace_lock_lock(unsigned mode, void *lock_)
+{
+ lock_wrapper *lock = lu_find(lock_);
+ if (!lock || lock->status == FREE) {
+ TT_FAIL(("lock: lock error"));
+ return -1;
+ } else {
+ ++lock->locked;
+ return lu_base.cbs.lock(mode, lock_);
+ }
+}
+static int trace_lock_unlock(unsigned mode, void *lock_)
+{
+ lock_wrapper *lock = lu_find(lock_);
+ if (!lock || lock->status == FREE || !lock->locked) {
+ TT_FAIL(("lock: unlock error"));
+ return -1;
+ } else {
+ --lock->locked;
+ return lu_base.cbs.unlock(mode, lock_);
+ }
+}
+static void lock_unlock_free_thread_cbs(void)
+{
+ event_base_free(NULL);
+
+ if (libevent_tests_running_in_debug_mode)
+ libevent_global_shutdown();
+
+ /** drop immutable flag */
+ evthread_set_lock_callbacks(NULL);
+ /** avoid calling of event_global_setup_locks_() for new cbs */
+ libevent_global_shutdown();
+ /** drop immutable flag for non-debug ops (since called after shutdown) */
+ evthread_set_lock_callbacks(NULL);
+}
+
+static int use_lock_unlock_profiler(void)
+{
+ struct evthread_lock_callbacks cbs = {
+ EVTHREAD_LOCK_API_VERSION,
+ EVTHREAD_LOCKTYPE_RECURSIVE,
+ trace_lock_alloc,
+ trace_lock_free,
+ trace_lock_lock,
+ trace_lock_unlock,
+ };
+ memcpy(&lu_base.cbs, evthread_get_lock_callbacks(),
+ sizeof(lu_base.cbs));
+ {
+ lock_unlock_free_thread_cbs();
+
+ evthread_set_lock_callbacks(&cbs);
+ /** re-create debug locks correctly */
+ evthread_enable_lock_debugging();
+
+ event_init();
+ }
+ return 0;
+}
+static void free_lock_unlock_profiler(struct basic_test_data *data)
+{
+ /** fix "held_by" for kqueue */
+ evthread_set_lock_callbacks(NULL);
+
+ lock_unlock_free_thread_cbs();
+ free(lu_base.locks);
+ data->base = NULL;
+}
+
+static void test_bufferevent_pair_release_lock(void *arg)
+{
+ struct basic_test_data *data = arg;
+ use_lock_unlock_profiler();
+ {
+ struct bufferevent *pair[2];
+ if (!bufferevent_pair_new(NULL, BEV_OPT_THREADSAFE, pair)) {
+ bufferevent_free(pair[0]);
+ bufferevent_free(pair[1]);
+ } else
+ tt_abort_perror("bufferevent_pair_new");
+ }
+ free_lock_unlock_profiler(data);
+end:
+ ;
+}
+#endif
+
+/*
+ * test watermarks and bufferevent
+ */
+
+static void
+wm_readcb(struct bufferevent *bev, void *arg)
+{
+ struct evbuffer *evbuf = evbuffer_new();
+ int len = (int)evbuffer_get_length(bev->input);
+ static int nread;
+
+ assert(len >= 10 && len <= 20);
+
+ assert(evbuf != NULL);
+
+ /* gratuitous test of bufferevent_read_buffer */
+ bufferevent_read_buffer(bev, evbuf);
+
+ nread += len;
+ if (nread == 65000) {
+ bufferevent_disable(bev, EV_READ);
+ test_ok++;
+ }
+
+ evbuffer_free(evbuf);
+}
+
+static void
+wm_writecb(struct bufferevent *bev, void *arg)
+{
+ assert(evbuffer_get_length(bev->output) <= 100);
+ if (evbuffer_get_length(bev->output) == 0) {
+ evbuffer_drain(bev->output, evbuffer_get_length(bev->output));
+ test_ok++;
+ }
+}
+
+static void
+wm_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ test_ok = -2;
+}
+
+static void
+test_bufferevent_watermarks_impl(int use_pair)
+{
+ struct bufferevent *bev1 = NULL, *bev2 = NULL;
+ char buffer[65000];
+ size_t low, high;
+ int i;
+ test_ok = 0;
+
+ if (use_pair) {
+ struct bufferevent *pair[2];
+ tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
+ bev1 = pair[0];
+ bev2 = pair[1];
+ bufferevent_setcb(bev1, NULL, wm_writecb, errorcb, NULL);
+ bufferevent_setcb(bev2, wm_readcb, NULL, errorcb, NULL);
+ } else {
+ bev1 = bufferevent_new(pair[0], NULL, wm_writecb, wm_errorcb, NULL);
+ bev2 = bufferevent_new(pair[1], wm_readcb, NULL, wm_errorcb, NULL);
+ }
+ tt_assert(bev1);
+ tt_assert(bev2);
+ bufferevent_disable(bev1, EV_READ);
+ bufferevent_enable(bev2, EV_READ);
+
+ /* By default, low watermarks are set to 0 */
+ bufferevent_getwatermark(bev1, EV_READ, &low, NULL);
+ tt_int_op(low, ==, 0);
+ bufferevent_getwatermark(bev2, EV_WRITE, &low, NULL);
+ tt_int_op(low, ==, 0);
+
+ for (i = 0; i < (int)sizeof(buffer); i++)
+ buffer[i] = (char)i;
+
+ /* limit the reading on the receiving bufferevent */
+ bufferevent_setwatermark(bev2, EV_READ, 10, 20);
+
+ bufferevent_getwatermark(bev2, EV_READ, &low, &high);
+ tt_int_op(low, ==, 10);
+ tt_int_op(high, ==, 20);
+
+ /* Tell the sending bufferevent not to notify us till it's down to
+ 100 bytes. */
+ bufferevent_setwatermark(bev1, EV_WRITE, 100, 2000);
+
+ bufferevent_getwatermark(bev1, EV_WRITE, &low, &high);
+ tt_int_op(low, ==, 100);
+ tt_int_op(high, ==, 2000);
+
+ {
+ int r = bufferevent_getwatermark(bev1, EV_WRITE | EV_READ, &low, &high);
+ tt_int_op(r, !=, 0);
+ }
+
+ bufferevent_write(bev1, buffer, sizeof(buffer));
+
+ event_dispatch();
+
+ tt_int_op(test_ok, ==, 2);
+
+ /* The write callback drained all the data from outbuf, so we
+ * should have removed the write event... */
+ tt_assert(!event_pending(&bev2->ev_write, EV_WRITE, NULL));
+
+end:
+ if (bev1)
+ bufferevent_free(bev1);
+ if (bev2)
+ bufferevent_free(bev2);
+}
+
+static void
+test_bufferevent_watermarks(void)
+{
+ test_bufferevent_watermarks_impl(0);
+}
+
+static void
+test_bufferevent_pair_watermarks(void)
+{
+ test_bufferevent_watermarks_impl(1);
+}
+
+/*
+ * Test bufferevent filters
+ */
+
+/* strip an 'x' from each byte */
+
+static enum bufferevent_filter_result
+bufferevent_input_filter(struct evbuffer *src, struct evbuffer *dst,
+ ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
+{
+ const unsigned char *buffer;
+ unsigned i;
+
+ buffer = evbuffer_pullup(src, evbuffer_get_length(src));
+ for (i = 0; i < evbuffer_get_length(src); i += 2) {
+ if (buffer[i] == '-')
+ continue;
+
+ assert(buffer[i] == 'x');
+ evbuffer_add(dst, buffer + i + 1, 1);
+ }
+
+ evbuffer_drain(src, i);
+ return (BEV_OK);
+}
+
+/* add an 'x' before each byte */
+
+static enum bufferevent_filter_result
+bufferevent_output_filter(struct evbuffer *src, struct evbuffer *dst,
+ ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
+{
+ const unsigned char *buffer;
+ unsigned i;
+ struct bufferevent **bevp = ctx;
+
+ ++test_ok;
+
+ if (test_ok == 1) {
+ buffer = evbuffer_pullup(src, evbuffer_get_length(src));
+ for (i = 0; i < evbuffer_get_length(src); ++i) {
+ evbuffer_add(dst, "x", 1);
+ evbuffer_add(dst, buffer + i, 1);
+ }
+ evbuffer_drain(src, evbuffer_get_length(src));
+ } else {
+ return BEV_ERROR;
+ }
+
+ if (bevp && test_ok == 1) {
+ int prev = ++test_ok;
+ bufferevent_write(*bevp, "-", 1);
+ /* check that during this bufferevent_write()
+ * bufferevent_output_filter() will not be called again */
+ assert(test_ok == prev);
+ --test_ok;
+ }
+
+ return (BEV_OK);
+}
+
+static void
+test_bufferevent_filters_impl(int use_pair, int disable)
+{
+ struct bufferevent *bev1 = NULL, *bev2 = NULL;
+ struct bufferevent *bev1_base = NULL, *bev2_base = NULL;
+ char buffer[8333];
+ int i;
+
+ test_ok = 0;
+
+ if (use_pair) {
+ struct bufferevent *pair[2];
+ tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
+ bev1 = pair[0];
+ bev2 = pair[1];
+ } else {
+ bev1 = bufferevent_socket_new(NULL, pair[0], 0);
+ bev2 = bufferevent_socket_new(NULL, pair[1], 0);
+ }
+ bev1_base = bev1;
+ bev2_base = bev2;
+
+ for (i = 0; i < (int)sizeof(buffer); i++)
+ buffer[i] = i;
+
+ bev1 = bufferevent_filter_new(bev1, NULL, bufferevent_output_filter,
+ BEV_OPT_CLOSE_ON_FREE, NULL,
+ disable ? &bev1 : NULL);
+
+ bev2 = bufferevent_filter_new(bev2, bufferevent_input_filter,
+ NULL, BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
+ bufferevent_setcb(bev1, NULL, writecb, errorcb, NULL);
+ bufferevent_setcb(bev2, readcb, NULL, errorcb, NULL);
+
+ tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev1_base);
+ tt_ptr_op(bufferevent_get_underlying(bev2), ==, bev2_base);
+ tt_int_op(bufferevent_getfd(bev1), ==, -1);
+ tt_int_op(bufferevent_getfd(bev2), ==, -1);
+
+ bufferevent_disable(bev1, EV_READ);
+ bufferevent_enable(bev2, EV_READ);
+ /* insert some filters */
+ bufferevent_write(bev1, buffer, sizeof(buffer));
+
+ event_dispatch();
+
+ if (test_ok != 3 + !!disable)
+ test_ok = 0;
+
+end:
+ if (bev1)
+ bufferevent_free(bev1);
+ if (bev2)
+ bufferevent_free(bev2);
+
+}
+
+static void test_bufferevent_filters(void)
+{ test_bufferevent_filters_impl(0, 0); }
+static void test_bufferevent_pair_filters(void)
+{ test_bufferevent_filters_impl(1, 0); }
+static void test_bufferevent_filters_disable(void)
+{ test_bufferevent_filters_impl(0, 1); }
+static void test_bufferevent_pair_filters_disable(void)
+{ test_bufferevent_filters_impl(1, 1); }
+
+
+static void
+sender_writecb(struct bufferevent *bev, void *ctx)
+{
+ if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
+ bufferevent_disable(bev,EV_READ|EV_WRITE);
+ TT_BLATHER(("Flushed %d: freeing it.", (int)bufferevent_getfd(bev)));
+ bufferevent_free(bev);
+ }
+}
+
+static void
+sender_errorcb(struct bufferevent *bev, short what, void *ctx)
+{
+ TT_FAIL(("Got sender error %d",(int)what));
+}
+
+static int bufferevent_connect_test_flags = 0;
+static int bufferevent_trigger_test_flags = 0;
+static int n_strings_read = 0;
+static int n_reads_invoked = 0;
+static int n_events_invoked = 0;
+
+#define TEST_STR "Now is the time for all good events to signal for " \
+ "the good of their protocol"
+static void
+listen_cb(struct evconnlistener *listener, evutil_socket_t fd,
+ struct sockaddr *sa, int socklen, void *arg)
+{
+ struct event_base *base = arg;
+ struct bufferevent *bev;
+ const char s[] = TEST_STR;
+ TT_BLATHER(("Got a request on socket %d", (int)fd ));
+ bev = bufferevent_socket_new(base, fd, bufferevent_connect_test_flags);
+ tt_assert(bev);
+ bufferevent_setcb(bev, NULL, sender_writecb, sender_errorcb, NULL);
+ bufferevent_write(bev, s, sizeof(s));
+end:
+ ;
+}
+
+static int
+fake_listener_create(struct sockaddr_in *localhost)
+{
+ struct sockaddr *sa = (struct sockaddr *)localhost;
+ evutil_socket_t fd = -1;
+ ev_socklen_t slen = sizeof(*localhost);
+
+ memset(localhost, 0, sizeof(*localhost));
+ localhost->sin_port = 0; /* have the kernel pick a port */
+ localhost->sin_addr.s_addr = htonl(0x7f000001L);
+ localhost->sin_family = AF_INET;
+
+ /* bind, but don't listen or accept. should trigger
+ "Connection refused" reliably on most platforms. */
+ fd = socket(localhost->sin_family, SOCK_STREAM, 0);
+ tt_assert(fd >= 0);
+ tt_assert(bind(fd, sa, slen) == 0);
+ tt_assert(getsockname(fd, sa, &slen) == 0);
+
+ return fd;
+
+end:
+ return -1;
+}
+
+static void
+reader_eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+ struct event_base *base = ctx;
+ if (what & BEV_EVENT_ERROR) {
+ perror("foobar");
+ TT_FAIL(("got connector error %d", (int)what));
+ return;
+ }
+ if (what & BEV_EVENT_CONNECTED) {
+ TT_BLATHER(("connected on %d", (int)bufferevent_getfd(bev)));
+ bufferevent_enable(bev, EV_READ);
+ }
+ if (what & BEV_EVENT_EOF) {
+ char buf[512];
+ size_t n;
+ n = bufferevent_read(bev, buf, sizeof(buf)-1);
+ tt_int_op(n, >=, 0);
+ buf[n] = '\0';
+ tt_str_op(buf, ==, TEST_STR);
+ if (++n_strings_read == 2)
+ event_base_loopexit(base, NULL);
+ TT_BLATHER(("EOF on %d: %d strings read.",
+ (int)bufferevent_getfd(bev), n_strings_read));
+ }
+end:
+ ;
+}
+
+static void
+reader_eventcb_simple(struct bufferevent *bev, short what, void *ctx)
+{
+ TT_BLATHER(("Read eventcb simple invoked on %d.",
+ (int)bufferevent_getfd(bev)));
+ n_events_invoked++;
+}
+
+static void
+reader_readcb(struct bufferevent *bev, void *ctx)
+{
+ TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev)));
+ n_reads_invoked++;
+}
+
+static void
+test_bufferevent_connect(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct evconnlistener *lev=NULL;
+ struct bufferevent *bev1=NULL, *bev2=NULL;
+ struct sockaddr_in localhost;
+ struct sockaddr_storage ss;
+ struct sockaddr *sa;
+ ev_socklen_t slen;
+
+ int be_flags=BEV_OPT_CLOSE_ON_FREE;
+
+ if (strstr((char*)data->setup_data, "defer")) {
+ be_flags |= BEV_OPT_DEFER_CALLBACKS;
+ }
+ if (strstr((char*)data->setup_data, "unlocked")) {
+ be_flags |= BEV_OPT_UNLOCK_CALLBACKS;
+ }
+ if (strstr((char*)data->setup_data, "lock")) {
+ be_flags |= BEV_OPT_THREADSAFE;
+ }
+ bufferevent_connect_test_flags = be_flags;
+#ifdef _WIN32
+ if (!strcmp((char*)data->setup_data, "unset_connectex")) {
+ struct win32_extension_fns *ext =
+ (struct win32_extension_fns *)
+ event_get_win32_extension_fns_();
+ ext->ConnectEx = NULL;
+ }
+#endif
+
+ memset(&localhost, 0, sizeof(localhost));
+
+ localhost.sin_port = 0; /* pick-a-port */
+ localhost.sin_addr.s_addr = htonl(0x7f000001L);
+ localhost.sin_family = AF_INET;
+ sa = (struct sockaddr *)&localhost;
+ lev = evconnlistener_new_bind(data->base, listen_cb, data->base,
+ LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
+ 16, sa, sizeof(localhost));
+ tt_assert(lev);
+
+ sa = (struct sockaddr *)&ss;
+ slen = sizeof(ss);
+ if (regress_get_listener_addr(lev, sa, &slen) < 0) {
+ tt_abort_perror("getsockname");
+ }
+
+ tt_assert(!evconnlistener_enable(lev));
+ bev1 = bufferevent_socket_new(data->base, -1, be_flags);
+ bev2 = bufferevent_socket_new(data->base, -1, be_flags);
+ tt_assert(bev1);
+ tt_assert(bev2);
+ bufferevent_setcb(bev1, reader_readcb,NULL, reader_eventcb, data->base);
+ bufferevent_setcb(bev2, reader_readcb,NULL, reader_eventcb, data->base);
+
+ bufferevent_enable(bev1, EV_READ);
+ bufferevent_enable(bev2, EV_READ);
+
+ tt_want(!bufferevent_socket_connect(bev1, sa, sizeof(localhost)));
+ tt_want(!bufferevent_socket_connect(bev2, sa, sizeof(localhost)));
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(n_strings_read, ==, 2);
+ tt_int_op(n_reads_invoked, >=, 2);
+end:
+ if (lev)
+ evconnlistener_free(lev);
+
+ if (bev1)
+ bufferevent_free(bev1);
+
+ if (bev2)
+ bufferevent_free(bev2);
+}
+
+static void
+test_bufferevent_connect_fail_eventcb(void *arg)
+{
+ struct basic_test_data *data = arg;
+ int flags = BEV_OPT_CLOSE_ON_FREE | (long)data->setup_data;
+ struct bufferevent *bev = NULL;
+ struct evconnlistener *lev = NULL;
+ struct sockaddr_in localhost;
+ ev_socklen_t slen = sizeof(localhost);
+ evutil_socket_t fake_listener = -1;
+
+ fake_listener = fake_listener_create(&localhost);
+
+ tt_int_op(n_events_invoked, ==, 0);
+
+ bev = bufferevent_socket_new(data->base, -1, flags);
+ tt_assert(bev);
+ bufferevent_setcb(bev, reader_readcb, reader_readcb,
+ reader_eventcb_simple, data->base);
+ bufferevent_enable(bev, EV_READ|EV_WRITE);
+ tt_int_op(n_events_invoked, ==, 0);
+ tt_int_op(n_reads_invoked, ==, 0);
+ /** @see also test_bufferevent_connect_fail() */
+ bufferevent_socket_connect(bev, (struct sockaddr *)&localhost, slen);
+ tt_int_op(n_events_invoked, ==, 0);
+ tt_int_op(n_reads_invoked, ==, 0);
+ event_base_dispatch(data->base);
+ tt_int_op(n_events_invoked, ==, 1);
+ tt_int_op(n_reads_invoked, ==, 0);
+
+end:
+ if (lev)
+ evconnlistener_free(lev);
+ if (bev)
+ bufferevent_free(bev);
+ if (fake_listener >= 0)
+ evutil_closesocket(fake_listener);
+}
+
+static void
+want_fail_eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+ struct event_base *base = ctx;
+ const char *err;
+ evutil_socket_t s;
+
+ if (what & BEV_EVENT_ERROR) {
+ s = bufferevent_getfd(bev);
+ err = evutil_socket_error_to_string(evutil_socket_geterror(s));
+ TT_BLATHER(("connection failure on "EV_SOCK_FMT": %s",
+ EV_SOCK_ARG(s), err));
+ test_ok = 1;
+ } else {
+ TT_FAIL(("didn't fail? what %hd", what));
+ }
+
+ event_base_loopexit(base, NULL);
+}
+
+static void
+close_socket_cb(evutil_socket_t fd, short what, void *arg)
+{
+ evutil_socket_t *fdp = arg;
+ if (*fdp >= 0) {
+ evutil_closesocket(*fdp);
+ *fdp = -1;
+ }
+}
+
+static void
+test_bufferevent_connect_fail(void *arg)
+{
+ struct basic_test_data *data = (struct basic_test_data *)arg;
+ struct bufferevent *bev=NULL;
+ struct event close_listener_event;
+ int close_listener_event_added = 0;
+ struct timeval one_second = { 1, 0 };
+ struct sockaddr_in localhost;
+ ev_socklen_t slen = sizeof(localhost);
+ evutil_socket_t fake_listener = -1;
+ int r;
+
+ test_ok = 0;
+
+ fake_listener = fake_listener_create(&localhost);
+ bev = bufferevent_socket_new(data->base, -1,
+ BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
+ tt_assert(bev);
+ bufferevent_setcb(bev, NULL, NULL, want_fail_eventcb, data->base);
+
+ r = bufferevent_socket_connect(bev, (struct sockaddr *)&localhost, slen);
+ /* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells
+ * detects the error immediately, which is not really wrong of it. */
+ tt_want(r == 0 || r == -1);
+
+ /* Close the listener socket after a second. This should trigger
+ "connection refused" on some other platforms, including OSX. */
+ evtimer_assign(&close_listener_event, data->base, close_socket_cb,
+ &fake_listener);
+ event_add(&close_listener_event, &one_second);
+ close_listener_event_added = 1;
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 1);
+
+end:
+ if (fake_listener >= 0)
+ evutil_closesocket(fake_listener);
+
+ if (bev)
+ bufferevent_free(bev);
+
+ if (close_listener_event_added)
+ event_del(&close_listener_event);
+}
+
+struct timeout_cb_result {
+ struct timeval read_timeout_at;
+ struct timeval write_timeout_at;
+ struct timeval last_wrote_at;
+ int n_read_timeouts;
+ int n_write_timeouts;
+ int total_calls;
+};
+
+static void
+bev_timeout_write_cb(struct bufferevent *bev, void *arg)
+{
+ struct timeout_cb_result *res = arg;
+ evutil_gettimeofday(&res->last_wrote_at, NULL);
+}
+
+static void
+bev_timeout_event_cb(struct bufferevent *bev, short what, void *arg)
+{
+ struct timeout_cb_result *res = arg;
+ ++res->total_calls;
+
+ if ((what & (BEV_EVENT_READING|BEV_EVENT_TIMEOUT))
+ == (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) {
+ evutil_gettimeofday(&res->read_timeout_at, NULL);
+ ++res->n_read_timeouts;
+ }
+ if ((what & (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT))
+ == (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) {
+ evutil_gettimeofday(&res->write_timeout_at, NULL);
+ ++res->n_write_timeouts;
+ }
+}
+
+static void
+test_bufferevent_timeouts(void *arg)
+{
+ /* "arg" is a string containing "pair" and/or "filter". */
+ struct bufferevent *bev1 = NULL, *bev2 = NULL;
+ struct basic_test_data *data = arg;
+ int use_pair = 0, use_filter = 0;
+ struct timeval tv_w, tv_r, started_at;
+ struct timeout_cb_result res1, res2;
+ char buf[1024];
+
+ memset(&res1, 0, sizeof(res1));
+ memset(&res2, 0, sizeof(res2));
+
+ if (strstr((char*)data->setup_data, "pair"))
+ use_pair = 1;
+ if (strstr((char*)data->setup_data, "filter"))
+ use_filter = 1;
+
+ if (use_pair) {
+ struct bufferevent *p[2];
+ tt_int_op(0, ==, bufferevent_pair_new(data->base, 0, p));
+ bev1 = p[0];
+ bev2 = p[1];
+ } else {
+ bev1 = bufferevent_socket_new(data->base, data->pair[0], 0);
+ bev2 = bufferevent_socket_new(data->base, data->pair[1], 0);
+ }
+
+ tt_assert(bev1);
+ tt_assert(bev2);
+
+ if (use_filter) {
+ struct bufferevent *bevf1, *bevf2;
+ bevf1 = bufferevent_filter_new(bev1, NULL, NULL,
+ BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
+ bevf2 = bufferevent_filter_new(bev2, NULL, NULL,
+ BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
+ tt_assert(bevf1);
+ tt_assert(bevf2);
+ bev1 = bevf1;
+ bev2 = bevf2;
+ }
+
+ /* Do this nice and early. */
+ bufferevent_disable(bev2, EV_READ);
+
+ /* bev1 will try to write and read. Both will time out. */
+ evutil_gettimeofday(&started_at, NULL);
+ tv_w.tv_sec = tv_r.tv_sec = 0;
+ tv_w.tv_usec = 100*1000;
+ tv_r.tv_usec = 150*1000;
+ bufferevent_setcb(bev1, NULL, bev_timeout_write_cb,
+ bev_timeout_event_cb, &res1);
+ bufferevent_setwatermark(bev1, EV_WRITE, 1024*1024+10, 0);
+ bufferevent_set_timeouts(bev1, &tv_r, &tv_w);
+ if (use_pair) {
+ /* For a pair, the fact that the other side isn't reading
+ * makes the writer stall */
+ bufferevent_write(bev1, "ABCDEFG", 7);
+ } else {
+ /* For a real socket, the kernel's TCP buffers can eat a
+ * fair number of bytes; make sure that at some point we
+ * have some bytes that will stall. */
+ struct evbuffer *output = bufferevent_get_output(bev1);
+ int i;
+ memset(buf, 0xbb, sizeof(buf));
+ for (i=0;i<1024;++i) {
+ evbuffer_add_reference(output, buf, sizeof(buf),
+ NULL, NULL);
+ }
+ }
+ bufferevent_enable(bev1, EV_READ|EV_WRITE);
+
+ /* bev2 has nothing to say, and isn't listening. */
+ bufferevent_setcb(bev2, NULL, bev_timeout_write_cb,
+ bev_timeout_event_cb, &res2);
+ tv_w.tv_sec = tv_r.tv_sec = 0;
+ tv_w.tv_usec = 200*1000;
+ tv_r.tv_usec = 100*1000;
+ bufferevent_set_timeouts(bev2, &tv_r, &tv_w);
+ bufferevent_enable(bev2, EV_WRITE);
+
+ tv_r.tv_sec = 0;
+ tv_r.tv_usec = 350000;
+
+ event_base_loopexit(data->base, &tv_r);
+ event_base_dispatch(data->base);
+
+ /* XXXX Test that actually reading or writing a little resets the
+ * timeouts. */
+
+ /* Each buf1 timeout happens, and happens only once. */
+ tt_want(res1.n_read_timeouts);
+ tt_want(res1.n_write_timeouts);
+ tt_want(res1.n_read_timeouts == 1);
+ tt_want(res1.n_write_timeouts == 1);
+
+ test_timeval_diff_eq(&started_at, &res1.read_timeout_at, 150);
+ test_timeval_diff_eq(&started_at, &res1.write_timeout_at, 100);
+
+end:
+ if (bev1)
+ bufferevent_free(bev1);
+ if (bev2)
+ bufferevent_free(bev2);
+}
+
+static void
+trigger_failure_cb(evutil_socket_t fd, short what, void *ctx)
+{
+ TT_FAIL(("The triggered callback did not fire or the machine is really slow (try increasing timeout)."));
+}
+
+static void
+trigger_eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+ struct event_base *base = ctx;
+ if (what == ~0) {
+ TT_BLATHER(("Event successfully triggered."));
+ event_base_loopexit(base, NULL);
+ return;
+ }
+ reader_eventcb(bev, what, ctx);
+}
+
+static void
+trigger_readcb_triggered(struct bufferevent *bev, void *ctx)
+{
+ TT_BLATHER(("Read successfully triggered."));
+ n_reads_invoked++;
+ bufferevent_trigger_event(bev, ~0, bufferevent_trigger_test_flags);
+}
+
+static void
+trigger_readcb(struct bufferevent *bev, void *ctx)
+{
+ struct timeval timeout = { 30, 0 };
+ struct event_base *base = ctx;
+ size_t low, high, len;
+ int expected_reads;
+
+ TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev)));
+ expected_reads = ++n_reads_invoked;
+
+ bufferevent_setcb(bev, trigger_readcb_triggered, NULL, trigger_eventcb, ctx);
+
+ bufferevent_getwatermark(bev, EV_READ, &low, &high);
+ len = evbuffer_get_length(bufferevent_get_input(bev));
+
+ bufferevent_setwatermark(bev, EV_READ, len + 1, 0);
+ bufferevent_trigger(bev, EV_READ, bufferevent_trigger_test_flags);
+ /* no callback expected */
+ tt_int_op(n_reads_invoked, ==, expected_reads);
+
+ if ((bufferevent_trigger_test_flags & BEV_TRIG_DEFER_CALLBACKS) ||
+ (bufferevent_connect_test_flags & BEV_OPT_DEFER_CALLBACKS)) {
+ /* will be deferred */
+ } else {
+ expected_reads++;
+ }
+
+ event_base_once(base, -1, EV_TIMEOUT, trigger_failure_cb, NULL, &timeout);
+
+ bufferevent_trigger(bev, EV_READ,
+ bufferevent_trigger_test_flags | BEV_TRIG_IGNORE_WATERMARKS);
+ tt_int_op(n_reads_invoked, ==, expected_reads);
+
+ bufferevent_setwatermark(bev, EV_READ, low, high);
+end:
+ ;
+}
+
+static void
+test_bufferevent_trigger(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct evconnlistener *lev=NULL;
+ struct bufferevent *bev=NULL;
+ struct sockaddr_in localhost;
+ struct sockaddr_storage ss;
+ struct sockaddr *sa;
+ ev_socklen_t slen;
+
+ int be_flags=BEV_OPT_CLOSE_ON_FREE;
+ int trig_flags=0;
+
+ if (strstr((char*)data->setup_data, "defer")) {
+ be_flags |= BEV_OPT_DEFER_CALLBACKS;
+ }
+ bufferevent_connect_test_flags = be_flags;
+
+ if (strstr((char*)data->setup_data, "postpone")) {
+ trig_flags |= BEV_TRIG_DEFER_CALLBACKS;
+ }
+ bufferevent_trigger_test_flags = trig_flags;
+
+ memset(&localhost, 0, sizeof(localhost));
+
+ localhost.sin_port = 0; /* pick-a-port */
+ localhost.sin_addr.s_addr = htonl(0x7f000001L);
+ localhost.sin_family = AF_INET;
+ sa = (struct sockaddr *)&localhost;
+ lev = evconnlistener_new_bind(data->base, listen_cb, data->base,
+ LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
+ 16, sa, sizeof(localhost));
+ tt_assert(lev);
+
+ sa = (struct sockaddr *)&ss;
+ slen = sizeof(ss);
+ if (regress_get_listener_addr(lev, sa, &slen) < 0) {
+ tt_abort_perror("getsockname");
+ }
+
+ tt_assert(!evconnlistener_enable(lev));
+ bev = bufferevent_socket_new(data->base, -1, be_flags);
+ tt_assert(bev);
+ bufferevent_setcb(bev, trigger_readcb, NULL, trigger_eventcb, data->base);
+
+ bufferevent_enable(bev, EV_READ);
+
+ tt_want(!bufferevent_socket_connect(bev, sa, sizeof(localhost)));
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(n_reads_invoked, ==, 2);
+end:
+ if (lev)
+ evconnlistener_free(lev);
+
+ if (bev)
+ bufferevent_free(bev);
+}
+
+static void
+test_bufferevent_socket_filter_inactive(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev = NULL, *bevf = NULL;
+
+ bev = bufferevent_socket_new(data->base, -1, 0);
+ tt_assert(bev);
+ bevf = bufferevent_filter_new(bev, NULL, NULL, 0, NULL, NULL);
+ tt_assert(bevf);
+
+end:
+ if (bevf)
+ bufferevent_free(bevf);
+ if (bev)
+ bufferevent_free(bev);
+}
+
+static void
+pair_flush_eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+ int *callback_what = ctx;
+ *callback_what = what;
+}
+
+static void
+test_bufferevent_pair_flush(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *pair[2];
+ struct bufferevent *bev1 = NULL;
+ struct bufferevent *bev2 = NULL;
+ int callback_what = 0;
+
+ tt_assert(0 == bufferevent_pair_new(data->base, 0, pair));
+ bev1 = pair[0];
+ bev2 = pair[1];
+ tt_assert(0 == bufferevent_enable(bev1, EV_WRITE));
+ tt_assert(0 == bufferevent_enable(bev2, EV_READ));
+
+ bufferevent_setcb(bev2, NULL, NULL, pair_flush_eventcb, &callback_what);
+
+ bufferevent_flush(bev1, EV_WRITE, BEV_FINISHED);
+
+ event_base_loop(data->base, EVLOOP_ONCE);
+
+ tt_assert(callback_what == (BEV_EVENT_READING | BEV_EVENT_EOF));
+
+end:
+ if (bev1)
+ bufferevent_free(bev1);
+ if (bev2)
+ bufferevent_free(bev2);
+}
+
+struct bufferevent_filter_data_stuck {
+ size_t header_size;
+ size_t total_read;
+};
+
+static void
+bufferevent_filter_data_stuck_readcb(struct bufferevent *bev, void *arg)
+{
+ struct bufferevent_filter_data_stuck *filter_data = arg;
+ struct evbuffer *input = bufferevent_get_input(bev);
+ size_t read_size = evbuffer_get_length(input);
+ evbuffer_drain(input, read_size);
+ filter_data->total_read += read_size;
+}
+
+/**
+ * This filter prepends header once before forwarding data.
+ */
+static enum bufferevent_filter_result
+bufferevent_filter_data_stuck_inputcb(
+ struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit,
+ enum bufferevent_flush_mode mode, void *ctx)
+{
+ struct bufferevent_filter_data_stuck *filter_data = ctx;
+ static int header_inserted = 0;
+ size_t payload_size;
+ size_t header_size = 0;
+
+ if (!header_inserted) {
+ char *header = calloc(filter_data->header_size, 1);
+ evbuffer_add(dst, header, filter_data->header_size);
+ free(header);
+ header_size = filter_data->header_size;
+ header_inserted = 1;
+ }
+
+ payload_size = evbuffer_get_length(src);
+ if (payload_size > dst_limit - header_size) {
+ payload_size = dst_limit - header_size;
+ }
+
+ tt_int_op(payload_size, ==, evbuffer_remove_buffer(src, dst, payload_size));
+
+end:
+ return BEV_OK;
+}
+
+static void
+test_bufferevent_filter_data_stuck(void *arg)
+{
+ const size_t read_high_wm = 4096;
+ struct bufferevent_filter_data_stuck filter_data;
+ struct basic_test_data *data = arg;
+ struct bufferevent *pair[2];
+ struct bufferevent *filter = NULL;
+
+ int options = BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS;
+
+ char payload[4096];
+ int payload_size = sizeof(payload);
+
+ memset(&filter_data, 0, sizeof(filter_data));
+ filter_data.header_size = 20;
+
+ tt_assert(bufferevent_pair_new(data->base, options, pair) == 0);
+
+ bufferevent_setwatermark(pair[0], EV_READ, 0, read_high_wm);
+ bufferevent_setwatermark(pair[1], EV_READ, 0, read_high_wm);
+
+ tt_assert(
+ filter =
+ bufferevent_filter_new(pair[1],
+ bufferevent_filter_data_stuck_inputcb,
+ NULL,
+ options,
+ NULL,
+ &filter_data));
+
+ bufferevent_setcb(filter,
+ bufferevent_filter_data_stuck_readcb,
+ NULL,
+ NULL,
+ &filter_data);
+
+ tt_assert(bufferevent_enable(filter, EV_READ|EV_WRITE) == 0);
+
+ bufferevent_setwatermark(filter, EV_READ, 0, read_high_wm);
+
+ tt_assert(bufferevent_write(pair[0], payload, sizeof(payload)) == 0);
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(filter_data.total_read, ==, payload_size + filter_data.header_size);
+end:
+ if (pair[0])
+ bufferevent_free(pair[0]);
+ if (filter)
+ bufferevent_free(filter);
+}
+
+struct testcase_t bufferevent_testcases[] = {
+
+ LEGACY(bufferevent, TT_ISOLATED),
+ LEGACY(bufferevent_pair, TT_ISOLATED),
+ LEGACY(bufferevent_flush_normal, TT_ISOLATED),
+ LEGACY(bufferevent_flush_flush, TT_ISOLATED),
+ LEGACY(bufferevent_flush_finished, TT_ISOLATED),
+ LEGACY(bufferevent_pair_flush_normal, TT_ISOLATED),
+ LEGACY(bufferevent_pair_flush_flush, TT_ISOLATED),
+ LEGACY(bufferevent_pair_flush_finished, TT_ISOLATED),
+#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
+ { "bufferevent_pair_release_lock", test_bufferevent_pair_release_lock,
+ TT_FORK|TT_ISOLATED|TT_NEED_THREADS|TT_NEED_BASE|TT_LEGACY,
+ &basic_setup, NULL },
+#endif
+ LEGACY(bufferevent_watermarks, TT_ISOLATED),
+ LEGACY(bufferevent_pair_watermarks, TT_ISOLATED),
+ LEGACY(bufferevent_filters, TT_ISOLATED),
+ LEGACY(bufferevent_pair_filters, TT_ISOLATED),
+ LEGACY(bufferevent_filters_disable, TT_ISOLATED),
+ LEGACY(bufferevent_pair_filters_disable, TT_ISOLATED),
+ { "bufferevent_connect", test_bufferevent_connect, TT_FORK|TT_NEED_BASE,
+ &basic_setup, (void*)"" },
+ { "bufferevent_connect_defer", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" },
+ { "bufferevent_connect_lock", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, (void*)"lock" },
+ { "bufferevent_connect_lock_defer", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
+ (void*)"defer lock" },
+ { "bufferevent_connect_unlocked_cbs", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
+ (void*)"lock defer unlocked" },
+ { "bufferevent_connect_fail", test_bufferevent_connect_fail,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "bufferevent_timeout", test_bufferevent_timeouts,
+ TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, (void*)"" },
+ { "bufferevent_timeout_pair", test_bufferevent_timeouts,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"pair" },
+ { "bufferevent_timeout_filter", test_bufferevent_timeouts,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter" },
+ { "bufferevent_timeout_filter_pair", test_bufferevent_timeouts,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter pair" },
+ { "bufferevent_trigger", test_bufferevent_trigger, TT_FORK|TT_NEED_BASE,
+ &basic_setup, (void*)"" },
+ { "bufferevent_trigger_defer", test_bufferevent_trigger,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" },
+ { "bufferevent_trigger_postpone", test_bufferevent_trigger,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
+ (void*)"postpone" },
+ { "bufferevent_trigger_defer_postpone", test_bufferevent_trigger,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
+ (void*)"defer postpone" },
+#ifdef EVENT__HAVE_LIBZ
+ LEGACY(bufferevent_zlib, TT_ISOLATED),
+#else
+ { "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL },
+#endif
+
+ { "bufferevent_connect_fail_eventcb_defer",
+ test_bufferevent_connect_fail_eventcb,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (void*)BEV_OPT_DEFER_CALLBACKS },
+ { "bufferevent_connect_fail_eventcb",
+ test_bufferevent_connect_fail_eventcb,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+
+ { "bufferevent_socket_filter_inactive",
+ test_bufferevent_socket_filter_inactive,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "bufferevent_pair_flush",
+ test_bufferevent_pair_flush,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "bufferevent_filter_data_stuck",
+ test_bufferevent_filter_data_stuck,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+
+ END_OF_TESTCASES,
+};
+
+struct testcase_t bufferevent_iocp_testcases[] = {
+
+ LEGACY(bufferevent, TT_ISOLATED|TT_ENABLE_IOCP),
+ LEGACY(bufferevent_flush_normal, TT_ISOLATED),
+ LEGACY(bufferevent_flush_flush, TT_ISOLATED),
+ LEGACY(bufferevent_flush_finished, TT_ISOLATED),
+ LEGACY(bufferevent_watermarks, TT_ISOLATED|TT_ENABLE_IOCP),
+ LEGACY(bufferevent_filters, TT_ISOLATED|TT_ENABLE_IOCP),
+ LEGACY(bufferevent_filters_disable, TT_ISOLATED|TT_ENABLE_IOCP),
+ { "bufferevent_connect", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"" },
+ { "bufferevent_connect_defer", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"defer" },
+ { "bufferevent_connect_lock", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup,
+ (void*)"lock" },
+ { "bufferevent_connect_lock_defer", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup,
+ (void*)"defer lock" },
+ { "bufferevent_connect_fail", test_bufferevent_connect_fail,
+ TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
+ { "bufferevent_connect_nonblocking", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup,
+ (void*)"unset_connectex" },
+
+ { "bufferevent_connect_fail_eventcb_defer",
+ test_bufferevent_connect_fail_eventcb,
+ TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup,
+ (void*)BEV_OPT_DEFER_CALLBACKS },
+ { "bufferevent_connect_fail_eventcb",
+ test_bufferevent_connect_fail_eventcb,
+ TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
+
+ END_OF_TESTCASES,
+};
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_dns.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_dns.c
new file mode 100644
index 000000000..11c015c50
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_dns.c
@@ -0,0 +1,2172 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "../util-internal.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#endif
+#ifdef EVENT__HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event2/dns.h"
+#include "event2/dns_compat.h"
+#include "event2/dns_struct.h"
+#include "event2/event.h"
+#include "event2/event_compat.h"
+#include "event2/event_struct.h"
+#include "event2/util.h"
+#include "event2/listener.h"
+#include "event2/bufferevent.h"
+#include "log-internal.h"
+#include "regress.h"
+#include "regress_testutils.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+static int dns_ok = 0;
+static int dns_got_cancel = 0;
+static int dns_err = 0;
+
+
+static void
+dns_gethostbyname_cb(int result, char type, int count, int ttl,
+ void *addresses, void *arg)
+{
+ dns_ok = dns_err = 0;
+
+ if (result == DNS_ERR_TIMEOUT) {
+ printf("[Timed out] ");
+ dns_err = result;
+ goto out;
+ }
+
+ if (result != DNS_ERR_NONE) {
+ printf("[Error code %d] ", result);
+ goto out;
+ }
+
+ TT_BLATHER(("type: %d, count: %d, ttl: %d: ", type, count, ttl));
+
+ switch (type) {
+ case DNS_IPv6_AAAA: {
+#if defined(EVENT__HAVE_STRUCT_IN6_ADDR) && defined(EVENT__HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN)
+ struct in6_addr *in6_addrs = addresses;
+ char buf[INET6_ADDRSTRLEN+1];
+ int i;
+ /* a resolution that's not valid does not help */
+ if (ttl < 0)
+ goto out;
+ for (i = 0; i < count; ++i) {
+ const char *b = evutil_inet_ntop(AF_INET6, &in6_addrs[i], buf,sizeof(buf));
+ if (b)
+ TT_BLATHER(("%s ", b));
+ else
+ TT_BLATHER(("%s ", strerror(errno)));
+ }
+#endif
+ break;
+ }
+ case DNS_IPv4_A: {
+ struct in_addr *in_addrs = addresses;
+ int i;
+ /* a resolution that's not valid does not help */
+ if (ttl < 0)
+ goto out;
+ for (i = 0; i < count; ++i)
+ TT_BLATHER(("%s ", inet_ntoa(in_addrs[i])));
+ break;
+ }
+ case DNS_PTR:
+ /* may get at most one PTR */
+ if (count != 1)
+ goto out;
+
+ TT_BLATHER(("%s ", *(char **)addresses));
+ break;
+ default:
+ goto out;
+ }
+
+ dns_ok = type;
+
+out:
+ if (arg == NULL)
+ event_loopexit(NULL);
+ else
+ event_base_loopexit((struct event_base *)arg, NULL);
+}
+
+static void
+dns_gethostbyname(void)
+{
+ dns_ok = 0;
+ evdns_resolve_ipv4("www.monkey.org", 0, dns_gethostbyname_cb, NULL);
+ event_dispatch();
+
+ tt_int_op(dns_ok, ==, DNS_IPv4_A);
+ test_ok = dns_ok;
+end:
+ ;
+}
+
+static void
+dns_gethostbyname6(void)
+{
+ dns_ok = 0;
+ evdns_resolve_ipv6("www.ietf.org", 0, dns_gethostbyname_cb, NULL);
+ event_dispatch();
+
+ if (!dns_ok && dns_err == DNS_ERR_TIMEOUT) {
+ tt_skip();
+ }
+
+ tt_int_op(dns_ok, ==, DNS_IPv6_AAAA);
+ test_ok = 1;
+end:
+ ;
+}
+
+static void
+dns_gethostbyaddr(void)
+{
+ struct in_addr in;
+ in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */
+ dns_ok = 0;
+ evdns_resolve_reverse(&in, 0, dns_gethostbyname_cb, NULL);
+ event_dispatch();
+
+ tt_int_op(dns_ok, ==, DNS_PTR);
+ test_ok = dns_ok;
+end:
+ ;
+}
+
+static void
+dns_resolve_reverse(void *ptr)
+{
+ struct in_addr in;
+ struct event_base *base = event_base_new();
+ struct evdns_base *dns = evdns_base_new(base, 1/* init name servers */);
+ struct evdns_request *req = NULL;
+
+ tt_assert(base);
+ tt_assert(dns);
+ in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */
+ dns_ok = 0;
+
+ req = evdns_base_resolve_reverse(
+ dns, &in, 0, dns_gethostbyname_cb, base);
+ tt_assert(req);
+
+ event_base_dispatch(base);
+
+ tt_int_op(dns_ok, ==, DNS_PTR);
+
+end:
+ if (dns)
+ evdns_base_free(dns, 0);
+ if (base)
+ event_base_free(base);
+}
+
+static int n_server_responses = 0;
+
+static void
+dns_server_request_cb(struct evdns_server_request *req, void *data)
+{
+ int i, r;
+ const char TEST_ARPA[] = "11.11.168.192.in-addr.arpa";
+ const char TEST_IN6[] =
+ "f.e.f.e." "0.0.0.0." "0.0.0.0." "1.1.1.1."
+ "a.a.a.a." "0.0.0.0." "0.0.0.0." "0.f.f.f.ip6.arpa";
+
+ for (i = 0; i < req->nquestions; ++i) {
+ const int qtype = req->questions[i]->type;
+ const int qclass = req->questions[i]->dns_question_class;
+ const char *qname = req->questions[i]->name;
+
+ struct in_addr ans;
+ ans.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */
+ if (qtype == EVDNS_TYPE_A &&
+ qclass == EVDNS_CLASS_INET &&
+ !evutil_ascii_strcasecmp(qname, "zz.example.com")) {
+ r = evdns_server_request_add_a_reply(req, qname,
+ 1, &ans.s_addr, 12345);
+ if (r<0)
+ dns_ok = 0;
+ } else if (qtype == EVDNS_TYPE_AAAA &&
+ qclass == EVDNS_CLASS_INET &&
+ !evutil_ascii_strcasecmp(qname, "zz.example.com")) {
+ char addr6[17] = "abcdefghijklmnop";
+ r = evdns_server_request_add_aaaa_reply(req,
+ qname, 1, addr6, 123);
+ if (r<0)
+ dns_ok = 0;
+ } else if (qtype == EVDNS_TYPE_PTR &&
+ qclass == EVDNS_CLASS_INET &&
+ !evutil_ascii_strcasecmp(qname, TEST_ARPA)) {
+ r = evdns_server_request_add_ptr_reply(req, NULL,
+ qname, "ZZ.EXAMPLE.COM", 54321);
+ if (r<0)
+ dns_ok = 0;
+ } else if (qtype == EVDNS_TYPE_PTR &&
+ qclass == EVDNS_CLASS_INET &&
+ !evutil_ascii_strcasecmp(qname, TEST_IN6)){
+ r = evdns_server_request_add_ptr_reply(req, NULL,
+ qname,
+ "ZZ-INET6.EXAMPLE.COM", 54322);
+ if (r<0)
+ dns_ok = 0;
+ } else if (qtype == EVDNS_TYPE_A &&
+ qclass == EVDNS_CLASS_INET &&
+ !evutil_ascii_strcasecmp(qname, "drop.example.com")) {
+ if (evdns_server_request_drop(req)<0)
+ dns_ok = 0;
+ return;
+ } else {
+ printf("Unexpected question %d %d \"%s\" ",
+ qtype, qclass, qname);
+ dns_ok = 0;
+ }
+ }
+ r = evdns_server_request_respond(req, 0);
+ if (r<0) {
+ printf("Couldn't send reply. ");
+ dns_ok = 0;
+ }
+}
+
+static void
+dns_server_gethostbyname_cb(int result, char type, int count, int ttl,
+ void *addresses, void *arg)
+{
+ if (result == DNS_ERR_CANCEL) {
+ if (arg != (void*)(char*)90909) {
+ printf("Unexpected cancelation");
+ dns_ok = 0;
+ }
+ dns_got_cancel = 1;
+ goto out;
+ }
+ if (result != DNS_ERR_NONE) {
+ printf("Unexpected result %d. ", result);
+ dns_ok = 0;
+ goto out;
+ }
+ if (count != 1) {
+ printf("Unexpected answer count %d. ", count);
+ dns_ok = 0;
+ goto out;
+ }
+ switch (type) {
+ case DNS_IPv4_A: {
+ struct in_addr *in_addrs = addresses;
+ if (in_addrs[0].s_addr != htonl(0xc0a80b0bUL) || ttl != 12345) {
+ printf("Bad IPv4 response \"%s\" %d. ",
+ inet_ntoa(in_addrs[0]), ttl);
+ dns_ok = 0;
+ goto out;
+ }
+ break;
+ }
+ case DNS_IPv6_AAAA: {
+#if defined (EVENT__HAVE_STRUCT_IN6_ADDR) && defined(EVENT__HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN)
+ struct in6_addr *in6_addrs = addresses;
+ char buf[INET6_ADDRSTRLEN+1];
+ if (memcmp(&in6_addrs[0].s6_addr, "abcdefghijklmnop", 16)
+ || ttl != 123) {
+ const char *b = evutil_inet_ntop(AF_INET6, &in6_addrs[0],buf,sizeof(buf));
+ printf("Bad IPv6 response \"%s\" %d. ", b, ttl);
+ dns_ok = 0;
+ goto out;
+ }
+#endif
+ break;
+ }
+ case DNS_PTR: {
+ char **addrs = addresses;
+ if (arg != (void*)6) {
+ if (strcmp(addrs[0], "ZZ.EXAMPLE.COM") ||
+ ttl != 54321) {
+ printf("Bad PTR response \"%s\" %d. ",
+ addrs[0], ttl);
+ dns_ok = 0;
+ goto out;
+ }
+ } else {
+ if (strcmp(addrs[0], "ZZ-INET6.EXAMPLE.COM") ||
+ ttl != 54322) {
+ printf("Bad ipv6 PTR response \"%s\" %d. ",
+ addrs[0], ttl);
+ dns_ok = 0;
+ goto out;
+ }
+ }
+ break;
+ }
+ default:
+ printf("Bad response type %d. ", type);
+ dns_ok = 0;
+ }
+ out:
+ if (++n_server_responses == 3) {
+ event_loopexit(NULL);
+ }
+}
+
+static void
+dns_server(void)
+{
+ evutil_socket_t sock=-1;
+ struct sockaddr_in my_addr;
+ struct sockaddr_storage ss;
+ ev_socklen_t slen;
+ struct evdns_server_port *port=NULL;
+ struct in_addr resolve_addr;
+ struct in6_addr resolve_addr6;
+ struct evdns_base *base=NULL;
+ struct evdns_request *req=NULL;
+
+ dns_ok = 1;
+
+ base = evdns_base_new(NULL, 0);
+
+ /* Now configure a nameserver port. */
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock<0) {
+ tt_abort_perror("socket");
+ }
+
+ evutil_make_socket_nonblocking(sock);
+
+ memset(&my_addr, 0, sizeof(my_addr));
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_port = 0; /* kernel picks */
+ my_addr.sin_addr.s_addr = htonl(0x7f000001UL);
+ if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) {
+ tt_abort_perror("bind");
+ }
+ slen = sizeof(ss);
+ if (getsockname(sock, (struct sockaddr*)&ss, &slen) < 0) {
+ tt_abort_perror("getsockname");
+ }
+
+ port = evdns_add_server_port(sock, 0, dns_server_request_cb, NULL);
+
+ /* Add ourself as the only nameserver, and make sure we really are
+ * the only nameserver. */
+ evdns_base_nameserver_sockaddr_add(base, (struct sockaddr*)&ss, slen, 0);
+ tt_int_op(evdns_base_count_nameservers(base), ==, 1);
+ {
+ struct sockaddr_storage ss2;
+ int slen2;
+
+ memset(&ss2, 0, sizeof(ss2));
+
+ slen2 = evdns_base_get_nameserver_addr(base, 0, (struct sockaddr *)&ss2, 3);
+ tt_int_op(slen2, ==, slen);
+ tt_int_op(ss2.ss_family, ==, 0);
+ slen2 = evdns_base_get_nameserver_addr(base, 0, (struct sockaddr *)&ss2, sizeof(ss2));
+ tt_int_op(slen2, ==, slen);
+ tt_mem_op(&ss2, ==, &ss, slen);
+
+ slen2 = evdns_base_get_nameserver_addr(base, 1, (struct sockaddr *)&ss2, sizeof(ss2));
+ tt_int_op(-1, ==, slen2);
+ }
+
+ /* Send some queries. */
+ evdns_base_resolve_ipv4(base, "zz.example.com", DNS_QUERY_NO_SEARCH,
+ dns_server_gethostbyname_cb, NULL);
+ evdns_base_resolve_ipv6(base, "zz.example.com", DNS_QUERY_NO_SEARCH,
+ dns_server_gethostbyname_cb, NULL);
+ resolve_addr.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */
+ evdns_base_resolve_reverse(base, &resolve_addr, 0,
+ dns_server_gethostbyname_cb, NULL);
+ memcpy(resolve_addr6.s6_addr,
+ "\xff\xf0\x00\x00\x00\x00\xaa\xaa"
+ "\x11\x11\x00\x00\x00\x00\xef\xef", 16);
+ evdns_base_resolve_reverse_ipv6(base, &resolve_addr6, 0,
+ dns_server_gethostbyname_cb, (void*)6);
+
+ req = evdns_base_resolve_ipv4(base,
+ "drop.example.com", DNS_QUERY_NO_SEARCH,
+ dns_server_gethostbyname_cb, (void*)(char*)90909);
+
+ evdns_cancel_request(base, req);
+
+ event_dispatch();
+
+ tt_assert(dns_got_cancel);
+ test_ok = dns_ok;
+
+end:
+ if (port)
+ evdns_close_server_port(port);
+ if (sock >= 0)
+ evutil_closesocket(sock);
+ if (base)
+ evdns_base_free(base, 0);
+}
+
+static int n_replies_left;
+static struct event_base *exit_base;
+static struct evdns_server_port *exit_port;
+
+struct generic_dns_callback_result {
+ int result;
+ char type;
+ int count;
+ int ttl;
+ size_t addrs_len;
+ void *addrs;
+ char addrs_buf[256];
+};
+
+static void
+generic_dns_callback(int result, char type, int count, int ttl, void *addresses,
+ void *arg)
+{
+ size_t len;
+ struct generic_dns_callback_result *res = arg;
+ res->result = result;
+ res->type = type;
+ res->count = count;
+ res->ttl = ttl;
+
+ if (type == DNS_IPv4_A)
+ len = count * 4;
+ else if (type == DNS_IPv6_AAAA)
+ len = count * 16;
+ else if (type == DNS_PTR)
+ len = strlen(addresses)+1;
+ else {
+ res->addrs_len = len = 0;
+ res->addrs = NULL;
+ }
+ if (len) {
+ res->addrs_len = len;
+ if (len > 256)
+ len = 256;
+ memcpy(res->addrs_buf, addresses, len);
+ res->addrs = res->addrs_buf;
+ }
+
+ --n_replies_left;
+ if (n_replies_left == 0) {
+ if (exit_port) {
+ evdns_close_server_port(exit_port);
+ exit_port = NULL;
+ } else
+ event_base_loopexit(exit_base, NULL);
+ }
+}
+
+static struct regress_dns_server_table search_table[] = {
+ { "host.a.example.com", "err", "3", 0, 0 },
+ { "host.b.example.com", "err", "3", 0, 0 },
+ { "host.c.example.com", "A", "11.22.33.44", 0, 0 },
+ { "host2.a.example.com", "err", "3", 0, 0 },
+ { "host2.b.example.com", "A", "200.100.0.100", 0, 0 },
+ { "host2.c.example.com", "err", "3", 0, 0 },
+ { "hostn.a.example.com", "errsoa", "0", 0, 0 },
+ { "hostn.b.example.com", "errsoa", "3", 0, 0 },
+ { "hostn.c.example.com", "err", "0", 0, 0 },
+
+ { "host", "err", "3", 0, 0 },
+ { "host2", "err", "3", 0, 0 },
+ { "*", "err", "3", 0, 0 },
+ { NULL, NULL, NULL, 0, 0 }
+};
+static void
+dns_search_test_impl(void *arg, int lower)
+{
+ struct regress_dns_server_table table[ARRAY_SIZE(search_table)];
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_base *dns = NULL;
+ ev_uint16_t portnum = 0;
+ char buf[64];
+
+ struct generic_dns_callback_result r[8];
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(table); ++i) {
+ table[i] = search_table[i];
+ table[i].lower = lower;
+ }
+
+ tt_assert(regress_dnsserver(base, &portnum, table));
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+ dns = evdns_base_new(base, 0);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+
+ evdns_base_search_add(dns, "a.example.com");
+ evdns_base_search_add(dns, "b.example.com");
+ evdns_base_search_add(dns, "c.example.com");
+
+ n_replies_left = ARRAY_SIZE(r);
+ exit_base = base;
+
+ evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r[0]);
+ evdns_base_resolve_ipv4(dns, "host2", 0, generic_dns_callback, &r[1]);
+ evdns_base_resolve_ipv4(dns, "host", DNS_NO_SEARCH, generic_dns_callback, &r[2]);
+ evdns_base_resolve_ipv4(dns, "host2", DNS_NO_SEARCH, generic_dns_callback, &r[3]);
+ evdns_base_resolve_ipv4(dns, "host3", 0, generic_dns_callback, &r[4]);
+ evdns_base_resolve_ipv4(dns, "hostn.a.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[5]);
+ evdns_base_resolve_ipv4(dns, "hostn.b.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[6]);
+ evdns_base_resolve_ipv4(dns, "hostn.c.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[7]);
+
+ event_base_dispatch(base);
+
+ tt_int_op(r[0].type, ==, DNS_IPv4_A);
+ tt_int_op(r[0].count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r[0].addrs)[0], ==, htonl(0x0b16212c));
+ tt_int_op(r[1].type, ==, DNS_IPv4_A);
+ tt_int_op(r[1].count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r[1].addrs)[0], ==, htonl(0xc8640064));
+ tt_int_op(r[2].result, ==, DNS_ERR_NOTEXIST);
+ tt_int_op(r[3].result, ==, DNS_ERR_NOTEXIST);
+ tt_int_op(r[4].result, ==, DNS_ERR_NOTEXIST);
+ tt_int_op(r[5].result, ==, DNS_ERR_NODATA);
+ tt_int_op(r[5].ttl, ==, 42);
+ tt_int_op(r[6].result, ==, DNS_ERR_NOTEXIST);
+ tt_int_op(r[6].ttl, ==, 42);
+ tt_int_op(r[7].result, ==, DNS_ERR_NODATA);
+ tt_int_op(r[7].ttl, ==, 0);
+
+end:
+ if (dns)
+ evdns_base_free(dns, 0);
+
+ regress_clean_dnsserver();
+}
+static void
+dns_search_empty_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_base *dns = NULL;
+
+ dns = evdns_base_new(base, 0);
+
+ evdns_base_search_add(dns, "whatever.example.com");
+
+ n_replies_left = 1;
+ exit_base = base;
+
+ tt_ptr_op(evdns_base_resolve_ipv4(dns, "", 0, generic_dns_callback, NULL), ==, NULL);
+
+end:
+ if (dns)
+ evdns_base_free(dns, 0);
+}
+static void
+dns_search_test(void *arg)
+{
+ return dns_search_test_impl(arg, 0);
+}
+static void
+dns_search_lower_test(void *arg)
+{
+ return dns_search_test_impl(arg, 1);
+}
+
+static int request_count = 0;
+static struct evdns_request *current_req = NULL;
+
+static void
+search_cancel_server_cb(struct evdns_server_request *req, void *data)
+{
+ const char *question;
+
+ if (req->nquestions != 1)
+ TT_DIE(("Only handling one question at a time; got %d",
+ req->nquestions));
+
+ question = req->questions[0]->name;
+
+ TT_BLATHER(("got question, %s", question));
+
+ tt_assert(request_count > 0);
+ tt_assert(!evdns_server_request_respond(req, 3));
+
+ if (!--request_count)
+ evdns_cancel_request(NULL, current_req);
+
+end:
+ ;
+}
+
+static void
+dns_search_cancel_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_base *dns = NULL;
+ struct evdns_server_port *port = NULL;
+ ev_uint16_t portnum = 0;
+ struct generic_dns_callback_result r1;
+ char buf[64];
+
+ port = regress_get_dnsserver(base, &portnum, NULL,
+ search_cancel_server_cb, NULL);
+ tt_assert(port);
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+ dns = evdns_base_new(base, 0);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+
+ evdns_base_search_add(dns, "a.example.com");
+ evdns_base_search_add(dns, "b.example.com");
+ evdns_base_search_add(dns, "c.example.com");
+ evdns_base_search_add(dns, "d.example.com");
+
+ exit_base = base;
+ request_count = 3;
+ n_replies_left = 1;
+
+ current_req = evdns_base_resolve_ipv4(dns, "host", 0,
+ generic_dns_callback, &r1);
+ event_base_dispatch(base);
+
+ tt_int_op(r1.result, ==, DNS_ERR_CANCEL);
+
+end:
+ if (port)
+ evdns_close_server_port(port);
+ if (dns)
+ evdns_base_free(dns, 0);
+}
+
+static void
+fail_server_cb(struct evdns_server_request *req, void *data)
+{
+ const char *question;
+ int *count = data;
+ struct in_addr in;
+
+ /* Drop the first N requests that we get. */
+ if (*count > 0) {
+ --*count;
+ tt_want(! evdns_server_request_drop(req));
+ return;
+ }
+
+ if (req->nquestions != 1)
+ TT_DIE(("Only handling one question at a time; got %d",
+ req->nquestions));
+
+ question = req->questions[0]->name;
+
+ if (!evutil_ascii_strcasecmp(question, "google.com")) {
+ /* Detect a probe, and get out of the loop. */
+ event_base_loopexit(exit_base, NULL);
+ }
+
+ tt_assert(evutil_inet_pton(AF_INET, "16.32.64.128", &in));
+ evdns_server_request_add_a_reply(req, question, 1, &in.s_addr,
+ 100);
+ tt_assert(! evdns_server_request_respond(req, 0))
+ return;
+end:
+ tt_want(! evdns_server_request_drop(req));
+}
+
+static void
+dns_retry_test_impl(void *arg, int flags)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_server_port *port = NULL;
+ struct evdns_base *dns = NULL;
+ int drop_count = 2;
+ ev_uint16_t portnum = 0;
+ char buf[64];
+
+ struct generic_dns_callback_result r1;
+
+ port = regress_get_dnsserver(base, &portnum, NULL,
+ fail_server_cb, &drop_count);
+ tt_assert(port);
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+ dns = evdns_base_new(base, flags);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+ tt_assert(! evdns_base_set_option(dns, "timeout", "0.2"));
+ tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "10"));
+ tt_assert(! evdns_base_set_option(dns, "initial-probe-timeout", "0.1"));
+
+ evdns_base_resolve_ipv4(dns, "host.example.com", 0,
+ generic_dns_callback, &r1);
+
+ n_replies_left = 1;
+ exit_base = base;
+
+ event_base_dispatch(base);
+
+ tt_int_op(drop_count, ==, 0);
+
+ tt_int_op(r1.type, ==, DNS_IPv4_A);
+ tt_int_op(r1.count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080));
+
+ /* Now try again, but this time have the server get treated as
+ * failed, so we can send it a test probe. */
+ drop_count = 4;
+ tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "2"));
+ tt_assert(! evdns_base_set_option(dns, "attempts:", "3"));
+ memset(&r1, 0, sizeof(r1));
+
+ evdns_base_resolve_ipv4(dns, "host.example.com", 0,
+ generic_dns_callback, &r1);
+
+ n_replies_left = 2;
+
+ /* This will run until it answers the "google.com" probe request. */
+ event_base_dispatch(base);
+
+ /* We'll treat the server as failed here. */
+ tt_int_op(r1.result, ==, DNS_ERR_TIMEOUT);
+
+ /* It should work this time. */
+ tt_int_op(drop_count, ==, 0);
+ evdns_base_resolve_ipv4(dns, "host.example.com", 0,
+ generic_dns_callback, &r1);
+
+ event_base_dispatch(base);
+ tt_int_op(r1.result, ==, DNS_ERR_NONE);
+ tt_int_op(r1.type, ==, DNS_IPv4_A);
+ tt_int_op(r1.count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080));
+
+end:
+ if (dns)
+ evdns_base_free(dns, 0);
+ if (port)
+ evdns_close_server_port(port);
+}
+static void
+dns_retry_test(void *arg)
+{
+ dns_retry_test_impl(arg, 0);
+}
+static void
+dns_retry_disable_when_inactive_test(void *arg)
+{
+ dns_retry_test_impl(arg, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
+}
+
+static struct regress_dns_server_table internal_error_table[] = {
+ /* Error 4 (NOTIMPL) makes us reissue the request to another server
+ if we can.
+
+ XXXX we should reissue under a much wider set of circumstances!
+ */
+ { "foof.example.com", "err", "4", 0, 0 },
+ { NULL, NULL, NULL, 0, 0 }
+};
+
+static struct regress_dns_server_table reissue_table[] = {
+ { "foof.example.com", "A", "240.15.240.15", 0, 0 },
+ { NULL, NULL, NULL, 0, 0 }
+};
+
+static void
+dns_reissue_test_impl(void *arg, int flags)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_server_port *port1 = NULL, *port2 = NULL;
+ struct evdns_base *dns = NULL;
+ struct generic_dns_callback_result r1;
+ ev_uint16_t portnum1 = 0, portnum2=0;
+ char buf1[64], buf2[64];
+
+ port1 = regress_get_dnsserver(base, &portnum1, NULL,
+ regress_dns_server_cb, internal_error_table);
+ tt_assert(port1);
+ port2 = regress_get_dnsserver(base, &portnum2, NULL,
+ regress_dns_server_cb, reissue_table);
+ tt_assert(port2);
+ evutil_snprintf(buf1, sizeof(buf1), "127.0.0.1:%d", (int)portnum1);
+ evutil_snprintf(buf2, sizeof(buf2), "127.0.0.1:%d", (int)portnum2);
+
+ dns = evdns_base_new(base, flags);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf1));
+ tt_assert(! evdns_base_set_option(dns, "timeout:", "0.3"));
+ tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "2"));
+ tt_assert(! evdns_base_set_option(dns, "attempts:", "5"));
+
+ memset(&r1, 0, sizeof(r1));
+ evdns_base_resolve_ipv4(dns, "foof.example.com", 0,
+ generic_dns_callback, &r1);
+
+ /* Add this after, so that we are sure to get a reissue. */
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf2));
+
+ n_replies_left = 1;
+ exit_base = base;
+
+ event_base_dispatch(base);
+ tt_int_op(r1.result, ==, DNS_ERR_NONE);
+ tt_int_op(r1.type, ==, DNS_IPv4_A);
+ tt_int_op(r1.count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0xf00ff00f));
+
+ /* Make sure we dropped at least once. */
+ tt_int_op(internal_error_table[0].seen, >, 0);
+
+end:
+ if (dns)
+ evdns_base_free(dns, 0);
+ if (port1)
+ evdns_close_server_port(port1);
+ if (port2)
+ evdns_close_server_port(port2);
+}
+static void
+dns_reissue_test(void *arg)
+{
+ dns_reissue_test_impl(arg, 0);
+}
+static void
+dns_reissue_disable_when_inactive_test(void *arg)
+{
+ dns_reissue_test_impl(arg, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
+}
+
+#if 0
+static void
+dumb_bytes_fn(char *p, size_t n)
+{
+ unsigned i;
+ /* This gets us 6 bits of entropy per transaction ID, which means we
+ * will have probably have collisions and need to pick again. */
+ for (i=0;i<n;++i)
+ p[i] = (char)(rand() & 7);
+}
+#endif
+
+static void
+dns_inflight_test_impl(void *arg, int flags)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_base *dns = NULL;
+ struct evdns_server_port *dns_port = NULL;
+ ev_uint16_t portnum = 0;
+ char buf[64];
+ int disable_when_inactive = flags & EVDNS_BASE_DISABLE_WHEN_INACTIVE;
+
+ struct generic_dns_callback_result r[20];
+ int i;
+
+ dns_port = regress_get_dnsserver(base, &portnum, NULL,
+ regress_dns_server_cb, reissue_table);
+ tt_assert(dns_port);
+ if (disable_when_inactive) {
+ exit_port = dns_port;
+ }
+
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+ dns = evdns_base_new(base, flags);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+ tt_assert(! evdns_base_set_option(dns, "max-inflight:", "3"));
+ tt_assert(! evdns_base_set_option(dns, "randomize-case:", "0"));
+
+ for (i=0;i<20;++i)
+ evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r[i]);
+
+ n_replies_left = 20;
+ exit_base = base;
+
+ event_base_dispatch(base);
+
+ for (i=0;i<20;++i) {
+ tt_int_op(r[i].type, ==, DNS_IPv4_A);
+ tt_int_op(r[i].count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r[i].addrs)[0], ==, htonl(0xf00ff00f));
+ }
+
+end:
+ if (dns)
+ evdns_base_free(dns, 0);
+ if (exit_port) {
+ evdns_close_server_port(exit_port);
+ exit_port = NULL;
+ } else if (! disable_when_inactive) {
+ evdns_close_server_port(dns_port);
+ }
+}
+
+static void
+dns_inflight_test(void *arg)
+{
+ dns_inflight_test_impl(arg, 0);
+}
+
+static void
+dns_disable_when_inactive_test(void *arg)
+{
+ dns_inflight_test_impl(arg, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
+}
+
+static void
+dns_disable_when_inactive_no_ns_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base, *inactive_base;
+ struct evdns_base *dns = NULL;
+ ev_uint16_t portnum = 0;
+ char buf[64];
+ struct generic_dns_callback_result r;
+
+ inactive_base = event_base_new();
+ tt_assert(inactive_base);
+
+ /** Create dns server with inactive base, to avoid replying to clients */
+ tt_assert(regress_dnsserver(inactive_base, &portnum, search_table));
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+ dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+ tt_assert(! evdns_base_set_option(dns, "timeout:", "0.1"));
+
+ evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r);
+ n_replies_left = 1;
+ exit_base = base;
+
+ event_base_dispatch(base);
+
+ tt_int_op(n_replies_left, ==, 0);
+
+ tt_int_op(r.result, ==, DNS_ERR_TIMEOUT);
+ tt_int_op(r.count, ==, 0);
+ tt_ptr_op(r.addrs, ==, NULL);
+
+end:
+ if (dns)
+ evdns_base_free(dns, 0);
+ regress_clean_dnsserver();
+ if (inactive_base)
+ event_base_free(inactive_base);
+}
+
+/* === Test for bufferevent_socket_connect_hostname */
+
+static int total_connected_or_failed = 0;
+static int total_n_accepted = 0;
+static struct event_base *be_connect_hostname_base = NULL;
+
+/* Implements a DNS server for the connect_hostname test and the
+ * getaddrinfo_async test */
+static void
+be_getaddrinfo_server_cb(struct evdns_server_request *req, void *data)
+{
+ int i;
+ int *n_got_p=data;
+ int added_any=0;
+ ++*n_got_p;
+
+ for (i=0;i<req->nquestions;++i) {
+ const int qtype = req->questions[i]->type;
+ const int qclass = req->questions[i]->dns_question_class;
+ const char *qname = req->questions[i]->name;
+ struct in_addr ans;
+ struct in6_addr ans6;
+ memset(&ans6, 0, sizeof(ans6));
+
+ TT_BLATHER(("Got question about %s, type=%d", qname, qtype));
+
+ if (qtype == EVDNS_TYPE_A &&
+ qclass == EVDNS_CLASS_INET &&
+ !evutil_ascii_strcasecmp(qname, "nobodaddy.example.com")) {
+ ans.s_addr = htonl(0x7f000001);
+ evdns_server_request_add_a_reply(req, qname,
+ 1, &ans.s_addr, 2000);
+ added_any = 1;
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "nosuchplace.example.com")) {
+ /* ok, just say notfound. */
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "both.example.com")) {
+ if (qtype == EVDNS_TYPE_A) {
+ ans.s_addr = htonl(0x50502020);
+ evdns_server_request_add_a_reply(req, qname,
+ 1, &ans.s_addr, 2000);
+ added_any = 1;
+ } else if (qtype == EVDNS_TYPE_AAAA) {
+ ans6.s6_addr[0] = 0x80;
+ ans6.s6_addr[1] = 0xff;
+ ans6.s6_addr[14] = 0xbb;
+ ans6.s6_addr[15] = 0xbb;
+ evdns_server_request_add_aaaa_reply(req, qname,
+ 1, &ans6.s6_addr, 2000);
+ added_any = 1;
+ }
+ evdns_server_request_add_cname_reply(req, qname,
+ "both-canonical.example.com", 1000);
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v4only.example.com") ||
+ !evutil_ascii_strcasecmp(qname, "v4assert.example.com")) {
+ if (qtype == EVDNS_TYPE_A) {
+ ans.s_addr = htonl(0x12345678);
+ evdns_server_request_add_a_reply(req, qname,
+ 1, &ans.s_addr, 2000);
+ added_any = 1;
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v4assert.example.com")) {
+ TT_FAIL(("Got an AAAA request for v4assert"));
+ }
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v6only.example.com") ||
+ !evutil_ascii_strcasecmp(qname, "v6assert.example.com")) {
+ if (qtype == EVDNS_TYPE_AAAA) {
+ ans6.s6_addr[0] = 0x0b;
+ ans6.s6_addr[1] = 0x0b;
+ ans6.s6_addr[14] = 0xf0;
+ ans6.s6_addr[15] = 0x0d;
+ evdns_server_request_add_aaaa_reply(req, qname,
+ 1, &ans6.s6_addr, 2000);
+ added_any = 1;
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v6assert.example.com")) {
+ TT_FAIL(("Got a A request for v6assert"));
+ }
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v6timeout.example.com")) {
+ if (qtype == EVDNS_TYPE_A) {
+ ans.s_addr = htonl(0xabcdef01);
+ evdns_server_request_add_a_reply(req, qname,
+ 1, &ans.s_addr, 2000);
+ added_any = 1;
+ } else if (qtype == EVDNS_TYPE_AAAA) {
+ /* Let the v6 request time out.*/
+ evdns_server_request_drop(req);
+ return;
+ }
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v4timeout.example.com")) {
+ if (qtype == EVDNS_TYPE_AAAA) {
+ ans6.s6_addr[0] = 0x0a;
+ ans6.s6_addr[1] = 0x0a;
+ ans6.s6_addr[14] = 0xff;
+ ans6.s6_addr[15] = 0x01;
+ evdns_server_request_add_aaaa_reply(req, qname,
+ 1, &ans6.s6_addr, 2000);
+ added_any = 1;
+ } else if (qtype == EVDNS_TYPE_A) {
+ /* Let the v4 request time out.*/
+ evdns_server_request_drop(req);
+ return;
+ }
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v6timeout-nonexist.example.com")) {
+ if (qtype == EVDNS_TYPE_A) {
+ /* Fall through, give an nexist. */
+ } else if (qtype == EVDNS_TYPE_AAAA) {
+ /* Let the v6 request time out.*/
+ evdns_server_request_drop(req);
+ return;
+ }
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "all-timeout.example.com")) {
+ /* drop all requests */
+ evdns_server_request_drop(req);
+ return;
+ } else {
+ TT_GRIPE(("Got weird request for %s",qname));
+ }
+ }
+ if (added_any) {
+ TT_BLATHER(("answering"));
+ evdns_server_request_respond(req, 0);
+ } else {
+ TT_BLATHER(("saying nexist."));
+ evdns_server_request_respond(req, 3);
+ }
+}
+
+/* Implements a listener for connect_hostname test. */
+static void
+nil_accept_cb(struct evconnlistener *l, evutil_socket_t fd, struct sockaddr *s,
+ int socklen, void *arg)
+{
+ int *p = arg;
+ (*p)++;
+ ++total_n_accepted;
+ /* don't do anything with the socket; let it close when we exit() */
+ if (total_n_accepted >= 3 && total_connected_or_failed >= 5)
+ event_base_loopexit(be_connect_hostname_base,
+ NULL);
+}
+
+struct be_conn_hostname_result {
+ int dnserr;
+ int what;
+};
+
+/* Bufferevent event callback for the connect_hostname test: remembers what
+ * event we got. */
+static void
+be_connect_hostname_event_cb(struct bufferevent *bev, short what, void *ctx)
+{
+ struct be_conn_hostname_result *got = ctx;
+ if (!got->what) {
+ TT_BLATHER(("Got a bufferevent event %d", what));
+ got->what = what;
+
+ if ((what & BEV_EVENT_CONNECTED) || (what & BEV_EVENT_ERROR)) {
+ int r;
+ if ((r = bufferevent_socket_get_dns_error(bev))) {
+ got->dnserr = r;
+ TT_BLATHER(("DNS error %d: %s", r,
+ evutil_gai_strerror(r)));
+ } ++total_connected_or_failed;
+ TT_BLATHER(("Got %d connections or errors.", total_connected_or_failed));
+
+ if (total_n_accepted >= 3 && total_connected_or_failed >= 5)
+ event_base_loopexit(be_connect_hostname_base,
+ NULL);
+ }
+ } else {
+ TT_FAIL(("Two events on one bufferevent. %d,%d",
+ got->what, (int)what));
+ }
+}
+
+static void
+test_bufferevent_connect_hostname(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct evconnlistener *listener = NULL;
+ struct bufferevent *be1=NULL, *be2=NULL, *be3=NULL, *be4=NULL, *be5=NULL;
+ struct be_conn_hostname_result be1_outcome={0,0}, be2_outcome={0,0},
+ be3_outcome={0,0}, be4_outcome={0,0}, be5_outcome={0,0};
+ int expect_err5;
+ struct evdns_base *dns=NULL;
+ struct evdns_server_port *port=NULL;
+ struct sockaddr_in sin;
+ int listener_port=-1;
+ ev_uint16_t dns_port=0;
+ int n_accept=0, n_dns=0;
+ char buf[128];
+
+ be_connect_hostname_base = data->base;
+
+ /* Bind an address and figure out what port it's on. */
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+ sin.sin_port = 0;
+ listener = evconnlistener_new_bind(data->base, nil_accept_cb,
+ &n_accept,
+ LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC,
+ -1, (struct sockaddr *)&sin, sizeof(sin));
+ tt_assert(listener);
+ listener_port = regress_get_socket_port(
+ evconnlistener_get_fd(listener));
+
+ port = regress_get_dnsserver(data->base, &dns_port, NULL,
+ be_getaddrinfo_server_cb, &n_dns);
+ tt_assert(port);
+ tt_int_op(dns_port, >=, 0);
+
+ /* Start an evdns_base that uses the server as its resolver. */
+ dns = evdns_base_new(data->base, 0);
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)dns_port);
+ evdns_base_nameserver_ip_add(dns, buf);
+
+ /* Now, finally, at long last, launch the bufferevents. One should do
+ * a failing lookup IP, one should do a successful lookup by IP,
+ * and one should do a successful lookup by hostname. */
+ be1 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
+ be2 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
+ be3 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
+ be4 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
+ be5 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
+
+ bufferevent_setcb(be1, NULL, NULL, be_connect_hostname_event_cb,
+ &be1_outcome);
+ bufferevent_setcb(be2, NULL, NULL, be_connect_hostname_event_cb,
+ &be2_outcome);
+ bufferevent_setcb(be3, NULL, NULL, be_connect_hostname_event_cb,
+ &be3_outcome);
+ bufferevent_setcb(be4, NULL, NULL, be_connect_hostname_event_cb,
+ &be4_outcome);
+ bufferevent_setcb(be5, NULL, NULL, be_connect_hostname_event_cb,
+ &be5_outcome);
+
+ /* Launch an async resolve that will fail. */
+ tt_assert(!bufferevent_socket_connect_hostname(be1, dns, AF_INET,
+ "nosuchplace.example.com", listener_port));
+ /* Connect to the IP without resolving. */
+ tt_assert(!bufferevent_socket_connect_hostname(be2, dns, AF_INET,
+ "127.0.0.1", listener_port));
+ /* Launch an async resolve that will succeed. */
+ tt_assert(!bufferevent_socket_connect_hostname(be3, dns, AF_INET,
+ "nobodaddy.example.com", listener_port));
+ /* Use the blocking resolver. This one will fail if your resolver
+ * can't resolve localhost to 127.0.0.1 */
+ tt_assert(!bufferevent_socket_connect_hostname(be4, NULL, AF_INET,
+ "localhost", listener_port));
+ /* Use the blocking resolver with a nonexistent hostname. */
+ tt_assert(!bufferevent_socket_connect_hostname(be5, NULL, AF_INET,
+ "nonesuch.nowhere.example.com", 80));
+ {
+ /* The blocking resolver will use the system nameserver, which
+ * might tell us anything. (Yes, some twits even pretend that
+ * example.com is real.) Let's see what answer to expect. */
+ struct evutil_addrinfo hints, *ai = NULL;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ expect_err5 = evutil_getaddrinfo(
+ "nonesuch.nowhere.example.com", "80", &hints, &ai);
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(be1_outcome.what, ==, BEV_EVENT_ERROR);
+ tt_int_op(be1_outcome.dnserr, ==, EVUTIL_EAI_NONAME);
+ tt_int_op(be2_outcome.what, ==, BEV_EVENT_CONNECTED);
+ tt_int_op(be2_outcome.dnserr, ==, 0);
+ tt_int_op(be3_outcome.what, ==, BEV_EVENT_CONNECTED);
+ tt_int_op(be3_outcome.dnserr, ==, 0);
+ tt_int_op(be4_outcome.what, ==, BEV_EVENT_CONNECTED);
+ tt_int_op(be4_outcome.dnserr, ==, 0);
+ if (expect_err5) {
+ tt_int_op(be5_outcome.what, ==, BEV_EVENT_ERROR);
+ tt_int_op(be5_outcome.dnserr, ==, expect_err5);
+ }
+
+ tt_int_op(n_accept, ==, 3);
+ tt_int_op(n_dns, ==, 2);
+
+end:
+ if (listener)
+ evconnlistener_free(listener);
+ if (port)
+ evdns_close_server_port(port);
+ if (dns)
+ evdns_base_free(dns, 0);
+ if (be1)
+ bufferevent_free(be1);
+ if (be2)
+ bufferevent_free(be2);
+ if (be3)
+ bufferevent_free(be3);
+ if (be4)
+ bufferevent_free(be4);
+ if (be5)
+ bufferevent_free(be5);
+}
+
+
+struct gai_outcome {
+ int err;
+ struct evutil_addrinfo *ai;
+};
+
+static int n_gai_results_pending = 0;
+static struct event_base *exit_base_on_no_pending_results = NULL;
+
+static void
+gai_cb(int err, struct evutil_addrinfo *res, void *ptr)
+{
+ struct gai_outcome *go = ptr;
+ go->err = err;
+ go->ai = res;
+ if (--n_gai_results_pending <= 0 && exit_base_on_no_pending_results)
+ event_base_loopexit(exit_base_on_no_pending_results, NULL);
+ if (n_gai_results_pending < 900)
+ TT_BLATHER(("Got an answer; expecting %d more.",
+ n_gai_results_pending));
+}
+
+static void
+cancel_gai_cb(evutil_socket_t fd, short what, void *ptr)
+{
+ struct evdns_getaddrinfo_request *r = ptr;
+ evdns_getaddrinfo_cancel(r);
+}
+
+static void
+test_getaddrinfo_async(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct evutil_addrinfo hints, *a;
+ struct gai_outcome local_outcome;
+ struct gai_outcome a_out[12];
+ int i;
+ struct evdns_getaddrinfo_request *r;
+ char buf[128];
+ struct evdns_server_port *port = NULL;
+ ev_uint16_t dns_port = 0;
+ int n_dns_questions = 0;
+ struct evdns_base *dns_base;
+
+ memset(a_out, 0, sizeof(a_out));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+
+ dns_base = evdns_base_new(data->base, 0);
+ tt_assert(dns_base);
+
+ /* for localhost */
+ evdns_base_load_hosts(dns_base, NULL);
+
+ tt_assert(! evdns_base_set_option(dns_base, "timeout", "0.3"));
+ tt_assert(! evdns_base_set_option(dns_base, "getaddrinfo-allow-skew", "0.2"));
+
+ n_gai_results_pending = 10000; /* don't think about exiting yet. */
+
+ /* 1. Try some cases that will never hit the asynchronous resolver. */
+ /* 1a. Simple case with a symbolic service name */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ r = evdns_getaddrinfo(dns_base, "1.2.3.4", "http",
+ &hints, gai_cb, &local_outcome);
+ tt_assert(! r);
+ if (!local_outcome.err) {
+ tt_ptr_op(local_outcome.ai,!=,NULL);
+ test_ai_eq(local_outcome.ai, "1.2.3.4:80", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+ } else {
+ TT_BLATHER(("Apparently we have no getservbyname."));
+ }
+
+ /* 1b. EVUTIL_AI_NUMERICHOST is set */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = EVUTIL_AI_NUMERICHOST;
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ r = evdns_getaddrinfo(dns_base, "www.google.com", "80",
+ &hints, gai_cb, &local_outcome);
+ tt_ptr_op(r,==,NULL);
+ tt_int_op(local_outcome.err,==,EVUTIL_EAI_NONAME);
+ tt_ptr_op(local_outcome.ai,==,NULL);
+
+ /* 1c. We give a numeric address (ipv6) */
+ memset(&hints, 0, sizeof(hints));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_protocol = IPPROTO_TCP;
+ r = evdns_getaddrinfo(dns_base, "f::f", "8008",
+ &hints, gai_cb, &local_outcome);
+ tt_assert(!r);
+ tt_int_op(local_outcome.err,==,0);
+ tt_assert(local_outcome.ai);
+ tt_ptr_op(local_outcome.ai->ai_next,==,NULL);
+ test_ai_eq(local_outcome.ai, "[f::f]:8008", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+
+ /* 1d. We give a numeric address (ipv4) */
+ memset(&hints, 0, sizeof(hints));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ hints.ai_family = PF_UNSPEC;
+ r = evdns_getaddrinfo(dns_base, "5.6.7.8", NULL,
+ &hints, gai_cb, &local_outcome);
+ tt_assert(!r);
+ tt_int_op(local_outcome.err,==,0);
+ tt_assert(local_outcome.ai);
+ a = ai_find_by_protocol(local_outcome.ai, IPPROTO_TCP);
+ tt_assert(a);
+ test_ai_eq(a, "5.6.7.8", SOCK_STREAM, IPPROTO_TCP);
+ a = ai_find_by_protocol(local_outcome.ai, IPPROTO_UDP);
+ tt_assert(a);
+ test_ai_eq(a, "5.6.7.8", SOCK_DGRAM, IPPROTO_UDP);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+
+ /* 1e. nodename is NULL (bind) */
+ memset(&hints, 0, sizeof(hints));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = EVUTIL_AI_PASSIVE;
+ r = evdns_getaddrinfo(dns_base, NULL, "9090",
+ &hints, gai_cb, &local_outcome);
+ tt_assert(!r);
+ tt_int_op(local_outcome.err,==,0);
+ tt_assert(local_outcome.ai);
+ /* we should get a v4 address of 0.0.0.0... */
+ a = ai_find_by_family(local_outcome.ai, PF_INET);
+ tt_assert(a);
+ test_ai_eq(a, "0.0.0.0:9090", SOCK_DGRAM, IPPROTO_UDP);
+ /* ... and a v6 address of ::0 */
+ a = ai_find_by_family(local_outcome.ai, PF_INET6);
+ tt_assert(a);
+ test_ai_eq(a, "[::]:9090", SOCK_DGRAM, IPPROTO_UDP);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+
+ /* 1f. nodename is NULL (connect) */
+ memset(&hints, 0, sizeof(hints));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ r = evdns_getaddrinfo(dns_base, NULL, "2",
+ &hints, gai_cb, &local_outcome);
+ tt_assert(!r);
+ tt_int_op(local_outcome.err,==,0);
+ tt_assert(local_outcome.ai);
+ /* we should get a v4 address of 127.0.0.1 .... */
+ a = ai_find_by_family(local_outcome.ai, PF_INET);
+ tt_assert(a);
+ test_ai_eq(a, "127.0.0.1:2", SOCK_STREAM, IPPROTO_TCP);
+ /* ... and a v6 address of ::1 */
+ a = ai_find_by_family(local_outcome.ai, PF_INET6);
+ tt_assert(a);
+ test_ai_eq(a, "[::1]:2", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+
+ /* 1g. We find localhost immediately. (pf_unspec) */
+ memset(&hints, 0, sizeof(hints));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ r = evdns_getaddrinfo(dns_base, "LOCALHOST", "80",
+ &hints, gai_cb, &local_outcome);
+ tt_assert(!r);
+ tt_int_op(local_outcome.err,==,0);
+ tt_assert(local_outcome.ai);
+ /* we should get a v4 address of 127.0.0.1 .... */
+ a = ai_find_by_family(local_outcome.ai, PF_INET);
+ tt_assert(a);
+ test_ai_eq(a, "127.0.0.1:80", SOCK_STREAM, IPPROTO_TCP);
+ /* ... and a v6 address of ::1 */
+ a = ai_find_by_family(local_outcome.ai, PF_INET6);
+ tt_assert(a);
+ test_ai_eq(a, "[::1]:80", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+
+ /* 1g. We find localhost immediately. (pf_inet6) */
+ memset(&hints, 0, sizeof(hints));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ hints.ai_family = PF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ r = evdns_getaddrinfo(dns_base, "LOCALHOST", "9999",
+ &hints, gai_cb, &local_outcome);
+ tt_assert(! r);
+ tt_int_op(local_outcome.err,==,0);
+ tt_assert(local_outcome.ai);
+ a = local_outcome.ai;
+ test_ai_eq(a, "[::1]:9999", SOCK_STREAM, IPPROTO_TCP);
+ tt_ptr_op(a->ai_next, ==, NULL);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+
+ /* 2. Okay, now we can actually test the asynchronous resolver. */
+ /* Start a dummy local dns server... */
+ port = regress_get_dnsserver(data->base, &dns_port, NULL,
+ be_getaddrinfo_server_cb, &n_dns_questions);
+ tt_assert(port);
+ tt_int_op(dns_port, >=, 0);
+ /* ... and tell the evdns_base about it. */
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", dns_port);
+ evdns_base_nameserver_ip_add(dns_base, buf);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = EVUTIL_AI_CANONNAME;
+ /* 0: Request for both.example.com should return both addresses. */
+ r = evdns_getaddrinfo(dns_base, "both.example.com", "8000",
+ &hints, gai_cb, &a_out[0]);
+ tt_assert(r);
+
+ /* 1: Request for v4only.example.com should return one address. */
+ r = evdns_getaddrinfo(dns_base, "v4only.example.com", "8001",
+ &hints, gai_cb, &a_out[1]);
+ tt_assert(r);
+
+ /* 2: Request for v6only.example.com should return one address. */
+ hints.ai_flags = 0;
+ r = evdns_getaddrinfo(dns_base, "v6only.example.com", "8002",
+ &hints, gai_cb, &a_out[2]);
+ tt_assert(r);
+
+ /* 3: PF_INET request for v4assert.example.com should not generate a
+ * v6 request. The server will fail the test if it does. */
+ hints.ai_family = PF_INET;
+ r = evdns_getaddrinfo(dns_base, "v4assert.example.com", "8003",
+ &hints, gai_cb, &a_out[3]);
+ tt_assert(r);
+
+ /* 4: PF_INET6 request for v6assert.example.com should not generate a
+ * v4 request. The server will fail the test if it does. */
+ hints.ai_family = PF_INET6;
+ r = evdns_getaddrinfo(dns_base, "v6assert.example.com", "8004",
+ &hints, gai_cb, &a_out[4]);
+ tt_assert(r);
+
+ /* 5: PF_INET request for nosuchplace.example.com should give NEXIST. */
+ hints.ai_family = PF_INET;
+ r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8005",
+ &hints, gai_cb, &a_out[5]);
+ tt_assert(r);
+
+ /* 6: PF_UNSPEC request for nosuchplace.example.com should give NEXIST.
+ */
+ hints.ai_family = PF_UNSPEC;
+ r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8006",
+ &hints, gai_cb, &a_out[6]);
+ tt_assert(r);
+
+ /* 7: PF_UNSPEC request for v6timeout.example.com should give an ipv4
+ * address only. */
+ hints.ai_family = PF_UNSPEC;
+ r = evdns_getaddrinfo(dns_base, "v6timeout.example.com", "8007",
+ &hints, gai_cb, &a_out[7]);
+ tt_assert(r);
+
+ /* 8: PF_UNSPEC request for v6timeout-nonexist.example.com should give
+ * a NEXIST */
+ hints.ai_family = PF_UNSPEC;
+ r = evdns_getaddrinfo(dns_base, "v6timeout-nonexist.example.com",
+ "8008", &hints, gai_cb, &a_out[8]);
+ tt_assert(r);
+
+ /* 9: AI_ADDRCONFIG should at least not crash. Can't test it more
+ * without knowing what kind of internet we have. */
+ hints.ai_flags |= EVUTIL_AI_ADDRCONFIG;
+ r = evdns_getaddrinfo(dns_base, "both.example.com",
+ "8009", &hints, gai_cb, &a_out[9]);
+ tt_assert(r);
+
+ /* 10: PF_UNSPEC for v4timeout.example.com should give an ipv6 address
+ * only. */
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = 0;
+ r = evdns_getaddrinfo(dns_base, "v4timeout.example.com", "8010",
+ &hints, gai_cb, &a_out[10]);
+ tt_assert(r);
+
+ /* 11: timeout.example.com: cancel it after 100 msec. */
+ r = evdns_getaddrinfo(dns_base, "all-timeout.example.com", "8011",
+ &hints, gai_cb, &a_out[11]);
+ tt_assert(r);
+ {
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100*1000; /* 100 msec */
+ event_base_once(data->base, -1, EV_TIMEOUT, cancel_gai_cb,
+ r, &tv);
+ }
+
+ /* XXXXX There are more tests we could do, including:
+
+ - A test to elicit NODATA.
+
+ */
+
+ n_gai_results_pending = 12;
+ exit_base_on_no_pending_results = data->base;
+
+ event_base_dispatch(data->base);
+
+ /* 0: both.example.com */
+ tt_int_op(a_out[0].err, ==, 0);
+ tt_assert(a_out[0].ai);
+ tt_assert(a_out[0].ai->ai_next);
+ tt_assert(!a_out[0].ai->ai_next->ai_next);
+ a = ai_find_by_family(a_out[0].ai, PF_INET);
+ tt_assert(a);
+ test_ai_eq(a, "80.80.32.32:8000", SOCK_STREAM, IPPROTO_TCP);
+ a = ai_find_by_family(a_out[0].ai, PF_INET6);
+ tt_assert(a);
+ test_ai_eq(a, "[80ff::bbbb]:8000", SOCK_STREAM, IPPROTO_TCP);
+ tt_assert(a_out[0].ai->ai_canonname);
+ tt_str_op(a_out[0].ai->ai_canonname, ==, "both-canonical.example.com");
+
+ /* 1: v4only.example.com */
+ tt_int_op(a_out[1].err, ==, 0);
+ tt_assert(a_out[1].ai);
+ tt_assert(! a_out[1].ai->ai_next);
+ test_ai_eq(a_out[1].ai, "18.52.86.120:8001", SOCK_STREAM, IPPROTO_TCP);
+ tt_assert(a_out[1].ai->ai_canonname == NULL);
+
+
+ /* 2: v6only.example.com */
+ tt_int_op(a_out[2].err, ==, 0);
+ tt_assert(a_out[2].ai);
+ tt_assert(! a_out[2].ai->ai_next);
+ test_ai_eq(a_out[2].ai, "[b0b::f00d]:8002", SOCK_STREAM, IPPROTO_TCP);
+
+ /* 3: v4assert.example.com */
+ tt_int_op(a_out[3].err, ==, 0);
+ tt_assert(a_out[3].ai);
+ tt_assert(! a_out[3].ai->ai_next);
+ test_ai_eq(a_out[3].ai, "18.52.86.120:8003", SOCK_STREAM, IPPROTO_TCP);
+
+ /* 4: v6assert.example.com */
+ tt_int_op(a_out[4].err, ==, 0);
+ tt_assert(a_out[4].ai);
+ tt_assert(! a_out[4].ai->ai_next);
+ test_ai_eq(a_out[4].ai, "[b0b::f00d]:8004", SOCK_STREAM, IPPROTO_TCP);
+
+ /* 5: nosuchplace.example.com (inet) */
+ tt_int_op(a_out[5].err, ==, EVUTIL_EAI_NONAME);
+ tt_assert(! a_out[5].ai);
+
+ /* 6: nosuchplace.example.com (unspec) */
+ tt_int_op(a_out[6].err, ==, EVUTIL_EAI_NONAME);
+ tt_assert(! a_out[6].ai);
+
+ /* 7: v6timeout.example.com */
+ tt_int_op(a_out[7].err, ==, 0);
+ tt_assert(a_out[7].ai);
+ tt_assert(! a_out[7].ai->ai_next);
+ test_ai_eq(a_out[7].ai, "171.205.239.1:8007", SOCK_STREAM, IPPROTO_TCP);
+
+ /* 8: v6timeout-nonexist.example.com */
+ tt_int_op(a_out[8].err, ==, EVUTIL_EAI_NONAME);
+ tt_assert(! a_out[8].ai);
+
+ /* 9: both (ADDRCONFIG) */
+ tt_int_op(a_out[9].err, ==, 0);
+ tt_assert(a_out[9].ai);
+ a = ai_find_by_family(a_out[9].ai, PF_INET);
+ if (a)
+ test_ai_eq(a, "80.80.32.32:8009", SOCK_STREAM, IPPROTO_TCP);
+ else
+ tt_assert(ai_find_by_family(a_out[9].ai, PF_INET6));
+ a = ai_find_by_family(a_out[9].ai, PF_INET6);
+ if (a)
+ test_ai_eq(a, "[80ff::bbbb]:8009", SOCK_STREAM, IPPROTO_TCP);
+ else
+ tt_assert(ai_find_by_family(a_out[9].ai, PF_INET));
+
+ /* 10: v4timeout.example.com */
+ tt_int_op(a_out[10].err, ==, 0);
+ tt_assert(a_out[10].ai);
+ tt_assert(! a_out[10].ai->ai_next);
+ test_ai_eq(a_out[10].ai, "[a0a::ff01]:8010", SOCK_STREAM, IPPROTO_TCP);
+
+ /* 11: cancelled request. */
+ tt_int_op(a_out[11].err, ==, EVUTIL_EAI_CANCEL);
+ tt_assert(a_out[11].ai == NULL);
+
+end:
+ if (local_outcome.ai)
+ evutil_freeaddrinfo(local_outcome.ai);
+ for (i=0;i<(int)ARRAY_SIZE(a_out);++i) {
+ if (a_out[i].ai)
+ evutil_freeaddrinfo(a_out[i].ai);
+ }
+ if (port)
+ evdns_close_server_port(port);
+ if (dns_base)
+ evdns_base_free(dns_base, 0);
+}
+
+struct gaic_request_status {
+ int magic;
+ struct event_base *base;
+ struct evdns_base *dns_base;
+ struct evdns_getaddrinfo_request *request;
+ struct event cancel_event;
+ int canceled;
+};
+
+#define GAIC_MAGIC 0x1234abcd
+
+static int pending = 0;
+
+static void
+gaic_cancel_request_cb(evutil_socket_t fd, short what, void *arg)
+{
+ struct gaic_request_status *status = arg;
+
+ tt_assert(status->magic == GAIC_MAGIC);
+ status->canceled = 1;
+ evdns_getaddrinfo_cancel(status->request);
+ return;
+end:
+ event_base_loopexit(status->base, NULL);
+}
+
+static void
+gaic_server_cb(struct evdns_server_request *req, void *arg)
+{
+ ev_uint32_t answer = 0x7f000001;
+ tt_assert(req->nquestions);
+ evdns_server_request_add_a_reply(req, req->questions[0]->name, 1,
+ &answer, 100);
+ evdns_server_request_respond(req, 0);
+ return;
+end:
+ evdns_server_request_respond(req, DNS_ERR_REFUSED);
+}
+
+
+static void
+gaic_getaddrinfo_cb(int result, struct evutil_addrinfo *res, void *arg)
+{
+ struct gaic_request_status *status = arg;
+ struct event_base *base = status->base;
+ tt_assert(status->magic == GAIC_MAGIC);
+
+ if (result == EVUTIL_EAI_CANCEL) {
+ tt_assert(status->canceled);
+ }
+ event_del(&status->cancel_event);
+
+ memset(status, 0xf0, sizeof(*status));
+ free(status);
+
+end:
+ if (--pending <= 0)
+ event_base_loopexit(base, NULL);
+}
+
+static void
+gaic_launch(struct event_base *base, struct evdns_base *dns_base)
+{
+ struct gaic_request_status *status = calloc(1,sizeof(*status));
+ struct timeval tv = { 0, 10000 };
+ status->magic = GAIC_MAGIC;
+ status->base = base;
+ status->dns_base = dns_base;
+ event_assign(&status->cancel_event, base, -1, 0, gaic_cancel_request_cb,
+ status);
+ status->request = evdns_getaddrinfo(dns_base,
+ "foobar.bazquux.example.com", "80", NULL, gaic_getaddrinfo_cb,
+ status);
+ event_add(&status->cancel_event, &tv);
+ ++pending;
+}
+
+#ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
+/* FIXME: We should move this to regress_main.c if anything else needs it.*/
+
+/* Trivial replacements for malloc/free/realloc to check for memory leaks.
+ * Not threadsafe. */
+static int allocated_chunks = 0;
+
+static void *
+cnt_malloc(size_t sz)
+{
+ allocated_chunks += 1;
+ return malloc(sz);
+}
+
+static void *
+cnt_realloc(void *old, size_t sz)
+{
+ if (!old)
+ allocated_chunks += 1;
+ if (!sz)
+ allocated_chunks -= 1;
+ return realloc(old, sz);
+}
+
+static void
+cnt_free(void *ptr)
+{
+ allocated_chunks -= 1;
+ free(ptr);
+}
+
+struct testleak_env_t {
+ struct event_base *base;
+ struct evdns_base *dns_base;
+ struct evdns_request *req;
+ struct generic_dns_callback_result r;
+};
+
+static void *
+testleak_setup(const struct testcase_t *testcase)
+{
+ struct testleak_env_t *env;
+
+ allocated_chunks = 0;
+
+ /* Reset allocation counter, to start allocations from the very beginning.
+ * (this will avoid false-positive negative numbers for allocated_chunks)
+ */
+ libevent_global_shutdown();
+
+ event_set_mem_functions(cnt_malloc, cnt_realloc, cnt_free);
+
+ event_enable_debug_mode();
+
+ /* not mm_calloc: we don't want to mess with the count. */
+ env = calloc(1, sizeof(struct testleak_env_t));
+ env->base = event_base_new();
+ env->dns_base = evdns_base_new(env->base, 0);
+ env->req = evdns_base_resolve_ipv4(
+ env->dns_base, "example.com", DNS_QUERY_NO_SEARCH,
+ generic_dns_callback, &env->r);
+ return env;
+}
+
+static int
+testleak_cleanup(const struct testcase_t *testcase, void *env_)
+{
+ int ok = 0;
+ struct testleak_env_t *env = env_;
+ tt_assert(env);
+#ifdef EVENT__DISABLE_DEBUG_MODE
+ tt_int_op(allocated_chunks, ==, 0);
+#else
+ libevent_global_shutdown();
+ tt_int_op(allocated_chunks, ==, 0);
+#endif
+ ok = 1;
+end:
+ if (env) {
+ if (env->dns_base)
+ evdns_base_free(env->dns_base, 0);
+ if (env->base)
+ event_base_free(env->base);
+ free(env);
+ }
+ return ok;
+}
+
+static struct testcase_setup_t testleak_funcs = {
+ testleak_setup, testleak_cleanup
+};
+
+static void
+test_dbg_leak_cancel(void *env_)
+{
+ /* cancel, loop, free/dns, free/base */
+ struct testleak_env_t *env = env_;
+ int send_err_shutdown = 1;
+ evdns_cancel_request(env->dns_base, env->req);
+ env->req = 0;
+
+ /* `req` is freed in callback, that's why one loop is required. */
+ event_base_loop(env->base, EVLOOP_NONBLOCK);
+
+ /* send_err_shutdown means nothing as soon as our request is
+ * already canceled */
+ evdns_base_free(env->dns_base, send_err_shutdown);
+ env->dns_base = 0;
+ event_base_free(env->base);
+ env->base = 0;
+}
+
+static void
+dbg_leak_resume(void *env_, int cancel, int send_err_shutdown)
+{
+ /* cancel, loop, free/dns, free/base */
+ struct testleak_env_t *env = env_;
+ if (cancel) {
+ evdns_cancel_request(env->dns_base, env->req);
+ tt_assert(!evdns_base_resume(env->dns_base));
+ } else {
+ /* TODO: No nameservers, request can't be processed, must be errored */
+ tt_assert(!evdns_base_resume(env->dns_base));
+ }
+
+ event_base_loop(env->base, EVLOOP_NONBLOCK);
+ /**
+ * Because we don't cancel request, and want our callback to recieve
+ * DNS_ERR_SHUTDOWN, we use deferred callback, and there was:
+ * - one extra malloc(),
+ * @see reply_schedule_callback()
+ * - and one missing free
+ * @see request_finished() (req->handle->pending_cb = 1)
+ * than we don't need to count in testleak_cleanup(), but we can clean them
+ * if we will run loop once again, but *after* evdns base freed.
+ */
+ evdns_base_free(env->dns_base, send_err_shutdown);
+ env->dns_base = 0;
+ event_base_loop(env->base, EVLOOP_NONBLOCK);
+
+end:
+ event_base_free(env->base);
+ env->base = 0;
+}
+
+#define IMPL_DBG_LEAK_RESUME(name, cancel, send_err_shutdown) \
+ static void \
+ test_dbg_leak_##name##_(void *env_) \
+ { \
+ dbg_leak_resume(env_, cancel, send_err_shutdown); \
+ }
+IMPL_DBG_LEAK_RESUME(resume, 0, 0)
+IMPL_DBG_LEAK_RESUME(cancel_and_resume, 1, 0)
+IMPL_DBG_LEAK_RESUME(resume_send_err, 0, 1)
+IMPL_DBG_LEAK_RESUME(cancel_and_resume_send_err, 1, 1)
+
+static void
+test_dbg_leak_shutdown(void *env_)
+{
+ /* free/dns, loop, free/base */
+ struct testleak_env_t *env = env_;
+ int send_err_shutdown = 1;
+
+ /* `req` is freed both with `send_err_shutdown` and without it,
+ * the only difference is `evdns_callback` call */
+ env->req = 0;
+
+ evdns_base_free(env->dns_base, send_err_shutdown);
+ env->dns_base = 0;
+
+ /* `req` is freed in callback, that's why one loop is required */
+ event_base_loop(env->base, EVLOOP_NONBLOCK);
+ event_base_free(env->base);
+ env->base = 0;
+}
+#endif
+
+static void
+test_getaddrinfo_async_cancel_stress(void *ptr)
+{
+ struct event_base *base;
+ struct evdns_base *dns_base = NULL;
+ struct evdns_server_port *server = NULL;
+ evutil_socket_t fd = -1;
+ struct sockaddr_in sin;
+ struct sockaddr_storage ss;
+ ev_socklen_t slen;
+ int i;
+
+ base = event_base_new();
+ dns_base = evdns_base_new(base, 0);
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = 0;
+ sin.sin_addr.s_addr = htonl(0x7f000001);
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ tt_abort_perror("socket");
+ }
+ evutil_make_socket_nonblocking(fd);
+ if (bind(fd, (struct sockaddr*)&sin, sizeof(sin))<0) {
+ tt_abort_perror("bind");
+ }
+ server = evdns_add_server_port_with_base(base, fd, 0, gaic_server_cb,
+ base);
+
+ memset(&ss, 0, sizeof(ss));
+ slen = sizeof(ss);
+ if (getsockname(fd, (struct sockaddr*)&ss, &slen)<0) {
+ tt_abort_perror("getsockname");
+ }
+ evdns_base_nameserver_sockaddr_add(dns_base,
+ (struct sockaddr*)&ss, slen, 0);
+
+ for (i = 0; i < 1000; ++i) {
+ gaic_launch(base, dns_base);
+ }
+
+ event_base_dispatch(base);
+
+end:
+ if (dns_base)
+ evdns_base_free(dns_base, 1);
+ if (server)
+ evdns_close_server_port(server);
+ if (base)
+ event_base_free(base);
+ if (fd >= 0)
+ evutil_closesocket(fd);
+}
+
+static void
+dns_client_fail_requests_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_base *dns = NULL;
+ struct evdns_server_port *dns_port = NULL;
+ ev_uint16_t portnum = 0;
+ char buf[64];
+
+ struct generic_dns_callback_result r[20];
+ int i;
+
+ dns_port = regress_get_dnsserver(base, &portnum, NULL,
+ regress_dns_server_cb, reissue_table);
+ tt_assert(dns_port);
+
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+ dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+
+ for (i = 0; i < 20; ++i)
+ evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r[i]);
+
+ n_replies_left = 20;
+ exit_base = base;
+
+ evdns_base_free(dns, 1 /** fail requests */);
+ /** run defered callbacks, to trigger UAF */
+ event_base_dispatch(base);
+
+ tt_int_op(n_replies_left, ==, 0);
+ for (i = 0; i < 20; ++i)
+ tt_int_op(r[i].result, ==, DNS_ERR_SHUTDOWN);
+
+end:
+ evdns_close_server_port(dns_port);
+}
+
+static void
+getaddrinfo_cb(int err, struct evutil_addrinfo *res, void *ptr)
+{
+ generic_dns_callback(err, 0, 0, 0, NULL, ptr);
+}
+static void
+dns_client_fail_requests_getaddrinfo_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_base *dns = NULL;
+ struct evdns_server_port *dns_port = NULL;
+ ev_uint16_t portnum = 0;
+ char buf[64];
+
+ struct generic_dns_callback_result r[20];
+ int i;
+
+ dns_port = regress_get_dnsserver(base, &portnum, NULL,
+ regress_dns_server_cb, reissue_table);
+ tt_assert(dns_port);
+
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+ dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+
+ for (i = 0; i < 20; ++i)
+ tt_assert(evdns_getaddrinfo(dns, "foof.example.com", "http", NULL, getaddrinfo_cb, &r[i]));
+
+ n_replies_left = 20;
+ exit_base = base;
+
+ evdns_base_free(dns, 1 /** fail requests */);
+ /** run defered callbacks, to trigger UAF */
+ event_base_dispatch(base);
+
+ tt_int_op(n_replies_left, ==, 0);
+ for (i = 0; i < 20; ++i)
+ tt_int_op(r[i].result, ==, EVUTIL_EAI_FAIL);
+
+end:
+ evdns_close_server_port(dns_port);
+}
+
+
+#define DNS_LEGACY(name, flags) \
+ { #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup, \
+ dns_##name }
+
+struct testcase_t dns_testcases[] = {
+ DNS_LEGACY(server, TT_FORK|TT_NEED_BASE),
+ DNS_LEGACY(gethostbyname, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT),
+ DNS_LEGACY(gethostbyname6, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT),
+ DNS_LEGACY(gethostbyaddr, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT),
+ { "resolve_reverse", dns_resolve_reverse, TT_FORK|TT_OFF_BY_DEFAULT, NULL, NULL },
+ { "search_empty", dns_search_empty_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "search", dns_search_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "search_lower", dns_search_lower_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "search_cancel", dns_search_cancel_test,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "retry", dns_retry_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
+ { "retry_disable_when_inactive", dns_retry_disable_when_inactive_test,
+ TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
+ { "reissue", dns_reissue_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
+ { "reissue_disable_when_inactive", dns_reissue_disable_when_inactive_test,
+ TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
+ { "inflight", dns_inflight_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "bufferevent_connect_hostname", test_bufferevent_connect_hostname,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "disable_when_inactive", dns_disable_when_inactive_test,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "disable_when_inactive_no_ns", dns_disable_when_inactive_no_ns_test,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+
+ { "getaddrinfo_async", test_getaddrinfo_async,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"" },
+ { "getaddrinfo_cancel_stress", test_getaddrinfo_async_cancel_stress,
+ TT_FORK, NULL, NULL },
+
+#ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
+ { "leak_shutdown", test_dbg_leak_shutdown, TT_FORK, &testleak_funcs, NULL },
+ { "leak_cancel", test_dbg_leak_cancel, TT_FORK, &testleak_funcs, NULL },
+
+ { "leak_resume", test_dbg_leak_resume_, TT_FORK, &testleak_funcs, NULL },
+ { "leak_cancel_and_resume", test_dbg_leak_cancel_and_resume_,
+ TT_FORK, &testleak_funcs, NULL },
+ { "leak_resume_send_err", test_dbg_leak_resume_send_err_,
+ TT_FORK, &testleak_funcs, NULL },
+ { "leak_cancel_and_resume_send_err", test_dbg_leak_cancel_and_resume_send_err_,
+ TT_FORK, &testleak_funcs, NULL },
+#endif
+
+ { "client_fail_requests", dns_client_fail_requests_test,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "client_fail_requests_getaddrinfo",
+ dns_client_fail_requests_getaddrinfo_test,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_et.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_et.c
new file mode 100644
index 000000000..f75c59b3b
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_et.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "../util-internal.h"
+#include "event2/event-config.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include "event2/event.h"
+#include "event2/util.h"
+
+#include "regress.h"
+
+static int was_et = 0;
+
+static void
+read_cb(evutil_socket_t fd, short event, void *arg)
+{
+ char buf;
+ int len;
+
+ len = recv(fd, &buf, sizeof(buf), 0);
+
+ called++;
+ if (event & EV_ET)
+ was_et = 1;
+
+ if (!len)
+ event_del(arg);
+}
+
+#ifdef _WIN32
+#define LOCAL_SOCKETPAIR_AF AF_INET
+#else
+#define LOCAL_SOCKETPAIR_AF AF_UNIX
+#endif
+
+static void
+test_edgetriggered(void *et)
+{
+ struct event *ev = NULL;
+ struct event_base *base = NULL;
+ const char *test = "test string";
+ evutil_socket_t pair[2] = {-1,-1};
+ int supports_et;
+
+ /* On Linux 3.2.1 (at least, as patched by Fedora and tested by Nick),
+ * doing a "recv" on an AF_UNIX socket resets the readability of the
+ * socket, even though there is no state change, so we don't actually
+ * get edge-triggered behavior. Yuck! Linux 3.1.9 didn't have this
+ * problem.
+ */
+#ifdef __linux__
+ if (evutil_ersatz_socketpair_(AF_INET, SOCK_STREAM, 0, pair) == -1) {
+ tt_abort_perror("socketpair");
+ }
+#else
+ if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair) == -1) {
+ tt_abort_perror("socketpair");
+ }
+#endif
+
+ called = was_et = 0;
+
+ tt_int_op(send(pair[0], test, (int)strlen(test)+1, 0), >, 0);
+ shutdown(pair[0], EVUTIL_SHUT_WR);
+
+ /* Initalize the event library */
+ base = event_base_new();
+
+ if (!strcmp(event_base_get_method(base), "epoll") ||
+ !strcmp(event_base_get_method(base), "epoll (with changelist)") ||
+ !strcmp(event_base_get_method(base), "kqueue"))
+ supports_et = 1;
+ else
+ supports_et = 0;
+
+ TT_BLATHER(("Checking for edge-triggered events with %s, which should %s"
+ "support edge-triggering", event_base_get_method(base),
+ supports_et?"":"not "));
+
+ /* Initalize one event */
+ ev = event_new(base, pair[1], EV_READ|EV_ET|EV_PERSIST, read_cb, &ev);
+
+ event_add(ev, NULL);
+
+ /* We're going to call the dispatch function twice. The first invocation
+ * will read a single byte from pair[1] in either case. If we're edge
+ * triggered, we'll only see the event once (since we only see transitions
+ * from no data to data), so the second invocation of event_base_loop will
+ * do nothing. If we're level triggered, the second invocation of
+ * event_base_loop will also activate the event (because there's still
+ * data to read). */
+ event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE);
+ event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE);
+
+ if (supports_et) {
+ tt_int_op(called, ==, 1);
+ tt_assert(was_et);
+ } else {
+ tt_int_op(called, ==, 2);
+ tt_assert(!was_et);
+ }
+
+ end:
+ if (ev) {
+ event_del(ev);
+ event_free(ev);
+ }
+ if (base)
+ event_base_free(base);
+ evutil_closesocket(pair[0]);
+ evutil_closesocket(pair[1]);
+}
+
+static void
+test_edgetriggered_mix_error(void *data_)
+{
+ struct basic_test_data *data = data_;
+ struct event_base *base = NULL;
+ struct event *ev_et=NULL, *ev_lt=NULL;
+
+#ifdef EVENT__DISABLE_DEBUG_MODE
+ if (1)
+ tt_skip();
+#endif
+
+ if (!libevent_tests_running_in_debug_mode)
+ event_enable_debug_mode();
+
+ base = event_base_new();
+
+ /* try mixing edge-triggered and level-triggered to make sure it fails*/
+ ev_et = event_new(base, data->pair[0], EV_READ|EV_ET, read_cb, ev_et);
+ tt_assert(ev_et);
+ ev_lt = event_new(base, data->pair[0], EV_READ, read_cb, ev_lt);
+ tt_assert(ev_lt);
+
+ /* Add edge-triggered, then level-triggered. Get an error. */
+ tt_int_op(0, ==, event_add(ev_et, NULL));
+ tt_int_op(-1, ==, event_add(ev_lt, NULL));
+ tt_int_op(EV_READ, ==, event_pending(ev_et, EV_READ, NULL));
+ tt_int_op(0, ==, event_pending(ev_lt, EV_READ, NULL));
+
+ tt_int_op(0, ==, event_del(ev_et));
+ /* Add level-triggered, then edge-triggered. Get an error. */
+ tt_int_op(0, ==, event_add(ev_lt, NULL));
+ tt_int_op(-1, ==, event_add(ev_et, NULL));
+ tt_int_op(EV_READ, ==, event_pending(ev_lt, EV_READ, NULL));
+ tt_int_op(0, ==, event_pending(ev_et, EV_READ, NULL));
+
+end:
+ if (ev_et)
+ event_free(ev_et);
+ if (ev_lt)
+ event_free(ev_lt);
+ if (base)
+ event_base_free(base);
+}
+
+struct testcase_t edgetriggered_testcases[] = {
+ { "et", test_edgetriggered, TT_FORK, NULL, NULL },
+ { "et_mix_error", test_edgetriggered_mix_error,
+ TT_FORK|TT_NEED_SOCKETPAIR|TT_NO_LOGS, &basic_setup, NULL },
+ END_OF_TESTCASES
+};
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_finalize.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_finalize.c
new file mode 100644
index 000000000..552210fe9
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_finalize.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2013 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+#include "tinytest.h"
+#include "tinytest_macros.h"
+#include <stdlib.h>
+
+#include "event2/event.h"
+#include "event2/util.h"
+#include "event-internal.h"
+#include "defer-internal.h"
+
+#include "regress.h"
+#include "regress_thread.h"
+
+static void
+timer_callback(evutil_socket_t fd, short what, void *arg)
+{
+ int *int_arg = arg;
+ *int_arg += 1;
+ (void)fd;
+ (void)what;
+}
+static void
+simple_callback(struct event_callback *evcb, void *arg)
+{
+ int *int_arg = arg;
+ *int_arg += 1;
+ (void)evcb;
+}
+static void
+event_finalize_callback_1(struct event *ev, void *arg)
+{
+ int *int_arg = arg;
+ *int_arg += 100;
+ (void)ev;
+}
+static void
+callback_finalize_callback_1(struct event_callback *evcb, void *arg)
+{
+ int *int_arg = arg;
+ *int_arg += 100;
+ (void)evcb;
+}
+
+
+static void
+test_fin_cb_invoked(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+
+ struct event *ev;
+ struct event ev2;
+ struct event_callback evcb;
+ int cb_called = 0;
+ int ev_called = 0;
+
+ const struct timeval ten_sec = {10,0};
+
+ event_deferred_cb_init_(&evcb, 0, simple_callback, &cb_called);
+ ev = evtimer_new(base, timer_callback, &ev_called);
+ /* Just finalize them; don't bother adding. */
+ event_free_finalize(0, ev, event_finalize_callback_1);
+ event_callback_finalize_(base, 0, &evcb, callback_finalize_callback_1);
+
+ event_base_dispatch(base);
+
+ tt_int_op(cb_called, ==, 100);
+ tt_int_op(ev_called, ==, 100);
+
+ ev_called = cb_called = 0;
+ event_base_assert_ok_(base);
+
+ /* Now try it when they're active. (actually, don't finalize: make
+ * sure activation can happen! */
+ ev = evtimer_new(base, timer_callback, &ev_called);
+ event_deferred_cb_init_(&evcb, 0, simple_callback, &cb_called);
+
+ event_active(ev, EV_TIMEOUT, 1);
+ event_callback_activate_(base, &evcb);
+
+ event_base_dispatch(base);
+ tt_int_op(cb_called, ==, 1);
+ tt_int_op(ev_called, ==, 1);
+
+ ev_called = cb_called = 0;
+ event_base_assert_ok_(base);
+
+ /* Great, it worked. Now activate and finalize and make sure only
+ * finalizing happens. */
+ event_active(ev, EV_TIMEOUT, 1);
+ event_callback_activate_(base, &evcb);
+ event_free_finalize(0, ev, event_finalize_callback_1);
+ event_callback_finalize_(base, 0, &evcb, callback_finalize_callback_1);
+
+ event_base_dispatch(base);
+ tt_int_op(cb_called, ==, 100);
+ tt_int_op(ev_called, ==, 100);
+
+ ev_called = 0;
+
+ event_base_assert_ok_(base);
+
+ /* Okay, now add but don't have it become active, and make sure *that*
+ * works. */
+ ev = evtimer_new(base, timer_callback, &ev_called);
+ event_add(ev, &ten_sec);
+ event_free_finalize(0, ev, event_finalize_callback_1);
+
+ event_base_dispatch(base);
+ tt_int_op(ev_called, ==, 100);
+
+ ev_called = 0;
+ event_base_assert_ok_(base);
+
+ /* Now try adding and deleting after finalizing. */
+ ev = evtimer_new(base, timer_callback, &ev_called);
+ evtimer_assign(&ev2, base, timer_callback, &ev_called);
+ event_add(ev, &ten_sec);
+ event_free_finalize(0, ev, event_finalize_callback_1);
+ event_finalize(0, &ev2, event_finalize_callback_1);
+
+ event_add(&ev2, &ten_sec);
+ event_del(ev);
+ event_active(&ev2, EV_TIMEOUT, 1);
+
+ event_base_dispatch(base);
+ tt_int_op(ev_called, ==, 200);
+
+ event_base_assert_ok_(base);
+
+end:
+ ;
+}
+
+#ifndef EVENT__DISABLE_MM_REPLACEMENT
+static void *
+tfff_malloc(size_t n)
+{
+ return malloc(n);
+}
+static void *tfff_p1=NULL, *tfff_p2=NULL;
+static int tfff_p1_freed=0, tfff_p2_freed=0;
+static void
+tfff_free(void *p)
+{
+ if (! p)
+ return;
+ if (p == tfff_p1)
+ ++tfff_p1_freed;
+ if (p == tfff_p2)
+ ++tfff_p2_freed;
+ free(p);
+}
+static void *
+tfff_realloc(void *p, size_t sz)
+{
+ return realloc(p,sz);
+}
+#endif
+
+static void
+test_fin_free_finalize(void *arg)
+{
+#ifdef EVENT__DISABLE_MM_REPLACEMENT
+ tinytest_set_test_skipped_();
+#else
+ struct event_base *base = NULL;
+ struct event *ev, *ev2;
+ int ev_called = 0;
+ int ev2_called = 0;
+
+ (void)arg;
+
+ event_set_mem_functions(tfff_malloc, tfff_realloc, tfff_free);
+
+ base = event_base_new();
+ tt_assert(base);
+
+ ev = evtimer_new(base, timer_callback, &ev_called);
+ ev2 = evtimer_new(base, timer_callback, &ev2_called);
+ tfff_p1 = ev;
+ tfff_p2 = ev2;
+ event_free_finalize(0, ev, event_finalize_callback_1);
+ event_finalize(0, ev2, event_finalize_callback_1);
+
+ event_base_dispatch(base);
+
+ tt_int_op(ev_called, ==, 100);
+ tt_int_op(ev2_called, ==, 100);
+
+ event_base_assert_ok_(base);
+ tt_int_op(tfff_p1_freed, ==, 1);
+ tt_int_op(tfff_p2_freed, ==, 0);
+
+ event_free(ev2);
+
+end:
+ if (base)
+ event_base_free(base);
+#endif
+}
+
+/* For test_fin_within_cb */
+struct event_and_count {
+ struct event *ev;
+ struct event *ev2;
+ int count;
+};
+static void
+event_finalize_callback_2(struct event *ev, void *arg)
+{
+ struct event_and_count *evc = arg;
+ evc->count += 100;
+ event_free(ev);
+}
+static void
+timer_callback_2(evutil_socket_t fd, short what, void *arg)
+{
+ struct event_and_count *evc = arg;
+ event_finalize(0, evc->ev, event_finalize_callback_2);
+ event_finalize(0, evc->ev2, event_finalize_callback_2);
+ ++ evc->count;
+ (void)fd;
+ (void)what;
+}
+
+static void
+test_fin_within_cb(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+
+ struct event_and_count evc1, evc2;
+ evc1.count = evc2.count = 0;
+ evc2.ev2 = evc1.ev = evtimer_new(base, timer_callback_2, &evc1);
+ evc1.ev2 = evc2.ev = evtimer_new(base, timer_callback_2, &evc2);
+
+ /* Activate both. The first one will have its callback run, which
+ * will finalize both of them, preventing the second one's callback
+ * from running. */
+ event_active(evc1.ev, EV_TIMEOUT, 1);
+ event_active(evc2.ev, EV_TIMEOUT, 1);
+
+ event_base_dispatch(base);
+ tt_int_op(evc1.count, ==, 101);
+ tt_int_op(evc2.count, ==, 100);
+
+ event_base_assert_ok_(base);
+ /* Now try with EV_PERSIST events. */
+ evc1.count = evc2.count = 0;
+ evc2.ev2 = evc1.ev = event_new(base, -1, EV_PERSIST, timer_callback_2, &evc1);
+ evc1.ev2 = evc2.ev = event_new(base, -1, EV_PERSIST, timer_callback_2, &evc2);
+
+ event_active(evc1.ev, EV_TIMEOUT, 1);
+ event_active(evc2.ev, EV_TIMEOUT, 1);
+
+ event_base_dispatch(base);
+ tt_int_op(evc1.count, ==, 101);
+ tt_int_op(evc2.count, ==, 100);
+
+ event_base_assert_ok_(base);
+end:
+ ;
+}
+
+#if 0
+static void
+timer_callback_3(evutil_socket_t *fd, short what, void *arg)
+{
+ (void)fd;
+ (void)what;
+
+}
+static void
+test_fin_many(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+
+ struct event *ev1, *ev2;
+ struct event_callback evcb1, evcb2;
+ int ev1_count = 0, ev2_count = 0;
+ int evcb1_count = 0, evcb2_count = 0;
+ struct event_callback *array[4];
+
+ int n;
+
+ /* First attempt: call finalize_many with no events running */
+ ev1 = evtimer_new(base, timer_callback, &ev1_count);
+ ev1 = evtimer_new(base, timer_callback, &ev2_count);
+ event_deferred_cb_init_(&evcb1, 0, simple_callback, &evcb1_called);
+ event_deferred_cb_init_(&evcb2, 0, simple_callback, &evcb2_called);
+ array[0] = &ev1->ev_evcallback;
+ array[1] = &ev2->ev_evcallback;
+ array[2] = &evcb1;
+ array[3] = &evcb2;
+
+
+
+ n = event_callback_finalize_many(base, 4, array,
+ callback_finalize_callback_1);
+
+}
+#endif
+
+
+#define TEST(name, flags) \
+ { #name, test_fin_##name, (flags), &basic_setup, NULL }
+
+struct testcase_t finalize_testcases[] = {
+
+ TEST(cb_invoked, TT_FORK|TT_NEED_BASE),
+ TEST(free_finalize, TT_FORK),
+ TEST(within_cb, TT_FORK|TT_NEED_BASE),
+// TEST(many, TT_FORK|TT_NEED_BASE),
+
+
+ END_OF_TESTCASES
+};
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_http.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_http.c
new file mode 100644
index 000000000..911707bc2
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_http.c
@@ -0,0 +1,4640 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util-internal.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event2/dns.h"
+
+#include "event2/event.h"
+#include "event2/http.h"
+#include "event2/buffer.h"
+#include "event2/bufferevent.h"
+#include "event2/bufferevent_ssl.h"
+#include "event2/util.h"
+#include "event2/listener.h"
+#include "log-internal.h"
+#include "http-internal.h"
+#include "regress.h"
+#include "regress_testutils.h"
+
+/* set if a test needs to call loopexit on a base */
+static struct event_base *exit_base;
+
+static char const BASIC_REQUEST_BODY[] = "This is funny";
+
+static void http_basic_cb(struct evhttp_request *req, void *arg);
+static void http_large_cb(struct evhttp_request *req, void *arg);
+static void http_chunked_cb(struct evhttp_request *req, void *arg);
+static void http_post_cb(struct evhttp_request *req, void *arg);
+static void http_put_cb(struct evhttp_request *req, void *arg);
+static void http_delete_cb(struct evhttp_request *req, void *arg);
+static void http_delay_cb(struct evhttp_request *req, void *arg);
+static void http_large_delay_cb(struct evhttp_request *req, void *arg);
+static void http_badreq_cb(struct evhttp_request *req, void *arg);
+static void http_dispatcher_cb(struct evhttp_request *req, void *arg);
+static void http_on_complete_cb(struct evhttp_request *req, void *arg);
+
+#define HTTP_BIND_IPV6 1
+#define HTTP_BIND_SSL 2
+static int
+http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int mask)
+{
+ int port;
+ struct evhttp_bound_socket *sock;
+ int ipv6 = mask & HTTP_BIND_IPV6;
+
+ if (ipv6)
+ sock = evhttp_bind_socket_with_handle(myhttp, "::1", *pport);
+ else
+ sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport);
+
+ if (sock == NULL) {
+ if (ipv6)
+ return -1;
+ else
+ event_errx(1, "Could not start web server");
+ }
+
+ port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
+ if (port < 0)
+ return -1;
+ *pport = (ev_uint16_t) port;
+
+ return 0;
+}
+
+#ifdef EVENT__HAVE_OPENSSL
+static struct bufferevent *
+https_bev(struct event_base *base, void *arg)
+{
+ SSL *ssl = SSL_new(get_ssl_ctx());
+
+ SSL_use_certificate(ssl, ssl_getcert());
+ SSL_use_PrivateKey(ssl, ssl_getkey());
+
+ return bufferevent_openssl_socket_new(
+ base, -1, ssl, BUFFEREVENT_SSL_ACCEPTING,
+ BEV_OPT_CLOSE_ON_FREE);
+}
+#endif
+static struct evhttp *
+http_setup(ev_uint16_t *pport, struct event_base *base, int mask)
+{
+ struct evhttp *myhttp;
+
+ /* Try a few different ports */
+ myhttp = evhttp_new(base);
+
+ if (http_bind(myhttp, pport, mask) < 0)
+ return NULL;
+#ifdef EVENT__HAVE_OPENSSL
+ if (mask & HTTP_BIND_SSL) {
+ init_ssl();
+ evhttp_set_bevcb(myhttp, https_bev, NULL);
+ }
+#endif
+
+ /* Register a callback for certain types of requests */
+ evhttp_set_cb(myhttp, "/test", http_basic_cb, myhttp);
+ evhttp_set_cb(myhttp, "/large", http_large_cb, base);
+ evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base);
+ evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base);
+ evhttp_set_cb(myhttp, "/postit", http_post_cb, base);
+ evhttp_set_cb(myhttp, "/putit", http_put_cb, base);
+ evhttp_set_cb(myhttp, "/deleteit", http_delete_cb, base);
+ evhttp_set_cb(myhttp, "/delay", http_delay_cb, base);
+ evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base);
+ evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base);
+ evhttp_set_cb(myhttp, "/oncomplete", http_on_complete_cb, base);
+ evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base);
+ return (myhttp);
+}
+
+#ifndef NI_MAXSERV
+#define NI_MAXSERV 1024
+#endif
+
+static evutil_socket_t
+http_connect(const char *address, ev_uint16_t port)
+{
+ /* Stupid code for connecting */
+ struct evutil_addrinfo ai, *aitop;
+ char strport[NI_MAXSERV];
+
+ struct sockaddr *sa;
+ int slen;
+ evutil_socket_t fd;
+
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_family = AF_INET;
+ ai.ai_socktype = SOCK_STREAM;
+ evutil_snprintf(strport, sizeof(strport), "%d", port);
+ if (evutil_getaddrinfo(address, strport, &ai, &aitop) != 0) {
+ event_warn("getaddrinfo");
+ return (-1);
+ }
+ sa = aitop->ai_addr;
+ slen = aitop->ai_addrlen;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd == -1)
+ event_err(1, "socket failed");
+
+ evutil_make_socket_nonblocking(fd);
+ if (connect(fd, sa, slen) == -1) {
+#ifdef _WIN32
+ int tmp_err = WSAGetLastError();
+ if (tmp_err != WSAEINPROGRESS && tmp_err != WSAEINVAL &&
+ tmp_err != WSAEWOULDBLOCK)
+ event_err(1, "connect failed");
+#else
+ if (errno != EINPROGRESS)
+ event_err(1, "connect failed");
+#endif
+ }
+
+ evutil_freeaddrinfo(aitop);
+
+ return (fd);
+}
+
+/* Helper: do a strcmp on the contents of buf and the string s. */
+static int
+evbuffer_datacmp(struct evbuffer *buf, const char *s)
+{
+ size_t b_sz = evbuffer_get_length(buf);
+ size_t s_sz = strlen(s);
+ unsigned char *d;
+ int r;
+
+ if (b_sz < s_sz)
+ return -1;
+
+ d = evbuffer_pullup(buf, s_sz);
+ if ((r = memcmp(d, s, s_sz)))
+ return r;
+
+ if (b_sz > s_sz)
+ return 1;
+ else
+ return 0;
+}
+
+/* Helper: Return true iff buf contains s */
+static int
+evbuffer_contains(struct evbuffer *buf, const char *s)
+{
+ struct evbuffer_ptr ptr;
+ ptr = evbuffer_search(buf, s, strlen(s), NULL);
+ return ptr.pos != -1;
+}
+
+static void
+http_readcb(struct bufferevent *bev, void *arg)
+{
+ const char *what = BASIC_REQUEST_BODY;
+ struct event_base *my_base = arg;
+
+ if (evbuffer_contains(bufferevent_get_input(bev), what)) {
+ struct evhttp_request *req = evhttp_request_new(NULL, NULL);
+ enum message_read_status done;
+
+ /* req->kind = EVHTTP_RESPONSE; */
+ done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
+ if (done != ALL_DATA_READ)
+ goto out;
+
+ done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
+ if (done != ALL_DATA_READ)
+ goto out;
+
+ if (done == 1 &&
+ evhttp_find_header(evhttp_request_get_input_headers(req),
+ "Content-Type") != NULL)
+ test_ok++;
+
+ out:
+ evhttp_request_free(req);
+ bufferevent_disable(bev, EV_READ);
+ if (exit_base)
+ event_base_loopexit(exit_base, NULL);
+ else if (my_base)
+ event_base_loopexit(my_base, NULL);
+ else {
+ fprintf(stderr, "No way to exit loop!\n");
+ exit(1);
+ }
+ }
+}
+
+static void
+http_writecb(struct bufferevent *bev, void *arg)
+{
+ if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
+ /* enable reading of the reply */
+ bufferevent_enable(bev, EV_READ);
+ test_ok++;
+ }
+}
+
+static void
+http_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ /** For ssl */
+ if (what & BEV_EVENT_CONNECTED)
+ return;
+ test_ok = -2;
+ event_base_loopexit(arg, NULL);
+}
+
+static int found_multi = 0;
+static int found_multi2 = 0;
+
+static void
+http_basic_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb = evbuffer_new();
+ struct evhttp_connection *evcon;
+ int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
+ event_debug(("%s: called\n", __func__));
+ evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
+
+ evcon = evhttp_request_get_connection(req);
+ tt_assert(evhttp_connection_get_server(evcon) == arg);
+
+ /* For multi-line headers test */
+ {
+ const char *multi =
+ evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi");
+ if (multi) {
+ found_multi = !strcmp(multi,"aaaaaaaa a END");
+ if (strcmp("END", multi + strlen(multi) - 3) == 0)
+ test_ok++;
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last"))
+ test_ok++;
+ }
+ }
+ {
+ const char *multi2 =
+ evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi-Extra-WS");
+ if (multi2) {
+ found_multi2 = !strcmp(multi2,"libevent 2.1");
+ }
+ }
+
+
+ /* injecting a bad content-length */
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Negative"))
+ evhttp_add_header(evhttp_request_get_output_headers(req),
+ "Content-Length", "-100");
+
+ /* allow sending of an empty reply */
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine",
+ !empty ? evb : NULL);
+
+end:
+ evbuffer_free(evb);
+}
+
+static void
+http_large_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb = evbuffer_new();
+ int i;
+
+ for (i = 0; i < 1<<20; ++i) {
+ evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
+ }
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+ evbuffer_free(evb);
+}
+
+static char const* const CHUNKS[] = {
+ "This is funny",
+ "but not hilarious.",
+ "bwv 1052"
+};
+
+struct chunk_req_state {
+ struct event_base *base;
+ struct evhttp_request *req;
+ int i;
+};
+
+static void
+http_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
+{
+ struct evbuffer *evb = evbuffer_new();
+ struct chunk_req_state *state = arg;
+ struct timeval when = { 0, 0 };
+
+ evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
+ evhttp_send_reply_chunk(state->req, evb);
+ evbuffer_free(evb);
+
+ if (++state->i < (int) (sizeof(CHUNKS)/sizeof(CHUNKS[0]))) {
+ event_base_once(state->base, -1, EV_TIMEOUT,
+ http_chunked_trickle_cb, state, &when);
+ } else {
+ evhttp_send_reply_end(state->req);
+ free(state);
+ }
+}
+
+static void
+http_chunked_cb(struct evhttp_request *req, void *arg)
+{
+ struct timeval when = { 0, 0 };
+ struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
+ event_debug(("%s: called\n", __func__));
+
+ memset(state, 0, sizeof(struct chunk_req_state));
+ state->req = req;
+ state->base = arg;
+
+ if (strcmp(evhttp_request_get_uri(req), "/streamed") == 0) {
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "39");
+ }
+
+ /* generate a chunked/streamed reply */
+ evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
+
+ /* but trickle it across several iterations to ensure we're not
+ * assuming it comes all at once */
+ event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
+}
+
+static void
+http_complete_write(evutil_socket_t fd, short what, void *arg)
+{
+ struct bufferevent *bev = arg;
+ const char *http_request = "host\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+ bufferevent_write(bev, http_request, strlen(http_request));
+}
+
+static struct bufferevent *
+create_bev(struct event_base *base, int fd, int ssl)
+{
+ int flags = BEV_OPT_DEFER_CALLBACKS;
+ struct bufferevent *bev = NULL;
+
+ if (!ssl) {
+ bev = bufferevent_socket_new(base, fd, flags);
+ } else {
+#ifdef EVENT__HAVE_OPENSSL
+ SSL *ssl = SSL_new(get_ssl_ctx());
+ bev = bufferevent_openssl_socket_new(
+ base, fd, ssl, BUFFEREVENT_SSL_CONNECTING, flags);
+ bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
+#endif
+ }
+
+ return bev;
+}
+
+static void
+http_basic_test_impl(void *arg, int ssl)
+{
+ struct basic_test_data *data = arg;
+ struct timeval tv;
+ struct bufferevent *bev = NULL;
+ evutil_socket_t fd;
+ const char *http_request;
+ ev_uint16_t port = 0, port2 = 0;
+ int server_flags = ssl ? HTTP_BIND_SSL : 0;
+ struct evhttp *http = http_setup(&port, data->base, server_flags);
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ /* bind to a second socket */
+ if (http_bind(http, &port2, server_flags) == -1) {
+ fprintf(stdout, "FAILED (bind)\n");
+ exit(1);
+ }
+
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = create_bev(data->base, fd, ssl);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ /* first half of the http request */
+ http_request =
+ "GET /test HTTP/1.1\r\n"
+ "Host: some";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+ evutil_timerclear(&tv);
+ tv.tv_usec = 100000;
+ event_base_once(data->base,
+ -1, EV_TIMEOUT, http_complete_write, bev, &tv);
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 3);
+
+ /* connect to the second port */
+ bufferevent_free(bev);
+ evutil_closesocket(fd);
+
+ fd = http_connect("127.0.0.1", port2);
+
+ /* Stupid thing to send a request */
+ bev = create_bev(data->base, fd, ssl);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ http_request =
+ "GET /test HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 5);
+
+ /* Connect to the second port again. This time, send an absolute uri. */
+ bufferevent_free(bev);
+ evutil_closesocket(fd);
+
+ fd = http_connect("127.0.0.1", port2);
+
+ /* Stupid thing to send a request */
+ bev = create_bev(data->base, fd, ssl);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ http_request =
+ "GET http://somehost.net/test HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 7);
+
+ evhttp_free(http);
+ end:
+ if (bev)
+ bufferevent_free(bev);
+}
+static void http_basic_test(void *arg)
+{ return http_basic_test_impl(arg, 0); }
+
+
+static void
+http_delay_reply(evutil_socket_t fd, short what, void *arg)
+{
+ struct evhttp_request *req = arg;
+
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
+
+ ++test_ok;
+}
+
+static void
+http_delay_cb(struct evhttp_request *req, void *arg)
+{
+ struct timeval tv;
+ evutil_timerclear(&tv);
+ tv.tv_sec = 0;
+ tv.tv_usec = 200 * 1000;
+
+ event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
+}
+
+static void
+http_badreq_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *buf = evbuffer_new();
+
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml; charset=UTF-8");
+ evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
+
+ evhttp_send_reply(req, HTTP_OK, "OK", buf);
+ evbuffer_free(buf);
+}
+
+static void
+http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
+ /* ignore */
+}
+
+static void
+http_badreq_readcb(struct bufferevent *bev, void *arg)
+{
+ const char *what = "Hello, 127.0.0.1";
+ const char *bad_request = "400 Bad Request";
+
+ if (evbuffer_contains(bufferevent_get_input(bev), bad_request)) {
+ TT_FAIL(("%s:bad request detected", __func__));
+ bufferevent_disable(bev, EV_READ);
+ event_base_loopexit(arg, NULL);
+ return;
+ }
+
+ if (evbuffer_contains(bufferevent_get_input(bev), what)) {
+ struct evhttp_request *req = evhttp_request_new(NULL, NULL);
+ enum message_read_status done;
+
+ /* req->kind = EVHTTP_RESPONSE; */
+ done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
+ if (done != ALL_DATA_READ)
+ goto out;
+
+ done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
+ if (done != ALL_DATA_READ)
+ goto out;
+
+ if (done == 1 &&
+ evhttp_find_header(evhttp_request_get_input_headers(req),
+ "Content-Type") != NULL)
+ test_ok++;
+
+ out:
+ evhttp_request_free(req);
+ evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev)));
+ }
+
+ shutdown(bufferevent_getfd(bev), EVUTIL_SHUT_WR);
+}
+
+static void
+http_badreq_successcb(evutil_socket_t fd, short what, void *arg)
+{
+ event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
+ event_base_loopexit(exit_base, NULL);
+}
+
+static void
+http_bad_request_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct timeval tv;
+ struct bufferevent *bev = NULL;
+ evutil_socket_t fd = -1;
+ const char *http_request;
+ ev_uint16_t port=0, port2=0;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ test_ok = 0;
+ exit_base = data->base;
+
+ /* bind to a second socket */
+ if (http_bind(http, &port2, 0) == -1)
+ TT_DIE(("Bind socket failed"));
+
+ /* NULL request test */
+ fd = http_connect("127.0.0.1", port);
+ tt_int_op(fd, >=, 0);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
+ http_badreq_errorcb, data->base);
+ bufferevent_enable(bev, EV_READ);
+
+ /* real NULL request */
+ http_request = "";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ shutdown(fd, EVUTIL_SHUT_WR);
+ timerclear(&tv);
+ tv.tv_usec = 10000;
+ event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
+
+ event_base_dispatch(data->base);
+
+ bufferevent_free(bev);
+ evutil_closesocket(fd);
+
+ if (test_ok != 0) {
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+ }
+
+ /* Second answer (BAD REQUEST) on connection close */
+
+ /* connect to the second port */
+ fd = http_connect("127.0.0.1", port2);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
+ http_badreq_errorcb, data->base);
+ bufferevent_enable(bev, EV_READ);
+
+ /* first half of the http request */
+ http_request =
+ "GET /badrequest HTTP/1.0\r\n" \
+ "Connection: Keep-Alive\r\n" \
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ timerclear(&tv);
+ tv.tv_usec = 10000;
+ event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 2);
+
+end:
+ evhttp_free(http);
+ if (bev)
+ bufferevent_free(bev);
+ if (fd >= 0)
+ evutil_closesocket(fd);
+}
+
+static struct evhttp_connection *delayed_client;
+
+static void
+http_large_delay_cb(struct evhttp_request *req, void *arg)
+{
+ struct timeval tv;
+ evutil_timerclear(&tv);
+ tv.tv_usec = 500000;
+
+ event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
+ evhttp_connection_fail_(delayed_client, EVREQ_HTTP_EOF);
+}
+
+/*
+ * HTTP DELETE test, just piggyback on the basic test
+ */
+
+static void
+http_delete_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb = evbuffer_new();
+ int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
+
+ /* Expecting a DELETE request */
+ if (evhttp_request_get_command(req) != EVHTTP_REQ_DELETE) {
+ fprintf(stdout, "FAILED (delete type)\n");
+ exit(1);
+ }
+
+ event_debug(("%s: called\n", __func__));
+ evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
+
+ /* allow sending of an empty reply */
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine",
+ !empty ? evb : NULL);
+
+ evbuffer_free(evb);
+}
+
+static void
+http_delete_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev;
+ evutil_socket_t fd = -1;
+ const char *http_request;
+ ev_uint16_t port = 0;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ tt_assert(http);
+ fd = http_connect("127.0.0.1", port);
+ tt_int_op(fd, >=, 0);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ http_request =
+ "DELETE /deleteit HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ bufferevent_free(bev);
+ evutil_closesocket(fd);
+ fd = -1;
+
+ evhttp_free(http);
+
+ tt_int_op(test_ok, ==, 2);
+ end:
+ if (fd >= 0)
+ evutil_closesocket(fd);
+}
+
+static void
+http_sent_cb(struct evhttp_request *req, void *arg)
+{
+ ev_uintptr_t val = (ev_uintptr_t)arg;
+ struct evbuffer *b;
+
+ if (val != 0xDEADBEEF) {
+ fprintf(stdout, "FAILED on_complete_cb argument\n");
+ exit(1);
+ }
+
+ b = evhttp_request_get_output_buffer(req);
+ if (evbuffer_get_length(b) != 0) {
+ fprintf(stdout, "FAILED on_complete_cb output buffer not written\n");
+ exit(1);
+ }
+
+ event_debug(("%s: called\n", __func__));
+
+ ++test_ok;
+}
+
+static void
+http_on_complete_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb = evbuffer_new();
+
+ evhttp_request_set_on_complete_cb(req, http_sent_cb, (void *)0xDEADBEEF);
+
+ event_debug(("%s: called\n", __func__));
+ evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
+
+ /* allow sending of an empty reply */
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+ evbuffer_free(evb);
+
+ ++test_ok;
+}
+
+static void
+http_on_complete_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev;
+ evutil_socket_t fd = -1;
+ const char *http_request;
+ ev_uint16_t port = 0;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ fd = http_connect("127.0.0.1", port);
+ tt_int_op(fd, >=, 0);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ http_request =
+ "GET /oncomplete HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ bufferevent_free(bev);
+
+ evhttp_free(http);
+
+ tt_int_op(test_ok, ==, 4);
+ end:
+ if (fd >= 0)
+ evutil_closesocket(fd);
+}
+
+static void
+http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg)
+{
+ char **output = arg;
+ if ((what & (BEV_EVENT_ERROR|BEV_EVENT_EOF))) {
+ char buf[4096];
+ int n;
+ n = evbuffer_remove(bufferevent_get_input(bev), buf,
+ sizeof(buf)-1);
+ if (n >= 0) {
+ buf[n]='\0';
+ if (*output)
+ free(*output);
+ *output = strdup(buf);
+ }
+ event_base_loopexit(exit_base, NULL);
+ }
+}
+
+static void
+http_allowed_methods_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev1, *bev2, *bev3;
+ evutil_socket_t fd1=-1, fd2=-1, fd3=-1;
+ const char *http_request;
+ char *result1=NULL, *result2=NULL, *result3=NULL;
+ ev_uint16_t port = 0;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ fd1 = http_connect("127.0.0.1", port);
+ tt_int_op(fd1, >=, 0);
+
+ /* GET is out; PATCH is in. */
+ evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH);
+
+ /* Stupid thing to send a request */
+ bev1 = bufferevent_socket_new(data->base, fd1, 0);
+ bufferevent_enable(bev1, EV_READ|EV_WRITE);
+ bufferevent_setcb(bev1, NULL, NULL,
+ http_allowed_methods_eventcb, &result1);
+
+ http_request =
+ "GET /index.html HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev1, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ fd2 = http_connect("127.0.0.1", port);
+ tt_int_op(fd2, >=, 0);
+
+ bev2 = bufferevent_socket_new(data->base, fd2, 0);
+ bufferevent_enable(bev2, EV_READ|EV_WRITE);
+ bufferevent_setcb(bev2, NULL, NULL,
+ http_allowed_methods_eventcb, &result2);
+
+ http_request =
+ "PATCH /test HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev2, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ fd3 = http_connect("127.0.0.1", port);
+ tt_int_op(fd3, >=, 0);
+
+ bev3 = bufferevent_socket_new(data->base, fd3, 0);
+ bufferevent_enable(bev3, EV_READ|EV_WRITE);
+ bufferevent_setcb(bev3, NULL, NULL,
+ http_allowed_methods_eventcb, &result3);
+
+ http_request =
+ "FLOOP /test HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev3, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ bufferevent_free(bev1);
+ bufferevent_free(bev2);
+ bufferevent_free(bev3);
+
+ evhttp_free(http);
+
+ /* Method known but disallowed */
+ tt_assert(result1);
+ tt_assert(!strncmp(result1, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
+
+ /* Method known and allowed */
+ tt_assert(result2);
+ tt_assert(!strncmp(result2, "HTTP/1.1 200 ", strlen("HTTP/1.1 200 ")));
+
+ /* Method unknown */
+ tt_assert(result3);
+ tt_assert(!strncmp(result3, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
+
+ end:
+ if (result1)
+ free(result1);
+ if (result2)
+ free(result2);
+ if (result3)
+ free(result3);
+ if (fd1 >= 0)
+ evutil_closesocket(fd1);
+ if (fd2 >= 0)
+ evutil_closesocket(fd2);
+ if (fd3 >= 0)
+ evutil_closesocket(fd3);
+}
+
+static void http_request_no_action_done(struct evhttp_request *, void *);
+static void http_request_done(struct evhttp_request *, void *);
+static void http_request_empty_done(struct evhttp_request *, void *);
+
+static void
+http_connection_test_(struct basic_test_data *data, int persistent,
+ const char *address, struct evdns_base *dnsbase, int ipv6, int family,
+ int ssl)
+{
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct evhttp *http;
+
+ int mask = 0;
+ if (ipv6)
+ mask |= HTTP_BIND_IPV6;
+ if (ssl)
+ mask |= HTTP_BIND_SSL;
+
+ http = http_setup(&port, data->base, mask);
+
+ test_ok = 0;
+ if (!http && ipv6) {
+ tt_skip();
+ }
+ tt_assert(http);
+
+ if (ssl) {
+#ifdef EVENT__HAVE_OPENSSL
+ SSL *ssl = SSL_new(get_ssl_ctx());
+ struct bufferevent *bev = bufferevent_openssl_socket_new(
+ data->base, -1, ssl,
+ BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS);
+ bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
+
+ evcon = evhttp_connection_base_bufferevent_new(data->base, dnsbase, bev, address, port);
+#else
+ tt_skip();
+#endif
+ } else {
+ evcon = evhttp_connection_base_new(data->base, dnsbase, address, port);
+ }
+ tt_assert(evcon);
+ evhttp_connection_set_family(evcon, family);
+
+ tt_assert(evhttp_connection_get_base(evcon) == data->base);
+
+ exit_base = data->base;
+
+ tt_assert(evhttp_connection_get_server(evcon) == NULL);
+
+ /*
+ * At this point, we want to schedule a request to the HTTP
+ * server using our make request method.
+ */
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok);
+
+ /* try to make another request over the same connection */
+ test_ok = 0;
+
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /*
+ * if our connections are not supposed to be persistent; request
+ * a close from the server.
+ */
+ if (!persistent)
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ /* make another request: request empty reply */
+ test_ok = 0;
+
+ req = evhttp_request_new(http_request_empty_done, data->base);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_connection_test(void *arg)
+{
+ http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, 0);
+}
+static void
+http_persist_connection_test(void *arg)
+{
+ http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC, 0);
+}
+
+static struct regress_dns_server_table search_table[] = {
+ { "localhost", "A", "127.0.0.1", 0, 0 },
+ { NULL, NULL, NULL, 0, 0 }
+};
+
+static void
+http_connection_async_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct evdns_base *dns_base = NULL;
+ ev_uint16_t portnum = 0;
+ char address[64];
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ exit_base = data->base;
+ tt_assert(regress_dnsserver(data->base, &portnum, search_table));
+
+ dns_base = evdns_base_new(data->base, 0/* init name servers */);
+ tt_assert(dns_base);
+
+ /* Add ourself as the only nameserver, and make sure we really are
+ * the only nameserver. */
+ evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
+ evdns_base_nameserver_ip_add(dns_base, address);
+
+ test_ok = 0;
+
+ evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule a request to the HTTP
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok);
+
+ /* try to make another request over the same connection */
+ test_ok = 0;
+
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /*
+ * if our connections are not supposed to be persistent; request
+ * a close from the server.
+ */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ /* make another request: request empty reply */
+ test_ok = 0;
+
+ req = evhttp_request_new(http_request_empty_done, data->base);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+ if (dns_base)
+ evdns_base_free(dns_base, 0);
+ regress_clean_dnsserver();
+}
+
+static void
+http_autofree_connection_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req[2] = { NULL };
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ test_ok = 0;
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule two request to the HTTP
+ * server using our make request method.
+ */
+ req[0] = evhttp_request_new(http_request_empty_done, data->base);
+ req[1] = evhttp_request_new(http_request_empty_done, data->base);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Host", "somehost");
+ evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Connection", "close");
+ evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Empty", "itis");
+ evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Host", "somehost");
+ evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Connection", "close");
+ evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Empty", "itis");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req[0], EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("couldn't make request");
+ }
+ if (evhttp_make_request(evcon, req[1], EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("couldn't make request");
+ }
+
+ /*
+ * Tell libevent to free the connection when the request completes
+ * We then set the evcon pointer to NULL since we don't want to free it
+ * when this function ends.
+ */
+ evhttp_connection_free_on_completion(evcon);
+ evcon = NULL;
+
+ event_base_dispatch(data->base);
+
+ /* at this point, the http server should have no connection */
+ tt_assert(TAILQ_FIRST(&http->connections) == NULL);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_request_never_call(struct evhttp_request *req, void *arg)
+{
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+}
+static void
+http_failed_request_done(struct evhttp_request *req, void *arg)
+{
+ tt_assert(!req);
+end:
+ event_base_loopexit(arg, NULL);
+}
+#ifndef _WIN32
+static void
+http_timed_out_request_done(struct evhttp_request *req, void *arg)
+{
+ tt_assert(req);
+ tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
+end:
+ event_base_loopexit(arg, NULL);
+}
+#endif
+
+static void
+http_request_error_cb_with_cancel(enum evhttp_request_error error, void *arg)
+{
+ if (error != EVREQ_HTTP_REQUEST_CANCEL) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+ test_ok = 1;
+
+ {
+ struct timeval tv;
+ evutil_timerclear(&tv);
+ tv.tv_sec = 0;
+ tv.tv_usec = 500 * 1000;
+ event_base_loopexit(exit_base, &tv);
+ }
+}
+static void
+http_do_cancel(evutil_socket_t fd, short what, void *arg)
+{
+ struct evhttp_request *req = arg;
+ evhttp_cancel_request(req);
+ ++test_ok;
+}
+static void
+http_no_write(struct evbuffer *buffer, const struct evbuffer_cb_info *info, void *arg)
+{
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+}
+static void
+http_free_evcons(struct evhttp_connection **evcons)
+{
+ struct evhttp_connection *evcon, **orig = evcons;
+
+ if (!evcons)
+ return;
+
+ while ((evcon = *evcons++)) {
+ evhttp_connection_free(evcon);
+ }
+ free(orig);
+}
+/** fill the backlog to force server drop packages for timeouts */
+static struct evhttp_connection **
+http_fill_backlog(struct event_base *base, int port)
+{
+#define BACKLOG_SIZE 256
+ struct evhttp_connection **evcon = malloc(sizeof(*evcon) * (BACKLOG_SIZE + 1));
+ int i;
+
+ for (i = 0; i < BACKLOG_SIZE; ++i) {
+ struct evhttp_request *req;
+
+ evcon[i] = evhttp_connection_base_new(base, NULL, "127.0.0.1", port);
+ tt_assert(evcon[i]);
+ evhttp_connection_set_timeout(evcon[i], 5);
+
+ req = evhttp_request_new(http_request_never_call, NULL);
+ tt_assert(req);
+ tt_int_op(evhttp_make_request(evcon[i], req, EVHTTP_REQ_GET, "/delay"), !=, -1);
+ }
+ evcon[i] = NULL;
+
+ return evcon;
+ end:
+ fprintf(stderr, "Couldn't fill the backlog");
+ return NULL;
+}
+
+enum http_cancel_test_type {
+ BASIC = 1,
+ BY_HOST = 2,
+ NO_NS = 4,
+ INACTIVE_SERVER = 8,
+ SERVER_TIMEOUT = 16,
+ NS_TIMEOUT = 32,
+};
+static struct evhttp_request *
+http_cancel_test_bad_request_new(enum http_cancel_test_type type,
+ struct event_base *base)
+{
+#ifndef _WIN32
+ if (!(type & NO_NS) && (type & SERVER_TIMEOUT))
+ return evhttp_request_new(http_timed_out_request_done, base);
+ else
+#endif
+ if ((type & INACTIVE_SERVER) || (type & NO_NS))
+ return evhttp_request_new(http_failed_request_done, base);
+ else
+ return NULL;
+}
+static void
+http_cancel_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct bufferevent *bufev = NULL;
+ struct timeval tv;
+ struct evdns_base *dns_base = NULL;
+ ev_uint16_t portnum = 0;
+ char address[64];
+ struct evhttp *inactive_http = NULL;
+ struct event_base *inactive_base = NULL;
+ struct evhttp_connection **evcons = NULL;
+ struct event_base *base_to_fill = data->base;
+
+ enum http_cancel_test_type type =
+ (enum http_cancel_test_type)data->setup_data;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ if (type & BY_HOST) {
+ const char *timeout = (type & NS_TIMEOUT) ? "6" : "3";
+
+ tt_assert(regress_dnsserver(data->base, &portnum, search_table));
+
+ dns_base = evdns_base_new(data->base, 0/* init name servers */);
+ tt_assert(dns_base);
+
+ /** XXX: Hack the port to make timeout after resolving */
+ if (type & NO_NS)
+ ++portnum;
+
+ evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
+ evdns_base_nameserver_ip_add(dns_base, address);
+
+ evdns_base_set_option(dns_base, "timeout:", timeout);
+ evdns_base_set_option(dns_base, "initial-probe-timeout:", timeout);
+ evdns_base_set_option(dns_base, "attempts:", "1");
+ }
+
+ exit_base = data->base;
+
+ test_ok = 0;
+
+ if (type & INACTIVE_SERVER) {
+ port = 0;
+ inactive_base = event_base_new();
+ inactive_http = http_setup(&port, inactive_base, 0);
+
+ base_to_fill = inactive_base;
+ }
+
+ if (type & SERVER_TIMEOUT)
+ evcons = http_fill_backlog(base_to_fill, port);
+
+ evcon = evhttp_connection_base_new(
+ data->base, dns_base,
+ type & BY_HOST ? "localhost" : "127.0.0.1",
+ port);
+ if (type & INACTIVE_SERVER)
+ evhttp_connection_set_timeout(evcon, 5);
+ tt_assert(evcon);
+
+ bufev = evhttp_connection_get_bufferevent(evcon);
+ /* Guarantee that we stack in connect() not after waiting EV_READ after
+ * write() */
+ if (type & SERVER_TIMEOUT)
+ evbuffer_add_cb(bufferevent_get_output(bufev), http_no_write, NULL);
+
+ /*
+ * At this point, we want to schedule a request to the HTTP
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_request_never_call, NULL);
+ evhttp_request_set_error_cb(req, http_request_error_cb_with_cancel);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/delay"),
+ !=, -1);
+
+ evutil_timerclear(&tv);
+ tv.tv_sec = 0;
+ tv.tv_usec = 100 * 1000;
+
+ event_base_once(data->base, -1, EV_TIMEOUT, http_do_cancel, req, &tv);
+
+ event_base_dispatch(data->base);
+
+ if (type & NO_NS || type & INACTIVE_SERVER)
+ tt_int_op(test_ok, ==, 2); /** no servers responses */
+ else
+ tt_int_op(test_ok, ==, 3);
+
+ /* try to make another request over the same connection */
+ test_ok = 0;
+
+ http_free_evcons(evcons);
+ if (type & SERVER_TIMEOUT)
+ evcons = http_fill_backlog(base_to_fill, port);
+
+ req = http_cancel_test_bad_request_new(type, data->base);
+ if (!req)
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
+ !=, -1);
+
+ event_base_dispatch(data->base);
+
+ /* make another request: request empty reply */
+ test_ok = 0;
+
+ http_free_evcons(evcons);
+ if (type & SERVER_TIMEOUT)
+ evcons = http_fill_backlog(base_to_fill, port);
+
+ req = http_cancel_test_bad_request_new(type, data->base);
+ if (!req)
+ req = evhttp_request_new(http_request_empty_done, data->base);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
+
+ /* We give ownership of the request to the connection */
+ tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
+ !=, -1);
+
+ event_base_dispatch(data->base);
+
+ end:
+ http_free_evcons(evcons);
+ if (bufev)
+ evbuffer_remove_cb(bufferevent_get_output(bufev), http_no_write, NULL);
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+ if (dns_base)
+ evdns_base_free(dns_base, 0);
+ regress_clean_dnsserver();
+ if (inactive_http)
+ evhttp_free(inactive_http);
+ if (inactive_base)
+ event_base_free(inactive_base);
+}
+
+static void
+http_request_no_action_done(struct evhttp_request *req, void *arg)
+{
+ EVUTIL_ASSERT(exit_base);
+ event_base_loopexit(exit_base, NULL);
+}
+
+static void
+http_request_done(struct evhttp_request *req, void *arg)
+{
+ const char *what = arg;
+
+ if (!req) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ EVUTIL_ASSERT(exit_base);
+ event_base_loopexit(exit_base, NULL);
+}
+
+static void
+http_request_expect_error(struct evhttp_request *req, void *arg)
+{
+ if (evhttp_request_get_response_code(req) == HTTP_OK) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ EVUTIL_ASSERT(arg);
+ event_base_loopexit(arg, NULL);
+}
+
+/* test virtual hosts */
+static void
+http_virtual_host_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct evhttp *second = NULL, *third = NULL;
+ evutil_socket_t fd;
+ struct bufferevent *bev;
+ const char *http_request;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ exit_base = data->base;
+
+ /* virtual host */
+ second = evhttp_new(NULL);
+ evhttp_set_cb(second, "/funnybunny", http_basic_cb, http);
+ third = evhttp_new(NULL);
+ evhttp_set_cb(third, "/blackcoffee", http_basic_cb, http);
+
+ if (evhttp_add_virtual_host(http, "foo.com", second) == -1) {
+ tt_abort_msg("Couldn't add vhost");
+ }
+
+ if (evhttp_add_virtual_host(http, "bar.*.foo.com", third) == -1) {
+ tt_abort_msg("Couldn't add wildcarded vhost");
+ }
+
+ /* add some aliases to the vhosts */
+ tt_assert(evhttp_add_server_alias(second, "manolito.info") == 0);
+ tt_assert(evhttp_add_server_alias(third, "bonkers.org") == 0);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /* make a request with a different host and expect an error */
+ req = evhttp_request_new(http_request_expect_error, data->base);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/funnybunny") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 1);
+
+ test_ok = 0;
+
+ /* make a request with the right host and expect a response */
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "foo.com");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/funnybunny") == -1) {
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 1);
+
+ test_ok = 0;
+
+ /* make a request with the right host and expect a response */
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bar.magic.foo.com");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/blackcoffee") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 1)
+
+ test_ok = 0;
+
+ /* make a request with the right host and expect a response */
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "manolito.info");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/funnybunny") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 1)
+
+ test_ok = 0;
+
+ /* make a request with the right host and expect a response */
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the Host header. This time with the optional port. */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bonkers.org:8000");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/blackcoffee") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 1)
+
+ test_ok = 0;
+
+ /* Now make a raw request with an absolute URI. */
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, NULL);
+
+ /* The host in the URI should override the Host: header */
+ http_request =
+ "GET http://manolito.info/funnybunny HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 2);
+
+ bufferevent_free(bev);
+ evutil_closesocket(fd);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+
+/* test date header and content length */
+
+static void
+http_request_empty_done(struct evhttp_request *req, void *arg)
+{
+ if (!req) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Date") == NULL) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length") == NULL) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (strcmp(evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length"),
+ "0")) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ EVUTIL_ASSERT(arg);
+ event_base_loopexit(arg, NULL);
+}
+
+/*
+ * HTTP DISPATCHER test
+ */
+
+void
+http_dispatcher_cb(struct evhttp_request *req, void *arg)
+{
+
+ struct evbuffer *evb = evbuffer_new();
+ event_debug(("%s: called\n", __func__));
+ evbuffer_add_printf(evb, "DISPATCHER_TEST");
+
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+ evbuffer_free(evb);
+}
+
+static void
+http_dispatcher_test_done(struct evhttp_request *req, void *arg)
+{
+ struct event_base *base = arg;
+ const char *what = "DISPATCHER_TEST";
+
+ if (!req) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
+ fprintf(stderr, "FAILED (content type)\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
+ fprintf(stderr, "FAILED (length %lu vs %lu)\n",
+ (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
+ exit(1);
+ }
+
+ if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
+ fprintf(stderr, "FAILED (data)\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ event_base_loopexit(base, NULL);
+}
+
+static void
+http_dispatcher_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ test_ok = 0;
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /* also bind to local host */
+ evhttp_connection_set_local_address(evcon, "127.0.0.1");
+
+ /*
+ * At this point, we want to schedule an HTTP GET request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_dispatcher_test_done, data->base);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+/*
+ * HTTP POST test.
+ */
+
+void http_postrequest_done(struct evhttp_request *, void *);
+
+#define POST_DATA "Okay. Not really printf"
+
+static void
+http_post_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ test_ok = 0;
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule an HTTP POST request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_postrequest_done, data->base);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+ evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 1);
+
+ test_ok = 0;
+
+ req = evhttp_request_new(http_postrequest_done, data->base);
+ tt_assert(req);
+
+ /* Now try with 100-continue. */
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
+ evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 1);
+
+ evhttp_connection_free(evcon);
+ evhttp_free(http);
+
+ end:
+ ;
+}
+
+void
+http_post_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb;
+ event_debug(("%s: called\n", __func__));
+
+ /* Yes, we are expecting a post request */
+ if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
+ fprintf(stdout, "FAILED (post type)\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(POST_DATA)) {
+ fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
+ (unsigned long) evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long) strlen(POST_DATA));
+ exit(1);
+ }
+
+ if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), POST_DATA) != 0) {
+ fprintf(stdout, "FAILED (data)\n");
+ fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
+ fprintf(stdout, "Want:%s\n", POST_DATA);
+ exit(1);
+ }
+
+ evb = evbuffer_new();
+ evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
+
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+ evbuffer_free(evb);
+}
+
+void
+http_postrequest_done(struct evhttp_request *req, void *arg)
+{
+ const char *what = BASIC_REQUEST_BODY;
+ struct event_base *base = arg;
+
+ if (req == NULL) {
+ fprintf(stderr, "FAILED (timeout)\n");
+ exit(1);
+ }
+
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+
+ fprintf(stderr, "FAILED (response code)\n");
+ exit(1);
+ }
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
+ fprintf(stderr, "FAILED (content type)\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
+ fprintf(stderr, "FAILED (length %lu vs %lu)\n",
+ (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
+ exit(1);
+ }
+
+ if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
+ fprintf(stderr, "FAILED (data)\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ event_base_loopexit(base, NULL);
+}
+
+/*
+ * HTTP PUT test, basically just like POST, but ...
+ */
+
+void http_putrequest_done(struct evhttp_request *, void *);
+
+#define PUT_DATA "Hi, I'm some PUT data"
+
+static void
+http_put_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ test_ok = 0;
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * Schedule the HTTP PUT request
+ */
+
+ req = evhttp_request_new(http_putrequest_done, data->base);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "someotherhost");
+ evbuffer_add_printf(evhttp_request_get_output_buffer(req), PUT_DATA);
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_PUT, "/putit") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ evhttp_connection_free(evcon);
+ evhttp_free(http);
+
+ tt_int_op(test_ok, ==, 1);
+ end:
+ ;
+}
+
+void
+http_put_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb;
+ event_debug(("%s: called\n", __func__));
+
+ /* Expecting a PUT request */
+ if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) {
+ fprintf(stdout, "FAILED (put type)\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(PUT_DATA)) {
+ fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
+ (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(PUT_DATA));
+ exit(1);
+ }
+
+ if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), PUT_DATA) != 0) {
+ fprintf(stdout, "FAILED (data)\n");
+ fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
+ fprintf(stdout, "Want:%s\n", PUT_DATA);
+ exit(1);
+ }
+
+ evb = evbuffer_new();
+ evbuffer_add_printf(evb, "That ain't funny");
+
+ evhttp_send_reply(req, HTTP_OK, "Everything is great", evb);
+
+ evbuffer_free(evb);
+}
+
+void
+http_putrequest_done(struct evhttp_request *req, void *arg)
+{
+ struct event_base *base = arg;
+ const char *what = "That ain't funny";
+
+ if (req == NULL) {
+ fprintf(stderr, "FAILED (timeout)\n");
+ exit(1);
+ }
+
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+
+ fprintf(stderr, "FAILED (response code)\n");
+ exit(1);
+ }
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
+ fprintf(stderr, "FAILED (content type)\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
+ fprintf(stderr, "FAILED (length %lu vs %lu)\n",
+ (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
+ exit(1);
+ }
+
+
+ if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
+ fprintf(stderr, "FAILED (data)\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ event_base_loopexit(base, NULL);
+}
+
+static void
+http_failure_readcb(struct bufferevent *bev, void *arg)
+{
+ const char *what = "400 Bad Request";
+ if (evbuffer_contains(bufferevent_get_input(bev), what)) {
+ test_ok = 2;
+ bufferevent_disable(bev, EV_READ);
+ event_base_loopexit(arg, NULL);
+ }
+}
+
+/*
+ * Testing that the HTTP server can deal with a malformed request.
+ */
+static void
+http_failure_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev;
+ evutil_socket_t fd = -1;
+ const char *http_request;
+ ev_uint16_t port = 0;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ test_ok = 0;
+
+ fd = http_connect("127.0.0.1", port);
+ tt_int_op(fd, >=, 0);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_failure_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ http_request = "illegal request\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ bufferevent_free(bev);
+
+ evhttp_free(http);
+
+ tt_int_op(test_ok, ==, 2);
+ end:
+ if (fd >= 0)
+ evutil_closesocket(fd);
+}
+
+static void
+close_detect_done(struct evhttp_request *req, void *arg)
+{
+ struct timeval tv;
+ tt_assert(req);
+ tt_assert(evhttp_request_get_response_code(req) == HTTP_OK);
+
+ test_ok = 1;
+
+ end:
+ evutil_timerclear(&tv);
+ tv.tv_usec = 150000;
+ event_base_loopexit(arg, &tv);
+}
+
+static void
+close_detect_launch(evutil_socket_t fd, short what, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+ struct event_base *base = evhttp_connection_get_base(evcon);
+ struct evhttp_request *req;
+
+ req = evhttp_request_new(close_detect_done, base);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_fail_msg("Couldn't make request");
+ }
+}
+
+static void
+close_detect_cb(struct evhttp_request *req, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+ struct event_base *base = evhttp_connection_get_base(evcon);
+ struct timeval tv;
+
+ if (req != NULL && evhttp_request_get_response_code(req) != HTTP_OK) {
+ tt_abort_msg("Failed");
+ }
+
+ evutil_timerclear(&tv);
+ tv.tv_sec = 0; /* longer than the http time out */
+ tv.tv_usec = 600000; /* longer than the http time out */
+
+ /* launch a new request on the persistent connection in .3 seconds */
+ event_base_once(base, -1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
+ end:
+ ;
+}
+
+
+static void
+http_close_detection_(struct basic_test_data *data, int with_delay)
+{
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ const struct timeval sec_tenth = { 0, 100000 };
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ test_ok = 0;
+
+ /* .1 second timeout */
+ evhttp_set_timeout_tv(http, &sec_tenth);
+
+ evcon = evhttp_connection_base_new(data->base, NULL,
+ "127.0.0.1", port);
+ tt_assert(evcon);
+ evhttp_connection_set_timeout_tv(evcon, &sec_tenth);
+
+
+ tt_assert(evcon);
+ delayed_client = evcon;
+
+ /*
+ * At this point, we want to schedule a request to the HTTP
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(close_detect_cb, evcon);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon,
+ req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
+ tt_abort_msg("couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ /* at this point, the http server should have no connection */
+ tt_assert(TAILQ_FIRST(&http->connections) == NULL);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+static void
+http_close_detection_test(void *arg)
+{
+ http_close_detection_(arg, 0);
+}
+static void
+http_close_detection_delay_test(void *arg)
+{
+ http_close_detection_(arg, 1);
+}
+
+static void
+http_highport_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ int i = -1;
+ struct evhttp *myhttp = NULL;
+
+ /* Try a few different ports */
+ for (i = 0; i < 50; ++i) {
+ myhttp = evhttp_new(data->base);
+ if (evhttp_bind_socket(myhttp, "127.0.0.1", 65535 - i) == 0) {
+ test_ok = 1;
+ evhttp_free(myhttp);
+ return;
+ }
+ evhttp_free(myhttp);
+ }
+
+ tt_fail_msg("Couldn't get a high port");
+}
+
+static void
+http_bad_header_test(void *ptr)
+{
+ struct evkeyvalq headers;
+
+ TAILQ_INIT(&headers);
+
+ tt_want(evhttp_add_header(&headers, "One", "Two") == 0);
+ tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0);
+ tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1);
+ tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1);
+ tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1);
+ tt_want(evhttp_add_header(&headers, "One", "Two\n") == -1);
+
+ evhttp_clear_headers(&headers);
+}
+
+static int validate_header(
+ const struct evkeyvalq* headers,
+ const char *key, const char *value)
+{
+ const char *real_val = evhttp_find_header(headers, key);
+ tt_assert(real_val != NULL);
+ tt_want(strcmp(real_val, value) == 0);
+end:
+ return (0);
+}
+
+static void
+http_parse_query_test(void *ptr)
+{
+ struct evkeyvalq headers;
+ int r;
+
+ TAILQ_INIT(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test", &headers);
+ tt_want(validate_header(&headers, "q", "test") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
+ tt_want(validate_header(&headers, "q", "test") == 0);
+ tt_want(validate_header(&headers, "foo", "bar") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
+ tt_want(validate_header(&headers, "q", "test foo") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
+ tt_want(validate_header(&headers, "q", "test\nfoo") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
+ tt_want(validate_header(&headers, "q", "test\rfoo") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test&&q2", &headers);
+ tt_int_op(r, ==, -1);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test+this", &headers);
+ tt_want(validate_header(&headers, "q", "test this") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test&q2=foo", &headers);
+ tt_int_op(r, ==, 0);
+ tt_want(validate_header(&headers, "q", "test") == 0);
+ tt_want(validate_header(&headers, "q2", "foo") == 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q&q2=foo", &headers);
+ tt_int_op(r, ==, -1);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=foo&q2", &headers);
+ tt_int_op(r, ==, -1);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=foo&q2&q3=x", &headers);
+ tt_int_op(r, ==, -1);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=&q2=&q3=", &headers);
+ tt_int_op(r, ==, 0);
+ tt_want(validate_header(&headers, "q", "") == 0);
+ tt_want(validate_header(&headers, "q2", "") == 0);
+ tt_want(validate_header(&headers, "q3", "") == 0);
+ evhttp_clear_headers(&headers);
+
+end:
+ evhttp_clear_headers(&headers);
+}
+
+static void
+http_parse_uri_test(void *ptr)
+{
+ const int nonconform = (ptr != NULL);
+ const unsigned parse_flags =
+ nonconform ? EVHTTP_URI_NONCONFORMANT : 0;
+ struct evhttp_uri *uri = NULL;
+ char url_tmp[4096];
+#define URI_PARSE(uri) \
+ evhttp_uri_parse_with_flags((uri), parse_flags)
+
+#define TT_URI(want) do { \
+ char *ret = evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)); \
+ tt_want(ret != NULL); \
+ tt_want(ret == url_tmp); \
+ if (strcmp(ret,want) != 0) \
+ TT_FAIL(("\"%s\" != \"%s\"",ret,want)); \
+ } while(0)
+
+ tt_want(evhttp_uri_join(NULL, 0, 0) == NULL);
+ tt_want(evhttp_uri_join(NULL, url_tmp, 0) == NULL);
+ tt_want(evhttp_uri_join(NULL, url_tmp, sizeof(url_tmp)) == NULL);
+
+ /* bad URIs: parsing */
+#define BAD(s) do { \
+ if (URI_PARSE(s) != NULL) \
+ TT_FAIL(("Expected error parsing \"%s\"",s)); \
+ } while(0)
+ /* Nonconformant URIs we can parse: parsing */
+#define NCF(s) do { \
+ uri = URI_PARSE(s); \
+ if (uri != NULL && !nonconform) { \
+ TT_FAIL(("Expected error parsing \"%s\"",s)); \
+ } else if (uri == NULL && nonconform) { \
+ TT_FAIL(("Couldn't parse nonconformant URI \"%s\"", \
+ s)); \
+ } \
+ if (uri) { \
+ tt_want(evhttp_uri_join(uri, url_tmp, \
+ sizeof(url_tmp))); \
+ evhttp_uri_free(uri); \
+ } \
+ } while(0)
+
+ NCF("http://www.test.com/ why hello");
+ NCF("http://www.test.com/why-hello\x01");
+ NCF("http://www.test.com/why-hello?\x01");
+ NCF("http://www.test.com/why-hello#\x01");
+ BAD("http://www.\x01.test.com/why-hello");
+ BAD("http://www.%7test.com/why-hello");
+ NCF("http://www.test.com/why-hell%7o");
+ BAD("h%3ttp://www.test.com/why-hello");
+ NCF("http://www.test.com/why-hello%7");
+ NCF("http://www.test.com/why-hell%7o");
+ NCF("http://www.test.com/foo?ba%r");
+ NCF("http://www.test.com/foo#ba%r");
+ BAD("99:99/foo");
+ BAD("http://www.test.com:999x/");
+ BAD("http://www.test.com:x/");
+ BAD("http://[hello-there]/");
+ BAD("http://[::1]]/");
+ BAD("http://[::1/");
+ BAD("http://[foob/");
+ BAD("http://[/");
+ BAD("http://[ffff:ffff:ffff:ffff:Ffff:ffff:ffff:"
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff]/");
+ BAD("http://[vX.foo]/");
+ BAD("http://[vX.foo]/");
+ BAD("http://[v.foo]/");
+ BAD("http://[v5.fo%o]/");
+ BAD("http://[v5X]/");
+ BAD("http://[v5]/");
+ BAD("http://[]/");
+ BAD("http://f\x01red@www.example.com/");
+ BAD("http://f%0red@www.example.com/");
+ BAD("http://www.example.com:9999999999999999999999999999999999999/");
+ BAD("http://www.example.com:hihi/");
+ BAD("://www.example.com/");
+
+ /* bad URIs: joining */
+ uri = evhttp_uri_new();
+ tt_want(0==evhttp_uri_set_host(uri, "www.example.com"));
+ tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) != NULL);
+ /* not enough space: */
+ tt_want(evhttp_uri_join(uri, url_tmp, 3) == NULL);
+ /* host is set, but path doesn't start with "/": */
+ tt_want(0==evhttp_uri_set_path(uri, "hi_mom"));
+ tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) == NULL);
+ tt_want(evhttp_uri_join(uri, NULL, sizeof(url_tmp))==NULL);
+ tt_want(evhttp_uri_join(uri, url_tmp, 0)==NULL);
+ evhttp_uri_free(uri);
+ uri = URI_PARSE("mailto:foo@bar");
+ tt_want(uri != NULL);
+ tt_want(evhttp_uri_get_host(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(!strcmp(evhttp_uri_get_scheme(uri), "mailto"));
+ tt_want(!strcmp(evhttp_uri_get_path(uri), "foo@bar"));
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("mailto:foo@bar");
+ evhttp_uri_free(uri);
+
+ uri = evhttp_uri_new();
+ /* Bad URI usage: setting invalid values */
+ tt_want(-1 == evhttp_uri_set_scheme(uri,""));
+ tt_want(-1 == evhttp_uri_set_scheme(uri,"33"));
+ tt_want(-1 == evhttp_uri_set_scheme(uri,"hi!"));
+ tt_want(-1 == evhttp_uri_set_userinfo(uri,"hello@"));
+ tt_want(-1 == evhttp_uri_set_host(uri,"[1.2.3.4]"));
+ tt_want(-1 == evhttp_uri_set_host(uri,"["));
+ tt_want(-1 == evhttp_uri_set_host(uri,"www.[foo].com"));
+ tt_want(-1 == evhttp_uri_set_port(uri,-3));
+ tt_want(-1 == evhttp_uri_set_path(uri,"hello?world"));
+ tt_want(-1 == evhttp_uri_set_query(uri,"hello#world"));
+ tt_want(-1 == evhttp_uri_set_fragment(uri,"hello#world"));
+ /* Valid URI usage: setting valid values */
+ tt_want(0 == evhttp_uri_set_scheme(uri,"http"));
+ tt_want(0 == evhttp_uri_set_scheme(uri,NULL));
+ tt_want(0 == evhttp_uri_set_userinfo(uri,"username:pass"));
+ tt_want(0 == evhttp_uri_set_userinfo(uri,NULL));
+ tt_want(0 == evhttp_uri_set_host(uri,"www.example.com"));
+ tt_want(0 == evhttp_uri_set_host(uri,"1.2.3.4"));
+ tt_want(0 == evhttp_uri_set_host(uri,"[1:2:3:4::]"));
+ tt_want(0 == evhttp_uri_set_host(uri,"[v7.wobblewobble]"));
+ tt_want(0 == evhttp_uri_set_host(uri,NULL));
+ tt_want(0 == evhttp_uri_set_host(uri,""));
+ tt_want(0 == evhttp_uri_set_port(uri, -1));
+ tt_want(0 == evhttp_uri_set_port(uri, 80));
+ tt_want(0 == evhttp_uri_set_port(uri, 65535));
+ tt_want(0 == evhttp_uri_set_path(uri, ""));
+ tt_want(0 == evhttp_uri_set_path(uri, "/documents/public/index.html"));
+ tt_want(0 == evhttp_uri_set_path(uri, NULL));
+ tt_want(0 == evhttp_uri_set_query(uri, "key=val&key2=val2"));
+ tt_want(0 == evhttp_uri_set_query(uri, "keyvalblarg"));
+ tt_want(0 == evhttp_uri_set_query(uri, ""));
+ tt_want(0 == evhttp_uri_set_query(uri, NULL));
+ tt_want(0 == evhttp_uri_set_fragment(uri, ""));
+ tt_want(0 == evhttp_uri_set_fragment(uri, "here?i?am"));
+ tt_want(0 == evhttp_uri_set_fragment(uri, NULL));
+ evhttp_uri_free(uri);
+
+ /* Valid parsing */
+ uri = URI_PARSE("http://www.test.com/?q=t%33est");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=t%33est") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://www.test.com/?q=t%33est");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://%77ww.test.com");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "%77ww.test.com") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://%77ww.test.com");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://www.test.com?q=test");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://www.test.com?q=test");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://www.test.com#fragment");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want_str_op(evhttp_uri_get_fragment(uri), ==, "fragment");
+ TT_URI("http://www.test.com#fragment");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://8000/");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "8000") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://8000/");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://:8000/");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == 8000);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://:8000/");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://www.test.com:/"); /* empty port */
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
+ tt_want_str_op(evhttp_uri_get_path(uri), ==, "/");
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://www.test.com/");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://www.test.com:"); /* empty port 2 */
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://www.test.com");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("ftp://www.test.com/?q=test");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("ftp://www.test.com/?q=test");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("ftp://[::1]:999/?q=test");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "[::1]") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == 999);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("ftp://[::1]:999/?q=test");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("ftp://[ff00::127.0.0.1]/?q=test");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "[ff00::127.0.0.1]") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("ftp://[ff00::127.0.0.1]/?q=test");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("ftp://[v99.not_(any:time)_soon]/?q=test");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "[v99.not_(any:time)_soon]") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
+ tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user:pass") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
+ tt_want(evhttp_uri_get_port(uri) == 42);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=test&s=some+thing") == 0);
+ tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
+ TT_URI("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("scheme://user@foo.com/#fragment");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
+ tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
+ TT_URI("scheme://user@foo.com/#fragment");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("scheme://%75ser@foo.com/#frag@ment");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
+ tt_want(strcmp(evhttp_uri_get_userinfo(uri), "%75ser") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(strcmp(evhttp_uri_get_fragment(uri), "frag@ment") == 0);
+ TT_URI("scheme://%75ser@foo.com/#frag@ment");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("file:///some/path/to/the/file");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "file") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the/file") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("file:///some/path/to/the/file");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("///some/path/to/the-file");
+ tt_want(uri != NULL);
+ tt_want(evhttp_uri_get_scheme(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the-file") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("///some/path/to/the-file");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("/s:ome/path/to/the-file?q=99#fred");
+ tt_want(uri != NULL);
+ tt_want(evhttp_uri_get_scheme(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_host(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/s:ome/path/to/the-file") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=99") == 0);
+ tt_want(strcmp(evhttp_uri_get_fragment(uri), "fred") == 0);
+ TT_URI("/s:ome/path/to/the-file?q=99#fred");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("relative/path/with/co:lon");
+ tt_want(uri != NULL);
+ tt_want(evhttp_uri_get_scheme(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_host(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "relative/path/with/co:lon") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("relative/path/with/co:lon");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("bob?q=99&q2=q?33#fr?ed");
+ tt_want(uri != NULL);
+ tt_want(evhttp_uri_get_scheme(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_host(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "bob") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=99&q2=q?33") == 0);
+ tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
+ TT_URI("bob?q=99&q2=q?33#fr?ed");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("#fr?ed");
+ tt_want(uri != NULL);
+ tt_want(evhttp_uri_get_scheme(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_host(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
+ TT_URI("#fr?ed");
+ evhttp_uri_free(uri);
+#undef URI_PARSE
+#undef TT_URI
+#undef BAD
+}
+
+static void
+http_uriencode_test(void *ptr)
+{
+ char *s=NULL, *s2=NULL;
+ size_t sz;
+ int bytes_decoded;
+
+#define ENC(from,want,plus) do { \
+ s = evhttp_uriencode((from), -1, (plus)); \
+ tt_assert(s); \
+ tt_str_op(s,==,(want)); \
+ sz = -1; \
+ s2 = evhttp_uridecode((s), (plus), &sz); \
+ tt_assert(s2); \
+ tt_str_op(s2,==,(from)); \
+ tt_int_op(sz,==,strlen(from)); \
+ free(s); \
+ free(s2); \
+ s = s2 = NULL; \
+ } while (0)
+
+#define DEC(from,want,dp) do { \
+ s = evhttp_uridecode((from),(dp),&sz); \
+ tt_assert(s); \
+ tt_str_op(s,==,(want)); \
+ tt_int_op(sz,==,strlen(want)); \
+ free(s); \
+ s = NULL; \
+ } while (0)
+
+#define OLD_DEC(from,want) do { \
+ s = evhttp_decode_uri((from)); \
+ tt_assert(s); \
+ tt_str_op(s,==,(want)); \
+ free(s); \
+ s = NULL; \
+ } while (0)
+
+
+ ENC("Hello", "Hello",0);
+ ENC("99", "99",0);
+ ENC("", "",0);
+ ENC(
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",0);
+ ENC(" ", "%20",0);
+ ENC(" ", "+",1);
+ ENC("\xff\xf0\xe0", "%FF%F0%E0",0);
+ ENC("\x01\x19", "%01%19",1);
+ ENC("http://www.ietf.org/rfc/rfc3986.txt",
+ "http%3A%2F%2Fwww.ietf.org%2Frfc%2Frfc3986.txt",1);
+
+ ENC("1+2=3", "1%2B2%3D3",1);
+ ENC("1+2=3", "1%2B2%3D3",0);
+
+ /* Now try encoding with internal NULs. */
+ s = evhttp_uriencode("hello\0world", 11, 0);
+ tt_assert(s);
+ tt_str_op(s,==,"hello%00world");
+ free(s);
+ s = NULL;
+
+ /* Now try decoding just part of string. */
+ s = malloc(6 + 1 /* NUL byte */);
+ bytes_decoded = evhttp_decode_uri_internal("hello%20%20", 6, s, 0);
+ tt_assert(s);
+ tt_int_op(bytes_decoded,==,6);
+ tt_str_op(s,==,"hello%");
+ free(s);
+ s = NULL;
+
+ /* Now try out some decoding cases that we don't generate with
+ * encode_uri: Make sure that malformed stuff doesn't crash... */
+ DEC("%%xhello th+ere \xff",
+ "%%xhello th+ere \xff", 0);
+ /* Make sure plus decoding works */
+ DEC("plus+should%20work+", "plus should work ",1);
+ /* Try some lowercase hex */
+ DEC("%f0%a0%b0", "\xf0\xa0\xb0",1);
+
+ /* Try an internal NUL. */
+ sz = 0;
+ s = evhttp_uridecode("%00%00x%00%00", 1, &sz);
+ tt_int_op(sz,==,5);
+ tt_assert(!memcmp(s, "\0\0x\0\0", 5));
+ free(s);
+ s = NULL;
+
+ /* Try with size == NULL */
+ sz = 0;
+ s = evhttp_uridecode("%00%00x%00%00", 1, NULL);
+ tt_assert(!memcmp(s, "\0\0x\0\0", 5));
+ free(s);
+ s = NULL;
+
+ /* Test out the crazy old behavior of the deprecated
+ * evhttp_decode_uri */
+ OLD_DEC("http://example.com/normal+path/?key=val+with+spaces",
+ "http://example.com/normal+path/?key=val with spaces");
+
+end:
+ if (s)
+ free(s);
+ if (s2)
+ free(s2);
+#undef ENC
+#undef DEC
+#undef OLD_DEC
+}
+
+static void
+http_base_test(void *ptr)
+{
+ struct event_base *base = NULL;
+ struct bufferevent *bev;
+ evutil_socket_t fd;
+ const char *http_request;
+ ev_uint16_t port = 0;
+ struct evhttp *http;
+
+ test_ok = 0;
+ base = event_base_new();
+ tt_assert(base);
+ http = http_setup(&port, base, 0);
+
+ fd = http_connect("127.0.0.1", port);
+ tt_int_op(fd, >=, 0);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(base, fd, 0);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, base);
+ bufferevent_base_set(base, bev);
+
+ http_request =
+ "GET /test HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(base);
+
+ bufferevent_free(bev);
+ evutil_closesocket(fd);
+
+ evhttp_free(http);
+
+ tt_int_op(test_ok, ==, 2);
+
+end:
+ if (base)
+ event_base_free(base);
+}
+
+/*
+ * the server is just going to close the connection if it times out during
+ * reading the headers.
+ */
+
+static void
+http_incomplete_readcb(struct bufferevent *bev, void *arg)
+{
+ test_ok = -1;
+ event_base_loopexit(exit_base,NULL);
+}
+
+static void
+http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ /** For ssl */
+ if (what & BEV_EVENT_CONNECTED)
+ return;
+
+ if (what == (BEV_EVENT_READING|BEV_EVENT_EOF))
+ test_ok++;
+ else
+ test_ok = -2;
+ event_base_loopexit(exit_base,NULL);
+}
+
+static void
+http_incomplete_writecb(struct bufferevent *bev, void *arg)
+{
+ if (arg != NULL) {
+ evutil_socket_t fd = *(evutil_socket_t *)arg;
+ /* terminate the write side to simulate EOF */
+ shutdown(fd, EVUTIL_SHUT_WR);
+ }
+ if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
+ /* enable reading of the reply */
+ bufferevent_enable(bev, EV_READ);
+ test_ok++;
+ }
+}
+
+static void
+http_incomplete_test_(struct basic_test_data *data, int use_timeout, int ssl)
+{
+ struct bufferevent *bev;
+ evutil_socket_t fd;
+ const char *http_request;
+ ev_uint16_t port = 0;
+ struct timeval tv_start, tv_end;
+ struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ evhttp_set_timeout(http, 1);
+
+ fd = http_connect("127.0.0.1", port);
+ tt_int_op(fd, >=, 0);
+
+ /* Stupid thing to send a request */
+ bev = create_bev(data->base, fd, ssl);
+ bufferevent_setcb(bev,
+ http_incomplete_readcb, http_incomplete_writecb,
+ http_incomplete_errorcb, use_timeout ? NULL : &fd);
+
+ http_request =
+ "GET /test HTTP/1.1\r\n"
+ "Host: somehost\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ evutil_gettimeofday(&tv_start, NULL);
+
+ event_base_dispatch(data->base);
+
+ evutil_gettimeofday(&tv_end, NULL);
+ evutil_timersub(&tv_end, &tv_start, &tv_end);
+
+ bufferevent_free(bev);
+ if (use_timeout) {
+ evutil_closesocket(fd);
+ fd = -1;
+ }
+
+ evhttp_free(http);
+
+ if (use_timeout && tv_end.tv_sec >= 3) {
+ tt_abort_msg("time");
+ } else if (!use_timeout && tv_end.tv_sec >= 1) {
+ /* we should be done immediately */
+ tt_abort_msg("time");
+ }
+
+ tt_int_op(test_ok, ==, 2);
+ end:
+ if (fd >= 0)
+ evutil_closesocket(fd);
+}
+static void http_incomplete_test(void *arg)
+{ http_incomplete_test_(arg, 0, 0); }
+static void http_incomplete_timeout_test(void *arg)
+{ http_incomplete_test_(arg, 1, 0); }
+
+
+/*
+ * the server is going to reply with chunked data.
+ */
+
+static void
+http_chunked_readcb(struct bufferevent *bev, void *arg)
+{
+ /* nothing here */
+}
+
+static void
+http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ struct evhttp_request *req = NULL;
+
+ /** SSL */
+ if (what & BEV_EVENT_CONNECTED)
+ return;
+
+ if (!test_ok)
+ goto out;
+
+ test_ok = -1;
+
+ if ((what & BEV_EVENT_EOF) != 0) {
+ const char *header;
+ enum message_read_status done;
+ req = evhttp_request_new(NULL, NULL);
+
+ /* req->kind = EVHTTP_RESPONSE; */
+ done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
+ if (done != ALL_DATA_READ)
+ goto out;
+
+ done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
+ if (done != ALL_DATA_READ)
+ goto out;
+
+ header = evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding");
+ if (header == NULL || strcmp(header, "chunked"))
+ goto out;
+
+ header = evhttp_find_header(evhttp_request_get_input_headers(req), "Connection");
+ if (header == NULL || strcmp(header, "close"))
+ goto out;
+
+ header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
+ if (header == NULL)
+ goto out;
+ /* 13 chars */
+ if (strcmp(header, "d")) {
+ free((void*)header);
+ goto out;
+ }
+ free((void*)header);
+
+ if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 13),
+ "This is funny", 13))
+ goto out;
+
+ evbuffer_drain(bufferevent_get_input(bev), 13 + 2);
+
+ header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
+ if (header == NULL)
+ goto out;
+ /* 18 chars */
+ if (strcmp(header, "12"))
+ goto out;
+ free((char *)header);
+
+ if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 18),
+ "but not hilarious.", 18))
+ goto out;
+
+ evbuffer_drain(bufferevent_get_input(bev), 18 + 2);
+
+ header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
+ if (header == NULL)
+ goto out;
+ /* 8 chars */
+ if (strcmp(header, "8")) {
+ free((void*)header);
+ goto out;
+ }
+ free((char *)header);
+
+ if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 8),
+ "bwv 1052.", 8))
+ goto out;
+
+ evbuffer_drain(bufferevent_get_input(bev), 8 + 2);
+
+ header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
+ if (header == NULL)
+ goto out;
+ /* 0 chars */
+ if (strcmp(header, "0")) {
+ free((void*)header);
+ goto out;
+ }
+ free((void *)header);
+
+ test_ok = 2;
+ }
+
+out:
+ if (req)
+ evhttp_request_free(req);
+
+ event_base_loopexit(arg, NULL);
+}
+
+static void
+http_chunked_writecb(struct bufferevent *bev, void *arg)
+{
+ if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
+ /* enable reading of the reply */
+ bufferevent_enable(bev, EV_READ);
+ test_ok++;
+ }
+}
+
+static void
+http_chunked_request_done(struct evhttp_request *req, void *arg)
+{
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req),
+ "Transfer-Encoding") == NULL) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 13 + 18 + 8) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (strncmp((char *)evbuffer_pullup(evhttp_request_get_input_buffer(req), 13 + 18 + 8),
+ "This is funnybut not hilarious.bwv 1052",
+ 13 + 18 + 8)) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ event_base_loopexit(arg, NULL);
+}
+
+static void
+http_chunk_out_test_impl(void *arg, int ssl)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev;
+ evutil_socket_t fd;
+ const char *http_request;
+ ev_uint16_t port = 0;
+ struct timeval tv_start, tv_end;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ int i;
+ struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = create_bev(data->base, fd, ssl);
+ bufferevent_setcb(bev,
+ http_chunked_readcb, http_chunked_writecb,
+ http_chunked_errorcb, data->base);
+
+ http_request =
+ "GET /chunked HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ evutil_gettimeofday(&tv_start, NULL);
+
+ event_base_dispatch(data->base);
+
+ bufferevent_free(bev);
+
+ evutil_gettimeofday(&tv_end, NULL);
+ evutil_timersub(&tv_end, &tv_start, &tv_end);
+
+ tt_int_op(tv_end.tv_sec, <, 1);
+
+ tt_int_op(test_ok, ==, 2);
+
+ /* now try again with the regular connection object */
+ bev = create_bev(data->base, -1, ssl);
+ evcon = evhttp_connection_base_bufferevent_new(
+ data->base, NULL, bev, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /* make two requests to check the keepalive behavior */
+ for (i = 0; i < 2; i++) {
+ test_ok = 0;
+ req = evhttp_request_new(http_chunked_request_done,data->base);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req,
+ EVHTTP_REQ_GET, "/chunked") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 1);
+ }
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+static void http_chunk_out_test(void *arg)
+{ return http_chunk_out_test_impl(arg, 0); }
+
+static void
+http_stream_out_test_impl(void *arg, int ssl)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct bufferevent *bev;
+ struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
+
+ test_ok = 0;
+ exit_base = data->base;
+
+ bev = create_bev(data->base, -1, ssl);
+ evcon = evhttp_connection_base_bufferevent_new(
+ data->base, NULL, bev, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule a request to the HTTP
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_request_done,
+ (void *)"This is funnybut not hilarious.bwv 1052");
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/streamed")
+ == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+static void http_stream_out_test(void *arg)
+{ return http_stream_out_test_impl(arg, 0); }
+
+static void
+http_stream_in_chunk(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *reply = arg;
+
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ evbuffer_add_buffer(reply, evhttp_request_get_input_buffer(req));
+}
+
+static void
+http_stream_in_done(struct evhttp_request *req, void *arg)
+{
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ event_base_loopexit(exit_base, NULL);
+}
+
+/**
+ * Makes a request and reads the response in chunks.
+ */
+static void
+http_stream_in_test_(struct basic_test_data *data, char const *url,
+ size_t expected_len, char const *expected)
+{
+ struct evhttp_connection *evcon;
+ struct evbuffer *reply = evbuffer_new();
+ struct evhttp_request *req = NULL;
+ ev_uint16_t port = 0;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ exit_base = data->base;
+
+ evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port);
+ tt_assert(evcon);
+
+ req = evhttp_request_new(http_stream_in_done, reply);
+ evhttp_request_set_chunked_cb(req, http_stream_in_chunk);
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, url) == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ if (evbuffer_get_length(reply) != expected_len) {
+ TT_DIE(("reply length %lu; expected %lu; FAILED (%s)\n",
+ (unsigned long)evbuffer_get_length(reply),
+ (unsigned long)expected_len,
+ (char*)evbuffer_pullup(reply, -1)));
+ }
+
+ if (memcmp(evbuffer_pullup(reply, -1), expected, expected_len) != 0) {
+ tt_abort_msg("Memory mismatch");
+ }
+
+ test_ok = 1;
+ end:
+ if (reply)
+ evbuffer_free(reply);
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_stream_in_test(void *arg)
+{
+ http_stream_in_test_(arg, "/chunked", 13 + 18 + 8,
+ "This is funnybut not hilarious.bwv 1052");
+
+ http_stream_in_test_(arg, "/test", strlen(BASIC_REQUEST_BODY),
+ BASIC_REQUEST_BODY);
+}
+
+static void
+http_stream_in_cancel_chunk(struct evhttp_request *req, void *arg)
+{
+ tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_OK);
+
+ end:
+ evhttp_cancel_request(req);
+ event_base_loopexit(arg, NULL);
+}
+
+static void
+http_stream_in_cancel_done(struct evhttp_request *req, void *arg)
+{
+ /* should never be called */
+ tt_fail_msg("In cancel done");
+}
+
+static void
+http_stream_in_cancel_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct evhttp_connection *evcon;
+ struct evhttp_request *req = NULL;
+ ev_uint16_t port = 0;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ req = evhttp_request_new(http_stream_in_cancel_done, data->base);
+ evhttp_request_set_chunked_cb(req, http_stream_in_cancel_chunk);
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ test_ok = 1;
+ end:
+ evhttp_connection_free(evcon);
+ evhttp_free(http);
+
+}
+
+static void
+http_connection_fail_done(struct evhttp_request *req, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+ struct event_base *base = evhttp_connection_get_base(evcon);
+
+ /* An ENETUNREACH error results in an unrecoverable
+ * evhttp_connection error (see evhttp_connection_fail_()). The
+ * connection will be reset, and the user will be notified with a NULL
+ * req parameter. */
+ tt_assert(!req);
+
+ evhttp_connection_free(evcon);
+
+ test_ok = 1;
+
+ end:
+ event_base_loopexit(base, NULL);
+}
+
+/* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH
+ * error on connection. */
+static void
+http_connection_fail_test_impl(void *arg, int ssl)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct bufferevent *bev;
+ struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ /* auto detect a port */
+ evhttp_free(http);
+
+ bev = create_bev(data->base, -1, ssl);
+ /* Pick an unroutable address. This administratively scoped multicast
+ * address should do when working with TCP. */
+ evcon = evhttp_connection_base_bufferevent_new(
+ data->base, NULL, bev, "239.10.20.30", 80);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule an HTTP GET request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_connection_fail_done, evcon);
+ tt_assert(req);
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 1);
+
+ end:
+ ;
+}
+static void http_connection_fail_test(void *arg)
+{ return http_connection_fail_test_impl(arg, 0); }
+
+static void
+http_connection_retry_done(struct evhttp_request *req, void *arg)
+{
+ tt_assert(req);
+ tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) {
+ tt_abort_msg("(content type)\n");
+ }
+
+ tt_uint_op(evbuffer_get_length(evhttp_request_get_input_buffer(req)), ==, 0);
+
+ test_ok = 1;
+ end:
+ event_base_loopexit(arg,NULL);
+}
+
+struct http_server
+{
+ ev_uint16_t port;
+ int ssl;
+ struct evhttp *http;
+};
+static struct event_base *http_make_web_server_base=NULL;
+static void
+http_make_web_server(evutil_socket_t fd, short what, void *arg)
+{
+ struct http_server *hs = (struct http_server *)arg;
+ hs->http = http_setup(&hs->port, http_make_web_server_base, hs->ssl ? HTTP_BIND_SSL : 0);
+}
+
+static void
+http_simple_test_impl(void *arg, int ssl, int dirty)
+{
+ struct basic_test_data *data = arg;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct bufferevent *bev;
+ struct http_server hs = { .port = 0, .ssl = ssl, };
+ struct evhttp *http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 0);
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ bev = create_bev(data->base, -1, ssl);
+#ifdef EVENT__HAVE_OPENSSL
+ bufferevent_openssl_set_allow_dirty_shutdown(bev, dirty);
+#endif
+
+ evcon = evhttp_connection_base_bufferevent_new(
+ data->base, NULL, bev, "127.0.0.1", hs.port);
+ tt_assert(evcon);
+ evhttp_connection_set_local_address(evcon, "127.0.0.1");
+
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+ tt_assert(req);
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+ tt_int_op(test_ok, ==, 1);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+static void http_simple_test(void *arg)
+{ return http_simple_test_impl(arg, 0, 0); }
+
+static void
+http_connection_retry_test_basic(void *arg, const char *addr, struct evdns_base *dns_base, int ssl)
+{
+ struct basic_test_data *data = arg;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct timeval tv, tv_start, tv_end;
+ struct bufferevent *bev;
+ struct http_server hs = { .port = 0, .ssl = ssl, };
+ struct evhttp *http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 0);
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ /* auto detect a port */
+ evhttp_free(http);
+
+ bev = create_bev(data->base, -1, ssl);
+ evcon = evhttp_connection_base_bufferevent_new(data->base, dns_base, bev, addr, hs.port);
+ tt_assert(evcon);
+ if (dns_base)
+ tt_assert(!evhttp_connection_set_flags(evcon, EVHTTP_CON_REUSE_CONNECTED_ADDR));
+
+ evhttp_connection_set_timeout(evcon, 1);
+ /* also bind to local host */
+ evhttp_connection_set_local_address(evcon, "127.0.0.1");
+
+ /*
+ * At this point, we want to schedule an HTTP GET request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_connection_retry_done, data->base);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/?arg=val") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ evutil_gettimeofday(&tv_start, NULL);
+ event_base_dispatch(data->base);
+ evutil_gettimeofday(&tv_end, NULL);
+ evutil_timersub(&tv_end, &tv_start, &tv_end);
+ tt_int_op(tv_end.tv_sec, <, 1);
+
+ tt_int_op(test_ok, ==, 1);
+
+ /*
+ * now test the same but with retries
+ */
+ test_ok = 0;
+ /** Shutdown dns server, to test conn_address reusing */
+ if (dns_base)
+ regress_clean_dnsserver();
+
+ {
+ const struct timeval tv_timeout = { 0, 500000 };
+ const struct timeval tv_retry = { 0, 500000 };
+ evhttp_connection_set_timeout_tv(evcon, &tv_timeout);
+ evhttp_connection_set_initial_retry_tv(evcon, &tv_retry);
+ }
+ evhttp_connection_set_retries(evcon, 1);
+
+ req = evhttp_request_new(http_connection_retry_done, data->base);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/?arg=val") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ evutil_gettimeofday(&tv_start, NULL);
+ event_base_dispatch(data->base);
+ evutil_gettimeofday(&tv_end, NULL);
+
+ /* fails fast, .5 sec to wait to retry, fails fast again. */
+ test_timeval_diff_leq(&tv_start, &tv_end, 500, 200);
+
+ tt_assert(test_ok == 1);
+
+ /*
+ * now test the same but with retries and give it a web server
+ * at the end
+ */
+ test_ok = 0;
+
+ evhttp_connection_set_timeout(evcon, 1);
+ evhttp_connection_set_retries(evcon, 3);
+
+ req = evhttp_request_new(http_dispatcher_test_done, data->base);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/?arg=val") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ /* start up a web server .2 seconds after the connection tried
+ * to send a request
+ */
+ evutil_timerclear(&tv);
+ tv.tv_usec = 200000;
+ http_make_web_server_base = data->base;
+ event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &hs, &tv);
+
+ evutil_gettimeofday(&tv_start, NULL);
+ event_base_dispatch(data->base);
+ evutil_gettimeofday(&tv_end, NULL);
+ /* We'll wait twice as long as we did last time. */
+ test_timeval_diff_leq(&tv_start, &tv_end, 1000, 400);
+
+ tt_int_op(test_ok, ==, 1);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(hs.http);
+}
+
+static void
+http_connection_retry_conn_address_test_impl(void *arg, int ssl)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t portnum = 0;
+ struct evdns_base *dns_base = NULL;
+ char address[64];
+
+ tt_assert(regress_dnsserver(data->base, &portnum, search_table));
+ dns_base = evdns_base_new(data->base, 0/* init name servers */);
+ tt_assert(dns_base);
+
+ /* Add ourself as the only nameserver, and make sure we really are
+ * the only nameserver. */
+ evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
+ evdns_base_nameserver_ip_add(dns_base, address);
+
+ http_connection_retry_test_basic(arg, "localhost", dns_base, ssl);
+
+ end:
+ if (dns_base)
+ evdns_base_free(dns_base, 0);
+ /** dnsserver will be cleaned in http_connection_retry_test_basic() */
+}
+static void http_connection_retry_conn_address_test(void *arg)
+{ return http_connection_retry_conn_address_test_impl(arg, 0); }
+
+static void
+http_connection_retry_test_impl(void *arg, int ssl)
+{
+ return http_connection_retry_test_basic(arg, "127.0.0.1", NULL, ssl);
+}
+static void
+http_connection_retry_test(void *arg)
+{ return http_connection_retry_test_impl(arg, 0); }
+
+static void
+http_primitives(void *ptr)
+{
+ char *escaped = NULL;
+ struct evhttp *http = NULL;
+
+ escaped = evhttp_htmlescape("<script>");
+ tt_assert(escaped);
+ tt_str_op(escaped, ==, "&lt;script&gt;");
+ free(escaped);
+
+ escaped = evhttp_htmlescape("\"\'&");
+ tt_assert(escaped);
+ tt_str_op(escaped, ==, "&quot;&#039;&amp;");
+
+ http = evhttp_new(NULL);
+ tt_assert(http);
+ tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, http), ==, 0);
+ tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, http), ==, -1);
+ tt_int_op(evhttp_del_cb(http, "/test"), ==, 0);
+ tt_int_op(evhttp_del_cb(http, "/test"), ==, -1);
+ tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, http), ==, 0);
+
+ end:
+ if (escaped)
+ free(escaped);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_multi_line_header_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev= NULL;
+ evutil_socket_t fd = -1;
+ const char *http_start_request;
+ ev_uint16_t port = 0;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ tt_ptr_op(http, !=, NULL);
+
+ fd = http_connect("127.0.0.1", port);
+
+ tt_int_op(fd, !=, -1);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ tt_ptr_op(bev, !=, NULL);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ http_start_request =
+ "GET /test HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "X-Multi-Extra-WS: libevent \r\n"
+ "\t\t\t2.1 \r\n"
+ "X-Multi: aaaaaaaa\r\n"
+ " a\r\n"
+ "\tEND\r\n"
+ "X-Last: last\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_start_request, strlen(http_start_request));
+ found_multi = found_multi2 = 0;
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(found_multi, ==, 1);
+ tt_int_op(found_multi2, ==, 1);
+ tt_int_op(test_ok, ==, 4);
+ end:
+ if (bev)
+ bufferevent_free(bev);
+ if (fd >= 0)
+ evutil_closesocket(fd);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_request_bad(struct evhttp_request *req, void *arg)
+{
+ if (req != NULL) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ event_base_loopexit(arg, NULL);
+}
+
+static void
+http_negative_content_length_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ test_ok = 0;
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule a request to the HTTP
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_request_bad, data->base);
+
+ /* Cause the response to have a negative content-length */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "X-Negative", "makeitso");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+
+static void
+http_data_length_constraints_test_done(struct evhttp_request *req, void *arg)
+{
+ tt_assert(req);
+ tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_BADREQUEST);
+end:
+ event_base_loopexit(arg, NULL);
+}
+static void
+http_large_entity_test_done(struct evhttp_request *req, void *arg)
+{
+ tt_assert(req);
+ tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_ENTITYTOOLARGE);
+end:
+ event_base_loopexit(arg, NULL);
+}
+#ifndef WIN32
+static void
+http_expectation_failed_done(struct evhttp_request *req, void *arg)
+{
+ tt_assert(req);
+ tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_EXPECTATIONFAILED);
+end:
+ event_base_loopexit(arg, NULL);
+}
+#endif
+
+static void
+http_data_length_constraints_test_impl(void *arg, int read_on_write_error)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ char *long_str = NULL;
+ const size_t continue_size = 1<<20;
+ const size_t size = (1<<20) * 3;
+ void (*cb)(struct evhttp_request *, void *);
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ test_ok = 0;
+ cb = http_failed_request_done;
+#ifndef WIN32
+ if (read_on_write_error)
+ cb = http_data_length_constraints_test_done;
+#endif
+
+ tt_assert(continue_size < size);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ if (read_on_write_error)
+ tt_assert(!evhttp_connection_set_flags(evcon, EVHTTP_CON_READ_ON_WRITE_ERROR));
+
+ /* also bind to local host */
+ evhttp_connection_set_local_address(evcon, "127.0.0.1");
+
+ /*
+ * At this point, we want to schedule an HTTP GET request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
+ tt_assert(req);
+
+ long_str = malloc(size);
+ memset(long_str, 'a', size);
+ long_str[size - 1] = '\0';
+ /* Add the information that we care about */
+ evhttp_set_max_headers_size(http, size - 1);
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Longheader", long_str);
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+ event_base_dispatch(data->base);
+
+ req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
+ tt_assert(req);
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* GET /?arg=verylongvalue HTTP/1.1 */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, long_str) == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+ event_base_dispatch(data->base);
+
+#ifndef WIN32
+ if (read_on_write_error)
+ cb = http_large_entity_test_done;
+#endif
+ evhttp_set_max_body_size(http, size - 2);
+ req = evhttp_request_new(cb, data->base);
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+ evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+ event_base_dispatch(data->base);
+
+ req = evhttp_request_new(http_large_entity_test_done, data->base);
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
+ evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+ event_base_dispatch(data->base);
+
+ req = evhttp_request_new(http_dispatcher_test_done, data->base);
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
+ long_str[continue_size] = '\0';
+ evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+ event_base_dispatch(data->base);
+
+#ifndef WIN32
+ if (read_on_write_error)
+ cb = http_expectation_failed_done;
+#endif
+ req = evhttp_request_new(cb, data->base);
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "101-continue");
+ evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+ event_base_dispatch(data->base);
+
+ test_ok = 1;
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+ if (long_str)
+ free(long_str);
+}
+static void http_data_length_constraints_test(void *arg)
+{ http_data_length_constraints_test_impl(arg, 0); }
+static void http_read_on_write_error_test(void *arg)
+{ http_data_length_constraints_test_impl(arg, 1); }
+
+static void
+http_lingering_close_test_impl(void *arg, int lingering)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ char *long_str = NULL;
+ size_t size = (1<<20) * 3;
+ void (*cb)(struct evhttp_request *, void *);
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ test_ok = 0;
+
+ if (lingering)
+ tt_assert(!evhttp_set_flags(http, EVHTTP_SERVER_LINGERING_CLOSE));
+ evhttp_set_max_body_size(http, size / 2);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+ evhttp_connection_set_local_address(evcon, "127.0.0.1");
+
+ /*
+ * At this point, we want to schedule an HTTP GET request
+ * server using our make request method.
+ */
+
+ long_str = malloc(size);
+ memset(long_str, 'a', size);
+ long_str[size - 1] = '\0';
+
+ if (lingering)
+ cb = http_large_entity_test_done;
+ else
+ cb = http_failed_request_done;
+ req = evhttp_request_new(cb, data->base);
+ tt_assert(req);
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+ evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+ event_base_dispatch(data->base);
+
+ test_ok = 1;
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+ if (long_str)
+ free(long_str);
+}
+static void http_non_lingering_close_test(void *arg)
+{ http_lingering_close_test_impl(arg, 0); }
+static void http_lingering_close_test(void *arg)
+{ http_lingering_close_test_impl(arg, 1); }
+
+/*
+ * Testing client reset of server chunked connections
+ */
+
+struct terminate_state {
+ struct event_base *base;
+ struct evhttp_request *req;
+ struct bufferevent *bev;
+ evutil_socket_t fd;
+ int gotclosecb: 1;
+ int oneshot: 1;
+};
+
+static void
+terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
+{
+ struct terminate_state *state = arg;
+ struct evbuffer *evb;
+
+ if (!state->req) {
+ return;
+ }
+
+ if (evhttp_request_get_connection(state->req) == NULL) {
+ test_ok = 1;
+ evhttp_request_free(state->req);
+ event_base_loopexit(state->base,NULL);
+ return;
+ }
+
+ evb = evbuffer_new();
+ evbuffer_add_printf(evb, "%p", evb);
+ evhttp_send_reply_chunk(state->req, evb);
+ evbuffer_free(evb);
+
+ if (!state->oneshot) {
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 3000;
+ EVUTIL_ASSERT(state);
+ EVUTIL_ASSERT(state->base);
+ event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
+ }
+}
+
+static void
+terminate_chunked_close_cb(struct evhttp_connection *evcon, void *arg)
+{
+ struct terminate_state *state = arg;
+ state->gotclosecb = 1;
+
+ /** TODO: though we can do this unconditionally */
+ if (state->oneshot) {
+ evhttp_request_free(state->req);
+ state->req = NULL;
+ event_base_loopexit(state->base,NULL);
+ }
+}
+
+static void
+terminate_chunked_cb(struct evhttp_request *req, void *arg)
+{
+ struct terminate_state *state = arg;
+ struct timeval tv;
+
+ /* we want to know if this connection closes on us */
+ evhttp_connection_set_closecb(
+ evhttp_request_get_connection(req),
+ terminate_chunked_close_cb, arg);
+
+ state->req = req;
+
+ evhttp_send_reply_start(req, HTTP_OK, "OK");
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 3000;
+ event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
+}
+
+static void
+terminate_chunked_client(evutil_socket_t fd, short event, void *arg)
+{
+ struct terminate_state *state = arg;
+ bufferevent_free(state->bev);
+ evutil_closesocket(state->fd);
+}
+
+static void
+terminate_readcb(struct bufferevent *bev, void *arg)
+{
+ /* just drop the data */
+ evbuffer_drain(bufferevent_get_input(bev), -1);
+}
+
+
+static void
+http_terminate_chunked_test_impl(void *arg, int oneshot)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev = NULL;
+ struct timeval tv;
+ const char *http_request;
+ ev_uint16_t port = 0;
+ evutil_socket_t fd = -1;
+ struct terminate_state terminate_state;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ test_ok = 0;
+
+ evhttp_del_cb(http, "/test");
+ tt_assert(evhttp_set_cb(http, "/test",
+ terminate_chunked_cb, &terminate_state) == 0);
+
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, terminate_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ memset(&terminate_state, 0, sizeof(terminate_state));
+ terminate_state.base = data->base;
+ terminate_state.fd = fd;
+ terminate_state.bev = bev;
+ terminate_state.gotclosecb = 0;
+ terminate_state.oneshot = oneshot;
+
+ /* first half of the http request */
+ http_request =
+ "GET /test HTTP/1.1\r\n"
+ "Host: some\r\n\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+ evutil_timerclear(&tv);
+ tv.tv_usec = 10000;
+ event_base_once(data->base, -1, EV_TIMEOUT, terminate_chunked_client, &terminate_state,
+ &tv);
+
+ event_base_dispatch(data->base);
+
+ if (terminate_state.gotclosecb == 0)
+ test_ok = 0;
+
+ end:
+ if (fd >= 0)
+ evutil_closesocket(fd);
+ if (http)
+ evhttp_free(http);
+}
+static void
+http_terminate_chunked_test(void *arg)
+{
+ http_terminate_chunked_test_impl(arg, 0);
+}
+static void
+http_terminate_chunked_oneshot_test(void *arg)
+{
+ http_terminate_chunked_test_impl(arg, 1);
+}
+
+static struct regress_dns_server_table ipv6_search_table[] = {
+ { "localhost", "AAAA", "::1", 0, 0 },
+ { NULL, NULL, NULL, 0, 0 }
+};
+
+static void
+http_ipv6_for_domain_test_impl(void *arg, int family)
+{
+ struct basic_test_data *data = arg;
+ struct evdns_base *dns_base = NULL;
+ ev_uint16_t portnum = 0;
+ char address[64];
+
+ tt_assert(regress_dnsserver(data->base, &portnum, ipv6_search_table));
+
+ dns_base = evdns_base_new(data->base, 0/* init name servers */);
+ tt_assert(dns_base);
+
+ /* Add ourself as the only nameserver, and make sure we really are
+ * the only nameserver. */
+ evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
+ evdns_base_nameserver_ip_add(dns_base, address);
+
+ http_connection_test_(arg, 0 /* not persistent */, "localhost", dns_base,
+ 1 /* ipv6 */, family, 0);
+
+ end:
+ if (dns_base)
+ evdns_base_free(dns_base, 0);
+ regress_clean_dnsserver();
+}
+static void
+http_ipv6_for_domain_test(void *arg)
+{
+ http_ipv6_for_domain_test_impl(arg, AF_UNSPEC);
+}
+
+static void
+http_request_get_addr_on_close(struct evhttp_connection *evcon, void *arg)
+{
+ const struct sockaddr *storage;
+ char addrbuf[128];
+ char local[] = "127.0.0.1:";
+
+ test_ok = 0;
+ tt_assert(evcon);
+
+ storage = evhttp_connection_get_addr(evcon);
+ tt_assert(storage);
+
+ evutil_format_sockaddr_port_((struct sockaddr *)storage, addrbuf, sizeof(addrbuf));
+ tt_assert(!strncmp(addrbuf, local, sizeof(local) - 1));
+
+ test_ok = 1;
+ return;
+
+end:
+ test_ok = 0;
+}
+
+static void
+http_get_addr_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ test_ok = 0;
+ exit_base = data->base;
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+ evhttp_connection_set_closecb(evcon, http_request_get_addr_on_close, arg);
+
+ /*
+ * At this point, we want to schedule a request to the HTTP
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_request_done, (void *)BASIC_REQUEST_BODY);
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ http_request_get_addr_on_close(evcon, NULL);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_set_family_test(void *arg)
+{
+ http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, 0);
+}
+static void
+http_set_family_ipv4_test(void *arg)
+{
+ http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_INET, 0);
+}
+static void
+http_set_family_ipv6_test(void *arg)
+{
+ http_ipv6_for_domain_test_impl(arg, AF_INET6);
+}
+
+static void
+http_write_during_read(evutil_socket_t fd, short what, void *arg)
+{
+ struct bufferevent *bev = arg;
+ struct timeval tv;
+
+ bufferevent_write(bev, "foobar", strlen("foobar"));
+
+ evutil_timerclear(&tv);
+ tv.tv_sec = 1;
+ event_base_loopexit(exit_base, &tv);
+}
+static void
+http_write_during_read_test_impl(void *arg, int ssl)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct bufferevent *bev = NULL;
+ struct timeval tv;
+ int fd;
+ const char *http_request;
+ struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
+
+ test_ok = 0;
+ exit_base = data->base;
+
+ fd = http_connect("127.0.0.1", port);
+ bev = create_bev(data->base, fd, 0);
+ bufferevent_setcb(bev, NULL, NULL, NULL, data->base);
+ bufferevent_disable(bev, EV_READ);
+
+ http_request =
+ "GET /large HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+ evutil_timerclear(&tv);
+ tv.tv_usec = 10000;
+ event_base_once(data->base, -1, EV_TIMEOUT, http_write_during_read, bev, &tv);
+
+ event_base_dispatch(data->base);
+
+ if (bev)
+ bufferevent_free(bev);
+ if (http)
+ evhttp_free(http);
+}
+static void http_write_during_read_test(void *arg)
+{ return http_write_during_read_test_impl(arg, 0); }
+
+static void
+http_request_own_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct evhttp *http = http_setup(&port, data->base, 0);
+
+ test_ok = 0;
+ exit_base = data->base;
+
+ evhttp_free(http);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ req = evhttp_request_new(http_request_no_action_done, NULL);
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+ evhttp_request_own(req);
+
+ event_base_dispatch(data->base);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (req)
+ evhttp_request_free(req);
+
+ test_ok = 1;
+}
+
+#define HTTP_LEGACY(name) \
+ { #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
+ http_##name##_test }
+
+#define HTTP_CAST_ARG(a) ((void *)(a))
+#define HTTP_N(title, name, arg) \
+ { #title, http_##name##_test, TT_ISOLATED, &basic_setup, HTTP_CAST_ARG(arg) }
+#define HTTP(name) HTTP_N(name, name, NULL)
+#define HTTPS(name) \
+ { "https_" #name, https_##name##_test, TT_ISOLATED, &basic_setup, NULL }
+
+#ifdef EVENT__HAVE_OPENSSL
+static void https_basic_test(void *arg)
+{ return http_basic_test_impl(arg, 1); }
+static void https_incomplete_test(void *arg)
+{ http_incomplete_test_(arg, 0, 1); }
+static void https_incomplete_timeout_test(void *arg)
+{ http_incomplete_test_(arg, 1, 1); }
+static void https_simple_test(void *arg)
+{ return http_simple_test_impl(arg, 1, 0); }
+static void https_simple_dirty_test(void *arg)
+{ return http_simple_test_impl(arg, 1, 1); }
+static void https_connection_retry_conn_address_test(void *arg)
+{ return http_connection_retry_conn_address_test_impl(arg, 1); }
+static void https_connection_retry_test(void *arg)
+{ return http_connection_retry_test_impl(arg, 1); }
+static void https_chunk_out_test(void *arg)
+{ return http_chunk_out_test_impl(arg, 1); }
+static void https_stream_out_test(void *arg)
+{ return http_stream_out_test_impl(arg, 1); }
+static void https_connection_fail_test(void *arg)
+{ return http_connection_fail_test_impl(arg, 1); }
+static void https_write_during_read_test(void *arg)
+{ return http_write_during_read_test_impl(arg, 1); }
+static void https_connection_test(void *arg)
+{ return http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, 1); }
+static void https_persist_connection_test(void *arg)
+{ return http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC, 1); }
+#endif
+
+struct testcase_t http_testcases[] = {
+ { "primitives", http_primitives, 0, NULL, NULL },
+ { "base", http_base_test, TT_FORK, NULL, NULL },
+ { "bad_headers", http_bad_header_test, 0, NULL, NULL },
+ { "parse_query", http_parse_query_test, 0, NULL, NULL },
+ { "parse_uri", http_parse_uri_test, 0, NULL, NULL },
+ { "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
+ { "uriencode", http_uriencode_test, 0, NULL, NULL },
+ HTTP(basic),
+ HTTP(simple),
+
+ HTTP_N(cancel, cancel, BASIC),
+ HTTP_N(cancel_by_host, cancel, BY_HOST),
+ HTTP_N(cancel_by_host_no_ns, cancel, BY_HOST | NO_NS),
+ HTTP_N(cancel_by_host_inactive_server, cancel, BY_HOST | INACTIVE_SERVER),
+ HTTP_N(cancel_inactive_server, cancel, INACTIVE_SERVER),
+ HTTP_N(cancel_by_host_no_ns_inactive_server, cancel, BY_HOST | NO_NS | INACTIVE_SERVER),
+#ifndef __FreeBSD__
+ HTTP_N(cancel_by_host_server_timeout, cancel, BY_HOST | INACTIVE_SERVER | SERVER_TIMEOUT),
+ HTTP_N(cancel_server_timeout, cancel, INACTIVE_SERVER | SERVER_TIMEOUT),
+ HTTP_N(cancel_by_host_no_ns_server_timeout, cancel, BY_HOST | NO_NS | INACTIVE_SERVER | SERVER_TIMEOUT),
+ HTTP_N(cancel_by_host_ns_timeout_server_timeout, cancel, BY_HOST | NO_NS | NS_TIMEOUT | INACTIVE_SERVER | SERVER_TIMEOUT),
+#endif
+ HTTP_N(cancel_by_host_ns_timeout, cancel, BY_HOST | NO_NS | NS_TIMEOUT),
+ HTTP_N(cancel_by_host_ns_timeout_inactive_server, cancel, BY_HOST | NO_NS | NS_TIMEOUT | INACTIVE_SERVER),
+
+ HTTP(virtual_host),
+ HTTP(post),
+ HTTP(put),
+ HTTP(delete),
+ HTTP(allowed_methods),
+ HTTP(failure),
+ HTTP(connection),
+ HTTP(persist_connection),
+ HTTP(autofree_connection),
+ HTTP(connection_async),
+ HTTP(close_detection),
+ HTTP(close_detection_delay),
+ HTTP(bad_request),
+ HTTP(incomplete),
+ HTTP(incomplete_timeout),
+ HTTP(terminate_chunked),
+ HTTP(terminate_chunked_oneshot),
+ HTTP(on_complete),
+
+ HTTP(highport),
+ HTTP(dispatcher),
+ HTTP(multi_line_header),
+ HTTP(negative_content_length),
+ HTTP(chunk_out),
+ HTTP(stream_out),
+
+ HTTP(stream_in),
+ HTTP(stream_in_cancel),
+
+ HTTP(connection_fail),
+ { "connection_retry", http_connection_retry_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
+ { "connection_retry_conn_address", http_connection_retry_conn_address_test,
+ TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
+
+ HTTP(data_length_constraints),
+ HTTP(read_on_write_error),
+ HTTP(non_lingering_close),
+ HTTP(lingering_close),
+
+ HTTP(ipv6_for_domain),
+ HTTP(get_addr),
+
+ HTTP(set_family),
+ HTTP(set_family_ipv4),
+ HTTP(set_family_ipv6),
+
+ HTTP(write_during_read),
+ HTTP(request_own),
+
+#ifdef EVENT__HAVE_OPENSSL
+ HTTPS(basic),
+ HTTPS(simple),
+ HTTPS(simple_dirty),
+ HTTPS(incomplete),
+ HTTPS(incomplete_timeout),
+ { "https_connection_retry", https_connection_retry_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
+ { "https_connection_retry_conn_address", https_connection_retry_conn_address_test,
+ TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
+ HTTPS(chunk_out),
+ HTTPS(stream_out),
+ HTTPS(connection_fail),
+ HTTPS(write_during_read),
+ HTTPS(connection),
+ HTTPS(persist_connection),
+#endif
+
+ END_OF_TESTCASES
+};
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_iocp.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_iocp.c
new file mode 100644
index 000000000..17b385241
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_iocp.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "event2/event.h"
+#include "event2/thread.h"
+#include "event2/buffer.h"
+#include "event2/buffer_compat.h"
+#include "event2/bufferevent.h"
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include "regress.h"
+#include "tinytest.h"
+#include "tinytest_macros.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock2.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include "iocp-internal.h"
+#include "evbuffer-internal.h"
+#include "evthread-internal.h"
+
+/* FIXME remove these ones */
+#include <sys/queue.h>
+#include "event2/event_struct.h"
+#include "event-internal.h"
+
+#define MAX_CALLS 16
+
+static void *count_lock = NULL, *count_cond = NULL;
+static int count = 0;
+
+static void
+count_init(void)
+{
+ EVTHREAD_ALLOC_LOCK(count_lock, 0);
+ EVTHREAD_ALLOC_COND(count_cond);
+
+ tt_assert(count_lock);
+ tt_assert(count_cond);
+
+end:
+ ;
+}
+
+static void
+count_free(void)
+{
+ EVTHREAD_FREE_LOCK(count_lock, 0);
+ EVTHREAD_FREE_COND(count_cond);
+}
+
+static void
+count_incr(void)
+{
+ EVLOCK_LOCK(count_lock, 0);
+ count++;
+ EVTHREAD_COND_BROADCAST(count_cond);
+ EVLOCK_UNLOCK(count_lock, 0);
+}
+
+static int
+count_wait_for(int i, int ms)
+{
+ struct timeval tv;
+ DWORD elapsed;
+ int rv = -1;
+
+ EVLOCK_LOCK(count_lock, 0);
+ while (ms > 0 && count != i) {
+ tv.tv_sec = 0;
+ tv.tv_usec = ms * 1000;
+ elapsed = GetTickCount();
+ EVTHREAD_COND_WAIT_TIMED(count_cond, count_lock, &tv);
+ elapsed = GetTickCount() - elapsed;
+ ms -= elapsed;
+ }
+ if (count == i)
+ rv = 0;
+ EVLOCK_UNLOCK(count_lock, 0);
+
+ return rv;
+}
+
+struct dummy_overlapped {
+ struct event_overlapped eo;
+ void *lock;
+ int call_count;
+ uintptr_t keys[MAX_CALLS];
+ ev_ssize_t sizes[MAX_CALLS];
+};
+
+static void
+dummy_cb(struct event_overlapped *o, uintptr_t key, ev_ssize_t n, int ok)
+{
+ struct dummy_overlapped *d_o =
+ EVUTIL_UPCAST(o, struct dummy_overlapped, eo);
+
+ EVLOCK_LOCK(d_o->lock, 0);
+ if (d_o->call_count < MAX_CALLS) {
+ d_o->keys[d_o->call_count] = key;
+ d_o->sizes[d_o->call_count] = n;
+ }
+ d_o->call_count++;
+ EVLOCK_UNLOCK(d_o->lock, 0);
+
+ count_incr();
+}
+
+static int
+pair_is_in(struct dummy_overlapped *o, uintptr_t key, ev_ssize_t n)
+{
+ int i;
+ int result = 0;
+ EVLOCK_LOCK(o->lock, 0);
+ for (i=0; i < o->call_count; ++i) {
+ if (o->keys[i] == key && o->sizes[i] == n) {
+ result = 1;
+ break;
+ }
+ }
+ EVLOCK_UNLOCK(o->lock, 0);
+ return result;
+}
+
+static void
+test_iocp_port(void *ptr)
+{
+ struct event_iocp_port *port = NULL;
+ struct dummy_overlapped o1, o2;
+
+ memset(&o1, 0, sizeof(o1));
+ memset(&o2, 0, sizeof(o2));
+
+ count_init();
+ EVTHREAD_ALLOC_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ EVTHREAD_ALLOC_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+
+ tt_assert(o1.lock);
+ tt_assert(o2.lock);
+
+ event_overlapped_init_(&o1.eo, dummy_cb);
+ event_overlapped_init_(&o2.eo, dummy_cb);
+
+ port = event_iocp_port_launch_(0);
+ tt_assert(port);
+
+ tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 10, 100));
+ tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 20, 200));
+
+ tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 11, 101));
+ tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 21, 201));
+
+ tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 12, 102));
+ tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 22, 202));
+
+ tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 13, 103));
+ tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 23, 203));
+
+ tt_int_op(count_wait_for(8, 2000), ==, 0);
+
+ tt_want(!event_iocp_shutdown_(port, 2000));
+
+ tt_int_op(o1.call_count, ==, 4);
+ tt_int_op(o2.call_count, ==, 4);
+
+ tt_want(pair_is_in(&o1, 10, 100));
+ tt_want(pair_is_in(&o1, 11, 101));
+ tt_want(pair_is_in(&o1, 12, 102));
+ tt_want(pair_is_in(&o1, 13, 103));
+
+ tt_want(pair_is_in(&o2, 20, 200));
+ tt_want(pair_is_in(&o2, 21, 201));
+ tt_want(pair_is_in(&o2, 22, 202));
+ tt_want(pair_is_in(&o2, 23, 203));
+
+end:
+ EVTHREAD_FREE_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ EVTHREAD_FREE_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ count_free();
+}
+
+static struct evbuffer *rbuf = NULL, *wbuf = NULL;
+
+static void
+read_complete(struct event_overlapped *eo, uintptr_t key,
+ ev_ssize_t nbytes, int ok)
+{
+ tt_assert(ok);
+ evbuffer_commit_read_(rbuf, nbytes);
+ count_incr();
+end:
+ ;
+}
+
+static void
+write_complete(struct event_overlapped *eo, uintptr_t key,
+ ev_ssize_t nbytes, int ok)
+{
+ tt_assert(ok);
+ evbuffer_commit_write_(wbuf, nbytes);
+ count_incr();
+end:
+ ;
+}
+
+static void
+test_iocp_evbuffer(void *ptr)
+{
+ struct event_overlapped rol, wol;
+ struct basic_test_data *data = ptr;
+ struct event_iocp_port *port = NULL;
+ struct evbuffer *buf=NULL;
+ struct evbuffer_chain *chain;
+ char junk[1024];
+ int i;
+
+ count_init();
+ event_overlapped_init_(&rol, read_complete);
+ event_overlapped_init_(&wol, write_complete);
+
+ for (i = 0; i < (int)sizeof(junk); ++i)
+ junk[i] = (char)(i);
+
+ rbuf = evbuffer_overlapped_new_(data->pair[0]);
+ wbuf = evbuffer_overlapped_new_(data->pair[1]);
+ evbuffer_enable_locking(rbuf, NULL);
+ evbuffer_enable_locking(wbuf, NULL);
+
+ port = event_iocp_port_launch_(0);
+ tt_assert(port);
+ tt_assert(rbuf);
+ tt_assert(wbuf);
+
+ tt_assert(!event_iocp_port_associate_(port, data->pair[0], 100));
+ tt_assert(!event_iocp_port_associate_(port, data->pair[1], 100));
+
+ for (i=0;i<10;++i)
+ evbuffer_add(wbuf, junk, sizeof(junk));
+
+ buf = evbuffer_new();
+ tt_assert(buf != NULL);
+ evbuffer_add(rbuf, junk, sizeof(junk));
+ tt_assert(!evbuffer_launch_read_(rbuf, 2048, &rol));
+ evbuffer_add_buffer(buf, rbuf);
+ tt_int_op(evbuffer_get_length(buf), ==, sizeof(junk));
+ for (chain = buf->first; chain; chain = chain->next)
+ tt_int_op(chain->flags & EVBUFFER_MEM_PINNED_ANY, ==, 0);
+ tt_assert(!evbuffer_get_length(rbuf));
+ tt_assert(!evbuffer_launch_write_(wbuf, 512, &wol));
+
+ tt_int_op(count_wait_for(2, 2000), ==, 0);
+
+ tt_int_op(evbuffer_get_length(rbuf),==,512);
+
+ /* FIXME Actually test some stuff here. */
+
+ tt_want(!event_iocp_shutdown_(port, 2000));
+end:
+ count_free();
+ evbuffer_free(rbuf);
+ evbuffer_free(wbuf);
+ if (buf) evbuffer_free(buf);
+}
+
+static int got_readcb = 0;
+
+static void
+async_readcb(struct bufferevent *bev, void *arg)
+{
+ /* Disabling read should cause the loop to quit */
+ bufferevent_disable(bev, EV_READ);
+ got_readcb++;
+}
+
+static void
+test_iocp_bufferevent_async(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_iocp_port *port = NULL;
+ struct bufferevent *bea1=NULL, *bea2=NULL;
+ char buf[128];
+ size_t n;
+
+ event_base_start_iocp_(data->base, 0);
+ port = event_base_get_iocp_(data->base);
+ tt_assert(port);
+
+ bea1 = bufferevent_async_new_(data->base, data->pair[0],
+ BEV_OPT_DEFER_CALLBACKS);
+ bea2 = bufferevent_async_new_(data->base, data->pair[1],
+ BEV_OPT_DEFER_CALLBACKS);
+ tt_assert(bea1);
+ tt_assert(bea2);
+
+ bufferevent_setcb(bea2, async_readcb, NULL, NULL, NULL);
+ bufferevent_enable(bea1, EV_WRITE);
+ bufferevent_enable(bea2, EV_READ);
+
+ bufferevent_write(bea1, "Hello world", strlen("Hello world")+1);
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(got_readcb, ==, 1);
+ n = bufferevent_read(bea2, buf, sizeof(buf)-1);
+ buf[n]='\0';
+ tt_str_op(buf, ==, "Hello world");
+
+end:
+ bufferevent_free(bea1);
+ bufferevent_free(bea2);
+}
+
+
+struct testcase_t iocp_testcases[] = {
+ { "port", test_iocp_port, TT_FORK|TT_NEED_THREADS, &basic_setup, NULL },
+ { "evbuffer", test_iocp_evbuffer,
+ TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS,
+ &basic_setup, NULL },
+ { "bufferevent_async", test_iocp_bufferevent_async,
+ TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS|TT_NEED_BASE,
+ &basic_setup, NULL },
+ END_OF_TESTCASES
+};
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_listener.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_listener.c
new file mode 100644
index 000000000..72f7237be
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_listener.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util-internal.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include <sys/types.h>
+
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
+#include <unistd.h>
+#endif
+#ifdef EVENT__HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#include <string.h>
+
+#include "event2/listener.h"
+#include "event2/event.h"
+#include "event2/util.h"
+
+#include "regress.h"
+#include "tinytest.h"
+#include "tinytest_macros.h"
+
+static void
+acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
+ struct sockaddr *addr, int socklen, void *arg)
+{
+ int *ptr = arg;
+ --*ptr;
+ TT_BLATHER(("Got one for %p", ptr));
+ evutil_closesocket(fd);
+
+ if (! *ptr)
+ evconnlistener_disable(listener);
+}
+
+static void
+regress_pick_a_port(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evconnlistener *listener1 = NULL, *listener2 = NULL;
+ struct sockaddr_in sin;
+ int count1 = 2, count2 = 1;
+ struct sockaddr_storage ss1, ss2;
+ struct sockaddr_in *sin1, *sin2;
+ ev_socklen_t slen1 = sizeof(ss1), slen2 = sizeof(ss2);
+ unsigned int flags =
+ LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC;
+
+ evutil_socket_t fd1 = -1, fd2 = -1, fd3 = -1;
+
+ if (data->setup_data && strstr((char*)data->setup_data, "ts")) {
+ flags |= LEV_OPT_THREADSAFE;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+ sin.sin_port = 0; /* "You pick!" */
+
+ listener1 = evconnlistener_new_bind(base, acceptcb, &count1,
+ flags, -1, (struct sockaddr *)&sin, sizeof(sin));
+ tt_assert(listener1);
+ listener2 = evconnlistener_new_bind(base, acceptcb, &count2,
+ flags, -1, (struct sockaddr *)&sin, sizeof(sin));
+ tt_assert(listener2);
+
+ tt_int_op(evconnlistener_get_fd(listener1), >=, 0);
+ tt_int_op(evconnlistener_get_fd(listener2), >=, 0);
+ tt_assert(getsockname(evconnlistener_get_fd(listener1),
+ (struct sockaddr*)&ss1, &slen1) == 0);
+ tt_assert(getsockname(evconnlistener_get_fd(listener2),
+ (struct sockaddr*)&ss2, &slen2) == 0);
+ tt_int_op(ss1.ss_family, ==, AF_INET);
+ tt_int_op(ss2.ss_family, ==, AF_INET);
+
+ sin1 = (struct sockaddr_in*)&ss1;
+ sin2 = (struct sockaddr_in*)&ss2;
+ tt_int_op(ntohl(sin1->sin_addr.s_addr), ==, 0x7f000001);
+ tt_int_op(ntohl(sin2->sin_addr.s_addr), ==, 0x7f000001);
+ tt_int_op(sin1->sin_port, !=, sin2->sin_port);
+
+ tt_ptr_op(evconnlistener_get_base(listener1), ==, base);
+ tt_ptr_op(evconnlistener_get_base(listener2), ==, base);
+
+ fd1 = fd2 = fd3 = -1;
+ evutil_socket_connect_(&fd1, (struct sockaddr*)&ss1, slen1);
+ evutil_socket_connect_(&fd2, (struct sockaddr*)&ss1, slen1);
+ evutil_socket_connect_(&fd3, (struct sockaddr*)&ss2, slen2);
+
+#ifdef _WIN32
+ Sleep(100); /* XXXX this is a stupid stopgap. */
+#endif
+ event_base_dispatch(base);
+
+ tt_int_op(count1, ==, 0);
+ tt_int_op(count2, ==, 0);
+
+end:
+ if (fd1>=0)
+ EVUTIL_CLOSESOCKET(fd1);
+ if (fd2>=0)
+ EVUTIL_CLOSESOCKET(fd2);
+ if (fd3>=0)
+ EVUTIL_CLOSESOCKET(fd3);
+ if (listener1)
+ evconnlistener_free(listener1);
+ if (listener2)
+ evconnlistener_free(listener2);
+}
+
+static void
+errorcb(struct evconnlistener *lis, void *data_)
+{
+ int *data = data_;
+ *data = 1000;
+ evconnlistener_disable(lis);
+}
+
+static void
+regress_listener_error(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evconnlistener *listener = NULL;
+ int count = 1;
+ unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE;
+
+ if (data->setup_data && strstr((char*)data->setup_data, "ts")) {
+ flags |= LEV_OPT_THREADSAFE;
+ }
+
+ /* send, so that pair[0] will look 'readable'*/
+ tt_int_op(send(data->pair[1], "hello", 5, 0), >, 0);
+
+ /* Start a listener with a bogus socket. */
+ listener = evconnlistener_new(base, acceptcb, &count,
+ flags, 0,
+ data->pair[0]);
+ tt_assert(listener);
+
+ evconnlistener_set_error_cb(listener, errorcb);
+
+ tt_assert(listener);
+
+ event_base_dispatch(base);
+ tt_int_op(count,==,1000); /* set by error cb */
+
+end:
+ if (listener)
+ evconnlistener_free(listener);
+}
+
+#ifdef EVENT__HAVE_SETRLIMIT
+static void
+regress_listener_error_unlock(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evconnlistener *listener = NULL;
+ unsigned int flags =
+ LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_THREADSAFE;
+
+ tt_int_op(send(data->pair[1], "hello", 5, 0), >, 0);
+
+ /* Start a listener with a bogus socket. */
+ listener = evconnlistener_new(base, acceptcb, NULL, flags, 0, data->pair[0]);
+ tt_assert(listener);
+
+ /** accept() must errored out with EMFILE */
+ {
+ struct rlimit rl;
+ rl.rlim_cur = rl.rlim_max = data->pair[1];
+ if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
+ TT_DIE(("Can't change RLIMIT_NOFILE"));
+ }
+ }
+
+ event_base_loop(base, EVLOOP_ONCE);
+
+ /** with lock debugging, can fail on lock->count assertion */
+
+end:
+ if (listener)
+ evconnlistener_free(listener);
+}
+#endif
+
+struct testcase_t listener_testcases[] = {
+
+ { "randport", regress_pick_a_port, TT_FORK|TT_NEED_BASE,
+ &basic_setup, NULL},
+
+ { "randport_ts", regress_pick_a_port, TT_FORK|TT_NEED_BASE,
+ &basic_setup, (char*)"ts"},
+
+#ifdef EVENT__HAVE_SETRLIMIT
+ { "error_unlock", regress_listener_error_unlock,
+ TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR,
+ &basic_setup, NULL},
+#endif
+
+ { "error", regress_listener_error,
+ TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR,
+ &basic_setup, NULL},
+
+ { "error_ts", regress_listener_error,
+ TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR,
+ &basic_setup, (char*)"ts"},
+
+ END_OF_TESTCASES,
+};
+
+struct testcase_t listener_iocp_testcases[] = {
+ { "randport", regress_pick_a_port,
+ TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP,
+ &basic_setup, NULL},
+
+ { "error", regress_listener_error,
+ TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR|TT_ENABLE_IOCP,
+ &basic_setup, NULL},
+
+ END_OF_TESTCASES,
+};
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_main.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_main.c
new file mode 100644
index 000000000..44e291119
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_main.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util-internal.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
+#if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
+ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
+#define FORK_BREAKS_GCOV
+#include <vproc.h>
+#endif
+#endif
+
+#include "event2/event-config.h"
+
+#if 0
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#include <signal.h>
+#include <errno.h>
+#endif
+
+#include <sys/types.h>
+#ifdef EVENT__HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "event2/util.h"
+#include "event2/event.h"
+#include "event2/event_compat.h"
+#include "event2/dns.h"
+#include "event2/dns_compat.h"
+#include "event2/thread.h"
+
+#include "event2/event-config.h"
+#include "regress.h"
+#include "tinytest.h"
+#include "tinytest_macros.h"
+#include "../iocp-internal.h"
+#include "../event-internal.h"
+
+struct evutil_weakrand_state test_weakrand_state;
+
+long
+timeval_msec_diff(const struct timeval *start, const struct timeval *end)
+{
+ long ms = end->tv_sec - start->tv_sec;
+ ms *= 1000;
+ ms += ((end->tv_usec - start->tv_usec)+500) / 1000;
+ return ms;
+}
+
+/* ============================================================ */
+/* Code to wrap up old legacy test cases that used setup() and cleanup().
+ *
+ * Not all of the tests designated "legacy" are ones that used setup() and
+ * cleanup(), of course. A test is legacy it it uses setup()/cleanup(), OR
+ * if it wants to find its event base/socketpair in global variables (ugh),
+ * OR if it wants to communicate success/failure through test_ok.
+ */
+
+/* This is set to true if we're inside a legacy test wrapper. It lets the
+ setup() and cleanup() functions in regress.c know they're not needed.
+ */
+int in_legacy_test_wrapper = 0;
+
+static void dnslogcb(int w, const char *m)
+{
+ TT_BLATHER(("%s", m));
+}
+
+/* creates a temporary file with the data in it. If *filename_out gets set,
+ * the caller should try to unlink it. */
+int
+regress_make_tmpfile(const void *data, size_t datalen, char **filename_out)
+{
+#ifndef _WIN32
+ char tmpfilename[32];
+ int fd;
+ *filename_out = NULL;
+ strcpy(tmpfilename, "/tmp/eventtmp.XXXXXX");
+#ifdef EVENT__HAVE_UMASK
+ umask(0077);
+#endif
+ fd = mkstemp(tmpfilename);
+ if (fd == -1)
+ return (-1);
+ if (write(fd, data, datalen) != (int)datalen) {
+ close(fd);
+ return (-1);
+ }
+ lseek(fd, 0, SEEK_SET);
+ /* remove it from the file system */
+ unlink(tmpfilename);
+ return (fd);
+#else
+ /* XXXX actually delete the file later */
+ char tmpfilepath[MAX_PATH];
+ char tmpfilename[MAX_PATH];
+ DWORD r, written;
+ int tries = 16;
+ HANDLE h;
+ r = GetTempPathA(MAX_PATH, tmpfilepath);
+ if (r > MAX_PATH || r == 0)
+ return (-1);
+ for (; tries > 0; --tries) {
+ r = GetTempFileNameA(tmpfilepath, "LIBEVENT", 0, tmpfilename);
+ if (r == 0)
+ return (-1);
+ h = CreateFileA(tmpfilename, GENERIC_READ|GENERIC_WRITE,
+ 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h != INVALID_HANDLE_VALUE)
+ break;
+ }
+ if (tries == 0)
+ return (-1);
+ written = 0;
+ *filename_out = strdup(tmpfilename);
+ WriteFile(h, data, (DWORD)datalen, &written, NULL);
+ /* Closing the fd returned by this function will indeed close h. */
+ return _open_osfhandle((intptr_t)h,_O_RDONLY);
+#endif
+}
+
+#ifndef _WIN32
+pid_t
+regress_fork(void)
+{
+ pid_t pid = fork();
+#ifdef FORK_BREAKS_GCOV
+ vproc_transaction_begin(0);
+#endif
+ return pid;
+}
+#endif
+
+static void
+ignore_log_cb(int s, const char *msg)
+{
+}
+
+static void *
+basic_test_setup(const struct testcase_t *testcase)
+{
+ struct event_base *base = NULL;
+ evutil_socket_t spair[2] = { -1, -1 };
+ struct basic_test_data *data = NULL;
+
+#ifndef _WIN32
+ if (testcase->flags & TT_ENABLE_IOCP_FLAG)
+ return (void*)TT_SKIP;
+#endif
+
+ if (testcase->flags & TT_NEED_THREADS) {
+ if (!(testcase->flags & TT_FORK))
+ return NULL;
+#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
+ if (evthread_use_pthreads())
+ exit(1);
+#elif defined(EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED)
+ if (evthread_use_windows_threads())
+ exit(1);
+#else
+ return (void*)TT_SKIP;
+#endif
+ }
+
+ if (testcase->flags & TT_NEED_SOCKETPAIR) {
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, spair) == -1) {
+ fprintf(stderr, "%s: socketpair\n", __func__);
+ exit(1);
+ }
+
+ if (evutil_make_socket_nonblocking(spair[0]) == -1) {
+ fprintf(stderr, "fcntl(O_NONBLOCK)");
+ exit(1);
+ }
+
+ if (evutil_make_socket_nonblocking(spair[1]) == -1) {
+ fprintf(stderr, "fcntl(O_NONBLOCK)");
+ exit(1);
+ }
+ }
+ if (testcase->flags & TT_NEED_BASE) {
+ if (testcase->flags & TT_LEGACY)
+ base = event_init();
+ else
+ base = event_base_new();
+ if (!base)
+ exit(1);
+ }
+ if (testcase->flags & TT_ENABLE_IOCP_FLAG) {
+ if (event_base_start_iocp_(base, 0)<0) {
+ event_base_free(base);
+ return (void*)TT_SKIP;
+ }
+ }
+
+ if (testcase->flags & TT_NEED_DNS) {
+ evdns_set_log_fn(dnslogcb);
+ if (evdns_init())
+ return NULL; /* fast failure */ /*XXX asserts. */
+ }
+
+ if (testcase->flags & TT_NO_LOGS)
+ event_set_log_callback(ignore_log_cb);
+
+ data = calloc(1, sizeof(*data));
+ if (!data)
+ exit(1);
+ data->base = base;
+ data->pair[0] = spair[0];
+ data->pair[1] = spair[1];
+ data->setup_data = testcase->setup_data;
+ return data;
+}
+
+static int
+basic_test_cleanup(const struct testcase_t *testcase, void *ptr)
+{
+ struct basic_test_data *data = ptr;
+
+ if (testcase->flags & TT_NO_LOGS)
+ event_set_log_callback(NULL);
+
+ if (testcase->flags & TT_NEED_SOCKETPAIR) {
+ if (data->pair[0] != -1)
+ evutil_closesocket(data->pair[0]);
+ if (data->pair[1] != -1)
+ evutil_closesocket(data->pair[1]);
+ }
+
+ if (testcase->flags & TT_NEED_DNS) {
+ evdns_shutdown(0);
+ }
+
+ if (testcase->flags & TT_NEED_BASE) {
+ if (data->base) {
+ event_base_assert_ok_(data->base);
+ event_base_free(data->base);
+ }
+ }
+
+ if (testcase->flags & TT_FORK)
+ libevent_global_shutdown();
+
+ free(data);
+
+ return 1;
+}
+
+const struct testcase_setup_t basic_setup = {
+ basic_test_setup, basic_test_cleanup
+};
+
+/* The "data" for a legacy test is just a pointer to the void fn(void)
+ function implementing the test case. We need to set up some globals,
+ though, since that's where legacy tests expect to find a socketpair
+ (sometimes) and a global event_base (sometimes).
+ */
+static void *
+legacy_test_setup(const struct testcase_t *testcase)
+{
+ struct basic_test_data *data = basic_test_setup(testcase);
+ if (data == (void*)TT_SKIP || data == NULL)
+ return data;
+ global_base = data->base;
+ pair[0] = data->pair[0];
+ pair[1] = data->pair[1];
+ data->legacy_test_fn = testcase->setup_data;
+ return data;
+}
+
+/* This function is the implementation of every legacy test case. It
+ sets test_ok to 0, invokes the test function, and tells tinytest that
+ the test failed if the test didn't set test_ok to 1.
+ */
+void
+run_legacy_test_fn(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ test_ok = called = 0;
+
+ in_legacy_test_wrapper = 1;
+ data->legacy_test_fn(); /* This part actually calls the test */
+ in_legacy_test_wrapper = 0;
+
+ if (!test_ok)
+ tt_abort_msg("Legacy unit test failed");
+
+end:
+ test_ok = 0;
+}
+
+/* This function doesn't have to clean up ptr (which is just a pointer
+ to the test function), but it may need to close the socketpair or
+ free the event_base.
+ */
+static int
+legacy_test_cleanup(const struct testcase_t *testcase, void *ptr)
+{
+ int r = basic_test_cleanup(testcase, ptr);
+ pair[0] = pair[1] = -1;
+ global_base = NULL;
+ return r;
+}
+
+const struct testcase_setup_t legacy_setup = {
+ legacy_test_setup, legacy_test_cleanup
+};
+
+/* ============================================================ */
+
+#if (!defined(EVENT__HAVE_PTHREADS) && !defined(_WIN32)) || defined(EVENT__DISABLE_THREAD_SUPPORT)
+struct testcase_t thread_testcases[] = {
+ { "basic", NULL, TT_SKIP, NULL, NULL },
+ END_OF_TESTCASES
+};
+#endif
+
+struct testgroup_t testgroups[] = {
+ { "main/", main_testcases },
+ { "heap/", minheap_testcases },
+ { "et/", edgetriggered_testcases },
+ { "finalize/", finalize_testcases },
+ { "evbuffer/", evbuffer_testcases },
+ { "signal/", signal_testcases },
+ { "util/", util_testcases },
+ { "bufferevent/", bufferevent_testcases },
+ { "http/", http_testcases },
+ { "dns/", dns_testcases },
+ { "evtag/", evtag_testcases },
+ { "rpc/", rpc_testcases },
+ { "thread/", thread_testcases },
+ { "listener/", listener_testcases },
+#ifdef _WIN32
+ { "iocp/", iocp_testcases },
+ { "iocp/bufferevent/", bufferevent_iocp_testcases },
+ { "iocp/listener/", listener_iocp_testcases },
+#endif
+#ifdef EVENT__HAVE_OPENSSL
+ { "ssl/", ssl_testcases },
+#endif
+ END_OF_GROUPS
+};
+
+const char *alltests[] = { "+..", NULL };
+const char *livenettests[] = {
+ "+util/getaddrinfo_live",
+ "+dns/gethostby..",
+ "+dns/resolve_reverse",
+ NULL
+};
+const char *finetimetests[] = {
+ "+util/monotonic_res_precise",
+ "+util/monotonic_res_fallback",
+ "+thread/deferred_cb_skew",
+ "+http/connection_retry",
+ "+http/https_connection_retry",
+ NULL
+};
+struct testlist_alias_t testaliases[] = {
+ { "all", alltests },
+ { "live_net", livenettests },
+ { "fine_timing", finetimetests },
+ END_OF_ALIASES
+};
+
+int libevent_tests_running_in_debug_mode = 0;
+
+int
+main(int argc, const char **argv)
+{
+#ifdef _WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ (void) WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+#ifndef _WIN32
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+ return 1;
+#endif
+
+#ifdef _WIN32
+ tinytest_skip(testgroups, "http/connection_retry");
+ tinytest_skip(testgroups, "http/https_connection_retry");
+#endif
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ if (!getenv("EVENT_NO_DEBUG_LOCKS"))
+ evthread_enable_lock_debugging();
+#endif
+
+ if (getenv("EVENT_DEBUG_MODE")) {
+ event_enable_debug_mode();
+ libevent_tests_running_in_debug_mode = 1;
+ }
+ if (getenv("EVENT_DEBUG_LOGGING_ALL")) {
+ event_enable_debug_logging(EVENT_DBG_ALL);
+ }
+
+ tinytest_set_aliases(testaliases);
+
+ evutil_weakrand_seed_(&test_weakrand_state, 0);
+
+ if (tinytest_main(argc,argv,testgroups))
+ return 1;
+
+ libevent_global_shutdown();
+
+ return 0;
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_minheap.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_minheap.c
new file mode 100644
index 000000000..05db32e26
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_minheap.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "../minheap-internal.h"
+
+#include <stdlib.h>
+#include "event2/event_struct.h"
+
+#include "tinytest.h"
+#include "tinytest_macros.h"
+#include "regress.h"
+
+static void
+set_random_timeout(struct event *ev)
+{
+ ev->ev_timeout.tv_sec = test_weakrand();
+ ev->ev_timeout.tv_usec = test_weakrand() & 0xfffff;
+ ev->ev_timeout_pos.min_heap_idx = -1;
+}
+
+static void
+check_heap(struct min_heap *heap)
+{
+ unsigned i;
+ for (i = 1; i < heap->n; ++i) {
+ unsigned parent_idx = (i-1)/2;
+ tt_want(evutil_timercmp(&heap->p[i]->ev_timeout,
+ &heap->p[parent_idx]->ev_timeout, >=));
+ }
+}
+
+static void
+test_heap_randomized(void *ptr)
+{
+ struct min_heap heap;
+ struct event *inserted[1024];
+ struct event *e, *last_e;
+ int i;
+
+ min_heap_ctor_(&heap);
+
+ for (i = 0; i < 1024; ++i) {
+ inserted[i] = malloc(sizeof(struct event));
+ set_random_timeout(inserted[i]);
+ min_heap_push_(&heap, inserted[i]);
+ }
+ check_heap(&heap);
+
+ tt_assert(min_heap_size_(&heap) == 1024);
+
+ for (i = 0; i < 512; ++i) {
+ min_heap_erase_(&heap, inserted[i]);
+ if (0 == (i % 32))
+ check_heap(&heap);
+ }
+ tt_assert(min_heap_size_(&heap) == 512);
+
+ last_e = min_heap_pop_(&heap);
+ while (1) {
+ e = min_heap_pop_(&heap);
+ if (!e)
+ break;
+ tt_want(evutil_timercmp(&last_e->ev_timeout,
+ &e->ev_timeout, <=));
+ }
+ tt_assert(min_heap_size_(&heap) == 0);
+end:
+ for (i = 0; i < 1024; ++i)
+ free(inserted[i]);
+
+ min_heap_dtor_(&heap);
+}
+
+struct testcase_t minheap_testcases[] = {
+ { "randomized", test_heap_randomized, 0, NULL, NULL },
+ END_OF_TESTCASES
+};
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_rpc.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_rpc.c
new file mode 100644
index 000000000..01a058cbb
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_rpc.c
@@ -0,0 +1,905 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* The old tests here need assertions to work. */
+#undef NDEBUG
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "event2/buffer.h"
+#include "event2/event.h"
+#include "event2/event_compat.h"
+#include "event2/http.h"
+#include "event2/http_compat.h"
+#include "event2/http_struct.h"
+#include "event2/rpc.h"
+#include "event2/rpc.h"
+#include "event2/rpc_struct.h"
+#include "event2/tag.h"
+#include "log-internal.h"
+
+#include "regress.gen.h"
+
+#include "regress.h"
+#include "regress_testutils.h"
+
+#ifndef NO_PYTHON_EXISTS
+
+static struct evhttp *
+http_setup(ev_uint16_t *pport)
+{
+ struct evhttp *myhttp;
+ ev_uint16_t port;
+ struct evhttp_bound_socket *sock;
+
+ myhttp = evhttp_new(NULL);
+ if (!myhttp)
+ event_errx(1, "Could not start web server");
+
+ /* Try a few different ports */
+ sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", 0);
+ if (!sock)
+ event_errx(1, "Couldn't open web port");
+
+ port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
+
+ *pport = port;
+ return (myhttp);
+}
+
+EVRPC_HEADER(Message, msg, kill)
+EVRPC_HEADER(NeverReply, msg, kill)
+
+EVRPC_GENERATE(Message, msg, kill)
+EVRPC_GENERATE(NeverReply, msg, kill)
+
+static int need_input_hook = 0;
+static int need_output_hook = 0;
+
+static void
+MessageCb(EVRPC_STRUCT(Message)* rpc, void *arg)
+{
+ struct kill* kill_reply = rpc->reply;
+
+ if (need_input_hook) {
+ struct evhttp_request* req = EVRPC_REQUEST_HTTP(rpc);
+ const char *header = evhttp_find_header(
+ req->input_headers, "X-Hook");
+ assert(header);
+ assert(strcmp(header, "input") == 0);
+ }
+
+ /* we just want to fill in some non-sense */
+ EVTAG_ASSIGN(kill_reply, weapon, "dagger");
+ EVTAG_ASSIGN(kill_reply, action, "wave around like an idiot");
+
+ /* no reply to the RPC */
+ EVRPC_REQUEST_DONE(rpc);
+}
+
+static EVRPC_STRUCT(NeverReply) *saved_rpc;
+
+static void
+NeverReplyCb(EVRPC_STRUCT(NeverReply)* rpc, void *arg)
+{
+ test_ok += 1;
+ saved_rpc = rpc;
+}
+
+static void
+rpc_setup(struct evhttp **phttp, ev_uint16_t *pport, struct evrpc_base **pbase)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+
+ http = http_setup(&port);
+ base = evrpc_init(http);
+
+ EVRPC_REGISTER(base, Message, msg, kill, MessageCb, NULL);
+ EVRPC_REGISTER(base, NeverReply, msg, kill, NeverReplyCb, NULL);
+
+ *phttp = http;
+ *pport = port;
+ *pbase = base;
+
+ need_input_hook = 0;
+ need_output_hook = 0;
+}
+
+static void
+rpc_teardown(struct evrpc_base *base)
+{
+ assert(EVRPC_UNREGISTER(base, Message) == 0);
+ assert(EVRPC_UNREGISTER(base, NeverReply) == 0);
+
+ evrpc_free(base);
+}
+
+static void
+rpc_postrequest_failure(struct evhttp_request *req, void *arg)
+{
+ if (req->response_code != HTTP_SERVUNAVAIL) {
+
+ fprintf(stderr, "FAILED (response code)\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ event_loopexit(NULL);
+}
+
+/*
+ * Test a malformed payload submitted as an RPC
+ */
+
+static void
+rpc_basic_test(void)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+
+ rpc_setup(&http, &port, &base);
+
+ evcon = evhttp_connection_new("127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule an HTTP POST request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(rpc_postrequest_failure, NULL);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(req->output_headers, "Host", "somehost");
+ evbuffer_add_printf(req->output_buffer, "Some Nonsense");
+
+ if (evhttp_make_request(evcon, req,
+ EVHTTP_REQ_POST,
+ "/.rpc.Message") == -1) {
+ tt_abort();
+ }
+
+ test_ok = 0;
+
+ event_dispatch();
+
+ evhttp_connection_free(evcon);
+
+ rpc_teardown(base);
+
+ tt_assert(test_ok == 1);
+
+end:
+ evhttp_free(http);
+}
+
+static void
+rpc_postrequest_done(struct evhttp_request *req, void *arg)
+{
+ struct kill* kill_reply = NULL;
+
+ if (req->response_code != HTTP_OK) {
+ fprintf(stderr, "FAILED (response code)\n");
+ exit(1);
+ }
+
+ kill_reply = kill_new();
+
+ if ((kill_unmarshal(kill_reply, req->input_buffer)) == -1) {
+ fprintf(stderr, "FAILED (unmarshal)\n");
+ exit(1);
+ }
+
+ kill_free(kill_reply);
+
+ test_ok = 1;
+ event_loopexit(NULL);
+}
+
+static void
+rpc_basic_message(void)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct msg *msg;
+
+ rpc_setup(&http, &port, &base);
+
+ evcon = evhttp_connection_new("127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule an HTTP POST request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(rpc_postrequest_done, NULL);
+ if (req == NULL) {
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+ }
+
+ /* Add the information that we care about */
+ evhttp_add_header(req->output_headers, "Host", "somehost");
+
+ /* set up the basic message */
+ msg = msg_new();
+ EVTAG_ASSIGN(msg, from_name, "niels");
+ EVTAG_ASSIGN(msg, to_name, "tester");
+ msg_marshal(req->output_buffer, msg);
+ msg_free(msg);
+
+ if (evhttp_make_request(evcon, req,
+ EVHTTP_REQ_POST,
+ "/.rpc.Message") == -1) {
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+ }
+
+ test_ok = 0;
+
+ event_dispatch();
+
+ evhttp_connection_free(evcon);
+
+ rpc_teardown(base);
+
+end:
+ evhttp_free(http);
+}
+
+static struct evrpc_pool *
+rpc_pool_with_connection(ev_uint16_t port)
+{
+ struct evhttp_connection *evcon;
+ struct evrpc_pool *pool;
+
+ pool = evrpc_pool_new(NULL);
+ assert(pool != NULL);
+
+ evcon = evhttp_connection_new("127.0.0.1", port);
+ assert(evcon != NULL);
+
+ evrpc_pool_add_connection(pool, evcon);
+
+ return (pool);
+}
+
+static void
+GotKillCb(struct evrpc_status *status,
+ struct msg *msg, struct kill *kill, void *arg)
+{
+ char *weapon;
+ char *action;
+
+ if (need_output_hook) {
+ struct evhttp_request *req = status->http_req;
+ const char *header = evhttp_find_header(
+ req->input_headers, "X-Pool-Hook");
+ assert(header);
+ assert(strcmp(header, "ran") == 0);
+ }
+
+ if (status->error != EVRPC_STATUS_ERR_NONE)
+ goto done;
+
+ if (EVTAG_GET(kill, weapon, &weapon) == -1) {
+ fprintf(stderr, "get weapon\n");
+ goto done;
+ }
+ if (EVTAG_GET(kill, action, &action) == -1) {
+ fprintf(stderr, "get action\n");
+ goto done;
+ }
+
+ if (strcmp(weapon, "dagger"))
+ goto done;
+
+ if (strcmp(action, "wave around like an idiot"))
+ goto done;
+
+ test_ok += 1;
+
+done:
+ event_loopexit(NULL);
+}
+
+static void
+GotKillCbTwo(struct evrpc_status *status,
+ struct msg *msg, struct kill *kill, void *arg)
+{
+ char *weapon;
+ char *action;
+
+ if (status->error != EVRPC_STATUS_ERR_NONE)
+ goto done;
+
+ if (EVTAG_GET(kill, weapon, &weapon) == -1) {
+ fprintf(stderr, "get weapon\n");
+ goto done;
+ }
+ if (EVTAG_GET(kill, action, &action) == -1) {
+ fprintf(stderr, "get action\n");
+ goto done;
+ }
+
+ if (strcmp(weapon, "dagger"))
+ goto done;
+
+ if (strcmp(action, "wave around like an idiot"))
+ goto done;
+
+ test_ok += 1;
+
+done:
+ if (test_ok == 2)
+ event_loopexit(NULL);
+}
+
+static int
+rpc_hook_add_header(void *ctx, struct evhttp_request *req,
+ struct evbuffer *evbuf, void *arg)
+{
+ const char *hook_type = arg;
+ if (strcmp("input", hook_type) == 0)
+ evhttp_add_header(req->input_headers, "X-Hook", hook_type);
+ else
+ evhttp_add_header(req->output_headers, "X-Hook", hook_type);
+
+ assert(evrpc_hook_get_connection(ctx) != NULL);
+
+ return (EVRPC_CONTINUE);
+}
+
+static int
+rpc_hook_add_meta(void *ctx, struct evhttp_request *req,
+ struct evbuffer *evbuf, void *arg)
+{
+ evrpc_hook_add_meta(ctx, "meta", "test", 5);
+
+ assert(evrpc_hook_get_connection(ctx) != NULL);
+
+ return (EVRPC_CONTINUE);
+}
+
+static int
+rpc_hook_remove_header(void *ctx, struct evhttp_request *req,
+ struct evbuffer *evbuf, void *arg)
+{
+ const char *header = evhttp_find_header(req->input_headers, "X-Hook");
+ void *data = NULL;
+ size_t data_len = 0;
+
+ assert(header != NULL);
+ assert(strcmp(header, arg) == 0);
+
+ evhttp_remove_header(req->input_headers, "X-Hook");
+ evhttp_add_header(req->input_headers, "X-Pool-Hook", "ran");
+
+ assert(evrpc_hook_find_meta(ctx, "meta", &data, &data_len) == 0);
+ assert(data != NULL);
+ assert(data_len == 5);
+
+ assert(evrpc_hook_get_connection(ctx) != NULL);
+
+ return (EVRPC_CONTINUE);
+}
+
+static void
+rpc_basic_client(void)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+ struct evrpc_pool *pool = NULL;
+ struct msg *msg = NULL;
+ struct kill *kill = NULL;
+
+ rpc_setup(&http, &port, &base);
+
+ need_input_hook = 1;
+ need_output_hook = 1;
+
+ assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_add_header, (void*)"input")
+ != NULL);
+ assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_add_header, (void*)"output")
+ != NULL);
+
+ pool = rpc_pool_with_connection(port);
+ tt_assert(pool);
+
+ assert(evrpc_add_hook(pool, EVRPC_OUTPUT, rpc_hook_add_meta, NULL));
+ assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_remove_header, (void*)"output"));
+
+ /* set up the basic message */
+ msg = msg_new();
+ tt_assert(msg);
+ EVTAG_ASSIGN(msg, from_name, "niels");
+ EVTAG_ASSIGN(msg, to_name, "tester");
+
+ kill = kill_new();
+
+ EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
+
+ test_ok = 0;
+
+ event_dispatch();
+
+ tt_assert(test_ok == 1);
+
+ /* we do it twice to make sure that reuse works correctly */
+ kill_clear(kill);
+
+ EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
+
+ event_dispatch();
+
+ tt_assert(test_ok == 2);
+
+ /* we do it trice to make sure other stuff works, too */
+ kill_clear(kill);
+
+ {
+ struct evrpc_request_wrapper *ctx =
+ EVRPC_MAKE_CTX(Message, msg, kill,
+ pool, msg, kill, GotKillCb, NULL);
+ evrpc_make_request(ctx);
+ }
+
+ event_dispatch();
+
+ rpc_teardown(base);
+
+ tt_assert(test_ok == 3);
+
+end:
+ if (msg)
+ msg_free(msg);
+ if (kill)
+ kill_free(kill);
+
+ if (pool)
+ evrpc_pool_free(pool);
+ if (http)
+ evhttp_free(http);
+
+ need_input_hook = 0;
+ need_output_hook = 0;
+}
+
+/*
+ * We are testing that the second requests gets send over the same
+ * connection after the first RPCs completes.
+ */
+static void
+rpc_basic_queued_client(void)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+ struct evrpc_pool *pool = NULL;
+ struct msg *msg=NULL;
+ struct kill *kill_one=NULL, *kill_two=NULL;
+
+ rpc_setup(&http, &port, &base);
+
+ pool = rpc_pool_with_connection(port);
+ tt_assert(pool);
+
+ /* set up the basic message */
+ msg = msg_new();
+ tt_assert(msg);
+ EVTAG_ASSIGN(msg, from_name, "niels");
+ EVTAG_ASSIGN(msg, to_name, "tester");
+
+ kill_one = kill_new();
+ kill_two = kill_new();
+
+ EVRPC_MAKE_REQUEST(Message, pool, msg, kill_one, GotKillCbTwo, NULL);
+ EVRPC_MAKE_REQUEST(Message, pool, msg, kill_two, GotKillCb, NULL);
+
+ test_ok = 0;
+
+ event_dispatch();
+
+ rpc_teardown(base);
+
+ tt_assert(test_ok == 2);
+
+end:
+ if (msg)
+ msg_free(msg);
+ if (kill_one)
+ kill_free(kill_one);
+ if (kill_two)
+ kill_free(kill_two);
+
+ if (pool)
+ evrpc_pool_free(pool);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+GotErrorCb(struct evrpc_status *status,
+ struct msg *msg, struct kill *kill, void *arg)
+{
+ if (status->error != EVRPC_STATUS_ERR_TIMEOUT)
+ goto done;
+
+ /* should never be complete but just to check */
+ if (kill_complete(kill) == 0)
+ goto done;
+
+ test_ok += 1;
+
+done:
+ event_loopexit(NULL);
+}
+
+/* we just pause the rpc and continue it in the next callback */
+
+struct rpc_hook_ctx_ {
+ void *vbase;
+ void *ctx;
+};
+
+static int hook_pause_cb_called=0;
+
+static void
+rpc_hook_pause_cb(evutil_socket_t fd, short what, void *arg)
+{
+ struct rpc_hook_ctx_ *ctx = arg;
+ ++hook_pause_cb_called;
+ evrpc_resume_request(ctx->vbase, ctx->ctx, EVRPC_CONTINUE);
+ free(arg);
+}
+
+static int
+rpc_hook_pause(void *ctx, struct evhttp_request *req, struct evbuffer *evbuf,
+ void *arg)
+{
+ struct rpc_hook_ctx_ *tmp = malloc(sizeof(*tmp));
+ struct timeval tv;
+
+ assert(tmp != NULL);
+ tmp->vbase = arg;
+ tmp->ctx = ctx;
+
+ memset(&tv, 0, sizeof(tv));
+ event_once(-1, EV_TIMEOUT, rpc_hook_pause_cb, tmp, &tv);
+ return EVRPC_PAUSE;
+}
+
+static void
+rpc_basic_client_with_pause(void)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+ struct evrpc_pool *pool = NULL;
+ struct msg *msg = NULL;
+ struct kill *kill= NULL;
+
+ rpc_setup(&http, &port, &base);
+
+ assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_pause, base));
+ assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_pause, base));
+
+ pool = rpc_pool_with_connection(port);
+ tt_assert(pool);
+ assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_pause, pool));
+ assert(evrpc_add_hook(pool, EVRPC_OUTPUT, rpc_hook_pause, pool));
+
+ /* set up the basic message */
+ msg = msg_new();
+ tt_assert(msg);
+ EVTAG_ASSIGN(msg, from_name, "niels");
+ EVTAG_ASSIGN(msg, to_name, "tester");
+
+ kill = kill_new();
+
+ EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
+
+ test_ok = 0;
+
+ event_dispatch();
+
+ tt_int_op(test_ok, ==, 1);
+ tt_int_op(hook_pause_cb_called, ==, 4);
+
+end:
+ if (base)
+ rpc_teardown(base);
+
+ if (msg)
+ msg_free(msg);
+ if (kill)
+ kill_free(kill);
+
+ if (pool)
+ evrpc_pool_free(pool);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+rpc_client_timeout(void)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+ struct evrpc_pool *pool = NULL;
+ struct msg *msg = NULL;
+ struct kill *kill = NULL;
+
+ rpc_setup(&http, &port, &base);
+
+ pool = rpc_pool_with_connection(port);
+ tt_assert(pool);
+
+ /* set the timeout to 1 second. */
+ evrpc_pool_set_timeout(pool, 1);
+
+ /* set up the basic message */
+ msg = msg_new();
+ tt_assert(msg);
+ EVTAG_ASSIGN(msg, from_name, "niels");
+ EVTAG_ASSIGN(msg, to_name, "tester");
+
+ kill = kill_new();
+
+ EVRPC_MAKE_REQUEST(NeverReply, pool, msg, kill, GotErrorCb, NULL);
+
+ test_ok = 0;
+
+ event_dispatch();
+
+ /* free the saved RPC structure up */
+ EVRPC_REQUEST_DONE(saved_rpc);
+
+ rpc_teardown(base);
+
+ tt_assert(test_ok == 2);
+
+end:
+ if (msg)
+ msg_free(msg);
+ if (kill)
+ kill_free(kill);
+
+ if (pool)
+ evrpc_pool_free(pool);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+rpc_test(void)
+{
+ struct msg *msg = NULL, *msg2 = NULL;
+ struct kill *attack = NULL;
+ struct run *run = NULL;
+ struct evbuffer *tmp = evbuffer_new();
+ struct timeval tv_start, tv_end;
+ ev_uint32_t tag;
+ int i;
+
+ msg = msg_new();
+
+ tt_assert(msg);
+
+ EVTAG_ASSIGN(msg, from_name, "niels");
+ EVTAG_ASSIGN(msg, to_name, "phoenix");
+
+ if (EVTAG_GET(msg, attack, &attack) == -1) {
+ tt_abort_msg("Failed to set kill message.");
+ }
+
+ EVTAG_ASSIGN(attack, weapon, "feather");
+ EVTAG_ASSIGN(attack, action, "tickle");
+ for (i = 0; i < 3; ++i) {
+ if (EVTAG_ARRAY_ADD_VALUE(attack, how_often, i) == NULL) {
+ tt_abort_msg("Failed to add how_often.");
+ }
+ }
+
+ evutil_gettimeofday(&tv_start, NULL);
+ for (i = 0; i < 1000; ++i) {
+ run = EVTAG_ARRAY_ADD(msg, run);
+ if (run == NULL) {
+ tt_abort_msg("Failed to add run message.");
+ }
+ EVTAG_ASSIGN(run, how, "very fast but with some data in it");
+ EVTAG_ASSIGN(run, fixed_bytes,
+ (ev_uint8_t*)"012345678901234567890123");
+
+ if (EVTAG_ARRAY_ADD_VALUE(
+ run, notes, "this is my note") == NULL) {
+ tt_abort_msg("Failed to add note.");
+ }
+ if (EVTAG_ARRAY_ADD_VALUE(run, notes, "pps") == NULL) {
+ tt_abort_msg("Failed to add note");
+ }
+
+ EVTAG_ASSIGN(run, large_number, 0xdead0a0bcafebeefLL);
+ EVTAG_ARRAY_ADD_VALUE(run, other_numbers, 0xdead0a0b);
+ EVTAG_ARRAY_ADD_VALUE(run, other_numbers, 0xbeefcafe);
+ }
+
+ if (msg_complete(msg) == -1)
+ tt_abort_msg("Failed to make complete message.");
+
+ evtag_marshal_msg(tmp, 0xdeaf, msg);
+
+ if (evtag_peek(tmp, &tag) == -1)
+ tt_abort_msg("Failed to peak tag.");
+
+ if (tag != 0xdeaf)
+ TT_DIE(("Got incorrect tag: %0x.", (unsigned)tag));
+
+ msg2 = msg_new();
+ if (evtag_unmarshal_msg(tmp, 0xdeaf, msg2) == -1)
+ tt_abort_msg("Failed to unmarshal message.");
+
+ evutil_gettimeofday(&tv_end, NULL);
+ evutil_timersub(&tv_end, &tv_start, &tv_end);
+ TT_BLATHER(("(%.1f us/add) ",
+ (float)tv_end.tv_sec/(float)i * 1000000.0 +
+ tv_end.tv_usec / (float)i));
+
+ if (!EVTAG_HAS(msg2, from_name) ||
+ !EVTAG_HAS(msg2, to_name) ||
+ !EVTAG_HAS(msg2, attack)) {
+ tt_abort_msg("Missing data structures.");
+ }
+
+ if (EVTAG_GET(msg2, attack, &attack) == -1) {
+ tt_abort_msg("Could not get attack.");
+ }
+
+ if (EVTAG_ARRAY_LEN(msg2, run) != i) {
+ tt_abort_msg("Wrong number of run messages.");
+ }
+
+ /* get the very first run message */
+ if (EVTAG_ARRAY_GET(msg2, run, 0, &run) == -1) {
+ tt_abort_msg("Failed to get run msg.");
+ } else {
+ /* verify the notes */
+ char *note_one, *note_two;
+ ev_uint64_t large_number;
+ ev_uint32_t short_number;
+
+ if (EVTAG_ARRAY_LEN(run, notes) != 2) {
+ tt_abort_msg("Wrong number of note strings.");
+ }
+
+ if (EVTAG_ARRAY_GET(run, notes, 0, &note_one) == -1 ||
+ EVTAG_ARRAY_GET(run, notes, 1, &note_two) == -1) {
+ tt_abort_msg("Could not get note strings.");
+ }
+
+ if (strcmp(note_one, "this is my note") ||
+ strcmp(note_two, "pps")) {
+ tt_abort_msg("Incorrect note strings encoded.");
+ }
+
+ if (EVTAG_GET(run, large_number, &large_number) == -1 ||
+ large_number != 0xdead0a0bcafebeefLL) {
+ tt_abort_msg("Incorrrect large_number.");
+ }
+
+ if (EVTAG_ARRAY_LEN(run, other_numbers) != 2) {
+ tt_abort_msg("Wrong number of other_numbers.");
+ }
+
+ if (EVTAG_ARRAY_GET(
+ run, other_numbers, 0, &short_number) == -1) {
+ tt_abort_msg("Could not get short number.");
+ }
+ tt_uint_op(short_number, ==, 0xdead0a0b);
+
+ }
+ tt_int_op(EVTAG_ARRAY_LEN(attack, how_often), ==, 3);
+
+ for (i = 0; i < 3; ++i) {
+ ev_uint32_t res;
+ if (EVTAG_ARRAY_GET(attack, how_often, i, &res) == -1) {
+ TT_DIE(("Cannot get %dth how_often msg.", i));
+ }
+ if ((int)res != i) {
+ TT_DIE(("Wrong message encoded %d != %d", i, res));
+ }
+ }
+
+ test_ok = 1;
+end:
+ if (msg)
+ msg_free(msg);
+ if (msg2)
+ msg_free(msg2);
+ if (tmp)
+ evbuffer_free(tmp);
+}
+
+#define RPC_LEGACY(name) \
+ { #name, run_legacy_test_fn, TT_FORK|TT_NEED_BASE|TT_LEGACY, \
+ &legacy_setup, \
+ rpc_##name }
+#else
+/* NO_PYTHON_EXISTS */
+
+#define RPC_LEGACY(name) \
+ { #name, NULL, TT_SKIP, NULL, NULL }
+
+#endif
+
+struct testcase_t rpc_testcases[] = {
+ RPC_LEGACY(basic_test),
+ RPC_LEGACY(basic_message),
+ RPC_LEGACY(basic_client),
+ RPC_LEGACY(basic_queued_client),
+ RPC_LEGACY(basic_client_with_pause),
+ RPC_LEGACY(client_timeout),
+ RPC_LEGACY(test),
+
+ END_OF_TESTCASES,
+};
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_ssl.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_ssl.c
new file mode 100644
index 000000000..8a5524a8e
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_ssl.c
@@ -0,0 +1,802 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Get rid of OSX 10.7 and greater deprecation warnings.
+#if defined(__APPLE__) && defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include "util-internal.h"
+
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#include "event2/util.h"
+#include "event2/event.h"
+#include "event2/bufferevent_ssl.h"
+#include "event2/bufferevent_struct.h"
+#include "event2/buffer.h"
+#include "event2/listener.h"
+
+#include "regress.h"
+#include "tinytest.h"
+#include "tinytest_macros.h"
+
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include "openssl-compat.h"
+
+#include <string.h>
+#ifdef _WIN32
+#include <io.h>
+#define read _read
+#define write _write
+#else
+#include <unistd.h>
+#endif
+
+/* A pre-generated key, to save the cost of doing an RSA key generation step
+ * during the unit tests. It is published in this file, so you would have to
+ * be very foolish to consider using it in your own code. */
+static const char KEY[] =
+ "-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIIEogIBAAKCAQEAtK07Ili0dkJb79m/sFmHoVJTWyLoveXex2yX/BtUzzcvZEOu\n"
+ "QLon/++5YOA48kzZm5K9mIwZkZhui1ZgJ5Bjq0LGAWTZGIn+NXjLFshPYvTKpOCW\n"
+ "uzL0Ir0LXMsBLYJQ5A4FomLNxs4I3H/dhDSGy/rSiJB1B4w2xNiwPK08/VL3zZqk\n"
+ "V+GsSvGIIkzhTMbqPJy9K8pqyjwOU2pgORS794yXciTGxWYjTDzJPgQ35YMDATaG\n"
+ "jr4HHo1zxU/Lj0pndSUK5rKLYxYQ3Uc8B3AVYDl9CP/GbOoQ4LBzS68JjcAUyp6i\n"
+ "6NfXlc2D9S9XgqVqwI+JqgJs0eW/+zPY2UEDWwIDAQABAoIBAD2HzV66FOM9YDAD\n"
+ "2RtGskEHV2nvLpIVadRCsFPkPvK+2X3s6rgSbbLkwh4y3lHuSCGKTNVZyQ9jeSos\n"
+ "xVxT+Q2HFQW+gYyw2gj91TQyDY8mzKhv8AVaqff2p5r3a7RC8CdqexK9UVUGL9Bg\n"
+ "H2F5vfpTtkVZ5PEoGDLblNFlMiMW/t1SobUeBVx+Msco/xqk9lFv1A9nnepGy0Gi\n"
+ "D+i6YNGTBsX22YhoCZl/ICxCL8lgqPei4FvBr9dBVh/jQgjuUBm2jz55p2r7+7Aw\n"
+ "khmXHReejoVokQ2+htgSgZNKlKuDy710ZpBqnDi8ynQi82Y2qCpyg/p/xcER54B6\n"
+ "hSftaiECgYEA2RkSoxU+nWk+BClQEUZRi88QK5W/M8oo1DvUs36hvPFkw3Jk/gz0\n"
+ "fgd5bnA+MXj0Fc0QHvbddPjIkyoI/evq9GPV+JYIuH5zabrlI3Jvya8q9QpAcEDO\n"
+ "KkL/O09qXVEW52S6l05nh4PLejyI7aTyTIN5nbVLac/+M8MY/qOjZksCgYEA1Q1o\n"
+ "L8kjSavU2xhQmSgZb9W62Do60sa3e73ljrDPoiyvbExldpSdziFYxHBD/Rep0ePf\n"
+ "eVSGS3VSwevt9/jSGo2Oa83TYYns9agBm03oR/Go/DukESdI792NsEM+PRFypVNy\n"
+ "AohWRLj0UU6DV+zLKp0VBavtx0ATeLFX0eN17TECgYBI2O/3Bz7uhQ0JSm+SjFz6\n"
+ "o+2SInp5P2G57aWu4VQWWY3tQ2p+EQzNaWam10UXRrXoxtmc+ktPX9e2AgnoYoyB\n"
+ "myqGcpnUhqHlnZAb999o9r1cYidDQ4uqhLauSTSwwXAFDzjJYsa8o03Y440y6QFh\n"
+ "CVD6yYXXqLJs3g96CqDexwKBgAHxq1+0QCQt8zVElYewO/svQhMzBNJjic0RQIT6\n"
+ "zAo4yij80XgxhvcYiszQEW6/xobpw2JCCS+rFGQ8mOFIXfJsFD6blDAxp/3d2JXo\n"
+ "MhRl+hrDGI4ng5zcsqxHEMxR2m/zwPiQ8eiSn3gWdVBaEsiCwmxY00ScKxFQ3PJH\n"
+ "Vw4hAoGAdZLd8KfjjG6lg7hfpVqavstqVi9LOgkHeCfdjn7JP+76kYrgLk/XdkrP\n"
+ "N/BHhtFVFjOi/mTQfQ5YfZImkm/1ePBy7437DT8BDkOxspa50kK4HPggHnU64h1w\n"
+ "lhdEOj7mAgHwGwwVZWOgs9Lq6vfztnSuhqjha1daESY6kDscPIQ=\n"
+ "-----END RSA PRIVATE KEY-----\n";
+
+EVP_PKEY *
+ssl_getkey(void)
+{
+ EVP_PKEY *key;
+ BIO *bio;
+
+ /* new read-only BIO backed by KEY. */
+ bio = BIO_new_mem_buf((char*)KEY, -1);
+ tt_assert(bio);
+
+ key = PEM_read_bio_PrivateKey(bio,NULL,NULL,NULL);
+ BIO_free(bio);
+ tt_assert(key);
+
+ return key;
+end:
+ return NULL;
+}
+
+X509 *
+ssl_getcert(void)
+{
+ /* Dummy code to make a quick-and-dirty valid certificate with
+ OpenSSL. Don't copy this code into your own program! It does a
+ number of things in a stupid and insecure way. */
+ X509 *x509 = NULL;
+ X509_NAME *name = NULL;
+ EVP_PKEY *key = ssl_getkey();
+ int nid;
+ time_t now = time(NULL);
+
+ tt_assert(key);
+
+ x509 = X509_new();
+ tt_assert(x509);
+ tt_assert(0 != X509_set_version(x509, 2));
+ tt_assert(0 != ASN1_INTEGER_set(X509_get_serialNumber(x509),
+ (long)now));
+
+ name = X509_NAME_new();
+ tt_assert(name);
+ nid = OBJ_txt2nid("commonName");
+ tt_assert(NID_undef != nid);
+ tt_assert(0 != X509_NAME_add_entry_by_NID(
+ name, nid, MBSTRING_ASC, (unsigned char*)"example.com",
+ -1, -1, 0));
+
+ X509_set_subject_name(x509, name);
+ X509_set_issuer_name(x509, name);
+
+ X509_time_adj(X509_get_notBefore(x509), 0, &now);
+ now += 3600;
+ X509_time_adj(X509_get_notAfter(x509), 0, &now);
+ X509_set_pubkey(x509, key);
+ tt_assert(0 != X509_sign(x509, key, EVP_sha1()));
+
+ return x509;
+end:
+ X509_free(x509);
+ return NULL;
+}
+
+static int disable_tls_11_and_12 = 0;
+static SSL_CTX *the_ssl_ctx = NULL;
+
+SSL_CTX *
+get_ssl_ctx(void)
+{
+ if (the_ssl_ctx)
+ return the_ssl_ctx;
+ the_ssl_ctx = SSL_CTX_new(SSLv23_method());
+ if (!the_ssl_ctx)
+ return NULL;
+ if (disable_tls_11_and_12) {
+#ifdef SSL_OP_NO_TLSv1_2
+ SSL_CTX_set_options(the_ssl_ctx, SSL_OP_NO_TLSv1_2);
+#endif
+#ifdef SSL_OP_NO_TLSv1_1
+ SSL_CTX_set_options(the_ssl_ctx, SSL_OP_NO_TLSv1_1);
+#endif
+ }
+ return the_ssl_ctx;
+}
+
+void
+init_ssl(void)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ SSL_library_init();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+ if (SSLeay() != OPENSSL_VERSION_NUMBER) {
+ TT_DECLARE("WARN", ("Version mismatch for openssl: compiled with %lx but running with %lx", (unsigned long)OPENSSL_VERSION_NUMBER, (unsigned long) SSLeay()));
+ }
+#endif
+}
+
+/* ====================
+ Here's a simple test: we read a number from the input, increment it, and
+ reply, until we get to 1001.
+*/
+
+static int test_is_done = 0;
+static int n_connected = 0;
+static int got_close = 0;
+static int got_error = 0;
+static int got_timeout = 0;
+static int renegotiate_at = -1;
+static int stop_when_connected = 0;
+static int pending_connect_events = 0;
+static struct event_base *exit_base = NULL;
+
+enum regress_openssl_type
+{
+ REGRESS_OPENSSL_SOCKETPAIR = 1,
+ REGRESS_OPENSSL_FILTER = 2,
+ REGRESS_OPENSSL_RENEGOTIATE = 4,
+ REGRESS_OPENSSL_OPEN = 8,
+ REGRESS_OPENSSL_DIRTY_SHUTDOWN = 16,
+ REGRESS_OPENSSL_FD = 32,
+
+ REGRESS_OPENSSL_CLIENT = 64,
+ REGRESS_OPENSSL_SERVER = 128,
+
+ REGRESS_OPENSSL_FREED = 256,
+ REGRESS_OPENSSL_TIMEOUT = 512,
+ REGRESS_OPENSSL_SLEEP = 1024,
+};
+
+static void
+bufferevent_openssl_check_fd(struct bufferevent *bev, int filter)
+{
+ if (filter) {
+ tt_int_op(bufferevent_getfd(bev), ==, -1);
+ tt_int_op(bufferevent_setfd(bev, -1), ==, -1);
+ } else {
+ tt_int_op(bufferevent_getfd(bev), !=, -1);
+ tt_int_op(bufferevent_setfd(bev, -1), ==, 0);
+ }
+ tt_int_op(bufferevent_getfd(bev), ==, -1);
+
+end:
+ ;
+}
+static void
+bufferevent_openssl_check_freed(struct bufferevent *bev)
+{
+ tt_int_op(event_pending(&bev->ev_read, EVLIST_ALL, NULL), ==, 0);
+ tt_int_op(event_pending(&bev->ev_write, EVLIST_ALL, NULL), ==, 0);
+
+end:
+ ;
+}
+
+static void
+respond_to_number(struct bufferevent *bev, void *ctx)
+{
+ struct evbuffer *b = bufferevent_get_input(bev);
+ char *line;
+ int n;
+
+ enum regress_openssl_type type;
+ type = (enum regress_openssl_type)ctx;
+
+ line = evbuffer_readln(b, NULL, EVBUFFER_EOL_LF);
+ if (! line)
+ return;
+ n = atoi(line);
+ if (n <= 0)
+ TT_FAIL(("Bad number: %s", line));
+ free(line);
+ TT_BLATHER(("The number was %d", n));
+ if (n == 1001) {
+ ++test_is_done;
+ bufferevent_free(bev); /* Should trigger close on other side. */
+ return;
+ }
+ if ((type & REGRESS_OPENSSL_CLIENT) && n == renegotiate_at) {
+ SSL_renegotiate(bufferevent_openssl_get_ssl(bev));
+ }
+ ++n;
+ evbuffer_add_printf(bufferevent_get_output(bev),
+ "%d\n", n);
+ TT_BLATHER(("Done reading; now writing."));
+ bufferevent_enable(bev, EV_WRITE);
+ bufferevent_disable(bev, EV_READ);
+}
+
+static void
+done_writing_cb(struct bufferevent *bev, void *ctx)
+{
+ struct evbuffer *b = bufferevent_get_output(bev);
+ if (evbuffer_get_length(b))
+ return;
+ TT_BLATHER(("Done writing."));
+ bufferevent_disable(bev, EV_WRITE);
+ bufferevent_enable(bev, EV_READ);
+}
+
+static void
+eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+ enum regress_openssl_type type;
+ type = (enum regress_openssl_type)ctx;
+
+ TT_BLATHER(("Got event %d", (int)what));
+ if (what & BEV_EVENT_CONNECTED) {
+ SSL *ssl;
+ X509 *peer_cert;
+ ++n_connected;
+ ssl = bufferevent_openssl_get_ssl(bev);
+ tt_assert(ssl);
+ peer_cert = SSL_get_peer_certificate(ssl);
+ if (type & REGRESS_OPENSSL_SERVER) {
+ tt_assert(peer_cert == NULL);
+ } else {
+ tt_assert(peer_cert != NULL);
+ }
+ if (stop_when_connected) {
+ if (--pending_connect_events == 0)
+ event_base_loopexit(exit_base, NULL);
+ }
+ } else if (what & BEV_EVENT_EOF) {
+ TT_BLATHER(("Got a good EOF"));
+ ++got_close;
+ if (type & REGRESS_OPENSSL_FD) {
+ bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER);
+ }
+ if (type & REGRESS_OPENSSL_FREED) {
+ bufferevent_openssl_check_freed(bev);
+ }
+ bufferevent_free(bev);
+ } else if (what & BEV_EVENT_ERROR) {
+ TT_BLATHER(("Got an error."));
+ ++got_error;
+ if (type & REGRESS_OPENSSL_FD) {
+ bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER);
+ }
+ if (type & REGRESS_OPENSSL_FREED) {
+ bufferevent_openssl_check_freed(bev);
+ }
+ bufferevent_free(bev);
+ } else if (what & BEV_EVENT_TIMEOUT) {
+ TT_BLATHER(("Got timeout."));
+ ++got_timeout;
+ if (type & REGRESS_OPENSSL_FD) {
+ bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER);
+ }
+ if (type & REGRESS_OPENSSL_FREED) {
+ bufferevent_openssl_check_freed(bev);
+ }
+ bufferevent_free(bev);
+ }
+end:
+ ;
+}
+
+static void
+open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out,
+ struct event_base *base, int is_open, int flags, SSL *ssl1, SSL *ssl2,
+ evutil_socket_t *fd_pair, struct bufferevent **underlying_pair,
+ enum regress_openssl_type type)
+{
+ int state1 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_CONNECTING;
+ int state2 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_ACCEPTING;
+ int dirty_shutdown = type & REGRESS_OPENSSL_DIRTY_SHUTDOWN;
+ if (fd_pair) {
+ *bev1_out = bufferevent_openssl_socket_new(
+ base, fd_pair[0], ssl1, state1, flags);
+ *bev2_out = bufferevent_openssl_socket_new(
+ base, fd_pair[1], ssl2, state2, flags);
+ } else {
+ *bev1_out = bufferevent_openssl_filter_new(
+ base, underlying_pair[0], ssl1, state1, flags);
+ *bev2_out = bufferevent_openssl_filter_new(
+ base, underlying_pair[1], ssl2, state2, flags);
+
+ }
+ bufferevent_setcb(*bev1_out, respond_to_number, done_writing_cb,
+ eventcb, (void*)(REGRESS_OPENSSL_CLIENT | (long)type));
+ bufferevent_setcb(*bev2_out, respond_to_number, done_writing_cb,
+ eventcb, (void*)(REGRESS_OPENSSL_SERVER | (long)type));
+
+ bufferevent_openssl_set_allow_dirty_shutdown(*bev1_out, dirty_shutdown);
+ bufferevent_openssl_set_allow_dirty_shutdown(*bev2_out, dirty_shutdown);
+}
+
+static void
+regress_bufferevent_openssl(void *arg)
+{
+ struct basic_test_data *data = arg;
+
+ struct bufferevent *bev1, *bev2;
+ SSL *ssl1, *ssl2;
+ X509 *cert = ssl_getcert();
+ EVP_PKEY *key = ssl_getkey();
+ int flags = BEV_OPT_DEFER_CALLBACKS;
+ struct bufferevent *bev_ll[2] = { NULL, NULL };
+ evutil_socket_t *fd_pair = NULL;
+
+ enum regress_openssl_type type;
+ type = (enum regress_openssl_type)data->setup_data;
+
+ tt_assert(cert);
+ tt_assert(key);
+
+ init_ssl();
+
+ if (type & REGRESS_OPENSSL_RENEGOTIATE) {
+ if (SSLeay() >= 0x10001000 &&
+ SSLeay() < 0x1000104f) {
+ /* 1.0.1 up to 1.0.1c has a bug where TLS1.1 and 1.2
+ * can't renegotiate with themselves. Disable. */
+ disable_tls_11_and_12 = 1;
+ }
+ renegotiate_at = 600;
+ }
+
+ ssl1 = SSL_new(get_ssl_ctx());
+ ssl2 = SSL_new(get_ssl_ctx());
+
+ SSL_use_certificate(ssl2, cert);
+ SSL_use_PrivateKey(ssl2, key);
+
+ if (!(type & REGRESS_OPENSSL_OPEN))
+ flags |= BEV_OPT_CLOSE_ON_FREE;
+
+ if (!(type & REGRESS_OPENSSL_FILTER)) {
+ tt_assert(type & REGRESS_OPENSSL_SOCKETPAIR);
+ fd_pair = data->pair;
+ } else {
+ bev_ll[0] = bufferevent_socket_new(data->base, data->pair[0],
+ BEV_OPT_CLOSE_ON_FREE);
+ bev_ll[1] = bufferevent_socket_new(data->base, data->pair[1],
+ BEV_OPT_CLOSE_ON_FREE);
+ }
+
+ open_ssl_bufevs(&bev1, &bev2, data->base, 0, flags, ssl1, ssl2,
+ fd_pair, bev_ll, type);
+
+ if (!(type & REGRESS_OPENSSL_FILTER)) {
+ tt_int_op(bufferevent_getfd(bev1), ==, data->pair[0]);
+ } else {
+ tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev_ll[0]);
+ }
+
+ if (type & REGRESS_OPENSSL_OPEN) {
+ pending_connect_events = 2;
+ stop_when_connected = 1;
+ exit_base = data->base;
+ event_base_dispatch(data->base);
+ /* Okay, now the renegotiation is done. Make new
+ * bufferevents to test opening in BUFFEREVENT_SSL_OPEN */
+ flags |= BEV_OPT_CLOSE_ON_FREE;
+ bufferevent_free(bev1);
+ bufferevent_free(bev2);
+ bev1 = bev2 = NULL;
+ open_ssl_bufevs(&bev1, &bev2, data->base, 1, flags, ssl1, ssl2,
+ fd_pair, bev_ll, type);
+ }
+
+ if (!(type & REGRESS_OPENSSL_TIMEOUT)) {
+ bufferevent_enable(bev1, EV_READ|EV_WRITE);
+ bufferevent_enable(bev2, EV_READ|EV_WRITE);
+
+ evbuffer_add_printf(bufferevent_get_output(bev1), "1\n");
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_is_done == 1);
+ tt_assert(n_connected == 2);
+
+ /* We don't handle shutdown properly yet */
+ if (type & REGRESS_OPENSSL_DIRTY_SHUTDOWN) {
+ tt_int_op(got_close, ==, 1);
+ tt_int_op(got_error, ==, 0);
+ } else {
+ tt_int_op(got_error, ==, 1);
+ }
+ tt_int_op(got_timeout, ==, 0);
+ } else {
+ struct timeval t = { 2, 0 };
+
+ bufferevent_enable(bev1, EV_READ|EV_WRITE);
+ bufferevent_disable(bev2, EV_READ|EV_WRITE);
+
+ bufferevent_set_timeouts(bev1, &t, &t);
+
+ evbuffer_add_printf(bufferevent_get_output(bev1), "1\n");
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_is_done == 0);
+ tt_assert(n_connected == 0);
+
+ tt_int_op(got_close, ==, 0);
+ tt_int_op(got_error, ==, 0);
+ tt_int_op(got_timeout, ==, 1);
+ }
+end:
+ return;
+}
+
+static void
+acceptcb_deferred(evutil_socket_t fd, short events, void *arg)
+{
+ struct bufferevent *bev = arg;
+ bufferevent_enable(bev, EV_READ|EV_WRITE);
+}
+static void
+acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
+ struct sockaddr *addr, int socklen, void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev;
+ enum regress_openssl_type type;
+ SSL *ssl = SSL_new(get_ssl_ctx());
+
+ type = (enum regress_openssl_type)data->setup_data;
+
+ SSL_use_certificate(ssl, ssl_getcert());
+ SSL_use_PrivateKey(ssl, ssl_getkey());
+
+ bev = bufferevent_openssl_socket_new(
+ data->base,
+ fd,
+ ssl,
+ BUFFEREVENT_SSL_ACCEPTING,
+ BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
+
+ bufferevent_setcb(bev, respond_to_number, NULL, eventcb,
+ (void*)(REGRESS_OPENSSL_SERVER));
+
+ if (type & REGRESS_OPENSSL_SLEEP) {
+ struct timeval when = { 1, 0 };
+ event_base_once(data->base, -1, EV_TIMEOUT,
+ acceptcb_deferred, bev, &when);
+ bufferevent_disable(bev, EV_READ|EV_WRITE);
+ } else {
+ bufferevent_enable(bev, EV_READ|EV_WRITE);
+ }
+
+ /* Only accept once, then disable ourself. */
+ evconnlistener_disable(listener);
+}
+
+struct rwcount
+{
+ int fd;
+ size_t read;
+ size_t write;
+};
+static int
+bio_rwcount_new(BIO *b)
+{
+ BIO_set_init(b, 0);
+ BIO_set_data(b, NULL);
+ return 1;
+}
+static int
+bio_rwcount_free(BIO *b)
+{
+ if (!b)
+ return 0;
+ if (BIO_get_shutdown(b)) {
+ BIO_set_init(b, 0);
+ BIO_set_data(b, NULL);
+ }
+ return 1;
+}
+static int
+bio_rwcount_read(BIO *b, char *out, int outlen)
+{
+ struct rwcount *rw = BIO_get_data(b);
+ ev_ssize_t ret = recv(rw->fd, out, outlen, 0);
+ ++rw->read;
+ if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) {
+ BIO_set_retry_read(b);
+ }
+ return ret;
+}
+static int
+bio_rwcount_write(BIO *b, const char *in, int inlen)
+{
+
+ struct rwcount *rw = BIO_get_data(b);
+ ev_ssize_t ret = send(rw->fd, in, inlen, 0);
+ ++rw->write;
+ if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) {
+ BIO_set_retry_write(b);
+ }
+ return ret;
+}
+static long
+bio_rwcount_ctrl(BIO *b, int cmd, long num, void *ptr)
+{
+ long ret = 0;
+ switch (cmd) {
+ case BIO_CTRL_GET_CLOSE:
+ ret = BIO_get_shutdown(b);
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ BIO_set_shutdown(b, (int)num);
+ break;
+ case BIO_CTRL_PENDING:
+ ret = 0;
+ break;
+ case BIO_CTRL_WPENDING:
+ ret = 0;
+ break;
+ case BIO_CTRL_DUP:
+ case BIO_CTRL_FLUSH:
+ ret = 1;
+ break;
+ }
+ return ret;
+}
+static int
+bio_rwcount_puts(BIO *b, const char *s)
+{
+ return bio_rwcount_write(b, s, strlen(s));
+}
+#define BIO_TYPE_LIBEVENT_RWCOUNT 0xff1
+static BIO_METHOD *methods_rwcount;
+
+static BIO_METHOD *
+BIO_s_rwcount(void)
+{
+ if (methods_rwcount == NULL) {
+ methods_rwcount = BIO_meth_new(BIO_TYPE_LIBEVENT_RWCOUNT, "rwcount");
+ if (methods_rwcount == NULL)
+ return NULL;
+ BIO_meth_set_write(methods_rwcount, bio_rwcount_write);
+ BIO_meth_set_read(methods_rwcount, bio_rwcount_read);
+ BIO_meth_set_puts(methods_rwcount, bio_rwcount_puts);
+ BIO_meth_set_ctrl(methods_rwcount, bio_rwcount_ctrl);
+ BIO_meth_set_create(methods_rwcount, bio_rwcount_new);
+ BIO_meth_set_destroy(methods_rwcount, bio_rwcount_free);
+ }
+ return methods_rwcount;
+}
+static BIO *
+BIO_new_rwcount(int close_flag)
+{
+ BIO *result;
+ if (!(result = BIO_new(BIO_s_rwcount())))
+ return NULL;
+ BIO_set_init(result, 1);
+ BIO_set_data(result, NULL);
+ BIO_set_shutdown(result, !!close_flag);
+ return result;
+}
+
+static void
+regress_bufferevent_openssl_connect(void *arg)
+{
+ struct basic_test_data *data = arg;
+
+ struct event_base *base = data->base;
+
+ struct evconnlistener *listener;
+ struct bufferevent *bev;
+ struct sockaddr_in sin;
+ struct sockaddr_storage ss;
+ ev_socklen_t slen;
+ SSL *ssl;
+ BIO *bio;
+ struct rwcount rw = { -1, 0, 0 };
+ enum regress_openssl_type type;
+
+ type = (enum regress_openssl_type)data->setup_data;
+
+ init_ssl();
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(0x7f000001);
+
+ memset(&ss, 0, sizeof(ss));
+ slen = sizeof(ss);
+
+ listener = evconnlistener_new_bind(base, acceptcb, data,
+ LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
+ -1, (struct sockaddr *)&sin, sizeof(sin));
+
+ tt_assert(listener);
+ tt_assert(evconnlistener_get_fd(listener) >= 0);
+
+ ssl = SSL_new(get_ssl_ctx());
+ tt_assert(ssl);
+
+ bev = bufferevent_openssl_socket_new(
+ data->base, -1, ssl,
+ BUFFEREVENT_SSL_CONNECTING,
+ BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
+ tt_assert(bev);
+
+ bufferevent_setcb(bev, respond_to_number, NULL, eventcb,
+ (void*)(REGRESS_OPENSSL_CLIENT));
+
+ tt_assert(getsockname(evconnlistener_get_fd(listener),
+ (struct sockaddr*)&ss, &slen) == 0);
+ tt_assert(slen == sizeof(struct sockaddr_in));
+ tt_int_op(((struct sockaddr*)&ss)->sa_family, ==, AF_INET);
+
+ tt_assert(0 ==
+ bufferevent_socket_connect(bev, (struct sockaddr*)&ss, slen));
+ /* Possible only when we have fd, since be_openssl can and will overwrite
+ * bio otherwise before */
+ if (type & REGRESS_OPENSSL_SLEEP) {
+ rw.fd = bufferevent_getfd(bev);
+ bio = BIO_new_rwcount(0);
+ tt_assert(bio);
+ BIO_set_data(bio, &rw);
+ SSL_set_bio(ssl, bio, bio);
+ }
+ evbuffer_add_printf(bufferevent_get_output(bev), "1\n");
+ bufferevent_enable(bev, EV_READ|EV_WRITE);
+
+ event_base_dispatch(base);
+
+ tt_int_op(rw.read, <=, 100);
+ tt_int_op(rw.write, <=, 100);
+end:
+ ;
+}
+
+struct testcase_t ssl_testcases[] = {
+#define T(a) ((void *)(a))
+ { "bufferevent_socketpair", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_SOCKETPAIR) },
+ { "bufferevent_filter", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_FILTER) },
+ { "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE) },
+ { "bufferevent_renegotiate_filter", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_RENEGOTIATE) },
+ { "bufferevent_socketpair_startopen", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_OPEN) },
+ { "bufferevent_filter_startopen", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_OPEN) },
+
+ { "bufferevent_socketpair_dirty_shutdown", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
+ { "bufferevent_filter_dirty_shutdown", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
+ { "bufferevent_renegotiate_socketpair_dirty_shutdown",
+ regress_bufferevent_openssl,
+ TT_ISOLATED,
+ &basic_setup,
+ T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
+ { "bufferevent_renegotiate_filter_dirty_shutdown",
+ regress_bufferevent_openssl,
+ TT_ISOLATED,
+ &basic_setup,
+ T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_RENEGOTIATE | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
+ { "bufferevent_socketpair_startopen_dirty_shutdown",
+ regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_OPEN | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
+ { "bufferevent_filter_startopen_dirty_shutdown",
+ regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_OPEN | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
+
+ { "bufferevent_socketpair_fd", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FD) },
+ { "bufferevent_socketpair_freed", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FREED) },
+ { "bufferevent_socketpair_freed_fd", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) },
+ { "bufferevent_filter_freed_fd", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) },
+
+ { "bufferevent_socketpair_timeout", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_TIMEOUT) },
+ { "bufferevent_socketpair_timeout_freed_fd", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup,
+ T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_TIMEOUT | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) },
+
+ { "bufferevent_connect", regress_bufferevent_openssl_connect,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "bufferevent_connect_sleep", regress_bufferevent_openssl_connect,
+ TT_FORK|TT_NEED_BASE, &basic_setup, T(REGRESS_OPENSSL_SLEEP) },
+
+#undef T
+
+ END_OF_TESTCASES,
+};
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_testutils.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_testutils.c
new file mode 100644
index 000000000..959347ea7
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_testutils.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "../util-internal.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#endif
+#ifdef EVENT__HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event2/dns.h"
+#include "event2/dns_struct.h"
+#include "event2/event.h"
+#include "event2/event_compat.h"
+#include "event2/util.h"
+#include "event2/listener.h"
+#include "event2/bufferevent.h"
+#include "log-internal.h"
+#include "regress.h"
+#include "regress_testutils.h"
+
+/* globals */
+static struct evdns_server_port *dns_port;
+evutil_socket_t dns_sock = -1;
+
+/* Helper: return the port that a socket is bound on, in host order. */
+int
+regress_get_socket_port(evutil_socket_t fd)
+{
+ struct sockaddr_storage ss;
+ ev_socklen_t socklen = sizeof(ss);
+ if (getsockname(fd, (struct sockaddr*)&ss, &socklen) != 0)
+ return -1;
+ if (ss.ss_family == AF_INET)
+ return ntohs( ((struct sockaddr_in*)&ss)->sin_port);
+ else if (ss.ss_family == AF_INET6)
+ return ntohs( ((struct sockaddr_in6*)&ss)->sin6_port);
+ else
+ return -1;
+}
+
+struct evdns_server_port *
+regress_get_dnsserver(struct event_base *base,
+ ev_uint16_t *portnum,
+ evutil_socket_t *psock,
+ evdns_request_callback_fn_type cb,
+ void *arg)
+{
+ struct evdns_server_port *port = NULL;
+ evutil_socket_t sock;
+ struct sockaddr_in my_addr;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ tt_abort_perror("socket");
+ }
+
+ evutil_make_socket_nonblocking(sock);
+
+ memset(&my_addr, 0, sizeof(my_addr));
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_port = htons(*portnum);
+ my_addr.sin_addr.s_addr = htonl(0x7f000001UL);
+ if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) {
+ evutil_closesocket(sock);
+ tt_abort_perror("bind");
+ }
+ port = evdns_add_server_port_with_base(base, sock, 0, cb, arg);
+ if (!*portnum)
+ *portnum = regress_get_socket_port(sock);
+ if (psock)
+ *psock = sock;
+
+ return port;
+end:
+ return NULL;
+}
+
+void
+regress_clean_dnsserver(void)
+{
+ if (dns_port) {
+ evdns_close_server_port(dns_port);
+ dns_port = NULL;
+ }
+ if (dns_sock >= 0) {
+ evutil_closesocket(dns_sock);
+ dns_sock = -1;
+ }
+}
+
+static void strtolower(char *s)
+{
+ while (*s) {
+ *s = EVUTIL_TOLOWER_(*s);
+ ++s;
+ }
+}
+void
+regress_dns_server_cb(struct evdns_server_request *req, void *data)
+{
+ struct regress_dns_server_table *tab = data;
+ char *question;
+
+ if (req->nquestions != 1)
+ TT_DIE(("Only handling one question at a time; got %d",
+ req->nquestions));
+
+ question = req->questions[0]->name;
+
+ while (tab->q && evutil_ascii_strcasecmp(question, tab->q) &&
+ strcmp("*", tab->q))
+ ++tab;
+ if (tab->q == NULL)
+ TT_DIE(("Unexpected question: '%s'", question));
+
+ ++tab->seen;
+
+ if (tab->lower)
+ strtolower(question);
+
+ if (!strcmp(tab->anstype, "err")) {
+ int err = atoi(tab->ans);
+ tt_assert(! evdns_server_request_respond(req, err));
+ return;
+ } else if (!strcmp(tab->anstype, "errsoa")) {
+ int err = atoi(tab->ans);
+ char soa_record[] =
+ "\x04" "dns1" "\x05" "icann" "\x03" "org" "\0"
+ "\x0a" "hostmaster" "\x05" "icann" "\x03" "org" "\0"
+ "\x77\xde\x5e\xba" /* serial */
+ "\x00\x00\x1c\x20" /* refreshtime = 2h */
+ "\x00\x00\x0e\x10" /* retry = 1h */
+ "\x00\x12\x75\x00" /* expiration = 14d */
+ "\x00\x00\x0e\x10" /* min.ttl = 1h */
+ ;
+ evdns_server_request_add_reply(
+ req, EVDNS_AUTHORITY_SECTION,
+ "example.com", EVDNS_TYPE_SOA, EVDNS_CLASS_INET,
+ 42, sizeof(soa_record) - 1, 0, soa_record);
+ tt_assert(! evdns_server_request_respond(req, err));
+ return;
+ } else if (!strcmp(tab->anstype, "A")) {
+ struct in_addr in;
+ if (!evutil_inet_pton(AF_INET, tab->ans, &in)) {
+ TT_DIE(("Bad A value %s in table", tab->ans));
+ }
+ evdns_server_request_add_a_reply(req, question, 1, &in.s_addr,
+ 100);
+ } else if (!strcmp(tab->anstype, "AAAA")) {
+ struct in6_addr in6;
+ if (!evutil_inet_pton(AF_INET6, tab->ans, &in6)) {
+ TT_DIE(("Bad AAAA value %s in table", tab->ans));
+ }
+ evdns_server_request_add_aaaa_reply(req,
+ question, 1, &in6.s6_addr, 100);
+ } else {
+ TT_DIE(("Weird table entry with type '%s'", tab->anstype));
+ }
+ tt_assert(! evdns_server_request_respond(req, 0))
+ return;
+end:
+ tt_want(! evdns_server_request_drop(req));
+}
+
+int
+regress_dnsserver(struct event_base *base, ev_uint16_t *port,
+ struct regress_dns_server_table *search_table)
+{
+ dns_port = regress_get_dnsserver(base, port, &dns_sock,
+ regress_dns_server_cb, search_table);
+ return dns_port != NULL;
+}
+
+int
+regress_get_listener_addr(struct evconnlistener *lev,
+ struct sockaddr *sa, ev_socklen_t *socklen)
+{
+ evutil_socket_t s = evconnlistener_get_fd(lev);
+ if (s <= 0)
+ return -1;
+ return getsockname(s, sa, socklen);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_testutils.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_testutils.h
new file mode 100644
index 000000000..040516a58
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_testutils.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef REGRESS_TESTUTILS_H_INCLUDED_
+#define REGRESS_TESTUTILS_H_INCLUDED_
+
+#include "event2/dns.h"
+
+struct regress_dns_server_table {
+ const char *q;
+ const char *anstype;
+ const char *ans;
+ int seen;
+ int lower;
+};
+
+struct evdns_server_port *
+regress_get_dnsserver(struct event_base *base,
+ ev_uint16_t *portnum,
+ evutil_socket_t *psock,
+ evdns_request_callback_fn_type cb,
+ void *arg);
+
+/* Helper: return the port that a socket is bound on, in host order. */
+int regress_get_socket_port(evutil_socket_t fd);
+
+/* used to look up pre-canned responses in a search table */
+void regress_dns_server_cb(
+ struct evdns_server_request *req, void *data);
+
+/* globally allocates a dns server that serves from a search table */
+int regress_dnsserver(struct event_base *base, ev_uint16_t *port,
+ struct regress_dns_server_table *seach_table);
+
+/* clean up the global dns server resources */
+void regress_clean_dnsserver(void);
+
+struct evconnlistener;
+struct sockaddr;
+int regress_get_listener_addr(struct evconnlistener *lev,
+ struct sockaddr *sa, ev_socklen_t *socklen);
+
+#endif /* REGRESS_TESTUTILS_H_INCLUDED_ */
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_thread.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_thread.c
new file mode 100644
index 000000000..9ff6a8fa8
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_thread.c
@@ -0,0 +1,590 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util-internal.h"
+
+/* The old tests here need assertions to work. */
+#undef NDEBUG
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef EVENT__HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef EVENT__HAVE_PTHREADS
+#include <pthread.h>
+#elif defined(_WIN32)
+#include <process.h>
+#endif
+#include <assert.h>
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+
+#include "sys/queue.h"
+
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/thread.h"
+#include "event2/util.h"
+#include "evthread-internal.h"
+#include "event-internal.h"
+#include "defer-internal.h"
+#include "regress.h"
+#include "tinytest_macros.h"
+#include "time-internal.h"
+#include "regress_thread.h"
+
+struct cond_wait {
+ void *lock;
+ void *cond;
+};
+
+static void
+wake_all_timeout(evutil_socket_t fd, short what, void *arg)
+{
+ struct cond_wait *cw = arg;
+ EVLOCK_LOCK(cw->lock, 0);
+ EVTHREAD_COND_BROADCAST(cw->cond);
+ EVLOCK_UNLOCK(cw->lock, 0);
+
+}
+
+static void
+wake_one_timeout(evutil_socket_t fd, short what, void *arg)
+{
+ struct cond_wait *cw = arg;
+ EVLOCK_LOCK(cw->lock, 0);
+ EVTHREAD_COND_SIGNAL(cw->cond);
+ EVLOCK_UNLOCK(cw->lock, 0);
+}
+
+#define NUM_THREADS 100
+#define NUM_ITERATIONS 100
+void *count_lock;
+static int count;
+
+static THREAD_FN
+basic_thread(void *arg)
+{
+ struct cond_wait cw;
+ struct event_base *base = arg;
+ struct event ev;
+ int i = 0;
+
+ EVTHREAD_ALLOC_LOCK(cw.lock, 0);
+ EVTHREAD_ALLOC_COND(cw.cond);
+ assert(cw.lock);
+ assert(cw.cond);
+
+ evtimer_assign(&ev, base, wake_all_timeout, &cw);
+ for (i = 0; i < NUM_ITERATIONS; i++) {
+ struct timeval tv;
+ evutil_timerclear(&tv);
+ tv.tv_sec = 0;
+ tv.tv_usec = 3000;
+
+ EVLOCK_LOCK(cw.lock, 0);
+ /* we need to make sure that event does not happen before
+ * we get to wait on the conditional variable */
+ assert(evtimer_add(&ev, &tv) == 0);
+
+ assert(EVTHREAD_COND_WAIT(cw.cond, cw.lock) == 0);
+ EVLOCK_UNLOCK(cw.lock, 0);
+
+ EVLOCK_LOCK(count_lock, 0);
+ ++count;
+ EVLOCK_UNLOCK(count_lock, 0);
+ }
+
+ /* exit the loop only if all threads fired all timeouts */
+ EVLOCK_LOCK(count_lock, 0);
+ if (count >= NUM_THREADS * NUM_ITERATIONS)
+ event_base_loopexit(base, NULL);
+ EVLOCK_UNLOCK(count_lock, 0);
+
+ EVTHREAD_FREE_LOCK(cw.lock, 0);
+ EVTHREAD_FREE_COND(cw.cond);
+
+ THREAD_RETURN();
+}
+
+static int notification_fd_used = 0;
+#ifndef _WIN32
+static int got_sigchld = 0;
+static void
+sigchld_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct timeval tv;
+ struct event_base *base = arg;
+
+ got_sigchld++;
+ tv.tv_usec = 100000;
+ tv.tv_sec = 0;
+ event_base_loopexit(base, &tv);
+}
+
+
+static void
+notify_fd_cb(evutil_socket_t fd, short event, void *arg)
+{
+ ++notification_fd_used;
+}
+#endif
+
+static void
+thread_basic(void *arg)
+{
+ THREAD_T threads[NUM_THREADS];
+ struct event ev;
+ struct timeval tv;
+ int i;
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+
+ struct event *notification_event = NULL;
+ struct event *sigchld_event = NULL;
+
+ EVTHREAD_ALLOC_LOCK(count_lock, 0);
+ tt_assert(count_lock);
+
+ tt_assert(base);
+ if (evthread_make_base_notifiable(base)<0) {
+ tt_abort_msg("Couldn't make base notifiable!");
+ }
+
+#ifndef _WIN32
+ if (data->setup_data && !strcmp(data->setup_data, "forking")) {
+ pid_t pid;
+ int status;
+ sigchld_event = evsignal_new(base, SIGCHLD, sigchld_cb, base);
+ /* This piggybacks on the th_notify_fd weirdly, and looks
+ * inside libevent internals. Not a good idea in non-testing
+ * code! */
+ notification_event = event_new(base,
+ base->th_notify_fd[0], EV_READ|EV_PERSIST, notify_fd_cb,
+ NULL);
+ event_add(sigchld_event, NULL);
+ event_add(notification_event, NULL);
+
+ if ((pid = fork()) == 0) {
+ event_del(notification_event);
+ if (event_reinit(base) < 0) {
+ TT_FAIL(("reinit"));
+ exit(1);
+ }
+ event_assign(notification_event, base,
+ base->th_notify_fd[0], EV_READ|EV_PERSIST,
+ notify_fd_cb, NULL);
+ event_add(notification_event, NULL);
+ goto child;
+ }
+
+ event_base_dispatch(base);
+
+ if (waitpid(pid, &status, 0) == -1)
+ tt_abort_perror("waitpid");
+ TT_BLATHER(("Waitpid okay\n"));
+
+ tt_assert(got_sigchld);
+ tt_int_op(notification_fd_used, ==, 0);
+
+ goto end;
+ }
+
+child:
+#endif
+ for (i = 0; i < NUM_THREADS; ++i)
+ THREAD_START(threads[i], basic_thread, base);
+
+ evtimer_assign(&ev, base, NULL, NULL);
+ evutil_timerclear(&tv);
+ tv.tv_sec = 1000;
+ event_add(&ev, &tv);
+
+ event_base_dispatch(base);
+
+ for (i = 0; i < NUM_THREADS; ++i)
+ THREAD_JOIN(threads[i]);
+
+ event_del(&ev);
+
+ tt_int_op(count, ==, NUM_THREADS * NUM_ITERATIONS);
+
+ EVTHREAD_FREE_LOCK(count_lock, 0);
+
+ TT_BLATHER(("notifiations==%d", notification_fd_used));
+
+end:
+
+ if (notification_event)
+ event_free(notification_event);
+ if (sigchld_event)
+ event_free(sigchld_event);
+}
+
+#undef NUM_THREADS
+#define NUM_THREADS 10
+
+struct alerted_record {
+ struct cond_wait *cond;
+ struct timeval delay;
+ struct timeval alerted_at;
+ int timed_out;
+};
+
+static THREAD_FN
+wait_for_condition(void *arg)
+{
+ struct alerted_record *rec = arg;
+ int r;
+
+ EVLOCK_LOCK(rec->cond->lock, 0);
+ if (rec->delay.tv_sec || rec->delay.tv_usec) {
+ r = EVTHREAD_COND_WAIT_TIMED(rec->cond->cond, rec->cond->lock,
+ &rec->delay);
+ } else {
+ r = EVTHREAD_COND_WAIT(rec->cond->cond, rec->cond->lock);
+ }
+ EVLOCK_UNLOCK(rec->cond->lock, 0);
+
+ evutil_gettimeofday(&rec->alerted_at, NULL);
+ if (r == 1)
+ rec->timed_out = 1;
+
+ THREAD_RETURN();
+}
+
+static void
+thread_conditions_simple(void *arg)
+{
+ struct timeval tv_signal, tv_timeout, tv_broadcast;
+ struct alerted_record alerted[NUM_THREADS];
+ THREAD_T threads[NUM_THREADS];
+ struct cond_wait cond;
+ int i;
+ struct timeval launched_at;
+ struct event wake_one;
+ struct event wake_all;
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ int n_timed_out=0, n_signal=0, n_broadcast=0;
+
+ tv_signal.tv_sec = tv_timeout.tv_sec = tv_broadcast.tv_sec = 0;
+ tv_signal.tv_usec = 30*1000;
+ tv_timeout.tv_usec = 150*1000;
+ tv_broadcast.tv_usec = 500*1000;
+
+ EVTHREAD_ALLOC_LOCK(cond.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ EVTHREAD_ALLOC_COND(cond.cond);
+ tt_assert(cond.lock);
+ tt_assert(cond.cond);
+ for (i = 0; i < NUM_THREADS; ++i) {
+ memset(&alerted[i], 0, sizeof(struct alerted_record));
+ alerted[i].cond = &cond;
+ }
+
+ /* Threads 5 and 6 will be allowed to time out */
+ memcpy(&alerted[5].delay, &tv_timeout, sizeof(tv_timeout));
+ memcpy(&alerted[6].delay, &tv_timeout, sizeof(tv_timeout));
+
+ evtimer_assign(&wake_one, base, wake_one_timeout, &cond);
+ evtimer_assign(&wake_all, base, wake_all_timeout, &cond);
+
+ evutil_gettimeofday(&launched_at, NULL);
+
+ /* Launch the threads... */
+ for (i = 0; i < NUM_THREADS; ++i) {
+ THREAD_START(threads[i], wait_for_condition, &alerted[i]);
+ }
+
+ /* Start the timers... */
+ tt_int_op(event_add(&wake_one, &tv_signal), ==, 0);
+ tt_int_op(event_add(&wake_all, &tv_broadcast), ==, 0);
+
+ /* And run for a bit... */
+ event_base_dispatch(base);
+
+ /* And wait till the threads are done. */
+ for (i = 0; i < NUM_THREADS; ++i)
+ THREAD_JOIN(threads[i]);
+
+ /* Now, let's see what happened. At least one of 5 or 6 should
+ * have timed out. */
+ n_timed_out = alerted[5].timed_out + alerted[6].timed_out;
+ tt_int_op(n_timed_out, >=, 1);
+ tt_int_op(n_timed_out, <=, 2);
+
+ for (i = 0; i < NUM_THREADS; ++i) {
+ const struct timeval *target_delay;
+ struct timeval target_time, actual_delay;
+ if (alerted[i].timed_out) {
+ TT_BLATHER(("%d looks like a timeout\n", i));
+ target_delay = &tv_timeout;
+ tt_assert(i == 5 || i == 6);
+ } else if (evutil_timerisset(&alerted[i].alerted_at)) {
+ long diff1,diff2;
+ evutil_timersub(&alerted[i].alerted_at,
+ &launched_at, &actual_delay);
+ diff1 = timeval_msec_diff(&actual_delay,
+ &tv_signal);
+ diff2 = timeval_msec_diff(&actual_delay,
+ &tv_broadcast);
+ if (labs(diff1) < labs(diff2)) {
+ TT_BLATHER(("%d looks like a signal\n", i));
+ target_delay = &tv_signal;
+ ++n_signal;
+ } else {
+ TT_BLATHER(("%d looks like a broadcast\n", i));
+ target_delay = &tv_broadcast;
+ ++n_broadcast;
+ }
+ } else {
+ TT_FAIL(("Thread %d never got woken", i));
+ continue;
+ }
+ evutil_timeradd(target_delay, &launched_at, &target_time);
+ test_timeval_diff_leq(&target_time, &alerted[i].alerted_at,
+ 0, 50);
+ }
+ tt_int_op(n_broadcast + n_signal + n_timed_out, ==, NUM_THREADS);
+ tt_int_op(n_signal, ==, 1);
+
+end:
+ EVTHREAD_FREE_LOCK(cond.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ EVTHREAD_FREE_COND(cond.cond);
+}
+
+#define CB_COUNT 128
+#define QUEUE_THREAD_COUNT 8
+
+static void
+SLEEP_MS(int ms)
+{
+ struct timeval tv;
+ tv.tv_sec = ms/1000;
+ tv.tv_usec = (ms%1000)*1000;
+ evutil_usleep_(&tv);
+}
+
+struct deferred_test_data {
+ struct event_callback cbs[CB_COUNT];
+ struct event_base *queue;
+};
+
+static struct timeval timer_start = {0,0};
+static struct timeval timer_end = {0,0};
+static unsigned callback_count = 0;
+static THREAD_T load_threads[QUEUE_THREAD_COUNT];
+static struct deferred_test_data deferred_data[QUEUE_THREAD_COUNT];
+
+static void
+deferred_callback(struct event_callback *cb, void *arg)
+{
+ SLEEP_MS(1);
+ callback_count += 1;
+}
+
+static THREAD_FN
+load_deferred_queue(void *arg)
+{
+ struct deferred_test_data *data = arg;
+ size_t i;
+
+ for (i = 0; i < CB_COUNT; ++i) {
+ event_deferred_cb_init_(&data->cbs[i], 0, deferred_callback,
+ NULL);
+ event_deferred_cb_schedule_(data->queue, &data->cbs[i]);
+ SLEEP_MS(1);
+ }
+
+ THREAD_RETURN();
+}
+
+static void
+timer_callback(evutil_socket_t fd, short what, void *arg)
+{
+ evutil_gettimeofday(&timer_end, NULL);
+}
+
+static void
+start_threads_callback(evutil_socket_t fd, short what, void *arg)
+{
+ int i;
+
+ for (i = 0; i < QUEUE_THREAD_COUNT; ++i) {
+ THREAD_START(load_threads[i], load_deferred_queue,
+ &deferred_data[i]);
+ }
+}
+
+static void
+thread_deferred_cb_skew(void *arg)
+{
+ struct timeval tv_timer = {1, 0};
+ struct event_base *base = NULL;
+ struct event_config *cfg = NULL;
+ struct timeval elapsed;
+ int elapsed_usec;
+ int i;
+
+ cfg = event_config_new();
+ tt_assert(cfg);
+ event_config_set_max_dispatch_interval(cfg, NULL, 16, 0);
+
+ base = event_base_new_with_config(cfg);
+ tt_assert(base);
+
+ for (i = 0; i < QUEUE_THREAD_COUNT; ++i)
+ deferred_data[i].queue = base;
+
+ evutil_gettimeofday(&timer_start, NULL);
+ event_base_once(base, -1, EV_TIMEOUT, timer_callback, NULL,
+ &tv_timer);
+ event_base_once(base, -1, EV_TIMEOUT, start_threads_callback,
+ NULL, NULL);
+ event_base_dispatch(base);
+
+ evutil_timersub(&timer_end, &timer_start, &elapsed);
+ TT_BLATHER(("callback count, %u", callback_count));
+ elapsed_usec =
+ (unsigned)(elapsed.tv_sec*1000000 + elapsed.tv_usec);
+ TT_BLATHER(("elapsed time, %u usec", elapsed_usec));
+
+ /* XXX be more intelligent here. just make sure skew is
+ * within .4 seconds for now. */
+ tt_assert(elapsed_usec >= 600000 && elapsed_usec <= 1400000);
+
+end:
+ for (i = 0; i < QUEUE_THREAD_COUNT; ++i)
+ THREAD_JOIN(load_threads[i]);
+ if (base)
+ event_base_free(base);
+ if (cfg)
+ event_config_free(cfg);
+}
+
+static struct event time_events[5];
+static struct timeval times[5];
+static struct event_base *exit_base = NULL;
+static void
+note_time_cb(evutil_socket_t fd, short what, void *arg)
+{
+ evutil_gettimeofday(arg, NULL);
+ if (arg == &times[4]) {
+ event_base_loopbreak(exit_base);
+ }
+}
+static THREAD_FN
+register_events_subthread(void *arg)
+{
+ struct timeval tv = {0,0};
+ SLEEP_MS(100);
+ event_active(&time_events[0], EV_TIMEOUT, 1);
+ SLEEP_MS(100);
+ event_active(&time_events[1], EV_TIMEOUT, 1);
+ SLEEP_MS(100);
+ tv.tv_usec = 100*1000;
+ event_add(&time_events[2], &tv);
+ tv.tv_usec = 150*1000;
+ event_add(&time_events[3], &tv);
+ SLEEP_MS(200);
+ event_active(&time_events[4], EV_TIMEOUT, 1);
+
+ THREAD_RETURN();
+}
+
+static void
+thread_no_events(void *arg)
+{
+ THREAD_T thread;
+ struct basic_test_data *data = arg;
+ struct timeval starttime, endtime;
+ int i;
+ exit_base = data->base;
+
+ memset(times,0,sizeof(times));
+ for (i=0;i<5;++i) {
+ event_assign(&time_events[i], data->base,
+ -1, 0, note_time_cb, &times[i]);
+ }
+
+ evutil_gettimeofday(&starttime, NULL);
+ THREAD_START(thread, register_events_subthread, data->base);
+ event_base_loop(data->base, EVLOOP_NO_EXIT_ON_EMPTY);
+ evutil_gettimeofday(&endtime, NULL);
+ tt_assert(event_base_got_break(data->base));
+ THREAD_JOIN(thread);
+ for (i=0; i<5; ++i) {
+ struct timeval diff;
+ double sec;
+ evutil_timersub(&times[i], &starttime, &diff);
+ sec = diff.tv_sec + diff.tv_usec/1.0e6;
+ TT_BLATHER(("event %d at %.4f seconds", i, sec));
+ }
+ test_timeval_diff_eq(&starttime, &times[0], 100);
+ test_timeval_diff_eq(&starttime, &times[1], 200);
+ test_timeval_diff_eq(&starttime, &times[2], 400);
+ test_timeval_diff_eq(&starttime, &times[3], 450);
+ test_timeval_diff_eq(&starttime, &times[4], 500);
+ test_timeval_diff_eq(&starttime, &endtime, 500);
+
+end:
+ ;
+}
+
+#define TEST(name) \
+ { #name, thread_##name, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE, \
+ &basic_setup, NULL }
+
+struct testcase_t thread_testcases[] = {
+ { "basic", thread_basic, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE,
+ &basic_setup, NULL },
+#ifndef _WIN32
+ { "forking", thread_basic, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE,
+ &basic_setup, (char*)"forking" },
+#endif
+ TEST(conditions_simple),
+ { "deferred_cb_skew", thread_deferred_cb_skew,
+ TT_FORK|TT_NEED_THREADS|TT_OFF_BY_DEFAULT,
+ &basic_setup, NULL },
+#ifndef _WIN32
+ /****** XXX TODO FIXME windows seems to be having some timing trouble,
+ * looking into it now. / ellzey
+ ******/
+ TEST(no_events),
+#endif
+ END_OF_TESTCASES
+};
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_thread.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_thread.h
new file mode 100644
index 000000000..831b51e50
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_thread.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef REGRESS_THREAD_H_INCLUDED_
+#define REGRESS_THREAD_H_INCLUDED_
+
+#ifdef EVENT__HAVE_PTHREADS
+#define THREAD_T pthread_t
+#define THREAD_FN void *
+#define THREAD_RETURN() return (NULL)
+#define THREAD_START(threadvar, fn, arg) \
+ pthread_create(&(threadvar), NULL, fn, arg)
+#define THREAD_JOIN(th) pthread_join(th, NULL)
+#else
+#define THREAD_T HANDLE
+#define THREAD_FN unsigned __stdcall
+#define THREAD_RETURN() return (0)
+#define THREAD_START(threadvar, fn, arg) do { \
+ uintptr_t threadhandle = _beginthreadex(NULL,0,fn,(arg),0,NULL); \
+ (threadvar) = (HANDLE) threadhandle; \
+ } while (0)
+#define THREAD_JOIN(th) WaitForSingleObject(th, INFINITE)
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_util.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_util.c
new file mode 100644
index 000000000..0a57f7ce6
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_util.c
@@ -0,0 +1,1478 @@
+/*
+ * Copyright (c) 2009-2012 Nick Mathewson and Niels Provos
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "../util-internal.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#endif
+#ifdef EVENT__HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef EVENT__HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "event2/event.h"
+#include "event2/util.h"
+#include "../ipv6-internal.h"
+#include "../log-internal.h"
+#include "../strlcpy-internal.h"
+#include "../mm-internal.h"
+#include "../time-internal.h"
+
+#include "regress.h"
+
+enum entry_status { NORMAL, CANONICAL, BAD };
+
+/* This is a big table of results we expect from generating and parsing */
+static struct ipv4_entry {
+ const char *addr;
+ ev_uint32_t res;
+ enum entry_status status;
+} ipv4_entries[] = {
+ { "1.2.3.4", 0x01020304u, CANONICAL },
+ { "255.255.255.255", 0xffffffffu, CANONICAL },
+ { "256.0.0.0", 0, BAD },
+ { "ABC", 0, BAD },
+ { "1.2.3.4.5", 0, BAD },
+ { "176.192.208.244", 0xb0c0d0f4, CANONICAL },
+ { NULL, 0, BAD },
+};
+
+static struct ipv6_entry {
+ const char *addr;
+ ev_uint32_t res[4];
+ enum entry_status status;
+} ipv6_entries[] = {
+ { "::", { 0, 0, 0, 0, }, CANONICAL },
+ { "0:0:0:0:0:0:0:0", { 0, 0, 0, 0, }, NORMAL },
+ { "::1", { 0, 0, 0, 1, }, CANONICAL },
+ { "::1.2.3.4", { 0, 0, 0, 0x01020304, }, CANONICAL },
+ { "ffff:1::", { 0xffff0001u, 0, 0, 0, }, CANONICAL },
+ { "ffff:0000::", { 0xffff0000u, 0, 0, 0, }, NORMAL },
+ { "ffff::1234", { 0xffff0000u, 0, 0, 0x1234, }, CANONICAL },
+ { "0102::1.2.3.4", {0x01020000u, 0, 0, 0x01020304u }, NORMAL },
+ { "::9:c0a8:1:1", { 0, 0, 0x0009c0a8u, 0x00010001u }, CANONICAL },
+ { "::ffff:1.2.3.4", { 0, 0, 0x000ffffu, 0x01020304u }, CANONICAL },
+ { "FFFF::", { 0xffff0000u, 0, 0, 0 }, NORMAL },
+ { "foobar.", { 0, 0, 0, 0 }, BAD },
+ { "foobar", { 0, 0, 0, 0 }, BAD },
+ { "fo:obar", { 0, 0, 0, 0 }, BAD },
+ { "ffff", { 0, 0, 0, 0 }, BAD },
+ { "fffff::", { 0, 0, 0, 0 }, BAD },
+ { "fffff::", { 0, 0, 0, 0 }, BAD },
+ { "::1.0.1.1000", { 0, 0, 0, 0 }, BAD },
+ { "1:2:33333:4::", { 0, 0, 0, 0 }, BAD },
+ { "1:2:3:4:5:6:7:8:9", { 0, 0, 0, 0 }, BAD },
+ { "1::2::3", { 0, 0, 0, 0 }, BAD },
+ { ":::1", { 0, 0, 0, 0 }, BAD },
+ { NULL, { 0, 0, 0, 0, }, BAD },
+};
+
+static void
+regress_ipv4_parse(void *ptr)
+{
+ int i;
+ for (i = 0; ipv4_entries[i].addr; ++i) {
+ char written[128];
+ struct ipv4_entry *ent = &ipv4_entries[i];
+ struct in_addr in;
+ int r;
+ r = evutil_inet_pton(AF_INET, ent->addr, &in);
+ if (r == 0) {
+ if (ent->status != BAD) {
+ TT_FAIL(("%s did not parse, but it's a good address!",
+ ent->addr));
+ }
+ continue;
+ }
+ if (ent->status == BAD) {
+ TT_FAIL(("%s parsed, but we expected an error", ent->addr));
+ continue;
+ }
+ if (ntohl(in.s_addr) != ent->res) {
+ TT_FAIL(("%s parsed to %lx, but we expected %lx", ent->addr,
+ (unsigned long)ntohl(in.s_addr),
+ (unsigned long)ent->res));
+ continue;
+ }
+ if (ent->status == CANONICAL) {
+ const char *w = evutil_inet_ntop(AF_INET, &in, written,
+ sizeof(written));
+ if (!w) {
+ TT_FAIL(("Tried to write out %s; got NULL.", ent->addr));
+ continue;
+ }
+ if (strcmp(written, ent->addr)) {
+ TT_FAIL(("Tried to write out %s; got %s",
+ ent->addr, written));
+ continue;
+ }
+ }
+
+ }
+
+}
+
+static void
+regress_ipv6_parse(void *ptr)
+{
+#ifdef AF_INET6
+ int i, j;
+
+ for (i = 0; ipv6_entries[i].addr; ++i) {
+ char written[128];
+ struct ipv6_entry *ent = &ipv6_entries[i];
+ struct in6_addr in6;
+ int r;
+ r = evutil_inet_pton(AF_INET6, ent->addr, &in6);
+ if (r == 0) {
+ if (ent->status != BAD)
+ TT_FAIL(("%s did not parse, but it's a good address!",
+ ent->addr));
+ continue;
+ }
+ if (ent->status == BAD) {
+ TT_FAIL(("%s parsed, but we expected an error", ent->addr));
+ continue;
+ }
+ for (j = 0; j < 4; ++j) {
+ /* Can't use s6_addr32 here; some don't have it. */
+ ev_uint32_t u =
+ ((ev_uint32_t)in6.s6_addr[j*4 ] << 24) |
+ ((ev_uint32_t)in6.s6_addr[j*4+1] << 16) |
+ ((ev_uint32_t)in6.s6_addr[j*4+2] << 8) |
+ ((ev_uint32_t)in6.s6_addr[j*4+3]);
+ if (u != ent->res[j]) {
+ TT_FAIL(("%s did not parse as expected.", ent->addr));
+ continue;
+ }
+ }
+ if (ent->status == CANONICAL) {
+ const char *w = evutil_inet_ntop(AF_INET6, &in6, written,
+ sizeof(written));
+ if (!w) {
+ TT_FAIL(("Tried to write out %s; got NULL.", ent->addr));
+ continue;
+ }
+ if (strcmp(written, ent->addr)) {
+ TT_FAIL(("Tried to write out %s; got %s", ent->addr, written));
+ continue;
+ }
+ }
+
+ }
+#else
+ TT_BLATHER(("Skipping IPv6 address parsing."));
+#endif
+}
+
+static struct sa_port_ent {
+ const char *parse;
+ int safamily;
+ const char *addr;
+ int port;
+} sa_port_ents[] = {
+ { "[ffff::1]:1000", AF_INET6, "ffff::1", 1000 },
+ { "[ffff::1]", AF_INET6, "ffff::1", 0 },
+ { "[ffff::1", 0, NULL, 0 },
+ { "[ffff::1]:65599", 0, NULL, 0 },
+ { "[ffff::1]:0", 0, NULL, 0 },
+ { "[ffff::1]:-1", 0, NULL, 0 },
+ { "::1", AF_INET6, "::1", 0 },
+ { "1:2::1", AF_INET6, "1:2::1", 0 },
+ { "192.168.0.1:50", AF_INET, "192.168.0.1", 50 },
+ { "1.2.3.4", AF_INET, "1.2.3.4", 0 },
+ { NULL, 0, NULL, 0 },
+};
+
+static void
+regress_sockaddr_port_parse(void *ptr)
+{
+ struct sockaddr_storage ss;
+ int i, r;
+
+ for (i = 0; sa_port_ents[i].parse; ++i) {
+ struct sa_port_ent *ent = &sa_port_ents[i];
+ int len = sizeof(ss);
+ memset(&ss, 0, sizeof(ss));
+ r = evutil_parse_sockaddr_port(ent->parse, (struct sockaddr*)&ss, &len);
+ if (r < 0) {
+ if (ent->safamily)
+ TT_FAIL(("Couldn't parse %s!", ent->parse));
+ continue;
+ } else if (! ent->safamily) {
+ TT_FAIL(("Shouldn't have been able to parse %s!", ent->parse));
+ continue;
+ }
+ if (ent->safamily == AF_INET) {
+ struct sockaddr_in sin;
+ memset(&sin, 0, sizeof(sin));
+#ifdef EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ sin.sin_len = sizeof(sin);
+#endif
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(ent->port);
+ r = evutil_inet_pton(AF_INET, ent->addr, &sin.sin_addr);
+ if (1 != r) {
+ TT_FAIL(("Couldn't parse ipv4 target %s.", ent->addr));
+ } else if (memcmp(&sin, &ss, sizeof(sin))) {
+ TT_FAIL(("Parse for %s was not as expected.", ent->parse));
+ } else if (len != sizeof(sin)) {
+ TT_FAIL(("Length for %s not as expected.",ent->parse));
+ }
+ } else {
+ struct sockaddr_in6 sin6;
+ memset(&sin6, 0, sizeof(sin6));
+#ifdef EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
+ sin6.sin6_len = sizeof(sin6);
+#endif
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(ent->port);
+ r = evutil_inet_pton(AF_INET6, ent->addr, &sin6.sin6_addr);
+ if (1 != r) {
+ TT_FAIL(("Couldn't parse ipv6 target %s.", ent->addr));
+ } else if (memcmp(&sin6, &ss, sizeof(sin6))) {
+ TT_FAIL(("Parse for %s was not as expected.", ent->parse));
+ } else if (len != sizeof(sin6)) {
+ TT_FAIL(("Length for %s not as expected.",ent->parse));
+ }
+ }
+ }
+}
+
+
+static void
+regress_sockaddr_port_format(void *ptr)
+{
+ struct sockaddr_storage ss;
+ int len;
+ const char *cp;
+ char cbuf[128];
+ int r;
+
+ len = sizeof(ss);
+ r = evutil_parse_sockaddr_port("192.168.1.1:80",
+ (struct sockaddr*)&ss, &len);
+ tt_int_op(r,==,0);
+ cp = evutil_format_sockaddr_port_(
+ (struct sockaddr*)&ss, cbuf, sizeof(cbuf));
+ tt_ptr_op(cp,==,cbuf);
+ tt_str_op(cp,==,"192.168.1.1:80");
+
+ len = sizeof(ss);
+ r = evutil_parse_sockaddr_port("[ff00::8010]:999",
+ (struct sockaddr*)&ss, &len);
+ tt_int_op(r,==,0);
+ cp = evutil_format_sockaddr_port_(
+ (struct sockaddr*)&ss, cbuf, sizeof(cbuf));
+ tt_ptr_op(cp,==,cbuf);
+ tt_str_op(cp,==,"[ff00::8010]:999");
+
+ ss.ss_family=99;
+ cp = evutil_format_sockaddr_port_(
+ (struct sockaddr*)&ss, cbuf, sizeof(cbuf));
+ tt_ptr_op(cp,==,cbuf);
+ tt_str_op(cp,==,"<addr with socktype 99>");
+end:
+ ;
+}
+
+static struct sa_pred_ent {
+ const char *parse;
+
+ int is_loopback;
+} sa_pred_entries[] = {
+ { "127.0.0.1", 1 },
+ { "127.0.3.2", 1 },
+ { "128.1.2.3", 0 },
+ { "18.0.0.1", 0 },
+ { "129.168.1.1", 0 },
+
+ { "::1", 1 },
+ { "::0", 0 },
+ { "f::1", 0 },
+ { "::501", 0 },
+ { NULL, 0 },
+
+};
+
+static void
+test_evutil_sockaddr_predicates(void *ptr)
+{
+ struct sockaddr_storage ss;
+ int r, i;
+
+ for (i=0; sa_pred_entries[i].parse; ++i) {
+ struct sa_pred_ent *ent = &sa_pred_entries[i];
+ int len = sizeof(ss);
+
+ r = evutil_parse_sockaddr_port(ent->parse, (struct sockaddr*)&ss, &len);
+
+ if (r<0) {
+ TT_FAIL(("Couldn't parse %s!", ent->parse));
+ continue;
+ }
+
+ /* sockaddr_is_loopback */
+ if (ent->is_loopback != evutil_sockaddr_is_loopback_((struct sockaddr*)&ss)) {
+ TT_FAIL(("evutil_sockaddr_loopback(%s) not as expected",
+ ent->parse));
+ }
+ }
+}
+
+static void
+test_evutil_strtoll(void *ptr)
+{
+ const char *s;
+ char *endptr;
+
+ tt_want(evutil_strtoll("5000000000", NULL, 10) ==
+ ((ev_int64_t)5000000)*1000);
+ tt_want(evutil_strtoll("-5000000000", NULL, 10) ==
+ ((ev_int64_t)5000000)*-1000);
+ s = " 99999stuff";
+ tt_want(evutil_strtoll(s, &endptr, 10) == (ev_int64_t)99999);
+ tt_want(endptr == s+6);
+ tt_want(evutil_strtoll("foo", NULL, 10) == 0);
+ }
+
+static void
+test_evutil_snprintf(void *ptr)
+{
+ char buf[16];
+ int r;
+ ev_uint64_t u64 = ((ev_uint64_t)1000000000)*200;
+ ev_int64_t i64 = -1 * (ev_int64_t) u64;
+ size_t size = 8000;
+ ev_ssize_t ssize = -9000;
+
+ r = evutil_snprintf(buf, sizeof(buf), "%d %d", 50, 100);
+ tt_str_op(buf, ==, "50 100");
+ tt_int_op(r, ==, 6);
+
+ r = evutil_snprintf(buf, sizeof(buf), "longish %d", 1234567890);
+ tt_str_op(buf, ==, "longish 1234567");
+ tt_int_op(r, ==, 18);
+
+ r = evutil_snprintf(buf, sizeof(buf), EV_U64_FMT, EV_U64_ARG(u64));
+ tt_str_op(buf, ==, "200000000000");
+ tt_int_op(r, ==, 12);
+
+ r = evutil_snprintf(buf, sizeof(buf), EV_I64_FMT, EV_I64_ARG(i64));
+ tt_str_op(buf, ==, "-200000000000");
+ tt_int_op(r, ==, 13);
+
+ r = evutil_snprintf(buf, sizeof(buf), EV_SIZE_FMT" "EV_SSIZE_FMT,
+ EV_SIZE_ARG(size), EV_SSIZE_ARG(ssize));
+ tt_str_op(buf, ==, "8000 -9000");
+ tt_int_op(r, ==, 10);
+
+ end:
+ ;
+}
+
+static void
+test_evutil_casecmp(void *ptr)
+{
+ tt_int_op(evutil_ascii_strcasecmp("ABC", "ABC"), ==, 0);
+ tt_int_op(evutil_ascii_strcasecmp("ABC", "abc"), ==, 0);
+ tt_int_op(evutil_ascii_strcasecmp("ABC", "abcd"), <, 0);
+ tt_int_op(evutil_ascii_strcasecmp("ABC", "abb"), >, 0);
+ tt_int_op(evutil_ascii_strcasecmp("ABCd", "abc"), >, 0);
+
+ tt_int_op(evutil_ascii_strncasecmp("Libevent", "LibEvEnT", 100), ==, 0);
+ tt_int_op(evutil_ascii_strncasecmp("Libevent", "LibEvEnT", 4), ==, 0);
+ tt_int_op(evutil_ascii_strncasecmp("Libevent", "LibEXXXX", 4), ==, 0);
+ tt_int_op(evutil_ascii_strncasecmp("Libevent", "LibE", 4), ==, 0);
+ tt_int_op(evutil_ascii_strncasecmp("Libe", "LibEvEnT", 4), ==, 0);
+ tt_int_op(evutil_ascii_strncasecmp("Lib", "LibEvEnT", 4), <, 0);
+ tt_int_op(evutil_ascii_strncasecmp("abc", "def", 99), <, 0);
+ tt_int_op(evutil_ascii_strncasecmp("Z", "qrst", 1), >, 0);
+end:
+ ;
+}
+
+static void
+test_evutil_rtrim(void *ptr)
+{
+#define TEST_TRIM(s, result) \
+ do { \
+ if (cp) mm_free(cp); \
+ cp = mm_strdup(s); \
+ tt_assert(cp); \
+ evutil_rtrim_lws_(cp); \
+ tt_str_op(cp, ==, result); \
+ } while(0)
+
+ char *cp = NULL;
+ (void) ptr;
+
+ TEST_TRIM("", "");
+ TEST_TRIM("a", "a");
+ TEST_TRIM("abcdef ghi", "abcdef ghi");
+
+ TEST_TRIM(" ", "");
+ TEST_TRIM(" ", "");
+ TEST_TRIM("a ", "a");
+ TEST_TRIM("abcdef gH ", "abcdef gH");
+
+ TEST_TRIM("\t\t", "");
+ TEST_TRIM(" \t", "");
+ TEST_TRIM("\t", "");
+ TEST_TRIM("a \t", "a");
+ TEST_TRIM("a\t ", "a");
+ TEST_TRIM("a\t", "a");
+ TEST_TRIM("abcdef gH \t ", "abcdef gH");
+
+end:
+ if (cp)
+ mm_free(cp);
+}
+
+static int logsev = 0;
+static char *logmsg = NULL;
+
+static void
+logfn(int severity, const char *msg)
+{
+ logsev = severity;
+ tt_want(msg);
+ if (msg) {
+ if (logmsg)
+ free(logmsg);
+ logmsg = strdup(msg);
+ }
+}
+
+static int fatal_want_severity = 0;
+static const char *fatal_want_message = NULL;
+static void
+fatalfn(int exitcode)
+{
+ if (logsev != fatal_want_severity ||
+ !logmsg ||
+ strcmp(logmsg, fatal_want_message))
+ exit(0);
+ else
+ exit(exitcode);
+}
+
+#ifndef _WIN32
+#define CAN_CHECK_ERR
+static void
+check_error_logging(void (*fn)(void), int wantexitcode,
+ int wantseverity, const char *wantmsg)
+{
+ pid_t pid;
+ int status = 0, exitcode;
+ fatal_want_severity = wantseverity;
+ fatal_want_message = wantmsg;
+ if ((pid = regress_fork()) == 0) {
+ /* child process */
+ fn();
+ exit(0); /* should be unreachable. */
+ } else {
+ wait(&status);
+ exitcode = WEXITSTATUS(status);
+ tt_int_op(wantexitcode, ==, exitcode);
+ }
+end:
+ ;
+}
+
+static void
+errx_fn(void)
+{
+ event_errx(2, "Fatal error; too many kumquats (%d)", 5);
+}
+
+static void
+err_fn(void)
+{
+ errno = ENOENT;
+ event_err(5,"Couldn't open %s", "/very/bad/file");
+}
+
+static void
+sock_err_fn(void)
+{
+ evutil_socket_t fd = socket(AF_INET, SOCK_STREAM, 0);
+#ifdef _WIN32
+ EVUTIL_SET_SOCKET_ERROR(WSAEWOULDBLOCK);
+#else
+ errno = EAGAIN;
+#endif
+ event_sock_err(20, fd, "Unhappy socket");
+}
+#endif
+
+static void
+test_evutil_log(void *ptr)
+{
+ evutil_socket_t fd = -1;
+ char buf[128];
+
+ event_set_log_callback(logfn);
+ event_set_fatal_callback(fatalfn);
+#define RESET() do { \
+ logsev = 0; \
+ if (logmsg) free(logmsg); \
+ logmsg = NULL; \
+ } while (0)
+#define LOGEQ(sev,msg) do { \
+ tt_int_op(logsev,==,sev); \
+ tt_assert(logmsg != NULL); \
+ tt_str_op(logmsg,==,msg); \
+ } while (0)
+
+#ifdef CAN_CHECK_ERR
+ /* We need to disable these tests for now. Previously, the logging
+ * module didn't enforce the requirement that a fatal callback
+ * actually exit. Now, it exits no matter what, so if we wan to
+ * reinstate these tests, we'll need to fork for each one. */
+ check_error_logging(errx_fn, 2, EVENT_LOG_ERR,
+ "Fatal error; too many kumquats (5)");
+ RESET();
+#endif
+
+ event_warnx("Far too many %s (%d)", "wombats", 99);
+ LOGEQ(EVENT_LOG_WARN, "Far too many wombats (99)");
+ RESET();
+
+ event_msgx("Connecting lime to coconut");
+ LOGEQ(EVENT_LOG_MSG, "Connecting lime to coconut");
+ RESET();
+
+ event_debug(("A millisecond passed! We should log that!"));
+#ifdef USE_DEBUG
+ LOGEQ(EVENT_LOG_DEBUG, "A millisecond passed! We should log that!");
+#else
+ tt_int_op(logsev,==,0);
+ tt_ptr_op(logmsg,==,NULL);
+#endif
+ RESET();
+
+ /* Try with an errno. */
+ errno = ENOENT;
+ event_warn("Couldn't open %s", "/bad/file");
+ evutil_snprintf(buf, sizeof(buf),
+ "Couldn't open /bad/file: %s",strerror(ENOENT));
+ LOGEQ(EVENT_LOG_WARN,buf);
+ RESET();
+
+#ifdef CAN_CHECK_ERR
+ evutil_snprintf(buf, sizeof(buf),
+ "Couldn't open /very/bad/file: %s",strerror(ENOENT));
+ check_error_logging(err_fn, 5, EVENT_LOG_ERR, buf);
+ RESET();
+#endif
+
+ /* Try with a socket errno. */
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+#ifdef _WIN32
+ evutil_snprintf(buf, sizeof(buf),
+ "Unhappy socket: %s",
+ evutil_socket_error_to_string(WSAEWOULDBLOCK));
+ EVUTIL_SET_SOCKET_ERROR(WSAEWOULDBLOCK);
+#else
+ evutil_snprintf(buf, sizeof(buf),
+ "Unhappy socket: %s", strerror(EAGAIN));
+ errno = EAGAIN;
+#endif
+ event_sock_warn(fd, "Unhappy socket");
+ LOGEQ(EVENT_LOG_WARN, buf);
+ RESET();
+
+#ifdef CAN_CHECK_ERR
+ check_error_logging(sock_err_fn, 20, EVENT_LOG_ERR, buf);
+ RESET();
+#endif
+
+#undef RESET
+#undef LOGEQ
+end:
+ if (logmsg)
+ free(logmsg);
+ if (fd >= 0)
+ evutil_closesocket(fd);
+}
+
+static void
+test_evutil_strlcpy(void *arg)
+{
+ char buf[8];
+
+ /* Successful case. */
+ tt_int_op(5, ==, strlcpy(buf, "Hello", sizeof(buf)));
+ tt_str_op(buf, ==, "Hello");
+
+ /* Overflow by a lot. */
+ tt_int_op(13, ==, strlcpy(buf, "pentasyllabic", sizeof(buf)));
+ tt_str_op(buf, ==, "pentasy");
+
+ /* Overflow by exactly one. */
+ tt_int_op(8, ==, strlcpy(buf, "overlong", sizeof(buf)));
+ tt_str_op(buf, ==, "overlon");
+end:
+ ;
+}
+
+struct example_struct {
+ const char *a;
+ const char *b;
+ long c;
+};
+
+static void
+test_evutil_upcast(void *arg)
+{
+ struct example_struct es1;
+ const char **cp;
+ es1.a = "World";
+ es1.b = "Hello";
+ es1.c = -99;
+
+ tt_int_op(evutil_offsetof(struct example_struct, b), ==, sizeof(char*));
+
+ cp = &es1.b;
+ tt_ptr_op(EVUTIL_UPCAST(cp, struct example_struct, b), ==, &es1);
+
+end:
+ ;
+}
+
+static void
+test_evutil_integers(void *arg)
+{
+ ev_int64_t i64;
+ ev_uint64_t u64;
+ ev_int32_t i32;
+ ev_uint32_t u32;
+ ev_int16_t i16;
+ ev_uint16_t u16;
+ ev_int8_t i8;
+ ev_uint8_t u8;
+
+ void *ptr;
+ ev_intptr_t iptr;
+ ev_uintptr_t uptr;
+
+ ev_ssize_t ssize;
+
+ tt_int_op(sizeof(u64), ==, 8);
+ tt_int_op(sizeof(i64), ==, 8);
+ tt_int_op(sizeof(u32), ==, 4);
+ tt_int_op(sizeof(i32), ==, 4);
+ tt_int_op(sizeof(u16), ==, 2);
+ tt_int_op(sizeof(i16), ==, 2);
+ tt_int_op(sizeof(u8), ==, 1);
+ tt_int_op(sizeof(i8), ==, 1);
+
+ tt_int_op(sizeof(ev_ssize_t), ==, sizeof(size_t));
+ tt_int_op(sizeof(ev_intptr_t), >=, sizeof(void *));
+ tt_int_op(sizeof(ev_uintptr_t), ==, sizeof(intptr_t));
+
+ u64 = 1000000000;
+ u64 *= 1000000000;
+ tt_assert(u64 / 1000000000 == 1000000000);
+ i64 = -1000000000;
+ i64 *= 1000000000;
+ tt_assert(i64 / 1000000000 == -1000000000);
+
+ u64 = EV_UINT64_MAX;
+ i64 = EV_INT64_MAX;
+ tt_assert(u64 > 0);
+ tt_assert(i64 > 0);
+ u64++;
+/* i64++; */
+ tt_assert(u64 == 0);
+/* tt_assert(i64 == EV_INT64_MIN); */
+/* tt_assert(i64 < 0); */
+
+ u32 = EV_UINT32_MAX;
+ i32 = EV_INT32_MAX;
+ tt_assert(u32 > 0);
+ tt_assert(i32 > 0);
+ u32++;
+/* i32++; */
+ tt_assert(u32 == 0);
+/* tt_assert(i32 == EV_INT32_MIN); */
+/* tt_assert(i32 < 0); */
+
+ u16 = EV_UINT16_MAX;
+ i16 = EV_INT16_MAX;
+ tt_assert(u16 > 0);
+ tt_assert(i16 > 0);
+ u16++;
+/* i16++; */
+ tt_assert(u16 == 0);
+/* tt_assert(i16 == EV_INT16_MIN); */
+/* tt_assert(i16 < 0); */
+
+ u8 = EV_UINT8_MAX;
+ i8 = EV_INT8_MAX;
+ tt_assert(u8 > 0);
+ tt_assert(i8 > 0);
+ u8++;
+/* i8++;*/
+ tt_assert(u8 == 0);
+/* tt_assert(i8 == EV_INT8_MIN); */
+/* tt_assert(i8 < 0); */
+
+/*
+ ssize = EV_SSIZE_MAX;
+ tt_assert(ssize > 0);
+ ssize++;
+ tt_assert(ssize < 0);
+ tt_assert(ssize == EV_SSIZE_MIN);
+*/
+
+ ptr = &ssize;
+ iptr = (ev_intptr_t)ptr;
+ uptr = (ev_uintptr_t)ptr;
+ ptr = (void *)iptr;
+ tt_assert(ptr == &ssize);
+ ptr = (void *)uptr;
+ tt_assert(ptr == &ssize);
+
+ iptr = -1;
+ tt_assert(iptr < 0);
+end:
+ ;
+}
+
+struct evutil_addrinfo *
+ai_find_by_family(struct evutil_addrinfo *ai, int family)
+{
+ while (ai) {
+ if (ai->ai_family == family)
+ return ai;
+ ai = ai->ai_next;
+ }
+ return NULL;
+}
+
+struct evutil_addrinfo *
+ai_find_by_protocol(struct evutil_addrinfo *ai, int protocol)
+{
+ while (ai) {
+ if (ai->ai_protocol == protocol)
+ return ai;
+ ai = ai->ai_next;
+ }
+ return NULL;
+}
+
+
+int
+test_ai_eq_(const struct evutil_addrinfo *ai, const char *sockaddr_port,
+ int socktype, int protocol, int line)
+{
+ struct sockaddr_storage ss;
+ int slen = sizeof(ss);
+ int gotport;
+ char buf[128];
+ memset(&ss, 0, sizeof(ss));
+ if (socktype > 0)
+ tt_int_op(ai->ai_socktype, ==, socktype);
+ if (protocol > 0)
+ tt_int_op(ai->ai_protocol, ==, protocol);
+
+ if (evutil_parse_sockaddr_port(
+ sockaddr_port, (struct sockaddr*)&ss, &slen)<0) {
+ TT_FAIL(("Couldn't parse expected address %s on line %d",
+ sockaddr_port, line));
+ return -1;
+ }
+ if (ai->ai_family != ss.ss_family) {
+ TT_FAIL(("Address family %d did not match %d on line %d",
+ ai->ai_family, ss.ss_family, line));
+ return -1;
+ }
+ if (ai->ai_addr->sa_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in*)ai->ai_addr;
+ evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf));
+ gotport = ntohs(sin->sin_port);
+ if (ai->ai_addrlen != sizeof(struct sockaddr_in)) {
+ TT_FAIL(("Addr size mismatch on line %d", line));
+ return -1;
+ }
+ } else {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)ai->ai_addr;
+ evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, sizeof(buf));
+ gotport = ntohs(sin6->sin6_port);
+ if (ai->ai_addrlen != sizeof(struct sockaddr_in6)) {
+ TT_FAIL(("Addr size mismatch on line %d", line));
+ return -1;
+ }
+ }
+ if (evutil_sockaddr_cmp(ai->ai_addr, (struct sockaddr*)&ss, 1)) {
+ TT_FAIL(("Wanted %s, got %s:%d on line %d", sockaddr_port,
+ buf, gotport, line));
+ return -1;
+ } else {
+ TT_BLATHER(("Wanted %s, got %s:%d on line %d", sockaddr_port,
+ buf, gotport, line));
+ }
+ return 0;
+end:
+ TT_FAIL(("Test failed on line %d", line));
+ return -1;
+}
+
+static void
+test_evutil_rand(void *arg)
+{
+ char buf1[32];
+ char buf2[32];
+ int counts[256];
+ int i, j, k, n=0;
+ struct evutil_weakrand_state seed = { 12346789U };
+
+ memset(buf2, 0, sizeof(buf2));
+ memset(counts, 0, sizeof(counts));
+
+ for (k=0;k<32;++k) {
+ /* Try a few different start and end points; try to catch
+ * the various misaligned cases of arc4random_buf */
+ int startpoint = evutil_weakrand_(&seed) % 4;
+ int endpoint = 32 - (evutil_weakrand_(&seed) % 4);
+
+ memset(buf2, 0, sizeof(buf2));
+
+ /* Do 6 runs over buf1, or-ing the result into buf2 each
+ * time, to make sure we're setting each byte that we mean
+ * to set. */
+ for (i=0;i<8;++i) {
+ memset(buf1, 0, sizeof(buf1));
+ evutil_secure_rng_get_bytes(buf1 + startpoint,
+ endpoint-startpoint);
+ n += endpoint - startpoint;
+ for (j=0; j<32; ++j) {
+ if (j >= startpoint && j < endpoint) {
+ buf2[j] |= buf1[j];
+ ++counts[(unsigned char)buf1[j]];
+ } else {
+ tt_assert(buf1[j] == 0);
+ tt_int_op(buf1[j], ==, 0);
+
+ }
+ }
+ }
+
+ /* This will give a false positive with P=(256**8)==(2**64)
+ * for each character. */
+ for (j=startpoint;j<endpoint;++j) {
+ tt_int_op(buf2[j], !=, 0);
+ }
+ }
+
+ evutil_weakrand_seed_(&seed, 0);
+ for (i = 0; i < 10000; ++i) {
+ ev_int32_t r = evutil_weakrand_range_(&seed, 9999);
+ tt_int_op(0, <=, r);
+ tt_int_op(r, <, 9999);
+ }
+
+ /* for (i=0;i<256;++i) { printf("%3d %2d\n", i, counts[i]); } */
+end:
+ ;
+}
+
+static void
+test_evutil_getaddrinfo(void *arg)
+{
+ struct evutil_addrinfo *ai = NULL, *a;
+ struct evutil_addrinfo hints;
+ int r;
+
+ /* Try using it as a pton. */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ r = evutil_getaddrinfo("1.2.3.4", "8080", &hints, &ai);
+ tt_int_op(r, ==, 0);
+ tt_assert(ai);
+ tt_ptr_op(ai->ai_next, ==, NULL); /* no ambiguity */
+ test_ai_eq(ai, "1.2.3.4:8080", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_protocol = IPPROTO_UDP;
+ r = evutil_getaddrinfo("1001:b0b::f00f", "4321", &hints, &ai);
+ tt_int_op(r, ==, 0);
+ tt_assert(ai);
+ tt_ptr_op(ai->ai_next, ==, NULL); /* no ambiguity */
+ test_ai_eq(ai, "[1001:b0b::f00f]:4321", SOCK_DGRAM, IPPROTO_UDP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ /* Try out the behavior of nodename=NULL */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_flags = EVUTIL_AI_PASSIVE; /* as if for bind */
+ r = evutil_getaddrinfo(NULL, "9999", &hints, &ai);
+ tt_int_op(r,==,0);
+ tt_assert(ai);
+ tt_ptr_op(ai->ai_next, ==, NULL);
+ test_ai_eq(ai, "0.0.0.0:9999", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+ hints.ai_flags = 0; /* as if for connect */
+ r = evutil_getaddrinfo(NULL, "9998", &hints, &ai);
+ tt_assert(ai);
+ tt_int_op(r,==,0);
+ test_ai_eq(ai, "127.0.0.1:9998", SOCK_STREAM, IPPROTO_TCP);
+ tt_ptr_op(ai->ai_next, ==, NULL);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ hints.ai_flags = 0; /* as if for connect */
+ hints.ai_family = PF_INET6;
+ r = evutil_getaddrinfo(NULL, "9997", &hints, &ai);
+ tt_assert(ai);
+ tt_int_op(r,==,0);
+ tt_ptr_op(ai->ai_next, ==, NULL);
+ test_ai_eq(ai, "[::1]:9997", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ hints.ai_flags = EVUTIL_AI_PASSIVE; /* as if for bind. */
+ hints.ai_family = PF_INET6;
+ r = evutil_getaddrinfo(NULL, "9996", &hints, &ai);
+ tt_assert(ai);
+ tt_int_op(r,==,0);
+ tt_ptr_op(ai->ai_next, ==, NULL);
+ test_ai_eq(ai, "[::]:9996", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ /* Now try an unspec one. We should get a v6 and a v4. */
+ hints.ai_family = PF_UNSPEC;
+ r = evutil_getaddrinfo(NULL, "9996", &hints, &ai);
+ tt_assert(ai);
+ tt_int_op(r,==,0);
+ a = ai_find_by_family(ai, PF_INET6);
+ tt_assert(a);
+ test_ai_eq(a, "[::]:9996", SOCK_STREAM, IPPROTO_TCP);
+ a = ai_find_by_family(ai, PF_INET);
+ tt_assert(a);
+ test_ai_eq(a, "0.0.0.0:9996", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ /* Try out AI_NUMERICHOST: successful case. Also try
+ * multiprotocol. */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = EVUTIL_AI_NUMERICHOST;
+ r = evutil_getaddrinfo("1.2.3.4", NULL, &hints, &ai);
+ tt_int_op(r, ==, 0);
+ a = ai_find_by_protocol(ai, IPPROTO_TCP);
+ tt_assert(a);
+ test_ai_eq(a, "1.2.3.4", SOCK_STREAM, IPPROTO_TCP);
+ a = ai_find_by_protocol(ai, IPPROTO_UDP);
+ tt_assert(a);
+ test_ai_eq(a, "1.2.3.4", SOCK_DGRAM, IPPROTO_UDP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ /* Try the failing case of AI_NUMERICHOST */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = EVUTIL_AI_NUMERICHOST;
+ r = evutil_getaddrinfo("www.google.com", "80", &hints, &ai);
+ tt_int_op(r, ==, EVUTIL_EAI_NONAME);
+ tt_ptr_op(ai, ==, NULL);
+
+ /* Try symbolic service names wit AI_NUMERICSERV */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = EVUTIL_AI_NUMERICSERV;
+ r = evutil_getaddrinfo("1.2.3.4", "http", &hints, &ai);
+ tt_int_op(r,==,EVUTIL_EAI_NONAME);
+
+ /* Try symbolic service names */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ r = evutil_getaddrinfo("1.2.3.4", "http", &hints, &ai);
+ if (r!=0) {
+ TT_DECLARE("SKIP", ("Symbolic service names seem broken."));
+ } else {
+ tt_assert(ai);
+ test_ai_eq(ai, "1.2.3.4:80", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+ }
+
+end:
+ if (ai)
+ evutil_freeaddrinfo(ai);
+}
+
+static void
+test_evutil_getaddrinfo_live(void *arg)
+{
+ struct evutil_addrinfo *ai = NULL;
+ struct evutil_addrinfo hints;
+
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in *sin;
+ char buf[128];
+ const char *cp;
+ int r;
+
+ /* Now do some actual lookups. */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_socktype = SOCK_STREAM;
+ r = evutil_getaddrinfo("www.google.com", "80", &hints, &ai);
+ if (r != 0) {
+ TT_DECLARE("SKIP", ("Couldn't resolve www.google.com"));
+ } else {
+ tt_assert(ai);
+ tt_int_op(ai->ai_family, ==, PF_INET);
+ tt_int_op(ai->ai_protocol, ==, IPPROTO_TCP);
+ tt_int_op(ai->ai_socktype, ==, SOCK_STREAM);
+ tt_int_op(ai->ai_addrlen, ==, sizeof(struct sockaddr_in));
+ sin = (struct sockaddr_in*)ai->ai_addr;
+ tt_int_op(sin->sin_family, ==, AF_INET);
+ tt_int_op(sin->sin_port, ==, htons(80));
+ tt_int_op(sin->sin_addr.s_addr, !=, 0xffffffff);
+
+ cp = evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf));
+ TT_BLATHER(("www.google.com resolved to %s",
+ cp?cp:"<unwriteable>"));
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+ }
+
+ hints.ai_family = PF_INET6;
+ r = evutil_getaddrinfo("ipv6.google.com", "80", &hints, &ai);
+ if (r != 0) {
+ TT_BLATHER(("Couldn't do an ipv6 lookup for ipv6.google.com"));
+ } else {
+ tt_assert(ai);
+ tt_int_op(ai->ai_family, ==, PF_INET6);
+ tt_int_op(ai->ai_addrlen, ==, sizeof(struct sockaddr_in6));
+ sin6 = (struct sockaddr_in6*)ai->ai_addr;
+ tt_int_op(sin6->sin6_port, ==, htons(80));
+
+ cp = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf,
+ sizeof(buf));
+ TT_BLATHER(("ipv6.google.com resolved to %s",
+ cp?cp:"<unwriteable>"));
+ }
+
+end:
+ if (ai)
+ evutil_freeaddrinfo(ai);
+}
+
+#ifdef _WIN32
+static void
+test_evutil_loadsyslib(void *arg)
+{
+ HMODULE h=NULL;
+
+ h = evutil_load_windows_system_library_(TEXT("kernel32.dll"));
+ tt_assert(h);
+
+end:
+ if (h)
+ CloseHandle(h);
+
+}
+#endif
+
+/** Test mm_malloc(). */
+static void
+test_event_malloc(void *arg)
+{
+ void *p = NULL;
+ (void)arg;
+
+ /* mm_malloc(0) should simply return NULL. */
+#ifndef EVENT__DISABLE_MM_REPLACEMENT
+ errno = 0;
+ p = mm_malloc(0);
+ tt_assert(p == NULL);
+ tt_int_op(errno, ==, 0);
+#endif
+
+ /* Trivial case. */
+ errno = 0;
+ p = mm_malloc(8);
+ tt_assert(p != NULL);
+ tt_int_op(errno, ==, 0);
+ mm_free(p);
+
+ end:
+ errno = 0;
+ return;
+}
+
+static void
+test_event_calloc(void *arg)
+{
+ void *p = NULL;
+ (void)arg;
+
+#ifndef EVENT__DISABLE_MM_REPLACEMENT
+ /* mm_calloc() should simply return NULL
+ * if either argument is zero. */
+ errno = 0;
+ p = mm_calloc(0, 0);
+ tt_assert(p == NULL);
+ tt_int_op(errno, ==, 0);
+ errno = 0;
+ p = mm_calloc(0, 1);
+ tt_assert(p == NULL);
+ tt_int_op(errno, ==, 0);
+ errno = 0;
+ p = mm_calloc(1, 0);
+ tt_assert(p == NULL);
+ tt_int_op(errno, ==, 0);
+#endif
+
+ /* Trivial case. */
+ errno = 0;
+ p = mm_calloc(8, 8);
+ tt_assert(p != NULL);
+ tt_int_op(errno, ==, 0);
+ mm_free(p);
+ p = NULL;
+
+ /* mm_calloc() should set errno = ENOMEM and return NULL
+ * in case of potential overflow. */
+ errno = 0;
+ p = mm_calloc(EV_SIZE_MAX/2, EV_SIZE_MAX/2 + 8);
+ tt_assert(p == NULL);
+ tt_int_op(errno, ==, ENOMEM);
+
+ end:
+ errno = 0;
+ if (p)
+ mm_free(p);
+
+ return;
+}
+
+static void
+test_event_strdup(void *arg)
+{
+ void *p = NULL;
+ (void)arg;
+
+#ifndef EVENT__DISABLE_MM_REPLACEMENT
+ /* mm_strdup(NULL) should set errno = EINVAL and return NULL. */
+ errno = 0;
+ p = mm_strdup(NULL);
+ tt_assert(p == NULL);
+ tt_int_op(errno, ==, EINVAL);
+#endif
+
+ /* Trivial cases. */
+
+ errno = 0;
+ p = mm_strdup("");
+ tt_assert(p != NULL);
+ tt_int_op(errno, ==, 0);
+ tt_str_op(p, ==, "");
+ mm_free(p);
+
+ errno = 0;
+ p = mm_strdup("foo");
+ tt_assert(p != NULL);
+ tt_int_op(errno, ==, 0);
+ tt_str_op(p, ==, "foo");
+ mm_free(p);
+
+ /* XXX
+ * mm_strdup(str) where str is a string of length EV_SIZE_MAX
+ * should set errno = ENOMEM and return NULL. */
+
+ end:
+ errno = 0;
+ return;
+}
+
+static void
+test_evutil_usleep(void *arg)
+{
+ struct timeval tv1, tv2, tv3, diff1, diff2;
+ const struct timeval quarter_sec = {0, 250*1000};
+ const struct timeval tenth_sec = {0, 100*1000};
+ long usec1, usec2;
+
+ evutil_gettimeofday(&tv1, NULL);
+ evutil_usleep_(&quarter_sec);
+ evutil_gettimeofday(&tv2, NULL);
+ evutil_usleep_(&tenth_sec);
+ evutil_gettimeofday(&tv3, NULL);
+
+ evutil_timersub(&tv2, &tv1, &diff1);
+ evutil_timersub(&tv3, &tv2, &diff2);
+ usec1 = diff1.tv_sec * 1000000 + diff1.tv_usec;
+ usec2 = diff2.tv_sec * 1000000 + diff2.tv_usec;
+
+ tt_int_op(usec1, >, 200000);
+ tt_int_op(usec1, <, 300000);
+ tt_int_op(usec2, >, 80000);
+ tt_int_op(usec2, <, 120000);
+
+end:
+ ;
+}
+
+static void
+test_evutil_monotonic_res(void *data_)
+{
+ /* Basic santity-test for monotonic timers. What we'd really like
+ * to do is make sure that they can't go backwards even when the
+ * system clock goes backwards. But we haven't got a good way to
+ * move the system clock backwards.
+ */
+ struct basic_test_data *data = data_;
+ struct evutil_monotonic_timer timer;
+ const int precise = strstr(data->setup_data, "precise") != NULL;
+ const int fallback = strstr(data->setup_data, "fallback") != NULL;
+ struct timeval tv[10], delay;
+ int total_diff = 0;
+
+ int flags = 0, wantres, acceptdiff, i;
+ if (precise)
+ flags |= EV_MONOT_PRECISE;
+ if (fallback)
+ flags |= EV_MONOT_FALLBACK;
+ if (precise || fallback) {
+#ifdef _WIN32
+ wantres = 10*1000;
+ acceptdiff = 1000;
+#else
+ wantres = 1000;
+ acceptdiff = 300;
+#endif
+ } else {
+ wantres = 40*1000;
+ acceptdiff = 20*1000;
+ }
+
+ TT_BLATHER(("Precise = %d", precise));
+ TT_BLATHER(("Fallback = %d", fallback));
+
+ /* First, make sure we match up with usleep. */
+
+ delay.tv_sec = 0;
+ delay.tv_usec = wantres;
+
+ tt_int_op(evutil_configure_monotonic_time_(&timer, flags), ==, 0);
+
+ for (i = 0; i < 10; ++i) {
+ evutil_gettime_monotonic_(&timer, &tv[i]);
+ evutil_usleep_(&delay);
+ }
+
+ for (i = 0; i < 9; ++i) {
+ struct timeval diff;
+ tt_assert(evutil_timercmp(&tv[i], &tv[i+1], <));
+ evutil_timersub(&tv[i+1], &tv[i], &diff);
+ tt_int_op(diff.tv_sec, ==, 0);
+ total_diff += diff.tv_usec;
+ TT_BLATHER(("Difference = %d", (int)diff.tv_usec));
+ }
+ tt_int_op(abs(total_diff/9 - wantres), <, acceptdiff);
+
+end:
+ ;
+}
+
+static void
+test_evutil_monotonic_prc(void *data_)
+{
+ struct basic_test_data *data = data_;
+ struct evutil_monotonic_timer timer;
+ const int precise = strstr(data->setup_data, "precise") != NULL;
+ const int fallback = strstr(data->setup_data, "fallback") != NULL;
+ struct timeval tv[10];
+ int total_diff = 0;
+ int i, maxstep = 25*1000,flags=0;
+ if (precise)
+ maxstep = 500;
+ if (precise)
+ flags |= EV_MONOT_PRECISE;
+ if (fallback)
+ flags |= EV_MONOT_FALLBACK;
+ tt_int_op(evutil_configure_monotonic_time_(&timer, flags), ==, 0);
+
+ /* find out what precision we actually see. */
+
+ evutil_gettime_monotonic_(&timer, &tv[0]);
+ for (i = 1; i < 10; ++i) {
+ do {
+ evutil_gettime_monotonic_(&timer, &tv[i]);
+ } while (evutil_timercmp(&tv[i-1], &tv[i], ==));
+ }
+
+ total_diff = 0;
+ for (i = 0; i < 9; ++i) {
+ struct timeval diff;
+ tt_assert(evutil_timercmp(&tv[i], &tv[i+1], <));
+ evutil_timersub(&tv[i+1], &tv[i], &diff);
+ tt_int_op(diff.tv_sec, ==, 0);
+ total_diff += diff.tv_usec;
+ TT_BLATHER(("Step difference = %d", (int)diff.tv_usec));
+ }
+ TT_BLATHER(("Average step difference = %d", total_diff / 9));
+ tt_int_op(total_diff/9, <, maxstep);
+
+end:
+ ;
+}
+
+static void
+create_tm_from_unix_epoch(struct tm *cur_p, const time_t t) {
+#ifdef _WIN32
+ cur_p = gmtime(&t);
+#else
+ gmtime_r(&t, cur_p);
+#endif
+}
+
+static struct date_rfc1123_case {
+ time_t t;
+ char date[30];
+} date_rfc1123_cases[] = {
+ { 0, "Thu, 01 Jan 1970 00:00:00 GMT"} /* UNIX time of zero */,
+ { 946684799, "Fri, 31 Dec 1999 23:59:59 GMT"} /* the last moment of the 20th century */,
+ { 946684800, "Sat, 01 Jan 2000 00:00:00 GMT"} /* the first moment of the 21st century */,
+ { 981072000, "Fri, 02 Feb 2001 00:00:00 GMT"},
+ { 1015113600, "Sun, 03 Mar 2002 00:00:00 GMT"},
+ { 1049414400, "Fri, 04 Apr 2003 00:00:00 GMT"},
+ { 1083715200, "Wed, 05 May 2004 00:00:00 GMT"},
+ { 1118016000, "Mon, 06 Jun 2005 00:00:00 GMT"},
+ { 1152230400, "Fri, 07 Jul 2006 00:00:00 GMT"},
+ { 1186531200, "Wed, 08 Aug 2007 00:00:00 GMT"},
+ { 1220918400, "Tue, 09 Sep 2008 00:00:00 GMT"},
+ { 1255132800, "Sat, 10 Oct 2009 00:00:00 GMT"},
+ { 1289433600, "Thu, 11 Nov 2010 00:00:00 GMT"},
+ { 1323648000, "Mon, 12 Dec 2011 00:00:00 GMT"},
+ { 4294967296, "Sun, 07 Feb 2106 06:28:16 GMT"} /* 2^32 */,
+ {253402300799, "Fri, 31 Dec 9999 23:59:59 GMT"} /* long long future no one can imagine */,
+ { 1456704000, "Mon, 29 Feb 2016 00:00:00 GMT"} /* leap year */,
+ { 1435708800, "Wed, 01 Jul 2015 00:00:00 GMT"} /* leap second */,
+ { 1481866376, "Fri, 16 Dec 2016 05:32:56 GMT"} /* the time this test case is generated */,
+ {0, ""} /* end of test cases. */
+};
+
+static void
+test_evutil_date_rfc1123(void *arg)
+{
+ struct tm query;
+ char result[30];
+
+ /* Checks if too small buffers are safely accepted. */
+ {
+ create_tm_from_unix_epoch(&query, 0);
+ evutil_date_rfc1123(result, 8, &query);
+ tt_str_op(result, ==, "Thu, 01");
+ }
+
+ /* Checks for testcases. */
+ for (size_t i=0; ; i++) {
+ struct date_rfc1123_case c = date_rfc1123_cases[i];
+
+ if (strlen(c.date) == 0)
+ break;
+
+ create_tm_from_unix_epoch(&query, c.t);
+ evutil_date_rfc1123(result, sizeof(result), &query);
+ tt_str_op(result, ==, c.date);
+ }
+
+end:
+ ;
+}
+
+struct testcase_t util_testcases[] = {
+ { "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL },
+ { "ipv6_parse", regress_ipv6_parse, 0, NULL, NULL },
+ { "sockaddr_port_parse", regress_sockaddr_port_parse, 0, NULL, NULL },
+ { "sockaddr_port_format", regress_sockaddr_port_format, 0, NULL, NULL },
+ { "sockaddr_predicates", test_evutil_sockaddr_predicates, 0,NULL,NULL },
+ { "evutil_snprintf", test_evutil_snprintf, 0, NULL, NULL },
+ { "evutil_strtoll", test_evutil_strtoll, 0, NULL, NULL },
+ { "evutil_casecmp", test_evutil_casecmp, 0, NULL, NULL },
+ { "evutil_rtrim", test_evutil_rtrim, 0, NULL, NULL },
+ { "strlcpy", test_evutil_strlcpy, 0, NULL, NULL },
+ { "log", test_evutil_log, TT_FORK, NULL, NULL },
+ { "upcast", test_evutil_upcast, 0, NULL, NULL },
+ { "integers", test_evutil_integers, 0, NULL, NULL },
+ { "rand", test_evutil_rand, TT_FORK, NULL, NULL },
+ { "getaddrinfo", test_evutil_getaddrinfo, TT_FORK, NULL, NULL },
+ { "getaddrinfo_live", test_evutil_getaddrinfo_live, TT_FORK|TT_OFF_BY_DEFAULT, NULL, NULL },
+#ifdef _WIN32
+ { "loadsyslib", test_evutil_loadsyslib, TT_FORK, NULL, NULL },
+#endif
+ { "mm_malloc", test_event_malloc, 0, NULL, NULL },
+ { "mm_calloc", test_event_calloc, 0, NULL, NULL },
+ { "mm_strdup", test_event_strdup, 0, NULL, NULL },
+ { "usleep", test_evutil_usleep, 0, NULL, NULL },
+ { "monotonic_res", test_evutil_monotonic_res, 0, &basic_setup, (void*)"" },
+ { "monotonic_res_precise", test_evutil_monotonic_res, TT_OFF_BY_DEFAULT, &basic_setup, (void*)"precise" },
+ { "monotonic_res_fallback", test_evutil_monotonic_res, TT_OFF_BY_DEFAULT, &basic_setup, (void*)"fallback" },
+ { "monotonic_prc", test_evutil_monotonic_prc, 0, &basic_setup, (void*)"" },
+ { "monotonic_prc_precise", test_evutil_monotonic_prc, 0, &basic_setup, (void*)"precise" },
+ { "monotonic_prc_fallback", test_evutil_monotonic_prc, 0, &basic_setup, (void*)"fallback" },
+ { "date_rfc1123", test_evutil_date_rfc1123, 0, NULL, NULL },
+ END_OF_TESTCASES,
+};
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_zlib.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_zlib.c
new file mode 100644
index 000000000..5fe774913
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/regress_zlib.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2008-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* The old tests here need assertions to work. */
+#undef NDEBUG
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+#include <errno.h>
+
+#include "event2/util.h"
+#include "event2/event.h"
+#include "event2/event_compat.h"
+#include "event2/buffer.h"
+#include "event2/bufferevent.h"
+
+#include "regress.h"
+#include "mm-internal.h"
+
+/* zlib 1.2.4 and 1.2.5 do some "clever" things with macros. Instead of
+ saying "(defined(FOO) ? FOO : 0)" they like to say "FOO-0", on the theory
+ that nobody will care if the compile outputs a no-such-identifier warning.
+
+ Sorry, but we like -Werror over here, so I guess we need to define these.
+ I hope that zlib 1.2.6 doesn't break these too.
+*/
+#ifndef _LARGEFILE64_SOURCE
+#define _LARGEFILE64_SOURCE 0
+#endif
+#ifndef _LFS64_LARGEFILE
+#define _LFS64_LARGEFILE 0
+#endif
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 0
+#endif
+#ifndef off64_t
+#define off64_t ev_int64_t
+#endif
+
+#include <zlib.h>
+
+static int infilter_calls;
+static int outfilter_calls;
+static int readcb_finished;
+static int writecb_finished;
+static int errorcb_invoked;
+
+/*
+ * Zlib filters
+ */
+
+static void
+zlib_deflate_free(void *ctx)
+{
+ z_streamp p = ctx;
+
+ assert(deflateEnd(p) == Z_OK);
+ mm_free(p);
+}
+
+static void
+zlib_inflate_free(void *ctx)
+{
+ z_streamp p = ctx;
+
+ assert(inflateEnd(p) == Z_OK);
+ mm_free(p);
+}
+
+static int
+getstate(enum bufferevent_flush_mode state)
+{
+ switch (state) {
+ case BEV_FINISHED:
+ return Z_FINISH;
+ case BEV_FLUSH:
+ return Z_SYNC_FLUSH;
+ case BEV_NORMAL:
+ default:
+ return Z_NO_FLUSH;
+ }
+}
+
+/*
+ * The input filter is triggered only on new input read from the network.
+ * That means all input data needs to be consumed or the filter needs to
+ * initiate its own triggering via a timeout.
+ */
+static enum bufferevent_filter_result
+zlib_input_filter(struct evbuffer *src, struct evbuffer *dst,
+ ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
+{
+ struct evbuffer_iovec v_in[1];
+ struct evbuffer_iovec v_out[1];
+ int nread, nwrite;
+ int res, n;
+
+ z_streamp p = ctx;
+
+ do {
+ /* let's do some decompression */
+ n = evbuffer_peek(src, -1, NULL, v_in, 1);
+ if (n) {
+ p->avail_in = v_in[0].iov_len;
+ p->next_in = (unsigned char *)v_in[0].iov_base;
+ } else {
+ p->avail_in = 0;
+ p->next_in = 0;
+ }
+
+ evbuffer_reserve_space(dst, 4096, v_out, 1);
+ p->next_out = (unsigned char *)v_out[0].iov_base;
+ p->avail_out = v_out[0].iov_len;
+
+ /* we need to flush zlib if we got a flush */
+ res = inflate(p, getstate(state));
+
+ /* let's figure out how much was compressed */
+ nread = v_in[0].iov_len - p->avail_in;
+ nwrite = v_out[0].iov_len - p->avail_out;
+
+ evbuffer_drain(src, nread);
+ v_out[0].iov_len = nwrite;
+ evbuffer_commit_space(dst, v_out, 1);
+
+ if (res==Z_BUF_ERROR) {
+ /* We're out of space, or out of decodeable input.
+ Only if nwrite == 0 assume the latter.
+ */
+ if (nwrite == 0)
+ return BEV_NEED_MORE;
+ } else {
+ assert(res == Z_OK || res == Z_STREAM_END);
+ }
+
+ } while (evbuffer_get_length(src) > 0);
+
+ ++infilter_calls;
+
+ return (BEV_OK);
+}
+
+static enum bufferevent_filter_result
+zlib_output_filter(struct evbuffer *src, struct evbuffer *dst,
+ ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
+{
+ struct evbuffer_iovec v_in[1];
+ struct evbuffer_iovec v_out[1];
+ int nread, nwrite;
+ int res, n;
+
+ z_streamp p = ctx;
+
+ do {
+ /* let's do some compression */
+ n = evbuffer_peek(src, -1, NULL, v_in, 1);
+ if (n) {
+ p->avail_in = v_in[0].iov_len;
+ p->next_in = (unsigned char *)v_in[0].iov_base;
+ } else {
+ p->avail_in = 0;
+ p->next_in = 0;
+ }
+
+ evbuffer_reserve_space(dst, 4096, v_out, 1);
+ p->next_out = (unsigned char *)v_out[0].iov_base;
+ p->avail_out = v_out[0].iov_len;
+
+ /* we need to flush zlib if we got a flush */
+ res = deflate(p, getstate(state));
+
+ /* let's figure out how much was decompressed */
+ nread = v_in[0].iov_len - p->avail_in;
+ nwrite = v_out[0].iov_len - p->avail_out;
+
+ evbuffer_drain(src, nread);
+ v_out[0].iov_len = nwrite;
+ evbuffer_commit_space(dst, v_out, 1);
+
+ if (res==Z_BUF_ERROR) {
+ /* We're out of space, or out of decodeable input.
+ Only if nwrite == 0 assume the latter.
+ */
+ if (nwrite == 0)
+ return BEV_NEED_MORE;
+ } else {
+ assert(res == Z_OK || res == Z_STREAM_END);
+ }
+
+ } while (evbuffer_get_length(src) > 0);
+
+ ++outfilter_calls;
+
+ return (BEV_OK);
+}
+
+/*
+ * simple bufferevent test (over transparent zlib treatment)
+ */
+
+static void
+readcb(struct bufferevent *bev, void *arg)
+{
+ if (evbuffer_get_length(bufferevent_get_input(bev)) == 8333) {
+ struct evbuffer *evbuf = evbuffer_new();
+ assert(evbuf != NULL);
+
+ /* gratuitous test of bufferevent_read_buffer */
+ bufferevent_read_buffer(bev, evbuf);
+
+ bufferevent_disable(bev, EV_READ);
+
+ if (evbuffer_get_length(evbuf) == 8333) {
+ ++readcb_finished;
+ }
+
+ evbuffer_free(evbuf);
+ }
+}
+
+static void
+writecb(struct bufferevent *bev, void *arg)
+{
+ if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
+ ++writecb_finished;
+ }
+}
+
+static void
+errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ errorcb_invoked = 1;
+}
+
+void
+test_bufferevent_zlib(void *arg)
+{
+ struct bufferevent *bev1=NULL, *bev2=NULL;
+ char buffer[8333];
+ z_stream *z_input, *z_output;
+ int i, r;
+ evutil_socket_t pair[2] = {-1, -1};
+ (void)arg;
+
+ infilter_calls = outfilter_calls = readcb_finished = writecb_finished
+ = errorcb_invoked = 0;
+
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
+ tt_abort_perror("socketpair");
+ }
+
+ evutil_make_socket_nonblocking(pair[0]);
+ evutil_make_socket_nonblocking(pair[1]);
+
+ bev1 = bufferevent_socket_new(NULL, pair[0], 0);
+ bev2 = bufferevent_socket_new(NULL, pair[1], 0);
+
+ z_output = mm_calloc(sizeof(*z_output), 1);
+ r = deflateInit(z_output, Z_DEFAULT_COMPRESSION);
+ tt_int_op(r, ==, Z_OK);
+ z_input = mm_calloc(sizeof(*z_input), 1);
+ r = inflateInit(z_input);
+ tt_int_op(r, ==, Z_OK);
+
+ /* initialize filters */
+ bev1 = bufferevent_filter_new(bev1, NULL, zlib_output_filter,
+ BEV_OPT_CLOSE_ON_FREE, zlib_deflate_free, z_output);
+ bev2 = bufferevent_filter_new(bev2, zlib_input_filter,
+ NULL, BEV_OPT_CLOSE_ON_FREE, zlib_inflate_free, z_input);
+ bufferevent_setcb(bev1, readcb, writecb, errorcb, NULL);
+ bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL);
+
+ bufferevent_disable(bev1, EV_READ);
+ bufferevent_enable(bev1, EV_WRITE);
+
+ bufferevent_enable(bev2, EV_READ);
+
+ for (i = 0; i < (int)sizeof(buffer); i++)
+ buffer[i] = i;
+
+ /* break it up into multiple buffer chains */
+ bufferevent_write(bev1, buffer, 1800);
+ bufferevent_write(bev1, buffer + 1800, sizeof(buffer) - 1800);
+
+ /* we are done writing - we need to flush everything */
+ bufferevent_flush(bev1, EV_WRITE, BEV_FINISHED);
+
+ event_dispatch();
+
+ tt_want(infilter_calls);
+ tt_want(outfilter_calls);
+ tt_want(readcb_finished);
+ tt_want(writecb_finished);
+ tt_want(!errorcb_invoked);
+
+ test_ok = 1;
+end:
+ if (bev1)
+ bufferevent_free(bev1);
+ if (bev2)
+ bufferevent_free(bev2);
+
+ if (pair[0] >= 0)
+ evutil_closesocket(pair[0]);
+ if (pair[1] >= 0)
+ evutil_closesocket(pair[1]);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/rpcgen_wrapper.sh b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/rpcgen_wrapper.sh
new file mode 100755
index 000000000..aaa03031a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/rpcgen_wrapper.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# libevent rpcgen_wrapper.sh
+# Transforms event_rpcgen.py failure into success for make, only if
+# regress.gen.c and regress.gen.h already exist in $srcdir. This
+# is needed for "make distcheck" to pass the read-only $srcdir build,
+# as with read-only sources fresh from tarball, regress.gen.[ch] will
+# be correct in $srcdir but unwritable. This previously triggered
+# Makefile.am to create stub regress.gen.c and regress.gen.h in the
+# distcheck _build directory, which were then detected as leftover
+# files in the build tree after distclean, breaking distcheck.
+# Note that regress.gen.[ch] are not in fresh git clones, making
+# working Python a requirement for make distcheck of a git tree.
+
+exit_updated() {
+# echo "Updated ${srcdir}/regress.gen.c and ${srcdir}/regress.gen.h"
+ exit 0
+}
+
+exit_reuse() {
+ echo "event_rpcgen.py failed, ${srcdir}/regress.gen.\[ch\] will be reused." >&2
+ exit 0
+}
+
+exit_failed() {
+ echo "Could not generate regress.gen.\[ch\] using event_rpcgen.sh" >&2
+ exit 1
+}
+
+if [ -x /usr/bin/python2 ] ; then
+ PYTHON2=/usr/bin/python2
+elif [ "x`which python2`" != x ] ; then
+ PYTHON2=python2
+else
+ PYTHON2=python
+fi
+
+srcdir=$1
+srcdir=${srcdir:-.}
+
+${PYTHON2} ${srcdir}/../event_rpcgen.py --quiet ${srcdir}/regress.rpc \
+ test/regress.gen.h test/regress.gen.c
+
+case "$?" in
+ 0)
+ exit_updated
+ ;;
+ *)
+ test -r ${srcdir}/regress.gen.c -a -r ${srcdir}/regress.gen.h && \
+ exit_reuse
+ exit_failed
+ ;;
+esac
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-changelist.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-changelist.c
new file mode 100644
index 000000000..6e2466d5a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-changelist.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event2/event.h"
+#include "event2/util.h"
+#include <time.h>
+
+struct cpu_usage_timer {
+#ifdef _WIN32
+ HANDLE thread;
+ FILETIME usertimeBegin;
+ FILETIME kerneltimeBegin;
+#else
+ clock_t ticksBegin;
+#endif
+ struct timeval timeBegin;
+};
+static void
+start_cpu_usage_timer(struct cpu_usage_timer *timer)
+{
+#ifdef _WIN32
+ int r;
+ FILETIME createtime, exittime;
+ timer->thread = GetCurrentThread();
+ r = GetThreadTimes(timer->thread, &createtime, &exittime,
+ &timer->usertimeBegin, &timer->kerneltimeBegin);
+ if (r==0) printf("GetThreadTimes failed.");
+#else
+ timer->ticksBegin = clock();
+#endif
+
+ evutil_gettimeofday(&timer->timeBegin, NULL);
+}
+#ifdef _WIN32
+static ev_int64_t
+filetime_to_100nsec(const FILETIME *ft)
+{
+ /* Number of 100-nanosecond units */
+ ev_int64_t n = ft->dwHighDateTime;
+ n <<= 32;
+ n += ft->dwLowDateTime;
+ return n;
+}
+static double
+filetime_diff(const FILETIME *ftStart, const FILETIME *ftEnd)
+{
+ ev_int64_t s, e, diff;
+ double r;
+ s = filetime_to_100nsec(ftStart);
+ e = filetime_to_100nsec(ftEnd);
+ diff = e - s;
+ r = (double) diff;
+ return r / 1.0e7;
+}
+#endif
+
+static void
+get_cpu_usage(struct cpu_usage_timer *timer, double *secElapsedOut,
+ double *secUsedOut, double *usageOut)
+{
+#ifdef _WIN32
+ double usertime_seconds, kerneltime_seconds;
+ FILETIME createtime, exittime, usertimeEnd, kerneltimeEnd;
+ int r;
+#else
+ clock_t ticksEnd;
+#endif
+ struct timeval timeEnd, timeDiff;
+ double secondsPassed, secondsUsed;
+
+#ifdef _WIN32
+ r = GetThreadTimes(timer->thread, &createtime, &exittime,
+ &usertimeEnd, &kerneltimeEnd);
+ if (r==0) printf("GetThreadTimes failed.");
+ usertime_seconds = filetime_diff(&timer->usertimeBegin, &usertimeEnd);
+ kerneltime_seconds = filetime_diff(&timer->kerneltimeBegin, &kerneltimeEnd);
+ secondsUsed = kerneltime_seconds + usertime_seconds;
+#else
+ ticksEnd = clock();
+ secondsUsed = (ticksEnd - timer->ticksBegin) / (double)CLOCKS_PER_SEC;
+#endif
+ evutil_gettimeofday(&timeEnd, NULL);
+ evutil_timersub(&timeEnd, &timer->timeBegin, &timeDiff);
+ secondsPassed = timeDiff.tv_sec + (timeDiff.tv_usec / 1.0e6);
+
+ *secElapsedOut = secondsPassed;
+ *secUsedOut = secondsUsed;
+ *usageOut = secondsUsed / secondsPassed;
+}
+
+static void
+write_cb(evutil_socket_t fd, short event, void *arg)
+{
+ printf("write callback. should only see this once\n");
+
+ /* got what we want remove the event */
+ event_del(*(struct event**)arg);
+
+ /* opps changed my mind add it back again */
+ event_add(*(struct event**)arg,NULL);
+
+ /* not a good day for decisiveness, I really didn't want it after all */
+ event_del(*(struct event**)arg);
+
+}
+
+static void
+timeout_cb(evutil_socket_t fd, short event, void *arg)
+{
+ printf("timeout fired, time to end test\n");
+ event_del(*(struct event**)arg);
+ return;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct event* ev;
+ struct event* timeout;
+ struct event_base* base;
+
+ evutil_socket_t pair[2];
+ struct timeval tv;
+ struct cpu_usage_timer timer;
+
+ double usage, secPassed, secUsed;
+
+#ifdef _WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ (void) WSAStartup(wVersionRequested, &wsaData);
+#endif
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+ return (1);
+
+ /* Initalize the event library */
+ if (!(base = event_base_new()))
+ return (1);
+
+ /* Initalize a timeout to terminate the test */
+ timeout = evtimer_new(base,timeout_cb,&timeout);
+ /* and watch for writability on one end of the pipe */
+ ev = event_new(base,pair[1],EV_WRITE | EV_PERSIST, write_cb, &ev);
+
+ tv.tv_sec = 1;
+ tv.tv_usec = 500*1000;
+
+ evtimer_add(timeout, &tv);
+
+ event_add(ev, NULL);
+
+ start_cpu_usage_timer(&timer);
+
+ event_base_dispatch(base);
+
+ event_free(ev);
+ event_free(timeout);
+ event_base_free(base);
+
+ get_cpu_usage(&timer, &secPassed, &secUsed, &usage);
+
+ /* attempt to calculate our cpu usage over the test should be
+ virtually nil */
+
+ printf("usec used=%d, usec passed=%d, cpu usage=%.2f%%\n",
+ (int)(secUsed*1e6),
+ (int)(secPassed*1e6),
+ usage*100);
+
+ if (usage > 50.0) /* way too high */
+ return 1;
+
+ return 0;
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-closed.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-closed.c
new file mode 100644
index 000000000..1dd988592
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-closed.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2013 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "../util-internal.h"
+#include "event2/event-config.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event.h>
+#include <evutil.h>
+
+struct timeval timeout = {3, 0};
+
+static void
+closed_cb(evutil_socket_t fd, short event, void *arg)
+{
+ if (EV_TIMEOUT & event) {
+ printf("%s: Timeout!\n", __func__);
+ exit(1);
+ }
+
+ if (EV_CLOSED & event) {
+ printf("%s: detected socket close with success\n", __func__);
+ return;
+ }
+
+ printf("%s: unable to detect socket close\n", __func__);
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct event_base *base;
+ struct event_config *cfg;
+ struct event *ev;
+ const char *test = "test string";
+ evutil_socket_t pair[2];
+
+ /* Initialize the library and check if the backend
+ supports EV_FEATURE_EARLY_CLOSE
+ */
+ cfg = event_config_new();
+ event_config_require_features(cfg, EV_FEATURE_EARLY_CLOSE);
+ base = event_base_new_with_config(cfg);
+ event_config_free(cfg);
+ if (!base) {
+ /* Backend doesn't support EV_FEATURE_EARLY_CLOSE */
+ return 0;
+ }
+
+ /* Create a pair of sockets */
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+ return (1);
+
+ /* Send some data on socket 0 and immediately close it */
+ if (send(pair[0], test, (int)strlen(test)+1, 0) < 0)
+ return (1);
+ shutdown(pair[0], EVUTIL_SHUT_WR);
+
+ /* Dispatch */
+ ev = event_new(base, pair[1], EV_CLOSED | EV_TIMEOUT, closed_cb, event_self_cbarg());
+ event_add(ev, &timeout);
+ event_base_dispatch(base);
+
+ /* Finalize library */
+ event_base_free(base);
+ return 0;
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-dumpevents.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-dumpevents.c
new file mode 100644
index 000000000..1c272d4c0
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-dumpevents.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util-internal.h"
+#include "event2/event-config.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <event2/event.h>
+#include <signal.h>
+
+static void
+sock_perror(const char *s)
+{
+#ifdef _WIN32
+ const char *err = evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR());
+ fprintf(stderr, "%s: %s\n", s, err);
+#else
+ perror(s);
+#endif
+}
+
+static void
+callback1(evutil_socket_t fd, short events, void *arg)
+{
+}
+static void
+callback2(evutil_socket_t fd, short events, void *arg)
+{
+}
+
+/* Testing code for event_base_dump_events().
+
+ Notes that just because we have code to exercise this function,
+ doesn't mean that *ANYTHING* about the output format is guaranteed to
+ remain in the future.
+ */
+int
+main(int argc, char **argv)
+{
+#define N_EVENTS 13
+ int i;
+ struct event *ev[N_EVENTS];
+ evutil_socket_t pair1[2];
+ evutil_socket_t pair2[2];
+ struct timeval tv_onesec = {1,0};
+ struct timeval tv_two5sec = {2,500*1000};
+ const struct timeval *tv_onesec_common;
+ const struct timeval *tv_two5sec_common;
+ struct event_base *base;
+ struct timeval now;
+
+#ifdef _WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+#ifdef _WIN32
+#define LOCAL_SOCKETPAIR_AF AF_INET
+#else
+#define LOCAL_SOCKETPAIR_AF AF_UNIX
+#endif
+
+ if (evutil_make_internal_pipe_(pair1) < 0 ||
+ evutil_make_internal_pipe_(pair2) < 0) {
+ sock_perror("evutil_make_internal_pipe_");
+ return 1;
+ }
+
+ if (!(base = event_base_new())) {
+ fprintf(stderr,"Couldn't make event_base\n");
+ return 2;
+ }
+
+ tv_onesec_common = event_base_init_common_timeout(base, &tv_onesec);
+ tv_two5sec_common = event_base_init_common_timeout(base, &tv_two5sec);
+
+ ev[0] = event_new(base, pair1[0], EV_WRITE, callback1, NULL);
+ ev[1] = event_new(base, pair1[1], EV_READ|EV_PERSIST, callback1, NULL);
+ ev[2] = event_new(base, pair2[0], EV_WRITE|EV_PERSIST, callback2, NULL);
+ ev[3] = event_new(base, pair2[1], EV_READ, callback2, NULL);
+
+ /* For timers */
+ ev[4] = evtimer_new(base, callback1, NULL);
+ ev[5] = evtimer_new(base, callback1, NULL);
+ ev[6] = evtimer_new(base, callback1, NULL);
+ ev[7] = event_new(base, -1, EV_PERSIST, callback2, NULL);
+ ev[8] = event_new(base, -1, EV_PERSIST, callback2, NULL);
+ ev[9] = event_new(base, -1, EV_PERSIST, callback2, NULL);
+
+ /* To activate */
+ ev[10] = event_new(base, -1, 0, callback1, NULL);
+ ev[11] = event_new(base, -1, 0, callback2, NULL);
+
+ /* Signals */
+ ev[12] = evsignal_new(base, SIGINT, callback2, NULL);
+
+ event_add(ev[0], NULL);
+ event_add(ev[1], &tv_onesec);
+ event_add(ev[2], tv_onesec_common);
+ event_add(ev[3], tv_two5sec_common);
+
+ event_add(ev[4], tv_onesec_common);
+ event_add(ev[5], tv_onesec_common);
+ event_add(ev[6], &tv_onesec);
+ event_add(ev[7], tv_two5sec_common);
+ event_add(ev[8], tv_onesec_common);
+ event_add(ev[9], &tv_two5sec);
+
+ event_active(ev[10], EV_READ, 1);
+ event_active(ev[11], EV_READ|EV_WRITE|EV_TIMEOUT, 1);
+ event_active(ev[1], EV_READ, 1);
+
+ event_add(ev[12], NULL);
+
+ evutil_gettimeofday(&now,NULL);
+ puts("=====expected");
+ printf("Now= %ld.%06d\n",(long)now.tv_sec,(int)now.tv_usec);
+ puts("Inserted:");
+ printf(" %p [fd %ld] Write\n",ev[0],(long)pair1[0]);
+ printf(" %p [fd %ld] Read Persist Timeout=T+1\n",ev[1],(long)pair1[1]);
+ printf(" %p [fd %ld] Write Persist Timeout=T+1\n",ev[2],(long)pair2[0]);
+ printf(" %p [fd %ld] Read Timeout=T+2.5\n",ev[3],(long)pair2[1]);
+ printf(" %p [fd -1] Timeout=T+1\n",ev[4]);
+ printf(" %p [fd -1] Timeout=T+1\n",ev[5]);
+ printf(" %p [fd -1] Timeout=T+1\n",ev[6]);
+ printf(" %p [fd -1] Persist Timeout=T+2.5\n",ev[7]);
+ printf(" %p [fd -1] Persist Timeout=T+1\n",ev[8]);
+ printf(" %p [fd -1] Persist Timeout=T+2.5\n",ev[9]);
+ printf(" %p [sig %d] Signal Persist\n", ev[12], (int)SIGINT);
+
+ puts("Active:");
+ printf(" %p [fd -1, priority=0] Read active\n", ev[10]);
+ printf(" %p [fd -1, priority=0] Read Write Timeout active\n", ev[11]);
+ printf(" %p [fd %ld, priority=0] Read active\n", ev[1], (long)pair1[1]);
+
+ puts("======received");
+ event_base_dump_events(base, stdout);
+
+ for (i = 0; i < N_EVENTS; ++i) {
+ event_free(ev[i]);
+ }
+ event_base_free(base);
+
+ return 0;
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-eof.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-eof.c
new file mode 100644
index 000000000..284ead78a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-eof.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "../util-internal.h"
+#include "event2/event-config.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event.h>
+#include <evutil.h>
+
+int test_okay = 1;
+int called = 0;
+struct timeval timeout = {60, 0};
+
+static void
+read_cb(evutil_socket_t fd, short event, void *arg)
+{
+ char buf[256];
+ int len;
+
+ if (EV_TIMEOUT & event) {
+ printf("%s: Timeout!\n", __func__);
+ exit(1);
+ }
+
+ len = recv(fd, buf, sizeof(buf), 0);
+
+ printf("%s: read %d%s\n", __func__,
+ len, len ? "" : " - means EOF");
+
+ if (len) {
+ if (!called)
+ event_add(arg, &timeout);
+ } else if (called == 1)
+ test_okay = 0;
+
+ called++;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct event ev;
+ const char *test = "test string";
+ evutil_socket_t pair[2];
+
+#ifdef _WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ (void) WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+ return (1);
+
+
+ if (send(pair[0], test, (int)strlen(test)+1, 0) < 0)
+ return (1);
+ shutdown(pair[0], EVUTIL_SHUT_WR);
+
+ /* Initalize the event library */
+ event_init();
+
+ /* Initalize one event */
+ event_set(&ev, pair[1], EV_READ | EV_TIMEOUT, read_cb, &ev);
+
+ event_add(&ev, &timeout);
+
+ event_dispatch();
+
+ return (test_okay);
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-fdleak.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-fdleak.c
new file mode 100644
index 000000000..4c4eba25e
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-fdleak.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2012 Ross Lagerwall <rosslagerwall@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef EVENT__HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+#ifdef EVENT__HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include "event2/event.h"
+#include "event2/bufferevent.h"
+#include "event2/buffer.h"
+#include "event2/listener.h"
+
+/* Number of requests to make. Setting this too high might result in the machine
+ running out of ephemeral ports */
+#ifdef _WIN32
+#define MAX_REQUESTS 1000
+#else
+#define MAX_REQUESTS 4000
+#endif
+
+/* Provide storage for the address, both for the server & the clients */
+static struct sockaddr_in saddr;
+
+/* Number of sucessful requests so far */
+static int num_requests;
+
+static void start_client(struct event_base *base);
+
+static void
+my_perror(const char *s)
+{
+ fprintf(stderr, "%s: %s",
+ s, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
+}
+
+/*
+===============================================
+Server functions
+===============================================
+*/
+
+/* Read a byte from the client and write it back */
+static void
+server_read_cb(struct bufferevent *bev, void *ctx)
+{
+ while (evbuffer_get_length(bufferevent_get_input(bev))) {
+ unsigned char tmp;
+ bufferevent_read(bev, &tmp, 1);
+ bufferevent_write(bev, &tmp, 1);
+ }
+}
+
+/* Wait for an EOF and then free the bufferevent */
+static void
+server_event_cb(struct bufferevent *bev, short events, void *ctx)
+{
+ if (events & BEV_EVENT_ERROR) {
+ my_perror("Error from bufferevent");
+ exit(1);
+ } else if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
+ bufferevent_free(bev);
+ }
+}
+
+/* Accept a client socket and set it up to for reading & writing */
+static void
+listener_accept_cb(struct evconnlistener *listener, evutil_socket_t sock,
+ struct sockaddr *addr, int len, void *ptr)
+{
+ struct event_base *base = evconnlistener_get_base(listener);
+ struct bufferevent *bev = bufferevent_socket_new(base, sock,
+ BEV_OPT_CLOSE_ON_FREE);
+
+ bufferevent_setcb(bev, server_read_cb, NULL, server_event_cb, NULL);
+ bufferevent_enable(bev, EV_READ|EV_WRITE);
+}
+
+/* Start the server listening on a random port and start the first client. */
+static void
+start_loop(void)
+{
+ struct event_base *base;
+ struct evconnlistener *listener;
+ struct sockaddr_storage ss;
+ ev_socklen_t socklen = sizeof(ss);
+ evutil_socket_t fd;
+
+ base = event_base_new();
+ if (base == NULL) {
+ puts("Could not open event base!");
+ exit(1);
+ }
+
+ listener = evconnlistener_new_bind(base, listener_accept_cb, NULL,
+ LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
+ -1, (struct sockaddr *)&saddr, sizeof(saddr));
+ if (listener == NULL) {
+ my_perror("Could not create listener!");
+ exit(1);
+ }
+ fd = evconnlistener_get_fd(listener);
+ if (fd < 0) {
+ puts("Couldn't get fd from listener");
+ exit(1);
+ }
+ if (getsockname(fd, (struct sockaddr *)&ss, &socklen) < 0) {
+ my_perror("getsockname()");
+ exit(1);
+ }
+ memcpy(&saddr, &ss, sizeof(saddr));
+ if (saddr.sin_family != AF_INET) {
+ puts("AF mismatch from getsockname().");
+ exit(1);
+ }
+
+ start_client(base);
+
+ event_base_dispatch(base);
+}
+
+/*
+===============================================
+Client functions
+===============================================
+*/
+
+/* Check that the server sends back the same byte that the client sent.
+ If MAX_REQUESTS have been reached, exit. Otherwise, start another client. */
+static void
+client_read_cb(struct bufferevent *bev, void *ctx)
+{
+ unsigned char tmp;
+ struct event_base *base = bufferevent_get_base(bev);
+
+ bufferevent_read(bev, &tmp, 1);
+ if (tmp != 'A') {
+ puts("Incorrect data received!");
+ exit(2);
+ }
+ bufferevent_free(bev);
+
+ num_requests++;
+ if (num_requests == MAX_REQUESTS) {
+ event_base_loopbreak(base);
+ } else {
+ start_client(base);
+ }
+}
+
+/* Send a byte to the server. */
+static void
+client_event_cb(struct bufferevent *bev, short events, void *ctx)
+{
+ if (events & BEV_EVENT_CONNECTED) {
+ unsigned char tmp = 'A';
+ bufferevent_write(bev, &tmp, 1);
+ } else if (events & BEV_EVENT_ERROR) {
+ puts("Client socket got error!");
+ exit(2);
+ }
+
+ bufferevent_enable(bev, EV_READ);
+}
+
+/* Open a client socket to connect to localhost on sin */
+static void
+start_client(struct event_base *base)
+{
+ struct bufferevent *bev = bufferevent_socket_new(base, -1,
+ BEV_OPT_CLOSE_ON_FREE);
+ bufferevent_setcb(bev, client_read_cb, NULL, client_event_cb, NULL);
+
+ if (bufferevent_socket_connect(bev, (struct sockaddr *)&saddr,
+ sizeof(saddr)) < 0) {
+ my_perror("Could not connect!");
+ bufferevent_free(bev);
+ exit(2);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+#ifdef EVENT__HAVE_SETRLIMIT
+ /* Set the fd limit to a low value so that any fd leak is caught without
+ making many requests. */
+ struct rlimit rl;
+ rl.rlim_cur = rl.rlim_max = 20;
+ if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
+ my_perror("setrlimit");
+ exit(3);
+ }
+#endif
+
+#ifdef _WIN32
+ WSADATA WSAData;
+ WSAStartup(0x101, &WSAData);
+#endif
+
+ /* Set up an address, used by both client & server. */
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = htonl(0x7f000001);
+ saddr.sin_port = 0; /* Tell the implementation to pick a port. */
+
+ start_loop();
+
+ return 0;
+}
+
+/* XXX why does this test cause so much latency sometimes (OSX 10.5)? */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-init.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-init.c
new file mode 100644
index 000000000..92fbc6b14
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-init.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <event.h>
+
+int
+main(int argc, char **argv)
+{
+#ifdef _WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ (void) WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+ /* Initalize the event library */
+ event_init();
+
+ return (0);
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-ratelim.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-ratelim.c
new file mode 100644
index 000000000..9ee989bd8
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-ratelim.c
@@ -0,0 +1,603 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "../util-internal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
+#endif
+#include <signal.h>
+
+#include "event2/bufferevent.h"
+#include "event2/buffer.h"
+#include "event2/event.h"
+#include "event2/util.h"
+#include "event2/listener.h"
+#include "event2/thread.h"
+
+static struct evutil_weakrand_state weakrand_state;
+
+static int cfg_verbose = 0;
+static int cfg_help = 0;
+
+static int cfg_n_connections = 30;
+static int cfg_duration = 5;
+static int cfg_connlimit = 0;
+static int cfg_grouplimit = 0;
+static int cfg_tick_msec = 1000;
+static int cfg_min_share = -1;
+static int cfg_group_drain = 0;
+
+static int cfg_connlimit_tolerance = -1;
+static int cfg_grouplimit_tolerance = -1;
+static int cfg_stddev_tolerance = -1;
+
+#ifdef _WIN32
+static int cfg_enable_iocp = 0;
+#endif
+
+static struct timeval cfg_tick = { 0, 500*1000 };
+
+static struct ev_token_bucket_cfg *conn_bucket_cfg = NULL;
+static struct ev_token_bucket_cfg *group_bucket_cfg = NULL;
+struct bufferevent_rate_limit_group *ratelim_group = NULL;
+static double seconds_per_tick = 0.0;
+
+struct client_state {
+ size_t queued;
+ ev_uint64_t received;
+
+};
+static const struct timeval *ms100_common=NULL;
+
+/* info from check_bucket_levels_cb */
+static int total_n_bev_checks = 0;
+static ev_int64_t total_rbucket_level=0;
+static ev_int64_t total_wbucket_level=0;
+static ev_int64_t total_max_to_read=0;
+static ev_int64_t total_max_to_write=0;
+static ev_int64_t max_bucket_level=EV_INT64_MIN;
+static ev_int64_t min_bucket_level=EV_INT64_MAX;
+
+/* from check_group_bucket_levels_cb */
+static int total_n_group_bev_checks = 0;
+static ev_int64_t total_group_rbucket_level = 0;
+static ev_int64_t total_group_wbucket_level = 0;
+
+static int n_echo_conns_open = 0;
+
+/* Info on the open connections */
+struct bufferevent **bevs;
+struct client_state *states;
+struct bufferevent_rate_limit_group *group = NULL;
+
+static void check_bucket_levels_cb(evutil_socket_t fd, short events, void *arg);
+
+static void
+loud_writecb(struct bufferevent *bev, void *ctx)
+{
+ struct client_state *cs = ctx;
+ struct evbuffer *output = bufferevent_get_output(bev);
+ char buf[1024];
+ int r = evutil_weakrand_(&weakrand_state);
+ memset(buf, r, sizeof(buf));
+ while (evbuffer_get_length(output) < 8192) {
+ evbuffer_add(output, buf, sizeof(buf));
+ cs->queued += sizeof(buf);
+ }
+}
+
+static void
+discard_readcb(struct bufferevent *bev, void *ctx)
+{
+ struct client_state *cs = ctx;
+ struct evbuffer *input = bufferevent_get_input(bev);
+ size_t len = evbuffer_get_length(input);
+ evbuffer_drain(input, len);
+ cs->received += len;
+}
+
+static void
+write_on_connectedcb(struct bufferevent *bev, short what, void *ctx)
+{
+ if (what & BEV_EVENT_CONNECTED) {
+ loud_writecb(bev, ctx);
+ /* XXXX this shouldn't be needed. */
+ bufferevent_enable(bev, EV_READ|EV_WRITE);
+ }
+}
+
+static void
+echo_readcb(struct bufferevent *bev, void *ctx)
+{
+ struct evbuffer *input = bufferevent_get_input(bev);
+ struct evbuffer *output = bufferevent_get_output(bev);
+
+ evbuffer_add_buffer(output, input);
+ if (evbuffer_get_length(output) > 1024000)
+ bufferevent_disable(bev, EV_READ);
+}
+
+static void
+echo_writecb(struct bufferevent *bev, void *ctx)
+{
+ struct evbuffer *output = bufferevent_get_output(bev);
+ if (evbuffer_get_length(output) < 512000)
+ bufferevent_enable(bev, EV_READ);
+}
+
+static void
+echo_eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+ if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
+ --n_echo_conns_open;
+ bufferevent_free(bev);
+ }
+}
+
+static void
+echo_listenercb(struct evconnlistener *listener, evutil_socket_t newsock,
+ struct sockaddr *sourceaddr, int socklen, void *ctx)
+{
+ struct event_base *base = ctx;
+ int flags = BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE;
+ struct bufferevent *bev;
+
+ bev = bufferevent_socket_new(base, newsock, flags);
+ bufferevent_setcb(bev, echo_readcb, echo_writecb, echo_eventcb, NULL);
+ if (conn_bucket_cfg) {
+ struct event *check_event =
+ event_new(base, -1, EV_PERSIST, check_bucket_levels_cb, bev);
+ bufferevent_set_rate_limit(bev, conn_bucket_cfg);
+
+ assert(bufferevent_get_token_bucket_cfg(bev) != NULL);
+ event_add(check_event, ms100_common);
+ }
+ if (ratelim_group)
+ bufferevent_add_to_rate_limit_group(bev, ratelim_group);
+ ++n_echo_conns_open;
+ bufferevent_enable(bev, EV_READ|EV_WRITE);
+}
+
+/* Called periodically to check up on how full the buckets are */
+static void
+check_bucket_levels_cb(evutil_socket_t fd, short events, void *arg)
+{
+ struct bufferevent *bev = arg;
+
+ ev_ssize_t r = bufferevent_get_read_limit(bev);
+ ev_ssize_t w = bufferevent_get_write_limit(bev);
+ ev_ssize_t rm = bufferevent_get_max_to_read(bev);
+ ev_ssize_t wm = bufferevent_get_max_to_write(bev);
+ /* XXXX check that no value is above the cofigured burst
+ * limit */
+ total_rbucket_level += r;
+ total_wbucket_level += w;
+ total_max_to_read += rm;
+ total_max_to_write += wm;
+#define B(x) \
+ if ((x) > max_bucket_level) \
+ max_bucket_level = (x); \
+ if ((x) < min_bucket_level) \
+ min_bucket_level = (x)
+ B(r);
+ B(w);
+#undef B
+
+ total_n_bev_checks++;
+ if (total_n_bev_checks >= .8 * ((double)cfg_duration / cfg_tick_msec) * cfg_n_connections) {
+ event_free(event_base_get_running_event(bufferevent_get_base(bev)));
+ }
+}
+
+static void
+check_group_bucket_levels_cb(evutil_socket_t fd, short events, void *arg)
+{
+ if (ratelim_group) {
+ ev_ssize_t r = bufferevent_rate_limit_group_get_read_limit(ratelim_group);
+ ev_ssize_t w = bufferevent_rate_limit_group_get_write_limit(ratelim_group);
+ total_group_rbucket_level += r;
+ total_group_wbucket_level += w;
+ }
+ ++total_n_group_bev_checks;
+}
+
+static void
+group_drain_cb(evutil_socket_t fd, short events, void *arg)
+{
+ bufferevent_rate_limit_group_decrement_read(ratelim_group, cfg_group_drain);
+ bufferevent_rate_limit_group_decrement_write(ratelim_group, cfg_group_drain);
+}
+
+static int
+test_ratelimiting(void)
+{
+ struct event_base *base;
+ struct sockaddr_in sin;
+ struct evconnlistener *listener;
+
+ struct sockaddr_storage ss;
+ ev_socklen_t slen;
+
+ int i;
+
+ struct timeval tv;
+
+ ev_uint64_t total_received;
+ double total_sq_persec, total_persec;
+ double variance;
+ double expected_total_persec = -1.0, expected_avg_persec = -1.0;
+ int ok = 1;
+ struct event_config *base_cfg;
+ struct event *periodic_level_check;
+ struct event *group_drain_event=NULL;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+ sin.sin_port = 0; /* unspecified port */
+
+ if (0)
+ event_enable_debug_mode();
+
+ base_cfg = event_config_new();
+
+#ifdef _WIN32
+ if (cfg_enable_iocp) {
+#ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
+ evthread_use_windows_threads();
+#endif
+ event_config_set_flag(base_cfg, EVENT_BASE_FLAG_STARTUP_IOCP);
+ }
+#endif
+
+ base = event_base_new_with_config(base_cfg);
+ event_config_free(base_cfg);
+ if (! base) {
+ fprintf(stderr, "Couldn't create event_base");
+ return 1;
+ }
+
+ listener = evconnlistener_new_bind(base, echo_listenercb, base,
+ LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,
+ (struct sockaddr *)&sin, sizeof(sin));
+ if (! listener) {
+ fprintf(stderr, "Couldn't create listener");
+ return 1;
+ }
+
+ slen = sizeof(ss);
+ if (getsockname(evconnlistener_get_fd(listener), (struct sockaddr *)&ss,
+ &slen) < 0) {
+ perror("getsockname");
+ return 1;
+ }
+
+ if (cfg_connlimit > 0) {
+ conn_bucket_cfg = ev_token_bucket_cfg_new(
+ cfg_connlimit, cfg_connlimit * 4,
+ cfg_connlimit, cfg_connlimit * 4,
+ &cfg_tick);
+ assert(conn_bucket_cfg);
+ }
+
+ if (cfg_grouplimit > 0) {
+ group_bucket_cfg = ev_token_bucket_cfg_new(
+ cfg_grouplimit, cfg_grouplimit * 4,
+ cfg_grouplimit, cfg_grouplimit * 4,
+ &cfg_tick);
+ group = ratelim_group = bufferevent_rate_limit_group_new(
+ base, group_bucket_cfg);
+ expected_total_persec = cfg_grouplimit - (cfg_group_drain / seconds_per_tick);
+ expected_avg_persec = cfg_grouplimit / cfg_n_connections;
+ if (cfg_connlimit > 0 && expected_avg_persec > cfg_connlimit)
+ expected_avg_persec = cfg_connlimit;
+ if (cfg_min_share >= 0)
+ bufferevent_rate_limit_group_set_min_share(
+ ratelim_group, cfg_min_share);
+ }
+
+ if (expected_avg_persec < 0 && cfg_connlimit > 0)
+ expected_avg_persec = cfg_connlimit;
+
+ if (expected_avg_persec > 0)
+ expected_avg_persec /= seconds_per_tick;
+ if (expected_total_persec > 0)
+ expected_total_persec /= seconds_per_tick;
+
+ bevs = calloc(cfg_n_connections, sizeof(struct bufferevent *));
+ states = calloc(cfg_n_connections, sizeof(struct client_state));
+
+ for (i = 0; i < cfg_n_connections; ++i) {
+ bevs[i] = bufferevent_socket_new(base, -1,
+ BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE);
+ assert(bevs[i]);
+ bufferevent_setcb(bevs[i], discard_readcb, loud_writecb,
+ write_on_connectedcb, &states[i]);
+ bufferevent_enable(bevs[i], EV_READ|EV_WRITE);
+ bufferevent_socket_connect(bevs[i], (struct sockaddr *)&ss,
+ slen);
+ }
+
+ tv.tv_sec = cfg_duration - 1;
+ tv.tv_usec = 995000;
+
+ event_base_loopexit(base, &tv);
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 100*1000;
+ ms100_common = event_base_init_common_timeout(base, &tv);
+
+ periodic_level_check = event_new(base, -1, EV_PERSIST, check_group_bucket_levels_cb, NULL);
+ event_add(periodic_level_check, ms100_common);
+
+ if (cfg_group_drain && ratelim_group) {
+ group_drain_event = event_new(base, -1, EV_PERSIST, group_drain_cb, NULL);
+ event_add(group_drain_event, &cfg_tick);
+ }
+
+ event_base_dispatch(base);
+
+ ratelim_group = NULL; /* So no more responders get added */
+ event_free(periodic_level_check);
+ if (group_drain_event)
+ event_del(group_drain_event);
+
+ for (i = 0; i < cfg_n_connections; ++i) {
+ bufferevent_free(bevs[i]);
+ }
+ evconnlistener_free(listener);
+
+ /* Make sure no new echo_conns get added to the group. */
+ ratelim_group = NULL;
+
+ /* This should get _everybody_ freed */
+ while (n_echo_conns_open) {
+ printf("waiting for %d conns\n", n_echo_conns_open);
+ tv.tv_sec = 0;
+ tv.tv_usec = 300000;
+ event_base_loopexit(base, &tv);
+ event_base_dispatch(base);
+ }
+
+ if (group)
+ bufferevent_rate_limit_group_free(group);
+
+ if (total_n_bev_checks) {
+ printf("Average read bucket level: %f\n",
+ (double)total_rbucket_level/total_n_bev_checks);
+ printf("Average write bucket level: %f\n",
+ (double)total_wbucket_level/total_n_bev_checks);
+ printf("Highest read bucket level: %f\n",
+ (double)max_bucket_level);
+ printf("Highest write bucket level: %f\n",
+ (double)min_bucket_level);
+ printf("Average max-to-read: %f\n",
+ ((double)total_max_to_read)/total_n_bev_checks);
+ printf("Average max-to-write: %f\n",
+ ((double)total_max_to_write)/total_n_bev_checks);
+ }
+ if (total_n_group_bev_checks) {
+ printf("Average group read bucket level: %f\n",
+ ((double)total_group_rbucket_level)/total_n_group_bev_checks);
+ printf("Average group write bucket level: %f\n",
+ ((double)total_group_wbucket_level)/total_n_group_bev_checks);
+ }
+
+ total_received = 0;
+ total_persec = 0.0;
+ total_sq_persec = 0.0;
+ for (i=0; i < cfg_n_connections; ++i) {
+ double persec = states[i].received;
+ persec /= cfg_duration;
+ total_received += states[i].received;
+ total_persec += persec;
+ total_sq_persec += persec*persec;
+ printf("%d: %f per second\n", i+1, persec);
+ }
+ printf(" total: %f per second\n",
+ ((double)total_received)/cfg_duration);
+ if (expected_total_persec > 0) {
+ double diff = expected_total_persec -
+ ((double)total_received/cfg_duration);
+ printf(" [Off by %lf]\n", diff);
+ if (cfg_grouplimit_tolerance > 0 &&
+ fabs(diff) > cfg_grouplimit_tolerance) {
+ fprintf(stderr, "Group bandwidth out of bounds\n");
+ ok = 0;
+ }
+ }
+
+ printf(" average: %f per second\n",
+ (((double)total_received)/cfg_duration)/cfg_n_connections);
+ if (expected_avg_persec > 0) {
+ double diff = expected_avg_persec - (((double)total_received)/cfg_duration)/cfg_n_connections;
+ printf(" [Off by %lf]\n", diff);
+ if (cfg_connlimit_tolerance > 0 &&
+ fabs(diff) > cfg_connlimit_tolerance) {
+ fprintf(stderr, "Connection bandwidth out of bounds\n");
+ ok = 0;
+ }
+ }
+
+ variance = total_sq_persec/cfg_n_connections - total_persec*total_persec/(cfg_n_connections*cfg_n_connections);
+
+ printf(" stddev: %f per second\n", sqrt(variance));
+ if (cfg_stddev_tolerance > 0 &&
+ sqrt(variance) > cfg_stddev_tolerance) {
+ fprintf(stderr, "Connection variance out of bounds\n");
+ ok = 0;
+ }
+
+ event_base_free(base);
+ free(bevs);
+ free(states);
+
+ return ok ? 0 : 1;
+}
+
+static struct option {
+ const char *name; int *ptr; int min; int isbool;
+} options[] = {
+ { "-v", &cfg_verbose, 0, 1 },
+ { "-h", &cfg_help, 0, 1 },
+ { "-n", &cfg_n_connections, 1, 0 },
+ { "-d", &cfg_duration, 1, 0 },
+ { "-c", &cfg_connlimit, 0, 0 },
+ { "-g", &cfg_grouplimit, 0, 0 },
+ { "-G", &cfg_group_drain, -100000, 0 },
+ { "-t", &cfg_tick_msec, 10, 0 },
+ { "--min-share", &cfg_min_share, 0, 0 },
+ { "--check-connlimit", &cfg_connlimit_tolerance, 0, 0 },
+ { "--check-grouplimit", &cfg_grouplimit_tolerance, 0, 0 },
+ { "--check-stddev", &cfg_stddev_tolerance, 0, 0 },
+#ifdef _WIN32
+ { "--iocp", &cfg_enable_iocp, 0, 1 },
+#endif
+ { NULL, NULL, -1, 0 },
+};
+
+static int
+handle_option(int argc, char **argv, int *i, const struct option *opt)
+{
+ long val;
+ char *endptr = NULL;
+ if (opt->isbool) {
+ *opt->ptr = 1;
+ return 0;
+ }
+ if (*i + 1 == argc) {
+ fprintf(stderr, "Too few arguments to '%s'\n",argv[*i]);
+ return -1;
+ }
+ val = strtol(argv[*i+1], &endptr, 10);
+ if (*argv[*i+1] == '\0' || !endptr || *endptr != '\0') {
+ fprintf(stderr, "Couldn't parse numeric value '%s'\n",
+ argv[*i+1]);
+ return -1;
+ }
+ if (val < opt->min || val > 0x7fffffff) {
+ fprintf(stderr, "Value '%s' is out-of-range'\n",
+ argv[*i+1]);
+ return -1;
+ }
+ *opt->ptr = (int)val;
+ ++*i;
+ return 0;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+"test-ratelim [-v] [-n INT] [-d INT] [-c INT] [-g INT] [-t INT]\n\n"
+"Pushes bytes through a number of possibly rate-limited connections, and\n"
+"displays average throughput.\n\n"
+" -n INT: Number of connections to open (default: 30)\n"
+" -d INT: Duration of the test in seconds (default: 5 sec)\n");
+ fprintf(stderr,
+" -c INT: Connection-rate limit applied to each connection in bytes per second\n"
+" (default: None.)\n"
+" -g INT: Group-rate limit applied to sum of all usage in bytes per second\n"
+" (default: None.)\n"
+" -G INT: drain INT bytes from the group limit every tick. (default: 0)\n"
+" -t INT: Granularity of timing, in milliseconds (default: 1000 msec)\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ int i,j;
+ double ratio;
+
+#ifdef _WIN32
+ WORD wVersionRequested = MAKEWORD(2,2);
+ WSADATA wsaData;
+
+ (void) WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+ evutil_weakrand_seed_(&weakrand_state, 0);
+
+#ifndef _WIN32
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+ return 1;
+#endif
+ for (i = 1; i < argc; ++i) {
+ for (j = 0; options[j].name; ++j) {
+ if (!strcmp(argv[i],options[j].name)) {
+ if (handle_option(argc,argv,&i,&options[j])<0)
+ return 1;
+ goto again;
+ }
+ }
+ fprintf(stderr, "Unknown option '%s'\n", argv[i]);
+ usage();
+ return 1;
+ again:
+ ;
+ }
+ if (cfg_help) {
+ usage();
+ return 0;
+ }
+
+ cfg_tick.tv_sec = cfg_tick_msec / 1000;
+ cfg_tick.tv_usec = (cfg_tick_msec % 1000)*1000;
+
+ seconds_per_tick = ratio = cfg_tick_msec / 1000.0;
+
+ cfg_connlimit *= ratio;
+ cfg_grouplimit *= ratio;
+
+ {
+ struct timeval tv;
+ evutil_gettimeofday(&tv, NULL);
+#ifdef _WIN32
+ srand(tv.tv_usec);
+#else
+ srandom(tv.tv_usec);
+#endif
+ }
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ evthread_enable_lock_debugging();
+#endif
+
+ return test_ratelimiting();
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-ratelim.sh b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-ratelim.sh
new file mode 100755
index 000000000..b5e0ca62a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-ratelim.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+
+FAILED=no
+
+if test "x$TEST_OUTPUT_FILE" = "x"
+then
+ TEST_OUTPUT_FILE=/dev/null
+fi
+
+# /bin/echo is a little more likely to support -n than sh's builtin echo.
+if test -x /bin/echo
+then
+ ECHO=/bin/echo
+else
+ ECHO=echo
+fi
+
+if test "$TEST_OUTPUT_FILE" != "/dev/null"
+then
+ touch "$TEST_OUTPUT_FILE" || exit 1
+fi
+
+TEST_DIR=.
+
+T=`echo "$0" | sed -e 's/test-ratelim.sh$//'`
+if test -x "$T/test-ratelim"
+then
+ TEST_DIR="$T"
+fi
+
+announce () {
+ echo $@
+ echo $@ >>"$TEST_OUTPUT_FILE"
+}
+
+announce_n () {
+ $ECHO -n $@
+ echo $@ >>"$TEST_OUTPUT_FILE"
+}
+
+
+run_tests () {
+ announce_n " Group limits, no connection limit:"
+ if $TEST_DIR/test-ratelim -g 30000 -n 30 -t 100 --check-grouplimit 1000 --check-stddev 100 >>"$TEST_OUTPUT_FILE"
+ then
+ announce OKAY
+ else
+ announce FAILED
+ FAILED=yes
+ fi
+
+ announce_n " Connection limit, no group limit:"
+ if $TEST_DIR/test-ratelim -c 1000 -n 30 -t 100 --check-connlimit 50 --check-stddev 50 >>"$TEST_OUTPUT_FILE"
+ then
+ announce OKAY ;
+ else
+ announce FAILED ;
+ FAILED=yes
+ fi
+
+ announce_n " Connection limit and group limit:"
+ if $TEST_DIR/test-ratelim -c 1000 -g 30000 -n 30 -t 100 --check-grouplimit 1000 --check-connlimit 50 --check-stddev 50 >>"$TEST_OUTPUT_FILE"
+ then
+ announce OKAY ;
+ else
+ announce FAILED ;
+ FAILED=yes
+ fi
+
+ announce_n " Connection limit and group limit with independent drain:"
+ if $TEST_DIR/test-ratelim -c 1000 -g 35000 -n 30 -t 100 -G 500 --check-grouplimit 1000 --check-connlimit 50 --check-stddev 50 >>"$TEST_OUTPUT_FILE"
+ then
+ announce OKAY ;
+ else
+ announce FAILED ;
+ FAILED=yes
+ fi
+
+
+}
+
+announce "Running rate-limiting tests:"
+
+run_tests
+
+if test "$FAILED" = "yes"; then
+ exit 1
+fi
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-time.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-time.c
new file mode 100644
index 000000000..c4d031e72
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-time.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "util-internal.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+#include <errno.h>
+
+#include "event2/event.h"
+#include "event2/event_compat.h"
+#include "event2/event_struct.h"
+
+int called = 0;
+
+#define NEVENT 20000
+
+struct event *ev[NEVENT];
+
+struct evutil_weakrand_state weakrand_state;
+
+static int
+rand_int(int n)
+{
+ return evutil_weakrand_(&weakrand_state) % n;
+}
+
+static void
+time_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct timeval tv;
+ int i, j;
+
+ called++;
+
+ if (called < 10*NEVENT) {
+ for (i = 0; i < 10; i++) {
+ j = rand_int(NEVENT);
+ tv.tv_sec = 0;
+ tv.tv_usec = rand_int(50000);
+ if (tv.tv_usec % 2 || called < NEVENT)
+ evtimer_add(ev[j], &tv);
+ else
+ evtimer_del(ev[j]);
+ }
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ struct timeval tv;
+ int i;
+#ifdef _WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ (void) WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+ evutil_weakrand_seed_(&weakrand_state, 0);
+
+ /* Initalize the event library */
+ event_init();
+
+ for (i = 0; i < NEVENT; i++) {
+ ev[i] = malloc(sizeof(struct event));
+
+ /* Initalize one event */
+ evtimer_set(ev[i], time_cb, ev[i]);
+ tv.tv_sec = 0;
+ tv.tv_usec = rand_int(50000);
+ evtimer_add(ev[i], &tv);
+ }
+
+ event_dispatch();
+
+
+ printf("%d, %d\n", called, NEVENT);
+ return (called < NEVENT);
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-weof.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-weof.c
new file mode 100644
index 000000000..52c7afbd6
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test-weof.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "../util-internal.h"
+#include "event2/event-config.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/event_compat.h"
+#include "event2/util.h"
+
+evutil_socket_t pair[2];
+int test_okay = 1;
+int called = 0;
+
+static void
+write_cb(evutil_socket_t fd, short event, void *arg)
+{
+ const char *test = "test string";
+ int len;
+
+ len = send(fd, test, (int)strlen(test) + 1, 0);
+
+ printf("%s: write %d%s\n", __func__,
+ len, len ? "" : " - means EOF");
+
+ if (len > 0) {
+ if (!called)
+ event_add(arg, NULL);
+ evutil_closesocket(pair[0]);
+ } else if (called == 1)
+ test_okay = 0;
+
+ called++;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct event ev;
+
+#ifdef _WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ (void) WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+#ifndef _WIN32
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+ return (1);
+#endif
+
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+ return (1);
+
+ /* Initalize the event library */
+ event_init();
+
+ /* Initalize one event */
+ event_set(&ev, pair[1], EV_WRITE, write_cb, &ev);
+
+ event_add(&ev, NULL);
+
+ event_dispatch();
+
+ return (test_okay);
+}
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test.sh b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test.sh
new file mode 100755
index 000000000..b73c1adce
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/test.sh
@@ -0,0 +1,160 @@
+#!/bin/sh
+
+BACKENDS="EVPORT KQUEUE EPOLL DEVPOLL POLL SELECT WIN32"
+TESTS="test-eof test-closed test-weof test-time test-changelist test-fdleak"
+FAILED=no
+TEST_OUTPUT_FILE=${TEST_OUTPUT_FILE:-/dev/null}
+REGRESS_ARGS=${REGRESS_ARGS:-}
+
+# /bin/echo is a little more likely to support -n than sh's builtin echo,
+# printf is even more likely
+if test "`printf %s hello 2>&1`" = "hello"
+then
+ ECHO_N="printf %s"
+else
+ if test -x /bin/echo
+ then
+ ECHO_N="/bin/echo -n"
+ else
+ ECHO_N="echo -n"
+ fi
+fi
+
+if test "$TEST_OUTPUT_FILE" != "/dev/null"
+then
+ touch "$TEST_OUTPUT_FILE" || exit 1
+fi
+
+TEST_DIR=.
+TEST_SRC_DIR=.
+
+T=`echo "$0" | sed -e 's/test.sh$//' | sed -e 's/test-script.sh//' `
+if test -x "$T/test-init"
+then
+ TEST_DIR="$T"
+elif test -x "./test/test-init"
+then
+ TEST_DIR="./test"
+fi
+if test -f "$T/check-dumpevents.py"
+then
+ TEST_SRC_DIR="$T"
+elif test -f "./test/check-dumpevents.py"
+then
+ TEST_SRC_DIR="./test"
+fi
+
+setup () {
+ for i in $BACKENDS; do
+ eval "EVENT_NO$i=yes; export EVENT_NO$i"
+ done
+ unset EVENT_EPOLL_USE_CHANGELIST
+ unset EVENT_PRECISE_TIMER
+}
+
+announce () {
+ echo "$@"
+ echo "$@" >>"$TEST_OUTPUT_FILE"
+}
+
+announce_n () {
+ $ECHO_N "$@"
+ echo "$@" >>"$TEST_OUTPUT_FILE"
+}
+
+
+run_tests () {
+ if $TEST_DIR/test-init 2>>"$TEST_OUTPUT_FILE" ;
+ then
+ true
+ else
+ announce Skipping test
+ return
+ fi
+ for i in $TESTS; do
+ announce_n " $i: "
+ if $TEST_DIR/$i >>"$TEST_OUTPUT_FILE" ;
+ then
+ announce OKAY ;
+ else
+ announce FAILED ;
+ FAILED=yes
+ fi
+ done
+ announce_n " test-dumpevents: "
+ if python2 -c 'import sys; assert(sys.version_info >= (2, 4))' 2>/dev/null && test -f $TEST_SRC_DIR/check-dumpevents.py; then
+ if $TEST_DIR/test-dumpevents | python2 $TEST_SRC_DIR/check-dumpevents.py >> "$TEST_OUTPUT_FILE" ;
+ then
+ announce OKAY ;
+ else
+ announce FAILED ;
+ fi
+ else
+ # no python
+ if $TEST_DIR/test-dumpevents >/dev/null; then
+ announce "OKAY (output not checked)" ;
+ else
+ announce "FAILED (output not checked)" ;
+ fi
+ fi
+
+ test -x $TEST_DIR/regress || return
+ announce_n " regress: "
+ if test "$TEST_OUTPUT_FILE" = "/dev/null" ;
+ then
+ $TEST_DIR/regress --quiet $REGRESS_ARGS
+ else
+ $TEST_DIR/regress $REGRESS_ARGS >>"$TEST_OUTPUT_FILE"
+ fi
+ if test "$?" = "0" ;
+ then
+ announce OKAY ;
+ else
+ announce FAILED ;
+ FAILED=yes
+ fi
+
+ announce_n " regress_debug: "
+ if test "$TEST_OUTPUT_FILE" = "/dev/null" ;
+ then
+ EVENT_DEBUG_MODE=1 $TEST_DIR/regress --quiet $REGRESS_ARGS
+ else
+ EVENT_DEBUG_MODE=1 $TEST_DIR/regress $REGRESS_ARGS >>"$TEST_OUTPUT_FILE"
+ fi
+ if test "$?" = "0" ;
+ then
+ announce OKAY ;
+ else
+ announce FAILED ;
+ FAILED=yes
+ fi
+}
+
+do_test() {
+ setup
+ announce "$1 $2"
+ unset EVENT_NO$1
+ if test "$2" = "(changelist)" ; then
+ EVENT_EPOLL_USE_CHANGELIST=yes; export EVENT_EPOLL_USE_CHANGELIST
+ elif test "$2" = "(timerfd)" ; then
+ EVENT_PRECISE_TIMER=1; export EVENT_PRECISE_TIMER
+ elif test "$2" = "(timerfd+changelist)" ; then
+ EVENT_EPOLL_USE_CHANGELIST=yes; export EVENT_EPOLL_USE_CHANGELIST
+ EVENT_PRECISE_TIMER=1; export EVENT_PRECISE_TIMER
+ fi
+
+ run_tests
+}
+
+announce "Running tests:"
+
+do_test EPOLL "(timerfd)"
+do_test EPOLL "(changelist)"
+do_test EPOLL "(timerfd+changelist)"
+for i in $BACKENDS; do
+ do_test $i
+done
+
+if test "$FAILED" = "yes"; then
+ exit 1
+fi
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest.c
new file mode 100644
index 000000000..3a8e33105
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest.c
@@ -0,0 +1,493 @@
+/* tinytest.c -- Copyright 2009-2012 Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef TINYTEST_LOCAL
+#include "tinytest_local.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifndef NO_FORKING
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif
+
+#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
+#if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
+ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
+/* Workaround for a stupid bug in OSX 10.6 */
+#define FORK_BREAKS_GCOV
+#include <vproc.h>
+#endif
+#endif
+
+#endif /* !NO_FORKING */
+
+#ifndef __GNUC__
+#define __attribute__(x)
+#endif
+
+#include "tinytest.h"
+#include "tinytest_macros.h"
+
+#define LONGEST_TEST_NAME 16384
+
+static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
+static int n_ok = 0; /**< Number of tests that have passed */
+static int n_bad = 0; /**< Number of tests that have failed. */
+static int n_skipped = 0; /**< Number of tests that have been skipped. */
+
+static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
+static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
+static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
+const char *verbosity_flag = "";
+
+const struct testlist_alias_t *cfg_aliases=NULL;
+
+enum outcome { SKIP=2, OK=1, FAIL=0 };
+static enum outcome cur_test_outcome = 0;
+const char *cur_test_prefix = NULL; /**< prefix of the current test group */
+/** Name of the current test, if we haven't logged is yet. Used for --quiet */
+const char *cur_test_name = NULL;
+
+#ifdef _WIN32
+/* Copy of argv[0] for win32. */
+static char commandname[MAX_PATH+1];
+#endif
+
+static void usage(struct testgroup_t *groups, int list_groups)
+ __attribute__((noreturn));
+static int process_test_option(struct testgroup_t *groups, const char *test);
+
+static enum outcome
+testcase_run_bare_(const struct testcase_t *testcase)
+{
+ void *env = NULL;
+ int outcome;
+ if (testcase->setup) {
+ env = testcase->setup->setup_fn(testcase);
+ if (!env)
+ return FAIL;
+ else if (env == (void*)TT_SKIP)
+ return SKIP;
+ }
+
+ cur_test_outcome = OK;
+ testcase->fn(env);
+ outcome = cur_test_outcome;
+
+ if (testcase->setup) {
+ if (testcase->setup->cleanup_fn(testcase, env) == 0)
+ outcome = FAIL;
+ }
+
+ return outcome;
+}
+
+#define MAGIC_EXITCODE 42
+
+#ifndef NO_FORKING
+
+static enum outcome
+testcase_run_forked_(const struct testgroup_t *group,
+ const struct testcase_t *testcase)
+{
+#ifdef _WIN32
+ /* Fork? On Win32? How primitive! We'll do what the smart kids do:
+ we'll invoke our own exe (whose name we recall from the command
+ line) with a command line that tells it to run just the test we
+ want, and this time without forking.
+
+ (No, threads aren't an option. The whole point of forking is to
+ share no state between tests.)
+ */
+ int ok;
+ char buffer[LONGEST_TEST_NAME+256];
+ STARTUPINFOA si;
+ PROCESS_INFORMATION info;
+ DWORD exitcode;
+
+ if (!in_tinytest_main) {
+ printf("\nERROR. On Windows, testcase_run_forked_ must be"
+ " called from within tinytest_main.\n");
+ abort();
+ }
+ if (opt_verbosity>0)
+ printf("[forking] ");
+
+ snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
+ commandname, verbosity_flag, group->prefix, testcase->name);
+
+ memset(&si, 0, sizeof(si));
+ memset(&info, 0, sizeof(info));
+ si.cb = sizeof(si);
+
+ ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
+ 0, NULL, NULL, &si, &info);
+ if (!ok) {
+ printf("CreateProcess failed!\n");
+ return 0;
+ }
+ WaitForSingleObject(info.hProcess, INFINITE);
+ GetExitCodeProcess(info.hProcess, &exitcode);
+ CloseHandle(info.hProcess);
+ CloseHandle(info.hThread);
+ if (exitcode == 0)
+ return OK;
+ else if (exitcode == MAGIC_EXITCODE)
+ return SKIP;
+ else
+ return FAIL;
+#else
+ int outcome_pipe[2];
+ pid_t pid;
+ (void)group;
+
+ if (pipe(outcome_pipe))
+ perror("opening pipe");
+
+ if (opt_verbosity>0)
+ printf("[forking] ");
+ pid = fork();
+#ifdef FORK_BREAKS_GCOV
+ vproc_transaction_begin(0);
+#endif
+ if (!pid) {
+ /* child. */
+ int test_r, write_r;
+ char b[1];
+ close(outcome_pipe[0]);
+ test_r = testcase_run_bare_(testcase);
+ assert(0<=(int)test_r && (int)test_r<=2);
+ b[0] = "NYS"[test_r];
+ write_r = (int)write(outcome_pipe[1], b, 1);
+ if (write_r != 1) {
+ perror("write outcome to pipe");
+ exit(1);
+ }
+ exit(0);
+ return FAIL; /* unreachable */
+ } else {
+ /* parent */
+ int status, r;
+ char b[1];
+ /* Close this now, so that if the other side closes it,
+ * our read fails. */
+ close(outcome_pipe[1]);
+ r = (int)read(outcome_pipe[0], b, 1);
+ if (r == 0) {
+ printf("[Lost connection!] ");
+ return 0;
+ } else if (r != 1) {
+ perror("read outcome from pipe");
+ }
+ waitpid(pid, &status, 0);
+ close(outcome_pipe[0]);
+ return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
+ }
+#endif
+}
+
+#endif /* !NO_FORKING */
+
+int
+testcase_run_one(const struct testgroup_t *group,
+ const struct testcase_t *testcase)
+{
+ enum outcome outcome;
+
+ if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) {
+ if (opt_verbosity>0)
+ printf("%s%s: %s\n",
+ group->prefix, testcase->name,
+ (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED");
+ ++n_skipped;
+ return SKIP;
+ }
+
+ if (opt_verbosity>0 && !opt_forked) {
+ printf("%s%s: ", group->prefix, testcase->name);
+ } else {
+ if (opt_verbosity==0) printf(".");
+ cur_test_prefix = group->prefix;
+ cur_test_name = testcase->name;
+ }
+
+#ifndef NO_FORKING
+ if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
+ outcome = testcase_run_forked_(group, testcase);
+ } else {
+#else
+ {
+#endif
+ outcome = testcase_run_bare_(testcase);
+ }
+
+ if (outcome == OK) {
+ ++n_ok;
+ if (opt_verbosity>0 && !opt_forked)
+ puts(opt_verbosity==1?"OK":"");
+ } else if (outcome == SKIP) {
+ ++n_skipped;
+ if (opt_verbosity>0 && !opt_forked)
+ puts("SKIPPED");
+ } else {
+ ++n_bad;
+ if (!opt_forked)
+ printf("\n [%s FAILED]\n", testcase->name);
+ }
+
+ if (opt_forked) {
+ exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
+ return 1; /* unreachable */
+ } else {
+ return (int)outcome;
+ }
+}
+
+int
+tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag)
+{
+ int i, j;
+ size_t length = LONGEST_TEST_NAME;
+ char fullname[LONGEST_TEST_NAME];
+ int found=0;
+ if (strstr(arg, ".."))
+ length = strstr(arg,"..")-arg;
+ for (i=0; groups[i].prefix; ++i) {
+ for (j=0; groups[i].cases[j].name; ++j) {
+ struct testcase_t *testcase = &groups[i].cases[j];
+ snprintf(fullname, sizeof(fullname), "%s%s",
+ groups[i].prefix, testcase->name);
+ if (!flag) { /* Hack! */
+ printf(" %s", fullname);
+ if (testcase->flags & TT_OFF_BY_DEFAULT)
+ puts(" (Off by default)");
+ else if (testcase->flags & TT_SKIP)
+ puts(" (DISABLED)");
+ else
+ puts("");
+ }
+ if (!strncmp(fullname, arg, length)) {
+ if (set)
+ testcase->flags |= flag;
+ else
+ testcase->flags &= ~flag;
+ ++found;
+ }
+ }
+ }
+ return found;
+}
+
+static void
+usage(struct testgroup_t *groups, int list_groups)
+{
+ puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
+ puts(" Specify tests by name, or using a prefix ending with '..'");
+ puts(" To skip a test, prefix its name with a colon.");
+ puts(" To enable a disabled test, prefix its name with a plus.");
+ puts(" Use --list-tests for a list of tests.");
+ if (list_groups) {
+ puts("Known tests are:");
+ tinytest_set_flag_(groups, "..", 1, 0);
+ }
+ exit(0);
+}
+
+static int
+process_test_alias(struct testgroup_t *groups, const char *test)
+{
+ int i, j, n, r;
+ for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) {
+ if (!strcmp(cfg_aliases[i].name, test)) {
+ n = 0;
+ for (j = 0; cfg_aliases[i].tests[j]; ++j) {
+ r = process_test_option(groups, cfg_aliases[i].tests[j]);
+ if (r<0)
+ return -1;
+ n += r;
+ }
+ return n;
+ }
+ }
+ printf("No such test alias as @%s!",test);
+ return -1;
+}
+
+static int
+process_test_option(struct testgroup_t *groups, const char *test)
+{
+ int flag = TT_ENABLED_;
+ int n = 0;
+ if (test[0] == '@') {
+ return process_test_alias(groups, test + 1);
+ } else if (test[0] == ':') {
+ ++test;
+ flag = TT_SKIP;
+ } else if (test[0] == '+') {
+ ++test;
+ ++n;
+ if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) {
+ printf("No such test as %s!\n", test);
+ return -1;
+ }
+ } else {
+ ++n;
+ }
+ if (!tinytest_set_flag_(groups, test, 1, flag)) {
+ printf("No such test as %s!\n", test);
+ return -1;
+ }
+ return n;
+}
+
+void
+tinytest_set_aliases(const struct testlist_alias_t *aliases)
+{
+ cfg_aliases = aliases;
+}
+
+int
+tinytest_main(int c, const char **v, struct testgroup_t *groups)
+{
+ int i, j, n=0;
+
+#ifdef _WIN32
+ const char *sp = strrchr(v[0], '.');
+ const char *extension = "";
+ if (!sp || stricmp(sp, ".exe"))
+ extension = ".exe"; /* Add an exe so CreateProcess will work */
+ snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
+ commandname[MAX_PATH]='\0';
+#endif
+ for (i=1; i<c; ++i) {
+ if (v[i][0] == '-') {
+ if (!strcmp(v[i], "--RUNNING-FORKED")) {
+ opt_forked = 1;
+ } else if (!strcmp(v[i], "--no-fork")) {
+ opt_nofork = 1;
+ } else if (!strcmp(v[i], "--quiet")) {
+ opt_verbosity = -1;
+ verbosity_flag = "--quiet";
+ } else if (!strcmp(v[i], "--verbose")) {
+ opt_verbosity = 2;
+ verbosity_flag = "--verbose";
+ } else if (!strcmp(v[i], "--terse")) {
+ opt_verbosity = 0;
+ verbosity_flag = "--terse";
+ } else if (!strcmp(v[i], "--help")) {
+ usage(groups, 0);
+ } else if (!strcmp(v[i], "--list-tests")) {
+ usage(groups, 1);
+ } else {
+ printf("Unknown option %s. Try --help\n",v[i]);
+ return -1;
+ }
+ } else {
+ int r = process_test_option(groups, v[i]);
+ if (r<0)
+ return -1;
+ n += r;
+ }
+ }
+ if (!n)
+ tinytest_set_flag_(groups, "..", 1, TT_ENABLED_);
+
+#ifdef _IONBF
+ setvbuf(stdout, NULL, _IONBF, 0);
+#endif
+
+ ++in_tinytest_main;
+ for (i=0; groups[i].prefix; ++i)
+ for (j=0; groups[i].cases[j].name; ++j)
+ if (groups[i].cases[j].flags & TT_ENABLED_)
+ testcase_run_one(&groups[i],
+ &groups[i].cases[j]);
+
+ --in_tinytest_main;
+
+ if (opt_verbosity==0)
+ puts("");
+
+ if (n_bad)
+ printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
+ n_bad+n_ok,n_skipped);
+ else if (opt_verbosity >= 1)
+ printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped);
+
+ return (n_bad == 0) ? 0 : 1;
+}
+
+int
+tinytest_get_verbosity_(void)
+{
+ return opt_verbosity;
+}
+
+void
+tinytest_set_test_failed_(void)
+{
+ if (opt_verbosity <= 0 && cur_test_name) {
+ if (opt_verbosity==0) puts("");
+ printf("%s%s: ", cur_test_prefix, cur_test_name);
+ cur_test_name = NULL;
+ }
+ cur_test_outcome = 0;
+}
+
+void
+tinytest_set_test_skipped_(void)
+{
+ if (cur_test_outcome==OK)
+ cur_test_outcome = SKIP;
+}
+
+char *
+tinytest_format_hex_(const void *val_, unsigned long len)
+{
+ const unsigned char *val = val_;
+ char *result, *cp;
+ size_t i;
+
+ if (!val)
+ return strdup("null");
+ if (!(result = malloc(len*2+1)))
+ return strdup("<allocation failure>");
+ cp = result;
+ for (i=0;i<len;++i) {
+ *cp++ = "0123456789ABCDEF"[val[i] >> 4];
+ *cp++ = "0123456789ABCDEF"[val[i] & 0x0f];
+ }
+ *cp = 0;
+ return result;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest.h
new file mode 100644
index 000000000..ed07b26bc
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest.h
@@ -0,0 +1,100 @@
+/* tinytest.h -- Copyright 2009-2012 Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TINYTEST_H_INCLUDED_
+#define TINYTEST_H_INCLUDED_
+
+/** Flag for a test that needs to run in a subprocess. */
+#define TT_FORK (1<<0)
+/** Runtime flag for a test we've decided to skip. */
+#define TT_SKIP (1<<1)
+/** Internal runtime flag for a test we've decided to run. */
+#define TT_ENABLED_ (1<<2)
+/** Flag for a test that's off by default. */
+#define TT_OFF_BY_DEFAULT (1<<3)
+/** If you add your own flags, make them start at this point. */
+#define TT_FIRST_USER_FLAG (1<<4)
+
+typedef void (*testcase_fn)(void *);
+
+struct testcase_t;
+
+/** Functions to initialize/teardown a structure for a testcase. */
+struct testcase_setup_t {
+ /** Return a new structure for use by a given testcase. */
+ void *(*setup_fn)(const struct testcase_t *);
+ /** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */
+ int (*cleanup_fn)(const struct testcase_t *, void *);
+};
+
+/** A single test-case that you can run. */
+struct testcase_t {
+ const char *name; /**< An identifier for this case. */
+ testcase_fn fn; /**< The function to run to implement this case. */
+ unsigned long flags; /**< Bitfield of TT_* flags. */
+ const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/
+ void *setup_data; /**< Extra data usable by setup function */
+};
+#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL }
+
+/** A group of tests that are selectable together. */
+struct testgroup_t {
+ const char *prefix; /**< Prefix to prepend to testnames. */
+ struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */
+};
+#define END_OF_GROUPS { NULL, NULL}
+
+struct testlist_alias_t {
+ const char *name;
+ const char **tests;
+};
+#define END_OF_ALIASES { NULL, NULL }
+
+/** Implementation: called from a test to indicate failure, before logging. */
+void tinytest_set_test_failed_(void);
+/** Implementation: called from a test to indicate that we're skipping. */
+void tinytest_set_test_skipped_(void);
+/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */
+int tinytest_get_verbosity_(void);
+/** Implementation: Set a flag on tests matching a name; returns number
+ * of tests that matched. */
+int tinytest_set_flag_(struct testgroup_t *, const char *, int set, unsigned long);
+/** Implementation: Put a chunk of memory into hex. */
+char *tinytest_format_hex_(const void *, unsigned long);
+
+/** Set all tests in 'groups' matching the name 'named' to be skipped. */
+#define tinytest_skip(groups, named) \
+ tinytest_set_flag_(groups, named, 1, TT_SKIP)
+
+/** Run a single testcase in a single group. */
+int testcase_run_one(const struct testgroup_t *,const struct testcase_t *);
+
+void tinytest_set_aliases(const struct testlist_alias_t *aliases);
+
+/** Run a set of testcases from an END_OF_GROUPS-terminated array of groups,
+ as selected from the command line. */
+int tinytest_main(int argc, const char **argv, struct testgroup_t *groups);
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest_demo.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest_demo.c
new file mode 100644
index 000000000..f6bfd66a1
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest_demo.c
@@ -0,0 +1,262 @@
+/* tinytest_demo.c -- Copyright 2009-2012 Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/* Welcome to the example file for tinytest! I'll show you how to set up
+ * some simple and not-so-simple testcases. */
+
+/* Make sure you include these headers. */
+#include "tinytest.h"
+#include "tinytest_macros.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+/* ============================================================ */
+
+/* First, let's see if strcmp is working. (All your test cases should be
+ * functions declared to take a single void * as an argument.) */
+void
+test_strcmp(void *data)
+{
+ (void)data; /* This testcase takes no data. */
+
+ /* Let's make sure the empty string is equal to itself */
+ if (strcmp("","")) {
+ /* This macro tells tinytest to stop the current test
+ * and go straight to the "end" label. */
+ tt_abort_msg("The empty string was not equal to itself");
+ }
+
+ /* Pretty often, calling tt_abort_msg to indicate failure is more
+ heavy-weight than you want. Instead, just say: */
+ tt_assert(strcmp("testcase", "testcase") == 0);
+
+ /* Occasionally, you don't want to stop the current testcase just
+ because a single assertion has failed. In that case, use
+ tt_want: */
+ tt_want(strcmp("tinytest", "testcase") > 0);
+
+ /* You can use the tt_*_op family of macros to compare values and to
+ fail unless they have the relationship you want. They produce
+ more useful output than tt_assert, since they display the actual
+ values of the failing things.
+
+ Fail unless strcmp("abc, "abc") == 0 */
+ tt_int_op(strcmp("abc", "abc"), ==, 0);
+
+ /* Fail unless strcmp("abc, "abcd") is less than 0 */
+ tt_int_op(strcmp("abc", "abcd"), < , 0);
+
+ /* Incidentally, there's a test_str_op that uses strcmp internally. */
+ tt_str_op("abc", <, "abcd");
+
+
+ /* Every test-case function needs to finish with an "end:"
+ label and (optionally) code to clean up local variables. */
+ end:
+ ;
+}
+
+/* ============================================================ */
+
+/* Now let's mess with setup and teardown functions! These are handy if
+ you have a bunch of tests that all need a similar environment, and you
+ want to reconstruct that environment freshly for each one. */
+
+/* First you declare a type to hold the environment info, and functions to
+ set it up and tear it down. */
+struct data_buffer {
+ /* We're just going to have couple of character buffer. Using
+ setup/teardown functions is probably overkill for this case.
+
+ You could also do file descriptors, complicated handles, temporary
+ files, etc. */
+ char buffer1[512];
+ char buffer2[512];
+};
+/* The setup function needs to take a const struct testcase_t and return
+ void* */
+void *
+setup_data_buffer(const struct testcase_t *testcase)
+{
+ struct data_buffer *db = malloc(sizeof(struct data_buffer));
+
+ /* If you had a complicated set of setup rules, you might behave
+ differently here depending on testcase->flags or
+ testcase->setup_data or even or testcase->name. */
+
+ /* Returning a NULL here would mean that we couldn't set up for this
+ test, so we don't need to test db for null. */
+ return db;
+}
+/* The clean function deallocates storage carefully and returns true on
+ success. */
+int
+clean_data_buffer(const struct testcase_t *testcase, void *ptr)
+{
+ struct data_buffer *db = ptr;
+
+ if (db) {
+ free(db);
+ return 1;
+ }
+ return 0;
+}
+/* Finally, declare a testcase_setup_t with these functions. */
+struct testcase_setup_t data_buffer_setup = {
+ setup_data_buffer, clean_data_buffer
+};
+
+
+/* Now let's write our test. */
+void
+test_memcpy(void *ptr)
+{
+ /* This time, we use the argument. */
+ struct data_buffer *db = ptr;
+
+ /* We'll also introduce a local variable that might need cleaning up. */
+ char *mem = NULL;
+
+ /* Let's make sure that memcpy does what we'd like. */
+ strcpy(db->buffer1, "String 0");
+ memcpy(db->buffer2, db->buffer1, sizeof(db->buffer1));
+ tt_str_op(db->buffer1, ==, db->buffer2);
+
+ /* This one works if there's an internal NUL. */
+ tt_mem_op(db->buffer1, <, db->buffer2, sizeof(db->buffer1));
+
+ /* Now we've allocated memory that's referenced by a local variable.
+ The end block of the function will clean it up. */
+ mem = strdup("Hello world.");
+ tt_assert(mem);
+
+ /* Another rather trivial test. */
+ tt_str_op(db->buffer1, !=, mem);
+
+ end:
+ /* This time our end block has something to do. */
+ if (mem)
+ free(mem);
+}
+
+void
+test_timeout(void *ptr)
+{
+ time_t t1, t2;
+ (void)ptr;
+ t1 = time(NULL);
+#ifdef _WIN32
+ Sleep(5000);
+#else
+ sleep(5);
+#endif
+ t2 = time(NULL);
+
+ tt_int_op(t2-t1, >=, 4);
+
+ tt_int_op(t2-t1, <=, 6);
+
+ end:
+ ;
+}
+
+/* ============================================================ */
+
+/* Now we need to make sure that our tests get invoked. First, you take
+ a bunch of related tests and put them into an array of struct testcase_t.
+*/
+
+struct testcase_t demo_tests[] = {
+ /* Here's a really simple test: it has a name you can refer to it
+ with, and a function to invoke it. */
+ { "strcmp", test_strcmp, },
+
+ /* The second test has a flag, "TT_FORK", to make it run in a
+ subprocess, and a pointer to the testcase_setup_t that configures
+ its environment. */
+ { "memcpy", test_memcpy, TT_FORK, &data_buffer_setup },
+
+ /* This flag is off-by-default, since it takes a while to run. You
+ * can enable it manually by passing +demo/timeout at the command line.*/
+ { "timeout", test_timeout, TT_OFF_BY_DEFAULT },
+
+ /* The array has to end with END_OF_TESTCASES. */
+ END_OF_TESTCASES
+};
+
+/* Next, we make an array of testgroups. This is mandatory. Unlike more
+ heavy-duty testing frameworks, groups can't nest. */
+struct testgroup_t groups[] = {
+
+ /* Every group has a 'prefix', and an array of tests. That's it. */
+ { "demo/", demo_tests },
+
+ END_OF_GROUPS
+};
+
+/* We can also define test aliases. These can be used for types of tests that
+ * cut across groups. */
+const char *alltests[] = { "+..", NULL };
+const char *slowtests[] = { "+demo/timeout", NULL };
+struct testlist_alias_t aliases[] = {
+
+ { "ALL", alltests },
+ { "SLOW", slowtests },
+
+ END_OF_ALIASES
+};
+
+
+int
+main(int c, const char **v)
+{
+ /* Finally, just call tinytest_main(). It lets you specify verbose
+ or quiet output with --verbose and --quiet. You can list
+ specific tests:
+
+ tinytest-demo demo/memcpy
+
+ or use a ..-wildcard to select multiple tests with a common
+ prefix:
+
+ tinytest-demo demo/..
+
+ If you list no tests, you get them all by default, so that
+ "tinytest-demo" and "tinytest-demo .." mean the same thing.
+
+ */
+ tinytest_set_aliases(aliases);
+ return tinytest_main(c, v, groups);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest_local.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest_local.h
new file mode 100644
index 000000000..87ec2fa67
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest_local.h
@@ -0,0 +1,12 @@
+
+#include "util-internal.h"
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+#include "event2/util.h"
+
+#ifdef snprintf
+#undef snprintf
+#endif
+#define snprintf evutil_snprintf
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest_macros.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest_macros.h
new file mode 100644
index 000000000..2c02a741b
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/test/tinytest_macros.h
@@ -0,0 +1,205 @@
+/* tinytest_macros.h -- Copyright 2009-2012 Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TINYTEST_MACROS_H_INCLUDED_
+#define TINYTEST_MACROS_H_INCLUDED_
+
+/* Helpers for defining statement-like macros */
+#define TT_STMT_BEGIN do {
+#define TT_STMT_END } while (0)
+
+/* Redefine this if your test functions want to abort with something besides
+ * "goto end;" */
+#ifndef TT_EXIT_TEST_FUNCTION
+#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END
+#endif
+
+/* Redefine this if you want to note success/failure in some different way. */
+#ifndef TT_DECLARE
+#define TT_DECLARE(prefix, args) \
+ TT_STMT_BEGIN \
+ printf("\n %s %s:%d: ",prefix,__FILE__,__LINE__); \
+ printf args ; \
+ TT_STMT_END
+#endif
+
+/* Announce a failure. Args are parenthesized printf args. */
+#define TT_GRIPE(args) TT_DECLARE("FAIL", args)
+
+/* Announce a non-failure if we're verbose. */
+#define TT_BLATHER(args) \
+ TT_STMT_BEGIN \
+ if (tinytest_get_verbosity_()>1) TT_DECLARE(" OK", args); \
+ TT_STMT_END
+
+#define TT_DIE(args) \
+ TT_STMT_BEGIN \
+ tinytest_set_test_failed_(); \
+ TT_GRIPE(args); \
+ TT_EXIT_TEST_FUNCTION; \
+ TT_STMT_END
+
+#define TT_FAIL(args) \
+ TT_STMT_BEGIN \
+ tinytest_set_test_failed_(); \
+ TT_GRIPE(args); \
+ TT_STMT_END
+
+/* Fail and abort the current test for the reason in msg */
+#define tt_abort_printf(msg) TT_DIE(msg)
+#define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno))
+#define tt_abort_msg(msg) TT_DIE(("%s", msg))
+#define tt_abort() TT_DIE(("%s", "(Failed.)"))
+
+/* Fail but do not abort the current test for the reason in msg. */
+#define tt_failprint_f(msg) TT_FAIL(msg)
+#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno))
+#define tt_fail_msg(msg) TT_FAIL(("%s", msg))
+#define tt_fail() TT_FAIL(("%s", "(Failed.)"))
+
+/* End the current test, and indicate we are skipping it. */
+#define tt_skip() \
+ TT_STMT_BEGIN \
+ tinytest_set_test_skipped_(); \
+ TT_EXIT_TEST_FUNCTION; \
+ TT_STMT_END
+
+#define tt_want_(b, msg, fail) \
+ TT_STMT_BEGIN \
+ if (!(b)) { \
+ tinytest_set_test_failed_(); \
+ TT_GRIPE(("%s",msg)); \
+ fail; \
+ } else { \
+ TT_BLATHER(("%s",msg)); \
+ } \
+ TT_STMT_END
+
+/* Assert b, but do not stop the test if b fails. Log msg on failure. */
+#define tt_want_msg(b, msg) \
+ tt_want_(b, msg, );
+
+/* Assert b and stop the test if b fails. Log msg on failure. */
+#define tt_assert_msg(b, msg) \
+ tt_want_(b, msg, TT_EXIT_TEST_FUNCTION);
+
+/* Assert b, but do not stop the test if b fails. */
+#define tt_want(b) tt_want_msg( (b), "want("#b")")
+/* Assert b, and stop the test if b fails. */
+#define tt_assert(b) tt_assert_msg((b), "assert("#b")")
+
+#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \
+ setup_block,cleanup_block,die_on_fail) \
+ TT_STMT_BEGIN \
+ type val1_ = (a); \
+ type val2_ = (b); \
+ int tt_status_ = (test); \
+ if (!tt_status_ || tinytest_get_verbosity_()>1) { \
+ printf_type print_; \
+ printf_type print1_; \
+ printf_type print2_; \
+ type value_ = val1_; \
+ setup_block; \
+ print1_ = print_; \
+ value_ = val2_; \
+ setup_block; \
+ print2_ = print_; \
+ TT_DECLARE(tt_status_?" OK":"FAIL", \
+ ("assert(%s): "printf_fmt" vs "printf_fmt, \
+ str_test, print1_, print2_)); \
+ print_ = print1_; \
+ cleanup_block; \
+ print_ = print2_; \
+ cleanup_block; \
+ if (!tt_status_) { \
+ tinytest_set_test_failed_(); \
+ die_on_fail ; \
+ } \
+ } \
+ TT_STMT_END
+
+#define tt_assert_test_type(a,b,str_test,type,test,fmt,die_on_fail) \
+ tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \
+ {print_=value_;},{},die_on_fail)
+
+#define tt_assert_test_type_opt(a,b,str_test,type,test,fmt,die_on_fail) \
+ tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \
+ {print_=value_?value_:"<NULL>";},{},die_on_fail)
+
+/* Helper: assert that a op b, when cast to type. Format the values with
+ * printf format fmt on failure. */
+#define tt_assert_op_type(a,op,b,type,fmt) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,type,(val1_ op val2_),fmt, \
+ TT_EXIT_TEST_FUNCTION)
+
+#define tt_int_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_), \
+ "%ld",TT_EXIT_TEST_FUNCTION)
+
+#define tt_uint_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \
+ (val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION)
+
+#define tt_ptr_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,const void*, \
+ (val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION)
+
+/** XXX: have some issues with printing this non-NUL terminated strings */
+#define tt_nstr_op(n,a,op,b) \
+ tt_assert_test_type_opt(a,b,#a" "#op" "#b,const char *, \
+ (val1_ && val2_ && strncmp(val1_,val2_,(n)) op 0),"<%s>", \
+ TT_EXIT_TEST_FUNCTION)
+
+#define tt_str_op(a,op,b) \
+ tt_assert_test_type_opt(a,b,#a" "#op" "#b,const char *, \
+ (val1_ && val2_ && strcmp(val1_,val2_) op 0),"<%s>", \
+ TT_EXIT_TEST_FUNCTION)
+
+#define tt_mem_op(expr1, op, expr2, len) \
+ tt_assert_test_fmt_type(expr1,expr2,#expr1" "#op" "#expr2, \
+ const void *, \
+ (val1_ && val2_ && memcmp(val1_, val2_, len) op 0), \
+ char *, "%s", \
+ { print_ = tinytest_format_hex_(value_, (len)); }, \
+ { if (print_) free(print_); }, \
+ TT_EXIT_TEST_FUNCTION \
+ );
+
+#define tt_want_int_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0)
+
+#define tt_want_uint_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \
+ (val1_ op val2_),"%lu",(void)0)
+
+#define tt_want_ptr_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,const void*, \
+ (val1_ op val2_),"%p",(void)0)
+
+#define tt_want_str_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \
+ (strcmp(val1_,val2_) op 0),"<%s>",(void)0)
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/time-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/time-internal.h
new file mode 100644
index 000000000..2c584fa75
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/time-internal.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef TIME_INTERNAL_H_INCLUDED_
+#define TIME_INTERNAL_H_INCLUDED_
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef EVENT__HAVE_MACH_MACH_TIME_H
+/* For mach_timebase_info */
+#include <mach/mach_time.h>
+#endif
+
+#include <time.h>
+
+#include "event2/util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+#define HAVE_POSIX_MONOTONIC
+#elif defined(EVENT__HAVE_MACH_ABSOLUTE_TIME)
+#define HAVE_MACH_MONOTONIC
+#elif defined(_WIN32)
+#define HAVE_WIN32_MONOTONIC
+#else
+#define HAVE_FALLBACK_MONOTONIC
+#endif
+
+long evutil_tv_to_msec_(const struct timeval *tv);
+void evutil_usleep_(const struct timeval *tv);
+
+#ifdef _WIN32
+typedef ULONGLONG (WINAPI *ev_GetTickCount_func)(void);
+#endif
+
+struct evutil_monotonic_timer {
+
+#ifdef HAVE_MACH_MONOTONIC
+ struct mach_timebase_info mach_timebase_units;
+#endif
+
+#ifdef HAVE_POSIX_MONOTONIC
+ int monotonic_clock;
+#endif
+
+#ifdef HAVE_WIN32_MONOTONIC
+ ev_GetTickCount_func GetTickCount64_fn;
+ ev_GetTickCount_func GetTickCount_fn;
+ ev_uint64_t last_tick_count;
+ ev_uint64_t adjust_tick_count;
+
+ ev_uint64_t first_tick;
+ ev_uint64_t first_counter;
+ double usec_per_count;
+ int use_performance_counter;
+#endif
+
+ struct timeval adjust_monotonic_clock;
+ struct timeval last_time;
+};
+
+int evutil_configure_monotonic_time_(struct evutil_monotonic_timer *mt,
+ int flags);
+int evutil_gettime_monotonic_(struct evutil_monotonic_timer *mt, struct timeval *tv);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EVENT_INTERNAL_H_INCLUDED_ */
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/util-internal.h b/fluent-bit/lib/monkey/mk_core/deps/libevent/util-internal.h
new file mode 100644
index 000000000..38d0f595f
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/util-internal.h
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef UTIL_INTERNAL_H_INCLUDED_
+#define UTIL_INTERNAL_H_INCLUDED_
+
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <errno.h>
+
+/* For EVUTIL_ASSERT */
+#include "log-internal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef EVENT__HAVE_SYS_EVENTFD_H
+#include <sys/eventfd.h>
+#endif
+#include "event2/util.h"
+
+#include "time-internal.h"
+#include "ipv6-internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* If we need magic to say "inline", get it for free internally. */
+#ifdef EVENT__inline
+#define inline EVENT__inline
+#endif
+#if defined(EVENT____func__) && !defined(__func__)
+#define __func__ EVENT____func__
+#endif
+
+/* A good no-op to use in macro definitions. */
+#define EVUTIL_NIL_STMT_ ((void)0)
+/* A no-op that tricks the compiler into thinking a condition is used while
+ * definitely not making any code for it. Used to compile out asserts while
+ * avoiding "unused variable" warnings. The "!" forces the compiler to
+ * do the sizeof() on an int, in case "condition" is a bitfield value.
+ */
+#define EVUTIL_NIL_CONDITION_(condition) do { \
+ (void)sizeof(!(condition)); \
+} while(0)
+
+/* Internal use only: macros to match patterns of error codes in a
+ cross-platform way. We need these macros because of two historical
+ reasons: first, nonblocking IO functions are generally written to give an
+ error on the "blocked now, try later" case, so sometimes an error from a
+ read, write, connect, or accept means "no error; just wait for more
+ data," and we need to look at the error code. Second, Windows defines
+ a different set of error codes for sockets. */
+
+#ifndef _WIN32
+
+#if EAGAIN == EWOULDBLOCK
+#define EVUTIL_ERR_IS_EAGAIN(e) \
+ ((e) == EAGAIN)
+#else
+#define EVUTIL_ERR_IS_EAGAIN(e) \
+ ((e) == EAGAIN || (e) == EWOULDBLOCK)
+#endif
+
+/* True iff e is an error that means a read/write operation can be retried. */
+#define EVUTIL_ERR_RW_RETRIABLE(e) \
+ ((e) == EINTR || EVUTIL_ERR_IS_EAGAIN(e))
+/* True iff e is an error that means an connect can be retried. */
+#define EVUTIL_ERR_CONNECT_RETRIABLE(e) \
+ ((e) == EINTR || (e) == EINPROGRESS)
+/* True iff e is an error that means a accept can be retried. */
+#define EVUTIL_ERR_ACCEPT_RETRIABLE(e) \
+ ((e) == EINTR || EVUTIL_ERR_IS_EAGAIN(e) || (e) == ECONNABORTED)
+
+/* True iff e is an error that means the connection was refused */
+#define EVUTIL_ERR_CONNECT_REFUSED(e) \
+ ((e) == ECONNREFUSED)
+
+#else
+/* Win32 */
+
+#define EVUTIL_ERR_IS_EAGAIN(e) \
+ ((e) == WSAEWOULDBLOCK || (e) == EAGAIN)
+
+#define EVUTIL_ERR_RW_RETRIABLE(e) \
+ ((e) == WSAEWOULDBLOCK || \
+ (e) == WSAEINTR)
+
+#define EVUTIL_ERR_CONNECT_RETRIABLE(e) \
+ ((e) == WSAEWOULDBLOCK || \
+ (e) == WSAEINTR || \
+ (e) == WSAEINPROGRESS || \
+ (e) == WSAEINVAL)
+
+#define EVUTIL_ERR_ACCEPT_RETRIABLE(e) \
+ EVUTIL_ERR_RW_RETRIABLE(e)
+
+#define EVUTIL_ERR_CONNECT_REFUSED(e) \
+ ((e) == WSAECONNREFUSED)
+
+#endif
+
+/* Arguments for shutdown() */
+#ifdef SHUT_RD
+#define EVUTIL_SHUT_RD SHUT_RD
+#else
+#define EVUTIL_SHUT_RD 0
+#endif
+#ifdef SHUT_WR
+#define EVUTIL_SHUT_WR SHUT_WR
+#else
+#define EVUTIL_SHUT_WR 1 /* SD_SEND */
+#endif
+#ifdef SHUT_BOTH
+#define EVUTIL_SHUT_BOTH SHUT_BOTH
+#else
+#define EVUTIL_SHUT_BOTH 2
+#endif
+
+/* Helper: Verify that all the elements in 'dlist' are internally consistent.
+ * Checks for circular lists and bad prev/next pointers.
+ *
+ * Example usage:
+ * EVUTIL_ASSERT_LIST_OK(eventlist, event, ev_next);
+ */
+#define EVUTIL_ASSERT_LIST_OK(dlist, type, field) do { \
+ struct type *elm1, *elm2, **nextp; \
+ if (LIST_EMPTY((dlist))) \
+ break; \
+ \
+ /* Check list for circularity using Floyd's */ \
+ /* 'Tortoise and Hare' algorithm */ \
+ elm1 = LIST_FIRST((dlist)); \
+ elm2 = LIST_NEXT(elm1, field); \
+ while (elm1 && elm2) { \
+ EVUTIL_ASSERT(elm1 != elm2); \
+ elm1 = LIST_NEXT(elm1, field); \
+ elm2 = LIST_NEXT(elm2, field); \
+ if (!elm2) \
+ break; \
+ EVUTIL_ASSERT(elm1 != elm2); \
+ elm2 = LIST_NEXT(elm2, field); \
+ } \
+ \
+ /* Now check next and prev pointers for consistency. */ \
+ nextp = &LIST_FIRST((dlist)); \
+ elm1 = LIST_FIRST((dlist)); \
+ while (elm1) { \
+ EVUTIL_ASSERT(*nextp == elm1); \
+ EVUTIL_ASSERT(nextp == elm1->field.le_prev); \
+ nextp = &LIST_NEXT(elm1, field); \
+ elm1 = *nextp; \
+ } \
+ } while (0)
+
+/* Helper: Verify that all the elements in a TAILQ are internally consistent.
+ * Checks for circular lists and bad prev/next pointers.
+ *
+ * Example usage:
+ * EVUTIL_ASSERT_TAILQ_OK(activelist, event, ev_active_next);
+ */
+#define EVUTIL_ASSERT_TAILQ_OK(tailq, type, field) do { \
+ struct type *elm1, *elm2, **nextp; \
+ if (TAILQ_EMPTY((tailq))) \
+ break; \
+ \
+ /* Check list for circularity using Floyd's */ \
+ /* 'Tortoise and Hare' algorithm */ \
+ elm1 = TAILQ_FIRST((tailq)); \
+ elm2 = TAILQ_NEXT(elm1, field); \
+ while (elm1 && elm2) { \
+ EVUTIL_ASSERT(elm1 != elm2); \
+ elm1 = TAILQ_NEXT(elm1, field); \
+ elm2 = TAILQ_NEXT(elm2, field); \
+ if (!elm2) \
+ break; \
+ EVUTIL_ASSERT(elm1 != elm2); \
+ elm2 = TAILQ_NEXT(elm2, field); \
+ } \
+ \
+ /* Now check next and prev pointers for consistency. */ \
+ nextp = &TAILQ_FIRST((tailq)); \
+ elm1 = TAILQ_FIRST((tailq)); \
+ while (elm1) { \
+ EVUTIL_ASSERT(*nextp == elm1); \
+ EVUTIL_ASSERT(nextp == elm1->field.tqe_prev); \
+ nextp = &TAILQ_NEXT(elm1, field); \
+ elm1 = *nextp; \
+ } \
+ EVUTIL_ASSERT(nextp == (tailq)->tqh_last); \
+ } while (0)
+
+/* Locale-independent replacements for some ctypes functions. Use these
+ * when you care about ASCII's notion of character types, because you are about
+ * to send those types onto the wire.
+ */
+int EVUTIL_ISALPHA_(char c);
+int EVUTIL_ISALNUM_(char c);
+int EVUTIL_ISSPACE_(char c);
+int EVUTIL_ISDIGIT_(char c);
+int EVUTIL_ISXDIGIT_(char c);
+int EVUTIL_ISPRINT_(char c);
+int EVUTIL_ISLOWER_(char c);
+int EVUTIL_ISUPPER_(char c);
+char EVUTIL_TOUPPER_(char c);
+char EVUTIL_TOLOWER_(char c);
+
+/** Remove all trailing horizontal whitespace (space or tab) from the end of a
+ * string */
+void evutil_rtrim_lws_(char *);
+
+
+/** Helper macro. If we know that a given pointer points to a field in a
+ structure, return a pointer to the structure itself. Used to implement
+ our half-baked C OO. Example:
+
+ struct subtype {
+ int x;
+ struct supertype common;
+ int y;
+ };
+ ...
+ void fn(struct supertype *super) {
+ struct subtype *sub = EVUTIL_UPCAST(super, struct subtype, common);
+ ...
+ }
+ */
+#define EVUTIL_UPCAST(ptr, type, field) \
+ ((type *)(((char*)(ptr)) - evutil_offsetof(type, field)))
+
+/* As open(pathname, flags, mode), except that the file is always opened with
+ * the close-on-exec flag set. (And the mode argument is mandatory.)
+ */
+int evutil_open_closeonexec_(const char *pathname, int flags, unsigned mode);
+
+int evutil_read_file_(const char *filename, char **content_out, size_t *len_out,
+ int is_binary);
+
+int evutil_socket_connect_(evutil_socket_t *fd_ptr, const struct sockaddr *sa, int socklen);
+
+int evutil_socket_finished_connecting_(evutil_socket_t fd);
+
+int evutil_ersatz_socketpair_(int, int , int, evutil_socket_t[]);
+
+int evutil_resolve_(int family, const char *hostname, struct sockaddr *sa,
+ ev_socklen_t *socklen, int port);
+
+const char *evutil_getenv_(const char *name);
+
+/* Structure to hold the state of our weak random number generator.
+ */
+struct evutil_weakrand_state {
+ ev_uint32_t seed;
+};
+
+#define EVUTIL_WEAKRAND_MAX EV_INT32_MAX
+
+/* Initialize the state of a week random number generator based on 'seed'. If
+ * the seed is 0, construct a new seed based on not-very-strong platform
+ * entropy, like the PID and the time of day.
+ *
+ * This function, and the other evutil_weakrand* functions, are meant for
+ * speed, not security or statistical strength. If you need a RNG which an
+ * attacker can't predict, or which passes strong statistical tests, use the
+ * evutil_secure_rng* functions instead.
+ */
+ev_uint32_t evutil_weakrand_seed_(struct evutil_weakrand_state *state, ev_uint32_t seed);
+/* Return a pseudorandom value between 0 and EVUTIL_WEAKRAND_MAX inclusive.
+ * Updates the state in 'seed' as needed -- this value must be protected by a
+ * lock.
+ */
+ev_int32_t evutil_weakrand_(struct evutil_weakrand_state *seed);
+/* Return a pseudorandom value x such that 0 <= x < top. top must be no more
+ * than EVUTIL_WEAKRAND_MAX. Updates the state in 'seed' as needed -- this
+ * value must be proteced by a lock */
+ev_int32_t evutil_weakrand_range_(struct evutil_weakrand_state *seed, ev_int32_t top);
+
+/* Evaluates to the same boolean value as 'p', and hints to the compiler that
+ * we expect this value to be false. */
+#if defined(__GNUC__) && __GNUC__ >= 3 /* gcc 3.0 or later */
+#define EVUTIL_UNLIKELY(p) __builtin_expect(!!(p),0)
+#else
+#define EVUTIL_UNLIKELY(p) (p)
+#endif
+
+/* Replacement for assert() that calls event_errx on failure. */
+#ifdef NDEBUG
+#define EVUTIL_ASSERT(cond) EVUTIL_NIL_CONDITION_(cond)
+#define EVUTIL_FAILURE_CHECK(cond) 0
+#else
+#define EVUTIL_ASSERT(cond) \
+ do { \
+ if (EVUTIL_UNLIKELY(!(cond))) { \
+ event_errx(EVENT_ERR_ABORT_, \
+ "%s:%d: Assertion %s failed in %s", \
+ __FILE__,__LINE__,#cond,__func__); \
+ /* In case a user-supplied handler tries to */ \
+ /* return control to us, log and abort here. */ \
+ (void)fprintf(stderr, \
+ "%s:%d: Assertion %s failed in %s", \
+ __FILE__,__LINE__,#cond,__func__); \
+ abort(); \
+ } \
+ } while (0)
+#define EVUTIL_FAILURE_CHECK(cond) EVUTIL_UNLIKELY(cond)
+#endif
+
+#ifndef EVENT__HAVE_STRUCT_SOCKADDR_STORAGE
+/* Replacement for sockaddr storage that we can use internally on platforms
+ * that lack it. It is not space-efficient, but neither is sockaddr_storage.
+ */
+struct sockaddr_storage {
+ union {
+ struct sockaddr ss_sa;
+ struct sockaddr_in ss_sin;
+ struct sockaddr_in6 ss_sin6;
+ char ss_padding[128];
+ } ss_union;
+};
+#define ss_family ss_union.ss_sa.sa_family
+#endif
+
+/* Internal addrinfo error code. This one is returned from only from
+ * evutil_getaddrinfo_common_, when we are sure that we'll have to hit a DNS
+ * server. */
+#define EVUTIL_EAI_NEED_RESOLVE -90002
+
+struct evdns_base;
+struct evdns_getaddrinfo_request;
+typedef struct evdns_getaddrinfo_request* (*evdns_getaddrinfo_fn)(
+ struct evdns_base *base,
+ const char *nodename, const char *servname,
+ const struct evutil_addrinfo *hints_in,
+ void (*cb)(int, struct evutil_addrinfo *, void *), void *arg);
+void evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo_fn fn);
+typedef void (*evdns_getaddrinfo_cancel_fn)(
+ struct evdns_getaddrinfo_request *req);
+void evutil_set_evdns_getaddrinfo_cancel_fn_(evdns_getaddrinfo_cancel_fn fn);
+
+struct evutil_addrinfo *evutil_new_addrinfo_(struct sockaddr *sa,
+ ev_socklen_t socklen, const struct evutil_addrinfo *hints);
+struct evutil_addrinfo *evutil_addrinfo_append_(struct evutil_addrinfo *first,
+ struct evutil_addrinfo *append);
+void evutil_adjust_hints_for_addrconfig_(struct evutil_addrinfo *hints);
+int evutil_getaddrinfo_common_(const char *nodename, const char *servname,
+ struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum);
+
+struct evdns_getaddrinfo_request *evutil_getaddrinfo_async_(
+ struct evdns_base *dns_base,
+ const char *nodename, const char *servname,
+ const struct evutil_addrinfo *hints_in,
+ void (*cb)(int, struct evutil_addrinfo *, void *), void *arg);
+void evutil_getaddrinfo_cancel_async_(struct evdns_getaddrinfo_request *data);
+
+/** Return true iff sa is a looback address. (That is, it is 127.0.0.1/8, or
+ * ::1). */
+int evutil_sockaddr_is_loopback_(const struct sockaddr *sa);
+
+
+/**
+ Formats a sockaddr sa into a string buffer of size outlen stored in out.
+ Returns a pointer to out. Always writes something into out, so it's safe
+ to use the output of this function without checking it for NULL.
+ */
+const char *evutil_format_sockaddr_port_(const struct sockaddr *sa, char *out, size_t outlen);
+
+int evutil_hex_char_to_int_(char c);
+
+
+void evutil_free_secure_rng_globals_(void);
+void evutil_free_globals_(void);
+
+#ifdef _WIN32
+HMODULE evutil_load_windows_system_library_(const TCHAR *library_name);
+#endif
+
+#ifndef EV_SIZE_FMT
+#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
+#define EV_U64_FMT "%I64u"
+#define EV_I64_FMT "%I64d"
+#define EV_I64_ARG(x) ((__int64)(x))
+#define EV_U64_ARG(x) ((unsigned __int64)(x))
+#else
+#define EV_U64_FMT "%llu"
+#define EV_I64_FMT "%lld"
+#define EV_I64_ARG(x) ((long long)(x))
+#define EV_U64_ARG(x) ((unsigned long long)(x))
+#endif
+#endif
+
+#ifdef _WIN32
+#define EV_SOCK_FMT EV_I64_FMT
+#define EV_SOCK_ARG(x) EV_I64_ARG((x))
+#else
+#define EV_SOCK_FMT "%d"
+#define EV_SOCK_ARG(x) (x)
+#endif
+
+#if defined(__STDC__) && defined(__STDC_VERSION__) && !defined(__MINGW64_VERSION_MAJOR)
+#if (__STDC_VERSION__ >= 199901L)
+#define EV_SIZE_FMT "%zu"
+#define EV_SSIZE_FMT "%zd"
+#define EV_SIZE_ARG(x) (x)
+#define EV_SSIZE_ARG(x) (x)
+#endif
+#endif
+
+#ifndef EV_SIZE_FMT
+#if (EVENT__SIZEOF_SIZE_T <= EVENT__SIZEOF_LONG)
+#define EV_SIZE_FMT "%lu"
+#define EV_SSIZE_FMT "%ld"
+#define EV_SIZE_ARG(x) ((unsigned long)(x))
+#define EV_SSIZE_ARG(x) ((long)(x))
+#else
+#define EV_SIZE_FMT EV_U64_FMT
+#define EV_SSIZE_FMT EV_I64_FMT
+#define EV_SIZE_ARG(x) EV_U64_ARG(x)
+#define EV_SSIZE_ARG(x) EV_I64_ARG(x)
+#endif
+#endif
+
+evutil_socket_t evutil_socket_(int domain, int type, int protocol);
+evutil_socket_t evutil_accept4_(evutil_socket_t sockfd, struct sockaddr *addr,
+ ev_socklen_t *addrlen, int flags);
+
+ /* used by one of the test programs.. */
+EVENT2_EXPORT_SYMBOL
+int evutil_make_internal_pipe_(evutil_socket_t fd[2]);
+evutil_socket_t evutil_eventfd_(unsigned initval, int flags);
+
+#ifdef SOCK_NONBLOCK
+#define EVUTIL_SOCK_NONBLOCK SOCK_NONBLOCK
+#else
+#define EVUTIL_SOCK_NONBLOCK 0x4000000
+#endif
+#ifdef SOCK_CLOEXEC
+#define EVUTIL_SOCK_CLOEXEC SOCK_CLOEXEC
+#else
+#define EVUTIL_SOCK_CLOEXEC 0x80000000
+#endif
+#ifdef EFD_NONBLOCK
+#define EVUTIL_EFD_NONBLOCK EFD_NONBLOCK
+#else
+#define EVUTIL_EFD_NONBLOCK 0x4000
+#endif
+#ifdef EFD_CLOEXEC
+#define EVUTIL_EFD_CLOEXEC EFD_CLOEXEC
+#else
+#define EVUTIL_EFD_CLOEXEC 0x8000
+#endif
+
+void evutil_memclear_(void *mem, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/whatsnew-2.0.txt b/fluent-bit/lib/monkey/mk_core/deps/libevent/whatsnew-2.0.txt
new file mode 100644
index 000000000..3561fcb94
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/whatsnew-2.0.txt
@@ -0,0 +1,609 @@
+What's New In Libevent 2.0 so far:
+
+1. Meta-issues
+
+1.1. About this document
+
+ This document describes the key differences between Libevent 1.4 and
+ Libevent 2.0, from a user's point of view. It was most recently
+ updated based on features in git master as of August 2010.
+
+ NOTE: I am very sure that I missed some thing on this list. Caveat
+ haxxor.
+
+1.2. Better documentation
+
+ There is now a book-in-progress that explains how to use Libevent and its
+ growing pile of APIs. As of this writing, it covers everything except the
+ http and rpc code. Check out the latest draft at
+ http://www.wangafu.net/~nickm/libevent-book/ .
+
+2. New and Improved Event APIs
+
+ Many APIs are improved, refactored, or deprecated in Libevent 2.0.
+
+ COMPATIBILITY:
+
+ Nearly all existing code that worked with Libevent 1.4 should still
+ work correctly with Libevent 2.0. However, if you are writing new code,
+ or if you want to port old code, we strongly recommend using the new APIs
+ and avoiding deprecated APIs as much as possible.
+
+ Binaries linked against Libevent 1.4 will need to be recompiled to link
+ against Libevent 2.0. This is nothing new; we have never been good at
+ preserving binary compatibility between releases. We'll try harder in the
+ future, though: see 2.1 below.
+
+2.1. New header layout for improved forward-compatibility
+
+ Libevent 2.0 has a new header layout to make it easier for programmers to
+ write good, well-supported libevent code. The new headers are divided
+ into three types.
+
+ There are *regular headers*, like event2/event.h. These headers contain
+ the functions that most programmers will want to use.
+
+ There are *backward compatibility headers*, like event2/event_compat.h.
+ These headers contain declarations for deprecated functions from older
+ versions of Libevent. Documentation in these headers should suggest what's
+ wrong with the old functions, and what functions you want to start using
+ instead of the old ones. Some of these functions might be removed in a
+ future release. New programs should generally not include these headers.
+
+ Finally, there are *structure headers*, like event2/event_struct.h.
+ These headers contain definitions of some structures that Libevent has
+ historically exposed. Exposing them caused problems in the past,
+ since programs that were compiled to work with one version of Libevent
+ would often stop working with another version that changed the size or
+ layout of some object. We've moving them into separate headers so
+ that programmers can know that their code is not depending on any
+ unstable aspect of the Libvent ABI. New programs should generally not
+ include these headers unless they really know what they are doing, are
+ willing to rebuild their software whenever they want to link it
+ against a new version of Libevent, and are willing to risk their code
+ breaking if and when data structures change.
+
+ Functionality that once was located in event.h is now more subdivided.
+ The core event logic is now in event2/event.h. The "evbuffer" functions
+ for low-level buffer manipulation are in event2/buffer.h. The
+ "bufferevent" functions for higher-level buffered IO are in
+ event2/bufferevent.h.
+
+ COMPATIBILITY:
+
+ All of the old headers (event.h, evdns.h, evhttp.h, evrpc.h, and
+ evutil.h) will continue to work by including the corresponding new
+ headers. Old code should not be broken by this change.
+
+2.2. New thread-safe, binary-compatible, harder-to-mess-up APIs
+
+ Some aspects of the historical Libevent API have encouraged
+ non-threadsafe code, or forced code built against one version of Libevent
+ to no longer build with another. The problems with now-deprecated APIs
+ fell into two categories:
+
+ 1) Dependence on the "current" event_base. In an application with
+ multiple event_bases, Libevent previously had a notion of the
+ "current" event_base. New events were linked to this base, and
+ the caller needed to explicitly reattach them to another base.
+ This was horribly error-prone.
+
+ Functions like "event_set" that worked with the "current" event_base
+ are now deprecated but still available (see 2.1). There are new
+ functions like "event_assign" that take an explicit event_base
+ argument when setting up a structure. Using these functions will help
+ prevent errors in your applications, and to be more threadsafe.
+
+ 2) Structure dependence. Applications needed to allocate 'struct
+ event' themselves, since there was no function in Libevent to do it
+ for them. But since the size and contents of struct event can
+ change between libevent versions, this created binary-compatibility
+ nightmares. All structures of this kind are now isolated in
+ _struct.h header (see 2.1), and there are new allocate-and-
+ initialize functions you can use instead of the old initialize-only
+ functions. For example, instead of malloc and event_set, you
+ can use event_new().
+
+ (For people who do really want to allocate a struct event on the
+ stack, or put one inside another structure, you can still use
+ event2/event_compat.h.)
+
+ So in the case where old code would look like this:
+
+ #include <event.h>
+ ...
+ struct event *ev = malloc(sizeof(struct event));
+ /* This call will cause a buffer overrun if you compile with one version
+ of Libevent and link dynamically against another. */
+ event_set(ev, fd, EV_READ, cb, NULL);
+ /* If you forget this call, your code will break in hard-to-diagnose
+ ways in the presence of multiple event bases. */
+ event_set_base(ev, base);
+
+ New code will look more like this:
+
+ #include <event2/event.h>
+ ...
+ struct event *ev;
+ ev = event_new(base, fd, EV_READ, cb, NULL);
+
+2.3. Overrideable allocation functions
+
+ If you want to override the allocation functions used by libevent
+ (for example, to use a specialized allocator, or debug memory
+ issues, or so on), you can replace them by calling
+ event_set_mem_functions. It takes replacements for malloc(),
+ free(), and realloc().
+
+ If you're going to use this facility, you need to call it _before_
+ Libevent does any memory allocation; otherwise, Libevent may allocate some
+ memory with malloc(), and free it with the free() function you provide.
+
+ You can disable this feature when you are building Libevent by passing
+ the --disable-malloc-replacement argument to configure.
+
+2.4. Configurable event_base creation
+
+ Older versions of Libevent would always got the fastest backend
+ available, unless you reconfigured their behavior with the environment
+ variables EVENT_NOSELECT, EVENT_NOPOLL, and so forth. This was annoying
+ to programmers who wanted to pick a backend explicitly without messing
+ with the environment.
+
+ Also, despite our best efforts, not every backend supports every
+ operation we might like. Some features (like edge-triggered events, or
+ working with non-socket file descriptors) only work with some operating
+ systems' fast backends. Previously, programmers who cared about this
+ needed to know which backends supported what. This tended to get quite
+ ungainly.
+
+ There is now an API to choose backends, either by name or by feature.
+ Here is an example:
+
+ struct event_config_t *config;
+ struct event_base *base;
+
+ /* Create a new configuration object. */
+ config = event_config_new();
+ /* We don't want to use the "select" method. */
+ event_config_avoid_method(config, "select");
+ /* We want a method that can work with non-socket file descriptors */
+ event_config_require_features(config, EV_FEATURE_FDS);
+
+ base = event_base_new_with_config(config);
+ if (!base) {
+ /* There is no backend method that does what we want. */
+ exit(1);
+ }
+ event_config_free(config);
+
+ Supported features are documented in event2/event.h
+
+2.5. Socket is now an abstract type
+
+ All APIs that formerly accepted int as a socket type now accept
+ "evutil_socket_t". On Unix, this is just an alias for "int" as
+ before. On Windows, however, it's an alias for SOCKET, which can
+ be wider than int on 64-bit platforms.
+
+2.6. Timeouts and persistent events work together.
+
+ Previously, it wasn't useful to set a timeout on a persistent event:
+ the timeout would trigger once, and never again. This is not what
+ applications tend to want. Instead, applications tend to want every
+ triggering of the event to re-set the timeout. So now, if you set
+ up an event like this:
+ struct event *ev;
+ struct timeval tv;
+ ev = event_new(base, fd, EV_READ|EV_PERSIST, cb, NULL);
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ event_add(ev, &tv);
+
+ The callback 'cb' will be invoked whenever fd is ready to read, OR whenever
+ a second has passed since the last invocation of cb.
+
+2.7. Multiple events allowed per fd
+
+ Older versions of Libevent allowed at most one EV_READ event and at most
+ one EV_WRITE event per socket, per event base. This restriction is no
+ longer present.
+
+2.8. evthread_* functions for thread-safe structures.
+
+ Libevent structures can now be built with locking support. This code
+ makes it safe to add, remove, and activate events on an event base from a
+ different thread. (Previously, if you wanted to write multithreaded code
+ with Libevent, you could only an event_base or its events in one thread at
+ a time.)
+
+ If you want threading support and you're using pthreads, you can just
+ call evthread_use_pthreads(). (You'll need to link against the
+ libevent_pthreads library in addition to libevent_core. These functions are
+ not in libevent_core.)
+
+ If you want threading support and you're using Windows, you can just
+ call evthread_use_windows_threads().
+
+ If you are using some locking system besides Windows and pthreads, You
+ can enable this on a per-event-base level by writing functions to
+ implement mutexes, conditions, and thread IDs, and passing them to
+ evthread_set_lock_callbacks and related functions in event2/thread.h.
+
+ Once locking functions are enabled, every new event_base is created with a
+ lock. You can prevent a single event_base from being built with a lock
+ disabled by using the EVENT_BASE_FLAG_NOLOCK flag in its
+ event_config. If an event_base is created with a lock, it is safe to call
+ event_del, event_add, and event_active on its events from any thread. The
+ event callbacks themselves are still all executed from the thread running
+ the event loop.
+
+ To make an evbuffer or a bufferevent object threadsafe, call its
+ *_enable_locking() function.
+
+ The HTTP api is not currently threadsafe.
+
+ To build Libevent with threading support disabled, pass
+ --disable-thread-support to the configure script.
+
+2.9. Edge-triggered events on some backends.
+
+ With some backends, it's now possible to add the EV_ET flag to an event
+ in order to request that the event's semantics be edge-triggered. Right
+ now, epoll and kqueue support this.
+
+ The corresponding event_config feature is EV_FEATURE_ET; see 2.4 for more
+ information.
+
+2.10. Better support for huge numbers of timeouts
+
+ The heap-based priority queue timer implementation for Libevent 1.4 is good
+ for randomly distributed timeouts, but suboptimal if you have huge numbers
+ of timeouts that all expire in the same amount of time after their
+ creation. The new event_base_init_common_timeout() logic lets you signal
+ that a given timeout interval will be very common, and should use a linked
+ list implementation instead of a priority queue.
+
+2.11. Improved debugging support
+
+ It's been pretty easy to forget to delete all your events before you
+ re-initialize them, or otherwise put Libevent in an internally inconsistent
+ state. You can tell libevent to catch these and other common errors with
+ the new event_enable_debug_mode() call. Just invoke it before you do
+ any calls to other libevent functions, and it'll catch many common
+ event-level errors in your code.
+
+2.12. Functions to access all event fields
+
+ So that you don't have to access the struct event fields directly, Libevent
+ now provides accessor functions to retrieve everything from an event that
+ you set during event_new() or event_assign().
+
+3. Backend-specific and performance improvements.
+
+3.1. Change-minimization on O(1) backends
+
+ With previous versions of Libevent, if you called event_del() and
+ event_add() repeatedly on a single event between trips to the backend's
+ dispatch function, the backend might wind up making unnecessary calls or
+ passing unnecessary data to the kernel. The new backend logic batches up
+ redundant adds and deletes, and performs no more operations than necessary
+ at the kernel level.
+
+ This logic is on for the kqueue backend, and available (but off by
+ default) for the epoll backend. To turn it on for the epoll backend,
+ set the EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST flag in the
+ event_base_cofig, or set the EVENT_EPOLL_USE_CHANGELIST environment
+ variable. Doing this with epoll may result in weird bugs if you give
+ any fds closed by dup() or its variants.
+
+3.2. Improved notification on Linux
+
+ When we need to wake the event loop up from another thread, we use
+ an epollfd to do so, instead of a socketpair. This is supposed to be
+ faster.
+
+3.3. Windows: better support for everything
+
+ Bufferevents on Windows can use a new mechanism (off-by-default; see below)
+ to send their data via Windows overlapped IO and get their notifications
+ via the IOCP API. This should be much faster than using event-based
+ notification.
+
+ Other functions throughout the code have been fixed to work more
+ consistently with Windows. Libevent now builds on Windows using either
+ mingw, or using MSVC (with nmake). Libevent works fine with UNICODE
+ defined, or not.
+
+ Data structures are a little smarter: our lookups from socket to pending
+ event are now done with O(1) hash tables rather than O(lg n) red-black
+ trees.
+
+ Unfortunately, the main Windows backend is still select()-based: from
+ testing the IOCP backends on the mailing list, it seems that there isn't
+ actually a way to tell for certain whether a socket is writable with IOCP.
+ Libevent 2.1 may add a multithreaded WaitForMultipleEvents-based
+ backend for better performance with many inactive sockets and better
+ integration with Windows events.
+
+4. Improvements to evbuffers
+
+ Libevent has long had an "evbuffer" implementation to wrap access to an
+ input or output memory buffer. In previous versions, the implementation
+ was very inefficient and lacked some desirable features. We've made many
+ improvements in Libevent 2.0.
+
+4.1. Chunked-memory internal representation
+
+ Previously, each evbuffer was a huge chunk of memory. When we ran out of
+ space in an evbuffer, we used realloc() to grow the chunk of memory. When
+ data was misaligned, we used memmove to move the data back to the front
+ of the buffer.
+
+ Needless to say, this is a terrible interface for networked IO.
+
+ Now, evbuffers are implemented as a linked list of memory chunks, like
+ most Unix kernels use for network IO. (See Linux's skbuf interfaces,
+ or *BSD's mbufs). Data is added at the end of the linked list and
+ removed from the front, so that we don't ever need realloc huge chunks
+ or memmove the whole buffer contents.
+
+ To avoid excessive calls to read and write, we use the readv/writev
+ interfaces (or WSASend/WSARecv on Windows) to do IO on multiple chunks at
+ once with a single system call.
+
+ COMPATIBILITY NOTE:
+ The evbuffer struct is no longer exposed in a header. The code here is
+ too volatile to expose an official evbuffer structure, and there was never
+ any means provided to create an evbuffer except via evbuffer_new which
+ heap-allocated the buffer.
+
+ If you need access to the whole buffer as a linear chunk of memory, the
+ EVBUFFER_DATA() function still works. Watch out, though: it needs to copy
+ the buffer's contents in a linear chunk before you can use it.
+
+4.2. More flexible readline support
+
+ The old evbuffer_readline() function (which accepted any sequence of
+ CR and LF characters as a newline, and which couldn't handle lines
+ containing NUL characters), is now deprecated. The preferred
+ function is evbuffer_readln(), which supports a variety of
+ line-ending styles, and which can return the number of characters in
+ the line returned.
+
+ You can also call evbuffer_search_eol() to find the end of a line
+ in an evbuffer without ever extracting the line.
+
+4.3. Support for file-based IO in evbuffers.
+
+ You can now add chunks of a file into a evbuffer, and Libevent will have
+ your OS use mapped-memory functionality, sendfile, or splice to transfer
+ the data without ever copying it to userspace. On OSs where this is not
+ supported, Libevent just loads the data.
+
+ There are probably some bugs remaining in this code. On some platforms
+ (like Windows), it just reads the relevant parts of the file into RAM.
+
+4.4. Support for zero-copy ("scatter/gather") writes in evbuffers.
+
+ You can add a piece of memory to an evbuffer without copying it.
+ Instead, Libevent adds a new element to the evbuffer's linked list of
+ chunks with a pointer to the memory you supplied. You can do this
+ either with a reference-counted chunk (via evbuffer_add_reference), or
+ by asking Libevent for a pointer to its internal vectors (via
+ evbuffer_reserve_space or evbuffer_peek()).
+
+4.5. Multiple callbacks per evbuffer
+
+ Previously, you could only have one callback active on an evbuffer at a
+ time. In practice, this meant that if one part of Libevent was using an
+ evbuffer callback to notice when an internal evbuffer was reading or
+ writing data, you couldn't have your own callback on that evbuffer.
+
+ Now, you can now use the evbuffer_add_cb() function to add a callback that
+ does not interfere with any other callbacks.
+
+ The evbuffer_setcb() function is now deprecated.
+
+4.6. New callback interface
+
+ Previously, evbuffer callbacks were invoked with the old size of the
+ buffer and the new size of the buffer. This interface could not capture
+ operations that simultaneously filled _and_ drained a buffer, or handle
+ cases where we needed to postpone callbacks until multiple operations were
+ complete.
+
+ Callbacks that are set with evbuffer_setcb still use the old API.
+ Callbacks added with evbuffer_add_cb() use a new interface that takes a
+ pointer to a struct holding the total number of bytes drained read and the
+ total number of bytes written. See event2/buffer.h for full details.
+
+4.7. Misc new evbuffer features
+
+ You can use evbuffer_remove() to move a given number of bytes from one
+ buffer to another.
+
+ The evbuffer_search() function lets you search for repeated instances of
+ a pattern inside an evbuffer.
+
+ You can use evbuffer_freeze() to temporarily suspend drains from or adds
+ to a given evbuffer. This is useful for code that exposes an evbuffer as
+ part of its public API, but wants users to treat it as a pure source or
+ sink.
+
+ There's an evbuffer_copyout() that looks at the data at the start of an
+ evbuffer without doing a drain.
+
+ You can have an evbuffer defer all of its callbacks, so that rather than
+ being invoked immediately when the evbuffer's length changes, they are
+ invoked from within the event_loop. This is useful when you have a
+ complex set of callbacks that can change the length of other evbuffers,
+ and you want to avoid having them recurse and overflow your stack.
+
+5. Bufferevents improvements
+
+ Libevent has long included a "bufferevents" structure and related
+ functions that were useful for generic buffered IO on a TCP connection.
+ This is what Libevent uses for its HTTP implementation. In addition to
+ the improvements that they get for free from the underlying evbuffer
+ implementation above, there are many new features in Libevent 2.0's
+ evbuffers.
+
+5.1. New OO implementations
+
+ The "bufferevent" structure is now an abstract base type with multiple
+ implementations. This should not break existing code, which always
+ allocated bufferevents with bufferevent_new().
+
+ Current implementations of the bufferevent interface are described below.
+
+5.2. bufferevent_socket_new() replaces bufferevent_new()
+
+ Since bufferevents that use a socket are not the only kind,
+ bufferevent_new() is now deprecated. Use bufferevent_socket_new()
+ instead.
+
+5.3. Filtered bufferevent IO
+
+ You can use bufferevent_filter_new() to create a bufferevent that wraps
+ around another bufferevent and transforms data it is sending and
+ receiving. See test/regress_zlib.c for a toy example that uses zlib to
+ compress data before sending it over a bufferevent.
+
+5.3. Linked pairs of bufferevents
+
+ You can use bufferevent_pair_new() to produce two linked
+ bufferevents. This is like using socketpair, but doesn't require
+ system-calls.
+
+5.4. SSL support for bufferevents with OpenSSL
+
+ There is now a bufferevent type that supports SSL/TLS using the
+ OpenSSL library. The code for this is build in a separate
+ library, libevent_openssl, so that your programs don't need to
+ link against OpenSSL unless they actually want SSL support.
+
+ There are two ways to construct one of these bufferevents, both
+ declared in <event2/bufferevent_ssl.h>. If you want to wrap an
+ SSL layer around an existing bufferevent, you would call the
+ bufferevent_openssl_filter_new() function. If you want to do SSL
+ on a socket directly, call bufferevent_openssl_socket_new().
+
+5.5. IOCP support for bufferevents on Windows
+
+ There is now a bufferevents backend that supports IOCP on Windows.
+ Supposedly, this will eventually make Windows IO much faster for
+ programs using bufferevents. We'll have to see; the code is not
+ currently optimized at all. To try it out, call the
+ event_base_start_iocp() method on an event_base before contructing
+ bufferevents.
+
+ This is tricky code; there are probably some bugs hiding here.
+
+5.6. Improved connect support for bufferevents.
+
+ You can now create a bufferevent that is not yet connected to any
+ host, and tell it to connect, either by address or by hostname.
+
+ The functions to do this are bufferevent_socket_connect and
+ bufferevent_socket_connect_hostname.
+
+5.7. Rate-limiting for bufferevents
+
+ If you need to limit the number of bytes read/written by a single
+ bufferevent, or by a group of them, you can do this with a new set of
+ bufferevent rate-limiting calls.
+
+6. Other improvements
+
+6.1. DNS improvements
+
+6.1.1. DNS: IPv6 nameservers
+
+ The evdns code now lets you have nameservers whose addresses are IPv6.
+
+6.1.2. DNS: Better security
+
+ Libevent 2.0 tries harder to resist DNS answer-sniping attacks than
+ earlier versions of evdns. See comments in the code for full details.
+
+ Notably, evdns now supports the "0x20 hack" to make it harder to
+ impersonate a DNS server. Additionally, Libevent now uses a strong
+ internal RNG to generate DNS transaction IDs, so you don't need to supply
+ your own.
+
+6.1.3. DNS: Getaddrinfo support
+
+ There's now an asynchronous getaddrinfo clone, evdns_getaddrinfo(),
+ to make the results of the evdns functions more usable. It doesn't
+ support every feature of a typical platform getaddrinfo() yet, but it
+ is quite close.
+
+ There is also a blocking evutil_getaddrinfo() declared in
+ event2/util.h, to provide a getaddrinfo() implementation for
+ platforms that don't have one, and smooth over the differences in
+ various platforms implementations of RFC3493.
+
+ Bufferevents provide bufferevent_connect_hostname(), which combines
+ the name lookup and connect operations.
+
+6.1.4. DNS: No more evdns globals
+
+ Like an event base, evdns operations are now supposed to use an evdns_base
+ argument. This makes them easier to wrap for other (more OO) languages,
+ and easier to control the lifetime of. The old evdns functions will
+ still, of course, continue working.
+
+6.2. Listener support
+
+ You can now more easily automate setting up a bound socket to listen for
+ TCP connections. Just use the evconnlistener_*() functions in the
+ event2/listener.h header.
+
+ The listener code supports IOCP on Windows if available.
+
+6.3. Secure RNG support
+
+ Network code very frequently needs a secure, hard-to-predict random number
+ generator. Some operating systems provide a good C implementation of one;
+ others do not. Libevent 2.0 now provides a consistent implementation
+ based on the arc4random code originally from OpenBSD. Libevent (and you)
+ can use the evutil_secure_rng_*() functions to access a fairly secure
+ random stream of bytes.
+
+6.4. HTTP
+
+ The evhttp uriencoding and uridecoding APIs have updated versions
+ that behave more correctly, and can handle strings with internal NULs.
+
+ The evhttp query parsing and URI parsing logic can now detect errors
+ more usefully. Moreover, we include an actual URI parsing function
+ (evhttp_uri_parse()) to correctly parse URIs, so as to discourage
+ people from rolling their own ad-hoc parsing functions.
+
+ There are now accessor functions for the useful fields of struct http
+ and friends; it shouldn't be necessary to access them directly any
+ more.
+
+ Libevent now lets you declare support for all specified HTTP methods,
+ including OPTIONS, PATCH, and so on. The default list is unchanged.
+
+ Numerous evhttp bugs also got fixed.
+
+7. Infrastructure improvements
+
+7.1. Better unit test framework
+
+ We now use a unit test framework that Nick wrote called "tinytest".
+ The main benefit from Libevent's point of view is that tests which
+ might mess with global state can all run each in their own
+ subprocess. This way, when there's a bug that makes one unit test
+ crash or mess up global state, it doesn't affect any others.
+
+7.2. Better unit tests
+
+ Despite all the code we've added, our unit tests are much better than
+ before. Right now, iterating over the different backends on various
+ platforms, I'm getting between 78% and 81% test coverage, compared
+ with less than 45% test coverage in Libevent 1.4.
+
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/whatsnew-2.1.txt b/fluent-bit/lib/monkey/mk_core/deps/libevent/whatsnew-2.1.txt
new file mode 100644
index 000000000..0be54ae11
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/whatsnew-2.1.txt
@@ -0,0 +1,690 @@
+ What's new in Libevent 2.1
+ Nick Mathewson
+
+0. Before we start
+
+0.1. About this document
+
+ This document describes the key differences between Libevent 2.0 and
+ Libevent 2.1, from a user's point of view. It's a work in progress.
+
+ For better documentation about libevent, see the links at
+ http://libevent.org/
+
+ Libevent 2.1 would not be possible without the generous help of
+ numerous volunteers. For a list of who did what in Libevent 2.1,
+ please see the ChangeLog!
+
+ NOTE: I am very sure that I missed some thing on this list. Caveat
+ haxxor.
+
+0.2. Where to get help
+
+ Try looking at the other documentation too. All of the header files
+ have documentation in the doxygen format; this gets turned into nice
+ HTML and linked to from the libevent.org website.
+
+ There is a work-in-progress book with reference manual at
+ http://www.wangafu.net/~nickm/libevent-book/ .
+
+ You can ask questions on the #libevent IRC channel at irc.oftc.net or
+ on the mailing list at libevent-users@freehaven.net. The mailing list
+ is subscribers-only, so you will need to subscribe before you post.
+
+0.3. Compatibility
+
+ Our source-compatibility policy is that correct code (that is to say,
+ code that uses public interfaces of Libevent and relies only on their
+ documented behavior) should have forward source compatibility: any
+ such code that worked with a previous version of Libevent should work
+ with this version too.
+
+ We don't try to do binary compatibility except within stable release
+ series, so binaries linked against any version of Libevent 2.0 will
+ probably need to be recompiled against Libevent 2.1.4-alpha if you
+ want to use it. It is probable that we'll break binary compatibility
+ again before Libevent 2.1 is stable.
+
+1. New APIs and features
+
+1.1. New ways to build libevent
+
+ We now provide an --enable-gcc-hardening configure option to turn on
+ GCC features designed for increased code security.
+
+ There is also an --enable-silent-rules configure option to make
+ compilation run more quietly with automake 1.11 or later.
+
+ You no longer need to use the --enable-gcc-warnings option to turn on
+ all of the GCC warnings that Libevent uses. The only change from
+ using that option now is to turn warnings into errors.
+
+ For IDE users, files that are not supposed to be built are now
+ surrounded with appropriate #ifdef lines to keep your IDE from getting
+ upset.
+
+ There is now an alternative cmake-based build process; cmake users
+ should see the relevant sections in the README.
+
+
+1.2. New functions for events and the event loop
+
+ If you're running Libevent with multiple event priorities, you might
+ want to make sure that Libevent checks for new events frequently, so
+ that time-consuming or numerous low-priority events don't keep it from
+ checking for new high-priority events. You can now use the
+ event_config_set_max_dispatch_interval() interface to ensure that the
+ loop checks for new events either every N microseconds, every M
+ callbacks, or both.
+
+ When configuring an event base, you can now choose whether you want
+ timers to be more efficient, or more precise. (This only has effect
+ on Linux for now.) Timers are efficient by default: to select more
+ precise timers, use the EVENT_BASE_FLAG_PRECISE_TIMER flag when
+ constructing the event_config, or set the EVENT_PRECISE_TIMER
+ environment variable to a non-empty string.
+
+ There is an EVLOOP_NO_EXIT_ON_EMPTY flag that tells event_base_loop()
+ to keep looping even when there are no pending events. (Ordinarily,
+ event_base_loop() will exit as soon as no events are pending.)
+
+ Past versions of Libevent have been annoying to use with some
+ memory-leak-checking tools, because Libevent allocated some global
+ singletons but provided no means to free them. There is now a
+ function, libevent_global_shutdown(), that you can use to free all
+ globally held resources before exiting, so that your leak-check tools
+ don't complain. (Note: this function doesn't free non-global things
+ like events, bufferevents, and so on; and it doesn't free anything
+ that wouldn't otherwise get cleaned up by the operating system when
+ your process exit()s. If you aren't using a leak-checking tool, there
+ is not much reason to call libevent_global_shutdown().)
+
+ There is a new event_base_get_npriorities() function to return the
+ number of priorities set in the event base.
+
+ Libevent 2.0 added an event_new() function to construct a new struct
+ event on the heap. Unfortunately, with event_new(), there was no
+ equivalent for:
+
+ struct event ev;
+ event_assign(&ev, base, fd, EV_READ, callback, &ev);
+
+ In other words, there was no easy way for event_new() to set up an
+ event so that the event itself would be its callback argument.
+ Libevent 2.1 lets you do this by passing "event_self_cbarg()" as the
+ callback argument:
+
+ struct event *evp;
+ evp = event_new(base, fd, EV_READ, callback,
+ event_self_cbarg());
+
+ There's also a new event_base_get_running_event() function you can
+ call from within a Libevent callback to get a pointer to the current
+ event. This should never be strictly necessary, but it's sometimes
+ convenient.
+
+ The event_base_once() function used to leak some memory if the event
+ that it added was never actually triggered. Now, its memory is
+ tracked in the event_base and freed when the event_base is freed.
+ Note however that Libevent doesn't know how to free any information
+ passed as the callback argument to event_base_once is still something
+ you'll might need a way to de-allocate yourself.
+
+ There is an event_get_priority() function to return an event's
+ priority.
+
+ By analogy to event_base_loopbreak(), there is now an
+ event_base_loopcontinue() that tells Libevent to stop processing
+ active event callbacks, and re-scan for new events right away.
+
+ There's a function, event_base_foreach_event(), that can iterate over
+ every event currently pending or active on an event base, and invoke a
+ user-supplied callback on each. The callback must not alter the events
+ or add or remove anything to the event base.
+
+ We now have an event_remove_timer() function to remove the timeout on
+ an event while leaving its socket and/or signal triggers unchanged.
+ (If we were designing the API from scratch, this would be the behavior
+ of "event_add(ev, NULL)" on an already-added event with a timeout. But
+ that's a no-op in past versions of Libevent, and we don't want to
+ break compatibility.)
+
+ You can use the new event_base_get_num_events() function to find the
+ number of events active or pending on an event_base. To find the
+ largest number of events that there have been since the last call, use
+ event_base_get_max_events().
+
+ You can now activate all the events waiting for a given fd or signal
+ using the event_base_active_by_fd() and event_base_active_by_signal()
+ APIs.
+
+ On backends that support it (currently epoll), there is now an
+ EV_CLOSED flag that programs can use to detect when a socket has
+ closed without having to read all the bytes until receiving an EOF.
+
+1.3. Event finalization
+
+ [NOTE: This is an experimental feature in Libevent 2.1.3-alpha. Though
+ it seems solid so far, its API might change between now and the first
+ release candidate for Libevent 2.1.]
+
+1.3.1. Why event finalization?
+
+ Libevent 2.1 now supports an API for safely "finalizing" events that
+ might be running in multiple threads, and provides a way to slightly
+ change the semantics of event_del() to prevent deadlocks in
+ multithreaded programs.
+
+ To motivate this feature, consider the following code, in the context
+ of a mulithreaded Libevent application:
+
+ struct connection *conn = event_get_callback_arg(ev);
+ event_del(ev);
+ connection_free(conn);
+
+ Suppose that the event's callback might be running in another thread,
+ and using the value of "conn" concurrently. We wouldn't want to
+ execute the connection_free() call until "conn" is no longer in use.
+ How can we make this code safe?
+
+ Libevent 2.0 answered that question by saying that the event_del()
+ call should block if the event's callback is running in another
+ thread. That way, we can be sure that event_del() has canceled the
+ callback (if the callback hadn't started running yet), or has waited
+ for the callback to finish.
+
+ But now suppose that the data structure is protected by a lock, and we
+ have the following code:
+
+ void check_disable(struct connection *connection) {
+ lock(connection);
+ if (should_stop_reading(connection))
+ event_del(connection->read_event);
+ unlock(connection);
+ }
+
+ What happens when we call check_disable() from a callback and from
+ another thread? Let's say that the other thread gets the lock
+ first. If it decides to call event_del(), it will wait for the
+ callback to finish. But meanwhile, the callback will be waiting for
+ the lock on the connection. Since each threads is waiting for the
+ other one to release a resource, the program will deadlock.
+
+ This bug showed up in multithreaded bufferevent programs in 2.1,
+ particularly when freeing bufferevents. (For more information, see
+ the "Deadlock when calling bufferevent_free from an other thread"
+ thread on libevent-users starting on 6 August 2012 and running through
+ February of 2013. You might also like to read my earlier writeup at
+ http://archives.seul.org/libevent/users/Feb-2012/msg00053.html and
+ the ensuing discussion.)
+
+1.3.2. The EV_FINALIZE flag and avoiding deadlock
+
+ To prevent the deadlock condition described above, Libevent
+ 2.1.3-alpha adds a new flag, "EV_FINALIZE". You can pass it to
+ event_new() and event_assign() along with EV_READ, EV_WRITE, and the
+ other event flags.
+
+ When an event is constructed with the EV_FINALIZE flag, event_del()
+ will not block on that event, even when the event's callback is
+ running in another thread. By using EV_FINALIZE, you are therefore
+ promising not to use the "event_del(ev); free(event_get_callback_arg(ev));"
+ pattern, but rather to use one of the finalization functions below to
+ clean up the event.
+
+ EV_FINALIZE has no effect on a single-threaded program, or on a
+ program where events are only used from one thread.
+
+
+ There are also two new variants of event_del() that you can use for
+ more fine-grained control:
+ event_del_noblock(ev)
+ event_del_block(ev)
+ The event_del_noblock() function will never block, even if the event
+ callback is running in another thread and doesn't have the EV_FINALIZE
+ flag. The event_del_block() function will _always_ block if the event
+ callback is running in another thread, even if the event _does_ have
+ the EV_FINALIZE flag.
+
+ [A future version of Libevent may have a way to make the EV_FINALIZE
+ flag the default.]
+
+1.3.3. Safely finalizing events
+
+ To safely tear down an event that may be running, Libevent 2.1.3-alpha
+ introduces event_finalize() and event_free_finalize(). You call them
+ on an event, and provide a finalizer callback to be run on the event
+ and its callback argument once the event is definitely no longer
+ running.
+
+ With event_free_finalize(), the event is also freed once the finalizer
+ callback has been invoked.
+
+ A finalized event cannot be re-added or activated. The finalizer
+ callback must not add events, activate events, or attempt to
+ "resucitate" the event being finalized in any way.
+
+ If any finalizer callbacks are pending as the event_base is being
+ freed, they will be invoked. You can override this behavior with the
+ new function event_base_free_nofinalize().
+
+1.4. New debugging features
+
+ You can now turn on debug logs at runtime using a new function,
+ event_enable_debug_logging().
+
+ The event_enable_lock_debugging() function is now spelled correctly.
+ You can still use the old "event_enable_lock_debuging" name, though,
+ so your old programs shouldnt' break.
+
+ There's also been some work done to try to make the debugging logs
+ more generally useful.
+
+1.5. New evbuffer functions
+
+ In Libevent 2.0, we introduced evbuffer_add_file() to add an entire
+ file's contents to an evbuffer, and then send them using sendfile() or
+ mmap() as appropriate. This API had some drawbacks, however.
+ Notably, it created one mapping or fd for every instance of the same
+ file added to any evbuffer. Also, adding a file to an evbuffer could
+ make that buffer unusable with SSL bufferevents, filtering
+ bufferevents, and any code that tried to read the contents of the
+ evbuffer.
+
+ Libevent 2.1 adds a new evbuffer_file_segment API to solve these
+ problems. Now, you can use evbuffer_file_segment_new() to construct a
+ file-segment object, and evbuffer_add_file_segment() to insert it (or
+ part of it) into an evbuffer. These segments avoid creating redundant
+ maps or fds. Better still, the code is smart enough (when the OS
+ supports sendfile) to map the file when that's necessary, and use
+ sendfile() otherwise.
+
+ File segments can receive callback functions that are invoked when the
+ file segments are freed.
+
+ The evbuffer_ptr interface has been extended so that an evbuffer_ptr
+ can now yield a point just after the end of the buffer. This makes
+ many algorithms simpler to implement.
+
+ There's a new evbuffer_add_buffer() interface that you can use to add
+ one buffer to another nondestructively. When you say
+ evbuffer_add_buffer_reference(outbuf, inbuf), outbuf now contains a
+ reference to the contents of inbuf.
+
+ To aid in adding data in bulk while minimizing evbuffer calls, there
+ is an evbuffer_add_iovec() function.
+
+ There's a new evbuffer_copyout_from() variant function to enable
+ copying data nondestructively from the middle of a buffer.
+
+ evbuffer_readln() now supports an EVBUFFER_EOL_NUL argument to fetch
+ NUL-terminated strings from buffers.
+
+1.6. New functions and features: bufferevents
+
+ You can now use the bufferevent_getcb() function to find out a
+ bufferevent's callbacks. Previously, there was no supported way to do
+ that.
+
+ The largest chunk readable or writeable in a single bufferevent
+ callback is no longer hardcoded; it's now configurable with
+ the new functions bufferevent_set_max_single_read() and
+ bufferevent_set_max_single_write().
+
+ For consistency, OpenSSL bufferevents now make sure to always set one
+ of BEV_EVENT_READING or BEV_EVENT_WRITING when invoking an event
+ callback.
+
+ Calling bufferevent_set_timeouts(bev, NULL, NULL) now removes the
+ timeouts from socket and ssl bufferevents correctly.
+
+ You can find the priority at which a bufferevent runs with
+ bufferevent_get_priority().
+
+ The function bufferevent_get_token_bucket_cfg() can retrieve the
+ rate-limit settings for a bufferevent; bufferevent_getwatermark() can
+ return a bufferevent's current watermark settings.
+
+ You can manually trigger a bufferevent's callbacks via
+ bufferevent_trigger() and bufferevent_trigger_event().
+
+1.7. New functions and features: evdns
+
+ The previous evdns interface used an "open a test UDP socket" trick in
+ order to detect IPv6 support. This was a hack, since it would
+ sometimes badly confuse people's firewall software, even though no
+ packets were sent. The current evdns interface-detection code uses
+ the appropriate OS functions to see which interfaces are configured.
+
+ The evdns_base_new() function now has multiple possible values for its
+ second (flags) argument. Using 1 and 0 have their old meanings, though the
+ 1 flag now has a symbolic name of EVDNS_BASE_INITIALIZE_NAMESERVERS.
+ A second flag is now supported too: the EVDNS_BASE_DISABLE_WHEN_INACTIVE
+ flag, which tells the evdns_base that it should not prevent Libevent from
+ exiting while it has no DNS requests in progress.
+
+ There is a new evdns_base_clear_host_addresses() function to remove
+ all the /etc/hosts addresses registered with an evdns instance.
+
+1.8. New functions and features: evconnlistener
+
+ Libevent 2.1 adds the following evconnlistener flags:
+
+ LEV_OPT_DEFERRED_ACCEPT -- Tells the OS that it doesn't need to
+ report sockets as having arrived until the initiator has sent some
+ data too. This can greatly improve performance with protocols like
+ HTTP where the client always speaks first. On operating systems
+ that don't support this functionality, this option has no effect.
+
+ LEV_OPT_DISABLED -- Creates an evconnlistener in the disabled (not
+ listening) state.
+
+ Libevent 2.1 changes the behavior of the LEV_OPT_CLOSE_ON_EXEC
+ flag. Previously, it would apply to the listener sockets, but not to
+ the accepted sockets themselves. That's almost never what you want.
+ Now, it applies both to the listener and the accepted sockets.
+
+1.9. New functions and features: evhttp
+
+ **********************************************************************
+ NOTE: The evhttp module will eventually be deprecated in favor of Mark
+ Ellzey's libevhtp library. Don't worry -- this won't happen until
+ libevhtp provides every feature that evhttp does, and provides a
+ compatible interface that applications can use to migrate.
+ **********************************************************************
+
+ Previously, you could only set evhttp timeouts in increments of one
+ second. Now, you can use evhttp_set_timeout_tv() and
+ evhttp_connection_set_timeout_tv() to configure
+ microsecond-granularity timeouts.
+
+ There are a new pair of functions: evhttp_set_bevcb() and
+ evhttp_connection_base_bufferevent_new(), that you can use to
+ configure which bufferevents will be used for incoming and outgoing
+ http connections respectively. These functions, combined with SSL
+ bufferevents, should enable HTTPS support.
+
+ There's a new evhttp_foreach_bound_socket() function to iterate over
+ every listener on an evhttp object.
+
+ Whitespace between lines in headers is now folded into a single space;
+ whitespace at the end of a header is now removed.
+
+ The socket errno value is now preserved when invoking an http error
+ callback.
+
+ There's a new kind of request callback for errors; you can set it with
+ evhttp_request_set_error_cb(). It gets called when there's a request error,
+ and actually reports the error code and lets you figure out which request
+ failed.
+
+ You can navigate from an evhttp_connection back to its evhttp with the
+ new evhttp_connection_get_server() function.
+
+ You can override the default HTTP Content-Type with the new
+ evhttp_set_default_content_type() function
+
+ There's a new evhttp_connection_get_addr() API to return the peer
+ address of an evhttp_connection.
+
+ The new evhttp_send_reply_chunk_with_cb() is a variant of
+ evhttp_send_reply_chunk() with a callback to be invoked when the
+ chunk is sent.
+
+ The evhttp_request_set_header_cb() facility adds a callback to be
+ invoked while parsing headers.
+
+ The evhttp_request_set_on_complete_cb() facility adds a callback to be
+ invoked on request completion.
+
+1.10. New functions and features: evutil
+
+ There's a function "evutil_secure_rng_set_urandom_device_file()" that
+ you can use to override the default file that Libevent uses to seed
+ its (sort-of) secure RNG.
+
+2. Cross-platform performance improvements
+
+2.1. Better data structures
+
+ We replaced several users of the sys/queue.h "TAILQ" data structure
+ with the "LIST" data structure. Because this data type doesn't
+ require FIFO access, it requires fewer pointer checks and
+ manipulations to keep it in line.
+
+ All previous versions of Libevent have kept every pending (added)
+ event in an "eventqueue" data structure. Starting in Libevent 2.0,
+ however, this structure became redundant: every pending timeout event
+ is stored in the timeout heap or in one of the common_timeout queues,
+ and every pending fd or signal event is stored in an evmap. Libevent
+ 2.1 removes this data structure, and thereby saves all of the code
+ that we'd been using to keep it updated.
+
+2.2. Faster activations and timeouts
+
+ It's a common pattern in older code to use event_base_once() with a
+ 0-second timeout to ensure that a callback will get run 'as soon as
+ possible' in the current iteration of the Libevent loop. We optimize
+ this case by calling event_active() directly, and bypassing the
+ timeout pool. (People who are using this pattern should also consider
+ using event_active() themselves.)
+
+ Libevent 2.0 would wake up a polling event loop whenever the first
+ timeout in the event loop was adjusted--whether it had become earlier
+ or later. We now only notify the event loop when a change causes the
+ expiration time to become _sooner_ than it would have been otherwise.
+
+ The timeout heap code is now optimized to perform fewer comparisons
+ and shifts when changing or removing a timeout.
+
+ Instead of checking for a wall-clock time jump every time we call
+ clock_gettime(), we now check only every 5 seconds. This should save
+ a huge number of gettimeofday() calls.
+
+2.3. Microoptimizations
+
+ Internal event list maintainance no longer use the antipattern where
+ we have one function with multiple totally independent behaviors
+ depending on an argument:
+ #define OP1 1
+ #define OP2 2
+ #define OP3 3
+ void func(int operation, struct event *ev) {
+ switch (op) {
+ ...
+ }
+ }
+ Instead, these functions are now split into separate functions for
+ each operation:
+ void func_op1(struct event *ev) { ... }
+ void func_op2(struct event *ev) { ... }
+ void func_op3(struct event *ev) { ... }
+
+ This produces better code generation and inlining decisions on some
+ compilers, and makes the code easier to read and check.
+
+2.4. Evbuffer performance improvements
+
+ The EVBUFFER_EOL_CRLF line-ending type is now much faster, thanks to
+ smart optimizations.
+
+2.5. HTTP performance improvements
+
+ o Performance tweak to evhttp_parse_request_line. (aee1a97 Mark Ellzey)
+ o Add missing break to evhttp_parse_request_line (0fcc536)
+
+2.6. Coarse timers by default on Linux
+
+ Due to limitations of the epoll interface, Libevent programs using epoll
+ have not previously been able to wait for timeouts with accuracy smaller
+ than 1 millisecond. But Libevent had been using CLOCK_MONOTONIC for
+ timekeeping on Linux, which is needlessly expensive: CLOCK_MONOTONIC_COARSE
+ has approximately the resolution corresponding to epoll, and is much faster
+ to invoke than CLOCK_MONOTONIC.
+
+ To disable coarse timers, and get a more plausible precision, use the
+ new EVENT_BASE_FLAG_PRECISE_TIMER flag when setting up your event base.
+
+3. Backend/OS-specific improvements
+
+3.1. Linux-specific improvements
+
+ The logic for deciding which arguements to use with epoll_ctl() is now
+ a table-driven lookup, rather than the previous pile of cascading
+ branches. This should minimize epoll_ctl() calls and make the epoll
+ code run a little faster on change-heavy loads.
+
+ Libevent now takes advantage of Linux's support for enhanced APIs
+ (e.g., SOCK_CLOEXEC, SOCK_NONBLOCK, accept4, pipe2) that allow us to
+ simultaneously create a socket, make it nonblocking, and make it
+ close-on-exec. This should save syscalls throughout our codebase, and
+ avoid race-conditions if an exec() occurs after a socket is socket is
+ created but before we can make it close-on-execute on it.
+
+3.2. Windows-specific improvements
+
+ We now use GetSystemTimeAsFileTime to implement gettimeofday. It's
+ significantly faster and more accurate than our old ftime()-based approach.
+
+3.3. Improvements in the solaris evport backend.
+
+ The evport backend has been updated to use many of the infrastructure
+ improvements from Libevent 2.0. Notably, it keeps track of per-fd
+ information using the evmap infrastructure, and removes a number of
+ linear scans over recently-added events. This last change makes it
+ efficient to receive many more events per evport_getn() call, thereby
+ reducing evport overhead in general.
+
+3.4. OSX backend improvements
+
+ The OSX select backend doesn't like to have more than a certain number
+ of fds set unless an "unlimited select" option has been set.
+ Therefore, we now set it.
+
+3.5. Monotonic clocks on even more platforms
+
+ Libevent previously used a monotonic clock for its internal timekeeping
+ only on platforms supporting the POSIX clock_gettime() interface. Now,
+ Libevent has support for monotonic clocks on OSX and Windows too, and a
+ fallback implementation for systems without monotonic clocks that will at
+ least keep time running forwards.
+
+ Using monotonic timers makes Libevent more resilient to changes in the
+ system time, as can happen in small amounts due to clock adjustments from
+ NTP, or in large amounts due to users who move their system clocks all over
+ the timeline in order to keep nagware from nagging them.
+
+3.6. Faster cross-thread notification on kqueue
+
+ When a thread other than the one in which the main event loop is
+ running needs to wake the thread running the main event loop, Libevent
+ usually writes to a socketpair in order to force the main event loop
+ to wake up. On Linux, we've been able to use eventfd() instead. Now
+ on BSD and OSX systems (any anywhere else that has kqueue with the
+ EVFILT_USER extension), we can use EVFILT_USER to wake up the main
+ thread from kqueue. This should be a tiny bit faster than the
+ previous approach.
+
+4. Infrastructure improvements
+
+4.1. Faster tests
+
+ I've spent some time to try to make the unit tests run faster in
+ Libevent 2.1. Nearly all of this was a matter of searching slow tests
+ for unreasonably long timeouts, and cutting them down to reasonably
+ long delays, though on one or two cases I actually had to parallelize
+ an operation or improve an algorithm.
+
+ On my desktop, a full "make verify" run of Libevent 2.0.18-stable
+ requires about 218 seconds. Libevent 2.1.1-alpha cuts this down to
+ about 78 seconds.
+
+ Faster unit tests are great, since they let programmers test their
+ changes without losing their train of thought.
+
+4.2. Finicky tests are now off-by-default
+
+ The Tinytest unit testing framework now supports optional tests, and
+ Libevent uses them. By default, Libevent's unit testing framework
+ does not run tests that require a working network, and does not run
+ tests that tend to fail on heavily loaded systems because of timing
+ issues. To re-enable all tests, run ./test/regress using the "@all"
+ alias.
+
+4.3. Modernized use of autotools
+
+ Our autotools-based build system has been updated to build without
+ warnings on recent autoconf/automake versions.
+
+ Libevent's autotools makefiles are no longer recursive. This allows
+ make to use the maximum possible parallelism to do the minimally
+ necessary amount of work. See Peter Miller's "Recursive Make
+ Considered Harmful" at http://miller.emu.id.au/pmiller/books/rmch/ for
+ more information here.
+
+ We now use the "quiet build" option to suppress distracting messages
+ about which commandlines are running. You can get them back with
+ "make V=1".
+
+4.4. Portability
+
+ Libevent now uses large-file support internally on platforms where it
+ matters. You shouldn't need to set _LARGEFILE or OFFSET_BITS or
+ anything magic before including the Libevent headers, either, since
+ Libevent now sets the size of ev_off_t to the size of off_t that it
+ received at compile time, not to some (possibly different) size based
+ on current macro definitions when your program is building.
+
+ We now also use the Autoconf AC_USE_SYSTEM_EXTENSIONS mechanism to
+ enable per-system macros needed to enable not-on-by-default features.
+ Unlike the rest of the autoconf macros, we output these to an
+ internal-use-only evconfig-private.h header, since their names need to
+ survive unmangled. This lets us build correctly on more platforms,
+ and avoid inconsistencies when some files define _GNU_SOURCE and
+ others don't.
+
+ Libevent now tries to detect OpenSSL via pkg-config.
+
+4.5. Standards conformance
+
+ Previous Libevent versions had no consistent convention for internal
+ vs external identifiers, and used identifiers starting with the "_"
+ character throughout the codebase. That's no good, since the C
+ standard says that identifiers beginning with _ are reserved. I'm not
+ aware of having any collisions with system identifiers, but it's best
+ to fix these things before they cause trouble.
+
+ We now avoid all use of the _identifiers in the Libevent source code.
+ These changes were made *mainly* through the use of automated scripts,
+ so there shouldn't be any mistakes, but you never know.
+
+ As an exception, the names _EVENT_LOG_DEBUG, _EVENT_LOG_MSG_,
+ _EVENT_LOG_WARN, and _EVENT_LOG_ERR are still exposed in event.h: they
+ are now deprecated, but to support older code, they will need to stay
+ around for a while. New code should use EVENT_LOG_DEBUG,
+ EVENT_LOG_MSG, EVENT_LOG_WARN, and EVENT_LOG_ERR instead.
+
+4.6. Event and callback refactoring
+
+ As a simplification and optimization to Libevent's "deferred callback"
+ logic (introduced in 2.0 to avoid callback recursion), Libevent now
+ treats all of its deferrable callback types using the same logic it
+ uses for active events. Now deferred events no longer cause priority
+ inversion, no longer require special code to cancel them, and so on.
+
+ Regular events and deferred callbacks now both descend from an
+ internal light-weight event_callback supertype, and both support
+ priorities and take part in the other anti-priority-inversion
+ mechanisms in Libevent.
+
+ To avoid starvation from callback recursion (which was the reason we
+ introduced "deferred callbacks" in the first place) the implementation
+ now allows an event callback to be scheduled as "active later":
+ instead of running in the current iteration of the event loop, it runs
+ in the next one.
+
+5. Testing
+
+ Libevent's test coverage level is more or less unchanged since before:
+ we still have over 80% line coverage in our tests on Linux and OSX.
+ There are some under-tested modules, though: we need to fix those.
diff --git a/fluent-bit/lib/monkey/mk_core/deps/libevent/win32select.c b/fluent-bit/lib/monkey/mk_core/deps/libevent/win32select.c
new file mode 100644
index 000000000..1766858c2
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/deps/libevent/win32select.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2007-2012 Niels Provos and Nick Mathewson
+ * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2003 Michael A. Davis <mike@datanerds.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef _WIN32
+
+#include <winsock2.h>
+#include <windows.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event2/util.h"
+#include "util-internal.h"
+#include "log-internal.h"
+#include "event2/event.h"
+#include "event-internal.h"
+#include "evmap-internal.h"
+#include "event2/thread.h"
+#include "evthread-internal.h"
+#include "time-internal.h"
+
+#define XFREE(ptr) do { if (ptr) mm_free(ptr); } while (0)
+
+extern struct event_list timequeue;
+extern struct event_list addqueue;
+
+struct win_fd_set {
+ unsigned int fd_count;
+ SOCKET fd_array[1];
+};
+
+/* MSDN says this is required to handle SIGFPE */
+volatile double SIGFPE_REQ = 0.0f;
+
+struct idx_info {
+ int read_pos_plus1;
+ int write_pos_plus1;
+};
+
+struct win32op {
+ unsigned num_fds_in_fd_sets;
+ int resize_out_sets;
+ struct win_fd_set *readset_in;
+ struct win_fd_set *writeset_in;
+ struct win_fd_set *readset_out;
+ struct win_fd_set *writeset_out;
+ struct win_fd_set *exset_out;
+ unsigned signals_are_broken : 1;
+};
+
+static void *win32_init(struct event_base *);
+static int win32_add(struct event_base *, evutil_socket_t, short old, short events, void *idx_);
+static int win32_del(struct event_base *, evutil_socket_t, short old, short events, void *idx_);
+static int win32_dispatch(struct event_base *base, struct timeval *);
+static void win32_dealloc(struct event_base *);
+
+struct eventop win32ops = {
+ "win32",
+ win32_init,
+ win32_add,
+ win32_del,
+ win32_dispatch,
+ win32_dealloc,
+ 0, /* doesn't need reinit */
+ 0, /* No features supported. */
+ sizeof(struct idx_info),
+};
+
+#define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET)))
+
+static int
+grow_fd_sets(struct win32op *op, unsigned new_num_fds)
+{
+ size_t size;
+
+ EVUTIL_ASSERT(new_num_fds >= op->readset_in->fd_count &&
+ new_num_fds >= op->writeset_in->fd_count);
+ EVUTIL_ASSERT(new_num_fds >= 1);
+
+ size = FD_SET_ALLOC_SIZE(new_num_fds);
+ if (!(op->readset_in = mm_realloc(op->readset_in, size)))
+ return (-1);
+ if (!(op->writeset_in = mm_realloc(op->writeset_in, size)))
+ return (-1);
+ op->resize_out_sets = 1;
+ op->num_fds_in_fd_sets = new_num_fds;
+ return (0);
+}
+
+static int
+do_fd_set(struct win32op *op, struct idx_info *ent, evutil_socket_t s, int read)
+{
+ struct win_fd_set *set = read ? op->readset_in : op->writeset_in;
+ if (read) {
+ if (ent->read_pos_plus1 > 0)
+ return (0);
+ } else {
+ if (ent->write_pos_plus1 > 0)
+ return (0);
+ }
+ if (set->fd_count == op->num_fds_in_fd_sets) {
+ if (grow_fd_sets(op, op->num_fds_in_fd_sets*2))
+ return (-1);
+ /* set pointer will have changed and needs reiniting! */
+ set = read ? op->readset_in : op->writeset_in;
+ }
+ set->fd_array[set->fd_count] = s;
+ if (read)
+ ent->read_pos_plus1 = set->fd_count+1;
+ else
+ ent->write_pos_plus1 = set->fd_count+1;
+ return (set->fd_count++);
+}
+
+static int
+do_fd_clear(struct event_base *base,
+ struct win32op *op, struct idx_info *ent, int read)
+{
+ int i;
+ struct win_fd_set *set = read ? op->readset_in : op->writeset_in;
+ if (read) {
+ i = ent->read_pos_plus1 - 1;
+ ent->read_pos_plus1 = 0;
+ } else {
+ i = ent->write_pos_plus1 - 1;
+ ent->write_pos_plus1 = 0;
+ }
+ if (i < 0)
+ return (0);
+ if (--set->fd_count != (unsigned)i) {
+ struct idx_info *ent2;
+ SOCKET s2;
+ s2 = set->fd_array[i] = set->fd_array[set->fd_count];
+
+ ent2 = evmap_io_get_fdinfo_(&base->io, s2);
+
+ if (!ent2) /* This indicates a bug. */
+ return (0);
+ if (read)
+ ent2->read_pos_plus1 = i+1;
+ else
+ ent2->write_pos_plus1 = i+1;
+ }
+ return (0);
+}
+
+#define NEVENT 32
+void *
+win32_init(struct event_base *base)
+{
+ struct win32op *winop;
+ size_t size;
+ if (!(winop = mm_calloc(1, sizeof(struct win32op))))
+ return NULL;
+ winop->num_fds_in_fd_sets = NEVENT;
+ size = FD_SET_ALLOC_SIZE(NEVENT);
+ if (!(winop->readset_in = mm_malloc(size)))
+ goto err;
+ if (!(winop->writeset_in = mm_malloc(size)))
+ goto err;
+ if (!(winop->readset_out = mm_malloc(size)))
+ goto err;
+ if (!(winop->writeset_out = mm_malloc(size)))
+ goto err;
+ if (!(winop->exset_out = mm_malloc(size)))
+ goto err;
+ winop->readset_in->fd_count = winop->writeset_in->fd_count = 0;
+ winop->readset_out->fd_count = winop->writeset_out->fd_count
+ = winop->exset_out->fd_count = 0;
+
+ if (evsig_init_(base) < 0)
+ winop->signals_are_broken = 1;
+
+ evutil_weakrand_seed_(&base->weakrand_seed, 0);
+
+ return (winop);
+ err:
+ XFREE(winop->readset_in);
+ XFREE(winop->writeset_in);
+ XFREE(winop->readset_out);
+ XFREE(winop->writeset_out);
+ XFREE(winop->exset_out);
+ XFREE(winop);
+ return (NULL);
+}
+
+int
+win32_add(struct event_base *base, evutil_socket_t fd,
+ short old, short events, void *idx_)
+{
+ struct win32op *win32op = base->evbase;
+ struct idx_info *idx = idx_;
+
+ if ((events & EV_SIGNAL) && win32op->signals_are_broken)
+ return (-1);
+
+ if (!(events & (EV_READ|EV_WRITE)))
+ return (0);
+
+ event_debug(("%s: adding event for %d", __func__, (int)fd));
+ if (events & EV_READ) {
+ if (do_fd_set(win32op, idx, fd, 1)<0)
+ return (-1);
+ }
+ if (events & EV_WRITE) {
+ if (do_fd_set(win32op, idx, fd, 0)<0)
+ return (-1);
+ }
+ return (0);
+}
+
+int
+win32_del(struct event_base *base, evutil_socket_t fd, short old, short events,
+ void *idx_)
+{
+ struct win32op *win32op = base->evbase;
+ struct idx_info *idx = idx_;
+
+ event_debug(("%s: Removing event for "EV_SOCK_FMT,
+ __func__, EV_SOCK_ARG(fd)));
+ if (events & EV_READ)
+ do_fd_clear(base, win32op, idx, 1);
+ if (events & EV_WRITE)
+ do_fd_clear(base, win32op, idx, 0);
+
+ return 0;
+}
+
+static void
+fd_set_copy(struct win_fd_set *out, const struct win_fd_set *in)
+{
+ out->fd_count = in->fd_count;
+ memcpy(out->fd_array, in->fd_array, in->fd_count * (sizeof(SOCKET)));
+}
+
+/*
+ static void dump_fd_set(struct win_fd_set *s)
+ {
+ unsigned int i;
+ printf("[ ");
+ for(i=0;i<s->fd_count;++i)
+ printf("%d ",(int)s->fd_array[i]);
+ printf("]\n");
+ }
+*/
+
+int
+win32_dispatch(struct event_base *base, struct timeval *tv)
+{
+ struct win32op *win32op = base->evbase;
+ int res = 0;
+ unsigned j, i;
+ int fd_count;
+ SOCKET s;
+
+ if (win32op->resize_out_sets) {
+ size_t size = FD_SET_ALLOC_SIZE(win32op->num_fds_in_fd_sets);
+ if (!(win32op->readset_out = mm_realloc(win32op->readset_out, size)))
+ return (-1);
+ if (!(win32op->exset_out = mm_realloc(win32op->exset_out, size)))
+ return (-1);
+ if (!(win32op->writeset_out = mm_realloc(win32op->writeset_out, size)))
+ return (-1);
+ win32op->resize_out_sets = 0;
+ }
+
+ fd_set_copy(win32op->readset_out, win32op->readset_in);
+ fd_set_copy(win32op->exset_out, win32op->writeset_in);
+ fd_set_copy(win32op->writeset_out, win32op->writeset_in);
+
+ fd_count =
+ (win32op->readset_out->fd_count > win32op->writeset_out->fd_count) ?
+ win32op->readset_out->fd_count : win32op->writeset_out->fd_count;
+
+ if (!fd_count) {
+ long msec = tv ? evutil_tv_to_msec_(tv) : LONG_MAX;
+ /* Sleep's DWORD argument is unsigned long */
+ if (msec < 0)
+ msec = LONG_MAX;
+ /* Windows doesn't like you to call select() with no sockets */
+ Sleep(msec);
+ return (0);
+ }
+
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ res = select(fd_count,
+ (struct fd_set*)win32op->readset_out,
+ (struct fd_set*)win32op->writeset_out,
+ (struct fd_set*)win32op->exset_out, tv);
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ event_debug(("%s: select returned %d", __func__, res));
+
+ if (res <= 0) {
+ return res;
+ }
+
+ if (win32op->readset_out->fd_count) {
+ i = evutil_weakrand_range_(&base->weakrand_seed,
+ win32op->readset_out->fd_count);
+ for (j=0; j<win32op->readset_out->fd_count; ++j) {
+ if (++i >= win32op->readset_out->fd_count)
+ i = 0;
+ s = win32op->readset_out->fd_array[i];
+ evmap_io_active_(base, s, EV_READ);
+ }
+ }
+ if (win32op->exset_out->fd_count) {
+ i = evutil_weakrand_range_(&base->weakrand_seed,
+ win32op->exset_out->fd_count);
+ for (j=0; j<win32op->exset_out->fd_count; ++j) {
+ if (++i >= win32op->exset_out->fd_count)
+ i = 0;
+ s = win32op->exset_out->fd_array[i];
+ evmap_io_active_(base, s, EV_WRITE);
+ }
+ }
+ if (win32op->writeset_out->fd_count) {
+ SOCKET s;
+ i = evutil_weakrand_range_(&base->weakrand_seed,
+ win32op->writeset_out->fd_count);
+ for (j=0; j<win32op->writeset_out->fd_count; ++j) {
+ if (++i >= win32op->writeset_out->fd_count)
+ i = 0;
+ s = win32op->writeset_out->fd_array[i];
+ evmap_io_active_(base, s, EV_WRITE);
+ }
+ }
+ return (0);
+}
+
+void
+win32_dealloc(struct event_base *base)
+{
+ struct win32op *win32op = base->evbase;
+
+ evsig_dealloc_(base);
+ if (win32op->readset_in)
+ mm_free(win32op->readset_in);
+ if (win32op->writeset_in)
+ mm_free(win32op->writeset_in);
+ if (win32op->readset_out)
+ mm_free(win32op->readset_out);
+ if (win32op->writeset_out)
+ mm_free(win32op->writeset_out);
+ if (win32op->exset_out)
+ mm_free(win32op->exset_out);
+ /* XXXXX free the tree. */
+
+ memset(win32op, 0, sizeof(*win32op));
+ mm_free(win32op);
+}
+
+#endif
diff --git a/fluent-bit/lib/monkey/mk_core/external/README.md b/fluent-bit/lib/monkey/mk_core/external/README.md
new file mode 100644
index 000000000..7e393a815
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/external/README.md
@@ -0,0 +1,3 @@
+## Windows Pthread
+
+Code taken from: https://github.com/janbar/cppmyth
diff --git a/fluent-bit/lib/monkey/mk_core/external/winpthreads.c b/fluent-bit/lib/monkey/mk_core/external/winpthreads.c
new file mode 100644
index 000000000..db4951989
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/external/winpthreads.c
@@ -0,0 +1,1261 @@
+/*
+ * Posix Threads library for Microsoft Windows
+ *
+ * Use at own risk, there is no implied warranty to this code.
+ * It uses undocumented features of Microsoft Windows that can change
+ * at any time in the future.
+ *
+ * (C) 2010 Lockless Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Lockless Inc. nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Version 1.0.1 Released 2 Feb 2012
+ * Fixes pthread_barrier_destroy() to wait for threads to exit the barrier.
+ */
+
+#include <mk_core/external/winpthreads.h>
+#include <sys/timeb.h>
+#include <setjmp.h>
+#include <intrin.h>
+#include <process.h>
+
+typedef struct _pthread_cleanup _pthread_cleanup;
+struct _pthread_cleanup
+{
+ void (*func)(void *);
+ void *arg;
+ _pthread_cleanup *next;
+};
+
+struct _pthread_v
+{
+ void *ret_arg;
+ void *(* func)(void *);
+ _pthread_cleanup *clean;
+ HANDLE h;
+ int cancelled;
+ unsigned p_state;
+ unsigned keymax;
+ void **keyval;
+
+ jmp_buf jb;
+};
+
+volatile long _pthread_cancelling;
+
+int _pthread_concur;
+
+/* Will default to zero as needed */
+pthread_once_t _pthread_tls_once;
+DWORD _pthread_tls;
+
+/* Note initializer is zero, so this works */
+pthread_rwlock_t _pthread_key_lock;
+unsigned _pthread_key_max;
+unsigned _pthread_key_sch;
+void (**_pthread_key_dest)(void *);
+
+
+#define pthread_cleanup_push(F, A)\
+{\
+ const _pthread_cleanup _pthread_cup = {(F), (A), pthread_self()->clean};\
+ _ReadWriteBarrier();\
+ pthread_self()->clean = (_pthread_cleanup *) &_pthread_cup;\
+ _ReadWriteBarrier()
+
+/* Note that if async cancelling is used, then there is a race here */
+#define pthread_cleanup_pop(E)\
+ (pthread_self()->clean = _pthread_cup.next, (E ? _pthread_cup.func(_pthread_cup.arg) : 0));}
+
+static void _pthread_once_cleanup(pthread_once_t *o)
+{
+ *o = 0;
+}
+
+int pthread_once(pthread_once_t *o, void (*func)(void))
+{
+ long state = *o;
+
+ _ReadWriteBarrier();
+
+ while (state != 1)
+ {
+ if (!state)
+ {
+ if (!_InterlockedCompareExchange(o, 2, 0))
+ {
+ /* Success */
+ pthread_cleanup_push((void(*)(void*))_pthread_once_cleanup, o);
+ func();
+ pthread_cleanup_pop(0);
+
+ /* Mark as done */
+ *o = 1;
+
+ return 0;
+ }
+ }
+
+ YieldProcessor();
+
+ _ReadWriteBarrier();
+
+ state = *o;
+ }
+
+ /* Done */
+ return 0;
+}
+
+static int _pthread_once_raw(pthread_once_t *o, void (*func)(void))
+{
+ long state = *o;
+
+ _ReadWriteBarrier();
+
+ while (state != 1)
+ {
+ if (!state)
+ {
+ if (!_InterlockedCompareExchange(o, 2, 0))
+ {
+ /* Success */
+ func();
+
+ /* Mark as done */
+ *o = 1;
+
+ return 0;
+ }
+ }
+
+ YieldProcessor();
+
+ _ReadWriteBarrier();
+
+ state = *o;
+ }
+
+ /* Done */
+ return 0;
+}
+
+int pthread_mutex_lock(pthread_mutex_t *m)
+{
+ EnterCriticalSection(m);
+ return 0;
+}
+
+int pthread_mutex_unlock(pthread_mutex_t *m)
+{
+ LeaveCriticalSection(m);
+ return 0;
+}
+
+int pthread_mutex_trylock(pthread_mutex_t *m)
+{
+ return TryEnterCriticalSection(m) ? 0 : EBUSY;
+}
+
+int pthread_mutex_init(pthread_mutex_t *m, pthread_mutexattr_t *a)
+{
+ (void) a;
+ InitializeCriticalSection(m);
+
+ return 0;
+}
+
+int pthread_mutex_destroy(pthread_mutex_t *m)
+{
+ DeleteCriticalSection(m);
+ return 0;
+}
+
+int pthread_equal(pthread_t t1, pthread_t t2)
+{
+ return t1 == t2;
+}
+
+int pthread_rwlock_init(pthread_rwlock_t *l, pthread_rwlockattr_t *a)
+{
+ (void) a;
+ InitializeSRWLock(l);
+
+ return 0;
+}
+
+int pthread_rwlock_destroy(pthread_rwlock_t *l)
+{
+ (void) *l;
+ return 0;
+}
+
+int pthread_rwlock_rdlock(pthread_rwlock_t *l)
+{
+ pthread_testcancel();
+ AcquireSRWLockShared(l);
+
+ return 0;
+}
+
+int pthread_rwlock_wrlock(pthread_rwlock_t *l)
+{
+ pthread_testcancel();
+ AcquireSRWLockExclusive(l);
+
+ return 0;
+}
+
+int pthread_rwlock_unlock(pthread_rwlock_t *l)
+{
+ void *state = *(void **)l;
+
+ if (state == (void *)1)
+ {
+ /* Known to be an exclusive lock */
+ ReleaseSRWLockExclusive(l);
+ }
+ else
+ {
+ /* A shared unlock will work */
+ ReleaseSRWLockShared(l);
+ }
+
+ return 0;
+}
+
+int pthread_rwlock_tryrdlock(pthread_rwlock_t *l)
+{
+ /* Get the current state of the lock */
+ void *state = *(void **)l;
+
+ if (!state)
+ {
+ /* Unlocked to locked */
+ if (!_InterlockedCompareExchangePointer((void *volatile *)l, (void *)0x11, NULL)) return 0;
+ return EBUSY;
+ }
+
+ /* A single writer exists */
+ if (state == (void *)1) return EBUSY;
+
+ /* Multiple writers exist? */
+ if ((uintptr_t)state & 14) return EBUSY;
+
+ if (_InterlockedCompareExchangePointer((void *volatile *)l, (void *)((uintptr_t)state + 16), state) == state) return 0;
+
+ return EBUSY;
+}
+
+int pthread_rwlock_trywrlock(pthread_rwlock_t *l)
+{
+ /* Try to grab lock if it has no users */
+ if (!_InterlockedCompareExchangePointer((void *volatile *)l, (void *)1, NULL)) return 0;
+
+ return EBUSY;
+}
+
+void pthread_tls_init(void)
+{
+ _pthread_tls = TlsAlloc();
+
+ /* Cannot continue if out of indexes */
+ if (_pthread_tls == TLS_OUT_OF_INDEXES) abort();
+}
+
+static void _pthread_cleanup_dest(pthread_t t)
+{
+ unsigned i, j;
+
+ for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++)
+ {
+ int flag = 0;
+
+ for (i = 0; i < t->keymax; i++)
+ {
+ void *val = t->keyval[i];
+
+ if (val)
+ {
+ pthread_rwlock_rdlock(&_pthread_key_lock);
+ if ((uintptr_t) _pthread_key_dest[i] > 1)
+ {
+ /* Call destructor */
+ t->keyval[i] = NULL;
+ _pthread_key_dest[i](val);
+ flag = 1;
+ }
+ pthread_rwlock_unlock(&_pthread_key_lock);
+ }
+ }
+
+ /* Nothing to do? */
+ if (!flag) return;
+ }
+}
+
+pthread_t pthread_self(void)
+{
+ pthread_t t;
+
+ _pthread_once_raw(&_pthread_tls_once, pthread_tls_init);
+
+ t = (struct _pthread_v*)TlsGetValue(_pthread_tls);
+ /* Main thread? */
+ if (!t)
+ {
+ t = (struct _pthread_v*)malloc(sizeof(struct _pthread_v));
+
+ /* If cannot initialize main thread, then the only thing we can do is abort */
+ if (!t) abort();
+
+ t->ret_arg = NULL;
+ t->func = NULL;
+ t->clean = NULL;
+ t->cancelled = 0;
+ t->p_state = PTHREAD_DEFAULT_ATTR;
+ t->keymax = 0;
+ t->keyval = NULL;
+ t->h = GetCurrentThread();
+
+ /* Save for later */
+ TlsSetValue(_pthread_tls, t);
+
+ if (setjmp(t->jb))
+ {
+ /* Make sure we free ourselves if we are detached */
+ if (!t->h) free(t);
+
+ /* Time to die */
+ _endthreadex(0);
+ }
+ }
+
+ return t;
+}
+
+static unsigned long long _pthread_time_in_ms(void)
+{
+ struct __timeb64 tb;
+
+ _ftime64(&tb);
+
+ return tb.time * 1000 + tb.millitm;
+}
+
+static unsigned long long _pthread_time_in_ms_from_timespec(const struct timespec *ts)
+{
+ unsigned long long t = ts->tv_sec * 1000;
+ t += ts->tv_nsec / 1000000;
+
+ return t;
+}
+
+static unsigned long long _pthread_rel_time_in_ms(const struct timespec *ts)
+{
+ unsigned long long t1 = _pthread_time_in_ms_from_timespec(ts);
+ unsigned long long t2 = _pthread_time_in_ms();
+
+ /* Prevent underflow */
+ if (t1 < t2) return 0;
+ return t1 - t2;
+}
+
+int pthread_rwlock_timedrdlock(pthread_rwlock_t *l, const struct timespec *ts)
+{
+ unsigned long long ct = _pthread_time_in_ms();
+ unsigned long long t = _pthread_time_in_ms_from_timespec(ts);
+
+ pthread_testcancel();
+
+ /* Use a busy-loop */
+ while (1)
+ {
+ /* Try to grab lock */
+ if (!pthread_rwlock_tryrdlock(l)) return 0;
+
+ /* Get current time */
+ ct = _pthread_time_in_ms();
+
+ /* Have we waited long enough? */
+ if (ct > t) return ETIMEDOUT;
+ }
+}
+
+int pthread_rwlock_timedwrlock(pthread_rwlock_t *l, const struct timespec *ts)
+{
+ unsigned long long ct = _pthread_time_in_ms();
+ unsigned long long t = _pthread_time_in_ms_from_timespec(ts);
+
+ pthread_testcancel();
+
+ /* Use a busy-loop */
+ while (1)
+ {
+ /* Try to grab lock */
+ if (!pthread_rwlock_trywrlock(l)) return 0;
+
+ /* Get current time */
+ ct = _pthread_time_in_ms();
+
+ /* Have we waited long enough? */
+ if (ct > t) return ETIMEDOUT;
+ }
+}
+
+int pthread_get_concurrency(int *val)
+{
+ *val = _pthread_concur;
+ return 0;
+}
+
+int pthread_set_concurrency(int val)
+{
+ _pthread_concur = val;
+ return 0;
+}
+
+int pthread_exit(void *res)
+{
+ pthread_t t = pthread_self();
+
+ t->ret_arg = res;
+
+ _pthread_cleanup_dest(t);
+
+ longjmp(t->jb, 1);
+}
+
+
+static void _pthread_invoke_cancel(void)
+{
+ _pthread_cleanup *pcup;
+
+ _InterlockedDecrement(&_pthread_cancelling);
+
+ /* Call cancel queue */
+ for (pcup = pthread_self()->clean; pcup; pcup = pcup->next)
+ {
+ pcup->func(pcup->arg);
+ }
+
+ pthread_exit(PTHREAD_CANCELED);
+}
+
+void pthread_testcancel(void)
+{
+ if (_pthread_cancelling)
+ {
+ pthread_t t = pthread_self();
+
+ if (t->cancelled && (t->p_state & PTHREAD_CANCEL_ENABLE))
+ {
+ _pthread_invoke_cancel();
+ }
+ }
+}
+
+
+int pthread_cancel(pthread_t t)
+{
+ if (t->p_state & PTHREAD_CANCEL_ASYNCHRONOUS)
+ {
+ /* Dangerous asynchronous cancelling */
+ CONTEXT ctxt;
+
+ /* Already done? */
+ if (t->cancelled) return ESRCH;
+
+ ctxt.ContextFlags = CONTEXT_CONTROL;
+
+ SuspendThread(t->h);
+ GetThreadContext(t->h, &ctxt);
+#if defined(_M_X64)
+ ctxt.Rip = (uintptr_t) _pthread_invoke_cancel;
+#elif defined(_M_ARM64)
+ ctxt.Pc = (uintptr_t) _pthread_invoke_cancel;
+ #else
+
+ ctxt.Eip = (uintptr_t) _pthread_invoke_cancel;
+#endif
+ SetThreadContext(t->h, &ctxt);
+
+ /* Also try deferred Cancelling */
+ t->cancelled = 1;
+
+ /* Notify everyone to look */
+ _InterlockedIncrement(&_pthread_cancelling);
+
+ ResumeThread(t->h);
+ }
+ else
+ {
+ /* Safe deferred Cancelling */
+ t->cancelled = 1;
+
+ /* Notify everyone to look */
+ _InterlockedIncrement(&_pthread_cancelling);
+ }
+
+ return 0;
+}
+
+static unsigned _pthread_get_state(pthread_attr_t *attr, unsigned flag)
+{
+ return attr->p_state & flag;
+}
+
+static int _pthread_set_state(pthread_attr_t *attr, unsigned flag, unsigned val)
+{
+ if (~flag & val) return EINVAL;
+ attr->p_state &= ~flag;
+ attr->p_state |= val;
+
+ return 0;
+}
+
+int pthread_attr_init(pthread_attr_t *attr)
+{
+ attr->p_state = PTHREAD_DEFAULT_ATTR;
+ attr->stack = NULL;
+ attr->s_size = 0;
+ return 0;
+}
+
+int pthread_attr_destroy(pthread_attr_t *attr)
+{
+ /* No need to do anything */
+ return 0;
+}
+
+
+int pthread_attr_setdetachstate(pthread_attr_t *a, int flag)
+{
+ return _pthread_set_state(a, PTHREAD_CREATE_DETACHED, flag);
+}
+
+int pthread_attr_getdetachstate(pthread_attr_t *a, int *flag)
+{
+ *flag = _pthread_get_state(a, PTHREAD_CREATE_DETACHED);
+ return 0;
+}
+
+int pthread_attr_setinheritsched(pthread_attr_t *a, int flag)
+{
+ return _pthread_set_state(a, PTHREAD_INHERIT_SCHED, flag);
+}
+
+int pthread_attr_getinheritsched(pthread_attr_t *a, int *flag)
+{
+ *flag = _pthread_get_state(a, PTHREAD_INHERIT_SCHED);
+ return 0;
+}
+
+int pthread_attr_setscope(pthread_attr_t *a, int flag)
+{
+ return _pthread_set_state(a, PTHREAD_SCOPE_SYSTEM, flag);
+}
+
+int pthread_attr_getscope(pthread_attr_t *a, int *flag)
+{
+ *flag = _pthread_get_state(a, PTHREAD_SCOPE_SYSTEM);
+ return 0;
+}
+
+int pthread_attr_getstackaddr(pthread_attr_t *attr, void **stack)
+{
+ *stack = attr->stack;
+ return 0;
+}
+
+int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack)
+{
+ attr->stack = stack;
+ return 0;
+}
+
+int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *size)
+{
+ *size = attr->s_size;
+ return 0;
+}
+
+int pthread_attr_setstacksize(pthread_attr_t *attr, size_t size)
+{
+ attr->s_size = size;
+ return 0;
+}
+
+#define pthread_attr_getguardsize(A, S) ENOTSUP
+#define pthread_attr_setgaurdsize(A, S) ENOTSUP
+#define pthread_attr_getschedparam(A, S) ENOTSUP
+#define pthread_attr_setschedparam(A, S) ENOTSUP
+#define pthread_attr_getschedpolicy(A, S) ENOTSUP
+#define pthread_attr_setschedpolicy(A, S) ENOTSUP
+
+
+int pthread_setcancelstate(int state, int *oldstate)
+{
+ pthread_t t = pthread_self();
+
+ if ((state & PTHREAD_CANCEL_ENABLE) != state) return EINVAL;
+ if (oldstate) *oldstate = t->p_state & PTHREAD_CANCEL_ENABLE;
+ t->p_state &= ~PTHREAD_CANCEL_ENABLE;
+ t->p_state |= state;
+
+ return 0;
+}
+
+int pthread_setcanceltype(int type, int *oldtype)
+{
+ pthread_t t = pthread_self();
+
+ if ((type & PTHREAD_CANCEL_ASYNCHRONOUS) != type) return EINVAL;
+ if (oldtype) *oldtype = t->p_state & PTHREAD_CANCEL_ASYNCHRONOUS;
+ t->p_state &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
+ t->p_state |= type;
+
+ return 0;
+}
+
+unsigned __stdcall pthread_create_wrapper(void *args)
+{
+ struct _pthread_v *tv = (struct _pthread_v*)args;
+
+ _pthread_once_raw(&_pthread_tls_once, pthread_tls_init);
+
+ TlsSetValue(_pthread_tls, tv);
+
+ if (!setjmp(tv->jb))
+ {
+ /* Call function and save return value */
+ tv->ret_arg = tv->func(tv->ret_arg);
+
+ /* Clean up destructors */
+ _pthread_cleanup_dest(tv);
+ }
+
+ /* If we exit too early, then we can race with create */
+ while (tv->h == (HANDLE) -1)
+ {
+ YieldProcessor();
+ _ReadWriteBarrier();
+ }
+
+ /* Make sure we free ourselves if we are detached */
+ if (!tv->h) free(tv);
+
+ return 0;
+}
+
+int pthread_create(pthread_t *th, pthread_attr_t *attr, void *(* func)(void *), void *arg)
+{
+ struct _pthread_v *tv = (struct _pthread_v*)malloc(sizeof(struct _pthread_v));
+ unsigned ssize = 0;
+
+ if (!tv) return 1;
+
+ *th = tv;
+
+ /* Save data in pthread_t */
+ tv->ret_arg = arg;
+ tv->func = func;
+ tv->clean = NULL;
+ tv->cancelled = 0;
+ tv->p_state = PTHREAD_DEFAULT_ATTR;
+ tv->keymax = 0;
+ tv->keyval = NULL;
+ tv->h = (HANDLE) -1;
+
+ if (attr)
+ {
+ tv->p_state = attr->p_state;
+ ssize = (unsigned) attr->s_size;
+ }
+
+ /* Make sure tv->h has value of -1 */
+ _ReadWriteBarrier();
+
+ tv->h = (HANDLE) _beginthreadex(NULL, ssize, pthread_create_wrapper, tv, 0, NULL);
+
+ /* Failed */
+ if (!tv->h) return 1;
+
+ if (tv->p_state & PTHREAD_CREATE_DETACHED)
+ {
+ CloseHandle(tv->h);
+ _ReadWriteBarrier();
+ tv->h = 0;
+ }
+
+ return 0;
+}
+
+int pthread_join(pthread_t t, void **res)
+{
+ struct _pthread_v *tv = t;
+
+ pthread_testcancel();
+
+ WaitForSingleObject(tv->h, INFINITE);
+ CloseHandle(tv->h);
+
+ /* Obtain return value */
+ if (res) *res = tv->ret_arg;
+
+ free(tv);
+
+ return 0;
+}
+
+int pthread_detach(pthread_t t)
+{
+ struct _pthread_v *tv = t;
+
+ /*
+ * This can't race with thread exit because
+ * our call would be undefined if called on a dead thread.
+ */
+
+ CloseHandle(tv->h);
+ _ReadWriteBarrier();
+ tv->h = 0;
+
+ return 0;
+}
+
+int pthread_mutexattr_init(pthread_mutexattr_t *a)
+{
+ *a = 0;
+ return 0;
+}
+
+int pthread_mutexattr_destroy(pthread_mutexattr_t *a)
+{
+ (void) a;
+ return 0;
+}
+
+int pthread_mutexattr_gettype(pthread_mutexattr_t *a, int *type)
+{
+ *type = *a & 3;
+
+ return 0;
+}
+
+int pthread_mutexattr_settype(pthread_mutexattr_t *a, int type)
+{
+ if ((unsigned) type > 3) return EINVAL;
+ *a &= ~3;
+ *a |= type;
+
+ return 0;
+}
+
+int pthread_mutexattr_getpshared(pthread_mutexattr_t *a, int *type)
+{
+ *type = *a & 4;
+
+ return 0;
+}
+
+int pthread_mutexattr_setpshared(pthread_mutexattr_t * a, int type)
+{
+ if ((type & 4) != type) return EINVAL;
+
+ *a &= ~4;
+ *a |= type;
+
+ return 0;
+}
+
+int pthread_mutexattr_getprotocol(pthread_mutexattr_t *a, int *type)
+{
+ *type = *a & (8 + 16);
+
+ return 0;
+}
+
+int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int type)
+{
+ if ((type & (8 + 16)) != 8 + 16) return EINVAL;
+
+ *a &= ~(8 + 16);
+ *a |= type;
+
+ return 0;
+}
+
+int pthread_mutexattr_getprioceiling(pthread_mutexattr_t *a, int * prio)
+{
+ *prio = *a / PTHREAD_PRIO_MULT;
+ return 0;
+}
+
+int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *a, int prio)
+{
+ *a &= (PTHREAD_PRIO_MULT - 1);
+ *a += prio * PTHREAD_PRIO_MULT;
+
+ return 0;
+}
+
+int pthread_mutex_timedlock(pthread_mutex_t *m, struct timespec *ts)
+{
+ unsigned long long t, ct;
+
+ struct _pthread_crit_t
+ {
+ void *debug;
+ LONG count;
+ LONG r_count;
+ HANDLE owner;
+ HANDLE sem;
+ ULONG_PTR spin;
+ };
+
+ /* Try to lock it without waiting */
+ if (!pthread_mutex_trylock(m)) return 0;
+
+ ct = _pthread_time_in_ms();
+ t = _pthread_time_in_ms_from_timespec(ts);
+
+ while (1)
+ {
+ /* Have we waited long enough? */
+ if (ct > t) return ETIMEDOUT;
+
+ /* Wait on semaphore within critical section */
+ WaitForSingleObject(((struct _pthread_crit_t *)m)->sem, (DWORD)(t - ct));
+
+ /* Try to grab lock */
+ if (!pthread_mutex_trylock(m)) return 0;
+
+ /* Get current time */
+ ct = _pthread_time_in_ms();
+ }
+}
+
+#define _PTHREAD_BARRIER_FLAG (1<<30)
+
+int pthread_barrier_destroy(pthread_barrier_t *b)
+{
+ EnterCriticalSection(&b->m);
+
+ while (b->total > _PTHREAD_BARRIER_FLAG)
+ {
+ /* Wait until everyone exits the barrier */
+ SleepConditionVariableCS(&b->cv, &b->m, INFINITE);
+ }
+
+ LeaveCriticalSection(&b->m);
+
+ DeleteCriticalSection(&b->m);
+
+ return 0;
+}
+
+int pthread_barrier_init(pthread_barrier_t *b, void *attr, int count)
+{
+ /* Ignore attr */
+ (void) attr;
+
+ b->count = count;
+ b->total = 0;
+
+ InitializeCriticalSection(&b->m);
+ InitializeConditionVariable(&b->cv);
+
+ return 0;
+}
+
+int pthread_barrier_wait(pthread_barrier_t *b)
+{
+ EnterCriticalSection(&b->m);
+
+ while (b->total > _PTHREAD_BARRIER_FLAG)
+ {
+ /* Wait until everyone exits the barrier */
+ SleepConditionVariableCS(&b->cv, &b->m, INFINITE);
+ }
+
+ /* Are we the first to enter? */
+ if (b->total == _PTHREAD_BARRIER_FLAG) b->total = 0;
+
+ b->total++;
+
+ if (b->total == b->count)
+ {
+ b->total += _PTHREAD_BARRIER_FLAG - 1;
+ WakeAllConditionVariable(&b->cv);
+
+ LeaveCriticalSection(&b->m);
+
+ return 1;
+ }
+ else
+ {
+ while (b->total < _PTHREAD_BARRIER_FLAG)
+ {
+ /* Wait until enough threads enter the barrier */
+ SleepConditionVariableCS(&b->cv, &b->m, INFINITE);
+ }
+
+ b->total--;
+
+ /* Get entering threads to wake up */
+ if (b->total == _PTHREAD_BARRIER_FLAG) WakeAllConditionVariable(&b->cv);
+
+ LeaveCriticalSection(&b->m);
+
+ return 0;
+ }
+}
+
+int pthread_barrierattr_init(void **attr)
+{
+ *attr = NULL;
+ return 0;
+}
+
+int pthread_barrierattr_destroy(void **attr)
+{
+ /* Ignore attr */
+ (void) attr;
+
+ return 0;
+}
+
+int pthread_barrierattr_setpshared(void **attr, int s)
+{
+ *attr = (void *) s;
+ return 0;
+}
+
+int pthread_barrierattr_getpshared(void **attr, int *s)
+{
+ *s = (int) (size_t) *attr;
+
+ return 0;
+}
+
+int pthread_key_create(pthread_key_t *key, void (* dest)(void *))
+{
+ unsigned i;
+ unsigned nmax;
+ void (**d)(void *);
+
+ if (!key) return EINVAL;
+
+ pthread_rwlock_wrlock(&_pthread_key_lock);
+
+ for (i = _pthread_key_sch; i < _pthread_key_max; i++)
+ {
+ if (!_pthread_key_dest[i])
+ {
+ *key = i;
+ if (dest)
+ {
+ _pthread_key_dest[i] = dest;
+ }
+ else
+ {
+ _pthread_key_dest[i] = (void(*)(void *))1;
+ }
+ pthread_rwlock_unlock(&_pthread_key_lock);
+
+ return 0;
+ }
+ }
+
+ for (i = 0; i < _pthread_key_sch; i++)
+ {
+ if (!_pthread_key_dest[i])
+ {
+ *key = i;
+ if (dest)
+ {
+ _pthread_key_dest[i] = dest;
+ }
+ else
+ {
+ _pthread_key_dest[i] = (void(*)(void *))1;
+ }
+ pthread_rwlock_unlock(&_pthread_key_lock);
+
+ return 0;
+ }
+ }
+
+ if (!_pthread_key_max) _pthread_key_max = 1;
+ if (_pthread_key_max == PTHREAD_KEYS_MAX)
+ {
+ pthread_rwlock_unlock(&_pthread_key_lock);
+
+ return ENOMEM;
+ }
+
+ nmax = _pthread_key_max * 2;
+ if (nmax > PTHREAD_KEYS_MAX) nmax = PTHREAD_KEYS_MAX;
+
+ /* No spare room anywhere */
+ d = (void (**)(void*))realloc(_pthread_key_dest, nmax * sizeof(*d));
+ if (!d)
+ {
+ pthread_rwlock_unlock(&_pthread_key_lock);
+
+ return ENOMEM;
+ }
+
+ /* Clear new region */
+ memset((void *) &d[_pthread_key_max], 0, (nmax-_pthread_key_max)*sizeof(void *));
+
+ /*
+ * The memset() above won't initialize _pthread_key_dest[0], so we
+ * need to initialize it manually to avoid an undefined behaviour.
+ *
+ * Having it initialized with `(void *) 1` means we never use d[0];
+ * It's ok since pthread_setspecific() and others are not designed
+ * to handle a zero key anyway.
+ */
+ if (_pthread_key_max == 1)
+ {
+ d[0] = (void *) 1;
+ }
+
+ /* Use new region */
+ _pthread_key_dest = d;
+ _pthread_key_sch = _pthread_key_max + 1;
+ *key = _pthread_key_max;
+ _pthread_key_max = nmax;
+
+ if (dest)
+ {
+ _pthread_key_dest[*key] = dest;
+ }
+ else
+ {
+ _pthread_key_dest[*key] = (void(*)(void *))1;
+ }
+
+ pthread_rwlock_unlock(&_pthread_key_lock);
+
+ return 0;
+}
+
+int pthread_key_delete(pthread_key_t key)
+{
+ if (key > _pthread_key_max) return EINVAL;
+ if (!_pthread_key_dest) return EINVAL;
+
+ pthread_rwlock_wrlock(&_pthread_key_lock);
+ _pthread_key_dest[key] = NULL;
+
+ /* Start next search from our location */
+ if (_pthread_key_sch > key) _pthread_key_sch = key;
+
+ pthread_rwlock_unlock(&_pthread_key_lock);
+
+ return 0;
+}
+
+void *pthread_getspecific(pthread_key_t key)
+{
+ pthread_t t = pthread_self();
+
+ if (key >= t->keymax) return NULL;
+
+ return t->keyval[key];
+
+}
+
+int pthread_setspecific(pthread_key_t key, const void *value)
+{
+ pthread_t t = pthread_self();
+
+ if (key >= t->keymax)
+ {
+ int keymax = (key + 1) * 2;
+ void **kv = (void**)realloc(t->keyval, keymax * sizeof(void *));
+
+ if (!kv) return ENOMEM;
+
+ /* Clear new region */
+ memset(&kv[t->keymax], 0, (keymax - t->keymax)*sizeof(void*));
+
+ t->keyval = kv;
+ t->keymax = keymax;
+ }
+
+ t->keyval[key] = (void *) value;
+
+ return 0;
+}
+
+
+int pthread_spin_init(pthread_spinlock_t *l, int pshared)
+{
+ (void) pshared;
+
+ *l = 0;
+ return 0;
+}
+
+int pthread_spin_destroy(pthread_spinlock_t *l)
+{
+ (void) l;
+ return 0;
+}
+
+/* No-fair spinlock due to lack of knowledge of thread number */
+int pthread_spin_lock(pthread_spinlock_t *l)
+{
+ while (_InterlockedExchange(l, EBUSY))
+ {
+ /* Don't lock the bus whilst waiting */
+ while (*l)
+ {
+ YieldProcessor();
+
+ /* Compiler barrier. Prevent caching of *l */
+ _ReadWriteBarrier();
+ }
+ }
+
+ return 0;
+}
+
+int pthread_spin_trylock(pthread_spinlock_t *l)
+{
+ return _InterlockedExchange(l, EBUSY);
+}
+
+int pthread_spin_unlock(pthread_spinlock_t *l)
+{
+ /* Compiler barrier. The store below acts with release symmantics */
+ _ReadWriteBarrier();
+
+ *l = 0;
+
+ return 0;
+}
+
+int pthread_cond_init(pthread_cond_t *c, pthread_condattr_t *a)
+{
+ (void) a;
+
+ InitializeConditionVariable(c);
+ return 0;
+}
+
+int pthread_cond_signal(pthread_cond_t *c)
+{
+ WakeConditionVariable(c);
+ return 0;
+}
+
+int pthread_cond_broadcast(pthread_cond_t *c)
+{
+ WakeAllConditionVariable(c);
+ return 0;
+}
+
+int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
+{
+ pthread_testcancel();
+ SleepConditionVariableCS(c, m, INFINITE);
+ return 0;
+}
+
+int pthread_cond_destroy(pthread_cond_t *c)
+{
+ (void) c;
+ return 0;
+}
+
+int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, struct timespec *t)
+{
+ unsigned long long tm = _pthread_rel_time_in_ms(t);
+
+ pthread_testcancel();
+
+ if (!SleepConditionVariableCS(c, m, (DWORD)tm)) return ETIMEDOUT;
+
+ /* We can have a spurious wakeup after the timeout */
+ if (!_pthread_rel_time_in_ms(t)) return ETIMEDOUT;
+
+ return 0;
+}
+
+int pthread_condattr_destroy(pthread_condattr_t *a)
+{
+ (void) a;
+ return 0;
+}
+
+int pthread_condattr_init(pthread_condattr_t *a)
+{
+ *a = 0;
+ return 0;
+}
+
+int pthread_condattr_getpshared(pthread_condattr_t *a, int *s)
+{
+ *s = *a;
+ return 0;
+}
+
+int pthread_condattr_setpshared(pthread_condattr_t *a, int s)
+{
+ *a = s;
+ return 0;
+}
+
+int pthread_rwlockattr_destroy(pthread_rwlockattr_t *a)
+{
+ (void) a;
+ return 0;
+}
+
+int pthread_rwlockattr_init(pthread_rwlockattr_t *a)
+{
+ *a = 0;
+ return 0;
+}
+
+int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *a, int *s)
+{
+ *s = *a;
+ return 0;
+}
+
+int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *a, int s)
+{
+ *a = s;
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/include/CMakeLists.txt b/fluent-bit/lib/monkey/mk_core/include/CMakeLists.txt
new file mode 100644
index 000000000..29400d7b8
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/include/CMakeLists.txt
@@ -0,0 +1,16 @@
+configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/mk_core/mk_core_info.h.in"
+ "${CMAKE_CURRENT_SOURCE_DIR}/mk_core/mk_core_info.h"
+ )
+
+# Install headers
+if(NOT WITHOUT_HEADERS)
+ install(FILES "mk_core.h"
+ DESTINATION include/
+ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+
+ file(GLOB headers "mk_core/*.h")
+ install(FILES ${headers}
+ DESTINATION include/mk_core
+ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+endif() \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/mk_core/mk_event.c b/fluent-bit/lib/monkey/mk_core/mk_event.c
new file mode 100644
index 000000000..5eaa8b00e
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/mk_event.c
@@ -0,0 +1,211 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <mk_core/mk_core_info.h>
+#include <mk_core/mk_pipe.h>
+#include <mk_core/mk_sleep.h>
+#include <mk_core/mk_unistd.h>
+#include <mk_core/mk_memory.h>
+#include <mk_core/mk_utils.h>
+#include <mk_core/mk_event.h>
+
+#if defined(_WIN32)
+ #include "mk_event_libevent.c"
+#elif defined(MK_HAVE_EVENT_SELECT)
+ #include "mk_event_select.c"
+#elif defined(__linux__) && !defined(LINUX_KQUEUE)
+ #include "mk_event_epoll.c"
+#else
+ #include "mk_event_kqueue.c"
+#endif
+
+/* Initialize backend */
+int mk_event_init()
+{
+ return _mk_event_init();
+}
+
+/* Create a new loop */
+struct mk_event_loop *mk_event_loop_create(int size)
+{
+ void *backend;
+ struct mk_event_loop *loop;
+
+ backend = _mk_event_loop_create(size);
+ if (!backend) {
+ return NULL;
+ }
+
+ loop = mk_mem_alloc_z(sizeof(struct mk_event_loop));
+ if (!loop) {
+ _mk_event_loop_destroy(backend);
+ return NULL;
+ }
+
+ loop->events = mk_mem_alloc_z(sizeof(struct mk_event) * size);
+ if (!loop->events) {
+ _mk_event_loop_destroy(backend);
+ mk_mem_free(loop);
+ return NULL;
+ }
+
+ loop->size = size;
+ loop->data = backend;
+
+ return loop;
+}
+
+/* Destroy a loop context */
+void mk_event_loop_destroy(struct mk_event_loop *loop)
+{
+ _mk_event_loop_destroy(loop->data);
+ mk_mem_free(loop->events);
+ mk_mem_free(loop);
+}
+
+/* Register or modify an event */
+int mk_event_add(struct mk_event_loop *loop, int fd,
+ int type, uint32_t mask, void *data)
+{
+ int ret;
+ struct mk_event_ctx *ctx;
+
+#ifdef MK_HAVE_TRACE
+ mk_bug(!data);
+#endif
+
+ ctx = loop->data;
+ ret = _mk_event_add(ctx, fd, type, mask, data);
+ if (ret == -1) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Inject an event */
+int mk_event_inject(struct mk_event_loop *loop, struct mk_event *event,
+ int flags, int prevent_duplication)
+{
+ if (loop->n_events + 1 >= loop->size) {
+ return -1;
+ }
+
+ _mk_event_inject(loop, event, flags, prevent_duplication);
+
+ return 0;
+}
+
+/* Remove an event */
+int mk_event_del(struct mk_event_loop *loop, struct mk_event *event)
+{
+ int ret;
+ struct mk_event_ctx *ctx;
+
+ ctx = loop->data;
+
+ /* just remove a registered event */
+ if ((event->status & MK_EVENT_REGISTERED) == 0) {
+ return -1;
+ }
+
+ ret = _mk_event_del(ctx, event);
+ if (ret == -1) {
+ return -1;
+ }
+
+ /* Reset the status and mask */
+ MK_EVENT_NEW(event);
+
+ return 0;
+}
+
+/* Create a new timer in the loop */
+int mk_event_timeout_create(struct mk_event_loop *loop,
+ time_t sec, long nsec, void *data)
+{
+ struct mk_event_ctx *ctx;
+
+ ctx = loop->data;
+ return _mk_event_timeout_create(ctx, sec, nsec, data);
+}
+
+/* Disable timer */
+int mk_event_timeout_disable(struct mk_event_loop *loop, void *data)
+{
+ return mk_event_del(loop, (struct mk_event *) data);
+}
+
+/* Destroy timer */
+int mk_event_timeout_destroy(struct mk_event_loop *loop, void *data)
+{
+ struct mk_event_ctx *ctx;
+
+ ctx = loop->data;
+ return _mk_event_timeout_destroy(ctx, data);
+}
+
+/* Create a new channel to distribute signals */
+int mk_event_channel_create(struct mk_event_loop *loop,
+ int *r_fd, int *w_fd,
+ void *data)
+{
+ struct mk_event_ctx *ctx;
+
+ mk_bug(!data);
+ ctx = loop->data;
+ return _mk_event_channel_create(ctx, r_fd, w_fd, data);
+}
+
+/* Destroy channel created to distribute signals */
+int mk_event_channel_destroy(struct mk_event_loop *loop,
+ int r_fd, int w_fd,
+ void *data)
+{
+ struct mk_event_ctx *ctx;
+
+ mk_bug(!data);
+ ctx = loop->data;
+ return _mk_event_channel_destroy(ctx, r_fd, w_fd, data);
+}
+
+/* Poll events */
+int mk_event_wait(struct mk_event_loop *loop)
+{
+ return _mk_event_wait_2(loop, -1);
+}
+
+/*
+ * Poll events with timeout in milliseconds
+ * zero timeout for non blocking wait
+ * -1 timeout for infinite wait
+ */
+int mk_event_wait_2(struct mk_event_loop *loop, int timeout)
+{
+ return _mk_event_wait_2(loop, timeout);
+}
+
+/* Return the backend name */
+char *mk_event_backend()
+{
+ return _mk_event_backend();
+}
diff --git a/fluent-bit/lib/monkey/mk_core/mk_event_epoll.c b/fluent-bit/lib/monkey/mk_core/mk_event_epoll.c
new file mode 100644
index 000000000..6ebb90ab2
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/mk_event_epoll.c
@@ -0,0 +1,461 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+
+#ifdef MK_HAVE_EVENTFD
+#include <sys/eventfd.h>
+#endif
+
+#ifdef MK_HAVE_TIMERFD_CREATE
+#include <sys/timerfd.h>
+#endif
+
+#include <time.h>
+
+#include <mk_core/mk_event.h>
+#include <mk_core/mk_memory.h>
+#include <mk_core/mk_utils.h>
+
+/* For old systems */
+#ifndef EPOLLRDHUP
+#define EPOLLRDHUP 0x2000
+#endif
+
+static inline int _mk_event_init()
+{
+ return 0;
+}
+
+static inline void *_mk_event_loop_create(int size)
+{
+ int efd;
+ struct mk_event_ctx *ctx;
+
+ /* Main event context */
+ ctx = mk_mem_alloc_z(sizeof(struct mk_event_ctx));
+ if (!ctx) {
+ return NULL;
+ }
+
+ /* Create the epoll instance */
+ #ifdef EPOLL_CLOEXEC
+ efd = epoll_create1(EPOLL_CLOEXEC);
+ #else
+ efd = epoll_create(1);
+ if (efd > 0) {
+ if (fcntl(efd, F_SETFD, FD_CLOEXEC) == -1) {
+ perror("fcntl");
+ }
+ }
+ #endif
+
+ if (efd == -1) {
+ mk_libc_error("epoll_create");
+ mk_mem_free(ctx);
+ return NULL;
+ }
+ ctx->efd = efd;
+
+ /* Allocate space for events queue */
+ ctx->events = mk_mem_alloc_z(sizeof(struct epoll_event) * size);
+ if (!ctx->events) {
+ close(ctx->efd);
+ mk_mem_free(ctx);
+ return NULL;
+ }
+ ctx->queue_size = size;
+ return ctx;
+}
+
+/* Close handlers and memory */
+static inline void _mk_event_loop_destroy(struct mk_event_ctx *ctx)
+{
+ close(ctx->efd);
+ mk_mem_free(ctx->events);
+ mk_mem_free(ctx);
+}
+
+/*
+ * It register certain events for the file descriptor in question, if
+ * the file descriptor have not been registered, create a new entry.
+ */
+static inline int _mk_event_add(struct mk_event_ctx *ctx, int fd,
+ int type, uint32_t events, void *data)
+{
+ int op;
+ int ret;
+ struct mk_event *event;
+ struct epoll_event ep_event;
+ memset(&ep_event, 0, sizeof(ep_event));
+
+ mk_bug(ctx == NULL);
+ mk_bug(data == NULL);
+
+ /* Verify the FD status and desired operation */
+ event = (struct mk_event *) data;
+ if (event->mask == MK_EVENT_EMPTY) {
+ op = EPOLL_CTL_ADD;
+ event->fd = fd;
+ event->status = MK_EVENT_REGISTERED;
+ event->type = type;
+
+ }
+ else {
+ op = EPOLL_CTL_MOD;
+ if (type != MK_EVENT_UNMODIFIED) {
+ event->type = type;
+ }
+ }
+ ep_event.events = EPOLLERR | EPOLLHUP | EPOLLRDHUP;
+ ep_event.data.ptr = data;
+
+ if (events & MK_EVENT_READ) {
+ ep_event.events |= EPOLLIN;
+ }
+ if (events & MK_EVENT_WRITE) {
+ ep_event.events |= EPOLLOUT;
+ }
+
+ ret = epoll_ctl(ctx->efd, op, fd, &ep_event);
+ if (ret < 0) {
+ mk_libc_error("epoll_ctl");
+ return -1;
+ }
+
+ event->mask = events;
+ event->priority = MK_EVENT_PRIORITY_DEFAULT;
+
+ /* Remove from priority queue */
+ if (!mk_list_entry_is_orphan(&event->_priority_head)) {
+ mk_list_del(&event->_priority_head);
+ }
+
+ return ret;
+}
+
+/* Delete an event */
+static inline int _mk_event_del(struct mk_event_ctx *ctx, struct mk_event *event)
+{
+ int ret;
+
+ mk_bug(ctx == NULL);
+ mk_bug(event == NULL);
+
+ if (!MK_EVENT_IS_REGISTERED(event)) {
+ return 0;
+ }
+
+ ret = epoll_ctl(ctx->efd, EPOLL_CTL_DEL, event->fd, NULL);
+
+ MK_TRACE("[FD %i] Epoll, remove from QUEUE_FD=%i, ret=%i",
+ event->fd, ctx->efd, ret);
+
+ if (ret < 0) {
+#ifdef MK_HAVE_TRACE
+ mk_libc_warn("epoll_ctl");
+#endif
+ }
+
+ /* Remove from priority queue */
+ if (!mk_list_entry_is_orphan(&event->_priority_head)) {
+ mk_list_del(&event->_priority_head);
+ }
+
+ MK_EVENT_NEW(event);
+
+ return ret;
+}
+
+#ifdef MK_HAVE_TIMERFD_CREATE
+/* Register a timeout file descriptor */
+static inline int _mk_event_timeout_create(struct mk_event_ctx *ctx,
+ time_t sec, long nsec, void *data)
+{
+ int ret;
+ int timer_fd;
+ struct itimerspec its;
+ struct timespec now;
+ struct mk_event *event;
+
+ mk_bug(data == NULL);
+
+ memset(&its, '\0', sizeof(struct itimerspec));
+
+ if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) {
+ mk_libc_error("clock_gettime");
+ return -1;
+ }
+
+ /* expiration interval */
+ its.it_interval.tv_sec = sec;
+ its.it_interval.tv_nsec = nsec;
+
+ /*
+ * initial expiration: note that we don't use nanoseconds in the timer,
+ * feel free to send a Pull Request if you need it.
+ */
+ its.it_value.tv_sec = now.tv_sec + sec;
+ its.it_value.tv_nsec = 0;
+
+ timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
+ if (timer_fd == -1) {
+ mk_libc_error("timerfd");
+ return -1;
+ }
+
+ ret = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL);
+ if (ret < 0) {
+ mk_libc_error("timerfd_settime");
+ close(timer_fd);
+ return -1;
+ }
+
+ event = data;
+ event->fd = timer_fd;
+ event->type = MK_EVENT_NOTIFICATION;
+ event->mask = MK_EVENT_EMPTY;
+
+ /* register the timer into the epoll queue */
+ ret = _mk_event_add(ctx, timer_fd,
+ MK_EVENT_NOTIFICATION, MK_EVENT_READ, data);
+ if (ret != 0) {
+ close(timer_fd);
+ return ret;
+ }
+
+ return timer_fd;
+}
+#else /* MK_HAVE_TIMERFD_CREATE */
+
+struct fd_timer {
+ int fd;
+ time_t sec;
+ long nsec;
+};
+
+/*
+ * Timeout worker, it writes a byte every certain amount of seconds, it finish
+ * once the other end of the pipe closes the fd[0].
+ */
+void _timeout_worker(void *arg)
+{
+ int ret;
+ uint64_t val = 1;
+ struct fd_timer *timer;
+ struct timespec t_spec;
+
+ timer = (struct fd_timer *) arg;
+ t_spec.tv_sec = timer->sec;
+ t_spec.tv_nsec = timer->nsec;
+
+ while (1) {
+ /* sleep for a while */
+ nanosleep(&t_spec, NULL);
+
+ /* send notification */
+ ret = write(timer->fd, &val, sizeof(uint64_t));
+ if (ret == -1) {
+ perror("write");
+ break;
+ }
+ }
+
+ close(timer->fd);
+ free(timer);
+}
+
+/*
+ * This routine creates a timer, since timerfd_create(2) is not available (as
+ * Monkey could be be compiled in a very old Linux system), we implement a similar
+ * function through a thread and a pipe(2).
+ */
+static inline int _mk_event_timeout_create(struct mk_event_ctx *ctx,
+ time_t sec, long nsec, void *data)
+{
+ int ret;
+ int fd[2];
+ struct mk_event *event;
+ struct fd_timer *timer;
+ pthread_t tid;
+
+ mk_bug(data == NULL);
+
+ timer = mk_mem_alloc(sizeof(struct fd_timer));
+ if (!timer) {
+ return -1;
+ }
+
+ ret = pipe(fd);
+ if (ret < 0) {
+ mk_mem_free(timer);
+ mk_libc_error("pipe");
+ return ret;
+ }
+
+ event = (struct mk_event *) data;
+ event->fd = fd[0];
+ event->type = MK_EVENT_NOTIFICATION;
+ event->mask = MK_EVENT_EMPTY;
+
+ _mk_event_add(ctx, fd[0], MK_EVENT_NOTIFICATION, MK_EVENT_READ, data);
+ event->mask = MK_EVENT_READ;
+
+ /* Compose the timer context, this is released inside the worker thread */
+ timer->fd = fd[1];
+ timer->sec = sec;
+ timer->nsec = nsec;
+
+ /* Now the dirty workaround, create a thread */
+ ret = mk_utils_worker_spawn(_timeout_worker, timer, &tid);
+ if (ret < 0) {
+ close(fd[0]);
+ close(fd[1]);
+ mk_mem_free(timer);
+ return -1;
+ }
+
+ return fd[0];
+}
+#endif /* MK_HAVE_TIMERFD_CREATE */
+
+static inline int _mk_event_timeout_destroy(struct mk_event_ctx *ctx, void *data)
+{
+ struct mk_event *event;
+
+ if (data == NULL) {
+ return 0;
+ }
+
+ event = (struct mk_event *) data;
+ _mk_event_del(ctx, event);
+ close(event->fd);
+ return 0;
+}
+
+static inline int _mk_event_channel_create(struct mk_event_ctx *ctx,
+ int *r_fd, int *w_fd, void *data)
+{
+ int ret;
+ int fd[2];
+ struct mk_event *event;
+
+ mk_bug(data == NULL);
+
+ ret = pipe(fd);
+ if (ret < 0) {
+ mk_libc_error("pipe");
+ return ret;
+ }
+
+ event = data;
+ event->fd = fd[0];
+ event->type = MK_EVENT_NOTIFICATION;
+ event->mask = MK_EVENT_EMPTY;
+
+ ret = _mk_event_add(ctx, fd[0],
+ MK_EVENT_NOTIFICATION, MK_EVENT_READ, event);
+ if (ret != 0) {
+ close(fd[0]);
+ close(fd[1]);
+ return ret;
+ }
+
+ *r_fd = fd[0];
+ *w_fd = fd[1];
+
+ return 0;
+}
+
+static inline int _mk_event_channel_destroy(struct mk_event_ctx *ctx,
+ int r_fd, int w_fd, void *data)
+{
+ struct mk_event *event;
+ int ret;
+
+
+ event = (struct mk_event *)data;
+ if (event->fd != r_fd) {
+ return -1;
+ }
+
+ ret = _mk_event_del(ctx, event);
+ if (ret != 0) {
+ return ret;
+ }
+
+ close(r_fd);
+ close(w_fd);
+
+ return 0;
+}
+
+static inline int _mk_event_inject(struct mk_event_loop *loop,
+ struct mk_event *event,
+ int mask,
+ int prevent_duplication)
+{
+ int index;
+ struct mk_event_ctx *ctx;
+
+ ctx = loop->data;
+
+ if (prevent_duplication) {
+ for (index = 0 ; index < loop->n_events ; index++) {
+ if (ctx->events[index].data.ptr == event) {
+ return 0;
+ }
+ }
+ }
+
+ event->mask = mask;
+
+ ctx->events[loop->n_events].data.ptr = event;
+
+ loop->n_events++;
+
+ return 0;
+}
+
+static inline int _mk_event_wait_2(struct mk_event_loop *loop, int timeout)
+{
+ struct mk_event_ctx *ctx = loop->data;
+ int ret = 0;
+
+ while(1) {
+ ret = epoll_wait(ctx->efd, ctx->events, ctx->queue_size, timeout);
+ if (ret >= 0) {
+ break;
+ }
+ else if(ret < 0 && errno != EINTR) {
+ mk_libc_error("epoll_wait");
+ break;
+ }
+ /* retry when errno is EINTR */
+ }
+ loop->n_events = ret;
+ return ret;
+}
+
+static inline char *_mk_event_backend()
+{
+ return "epoll";
+}
diff --git a/fluent-bit/lib/monkey/mk_core/mk_event_kqueue.c b/fluent-bit/lib/monkey/mk_core/mk_event_kqueue.c
new file mode 100644
index 000000000..46b4f3524
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/mk_event_kqueue.c
@@ -0,0 +1,373 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <mk_core/mk_event.h>
+#include <mk_core/mk_memory.h>
+#include <mk_core/mk_utils.h>
+
+static inline int _mk_event_init()
+{
+ return 0;
+}
+
+static inline void *_mk_event_loop_create(int size)
+{
+ struct mk_event_ctx *ctx;
+
+ /* Main event context */
+ ctx = mk_mem_alloc_z(sizeof(struct mk_event_ctx));
+ if (!ctx) {
+ return NULL;
+ }
+
+ /* Create the epoll instance */
+ ctx->kfd = kqueue();
+ if (ctx->kfd == -1) {
+ mk_libc_error("kqueue");
+ mk_mem_free(ctx);
+ return NULL;
+ }
+
+ /* Allocate space for events queue */
+ ctx->events = mk_mem_alloc_z(sizeof(struct kevent) * size);
+ if (!ctx->events) {
+ close(ctx->kfd);
+ mk_mem_free(ctx);
+ return NULL;
+ }
+ ctx->queue_size = size;
+ return ctx;
+}
+
+/* Close handlers and memory */
+static inline void _mk_event_loop_destroy(struct mk_event_ctx *ctx)
+{
+ close(ctx->kfd);
+ mk_mem_free(ctx->events);
+ mk_mem_free(ctx);
+}
+
+static inline int _mk_event_add(struct mk_event_ctx *ctx, int fd,
+ int type, uint32_t events, void *data)
+{
+ int ret;
+ int set = MK_FALSE;
+ struct mk_event *event;
+ struct kevent ke = {0, 0, 0, 0, 0, 0};
+
+ mk_bug(ctx == NULL);
+ mk_bug(data == NULL);
+
+ event = (struct mk_event *) data;
+ if (event->mask == MK_EVENT_EMPTY) {
+ event->fd = fd;
+ event->type = type;
+ event->status = MK_EVENT_REGISTERED;
+ }
+ else {
+ if (type != MK_EVENT_UNMODIFIED) {
+ event->type = type;
+ }
+ }
+
+ /* Read flag */
+ if ((event->mask ^ MK_EVENT_READ) && (events & MK_EVENT_READ)) {
+ EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, event);
+ set = MK_TRUE;
+ }
+ else if ((event->mask & MK_EVENT_READ) && (events ^ MK_EVENT_READ)) {
+ EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, 0, 0, event);
+ set = MK_TRUE;
+ }
+
+ if (set == MK_TRUE) {
+ ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
+ if (ret < 0) {
+ mk_libc_error("kevent");
+ return ret;
+ }
+ }
+
+ /* Write flag */
+ set = MK_FALSE;
+ if ((event->mask ^ MK_EVENT_WRITE) && (events & MK_EVENT_WRITE)) {
+ EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD, 0, 0, event);
+ set = MK_TRUE;
+ }
+ else if ((event->mask & MK_EVENT_WRITE) && (events ^ MK_EVENT_WRITE)) {
+ EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, 0, 0, event);
+ set = MK_TRUE;
+ }
+
+ if (set == MK_TRUE) {
+ ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
+ if (ret < 0) {
+ mk_libc_error("kevent");
+ return ret;
+ }
+ }
+
+ event->mask = events;
+ event->priority = MK_EVENT_PRIORITY_DEFAULT;
+
+ /* Remove from priority queue */
+ if (!mk_list_entry_is_orphan(&event->_priority_head)) {
+ mk_list_del(&event->_priority_head);
+ }
+
+ return 0;
+}
+
+static inline int _mk_event_del(struct mk_event_ctx *ctx, struct mk_event *event)
+{
+ int ret;
+ struct kevent ke = {0, 0, 0, 0, 0, 0};
+
+ mk_bug(ctx == NULL);
+ mk_bug(event == NULL);
+
+ if (!MK_EVENT_IS_REGISTERED(event)) {
+ return 0;
+ }
+
+ if (event->mask & MK_EVENT_READ) {
+ EV_SET(&ke, event->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
+ if (ret < 0) {
+ mk_libc_error("kevent");
+ return ret;
+ }
+ }
+
+ if (event->mask & MK_EVENT_WRITE) {
+ EV_SET(&ke, event->fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
+ ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
+ if (ret < 0) {
+ mk_libc_error("kevent");
+ return ret;
+ }
+ }
+
+ /* Remove from priority queue */
+ if (!mk_list_entry_is_orphan(&event->_priority_head)) {
+ mk_list_del(&event->_priority_head);
+ }
+
+ MK_EVENT_NEW(event);
+
+ return 0;
+}
+
+static inline int _mk_event_timeout_create(struct mk_event_ctx *ctx,
+ time_t sec, long nsec, void *data)
+{
+ int fd;
+ int ret;
+ struct mk_event *event;
+ struct kevent ke;
+
+ mk_bug(data == NULL);
+
+ /*
+ * We just need a file descriptor number, we don't care from where it
+ * comes from.
+ */
+ fd = open("/dev/null", 0);
+ if (fd == -1) {
+ mk_libc_error("open");
+ return -1;
+ }
+
+ event = data;
+ event->fd = fd;
+ event->status = MK_EVENT_REGISTERED;
+ event->type = MK_EVENT_NOTIFICATION;
+ event->mask = MK_EVENT_EMPTY;
+
+ event->priority = MK_EVENT_PRIORITY_DEFAULT;
+ mk_list_entry_init(&event->_priority_head);
+
+#if defined(NOTE_SECONDS) && !defined(__APPLE__)
+ /* FreeBSD or LINUX_KQUEUE defined */
+ /* TODO : high resolution interval support. */
+ EV_SET(&ke, fd, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, sec, event);
+#else
+ /* Other BSD have no NOTE_SECONDS & specify milliseconds */
+ /* Also, on macOS, NOTE_SECONDS has severe side effect that cause
+ * performance degradation. */
+ EV_SET(&ke, fd, EVFILT_TIMER, EV_ADD, 0, (sec * 1000) + (nsec / 1000000) , event);
+#endif
+
+ ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
+ if (ret < 0) {
+ close(fd);
+ mk_libc_error("kevent");
+ return -1;
+ }
+
+ /*
+ * FIXME: the timeout event is not triggered when using libkqueue, need
+ * to confirm how it behave on native OSX.
+ */
+ event->mask = MK_EVENT_READ;
+
+ return fd;
+}
+
+static inline int _mk_event_timeout_destroy(struct mk_event_ctx *ctx, void *data)
+{
+ int ret;
+ struct mk_event *event;
+ struct kevent ke = {0, 0, 0, 0, 0, 0};
+
+ if (data == NULL) {
+ return 0;
+ }
+
+ event = (struct mk_event *) data;
+ if (!MK_EVENT_IS_REGISTERED(event)) {
+ return 0;
+ }
+ EV_SET(&ke, event->fd, EVFILT_TIMER, EV_DELETE, 0,0, NULL);
+
+ ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
+ if (ret < 0) {
+ mk_libc_error("kevent");
+ return ret;
+ }
+
+ /* Remove from priority queue */
+ if (!mk_list_entry_is_orphan(&event->_priority_head)) {
+ mk_list_del(&event->_priority_head);
+ }
+
+ close(event->fd);
+
+ MK_EVENT_NEW(event);
+
+ return 0;
+}
+
+static inline int _mk_event_channel_create(struct mk_event_ctx *ctx,
+ int *r_fd, int *w_fd, void *data)
+{
+ int ret;
+ int fd[2];
+ struct mk_event *event;
+
+ mk_bug(data == NULL);
+
+ ret = pipe(fd);
+ if (ret < 0) {
+ mk_libc_error("pipe");
+ return ret;
+ }
+
+ event = data;
+ event->fd = fd[0];
+ event->type = MK_EVENT_NOTIFICATION;
+ event->mask = MK_EVENT_EMPTY;
+
+ ret = _mk_event_add(ctx, fd[0],
+ MK_EVENT_NOTIFICATION, MK_EVENT_READ, event);
+ if (ret != 0) {
+ close(fd[0]);
+ close(fd[1]);
+ return ret;
+ }
+
+ *r_fd = fd[0];
+ *w_fd = fd[1];
+
+ return 0;
+}
+
+static inline int _mk_event_channel_destroy(struct mk_event_ctx *ctx,
+ int r_fd, int w_fd, void *data)
+{
+ struct mk_event *event;
+ int ret;
+
+
+ event = (struct mk_event *)data;
+ if (event->fd != r_fd) {
+ return -1;
+ }
+
+ ret = _mk_event_del(ctx, event);
+ if (ret != 0) {
+ return ret;
+ }
+
+ close(r_fd);
+ close(w_fd);
+
+ return 0;
+}
+
+static inline int _mk_event_inject(struct mk_event_loop *loop,
+ struct mk_event *event,
+ int mask,
+ int prevent_duplication)
+{
+ size_t index;
+ struct mk_event_ctx *ctx;
+
+ ctx = loop->data;
+
+ if (prevent_duplication) {
+ for (index = 0 ; index < loop->n_events ; index++) {
+ if (ctx->events[index].udata == event) {
+ return 0;
+ }
+ }
+ }
+
+ event->mask = mask;
+
+ ctx->events[loop->n_events].udata = event;
+
+ loop->n_events++;
+
+ return 0;
+}
+
+static inline int _mk_event_wait_2(struct mk_event_loop *loop, int timeout)
+{
+ struct mk_event_ctx *ctx = loop->data;
+
+ struct timespec timev = {timeout / 1000, (timeout % 1000) * 1000000};
+ loop->n_events = kevent(ctx->kfd, NULL, 0, ctx->events, ctx->queue_size,
+ (timeout != -1) ? &timev : NULL);
+ return loop->n_events;
+}
+
+static inline char *_mk_event_backend()
+{
+#ifdef LINUX_KQUEUE
+ return "libkqueue";
+#else
+ return "kqueue";
+#endif
+}
diff --git a/fluent-bit/lib/monkey/mk_core/mk_event_libevent.c b/fluent-bit/lib/monkey/mk_core/mk_event_libevent.c
new file mode 100644
index 000000000..b155159ef
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/mk_event_libevent.c
@@ -0,0 +1,514 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <mk_core/mk_event.h>
+
+/* Libevent */
+#include <event.h>
+
+#ifdef _WIN32
+#define ERR(e) (WSA##e)
+#else
+#define ERR(e) (e)
+#endif
+
+struct ev_map {
+ /* for pipes */
+ evutil_socket_t pipe[2];
+
+ struct event *event;
+ struct mk_event_ctx *ctx;
+};
+
+static inline int _mk_event_init()
+{
+ return 0;
+}
+
+static inline void *_mk_event_loop_create(int size)
+{
+ struct mk_event_ctx *ctx;
+
+ /* Main event context */
+ ctx = mk_mem_alloc_z(sizeof(struct mk_event_ctx));
+ if (!ctx) {
+ return NULL;
+ }
+
+ /* Libevent context */
+ ctx->base = event_base_new();
+
+ /* Fired events (upon select(2) return) */
+ ctx->fired = mk_mem_alloc_z(sizeof(struct mk_event) * size);
+ if (!ctx->fired) {
+ mk_mem_free(ctx);
+ return NULL;
+ }
+ ctx->queue_size = size;
+
+ return ctx;
+}
+
+/* Close handlers and memory */
+static inline void _mk_event_loop_destroy(struct mk_event_ctx *ctx)
+{
+ event_base_free(ctx->base);
+ mk_mem_free(ctx->fired);
+ mk_mem_free(ctx);
+}
+
+static void cb_event(evutil_socket_t fd, short flags, void *data)
+{
+ int i;
+ int mask = 0;
+ struct mk_event *event = data;
+ struct mk_event *fired;
+ struct mk_event_ctx *ctx;
+ struct ev_map *map = event->data;
+
+ ctx = map->ctx;
+
+ /* Compose mask */
+ if (flags & EV_READ) {
+ mask |= MK_EVENT_READ;
+ }
+ if (flags & EV_WRITE) {
+ mask |= MK_EVENT_WRITE;
+ }
+
+ /* Register the event in the fired array */
+ i = ctx->fired_count;
+ fired = &ctx->fired[i];
+ fired->fd = event->fd;
+ fired->mask = mask;
+ fired->data = event;
+
+ ctx->fired_count++;
+}
+
+/*
+ * Update an event that is already associated with an event loop.
+ *
+ * We use this method in _mk_event_add so that it can handle a dirty
+ * event transparently. In particular, this allows users to reuse an
+ * event object without reconstructing it.
+ *
+ * Return 0 on success and -1 otherwise.
+ */
+static inline int _mk_event_update(struct mk_event_ctx *ctx, evutil_socket_t fd,
+ int type, uint32_t events, void *data)
+{
+ int ret;
+ int flags = 0;
+ struct ev_map *ev_map;
+ struct mk_event *event;
+ struct event *libev;
+
+ event = (struct mk_event *) data;
+ ev_map = (struct ev_map *) event->data;
+
+ /* Remove an existing timer first */
+ event_del(ev_map->event);
+ event_free(ev_map->event);
+
+ /* Compose context */
+ if (type != MK_EVENT_UNMODIFIED) {
+ event->type = type;
+ }
+ if (events & MK_EVENT_READ) {
+ flags |= EV_READ;
+ }
+ if (events & MK_EVENT_WRITE) {
+ flags |= EV_WRITE;
+ }
+ flags |= EV_PERSIST;
+
+ /* Register into libevent */
+ libev = event_new(ctx->base, fd, flags, cb_event, event);
+ if (libev == NULL) {
+ return -1;
+ }
+
+ ret = event_add(libev, NULL);
+ if (ret < 0) {
+ return -1;
+ }
+
+ ev_map->event = libev;
+ ev_map->ctx = ctx;
+ return 0;
+}
+
+/* Add the file descriptor to the arrays */
+static inline int _mk_event_add(struct mk_event_ctx *ctx, evutil_socket_t fd,
+ int type, uint32_t events, void *data)
+{
+ int ret;
+ int flags = 0;
+ struct event *libev;
+ struct mk_event *event;
+ struct ev_map *ev_map;
+
+ mk_bug(ctx == NULL);
+ mk_bug(data == NULL);
+
+ event = (struct mk_event *) data;
+
+ if (event->mask != MK_EVENT_EMPTY) {
+ return _mk_event_update(ctx, fd, type, events, data);
+ }
+
+ ev_map = mk_mem_alloc_z(sizeof(struct ev_map));
+ if (!ev_map) {
+ perror("malloc");
+ return -1;
+ }
+
+ if (events & MK_EVENT_READ) {
+ flags |= EV_READ;
+ }
+ if (events & MK_EVENT_WRITE) {
+ flags |= EV_WRITE;
+ }
+
+ /* Compose context */
+ event->fd = fd;
+ event->type = type;
+ event->mask = events;
+ event->status = MK_EVENT_REGISTERED;
+ event->data = ev_map;
+
+ event->priority = MK_EVENT_PRIORITY_DEFAULT;
+
+ /* Remove from priority queue */
+ if (!mk_list_entry_is_orphan(&event->_priority_head)) {
+ mk_list_del(&event->_priority_head);
+ }
+
+ /* Register into libevent */
+ flags |= EV_PERSIST;
+ libev = event_new(ctx->base, fd, flags, cb_event, event);
+
+ ev_map->event = libev;
+ ev_map->ctx = ctx;
+
+ ret = event_add(libev, NULL);
+ if (ret < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Delete an event */
+static inline int _mk_event_del(struct mk_event_ctx *ctx, struct mk_event *event)
+{
+ int ret;
+ struct ev_map *ev_map;
+
+ mk_bug(ctx == NULL);
+ mk_bug(event == NULL);
+
+ if (!MK_EVENT_IS_REGISTERED(event)) {
+ return 0;
+ }
+
+ ev_map = event->data;
+
+ mk_bug(ev_map == NULL);
+
+ if (ev_map->pipe[0] > 0) {
+ evutil_closesocket(ev_map->pipe[0]);
+ ev_map->pipe[0] = -1;
+ }
+ if (ev_map->pipe[1] > 0) {
+ evutil_closesocket(ev_map->pipe[1]);
+ ev_map->pipe[1] = -1;
+ }
+
+ ret = event_del(ev_map->event);
+ event_free(ev_map->event);
+ mk_mem_free(ev_map);
+
+ event->data = NULL;
+
+ /* Remove from priority queue */
+ if (!mk_list_entry_is_orphan(&event->_priority_head)) {
+ mk_list_del(&event->_priority_head);
+ }
+
+ MK_EVENT_NEW(event);
+
+ return ret;
+}
+
+/*
+ * Timeout worker, it writes a byte every certain amount of seconds, it finish
+ * once the other end of the pipe closes the fd[0].
+ */
+static void cb_timeout(evutil_socket_t fd, short flags, void *data)
+{
+ int ret;
+ uint64_t val = 1;
+ struct ev_map *ev_map = data;
+
+ ret = send(ev_map->pipe[1], (char *) &val, sizeof(uint64_t), 0);
+
+ if (ret == -1) {
+ if (evutil_socket_geterror(fd) != ERR(ECONNABORTED)) {
+ perror("write");
+ }
+ evutil_closesocket(ev_map->pipe[1]);
+ event_del(ev_map->event);
+ event_free(ev_map->event);
+ mk_mem_free(ev_map);
+ }
+}
+
+/*
+ * This routine creates a timer, since this select(2) backend aims to be used
+ * in very old systems to be compatible, we cannot trust timerfd_create(2)
+ * will be available (e.g: Cygwin), so our workaround is to create a pipe(2)
+ * and a thread, this thread writes a byte upon the expiration time is reached.
+ */
+static inline int _mk_event_timeout_create(struct mk_event_ctx *ctx,
+ time_t sec, long nsec, void *data)
+{
+ int ret;
+ evutil_socket_t fd[2];
+ struct event *libev;
+ struct mk_event *event;
+ struct timeval timev = {sec, nsec / 1000}; /* (tv_sec, tv_usec} */
+ struct ev_map *ev_map;
+
+ mk_bug(data == NULL);
+
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) {
+ perror("socketpair");
+ return -1;
+ }
+
+ event = (struct mk_event *) data;
+
+ ev_map = mk_mem_alloc_z(sizeof(struct ev_map));
+ if (!ev_map) {
+ perror("malloc");
+ return -1;
+ }
+
+ ev_map->pipe[0] = fd[0];
+ ev_map->pipe[1] = fd[1];
+ ev_map->ctx = ctx;
+
+ libev = event_new(ctx->base, -1,
+ EV_TIMEOUT | EV_PERSIST,
+ cb_timeout, ev_map);
+ ev_map->event = libev;
+
+ event_add(libev, &timev);
+
+ event->fd = fd[0];
+ event->type = MK_EVENT_NOTIFICATION;
+ event->mask = MK_EVENT_EMPTY;
+
+ _mk_event_add(ctx, fd[0], MK_EVENT_NOTIFICATION, MK_EVENT_READ, data);
+ event->mask = MK_EVENT_READ;
+
+ return fd[0];
+}
+
+static inline int _mk_event_timeout_destroy(struct mk_event_ctx *ctx, void *data)
+{
+ struct mk_event *event;
+
+ if (data == NULL) {
+ return 0;
+ }
+
+ /* In the case that the timeout is being destroyed manually, we need to close the
+ * read end of the socket to ensure that cb_timeout will eventually fail to send
+ * data and clean itself up (including the write end of the socket and the event's
+ * data).
+ */
+ event = (struct mk_event*)data;
+ if (event->fd > 0) {
+ evutil_closesocket(event->fd);
+ }
+
+ return _mk_event_del(ctx, data);
+}
+
+static inline int _mk_event_channel_create(struct mk_event_ctx *ctx,
+ int *r_fd, int *w_fd, void *data)
+{
+ struct mk_event *event;
+ evutil_socket_t fd[2];
+ int ret;
+
+ mk_bug(data == NULL);
+
+ ret = evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
+
+ if (ret == -1) {
+ perror("socketpair");
+ return -1;
+ }
+
+ event = data;
+ event->fd = fd[0];
+ event->type = MK_EVENT_NOTIFICATION;
+ event->mask = MK_EVENT_EMPTY;
+
+ ret = _mk_event_add(ctx, fd[0],
+ MK_EVENT_NOTIFICATION, MK_EVENT_READ, event);
+ if (ret != 0) {
+ evutil_closesocket(fd[0]);
+ evutil_closesocket(fd[1]);
+ return ret;
+ }
+ event->mask = MK_EVENT_READ;
+
+ *r_fd = fd[0];
+ *w_fd = fd[1];
+
+ return 0;
+}
+
+static inline int _mk_event_channel_destroy(struct mk_event_ctx *ctx,
+ int r_fd, int w_fd, void *data)
+{
+ struct mk_event *event;
+ int ret;
+
+
+ event = (struct mk_event *)data;
+ if (event->fd != r_fd) {
+ return -1;
+ }
+
+ ret = _mk_event_del(ctx, event);
+ if (ret != 0) {
+ return ret;
+ }
+
+ evutil_closesocket(r_fd);
+ evutil_closesocket(w_fd);
+
+ return 0;
+}
+
+static inline int _mk_event_inject(struct mk_event_loop *loop,
+ struct mk_event *event,
+ int mask,
+ int prevent_duplication)
+{
+ size_t index;
+ struct mk_event_ctx *ctx;
+
+ ctx = loop->data;
+
+ if (prevent_duplication) {
+ for (index = 0 ; index < loop->n_events ; index++) {
+ if (ctx->fired[index].data == event) {
+ return 0;
+ }
+ }
+ }
+
+ event->mask = mask;
+
+ ctx->fired[ctx->fired_count].fd = event->fd;
+ ctx->fired[ctx->fired_count].mask = mask;
+ ctx->fired[ctx->fired_count].data = event;
+
+ ctx->fired_count++;
+ loop->n_events++;
+
+ return 0;
+}
+
+static inline int _mk_event_wait_with_flags(struct mk_event_loop *loop, int flags)
+{
+ struct mk_event_ctx *ctx = loop->data;
+
+ /*
+ * Libevent use callbacks, so on every callback the 'fired' array
+ * is populated, so we reset the counter every time this function
+ * is called.
+ */
+
+ ctx->fired_count = 0;
+ event_base_loop(ctx->base, flags);
+ loop->n_events = ctx->fired_count;
+
+ return loop->n_events;
+}
+
+/* This is a callback stub for wait_2 resume. It does nothing */
+static void cb_wait_2_timeout(evutil_socket_t fd, short flags, void *data)
+{
+ return;
+}
+
+static inline int _mk_event_wait_2(struct mk_event_loop *loop, int timeout)
+{
+ struct mk_event_ctx *ctx = loop->data;
+ struct timeval timev = {timeout / 1000, (timeout % 1000) * 1000}; /* (tv_sec, tv_usec} */
+ int timedout_flag = 0;
+ struct event *timeout_event;
+ int ret;
+
+ /* Infinite wait */
+ if (timeout == -1) {
+ return _mk_event_wait_with_flags(loop, EVLOOP_ONCE);
+ }
+
+ /* No wait: fast path, zero second timeout is nonblocking wait */
+ if (timeout == 0) {
+ return _mk_event_wait_with_flags(loop, EVLOOP_ONCE | EVLOOP_NONBLOCK);
+ }
+
+ /* Timed wait: slow path, blocking wait with timeout via timeout event */
+ /* Add timeout */
+ timeout_event = event_new(ctx->base, -1,
+ EV_TIMEOUT,
+ cb_wait_2_timeout, &timedout_flag);
+
+ event_add(timeout_event, &timev);
+
+ /* Blocking wait */
+ ret = _mk_event_wait_with_flags(loop, EVLOOP_ONCE);
+
+ /*
+ * Remove timeout
+ * "To deallocate an event, call event_free(). It is safe to call event_free()
+ * on an event that is pending or active: doing so makes the event non-pending
+ * and inactive before deallocating it."
+ * ref: http://www.wangafu.net/~nickm/libevent-book/Ref4_event.html
+ */
+ event_free(timeout_event);
+
+ return ret;
+}
+
+static inline char *_mk_event_backend()
+{
+ return "libevent";
+}
diff --git a/fluent-bit/lib/monkey/mk_core/mk_event_select.c b/fluent-bit/lib/monkey/mk_core/mk_event_select.c
new file mode 100644
index 000000000..e326ba85b
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/mk_event_select.c
@@ -0,0 +1,439 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef _WIN32
+#include <Winsock2.h>
+#else
+#include <sys/select.h>
+#endif
+
+#include <mk_core/mk_event.h>
+#include <time.h>
+
+/* I could be wrong but i think the whole way in which
+ * this module handles the event array seems to be flawed
+ * because it's addressed by the file descriptor, which in
+ * some cases could cause an out of bounds write of a non
+ * controllable QWORD (ie. line 117)
+ *
+ * I'll leave it for the moment but I think we might want
+ * to come back to it and refactor it to just use the event
+ * array as a list (at most implementing a hash table like
+ * addressing mechanism to make it faster)
+ */
+
+struct fd_timer {
+ int fd;
+ int run;
+ time_t sec;
+ long nsec;
+ pthread_t tid;
+};
+
+static inline int _mk_event_init()
+{
+ return 0;
+}
+
+static inline void *_mk_event_loop_create(int size)
+{
+ struct mk_event_ctx *ctx;
+
+ /* Override caller 'size', we always use FD_SETSIZE */
+ size = FD_SETSIZE;
+
+ /* Main event context */
+ ctx = mk_mem_alloc_z(sizeof(struct mk_event_ctx));
+ if (!ctx) {
+ return NULL;
+ }
+
+ FD_ZERO(&ctx->rfds);
+ FD_ZERO(&ctx->wfds);
+
+ /* Allocate space for events queue, re-use the struct mk_event */
+ ctx->events = mk_mem_alloc_z(sizeof(struct mk_event *) * size);
+ if (!ctx->events) {
+ mk_mem_free(ctx);
+ return NULL;
+ }
+
+ /* Fired events (upon select(2) return) */
+ ctx->fired = mk_mem_alloc_z(sizeof(struct mk_event) * size);
+ if (!ctx->fired) {
+ mk_mem_free(ctx->events);
+ mk_mem_free(ctx);
+ return NULL;
+ }
+ ctx->queue_size = size;
+
+ return ctx;
+}
+
+/* Close handlers and memory */
+static inline void _mk_event_loop_destroy(struct mk_event_ctx *ctx)
+{
+ mk_mem_free(ctx->events);
+ mk_mem_free(ctx->fired);
+ mk_mem_free(ctx);
+}
+
+/* Add the file descriptor to the arrays */
+static inline int _mk_event_add(struct mk_event_ctx *ctx, int fd,
+ int type, uint32_t events, void *data)
+{
+ struct mk_event *event;
+
+ mk_bug(ctx == NULL);
+ mk_bug(data == NULL);
+
+ if (fd > FD_SETSIZE) {
+ return -1;
+ }
+
+ if (events & MK_EVENT_READ) {
+ FD_SET(fd, &ctx->rfds);
+ }
+ if (events & MK_EVENT_WRITE) {
+ FD_SET(fd, &ctx->wfds);
+ }
+
+ event = (struct mk_event *) data;
+ event->fd = fd;
+ event->mask = events;
+ event->status = MK_EVENT_REGISTERED;
+
+ event->priority = MK_EVENT_PRIORITY_DEFAULT;
+
+ /* Remove from priority queue */
+ if (!mk_list_entry_is_orphan(&event->_priority_head)) {
+ mk_list_del(&event->_priority_head);
+ }
+
+ if (type != MK_EVENT_UNMODIFIED) {
+ event->type = type;
+ }
+
+ ctx->events[fd] = event;
+ if (fd > ctx->max_fd) {
+ ctx->max_fd = fd;
+ }
+
+ return 0;
+}
+
+/* Delete an event */
+static inline int _mk_event_del(struct mk_event_ctx *ctx, struct mk_event *event)
+{
+ int i;
+ int fd;
+ struct mk_event *s_event;
+
+ mk_bug(ctx == NULL);
+ mk_bug(event == NULL);
+
+ if (!MK_EVENT_IS_REGISTERED(event)) {
+ return 0;
+ }
+
+ fd = event->fd;
+
+ if (event->mask & MK_EVENT_READ) {
+ FD_CLR(event->fd, &ctx->rfds);
+ }
+
+ if (event->mask & MK_EVENT_WRITE) {
+ FD_CLR(event->fd, &ctx->wfds);
+ }
+
+ /* Update max_fd, lookup */
+ if (event->fd == ctx->max_fd) {
+ for (i = (ctx->max_fd - 1); i > 0; i--) {
+ if (!ctx->events[i]) {
+ continue;
+ }
+
+ s_event = ctx->events[i];
+ if (s_event->mask != MK_EVENT_EMPTY) {
+ break;
+ }
+ }
+ ctx->max_fd = i;
+ }
+
+ ctx->events[fd] = NULL;
+
+ /* Remove from priority queue */
+ if (!mk_list_entry_is_orphan(&event->_priority_head)) {
+ mk_list_del(&event->_priority_head);
+ }
+
+ MK_EVENT_NEW(event);
+
+ return 0;
+}
+
+/*
+ * Timeout worker, it writes a byte every certain amount of seconds, it finish
+ * once the other end of the pipe closes the fd[0].
+ */
+void _timeout_worker(void *arg)
+{
+ int ret;
+ uint64_t val = 1;
+ struct fd_timer *timer;
+ struct timespec t_spec;
+
+ timer = (struct fd_timer *) arg;
+ t_spec.tv_sec = timer->sec;
+ t_spec.tv_nsec = timer->nsec;
+
+ while (timer->run == MK_TRUE) {
+ /* sleep for a while */
+ nanosleep(&t_spec, NULL);
+
+ /* send notification */
+ ret = write(timer->fd, &val, sizeof(uint64_t));
+ if (ret == -1) {
+ perror("write");
+ break;
+ }
+ }
+
+ pthread_exit(NULL);
+}
+
+/*
+ * This routine creates a timer, since this select(2) backend aims to be used
+ * in very old systems to be compatible, we cannot trust timerfd_create(2)
+ * will be available (e.g: Cygwin), so our workaround is to create a pipe(2)
+ * and a thread, this thread writes a byte upon the expiration time is reached.
+ */
+static inline int _mk_event_timeout_create(struct mk_event_ctx *ctx,
+ time_t sec, long nsec, void *data)
+{
+ int ret;
+ int fd[2];
+ struct mk_event *event;
+ struct fd_timer *timer;
+
+ timer = mk_mem_alloc(sizeof(struct fd_timer));
+ if (!timer) {
+ return -1;
+ }
+
+ ret = pipe(fd);
+ if (ret < 0) {
+ mk_mem_free(timer);
+ mk_libc_error("pipe");
+ return ret;
+ }
+
+ event = (struct mk_event *) data;
+ event->fd = fd[0];
+ event->type = MK_EVENT_NOTIFICATION;
+ event->mask = MK_EVENT_EMPTY;
+
+ _mk_event_add(ctx, fd[0], MK_EVENT_NOTIFICATION, MK_EVENT_READ, data);
+ event->mask = MK_EVENT_READ;
+
+ /* Compose the timer context, this is released inside the worker thread */
+ timer->fd = fd[1];
+ timer->sec = sec;
+ timer->nsec = nsec;
+ timer->run = MK_TRUE;
+
+ event->data = timer;
+
+ /* Now the dirty workaround, create a thread */
+ ret = mk_utils_worker_spawn(_timeout_worker, timer, &timer->tid);
+ if (ret < 0) {
+ close(fd[0]);
+ close(fd[1]);
+ mk_mem_free(timer);
+ return -1;
+ }
+
+ return fd[0];
+}
+
+static inline int _mk_event_timeout_destroy(struct mk_event_ctx *ctx, void *data)
+{
+ int fd;
+ struct mk_event *event;
+ struct fd_timer *timer;
+
+ event = (struct mk_event *) data;
+
+ fd = event->fd;
+ _mk_event_del(ctx, event);
+
+ timer = event->data;
+ timer->run = MK_FALSE;
+
+ /* Wait for the background worker to finish */
+ pthread_join(timer->tid, NULL);
+
+ /* Cleanup */
+ close(timer->fd);
+ close(fd);
+ mk_mem_free(timer);
+ return 0;
+}
+
+static inline int _mk_event_channel_create(struct mk_event_ctx *ctx,
+ int *r_fd, int *w_fd, void *data)
+{
+ int ret;
+ int fd[2];
+ struct mk_event *event;
+
+ mk_bug(data == NULL);
+
+ ret = pipe(fd);
+ if (ret < 0) {
+ mk_libc_error("pipe");
+ return ret;
+ }
+
+ event = data;
+ event->fd = fd[0];
+ event->type = MK_EVENT_NOTIFICATION;
+ event->mask = MK_EVENT_EMPTY;
+
+ ret = _mk_event_add(ctx, fd[0],
+ MK_EVENT_NOTIFICATION, MK_EVENT_READ, event);
+ if (ret != 0) {
+ close(fd[0]);
+ close(fd[1]);
+ return ret;
+ }
+ event->mask = MK_EVENT_READ;
+
+ *r_fd = fd[0];
+ *w_fd = fd[1];
+
+ return 0;
+}
+
+static inline int _mk_event_channel_destroy(struct mk_event_ctx *ctx,
+ int r_fd, int w_fd, void *data)
+{
+ struct mk_event *event;
+ int ret;
+
+
+ event = (struct mk_event *)data;
+ if (event->fd != r_fd) {
+ return -1;
+ }
+
+ ret = _mk_event_del(ctx, event);
+ if (ret != 0) {
+ return ret;
+ }
+
+ close(r_fd);
+ close(w_fd);
+
+ return 0;
+}
+
+static inline int _mk_event_inject(struct mk_event_loop *loop,
+ struct mk_event *event,
+ int mask,
+ int prevent_duplication)
+{
+ size_t index;
+ struct mk_event_ctx *ctx;
+
+ ctx = loop->data;
+
+ if (prevent_duplication) {
+ for (index = 0 ; index < loop->n_events ; index++) {
+ if (ctx->fired[index]->fd == event->fd) {
+ return 0;
+ }
+ }
+ }
+
+ event->mask = mask;
+
+ ctx->fired[loop->n_events] = event;
+
+ loop->n_events++;
+
+ return 0;
+}
+
+static inline int _mk_event_wait_2(struct mk_event_loop *loop, int timeout)
+{
+ int i;
+ int f = 0;
+ uint32_t mask;
+ struct mk_event *fired;
+ struct mk_event_ctx *ctx = loop->data;
+ struct timeval timev = {timeout / 1000, (timeout % 1000) * 1000};
+
+ memcpy(&ctx->_rfds, &ctx->rfds, sizeof(fd_set));
+ memcpy(&ctx->_wfds, &ctx->wfds, sizeof(fd_set));
+
+ loop->n_events = select(ctx->max_fd + 1, &ctx->_rfds, &ctx->_wfds, NULL,
+ (timeout != -1) ? &timev : NULL);
+ if (loop->n_events <= 0) {
+ return loop->n_events;
+ }
+
+ /*
+ * Populate our events array with the data reported. In other backends such
+ * as mk_event_epoll and mk_event_kqueue this is done when iterating the
+ * results as their native implementation already provided an array ready
+ * for processing.
+ */
+ for (i = 0; i <= ctx->max_fd; i++) {
+ /* skip empty references */
+ if (!ctx->events[i]) {
+ continue;
+ }
+
+ mask = 0;
+ if (FD_ISSET(i, &ctx->_rfds)) {
+ mask |= MK_EVENT_READ;
+ }
+ if (FD_ISSET(i, &ctx->_wfds)) {
+ mask |= MK_EVENT_WRITE;
+ }
+
+ if (mask) {
+ fired = &ctx->fired[f];
+ fired->fd = i;
+ fired->mask = mask;
+ fired->data = ctx->events[i];
+ f++;
+ }
+ }
+
+ loop->n_events = f;
+ return loop->n_events;
+}
+
+static inline char *_mk_event_backend()
+{
+ return "select";
+}
diff --git a/fluent-bit/lib/monkey/mk_core/mk_file.c b/fluent-bit/lib/monkey/mk_core/mk_file.c
new file mode 100644
index 000000000..21593281e
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/mk_file.c
@@ -0,0 +1,153 @@
+/*-*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mk_core.h"
+
+#ifdef _WIN32
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#define S_ISLNK(m) (0)
+#define O_NONBLOCK (0)
+#define lstat stat
+#endif
+
+int mk_file_get_info(const char *path, struct file_info *f_info, int mode)
+{
+ struct stat f, target;
+
+ f_info->exists = MK_FALSE;
+
+ /* Stat right resource */
+ if (lstat(path, &f) == -1) {
+ if (errno == EACCES) {
+ f_info->exists = MK_TRUE;
+ }
+ return -1;
+ }
+
+ f_info->exists = MK_TRUE;
+ f_info->is_file = MK_TRUE;
+ f_info->is_link = MK_FALSE;
+ f_info->is_directory = MK_FALSE;
+ f_info->exec_access = MK_FALSE;
+ f_info->read_access = MK_FALSE;
+
+ if (S_ISLNK(f.st_mode)) {
+ f_info->is_link = MK_TRUE;
+ f_info->is_file = MK_FALSE;
+ if (stat(path, &target) == -1) {
+ return -1;
+ }
+ }
+ else {
+ target = f;
+ }
+
+ f_info->size = target.st_size;
+ f_info->last_modification = target.st_mtime;
+
+ if (S_ISDIR(target.st_mode)) {
+ f_info->is_directory = MK_TRUE;
+ f_info->is_file = MK_FALSE;
+ }
+
+#ifndef _WIN32
+ gid_t EGID = getegid();
+ gid_t EUID = geteuid();
+
+ /* Check read access */
+ if (mode & MK_FILE_READ) {
+ if (((target.st_mode & S_IRUSR) && target.st_uid == EUID) ||
+ ((target.st_mode & S_IRGRP) && target.st_gid == EGID) ||
+ (target.st_mode & S_IROTH)) {
+ f_info->read_access = MK_TRUE;
+ }
+ }
+
+ /* Checking execution */
+ if (mode & MK_FILE_EXEC) {
+ if ((target.st_mode & S_IXUSR && target.st_uid == EUID) ||
+ (target.st_mode & S_IXGRP && target.st_gid == EGID) ||
+ (target.st_mode & S_IXOTH)) {
+ f_info->exec_access = MK_TRUE;
+ }
+ }
+#endif
+
+ /* Suggest open(2) flags */
+ f_info->flags_read_only = O_RDONLY | O_NONBLOCK;
+
+#if defined(__linux__)
+ /*
+ * If the user is the owner of the file or the user is root, it
+ * can set the O_NOATIME flag for open(2) operations to avoid
+ * inode updates about last accessed time
+ */
+ if (target.st_uid == EUID || EUID == 0) {
+ f_info->flags_read_only |= O_NOATIME;
+ }
+#endif
+
+ return 0;
+}
+
+/* Read file content to a memory buffer,
+ * Use this function just for really SMALL files
+ */
+char *mk_file_to_buffer(const char *path)
+{
+ FILE *fp;
+ char *buffer;
+ long bytes;
+ struct file_info finfo;
+
+ if (mk_file_get_info(path, &finfo, MK_FILE_READ) != 0) {
+ return NULL;
+ }
+
+ if (!(fp = fopen(path, "rb"))) {
+ return NULL;
+ }
+
+ buffer = mk_mem_alloc_z(finfo.size + 1);
+ if (!buffer) {
+ fclose(fp);
+ return NULL;
+ }
+
+ bytes = fread(buffer, finfo.size, 1, fp);
+
+ if (bytes < 1) {
+ mk_mem_free(buffer);
+ fclose(fp);
+ return NULL;
+ }
+
+ fclose(fp);
+ return (char *) buffer;
+
+}
diff --git a/fluent-bit/lib/monkey/mk_core/mk_iov.c b/fluent-bit/lib/monkey/mk_core/mk_iov.c
new file mode 100644
index 000000000..41ff9e174
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/mk_iov.c
@@ -0,0 +1,209 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+
+//#include <sys/mman.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <mk_core/mk_macros.h>
+#include <mk_core/mk_memory.h>
+#include <mk_core/mk_iov.h>
+#include <mk_core/mk_uio.h>
+
+const mk_ptr_t mk_iov_crlf = mk_ptr_init(MK_IOV_CRLF);
+const mk_ptr_t mk_iov_lf = mk_ptr_init(MK_IOV_LF);
+const mk_ptr_t mk_iov_space = mk_ptr_init(MK_IOV_SPACE);
+const mk_ptr_t mk_iov_slash = mk_ptr_init(MK_IOV_SLASH);
+const mk_ptr_t mk_iov_none = mk_ptr_init(MK_IOV_NONE);
+const mk_ptr_t mk_iov_equal = mk_ptr_init(MK_IOV_EQUAL);
+
+struct mk_iov *mk_iov_create(int n, int offset)
+{
+ int s_all;
+ int s_iovec;
+ int s_free_buf;
+ void *p;
+ struct mk_iov *iov;
+
+ s_all = sizeof(struct mk_iov); /* main mk_iov structure */
+ s_iovec = (n * sizeof(struct mk_iovec)); /* iovec array size */
+ s_free_buf = (n * sizeof(void *)); /* free buf array */
+
+ p = mk_mem_alloc_z(s_all + s_iovec + s_free_buf);
+ if (!p) {
+ return NULL;
+ }
+
+ /* Set pointer address */
+ iov = p;
+ iov->io = (struct mk_iovec *)((uint8_t *)p + sizeof(struct mk_iov));
+ iov->buf_to_free = (void *) ((uint8_t*)p + sizeof(struct mk_iov) + s_iovec);
+
+ mk_iov_init(iov, n, offset);
+ return iov;
+}
+
+struct mk_iov *mk_iov_realloc(struct mk_iov *mk_io, int new_size)
+{
+ int i;
+ struct mk_iov *iov;
+
+ /*
+ * We do not perform a memory realloc because our struct iov have
+ * self references on it 'io' and 'buf_to_free' pointers. So we create a
+ * new mk_iov and perform a data migration.
+ */
+ iov = mk_iov_create(new_size, 0);
+ if (!iov) {
+ return NULL;
+ }
+
+ /* Migrate data */
+ iov->iov_idx = mk_io->iov_idx;
+ iov->buf_idx = mk_io->buf_idx;
+ iov->size = new_size;
+ iov->total_len = mk_io->total_len;
+
+ for (i = 0; i < mk_io->iov_idx; i++) {
+ iov->io[i].iov_base = mk_io->io[i].iov_base;
+ iov->io[i].iov_len = mk_io->io[i].iov_len;
+ }
+
+ for (i = 0; i < mk_io->buf_idx; i++) {
+ iov->buf_to_free[i] = mk_io->buf_to_free[i];
+ }
+
+ return iov;
+}
+
+int mk_iov_set_entry(struct mk_iov *mk_io, void *buf, int len,
+ int free, int idx)
+{
+ mk_io->io[idx].iov_base = buf;
+ mk_io->io[idx].iov_len = len;
+ mk_io->total_len += len;
+
+ if (free == MK_TRUE) {
+ _mk_iov_set_free(mk_io, buf);
+ }
+
+ return 0;
+}
+
+ssize_t mk_iov_send(int fd, struct mk_iov *mk_io)
+{
+ ssize_t n = writev(fd, mk_io->io, mk_io->iov_idx);
+ if (mk_unlikely(n < 0)) {
+ MK_TRACE( "[FD %i] writev() '%s'", fd, strerror(errno));
+ return -1;
+ }
+
+ return n;
+}
+
+void mk_iov_free(struct mk_iov *mk_io)
+{
+ mk_iov_free_marked(mk_io);
+ mk_mem_free(mk_io);
+ mk_io = NULL;
+}
+
+void mk_iov_free_marked(struct mk_iov *mk_io)
+{
+ int i, limit = 0;
+
+ limit = mk_io->buf_idx;
+
+ for (i = 0; i < limit; i++) {
+
+#ifdef DEBUG_IOV
+ printf("\nDEBUG IOV :: going free (idx: %i/%i): %s", i,
+ limit, mk_io->buf_to_free[i]);
+ fflush(stdout);
+#endif
+ mk_mem_free(mk_io->buf_to_free[i]);
+ }
+
+ mk_io->iov_idx = 0;
+ mk_io->buf_idx = 0;
+ mk_io->total_len = 0;
+}
+
+void mk_iov_print(struct mk_iov *mk_io)
+{
+ int i;
+ unsigned j;
+ char *c;
+
+ for (i = 0; i < mk_io->iov_idx; i++) {
+ printf("\n[index=%i len=%i]\n'", i, (int) mk_io->io[i].iov_len);
+ fflush(stdout);
+
+ for (j=0; j < mk_io->io[i].iov_len; j++) {
+ c = mk_io->io[i].iov_base;
+ printf("%c", c[j]);
+ fflush(stdout);
+ }
+ printf("'[end=%i]\n", j);
+ fflush(stdout);
+ }
+}
+
+int mk_iov_consume(struct mk_iov *mk_io, size_t bytes)
+{
+ int i;
+ size_t len;
+
+ if (mk_io->total_len == bytes) {
+ mk_io->total_len = 0;
+ mk_io->iov_idx = 0;
+ return 0;
+ }
+
+ for (i = 0; i < mk_io->iov_idx; i++) {
+ len = mk_io->io[i].iov_len;
+ if (len == 0) {
+ continue;
+ }
+
+ if (bytes < len) {
+ mk_io->io[i].iov_base = (uint8_t *)mk_io->io[i].iov_base + bytes;
+ mk_io->io[i].iov_len = (len - bytes);
+ break;
+ }
+ else if (bytes == len) {
+ /* this entry was consumed */
+ mk_io->io[i].iov_len = 0;
+ break;
+ }
+ else {
+ /* bytes > 0, consume this entry */
+ mk_io->io[i].iov_len = 0;
+ bytes -= len;
+ }
+ }
+
+ mk_io->total_len -= (unsigned long)bytes;
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/mk_memory.c b/fluent-bit/lib/monkey/mk_core/mk_memory.c
new file mode 100644
index 000000000..c4073e231
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/mk_memory.c
@@ -0,0 +1,80 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <mk_core/mk_pthread.h>
+#include <mk_core/mk_memory.h>
+#include <mk_core/mk_macros.h>
+
+mk_ptr_t mk_ptr_create(char *buf, long init, long end)
+{
+ mk_ptr_t p;
+
+ p.data = buf + init;
+
+ if (init != end) {
+ p.len = (end - init);
+ }
+ else {
+ p.len = 1;
+ }
+
+ return p;
+}
+
+void mk_ptr_free(mk_ptr_t * p)
+{
+ mk_mem_free(p->data);
+ p->len = 0;
+}
+
+char *mk_ptr_to_buf(mk_ptr_t p)
+{
+ char *buf;
+
+ buf = mk_mem_alloc(p.len + 1);
+ if (!buf) return NULL;
+
+ memcpy(buf, p.data, p.len);
+ buf[p.len] = '\0';
+
+ return (char *) buf;
+}
+
+void mk_ptr_print(mk_ptr_t p)
+{
+ unsigned int i;
+
+ printf("\nDEBUG MK_POINTER: '");
+ for (i = 0; i < p.len && p.data != NULL; i++) {
+ printf("%c", p.data[i]);
+ }
+ printf("'");
+ fflush(stdout);
+}
+
+void mk_ptr_set(mk_ptr_t *p, char *data)
+{
+ p->data = data;
+ p->len = strlen(data);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/mk_rconf.c b/fluent-bit/lib/monkey/mk_core/mk_rconf.c
new file mode 100644
index 000000000..bf169d0e8
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/mk_rconf.c
@@ -0,0 +1,779 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef _MSC_VER
+#include <glob.h>
+#endif
+
+#include <mk_core/mk_rconf.h>
+#include <mk_core/mk_utils.h>
+#include <mk_core/mk_string.h>
+#include <mk_core/mk_list.h>
+
+#ifdef _WIN32
+#include <Windows.h>
+#include <strsafe.h>
+#define PATH_MAX MAX_PATH
+#endif
+
+/* Raise a configuration schema error */
+static void mk_config_error(const char *path, int line, const char *msg)
+{
+ mk_err("File %s", path);
+ mk_err("Error in line %i: %s", line, msg);
+}
+
+/* Raise a warning */
+static void mk_rconf_warning(const char *path, int line, const char *msg)
+{
+ mk_warn("Config file warning '%s':\n"
+ "\t\t\t\tat line %i: %s",
+ path, line, msg);
+}
+
+
+/* Returns a configuration section by [section name] */
+struct mk_rconf_section *mk_rconf_section_get(struct mk_rconf *conf,
+ const char *name)
+{
+ struct mk_list *head;
+ struct mk_rconf_section *section;
+
+ mk_list_foreach(head, &conf->sections) {
+ section = mk_list_entry(head, struct mk_rconf_section, _head);
+ if (strcasecmp(section->name, name) == 0) {
+ return section;
+ }
+ }
+
+ return NULL;
+}
+
+/* Register a key/value entry in the last section available of the struct */
+static void mk_rconf_section_entry_add(struct mk_rconf *conf,
+ const char *key, const char *val)
+{
+ struct mk_rconf_section *section;
+ struct mk_rconf_entry *new;
+ struct mk_list *head = &conf->sections;
+
+ if (mk_list_is_empty(&conf->sections) == 0) {
+ mk_err("Error: there are not sections available on %s!", conf->file);
+ return;
+ }
+
+ /* Last section */
+ section = mk_list_entry_last(head, struct mk_rconf_section, _head);
+
+ /* Alloc new entry */
+ new = mk_mem_alloc(sizeof(struct mk_rconf_entry));
+ new->key = mk_string_dup(key);
+ new->val = mk_string_dup(val);
+
+ mk_list_add(&new->_head, &section->entries);
+}
+
+/* Create a configuration schema */
+struct mk_rconf *mk_rconf_create(const char *name)
+{
+ struct mk_rconf *conf = NULL;
+
+ /* Alloc configuration node */
+ conf = mk_mem_alloc_z(sizeof(struct mk_rconf));
+ if (!conf) {
+ perror("malloc");
+ return NULL;
+ }
+ conf->created = time(NULL);
+ conf->file = mk_string_dup(name);
+ mk_list_init(&conf->sections);
+
+ return conf;
+}
+
+static int is_file_included(struct mk_rconf *conf, const char *path)
+{
+ struct mk_list *head;
+ struct mk_rconf_file *file;
+
+ mk_list_foreach(head, &conf->includes) {
+ file = mk_list_entry(head, struct mk_rconf_file, _head);
+ if (strcmp(file->path, path) == 0) {
+ return MK_TRUE;
+ }
+ }
+
+ return MK_FALSE;
+}
+
+char *mk_rconf_meta_get(struct mk_rconf *conf, char *key)
+{
+ struct mk_list *head;
+ struct mk_rconf_entry *meta;
+
+ mk_list_foreach(head, &conf->metas) {
+ meta = mk_list_entry(head, struct mk_rconf_entry, _head);
+ if (strcmp(meta->key, key) == 0) {
+ return meta->val;
+ }
+ }
+
+ return NULL;
+}
+
+static int mk_rconf_meta_add(struct mk_rconf *conf, char *buf, int len)
+{
+ int xlen;
+ char *p;
+ char *tmp;
+ struct mk_rconf_entry *meta;
+
+ if (buf[0] != '@') {
+ return -1;
+ }
+
+ meta = mk_mem_alloc(sizeof(struct mk_rconf_entry));
+ if (!meta) {
+ return -1;
+ }
+
+ p = buf;
+ tmp = strchr(p, ' ');
+ xlen = (tmp - p);
+ meta->key = mk_string_copy_substr(buf, 1, xlen);
+ mk_string_trim(&meta->key);
+
+ meta->val = mk_string_copy_substr(buf, xlen + 1, len);
+ mk_string_trim(&meta->val);
+
+ mk_list_add(&meta->_head, &conf->metas);
+ return 0;
+}
+
+static int check_indent(const char *line, const char *indent)
+{
+ while (*line == *indent && *indent) {
+ line++;
+ indent++;
+ }
+
+ if (*indent != '\0') {
+ if (isblank(*line)) {
+ mk_err("[config] Inconsistent use of tab and space");
+ }
+ else {
+ mk_err("[config] Indentation level is too low");
+ }
+ return -1;
+ }
+
+ if (isblank(*line)) {
+ mk_err("[config] Extra indentation level found");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* To call this function from mk_rconf_read */
+static int mk_rconf_read_glob(struct mk_rconf *conf, const char * path);
+
+static int mk_rconf_read(struct mk_rconf *conf, const char *path)
+{
+ int i;
+ int len;
+ int ret;
+ int line = 0;
+ int indent_len = -1;
+ int n_keys = 0;
+ char *buf;
+ char tmp[PATH_MAX];
+ char *section = NULL;
+ char *indent = NULL;
+ char *key, *val;
+ char *cfg_file = (char *) path;
+ struct stat st;
+ struct mk_rconf_file *file;
+ struct mk_rconf_section *current = NULL;
+ FILE *f;
+
+ /* Check if the path exists (relative cases for included files) */
+ if (conf->level >= 0) {
+ ret = stat(path, &st);
+ if (ret == -1 && errno == ENOENT) {
+ /* Try to resolve the real path (if exists) */
+ if (path[0] == '/') {
+ return -1;
+ }
+
+ if (conf->root_path) {
+ snprintf(tmp, PATH_MAX, "%s/%s", conf->root_path, path);
+ cfg_file = tmp;
+ }
+ }
+ }
+
+ /* Check this file have not been included before */
+ ret = is_file_included(conf, cfg_file);
+ if (ret == MK_TRUE) {
+ mk_err("[config] file already included %s", cfg_file);
+ return -1;
+ }
+
+ conf->level++;
+
+ /* Open configuration file */
+ if ((f = fopen(cfg_file, "r")) == NULL) {
+ mk_warn("[config] I cannot open %s file", cfg_file);
+ return -1;
+ }
+
+ /* Allocate temporal buffer to read file content */
+ buf = mk_mem_alloc(MK_RCONF_KV_SIZE);
+ if (!buf) {
+ fclose(f);
+ perror("malloc");
+ return -1;
+ }
+
+ /* looking for configuration directives */
+ while (fgets(buf, MK_RCONF_KV_SIZE, f)) {
+ len = strlen(buf);
+ if (len > 0 && buf[len - 1] == '\n') {
+ buf[--len] = 0;
+ if (len && buf[len - 1] == '\r') {
+ buf[--len] = 0;
+ }
+ }
+ else {
+ /*
+ * If we don't find a break line, validate if we got an EOF or not. No EOF
+ * means that the incoming string is not finished so we must raise an
+ * exception.
+ */
+ if (!feof(f)) {
+ mk_config_error(path, line, "Length of content has exceeded limit");
+ fclose(f);
+ mk_mem_free(buf);
+ return -1;
+ }
+ }
+
+ /* Line number */
+ line++;
+
+ if (!buf[0]) {
+ continue;
+ }
+
+ /* Skip commented lines */
+ if (buf[0] == '#') {
+ continue;
+ }
+
+ if (len > 9 && strncasecmp(buf, "@INCLUDE ", 9) == 0) {
+ if (strchr(buf + 9, '*') != NULL) {
+ ret = mk_rconf_read_glob(conf, buf + 9);
+ }
+ else {
+ ret = mk_rconf_read(conf, buf + 9);
+ }
+ if (ret == -1) {
+ conf->level--;
+ fclose(f);
+ if (indent) {
+ mk_mem_free(indent);
+ }
+ mk_mem_free(buf);
+ return -1;
+ }
+ continue;
+ }
+ else if (buf[0] == '@' && len > 3) {
+ ret = mk_rconf_meta_add(conf, buf, len);
+ if (ret == -1) {
+ fclose(f);
+ if (indent) {
+ mk_mem_free(indent);
+ }
+ mk_mem_free(buf);
+ return -1;
+ }
+ continue;
+ }
+
+ /* Section definition */
+ if (buf[0] == '[') {
+ int end = -1;
+ end = mk_string_char_search(buf, ']', len);
+ if (end > 0) {
+ /*
+ * Before to add a new section, lets check the previous
+ * one have at least one key set
+ */
+ if (current && n_keys == 0) {
+ mk_rconf_warning(path, line, "Previous section did not have keys");
+ }
+
+ /* Create new section */
+ section = mk_string_copy_substr(buf, 1, end);
+ current = mk_rconf_section_add(conf, section);
+ if (!current) {
+ fclose(f);
+ if (indent) {
+ mk_mem_free(indent);
+ }
+ mk_mem_free(buf);
+ mk_mem_free(section);
+ return -1;
+ }
+ mk_mem_free(section);
+ n_keys = 0;
+ continue;
+ }
+ else {
+ mk_config_error(path, line, "Bad header definition");
+ fclose(f);
+ mk_mem_free(buf);
+ return -1;
+ }
+ }
+
+ /* No separator defined */
+ if (!indent) {
+ i = 0;
+
+ do { i++; } while (i < len && isblank(buf[i]));
+
+ indent = mk_string_copy_substr(buf, 0, i);
+ indent_len = strlen(indent);
+
+ /* Blank indented line */
+ if (i == len) {
+ continue;
+ }
+ }
+
+ /* Validate indentation level */
+ if (check_indent(buf, indent) < 0) {
+ mk_config_error(path, line, "Invalid indentation level");
+ fclose(f);
+ return -1;
+ }
+
+ if (buf[indent_len] == '#' || indent_len == len) {
+ continue;
+ }
+
+ if (len - indent_len >= 3 && strncmp(buf + indent_len, "---", 3) == 0) {
+ continue;
+ }
+
+ /* Get key and val */
+ i = mk_string_char_search(buf + indent_len, ' ', len - indent_len);
+ key = mk_string_copy_substr(buf + indent_len, 0, i);
+ val = mk_string_copy_substr(buf + indent_len + i, 1, len - indent_len - i);
+
+ if (!key || !val || i < 0) {
+ mk_config_error(path, line, "Each key must have a value");
+ fclose(f);
+ mk_mem_free(key);
+ mk_mem_free(val);
+ return -1;
+ }
+
+ /* Trim strings */
+ mk_string_trim(&key);
+ mk_string_trim(&val);
+
+ if (strlen(val) == 0) {
+ mk_config_error(path, line, "Key has an empty value");
+ fclose(f);
+ mk_mem_free(key);
+ mk_mem_free(val);
+ return -1;
+ }
+
+ /* Register entry: key and val are copied as duplicated */
+ mk_rconf_section_entry_add(conf, key, val);
+
+ /* Free temporal key and val */
+ mk_mem_free(key);
+ mk_mem_free(val);
+
+ n_keys++;
+ }
+
+ if (section && n_keys == 0) {
+ /* No key, no warning */
+ }
+
+ /*
+ struct mk_config_section *s;
+ struct mk_rconf_entry *e;
+
+ s = conf->section;
+ while(s) {
+ printf("\n[%s]", s->name);
+ e = s->entry;
+ while(e) {
+ printf("\n %s = %s", e->key, e->val);
+ e = e->next;
+ }
+ s = s->next;
+ }
+ fflush(stdout);
+ */
+ fclose(f);
+ if (indent) {
+ mk_mem_free(indent);
+ }
+ mk_mem_free(buf);
+
+ /* Append this file to the list */
+ file = mk_mem_alloc(sizeof(struct mk_rconf_file));
+ if (!file) {
+ conf->level--;
+ return -1;
+ }
+
+ file->path = mk_string_dup(path);
+ mk_list_add(&file->_head, &conf->includes);
+ conf->level--;
+ return 0;
+}
+
+#ifndef _WIN32
+static int mk_rconf_read_glob(struct mk_rconf *conf, const char * path)
+{
+ int ret = -1;
+ glob_t glb;
+ char tmp[PATH_MAX];
+
+ const char *glb_path;
+ size_t i;
+ int ret_glb = -1;
+
+ if (conf->root_path && path[0] != '/') {
+ snprintf(tmp, PATH_MAX, "%s/%s", conf->root_path, path);
+ glb_path = tmp;
+ }
+ else {
+ glb_path = path;
+ }
+
+ ret_glb = glob(glb_path, GLOB_NOSORT, NULL, &glb);
+ if (ret_glb != 0) {
+ switch(ret_glb){
+ case GLOB_NOSPACE:
+ mk_warn("[%s] glob: [%s] no space", __FUNCTION__, glb_path);
+ break;
+ case GLOB_NOMATCH:
+ mk_warn("[%s] glob: [%s] no match", __FUNCTION__, glb_path);
+ break;
+ case GLOB_ABORTED:
+ mk_warn("[%s] glob: [%s] aborted", __FUNCTION__, glb_path);
+ break;
+ default:
+ mk_warn("[%s] glob: [%s] other error", __FUNCTION__, glb_path);
+ }
+ return ret;
+ }
+
+ for (i = 0; i < glb.gl_pathc; i++) {
+ ret = mk_rconf_read(conf, glb.gl_pathv[i]);
+ if (ret < 0) {
+ break;
+ }
+ }
+
+ globfree(&glb);
+ return ret;
+}
+#else
+static int mk_rconf_read_glob(struct mk_rconf *conf, const char *path)
+{
+ char *star, *p0, *p1;
+ char pattern[MAX_PATH];
+ char buf[MAX_PATH];
+ int ret;
+ struct stat st;
+ HANDLE h;
+ WIN32_FIND_DATA data;
+
+ if (strlen(path) > MAX_PATH - 1) {
+ return -1;
+ }
+
+ star = strchr(path, '*');
+ if (star == NULL) {
+ return -1;
+ }
+
+ /*
+ * C:\data\tmp\input_*.conf
+ * 0<-----|
+ */
+ p0 = star;
+ while (path <= p0 && *p0 != '\\') {
+ p0--;
+ }
+
+ /*
+ * C:\data\tmp\input_*.conf
+ * |---->1
+ */
+ p1 = star;
+ while (*p1 && *p1 != '\\') {
+ p1++;
+ }
+
+ memcpy(pattern, path, (p1 - path));
+ pattern[p1 - path] = '\0';
+
+ h = FindFirstFileA(pattern, &data);
+ if (h == INVALID_HANDLE_VALUE) {
+ return 0;
+ }
+
+ do {
+ /* Ignore the current and parent dirs */
+ if (!strcmp(".", data.cFileName) || !strcmp("..", data.cFileName)) {
+ continue;
+ }
+
+ /* Avoid an infinite loop */
+ if (strchr(data.cFileName, '*')) {
+ continue;
+ }
+
+ /* Create a path (prefix + filename + suffix) */
+ memcpy(buf, path, p0 - path + 1);
+ buf[p0 - path + 1] = '\0';
+
+ if (FAILED(StringCchCatA(buf, MAX_PATH, data.cFileName))) {
+ continue;
+ }
+ if (FAILED(StringCchCatA(buf, MAX_PATH, p1))) {
+ continue;
+ }
+
+ if (strchr(p1, '*')) {
+ mk_rconf_read_glob(conf, buf); /* recursive */
+ continue;
+ }
+
+ ret = stat(buf, &st);
+ if (ret == 0 && (st.st_mode & S_IFMT) == S_IFREG) {
+ if (mk_rconf_read(conf, buf) < 0) {
+ return -1;
+ }
+ }
+ } while (FindNextFileA(h, &data) != 0);
+
+ FindClose(h);
+ return 0;
+}
+#endif
+
+static int mk_rconf_path_set(struct mk_rconf *conf, char *file)
+{
+ char *p;
+ char *end;
+ char path[PATH_MAX + 1];
+
+#ifdef _MSC_VER
+ p = _fullpath(path, file, PATH_MAX + 1);
+#else
+ p = realpath(file, path);
+#endif
+ if (!p) {
+ return -1;
+ }
+
+ /* lookup path ending and truncate */
+ end = strrchr(path, '/');
+ if (!end) {
+ return -1;
+ }
+
+ end++;
+ *end = '\0';
+ conf->root_path = mk_string_dup(path);
+
+ return 0;
+}
+
+struct mk_rconf *mk_rconf_open(const char *path)
+{
+ int ret;
+ struct mk_rconf *conf = NULL;
+
+ if (!path) {
+ mk_warn("[config] invalid path file %s", path);
+ return NULL;
+ }
+
+ /* Alloc configuration node */
+ conf = mk_mem_alloc_z(sizeof(struct mk_rconf));
+ if (!conf) {
+ perror("malloc");
+ return NULL;
+ }
+ conf->created = time(NULL);
+ conf->file = mk_string_dup(path);
+ conf->level = -1;
+ mk_list_init(&conf->sections);
+ mk_list_init(&conf->includes);
+ mk_list_init(&conf->metas);
+
+ /* Set the absolute path for the entrypoint file */
+ mk_rconf_path_set(conf, (char *) path);
+
+ /* Read entrypoint */
+ ret = mk_rconf_read(conf, path);
+ if (ret == -1) {
+ mk_rconf_free(conf);
+ return NULL;
+ }
+
+ return conf;
+}
+
+void mk_rconf_free(struct mk_rconf *conf)
+{
+ struct mk_list *head, *tmp;
+ struct mk_rconf_section *section;
+ struct mk_rconf_entry *entry;
+ struct mk_rconf_file *file;
+
+ /* Remove included files */
+ mk_list_foreach_safe(head, tmp, &conf->includes) {
+ file = mk_list_entry(head, struct mk_rconf_file, _head);
+ mk_list_del(&file->_head);
+ mk_mem_free(file->path);
+ mk_mem_free(file);
+ }
+
+ /* Remove metas */
+ mk_list_foreach_safe(head, tmp, &conf->metas) {
+ entry = mk_list_entry(head, struct mk_rconf_entry, _head);
+ mk_list_del(&entry->_head);
+ mk_mem_free(entry->key);
+ mk_mem_free(entry->val);
+ mk_mem_free(entry);
+ }
+
+ /* Free sections */
+ mk_list_foreach_safe(head, tmp, &conf->sections) {
+ section = mk_list_entry(head, struct mk_rconf_section, _head);
+ mk_list_del(&section->_head);
+
+ /* Free section entries */
+ mk_rconf_free_entries(section);
+
+ /* Free section node */
+ mk_mem_free(section->name);
+ mk_mem_free(section);
+ }
+ if (conf->file) {
+ mk_mem_free(conf->file);
+ }
+
+ mk_mem_free(conf->root_path);
+ mk_mem_free(conf);
+}
+
+void mk_rconf_free_entries(struct mk_rconf_section *section)
+{
+ struct mk_rconf_entry *entry;
+ struct mk_list *head, *tmp;
+
+ mk_list_foreach_safe(head, tmp, &section->entries) {
+ entry = mk_list_entry(head, struct mk_rconf_entry, _head);
+ mk_list_del(&entry->_head);
+
+ /* Free memory assigned */
+ mk_mem_free(entry->key);
+ mk_mem_free(entry->val);
+ mk_mem_free(entry);
+ }
+}
+
+/* Register a new section into the configuration struct */
+struct mk_rconf_section *mk_rconf_section_add(struct mk_rconf *conf,
+ char *name)
+{
+ struct mk_rconf_section *new;
+
+ /* Alloc section node */
+ new = mk_mem_alloc(sizeof(struct mk_rconf_section));
+ if (!new) {
+ return NULL;
+ }
+ new->name = mk_string_dup(name);
+ mk_list_init(&new->entries);
+ mk_list_add(&new->_head, &conf->sections);
+
+ return new;
+}
+
+/* Return the value of a key of a specific section */
+void *mk_rconf_section_get_key(struct mk_rconf_section *section,
+ char *key, int mode)
+{
+ int on, off;
+ struct mk_rconf_entry *entry;
+ struct mk_list *head;
+
+ mk_list_foreach(head, &section->entries) {
+ entry = mk_list_entry(head, struct mk_rconf_entry, _head);
+
+ if (strcasecmp(entry->key, key) == 0) {
+ switch (mode) {
+ case MK_RCONF_STR:
+ return (void *) mk_string_dup(entry->val);
+ case MK_RCONF_NUM:
+ return (void *) strtol(entry->val, (char **) NULL, 10);
+ case MK_RCONF_BOOL:
+ on = strcasecmp(entry->val, MK_RCONF_ON);
+ off = strcasecmp(entry->val, MK_RCONF_OFF);
+
+ if (on != 0 && off != 0) {
+ return (void *) -1;
+ }
+ else if (on >= 0) {
+ return (void *) MK_TRUE;
+ }
+ else {
+ return (void *) MK_FALSE;
+ }
+ case MK_RCONF_LIST:
+ return (void *)mk_string_split_line(entry->val);
+ }
+ }
+ }
+ return NULL;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/mk_string.c b/fluent-bit/lib/monkey/mk_core/mk_string.c
new file mode 100644
index 000000000..b2fdc5714
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/mk_string.c
@@ -0,0 +1,615 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <mk_core/mk_core_info.h>
+#include <mk_core/mk_macros.h>
+#include <mk_core/mk_utils.h>
+#include <mk_core/mk_memory.h>
+#include <mk_core/mk_string.h>
+
+#include <stdio.h>
+
+/* OSX and Windows lacks of memrchr() */
+#if !defined(MK_HAVE_MEMRCHR)
+void *memrchr(const void *s, int c, size_t n)
+{
+ const unsigned char *cp;
+
+ if (n != 0) {
+ cp = (unsigned char *)s + n;
+ do {
+ if (*(--cp) == (unsigned char)c)
+ return((void *)cp);
+ } while (--n != 0);
+ }
+ return(NULL);
+}
+#endif
+
+#ifndef MK_HAVE_MEMMEM
+void *memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen)
+{
+ char *null_terminated_haystack_buffer;
+ char *null_terminated_needle_buffer;
+ void *result;
+
+ result = NULL;
+
+ null_terminated_haystack_buffer = (char *) calloc(haystacklen + 1,
+ sizeof(char));
+
+ if(NULL != null_terminated_haystack_buffer){
+ null_terminated_needle_buffer = (char *) calloc(needlelen + 1,
+ sizeof(char));
+
+ if(NULL != null_terminated_needle_buffer){
+ strncpy(null_terminated_haystack_buffer, haystack, haystacklen);
+ strncpy(null_terminated_needle_buffer, needle, needlelen);
+
+ result = strstr(null_terminated_haystack_buffer,
+ null_terminated_needle_buffer);
+
+ if (result != NULL) {
+ result = (void *)
+ ((((uintptr_t) null_terminated_haystack_buffer) - \
+ ((uintptr_t) result)) +
+ ((uintptr_t) haystack));
+ }
+
+ free(null_terminated_needle_buffer);
+ }
+
+ free(null_terminated_haystack_buffer);
+ }
+
+ return result;
+}
+#endif
+
+/* Windows lack of strndup() & strcasestr() */
+#ifdef _WIN32
+char *strndup (const char *s, size_t n)
+{
+ char *result;
+ size_t len = strlen (s);
+
+ if (n < len) {
+ len = n;
+ }
+
+ result = (char *) mk_mem_alloc(len + 1);
+ if (!result) {
+ return 0;
+ }
+
+ result[len] = '\0';
+ return (char *) memcpy (result, s, len);
+}
+
+char *strcasestr(const char *phaystack, const char *pneedle)
+{
+ register const unsigned char *haystack, *needle;
+ register unsigned bl, bu, cl, cu;
+
+ haystack = (const unsigned char *) phaystack;
+ needle = (const unsigned char *) pneedle;
+
+ bl = tolower(*needle);
+ if (bl != '\0')
+ {
+ // Scan haystack until the first character of needle is found:
+ bu = toupper(bl);
+ haystack--; /* possible ANSI violation */
+ do
+ {
+ cl = *++haystack;
+ if (cl == '\0')
+ goto ret0;
+ }
+ while ((cl != bl) && (cl != bu));
+
+ cl = tolower(*++needle);
+ if (cl == '\0') {
+ goto foundneedle;
+ }
+
+ cu = toupper(cl);
+ ++needle;
+ goto jin;
+
+ for (;;)
+ {
+ register unsigned a;
+ register const unsigned char *rhaystack, *rneedle;
+ do
+ {
+ a = *++haystack;
+ if (a == '\0')
+ goto ret0;
+ if ((a == bl) || (a == bu))
+ break;
+ a = *++haystack;
+ if (a == '\0')
+ goto ret0;
+shloop:
+ ;
+ }
+ while ((a != bl) && (a != bu));
+
+jin:
+ a = *++haystack;
+ if (a == '\0') {
+ goto ret0;
+ }
+
+ if ((a != cl) && (a != cu)) {
+ goto shloop;
+ }
+
+ rhaystack = haystack-- + 1;
+ rneedle = needle;
+ a = tolower(*rneedle);
+
+ if (tolower(*rhaystack) == (int) a)
+ do
+ {
+ if (a == '\0')
+ goto foundneedle;
+ ++rhaystack;
+ a = tolower(*++needle);
+ if (tolower(*rhaystack) != (int) a)
+ break;
+ if (a == '\0')
+ goto foundneedle;
+ ++rhaystack;
+ a = tolower(*++needle);
+ }
+ while (tolower(*rhaystack) == (int) a);
+
+ needle = rneedle; /* took the register-poor approach */
+
+ if (a == '\0')
+ break;
+ } // for(;;)
+ } // if (bl != '\0')
+foundneedle:
+ return (char*) haystack;
+ret0:
+ return 0;
+}
+#endif
+
+/*
+ * Base function for search routines, it accept modifiers to enable/disable
+ * the case sensitive feature and also allow to specify a haystack len
+ * Get position of a substring.
+*/
+static int _mk_string_search(const char *string, const char *search,
+ int sensitive, int len)
+{
+ int i = 0;
+ char *p = NULL, *q = NULL;
+ char *s = NULL;
+
+ /* Fast path */
+ if (len <= 0) {
+ switch(sensitive) {
+ case MK_STR_SENSITIVE:
+ p = strstr(string, search);
+ break;
+ case MK_STR_INSENSITIVE:
+ p = strcasestr(string, search);
+ break;
+ }
+
+ if (p) {
+ return (p - string);
+ }
+ else {
+ return -1;
+ }
+ }
+
+ p = (char *) string;
+ do {
+ q = p;
+ s = (char *) search;
+ if (sensitive == MK_STR_SENSITIVE) {
+ while (*s && (*s == *q)) {
+ q++, s++;
+ }
+ }
+ else if (sensitive == MK_STR_INSENSITIVE) {
+ while (*s && (toupper(*q) == toupper(*s))) {
+ q++, s++;
+ }
+ }
+
+ /* match */
+ if (*s == 0) {
+ return (p - string);
+ }
+
+ i++;
+ if (i >= len) {
+ break;
+ }
+ } while (*p++);
+
+ return -1;
+}
+
+/* Lookup char into string, return position */
+int mk_string_char_search(const char *string, int c, int len)
+{
+ char *p;
+
+ if (len < 0) {
+ len = strlen(string);
+ }
+
+ p = memchr(string, c, len);
+ if (p) {
+ return (p - string);
+ }
+
+ return -1;
+}
+
+/* Find char into string searching in reverse order, returns position */
+int mk_string_char_search_r(const char *string, int c, int len)
+{
+ char *p;
+
+ if (len <= 0) {
+ len = strlen(string);
+ }
+
+ p = memrchr(string, c, len);
+ if (p) {
+ return (p - string);
+ }
+
+ return -1;
+}
+
+int mk_string_search(const char *haystack, const char *needle, int sensitive)
+{
+ return _mk_string_search(haystack, needle, sensitive, -1);
+}
+
+int mk_string_search_n(const char *haystack, const char *needle, int sensitive, int len)
+{
+ return _mk_string_search(haystack, needle, sensitive, len);
+}
+
+char *mk_string_casestr(char *heystack, char *needle)
+{
+ if (!heystack || !needle) {
+ return NULL;
+ }
+
+ return strcasestr(heystack, needle);
+}
+
+char *mk_string_dup(const char *s)
+{
+ size_t len;
+ char *p;
+
+ if (!s) {
+ return NULL;
+ }
+
+ len = strlen(s);
+ p = mk_mem_alloc(len + 1);
+ if (!p) {
+ return NULL;
+ }
+ memcpy(p, s, len);
+ p[len] = '\0';
+
+ return p;
+}
+
+struct mk_list *mk_string_split_line(const char *line)
+{
+ unsigned int i = 0, len, val_len;
+ int end;
+ char *val;
+ struct mk_list *list;
+ struct mk_string_line *new;
+
+ if (!line) {
+ return NULL;
+ }
+
+ list = mk_mem_alloc(sizeof(struct mk_list));
+ if (!list) {
+ return NULL;
+ }
+ mk_list_init(list);
+
+ len = strlen(line);
+
+ while (i < len) {
+ end = mk_string_char_search(line + i, ' ', len - i);
+
+ if (end >= 0 && end + i < len) {
+ end += i;
+
+ if (i == (unsigned int) end) {
+ i++;
+ continue;
+ }
+
+ val = mk_string_copy_substr(line, i, end);
+ val_len = end - i;
+ }
+ else {
+ val = mk_string_copy_substr(line, i, len);
+ val_len = len - i;
+ end = len;
+
+ }
+
+ /* Alloc node */
+ new = mk_mem_alloc(sizeof(struct mk_string_line));
+ new->val = val;
+ new->len = val_len;
+
+ mk_list_add(&new->_head, list);
+ i = end + 1;
+ }
+
+ return list;
+}
+
+void mk_string_split_free(struct mk_list *list)
+{
+ struct mk_list *head, *tmp;
+ struct mk_string_line *entry;
+
+ mk_list_foreach_safe(head, tmp, list) {
+ entry = mk_list_entry(head, struct mk_string_line, _head);
+ mk_list_del(&entry->_head);
+ mk_mem_free(entry->val);
+ mk_mem_free(entry);
+ }
+
+ mk_mem_free(list);
+}
+
+char *mk_string_build(char **buffer, unsigned long *len,
+ const char *format, ...)
+{
+ va_list ap;
+ int length;
+ char *ptr;
+ const size_t _mem_alloc = 64;
+ size_t alloc = 0;
+
+ /* *buffer *must* be an empty/NULL buffer */
+ mk_bug(*buffer);
+ *buffer = (char *) mk_mem_alloc(_mem_alloc);
+
+ if (!*buffer) {
+ return NULL;
+ }
+ alloc = _mem_alloc;
+
+ va_start(ap, format);
+ length = vsnprintf(*buffer, alloc, format, ap);
+ va_end(ap);
+
+ if (length < 0) {
+ return NULL;
+ }
+
+ if ((unsigned int) length >= alloc) {
+ ptr = mk_mem_realloc(*buffer, length + 1);
+ if (!ptr) {
+ return NULL;
+ }
+ *buffer = ptr;
+ alloc = length + 1;
+
+ va_start(ap, format);
+ length = vsnprintf(*buffer, alloc, format, ap);
+ va_end(ap);
+ }
+
+ ptr = *buffer;
+ ptr[length] = '\0';
+ *len = length;
+
+ return *buffer;
+}
+
+int mk_string_trim(char **str)
+{
+ unsigned int i;
+ unsigned int len;
+ char *left = 0, *right = 0;
+ char *buf;
+
+ buf = *str;
+ if (!buf) {
+ return -1;
+ }
+
+ len = strlen(buf);
+ left = buf;
+
+ if(len == 0) {
+ return 0;
+ }
+
+ /* left spaces */
+ while (left) {
+ if (isspace(*left)) {
+ left++;
+ }
+ else {
+ break;
+ }
+ }
+
+ right = buf + (len - 1);
+ /* Validate right v/s left */
+ if (right < left) {
+ buf[0] = '\0';
+ return -1;
+ }
+
+ /* Move back */
+ while (right != buf){
+ if (isspace(*right)) {
+ right--;
+ }
+ else {
+ break;
+ }
+ }
+
+ len = (right - left) + 1;
+ for(i=0; i<len; i++){
+ buf[i] = (char) left[i];
+ }
+ buf[i] = '\0';
+
+ return 0;
+}
+
+uint32_t digits10(uint64_t v) {
+ if (v < 10) return 1;
+ if (v < 100) return 2;
+ if (v < 1000) return 3;
+ if (v < 1000000000000UL) {
+ if (v < 100000000UL) {
+ if (v < 1000000) {
+ if (v < 10000) return 4;
+ return 5 + (v >= 100000);
+ }
+ return 7 + (v >= 10000000UL);
+ }
+ if (v < 10000000000UL) {
+ return 9 + (v >= 1000000000UL);
+ }
+ return 11 + (v >= 100000000000UL);
+ }
+ return 12 + digits10(v / 1000000000000UL);
+}
+
+#if defined(__GNUC__) || defined(_WIN32)
+int mk_string_itop(uint64_t value, mk_ptr_t *p)
+{
+ static const char digits[201] =
+ "0001020304050607080910111213141516171819"
+ "2021222324252627282930313233343536373839"
+ "4041424344454647484950515253545556575859"
+ "6061626364656667686970717273747576777879"
+ "8081828384858687888990919293949596979899";
+
+ uint32_t const length = digits10(value);
+ uint32_t next = length - 1;
+ char *dst = p->data;
+
+ while (value >= 100) {
+ int const i = (value % 100) * 2;
+ value /= 100;
+ dst[next] = digits[i + 1];
+ dst[next - 1] = digits[i];
+ next -= 2;
+ }
+
+ /* Handle last 1-2 digits */
+ if (value < 10) {
+ dst[next] = '0' + (uint32_t) value;
+ }
+ else {
+ int i = (uint32_t) value * 2;
+ dst[next] = digits[i + 1];
+ dst[next - 1] = digits[i];
+ }
+
+ dst = p->data + length;
+ *dst++ = '\r';
+ *dst++ = '\n';
+ *dst++ = '\0';
+
+ p->len = (dst - p->data - 1);
+ return p->len;
+}
+#endif
+
+/* Return a buffer with a new string from string */
+char *mk_string_copy_substr(const char *string, int pos_init, int pos_end)
+{
+ unsigned int size, bytes;
+ char *buffer = 0;
+
+ if (pos_init > pos_end) {
+ return NULL;
+ }
+
+ size = (unsigned int) (pos_end - pos_init) + 1;
+ if (size <= 2) {
+ size = 4;
+ }
+
+ buffer = mk_mem_alloc(size);
+
+ if (!buffer) {
+ return NULL;
+ }
+
+ bytes = pos_end - pos_init;
+ memcpy(buffer, string + pos_init, bytes);
+ buffer[bytes] = '\0';
+
+ return (char *) buffer;
+}
+
+char *mk_string_tolower(const char *in)
+{
+ char *out = mk_string_dup(in);
+ const char *ip = in;
+ char *op = out;
+
+ if (!out) {
+ return NULL;
+ }
+
+ while (*ip) {
+ *op = tolower(*ip);
+ ip++, op++;
+ }
+ *op = '\0';
+
+ return out;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/mk_thread.c b/fluent-bit/lib/monkey/mk_core/mk_thread.c
new file mode 100644
index 000000000..9b5589f36
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/mk_thread.c
@@ -0,0 +1,347 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server (Duda I/O)
+ * -----------------------------
+ * Copyright 2017 Eduardo Silva <eduardo@monkey.io>
+ * Copyright 2014, Zeying Xie <swpdtz at gmail dot com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#if defined (__APPLE__)
+#include <sys/ucontext.h>
+#else
+#include <ucontext.h>
+#endif
+
+#include <limits.h>
+
+#include <mk_core/mk_pthread.h>
+#include <mk_core/mk_memory.h>
+#include <mk_core/mk_thread.h>
+
+/*
+ * @OBJ_NAME: dthread
+ * @OBJ_MENU: Dthread
+ * @OBJ_DESC: The dthread object provides a set of methods to handle user space cooperative thread, namely dthread(duda thread).
+ * A dthread can be suspended when it encounters something that will block(in other
+ * words, something will be available in the future), while another dthread that
+ * is ready to run is awakened. Back and forth, all dthreads within the same pthread
+ * work collaboratively. This means dthread is non-preemptive and requires the user
+ * to explicitly give up control when necessary.
+ * Dthreads communicate with each other by using channel, a channel is like a pipe,
+ * one dthread feeds data to the channel while another cosumes from it.
+ *
+ */
+
+#ifdef USE_VALGRIND
+#include <valgrind/valgrind.h>
+#endif
+
+#define MK_THREAD_STACK_SIZE (3 * (PTHREAD_STACK_MIN) / 2)
+#define DEFAULT_MK_THREAD_NUM 16
+
+struct mk_thread {
+ mk_thread_func func;
+ void *data;
+ ucontext_t context;
+ struct mk_thread_scheduler *sch;
+ int status;
+ int parent_id;
+#ifdef USE_VALGRIND
+ unsigned int valgrind_stack_id;
+#endif
+ struct mk_list chan_list;
+ char stack[MK_THREAD_STACK_SIZE];
+} mk_thread_t;
+
+struct mk_thread_scheduler {
+ ucontext_t main;
+ int n_dthread;
+ int cap;
+ int running_id;
+ struct mk_thread **dt;
+};
+
+static void _mk_thread_release(struct mk_thread *dt);
+
+static void _mk_thread_entry_point(struct mk_thread_scheduler *sch)
+{
+ int id;
+ struct mk_thread *dt;
+ struct mk_list *head;
+ struct mk_thread_channel *chan;
+
+ assert(sch);
+ id = sch->running_id;
+ dt = sch->dt[id];
+ dt->func(dt->data);
+ dt->status = MK_THREAD_DEAD;
+
+ mk_list_foreach(head, &dt->chan_list) {
+ chan = mk_list_entry(head, struct mk_thread_channel, _head);
+ chan->receiver = -1;
+ }
+ sch->n_dthread--;
+ sch->running_id = dt->parent_id;
+}
+
+struct mk_thread_scheduler *mk_thread_open()
+{
+ struct mk_thread_scheduler *sch;
+
+ sch = mk_mem_alloc(sizeof(*sch));
+ if (!sch) {
+ return NULL;
+ }
+
+ sch->n_dthread = 0;
+ sch->cap = DEFAULT_MK_THREAD_NUM;
+ sch->running_id = -1;
+ sch->dt = mk_mem_alloc_z(sizeof(struct mk_thread *) * sch->cap);
+ if (!sch->dt) {
+ mk_mem_free(sch);
+ return NULL;
+ }
+
+ return sch;
+}
+
+void mk_thread_close(struct mk_thread_scheduler *sch)
+{
+ struct mk_thread *dt;
+
+ int i;
+ for (i = 0; i < sch->cap; ++i) {
+ dt = sch->dt[i];
+ if (dt) {
+ _mk_thread_release(dt);
+ }
+ }
+ mk_mem_free(sch->dt);
+ sch->dt = NULL;
+ mk_mem_free(sch);
+}
+
+/*
+ * @METHOD_NAME: create
+ * @METHOD_DESC: create a new dthread.
+ * @METHOD_PROTO: int create(mk_thread_func func, void *data)
+ * @METHOD_PARAM: func the function to be executed when the newly created dthread
+ * is started.
+ * @METHOD_PARAM: data user specific data that will be passed to func.
+ * @METHOD_RETURN: the dthread id associated with the new dthread.
+ */
+int mk_thread_create(mk_thread_func func, void *data)
+{
+ int i;
+ int id;
+ void *p;
+ struct mk_thread_scheduler *sch;
+ struct mk_thread *dt;
+
+ sch = pthread_getspecific(mk_thread_scheduler);
+ if (!sch) {
+ sch = mk_thread_open();
+ assert(sch);
+ pthread_setspecific(mk_thread_scheduler, (void *) sch);
+ }
+
+ if (sch->n_dthread >= sch->cap) {
+ id = sch->cap;
+
+ p = mk_mem_realloc(sch->dt, sch->cap * 2 * sizeof(struct mk_thread *));
+ if (!p) {
+ return -1;
+ }
+ sch->dt = p;
+ memset(sch->dt + sch->cap, 0, sizeof(struct mk_thread *) * sch->cap);
+ sch->cap *= 2;
+ }
+ else {
+ for (i = 0; i < sch->cap; ++i) {
+ id = (i + sch->cap) % sch->cap;
+ if (sch->dt[id] == NULL || sch->dt[id]->status == MK_THREAD_DEAD) {
+ break;
+ }
+ }
+ }
+
+ /* may use dthread pooling instead of release and realloc */
+ if (sch->dt[id] && sch->dt[id]->status == MK_THREAD_DEAD) {
+ _mk_thread_release(sch->dt[id]);
+ sch->dt[id] = NULL;
+ }
+
+ dt = mk_mem_alloc(sizeof(*dt));
+ if (!dt) {
+ return -1;
+ }
+
+ dt->func = func;
+ dt->data = data;
+ dt->sch = sch;
+ dt->status = MK_THREAD_READY;
+ dt->parent_id = -1;
+#ifdef USE_VALGRIND
+ dt->valgrind_stack_id = VALGRIND_STACK_REGISTER(dt->stack, dt->stack + MK_THREAD_STACK_SIZE);
+#endif
+ mk_list_init(&dt->chan_list);
+ sch->dt[id] = dt;
+ sch->n_dthread++;
+ return id;
+}
+
+static void _mk_thread_release(struct mk_thread *dt)
+{
+ assert(dt);
+#ifdef USE_VALGRIND
+ VALGRIND_STACK_DEREGISTER(dt->valgrind_stack_id);
+#endif
+ mk_mem_free(dt);
+}
+
+/*
+ * @METHOD_NAME: status
+ * @METHOD_DESC: get the status of a given dthread.
+ * @METHOD_PROTO: int status(int id)
+ * @METHOD_PARAM: id the dthread id of the target dthread.
+ * @METHOD_RETURN: it returns one of the following status: MK_THREAD_DEAD, MK_THREAD_READY,
+ * MK_THREAD_RUNNING, MK_THREAD_SUSPEND.
+ */
+int mk_thread_status(int id)
+{
+ struct mk_thread_scheduler *sch;
+
+ sch = pthread_getspecific(mk_thread_scheduler);
+ assert(sch);
+ assert(id >= 0 && id < sch->cap);
+ if (!sch->dt[id]) return MK_THREAD_DEAD;
+ return sch->dt[id]->status;
+}
+
+/*
+ * @METHOD_NAME: yield
+ * @METHOD_DESC: require the currently running dthread explicitly to give up control
+ * back to the dthread scheduler.
+ * @METHOD_PROTO: void yield()
+ * @METHOD_RETURN: this method do not return any value.
+ */
+void mk_thread_yield()
+{
+ int id;
+ struct mk_thread *dt;
+ struct mk_thread_scheduler *sch;
+
+ sch = pthread_getspecific(mk_thread_scheduler);
+ assert(sch);
+
+ id = sch->running_id;
+ assert(id >= 0);
+
+ dt = sch->dt[id];
+ dt->status = MK_THREAD_SUSPEND;
+ sch->running_id = -1;
+ swapcontext(&dt->context, &sch->main);
+}
+
+/*
+ * @METHOD_NAME: resume
+ * @METHOD_DESC: resume a given dthread and suspend the currently running dthread.
+ * @METHOD_PROTO: void resume(int id)
+ * @METHOD_PARAM: id the dthread id of the target dthread.
+ * @METHOD_RETURN: this method do not return any value.
+ */
+void mk_thread_resume(int id)
+{
+ struct mk_thread *dt;
+ struct mk_thread *running_dt;
+ struct mk_thread_scheduler *sch;
+
+ sch = pthread_getspecific(mk_thread_scheduler);
+ assert(sch);
+ assert(id >= 0 && id < sch->cap);
+
+ running_dt = NULL;
+ if (sch->running_id != -1) {
+ running_dt = sch->dt[sch->running_id];
+ }
+
+ dt = sch->dt[id];
+ if (!dt) return;
+ switch (dt->status) {
+ case MK_THREAD_READY:
+ getcontext(&dt->context);
+ dt->context.uc_stack.ss_sp = dt->stack;
+ dt->context.uc_stack.ss_size = MK_THREAD_STACK_SIZE;
+ if (running_dt) {
+ dt->context.uc_link = &running_dt->context;
+ dt->parent_id = sch->running_id;
+ running_dt->status = MK_THREAD_SUSPEND;
+ } else {
+ dt->context.uc_link = &sch->main;
+ }
+ sch->running_id = id;
+ dt->status = MK_THREAD_RUNNING;
+ makecontext(&dt->context, (void (*)(void))_mk_thread_entry_point, 1, sch);
+ if (running_dt) {
+ swapcontext(&running_dt->context, &dt->context);
+ } else {
+ swapcontext(&sch->main, &dt->context);
+ }
+ break;
+ case MK_THREAD_SUSPEND:
+ sch->running_id = id;
+ dt->status = MK_THREAD_RUNNING;
+ if (running_dt) {
+ running_dt->status = MK_THREAD_SUSPEND;
+ swapcontext(&running_dt->context, &dt->context);
+ } else {
+ swapcontext(&sch->main, &dt->context);
+ }
+ break;
+ default:
+ assert(0);
+ }
+}
+
+/*
+ * @METHOD_NAME: running
+ * @METHOD_DESC: get the id of the currently running dthread.
+ * @METHOD_PROTO: int running()
+ * @METHOD_RETURN: the dthread id associated with the currently running dthread.
+ */
+int mk_thread_running()
+{
+ struct mk_thread_scheduler *sch;
+
+ sch = pthread_getspecific(mk_thread_scheduler);
+ assert(sch);
+ return sch->running_id;
+}
+
+void mk_thread_add_channel(int id, struct mk_thread_channel *chan)
+{
+ struct mk_thread_scheduler *sch;
+ struct mk_thread *dt;
+
+ assert(chan);
+ sch = pthread_getspecific(mk_thread_scheduler);
+ assert(sch);
+ assert(id >= 0 && id < sch->cap);
+ dt = sch->dt[id];
+ mk_list_add(&chan->_head, &dt->chan_list);
+}
diff --git a/fluent-bit/lib/monkey/mk_core/mk_thread_channel.c b/fluent-bit/lib/monkey/mk_core/mk_thread_channel.c
new file mode 100644
index 000000000..a31949d7b
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/mk_thread_channel.c
@@ -0,0 +1,150 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server (Duda I/O)
+ * -----------------------------
+ * Copyright 2017 Eduardo Silva <eduardo@monkey.io>
+ * Copyright 2014, Zeying Xie <swpdtz at gmail dot com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include <mk_core/mk_memory.h>
+#include <mk_core/mk_thread.h>
+#include <mk_core/mk_thread_channel.h>
+
+struct mk_thread_channel_elem {
+ void *data;
+ struct mk_list _head;
+};
+
+struct mk_thread_channel_elem *mk_thread_channel_elem_create(void *data)
+{
+ struct mk_thread_channel_elem *elem;
+
+ elem = mk_mem_alloc(sizeof(*elem));
+ if (!elem) {
+ return NULL;
+ }
+ elem->data = data;
+ return elem;
+}
+
+static void mk_thread_channel_elem_free(struct mk_thread_channel_elem *elem)
+{
+ assert(elem);
+ mk_list_del(&elem->_head);
+ mk_mem_free(elem);
+}
+
+/*
+ * @METHOD_NAME: chan_create
+ * @METHOD_DESC: create a channel(pipe) for dthread communication.
+ * @METHOD_PROTO: mk_thread_channel_t *chan_create(int size)
+ * @METHOD_PARAM: size the buffered size of the channel.
+ * @METHOD_RETURN: returns a new channel.
+ */
+struct mk_thread_channel *mk_thread_channel_create(int size)
+{
+ struct mk_thread_channel *chan;
+
+ chan = mk_mem_alloc(sizeof(*chan));
+ if (!chan) {
+ return NULL;
+ }
+
+ chan->size = size + 1;
+ chan->used = 0;
+ mk_list_init(&chan->bufs);
+ chan->sender = -1;
+ chan->receiver = -1;
+ chan->ended = 0;
+ chan->done = 0;
+ return chan;
+}
+
+/*
+ * @METHOD_NAME: chan_free
+ * @METHOD_DESC: release a given channel.
+ * @METHOD_PROTO: void chan_free(mk_thread_channel_t *chan)
+ * @METHOD_PARAM: chan the target channel to be released.
+ * @METHOD_RETURN: this method do not return any value.
+ */
+void mk_thread_channel_free(struct mk_thread_channel *chan)
+{
+ assert(chan);
+ if (chan->receiver != -1) {
+ mk_list_del(&chan->_head);
+ }
+ mk_mem_free(chan);
+}
+
+/*
+ * @METHOD_NAME: chan_send
+ * @METHOD_DESC: add a new element to the given channel.
+ * @METHOD_PROTO: int chan_send(mk_thread_channel_t *chan, void *data)
+ * @METHOD_PARAM: chan the target channel to send.
+ * @METHOD_PARAM: data the new element to be sent to channel.
+ * @METHOD_RETURN: return THREAD_CHANNEL_BROKEN if the other side of the pipe
+ * is closed, otherwise return THREAD_CHANNEL_OK.
+ */
+int mk_thread_channel_send(struct mk_thread_channel *chan, void *data)
+{
+ struct mk_thread_channel_elem *elem;
+
+ assert(chan);
+ if (chan->receiver == -1) {
+ return MK_THREAD_CHANNEL_BROKEN;
+ }
+ if (chan->used == chan->size) {
+ // channel is full
+ mk_thread_resume(chan->receiver);
+ }
+
+ elem = mk_thread_channel_elem_create(data);
+ mk_list_add(&elem->_head, &chan->bufs);
+ chan->used++;
+ return MK_THREAD_CHANNEL_OK;
+}
+
+/*
+ * @METHOD_NAME: chan_recv
+ * @METHOD_DESC: remove an element from a given channel.
+ * @METHOD_PROTO: void *chan_recv(mk_thread_channel_t *chan)
+ * @METHOD_PARAM: chan the target channel to receive.
+ * @METHOD_RETURN: the front element of the channel.
+ */
+void *mk_thread_channel_recv(struct mk_thread_channel *chan)
+{
+ void *data;
+ struct mk_thread_channel_elem *elem;
+
+ assert(chan);
+ assert(!chan->done);
+
+ if (chan->used == 0) {
+ /* channel is empty */
+ mk_thread_resume(chan->sender);
+ }
+
+ elem = mk_list_entry_first(&chan->bufs, struct mk_thread_channel_elem, _head);
+ data = elem->data;
+ mk_thread_channel_elem_free(elem);
+ chan->used--;
+ if (chan->used == 0 && chan->ended) {
+ chan->done = 1;
+ }
+ return data;
+}
diff --git a/fluent-bit/lib/monkey/mk_core/mk_utils.c b/fluent-bit/lib/monkey/mk_core/mk_utils.c
new file mode 100644
index 000000000..54cdd3938
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_core/mk_utils.c
@@ -0,0 +1,393 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <mk_core/mk_utils.h>
+
+#include <mk_core/mk_unistd.h>
+
+#if defined (__linux__)
+#include <sys/prctl.h>
+#elif defined (_WIN32)
+#include <winsock2.h>
+
+#ifndef localtime_r
+ struct tm *localtime_r(time_t *_clock, struct tm *_result)
+ {
+ struct tm *p = localtime(_clock);
+ if (p)
+ *(_result) = *p;
+ return p;
+ }
+ #endif
+ struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of DST correction */
+ };
+
+ int gettimeofday(struct timeval *tv, struct timezone *tz)
+ {
+ FILETIME result;
+ ULARGE_INTEGER temp;
+
+ memset(&result, 0, sizeof(FILETIME));
+
+ GetSystemTimeAsFileTime(&result);
+
+ if (NULL != tv) {
+ temp.LowPart = result.dwLowDateTime;
+ temp.HighPart = result.dwHighDateTime;
+
+ tv->tv_usec = ((temp.QuadPart / 10LL) % 1000000LL);
+ tv->tv_sec = ((temp.QuadPart - (116444736000000000LL)) / 10000000LL);
+ }
+
+ return 0;
+ }
+
+#endif
+
+/* core init time variable */
+/*
+ * Max amount of pid digits. Glibc's pid_t is implemented as a signed
+ * 32bit integer, for both 32 and 64bit systems - max value: 2147483648.
+ */
+#define MK_MAX_PID_LEN 10
+
+#include <mk_core/mk_macros.h>
+#include <mk_core/mk_utils.h>
+
+pthread_mutex_t mutex_trace;
+pthread_key_t mk_utils_error_key; /* Initialized by MK_INIT_INITIALIZE_TLS_UNIVERSAL */
+
+#ifdef MK_HAVE_TRACE
+#ifdef _WIN32
+/* struct timeval is defined in winsock.h according to msdn */
+#include <winsock2.h>
+#else
+#include <sys/time.h>
+#endif
+
+static time_t mk_core_init_time;
+static char *env_trace_filter;
+
+void mk_utils_trace(const char *component, int color, const char *function,
+ char *file, int line, const char* format, ...)
+{
+ va_list args;
+ char *color_function = NULL;
+ char *color_fileline = NULL;
+ char *color_component = NULL;
+
+ char *reset_color = ANSI_RESET;
+ char *magenta_color = ANSI_RESET ANSI_MAGENTA;
+ char *red_color = ANSI_RESET ANSI_RED;
+ char *time_color = ANSI_RESET "\033[38;5;241m";
+
+ struct timeval tv;
+ struct timezone tz;
+
+ if (env_trace_filter) {
+ if (!strstr(env_trace_filter, file)) {
+ return;
+ }
+ }
+
+ /* Mutex lock */
+ //pthread_mutex_lock(&mutex_trace);
+
+ gettimeofday(&tv, &tz);
+
+ switch(color) {
+ case MK_TRACE_CORE:
+ color_component = ANSI_GREEN;
+ color_function = ANSI_YELLOW;
+ color_fileline = ANSI_WHITE;
+ break;
+ case MK_TRACE_PLUGIN:
+ color_component = ANSI_BLUE;
+ color_function = ANSI_BLUE;
+ color_fileline = ANSI_WHITE;
+ break;
+ }
+
+ /* Only print colors to a terminal */
+ if (!isatty(STDOUT_FILENO)) {
+ color_function = "";
+ color_fileline = "";
+ reset_color = "";
+ magenta_color = "";
+ red_color = "";
+ time_color = "";
+ }
+
+ va_start( args, format );
+
+ printf("~ %s%2lu.%lu%s %s[%s%s%s|%s:%-3i%s] %s%s()%s ",
+ time_color, (tv.tv_sec - mk_core_init_time),
+ tv.tv_usec, reset_color,
+ magenta_color, color_component, component, color_fileline, file,
+ line, magenta_color,
+ color_function, function, red_color);
+ vprintf(format, args );
+ va_end(args);
+ printf("%s\n", reset_color);
+ fflush(stdout);
+
+ /* Mutex unlock */
+ //pthread_mutex_unlock(&mutex_trace);
+}
+
+int mk_utils_print_errno(int n)
+{
+ switch(n) {
+ case EAGAIN:
+ MK_TRACE("EAGAIN");
+ return -1;
+ case EBADF:
+ MK_TRACE("EBADF");
+ return -1;
+ case EFAULT:
+ MK_TRACE("EFAULT");
+ return -1;
+ case EFBIG:
+ MK_TRACE("EFBIG");
+ return -1;
+ case EINTR:
+ MK_TRACE("EINTR");
+ return -1;
+ case EINVAL:
+ MK_TRACE("EINVAL");
+ return -1;
+ case EPIPE:
+ MK_TRACE("EPIPE");
+ return -1;
+ default:
+ MK_TRACE("DONT KNOW");
+ return 0;
+ }
+
+ return 0;
+}
+#endif
+
+void mk_print(int type, const char *format, ...)
+{
+ time_t now;
+ struct tm *current;
+
+ const char *header_color = NULL;
+ const char *header_title = NULL;
+ const char *bold_color = ANSI_BOLD;
+ const char *reset_color = ANSI_RESET;
+ const char *white_color = ANSI_WHITE;
+ va_list args;
+
+ va_start(args, format);
+
+ switch (type) {
+ case MK_INFO:
+ header_title = "Info";
+ header_color = ANSI_GREEN;
+ break;
+ case MK_ERR:
+ header_title = "Error";
+ header_color = ANSI_RED;
+ break;
+ case MK_WARN:
+ header_title = "Warning";
+ header_color = ANSI_YELLOW;
+ break;
+ case MK_BUG:
+#ifdef DEBUG
+ mk_utils_stacktrace();
+#endif
+ header_title = " BUG !";
+ header_color = ANSI_BOLD ANSI_RED;
+ break;
+ }
+
+ /* Only print colors to a terminal */
+ if (!isatty(STDOUT_FILENO)) {
+ header_color = "";
+ bold_color = "";
+ reset_color = "";
+ white_color = "";
+ }
+
+ now = time(NULL);
+ struct tm result;
+ current = localtime_r(&now, &result);
+ printf("%s[%s%i/%02i/%02i %02i:%02i:%02i%s]%s ",
+ bold_color, reset_color,
+ current->tm_year + 1900,
+ current->tm_mon + 1,
+ current->tm_mday,
+ current->tm_hour,
+ current->tm_min,
+ current->tm_sec,
+ bold_color, reset_color);
+
+ printf("%s[%s%7s%s]%s ",
+ bold_color, header_color, header_title, white_color, reset_color);
+
+ vprintf(format, args);
+ va_end(args);
+ printf("%s\n", reset_color);
+ fflush(stdout);
+}
+
+int mk_utils_worker_rename(const char *title)
+{
+#if defined (__linux__)
+ return prctl(PR_SET_NAME, title, 0, 0, 0);
+#elif defined (__APPLE__)
+ return pthread_setname_np(title);
+#else
+ (void) title;
+ return -1;
+#endif
+}
+
+int mk_utils_worker_spawn(void (*func) (void *), void *arg, pthread_t *tid)
+{
+ pthread_attr_t thread_attr;
+
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+ if (pthread_create(tid, &thread_attr, (void *) func, arg) < 0) {
+ mk_libc_error("pthread_create");
+ return -1;
+ }
+
+ return 0;
+}
+
+#ifndef _WIN32
+/* Run current process in background mode (daemon, evil Monkey >:) */
+int mk_utils_set_daemon()
+{
+ pid_t pid;
+
+ if ((pid = fork()) < 0) {
+ mk_err("Error: Failed creating to switch to daemon mode(fork failed)");
+ return -1;
+ }
+
+ if (pid > 0) { /* parent */
+ exit(EXIT_SUCCESS);
+ }
+
+ /* set files mask */
+ umask(0);
+
+ /* Create new session */
+ setsid();
+
+ if (chdir("/") < 0) { /* make sure we can unmount the inherited filesystem */
+ mk_err("Error: Unable to unmount the inherited filesystem in the daemon process");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Our last STDOUT messages */
+ mk_info("Background mode ON");
+
+ fclose(stderr);
+ fclose(stdout);
+
+ return 0;
+}
+
+/* Write Monkey's PID */
+int mk_utils_register_pid(char *path)
+{
+ int fd;
+ int ret;
+ char pidstr[MK_MAX_PID_LEN + 1];
+ struct flock lock;
+ struct stat sb;
+
+ if (stat(path, &sb) == 0) {
+ /* file exists, perhaps previously kepts by SIGKILL */
+ ret = unlink(path);
+ if (ret == -1) {
+ mk_err("Could not remove old PID-file path: %s", path);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if ((fd = open(path,
+ O_WRONLY | O_CREAT | O_CLOEXEC, 0444)) < 0) {
+ mk_err("I cannot create PID file '%s'", path);
+ return -1;
+ }
+
+ /* create a write exclusive lock for the entire file */
+ lock.l_type = F_WRLCK;
+ lock.l_start = 0;
+ lock.l_whence = SEEK_SET;
+ lock.l_len = 0;
+
+ if (fcntl(fd, F_SETLK, &lock) < 0) {
+ close(fd);
+ mk_err("I cannot set the lock for the PID file '%s'", path);
+ return -1;
+ }
+
+ sprintf(pidstr, "%ld", (long) getpid());
+ ssize_t write_len = strlen(pidstr);
+ if (write(fd, pidstr, write_len) != write_len) {
+ close(fd);
+ mk_err("I cannot write PID number at '%s' file", path);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+/* Remove PID file */
+int mk_utils_remove_pid(char *path)
+{
+ if (unlink(path)) {
+ mk_warn("cannot delete pidfile\n");
+ }
+ return 0;
+}
+#endif
+
+int mk_core_init()
+{
+#ifdef MK_HAVE_TRACE
+ mk_core_init_time = time(NULL);
+ env_trace_filter = getenv("MK_TRACE_FILTER");
+#endif
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_server/CMakeLists.txt b/fluent-bit/lib/monkey/mk_server/CMakeLists.txt
new file mode 100644
index 000000000..457525e62
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/CMakeLists.txt
@@ -0,0 +1,57 @@
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+set(src
+ monkey.c
+ mk_lib.c
+ mk_fifo.c
+ mk_mimetype.c
+ mk_vhost.c
+ mk_header.c
+ mk_config.c
+ mk_user.c
+ mk_utils.c
+ mk_stream.c
+ mk_scheduler.c
+ mk_http.c
+ mk_http_parser.c
+ mk_http_thread.c
+ mk_socket.c
+ mk_net.c
+ mk_clock.c
+ mk_cache.c
+ mk_server.c
+ mk_kernel.c
+ mk_plugin.c
+ )
+
+if(MK_HTTP2)
+ set(src
+ ${src}
+ "mk_http2.c"
+ )
+endif()
+
+# Always build a static library, thats our core :)
+add_library(monkey-core-static STATIC ${src})
+set_target_properties(monkey-core-static PROPERTIES OUTPUT_NAME monkey)
+target_link_libraries(monkey-core-static mk_core ${CMAKE_THREAD_LIBS_INIT} ${STATIC_PLUGINS_LIBS} ${CMAKE_DL_LIBS} rbtree co)
+
+message(STATUS "LINKING ${STATIC_PLUGINS_LIBS}")
+
+if(NOT DEFINED MK_HAVE_REGEX)
+ target_link_libraries(monkey-core-static regex)
+endif()
+
+# Linux Kqueue emulation
+if(MK_HAVE_LINUX_KQUEUE)
+ target_link_libraries(monkey-core-static kqueue)
+endif()
+
+# FreeBSD backtrace
+if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+ target_link_libraries(monkey-core-static execinfo)
+endif()
+
+if (CMAKE_SYSTEM_NAME MATCHES "SunOS")
+ target_link_libraries(monkey-core-static socket nsl)
+endif()
diff --git a/fluent-bit/lib/monkey/mk_server/mk_cache.c b/fluent-bit/lib/monkey/mk_server/mk_cache.c
new file mode 100644
index 000000000..c678afa82
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_cache.c
@@ -0,0 +1,81 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <monkey/mk_core.h>
+#include <monkey/mk_cache.h>
+#include <monkey/mk_cache_tls.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_vhost.h>
+#include <monkey/mk_tls.h>
+
+/* This function is called when a thread is created */
+void mk_cache_worker_init()
+{
+ char *cache_error;
+ mk_ptr_t *p_tmp;
+
+ /* Cache header request -> last modified */
+ p_tmp = mk_mem_alloc_z(sizeof(mk_ptr_t));
+ p_tmp->data = mk_mem_alloc_z(32);
+ p_tmp->len = -1;
+ MK_TLS_SET(mk_tls_cache_header_lm, p_tmp);
+
+ /* Cache header request -> content length */
+ p_tmp = mk_mem_alloc_z(sizeof(mk_ptr_t));
+ p_tmp->data = mk_mem_alloc_z(MK_UTILS_INT2MKP_BUFFER_LEN);
+ p_tmp->len = -1;
+ MK_TLS_SET(mk_tls_cache_header_cl, p_tmp);
+
+ /* Cache gmtime buffer */
+ MK_TLS_SET(mk_tls_cache_gmtime, mk_mem_alloc(sizeof(struct tm)));
+
+ /* Cache the most used text representations of utime2gmt */
+ MK_TLS_SET(mk_tls_cache_gmtext,
+ mk_mem_alloc_z(sizeof(struct mk_gmt_cache) * MK_GMT_CACHES));
+
+ /* Cache buffer for strerror_r(2) */
+ cache_error = mk_mem_alloc(MK_UTILS_ERROR_SIZE);
+ pthread_setspecific(mk_utils_error_key, (void *) cache_error);
+}
+
+void mk_cache_worker_exit()
+{
+ char *cache_error;
+
+ /* Cache header request -> last modified */
+ mk_ptr_free(MK_TLS_GET(mk_tls_cache_header_lm));
+ mk_mem_free(MK_TLS_GET(mk_tls_cache_header_lm));
+
+ /* Cache header request -> content length */
+ mk_ptr_free(MK_TLS_GET(mk_tls_cache_header_cl));
+ mk_mem_free(MK_TLS_GET(mk_tls_cache_header_cl));
+
+ /* Cache gmtime buffer */
+ mk_mem_free(MK_TLS_GET(mk_tls_cache_gmtime));
+
+ /* Cache the most used text representations of utime2gmt */
+ mk_mem_free(MK_TLS_GET(mk_tls_cache_gmtext));
+
+ /* Cache buffer for strerror_r(2) */
+ cache_error = pthread_getspecific(mk_utils_error_key);
+ mk_mem_free(cache_error);
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_clock.c b/fluent-bit/lib/monkey/mk_server/mk_clock.c
new file mode 100644
index 000000000..3a45512f2
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_clock.c
@@ -0,0 +1,171 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <mk_core/mk_pthread.h>
+#include <mk_core/mk_unistd.h>
+
+#include <monkey/mk_core.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_clock.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_tls.h>
+
+#ifdef _WIN32
+static struct tm* localtime_r(const time_t* timep, struct tm* result)
+{
+ localtime_s(result, timep);
+
+ return result;
+}
+
+static struct tm* gmtime_r(const time_t* timep, struct tm* result)
+{
+ gmtime_s(result, timep);
+
+ return result;
+}
+#endif
+
+
+/*
+ * The mk_ptr_ts have two buffers for avoid in half-way access from
+ * another thread while a buffer is being modified. The function below returns
+ * one of two buffers to work with.
+ */
+static inline char *_next_buffer(mk_ptr_t *pointer, char **buffers)
+{
+ if (pointer->data == buffers[0]) {
+ return buffers[1];
+ }
+ else {
+ return buffers[0];
+ }
+}
+
+static void mk_clock_log_set_time(time_t utime, struct mk_server *server)
+{
+ char *time_string;
+ struct tm result;
+
+ time_string = _next_buffer(&server->clock_context->log_current_time, server->clock_context->log_time_buffers);
+ server->clock_context->log_current_utime = utime;
+
+ strftime(time_string, LOG_TIME_BUFFER_SIZE, "[%d/%b/%G %T %z]",
+ localtime_r(&utime, &result));
+
+ server->clock_context->log_current_time.data = time_string;
+}
+
+static void mk_clock_headers_preset(time_t utime, struct mk_server *server)
+{
+ int len1;
+ int len2;
+ struct tm *gmt_tm;
+ struct tm result;
+ char *buffer;
+
+ buffer = _next_buffer(&server->clock_context->headers_preset,
+ server->clock_context->header_time_buffers);
+
+ gmt_tm = gmtime_r(&utime, &result);
+
+ len1 = snprintf(buffer,
+ HEADER_TIME_BUFFER_SIZE,
+ "%s",
+ server->server_signature_header);
+
+ len2 = strftime(buffer + len1,
+ HEADER_PRESET_SIZE - len1,
+ MK_CLOCK_GMT_DATEFORMAT,
+ gmt_tm);
+
+ server->clock_context->headers_preset.data = buffer;
+ server->clock_context->headers_preset.len = len1 + len2;
+}
+
+void *mk_clock_worker_init(void *data)
+{
+ time_t cur_time;
+ struct mk_server *server = data;
+
+ mk_utils_worker_rename("monkey: clock");
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+
+ server->clock_context->mk_clock_tid = pthread_self();
+
+ while (1) {
+ cur_time = time(NULL);
+
+ if(cur_time != ((time_t)-1)) {
+ mk_clock_log_set_time(cur_time, server);
+ mk_clock_headers_preset(cur_time, server);
+ }
+ sleep(1);
+ }
+
+ return NULL;
+}
+
+void mk_clock_exit(struct mk_server *server)
+{
+ pthread_cancel(server->clock_context->mk_clock_tid);
+ pthread_join(server->clock_context->mk_clock_tid, NULL);
+
+ mk_mem_free(server->clock_context->header_time_buffers[0]);
+ mk_mem_free(server->clock_context->header_time_buffers[1]);
+ mk_mem_free(server->clock_context->log_time_buffers[0]);
+ mk_mem_free(server->clock_context->log_time_buffers[1]);
+
+ mk_mem_free(server->clock_context);
+}
+
+/* This function must be called before any threads are created */
+void mk_clock_sequential_init(struct mk_server *server)
+{
+ server->clock_context = mk_mem_alloc_z(sizeof(struct mk_clock_context));
+
+ if (server->clock_context == NULL) {
+ return;
+ }
+
+ /* Time when monkey was started */
+ server->clock_context->monkey_init_time = time(NULL);
+
+ server->clock_context->log_current_time.len = LOG_TIME_BUFFER_SIZE - 2;
+ server->clock_context->headers_preset.len = HEADER_PRESET_SIZE - 1;
+
+ server->clock_context->header_time_buffers[0] = mk_mem_alloc_z(HEADER_PRESET_SIZE);
+ server->clock_context->header_time_buffers[1] = mk_mem_alloc_z(HEADER_PRESET_SIZE);
+
+ server->clock_context->log_time_buffers[0] = mk_mem_alloc_z(LOG_TIME_BUFFER_SIZE);
+ server->clock_context->log_time_buffers[1] = mk_mem_alloc_z(LOG_TIME_BUFFER_SIZE);
+
+ /* Set the time once */
+ time_t cur_time = time(NULL);
+
+ if (cur_time != ((time_t)-1)) {
+ mk_clock_log_set_time(cur_time, server);
+ mk_clock_headers_preset(cur_time, server);
+ }
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_config.c b/fluent-bit/lib/monkey/mk_server/mk_config.c
new file mode 100644
index 000000000..f8dc9c00f
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_config.c
@@ -0,0 +1,636 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/monkey.h>
+#include <monkey/mk_kernel.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_mimetype.h>
+#include <monkey/mk_info.h>
+#include <monkey/mk_core.h>
+#include <monkey/mk_server.h>
+#include <monkey/mk_plugin.h>
+#include <monkey/mk_vhost.h>
+#include <monkey/mk_mimetype.h>
+#include <monkey/mk_info.h>
+
+#include <ctype.h>
+#include <limits.h>
+#include <mk_core/mk_dirent.h>
+#include <sys/stat.h>
+
+struct mk_server_config *mk_config;
+
+static int mk_config_key_have(struct mk_list *list, const char *value)
+{
+ struct mk_list *head;
+ struct mk_string_line *entry;
+
+ mk_list_foreach(head, list) {
+ entry = mk_list_entry(head, struct mk_string_line, _head);
+ if (strcasecmp(entry->val, value) == 0) {
+ return MK_TRUE;
+ }
+ }
+ return MK_FALSE;
+}
+
+void mk_config_listeners_free(struct mk_server *server)
+{
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_config_listener *l;
+
+ mk_list_foreach_safe(head, tmp, &server->listeners) {
+ l = mk_list_entry(head, struct mk_config_listener, _head);
+ mk_list_del(&l->_head);
+ mk_mem_free(l->address);
+ mk_mem_free(l->port);
+ mk_mem_free(l);
+ }
+}
+
+void mk_config_free_all(struct mk_server *server)
+{
+ mk_vhost_free_all(server);
+ mk_mimetype_free_all(server);
+
+ if (server->config) {
+ mk_rconf_free(server->config);
+ }
+
+ if (server->path_conf_root) {
+ mk_mem_free(server->path_conf_root);
+ }
+
+ if (server->path_conf_pidfile) {
+ mk_mem_free(server->path_conf_pidfile);
+ }
+
+ if (server->conf_user_pub) {
+ mk_mem_free(server->conf_user_pub);
+ }
+
+ /* free config->index_files */
+ if (server->index_files) {
+ mk_string_split_free(server->index_files);
+ }
+
+ if (server->user) {
+ mk_mem_free(server->user);
+ }
+
+ if (server->transport_layer) {
+ mk_mem_free(server->transport_layer);
+ }
+
+ mk_config_listeners_free(server);
+
+ mk_ptr_free(&server->server_software);
+ mk_mem_free(server);
+}
+
+/* Print a specific error */
+static void mk_config_print_error_msg(char *variable, char *path)
+{
+ mk_err("[config] %s at %s has an invalid value",
+ variable, path);
+ mk_mem_free(path);
+ exit(EXIT_FAILURE);
+}
+
+/*
+ * Check if at least one of the Listen interfaces are being used by another
+ * process.
+ */
+int mk_config_listen_check_busy(struct mk_server *server)
+{
+ int fd;
+ struct mk_list *head;
+ struct mk_plugin *p;
+ struct mk_config_listener *listen;
+
+ p = mk_plugin_cap(MK_CAP_SOCK_PLAIN, server);
+ if (!p) {
+ mk_warn("Listen check: consider build monkey with basic socket handling!");
+ return MK_FALSE;
+ }
+
+ mk_list_foreach(head, &server->listeners) {
+ listen = mk_list_entry(head, struct mk_config_listener, _head);
+
+ fd = mk_socket_connect(listen->address, atol(listen->port), MK_FALSE);
+ if (fd != -1) {
+ close(fd);
+ return MK_TRUE;
+ }
+ }
+
+ return MK_FALSE;
+}
+
+int mk_config_listen_parse(char *value, struct mk_server *server)
+{
+ int ret = -1;
+ int flags = 0;
+ long port_num;
+ char *address = NULL;
+ char *port = NULL;
+ char *divider;
+ struct mk_list *list = NULL;
+ struct mk_string_line *listener;
+
+ list = mk_string_split_line(value);
+ if (!list) {
+ goto error;
+ }
+
+ if (mk_list_is_empty(list) == 0) {
+ goto error;
+ }
+
+ /* Parse the listener interface */
+ listener = mk_list_entry_first(list, struct mk_string_line, _head);
+ if (listener->val[0] == '[') {
+ /* IPv6 address */
+ divider = strchr(listener->val, ']');
+ if (divider == NULL) {
+ mk_err("[config] Expected closing ']' in IPv6 address.");
+ goto error;
+ }
+ if (divider[1] != ':' || divider[2] == '\0') {
+ mk_err("[config] Expected ':port' after IPv6 address.");
+ goto error;
+ }
+
+ address = mk_string_copy_substr(listener->val + 1, 0,
+ divider - listener->val - 1);
+ port = mk_string_dup(divider + 2);
+ }
+ else if (strchr(listener->val, ':') != NULL) {
+ /* IPv4 address */
+ divider = strrchr(listener->val, ':');
+ if (divider == NULL || divider[1] == '\0') {
+ mk_err("[config] Expected ':port' after IPv4 address.");
+ goto error;
+ }
+
+ address = mk_string_copy_substr(listener->val, 0,
+ divider - listener->val);
+ port = mk_string_dup(divider + 1);
+ }
+ else {
+ /* Port only */
+ address = NULL;
+ port = mk_string_dup(listener->val);
+ }
+
+ errno = 0;
+ port_num = strtol(port, NULL, 10);
+ if (errno != 0 || port_num == LONG_MAX || port_num == LONG_MIN) {
+ mk_warn("Using defaults, could not understand \"Listen %s\"",
+ listener->val);
+ port = NULL;
+ }
+
+ /* Check extra properties of the listener */
+ flags = MK_CAP_HTTP;
+ if (mk_config_key_have(list, "!http")) {
+ flags |= ~MK_CAP_HTTP;
+ }
+
+#ifdef MK_HAVE_HTTP2
+ if (mk_config_key_have(list, "h2")) {
+ flags |= (MK_CAP_HTTP2 | MK_CAP_SOCK_TLS);
+ }
+
+ if (mk_config_key_have(list, "h2c")) {
+ flags |= MK_CAP_HTTP2;
+ }
+#endif
+
+ if (mk_config_key_have(list, "tls")) {
+ flags |= MK_CAP_SOCK_TLS;
+ }
+
+ /* register the new listener */
+ mk_config_listener_add(address, port, flags, server);
+ mk_string_split_free(list);
+ list = NULL;
+ ret = 0;
+
+error:
+ if (address) {
+ mk_mem_free(address);
+ }
+ if (port) {
+ mk_mem_free(port);
+ }
+ if (list) {
+ mk_string_split_free(list);
+ }
+
+ return ret;
+}
+
+static int mk_config_listen_read(struct mk_rconf_section *section,
+ struct mk_server *server)
+{
+ int ret;
+ struct mk_list *cur;
+ struct mk_rconf_entry *entry;
+
+ mk_list_foreach(cur, &section->entries) {
+ entry = mk_list_entry(cur, struct mk_rconf_entry, _head);
+ if (strcasecmp(entry->key, "Listen")) {
+ continue;
+ }
+
+ ret = mk_config_listen_parse(entry->val, server);
+ if (ret != 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* Read configuration files */
+static int mk_config_read_files(char *path_conf, char *file_conf,
+ struct mk_server *server)
+{
+ unsigned long len;
+ char *tmp = NULL;
+ struct stat checkdir;
+ struct mk_rconf *cnf;
+ struct mk_rconf_section *section;
+
+ if (!path_conf) {
+ return -1;
+ }
+
+ if (!file_conf) {
+ file_conf = "monkey.conf";
+ }
+
+ server->path_conf_root = mk_string_dup(path_conf);
+
+ if (stat(server->path_conf_root, &checkdir) == -1) {
+ mk_err("ERROR: Cannot find/open '%s'", server->path_conf_root);
+ return -1;
+ }
+
+ mk_string_build(&tmp, &len, "%s/%s", path_conf, file_conf);
+ cnf = mk_rconf_open(tmp);
+ if (!cnf) {
+ mk_mem_free(tmp);
+ mk_err("Cannot read '%s'", server->conf_main);
+ return -1;
+ }
+ section = mk_rconf_section_get(cnf, "SERVER");
+ if (!section) {
+ mk_err("ERROR: No 'SERVER' section defined");
+ return -1;
+ }
+
+ /* Map source configuration */
+ server->config = cnf;
+
+ /* Listen */
+ if (!server->port_override) {
+ /* Process each Listen entry */
+ if (mk_config_listen_read(section, server)) {
+ mk_err("[config] Failed to read listen sections.");
+ }
+ if (mk_list_is_empty(&server->listeners) == 0) {
+ mk_warn("[config] No valid Listen entries found, set default");
+ mk_config_listener_add(NULL, NULL, MK_CAP_HTTP, server);
+ }
+ }
+ else {
+ mk_config_listener_add(NULL, server->port_override,
+ MK_CAP_HTTP, server);
+ }
+
+ /* Number of thread workers */
+ if (server->workers == -1) {
+ server->workers = (size_t) mk_rconf_section_get_key(section,
+ "Workers",
+ MK_RCONF_NUM);
+ }
+
+ if (server->workers < 1) {
+ server->workers = mk_utils_get_system_core_count();
+
+ if (server->workers < 1) {
+ mk_config_print_error_msg("Workers", tmp);
+ }
+ }
+
+ /* Timeout */
+ server->timeout = (size_t) mk_rconf_section_get_key(section,
+ "Timeout", MK_RCONF_NUM);
+ if (server->timeout < 1) {
+ mk_config_print_error_msg("Timeout", tmp);
+ }
+
+ /* KeepAlive */
+ server->keep_alive = (size_t) mk_rconf_section_get_key(section,
+ "KeepAlive",
+ MK_RCONF_BOOL);
+ if (server->keep_alive == MK_ERROR) {
+ mk_config_print_error_msg("KeepAlive", tmp);
+ }
+
+ /* MaxKeepAliveRequest */
+ server->max_keep_alive_request = (size_t)
+ mk_rconf_section_get_key(section,
+ "MaxKeepAliveRequest",
+ MK_RCONF_NUM);
+
+ if (server->max_keep_alive_request == 0) {
+ mk_config_print_error_msg("MaxKeepAliveRequest", tmp);
+ }
+
+ /* KeepAliveTimeout */
+ server->keep_alive_timeout = (size_t) mk_rconf_section_get_key(section,
+ "KeepAliveTimeout",
+ MK_RCONF_NUM);
+ if (server->keep_alive_timeout == 0) {
+ mk_config_print_error_msg("KeepAliveTimeout", tmp);
+ }
+
+ /* Pid File */
+ if (!server->path_conf_pidfile) {
+ server->path_conf_pidfile = mk_rconf_section_get_key(section,
+ "PidFile",
+ MK_RCONF_STR);
+ }
+
+ /* Home user's directory /~ */
+ server->conf_user_pub = mk_rconf_section_get_key(section,
+ "UserDir",
+ MK_RCONF_STR);
+
+ /* Index files */
+ server->index_files = mk_rconf_section_get_key(section,
+ "Indexfile", MK_RCONF_LIST);
+
+ /* HideVersion Variable */
+ server->hideversion = (size_t) mk_rconf_section_get_key(section,
+ "HideVersion",
+ MK_RCONF_BOOL);
+ if (server->hideversion == MK_ERROR) {
+ mk_config_print_error_msg("HideVersion", tmp);
+ }
+
+ /* User Variable */
+ server->user = mk_rconf_section_get_key(section, "User", MK_RCONF_STR);
+
+ /* Resume */
+ server->resume = (size_t) mk_rconf_section_get_key(section,
+ "Resume", MK_RCONF_BOOL);
+ if (server->resume == MK_ERROR) {
+ mk_config_print_error_msg("Resume", tmp);
+ }
+
+ /* Max Request Size */
+ server->max_request_size = (size_t) mk_rconf_section_get_key(section,
+ "MaxRequestSize",
+ MK_RCONF_NUM);
+ if (server->max_request_size <= 0) {
+ mk_config_print_error_msg("MaxRequestSize", tmp);
+ }
+ else {
+ server->max_request_size *= 1024;
+ }
+
+ /* Symbolic Links */
+ server->symlink = (size_t) mk_rconf_section_get_key(section,
+ "SymLink", MK_RCONF_BOOL);
+ if (server->symlink == MK_ERROR) {
+ mk_config_print_error_msg("SymLink", tmp);
+ }
+
+ /* Transport Layer plugin */
+ if (!server->transport_layer) {
+ server->transport_layer = mk_rconf_section_get_key(section,
+ "TransportLayer",
+ MK_RCONF_STR);
+ }
+
+ /* Default Mimetype */
+ mk_mem_free(tmp);
+ tmp = mk_rconf_section_get_key(section, "DefaultMimeType", MK_RCONF_STR);
+ if (tmp) {
+ mk_string_build(&server->mimetype_default_str, &len, "%s\r\n", tmp);
+ }
+
+ /* File Descriptor Table (FDT) */
+ server->fdt = (size_t) mk_rconf_section_get_key(section,
+ "FDT",
+ MK_RCONF_BOOL);
+
+ /* FIXME: Overcapacity not ready */
+ server->fd_limit = (size_t) mk_rconf_section_get_key(section,
+ "FDLimit",
+ MK_RCONF_NUM);
+ /* Get each worker clients capacity based on FDs system limits */
+ server->server_capacity = mk_server_capacity(server);
+
+
+ if (!server->one_shot) {
+ mk_vhost_init(path_conf, server);
+ }
+ else {
+ mk_vhost_set_single(server->one_shot, server);
+ }
+
+ mk_mem_free(tmp);
+ return 0;
+}
+
+void mk_config_signature(struct mk_server *server)
+{
+ unsigned long len;
+
+ /* Server Signature */
+ if (server->hideversion == MK_FALSE) {
+ snprintf(server->server_signature,
+ sizeof(server->server_signature) - 1,
+ "Monkey/%s", MK_VERSION_STR);
+ }
+ else {
+ snprintf(server->server_signature,
+ sizeof(server->server_signature) - 1,
+ "Monkey");
+ }
+ len = snprintf(server->server_signature_header,
+ sizeof(server->server_signature_header) - 1,
+ "Server: %s\r\n", server->server_signature);
+ server->server_signature_header_len = len;
+}
+
+/* read main configuration from monkey.conf */
+void mk_config_start_configure(struct mk_server *server)
+{
+ int ret;
+ unsigned long len;
+
+ ret = mk_config_read_files(server->path_conf_root,
+ server->conf_main, server);
+ if (ret != 0) {
+ return;
+ }
+
+ /* Load mimes */
+ mk_mimetype_read_config(server);
+
+ mk_ptr_reset(&server->server_software);
+
+ /* Basic server information */
+ if (server->hideversion == MK_FALSE) {
+ mk_string_build(&server->server_software.data,
+ &len, "Monkey/%s (%s)", MK_VERSION_STR, MK_BUILD_OS);
+ server->server_software.len = len;
+ }
+ else {
+ mk_string_build(&server->server_software.data, &len, "Monkey Server");
+ server->server_software.len = len;
+ }
+}
+
+/* Register a new listener into the main configuration */
+struct mk_config_listener *mk_config_listener_add(char *address,
+ char *port, int flags,
+ struct mk_server *server)
+{
+ struct mk_list *head;
+ struct mk_config_listener *check;
+ struct mk_config_listener *listen = NULL;
+
+ listen = mk_mem_alloc(sizeof(struct mk_config_listener));
+ if (!listen) {
+ mk_err("[listen_add] malloc() failed");
+ return NULL;
+ }
+
+ if (!address) {
+ listen->address = mk_string_dup(MK_DEFAULT_LISTEN_ADDR);
+ }
+ else {
+ listen->address = mk_string_dup(address);
+ }
+
+ /* Set the port */
+ if (!port) {
+ mk_err("[listen_add] TCP port not defined");
+ exit(EXIT_FAILURE);
+ }
+
+ listen->port = mk_string_dup(port);
+ listen->flags = flags;
+
+ /* Before to add a new listener, lets make sure it's not a duplicated */
+ mk_list_foreach(head, &server->listeners) {
+ check = mk_list_entry(head, struct mk_config_listener, _head);
+ if (strcmp(listen->address, check->address) == 0 &&
+ strcmp(listen->port, check->port) == 0) {
+ mk_warn("Listener: duplicated %s:%s, skip.",
+ listen->address, listen->port);
+
+ /* free resources */
+ mk_mem_free(listen->address);
+ mk_mem_free(listen->port);
+ mk_mem_free(listen);
+ return NULL;
+ }
+ }
+
+ mk_list_add(&listen->_head, &server->listeners);
+ return listen;
+}
+
+void mk_config_set_init_values(struct mk_server *server)
+{
+ /* Init values */
+ server->is_seteuid = MK_FALSE;
+ server->timeout = 15;
+ server->hideversion = MK_FALSE;
+ server->keep_alive = MK_TRUE;
+ server->keep_alive_timeout = 15;
+ server->max_keep_alive_request = 50;
+ server->resume = MK_TRUE;
+ server->standard_port = 80;
+ server->symlink = MK_FALSE;
+ server->nhosts = 0;
+ mk_list_init(&server->hosts);
+ server->user = NULL;
+ server->open_flags = O_RDONLY; /* The only place this is effectively used (other than the sanity check)
+ * is mk_http.c where it's used to test for file existence and the fd is apparently leaked */
+ server->index_files = NULL;
+ server->conf_user_pub = NULL;
+ server->workers = 1;
+
+ /* TCP REUSEPORT: available on Linux >= 3.9 */
+ if (server->scheduler_mode == -1) {
+ if (server->kernel_features & MK_KERNEL_SO_REUSEPORT) {
+ server->scheduler_mode = MK_SCHEDULER_REUSEPORT;
+ }
+ else {
+ server->scheduler_mode = MK_SCHEDULER_FAIR_BALANCING;
+ }
+ }
+
+ /* Max request buffer size allowed
+ * right now, every chunk size is 4KB (4096 bytes),
+ * so we are setting a maximum request size to 32 KB */
+ server->max_request_size = MK_REQUEST_CHUNK * 8;
+
+ /* Internals */
+ server->safe_event_write = MK_FALSE;
+
+ /* Init plugin list */
+ mk_list_init(&server->plugins);
+
+ /* Init listeners */
+ mk_list_init(&server->listeners);
+}
+
+void mk_config_sanity_check(struct mk_server *server)
+{
+ /* Check O_NOATIME for current user, flag will just be used
+ * if running user is allowed to.
+ */
+ int fd;
+ int flags;
+
+ if (!server->path_conf_root) {
+ return;
+ }
+
+ flags = server->open_flags;
+ flags |= O_NOATIME;
+ fd = open(server->path_conf_root, flags);
+
+ if (fd > -1) {
+ server->open_flags = flags;
+ close(fd);
+ }
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_fifo.c b/fluent-bit/lib/monkey/mk_server/mk_fifo.c
new file mode 100644
index 000000000..fd148db7b
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_fifo.c
@@ -0,0 +1,463 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_fifo.h>
+#include <monkey/mk_scheduler.h>
+
+#ifdef _WIN32
+#include <event.h>
+#endif
+
+static struct mk_fifo_worker *mk_fifo_worker_create(struct mk_fifo *ctx,
+ void *data)
+{
+ int id;
+ int ret;
+ struct mk_fifo_worker *fw;
+
+ /* Get an ID */
+ id = mk_list_size(&ctx->workers);
+
+ fw = mk_mem_alloc_z(sizeof(struct mk_fifo_worker));
+ if (!fw) {
+ perror("malloc");
+ return NULL;
+ }
+ MK_EVENT_NEW(&fw->event);
+
+ fw->worker_id = id;
+ fw->data = data;
+ fw->fifo = ctx;
+
+ fw->buf_data = mk_mem_alloc(MK_FIFO_BUF_SIZE);
+ if (!fw->buf_data) {
+ perror("malloc");
+ mk_mem_free(fw);
+ return NULL;
+ }
+ fw->buf_len = 0;
+ fw->buf_size = MK_FIFO_BUF_SIZE;
+
+#ifdef _WIN32
+ ret = evutil_socketpair(AF_INET, SOCK_STREAM, 0, fw->channel);
+ if (ret == -1) {
+ perror("socketpair");
+ mk_mem_free(fw);
+ return NULL;
+ }
+#else
+ ret = pipe(fw->channel);
+ if (ret == -1) {
+ perror("pipe");
+ mk_mem_free(fw);
+ return NULL;
+ }
+#endif
+
+ mk_list_add(&fw->_head, &ctx->workers);
+ return fw;
+}
+
+/*
+ * Function used as a callback triggered by mk_worker_callback() or
+ * through a mk_sched_worker_cb_add(). It purpose is to prepare the
+ * channels on the final worker thread so it can consume pushed
+ * messages.
+ */
+void mk_fifo_worker_setup(void *data)
+{
+ struct mk_fifo_worker *mw = NULL;
+ struct mk_fifo *ctx = data;
+
+ pthread_mutex_lock(&ctx->mutex_init);
+
+ mw = mk_fifo_worker_create(ctx, data);
+ if (!mw) {
+ mk_err("[msg] error configuring msg-worker context ");
+ pthread_mutex_unlock(&ctx->mutex_init);
+ return;
+ }
+
+ /* Make the current worker context available */
+ pthread_setspecific(*ctx->key, mw);
+ pthread_mutex_unlock(&ctx->mutex_init);
+}
+
+struct mk_fifo *mk_fifo_create(pthread_key_t *key, void *data)
+{
+ struct mk_fifo *ctx;
+
+ ctx = mk_mem_alloc(sizeof(struct mk_fifo));
+ if (!ctx) {
+ perror("malloc");
+ return NULL;
+ }
+ ctx->data = data;
+
+ /* Lists */
+ mk_list_init(&ctx->queues);
+ mk_list_init(&ctx->workers);
+
+
+ /* Pthread specifics */
+
+ /* We need to isolate this because there is a key that's shared between monkey
+ * instances by design.
+ */
+ if (key != NULL) {
+ ctx->key = key;
+ pthread_key_create(ctx->key, NULL);
+ }
+
+ pthread_mutex_init(&ctx->mutex_init, NULL);
+
+ return ctx;
+}
+
+int mk_fifo_queue_create(struct mk_fifo *ctx, char *name,
+ void (*cb)(struct mk_fifo_queue *, void *,
+ size_t, void *),
+ void *data)
+
+{
+ int id = -1;
+ int len;
+ struct mk_list *head;
+ struct mk_fifo_queue *q;
+
+ /* Get ID for the new queue */
+ if (mk_list_is_empty(&ctx->queues) == 0) {
+ id = 0;
+ }
+ else {
+ q = mk_list_entry_last(&ctx->queues, struct mk_fifo_queue, _head);
+ id = q->id + 1;
+ }
+
+ /* queue name might need to be truncated if is too long */
+ len = strlen(name);
+ if (len > (int) sizeof(q->name) - 1) {
+ len = sizeof(q->name) - 1;
+ }
+
+ /* Validate that name is not a duplicated */
+ mk_list_foreach(head, &ctx->queues) {
+ q = mk_list_entry(head, struct mk_fifo_queue, _head);
+ if (strlen(q->name) != (unsigned int) len) {
+ continue;
+ }
+
+ if (strncmp(q->name, name, len) == 0) {
+ return -1;
+ }
+ }
+
+ /* Allocate and register queue */
+ q = mk_mem_alloc(sizeof(struct mk_fifo_queue));
+ if (!q) {
+ perror("malloc");
+ return -1;
+ }
+ q->id = id;
+ q->cb_message = cb;
+ q->data = data;
+
+ strncpy(q->name, name, len);
+ q->name[len] = '\0';
+ mk_list_add(&q->_head, &ctx->queues);
+
+ return id;
+}
+
+struct mk_fifo_queue *mk_fifo_queue_get(struct mk_fifo *ctx, int id)
+{
+ struct mk_list *head;
+ struct mk_fifo_queue *q = NULL;
+
+ mk_list_foreach(head, &ctx->queues) {
+ q = mk_list_entry(head, struct mk_fifo_queue, _head);
+ if (q->id == id) {
+ return q;
+ }
+ }
+
+ return NULL;
+}
+
+int mk_fifo_queue_destroy(struct mk_fifo *ctx, struct mk_fifo_queue *q)
+{
+ (void) ctx;
+
+ mk_list_del(&q->_head);
+ mk_mem_free(q);
+ return 0;
+}
+
+int mk_fifo_queue_id_destroy(struct mk_fifo *ctx, int id)
+{
+ struct mk_fifo_queue *q;
+
+ q = mk_fifo_queue_get(ctx, id);
+ if (!q) {
+ return -1;
+ }
+
+ mk_fifo_queue_destroy(ctx, q);
+ return 0;
+}
+
+static int mk_fifo_queue_destroy_all(struct mk_fifo *ctx)
+{
+ int c = 0;
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_fifo_queue *q;
+
+ mk_list_foreach_safe(head, tmp, &ctx->queues) {
+ q = mk_list_entry(head, struct mk_fifo_queue, _head);
+ mk_fifo_queue_destroy(ctx, q);
+ c++;
+ }
+
+ return c;
+}
+
+static int mk_fifo_worker_destroy_all(struct mk_fifo *ctx)
+{
+ int c = 0;
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_fifo_worker *fw;
+
+ mk_list_foreach_safe(head, tmp, &ctx->workers) {
+ fw = mk_list_entry(head, struct mk_fifo_worker, _head);
+
+#ifdef _WIN32
+ evutil_closesocket(fw->channel[0]);
+ evutil_closesocket(fw->channel[1]);
+#else
+ close(fw->channel[0]);
+ close(fw->channel[1]);
+#endif
+ mk_list_del(&fw->_head);
+ mk_mem_free(fw->buf_data);
+ mk_mem_free(fw);
+ c++;
+ }
+
+ return c;
+}
+
+static int msg_write(int fd, void *buf, size_t count)
+{
+ ssize_t bytes;
+ size_t total = 0;
+
+ do {
+#ifdef _WIN32
+ bytes = send(fd, (uint8_t *)buf + total, count - total, 0);
+#else
+ bytes = write(fd, (uint8_t *)buf + total, count - total);
+#endif
+ if (bytes == -1) {
+ if (errno == EAGAIN) {
+ /*
+ * This could happen, since this function goal is not to
+ * return until all data have been read, just sleep a little
+ * bit (0.05 seconds)
+ */
+
+#ifdef _WIN32
+ Sleep(5);
+#else
+ usleep(50000);
+#endif
+ continue;
+ }
+ }
+ else if (bytes == 0) {
+ /* Broken pipe ? */
+ perror("write");
+ return -1;
+ }
+ total += bytes;
+
+ } while (total < count);
+
+ return total;
+}
+
+/*
+ * Push a message into a queue: this function runs from the parent thread
+ * so it needs to write the message to every thread pipe channel.
+ */
+int mk_fifo_send(struct mk_fifo *ctx, int id, void *data, size_t size)
+{
+ int ret;
+ struct mk_list *head;
+ struct mk_fifo_msg msg;
+ struct mk_fifo_queue *q;
+ struct mk_fifo_worker *fw;
+
+ /* Validate queue ID */
+ q = mk_fifo_queue_get(ctx, id);
+ if (!q) {
+ return -1;
+ }
+
+ pthread_mutex_lock(&ctx->mutex_init);
+
+ mk_list_foreach(head, &ctx->workers) {
+ fw = mk_list_entry(head, struct mk_fifo_worker, _head);
+
+ msg.length = size;
+ msg.flags = 0;
+ msg.queue_id = (uint16_t) id;
+
+ ret = msg_write(fw->channel[1], &msg, sizeof(struct mk_fifo_msg));
+ if (ret == -1) {
+ pthread_mutex_unlock(&ctx->mutex_init);
+ perror("write");
+ fprintf(stderr, "[msg] error writing message header\n");
+ return -1;
+ }
+
+ ret = msg_write(fw->channel[1], data, size);
+ if (ret == -1) {
+ pthread_mutex_unlock(&ctx->mutex_init);
+ perror("write");
+ fprintf(stderr, "[msg] error writing message body\n");
+ return -1;
+ }
+ }
+
+ pthread_mutex_unlock(&ctx->mutex_init);
+
+ return 0;
+}
+
+static inline void consume_bytes(char *buf, int bytes, int length)
+{
+ memmove(buf, buf + bytes, length - bytes);
+}
+
+static inline int fifo_drop_msg(struct mk_fifo_worker *fw)
+{
+ size_t drop_bytes;
+ struct mk_fifo_msg *msg;
+
+ msg = (struct mk_fifo_msg *) fw->buf_data;
+ drop_bytes = (sizeof(struct mk_fifo_msg) + msg->length);
+ consume_bytes(fw->buf_data, drop_bytes, fw->buf_len);
+ fw->buf_len -= drop_bytes;
+
+ return 0;
+}
+
+static inline int fifo_is_msg_ready(struct mk_fifo_worker *fw)
+{
+ struct mk_fifo_msg *msg;
+
+ msg = (struct mk_fifo_msg *) fw->buf_data;
+ if (fw->buf_len >= (msg->length + sizeof(struct mk_fifo_msg))) {
+ return MK_TRUE;
+ }
+
+ return MK_FALSE;
+}
+
+int mk_fifo_worker_read(void *event)
+{
+ int available;
+ char *tmp;
+ size_t size;
+ ssize_t bytes;
+ struct mk_fifo_msg *fm;
+ struct mk_fifo_worker *fw;
+ struct mk_fifo_queue *fq;
+
+ fw = (struct mk_fifo_worker *) event;
+
+ /* Check available space */
+ available = fw->buf_size - fw->buf_len;
+ if (available <= 1) {
+ size = fw->buf_size + (MK_FIFO_BUF_SIZE / 2);
+ tmp = mk_mem_realloc(fw->buf_data, size);
+ if (!tmp) {
+ perror("realloc");
+ return -1;
+ }
+ fw->buf_data = tmp;
+ fw->buf_size = size;
+ available = fw->buf_size - fw->buf_len;
+ }
+
+ /* Read data from pipe */
+#ifdef _WIN32
+ bytes = recv(fw->channel[0], fw->buf_data + fw->buf_len, available, 0);
+#else
+ bytes = read(fw->channel[0], fw->buf_data + fw->buf_len, available);
+#endif
+
+ if (bytes == 0) {
+ return -1;
+ }
+ else if (bytes == -1){
+ perror("read");
+ return -1;
+ }
+
+ fw->buf_len += bytes;
+
+ /* Find messages and trigger callbacks */
+ while (fw->buf_len > 0) {
+ if (fifo_is_msg_ready(fw) == MK_TRUE) {
+ /* we got a complete message */
+ fm = (struct mk_fifo_msg *) fw->buf_data;
+ fq = mk_fifo_queue_get(fw->fifo, fm->queue_id);
+ if (!fq) {
+ /* Invalid queue */
+ fprintf(stderr, "[fifo worker read] invalid queue id %i\n",
+ fm->queue_id);
+ fifo_drop_msg(fw);
+ continue;
+ }
+
+ /* Trigger callback if any */
+ if (fq->cb_message) {
+ fq->cb_message(fq, fm->data, fm->length, fq->data);
+ }
+ fifo_drop_msg(fw);
+ }
+ else {
+ /* msg not ready */
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int mk_fifo_destroy(struct mk_fifo *ctx)
+{
+ mk_fifo_queue_destroy_all(ctx);
+ mk_fifo_worker_destroy_all(ctx);
+ mk_mem_free(ctx);
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_header.c b/fluent-bit/lib/monkey/mk_server/mk_header.c
new file mode 100644
index 000000000..cd8f77bde
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_header.c
@@ -0,0 +1,451 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/monkey.h>
+#include <monkey/mk_server.h>
+#include <monkey/mk_header.h>
+#include <monkey/mk_core.h>
+#include <monkey/mk_http_status.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_socket.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_clock.h>
+#include <monkey/mk_cache.h>
+#include <monkey/mk_http.h>
+#include <monkey/mk_vhost.h>
+#include <monkey/mk_tls.h>
+
+#define MK_HEADER_SHORT_DATE "Date: "
+#define MK_HEADER_SHORT_LOCATION "Location: "
+#define MK_HEADER_SHORT_CT "Content-Type: "
+#define MK_HEADER_ACCEPT_RANGES "Accept-Ranges: bytes" MK_CRLF
+#define MK_HEADER_ALLOWED_METHODS "Allow: "
+#define MK_HEADER_CONN_KA "Connection: Keep-Alive" MK_CRLF
+#define MK_HEADER_CONN_CLOSE "Connection: Close" MK_CRLF
+#define MK_HEADER_CONN_UPGRADE "Connection: Upgrade" MK_CRLF
+#define MK_HEADER_CONTENT_LENGTH "Content-Length: "
+#define MK_HEADER_CONTENT_ENCODING "Content-Encoding: "
+#define MK_HEADER_TE_CHUNKED "Transfer-Encoding: chunked" MK_CRLF
+#define MK_HEADER_LAST_MODIFIED "Last-Modified: "
+#define MK_HEADER_UPGRADE_H2C "Upgrade: h2c" MK_CRLF
+
+const mk_ptr_t mk_header_short_date = mk_ptr_init(MK_HEADER_SHORT_DATE);
+const mk_ptr_t mk_header_short_location = mk_ptr_init(MK_HEADER_SHORT_LOCATION);
+const mk_ptr_t mk_header_short_ct = mk_ptr_init(MK_HEADER_SHORT_CT);
+const mk_ptr_t mk_header_allow = mk_ptr_init(MK_HEADER_ALLOWED_METHODS);
+
+const mk_ptr_t mk_header_conn_ka = mk_ptr_init(MK_HEADER_CONN_KA);
+const mk_ptr_t mk_header_conn_close = mk_ptr_init(MK_HEADER_CONN_CLOSE);
+const mk_ptr_t mk_header_conn_upgrade = mk_ptr_init(MK_HEADER_CONN_UPGRADE);
+const mk_ptr_t mk_header_content_length = mk_ptr_init(MK_HEADER_CONTENT_LENGTH);
+const mk_ptr_t mk_header_content_encoding = mk_ptr_init(MK_HEADER_CONTENT_ENCODING);
+const mk_ptr_t mk_header_accept_ranges = mk_ptr_init(MK_HEADER_ACCEPT_RANGES);
+const mk_ptr_t mk_header_te_chunked = mk_ptr_init(MK_HEADER_TE_CHUNKED);
+const mk_ptr_t mk_header_last_modified = mk_ptr_init(MK_HEADER_LAST_MODIFIED);
+const mk_ptr_t mk_header_upgrade_h2c = mk_ptr_init(MK_HEADER_UPGRADE_H2C);
+
+#define status_entry(num, str) {num, sizeof(str) - 1, str}
+
+static const struct header_status_response status_response[] = {
+
+ /*
+ * The most used first:
+ *
+ * - HTTP/1.1 200 OK
+ * - HTTP/1.1 404 Not Found
+ */
+ status_entry(MK_HTTP_OK, MK_RH_HTTP_OK),
+ status_entry(MK_CLIENT_NOT_FOUND, MK_RH_CLIENT_NOT_FOUND),
+
+ /* Informational */
+ status_entry(MK_INFO_CONTINUE, MK_RH_INFO_CONTINUE),
+ status_entry(MK_INFO_SWITCH_PROTOCOL, MK_RH_INFO_SWITCH_PROTOCOL),
+
+ /* Successful */
+ status_entry(MK_HTTP_CREATED, MK_RH_HTTP_CREATED),
+ status_entry(MK_HTTP_ACCEPTED, MK_RH_HTTP_ACCEPTED),
+ status_entry(MK_HTTP_NON_AUTH_INFO, MK_RH_HTTP_NON_AUTH_INFO),
+ status_entry(MK_HTTP_NOCONTENT, MK_RH_HTTP_NOCONTENT),
+ status_entry(MK_HTTP_RESET, MK_RH_HTTP_RESET),
+ status_entry(MK_HTTP_PARTIAL, MK_RH_HTTP_PARTIAL),
+
+ /* Redirections */
+ status_entry(MK_REDIR_MULTIPLE, MK_RH_REDIR_MULTIPLE),
+ status_entry(MK_REDIR_MOVED, MK_RH_REDIR_MOVED),
+ status_entry(MK_REDIR_MOVED_T, MK_RH_REDIR_MOVED_T),
+ status_entry(MK_REDIR_SEE_OTHER, MK_RH_REDIR_SEE_OTHER),
+ status_entry(MK_NOT_MODIFIED, MK_RH_NOT_MODIFIED),
+ status_entry(MK_REDIR_USE_PROXY, MK_RH_REDIR_USE_PROXY),
+
+ /* Client side errors */
+ status_entry(MK_CLIENT_BAD_REQUEST, MK_RH_CLIENT_BAD_REQUEST),
+ status_entry(MK_CLIENT_UNAUTH, MK_RH_CLIENT_UNAUTH),
+ status_entry(MK_CLIENT_PAYMENT_REQ, MK_RH_CLIENT_PAYMENT_REQ),
+ status_entry(MK_CLIENT_FORBIDDEN, MK_RH_CLIENT_FORBIDDEN),
+ status_entry(MK_CLIENT_METHOD_NOT_ALLOWED, MK_RH_CLIENT_METHOD_NOT_ALLOWED),
+ status_entry(MK_CLIENT_NOT_ACCEPTABLE, MK_RH_CLIENT_NOT_ACCEPTABLE),
+ status_entry(MK_CLIENT_PROXY_AUTH, MK_RH_CLIENT_PROXY_AUTH),
+ status_entry(MK_CLIENT_REQUEST_TIMEOUT, MK_RH_CLIENT_REQUEST_TIMEOUT),
+ status_entry(MK_CLIENT_CONFLICT, MK_RH_CLIENT_CONFLICT),
+ status_entry(MK_CLIENT_GONE, MK_RH_CLIENT_GONE),
+ status_entry(MK_CLIENT_LENGTH_REQUIRED, MK_RH_CLIENT_LENGTH_REQUIRED),
+ status_entry(MK_CLIENT_PRECOND_FAILED, MK_RH_CLIENT_PRECOND_FAILED),
+ status_entry(MK_CLIENT_REQUEST_ENTITY_TOO_LARGE,
+ MK_RH_CLIENT_REQUEST_ENTITY_TOO_LARGE),
+ status_entry(MK_CLIENT_REQUEST_URI_TOO_LONG,
+ MK_RH_CLIENT_REQUEST_URI_TOO_LONG),
+ status_entry(MK_CLIENT_UNSUPPORTED_MEDIA, MK_RH_CLIENT_UNSUPPORTED_MEDIA),
+ status_entry(MK_CLIENT_REQUESTED_RANGE_NOT_SATISF,
+ MK_RH_CLIENT_REQUESTED_RANGE_NOT_SATISF),
+
+ /* Server side errors */
+ status_entry(MK_SERVER_INTERNAL_ERROR, MK_RH_SERVER_INTERNAL_ERROR),
+ status_entry(MK_SERVER_NOT_IMPLEMENTED, MK_RH_SERVER_NOT_IMPLEMENTED),
+ status_entry(MK_SERVER_BAD_GATEWAY, MK_RH_SERVER_BAD_GATEWAY),
+ status_entry(MK_SERVER_SERVICE_UNAV, MK_RH_SERVER_SERVICE_UNAV),
+ status_entry(MK_SERVER_GATEWAY_TIMEOUT, MK_RH_SERVER_GATEWAY_TIMEOUT),
+ status_entry(MK_SERVER_HTTP_VERSION_UNSUP, MK_RH_SERVER_HTTP_VERSION_UNSUP)
+};
+
+static const int status_response_len =
+ (sizeof(status_response)/(sizeof(status_response[0])));
+
+static void mk_header_cb_finished(struct mk_stream_input *in)
+{
+ struct mk_iov *iov = in->buffer;
+
+ mk_iov_free_marked(iov);
+
+#if defined(__APPLE__)
+ /*
+ * Disable TCP_CORK right away, according to:
+ *
+ * ---
+ * commit 81e8b869d70f9da93ddfbfb17ec7f12ce3c28fc6
+ * Author: Sonny Karlsson <ksonny@lotrax.org>
+ * Date: Sat Oct 18 12:11:49 2014 +0200
+ *
+ * http: Remove cork before first call to sendfile().
+ *
+ * This removes a large delay on Mac OS X when headers and file content
+ * does not fill a single frame.
+ * Deactivating TCP_NOPUSH does not cause pending frames to be sent until
+ * the next write operation.
+ * ---
+ */
+
+ mk_server_cork_flag(in->stream->channel->fd, TCP_CORK_OFF);
+#endif
+}
+
+static void cb_stream_iov_extended_free(struct mk_stream_input *in)
+{
+ struct mk_iov *iov;
+
+ iov = in->buffer;
+ mk_iov_free(iov);
+}
+
+/* Send response headers */
+int mk_header_prepare(struct mk_http_session *cs, struct mk_http_request *sr,
+ struct mk_server *server)
+{
+ int i = 0;
+ unsigned long len = 0;
+ char *buffer = 0;
+ mk_ptr_t response;
+ struct response_headers *sh;
+ struct mk_iov *iov;
+
+ sh = &sr->headers;
+ iov = &sh->headers_iov;
+
+ /* HTTP Status Code */
+ if (sh->status == MK_CUSTOM_STATUS) {
+ response.data = sh->custom_status.data;
+ response.len = sh->custom_status.len;
+ }
+ else {
+ for (i = 0; i < status_response_len; i++) {
+ if (status_response[i].status == sh->status) {
+ response.data = status_response[i].response;
+ response.len = status_response[i].length;
+ break;
+ }
+ }
+ }
+
+ /* Invalid status set */
+ mk_bug(i == status_response_len);
+
+ mk_iov_add(iov, response.data, response.len, MK_FALSE);
+
+ /*
+ * Preset headers (mk_clock.c):
+ *
+ * - Server
+ * - Date
+ */
+ mk_iov_add(iov,
+ server->clock_context->headers_preset.data,
+ server->clock_context->headers_preset.len,
+ MK_FALSE);
+
+ /* Last-Modified */
+ if (sh->last_modified > 0) {
+ mk_ptr_t *lm = MK_TLS_GET(mk_tls_cache_header_lm);
+ lm->len = mk_utils_utime2gmt(&lm->data, sh->last_modified);
+
+ mk_iov_add(iov,
+ mk_header_last_modified.data,
+ mk_header_last_modified.len,
+ MK_FALSE);
+ mk_iov_add(iov,
+ lm->data,
+ lm->len,
+ MK_FALSE);
+ }
+
+ /* Connection */
+ if (sh->connection == 0) {
+ if (cs->close_now == MK_FALSE) {
+ if (sr->connection.len > 0) {
+ if (sr->protocol != MK_HTTP_PROTOCOL_11) {
+ mk_iov_add(iov,
+ mk_header_conn_ka.data,
+ mk_header_conn_ka.len,
+ MK_FALSE);
+ }
+ }
+ }
+ else {
+ mk_iov_add(iov,
+ mk_header_conn_close.data,
+ mk_header_conn_close.len,
+ MK_FALSE);
+ }
+ }
+ else if (sh->connection == MK_HEADER_CONN_UPGRADED) {
+ mk_iov_add(iov,
+ mk_header_conn_upgrade.data,
+ mk_header_conn_upgrade.len,
+ MK_FALSE);
+ }
+
+ /* Location */
+ if (sh->location != NULL) {
+ mk_iov_add(iov,
+ mk_header_short_location.data,
+ mk_header_short_location.len,
+ MK_FALSE);
+
+ mk_iov_add(iov,
+ sh->location,
+ strlen(sh->location),
+ MK_TRUE);
+ }
+
+ /* allowed methods */
+ if (sh->allow_methods.len > 0) {
+ mk_iov_add(iov,
+ mk_header_allow.data,
+ mk_header_allow.len,
+ MK_FALSE);
+ mk_iov_add(iov,
+ sh->allow_methods.data,
+ sh->allow_methods.len,
+ MK_FALSE);
+ }
+
+ /* Content type */
+ if (sh->content_type.len > 0) {
+ mk_iov_add(iov,
+ sh->content_type.data,
+ sh->content_type.len,
+ MK_FALSE);
+ }
+
+ /*
+ * Transfer Encoding: the transfer encoding header is just sent when
+ * the response has some content defined by the HTTP status response
+ */
+ switch (sh->transfer_encoding) {
+ case MK_HEADER_TE_TYPE_CHUNKED:
+ mk_iov_add(iov,
+ mk_header_te_chunked.data,
+ mk_header_te_chunked.len,
+ MK_FALSE);
+ break;
+ }
+
+ /* E-Tag */
+ if (sh->etag_len > 0) {
+ mk_iov_add(iov, sh->etag_buf, sh->etag_len, MK_FALSE);
+ }
+
+ /* Content-Encoding */
+ if (sh->content_encoding.len > 0) {
+ mk_iov_add(iov, mk_header_content_encoding.data,
+ mk_header_content_encoding.len,
+ MK_FALSE);
+ mk_iov_add(iov, sh->content_encoding.data,
+ sh->content_encoding.len,
+ MK_FALSE);
+ }
+
+ /* Content-Length */
+ if (sh->content_length >= 0 && sh->transfer_encoding != 0) {
+ /* Map content length to MK_POINTER */
+ mk_ptr_t *cl = MK_TLS_GET(mk_tls_cache_header_cl);
+ mk_string_itop(sh->content_length, cl);
+
+ /* Set headers */
+ mk_iov_add(iov,
+ mk_header_content_length.data,
+ mk_header_content_length.len,
+ MK_FALSE);
+ mk_iov_add(iov,
+ cl->data,
+ cl->len,
+ MK_FALSE);
+ }
+
+ if ((sh->content_length != 0 && (sh->ranges[0] >= 0 || sh->ranges[1] >= 0)) &&
+ server->resume == MK_TRUE) {
+ buffer = 0;
+
+ /* yyy- */
+ if (sh->ranges[0] >= 0 && sh->ranges[1] == -1) {
+ mk_string_build(&buffer,
+ &len,
+ "%s bytes %d-%ld/%ld\r\n",
+ RH_CONTENT_RANGE,
+ sh->ranges[0],
+ (sh->real_length - 1), sh->real_length);
+ mk_iov_add(iov, buffer, len, MK_TRUE);
+ }
+
+ /* yyy-xxx */
+ if (sh->ranges[0] >= 0 && sh->ranges[1] >= 0) {
+ mk_string_build(&buffer,
+ &len,
+ "%s bytes %d-%d/%ld\r\n",
+ RH_CONTENT_RANGE,
+ sh->ranges[0], sh->ranges[1], sh->real_length);
+
+ mk_iov_add(iov, buffer, len, MK_TRUE);
+ }
+
+ /* -xxx */
+ if (sh->ranges[0] == -1 && sh->ranges[1] > 0) {
+ mk_string_build(&buffer,
+ &len,
+ "%s bytes %ld-%ld/%ld\r\n",
+ RH_CONTENT_RANGE,
+ (sh->real_length - sh->ranges[1]),
+ (sh->real_length - 1), sh->real_length);
+ mk_iov_add(iov, buffer, len, MK_TRUE);
+ }
+ }
+
+ if (sh->upgrade == MK_HEADER_UPGRADED_H2C) {
+ mk_iov_add(iov, mk_header_upgrade_h2c.data, mk_header_upgrade_h2c.len,
+ MK_FALSE);
+ }
+
+
+ if (sh->cgi == SH_NOCGI || sh->breakline == MK_HEADER_BREAKLINE) {
+ if (!sr->headers._extra_rows) {
+ mk_iov_add(iov, mk_iov_crlf.data, mk_iov_crlf.len,
+ MK_FALSE);
+ }
+ else {
+ mk_iov_add(sr->headers._extra_rows, mk_iov_crlf.data,
+ mk_iov_crlf.len, MK_FALSE);
+ }
+ }
+
+ /*
+ * Configure the Stream to dispatch the headers
+ */
+
+ /* Set the IOV input stream */
+ sr->in_headers.buffer = iov;
+ sr->in_headers.bytes_total = iov->total_len;
+ sr->in_headers.cb_finished = mk_header_cb_finished;
+
+ if (sr->headers._extra_rows) {
+ /* Our main sr->stream contains the main headers (header_iov)
+ * and 'may' have already some linked data. If we have some
+ * extra headers rows we need to link this IOV right after
+ * the main header_iov.
+ */
+ struct mk_stream_input *in = &sr->in_headers_extra;
+ in->type = MK_STREAM_IOV;
+ in->dynamic = MK_FALSE;
+ in->cb_consumed = NULL;
+ in->cb_finished = cb_stream_iov_extended_free;
+ in->stream = &sr->stream;
+ in->buffer = sr->headers._extra_rows;
+ in->bytes_total = sr->headers._extra_rows->total_len;
+
+ mk_list_add_after(&sr->in_headers_extra._head,
+ &sr->in_headers._head,
+ &sr->stream.inputs);
+ }
+
+ sh->sent = MK_TRUE;
+
+ return 0;
+}
+
+void mk_header_set_http_status(struct mk_http_request *sr, int status)
+{
+ mk_bug(!sr);
+ sr->headers.status = status;
+
+ MK_TRACE("Set HTTP status = %i", status);
+}
+
+void mk_header_response_reset(struct response_headers *header)
+{
+ struct mk_iov *iov;
+
+ header->status = -1;
+ header->sent = MK_FALSE;
+ header->ranges[0] = -1;
+ header->ranges[1] = -1;
+ header->content_length = -1;
+ header->connection = 0;
+ header->transfer_encoding = -1;
+ header->last_modified = -1;
+ header->upgrade = -1;
+ header->cgi = SH_NOCGI;
+ mk_ptr_reset(&header->content_type);
+ mk_ptr_reset(&header->content_encoding);
+ header->location = NULL;
+ header->_extra_rows = NULL;
+ header->allow_methods.len = 0;
+
+ /* Initialize headers IOV */
+ iov = &header->headers_iov;
+ iov->io = (struct iovec *) &header->__iov_io;
+ iov->buf_to_free = (void *) &header->__iov_buf;
+ mk_iov_init(&header->headers_iov, MK_HEADER_IOV, 0);
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_http.c b/fluent-bit/lib/monkey/mk_server/mk_http.c
new file mode 100644
index 000000000..1e2d219de
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_http.c
@@ -0,0 +1,1638 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+//#include <regex.h>
+#include <re.h>
+
+#include <monkey/monkey.h>
+#include <monkey/mk_user.h>
+#include <monkey/mk_core.h>
+#include <monkey/mk_http.h>
+#include <monkey/mk_http_status.h>
+#include <monkey/mk_http_thread.h>
+#include <monkey/mk_clock.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_socket.h>
+#include <monkey/mk_mimetype.h>
+#include <monkey/mk_header.h>
+#include <monkey/mk_plugin.h>
+#include <monkey/mk_vhost.h>
+#include <monkey/mk_server.h>
+#include <monkey/mk_plugin_stage.h>
+
+const mk_ptr_t mk_http_method_get_p = mk_ptr_init(MK_METHOD_GET_STR);
+const mk_ptr_t mk_http_method_post_p = mk_ptr_init(MK_METHOD_POST_STR);
+const mk_ptr_t mk_http_method_head_p = mk_ptr_init(MK_METHOD_HEAD_STR);
+const mk_ptr_t mk_http_method_put_p = mk_ptr_init(MK_METHOD_PUT_STR);
+const mk_ptr_t mk_http_method_delete_p = mk_ptr_init(MK_METHOD_DELETE_STR);
+const mk_ptr_t mk_http_method_options_p = mk_ptr_init(MK_METHOD_OPTIONS_STR);
+const mk_ptr_t mk_http_method_null_p = { NULL, 0 };
+
+const mk_ptr_t mk_http_protocol_09_p = mk_ptr_init(MK_HTTP_PROTOCOL_09_STR);
+const mk_ptr_t mk_http_protocol_10_p = mk_ptr_init(MK_HTTP_PROTOCOL_10_STR);
+const mk_ptr_t mk_http_protocol_11_p = mk_ptr_init(MK_HTTP_PROTOCOL_11_STR);
+const mk_ptr_t mk_http_protocol_null_p = { NULL, 0 };
+
+/* Create a memory allocation in order to handle the request data */
+void mk_http_request_init(struct mk_http_session *session,
+ struct mk_http_request *request,
+ struct mk_server *server)
+{
+ struct mk_list *host_list = &server->hosts;
+
+ request->port = 0;
+ request->status = MK_TRUE;
+ request->uri.data = NULL;
+ request->method = MK_METHOD_UNKNOWN;
+ request->protocol = MK_HTTP_PROTOCOL_UNKNOWN;
+ request->connection.len = -1;
+ request->file_fd = -1;
+ request->file_info.size = -1;
+ request->vhost_fdt_id = 0;
+ request->vhost_fdt_hash = 0;
+ request->vhost_fdt_enabled = MK_FALSE;
+ request->host.data = NULL;
+ request->stage30_blocked = MK_FALSE;
+ request->session = session;
+ request->host_conf = mk_list_entry_first(host_list, struct mk_vhost, _head);
+ request->uri_processed.data = NULL;
+ request->real_path.data = NULL;
+ request->handler_data = NULL;
+
+ request->in_file.fd = -1;
+
+ /* Response Headers */
+ mk_header_response_reset(&request->headers);
+
+ /* Reset callbacks for headers stream */
+ mk_stream_set(&request->stream,
+ session->channel,
+ NULL,
+ NULL, NULL, NULL);
+}
+
+static inline int mk_http_point_header(mk_ptr_t *h,
+ struct mk_http_parser *parser, int key)
+{
+ struct mk_http_header *header;
+
+ header = &parser->headers[key];
+ if (header->type == key) {
+ h->data = header->val.data;
+ h->len = header->val.len;
+ return 0;
+ }
+ else {
+ h->data = NULL;
+ h->len = -1;
+ }
+
+ return -1;
+}
+
+static int mk_http_request_prepare(struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ struct mk_server *server)
+{
+ int ret;
+ int status = 0;
+ char *temp;
+ struct mk_list *hosts = &server->hosts;
+ struct mk_list *alias;
+ struct mk_http_header *header;
+
+ /*
+ * Process URI, if it contains ASCII encoded strings like '%20',
+ * it will return a new memory buffer with the decoded string, otherwise
+ * it returns NULL
+ */
+ temp = mk_utils_url_decode(sr->uri);
+
+ if (temp) {
+ sr->uri_processed.data = temp;
+ sr->uri_processed.len = strlen(temp);
+ }
+ else {
+ sr->uri_processed.data = sr->uri.data;
+ sr->uri_processed.len = sr->uri.len;
+ }
+
+ /* Always assign the default vhost' */
+ sr->host_conf = mk_list_entry_first(hosts, struct mk_vhost, _head);
+ sr->user_home = MK_FALSE;
+
+ /* Valid request URI? */
+ if (sr->uri_processed.data[0] != '/') {
+ mk_http_error(MK_CLIENT_BAD_REQUEST, cs, sr, server);
+ return MK_EXIT_OK;
+ }
+
+ /* Check if we have a Host header: Hostname ; port */
+ mk_http_point_header(&sr->host, &cs->parser, MK_HEADER_HOST);
+
+ /* Header: Connection */
+ mk_http_point_header(&sr->connection, &cs->parser, MK_HEADER_CONNECTION);
+
+ /* Header: Range */
+ mk_http_point_header(&sr->range, &cs->parser, MK_HEADER_RANGE);
+
+ /* Header: If-Modified-Since */
+ mk_http_point_header(&sr->if_modified_since,
+ &cs->parser,
+ MK_HEADER_IF_MODIFIED_SINCE);
+
+ /* HTTP/1.1 needs Host header */
+ if (!sr->host.data && sr->protocol == MK_HTTP_PROTOCOL_11) {
+ mk_http_error(MK_CLIENT_BAD_REQUEST, cs, sr, server);
+ return MK_EXIT_OK;
+ }
+
+ /* Should we close the session after this request ? */
+ mk_http_keepalive_check(cs, sr, server);
+
+ /* Content Length */
+ header = &cs->parser.headers[MK_HEADER_CONTENT_LENGTH];
+ if (header->type == MK_HEADER_CONTENT_LENGTH) {
+ sr->_content_length.data = header->val.data;
+ sr->_content_length.len = header->val.len;
+ }
+ else {
+ sr->_content_length.data = NULL;
+ }
+
+ /* Assign the first node alias */
+ alias = &sr->host_conf->server_names;
+ sr->host_alias = mk_list_entry_first(alias,
+ struct mk_vhost_alias, _head);
+
+ if (sr->host.data) {
+ /* Set the given port */
+ if (cs->parser.header_host_port > 0) {
+ sr->port = cs->parser.header_host_port;
+ }
+
+ /* Match the virtual host */
+ mk_vhost_get(sr->host, &sr->host_conf, &sr->host_alias, server);
+
+ /* Check if this virtual host have some redirection */
+ if (sr->host_conf->header_redirect.data) {
+ mk_header_set_http_status(sr, MK_REDIR_MOVED);
+ sr->headers.location = mk_string_dup(sr->host_conf->header_redirect.data);
+ sr->headers.content_length = 0;
+ sr->headers.location = NULL;
+ mk_header_prepare(cs, sr, server);
+ return 0;
+ }
+ }
+
+ /* Is requesting an user home directory ? */
+ if (server->conf_user_pub &&
+ sr->uri_processed.len > 2 &&
+ sr->uri_processed.data[1] == MK_USER_HOME) {
+
+ if (mk_user_init(cs, sr, server) != 0) {
+ mk_http_error(MK_CLIENT_NOT_FOUND, cs, sr, server);
+ return MK_EXIT_ABORT;
+ }
+ }
+
+ /* Plugins Stage 20 */
+ ret = mk_plugin_stage_run_20(cs, sr, server);
+ if (ret == MK_PLUGIN_RET_CLOSE_CONX) {
+ MK_TRACE("STAGE 20 requested close conexion");
+ return MK_EXIT_ABORT;
+ }
+
+ /* Normal HTTP process */
+ status = mk_http_init(cs, sr, server);
+
+ MK_TRACE("[FD %i] HTTP Init returning %i", cs->socket, status);
+ return status;
+}
+
+/*
+ * This function allow the core to invoke the closing connection process
+ * when some connection was not proceesed due to a premature close or similar
+ * exception, it also take care of invoke the STAGE_40 and STAGE_50 plugins events
+ */
+static void mk_request_premature_close(int http_status, struct mk_http_session *cs,
+ struct mk_server *server)
+{
+ struct mk_http_request *sr;
+ struct mk_list *sr_list = &cs->request_list;
+ struct mk_list *host_list = &server->hosts;
+
+ /*
+ * If the connection is too premature, we need to allocate a temporal session_request
+ * to do not break the plugins stages
+ */
+ if (mk_list_is_empty(sr_list) == 0) {
+ sr = &cs->sr_fixed;
+ memset(sr, 0, sizeof(struct mk_http_request));
+ mk_http_request_init(cs, sr, server);
+ mk_list_add(&sr->_head, &cs->request_list);
+ }
+ else {
+ sr = mk_list_entry_first(sr_list, struct mk_http_request, _head);
+ }
+
+ /* Raise error */
+ if (http_status > 0) {
+ if (!sr->host_conf) {
+ sr->host_conf = mk_list_entry_first(host_list,
+ struct mk_vhost, _head);
+ }
+ mk_http_error(http_status, cs, sr, server);
+
+ /* STAGE_40, request has ended */
+ mk_plugin_stage_run_40(cs, sr, server);
+ }
+
+ /* STAGE_50, connection closed and remove the http_session */
+ mk_plugin_stage_run_50(cs->socket, server);
+ mk_http_session_remove(cs, server);
+}
+
+int mk_http_handler_read(struct mk_sched_conn *conn, struct mk_http_session *cs,
+ struct mk_server *server)
+{
+ int bytes;
+ int max_read;
+ int available = 0;
+ int new_size;
+ int total_bytes = 0;
+ char *tmp = 0;
+
+#ifdef MK_HAVE_TRACE
+ int socket = conn->event.fd;
+#endif
+
+ MK_TRACE("MAX REQUEST SIZE: %i", server->max_request_size);
+
+ try_pending:
+
+ available = cs->body_size - cs->body_length;
+ if (available <= 0) {
+ /* Reallocate buffer size if pending data does not have space */
+ new_size = cs->body_size + conn->net->buffer_size;
+ if (new_size > server->max_request_size) {
+ MK_TRACE("Requested size is > mk_config->max_request_size");
+ mk_request_premature_close(MK_CLIENT_REQUEST_ENTITY_TOO_LARGE, cs,
+ server);
+ return -1;
+ }
+
+ /*
+ * Check if the body field still points to the initial body_fixed, if so,
+ * allow the new space required in body, otherwise perform a realloc over
+ * body.
+ */
+ if (cs->body == cs->body_fixed) {
+ cs->body = mk_mem_alloc(new_size + 1);
+ cs->body_size = new_size;
+ memcpy(cs->body, cs->body_fixed, cs->body_length);
+ MK_TRACE("[FD %i] New size: %i, length: %i",
+ socket, new_size, cs->body_length);
+ }
+ else {
+ MK_TRACE("[FD %i] Realloc from %i to %i",
+ socket, cs->body_size, new_size);
+ tmp = mk_mem_realloc(cs->body, new_size + 1);
+ if (tmp) {
+ cs->body = tmp;
+ cs->body_size = new_size;
+ }
+ else {
+ mk_request_premature_close(MK_SERVER_INTERNAL_ERROR, cs,
+ server);
+ return -1;
+ }
+ }
+ }
+
+ /* Read content */
+ max_read = (cs->body_size - cs->body_length);
+ bytes = mk_sched_conn_read(conn, cs->body + cs->body_length, max_read);
+ MK_TRACE("[FD %i] read %i", socket, bytes);
+
+ if (bytes == 0) {
+ MK_TRACE("[FD %i] broken pipe?", socket);
+ errno = 0;
+ return -1;
+ }
+ else if (bytes == -1) {
+ return -1;
+ }
+
+ if (bytes > max_read) {
+ MK_TRACE("[FD %i] Buffer still have data: %i",
+ socket, bytes - max_read);
+ cs->body_length += max_read;
+ cs->body[cs->body_length] = '\0';
+ total_bytes += max_read;
+
+ goto try_pending;
+ }
+ else {
+ cs->body_length += bytes;
+ cs->body[cs->body_length] = '\0';
+
+ total_bytes += bytes;
+ }
+
+ MK_TRACE("[FD %i] Retry total bytes: %i", socket, total_bytes);
+ return total_bytes;
+}
+
+/* Build error page */
+static int mk_http_error_page(char *title, mk_ptr_t *message, char *signature,
+ char **out_buf, unsigned long *out_size)
+{
+ char *temp;
+
+ *out_buf = NULL;
+
+ if (message) {
+ temp = mk_ptr_to_buf(*message);
+ }
+ else {
+ temp = mk_string_dup("");
+ }
+
+ mk_string_build(out_buf, out_size,
+ MK_REQUEST_DEFAULT_PAGE, title, temp, signature);
+ mk_mem_free(temp);
+ return 0;
+}
+
+static int mk_http_range_set(struct mk_http_request *sr, size_t file_size,
+ struct mk_server *server)
+{
+ struct response_headers *sh = &sr->headers;
+ struct mk_stream_input *in;
+
+ in = &sr->in_file;
+ in->bytes_total = file_size;
+ in->bytes_offset = 0;
+
+ if (server->resume == MK_TRUE && sr->range.data) {
+ /* yyy- */
+ if (sh->ranges[0] >= 0 && sh->ranges[1] == -1) {
+ in->bytes_offset = sh->ranges[0];
+ in->bytes_total = file_size - in->bytes_offset;
+ }
+
+ /* yyy-xxx */
+ if (sh->ranges[0] >= 0 && sh->ranges[1] >= 0) {
+ in->bytes_offset = sh->ranges[0];
+ in->bytes_total = labs(sh->ranges[1] - sh->ranges[0]) + 1;
+ }
+
+ /* -xxx */
+ if (sh->ranges[0] == -1 && sh->ranges[1] > 0) {
+ in->bytes_total = sh->ranges[1];
+ in->bytes_offset = file_size - sh->ranges[1];
+ }
+
+ if ((size_t) in->bytes_offset >= file_size ||
+ in->bytes_total > file_size) {
+ return -1;
+ }
+
+ lseek(in->fd, in->bytes_offset, SEEK_SET);
+ }
+ return 0;
+}
+
+static int mk_http_range_parse(struct mk_http_request *sr)
+{
+ int eq_pos, sep_pos, len;
+ char *buffer = 0;
+ struct response_headers *sh;
+
+ if (!sr->range.data)
+ return -1;
+
+ if ((eq_pos = mk_string_char_search(sr->range.data, '=', sr->range.len)) < 0)
+ return -1;
+
+ if (strncasecmp(sr->range.data, "Bytes", eq_pos) != 0)
+ return -1;
+
+ if ((sep_pos = mk_string_char_search(sr->range.data, '-', sr->range.len)) < 0)
+ return -1;
+
+ len = sr->range.len;
+ sh = &sr->headers;
+
+ /* =-xxx */
+ if (eq_pos + 1 == sep_pos) {
+ sh->ranges[0] = -1;
+ sh->ranges[1] = (unsigned long) atol(sr->range.data + sep_pos + 1);
+
+ if (sh->ranges[1] <= 0) {
+ return -1;
+ }
+
+ sh->content_length = sh->ranges[1];
+ return 0;
+ }
+
+ /* =yyy-xxx */
+ if ((eq_pos + 1 != sep_pos) && (len > sep_pos + 1)) {
+ buffer = mk_string_copy_substr(sr->range.data, eq_pos + 1, sep_pos);
+ sh->ranges[0] = (unsigned long) atol(buffer);
+ mk_mem_free(buffer);
+
+ buffer = mk_string_copy_substr(sr->range.data, sep_pos + 1, len);
+ sh->ranges[1] = (unsigned long) atol(buffer);
+ mk_mem_free(buffer);
+
+ if (sh->ranges[1] < 0 || (sh->ranges[0] > sh->ranges[1])) {
+ return -1;
+ }
+
+ sh->content_length = abs(sh->ranges[1] - sh->ranges[0]) + 1;
+ return 0;
+ }
+ /* =yyy- */
+ if ((eq_pos + 1 != sep_pos) && (len == sep_pos + 1)) {
+ buffer = mk_string_copy_substr(sr->range.data, eq_pos + 1, len);
+ sr->headers.ranges[0] = (unsigned long) atol(buffer);
+ mk_mem_free(buffer);
+
+ sh->content_length = (sh->content_length - sh->ranges[0]);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int mk_http_directory_redirect_check(struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ struct mk_server *server)
+{
+ int port_redirect = 0;
+ char *host;
+ char *location = 0;
+ char *real_location = 0;
+ char *protocol = "http";
+ unsigned long len;
+
+ /*
+ * We have to check if there is a slash at the end of
+ * this string. If it doesn't exist, we send a redirection header.
+ */
+ if (sr->uri_processed.data[sr->uri_processed.len - 1] == '/') {
+ return 0;
+ }
+
+ host = mk_ptr_to_buf(sr->host);
+
+ /*
+ * Add ending slash to the location string
+ */
+ location = mk_mem_alloc(sr->uri_processed.len + 2);
+ memcpy(location, sr->uri_processed.data, sr->uri_processed.len);
+ location[sr->uri_processed.len] = '/';
+ location[sr->uri_processed.len + 1] = '\0';
+
+ /* FIXME: should we done something similar for SSL = 443 */
+ if (sr->host.data && sr->port > 0) {
+ if (sr->port != server->standard_port) {
+ port_redirect = sr->port;
+ }
+ }
+
+ if (MK_SCHED_CONN_PROP(cs->conn) & MK_CAP_SOCK_TLS) {
+ protocol = "https";
+ }
+
+ if (port_redirect > 0) {
+ mk_string_build(&real_location, &len, "%s://%s:%i%s\r\n",
+ protocol, host, port_redirect, location);
+ }
+ else {
+ mk_string_build(&real_location, &len, "%s://%s%s\r\n",
+ protocol, host, location);
+ }
+
+ MK_TRACE("Redirecting to '%s'", real_location);
+ mk_mem_free(host);
+
+ mk_header_set_http_status(sr, MK_REDIR_MOVED);
+ sr->headers.content_length = 0;
+
+ mk_ptr_reset(&sr->headers.content_type);
+ sr->headers.location = real_location;
+ sr->headers.cgi = SH_NOCGI;
+ sr->headers.pconnections_left =
+ (server->max_keep_alive_request - cs->counter_connections);
+
+ mk_header_prepare(cs, sr, server);
+
+ /* we do not free() real_location as it's freed by iov */
+ mk_mem_free(location);
+ sr->headers.location = NULL;
+ return -1;
+}
+
+/* Look for some index.xxx in pathfile */
+static inline char *mk_http_index_lookup(mk_ptr_t *path_base,
+ char *buf, size_t buf_size,
+ size_t *out, size_t *bytes,
+ struct mk_server *server)
+{
+ off_t off = 0;
+ size_t len;
+ struct mk_string_line *entry;
+ struct mk_list *head;
+
+ if (!server->index_files) {
+ return NULL;
+ }
+
+ off = path_base->len;
+ memcpy(buf, path_base->data, off);
+
+ mk_list_foreach(head, server->index_files) {
+ entry = mk_list_entry(head, struct mk_string_line, _head);
+
+ len = off + entry->len + 1;
+ if (len >= buf_size) {
+ continue;
+ }
+
+ memcpy(buf + off, entry->val, entry->len);
+ buf[off + entry->len] = '\0';
+
+ if (access(buf, F_OK) == 0) {
+ MK_TRACE("Index lookup OK '%s'", buf);
+ *out = off + entry->len;
+ *bytes = path_base->len - 1;
+ return buf;
+ }
+ }
+
+ return NULL;
+}
+
+/* Turn CORK_OFF once headers are sent */
+#if defined (__linux__)
+static inline void mk_http_cb_file_on_consume(struct mk_stream_input *in,
+ long bytes)
+{
+ int ret;
+ (void) bytes;
+
+ /*
+ * This callback is invoked just once as we want to turn off
+ * the TCP Cork. We do this just overriding the callback for
+ * the file stream.
+ */
+ ret = mk_server_cork_flag(in->stream->channel->fd, TCP_CORK_OFF);
+ if (ret == -1) {
+ mk_warn("Could not set TCP_CORK/TCP_NOPUSH off");
+ }
+ MK_TRACE("[FD %i] Disable TCP_CORK/TCP_NOPUSH",
+ in->stream->channel->fd);
+ in->cb_consumed = NULL;
+}
+#endif
+
+int mk_http_init(struct mk_http_session *cs, struct mk_http_request *sr,
+ struct mk_server *server)
+{
+ int ret;
+ int ret_file;
+ struct mk_mimetype *mime;
+ struct mk_list *head;
+ struct mk_list *handlers;
+ struct mk_plugin *plugin;
+ struct mk_vhost_handler *h_handler;
+ struct mk_http_thread *mth = NULL;
+ size_t index_length;
+ size_t index_bytes;
+ char *index_path = NULL;
+
+ MK_TRACE("[FD %i] HTTP Protocol Init, session %p", cs->socket, sr);
+
+ /* Request to root path of the virtualhost in question */
+ if (sr->uri_processed.len == 1 && sr->uri_processed.data[0] == '/') {
+ sr->real_path.data = sr->host_conf->documentroot.data;
+ sr->real_path.len = sr->host_conf->documentroot.len;
+ }
+
+ /* Compose real path */
+ if (sr->user_home == MK_FALSE) {
+ int len;
+
+ len = sr->host_conf->documentroot.len + sr->uri_processed.len;
+ if (len < MK_PATH_BASE) {
+ memcpy(sr->real_path_static,
+ sr->host_conf->documentroot.data,
+ sr->host_conf->documentroot.len);
+ memcpy(sr->real_path_static + sr->host_conf->documentroot.len,
+ sr->uri_processed.data,
+ sr->uri_processed.len);
+ sr->real_path_static[len] = '\0';
+ sr->real_path.data = sr->real_path_static;
+ sr->real_path.len = len;
+ }
+ else {
+ ret = mk_buffer_cat(&sr->real_path,
+ sr->host_conf->documentroot.data,
+ sr->host_conf->documentroot.len,
+ sr->uri_processed.data,
+ sr->uri_processed.len);
+
+ if (ret < 0) {
+ MK_TRACE("Error composing real path");
+ return MK_EXIT_ERROR;
+ }
+ }
+ }
+
+ /* Check if this is related to a protocol upgrade */
+#ifdef MK_HAVE_HTTP2
+ if (cs->parser.header_connection & MK_HTTP_PARSER_CONN_UPGRADE) {
+ /* HTTP/2.0 upgrade ? */
+ if (cs->parser.header_connection & MK_HTTP_PARSER_CONN_HTTP2_SE) {
+ MK_TRACE("Connection Upgrade request: HTTP/2.0");
+ /*
+ * This is a HTTP/2.0 upgrade, we need to validate that we
+ * have at least the 'Upgrade' and 'HTTP2-Settings' headers.
+ */
+ struct mk_http_header *p;
+ p = &cs->parser.headers[MK_HEADER_HTTP2_SETTINGS];
+ if (cs->parser.header_upgrade == MK_HTTP_PARSER_UPGRADE_H2C &&
+ p->key.data) {
+ /*
+ * Switch protocols and invoke the callback upgrade to prepare
+ * the new protocol internals.
+ */
+ mk_sched_switch_protocol(cs->conn, MK_CAP_HTTP2);
+ return cs->conn->protocol->cb_upgrade(cs, sr, server);
+ }
+ else {
+ MK_TRACE("Invalid client upgrade request, skip it");
+ }
+ }
+ }
+#endif
+
+ /* Check backward directory request */
+ if (memmem(sr->uri_processed.data, sr->uri_processed.len,
+ MK_HTTP_DIRECTORY_BACKWARD,
+ sizeof(MK_HTTP_DIRECTORY_BACKWARD) - 1)) {
+ return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server);
+ }
+
+ if (sr->_content_length.data &&
+ (sr->method != MK_METHOD_POST &&
+ sr->method != MK_METHOD_PUT)) {
+ sr->_content_length.data = NULL;
+ sr->_content_length.len = 0;
+ }
+
+ ret_file = mk_file_get_info(sr->real_path.data, &sr->file_info, MK_FILE_READ);
+
+ /* Manually set the headers input streams */
+ sr->in_headers.type = MK_STREAM_IOV;
+ sr->in_headers.dynamic = MK_FALSE;
+ sr->in_headers.cb_consumed = NULL;
+ sr->in_headers.cb_finished = NULL;
+ sr->in_headers.stream = &sr->stream;
+ mk_list_add(&sr->in_headers._head, &sr->stream.inputs);
+
+ /* Plugin Stage 30: look for handlers for this request */
+ if (sr->stage30_blocked == MK_FALSE) {
+ sr->uri_processed.data[sr->uri_processed.len] = '\0';
+ handlers = &sr->host_conf->handlers;
+ mk_list_foreach(head, handlers) {
+ h_handler = mk_list_entry(head, struct mk_vhost_handler, _head);
+
+ if (re_matchp(h_handler->match,
+ sr->uri_processed.data, NULL) == -1) {
+ continue;
+ }
+
+ if (h_handler->cb) {
+ /* Create coroutine/thread context */
+ sr->headers.content_length = 0;
+ mth = mk_http_thread_create(MK_HTTP_THREAD_LIB,
+ h_handler,
+ cs, sr,
+ 0, NULL);
+ if (!mth) {
+ return -1;
+ }
+
+ mk_http_thread_start(mth);
+ return MK_EXIT_OK;
+ }
+ else {
+ if (!h_handler->handler) {
+ return mk_http_error(MK_SERVER_INTERNAL_ERROR, cs, sr,
+ server);
+ }
+ plugin = h_handler->handler;
+ sr->stage30_handler = h_handler->handler;
+ ret = plugin->stage->stage30(plugin, cs, sr,
+ h_handler->n_params,
+ &h_handler->params);
+ mk_header_prepare(cs, sr, server);
+ }
+
+ MK_TRACE("[FD %i] STAGE_30 returned %i", cs->socket, ret);
+ switch (ret) {
+ case MK_PLUGIN_RET_CONTINUE:
+ /* FIXME: PLUGINS DISABLED
+ if ((plugin->flags & MK_PLUGIN_THREAD) &&
+ plugin->stage->stage30_thread) {
+ mth = mk_http_thread_new(MK_HTTP_THREAD_PLUGIN,
+ plugin, cs, sr,
+ h_handler->n_params,
+ &h_handler->params);
+ printf("[http thread] %p\n", mth);
+ mk_http_thread_resume(mth->parent);
+ }
+ */
+ return MK_PLUGIN_RET_CONTINUE;
+ case MK_PLUGIN_RET_CLOSE_CONX:
+ if (sr->headers.status > 0) {
+ return mk_http_error(sr->headers.status, cs, sr, server);
+ }
+ else {
+ return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server);
+ }
+ case MK_PLUGIN_RET_END:
+ return MK_EXIT_OK;
+ }
+ }
+ }
+
+ /* If there is no handler and the resource don't exists, raise a 404 */
+ if (ret_file == -1) {
+ return mk_http_error(MK_CLIENT_NOT_FOUND, cs, sr, server);
+ }
+
+ /* is it a valid directory ? */
+ if (sr->file_info.is_directory == MK_TRUE) {
+ /* Send redirect header if end slash is not found */
+ if (mk_http_directory_redirect_check(cs, sr, server) == -1) {
+ MK_TRACE("Directory Redirect");
+
+ /* Redirect has been sent */
+ return -1;
+ }
+
+ /* looking for an index file */
+ char tmppath[MK_MAX_PATH];
+ index_path = mk_http_index_lookup(&sr->real_path,
+ tmppath, MK_MAX_PATH,
+ &index_length, &index_bytes,
+ server);
+ if (index_path) {
+ if (sr->real_path.data != sr->real_path_static) {
+ mk_ptr_free(&sr->real_path);
+ sr->real_path.data = mk_string_dup(index_path);
+ }
+ /* If it's static and it still fits */
+ else if (index_length < MK_PATH_BASE) {
+ memcpy(sr->real_path_static, index_path, index_length);
+ sr->real_path_static[index_length] = '\0';
+ }
+ /* It was static, but didn't fit */
+ else {
+ sr->real_path.data = mk_string_dup(index_path);
+ }
+ sr->real_path.len = index_length;
+
+ ret = mk_file_get_info(sr->real_path.data,
+ &sr->file_info, MK_FILE_READ);
+ if (ret != 0) {
+ return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server);
+ }
+
+ }
+ }
+
+#ifndef _WIN32
+ /* Check symbolic link file */
+ if (sr->file_info.is_link == MK_TRUE) {
+ if (server->symlink == MK_FALSE) {
+ return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server);
+ }
+ else {
+ int n;
+ char linked_file[MK_MAX_PATH];
+ n = readlink(sr->real_path.data, linked_file, MK_MAX_PATH);
+ if (n < 0) {
+ return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server);
+ }
+ }
+ }
+#endif
+
+ /* Plugin Stage 30: look for handlers for this request */
+ if (sr->stage30_blocked == MK_FALSE) {
+ char *uri;
+
+ if (!index_path) {
+ sr->uri_processed.data[sr->uri_processed.len] = '\0';
+ uri = sr->uri_processed.data;
+ }
+ else {
+ uri = sr->real_path.data + index_bytes;
+ }
+
+ handlers = &sr->host_conf->handlers;
+ mk_list_foreach(head, handlers) {
+ h_handler = mk_list_entry(head, struct mk_vhost_handler, _head);
+ if (re_matchp(h_handler->match, uri, NULL) == -1) {
+ continue;
+ }
+
+ plugin = h_handler->handler;
+ sr->stage30_handler = h_handler->handler;
+ ret = plugin->stage->stage30(plugin, cs, sr,
+ h_handler->n_params,
+ &h_handler->params);
+
+ MK_TRACE("[FD %i] STAGE_30 returned %i", cs->socket, ret);
+ switch (ret) {
+ case MK_PLUGIN_RET_CONTINUE:
+ return MK_PLUGIN_RET_CONTINUE;
+ case MK_PLUGIN_RET_CLOSE_CONX:
+ if (sr->headers.status > 0) {
+ return mk_http_error(sr->headers.status, cs, sr, server);
+ }
+ else {
+ return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server);
+ }
+ case MK_PLUGIN_RET_END:
+ return MK_EXIT_OK;
+ }
+ }
+ }
+
+ /*
+ * Monkey listens for PUT and DELETE methods in addition to GET, POST and
+ * HEAD, but it does not care about them, so if any plugin did not worked
+ * on it, Monkey will return error 501 (501 Not Implemented).
+ */
+ if (sr->method == MK_METHOD_PUT || sr->method == MK_METHOD_DELETE) {
+ return mk_http_error(MK_CLIENT_METHOD_NOT_ALLOWED, cs, sr, server);
+ }
+ else if (sr->method == MK_METHOD_UNKNOWN) {
+ return mk_http_error(MK_SERVER_NOT_IMPLEMENTED, cs, sr, server);
+ }
+
+ /* counter connections */
+ sr->headers.pconnections_left = (int)
+ (server->max_keep_alive_request - cs->counter_connections);
+
+ /* Set default value */
+ mk_header_set_http_status(sr, MK_HTTP_OK);
+ sr->headers.location = NULL;
+ sr->headers.content_length = 0;
+
+ /*
+ * For OPTIONS method, we let the plugin handle it and
+ * return without any content.
+ */
+ if (sr->method == MK_METHOD_OPTIONS) {
+ /* FIXME: OPTIONS NOT WORKING */
+ //sr->headers.allow_methods.data = MK_METHOD_AVAILABLE;
+ //sr->headers.allow_methods.len = strlen(MK_METHOD_AVAILABLE);
+
+ mk_ptr_reset(&sr->headers.content_type);
+ mk_header_prepare(cs, sr, server);
+ return MK_EXIT_OK;
+ }
+ else {
+ mk_ptr_reset(&sr->headers.allow_methods);
+ }
+
+ /* read permissions and check file */
+ if (sr->file_info.read_access == MK_FALSE) {
+ return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server);
+ }
+
+ /* Matching MimeType */
+ mime = mk_mimetype_find(server, &sr->real_path);
+ if (!mime) {
+ mime = server->mimetype_default;
+ }
+
+ if (sr->file_info.is_directory == MK_TRUE) {
+ return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server);
+ }
+
+ /* get file size */
+ if (sr->file_info.size == 0) {
+ return mk_http_error(MK_CLIENT_NOT_FOUND, cs, sr, server);
+ }
+
+ /* Configure some headers */
+ sr->headers.last_modified = sr->file_info.last_modification;
+ sr->headers.etag_len = snprintf(sr->headers.etag_buf,
+ MK_HEADER_ETAG_SIZE,
+ "ETag: \"%x-%zx\"\r\n",
+ (unsigned int) sr->file_info.last_modification,
+ sr->file_info.size);
+
+ if (sr->if_modified_since.data && sr->method == MK_METHOD_GET) {
+ time_t date_client; /* Date sent by client */
+ time_t date_file_server; /* Date server file */
+
+ date_client = mk_utils_gmt2utime(sr->if_modified_since.data);
+ date_file_server = sr->file_info.last_modification;
+
+ if (date_file_server <= date_client &&
+ date_client > 0) {
+ mk_header_set_http_status(sr, MK_NOT_MODIFIED);
+ mk_header_prepare(cs, sr, server);
+ return MK_EXIT_OK;
+ }
+ }
+
+ /* Object size for log and response headers */
+ sr->headers.content_length = sr->file_info.size;
+ sr->headers.real_length = sr->file_info.size;
+
+ /* Open file */
+ if (mk_likely(sr->file_info.size > 0)) {
+ sr->file_fd = mk_vhost_open(sr, server);
+ if (sr->file_fd == -1) {
+ MK_TRACE("open() failed");
+ return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server);
+ }
+ sr->in_file.fd = sr->file_fd;
+ sr->in_file.bytes_offset = 0;
+ sr->in_file.bytes_total = sr->file_info.size;
+ sr->in_file.stream = &sr->stream;
+ }
+
+ /* Process methods */
+ if (sr->method == MK_METHOD_GET || sr->method == MK_METHOD_HEAD) {
+ if (mime) {
+ sr->headers.content_type = mime->header_type;
+ }
+
+ /* HTTP Ranges */
+ if (sr->range.data != NULL && server->resume == MK_TRUE) {
+ if (mk_http_range_parse(sr) < 0) {
+ sr->headers.ranges[0] = -1;
+ sr->headers.ranges[1] = -1;
+ return mk_http_error(MK_CLIENT_BAD_REQUEST, cs, sr, server);
+ }
+ if (sr->headers.ranges[0] >= 0 || sr->headers.ranges[1] >= 0) {
+ mk_header_set_http_status(sr, MK_HTTP_PARTIAL);
+ }
+
+ /* Calc bytes to send & offset */
+ if (mk_http_range_set(sr, sr->file_info.size, server) != 0) {
+ sr->headers.content_length = -1;
+ sr->headers.ranges[0] = -1;
+ sr->headers.ranges[1] = -1;
+ return mk_http_error(MK_CLIENT_REQUESTED_RANGE_NOT_SATISF,
+ cs, sr, server);
+ }
+ }
+ }
+ else {
+ /* without content-type */
+ mk_ptr_reset(&sr->headers.content_type);
+ }
+
+ /* Send headers */
+ mk_header_prepare(cs, sr, server);
+ if (mk_unlikely(sr->headers.content_length == 0)) {
+ return 0;
+ }
+ /* Send file content */
+ if (sr->method == MK_METHOD_GET || sr->method == MK_METHOD_POST) {
+ /* Note: bytes and offsets are set after the Range check */
+ sr->in_file.type = MK_STREAM_FILE;
+ mk_stream_append(&sr->in_file, &sr->stream);
+ }
+
+ /*
+ * Enable TCP Cork for the remote socket. It will be disabled
+ * later by the file stream on the channel after send the first
+ * file bytes.
+ */
+#if defined(__linux__)
+ sr->in_file.cb_consumed = mk_http_cb_file_on_consume;
+#endif
+
+ /*
+ * Enable CORK/NO_PUSH
+ * -------------------
+ * If it was compiled for Linux, it will turn the Cork off after
+ * send the first round of bytes from the target static file.
+ *
+ * For OSX, it sets TCP_NOPUSH off after send all HTTP headers. Refer
+ * to mk_header.c for more details.
+ */
+ //mk_server_cork_flag(cs->socket, TCP_CORK_ON);
+
+ /* Start sending data to the channel */
+ return MK_EXIT_OK;
+}
+
+/*
+ * Check if a connection can stay open using
+ * the keepalive headers vars and Monkey configuration as criteria
+ */
+int mk_http_keepalive_check(struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ struct mk_server *server)
+{
+ if (server->keep_alive == MK_FALSE) {
+ return -1;
+ }
+
+ /* Default Keepalive is off */
+ if (sr->protocol == MK_HTTP_PROTOCOL_10) {
+ cs->close_now = MK_TRUE;
+ }
+ else if (sr->protocol == MK_HTTP_PROTOCOL_11) {
+ cs->close_now = MK_FALSE;
+ }
+
+ if (sr->connection.data) {
+ if (cs->parser.header_connection == MK_HTTP_PARSER_CONN_KA &&
+ sr->protocol == MK_HTTP_PROTOCOL_11) {
+ cs->close_now = MK_FALSE;
+ }
+ else if (cs->parser.header_connection == MK_HTTP_PARSER_CONN_CLOSE) {
+ cs->close_now = MK_TRUE;
+ }
+ }
+
+ /* Client has reached keep-alive connections limit */
+ if (cs->counter_connections >= server->max_keep_alive_request) {
+ cs->close_now = MK_TRUE;
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline void mk_http_request_ka_next(struct mk_http_session *cs)
+{
+ cs->body_length = 0;
+ cs->counter_connections++;
+
+ /* Update data for scheduler */
+ cs->init_time = cs->server->clock_context->log_current_utime;
+ cs->status = MK_REQUEST_STATUS_INCOMPLETE;
+
+ /* Initialize parser */
+ mk_http_parser_init(&cs->parser);
+}
+
+int mk_http_request_end(struct mk_http_session *cs, struct mk_server *server)
+{
+ int ret;
+ int status;
+ int len;
+ struct mk_http_request *sr = NULL;
+
+ if (server->max_keep_alive_request <= cs->counter_connections) {
+ cs->close_now = MK_TRUE;
+ goto shutdown;
+ }
+
+ /* Check if we have some enqueued pipeline requests */
+ ret = mk_http_parser_more(&cs->parser, cs->body_length);
+ if (ret == MK_TRUE) {
+ /* Our pipeline request limit is the same that our keepalive limit */
+ cs->counter_connections++;
+ len = (cs->body_length - cs->parser.i) -1;
+ memmove(cs->body,
+ cs->body + cs->parser.i + 1,
+ len);
+ cs->body_length = len;
+
+ /* Prepare for next one */
+ sr = mk_list_entry_first(&cs->request_list, struct mk_http_request, _head);
+ mk_http_request_free(sr, server);
+ mk_http_request_init(cs, sr, server);
+ mk_http_parser_init(&cs->parser);
+ status = mk_http_parser(sr, &cs->parser, cs->body, cs->body_length,
+ server);
+ if (status == MK_HTTP_PARSER_OK) {
+ ret = mk_http_request_prepare(cs, sr, server);
+ if (ret == MK_EXIT_ABORT) {
+ return -1;
+ }
+
+ /*
+ * Return 1 means, we still have more data to send in a different
+ * scheduler round.
+ */
+ return 1;
+ }
+ else if (status == MK_HTTP_PARSER_PENDING) {
+ return 0;
+ }
+ else if (status == MK_HTTP_PARSER_ERROR) {
+ cs->close_now = MK_TRUE;
+ }
+ }
+
+ shutdown:
+ /*
+ * We need to ask to http_keepalive if this
+ * connection can continue working or we must
+ * close it.
+ */
+ if (cs->close_now == MK_TRUE) {
+ MK_TRACE("[FD %i] No KeepAlive mode, remove", cs->conn->event.fd);
+ mk_http_session_remove(cs, server);
+ return -1;
+ }
+ else {
+ mk_http_request_free_list(cs, server);
+ mk_http_request_ka_next(cs);
+ mk_sched_conn_timeout_add(cs->conn, mk_sched_get_thread_conf());
+ return 0;
+ }
+
+ return -1;
+}
+
+void cb_stream_page_finished(struct mk_stream_input *in)
+{
+ mk_ptr_t *page = in->buffer;
+
+ mk_ptr_free(page);
+ mk_mem_free(page);
+}
+
+/* Enqueue an error response. This function always returns MK_EXIT_OK */
+int mk_http_error(int http_status, struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ struct mk_server *server)
+{
+ int ret, fd;
+ size_t count;
+ mk_ptr_t message;
+ mk_ptr_t page;
+ struct mk_vhost_error_page *entry;
+ struct mk_list *head;
+ struct file_info finfo;
+ struct mk_iov *iov;
+
+ /* This function requires monkey to be properly initialized which is not the case
+ * when it's just used to parse http requests in fluent-bit so we want it to ignore
+ * that case and let fluent-bit handle it.
+ */
+ if (server->workers == 0) {
+ return MK_EXIT_OK;
+ }
+
+ mk_header_set_http_status(sr, http_status);
+ mk_ptr_reset(&page);
+
+ /*
+ * We are nice sending error pages for clients who at least respect
+ * the especification
+ */
+ if (http_status != MK_CLIENT_LENGTH_REQUIRED &&
+ http_status != MK_CLIENT_BAD_REQUEST &&
+ http_status != MK_CLIENT_REQUEST_ENTITY_TOO_LARGE) {
+
+ /* Lookup a customized error page */
+ mk_list_foreach(head, &sr->host_conf->error_pages) {
+ entry = mk_list_entry(head, struct mk_vhost_error_page, _head);
+ if (entry->status != http_status) {
+ continue;
+ }
+
+ /* validate error file */
+ ret = mk_file_get_info(entry->real_path, &finfo, MK_FILE_READ);
+ if (ret == -1) {
+ break;
+ }
+
+ /* open file */
+ fd = open(entry->real_path, server->open_flags);
+ if (fd == -1) {
+ break;
+ }
+ /* This fd seems to be leaked, we need to verify this logic */
+
+ /* Outgoing headers */
+ sr->headers.content_length = finfo.size;
+ sr->headers.real_length = finfo.size;
+ mk_header_prepare(cs, sr, server);
+
+ /* Stream setup */
+ mk_stream_in_file(&sr->stream, &sr->in_file, sr->file_fd,
+ finfo.size, 0, NULL, NULL);
+ return MK_EXIT_OK;
+ }
+ }
+
+ mk_ptr_reset(&message);
+
+ switch (http_status) {
+ case MK_CLIENT_FORBIDDEN:
+ mk_http_error_page("Forbidden",
+ &sr->uri,
+ server->server_signature,
+ &page.data, &page.len);
+ break;
+ case MK_CLIENT_NOT_FOUND:
+ mk_string_build(&message.data, &message.len,
+ "The requested URL was not found on this server.");
+ mk_http_error_page("Not Found",
+ &message,
+ server->server_signature,
+ &page.data, &page.len);
+ mk_ptr_free(&message);
+ break;
+ case MK_CLIENT_REQUEST_ENTITY_TOO_LARGE:
+ mk_string_build(&message.data, &message.len,
+ "The request entity is too large.");
+ mk_http_error_page("Entity too large",
+ &message,
+ server->server_signature,
+ &page.data, &page.len);
+ mk_ptr_free(&message);
+ break;
+ case MK_CLIENT_METHOD_NOT_ALLOWED:
+ mk_http_error_page("Method Not Allowed",
+ &sr->uri,
+ server->server_signature,
+ &page.data, &page.len);
+ break;
+ case MK_SERVER_NOT_IMPLEMENTED:
+ mk_http_error_page("Method Not Implemented",
+ &sr->uri,
+ server->server_signature,
+ &page.data, &page.len);
+ break;
+ case MK_SERVER_INTERNAL_ERROR:
+ mk_http_error_page("Internal Server Error",
+ &sr->uri,
+ server->server_signature,
+ &page.data, &page.len);
+ break;
+ }
+
+ if (page.len > 0 && sr->method != MK_METHOD_HEAD && sr->method != MK_METHOD_UNKNOWN) {
+ sr->headers.content_length = page.len;
+ }
+ else {
+ sr->headers.content_length = 0;
+ }
+
+ sr->headers.location = NULL;
+ sr->headers.cgi = SH_NOCGI;
+ sr->headers.pconnections_left = 0;
+ sr->headers.last_modified = -1;
+
+ if (!page.data) {
+ mk_ptr_reset(&sr->headers.content_type);
+ }
+ else {
+ mk_ptr_set(&sr->headers.content_type, "Content-Type: text/html\r\n");
+ }
+
+ mk_header_prepare(cs, sr, server);
+ if (page.data) {
+ if (sr->method != MK_METHOD_HEAD) {
+ if (sr->headers._extra_rows) {
+ iov = sr->headers._extra_rows;
+ sr->in_headers_extra.bytes_total += page.len;
+ }
+ else {
+ iov = &sr->headers.headers_iov;
+ sr->in_headers.bytes_total += page.len;
+ }
+ mk_iov_add(iov, page.data, page.len, MK_TRUE);
+ }
+ else {
+ mk_mem_free(page.data);
+ }
+ }
+
+ mk_channel_write(cs->channel, &count);
+ mk_http_request_end(cs, server);
+
+ return MK_EXIT_OK;
+}
+
+/*
+ * From thread mk_sched_worker "list", remove the http_session
+ * struct information
+ */
+void mk_http_session_remove(struct mk_http_session *cs,
+ struct mk_server *server)
+{
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_plugin *handler;
+ struct mk_http_request *sr;
+
+ MK_TRACE("[FD %i] HTTP Session remove", cs->socket);
+ if (cs->_sched_init == MK_FALSE) {
+ return;
+ }
+
+ /* On session remove, make sure to cleanup any handler */
+ mk_list_foreach_safe(head, tmp, &cs->request_list) {
+ sr = mk_list_entry(head, struct mk_http_request, _head);
+ if (sr->stage30_handler) {
+ MK_TRACE("Hangup stage30 handler");
+ handler = sr->stage30_handler;
+ if (mk_unlikely(!handler->stage->stage30_hangup)) {
+ mk_warn("Plugin %s, do not implement stage30_hangup", handler->name);
+ continue;
+ }
+ handler->stage->stage30_hangup(handler, cs, sr);
+ }
+ }
+
+ if (cs->body != cs->body_fixed) {
+ mk_mem_free(cs->body);
+ }
+ mk_http_request_free_list(cs, server);
+ mk_list_del(&cs->request_list);
+
+ cs->_sched_init = MK_FALSE;
+}
+
+/* FIXME: nobody is using this */
+struct mk_http_session *mk_http_session_lookup(int socket)
+{
+ (void) socket;
+ return NULL;
+}
+
+
+/* Initialize a HTTP session (just created) */
+int mk_http_session_init(struct mk_http_session *cs, struct mk_sched_conn *conn,
+ struct mk_server *server)
+{
+ /* Alloc memory for node */
+ cs->_sched_init = MK_TRUE;
+ cs->pipelined = MK_FALSE;
+ cs->counter_connections = 0;
+ cs->close_now = MK_FALSE;
+ cs->socket = conn->event.fd;
+ cs->status = MK_REQUEST_STATUS_INCOMPLETE;
+ cs->server = server;
+
+ /* Map the channel, just for protocol-handler internal stuff */
+ cs->channel = &conn->channel;
+
+ /* Map the connection instance, required to handle exceptions */
+ cs->conn = conn;
+
+ /* creation time in unix time */
+ cs->init_time = conn->arrive_time;
+
+ /* alloc space for body content */
+ if (conn->net->buffer_size > MK_REQUEST_CHUNK) {
+ cs->body = mk_mem_alloc(conn->net->buffer_size);
+ cs->body_size = conn->net->buffer_size;
+ }
+ else {
+ /* Buffer size based in Chunk bytes */
+ cs->body = cs->body_fixed;
+ cs->body_size = MK_REQUEST_CHUNK;
+ }
+
+ /* Current data length */
+ cs->body_length = 0;
+
+ /* Init session request list */
+ mk_list_init(&cs->request_list);
+
+ /* Initialize the parser */
+ mk_http_parser_init(&cs->parser);
+
+ return 0;
+}
+
+
+void mk_http_request_free(struct mk_http_request *sr, struct mk_server *server)
+{
+ /* Let the vhost interface to handle the session close */
+ mk_vhost_close(sr, server);
+
+ if (sr->headers.location) {
+ mk_mem_free(sr->headers.location);
+ }
+
+ if (sr->uri_processed.data != sr->uri.data) {
+ mk_ptr_free(&sr->uri_processed);
+ }
+
+ if (sr->real_path.data != sr->real_path_static) {
+ mk_ptr_free(&sr->real_path);
+ }
+
+ if (sr->stream.channel) {
+ mk_stream_release(&sr->stream);
+ }
+}
+
+void mk_http_request_free_list(struct mk_http_session *cs,
+ struct mk_server *server)
+{
+ struct mk_list *head, *tmp;
+ struct mk_http_request *request;
+
+ /* sr = last node */
+ MK_TRACE("[FD %i] Free struct client_session", cs->socket);
+ mk_list_foreach_safe(head, tmp, &cs->request_list) {
+ request = mk_list_entry(head, struct mk_http_request, _head);
+ mk_list_del(&request->_head);
+
+ mk_http_request_free(request, server);
+ if (request != &cs->sr_fixed) {
+ mk_mem_free(request);
+ }
+ }
+}
+
+/*
+ * Lookup a known header or a non-known header. For unknown headers
+ * set the 'key' value wth a lowercase string
+ */
+struct mk_http_header *mk_http_header_get(int name, struct mk_http_request *req,
+ const char *key, unsigned int len)
+{
+ int i;
+ struct mk_http_parser *parser = &req->session->parser;
+ struct mk_http_header *header;
+
+ /* Known header */
+ if (name >= 0 && name < MK_HEADER_SIZEOF) {
+ return &parser->headers[name];
+ }
+
+ /* Check if want to retrieve a custom header */
+ if (name == MK_HEADER_OTHER) {
+ /* Iterate over the extra headers identified by the parser */
+ for (i = 0; i < parser->headers_extra_count; i++) {
+ header = &parser->headers_extra[i];
+ if (header->key.len != len) {
+ continue;
+ }
+
+ if (strncmp(header->key.data, key, len) == 0) {
+ return header;
+ }
+ }
+ return NULL;
+ }
+
+ return NULL;
+}
+
+/*
+ * Main callbacks for the Scheduler
+ */
+int mk_http_sched_read(struct mk_sched_conn *conn,
+ struct mk_sched_worker *worker,
+ struct mk_server *server)
+{
+ int ret;
+ int status;
+ size_t count;
+ (void) worker;
+ struct mk_http_session *cs;
+ struct mk_http_request *sr;
+
+#ifdef MK_HAVE_TRACE
+ int socket = conn->event.fd;
+#endif
+
+ cs = mk_http_session_get(conn);
+ if (cs->_sched_init == MK_FALSE) {
+ /* Create session for the client */
+ MK_TRACE("[FD %i] Create HTTP session", socket);
+ ret = mk_http_session_init(cs, conn, server);
+ if (ret == -1) {
+ return -1;
+ }
+ }
+
+ /* Invoke the read handler, on this case we only support HTTP (for now :) */
+ ret = mk_http_handler_read(conn, cs, server);
+ if (ret > 0) {
+ if (mk_list_is_empty(&cs->request_list) == 0) {
+ /* Add the first entry */
+ sr = &cs->sr_fixed;
+ mk_list_add(&sr->_head, &cs->request_list);
+ mk_http_request_init(cs, sr, server);
+ }
+ else {
+ sr = mk_list_entry_first(&cs->request_list, struct mk_http_request, _head);
+ }
+ status = mk_http_parser(sr, &cs->parser, cs->body,
+ cs->body_length, server);
+ if (status == MK_HTTP_PARSER_OK) {
+ MK_TRACE("[FD %i] HTTP_PARSER_OK", socket);
+ if (mk_http_status_completed(cs, conn) == -1) {
+ mk_http_session_remove(cs, server);
+ return -1;
+ }
+ mk_sched_conn_timeout_del(conn);
+ ret = mk_http_request_prepare(cs, sr, server);
+ }
+ else if (status == MK_HTTP_PARSER_ERROR) {
+ /* The HTTP parser may enqueued some response error */
+ if (mk_channel_is_empty(cs->channel) != 0) {
+ mk_channel_write(cs->channel, &count);
+ }
+ mk_http_session_remove(cs, server);
+ MK_TRACE("[FD %i] HTTP_PARSER_ERROR", socket);
+ return -1;
+ }
+ else {
+ MK_TRACE("[FD %i] HTTP_PARSER_PENDING", socket);
+ }
+ }
+
+ return ret;
+}
+
+/* The scheduler got a connection close event from the remote client */
+int mk_http_sched_close(struct mk_sched_conn *conn,
+ struct mk_sched_worker *sched,
+ int type, struct mk_server *server)
+{
+ struct mk_http_session *session;
+ (void) sched;
+
+#ifdef MK_HAVE_TRACE
+ MK_TRACE("[FD %i] HTTP sched close (type=%i)", conn->event.fd, type);
+#else
+ (void) type;
+#endif
+
+ /* Release resources of the requests and session */
+ session = mk_http_session_get(conn);
+ mk_http_session_remove(session, server);
+ return 0;
+}
+
+int mk_http_sched_done(struct mk_sched_conn *conn,
+ struct mk_sched_worker *worker,
+ struct mk_server *server)
+{
+ (void) worker;
+ struct mk_http_session *session;
+ struct mk_http_request *sr;
+
+ session = mk_http_session_get(conn);
+ sr = mk_list_entry_first(&session->request_list,
+ struct mk_http_request, _head);
+ mk_plugin_stage_run_40(session, sr, server);
+
+ return mk_http_request_end(session, server);
+}
+
+struct mk_sched_handler mk_http_handler = {
+ .name = "http",
+ .cb_read = mk_http_sched_read,
+ .cb_close = mk_http_sched_close,
+ .cb_done = mk_http_sched_done,
+ .sched_extra_size = sizeof(struct mk_http_session),
+ .capabilities = MK_CAP_HTTP
+};
diff --git a/fluent-bit/lib/monkey/mk_server/mk_http2.c b/fluent-bit/lib/monkey/mk_server/mk_http2.c
new file mode 100644
index 000000000..7a4f1e82b
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_http2.c
@@ -0,0 +1,384 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <inttypes.h>
+
+#include <monkey/mk_http2.h>
+#include <monkey/mk_http2_settings.h>
+#include <monkey/mk_header.h>
+#include <monkey/mk_scheduler.h>
+
+/* HTTP/2 Connection Preface */
+#define MK_HTTP2_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
+static mk_ptr_t http2_preface = {
+ .data = MK_HTTP2_PREFACE,
+ .len = sizeof(MK_HTTP2_PREFACE) - 1
+};
+
+static inline void buffer_consume(struct mk_http2_session *h2s, int bytes)
+{
+ memmove(h2s->buffer,
+ h2s->buffer + bytes,
+ h2s->buffer_length - bytes);
+
+ MK_TRACE("[h2] consume buffer length from %i to %i",
+ h2s->buffer_length, h2s->buffer_length - bytes);
+ h2s->buffer_length -= bytes;
+}
+
+static struct mk_http2_session *mk_http2_session_create()
+{
+ struct mk_http2_session *h2s;
+
+ h2s = mk_mem_alloc(sizeof(struct mk_http2_session));
+ if (!h2s) {
+ return NULL;
+ }
+ h2s->buffer = NULL;
+ h2s->buffer_length = 0;
+ h2s->buffer_size = sizeof(h2s->buffer_fixed);
+ h2s->buffer = h2s->buffer_fixed;
+ h2s->settings = MK_HTTP2_SETTINGS_DEFAULT;
+
+ return h2s;
+}
+
+/* FIXME
+static int mk_http2_session_destroy(struct mk_http2_session *h2s)
+{
+ if (h2s->buffer != h2s->buffer_fixed) {
+ mk_mem_free(h2s->buffer);
+ }
+ mk_mem_free(h2s);
+ return 0;
+}
+
+static int mk_http2_frame_header(char *buf, uint32_t length, uint8_t type,
+ uint32_t flags, void *data)
+{
+ struct mk_http2_frame *f = (struct mk_http2_frame *) buf;
+
+ f->len_type = (length << 8 | type);
+ f->flags = flags;
+ f->payload = data;
+
+ return sizeof(struct mk_http2_frame);
+}
+
+*/
+
+/* Handle an upgraded session */
+static int mk_http2_upgrade(void *cs, void *sr, struct mk_server *server)
+{
+ struct mk_http_session *s = cs;
+ struct mk_http_request *r = sr;
+ struct mk_http2_session *h2s;
+
+ mk_header_set_http_status(r, MK_INFO_SWITCH_PROTOCOL);
+ r->headers.connection = MK_HEADER_CONN_UPGRADED;
+ r->headers.upgrade = MK_HEADER_UPGRADED_H2C;
+ mk_header_prepare(s, r, server);
+
+ h2s = mk_http2_session_create();
+ if (!h2s) {
+ return -1;
+ }
+
+ h2s->status = MK_HTTP2_UPGRADED;
+ s->conn->data = h2s;
+
+ return MK_HTTP_OK;
+}
+
+/* FIXME Decode a frame header, no more... no less
+static inline void mk_http2_frame_decode_header(uint8_t *buf,
+ struct mk_http2_frame *frame)
+{
+ struct mk_http2_session *h2s;
+ (void) h2s;
+
+ frame->len_type = mk_http2_bitdec_32u(buf);
+ frame->flags = buf[4];
+ frame->stream_id = mk_http2_bitdec_stream_id(buf + 5);
+ frame->payload = buf + 9;
+
+#ifdef MK_HAVE_TRACE
+ MK_TRACE("Frame Header");
+ printf(" length=%i, type=%i, stream_id=%i\n",
+ mk_http2_frame_len(frame),
+ mk_http2_frame_type(frame),
+ frame->stream_id);
+#endif
+}
+*/
+
+static inline int mk_http2_handle_settings(struct mk_sched_conn *conn,
+ struct mk_http2_frame *frame)
+{
+ int i;
+ int frame_len;
+ int settings;
+ int setting_size = 6; /* 16 bits identifier + 32 bits value = 6 bytes */
+ uint16_t setting_id;
+ uint32_t setting_value;
+ uint8_t *p;
+ struct mk_http2_session *h2s;
+
+ h2s = conn->data;
+ frame_len = mk_http2_frame_len(frame);
+ if (frame->flags == MK_HTTP2_SETTINGS_ACK) {
+ /*
+ * Nothing to do, the peer just received our SETTINGS and it's
+ * sending an acknowledge.
+ *
+ * note: validate that frame length is zero.
+ */
+ if (frame_len > 0) {
+ /*
+ * This must he handled as a connection error, we must reply
+ * with a FRAME_SIZE_ERROR. ref:
+ *
+ * https://httpwg.github.io/specs/rfc7540.html#SETTINGS
+ */
+
+ /* FIXME: send a GOAWAY error frame */
+ MK_TRACE("FRAME SIZE ERR: %i\n", frame_len);
+ return -1;
+
+ }
+ return 0;
+ }
+
+ /*
+ * Iterate our SETTINGS payload, it may contain many entries in the
+ * following format:
+ *
+ * +-------------------------------+
+ * | Identifier (16) |
+ * +-------------------------------+-------------------------------+
+ * | Value (32) |
+ * +---------------------------------------------------------------+
+ *
+ * 48 bits = 6 bytes
+ */
+ settings = (frame_len / setting_size);
+ for (i = 0; i < settings; i++ ) {
+ /* Seek payload per SETTINGS entry */
+ p = frame->payload + (setting_size * i);
+
+ setting_id = p[0] << 8 | p[1];
+ setting_value = p[2] << 24 | p[3] << 16 | p[4] << 8 | p[5];
+ MK_H2_TRACE(conn, "[Setting] ID=%" PRIu16 " VAL=%" PRIu32,
+ setting_id, setting_value);
+
+ switch (setting_id) {
+ case MK_HTTP2_SETTINGS_HEADER_TABLE_SIZE:
+ /* unhandled */
+ break;
+ case MK_HTTP2_SETTINGS_ENABLE_PUSH:
+ if (setting_value != 0 && setting_value != 1) {
+ /* FIXME: PROTOCOL_ERROR */
+ MK_H2_TRACE(conn, "Invalid SETTINGS_ENABLE_PUSH");
+ return -1;
+ }
+ h2s->settings.enable_push = setting_value;
+ break;
+ case MK_HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:
+ if (setting_value < 64) {
+ h2s->settings.max_concurrent_streams = setting_value;
+ }
+ else {
+ h2s->settings.max_concurrent_streams = 64;
+ }
+ MK_H2_TRACE(conn, "SETTINGS MAX_CONCURRENT_STREAMS=%i",
+ setting_value);
+ break;
+ case MK_HTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
+ if (setting_value < 65535 || setting_value > 2147483647) {
+ /* FIXME: send FLOW_CONTROL_ERROR */
+ MK_H2_TRACE(conn, "Invalid INITIAL_WINDOW_SIZE");
+ return -1;
+ }
+ h2s->settings.initial_window_size = setting_value;
+ break;
+ case MK_HTTP2_SETTINGS_MAX_FRAME_SIZE:
+ if (setting_value < 16384 || setting_value > 2147483647) {
+ /* FIXME: send PROTOCOL_ERROR */
+ return -1;
+ }
+ h2s->settings.max_frame_size = setting_value;
+ break;
+ case MK_HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
+ /* Unhandled */
+ break;
+ default:
+ /*
+ * 5.5 Extending HTTP/2: ...Implementations MUST ignore unknown
+ * or unsupported values in all extensible protocol elements...
+ */
+ break;
+ }
+ }
+
+ /* FIXME // No errors, send the ACK
+ mk_http2_send_raw(conn, MK_HTTP2_SETTINGS_ACK_FRAME,
+ sizeof(MK_HTTP2_SETTINGS_ACK_FRAME) - 1);
+ */
+ return 0;
+}
+
+
+static inline int mk_http2_frame_run(struct mk_sched_conn *conn,
+ struct mk_sched_worker *worker)
+{
+ int ret;
+ struct mk_http2_frame frame;
+ struct mk_http2_session *h2s;
+ (void) worker;
+
+ h2s = conn->data;
+
+ /* Decode the frame header */
+ //FIXME mk_http2_frame_decode_header(h2s->buffer, &frame);
+
+ /* Do some validations */
+ if (h2s->buffer_length < (MK_HTTP2_HEADER_SIZE + (frame.len_type >> 8))) {
+ /* FIXME: need more data */
+ return 0;
+ }
+
+ /* Do some work based on the frame type */
+ if (mk_http2_frame_type(&frame) == MK_HTTP2_SETTINGS) {
+ ret = mk_http2_handle_settings(conn, &frame);
+ /* FIXME: send our MK_HTTP2_SETTINGS_ACK_FRAME */
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mk_http2_sched_read(struct mk_sched_conn *conn,
+ struct mk_sched_worker *worker,
+ struct mk_server *server)
+{
+ int bytes;
+ int new_size;
+ int available;
+ char *tmp;
+ struct mk_http2_session *h2s;
+ (void) worker;
+ (void) server;
+
+ h2s = conn->data;
+ available = h2s->buffer_size - h2s->buffer_length;
+ if (available == 0) {
+ new_size = h2s->buffer_size + MK_HTTP2_CHUNK;
+ if (h2s->buffer == h2s->buffer_fixed) {
+ h2s->buffer = mk_mem_alloc(new_size);
+ if (!h2s->buffer) {
+ /* FIXME: send internal server error ? */
+ return -1;
+ }
+ memcpy(h2s->buffer, h2s->buffer_fixed, h2s->buffer_length);
+ MK_TRACE("[FD %i] Buffer new size: %i, length: %i",
+ conn->event.fd, new_size, h2s->buffer_length);
+ }
+ else {
+ MK_TRACE("[FD %i] Buffer realloc from %i to %i",
+ conn->event.fd, h2s->buffer_size, new_size);
+ tmp = mk_mem_realloc(h2s->buffer, new_size);
+ if (tmp) {
+ h2s->buffer = tmp;
+ h2s->buffer_size = new_size;
+ }
+ else {
+ /* FIXME: send internal server error ? */
+ return -1;
+ }
+
+ }
+ }
+
+ /* Read the incoming data */
+ bytes = mk_sched_conn_read(conn,
+ h2s->buffer,
+ h2s->buffer_size - h2s->buffer_length);
+ if (bytes == 0) {
+ errno = 0;
+ return -1;
+ }
+ else if (bytes == -1) {
+ return -1;
+ }
+
+ h2s->buffer_length += bytes;
+
+ /* Upgraded connections from HTTP/1.x requires the preface */
+ if (h2s->status == MK_HTTP2_UPGRADED) {
+ if (h2s->buffer_length >= http2_preface.len) {
+ if (memcmp(h2s->buffer,
+ http2_preface.data, http2_preface.len) != 0) {
+ MK_H2_TRACE(conn, "Invalid HTTP/2 preface");
+ return 0;
+ }
+
+ MK_H2_TRACE(conn, "HTTP/2 preface OK");
+
+ buffer_consume(h2s, http2_preface.len);
+ h2s->status = MK_HTTP2_OK;
+
+ /* Send out our default settings
+ mk_stream_set(&h2s->stream_settings,
+ MK_STREAM_RAW,
+ &conn->channel,
+ MK_HTTP2_SETTINGS_DEFAULT_FRAME,
+ sizeof(MK_HTTP2_SETTINGS_DEFAULT_FRAME) - 1,
+ NULL,
+ NULL, NULL, NULL);
+ */
+ }
+ else {
+ /* We need more data */
+ return 0;
+ }
+ }
+
+ /* Check that we have a minimum header size */
+ if (h2s->buffer_length < MK_HTTP2_HEADER_SIZE) {
+ MK_TRACE("HEADER FRAME incomplete %i/%i bytes",
+ h2s->buffer_length, MK_HTTP2_HEADER_SIZE);
+ return 0;
+ }
+
+ /* We have at least one frame */
+ return mk_http2_frame_run(conn, worker);
+}
+
+
+struct mk_sched_handler mk_http2_handler = {
+ .name = "http2",
+ .cb_read = mk_http2_sched_read,
+ .cb_close = NULL,
+ .cb_done = NULL,
+ .cb_upgrade = mk_http2_upgrade,
+ .sched_extra_size = sizeof(struct mk_http2_session),
+ .capabilities = MK_CAP_HTTP2
+};
diff --git a/fluent-bit/lib/monkey/mk_server/mk_http_parser.c b/fluent-bit/lib/monkey/mk_server/mk_http_parser.c
new file mode 100644
index 000000000..4e7aa3161
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_http_parser.c
@@ -0,0 +1,744 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <limits.h>
+
+#include <monkey/mk_http.h>
+#include <monkey/mk_http_parser.h>
+#include <monkey/mk_http_status.h>
+
+#define mark_end() \
+ p->end = p->i; \
+ p->chars = -1;
+
+#define start_next() \
+ p->start = p->i + 1; \
+ continue
+
+#define field_len() (p->end - p->start)
+#define header_scope_eq(p, x) p->header_min = p->header_max = x
+
+struct row_entry {
+ int len;
+ const char name[32];
+};
+
+struct row_entry mk_methods_table[] = {
+ { 3, "GET" },
+ { 4, "POST" },
+ { 4, "HEAD" },
+ { 3, "PUT" },
+ { 6, "DELETE" },
+ { 7, "OPTIONS" }
+};
+
+struct row_entry mk_headers_table[] = {
+ { 6, "accept" },
+ { 14, "accept-charset" },
+ { 15, "accept-encoding" },
+ { 15, "accept-language" },
+ { 13, "authorization" },
+ { 13, "cache-control" },
+ { 6, "cookie" },
+ { 10, "connection" },
+ { 14, "content-length" },
+ { 13, "content-range" },
+ { 12, "content-type" },
+ { 4, "host" },
+ { 14, "http2-settings" },
+ { 17, "if-modified-since" },
+ { 13, "last-modified" },
+ { 19, "last-modified-since" },
+ { 5, "range" },
+ { 7, "referer" },
+ { 7, "upgrade" },
+ { 10, "user-agent" }
+};
+
+static inline void reverse_char_lookup(char *buf, char c, int len, struct mk_http_parser *p)
+{
+ int x = 0;
+ int y = 0;
+
+ x = p->i;
+ do {
+ if (buf[x - y] == c) {
+ p->i = x - y;
+ return;
+ }
+ y++;
+ } while (y < len);
+}
+
+static inline void char_lookup(char *buf, char c, int len, struct mk_http_parser *p)
+{
+ int x = 0;
+
+ x = p->i;
+ do {
+ if (buf[x] == c) {
+ p->i = x;
+ return;
+ }
+ x++;
+ } while (x < len);
+}
+
+static inline int str_searchr(char *buf, char c, int len)
+{
+ int i;
+
+ for (i = len - 1; i >= 0; i--) {
+ if (buf[i] == c) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static inline int method_lookup(struct mk_http_request *req,
+ struct mk_http_parser *p, char *buffer)
+{
+ int i = 0;
+ int len;
+
+ /* Method lenght */
+ len = field_len();
+
+ /* Point the buffer */
+ req->method = MK_METHOD_UNKNOWN;
+ req->method_p.data = buffer + p->start;
+ req->method_p.len = len;
+
+ if (p->method >= 0) {
+ if (strncmp(buffer + p->start + 1,
+ mk_methods_table[p->method].name + 1,
+ len - 1) == 0) {
+ req->method = p->method;
+ return req->method;
+ }
+ }
+
+ for (i = 0; i < MK_METHOD_SIZEOF; i++) {
+ if (len != mk_methods_table[i].len) {
+ continue;
+ }
+
+ if (strncmp(buffer + p->start, mk_methods_table[i].name, len) == 0) {
+ req->method = i;
+ return i;
+ }
+ }
+ return MK_METHOD_UNKNOWN;
+}
+
+static inline void request_set(mk_ptr_t *ptr, struct mk_http_parser *p, char *buffer)
+{
+ ptr->data = buffer + p->start;
+ ptr->len = field_len();
+}
+
+/*
+ * expected: a known & expected value in lowercase
+ * value : the expected string value in the header
+ * len : the value string length.
+ *
+ * If it matches it return zero. Otherwise -1.
+ */
+static inline int header_cmp(const char *expected, char *value, int len)
+{
+ int i = 0;
+
+ if (len >= 8) {
+ if (expected[0] != tolower(value[0])) return -1;
+ if (expected[1] != tolower(value[1])) return -1;
+ if (expected[2] != tolower(value[2])) return -1;
+ if (expected[3] != tolower(value[3])) return -1;
+ if (expected[4] != tolower(value[4])) return -1;
+ if (expected[5] != tolower(value[5])) return -1;
+ if (expected[6] != tolower(value[6])) return -1;
+ if (expected[7] != tolower(value[7])) return -1;
+ i = 8;
+ }
+
+ for (; i < len; i++) {
+ if (expected[i] != tolower(value[i])) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static inline int header_lookup(struct mk_http_parser *p, char *buffer)
+{
+ int i;
+ int len;
+ int pos;
+ long val;
+ char *endptr;
+ char *tmp;
+
+ struct mk_http_header *header;
+ struct mk_http_header *header_extra;
+ struct row_entry *h;
+
+ len = (p->header_sep - p->header_key);
+ for (i = p->header_min; i <= p->header_max && i >= 0; i++) {
+ h = &mk_headers_table[i];
+ /* Check string length first */
+ if (h->len != len) {
+ continue;
+ }
+
+ if (header_cmp(h->name + 1, buffer + p->header_key + 1, len - 1) == 0) {
+ /* We got a header match, register the header index */
+ header = &p->headers[i];
+ header->type = i;
+ header->key.data = buffer + p->header_key;
+ header->key.len = len;
+ header->val.data = buffer + p->header_val;
+ header->val.len = p->end - p->header_val;
+ p->header_count++;
+ mk_list_add(&header->_head, &p->header_list);
+
+ if (i == MK_HEADER_HOST) {
+ /* Handle a possible port number in the Host header */
+ int sep = str_searchr(header->val.data, ':', header->val.len);
+ if (sep > 0) {
+ int plen;
+ short int port_size = 6;
+ char port[6]; /* Can't use port_size to declare a stack allocated array in vc++ */
+
+ plen = header->val.len - sep - 1;
+ if (plen <= 0 || plen >= port_size) {
+ return -MK_CLIENT_BAD_REQUEST;
+ }
+ memcpy(&port, header->val.data + sep + 1, plen);
+ port[plen] = '\0';
+
+ errno = 0;
+ val = strtol(port, &endptr, 10);
+ if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+ || (errno != 0 && val == 0)) {
+ return -MK_CLIENT_BAD_REQUEST;
+ }
+
+ if (endptr == port || *endptr != '\0') {
+ return -MK_CLIENT_BAD_REQUEST;
+ }
+
+ p->header_host_port = val;
+
+ /* Re-set the Host header value without port */
+ header->val.len = sep;
+ }
+ }
+ else if (i == MK_HEADER_CONTENT_LENGTH) {
+ errno = 0;
+ val = strtol(header->val.data, &endptr, 10);
+ if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+ || (errno != 0 && val == 0)) {
+ return -MK_CLIENT_REQUEST_ENTITY_TOO_LARGE;
+ }
+ if (endptr == header->val.data) {
+ return -1;
+ }
+ if (val < 0) {
+ return -1;
+ }
+
+ p->header_content_length = val;
+ }
+ else if (i == MK_HEADER_CONNECTION) {
+ /* Check Connection: Keep-Alive */
+ if (header->val.len == sizeof(MK_CONN_KEEP_ALIVE) - 1) {
+ if (header_cmp(MK_CONN_KEEP_ALIVE,
+ header->val.data,
+ header->val.len ) == 0) {
+ p->header_connection = MK_HTTP_PARSER_CONN_KA;
+ }
+ }
+ /* Check Connection: Close */
+ else if (header->val.len == sizeof(MK_CONN_CLOSE) -1) {
+ if (header_cmp(MK_CONN_CLOSE,
+ header->val.data, header->val.len) == 0) {
+ p->header_connection = MK_HTTP_PARSER_CONN_CLOSE;
+ }
+ }
+ else {
+ p->header_connection = MK_HTTP_PARSER_CONN_UNKNOWN;
+
+ /* Try to find some known values */
+
+ /* Connection: upgrade */
+ pos = mk_string_search_n(header->val.data,
+ "Upgrade",
+ MK_STR_INSENSITIVE,
+ header->val.len);
+ if (pos >= 0) {
+ p->header_connection = MK_HTTP_PARSER_CONN_UPGRADE;
+ }
+
+ /* Connection: HTTP2-Settings */
+ pos = mk_string_search_n(header->val.data,
+ "HTTP2-Settings",
+ MK_STR_INSENSITIVE,
+ header->val.len);
+ if (pos >= 0) {
+ p->header_connection |= MK_HTTP_PARSER_CONN_HTTP2_SE;
+ }
+ }
+ }
+ else if (i == MK_HEADER_UPGRADE) {
+ if (header_cmp(MK_UPGRADE_H2C,
+ header->val.data, header->val.len) == 0) {
+ p->header_upgrade = MK_HTTP_PARSER_UPGRADE_H2C;
+ }
+ }
+
+ return 0;
+ }
+ }
+
+ /*
+ * The header_lookup did not match any known header, so we register this
+ * entry into the headers_extra array.
+ */
+ if (p->headers_extra_count < MK_HEADER_EXTRA_SIZE) {
+ header_extra = &p->headers_extra[p->headers_extra_count];
+ header_extra->key.data = tmp = (buffer + p->header_key);
+ header_extra->key.len = len;
+
+ /* Transform the header key string to lowercase */
+ for (i = 0; i < len; i++) {
+ tmp[i] = tolower(tmp[i]);
+ }
+
+ header_extra->val.data = buffer + p->header_val;
+ header_extra->val.len = p->end - p->header_val;
+ p->headers_extra_count++;
+ p->header_count++;
+ mk_list_add(&header_extra->_head, &p->header_list);
+ return 0;
+ }
+
+ /*
+ * Header is unknown and we cannot store it on our extra headers
+ * list as it's already full. Request is too large.
+ */
+ return -MK_CLIENT_REQUEST_ENTITY_TOO_LARGE;
+}
+
+/*
+ * This function is invoked everytime the parser evaluate the request is
+ * OK. Here we perform some extra validations mostly based on some logic
+ * and protocol requirements according to the data received.
+ */
+static inline int mk_http_parser_ok(struct mk_http_request *req,
+ struct mk_http_parser *p,
+ struct mk_server *server)
+{
+ /* Validate HTTP Version */
+ if (req->protocol == MK_HTTP_PROTOCOL_UNKNOWN) {
+ mk_http_error(MK_SERVER_HTTP_VERSION_UNSUP, req->session, req, server);
+ return MK_HTTP_PARSER_ERROR;
+ }
+
+ /* POST checks */
+ if (req->method == MK_METHOD_POST || req->method == MK_METHOD_PUT) {
+ /* validate Content-Length exists */
+ if (p->headers[MK_HEADER_CONTENT_LENGTH].type == 0) {
+ mk_http_error(MK_CLIENT_LENGTH_REQUIRED, req->session, req, server);
+ return MK_HTTP_PARSER_ERROR;
+ }
+ }
+
+ return MK_HTTP_PARSER_OK;
+}
+
+/*
+ * Parse the protocol and point relevant fields, don't take logic decisions
+ * based on this, just parse to locate things.
+ */
+int mk_http_parser(struct mk_http_request *req, struct mk_http_parser *p,
+ char *buffer, int buf_len, struct mk_server *server)
+{
+ int s;
+ int tmp;
+ int ret;
+ int len;
+
+ /* lazy test
+ printf("p->i=%i buf_len=%i\n",
+ p->i, buf_len);
+
+ for (s = p->i; s < buf_len; s++) {
+ if (buffer[s] == '\r') {
+ printf("CR");
+ }
+ else if (buffer[s] == '\n') {
+ printf("LF");
+ }
+ else {
+ printf("%c", buffer[s]);
+ }
+ }
+ printf("\n");
+ */
+
+ len = buf_len;
+ for (; p->i < len; p->i++, p->chars++) {
+ /* FIRST LINE LEVEL: Method, URI & Protocol */
+ if (p->level == REQ_LEVEL_FIRST) {
+ switch (p->status) {
+ case MK_ST_REQ_METHOD: /* HTTP Method */
+ if (p->chars == -1) {
+ switch (buffer[p->i]) {
+ case 'G':
+ p->method = MK_METHOD_GET;
+ break;
+ case 'P':
+ p->method = MK_METHOD_POST;
+ break;
+ case 'H':
+ p->method = MK_METHOD_HEAD;
+ break;
+ case 'D':
+ p->method = MK_METHOD_DELETE;
+ break;
+ case 'O':
+ p->method = MK_METHOD_OPTIONS;
+ break;
+ }
+ continue;
+ }
+
+ if (buffer[p->i] == ' ') {
+ mark_end();
+ p->status = MK_ST_REQ_URI;
+ if (p->end < 2) {
+ return MK_HTTP_PARSER_ERROR;
+ }
+ method_lookup(req, p, buffer);
+ start_next();
+ }
+ else {
+ if ((p->i - p->start) > 10) {
+ return MK_HTTP_PARSER_ERROR;
+ }
+ }
+ break;
+ case MK_ST_REQ_URI: /* URI */
+ if (buffer[p->i] == ' ') {
+ mark_end();
+ p->status = MK_ST_REQ_PROT_VERSION;
+ if (field_len() < 1) {
+ return MK_HTTP_PARSER_ERROR;
+ }
+ request_set(&req->uri, p, buffer);
+ start_next();
+ }
+ else if (buffer[p->i] == '?') {
+ mark_end();
+ request_set(&req->uri, p, buffer);
+ p->status = MK_ST_REQ_QUERY_STRING;
+ start_next();
+ }
+ else if (buffer[p->i] == '\r' || buffer[p->i] == '\n') {
+ mk_http_error(MK_CLIENT_BAD_REQUEST, req->session,
+ req, server);
+ return MK_HTTP_PARSER_ERROR;
+ }
+ break;
+ case MK_ST_REQ_QUERY_STRING: /* Query string */
+ char_lookup(buffer, '\n', len, p);
+
+ if (buffer[p->i] == '\n') {
+ reverse_char_lookup(buffer, ' ', p->i, p);
+ }
+
+ if (buffer[p->i] == ' ') {
+ mark_end();
+ request_set(&req->query_string, p, buffer);
+ p->status = MK_ST_REQ_PROT_VERSION;
+ start_next();
+ }
+ else if (buffer[p->i] == '\r' || buffer[p->i] == '\n') {
+ mk_http_error(MK_CLIENT_BAD_REQUEST, req->session,
+ req, server);
+ return MK_HTTP_PARSER_ERROR;
+ }
+ break;
+ case MK_ST_REQ_PROT_VERSION: /* Protocol Version */
+ /*
+ * Most of the time we already have the string version in our
+ * buffer, for that case try to match the version and avoid
+ * loop rounds.
+ */
+ if (p->start + 6 >= p->i) {
+ continue;
+ }
+
+ tmp = p->start;
+ if (buffer[tmp] == 'H' &&
+ buffer[tmp + 1] == 'T' &&
+ buffer[tmp + 2] == 'T' &&
+ buffer[tmp + 3] == 'P' &&
+ buffer[tmp + 4] == '/' &&
+ buffer[tmp + 5] == '1' &&
+ buffer[tmp + 6] == '.') {
+
+ request_set(&req->protocol_p, p, buffer);
+ req->protocol_p.len = 8;
+ mk_http_set_minor_version(buffer[tmp + 7]);
+ }
+ else {
+ mk_http_error(MK_SERVER_HTTP_VERSION_UNSUP,
+ req->session, req, server);
+ return MK_HTTP_PARSER_ERROR;
+ }
+ p->status = MK_ST_FIRST_CONTINUE;
+ break;
+ case MK_ST_FIRST_CONTINUE:
+ if (buffer[p->i] == '\r') {
+ p->status = MK_ST_FIRST_FINALIZING;
+ }
+ else {
+ return MK_HTTP_PARSER_ERROR;
+ }
+ break;
+ case MK_ST_FIRST_FINALIZING: /* New Line */
+ if (buffer[p->i] == '\n') {
+ p->level = REQ_LEVEL_CONTINUE;
+ start_next();
+ }
+ else {
+ return MK_HTTP_PARSER_ERROR;
+ }
+ break;
+ case MK_ST_BLOCK_END:
+ if (buffer[p->i] == '\n') {
+ return mk_http_parser_ok(req, p, server);
+ }
+ else {
+ return MK_HTTP_PARSER_ERROR;
+ }
+ break;
+ };
+ }
+ else if (p->level == REQ_LEVEL_CONTINUE) {
+ if (buffer[p->i] == '\r') {
+ p->level = REQ_LEVEL_FIRST;
+ p->status = MK_ST_BLOCK_END;
+ }
+ else {
+ p->level = REQ_LEVEL_HEADERS;
+ p->status = MK_ST_HEADER_KEY;
+ p->chars = 0;
+ }
+ }
+ /* HEADERS: all headers stuff */
+ if (p->level == REQ_LEVEL_HEADERS) {
+ /* Expect a Header key */
+ if (p->status == MK_ST_HEADER_KEY) {
+ if (buffer[p->i] == '\r') {
+ if (p->chars == 0) {
+ p->level = REQ_LEVEL_END;
+ start_next();
+ }
+ else {
+ return MK_HTTP_PARSER_ERROR;
+ }
+ }
+
+ if (p->chars == 0) {
+ /*
+ * We reach the start of a Header row, lets catch the most
+ * probable header.
+ *
+ * The goal of this 'first row character lookup', is to define a
+ * small range set of probable headers comparison once we catch
+ * a header end.
+ */
+ s = tolower(buffer[p->i]);
+ switch (s) {
+ case 'a':
+ p->header_min = MK_HEADER_ACCEPT;
+ p->header_max = MK_HEADER_AUTHORIZATION;
+ break;
+ case 'c':
+ p->header_min = MK_HEADER_CACHE_CONTROL;
+ p->header_max = MK_HEADER_CONTENT_TYPE;
+ break;
+ case 'h':
+ p->header_min = MK_HEADER_HOST;
+ p->header_max = MK_HEADER_HTTP2_SETTINGS;
+ break;
+ case 'i':
+ header_scope_eq(p, MK_HEADER_IF_MODIFIED_SINCE);
+ break;
+ case 'l':
+ p->header_min = MK_HEADER_LAST_MODIFIED;
+ p->header_max = MK_HEADER_LAST_MODIFIED_SINCE;
+ break;
+ case 'r':
+ p->header_min = MK_HEADER_RANGE;
+ p->header_max = MK_HEADER_REFERER;
+ break;
+ case 'u':
+ p->header_min = MK_HEADER_UPGRADE;
+ p->header_max = MK_HEADER_USER_AGENT;
+ break;
+ default:
+ p->header_key = -1;
+ p->header_sep = -1;
+ p->header_min = -1;
+ p->header_max = -1;
+ };
+ p->header_key = p->i;
+ continue;
+ }
+
+ /* Found key/value separator */
+ char_lookup(buffer, ':', len, p);
+ if (buffer[p->i] == ':') {
+ /* Set the key/value middle point */
+ p->header_sep = p->i;
+
+ /* validate length */
+ mark_end();
+ if (field_len() < 1) {
+ return MK_HTTP_PARSER_ERROR;
+ }
+
+ /* Wait for a value */
+ p->status = MK_ST_HEADER_VALUE;
+ start_next();
+ }
+ }
+ /* Parsing the header value */
+ else if (p->status == MK_ST_HEADER_VALUE) {
+ /* Trim left, set starts only when found something != ' ' */
+ if (buffer[p->i] == '\r' || buffer[p->i] == '\n') {
+ return MK_HTTP_PARSER_ERROR;
+ }
+ else if (buffer[p->i] != ' ') {
+ p->status = MK_ST_HEADER_VAL_STARTS;
+ p->start = p->header_val = p->i;
+ }
+ continue;
+ }
+ /* New header row starts */
+ else if (p->status == MK_ST_HEADER_VAL_STARTS) {
+ /* Maybe there is no more headers and we reach the end ? */
+ if (buffer[p->i] == '\r') {
+ mark_end();
+ if (field_len() <= 0) {
+ return MK_HTTP_PARSER_ERROR;
+ }
+
+ /*
+ * A header row has ended, lets lookup the header and populate
+ * our headers table index.
+ */
+ ret = header_lookup(p, buffer);
+ if (ret != 0) {
+ if (ret < -1) {
+ mk_http_error(-ret, req->session, req, server);
+ }
+ return MK_HTTP_PARSER_ERROR;
+ }
+
+ /* Try to catch next LF */
+ if (p->i + 1 < len) {
+ if (buffer[p->i + 1] == '\n') {
+ p->i++;
+ p->status = MK_ST_HEADER_KEY;
+ p->chars = -1;
+ start_next();
+ }
+ }
+
+ p->status = MK_ST_HEADER_END;
+ start_next();
+ }
+ else if (buffer[p->i] == '\n' && buffer[p->i - 1] != '\r') {
+ return MK_HTTP_PARSER_ERROR;
+ }
+ }
+ else if (p->status == MK_ST_HEADER_END) {
+ if (buffer[p->i] == '\n') {
+ p->status = MK_ST_HEADER_KEY;
+ p->chars = -1;
+ start_next();
+ }
+ else {
+ return MK_HTTP_PARSER_ERROR;
+ }
+ }
+ }
+ else if (p->level == REQ_LEVEL_END) {
+ if (buffer[p->i] == '\n') {
+ if (p->header_content_length > 0) {
+ p->level = REQ_LEVEL_BODY;
+ p->chars = -1;
+ start_next();
+ }
+ else {
+ return mk_http_parser_ok(req, p, server);
+ }
+ }
+ else {
+ return MK_HTTP_PARSER_ERROR;
+ }
+ }
+ else if (p->level == REQ_LEVEL_BODY) {
+ /*
+ * Reaching this level can means two things:
+ *
+ * - A Pipeline Request
+ * - A Body content (POST/PUT methods)
+ */
+ if (p->header_content_length > 0) {
+
+ p->body_received = len - p->start;
+ if ((len - p->start) < p->header_content_length) {
+ return MK_HTTP_PARSER_PENDING;
+ }
+
+ /* Cut off */
+ p->i += p->body_received;
+ req->data.len = p->body_received;
+ req->data.data = (buffer + p->start);
+ }
+ return mk_http_parser_ok(req, p, server);
+ }
+ }
+
+ return MK_HTTP_PARSER_PENDING;
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_http_thread.c b/fluent-bit/lib/monkey/mk_server/mk_http_thread.c
new file mode 100644
index 000000000..d3c606f3a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_http_thread.c
@@ -0,0 +1,290 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2016 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_info.h>
+#include <monkey/mk_plugin.h>
+#include <monkey/mk_thread.h>
+#include <monkey/mk_net.h>
+#include <monkey/mk_vhost.h>
+#include <monkey/mk_http_thread.h>
+
+#include <stdlib.h>
+
+/*
+ * libco do not support parameters in the entrypoint function due to the
+ * complexity of implementation in terms of architecture and compiler, but
+ * it provide a workaround using a global structure as a middle entry-point
+ * that achieve the same stuff.
+ */
+struct mk_http_libco_params {
+ int type;
+ struct mk_vhost_handler *handler;
+ struct mk_http_session *session;
+ struct mk_http_request *request;
+ int n_params;
+ struct mk_list *params;
+ struct mk_thread *th;
+};
+
+pthread_once_t mk_http_thread_initialize_tls_once_flag = PTHREAD_ONCE_INIT;
+
+MK_TLS_DEFINE(struct mk_http_libco_params, mk_http_thread_libco_params);
+MK_TLS_DEFINE(struct mk_thread, mk_thread);
+
+/* This function could return NULL if the process runs out of memory, in that
+ * case failure is imminent.
+ */
+static inline struct mk_http_libco_params *thread_get_libco_params()
+{
+ struct mk_http_libco_params *libco_params;
+
+ libco_params = MK_TLS_GET(mk_http_thread_libco_params);
+
+ if (libco_params == NULL) {
+ libco_params = mk_mem_alloc_z(sizeof(struct mk_http_libco_params));
+
+ if (libco_params == NULL) {
+ mk_err("libco thread params could not be allocated.");
+ }
+
+ MK_TLS_SET(mk_http_thread_libco_params, libco_params);
+ }
+
+ return libco_params;
+}
+
+static void mk_http_thread_initialize_tls_once()
+{
+ MK_TLS_INIT(mk_http_thread_libco_params);
+ MK_TLS_INIT(mk_thread);
+}
+
+void mk_http_thread_initialize_tls()
+{
+ pthread_once(&mk_http_thread_initialize_tls_once_flag,
+ mk_http_thread_initialize_tls_once);
+}
+
+static inline void thread_cb_init_vars()
+{
+ struct mk_http_libco_params *libco_params;
+ struct mk_vhost_handler *handler;
+ struct mk_http_session *session;
+ struct mk_http_request *request;
+ int close;
+ int type;
+ struct mk_http_thread *mth;
+ struct mk_thread *th;
+
+ libco_params = thread_get_libco_params();
+
+ type = libco_params->type;
+ handler = libco_params->handler;
+ session = libco_params->session;
+ request = libco_params->request;
+ th = libco_params->th;
+
+ /*
+ * Until this point the th->callee already set the variables, so we
+ * wait until the core wanted to resume so we really trigger the
+ * output callback.
+ */
+ co_switch(th->caller);
+
+ if (type == MK_HTTP_THREAD_LIB) {
+ /* Invoke the handler callback */
+ handler->cb(request, handler->data);
+
+ /*
+ * Once the callback finished, we need to sanitize the connection
+ * so other further requests can be processed.
+ */
+ int ret;
+ struct mk_sched_worker *sched;
+ struct mk_channel *channel;
+
+ channel = request->session->channel;
+ sched = mk_sched_get_thread_conf();
+
+ MK_EVENT_NEW(channel->event);
+ ret = mk_event_add(sched->loop,
+ channel->fd,
+ MK_EVENT_CONNECTION,
+ MK_EVENT_READ, channel->event);
+ if (ret == -1) {
+ //return -1;
+ }
+
+ /* Save temporal session */
+ mth = request->thread;
+
+ /*
+ * Finalize request internally, if ret == -1 means we should
+ * ask to shutdown the connection.
+ */
+ ret = mk_http_request_end(session, session->server);
+ if (ret == -1) {
+ close = MK_TRUE;
+ }
+ else {
+ close = MK_FALSE;
+ }
+ mk_http_thread_purge(mth, close);
+
+ /* Return control to caller */
+ mk_thread_yield(th);
+ }
+ else if (type == MK_HTTP_THREAD_PLUGIN) {
+ /* FIXME: call plugin handler callback with params */
+ }
+}
+
+static inline void thread_params_set(struct mk_thread *th,
+ int type,
+ struct mk_vhost_handler *handler,
+ struct mk_http_session *session,
+ struct mk_http_request *request,
+ int n_params,
+ struct mk_list *params)
+{
+ struct mk_http_libco_params *libco_params;
+
+ libco_params = thread_get_libco_params();
+
+ /* Callback parameters in order */
+ libco_params->type = type;
+ libco_params->handler = handler;
+ libco_params->session = session;
+ libco_params->request = request;
+ libco_params->n_params = n_params;
+ libco_params->params = params;
+ libco_params->th = th;
+
+ co_switch(th->callee);
+}
+
+struct mk_http_thread *mk_http_thread_create(int type,
+ struct mk_vhost_handler *handler,
+ struct mk_http_session *session,
+ struct mk_http_request *request,
+ int n_params,
+ struct mk_list *params)
+{
+ size_t stack_size;
+ struct mk_thread *th = NULL;
+ struct mk_http_thread *mth;
+ struct mk_sched_worker *sched;
+
+ sched = mk_sched_get_thread_conf();
+ if (!sched) {
+ return NULL;
+ }
+
+ th = mk_thread_new(sizeof(struct mk_http_thread), NULL);
+ if (!th) {
+ return NULL;
+ }
+
+ mth = (struct mk_http_thread *) MK_THREAD_DATA(th);
+ if (!mth) {
+ return NULL;
+ }
+
+ mth->session = session;
+ mth->request = request;
+ mth->parent = th;
+ mth->close = MK_FALSE;
+ request->thread = mth;
+ mk_list_add(&mth->_head, &sched->threads);
+
+ th->caller = co_active();
+ th->callee = co_create(MK_THREAD_STACK_SIZE,
+ thread_cb_init_vars, &stack_size);
+
+#ifdef MK_HAVE_VALGRIND
+ th->valgrind_stack_id = VALGRIND_STACK_REGISTER(th->callee,
+ ((char *)th->callee) + stack_size);
+#endif
+
+ /* Workaround for makecontext() */
+ thread_params_set(th, type, handler, session, request, n_params, params);
+
+ return mth;
+}
+
+/*
+ * Move a http thread context from sched->thread to sched->threads_purge list.
+ * On this way the scheduler will release or reasign the resource later.
+ */
+int mk_http_thread_purge(struct mk_http_thread *mth, int close)
+{
+ struct mk_sched_worker *sched;
+
+ sched = mk_sched_get_thread_conf();
+ if (!sched) {
+ return -1;
+ }
+
+ mth->close = close;
+ mk_list_del(&mth->_head);
+ mk_list_add(&mth->_head, &sched->threads_purge);
+
+ return 0;
+}
+
+int mk_http_thread_destroy(struct mk_http_thread *mth)
+{
+ struct mk_thread *th;
+
+ /* Unlink from scheduler thread list */
+ mk_list_del(&mth->_head);
+
+ /* release original memory context */
+ th = mth->parent;
+ mth->session->channel->event->type = MK_EVENT_CONNECTION;
+ mk_thread_destroy(th);
+
+ return 0;
+}
+
+int mk_http_thread_event(struct mk_event *event)
+{
+ struct mk_sched_conn *conn = (struct mk_sched_conn *) event;
+
+ /*
+ struct mk_thread *th;
+ struct mk_http_thread *mth;
+
+ th = conn->channel.thread;
+ mth = (struct mk_http_thread *) MK_THREAD_DATA(th);
+ */
+
+ mk_thread_resume(conn->channel.thread);
+ return 0;
+}
+
+/*
+ * Start the co-routine: invoke coroutine callback and start processing
+ * data flush requests.
+ */
+int mk_http_thread_start(struct mk_http_thread *mth)
+{
+ mk_http_thread_resume(mth);
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_kernel.c b/fluent-bit/lib/monkey/mk_server/mk_kernel.c
new file mode 100644
index 000000000..cc69e96c5
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_kernel.c
@@ -0,0 +1,165 @@
+/*-*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/monkey.h>
+#include <monkey/mk_core.h>
+#include <monkey/mk_kernel.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_server.h>
+#include <monkey/mk_scheduler.h>
+
+#include <ctype.h>
+
+#ifndef _WIN32
+#include <sys/utsname.h>
+
+int mk_kernel_version()
+{
+ int a, b, c;
+ int len;
+ int pos;
+ char *p, *t;
+ char *tmp;
+ struct utsname uts;
+
+ if (uname(&uts) == -1) {
+ mk_libc_error("uname");
+ }
+ len = strlen(uts.release);
+
+ /* Fixme: this don't support Linux Kernel 10.x.x :P */
+ a = (*uts.release - '0');
+
+ /* Second number */
+ p = (uts.release) + 2;
+ pos = mk_string_char_search(p, '.', len - 2);
+ if (pos <= 0) {
+ /* Some Debian systems uses a different notation, e.g: 3.14-2-amd64 */
+ pos = mk_string_char_search(p, '-', len - 2);
+ if (pos <= 0) {
+ return -1;
+ }
+ }
+
+ tmp = mk_string_copy_substr(p, 0, pos);
+ if (!tmp) {
+ return -1;
+ }
+ b = atoi(tmp);
+ mk_mem_free(tmp);
+
+ /* Last number (it needs filtering) */
+ t = p = p + pos + 1;
+ do {
+ t++;
+ } while (isdigit(*t));
+
+ tmp = mk_string_copy_substr(p, 0, t - p);
+ if (!tmp) {
+ return -1;
+ }
+ c = atoi(tmp);
+ mk_mem_free(tmp);
+
+ MK_TRACE("Kernel detected: %i.%i.%i", a, b, c);
+ return MK_KERNEL_VERSION(a, b, c);
+}
+
+/* Detect specific Linux Kernel features that we may use */
+int mk_kernel_features(int version)
+{
+ int flags = 0;
+
+ /*
+ * TCP Auto Corking (disabled by #175)
+ * -----------------------------------
+ * I found that running some benchmarks on Linux 3.16 with
+ * tcp_autocorking enabled, it lead to lower performance, looks like
+ * a manual cork fits better for our needs.
+ *
+ * I think there is something wrong that we need to clarify, by now
+ * I've logged the following issue:
+ *
+ * https://github.com/monkey/monkey/issues/175
+ *
+ if (mk_kernel_runver >= MK_KERNEL_VERSION(3, 14, 0) &&
+ mk_socket_tcp_autocorking() == MK_TRUE) {
+ flags |= MK_KERNEL_TCP_AUTOCORKING;
+ }
+ */
+
+ /* SO_REUSEPORT */
+ if (version >= MK_KERNEL_VERSION(3, 9, 0)) {
+ flags |= MK_KERNEL_SO_REUSEPORT;
+ }
+
+ /* TCP_FASTOPEN */
+ if (version >= MK_KERNEL_VERSION(3, 7, 0)) {
+ flags |= MK_KERNEL_TCP_FASTOPEN;
+ }
+
+ return flags;
+}
+
+int mk_kernel_features_print(char *buffer, size_t size,
+ struct mk_server *server)
+{
+ int offset = 0;
+ int features = 0;
+
+ if (server->kernel_features & MK_KERNEL_TCP_FASTOPEN) {
+ offset += snprintf(buffer, size - offset, "%s", "TCP_FASTOPEN ");
+ features++;
+ }
+
+ if (server->kernel_features & MK_KERNEL_SO_REUSEPORT) {
+ if (server->scheduler_mode == MK_SCHEDULER_FAIR_BALANCING) {
+ offset += snprintf(buffer + offset, size - offset,
+ "%s!%s", ANSI_BOLD ANSI_RED, ANSI_RESET);
+ }
+ offset += snprintf(buffer + offset, size - offset, "%s", "SO_REUSEPORT ");
+ features++;
+ }
+
+ if (server->kernel_features & MK_KERNEL_TCP_AUTOCORKING) {
+ snprintf(buffer + offset, size - offset, "%s", "TCP_AUTOCORKING ");
+ features++;
+ }
+
+ return features;
+}
+#else
+/* We still need to determine if this can be safely ignored or what do we need to do here */
+
+int mk_kernel_version()
+{
+ return 1;
+}
+
+int mk_kernel_features(int version)
+{
+ return 0;
+}
+
+int mk_kernel_features_print(char* buffer, size_t size,
+ struct mk_server* server)
+{
+ return 0;
+}
+#endif
diff --git a/fluent-bit/lib/monkey/mk_server/mk_lib.c b/fluent-bit/lib/monkey/mk_server/mk_lib.c
new file mode 100644
index 000000000..c29400864
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_lib.c
@@ -0,0 +1,796 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <mk_core/mk_pthread.h>
+
+#include <monkey/mk_lib.h>
+#include <monkey/monkey.h>
+#include <monkey/mk_stream.h>
+#include <monkey/mk_thread.h>
+#include <monkey/mk_scheduler.h>
+#include <monkey/mk_fifo.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_tls.h>
+
+#define config_eq(a, b) strcasecmp(a, b)
+
+static inline int bool_val(char *v)
+{
+ if (strcasecmp(v, "On") == 0 || strcasecmp(v, "Yes") == 0) {
+ return MK_TRUE;
+ }
+ else if (strcasecmp(v, "Off") == 0 || strcasecmp(v, "No") == 0) {
+ return MK_FALSE;
+ }
+
+ return -1;
+}
+
+mk_ctx_t *mk_create()
+{
+ mk_ctx_t *ctx;
+
+ ctx = mk_mem_alloc_z(sizeof(mk_ctx_t));
+ if (!ctx) {
+ return NULL;
+ }
+
+ /* Create Monkey server instance */
+ ctx->server = mk_server_create();
+
+ /*
+ * FIFO
+ * ====
+ * Before to prepare the background service, we create a MK_FIFO interface
+ * for further communication between the caller (user) and HTTP end-point
+ * callbacks.
+ */
+ ctx->fifo = mk_fifo_create(NULL, ctx->server);
+ ctx->fifo->key = &mk_server_fifo_key;
+
+ /*
+ * FIFO: Set workers callback associated to the Monkey scheduler to prepare them
+ * before to enter the event loop
+ */
+ mk_sched_worker_cb_add(ctx->server, mk_fifo_worker_setup, ctx->fifo);
+ return ctx;
+}
+
+int mk_destroy(mk_ctx_t *ctx)
+{
+ mk_fifo_destroy(ctx->fifo);
+ mk_mem_free(ctx);
+
+ return 0;
+}
+
+static inline int mk_lib_yield(mk_request_t *req)
+{
+ int ret;
+ struct mk_thread *th;
+ struct mk_channel *channel;
+ struct mk_sched_worker *sched;
+
+ sched = mk_sched_get_thread_conf();
+ if (!sched) {
+ return -1;
+ }
+
+ th = MK_TLS_GET(mk_thread);
+ channel = req->session->channel;
+
+ channel->thread = th;
+
+ ret = mk_event_add(sched->loop,
+ channel->fd,
+ MK_EVENT_THREAD,
+ MK_EVENT_WRITE, channel->event);
+ if (ret == -1) {
+ return -1;
+ }
+
+ /* Just wait */
+ mk_thread_yield(th);
+
+ if (channel->event->status & MK_EVENT_REGISTERED) {
+ /* We got a notification, remove the event registered
+ ret = mk_event_add(sched->loop,
+ channel->fd,
+ MK_EVENT_CONNECTION,
+ MK_EVENT_READ, channel->event);
+ mk_thread_yield(th);
+ */
+
+ ret = mk_event_del(sched->loop, channel->event);
+ }
+
+ return 0;
+}
+
+static void mk_lib_worker(void *data)
+{
+ int fd;
+ int bytes;
+ uint64_t val;
+ struct mk_server *server;
+ struct mk_event *event;
+
+ mk_ctx_t *ctx = data;
+ server = ctx->server;
+
+ /* Start the service */
+ mk_server_setup(server);
+ mk_server_loop(server);
+
+ /*
+ * Give a second to the parent context to avoid consume an event
+ * we should not read at the moment (SIGNAL_START).
+ */
+ sleep(1);
+
+ /* Wait for events */
+ mk_event_wait(server->lib_evl);
+ mk_event_foreach(event, server->lib_evl) {
+ fd = event->fd;
+
+#ifdef _WIN32
+ bytes = recv(fd, &val, sizeof(uint64_t), MSG_WAITALL);
+#else
+ bytes = read(fd, &val, sizeof(uint64_t));
+#endif
+
+ if (bytes <= 0) {
+ return;
+ }
+
+ if (val == MK_SERVER_SIGNAL_STOP) {
+ break;
+ }
+ }
+
+ mk_event_loop_destroy(server->lib_evl);
+ mk_exit_all(server);
+ pthread_kill(pthread_self(), 0);
+
+ return;
+}
+
+int mk_start(mk_ctx_t *ctx)
+{
+ int fd;
+ int bytes;
+ int ret;
+ uint64_t val;
+ pthread_t tid;
+ struct mk_event *event;
+ struct mk_server *server;
+
+ server = ctx->server;
+
+ ret = mk_utils_worker_spawn(mk_lib_worker, ctx, &tid);
+ if (ret == -1) {
+ return -1;
+ }
+ ctx->worker_tid = tid;
+
+ /* Wait for the started signal so we can return to the caller */
+ mk_event_wait(server->lib_evl_start);
+ mk_event_foreach(event, server->lib_evl_start) {
+ fd = event->fd;
+
+ /* When using libevent _mk_event_channel_create creates a unix socket
+ * instead of a pipe and windows doesn't us calling read / write on a
+ * socket instead of recv / send
+ */
+#ifdef _WIN32
+ bytes = recv(fd, &val, sizeof(uint64_t), MSG_WAITALL);
+#else
+ bytes = read(fd, &val, sizeof(uint64_t));
+#endif
+
+ if (bytes <= 0) {
+ ret = -1;
+ break;
+ }
+
+ if (val == MK_SERVER_SIGNAL_START) {
+ ret = 0;
+ break;
+ }
+ else {
+ ret = -1;
+ break;
+ }
+ }
+
+ mk_event_loop_destroy(server->lib_evl_start);
+ if (ret == -1) {
+ mk_stop(ctx);
+ }
+
+ return ret;
+}
+
+int mk_stop(mk_ctx_t *ctx)
+{
+ int n;
+ uint64_t val;
+ int8_t scheduler_mode ;
+ struct mk_server *server = ctx->server;
+
+ /* Keep track of the scheduler mode on stack, since the
+ * the worker may free the server before we need the info.
+ */
+ scheduler_mode = server->scheduler_mode;
+
+ val = MK_SERVER_SIGNAL_STOP;
+
+ /* Send a stop signal to the main lib channel to abort.
+ *
+ * MK_SCHEDULER_FAIR_BALANCING: this signal will be
+ * consumed by mk_server_loop_balancer.
+ *
+ * MK_SCHEDULER_REUSEPORT: this signal will be consumed
+ * by mk_lib_worker.
+ */
+#ifdef _WIN32
+ n = send(server->lib_ch_manager[1], &val, sizeof(val), 0);
+#else
+ n = write(server->lib_ch_manager[1], &val, sizeof(val));
+#endif
+ if (n <= 0) {
+ perror("write");
+ return -1;
+ }
+
+ /* In MK_SCHEDULER_FAIR_BALANCING mode, we need one more
+ * stop signal to abort mk_lib_worker.
+ */
+ if (scheduler_mode == MK_SCHEDULER_FAIR_BALANCING) {
+ /* Give mk_server_loop_balancer time to clean up. */
+ sleep(1);
+
+ /* Send a signal for mk_lib_worker to abort */
+#ifdef _WIN32
+ n = send(server->lib_ch_manager[1], &val, sizeof(val), 0);
+#else
+ n = write(server->lib_ch_manager[1], &val, sizeof(val));
+#endif
+ if (n <= 0) {
+ perror("write");
+ return -1;
+ }
+ }
+
+ /* Wait for the child thread to exit */
+ pthread_join(ctx->worker_tid, NULL);
+ return 0;
+}
+
+/*
+ * Instruct Monkey core to invoke a callback function inside each worker
+ * started by the scheduler.
+ */
+int mk_worker_callback(mk_ctx_t *ctx,
+ void (*cb_func) (void *),
+ void *data)
+{
+ return mk_sched_worker_cb_add(ctx->server, cb_func, data);
+}
+
+int mk_config_set_property(struct mk_server *server, char *k, char *v)
+{
+ int b;
+ int ret;
+ int num;
+ unsigned long len;
+
+ if (config_eq(k, "Listen") == 0) {
+ ret = mk_config_listen_parse(v, server);
+ if (ret != 0) {
+ return -1;
+ }
+ }
+ else if (config_eq(k, "Workers") == 0) {
+ num = atoi(v);
+ if (num <= 0) {
+ server->workers = mk_utils_get_system_core_count();
+ }
+ else {
+ server->workers = num;
+ }
+ }
+ else if (config_eq(k, "Timeout") == 0) {
+ num = atoi(v);
+ if (num <= 0) {
+ return -1;
+ }
+ server->timeout = num;
+ }
+ else if (config_eq(k, "KeepAlive") == 0) {
+ b = bool_val(v);
+ if (b == -1) {
+ return -1;
+ }
+ server->keep_alive = b;
+ }
+ else if (config_eq(k, "MaxKeepAliveRequest") == 0) {
+ num = atoi(v);
+ if (num <= 0) {
+ return -1;
+ }
+ server->max_keep_alive_request = num;
+ }
+ else if (config_eq(k, "KeepAliveTimeout") == 0) {
+ num = atoi(v);
+ if (num <= 0) {
+ return -1;
+ }
+ server->keep_alive_timeout = num;
+ }
+ else if (config_eq(k, "UserDir") == 0) {
+ server->conf_user_pub = mk_string_dup(v);
+ }
+ else if (config_eq(k, "IndexFile") == 0) {
+ server->index_files = mk_string_split_line(v);
+ if (!server->index_files) {
+ return -1;
+ }
+ }
+ else if (config_eq(k, "HideVersion") == 0) {
+ b = bool_val(v);
+ if (b == -1) {
+ return -1;
+ }
+ server->hideversion = b;
+ }
+ else if (config_eq(k, "Resume") == 0) {
+ b = bool_val(v);
+ if (b == -1) {
+ return -1;
+ }
+ server->resume = b;
+ }
+ else if (config_eq(k, "MaxRequestSize") == 0) {
+ num = atoi(v);
+ if (num <= 0) {
+ return -1;
+ }
+ server->max_request_size = num;
+ }
+ else if (config_eq(k, "SymLink") == 0) {
+ b = bool_val(v);
+ if (b == -1) {
+ return -1;
+ }
+ server->symlink = b;
+ }
+ else if (config_eq(k, "DefaultMimeType") == 0) {
+ mk_string_build(&server->mimetype_default_str, &len, "%s\r\n", v);
+ }
+ else if (config_eq(k, "FDT") == 0) {
+ b = bool_val(v);
+ if (b == -1) {
+ return -1;
+ }
+ server->fdt = b;
+ }
+
+ return 0;
+}
+
+int mk_config_set(mk_ctx_t *ctx, ...)
+{
+ int ret;
+ char *key;
+ char *value;
+ va_list va;
+
+ va_start(va, ctx);
+
+ while ((key = va_arg(va, char *))) {
+ value = va_arg(va, char *);
+ if (!value) {
+ /* Wrong parameter */
+ va_end(va);
+ return -1;
+ }
+
+ ret = mk_config_set_property(ctx->server, key, value);
+ if (ret != 0) {
+ va_end(va);
+ return -1;
+ }
+ }
+
+ va_end(va);
+ return 0;
+}
+
+/* Given a vhost id, return the vhost context */
+struct mk_vhost *mk_vhost_lookup(mk_ctx_t *ctx, int id)
+{
+ struct mk_vhost *host;
+ struct mk_list *head;
+
+ mk_list_foreach(head, &ctx->server->hosts) {
+ host = mk_list_entry(head, struct mk_vhost, _head);
+ if (host->id == id) {
+ return host;
+ }
+ }
+
+ return NULL;
+}
+
+int mk_vhost_create(mk_ctx_t *ctx, char *name)
+{
+ struct mk_vhost *h;
+ struct mk_vhost_alias *halias;
+
+ /* Virtual host */
+ h = mk_mem_alloc_z(sizeof(struct mk_vhost));
+ if (!h) {
+ return -1;
+ }
+
+ /* Assign a virtual host id, we just set based on list size */
+ h->id = mk_list_size(&ctx->server->hosts);
+ mk_list_init(&h->error_pages);
+ mk_list_init(&h->server_names);
+ mk_list_init(&h->handlers);
+
+ /* Host alias */
+ halias = mk_mem_alloc_z(sizeof(struct mk_vhost_alias));
+ if (!halias) {
+ mk_mem_free(h);
+ return -1;
+ }
+
+ /* Host name */
+ if (!name) {
+ halias->name = mk_string_dup("127.0.0.1");
+ }
+ else {
+ halias->name = mk_string_dup(name);
+ }
+ mk_list_add(&halias->_head, &h->server_names);
+ mk_list_add(&h->_head, &ctx->server->hosts);
+
+ /* Return the host id, that number is enough for further operations */
+ return h->id;
+}
+
+static int mk_vhost_set_property(struct mk_vhost *vh, char *k, char *v)
+{
+ struct mk_vhost_alias *ha;
+
+ if (config_eq(k, "Name") == 0) {
+ ha = mk_mem_alloc(sizeof(struct mk_vhost_alias));
+ if (!ha) {
+ return -1;
+ }
+ ha->name = mk_string_dup(v);
+ ha->len = strlen(v);
+ mk_list_add(&ha->_head, &vh->server_names);
+ }
+ else if (config_eq(k, "DocumentRoot") == 0) {
+ vh->documentroot.data = mk_string_dup(v);
+ vh->documentroot.len = strlen(v);
+ }
+
+ return 0;
+}
+
+int mk_vhost_set(mk_ctx_t *ctx, int vid, ...)
+{
+ int ret;
+ char *key;
+ char *value;
+ va_list va;
+ struct mk_vhost *vh;
+
+ /* Lookup the virtual host */
+ vh = mk_vhost_lookup(ctx, vid);
+ if (!vh) {
+ return -1;
+ }
+
+ va_start(va, vid);
+
+ while ((key = va_arg(va, char *))) {
+ value = va_arg(va, char *);
+ if (!value) {
+ /* Wrong parameter */
+ return -1;
+ }
+
+ ret = mk_vhost_set_property(vh, key, value);
+ if (ret != 0) {
+ va_end(va);
+ return -1;
+ }
+ }
+
+ va_end(va);
+ return 0;
+}
+
+int mk_vhost_handler(mk_ctx_t *ctx, int vid, char *regex,
+ void (*cb)(mk_request_t *, void *), void *data)
+{
+ struct mk_vhost *vh;
+ struct mk_vhost_handler *handler;
+ void (*_cb) (struct mk_http_request *, void *);
+
+ /* Lookup the virtual host */
+ vh = mk_vhost_lookup(ctx, vid);
+ if (!vh) {
+ return -1;
+ }
+
+ _cb = cb;
+ handler = mk_vhost_handler_match(regex, _cb, data);
+ if (!handler) {
+ return -1;
+ }
+ mk_list_add(&handler->_head, &vh->handlers);
+
+ return 0;
+}
+
+/* Flush streams data associated to a request in question */
+int mk_http_flush(mk_request_t *req)
+{
+ int ret;
+ size_t out_bytes = 0;
+
+ ret = mk_channel_stream_write(&req->stream, &out_bytes);
+ return ret;
+}
+
+int mk_http_status(mk_request_t *req, int status)
+{
+ req->headers.status = status;
+ return 0;
+}
+
+/* Append a response header */
+int mk_http_header(mk_request_t *req,
+ char *key, int key_len,
+ char *val, int val_len)
+{
+ int pos;
+ int len;
+ char *buf;
+ struct response_headers *h;
+
+ h = &req->headers;
+ if (!h->_extra_rows) {
+ h->_extra_rows = mk_iov_create(MK_PLUGIN_HEADER_EXTRA_ROWS * 2, 0);
+ if (!h->_extra_rows) {
+ return -1;
+ }
+ }
+
+ len = key_len + val_len + 4;
+ buf = mk_mem_alloc(len);
+ if (!buf) {
+ /* we don't free extra_rows as it's released later */
+ return -1;
+ }
+
+ /* Compose the buffer */
+ memcpy(buf, key, key_len);
+ pos = key_len;
+ buf[pos++] = ':';
+ buf[pos++] = ' ';
+ memcpy(buf + pos, val, val_len);
+ pos += val_len;
+ buf[pos++] = '\r';
+ buf[pos++] = '\n';
+
+ /* Add the new buffer */
+ mk_iov_add(h->_extra_rows, buf, pos, MK_TRUE);
+
+ return 0;
+}
+
+static inline int chunk_header(long num, char *out)
+{
+ int i = 1;
+ int j, c;
+ int remainder;
+ int quotient;
+ char tmp[32];
+ char hex[] = "0123456789ABCDEF";
+
+ if (num == 0) {
+ out[0] = '0';
+ out[1] = '\r';
+ out[2] = '\n';
+ out[3] = '\r';
+ out[4] = '\n';
+ out[5] = '\0';
+ return 5;
+ }
+
+ quotient = num;
+ while (quotient != 0) {
+ remainder = quotient % 16;
+ tmp[i++] = hex[remainder];
+ quotient = quotient / 16;
+ }
+
+ c = 0;
+ for (j = i -1 ; j > 0; j--, c++) {
+ out[c] = tmp[j];
+ }
+
+ out[c++] = '\r';
+ out[c++] = '\n';
+ out[c] = '\0';
+
+ return c;
+}
+
+static void free_chunk_header(struct mk_stream_input *input)
+{
+ mk_mem_free(input->buffer);
+ input->buffer = NULL;
+}
+
+
+/* Check if response headers were processed, otherwise prepare them */
+static int headers_setup(mk_request_t *req)
+{
+ /*
+ * Let's keep it simple for now: if the headers have not been sent, do it
+ * now and then send the body content just queued.
+ */
+ if (req->headers.sent == MK_FALSE) {
+ /* Force chunked-transfer encoding */
+ if (req->protocol == MK_HTTP_PROTOCOL_11) {
+ req->headers.transfer_encoding = MK_HEADER_TE_TYPE_CHUNKED;
+ }
+ else {
+ req->headers.content_length = -1;
+ }
+ mk_header_prepare(req->session, req, req->session->server);
+ }
+ return 0;
+}
+
+/* Enqueue some data for the body response */
+int mk_http_send(mk_request_t *req, char *buf, size_t len,
+ void (*cb_finish)(mk_request_t *))
+{
+ int chunk_len;
+ int ret;
+ char *tmp;
+ char chunk_pre[32];
+ (void) cb_finish;
+
+ if (req->session->channel->status != MK_CHANNEL_OK) {
+ return -1;
+ }
+
+ if (req->headers.status == -1) {
+ /* Cannot append data if the status have not been set */
+ mk_err("HTTP: set the response status first");
+ return -1;
+ }
+
+ /* Chunk encoding prefix */
+ if (req->protocol == MK_HTTP_PROTOCOL_11) {
+ chunk_len = chunk_header(len, chunk_pre);
+ tmp = mk_string_dup(chunk_pre);
+ if (!tmp) {
+ return -1;
+ }
+ ret = mk_stream_in_raw(&req->stream, NULL,
+ tmp, chunk_len, NULL, free_chunk_header);
+ if (ret != 0) {
+ return -1;
+ }
+ }
+
+ /* Append raw data */
+ if (len > 0) {
+ ret = mk_stream_in_raw(&req->stream, NULL,
+ buf, len, NULL, NULL);
+ if (ret == 0) {
+ /* Update count of bytes */
+ req->stream_size += len;
+ }
+ }
+
+ if (req->protocol == MK_HTTP_PROTOCOL_11 && len > 0) {
+ ret = mk_stream_in_raw(&req->stream, NULL,
+ "\r\n", 2, NULL, NULL);
+ }
+
+ /* Validate if the response headers are ready */
+ headers_setup(req);
+
+ /* Flush channel data */
+ ret = mk_http_flush(req);
+
+ /*
+ * Flush have been done, before to return our original caller, we want to yield
+ * and give some execution time to the event loop to avoid possible blocking
+ * since the caller might be using this mk_http_send() in a loop.
+ */
+ mk_lib_yield(req);
+ return ret;
+}
+
+int mk_http_done(mk_request_t *req)
+{
+ if (req->session->channel->status != MK_CHANNEL_OK) {
+ return -1;
+ }
+
+ /* Validate if the response headers are ready */
+ headers_setup(req);
+
+ if (req->headers.transfer_encoding == MK_HEADER_TE_TYPE_CHUNKED) {
+ /* Append end-of-chunk bytes */
+ mk_http_send(req, NULL, 0, NULL);
+ }
+ else {
+ mk_http_send(req, NULL, 0, NULL);
+ }
+
+ if (req->session->close_now == MK_TRUE) {
+ mk_lib_yield(req);
+ }
+
+ return 0;
+}
+
+/* Create a messaging queue end-point */
+int mk_mq_create(mk_ctx_t *ctx, char *name, void (*cb), void *data)
+{
+ int id;
+
+ id = mk_fifo_queue_create(ctx->fifo, name, cb, data);
+ return id;
+}
+
+/* Write a message to a specific queue ID */
+int mk_mq_send(mk_ctx_t *ctx, int qid, void *data, size_t size)
+{
+ return mk_fifo_send(ctx->fifo, qid, data, size);
+}
+
+int mk_main()
+{
+ while (1) {
+ sleep(60);
+ }
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_mimetype.c b/fluent-bit/lib/monkey/mk_server/mk_mimetype.c
new file mode 100644
index 000000000..b86b4ef1a
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_mimetype.c
@@ -0,0 +1,227 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <mk_core/mk_unistd.h>
+
+#include <monkey/monkey.h>
+#include <monkey/mk_mimetype.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_core.h>
+#include <monkey/mk_http.h>
+
+struct mk_mimetype *mimetype_default;
+
+static int rbtree_compare(const void *lhs, const void *rhs)
+{
+ return strcmp((const char *)lhs, (const char *)rhs);
+}
+
+/* Match mime type for requested resource */
+struct mk_mimetype *mk_mimetype_lookup(struct mk_server *server, char *name)
+{
+ int cmp;
+ struct rb_tree_node *node = server->mimetype_rb_head.root;
+
+ while (node) {
+ struct mk_mimetype *entry = container_of(node, struct mk_mimetype, _rb_head);
+ cmp = strcmp(name, entry->name);
+ if (cmp < 0)
+ node = node->left;
+ else if (cmp > 0)
+ node = node->right;
+ else {
+ return entry;
+ }
+ }
+ return NULL;
+}
+
+int mk_mimetype_add(struct mk_server *server, char *name, const char *type)
+{
+ int len = strlen(type) + 3;
+ char *p;
+ struct mk_mimetype *new_mime;
+
+ /* make sure we register the extension in lower case */
+ p = name;
+ for ( ; *p; ++p) *p = tolower(*p);
+
+ new_mime = mk_mem_alloc_z(sizeof(struct mk_mimetype));
+ if (!new_mime) {
+ return -1;
+ }
+ new_mime->name = mk_string_dup(name);
+ if (!new_mime->name) {
+ mk_mem_free(new_mime);
+ return -1;
+ }
+ new_mime->type.data = mk_mem_alloc(len);
+ if (!new_mime->type.data) {
+ mk_mem_free(new_mime->name);
+ mk_mem_free(new_mime);
+ return -1;
+ }
+ new_mime->type.len = len - 1;
+ new_mime->header_type.data = mk_mem_alloc(len + 32);
+ if (!new_mime->header_type.data) {
+ mk_mem_free(new_mime->name);
+ mk_mem_free(new_mime->type.data);
+ mk_mem_free(new_mime);
+ return -1;
+ }
+ new_mime->header_type.len = snprintf(new_mime->header_type.data,
+ len + 32,
+ "Content-Type: %s\r\n",
+ type);
+ strcpy(new_mime->type.data, type);
+ strcat(new_mime->type.data, MK_CRLF);
+ new_mime->type.data[len-1] = '\0';
+
+ /* Insert the node into the RBT */
+ rb_tree_insert(&server->mimetype_rb_head,
+ new_mime->name, &new_mime->_rb_head);
+
+ /* Add to linked list head */
+ mk_list_add(&new_mime->_head, &server->mimetype_list);
+
+ return 0;
+}
+
+int mk_mimetype_init(struct mk_server *server)
+{
+ char *name;
+ int ret;
+
+ /* Initialize the heads */
+ mk_list_init(&server->mimetype_list);
+ rb_tree_new(&server->mimetype_rb_head, rbtree_compare);
+
+ name = mk_string_dup(MIMETYPE_DEFAULT_NAME);
+ if (server->mimetype_default_str) {
+ ret = mk_mimetype_add(server, name, server->mimetype_default_str);
+ }
+ else {
+ ret = mk_mimetype_add(server, name, MIMETYPE_DEFAULT_TYPE);
+ }
+ if (ret < 0) {
+ mk_mem_free(name);
+ return -1;
+ }
+ server->mimetype_default = mk_list_entry_first(&server->mimetype_list,
+ struct mk_mimetype,
+ _head);
+ mk_mem_free(name);
+ return 0;
+}
+
+/* Load the two mime arrays into memory */
+int mk_mimetype_read_config(struct mk_server *server)
+{
+ char path[MK_MAX_PATH];
+ struct mk_rconf *cnf;
+ struct mk_rconf_section *section;
+ struct mk_rconf_entry *entry;
+ struct mk_list *head;
+ struct file_info f_info;
+ int ret;
+
+ if (!server->conf_mimetype) {
+ return -1;
+ }
+
+ /* Read mime types configuration file */
+ snprintf(path, MK_MAX_PATH, "%s/%s",
+ server->path_conf_root,
+ server->conf_mimetype);
+
+ ret = mk_file_get_info(path, &f_info, MK_FILE_EXISTS);
+ if (ret == -1 || f_info.is_file == MK_FALSE) {
+ snprintf(path, MK_MAX_PATH, "%s", server->conf_mimetype);
+ }
+ cnf = mk_rconf_open(path);
+ if (!cnf) {
+ mk_warn("[mime] skipping mimetype configuration file");
+ return -1;
+ }
+
+ /* Get MimeTypes tag */
+ section = mk_rconf_section_get(cnf, "MIMETYPES");
+ if (!section) {
+ mk_err("[mime] Invalid mime type file");
+ return -1;
+ }
+
+ mk_list_foreach(head, &section->entries) {
+ entry = mk_list_entry(head, struct mk_rconf_entry, _head);
+ if (!entry->key || !entry->val) {
+ continue;
+ }
+
+ if (mk_mimetype_add(server, entry->key, entry->val) != 0) {
+ mk_err("[mime] Error loading Mime Types");
+ return -1;
+ }
+ }
+
+ mk_rconf_free(cnf);
+
+ return 0;
+}
+
+struct mk_mimetype *mk_mimetype_find(struct mk_server *server, mk_ptr_t *filename)
+{
+ int j, len;
+
+ j = len = filename->len;
+
+ /* looking for extension */
+ while (j >= 0 && filename->data[j] != '.') {
+ j--;
+ }
+
+ if (j <= 0) {
+ return NULL;
+ }
+
+ return mk_mimetype_lookup(server, filename->data + j + 1);
+}
+
+void mk_mimetype_free_all(struct mk_server *server)
+{
+ struct mk_list *head;
+ struct mk_list *tmp;
+ struct mk_mimetype *mime;
+
+ mk_list_foreach_safe(head, tmp, &server->mimetype_list) {
+ mime = mk_list_entry(head, struct mk_mimetype, _head);
+ mk_ptr_free(&mime->type);
+ mk_mem_free(mime->name);
+ mk_mem_free(mime->header_type.data);
+ mk_mem_free(mime);
+ }
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_net.c b/fluent-bit/lib/monkey/mk_server/mk_net.c
new file mode 100644
index 000000000..de183de48
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_net.c
@@ -0,0 +1,284 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2016 Monkey Software LLC <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_core.h>
+#include <monkey/mk_net.h>
+#include <monkey/mk_scheduler.h>
+#include <monkey/mk_plugin.h>
+#include <monkey/mk_thread.h>
+#include <monkey/mk_tls.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <afunix.h>
+#else
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#endif
+
+/* Initialize the network stack*/
+int mk_net_init()
+{
+#ifdef _WIN32
+ int result;
+ WSADATA wsa_data;
+ static int initialized = 0;
+
+ if(0 != initialized) {
+ return 0;
+ }
+
+ result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+
+ if(0 != result) {
+ if(WSAEINPROGRESS == result)
+ {
+ Sleep(100); /* Let the other thread finish initializing the stack */
+
+ return 0;
+ }
+
+ return -1;
+ }
+
+ initialized = 1;
+#endif
+
+ return 0;
+}
+
+/* Connect to a TCP socket server */
+static int mk_net_fd_connect(int fd, char *host, unsigned long port)
+{
+ int ret;
+ struct addrinfo hints;
+ struct addrinfo *res;
+ char _port[6];
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ snprintf(_port, sizeof(_port), "%lu", port);
+ ret = getaddrinfo(host, _port, &hints, &res);
+ if (ret != 0) {
+ return -1;
+ }
+
+ ret = connect(fd, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+
+ return ret;
+}
+
+struct mk_net_connection *mk_net_conn_create(char *addr, int port)
+{
+ int fd;
+ int ret;
+ int error = 0;
+ socklen_t len = sizeof(error);
+ struct mk_sched_worker *sched;
+ struct mk_net_connection *conn;
+
+ /* Allocate connection context */
+ conn = mk_mem_alloc(sizeof(struct mk_net_connection));
+ if (!conn) {
+ return NULL;
+ }
+
+ /* Create socket */
+ fd = mk_socket_create(AF_INET, SOCK_STREAM, 0);
+ if (fd == -1) {
+ mk_mem_free(conn);
+ return NULL;
+ }
+
+ /* Make socket async */
+ mk_socket_set_nonblocking(fd);
+ conn->fd = fd;
+
+ ret = mk_net_fd_connect(conn->fd, addr, port);
+ if (ret == -1) {
+ if (errno != EINPROGRESS) {
+ close(fd);
+ mk_mem_free(conn);
+ return NULL;
+ }
+
+ MK_EVENT_NEW(&conn->event);
+
+ sched = mk_sched_get_thread_conf();
+ // FIXME: not including the thread
+ //conn->thread = mk_thread_get();
+ ret = mk_event_add(sched->loop, conn->fd, MK_EVENT_THREAD,
+ MK_EVENT_WRITE, &conn->event);
+ if (ret == -1) {
+ close(fd);
+ mk_mem_free(conn);
+ return NULL;
+ }
+
+ /*
+ * Return the control to the parent caller, we need to wait for
+ * the event loop to get back to us.
+ */
+ mk_thread_yield(conn->thread);
+
+ /* We got a notification, remove the event registered */
+ ret = mk_event_del(sched->loop, &conn->event);
+
+ /* Check the connection status */
+ if (conn->event.mask & MK_EVENT_WRITE) {
+ ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
+ if (ret == -1) {
+ close(fd);
+ mk_mem_free(conn);
+ return NULL;
+ }
+
+ if (error != 0) {
+ /* Connection is broken, not much to do here */
+ fprintf(stderr, "Async connection failed %s:%i\n",
+ conn->host, conn->port);
+ close(fd);
+ mk_mem_free(conn);
+ return NULL;
+ }
+ MK_EVENT_NEW(&conn->event);
+ return conn;
+ }
+ else {
+ close(fd);
+ mk_mem_free(conn);
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+int mk_net_conn_write(struct mk_channel *channel,
+ void *data, size_t len)
+{
+ int ret = 0;
+ int error;
+ ssize_t bytes;
+ size_t total = 0;
+ size_t send;
+ socklen_t slen = sizeof(error);
+ struct mk_thread *th = MK_TLS_GET(mk_thread);
+ struct mk_sched_worker *sched;
+
+ sched = mk_sched_get_thread_conf();
+ if (!sched) {
+ return -1;
+ }
+
+ retry:
+ error = 0;
+
+ if (len - total > 524288) {
+ send = 524288;
+ }
+ else {
+ send = (len - total);
+ }
+
+ send = len - total;
+ bytes = channel->io->write(channel->io->plugin, channel->fd, (uint8_t *)data + total, send);
+ if (bytes == -1) {
+ if (errno == EAGAIN) {
+ MK_EVENT_NEW(channel->event);
+ channel->thread = th;
+ ret = mk_event_add(sched->loop,
+ channel->fd,
+ MK_EVENT_THREAD,
+ MK_EVENT_WRITE, channel->event);
+ if (ret == -1) {
+ /*
+ * If we failed here there no much that we can do, just
+ * let the caller we failed
+ */
+ return -1;
+ }
+
+ /*
+ * Return the control to the parent caller, we need to wait for
+ * the event loop to get back to us.
+ */
+ mk_thread_yield(th);
+
+ /* We got a notification, remove the event registered */
+ ret = mk_event_del(sched->loop, channel->event);
+ if (ret == -1) {
+ return -1;
+ }
+
+ /* Check the connection status */
+ if (channel->event->mask & MK_EVENT_WRITE) {
+ ret = getsockopt(channel->fd, SOL_SOCKET, SO_ERROR, &error, &slen);
+ if (ret == -1) {
+ fprintf(stderr, "[io] could not validate socket status");
+ return -1;
+ }
+
+ if (error != 0) {
+ return -1;
+ }
+
+ MK_EVENT_NEW(channel->event);
+ goto retry;
+ }
+ else {
+ return -1;
+ }
+
+ }
+ else {
+ return -1;
+ }
+ }
+
+ /* Update counters */
+ total += bytes;
+ if (total < len) {
+ channel->thread = th;
+ ret = mk_event_add(sched->loop,
+ channel->fd,
+ MK_EVENT_THREAD,
+ MK_EVENT_WRITE, channel->event);
+ if (ret == -1) {
+ /*
+ * If we failed here there no much that we can do, just
+ * let the caller we failed
+ */
+ return -1;
+ }
+
+ mk_thread_yield(th);
+ goto retry;
+ }
+
+ if (channel->event->status & MK_EVENT_REGISTERED) {
+ /* We got a notification, remove the event registered */
+ ret = mk_event_del(sched->loop, channel->event);
+ }
+
+ return total;
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_plugin.c b/fluent-bit/lib/monkey/mk_server/mk_plugin.c
new file mode 100644
index 000000000..50e2886b7
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_plugin.c
@@ -0,0 +1,804 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/monkey.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_http.h>
+#include <monkey/mk_clock.h>
+#include <monkey/mk_plugin.h>
+#include <monkey/mk_mimetype.h>
+#include <monkey/mk_vhost.h>
+#include <monkey/mk_static_plugins.h>
+#include <monkey/mk_plugin_stage.h>
+#include <monkey/mk_core.h>
+#include <monkey/mk_net.h>
+
+#ifndef _WIN32
+#include <dlfcn.h>
+#include <err.h>
+#endif
+
+enum {
+ bufsize = 256
+};
+
+static struct plugin_stagemap *plg_stagemap;
+struct plugin_network_io *plg_netiomap;
+
+struct mk_plugin *mk_plugin_lookup(char *shortname, struct mk_server *server)
+{
+ struct mk_list *head;
+ struct mk_plugin *p = NULL;
+
+ mk_list_foreach(head, &server->plugins) {
+ p = mk_list_entry(head, struct mk_plugin, _head);
+ if (strcmp(p->shortname, shortname) == 0){
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+void *mk_plugin_load_dynamic(const char *path)
+{
+ void *handle;
+
+#ifdef _WIN32
+ handle = (void *) LoadLibraryA(path);
+#else
+ handle = dlopen(path, RTLD_LAZY);
+
+ if (!handle) {
+ mk_warn("dlopen() %s", dlerror());
+ }
+#endif
+
+ return handle;
+}
+
+void *mk_plugin_load_symbol(void *handler, const char *symbol)
+{
+ void *s;
+
+#ifdef _WIN32
+ s = GetProcAddress((HMODULE)handler, symbol);
+#else
+ dlerror();
+ s = dlsym(handler, symbol);
+ if (dlerror() != NULL) {
+ return NULL;
+ }
+#endif
+
+ return s;
+}
+
+/* Initialize a plugin, trigger the init_plugin callback */
+static int mk_plugin_init(struct plugin_api *api,
+ struct mk_plugin *plugin,
+ struct mk_server *server)
+{
+ int ret;
+ unsigned long len;
+ char path[1024];
+ char *conf_dir = NULL;
+ struct file_info f_info;
+
+ MK_TRACE("Load Plugin: '%s'", plugin->shortname);
+
+ snprintf(path, 1024, "%s/%s",
+ server->path_conf_root, server->conf_plugins);
+ ret = mk_file_get_info(path, &f_info, MK_FILE_READ);
+ if (ret == -1 || f_info.is_directory == MK_FALSE) {
+ snprintf(path, 1024, "%s", server->conf_plugins);
+ }
+
+ /* Build plugin configuration path */
+ mk_string_build(&conf_dir,
+ &len,
+ "%s/%s/",
+ path, plugin->shortname);
+
+ /* Init plugin */
+ plugin->api = api;
+ plugin->server_ctx = server;
+
+ if (plugin->network != NULL) {
+ plugin->network->plugin = plugin;
+ }
+
+ ret = plugin->init_plugin(plugin, conf_dir);
+ mk_mem_free(conf_dir);
+
+ return ret;
+}
+
+
+/*
+ * Load a plugin into Monkey core, 'type' defines if it's a MK_PLUGIN_STATIC or
+ * a MK_PLUGIN_DYNAMIC. 'shortname' is mandatory and 'path' is only used when
+ * MK_PLUGIN_DYNAMIC is set and represents the absolute path of the shared
+ * library.
+ */
+struct mk_plugin *mk_plugin_load(int type, const char *shortname,
+ void *data, struct mk_server *server)
+{
+ char *path;
+ char symbol[64];
+ void *handler;
+ struct mk_list *head;
+ struct mk_plugin *tmp;
+ struct mk_plugin *plugin = NULL;
+ struct mk_plugin_stage *stage;
+
+ /* Set main struct name to reference */
+ if (type == MK_PLUGIN_DYNAMIC) {
+ path = (char *) data;
+ handler = mk_plugin_load_dynamic(path);
+ if (!handler) {
+ return NULL;
+ }
+
+ snprintf(symbol, sizeof(symbol) - 1, "mk_plugin_%s", shortname);
+ plugin = mk_plugin_load_symbol(handler, symbol);
+ if (!plugin) {
+ mk_warn("Plugin '%s' is not registering properly", path);
+#ifdef _WIN32
+ FreeLibrary((HMODULE)handler);
+#else
+ dlclose(handler);
+#endif
+ return NULL;
+ }
+
+ /* Make sure this is not loaded twice (ref #218) */
+ mk_list_foreach(head, &server->plugins) {
+ tmp = mk_list_entry(head, struct mk_plugin, _head);
+ if (tmp->load_type == MK_PLUGIN_STATIC &&
+ strcmp(tmp->name, plugin->name) == 0){
+ mk_warn("Plugin '%s' have been built-in.",
+ tmp->shortname);
+#ifdef _WIN32
+ FreeLibrary((HMODULE)handler);
+#else
+ dlclose(handler);
+#endif
+ return NULL;
+ }
+ }
+
+ plugin->load_type = MK_PLUGIN_DYNAMIC;
+ plugin->handler = handler;
+ plugin->path = mk_string_dup(path);
+ }
+ else if (type == MK_PLUGIN_STATIC) {
+ plugin = (struct mk_plugin *) data;
+ plugin->load_type = MK_PLUGIN_STATIC;
+ }
+
+ if (!plugin) {
+ return NULL;
+ }
+
+ /* Validate all callbacks are set */
+ if (!plugin->shortname || !plugin->name || !plugin->version ||
+ !plugin->init_plugin || !plugin->exit_plugin) {
+ mk_warn("Plugin '%s' is not registering all fields properly",
+ shortname);
+ return NULL;
+ }
+
+ if (plugin->hooks & MK_PLUGIN_NETWORK_LAYER) {
+ mk_bug(!plugin->network);
+ }
+
+ mk_list_init(&plugin->stage_list);
+ if (plugin->hooks & MK_PLUGIN_STAGE) {
+ struct mk_plugin_stage *st;
+
+ stage = plugin->stage;
+ if (stage->stage10) {
+ st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
+ st->stage10 = stage->stage10;
+ st->plugin = plugin;
+ mk_list_add(&st->_head, &server->stage10_handler);
+ mk_list_add(&st->_parent_head, &plugin->stage_list);
+ }
+ if (stage->stage20) {
+ st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
+ st->stage20 = stage->stage20;
+ st->plugin = plugin;
+ mk_list_add(&st->_head, &server->stage20_handler);
+ mk_list_add(&st->_parent_head, &plugin->stage_list);
+ }
+ if (stage->stage30) {
+ st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
+ st->stage30 = stage->stage30;
+ st->plugin = plugin;
+ mk_list_add(&st->_head, &server->stage30_handler);
+ mk_list_add(&st->_parent_head, &plugin->stage_list);
+ }
+ if (stage->stage40) {
+ st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
+ st->stage40 = stage->stage40;
+ st->plugin = plugin;
+ mk_list_add(&st->_head, &server->stage40_handler);
+ mk_list_add(&st->_parent_head, &plugin->stage_list);
+ }
+ if (stage->stage50) {
+ st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
+ st->stage50 = stage->stage50;
+ st->plugin = plugin;
+ mk_list_add(&st->_head, &server->stage50_handler);
+ mk_list_add(&st->_parent_head, &plugin->stage_list);
+ }
+ }
+
+ if (type == MK_PLUGIN_DYNAMIC) {
+ /* Add Plugin to the end of the list */
+ mk_list_add(&plugin->_head, &server->plugins);
+ }
+
+ return plugin;
+}
+
+void mk_plugin_unregister(struct mk_plugin *p)
+{
+ mk_mem_free(p->path);
+ mk_list_del(&p->_head);
+ if (p->load_type == MK_PLUGIN_DYNAMIC) {
+#ifdef _WIN32
+ FreeLibrary((HMODULE)p->handler);
+#else
+ dlclose(p->handler);
+#endif
+ }
+
+}
+
+void mk_plugin_api_init(struct mk_server *server)
+{
+ struct plugin_api *api;
+
+ /* Create an instance of the API */
+ api = mk_mem_alloc_z(sizeof(struct plugin_api));
+
+#ifndef _WIN32
+ __builtin_prefetch(api);
+#endif
+
+ /* Setup and connections list */
+ /* FIXME: api->config = server; */
+
+ /* API plugins funcions */
+
+ /* Error helper */
+ api->_error = mk_print;
+
+ /* HTTP callbacks */
+ api->http_request_end = mk_plugin_http_request_end;
+ api->http_request_error = mk_plugin_http_error;
+
+ /* Memory callbacks */
+ api->pointer_set = mk_ptr_set;
+ api->pointer_print = mk_ptr_print;
+ api->pointer_to_buf = mk_ptr_to_buf;
+ api->plugin_load_symbol = mk_plugin_load_symbol;
+ api->mem_alloc = mk_mem_alloc;
+ api->mem_alloc_z = mk_mem_alloc_z;
+ api->mem_realloc = mk_mem_realloc;
+ api->mem_free = mk_mem_free;
+
+ /* String Callbacks */
+ api->str_build = mk_string_build;
+ api->str_dup = mk_string_dup;
+ api->str_search = mk_string_search;
+ api->str_search_n = mk_string_search_n;
+ api->str_char_search = mk_string_char_search;
+ api->str_copy_substr = mk_string_copy_substr;
+ api->str_itop = mk_string_itop;
+ api->str_split_line = mk_string_split_line;
+ api->str_split_free = mk_string_split_free;
+
+ /* File Callbacks */
+ api->file_to_buffer = mk_file_to_buffer;
+ api->file_get_info = mk_file_get_info;
+
+ /* HTTP Callbacks */
+ api->header_prepare = mk_plugin_header_prepare;
+ api->header_add = mk_plugin_header_add;
+ api->header_get = mk_http_header_get;
+ api->header_set_http_status = mk_header_set_http_status;
+
+ /* Channels / Streams */
+ api->channel_new = mk_channel_new;
+ api->channel_flush = mk_channel_flush;
+ api->channel_write = mk_channel_write;
+ api->channel_append_stream = mk_channel_append_stream;
+
+ /* IOV callbacks */
+ api->iov_create = mk_iov_create;
+ api->iov_realloc = mk_iov_realloc;
+ api->iov_free = mk_iov_free;
+ api->iov_free_marked = mk_iov_free_marked;
+ api->iov_add = mk_iov_add;
+ api->iov_set_entry = mk_iov_set_entry;
+ api->iov_send = mk_iov_send;
+ api->iov_print = mk_iov_print;
+
+ /* events mechanism */
+ api->ev_loop_create = mk_event_loop_create;
+ api->ev_add = mk_event_add;
+ api->ev_del = mk_event_del;
+ api->ev_timeout_create = mk_event_timeout_create;
+ api->ev_channel_create = mk_event_channel_create;
+ api->ev_wait = mk_event_wait;
+ api->ev_backend = mk_event_backend;
+
+ /* Mimetype */
+ api->mimetype_lookup = mk_mimetype_lookup;
+
+ /* Socket callbacks */
+ api->socket_cork_flag = mk_socket_set_cork_flag;
+ api->socket_connect = mk_socket_connect;
+ api->socket_open = mk_socket_open;
+ api->socket_reset = mk_socket_reset;
+ api->socket_set_tcp_fastopen = mk_socket_set_tcp_fastopen;
+ api->socket_set_tcp_reuseport = mk_socket_set_tcp_reuseport;
+ api->socket_set_tcp_nodelay = mk_socket_set_tcp_nodelay;
+ api->socket_set_nonblocking = mk_socket_set_nonblocking;
+ api->socket_create = mk_socket_create;
+ api->socket_ip_str = mk_socket_ip_str;
+
+ /* Async network */
+ api->net_conn_create = mk_net_conn_create;
+
+ /* Config Callbacks */
+ api->config_create = mk_rconf_create;
+ api->config_open = mk_rconf_open;
+ api->config_free = mk_rconf_free;
+ api->config_section_get = mk_rconf_section_get;
+ api->config_section_get_key = mk_rconf_section_get_key;
+
+ /* Scheduler and Event callbacks */
+ api->sched_loop = mk_sched_loop;
+ api->sched_get_connection = mk_sched_get_connection;
+ api->sched_event_free = mk_sched_event_free;
+ api->sched_remove_client = mk_plugin_sched_remove_client;
+ api->sched_worker_info = mk_plugin_sched_get_thread_conf;
+
+ /* Worker functions */
+ api->worker_spawn = mk_utils_worker_spawn;
+ api->worker_rename = mk_utils_worker_rename;
+
+ /* Time functions */
+ api->time_unix = mk_plugin_time_now_unix;
+ api->time_to_gmt = mk_utils_utime2gmt;
+ api->time_human = mk_plugin_time_now_human;
+
+ api->stacktrace = (void *) mk_utils_stacktrace;
+ api->kernel_version = mk_kernel_version;
+ api->kernel_features_print = mk_kernel_features_print;
+ api->plugins = &server->plugins;
+
+ /* handler */
+ api->handler_param_get = mk_handler_param_get;
+
+ server->api = api;
+}
+
+void mk_plugin_load_static(struct mk_server *server)
+{
+ /* Load static plugins */
+ mk_list_init(&server->plugins);
+ mk_static_plugins(&server->plugins);
+}
+
+void mk_plugin_load_all(struct mk_server *server)
+{
+ int ret;
+ char *tmp;
+ char *path;
+ char shortname[64];
+ struct mk_plugin *p;
+ struct mk_rconf *cnf;
+ struct mk_rconf_section *section;
+ struct mk_rconf_entry *entry;
+ struct mk_list *head;
+ struct mk_list *htmp;
+ struct file_info f_info;
+
+ mk_plugin_load_static(server);
+ mk_list_foreach_safe(head, htmp, &server->plugins) {
+ p = mk_list_entry(head, struct mk_plugin, _head);
+
+ /* Load the static plugin */
+ p = mk_plugin_load(MK_PLUGIN_STATIC,
+ p->shortname,
+ (void *) p,
+ server);
+ if (!p) {
+ continue;
+ }
+ ret = mk_plugin_init(server->api, p, server);
+ if (ret == -1) {
+ /* Free plugin, do not register, error initializing */
+ mk_warn("Plugin initialization failed: %s", p->shortname);
+ mk_plugin_unregister(p);
+ continue;
+ }
+ else if (ret == -2) {
+ /* Do not register, just skip it */
+ mk_plugin_unregister(p);
+ continue;
+ }
+ }
+
+ /* In case there are not dynamic plugins */
+ if (!server->conf_plugin_load) {
+ return;
+ }
+
+ /* Read configuration file */
+ path = mk_mem_alloc_z(1024);
+ snprintf(path, 1024, "%s/%s", server->path_conf_root,
+ server->conf_plugin_load);
+ ret = mk_file_get_info(path, &f_info, MK_FILE_READ);
+ if (ret == -1 || f_info.is_file == MK_FALSE) {
+ snprintf(path, 1024, "%s", server->conf_plugin_load);
+ }
+
+ cnf = mk_rconf_open(path);
+ if (!cnf) {
+ mk_warn("No dynamic plugins loaded.");
+ mk_mem_free(path);
+ return;
+ }
+
+ /* Read section 'PLUGINS' */
+ section = mk_rconf_section_get(cnf, "PLUGINS");
+ if (!section) {
+ exit(EXIT_FAILURE);
+ }
+
+ /* Read key entries */
+ mk_list_foreach_safe(head, htmp, &section->entries) {
+ entry = mk_list_entry(head, struct mk_rconf_entry, _head);
+ if (strcasecmp(entry->key, "Load") == 0) {
+
+ /* Get plugin 'shortname' */
+ tmp = memrchr(entry->val, '-', strlen(entry->val));
+ ++tmp;
+ memset(shortname, '\0', sizeof(shortname) - 1);
+ strncpy(shortname, tmp, strlen(tmp) - 3);
+
+ /* Load the dynamic plugin */
+ p = mk_plugin_load(MK_PLUGIN_DYNAMIC,
+ shortname,
+ entry->val,
+ server);
+ if (!p) {
+ mk_warn("Invalid plugin '%s'", entry->val);
+ continue;
+ }
+
+ ret = mk_plugin_init(server->api, p, server);
+ if (ret < 0) {
+ /* Free plugin, do not register */
+ MK_TRACE("Unregister plugin '%s'", p->shortname);
+ mk_plugin_unregister(p);
+ continue;
+ }
+ }
+ }
+
+ /* Look for plugins thread key data */
+ mk_plugin_preworker_calls(server);
+ mk_vhost_map_handlers(server);
+ mk_mem_free(path);
+ mk_rconf_free(cnf);
+}
+
+static void mk_plugin_exit_stages(struct mk_plugin *p)
+{
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_plugin_stage *st;
+
+ mk_list_foreach_safe(head, tmp, &p->stage_list) {
+ st = mk_list_entry(head, struct mk_plugin_stage, _parent_head);
+
+ /* remove from direct config->stageN head list */
+ mk_list_del(&st->_head);
+
+ /* remove from plugin->stage_lists */
+ mk_list_del(&st->_parent_head);
+ mk_mem_free(st);
+ }
+}
+
+/* Invoke all plugins 'exit' hook and free resources by the plugin interface */
+void mk_plugin_exit_all(struct mk_server *server)
+{
+ struct mk_plugin *plugin;
+ struct mk_list *head, *tmp;
+
+ /* Plugins */
+ mk_list_foreach(head, &server->plugins) {
+ plugin = mk_list_entry(head, struct mk_plugin, _head);
+ plugin->exit_plugin(plugin);
+ }
+
+ /* Plugin interface it self */
+ mk_list_foreach_safe(head, tmp, &server->plugins) {
+ plugin = mk_list_entry(head, struct mk_plugin, _head);
+ mk_list_del(&plugin->_head);
+ mk_plugin_exit_stages(plugin);
+
+ if (plugin->load_type == MK_PLUGIN_DYNAMIC) {
+ mk_mem_free(plugin->path);
+#ifdef _WIN32
+ FreeLibrary((HMODULE)plugin->handler);
+#else
+ dlclose(plugin ->handler);
+#endif
+ }
+ else if (plugin->load_type == MK_PLUGIN_STATIC) {
+ if (plugin->network != NULL) {
+ mk_mem_free(plugin->network);
+ }
+
+ mk_mem_free(plugin);
+ }
+ }
+
+ mk_mem_free(server->api);
+ mk_mem_free(plg_stagemap);
+}
+
+/*
+ * When a worker is exiting, it invokes this function to release any plugin
+ * associated data.
+ */
+void mk_plugin_exit_worker()
+{
+}
+
+/* This function is called by every created worker
+ * for plugins which need to set some data under a thread
+ * context
+ */
+void mk_plugin_core_process(struct mk_server *server)
+{
+ struct mk_plugin *node;
+ struct mk_list *head;
+
+ mk_list_foreach(head, &server->plugins) {
+ node = mk_list_entry(head, struct mk_plugin, _head);
+
+ /* Init plugin */
+ if (node->master_init) {
+ node->master_init(server);
+ }
+ }
+}
+
+/* This function is called by every created worker
+ * for plugins which need to set some data under a thread
+ * context
+ */
+void mk_plugin_core_thread(struct mk_server *server)
+{
+
+ struct mk_plugin *node;
+ struct mk_list *head;
+
+ mk_list_foreach(head, &server->plugins) {
+ node = mk_list_entry(head, struct mk_plugin, _head);
+
+ /* Init plugin thread context */
+ if (node->worker_init) {
+ node->worker_init(server);
+ }
+ }
+}
+
+/* This function is called by Monkey *outside* of the
+ * thread context for plugins, so here's the right
+ * place to set pthread keys or similar
+ */
+void mk_plugin_preworker_calls(struct mk_server *server)
+{
+ int ret;
+ struct mk_plugin *node;
+ struct mk_list *head;
+
+ mk_list_foreach(head, &server->plugins) {
+ node = mk_list_entry(head, struct mk_plugin, _head);
+
+ /* Init pthread keys */
+ if (node->thread_key) {
+ MK_TRACE("[%s] Set thread key", node->shortname);
+
+ ret = pthread_key_create(node->thread_key, NULL);
+ if (ret != 0) {
+ mk_err("Plugin Error: could not create key for %s",
+ node->shortname);
+ }
+ }
+ }
+}
+
+int mk_plugin_http_error(int http_status, struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ struct mk_plugin *plugin)
+{
+ return mk_http_error(http_status, cs, sr, plugin->server_ctx);
+}
+
+
+int mk_plugin_http_request_end(struct mk_plugin *plugin,
+ struct mk_http_session *cs, int close)
+{
+ int ret;
+ int con;
+ struct mk_http_request *sr;
+ struct mk_server *server = plugin->server_ctx;
+
+ MK_TRACE("[FD %i] PLUGIN HTTP REQUEST END", cs->socket);
+
+ cs->status = MK_REQUEST_STATUS_INCOMPLETE;
+ if (mk_list_is_empty(&cs->request_list) == 0) {
+ MK_TRACE("[FD %i] Tried to end non-existing request.", cs->socket);
+ return -1;
+ }
+
+ sr = mk_list_entry_last(&cs->request_list, struct mk_http_request, _head);
+ mk_plugin_stage_run_40(cs, sr, server);
+
+ if (close == MK_TRUE) {
+ cs->close_now = MK_TRUE;
+ }
+
+ /* Let's check if we should ask to finalize the connection or not */
+ ret = mk_http_request_end(cs, server);
+ MK_TRACE("[FD %i] HTTP session end = %i", cs->socket, ret);
+ if (ret < 0) {
+ con = mk_sched_event_close(cs->conn, mk_sched_get_thread_conf(),
+ MK_EP_SOCKET_DONE, server);
+ if (con != 0) {
+ return con;
+ }
+ else {
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+/* Plugin epoll event handlers
+ * ---------------------------
+ * this functions are called by connection.c functions as mk_conn_read(),
+ * mk_conn_write(),mk_conn_error(), mk_conn_close() and mk_conn_timeout().
+ *
+ * Return Values:
+ * -------------
+ * MK_PLUGIN_RET_EVENT_NOT_ME: There's no plugin hook associated
+ */
+
+void mk_plugin_event_bad_return(const char *hook, int ret)
+{
+ mk_err("[%s] Not allowed return value %i", hook, ret);
+}
+
+int mk_plugin_time_now_unix(struct mk_server *server)
+{
+ return server->clock_context->log_current_utime;
+}
+
+mk_ptr_t *mk_plugin_time_now_human(struct mk_server *server)
+{
+ return &server->clock_context->log_current_time;
+}
+
+int mk_plugin_sched_remove_client(int socket, struct mk_server *server)
+{
+ struct mk_sched_conn *conn;
+ struct mk_sched_worker *sched;
+
+ MK_TRACE("[FD %i] remove client", socket);
+
+ sched = mk_sched_get_thread_conf();
+ conn = mk_sched_get_connection(sched, socket);
+ if (!conn) {
+ return -1;
+ }
+
+ return mk_sched_remove_client(conn, sched, server);
+}
+
+int mk_plugin_header_prepare(struct mk_plugin *plugin,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr)
+{
+ return mk_header_prepare(cs, sr, plugin->server_ctx);
+}
+
+
+int mk_plugin_header_add(struct mk_http_request *sr, char *row, int len)
+{
+ mk_bug(!sr);
+
+ if (!sr->headers._extra_rows) {
+ /*
+ * We allocate space for a fixed number of IOV entries:
+ *
+ * MK_PLUGIN_HEADER_EXTRA_ROWS = X
+ *
+ * we use (MK_PLUGIN_HEADER_EXTRA_ROWS * 2) thinking in an ending CRLF
+ */
+ sr->headers._extra_rows = mk_iov_create(MK_PLUGIN_HEADER_EXTRA_ROWS * 2, 0);
+ mk_bug(!sr->headers._extra_rows);
+ }
+
+ mk_iov_add(sr->headers._extra_rows, row, len,
+ MK_FALSE);
+ mk_iov_add(sr->headers._extra_rows,
+ mk_iov_crlf.data, mk_iov_crlf.len,
+ MK_FALSE);
+ return 0;
+}
+
+struct mk_sched_worker *mk_plugin_sched_get_thread_conf()
+{
+ return MK_TLS_GET(mk_tls_sched_worker_node);
+}
+
+struct mk_plugin *mk_plugin_cap(char cap, struct mk_server *server)
+{
+ struct mk_list *head;
+ struct mk_plugin *plugin;
+
+ mk_list_foreach(head, &server->plugins) {
+ plugin = mk_list_entry(head, struct mk_plugin, _head);
+ if (plugin->capabilities & cap) {
+ return plugin;
+ }
+ }
+
+ return NULL;
+}
+
+struct mk_vhost_handler_param *mk_handler_param_get(int id,
+ struct mk_list *params)
+{
+ int i = 0;
+ struct mk_list *head;
+
+ mk_list_foreach(head, params) {
+ if (i == id) {
+ return mk_list_entry(head, struct mk_vhost_handler_param, _head);
+ }
+ i++;
+ }
+
+ return NULL;
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_scheduler.c b/fluent-bit/lib/monkey/mk_server/mk_scheduler.c
new file mode 100644
index 000000000..a680d3cdf
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_scheduler.c
@@ -0,0 +1,866 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/monkey.h>
+#include <monkey/mk_info.h>
+#include <monkey/mk_core.h>
+#include <monkey/mk_vhost.h>
+#include <monkey/mk_scheduler.h>
+#include <monkey/mk_scheduler_tls.h>
+#include <monkey/mk_server.h>
+#include <monkey/mk_thread.h>
+#include <monkey/mk_cache.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_clock.h>
+#include <monkey/mk_plugin.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_linuxtrace.h>
+#include <monkey/mk_server.h>
+#include <monkey/mk_plugin_stage.h>
+#include <monkey/mk_http_thread.h>
+
+#include <signal.h>
+
+#ifndef _WIN32
+#include <sys/syscall.h>
+#endif
+
+extern struct mk_sched_handler mk_http_handler;
+extern struct mk_sched_handler mk_http2_handler;
+
+pthread_mutex_t mutex_worker_init = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t mutex_worker_exit = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * Returns the worker id which should take a new incomming connection,
+ * it returns the worker id with less active connections. Just used
+ * if config->scheduler_mode is MK_SCHEDULER_FAIR_BALANCING.
+ */
+static inline int _next_target(struct mk_server *server)
+{
+ int i;
+ int target = 0;
+ unsigned long long tmp = 0, cur = 0;
+ struct mk_sched_ctx *ctx = server->sched_ctx;
+ struct mk_sched_worker *worker;
+
+ cur = (ctx->workers[0].accepted_connections -
+ ctx->workers[0].closed_connections);
+ if (cur == 0) {
+ return 0;
+ }
+
+ /* Finds the lowest load worker */
+ for (i = 1; i < server->workers; i++) {
+ worker = &ctx->workers[i];
+ tmp = worker->accepted_connections - worker->closed_connections;
+ if (tmp < cur) {
+ target = i;
+ cur = tmp;
+
+ if (cur == 0)
+ break;
+ }
+ }
+
+ /*
+ * If sched_ctx->workers[target] worker is full then the whole server too,
+ * because it has the lowest load.
+ */
+ if (mk_unlikely(server->server_capacity > 0 &&
+ server->server_capacity <= cur)) {
+ MK_TRACE("Too many clients: %i", server->server_capacity);
+
+ /* Instruct to close the connection anyways, we lie, it will die */
+ return -1;
+ }
+
+ return target;
+}
+
+struct mk_sched_worker *mk_sched_next_target(struct mk_server *server)
+{
+ int t;
+ struct mk_sched_ctx *ctx = server->sched_ctx;
+
+ t = _next_target(server);
+ if (mk_likely(t != -1)) {
+ return &ctx->workers[t];
+ }
+
+ return NULL;
+}
+
+/*
+ * This function is invoked when the core triggers a MK_SCHED_SIGNAL_FREE_ALL
+ * event through the signal channels, it means the server will stop working
+ * so this is the last call to release all memory resources in use. Of course
+ * this takes place in a thread context.
+ */
+void mk_sched_worker_free(struct mk_server *server)
+{
+ int i;
+ pthread_t tid;
+ struct mk_sched_ctx *ctx = server->sched_ctx;
+ struct mk_sched_worker *worker = NULL;
+
+ pthread_mutex_lock(&mutex_worker_exit);
+
+ /*
+ * Fix Me: needs to implement API to make plugins release
+ * their resources first at WORKER LEVEL
+ */
+
+ /* External */
+ mk_plugin_exit_worker();
+ mk_vhost_fdt_worker_exit(server);
+ mk_cache_worker_exit();
+
+ /* Scheduler stuff */
+ tid = pthread_self();
+ for (i = 0; i < server->workers; i++) {
+ worker = &ctx->workers[i];
+ if (worker->tid == tid) {
+ break;
+ }
+ worker = NULL;
+ }
+
+ mk_bug(!worker);
+
+ /* FIXME!: there is nothing done here with the worker context */
+
+ /* Free master array (av queue & busy queue) */
+ mk_mem_free(MK_TLS_GET(mk_tls_sched_cs));
+ mk_mem_free(MK_TLS_GET(mk_tls_sched_cs_incomplete));
+ mk_mem_free(MK_TLS_GET(mk_tls_sched_worker_notif));
+ pthread_mutex_unlock(&mutex_worker_exit);
+}
+
+struct mk_sched_handler *mk_sched_handler_cap(char cap)
+{
+ if (cap == MK_CAP_HTTP) {
+ return &mk_http_handler;
+ }
+
+#ifdef MK_HAVE_HTTP2
+ else if (cap == MK_CAP_HTTP2) {
+ return &mk_http2_handler;
+ }
+#endif
+
+ return NULL;
+}
+
+/*
+ * Register a new client connection into the scheduler, this call takes place
+ * inside the worker/thread context.
+ */
+struct mk_sched_conn *mk_sched_add_connection(int remote_fd,
+ struct mk_server_listen *listener,
+ struct mk_sched_worker *sched,
+ struct mk_server *server)
+{
+ int ret;
+ int size;
+ struct mk_sched_handler *handler;
+ struct mk_sched_conn *conn;
+ struct mk_event *event;
+
+ /* Before to continue, we need to run plugin stage 10 */
+ ret = mk_plugin_stage_run_10(remote_fd, server);
+
+ /* Close connection, otherwise continue */
+ if (ret == MK_PLUGIN_RET_CLOSE_CONX) {
+ listener->network->network->close(listener->network, remote_fd);
+ MK_LT_SCHED(remote_fd, "PLUGIN_CLOSE");
+ return NULL;
+ }
+
+ handler = listener->protocol;
+ if (handler->sched_extra_size > 0) {
+ void *data;
+ size = (sizeof(struct mk_sched_conn) + handler->sched_extra_size);
+ data = mk_mem_alloc_z(size);
+ conn = (struct mk_sched_conn *) data;
+ }
+ else {
+ conn = mk_mem_alloc_z(sizeof(struct mk_sched_conn));
+ }
+
+ if (!conn) {
+ mk_err("[server] Could not register client");
+ return NULL;
+ }
+
+ event = &conn->event;
+ event->fd = remote_fd;
+ event->type = MK_EVENT_CONNECTION;
+ event->mask = MK_EVENT_EMPTY;
+ event->status = MK_EVENT_NONE;
+ conn->arrive_time = server->clock_context->log_current_utime;
+ conn->protocol = handler;
+ conn->net = listener->network->network;
+ conn->is_timeout_on = MK_FALSE;
+ conn->server_listen = listener;
+
+ /* Stream channel */
+ conn->channel.type = MK_CHANNEL_SOCKET; /* channel type */
+ conn->channel.fd = remote_fd; /* socket conn */
+ conn->channel.io = conn->net; /* network layer */
+ conn->channel.event = event; /* parent event ref */
+ mk_list_init(&conn->channel.streams);
+
+ /*
+ * Register the connections into the timeout_queue:
+ *
+ * When a new connection arrives, we cannot assume it contains some data
+ * to read, meaning the event loop may not get notifications and the protocol
+ * handler will never be called. So in order to avoid DDoS we always register
+ * this session in the timeout_queue for further lookup.
+ *
+ * The protocol handler is in charge to remove the session from the
+ * timeout_queue.
+ */
+ mk_sched_conn_timeout_add(conn, sched);
+
+ /* Linux trace message */
+ MK_LT_SCHED(remote_fd, "REGISTERED");
+
+ return conn;
+}
+
+static void mk_sched_thread_lists_init()
+{
+ struct mk_list *sched_cs_incomplete;
+
+ /* mk_tls_sched_cs_incomplete */
+ sched_cs_incomplete = mk_mem_alloc(sizeof(struct mk_list));
+ mk_list_init(sched_cs_incomplete);
+ MK_TLS_SET(mk_tls_sched_cs_incomplete, sched_cs_incomplete);
+}
+
+/* Register thread information. The caller thread is the thread information's owner */
+static int mk_sched_register_thread(struct mk_server *server)
+{
+ struct mk_sched_ctx *ctx = server->sched_ctx;
+ struct mk_sched_worker *worker;
+
+ /*
+ * If this thread slept inside this section, some other thread may touch
+ * server->worker_id.
+ * So protect it with a mutex, only one thread may handle server->worker_id.
+ *
+ * Note : Let's use the platform agnostic atomics we implemented in cmetrics here
+ * instead of a lock.
+ */
+ worker = &ctx->workers[server->worker_id];
+ worker->idx = server->worker_id++;
+ worker->tid = pthread_self();
+
+#if defined(__linux__)
+ /*
+ * Under Linux does not exists the difference between process and
+ * threads, everything is a thread in the kernel task struct, and each
+ * one has it's own numerical identificator: PID .
+ *
+ * Here we want to know what's the PID associated to this running
+ * task (which is different from parent Monkey PID), it can be
+ * retrieved with gettid() but Glibc does not export to userspace
+ * the syscall, we need to call it directly through syscall(2).
+ */
+ worker->pid = syscall(__NR_gettid);
+#elif defined(__APPLE__)
+ uint64_t tid;
+ pthread_threadid_np(NULL, &tid);
+ worker->pid = tid;
+#else
+ worker->pid = 0xdeadbeef;
+#endif
+
+ /* Initialize lists */
+ mk_list_init(&worker->timeout_queue);
+ worker->request_handler = NULL;
+
+ return worker->idx;
+}
+
+static void mk_signal_thread_sigpipe_safe()
+{
+#ifndef _WIN32
+ sigset_t old;
+ sigset_t set;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGPIPE);
+ pthread_sigmask(SIG_BLOCK, &set, &old);
+#endif
+}
+
+/* created thread, all these calls are in the thread context */
+void *mk_sched_launch_worker_loop(void *data)
+{
+ int ret;
+ int wid;
+ unsigned long len;
+ char *thread_name = 0;
+ struct mk_list *head;
+ struct mk_sched_worker_cb *wcb;
+ struct mk_sched_worker *sched = NULL;
+ struct mk_sched_notif *notif = NULL;
+ struct mk_sched_thread_conf *thinfo = data;
+ struct mk_sched_ctx *ctx;
+ struct mk_server *server;
+
+ server = thinfo->server;
+ ctx = server->sched_ctx;
+
+ /* Avoid SIGPIPE signals on this thread */
+ mk_signal_thread_sigpipe_safe();
+
+ /* Init specific thread cache */
+ mk_sched_thread_lists_init();
+ mk_cache_worker_init();
+
+ /* Virtual hosts: initialize per thread-vhost data */
+ mk_vhost_fdt_worker_init(server);
+
+ /* Register working thread */
+ wid = mk_sched_register_thread(server);
+ sched = &ctx->workers[wid];
+ sched->loop = mk_event_loop_create(MK_EVENT_QUEUE_SIZE);
+ if (!sched->loop) {
+ mk_err("Error creating Scheduler loop");
+ exit(EXIT_FAILURE);
+ }
+
+
+ sched->mem_pagesize = mk_utils_get_system_page_size();
+
+ /*
+ * Create the notification instance and link it to the worker
+ * thread-scope list.
+ */
+ notif = mk_mem_alloc_z(sizeof(struct mk_sched_notif));
+ MK_TLS_SET(mk_tls_sched_worker_notif, notif);
+
+ /* Register the scheduler channel to signal active workers */
+ ret = mk_event_channel_create(sched->loop,
+ &sched->signal_channel_r,
+ &sched->signal_channel_w,
+ notif);
+ if (ret < 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ mk_list_init(&sched->event_free_queue);
+ mk_list_init(&sched->threads);
+ mk_list_init(&sched->threads_purge);
+
+ /*
+ * ULONG_MAX BUG test only
+ * =======================
+ * to test the workaround we can use the following value:
+ *
+ * thinfo->closed_connections = 1000;
+ */
+
+ //thinfo->ctx = thconf->ctx;
+
+ /* Rename worker */
+ mk_string_build(&thread_name, &len, "monkey: wrk/%i", sched->idx);
+ mk_utils_worker_rename(thread_name);
+ mk_mem_free(thread_name);
+
+ /* Export known scheduler node to context thread */
+ MK_TLS_SET(mk_tls_sched_worker_node, sched);
+ mk_plugin_core_thread(server);
+
+ if (server->scheduler_mode == MK_SCHEDULER_REUSEPORT) {
+ sched->listeners = mk_server_listen_init(server);
+ if (!sched->listeners) {
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Unlock the conditional initializator */
+ pthread_mutex_lock(&server->pth_mutex);
+ server->pth_init = MK_TRUE;
+ pthread_cond_signal(&server->pth_cond);
+ pthread_mutex_unlock(&server->pth_mutex);
+
+ /* Invoke custom worker-callbacks defined by the scheduler (lib) */
+ mk_list_foreach(head, &server->sched_worker_callbacks) {
+ wcb = mk_list_entry(head, struct mk_sched_worker_cb, _head);
+ wcb->cb_func(wcb->data);
+ }
+
+ mk_mem_free(thinfo);
+
+ /* init server thread loop */
+ mk_server_worker_loop(server);
+
+ return 0;
+}
+
+/* Create thread which will be listening for incomings requests */
+int mk_sched_launch_thread(struct mk_server *server, pthread_t *tout)
+{
+ pthread_t tid;
+ pthread_attr_t attr;
+ struct mk_sched_thread_conf *thconf;
+
+ server->pth_init = MK_FALSE;
+
+ /*
+ * This lock is used for the 'pth_cond' conditional. Once the worker
+ * thread is ready it will signal the condition.
+ */
+ pthread_mutex_lock(&server->pth_mutex);
+
+ /* Thread data */
+ thconf = mk_mem_alloc_z(sizeof(struct mk_sched_thread_conf));
+ thconf->server = server;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ if (pthread_create(&tid, &attr, mk_sched_launch_worker_loop,
+ (void *) thconf) != 0) {
+ mk_libc_error("pthread_create");
+ pthread_mutex_unlock(&server->pth_mutex);
+ return -1;
+ }
+
+ *tout = tid;
+
+ /* Block until the child thread is ready */
+ while (!server->pth_init) {
+ pthread_cond_wait(&server->pth_cond, &server->pth_mutex);
+ }
+
+ pthread_mutex_unlock(&server->pth_mutex);
+
+ return 0;
+}
+
+/*
+ * The scheduler nodes are an array of struct mk_sched_worker type,
+ * each worker thread belongs to a scheduler node, on this function we
+ * allocate a scheduler node per number of workers defined.
+ */
+int mk_sched_init(struct mk_server *server)
+{
+ int size;
+ struct mk_sched_ctx *ctx;
+
+ ctx = mk_mem_alloc_z(sizeof(struct mk_sched_ctx));
+ if (!ctx) {
+ mk_libc_error("malloc");
+ return -1;
+ }
+
+ size = (sizeof(struct mk_sched_worker) * server->workers);
+ ctx->workers = mk_mem_alloc(size);
+ if (!ctx->workers) {
+ mk_libc_error("malloc");
+ mk_mem_free(ctx);
+ return -1;
+ }
+ memset(ctx->workers, '\0', size);
+
+ /* Initialize helpers */
+ pthread_mutex_init(&server->pth_mutex, NULL);
+ pthread_cond_init(&server->pth_cond, NULL);
+ server->pth_init = MK_FALSE;
+
+ /* Map context into server context */
+ server->sched_ctx = ctx;
+
+ /* The mk_thread_prepare call was replaced by mk_http_thread_initialize_tls
+ * which is called earlier.
+ */
+
+ return 0;
+}
+
+int mk_sched_exit(struct mk_server *server)
+{
+ struct mk_sched_ctx *ctx;
+
+ ctx = server->sched_ctx;
+ mk_sched_worker_cb_free(server);
+ mk_mem_free(ctx->workers);
+ mk_mem_free(ctx);
+
+ return 0;
+}
+
+void mk_sched_set_request_list(struct rb_root *list)
+{
+ MK_TLS_SET(mk_tls_sched_cs, list);
+}
+
+int mk_sched_remove_client(struct mk_sched_conn *conn,
+ struct mk_sched_worker *sched,
+ struct mk_server *server)
+{
+ struct mk_event *event;
+
+ /*
+ * Close socket and change status: we must invoke mk_epoll_del()
+ * because when the socket is closed is cleaned from the queue by
+ * the Kernel at its leisure, and we may get false events if we rely
+ * on that.
+ */
+ event = &conn->event;
+ MK_TRACE("[FD %i] Scheduler remove", event->fd);
+
+ mk_event_del(sched->loop, event);
+
+ /* Invoke plugins in stage 50 */
+ mk_plugin_stage_run_50(event->fd, server);
+
+ sched->closed_connections++;
+
+ /* Unlink from the red-black tree */
+ //rb_erase(&conn->_rb_head, &sched->rb_queue);
+ mk_sched_conn_timeout_del(conn);
+
+ /* Close at network layer level */
+ conn->net->close(conn->net->plugin, event->fd);
+
+ /* Release and return */
+ mk_channel_clean(&conn->channel);
+ mk_sched_event_free(&conn->event);
+ conn->status = MK_SCHED_CONN_CLOSED;
+
+ MK_LT_SCHED(remote_fd, "DELETE_CLIENT");
+ return 0;
+}
+
+/* FIXME: nobody is using this function, check back later */
+struct mk_sched_conn *mk_sched_get_connection(struct mk_sched_worker *sched,
+ int remote_fd)
+{
+ (void) sched;
+ (void) remote_fd;
+ return NULL;
+}
+
+/*
+ * For a given connection number, remove all resources associated: it can be
+ * used on any context such as: timeout, I/O errors, request finished,
+ * exceptions, etc.
+ */
+int mk_sched_drop_connection(struct mk_sched_conn *conn,
+ struct mk_sched_worker *sched,
+ struct mk_server *server)
+{
+ mk_sched_threads_destroy_conn(sched, conn);
+ return mk_sched_remove_client(conn, sched, server);
+}
+
+int mk_sched_check_timeouts(struct mk_sched_worker *sched,
+ struct mk_server *server)
+{
+ int client_timeout;
+ struct mk_sched_conn *conn;
+ struct mk_list *head;
+ struct mk_list *temp;
+
+ /* PENDING CONN TIMEOUT */
+ mk_list_foreach_safe(head, temp, &sched->timeout_queue) {
+ conn = mk_list_entry(head, struct mk_sched_conn, timeout_head);
+ if (conn->event.type & MK_EVENT_IDLE) {
+ continue;
+ }
+
+ client_timeout = conn->arrive_time + server->timeout;
+
+ /* Check timeout */
+ if (client_timeout <= server->clock_context->log_current_utime) {
+ MK_TRACE("Scheduler, closing fd %i due TIMEOUT",
+ conn->event.fd);
+ MK_LT_SCHED(conn->event.fd, "TIMEOUT_CONN_PENDING");
+ conn->protocol->cb_close(conn, sched, MK_SCHED_CONN_TIMEOUT,
+ server);
+ mk_sched_drop_connection(conn, sched, server);
+ }
+ }
+
+ return 0;
+}
+
+static int sched_thread_cleanup(struct mk_sched_worker *sched,
+ struct mk_list *list)
+{
+ int c = 0;
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_http_thread *mth;
+ (void) sched;
+
+ mk_list_foreach_safe(head, tmp, list) {
+ mth = mk_list_entry(head, struct mk_http_thread, _head);
+ mk_http_thread_destroy(mth);
+ c++;
+ }
+
+ return c;
+
+}
+
+int mk_sched_threads_purge(struct mk_sched_worker *sched)
+{
+ int c = 0;
+
+ c = sched_thread_cleanup(sched, &sched->threads_purge);
+ return c;
+}
+
+int mk_sched_threads_destroy_all(struct mk_sched_worker *sched)
+{
+ int c = 0;
+
+ c = sched_thread_cleanup(sched, &sched->threads_purge);
+ c += sched_thread_cleanup(sched, &sched->threads);
+
+ return c;
+}
+
+/*
+ * Destroy the thread contexts associated to the particular
+ * connection.
+ *
+ * Return the number of contexts destroyed.
+ */
+int mk_sched_threads_destroy_conn(struct mk_sched_worker *sched,
+ struct mk_sched_conn *conn)
+{
+ int c = 0;
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_http_thread *mth;
+ (void) sched;
+
+ mk_list_foreach_safe(head, tmp, &sched->threads) {
+ mth = mk_list_entry(head, struct mk_http_thread, _head);
+ if (mth->session->conn == conn) {
+ mk_http_thread_destroy(mth);
+ c++;
+ }
+ }
+ return c;
+}
+
+/*
+ * Scheduler events handler: lookup for event handler and invoke
+ * proper callbacks.
+ */
+int mk_sched_event_read(struct mk_sched_conn *conn,
+ struct mk_sched_worker *sched,
+ struct mk_server *server)
+{
+ int ret = 0;
+
+#ifdef MK_HAVE_TRACE
+ MK_TRACE("[FD %i] Connection Handler / read", conn->event.fd);
+#endif
+
+ /*
+ * When the event loop notify that there is some readable information
+ * from the socket, we need to invoke the protocol handler associated
+ * to this connection and also pass as a reference the 'read()' function
+ * that handle 'read I/O' operations, e.g:
+ *
+ * - plain sockets through liana will use just read(2)
+ * - ssl though mbedtls should use mk_mbedtls_read(..)
+ */
+ ret = conn->protocol->cb_read(conn, sched, server);
+ if (ret == -1) {
+ if (errno == EAGAIN) {
+ MK_TRACE("[FD %i] EAGAIN: need to read more data", conn->event.fd);
+ return 1;
+ }
+ return -1;
+ }
+
+ return ret;
+}
+
+int mk_sched_event_write(struct mk_sched_conn *conn,
+ struct mk_sched_worker *sched,
+ struct mk_server *server)
+{
+ int ret = -1;
+ size_t count;
+ struct mk_event *event;
+
+ MK_TRACE("[FD %i] Connection Handler / write", conn->event.fd);
+
+ ret = mk_channel_write(&conn->channel, &count);
+ if (ret == MK_CHANNEL_FLUSH || ret == MK_CHANNEL_BUSY) {
+ return 0;
+ }
+ else if (ret == MK_CHANNEL_DONE || ret == MK_CHANNEL_EMPTY) {
+ if (conn->protocol->cb_done) {
+ ret = conn->protocol->cb_done(conn, sched, server);
+ }
+ if (ret == -1) {
+ return -1;
+ }
+ else if (ret == 0) {
+ event = &conn->event;
+ mk_event_add(sched->loop, event->fd,
+ MK_EVENT_CONNECTION,
+ MK_EVENT_READ,
+ conn);
+ }
+ return 0;
+ }
+ else if (ret & MK_CHANNEL_ERROR) {
+ return -1;
+ }
+
+ /* avoid to make gcc cry :_( */
+ return -1;
+}
+
+int mk_sched_event_close(struct mk_sched_conn *conn,
+ struct mk_sched_worker *sched,
+ int type, struct mk_server *server)
+{
+ MK_TRACE("[FD %i] Connection Handler, closed", conn->event.fd);
+ mk_event_del(sched->loop, &conn->event);
+
+ if (type != MK_EP_SOCKET_DONE) {
+ conn->protocol->cb_close(conn, sched, type, server);
+ }
+ /*
+ * Remove the socket from the scheduler and make sure
+ * to disable all notifications.
+ */
+ mk_sched_drop_connection(conn, sched, server);
+ return 0;
+}
+
+void mk_sched_event_free(struct mk_event *event)
+{
+ struct mk_sched_worker *sched = mk_sched_get_thread_conf();
+
+ if ((event->type & MK_EVENT_IDLE) != 0) {
+ return;
+ }
+
+ event->type |= MK_EVENT_IDLE;
+ mk_list_add(&event->_head, &sched->event_free_queue);
+}
+
+/* Register a new callback function to invoke when a worker is created */
+int mk_sched_worker_cb_add(struct mk_server *server,
+ void (*cb_func) (void *),
+ void *data)
+{
+ struct mk_sched_worker_cb *wcb;
+
+ wcb = mk_mem_alloc(sizeof(struct mk_sched_worker_cb));
+ if (!wcb) {
+ return -1;
+ }
+
+ wcb->cb_func = cb_func;
+ wcb->data = data;
+ mk_list_add(&wcb->_head, &server->sched_worker_callbacks);
+ return 0;
+}
+
+void mk_sched_worker_cb_free(struct mk_server *server)
+{
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_sched_worker_cb *wcb;
+
+ mk_list_foreach_safe(head, tmp, &server->sched_worker_callbacks) {
+ wcb = mk_list_entry(head, struct mk_sched_worker_cb, _head);
+ mk_list_del(&wcb->_head);
+ mk_mem_free(wcb);
+ }
+}
+
+int mk_sched_send_signal(struct mk_sched_worker *worker, uint64_t val)
+{
+ ssize_t n;
+
+ /* When using libevent _mk_event_channel_create creates a unix socket
+ * instead of a pipe and windows doesn't us calling read / write on a
+ * socket instead of recv / send
+ */
+
+#ifdef _WIN32
+ n = send(worker->signal_channel_w, &val, sizeof(uint64_t), 0);
+#else
+ n = write(worker->signal_channel_w, &val, sizeof(uint64_t));
+#endif
+
+ if (n < 0) {
+ mk_libc_error("write");
+
+ return 0;
+ }
+
+ return 1;
+}
+
+int mk_sched_broadcast_signal(struct mk_server *server, uint64_t val)
+{
+ int i;
+ int count = 0;
+ struct mk_sched_ctx *ctx;
+ struct mk_sched_worker *worker;
+
+ ctx = server->sched_ctx;
+ for (i = 0; i < server->workers; i++) {
+ worker = &ctx->workers[i];
+
+ count += mk_sched_send_signal(worker, val);
+ }
+
+ return count;
+}
+
+/*
+ * Wait for all workers to finish: this function assumes that previously a
+ * MK_SCHED_SIGNAL_FREE_ALL was sent to the worker channels.
+ */
+int mk_sched_workers_join(struct mk_server *server)
+{
+ int i;
+ int count = 0;
+ struct mk_sched_ctx *ctx;
+ struct mk_sched_worker *worker;
+
+ ctx = server->sched_ctx;
+ for (i = 0; i < server->workers; i++) {
+ worker = &ctx->workers[i];
+ pthread_join(worker->tid, NULL);
+ count++;
+ }
+
+ return count;
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_server.c b/fluent-bit/lib/monkey/mk_server/mk_server.c
new file mode 100644
index 000000000..a84ef4485
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_server.c
@@ -0,0 +1,679 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_info.h>
+#include <monkey/monkey.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_scheduler.h>
+#include <monkey/mk_plugin.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_server.h>
+#include <monkey/mk_server_tls.h>
+#include <monkey/mk_scheduler.h>
+#include <monkey/mk_core.h>
+#include <monkey/mk_fifo.h>
+#include <monkey/mk_http_thread.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#ifndef _WIN32
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+pthread_key_t mk_server_fifo_key;
+
+static int mk_server_lib_notify_event_loop_break(struct mk_sched_worker *sched);
+
+/* Return the number of clients that can be attended */
+unsigned int mk_server_capacity(struct mk_server *server)
+{
+ int ret;
+ int cur;
+
+#ifndef _WIN32
+ struct rlimit lim;
+
+ /* Limit by system */
+ getrlimit(RLIMIT_NOFILE, &lim);
+ cur = lim.rlim_cur;
+
+ if (server->fd_limit > cur) {
+ lim.rlim_cur = server->fd_limit;
+ lim.rlim_max = server->fd_limit;
+
+ ret = setrlimit(RLIMIT_NOFILE, &lim);
+ if (ret == -1) {
+ mk_warn("Could not increase FDLimit to %i.", server->fd_limit);
+ }
+ else {
+ cur = server->fd_limit;
+ }
+ }
+ else if (server->fd_limit > 0) {
+ cur = server->fd_limit;
+ }
+
+#else
+ ret = 0;
+ cur = INT_MAX;
+
+ /* This is not the right way to plug this, according to raymond chen the only limit
+ * to fd count is free memory in their winsock provider and there are no other limits
+ * that I know of but I should still look for a more elegant solution. (even if it
+ * was just ignoring the server_capacity limit in scheduler.c: _next_target)
+ */
+#endif
+
+ return cur;
+}
+
+static inline
+struct mk_sched_conn *mk_server_listen_handler(struct mk_sched_worker *sched,
+ void *data,
+ struct mk_server *server)
+{
+ int ret;
+ int client_fd = -1;
+ struct mk_sched_conn *conn;
+ struct mk_server_listen *listener = data;
+
+ client_fd = mk_socket_accept(listener->server_fd);
+ if (mk_unlikely(client_fd == -1)) {
+ MK_TRACE("[server] Accept connection failed: %s", strerror(errno));
+ goto error;
+ }
+
+ conn = mk_sched_add_connection(client_fd, listener, sched, server);
+ if (mk_unlikely(!conn)) {
+ goto error;
+ }
+
+ ret = mk_event_add(sched->loop, client_fd,
+ MK_EVENT_CONNECTION, MK_EVENT_READ, conn);
+ if (mk_unlikely(ret != 0)) {
+ mk_err("[server] Error registering file descriptor: %s",
+ strerror(errno));
+ goto error;
+ }
+
+ sched->accepted_connections++;
+ MK_TRACE("[server] New connection arrived: FD %i", client_fd);
+ return conn;
+
+error:
+ if (client_fd != -1) {
+ listener->network->network->close(listener->network, client_fd);
+ }
+
+ return NULL;
+}
+
+void mk_server_listen_free()
+{
+ struct mk_list *list;
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_server_listen *listener;
+
+ list = MK_TLS_GET(mk_tls_server_listen);
+ mk_list_foreach_safe(head, tmp, list) {
+ listener = mk_list_entry(head, struct mk_server_listen, _head);
+ mk_list_del(&listener->_head);
+ mk_mem_free(listener);
+ }
+}
+
+void mk_server_listen_exit(struct mk_list *list)
+{
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_server_listen *listen;
+
+ if (!list) {
+ return;
+ }
+
+ mk_list_foreach_safe(head, tmp, list) {
+ listen = mk_list_entry(head, struct mk_server_listen, _head);
+ mk_event_closesocket(listen->server_fd);
+ mk_list_del(&listen->_head);
+ mk_mem_free(listen);
+ }
+
+ mk_mem_free(list);
+}
+
+struct mk_list *mk_server_listen_init(struct mk_server *server)
+{
+ int server_fd;
+ int reuse_port = MK_FALSE;
+ struct mk_list *head;
+ struct mk_list *listeners;
+ struct mk_event *event;
+ struct mk_server_listen *listener;
+ struct mk_sched_handler *protocol;
+ struct mk_plugin *plugin;
+ struct mk_config_listener *listen;
+
+ if (!server) {
+ goto error;
+ }
+
+ listeners = mk_mem_alloc(sizeof(struct mk_list));
+ mk_list_init(listeners);
+
+ if (server->scheduler_mode == MK_SCHEDULER_REUSEPORT) {
+ reuse_port = MK_TRUE;
+ }
+
+ mk_list_foreach(head, &server->listeners) {
+ listen = mk_list_entry(head, struct mk_config_listener, _head);
+
+ server_fd = mk_socket_server(listen->port,
+ listen->address,
+ reuse_port,
+ server);
+ if (server_fd >= 0) {
+ if (mk_socket_set_tcp_defer_accept(server_fd) != 0) {
+#if defined (__linux__)
+ mk_warn("[server] Could not set TCP_DEFER_ACCEPT");
+#endif
+ }
+
+ listener = mk_mem_alloc_z(sizeof(struct mk_server_listen));
+
+ /* configure the internal event_state */
+ event = &listener->event;
+ event->fd = server_fd;
+ event->type = MK_EVENT_LISTENER;
+ event->mask = MK_EVENT_EMPTY;
+ event->status = MK_EVENT_NONE;
+
+ /* continue with listener setup and linking */
+ listener->server_fd = server_fd;
+ listener->listen = listen;
+
+ if (listen->flags & MK_CAP_HTTP) {
+ protocol = mk_sched_handler_cap(MK_CAP_HTTP);
+ if (!protocol) {
+ mk_err("HTTP protocol not supported");
+ exit(EXIT_FAILURE);
+ }
+ listener->protocol = protocol;
+ }
+
+#ifdef MK_HAVE_HTTP2
+ if (listen->flags & MK_CAP_HTTP2) {
+ protocol = mk_sched_handler_cap(MK_CAP_HTTP2);
+ if (!protocol) {
+ mk_err("HTTP2 protocol not supported");
+ exit(EXIT_FAILURE);
+ }
+ listener->protocol = protocol;
+ }
+#endif
+ listener->network = mk_plugin_cap(MK_CAP_SOCK_PLAIN, server);
+
+ if (listen->flags & MK_CAP_SOCK_TLS) {
+ plugin = mk_plugin_cap(MK_CAP_SOCK_TLS, server);
+ if (!plugin) {
+ mk_err("SSL/TLS not supported");
+ exit(EXIT_FAILURE);
+ }
+ listener->network = plugin;
+ }
+
+ mk_list_add(&listener->_head, listeners);
+ }
+ else {
+ mk_err("[server] Failed to bind server socket to %s:%s.",
+ listen->address,
+ listen->port);
+ return NULL;
+ }
+ }
+
+ if (reuse_port == MK_TRUE) {
+ MK_TLS_SET(mk_tls_server_listen, listeners);
+ }
+
+ return listeners;
+
+error:
+ return NULL;
+}
+
+/* Here we launch the worker threads to attend clients */
+void mk_server_launch_workers(struct mk_server *server)
+{
+ int i;
+ pthread_t skip;
+
+ /* Launch workers */
+ for (i = 0; i < server->workers; i++) {
+ /* Spawn the thread */
+ mk_sched_launch_thread(server, &skip);
+ }
+}
+
+/*
+ * When using the FIFO interface, this function get's the FIFO worker
+ * context and register the pipe file descriptor into the main event
+ * loop.
+ *
+ * note: this function is invoked by each worker thread.
+ */
+static int mk_server_fifo_worker_setup(struct mk_event_loop *evl)
+{
+ int ret;
+ struct mk_fifo_worker *fw;
+
+ fw = pthread_getspecific(mk_server_fifo_key);
+ if (!fw) {
+ return -1;
+ }
+
+ ret = mk_event_add(evl, fw->channel[0],
+ MK_EVENT_FIFO, MK_EVENT_READ,
+ fw);
+ if (ret != 0) {
+ mk_err("[server] Error registering fifo worker channel: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * The loop_balancer() runs in the main process context and is considered
+ * the old-fashion way to handle connections. It have an event queue waiting
+ * for connections, once one arrives, it decides which worker (thread) may
+ * handle it registering the accept(2)ed file descriptor on the worker
+ * event monitored queue.
+ */
+void mk_server_loop_balancer(struct mk_server *server)
+{
+ size_t bytes;
+ uint64_t val;
+ int operation_flag;
+ struct mk_list *head;
+ struct mk_list *listeners;
+ struct mk_server_listen *listener;
+ struct mk_event *event;
+ struct mk_event_loop *evl;
+ struct mk_sched_worker *sched;
+ struct mk_event management_event;
+
+ /* Init the listeners */
+ listeners = mk_server_listen_init(server);
+ if (!listeners) {
+ mk_err("Failed to initialize listen sockets.");
+ return;
+ }
+
+ /* Create an event loop context */
+ evl = mk_event_loop_create(MK_EVENT_QUEUE_SIZE);
+ if (!evl) {
+ mk_err("Could not initialize event loop");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Register the listeners */
+ mk_list_foreach(head, listeners) {
+ listener = mk_list_entry(head, struct mk_server_listen, _head);
+ mk_event_add(evl, listener->server_fd,
+ MK_EVENT_LISTENER, MK_EVENT_READ,
+ listener);
+ }
+
+ memset(&management_event, 0, sizeof(struct mk_event));
+
+ mk_event_add(evl,
+ server->lib_ch_manager[0],
+ MK_EVENT_NOTIFICATION,
+ MK_EVENT_READ,
+ &management_event);
+
+ operation_flag = MK_TRUE;
+ while (operation_flag) {
+ mk_event_wait(evl);
+ mk_event_foreach(event, evl) {
+ if (event->mask & MK_EVENT_READ) {
+ /* This signal is sent by mk_stop and both this and
+ * mk_lib_worker are expecting it.
+ */
+ if (server->lib_ch_manager[0] == event->fd) {
+#ifdef _WIN32
+ bytes = recv(event->fd, &val, sizeof(uint64_t), MSG_WAITALL);
+#else
+ bytes = read(event->fd, &val, sizeof(uint64_t));
+#endif
+
+ if (bytes <= 0) {
+ return;
+ }
+
+ if (val == MK_SERVER_SIGNAL_STOP) {
+ operation_flag = MK_FALSE;
+
+ break;
+ }
+
+ continue;
+ }
+
+ /*
+ * Accept connection: determinate which thread may work on this
+ * new connection.
+ */
+ sched = mk_sched_next_target(server);
+ if (sched != NULL) {
+ mk_server_listen_handler(sched, event, server);
+
+ mk_server_lib_notify_event_loop_break(sched);
+
+#ifdef MK_HAVE_TRACE
+ int i;
+ struct mk_sched_ctx *ctx = server->sched_ctx;
+
+ for (i = 0; i < server->workers; i++) {
+ MK_TRACE("Worker Status");
+ MK_TRACE(" WID %i / conx = %llu",
+ ctx->workers[i].idx,
+ ctx->workers[i].accepted_connections -
+ ctx->workers[i].closed_connections);
+ }
+#endif
+ }
+ else {
+ mk_warn("[server] Over capacity.");
+ }
+ }
+ else if (event->mask & MK_EVENT_CLOSE) {
+ mk_err("[server] Error on socket %d: %s",
+ event->fd, strerror(errno));
+ }
+ }
+ }
+ mk_event_loop_destroy(evl);
+ mk_server_listen_exit(listeners);
+}
+
+/*
+ * This function is called when the scheduler is running in the REUSEPORT
+ * mode. That means that each worker is listening on shared TCP ports.
+ *
+ * When using shared TCP ports the Kernel decides to which worker the
+ * connection will be assigned.
+ */
+void mk_server_worker_loop(struct mk_server *server)
+{
+ int ret = -1;
+ int timeout_fd;
+ uint64_t val;
+ struct mk_event *event;
+ struct mk_event_loop *evl;
+ struct mk_list *list;
+ struct mk_list *head;
+ struct mk_sched_conn *conn;
+ struct mk_sched_worker *sched;
+ struct mk_server_listen *listener;
+ struct mk_server_timeout *server_timeout;
+
+ /* Get thread conf */
+ sched = mk_sched_get_thread_conf();
+ evl = sched->loop;
+
+ /*
+ * The worker will NOT process any connection until the master
+ * process through mk_server_loop() send us the green light
+ * signal MK_SERVER_SIGNAL_START.
+ */
+ mk_event_wait(evl);
+ mk_event_foreach(event, evl) {
+ if ((event->mask & MK_EVENT_READ) &&
+ event->type == MK_EVENT_NOTIFICATION) {
+ if (event->fd == sched->signal_channel_r) {
+ /* When using libevent _mk_event_channel_create creates a unix socket
+ * instead of a pipe and windows doesn't us calling read / write on a
+ * socket instead of recv / send
+ */
+#ifdef _WIN32
+ ret = recv(event->fd, &val, sizeof(val), MSG_WAITALL);
+#else
+ ret = read(event->fd, &val, sizeof(val));
+#endif
+ if (ret < 0) {
+ mk_libc_error("read");
+ continue;
+ }
+ if (val == MK_SERVER_SIGNAL_START) {
+ MK_TRACE("Worker %i started (SIGNAL_START)", sched->idx);
+ break;
+ }
+ }
+ }
+ }
+
+ if (server->scheduler_mode == MK_SCHEDULER_REUSEPORT) {
+ /* Register listeners */
+ list = MK_TLS_GET(mk_tls_server_listen);
+ mk_list_foreach(head, list) {
+ listener = mk_list_entry(head, struct mk_server_listen, _head);
+ mk_event_add(sched->loop, listener->server_fd,
+ MK_EVENT_LISTENER, MK_EVENT_READ,
+ listener);
+ }
+ }
+
+ /*
+ * If running in library mode, register the FIFO pipe file descriptors
+ * into the main event loop.
+ */
+ if (server->lib_mode == MK_TRUE) {
+ mk_server_fifo_worker_setup(evl);
+ }
+
+ /* create a new timeout file descriptor */
+ server_timeout = mk_mem_alloc_z(sizeof(struct mk_server_timeout));
+ MK_TLS_SET(mk_tls_server_timeout, server_timeout);
+ timeout_fd = mk_event_timeout_create(evl, server->timeout, 0, server_timeout);
+
+ while (1) {
+ mk_event_wait(evl);
+ mk_event_foreach(event, evl) {
+ ret = 0;
+ if (event->type & MK_EVENT_IDLE) {
+ continue;
+ }
+
+ if (event->type == MK_EVENT_CONNECTION) {
+ conn = (struct mk_sched_conn *) event;
+
+ if (event->mask & MK_EVENT_WRITE) {
+ MK_TRACE("[FD %i] Event WRITE", event->fd);
+ ret = mk_sched_event_write(conn, sched, server);
+ }
+
+ if (event->mask & MK_EVENT_READ) {
+ MK_TRACE("[FD %i] Event READ", event->fd);
+ ret = mk_sched_event_read(conn, sched, server);
+ }
+
+
+ if (event->mask & MK_EVENT_CLOSE && ret != -1) {
+ MK_TRACE("[FD %i] Event CLOSE", event->fd);
+ ret = -1;
+ }
+
+ if (ret < 0 && conn->status != MK_SCHED_CONN_CLOSED) {
+ MK_TRACE("[FD %i] Event FORCE CLOSE | ret = %i",
+ event->fd, ret);
+ mk_sched_event_close(conn, sched, MK_EP_SOCKET_CLOSED,
+ server);
+ }
+ }
+ else if (event->type == MK_EVENT_LISTENER) {
+ /*
+ * A new connection have been accepted..or failed, despite
+ * the result, we let the loop continue processing the other
+ * events triggered.
+ */
+ conn = mk_server_listen_handler(sched, event, server);
+ if (conn) {
+ //conn->event.mask = MK_EVENT_READ
+ //goto speed;
+ }
+ continue;
+ }
+ else if (event->type == MK_EVENT_CUSTOM) {
+ /*
+ * We got an event associated to a custom interface, that
+ * means a plugin registered some file descriptor on this
+ * event loop and an event was triggered. We pass the control
+ * to the defined event handler.
+ */
+ event->handler(event);
+ }
+ else if (event->type == MK_EVENT_NOTIFICATION) {
+#ifdef _WIN32
+ ret = recv(event->fd, &val, sizeof(val), MSG_WAITALL);
+#else
+ ret = read(event->fd, &val, sizeof(val));
+#endif
+ if (ret < 0) {
+ mk_libc_error("read");
+ continue;
+ }
+
+ if (event->fd == sched->signal_channel_r) {
+ if (val == MK_SCHED_SIGNAL_DEADBEEF) {
+ //FIXME:mk_sched_sync_counters();
+ continue;
+ }
+ else if (val == MK_SCHED_SIGNAL_FREE_ALL) {
+ if (timeout_fd > 0) {
+ mk_event_timeout_destroy(evl, server_timeout);
+ }
+ mk_mem_free(MK_TLS_GET(mk_tls_server_timeout));
+ mk_server_listen_exit(sched->listeners);
+ mk_event_loop_destroy(evl);
+ mk_sched_worker_free(server);
+ return;
+ }
+ else if (val == MK_SCHED_SIGNAL_EVENT_LOOP_BREAK) {
+ /* NOTE: This is just a notification that's sent to break out
+ * of the libevent loop in windows after accepting a new
+ * client
+ */
+ MK_TRACE("New client accepted, awesome!");
+ }
+ }
+ else if (event->fd == timeout_fd) {
+ mk_sched_check_timeouts(sched, server);
+ }
+ continue;
+ }
+ else if (event->type == MK_EVENT_THREAD) {
+ mk_http_thread_event(event);
+ continue;
+ }
+ else if (event->type == MK_EVENT_FIFO) {
+ mk_fifo_worker_read(event);
+ continue;
+ }
+ }
+ mk_sched_threads_purge(sched);
+ mk_sched_event_free_all(sched);
+ }
+}
+
+static int mk_server_lib_notify_event_loop_break(struct mk_sched_worker *sched)
+{
+ uint64_t val;
+
+ /* Check the channel is valid (enabled by library mode) */
+ if (sched->signal_channel_w <= 0) {
+ return -1;
+ }
+
+ val = MK_SCHED_SIGNAL_EVENT_LOOP_BREAK;
+
+#ifdef _WIN32
+ return send(sched->signal_channel_w, &val, sizeof(uint64_t), 0);
+#else
+ return write(sched->signal_channel_w, &val, sizeof(uint64_t));
+#endif
+}
+
+static int mk_server_lib_notify_started(struct mk_server *server)
+{
+ uint64_t val;
+
+ /* Check the channel is valid (enabled by library mode) */
+ if (server->lib_ch_start[1] <= 0) {
+ return -1;
+ }
+
+ val = MK_SERVER_SIGNAL_START;
+
+#ifdef _WIN32
+ return send(server->lib_ch_start[1], &val, sizeof(uint64_t), 0);
+#else
+ return write(server->lib_ch_start[1], &val, sizeof(uint64_t));
+#endif
+}
+
+void mk_server_loop(struct mk_server *server)
+{
+ uint64_t val;
+
+ /* Rename worker */
+ mk_utils_worker_rename("monkey: server");
+
+ if (server->lib_mode == MK_FALSE) {
+ mk_info("HTTP Server started");
+ }
+
+ /* Wake up workers */
+ val = MK_SERVER_SIGNAL_START;
+ mk_sched_broadcast_signal(server, val);
+
+ /* Signal lib caller (if any) */
+ mk_server_lib_notify_started(server);
+
+ /*
+ * When using REUSEPORT mode on the Scheduler, we need to signal
+ * them so they can start processing connections.
+ */
+ if (server->scheduler_mode == MK_SCHEDULER_REUSEPORT) {
+ /* do thing :) */
+ }
+ else {
+ /* FIXME!: this old mode needs some checks on library mode */
+ mk_server_loop_balancer(server);
+ }
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_socket.c b/fluent-bit/lib/monkey/mk_server/mk_socket.c
new file mode 100644
index 000000000..0277ab1c3
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_socket.c
@@ -0,0 +1,402 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#ifndef SOL_TCP
+#define SOL_TCP IPPROTO_TCP
+#endif
+
+#include <monkey/monkey.h>
+#include <monkey/mk_info.h>
+#include <monkey/mk_socket.h>
+#include <monkey/mk_kernel.h>
+#include <monkey/mk_net.h>
+#include <monkey/mk_core.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_plugin.h>
+
+#include <time.h>
+
+/*
+ * Example from:
+ * http://www.baus.net/on-tcp_cork
+ */
+int mk_socket_set_cork_flag(int fd, int state)
+{
+ MK_TRACE("Socket, set Cork Flag FD %i to %s", fd, (state ? "ON" : "OFF"));
+
+#if defined (TCP_CORK)
+ return setsockopt(fd, SOL_TCP, TCP_CORK, &state, sizeof(state));
+#elif defined (TCP_NOPUSH)
+ return setsockopt(fd, SOL_SOCKET, TCP_NOPUSH, &state, sizeof(state));
+#endif
+
+ return 0;
+}
+
+int mk_socket_set_nonblocking(int sockfd)
+{
+
+ MK_TRACE("Socket, set FD %i to non-blocking", sockfd);
+
+#ifdef _WIN32
+ u_long flags;
+
+ flags = 0;
+ if (SOCKET_ERROR == ioctlsocket(sockfd, FIONBIO, &flags)) {
+ mk_err("Can't set to non-blocking mode socket %i", sockfd);
+ return -1;
+ }
+#else
+ if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK) == -1) {
+ mk_err("Can't set to non-blocking mode socket %i", sockfd);
+ return -1;
+ }
+ fcntl(sockfd, F_SETFD, FD_CLOEXEC);
+#endif
+
+ return 0;
+}
+
+/*
+ * Enable the TCP_FASTOPEN feature for server side implemented in
+ * Linux Kernel >= 3.7, for more details read here:
+ *
+ * TCP Fast Open: expediting web services: http://lwn.net/Articles/508865/
+ */
+int mk_socket_set_tcp_fastopen(int sockfd)
+{
+#if defined (__linux__)
+ int qlen = 5;
+ return setsockopt(sockfd, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen));
+#endif
+
+ (void) sockfd;
+ return -1;
+}
+
+int mk_socket_set_tcp_nodelay(int sockfd)
+{
+ int on = 1;
+
+ return setsockopt(sockfd, SOL_TCP, TCP_NODELAY, &on, sizeof(on));
+}
+
+int mk_socket_set_tcp_defer_accept(int sockfd)
+{
+#if defined (__linux__)
+ int timeout = 0;
+
+ return setsockopt(sockfd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, sizeof(int));
+#else
+ (void) sockfd;
+ return -1;
+#endif
+}
+
+int mk_socket_set_tcp_reuseport(int sockfd)
+{
+ int on = 1;
+ return setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
+}
+
+int mk_socket_create(int domain, int type, int protocol)
+{
+ int fd;
+
+#ifdef SOCK_CLOEXEC
+ fd = socket(domain, type | SOCK_CLOEXEC, protocol);
+#else
+ fd = socket(domain, type, protocol);
+
+#ifndef _WIN32
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+#endif
+
+ if (fd == -1) {
+ mk_libc_error("socket");
+ return -1;
+ }
+
+ return fd;
+}
+
+int mk_socket_open(char *path, int async)
+{
+ int ret;
+ int socket_fd;
+ struct sockaddr_un address;
+
+ socket_fd = mk_socket_create(PF_UNIX, SOCK_STREAM, 0);
+ if (socket_fd == -1) {
+ return -1;
+ }
+
+ memset(&address, '\0', sizeof(struct sockaddr_un));
+ address.sun_family = AF_UNIX;
+ snprintf(address.sun_path, sizeof(address.sun_path), "%s", path);
+
+ if (async == MK_TRUE) {
+ mk_socket_set_nonblocking(socket_fd);
+ }
+
+ ret = connect(socket_fd, (struct sockaddr *) &address,
+ sizeof(struct sockaddr_un));
+ if (ret == -1) {
+ if (errno == EINPROGRESS) {
+ return socket_fd;
+ }
+ else {
+#ifdef MK_HAVE_TRACE
+ mk_libc_error("connect");
+#endif
+ close(socket_fd);
+ return -1;
+ }
+ }
+
+ return socket_fd;
+}
+
+
+int mk_socket_connect(char *host, int port, int async)
+{
+ int ret;
+ int socket_fd = -1;
+ char *port_str = 0;
+ unsigned long len;
+ struct addrinfo hints;
+ struct addrinfo *res, *rp;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ mk_string_build(&port_str, &len, "%d", port);
+
+ ret = getaddrinfo(host, port_str, &hints, &res);
+ mk_mem_free(port_str);
+ if(ret != 0) {
+ mk_err("Can't get addr info: %s", gai_strerror(ret));
+ return -1;
+ }
+ for (rp = res; rp != NULL; rp = rp->ai_next) {
+ socket_fd = mk_socket_create(rp->ai_family,
+ rp->ai_socktype, rp->ai_protocol);
+
+ if (socket_fd == -1) {
+ mk_warn("Error creating client socket, retrying");
+ continue;
+ }
+
+ if (async == MK_TRUE) {
+ mk_socket_set_nonblocking(socket_fd);
+ }
+
+ ret = connect(socket_fd,
+ (struct sockaddr *) rp->ai_addr, rp->ai_addrlen);
+ if (ret == -1) {
+ if (errno == EINPROGRESS) {
+ break;
+ }
+ else {
+ printf("%s", strerror(errno));
+ perror("connect");
+ exit(1);
+ close(socket_fd);
+ continue;
+ }
+ }
+ break;
+ }
+ freeaddrinfo(res);
+
+ if (rp == NULL)
+ return -1;
+
+ return socket_fd;
+}
+
+int mk_socket_reset(int socket)
+{
+ int status = 1;
+
+ if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &status, sizeof(int)) == -1) {
+ mk_libc_error("socket");
+ exit(EXIT_FAILURE);
+ }
+
+ return 0;
+}
+
+int mk_socket_bind(int socket_fd, const struct sockaddr *addr,
+ socklen_t addrlen, int backlog, struct mk_server *server)
+{
+ int ret;
+
+ ret = bind(socket_fd, addr, addrlen);
+ if( ret == -1 ) {
+ mk_warn("Error binding socket");
+ return ret;
+ }
+
+ /*
+ * Enable TCP_FASTOPEN by default: if for some reason this call fail,
+ * it will not affect the behavior of the server, in order to succeed,
+ * Monkey must be running in a Linux system with Kernel >= 3.7 and the
+ * tcp_fastopen flag enabled here:
+ *
+ * # cat /proc/sys/net/ipv4/tcp_fastopen
+ *
+ * To enable this feature just do:
+ *
+ * # echo 1 > /proc/sys/net/ipv4/tcp_fastopen
+ */
+ if (server->kernel_features & MK_KERNEL_TCP_FASTOPEN) {
+ ret = mk_socket_set_tcp_fastopen(socket_fd);
+ if (ret == -1) {
+ mk_warn("Could not set TCP_FASTOPEN");
+ }
+ }
+
+ ret = listen(socket_fd, backlog);
+ if(ret == -1 ) {
+ return -1;
+ }
+
+ return ret;
+}
+
+/* Just IPv4 for now... */
+int mk_socket_server(char *port, char *listen_addr,
+ int reuse_port, struct mk_server *server)
+{
+ int ret;
+ int socket_fd = -1;
+ struct addrinfo hints;
+ struct addrinfo *res, *rp;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+
+ mk_net_init();
+
+ ret = getaddrinfo(listen_addr, port, &hints, &res);
+ if(ret != 0) {
+ mk_err("Can't get addr info: %s", gai_strerror(ret));
+ return -1;
+ }
+
+ for (rp = res; rp != NULL; rp = rp->ai_next) {
+ socket_fd = mk_socket_create(rp->ai_family,
+ rp->ai_socktype, rp->ai_protocol);
+ if (socket_fd == -1) {
+ mk_warn("Error creating server socket, retrying");
+ continue;
+ }
+
+ ret = mk_socket_set_tcp_nodelay(socket_fd);
+ if (ret == -1) {
+ mk_warn("Could not set TCP_NODELAY");
+ }
+
+ mk_socket_reset(socket_fd);
+
+ /* Check if reuse port can be enabled on this socket */
+ if (reuse_port == MK_TRUE &&
+ (server->kernel_features & MK_KERNEL_SO_REUSEPORT)) {
+ ret = mk_socket_set_tcp_reuseport(socket_fd);
+ if (ret == -1) {
+ mk_warn("Could not use SO_REUSEPORT, using fair balancing mode");
+ server->scheduler_mode = MK_SCHEDULER_FAIR_BALANCING;
+ }
+ }
+
+ ret = mk_socket_bind(socket_fd, rp->ai_addr, rp->ai_addrlen,
+ MK_SOMAXCONN, server);
+ if(ret == -1) {
+ mk_err("Cannot listen on %s:%s", listen_addr, port);
+ freeaddrinfo(res);
+ return -1;
+ }
+ break;
+ }
+ freeaddrinfo(res);
+
+ if (rp == NULL)
+ return -1;
+
+ return socket_fd;
+}
+
+int mk_socket_ip_str(int socket_fd, char **buf, int size, unsigned long *len)
+{
+ int ret;
+ struct sockaddr_storage addr;
+ socklen_t s_len = sizeof(addr);
+
+ ret = getpeername(socket_fd, (struct sockaddr *) &addr, &s_len);
+
+ if (mk_unlikely(ret == -1)) {
+ MK_TRACE("[FD %i] Can't get addr for this socket", socket_fd);
+ return -1;
+ }
+
+ errno = 0;
+
+ if(addr.ss_family == AF_INET) {
+ if((inet_ntop(AF_INET, &((struct sockaddr_in *)&addr)->sin_addr,
+ *buf, size)) == NULL) {
+ mk_warn("mk_socket_ip_str: Can't get the IP text form (%i)", errno);
+ return -1;
+ }
+ }
+ else if(addr.ss_family == AF_INET6) {
+ if((inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr,
+ *buf, size)) == NULL) {
+ mk_warn("mk_socket_ip_str: Can't get the IP text form (%i)", errno);
+ return -1;
+ }
+ }
+
+ *len = strlen(*buf);
+ return 0;
+}
+
+int mk_socket_accept(int server_fd)
+{
+ int remote_fd;
+
+ struct sockaddr sock_addr;
+ socklen_t socket_size = sizeof(struct sockaddr);
+
+#ifdef MK_HAVE_ACCEPT4
+ remote_fd = accept4(server_fd, &sock_addr, &socket_size,
+ SOCK_NONBLOCK | SOCK_CLOEXEC);
+#else
+ remote_fd = accept(server_fd, &sock_addr, &socket_size);
+ mk_socket_set_nonblocking(remote_fd);
+#endif
+
+ return remote_fd;
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_stream.c b/fluent-bit/lib/monkey/mk_server/mk_stream.c
new file mode 100644
index 000000000..df0f1b0b8
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_stream.c
@@ -0,0 +1,338 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/monkey.h>
+#include <monkey/mk_stream.h>
+#include <assert.h>
+
+/* Create a new channel */
+struct mk_channel *mk_channel_new(int type, int fd)
+{
+ struct mk_channel *channel;
+
+ channel = mk_mem_alloc(sizeof(struct mk_channel));
+ if (!channel) {
+ return NULL;
+ }
+ channel->type = type;
+ channel->fd = fd;
+ channel->status = MK_CHANNEL_OK;
+ mk_list_init(&channel->streams);
+
+ return channel;
+}
+
+int mk_channel_release(struct mk_channel *channel)
+{
+ mk_mem_free(channel);
+ return 0;
+}
+
+static inline size_t channel_write_in_file(struct mk_channel *channel,
+ struct mk_stream_input *in)
+{
+ ssize_t bytes = 0;
+
+ MK_TRACE("[CH %i] STREAM_FILE [fd=%i], bytes=%lu",
+ channel->fd, in->fd, in->bytes_total);
+
+ /* Direct write */
+ bytes = mk_sched_conn_sendfile(channel,
+ in->fd,
+ &in->bytes_offset,
+ in->bytes_total
+ );
+ MK_TRACE("[CH=%d] [FD=%i] WRITE STREAM FILE: %lu bytes",
+ channel->fd, in->fd, bytes);
+
+ return bytes;
+}
+
+size_t mk_stream_size(struct mk_stream *stream)
+{
+ return (stream->bytes_total - stream->bytes_offset);
+}
+
+/*
+ * It 'intent' to write a few streams over the channel and alter the
+ * channel notification side if required: READ -> WRITE.
+ */
+int mk_channel_flush(struct mk_channel *channel)
+{
+ int ret = 0;
+ size_t count = 0;
+ size_t total = 0;
+ uint32_t stop = (MK_CHANNEL_DONE | MK_CHANNEL_ERROR | MK_CHANNEL_EMPTY);
+
+ do {
+ ret = mk_channel_write(channel, &count);
+ total += count;
+
+#ifdef MK_HAVE_TRACE
+ MK_TRACE("Channel flush: %d bytes", count);
+ if (ret & MK_CHANNEL_DONE) {
+ MK_TRACE("Channel was empty");
+ }
+ if (ret & MK_CHANNEL_ERROR) {
+ MK_TRACE("Channel error");
+ }
+ if (ret & MK_CHANNEL_EMPTY) {
+ MK_TRACE("Channel empty");
+ }
+#endif
+ } while (total <= 4096 && ((ret & stop) == 0));
+
+ if (ret == MK_CHANNEL_DONE) {
+ MK_TRACE("Channel done");
+ return ret;
+ }
+ else if (ret & (MK_CHANNEL_FLUSH | MK_CHANNEL_BUSY)) {
+ MK_TRACE("Channel FLUSH | BUSY");
+ if ((channel->event->mask & MK_EVENT_WRITE) == 0) {
+ mk_event_add(mk_sched_loop(),
+ channel->fd,
+ MK_EVENT_CONNECTION,
+ MK_EVENT_WRITE,
+ channel->event);
+ }
+ }
+
+ return ret;
+}
+
+int mk_stream_in_release(struct mk_stream_input *in)
+{
+ if (in->cb_finished) {
+ in->cb_finished(in);
+ }
+
+ mk_stream_input_unlink(in);
+ if (in->dynamic == MK_TRUE) {
+ mk_mem_free(in);
+ }
+
+ return 0;
+}
+
+int mk_channel_stream_write(struct mk_stream *stream, size_t *count)
+{
+ ssize_t bytes = 0;
+ struct mk_iov *iov;
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_channel *channel;
+ struct mk_stream_input *input;
+
+ channel = stream->channel;
+
+ /* Validate channel status */
+ if (channel->status != MK_CHANNEL_OK) {
+ return -MK_CHANNEL_ERROR;
+ }
+
+ /* Iterate inputs and process stream */
+ mk_list_foreach_safe(head, tmp, &stream->inputs) {
+ input = mk_list_entry(head, struct mk_stream_input, _head);
+ if (input->type == MK_STREAM_FILE) {
+ bytes = channel_write_in_file(channel, input);
+ }
+ else if (input->type == MK_STREAM_IOV) {
+ iov = input->buffer;
+ if (!iov) {
+ return MK_CHANNEL_EMPTY;
+ }
+
+ bytes = mk_sched_conn_writev(channel, iov);
+
+ MK_TRACE("[CH %i] STREAM_IOV, wrote %d bytes",
+ channel->fd, bytes);
+ if (bytes > 0) {
+ /* Perform the adjustment on mk_iov */
+ mk_iov_consume(iov, bytes);
+ }
+ }
+ else if (input->type == MK_STREAM_RAW) {
+ bytes = mk_sched_conn_write(channel,
+ input->buffer, input->bytes_total);
+ MK_TRACE("[CH %i] STREAM_RAW, bytes=%lu/%lu\n",
+ channel->fd, bytes, input->bytes_total);
+ }
+
+ if (bytes > 0) {
+ *count = bytes;
+ mk_stream_input_consume(input, bytes);
+
+ /* notification callback, optional */
+ if (stream->cb_bytes_consumed) {
+ stream->cb_bytes_consumed(stream, bytes);
+ }
+
+ if (input->cb_consumed) {
+ input->cb_consumed(input, bytes);
+ }
+
+ if (input->bytes_total == 0) {
+ MK_TRACE("Input done, unlinking (channel=%p)", channel);
+ mk_stream_in_release(input);
+ }
+ MK_TRACE("[CH %i] CHANNEL_FLUSH", channel->fd);
+ }
+ else if (bytes < 0) {
+ mk_stream_in_release(input);
+ return -MK_CHANNEL_ERROR;
+ }
+ else if (bytes == 0) {
+ mk_stream_in_release(input);
+ return -MK_CHANNEL_ERROR;
+ }
+ }
+
+ return bytes;
+}
+
+/* It perform a direct stream I/O write through the network layer */
+int mk_channel_write(struct mk_channel *channel, size_t *count)
+{
+ ssize_t bytes = -1;
+ struct mk_iov *iov;
+ struct mk_stream *stream = NULL;
+ struct mk_stream_input *input;
+
+ errno = 0;
+
+ if (mk_list_is_empty(&channel->streams) == 0) {
+ MK_TRACE("[CH %i] CHANNEL_EMPTY", channel->fd);
+ return MK_CHANNEL_EMPTY;
+ }
+
+ /* Get the input source */
+ stream = mk_list_entry_first(&channel->streams, struct mk_stream, _head);
+ if (mk_list_is_empty(&stream->inputs) == 0) {
+ return MK_CHANNEL_EMPTY;
+ }
+ input = mk_list_entry_first(&stream->inputs, struct mk_stream_input, _head);
+
+ /*
+ * Based on the Stream Input type we consume on that way, not all inputs
+ * requires to read from buffer, e.g: Static File, Pipes.
+ */
+ if (channel->type == MK_CHANNEL_SOCKET) {
+ if (input->type == MK_STREAM_FILE) {
+ bytes = channel_write_in_file(channel, input);
+ }
+ else if (input->type == MK_STREAM_IOV) {
+ iov = input->buffer;
+ if (!iov) {
+ return MK_CHANNEL_EMPTY;
+ }
+
+ bytes = mk_sched_conn_writev(channel, iov);
+
+ MK_TRACE("[CH %i] STREAM_IOV, wrote %d bytes",
+ channel->fd, bytes);
+ if (bytes > 0) {
+ /* Perform the adjustment on mk_iov */
+ mk_iov_consume(iov, bytes);
+ }
+ }
+ else if (input->type == MK_STREAM_RAW) {
+ bytes = mk_sched_conn_write(channel,
+ input->buffer, input->bytes_total);
+ MK_TRACE("[CH %i] STREAM_RAW, bytes=%lu/%lu",
+ channel->fd, bytes, input->bytes_total);
+ if (bytes > 0) {
+ /* DEPRECATED: consume_raw(input, bytes); */
+ }
+ }
+
+ if (bytes > 0) {
+ *count = bytes;
+ mk_stream_input_consume(input, bytes);
+
+ /* notification callback, optional */
+ if (stream->cb_bytes_consumed) {
+ stream->cb_bytes_consumed(stream, bytes);
+ }
+
+ if (input->cb_consumed) {
+ input->cb_consumed(input, bytes);
+ }
+
+ if (input->bytes_total == 0) {
+ MK_TRACE("Input done, unlinking (channel=%p)", channel);
+ mk_stream_in_release(input);
+ }
+
+ if (mk_list_is_empty(&stream->inputs) == 0) {
+ /* Everytime the stream is empty, we notify the trigger the cb */
+ if (stream->cb_finished) {
+ stream->cb_finished(stream);
+ }
+
+ if (mk_channel_is_empty(channel) == 0) {
+ MK_TRACE("[CH %i] CHANNEL_DONE", channel->fd);
+ return MK_CHANNEL_DONE;
+ }
+ else {
+ MK_TRACE("[CH %i] CHANNEL_FLUSH", channel->fd);
+ return MK_CHANNEL_FLUSH;
+ }
+ }
+
+ MK_TRACE("[CH %i] CHANNEL_FLUSH", channel->fd);
+ return MK_CHANNEL_FLUSH;
+ }
+ else if (bytes < 0) {
+ if (errno == EAGAIN) {
+ return MK_CHANNEL_BUSY;
+ }
+
+ mk_stream_in_release(input);
+ return MK_CHANNEL_ERROR;
+ }
+ else if (bytes == 0) {
+ mk_stream_in_release(input);
+ return MK_CHANNEL_ERROR;
+ }
+ }
+
+ return MK_CHANNEL_ERROR;
+}
+
+/* Remove any dynamic memory associated */
+int mk_channel_clean(struct mk_channel *channel)
+{
+ struct mk_list *tmp;
+ struct mk_list *tmp_in;
+ struct mk_list *head;
+ struct mk_list *head_in;
+ struct mk_stream *stream;
+ struct mk_stream_input *in;
+
+ mk_list_foreach_safe(head, tmp, &channel->streams) {
+ stream = mk_list_entry(head, struct mk_stream, _head);
+ mk_list_foreach_safe(head_in, tmp_in, &stream->inputs) {
+ in = mk_list_entry(head_in, struct mk_stream_input, _head);
+ mk_stream_in_release(in);
+ }
+ mk_stream_release(stream);
+ }
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_user.c b/fluent-bit/lib/monkey/mk_server/mk_user.c
new file mode 100644
index 000000000..7200ff08c
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_user.c
@@ -0,0 +1,175 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/monkey.h>
+#include <monkey/mk_user.h>
+#include <monkey/mk_http.h>
+#include <monkey/mk_http_status.h>
+#include <monkey/mk_core.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_config.h>
+
+#ifndef _WIN32
+#include <pwd.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <grp.h>
+
+int mk_user_init(struct mk_http_session *cs, struct mk_http_request *sr,
+ struct mk_server *server)
+{
+ int limit;
+ const int offset = 2; /* The user is defined after the '/~' string, so offset = 2 */
+ const int user_len = 255;
+ char user[/*user_len*/ 255]; /* VC++ Doesn't allow for this to be a const int*/
+ char *user_uri;
+ struct passwd *s_user;
+
+ if (sr->uri_processed.len <= 2) {
+ return -1;
+ }
+
+ limit = mk_string_char_search(sr->uri_processed.data + offset, '/',
+ sr->uri_processed.len);
+
+ if (limit == -1) {
+ limit = (sr->uri_processed.len) - offset;
+ }
+
+ if (limit + offset >= (user_len)) {
+ return -1;
+ }
+
+ memcpy(user, sr->uri_processed.data + offset, limit);
+ user[limit] = '\0';
+
+ MK_TRACE("user: '%s'", user);
+
+ /* Check system user */
+ if ((s_user = getpwnam(user)) == NULL) {
+ mk_http_error(MK_CLIENT_NOT_FOUND, cs, sr, server);
+ return -1;
+ }
+
+ if (sr->uri_processed.len > (unsigned int) (offset+limit)) {
+ user_uri = mk_mem_alloc(sr->uri_processed.len);
+ if (!user_uri) {
+ return -1;
+ }
+
+ memcpy(user_uri,
+ sr->uri_processed.data + (offset + limit),
+ sr->uri_processed.len - offset - limit);
+ user_uri[sr->uri_processed.len - offset - limit] = '\0';
+
+ mk_string_build(&sr->real_path.data, &sr->real_path.len,
+ "%s/%s%s",
+ s_user->pw_dir, server->conf_user_pub, user_uri);
+ mk_mem_free(user_uri);
+ }
+ else {
+ mk_string_build(&sr->real_path.data, &sr->real_path.len,
+ "%s/%s", s_user->pw_dir, server->conf_user_pub);
+ }
+
+ sr->user_home = MK_TRUE;
+ return 0;
+}
+
+/* Change process user */
+int mk_user_set_uidgid(struct mk_server *server)
+{
+ struct passwd *usr;
+
+ /* Launched by root ? */
+ if (geteuid() == 0 && server->user) {
+ struct rlimit rl;
+
+ if (getrlimit(RLIMIT_NOFILE, &rl)) {
+ mk_warn("cannot get resource limits");
+ }
+
+ /* Check if user exists */
+ if ((usr = getpwnam(server->user)) == NULL) {
+ mk_err("Invalid user '%s'", server->user);
+ goto out;
+ }
+
+ if (initgroups(server->user, usr->pw_gid) != 0) {
+ mk_err("Initgroups() failed");
+ }
+
+ /* Change process UID and GID */
+ if (setegid(usr->pw_gid) == -1) {
+ mk_err("I cannot change the GID to %u", usr->pw_gid);
+ }
+
+ if (seteuid(usr->pw_uid) == -1) {
+ mk_err("I cannot change the UID to %u", usr->pw_uid);
+ }
+
+ server->is_seteuid = MK_TRUE;
+ }
+
+ out:
+ /* Variables set for run checks on file permission */
+ //FIXME
+ //EUID = geteuid();
+ //EGID = getegid();
+
+ return 0;
+}
+
+/* Return process to the original user */
+int mk_user_undo_uidgid(struct mk_server *server)
+{
+ if (server->is_seteuid == MK_TRUE) {
+ if (setegid(0) < 0) {
+ mk_err("Can't restore effective GID");
+ }
+ if (seteuid(0) < 0) {
+ mk_err("Can't restore effective UID");
+ }
+ }
+ return 0;
+}
+
+#else
+/*
+ None of these functionalities are going to be available in windows at the moment
+*/
+
+int mk_user_init(struct mk_http_session* cs, struct mk_http_request* sr,
+ struct mk_server* server)
+{
+ return -1;
+}
+
+int mk_user_set_uidgid(struct mk_server* server)
+{
+ mk_err("Cannot impersonate users in windows");
+
+ return 0;
+}
+
+int mk_user_undo_uidgid(struct mk_server* server)
+{
+ return 0;
+}
+#endif
diff --git a/fluent-bit/lib/monkey/mk_server/mk_utils.c b/fluent-bit/lib/monkey/mk_server/mk_utils.c
new file mode 100644
index 000000000..443c0ec35
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_utils.c
@@ -0,0 +1,589 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/* local headers */
+#include <monkey/monkey.h>
+#include <monkey/mk_core.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_config.h>
+#include <monkey/mk_socket.h>
+#include <monkey/mk_clock.h>
+#include <monkey/mk_user.h>
+#include <monkey/mk_cache.h>
+#include <monkey/mk_tls.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <time.h>
+#include <inttypes.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#endif
+
+/* stacktrace */
+#ifndef _WIN32
+#include <dlfcn.h>
+#endif
+
+#ifdef MK_HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+
+#define MK_UTILS_GMT_DATEFORMAT "%a, %d %b %Y %H:%M:%S GMT"
+
+#ifdef _WIN32
+static struct tm* localtime_r(const time_t* timep, struct tm* result)
+{
+ localtime_s(result, timep);
+
+ return result;
+}
+
+static struct tm* gmtime_r(const time_t* timep, struct tm* result)
+{
+ gmtime_s(result, timep);
+
+ return result;
+}
+
+static time_t timegm(struct tm* timeptr)
+{
+ return _mkgmtime(timeptr);
+}
+#endif
+
+#ifdef _WIN32
+int mk_utils_get_system_core_count()
+{
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION *proc_info_buffer;
+ unsigned int result_entry_count;
+ unsigned int entry_index;
+ DWORD result_length;
+ int result_code;
+ int core_count;
+
+ core_count = 1;
+ result_length = 0;
+ proc_info_buffer = NULL;
+
+ result_code = GetLogicalProcessorInformation(proc_info_buffer, &result_length);
+ /* We're passing a null buffer, result_code has to be false */
+
+ if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) {
+ result_entry_count = result_length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
+ proc_info_buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION *) _alloca(result_length);
+
+ if(NULL != proc_info_buffer) {
+ result_code = GetLogicalProcessorInformation(proc_info_buffer, &result_length);
+
+ if (0 != result_code) {
+ core_count = 0;
+
+ for(entry_index = 0 ; entry_index < result_entry_count ; entry_index++) {
+ if(RelationProcessorCore == proc_info_buffer[entry_index].Relationship) {
+ core_count++;
+ }
+ }
+ }
+ }
+
+ /* Athread stack allocation error is a pretty serious
+ * error so in that case we let someone else handle it by returning a
+ * sane default (1 core)
+ */
+ }
+
+ return core_count;
+}
+
+int mk_utils_get_system_page_size()
+{
+ SYSTEM_INFO si;
+
+ GetSystemInfo(&si);
+
+ return si.dwPageSize;
+}
+
+#else
+int mk_utils_get_system_core_count()
+{
+ return sysconf(_SC_NPROCESSORS_ONLN);
+}
+
+int mk_utils_get_system_page_size()
+{
+ return sysconf(_SC_PAGESIZE);
+}
+
+#endif
+
+
+/* Date helpers */
+static const char mk_date_wd[][6] = {"Sun, ", "Mon, ", "Tue, ", "Wed, ", "Thu, ", "Fri, ", "Sat, "};
+static const char mk_date_ym[][5] = {"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ", "Jul ",
+ "Aug ", "Sep ", "Oct ", "Nov ", "Dec "};
+
+static int mk_utils_gmt_cache_get(char **data, time_t date)
+{
+ unsigned int i;
+ struct mk_gmt_cache *gcache = MK_TLS_GET(mk_tls_cache_gmtext);
+
+ if (mk_unlikely(!gcache)) {
+ return MK_FALSE;
+ }
+
+ for (i = 0; i < MK_GMT_CACHES; i++) {
+ if (date == gcache[i].time) {
+ memcpy(*data, gcache[i].text, 32);
+ gcache[i].hits++;
+ return MK_TRUE;
+ }
+ }
+
+ return MK_FALSE;
+}
+
+static void mk_utils_gmt_cache_add(char *data, time_t time)
+{
+ unsigned int i, min = 0;
+ struct mk_gmt_cache *gcache = MK_TLS_GET(mk_tls_cache_gmtext);
+
+ for (i = 1; i < MK_GMT_CACHES; i++) {
+ if (gcache[i].hits < gcache[min].hits)
+ min = i;
+ }
+
+ gcache[min].hits = 1;
+ gcache[min].time = time;
+ memcpy(gcache[min].text, data, 32);
+}
+
+/*
+ *This function given a unix time, set in a mk_ptr_t
+ * the date in the RFC1123 format like:
+ *
+ * Wed, 23 Jun 2010 22:32:01 GMT
+ *
+ * it also adds a 'CRLF' at the end
+ */
+int mk_utils_utime2gmt(char **data, time_t date)
+{
+ const int size = 31;
+ unsigned short year, mday, hour, min, sec;
+ char *buf=0;
+ struct tm *gtm;
+
+ if (date == 0) {
+ if ((date = time(NULL)) == -1) {
+ return -1;
+ }
+ }
+ else {
+ /* Maybe it's converted already? */
+ if (mk_utils_gmt_cache_get(data, date) == MK_TRUE) {
+ return size;
+ }
+ }
+
+ /* Convert unix time to struct tm */
+ gtm = MK_TLS_GET(mk_tls_cache_gmtime);
+
+ /* If this function was invoked from a non-thread context it should exit */
+ mk_bug(!gtm);
+ gtm = gmtime_r(&date, gtm);
+ if (!gtm) {
+ return -1;
+ }
+
+ /* struct tm -> tm_year counts number of years after 1900 */
+ year = gtm->tm_year + 1900;
+
+ /* Signed division is slow, by using unsigned we gain 25% speed */
+ mday = gtm->tm_mday;
+ hour = gtm->tm_hour;
+ min = gtm->tm_min;
+ sec = gtm->tm_sec;
+
+ /* Compose template */
+ buf = *data;
+
+ /* Week day */
+ memcpy(buf, mk_date_wd[gtm->tm_wday], 5);
+ buf += 5;
+
+ /* Day of the month */
+ *buf++ = ('0' + (mday / 10));
+ *buf++ = ('0' + (mday % 10));
+ *buf++ = ' ';
+
+ /* Month */
+ memcpy(buf, mk_date_ym[gtm->tm_mon], 4);
+ buf += 4;
+
+ /* Year */
+ *buf++ = ('0' + (year / 1000) % 10);
+ *buf++ = ('0' + (year / 100) % 10);
+ *buf++ = ('0' + (year / 10) % 10);
+ *buf++ = ('0' + (year % 10));
+ *buf++ = ' ';
+
+ /* Hour */
+ *buf++ = ('0' + (hour / 10));
+ *buf++ = ('0' + (hour % 10));
+ *buf++ = ':';
+
+ /* Minutes */
+ *buf++ = ('0' + (min / 10));
+ *buf++ = ('0' + (min % 10));
+ *buf++ = ':';
+
+ /* Seconds */
+ *buf++ = ('0' + (sec / 10));
+ *buf++ = ('0' + (sec % 10));
+
+ /* GMT Time zone + CRLF */
+ memcpy(buf, " GMT\r\n\0", 7);
+
+ /* Add new entry to the cache */
+ mk_utils_gmt_cache_add(*data, date);
+
+ /* Set mk_ptr_t data len */
+ return size;
+}
+
+time_t mk_utils_gmt2utime(char *date)
+{
+ time_t new_unix_time;
+ struct tm t_data;
+ memset(&t_data, 0, sizeof(struct tm));
+
+
+#ifdef _WIN32
+#pragma message("Since there is no strptime in windows we'll parse the date in a really crude way just to get it out of the way")
+
+ if (0 != strcmp(MK_UTILS_GMT_DATEFORMAT, "%a, %d %b %Y %H:%M:%S GMT")) {
+ return -1;
+ }
+
+ {
+ char *token;
+
+ token = strtok(date, " "); /* "%a, " */
+
+ if (NULL == token) {
+ return -1;
+ }
+
+ token = strtok(NULL, " "); /* "%d " */
+
+ if (NULL == token) {
+ return -1;
+ }
+
+ t_data.tm_mday = strtol(token, NULL, 10);
+
+ token = strtok(NULL, " "); /* "%b " */
+
+ if (NULL == token) {
+ return -1;
+ }
+
+ if(0 == _strnicmp(token, "jan", 3)){
+ t_data.tm_mon = 0;
+ }
+ else if(0 == _strnicmp(token, "feb", 3)){
+ t_data.tm_mon = 1;
+ }
+ else if(0 == _strnicmp(token, "mar", 3)){
+ t_data.tm_mon = 2;
+ }
+ else if(0 == _strnicmp(token, "apr", 3)){
+ t_data.tm_mon = 3;
+ }
+ else if(0 == _strnicmp(token, "may", 3)){
+ t_data.tm_mon = 4;
+ }
+ else if(0 == _strnicmp(token, "jun", 3)){
+ t_data.tm_mon = 5;
+ }
+ else if(0 == _strnicmp(token, "jul", 3)){
+ t_data.tm_mon = 6;
+ }
+ else if(0 == _strnicmp(token, "aug", 3)){
+ t_data.tm_mon = 7;
+ }
+ else if(0 == _strnicmp(token, "sep", 3)){
+ t_data.tm_mon = 8;
+ }
+ else if(0 == _strnicmp(token, "oct", 3)){
+ t_data.tm_mon = 9;
+ }
+ else if(0 == _strnicmp(token, "nov", 3)){
+ t_data.tm_mon = 10;
+ }
+ else if(0 == _strnicmp(token, "dec", 3)){
+ t_data.tm_mon = 11;
+ }
+ else {
+ return -1;
+ }
+
+ token = strtok(NULL, " "); /* "%Y " */
+
+ if (NULL == token) {
+ return -1;
+ }
+
+ t_data.tm_year = strtol(token, NULL, 10);
+
+ token = strtok(NULL, ":"); /* "%H:" */
+
+ if (NULL == token) {
+ return -1;
+ }
+
+ t_data.tm_hour = strtol(token, NULL, 10);
+
+ token = strtok(NULL, ":"); /* "%M:" */
+
+ if (NULL == token) {
+ return -1;
+ }
+
+ t_data.tm_min = strtol(token, NULL, 10);
+
+ token = strtok(NULL, " "); /* "%S " */
+
+ if (NULL == token) {
+ return -1;
+ }
+
+ t_data.tm_sec = strtol(token, NULL, 10);
+ }
+
+#else
+ if (!strptime(date, MK_UTILS_GMT_DATEFORMAT, (struct tm*)&t_data)) {
+ return -1;
+ }
+#endif
+
+ new_unix_time = timegm((struct tm *) &t_data);
+
+ return (new_unix_time);
+}
+
+int mk_buffer_cat(mk_ptr_t *p, char *buf1, int len1, char *buf2, int len2)
+{
+ /* Validate lengths */
+ if (mk_unlikely(len1 < 0 || len2 < 0)) {
+ return -1;
+ }
+
+ /* alloc space */
+ p->data = (char *) mk_mem_alloc(len1 + len2 + 1);
+
+ /* copy data */
+ memcpy(p->data, buf1, len1);
+ memcpy(p->data + len1, buf2, len2);
+ p->data[len1 + len2] = '\0';
+
+ /* assign len */
+ p->len = len1 + len2;
+
+ return 0;
+}
+
+/* Convert hexadecimal to int */
+int mk_utils_hex2int(char *hex, int len)
+{
+ int i = 0;
+ int res = 0;
+ char c;
+
+ while ((c = *hex++) && i < len) {
+ res *= 0x10;
+
+ if (c >= 'a' && c <= 'f') {
+ res += (c - 0x57);
+ }
+ else if (c >= 'A' && c <= 'F') {
+ res += (c - 0x37);
+ }
+ else if (c >= '0' && c <= '9') {
+ res += (c - 0x30);
+ }
+ else {
+ return -1;
+ }
+ i++;
+ }
+
+ if (res < 0) {
+ return -1;
+ }
+
+ return res;
+}
+
+/* If the URI contains hexa format characters it will return
+ * convert the Hexa values to ASCII character
+ */
+char *mk_utils_url_decode(mk_ptr_t uri)
+{
+ int tmp, hex_result;
+ unsigned int i;
+ int buf_idx = 0;
+ char *buf;
+ char hex[3];
+
+ if ((tmp = mk_string_char_search(uri.data, '%', uri.len)) < 0) {
+ return NULL;
+ }
+
+ i = tmp;
+
+ buf = mk_mem_alloc_z(uri.len + 1);
+ if (i > 0) {
+ memcpy(buf, uri.data, i);
+ buf_idx = i;
+ }
+
+ while (i < uri.len) {
+ if (uri.data[i] == '%' && i + 2 < uri.len) {
+ memcpy(hex, uri.data + i + 1, 2);
+ hex[2] = '\0';
+
+ hex_result = mk_utils_hex2int(hex, 2);
+
+ if (hex_result != -1) {
+ buf[buf_idx] = hex_result;
+ }
+ else {
+ mk_mem_free(buf);
+ return NULL;
+ }
+ i += 2;
+ }
+ else {
+ buf[buf_idx] = uri.data[i];
+ }
+ i++;
+ buf_idx++;
+ }
+ buf[buf_idx] = '\0';
+
+ return buf;
+}
+
+#ifndef MK_HAVE_BACKTRACE
+void mk_utils_stacktrace(void) {}
+#else
+void mk_utils_stacktrace(void)
+{
+ unsigned int i;
+ int ret;
+ size_t size;
+ void *arr[10];
+ Dl_info d;
+
+ printf("[stack trace]\n");
+ size = backtrace(arr, 10);
+
+ for (i = 1; i < size && i < 10; i++) {
+ ret = dladdr(arr[i], &d);
+ if (ret == 0 || !d.dli_sname) {
+ printf(" #%i 0x%016" PRIxPTR " in \?\?\?\?\?\?\?()\n",
+ (i - 1), (uintptr_t) arr[i]);
+ continue;
+ }
+
+ printf(" #%i 0x%016" PRIxPTR " in %s() from %s\n",
+ (i - 1), (uintptr_t) arr[i], d.dli_sname, d.dli_fname);
+ }
+}
+#endif
+
+
+
+/*
+ * This hash generation function is taken originally from Redis source code:
+ *
+ * https://github.com/antirez/redis/blob/unstable/src/dict.c#L109
+ *
+ * ----
+ * MurmurHash2, by Austin Appleby
+ * Note - This code makes a few assumptions about how your machine behaves -
+ * 1. We can read a 4-byte value from any address without crashing
+ * 2. sizeof(int) == 4
+ *
+ * And it has a few limitations -
+ *
+ * 1. It will not work incrementally.
+ * 2. It will not produce the same results on little-endian and big-endian
+ * machines.
+ */
+unsigned int mk_utils_gen_hash(const void *key, int len)
+{
+ /* 'm' and 'r' are mixing constants generated offline.
+ They're not really 'magic', they just happen to work well. */
+ uint32_t seed = 5381;
+ const uint32_t m = 0x5bd1e995;
+ const int r = 24;
+
+ /* Initialize the hash to a 'random' value */
+ uint32_t h = seed ^ len;
+
+ /* Mix 4 bytes at a time into the hash */
+ const unsigned char *data = (const unsigned char *)key;
+
+ while(len >= 4) {
+ uint32_t k = *(uint32_t*) data;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ len -= 4;
+ }
+
+ /* Handle the last few bytes of the input array */
+ switch(len) {
+ case 3: h ^= data[2] << 16; // fallthrough
+ case 2: h ^= data[1] << 8; // fallthrough
+ case 1: h ^= data[0]; h *= m;
+ };
+
+ /* Do a few final mixes of the hash to ensure the last few
+ * bytes are well-incorporated. */
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return (unsigned int) h;
+}
diff --git a/fluent-bit/lib/monkey/mk_server/mk_vhost.c b/fluent-bit/lib/monkey/mk_server/mk_vhost.c
new file mode 100644
index 000000000..2dc35fb1f
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/mk_vhost.c
@@ -0,0 +1,821 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_info.h>
+#include <monkey/monkey.h>
+#include <monkey/mk_core.h>
+#include <monkey/mk_vhost.h>
+#include <monkey/mk_vhost_tls.h>
+#include <monkey/mk_utils.h>
+#include <monkey/mk_http_status.h>
+#include <monkey/mk_info.h>
+
+#include <mk_core/mk_dirent.h>
+
+#include <re.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+static int str_to_regex(char *str, regex_t *reg)
+{
+ char *p = str;
+ regex_t *result;
+
+ while (*p) {
+ if (*p == ' ') *p = '|';
+ p++;
+ }
+
+ result = re_compile(str);
+
+ memcpy(reg, result, REGEXP_SIZE);
+
+ return 0;
+}
+
+/*
+ * This function is triggered upon thread creation (inside the thread
+ * context), here we configure per-thread data.
+ */
+int mk_vhost_fdt_worker_init(struct mk_server *server)
+{
+ int i;
+ int j;
+ struct mk_vhost *h;
+ struct mk_list *list;
+ struct mk_list *head;
+ struct vhost_fdt_host *fdt;
+ struct vhost_fdt_hash_table *ht;
+ struct vhost_fdt_hash_chain *hc;
+
+ if (server->fdt == MK_FALSE) {
+ return -1;
+ }
+
+ /*
+ * We are under a thread context and the main configuration is
+ * already in place. Now for every existent virtual host we are
+ * going to create the File Descriptor Table (FDT) which aims to
+ * hold references of 'open and shared' file descriptors under
+ * the Virtual Host context.
+ */
+
+ /*
+ * Under an initialization context we need to protect this critical
+ * section
+ */
+ pthread_mutex_lock(&server->vhost_fdt_mutex);
+
+ /*
+ * Initialize the thread FDT/Hosts list and create an entry per
+ * existent virtual host
+ */
+ list = mk_mem_alloc_z(sizeof(struct mk_list));
+ mk_list_init(list);
+
+ mk_list_foreach(head, &server->hosts) {
+ h = mk_list_entry(head, struct mk_vhost, _head);
+
+ fdt = mk_mem_alloc(sizeof(struct vhost_fdt_host));
+ fdt->host = h;
+
+ /* Initialize hash table */
+ for (i = 0; i < VHOST_FDT_HASHTABLE_SIZE; i++) {
+ ht = &fdt->hash_table[i];
+ ht->av_slots = VHOST_FDT_HASHTABLE_CHAINS;
+
+ /* for each chain under the hash table, set the fd */
+ for (j = 0; j < VHOST_FDT_HASHTABLE_CHAINS; j++) {
+ hc = &ht->chain[j];
+ hc->fd = -1;
+ hc->hash = 0;
+ hc->readers = 0;
+ }
+ }
+ mk_list_add(&fdt->_head, list);
+ }
+
+ MK_TLS_SET(mk_tls_vhost_fdt, list);
+ pthread_mutex_unlock(&server->vhost_fdt_mutex);
+
+ return 0;
+}
+
+int mk_vhost_fdt_worker_exit(struct mk_server *server)
+{
+ struct mk_list *list;
+ struct mk_list *head;
+ struct mk_list *tmp;
+ struct vhost_fdt_host *fdt;
+
+ if (server->fdt == MK_FALSE) {
+ return -1;
+ }
+
+ list = MK_TLS_GET(mk_tls_vhost_fdt);
+ mk_list_foreach_safe(head, tmp, list) {
+ fdt = mk_list_entry(head, struct vhost_fdt_host, _head);
+ mk_list_del(&fdt->_head);
+ mk_mem_free(fdt);
+ }
+
+ mk_mem_free(list);
+ return 0;
+}
+
+
+static inline
+struct vhost_fdt_hash_table *mk_vhost_fdt_table_lookup(int id, struct mk_vhost *host)
+{
+ struct mk_list *head;
+ struct mk_list *list;
+ struct vhost_fdt_host *fdt_host;
+ struct vhost_fdt_hash_table *ht = NULL;
+
+ list = MK_TLS_GET(mk_tls_vhost_fdt);
+ mk_list_foreach(head, list) {
+ fdt_host = mk_list_entry(head, struct vhost_fdt_host, _head);
+ if (fdt_host->host == host) {
+ ht = &fdt_host->hash_table[id];
+ return ht;
+ }
+ }
+
+ return ht;
+}
+
+static inline
+struct vhost_fdt_hash_chain
+*mk_vhost_fdt_chain_lookup(unsigned int hash, struct vhost_fdt_hash_table *ht)
+{
+ int i;
+ struct vhost_fdt_hash_chain *hc = NULL;
+
+ for (i = 0; i < VHOST_FDT_HASHTABLE_CHAINS; i++) {
+ hc = &ht->chain[i];
+ if (hc->hash == hash) {
+ return hc;
+ }
+ }
+
+ return NULL;
+}
+
+
+static inline int mk_vhost_fdt_open(int id, unsigned int hash,
+ struct mk_http_request *sr,
+ struct mk_server *server)
+{
+ int i;
+ int fd = -1;
+ struct vhost_fdt_hash_table *ht = NULL;
+ struct vhost_fdt_hash_chain *hc;
+
+ if (server->fdt == MK_FALSE) {
+ return open(sr->real_path.data, sr->file_info.flags_read_only);
+ }
+
+ ht = mk_vhost_fdt_table_lookup(id, sr->host_conf);
+ if (mk_unlikely(!ht)) {
+ return open(sr->real_path.data, sr->file_info.flags_read_only);
+ }
+
+ /* We got the hash table, now look around the chains array */
+ hc = mk_vhost_fdt_chain_lookup(hash, ht);
+ if (hc) {
+ /* Increment the readers and return the shared FD */
+ hc->readers++;
+ sr->vhost_fdt_id = id;
+ sr->vhost_fdt_hash = hash;
+ sr->vhost_fdt_enabled = MK_TRUE;
+ return hc->fd;
+ }
+
+ /*
+ * Get here means that no entry exists in the hash table for the
+ * requested file descriptor and hash, we must try to open the file
+ * and register the entry in the table.
+ */
+ fd = open(sr->real_path.data, sr->file_info.flags_read_only);
+ if (fd == -1) {
+ return -1;
+ }
+
+ /* If chains are full, just return the new FD, bad luck... */
+ if (ht->av_slots <= 0) {
+ return fd;
+ }
+
+ /* Register the new entry in an available slot */
+ for (i = 0; i < VHOST_FDT_HASHTABLE_CHAINS; i++) {
+ hc = &ht->chain[i];
+ if (hc->fd == -1) {
+ hc->fd = fd;
+ hc->hash = hash;
+ hc->readers++;
+ ht->av_slots--;
+
+ sr->vhost_fdt_id = id;
+ sr->vhost_fdt_hash = hash;
+ sr->vhost_fdt_enabled = MK_TRUE;
+
+ return fd;
+ }
+ }
+
+ return fd;
+}
+
+static inline int mk_vhost_fdt_close(struct mk_http_request *sr,
+ struct mk_server *server)
+{
+ int id;
+ unsigned int hash;
+ struct vhost_fdt_hash_table *ht = NULL;
+ struct vhost_fdt_hash_chain *hc;
+
+ if (server->fdt == MK_FALSE || sr->vhost_fdt_enabled == MK_FALSE) {
+ if (sr->in_file.fd > 0) {
+ return close(sr->in_file.fd);
+ }
+ return -1;
+ }
+
+ id = sr->vhost_fdt_id;
+ hash = sr->vhost_fdt_hash;
+
+ ht = mk_vhost_fdt_table_lookup(id, sr->host_conf);
+ if (mk_unlikely(!ht)) {
+ return close(sr->in_file.fd);
+ }
+
+ /* We got the hash table, now look around the chains array */
+ hc = mk_vhost_fdt_chain_lookup(hash, ht);
+ if (hc) {
+ /* Increment the readers and check if we should close */
+ hc->readers--;
+ sr->vhost_fdt_enabled = MK_FALSE;
+
+ if (hc->readers == 0) {
+ hc->fd = -1;
+ hc->hash = 0;
+ ht->av_slots++;
+ return close(sr->in_file.fd);
+ }
+ else {
+ return 0;
+ }
+ }
+ return close(sr->in_file.fd);
+}
+
+
+int mk_vhost_open(struct mk_http_request *sr, struct mk_server *server)
+{
+ int id;
+ int off;
+ unsigned int hash;
+
+ off = sr->host_conf->documentroot.len;
+ hash = mk_utils_gen_hash(sr->real_path.data + off,
+ sr->real_path.len - off);
+ id = (hash % VHOST_FDT_HASHTABLE_SIZE);
+
+ return mk_vhost_fdt_open(id, hash, sr, server);
+}
+
+int mk_vhost_close(struct mk_http_request *sr, struct mk_server *server)
+{
+ return mk_vhost_fdt_close(sr, server);
+}
+
+struct mk_vhost_handler *mk_vhost_handler_match(char *match,
+ void (*cb)(struct mk_http_request *,
+ void *),
+ void *data)
+{
+ int ret;
+ struct mk_vhost_handler *h;
+
+ h = mk_mem_alloc(sizeof(struct mk_vhost_handler));
+ if (!h) {
+ return NULL;
+ }
+ h->name = NULL;
+ h->cb = cb;
+ h->data = data;
+ h->match = mk_mem_alloc(REGEXP_SIZE);
+ if (!h->match) {
+ mk_mem_free(h);
+ return NULL;
+ }
+ mk_list_init(&h->params);
+
+ ret = str_to_regex(match, h->match);
+ if (ret == -1) {
+ mk_mem_free(h);
+ return NULL;
+ }
+
+ return h;
+}
+
+/*
+ * Open a virtual host configuration file and return a structure with
+ * definitions.
+ */
+struct mk_vhost *mk_vhost_read(char *path)
+{
+ int ret;
+ char *tmp;
+ char *host_low;
+ struct stat checkdir;
+ struct mk_vhost *host;
+ struct mk_vhost_alias *new_alias;
+ struct mk_vhost_error_page *err_page;
+ struct mk_rconf *cnf;
+ struct mk_rconf_section *section_host;
+ struct mk_rconf_section *section_ep;
+ struct mk_rconf_section *section_handlers;
+ struct mk_rconf_entry *entry_ep;
+ struct mk_string_line *entry;
+ struct mk_list *head, *list, *line;
+ struct mk_vhost_handler *h_handler;
+ struct mk_vhost_handler_param *h_param;
+
+ /* Read configuration file */
+ cnf = mk_rconf_open(path);
+ if (!cnf) {
+ mk_err("Configuration error, aborting.");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Read 'HOST' section */
+ section_host = mk_rconf_section_get(cnf, "HOST");
+ if (!section_host) {
+ mk_err("Invalid config file %s", path);
+ return NULL;
+ }
+
+ /* Alloc configuration node */
+ host = mk_mem_alloc_z(sizeof(struct mk_vhost));
+ host->config = cnf;
+ host->file = mk_string_dup(path);
+
+ /* Init list for host name aliases */
+ mk_list_init(&host->server_names);
+
+ /* Init list for custom error pages */
+ mk_list_init(&host->error_pages);
+
+ /* Init list for content handlers */
+ mk_list_init(&host->handlers);
+
+ /* Lookup Servername */
+ list = mk_rconf_section_get_key(section_host, "Servername", MK_RCONF_LIST);
+ if (!list) {
+ mk_err("Hostname does not contain a Servername");
+ exit(EXIT_FAILURE);
+ }
+
+ mk_list_foreach(head, list) {
+ entry = mk_list_entry(head, struct mk_string_line, _head);
+ if (entry->len > MK_HOSTNAME_LEN - 1) {
+ continue;
+ }
+
+ /* Hostname to lowercase */
+ host_low = mk_string_tolower(entry->val);
+
+ /* Alloc node */
+ new_alias = mk_mem_alloc_z(sizeof(struct mk_vhost_alias));
+ new_alias->name = mk_mem_alloc_z(entry->len + 1);
+ strncpy(new_alias->name, host_low, entry->len);
+ mk_mem_free(host_low);
+
+ new_alias->len = entry->len;
+
+ mk_list_add(&new_alias->_head, &host->server_names);
+ }
+ mk_string_split_free(list);
+
+ /* Lookup document root handled by a mk_ptr_t */
+ host->documentroot.data = mk_rconf_section_get_key(section_host,
+ "DocumentRoot",
+ MK_RCONF_STR);
+ if (!host->documentroot.data) {
+ mk_err("Missing DocumentRoot entry on %s file", path);
+ mk_rconf_free(cnf);
+ mk_mem_free(host->file);
+ mk_mem_free(host);
+ return NULL;
+ }
+
+ host->documentroot.len = strlen(host->documentroot.data);
+
+ /* Validate document root configured */
+ if (stat(host->documentroot.data, &checkdir) == -1) {
+ mk_err("Invalid path to DocumentRoot in %s", path);
+ }
+ else if (!(checkdir.st_mode & S_IFDIR)) {
+ mk_err("DocumentRoot variable in %s has an invalid directory path", path);
+ }
+
+ if (mk_list_is_empty(&host->server_names) == 0) {
+ mk_rconf_free(cnf);
+ mk_mem_free(host->file);
+ mk_mem_free(host);
+ return NULL;
+ }
+
+ /* Check Virtual Host redirection */
+ host->header_redirect.data = NULL;
+ host->header_redirect.len = 0;
+
+ tmp = mk_rconf_section_get_key(section_host,
+ "Redirect",
+ MK_RCONF_STR);
+ if (tmp) {
+ host->header_redirect.data = mk_string_dup(tmp);
+ host->header_redirect.len = strlen(tmp);
+ mk_mem_free(tmp);
+ }
+
+ /* Error Pages */
+ section_ep = mk_rconf_section_get(cnf, "ERROR_PAGES");
+ if (section_ep) {
+ mk_list_foreach(head, &section_ep->entries) {
+ entry_ep = mk_list_entry(head, struct mk_rconf_entry, _head);
+
+ int ep_status = -1;
+ char *ep_file = NULL;
+ unsigned long len;
+
+ ep_status = atoi(entry_ep->key);
+ ep_file = entry_ep->val;
+
+ /* Validate input values */
+ if (ep_status < MK_CLIENT_BAD_REQUEST ||
+ ep_status > MK_SERVER_HTTP_VERSION_UNSUP ||
+ ep_file == NULL) {
+ continue;
+ }
+
+ /* Alloc error page node */
+ err_page = mk_mem_alloc_z(sizeof(struct mk_vhost_error_page));
+ err_page->status = ep_status;
+ err_page->file = mk_string_dup(ep_file);
+ err_page->real_path = NULL;
+ mk_string_build(&err_page->real_path, &len, "%s/%s",
+ host->documentroot.data, err_page->file);
+
+ MK_TRACE("Map error page: status %i -> %s", err_page->status, err_page->file);
+
+ /* Link page to the error page list */
+ mk_list_add(&err_page->_head, &host->error_pages);
+ }
+ }
+
+ /* Handlers */
+ int i;
+ int params;
+ struct mk_list *head_line;
+
+ section_handlers = mk_rconf_section_get(cnf, "HANDLERS");
+ if (!section_handlers) {
+ return host;
+ }
+ mk_list_foreach(head, &section_handlers->entries) {
+ entry_ep = mk_list_entry(head, struct mk_rconf_entry, _head);
+ if (strncasecmp(entry_ep->key, "Match", strlen(entry_ep->key)) == 0) {
+ line = mk_string_split_line(entry_ep->val);
+ if (!line) {
+ continue;
+ }
+ h_handler = mk_mem_alloc(sizeof(struct mk_vhost_handler));
+ if (!h_handler) {
+ exit(EXIT_FAILURE);
+ }
+ h_handler->match = mk_mem_alloc(REGEXP_SIZE);
+ if (!h_handler->match) {
+ mk_mem_free(h_handler);
+ exit(EXIT_FAILURE);
+ }
+ h_handler->cb = NULL;
+ mk_list_init(&h_handler->params);
+
+ i = 0;
+ params = 0;
+ mk_list_foreach(head_line, line) {
+ entry = mk_list_entry(head_line, struct mk_string_line, _head);
+ switch (i) {
+ case 0:
+ ret = str_to_regex(entry->val, h_handler->match);
+ if (ret == -1) {
+ return NULL;
+ }
+ break;
+ case 1:
+ h_handler->name = mk_string_dup(entry->val);
+ break;
+ default:
+ /* link parameters */
+ h_param = mk_mem_alloc(sizeof(struct mk_vhost_handler_param));
+ h_param->p.data = mk_string_dup(entry->val);
+ h_param->p.len = entry->len;
+ mk_list_add(&h_param->_head, &h_handler->params);
+ params++;
+ };
+ i++;
+ }
+ h_handler->n_params = params;
+ mk_string_split_free(line);
+
+ if (i < 2) {
+ mk_err("[Host Handlers] invalid Match value\n");
+ exit(EXIT_FAILURE);
+ }
+ mk_list_add(&h_handler->_head, &host->handlers);
+ }
+ }
+
+
+ return host;
+}
+
+int mk_vhost_map_handlers(struct mk_server *server)
+{
+ int n = 0;
+ struct mk_list *head;
+ struct mk_list *head_handler;
+ struct mk_vhost *host;
+ struct mk_vhost_handler *h_handler;
+ struct mk_plugin *p;
+
+ mk_list_foreach(head, &server->hosts) {
+ host = mk_list_entry(head, struct mk_vhost, _head);
+ mk_list_foreach(head_handler, &host->handlers) {
+ h_handler = mk_list_entry(head_handler,
+ struct mk_vhost_handler, _head);
+
+ /* Lookup plugin by name */
+ p = mk_plugin_lookup(h_handler->name, server);
+ if (!p) {
+ mk_err("Plugin '%s' was not loaded", h_handler->name);
+ continue;
+ }
+
+ if (p->hooks != MK_PLUGIN_STAGE) {
+ mk_err("Plugin '%s' is not a handler", h_handler->name);
+ continue;
+ }
+
+ h_handler->handler = p;
+ n++;
+ }
+ }
+
+ return n;
+}
+
+void mk_vhost_set_single(char *path, struct mk_server *server)
+{
+ struct mk_vhost *host;
+ struct mk_vhost_alias *halias;
+ struct stat checkdir;
+
+ /* Set the default host */
+ host = mk_mem_alloc_z(sizeof(struct mk_vhost));
+ mk_list_init(&host->error_pages);
+ mk_list_init(&host->server_names);
+
+ /* Prepare the unique alias */
+ halias = mk_mem_alloc_z(sizeof(struct mk_vhost_alias));
+ halias->name = mk_string_dup("127.0.0.1");
+ mk_list_add(&halias->_head, &host->server_names);
+
+ host->documentroot.data = mk_string_dup(path);
+ host->documentroot.len = strlen(path);
+ host->header_redirect.data = NULL;
+
+ /* Validate document root configured */
+ if (stat(host->documentroot.data, &checkdir) == -1) {
+ mk_err("Invalid path to DocumentRoot in %s", path);
+ exit(EXIT_FAILURE);
+ }
+ else if (!(checkdir.st_mode & S_IFDIR)) {
+ mk_err("DocumentRoot variable in %s has an invalid directory path", path);
+ exit(EXIT_FAILURE);
+ }
+ mk_list_add(&host->_head, &server->hosts);
+ mk_list_init(&host->handlers);
+}
+
+/* Given a configuration directory, start reading the virtual host entries */
+void mk_vhost_init(char *path, struct mk_server *server)
+{
+ DIR *dir;
+ unsigned long len;
+ char *buf = 0;
+ char *sites = 0;
+ char *file;
+ struct mk_vhost *p_host; /* debug */
+ struct dirent *ent;
+ struct file_info f_info;
+ int ret;
+
+ if (!server->conf_sites) {
+ mk_warn("[vhost] skipping default site");
+ return;
+ }
+
+ /* Read default virtual host file */
+ mk_string_build(&sites, &len, "%s/%s/",
+ path, server->conf_sites);
+ ret = mk_file_get_info(sites, &f_info, MK_FILE_EXISTS);
+ if (ret == -1 || f_info.is_directory == MK_FALSE) {
+ mk_mem_free(sites);
+ sites = server->conf_sites;
+ }
+
+ mk_string_build(&buf, &len, "%s/default", sites);
+
+ p_host = mk_vhost_read(buf);
+ if (!p_host) {
+ mk_err("Error parsing main configuration file 'default'");
+ }
+ mk_list_add(&p_host->_head, &server->hosts);
+ server->nhosts++;
+ mk_mem_free(buf);
+ buf = NULL;
+
+
+ /* Read all virtual hosts defined in sites/ */
+ if (!(dir = opendir(sites))) {
+ mk_mem_free(sites);
+ mk_err("Could not open %s", sites);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Reading content */
+ while ((ent = readdir(dir)) != NULL) {
+ if (ent->d_name[0] == '.') {
+ continue;
+ }
+ if (strcmp((char *) ent->d_name, "..") == 0) {
+ continue;
+ }
+ if (ent->d_name[strlen(ent->d_name) - 1] == '~') {
+ continue;
+ }
+ if (strcasecmp((char *) ent->d_name, "default") == 0) {
+ continue;
+ }
+ file = NULL;
+ mk_string_build(&file, &len, "%s/%s", sites, ent->d_name);
+
+ p_host = mk_vhost_read(file);
+ mk_mem_free(file);
+ if (!p_host) {
+ continue;
+ }
+ else {
+ mk_list_add(&p_host->_head, &server->hosts);
+ server->nhosts++;
+ }
+ }
+ closedir(dir);
+ mk_mem_free(sites);
+}
+
+
+/* Lookup a registered virtual host based on the given 'host' input */
+int mk_vhost_get(mk_ptr_t host, struct mk_vhost **vhost,
+ struct mk_vhost_alias **alias,
+ struct mk_server *server)
+{
+ struct mk_vhost *entry_host;
+ struct mk_vhost_alias *entry_alias;
+ struct mk_list *head_vhost, *head_alias;
+
+ mk_list_foreach(head_vhost, &server->hosts) {
+ entry_host = mk_list_entry(head_vhost, struct mk_vhost, _head);
+ mk_list_foreach(head_alias, &entry_host->server_names) {
+ entry_alias = mk_list_entry(head_alias, struct mk_vhost_alias, _head);
+ if (entry_alias->len == host.len &&
+ strncmp(entry_alias->name, host.data, host.len) == 0) {
+ *vhost = entry_host;
+ *alias = entry_alias;
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+static void mk_vhost_handler_free(struct mk_vhost_handler *h)
+{
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_vhost_handler_param *param;
+
+ /* Release Params */
+ mk_list_foreach_safe(head, tmp, &h->params) {
+ param = mk_list_entry(head, struct mk_vhost_handler_param, _head);
+ mk_list_del(&param->_head);
+ mk_mem_free(param->p.data);
+ mk_mem_free(param);
+ }
+
+ mk_mem_free(h->match);
+ mk_mem_free(h->name);
+ mk_mem_free(h);
+}
+
+int mk_vhost_destroy(struct mk_vhost *vh)
+{
+ struct mk_vhost_alias *halias = NULL;
+ struct mk_vhost_handler *hhandler;
+ struct mk_vhost_error_page *ep;
+ struct mk_list *head;
+ struct mk_list *tmp;
+
+ if (vh) {
+ /* Free aliases or servernames */
+ mk_list_foreach_safe(head, tmp, &vh->server_names) {
+ halias = mk_list_entry(head, struct mk_vhost_alias, _head);
+ if (halias) {
+ mk_list_del(&halias->_head);
+ if (halias->name) {
+ mk_mem_free(halias->name);
+ }
+ mk_mem_free(halias);
+ }
+ }
+
+ /* Handlers */
+ mk_list_foreach_safe(head, tmp, &vh->handlers) {
+ hhandler = mk_list_entry(head, struct mk_vhost_handler, _head);
+ if (hhandler) {
+ mk_vhost_handler_free(hhandler);
+ }
+ }
+
+ /* Free error pages */
+ mk_list_foreach_safe(head, tmp, &vh->error_pages) {
+ ep = mk_list_entry(head, struct mk_vhost_error_page, _head);
+ if (ep) {
+ mk_list_del(&ep->_head);
+ if (ep->file) {
+ mk_mem_free(ep->file);
+ }
+ if (ep->real_path) {
+ mk_mem_free(ep->real_path);
+ }
+ mk_mem_free(ep);
+ }
+ }
+ mk_ptr_free(&vh->documentroot);
+
+ /* Free source configuration */
+ if (vh->config) {
+ mk_rconf_free(vh->config);
+ }
+ mk_list_del(&vh->_head);
+ if (vh->file) {
+ mk_mem_free(vh->file);
+ }
+
+ mk_mem_free(vh);
+ }
+ return 0;
+}
+
+void mk_vhost_free_all(struct mk_server *server)
+{
+ struct mk_vhost *host;
+ struct mk_list *head;
+ struct mk_list *tmp;
+
+ mk_list_foreach_safe(head, tmp, &server->hosts) {
+ host = mk_list_entry(head, struct mk_vhost, _head);
+ mk_vhost_destroy(host);
+ }
+}
diff --git a/fluent-bit/lib/monkey/mk_server/monkey.c b/fluent-bit/lib/monkey/mk_server/monkey.c
new file mode 100644
index 000000000..68513d21b
--- /dev/null
+++ b/fluent-bit/lib/monkey/mk_server/monkey.c
@@ -0,0 +1,241 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <mk_core/mk_pthread.h>
+#include <mk_core/mk_event.h>
+
+#include <monkey/mk_scheduler.h>
+#include <monkey/mk_plugin.h>
+#include <monkey/mk_clock.h>
+#include <monkey/mk_thread.h>
+#include <monkey/mk_mimetype.h>
+#include <monkey/mk_http_thread.h>
+
+pthread_once_t mk_server_tls_setup_once = PTHREAD_ONCE_INIT;
+
+static void mk_set_up_tls_keys()
+{
+ MK_INIT_INITIALIZE_TLS_UNIVERSAL();
+ MK_INIT_INITIALIZE_TLS();
+
+ mk_http_thread_initialize_tls();
+}
+
+void mk_server_info(struct mk_server *server)
+{
+ struct mk_list *head;
+ struct mk_plugin *p;
+ struct mk_config_listener *l;
+
+#ifdef _WIN32
+ printf(MK_BANNER_ENTRY "Process ID is %ld\n", (long)GetCurrentProcessId());
+#else
+ printf(MK_BANNER_ENTRY "Process ID is %ld\n", (long) getpid());
+#endif
+ mk_list_foreach(head, &server->listeners) {
+ l = mk_list_entry(head, struct mk_config_listener, _head);
+ printf(MK_BANNER_ENTRY "Server listening on %s:%s\n",
+ l->address, l->port);
+ }
+ printf(MK_BANNER_ENTRY
+ "%i threads, may handle up to %i client connections\n",
+ server->workers, server->server_capacity);
+
+ /* List loaded plugins */
+ printf(MK_BANNER_ENTRY "Loaded Plugins: ");
+ mk_list_foreach(head, &server->plugins) {
+ p = mk_list_entry(head, struct mk_plugin, _head);
+ printf("%s ", p->shortname);
+ }
+ printf("\n");
+
+#ifdef __linux__
+ char tmp[64];
+
+ if (mk_kernel_features_print(tmp, sizeof(tmp), server) > 0) {
+ printf(MK_BANNER_ENTRY "Linux Features: %s\n", tmp);
+ }
+#endif
+
+ fflush(stdout);
+}
+
+/* Initialize Monkey Server */
+struct mk_server *mk_server_create()
+{
+ int ret;
+ int kern_version;
+ int kern_features;
+ struct mk_server *server;
+
+ server = mk_mem_alloc_z(sizeof(struct mk_server));
+ if (!server) {
+ return NULL;
+ }
+
+ /* I'll try to leave both initializations here because
+ * it should be possible to run in windows using the accept
+ * backend in which case it doesn't make sense to tie the net stack
+ * initialization to libevent.
+ */
+ mk_net_init();
+ mk_event_init();
+
+ /* Library mode: event loop */
+ server->lib_mode = MK_TRUE;
+ server->lib_evl = mk_event_loop_create(8);
+ if (!server->lib_evl) {
+ mk_mem_free(server);
+ return NULL;
+ }
+
+ /* Library mode: channel manager */
+
+ memset(&server->lib_ch_event, 0, sizeof(struct mk_event));
+
+ ret = mk_event_channel_create(server->lib_evl,
+ &server->lib_ch_manager[0],
+ &server->lib_ch_manager[1],
+ &server->lib_ch_event);
+
+ if (ret != 0) {
+ mk_event_loop_destroy(server->lib_evl);
+ mk_mem_free(server);
+ return NULL;
+ }
+
+ /* Library mode: start event loop */
+ server->lib_evl_start = mk_event_loop_create(1);
+ if (!server->lib_evl_start) {
+ mk_event_loop_destroy(server->lib_evl);
+ mk_mem_free(server);
+ return NULL;
+ }
+
+ memset(&server->lib_ch_start_event, 0, sizeof(struct mk_event));
+
+ ret = mk_event_channel_create(server->lib_evl_start,
+ &server->lib_ch_start[0],
+ &server->lib_ch_start[1],
+ &server->lib_ch_start_event);
+
+ if (ret != 0) {
+ mk_event_loop_destroy(server->lib_evl);
+ mk_event_loop_destroy(server->lib_evl_start);
+ mk_mem_free(server);
+ return NULL;
+ }
+
+ /* Initialize linked list heads */
+ mk_list_init(&server->plugins);
+ mk_list_init(&server->sched_worker_callbacks);
+ mk_list_init(&server->stage10_handler);
+ mk_list_init(&server->stage20_handler);
+ mk_list_init(&server->stage30_handler);
+ mk_list_init(&server->stage40_handler);
+ mk_list_init(&server->stage50_handler);
+ server->scheduler_mode = -1;
+
+ mk_core_init();
+
+ /* Init thread keys */
+ pthread_once(&mk_server_tls_setup_once, mk_set_up_tls_keys);
+
+ /* Init Kernel version data */
+ kern_version = mk_kernel_version();
+ kern_features = mk_kernel_features(kern_version);
+
+ server->kernel_version = kern_version;
+ server->kernel_features = kern_features;
+
+#ifdef MK_HAVE_TRACE
+ MK_TRACE("Monkey TRACE is enabled");
+ //pthread_mutex_init(&mutex_trace, (pthread_mutexattr_t *) NULL);
+#endif
+
+#ifdef LINUX_TRACE
+ mk_info("Linux Trace enabled");
+#endif
+
+ mk_config_set_init_values(server);
+
+ mk_mimetype_init(server);
+
+ pthread_mutex_init(&server->vhost_fdt_mutex, NULL);
+
+ return server;
+}
+
+int mk_server_setup(struct mk_server *server)
+{
+ int ret;
+ pthread_t tid;
+
+ /* Core and Scheduler setup */
+ mk_config_start_configure(server);
+ mk_config_signature(server);
+
+ mk_sched_init(server);
+
+
+ /* Clock init that must happen before starting threads */
+ mk_clock_sequential_init(server);
+
+ /* Load plugins */
+ mk_plugin_api_init(server);
+ mk_plugin_load_all(server);
+
+ /* Workers: logger and clock */
+ ret = mk_utils_worker_spawn((void *) mk_clock_worker_init, server, &tid);
+ if (ret != 0) {
+ return -1;
+ }
+
+ /* Configuration sanity check */
+ mk_config_sanity_check(server);
+
+ /* Invoke Plugin PRCTX hooks */
+ mk_plugin_core_process(server);
+
+ /* Launch monkey http workers */
+ mk_server_launch_workers(server);
+
+ return 0;
+}
+
+void mk_exit_all(struct mk_server *server)
+{
+ uint64_t val;
+
+ /* Distribute worker signals to stop working */
+ val = MK_SCHED_SIGNAL_FREE_ALL;
+ mk_sched_broadcast_signal(server, val);
+
+ /* Wait for all workers to finish */
+ mk_sched_workers_join(server);
+
+ /* Continue exiting */
+ mk_plugin_exit_all(server);
+ mk_clock_exit(server);
+
+ mk_sched_exit(server);
+ mk_config_free_all(server);
+}
diff --git a/fluent-bit/lib/monkey/monkey.pc.in b/fluent-bit/lib/monkey/monkey.pc.in
new file mode 100644
index 000000000..bd04d076d
--- /dev/null
+++ b/fluent-bit/lib/monkey/monkey.pc.in
@@ -0,0 +1,10 @@
+prefix=PREFIX
+libdir=LIBDIR
+includedir=INCDIR
+
+Name: Monkey
+Description: Fast embeddable web server
+Version: VERSION
+Requires:
+Libs: -L${libdir} -lmonkey -pthread
+Cflags: -I${includedir}
diff --git a/fluent-bit/lib/monkey/monkey.spec b/fluent-bit/lib/monkey/monkey.spec
new file mode 100644
index 000000000..cfc3aa9bd
--- /dev/null
+++ b/fluent-bit/lib/monkey/monkey.spec
@@ -0,0 +1,145 @@
+Name: monkey
+Version: 1.4.0
+Release: 1%{?dist}
+Summary: A fast and lightweight web server for Linux
+Group: System Environment/Daemons
+License: GPLv2+
+URL: http://www.monkey-project.com
+Source: http://www.monkey-project.com/releases/1.4/%{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+
+#BuildRequires: gettext
+#Requires(pre): shadow-utils
+
+
+%description
+Monkey is a fast and lightweight web server for Linux. It has been
+designed to be very scalable with low memory and CPU consumption, the
+perfect solution for embedded and high production environments.
+
+
+%prep
+%setup -q
+
+
+%build
+./configure \
+ --prefix=%{_prefix} \
+ --bindir=%{_bindir} \
+ --incdir=%{_prefix}/include/monkey/ \
+ --sysconfdir=%{_sysconfdir}/%{name} \
+ --datadir=%{_var}/www/%{name} \
+ --logdir=%{_var}/log/%{name} \
+ --plugdir=%{_libexecdir}/%{name}
+
+
+make %{?_smp_mflags}
+
+
+%install
+rm -rf %{buildroot}
+install -d %{buildroot}%{_var}/log/%{name}
+
+make install DESTDIR=%{buildroot}
+
+%{__sed} -i 's/User nobody/User www-data/g' \
+ %{buildroot}/etc/%{name}/monkey.conf
+
+%clean
+rm -rf %{buildroot}
+
+
+%pre
+getent group monkey > /dev/null || groupadd -r monkey
+getent passwd monkey > /dev/null || \
+ useradd -r -g monkey -d %{_var}/www/%{name} -s /sbin/nologin \
+ -c "Monkey HTTP Daemon" monkey
+exit 0
+
+
+%files
+%defattr(-,root,root)
+%doc README LICENSE ChangeLog*
+%attr(644,root,root) %config(noreplace) %{_sysconfdir}/%{name}/monkey.conf
+%attr(644,root,root) %config(noreplace) %{_sysconfdir}/%{name}/monkey.mime
+%attr(644,root,root) %{_sysconfdir}/%{name}/plugins
+%attr(644,root,root) %{_sysconfdir}/%{name}/plugins.load
+%attr(644,root,root) %{_sysconfdir}/%{name}/sites
+%attr(700,root,root) %{_bindir}
+%attr(644,root,root) %{_libexecdir}
+%attr(700,monkey,monkey) %{_var}/www/%{name}
+%attr(0750, monkey, monkey) %{_var}/log/%{name}
+
+# Header files
+%attr(644,root,root) %{_prefix}/include/monkey/MKPlugin.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_cache.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_clock.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_config.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_connection.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_env.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_epoll.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_file.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_header.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_http.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_http_status.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_info.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_iov.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_lib.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_limits.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_linuxtrace.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_list.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_macros.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_memory.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_method.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_mimetype.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_plugin.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_rbtree.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_rbtree_augmented.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_request.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_scheduler.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_server.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_signals.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_socket.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_string.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_user.h
+%attr(644,root,root) %{_prefix}/include/monkey/mk_utils.h
+%attr(644,root,root) %{_prefix}/include/monkey/monkey.h
+
+# Manpages
+%attr(644,root,root) /usr/man/man1/banana.1.gz
+%attr(644,root,root) /usr/man/man1/monkey.1.gz
+%attr(644,root,root) /usr/man/man3/mklib_callback_set.3.gz
+%attr(644,root,root) /usr/man/man3/mklib_config.3.gz
+%attr(644,root,root) /usr/man/man3/mklib_init.3.gz
+%attr(644,root,root) /usr/man/man3/mklib_mimetype_add.3.gz
+%attr(644,root,root) /usr/man/man3/mklib_mimetype_list.3.gz
+%attr(644,root,root) /usr/man/man3/mklib_scheduler_worker_info.3.gz
+%attr(644,root,root) /usr/man/man3/mklib_start.3.gz
+%attr(644,root,root) /usr/man/man3/mklib_stop.3.gz
+%attr(644,root,root) /usr/man/man3/mklib_vhost_config.3.gz
+%attr(644,root,root) /usr/man/man3/mklib_vhost_list.3.gz
+%attr(644,root,root) /usr/man/man3/monkey-api.3.gz
+
+# Libraries
+%attr(744,root,root) /usr/lib/libmonkey.so
+%attr(744,root,root) /usr/lib/pkgconfig/monkey.pc
+
+%postun
+cat %{_var}/log/%{name}/monkey.pid | xargs kill -9 > /dev/null 2>&1
+rm %{_var}/log/%{name}/*pid > /dev/null 2>&1
+rmdir %{_var}/log/%{name} > /dev/null 2>&1
+rmdir %{_sysconfdir}/%{name} > /dev/null 2>&1
+
+
+%changelog
+* Sun Dec 22 2013 Eduardo Silva <edsiper@gmail.com> - 1.4.0-1
+- Testing new spec file for v1.4
+
+* Tue Aug 24 2010 Antonio Salles <antonio@salles.cl> - 0.11.1-2
+- Spec rebuild. Now it work fine with Fedora.
+
+* Thu Jul 22 2010 Horst H. von Brand <vonbrand@inf.utfsm.cl> - 0.11.0-2
+- First cut at cleaning up specfile according to Fedora guidelines
+
+* Thu Jul 08 2010 Eduardo Silva <edsiper at gmail.com> 0.11.0-1
+- Initial rpm package for Fedora 13
diff --git a/fluent-bit/lib/monkey/plugins/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/CMakeLists.txt
new file mode 100644
index 000000000..a78d83695
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/CMakeLists.txt
@@ -0,0 +1,111 @@
+set(static_plugins "" CACHE INTERNAL "static_plugins")
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+# CHECK_STATIC_PLUGIN: Check if a plugin will be linked statically
+macro(CHECK_STATIC_PLUGIN name)
+ string(REPLACE "," ";" plugins ${MK_STATIC_PLUGINS})
+ list(FIND plugins ${name} found)
+ if(NOT found EQUAL -1)
+ set(IS_STATIC TRUE)
+ else()
+ set(IS_STATIC FALSE)
+ endif()
+endmacro()
+
+# MONKEY_PLUGIN: Used by plugins to register and create the targets
+macro(MONKEY_PLUGIN name src)
+ CHECK_STATIC_PLUGIN(${name})
+ if(IS_STATIC)
+ add_library(monkey-${name}-static STATIC ${src})
+ set_target_properties(monkey-${name}-static PROPERTIES OUTPUT_NAME monkey-${name})
+ set_target_properties(monkey-${name}-static PROPERTIES PREFIX "")
+ else()
+ if(APPLE)
+ add_library(monkey-${name}-shared MODULE ${src})
+ else()
+ add_library(monkey-${name}-shared SHARED ${src})
+ endif()
+ set_target_properties(monkey-${name}-shared PROPERTIES OUTPUT_NAME monkey-${name})
+ set_target_properties(monkey-${name}-shared PROPERTIES PREFIX "")
+
+ if(NOT MK_LOCAL)
+ if(CMAKE_INSTALL_LIBDIR)
+ install(TARGETS monkey-${name}-shared LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ else()
+ install(TARGETS monkey-${name}-shared LIBRARY DESTINATION lib)
+ endif()
+ endif()
+ endif()
+endmacro()
+
+# MK_BUILD_PLUGIN: This macro determinate if the plugin is enabled through the
+# option MK_PLUGIN_NAME defined on the root CMakeLists.txt
+macro(MK_BUILD_PLUGIN name)
+ set(mode "")
+ string(TOUPPER ${name} NAME)
+
+ # Check if the plugin is enabled
+ set(option MK_PLUGIN_${NAME})
+ if(${option})
+ add_subdirectory(${name})
+
+ # Is this a static plugin ?
+ CHECK_STATIC_PLUGIN(${name})
+ if(IS_STATIC)
+ # Let Monkey and CMake aware about this is a static plugin. A static plugin
+ # requires a different handling: link the object and register the plugin
+ # struct reference on mk_static_plugins.h
+ set(static_plugins "${static_plugins}monkey-${name}-static;")
+ set(STATIC_PLUGINS_INIT "${STATIC_PLUGINS_INIT}\n mk_static_plugin_attach(plugins, &mk_plugin_${name});\n")
+ set(STATIC_PLUGINS_DECL "${STATIC_PLUGINS_DECL}extern struct mk_plugin mk_plugin_${name};\n")
+
+ # append message to stdout
+ set(mode "[== static ==]")
+ else()
+ if(MK_LOCAL)
+ set(MK_LOAD_PLUGINS "${MK_LOAD_PLUGINS} # Load ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/monkey-${name}.so\n")
+ else()
+ set(MK_LOAD_PLUGINS "${MK_LOAD_PLUGINS} # Load ${CMAKE_INSTALL_FULL_LIBDIR}/monkey-${name}.so\n")
+ endif()
+ endif()
+ message(STATUS "Plugin ${name} enabled ${mode}")
+ endif()
+endmacro()
+
+
+macro(MONKEY_PLUGIN_LINK_LIB target lib)
+ CHECK_STATIC_PLUGIN(${target})
+ if(IS_STATIC)
+ target_link_libraries(monkey-${target}-static ${lib})
+ else()
+ target_link_libraries(monkey-${target}-shared ${lib})
+ endif()
+endmacro()
+
+# Try to configure/build all plugins
+MK_BUILD_PLUGIN("auth")
+MK_BUILD_PLUGIN("cgi")
+MK_BUILD_PLUGIN("cheetah")
+MK_BUILD_PLUGIN("dirlisting")
+MK_BUILD_PLUGIN("fastcgi")
+MK_BUILD_PLUGIN("liana")
+MK_BUILD_PLUGIN("logger")
+MK_BUILD_PLUGIN("mandril")
+MK_BUILD_PLUGIN("tls")
+MK_BUILD_PLUGIN("duda")
+
+# Generate include/monkey/mk_static_plugins.h
+configure_file(
+ "${PROJECT_SOURCE_DIR}/include/monkey/mk_static_plugins.h.in"
+ "${PROJECT_SOURCE_DIR}/include/monkey/mk_static_plugins.h"
+ )
+
+# Generate conf/plugins.load
+if(NOT MK_WITHOUT_CONF)
+ configure_file(
+ "${PROJECT_SOURCE_DIR}/conf/plugins.load.in"
+ "${PROJECT_BINARY_DIR}/conf/plugins.load"
+ )
+endif()
+
+set(STATIC_PLUGINS_LIBS "${static_plugins}" PARENT_SCOPE)
diff --git a/fluent-bit/lib/monkey/plugins/README b/fluent-bit/lib/monkey/plugins/README
new file mode 100644
index 000000000..0daa023cb
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/README
@@ -0,0 +1,61 @@
+Monkey Plugins
+==============
+Plugins are extra features which modifies the Monkey behavior, all of them
+are shared libraries which are loaded on runtime.
+
+Each plugin is loaded per configuration instruction and it will work on a
+defined stage or event depending of it's type.
+
+Please review the file API.txt for more details
+
+
+
+MK_PLUGIN_STAGE_10: Server has not yet entered in the server loop, no
+ listeners yet available
+---------------------------------------------------------------------
+ Return Values >
+
+
+MK_PLUGIN_STAGE_20: Accepted connection has not been assigned to worker thread
+------------------------------------------------------------------------------
+ Return Values >
+
+ * MK_PLUGIN_RET_CLOSE_CONX: The connection must be closed.
+
+
+MK_PLUGIN_STAGE_30: HTTP Request received
+-----------------------------------------
+ Return Values >
+ * MK_PLUGIN_RET_CLOSE_CONX: The connection must be closed.
+
+
+MK_PLUGIN_STAGE_40: Object Handler
+-----------------------------------------
+ Extra functions >
+ * _mk_plugin_stage_40_loop(): if _mk_plugin_stage_40() has
+ returned MK_PLUGIN_RET_CONTINUE, the server will wait
+ for an event and call _mk_plugin_stage_40() until it
+ returns MK_PLUGIN_RET_END.
+
+ Return Values >
+ * MK_PLUGIN_RET_END
+ * MK_PLUGIN_RET_CONTINUE
+
+ Return Values >
+ * MK_PLUGIN_RET_NOT_ME: Plugin will not handle this request.
+
+ * MK_PLUGIN_RET_END: Plugin has taken some action and
+ has finished the work, the handler will no take the request
+ again.
+
+ * MK_PLUGIN_RET_CONTINUE:: Plugin has taken some action and
+ will continue in the next loop.
+
+
+MK_PLUGIN_STAGE_50: Request ended
+-----------------------------------------
+
+
+MK_PLUGIN_STAGE_60: The Connection has been closed
+--------------------------------------------------
+
diff --git a/fluent-bit/lib/monkey/plugins/auth/ABOUT b/fluent-bit/lib/monkey/plugins/auth/ABOUT
new file mode 100644
index 000000000..66a5384c3
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/auth/ABOUT
@@ -0,0 +1,2 @@
+HTTP Basic Authentication
+=========================
diff --git a/fluent-bit/lib/monkey/plugins/auth/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/auth/CMakeLists.txt
new file mode 100644
index 000000000..a6fd27a06
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/auth/CMakeLists.txt
@@ -0,0 +1,10 @@
+set(src
+ auth.c
+ base64.c
+ conf.c
+ sha1.c
+ )
+
+add_subdirectory(tools)
+
+MONKEY_PLUGIN(auth "${src}")
diff --git a/fluent-bit/lib/monkey/plugins/auth/OPTIONAL b/fluent-bit/lib/monkey/plugins/auth/OPTIONAL
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/auth/OPTIONAL
diff --git a/fluent-bit/lib/monkey/plugins/auth/auth.c b/fluent-bit/lib/monkey/plugins/auth/auth.c
new file mode 100644
index 000000000..b0f983bfb
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/auth/auth.c
@@ -0,0 +1,254 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_api.h>
+
+#include <sys/stat.h>
+
+#include "auth.h"
+#include "conf.h"
+#include "sha1.h"
+#include "base64.h"
+
+static int mk_auth_validate_user(struct users_file *users,
+ const char *credentials, unsigned int len)
+{
+ int sep;
+ size_t auth_len;
+ unsigned char *decoded = NULL;
+ unsigned char digest[SHA1_DIGEST_LEN];
+ struct mk_list *head;
+ struct user *entry;
+
+ SHA_CTX sha; /* defined in sha1/sha1.h */
+
+ /* Validate value length */
+ if (len <= auth_header_basic.len + 1) {
+ return -1;
+ }
+
+ /* Validate 'basic' credential type */
+ if (strncmp(credentials, auth_header_basic.data,
+ auth_header_basic.len) != 0) {
+ return -1;
+ }
+
+ /* Decode credentials: incoming credentials comes in base64 encode */
+ decoded = base64_decode((unsigned char *) credentials + auth_header_basic.len,
+ len - auth_header_basic.len,
+ &auth_len);
+ if (decoded == NULL) {
+ PLUGIN_TRACE("Failed to decode credentials.");
+ goto error;
+ }
+
+ if (auth_len <= 3) {
+ goto error;
+ }
+
+ sep = mk_api->str_search_n((char *) decoded, ":", 1, auth_len);
+ if (sep == -1 || sep == 0 || (unsigned int) sep == auth_len - 1) {
+ goto error;
+ }
+
+ /* Get SHA1 hash */
+ SHA1_Init(&sha);
+ SHA1_Update(&sha, (unsigned char *) decoded + sep + 1, auth_len - (sep + 1));
+ SHA1_Final(digest, &sha);
+
+ mk_list_foreach(head, &users->_users) {
+ entry = mk_list_entry(head, struct user, _head);
+ /* match user */
+ if (strlen(entry->user) != (unsigned int) sep) {
+ continue;
+ }
+ if (strncmp(entry->user, (char *) decoded, sep) != 0) {
+ continue;
+ }
+
+ PLUGIN_TRACE("User match '%s'", entry->user);
+
+ /* match password */
+ if (memcmp(entry->passwd_decoded, digest, SHA1_DIGEST_LEN) == 0) {
+ PLUGIN_TRACE("User '%s' matched password", entry->user);
+ mk_api->mem_free(decoded);
+ return 0;
+ }
+ PLUGIN_TRACE("Invalid password");
+ break;
+ }
+
+ error:
+ if (decoded) {
+ mk_api->mem_free(decoded);
+ }
+ return -1;
+}
+
+int mk_auth_plugin_init(struct plugin_api **api, char *confdir)
+{
+ (void) confdir;
+
+ mk_api = *api;
+
+ /* Init and load global users list */
+ mk_list_init(&vhosts_list);
+ mk_list_init(&users_file_list);
+ mk_auth_conf_init_users_list();
+
+ /* Set HTTP headers key */
+ auth_header_basic.data = MK_AUTH_HEADER_BASIC;
+ auth_header_basic.len = sizeof(MK_AUTH_HEADER_BASIC) - 1;
+
+ return 0;
+}
+
+int mk_auth_plugin_exit()
+{
+ return 0;
+}
+
+void mk_auth_worker_init()
+{
+ char *user;
+
+ /* Init thread buffer for given credentials */
+ user = mk_api->mem_alloc(MK_AUTH_CREDENTIALS_LEN - 1);
+ pthread_setspecific(_mkp_data, (void *) user);
+}
+
+/* Object handler */
+int mk_auth_stage30(struct mk_plugin *plugin,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ int n_params,
+ struct mk_list *params)
+{
+ int val;
+ short int is_restricted = MK_FALSE;
+ struct mk_list *vh_head;
+ struct mk_list *loc_head;
+ struct vhost *vh_entry = NULL;
+ struct location *loc_entry;
+ struct mk_http_header *header;
+ (void) plugin;
+ (void) n_params;
+ (void) params;
+
+ PLUGIN_TRACE("[FD %i] Handler received request");
+
+ /* Match auth_vhost with global vhost */
+ mk_list_foreach(vh_head, &vhosts_list) {
+ vh_entry = mk_list_entry(vh_head, struct vhost, _head);
+ if (vh_entry->host == sr->host_conf) {
+ PLUGIN_TRACE("[FD %i] host matched %s",
+ cs->socket,
+ mk_api->config->server_signature);
+ break;
+ }
+ }
+
+ if (!vh_entry) {
+ return MK_PLUGIN_RET_NOT_ME;
+ }
+
+ /* Check vhost locations */
+ mk_list_foreach(loc_head, &vh_entry->locations) {
+ loc_entry = mk_list_entry(loc_head, struct location, _head);
+ if (sr->uri_processed.len < loc_entry->path.len) {
+ continue;
+ }
+ if (strncmp(sr->uri_processed.data,
+ loc_entry->path.data, loc_entry->path.len) == 0) {
+ is_restricted = MK_TRUE;
+ PLUGIN_TRACE("[FD %i] Location matched %s",
+ cs->socket,
+ loc_entry->path.data);
+ break;
+ }
+ }
+
+ /* For non-restricted location do not take any action, just returns */
+ if (is_restricted == MK_FALSE) {
+ return MK_PLUGIN_RET_NOT_ME;
+ }
+
+ /* Check authorization header */
+ header = mk_api->header_get(MK_HEADER_AUTHORIZATION,
+ sr, NULL, 0);
+
+ if (header) {
+ /* Validate user */
+ val = mk_auth_validate_user(loc_entry->users,
+ header->val.data, header->val.len);
+ if (val == 0) {
+ /* user validated, success */
+ PLUGIN_TRACE("[FD %i] user validated!", cs->socket);
+ return MK_PLUGIN_RET_NOT_ME;
+ }
+ }
+
+ /* Restricted access: requires auth */
+ PLUGIN_TRACE("[FD %i] unauthorized user, credentials required",
+ cs->socket);
+
+ sr->headers.content_length = 0;
+ mk_api->header_set_http_status(sr, MK_CLIENT_UNAUTH);
+ mk_api->header_add(sr,
+ loc_entry->auth_http_header.data,
+ loc_entry->auth_http_header.len);
+
+ mk_api->header_prepare(plugin, cs, sr);
+ return MK_PLUGIN_RET_END;
+}
+
+int mk_auth_stage30_hangup(struct mk_plugin *plugin,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr)
+{
+ (void) plugin;
+ (void) cs;
+ (void) sr;
+
+ return 0;
+}
+
+struct mk_plugin_stage mk_plugin_stage_auth = {
+ .stage30 = &mk_auth_stage30,
+ .stage30_hangup = &mk_auth_stage30_hangup
+};
+
+struct mk_plugin mk_plugin_auth = {
+ /* Identification */
+ .shortname = "auth",
+ .name = "Basic Authentication",
+ .version = MK_VERSION_STR,
+ .hooks = MK_PLUGIN_STAGE,
+
+ /* Init / Exit */
+ .init_plugin = mk_auth_plugin_init,
+ .exit_plugin = mk_auth_plugin_exit,
+
+ /* Init Levels */
+ .master_init = NULL,
+ .worker_init = mk_auth_worker_init,
+
+ /* Type */
+ .stage = &mk_plugin_stage_auth
+};
diff --git a/fluent-bit/lib/monkey/plugins/auth/auth.h b/fluent-bit/lib/monkey/plugins/auth/auth.h
new file mode 100644
index 000000000..f6eebe83e
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/auth/auth.h
@@ -0,0 +1,106 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_AUTH_H
+#define MK_AUTH_H
+
+#include <monkey/mk_api.h>
+
+/* Header stuff */
+#define MK_AUTH_HEADER_BASIC "Basic "
+#define MK_AUTH_HEADER_TITLE "WWW-Authenticate: Basic realm=\"%s\""
+
+/* Credentials length */
+#define MK_AUTH_CREDENTIALS_LEN 256
+
+/*
+ * The plugin hold one struct per virtual host and link to the
+ * locations and users file associated:
+ *
+ * +---------------------------------+
+ * struct vhost > vhost (1:N) |
+ * | +---------+----------+ |
+ * | | | | |
+ * struct location > location location location |
+ * | | | | |
+ * | +----+----+ + |
+ * | | | |
+ * struct users > users users |
+ * +---------------------------------+
+ *
+ */
+
+/* List of virtual hosts to handle locations */
+struct mk_list vhosts_list;
+
+/* main index for locations under a virtualhost */
+struct vhost {
+ struct mk_vhost *host;
+ struct mk_list locations;
+ struct mk_list _head;
+};
+
+/*
+ * A location restrict a filesystem path with a list
+ * of allowed users
+ */
+struct location {
+ mk_ptr_t path;
+ mk_ptr_t title;
+ mk_ptr_t auth_http_header;
+
+ struct users_file *users;
+ struct mk_list _head;
+};
+
+/* Head index for user files list */
+struct mk_list users_file_list;
+
+/*
+ * Represents a users file, each entry represents a physical
+ * file and belongs to a node of the users_file_list list
+ */
+struct users_file {
+ time_t last_updated; /* last time this entry was modified */
+ char *path; /* file path */
+ struct mk_list _users; /* list of users */
+ struct mk_list _head; /* head for main mk_list users_file_list */
+};
+
+/*
+ * a list of users, this list belongs to a
+ * struct location
+ */
+struct user {
+ char user[128];
+ char passwd_raw[256];
+ unsigned char *passwd_decoded;
+
+ struct mk_list _head;
+};
+
+struct mk_list users_file_list;
+
+/* Thread key */
+mk_ptr_t auth_header_request;
+mk_ptr_t auth_header_basic;
+
+#define SHA1_DIGEST_LEN 20
+
+#endif
diff --git a/fluent-bit/lib/monkey/plugins/auth/base64.c b/fluent-bit/lib/monkey/plugins/auth/base64.c
new file mode 100644
index 000000000..e3149fe73
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/auth/base64.c
@@ -0,0 +1,172 @@
+/*
+ * Base64 encoding/decoding (RFC1341)
+ * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifdef _FORCE_SYSMALLOC
+#undef MALLOC_JEMALLOC
+#endif
+
+#include <monkey/mk_api.h>
+#include "base64.h"
+
+#if defined(MALLOC_JEMALLOC)
+#define __mem_alloc mk_api->mem_alloc
+#define __mem_free mk_api->mem_free
+#else
+#define __mem_alloc malloc
+#define __mem_free free
+#endif
+
+static const unsigned char base64_table[65] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * base64_encode - Base64 encode
+ * @src: Data to be encoded
+ * @len: Length of the data to be encoded
+ * @out_len: Pointer to output length variable, or %NULL if not used
+ * Returns: Allocated buffer of out_len bytes of encoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer. Returned buffer is
+ * nul terminated to make it easier to use as a C string. The nul terminator is
+ * not included in out_len.
+ */
+unsigned char * base64_encode(const unsigned char *src, size_t len,
+ size_t *out_len)
+{
+ unsigned char *out, *pos;
+ const unsigned char *end, *in;
+ size_t olen;
+ int line_len;
+
+ olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
+ olen += olen / 72; /* line feeds */
+ olen++; /* nul termination */
+ if (olen < len)
+ return NULL; /* integer overflow */
+ if (mk_api != NULL) {
+ out = __mem_alloc(olen);
+ }
+ else {
+ out = __mem_alloc(olen);
+ }
+
+ if (out == NULL)
+ return NULL;
+
+ end = src + len;
+ in = src;
+ pos = out;
+ line_len = 0;
+ while (end - in >= 3) {
+ *pos++ = base64_table[in[0] >> 2];
+ *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
+ *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
+ *pos++ = base64_table[in[2] & 0x3f];
+ in += 3;
+ line_len += 4;
+ if (line_len >= 72) {
+ *pos++ = '\n';
+ line_len = 0;
+ }
+ }
+
+ if (end - in) {
+ *pos++ = base64_table[in[0] >> 2];
+ if (end - in == 1) {
+ *pos++ = base64_table[(in[0] & 0x03) << 4];
+ *pos++ = '=';
+ } else {
+ *pos++ = base64_table[((in[0] & 0x03) << 4) |
+ (in[1] >> 4)];
+ *pos++ = base64_table[(in[1] & 0x0f) << 2];
+ }
+ *pos++ = '=';
+ line_len += 4;
+ }
+
+ if (line_len)
+ *pos++ = '\n';
+
+ *pos = '\0';
+ if (out_len)
+ *out_len = pos - out;
+ return out;
+}
+
+
+/**
+ * base64_decode - Base64 decode
+ * @src: Data to be decoded
+ * @len: Length of the data to be decoded
+ * @out_len: Pointer to output length variable
+ * Returns: Allocated buffer of out_len bytes of decoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer.
+ */
+unsigned char * base64_decode(const unsigned char *src, size_t len,
+ size_t *out_len)
+{
+ unsigned char dtable[256], *out, *pos, block[4], tmp;
+ size_t i, count, olen;
+ int pad = 0;
+
+ memset(dtable, 0x80, 256);
+ for (i = 0; i < sizeof(base64_table) - 1; i++)
+ dtable[base64_table[i]] = (unsigned char) i;
+ dtable['='] = 0;
+
+ count = 0;
+ for (i = 0; i < len; i++) {
+ if (dtable[src[i]] != 0x80)
+ count++;
+ }
+
+ if (count == 0 || count % 4)
+ return NULL;
+
+ olen = (count / 4 * 3) + 1;
+ pos = out = __mem_alloc(olen);
+ if (out == NULL)
+ return NULL;
+
+ count = 0;
+ for (i = 0; i < len; i++) {
+ tmp = dtable[src[i]];
+ if (tmp == 0x80)
+ continue;
+
+ if (src[i] == '=')
+ pad++;
+ block[count] = tmp;
+ count++;
+ if (count == 4) {
+ *pos++ = (block[0] << 2) | (block[1] >> 4);
+ *pos++ = (block[1] << 4) | (block[2] >> 2);
+ *pos++ = (block[2] << 6) | block[3];
+ count = 0;
+ if (pad) {
+ if (pad == 1)
+ pos--;
+ else if (pad == 2)
+ pos -= 2;
+ else {
+ /* Invalid padding */
+ __mem_free(out);
+ return NULL;
+ }
+ break;
+ }
+ }
+ }
+ *pos = '\0';
+
+ *out_len = pos - out;
+ return out;
+}
diff --git a/fluent-bit/lib/monkey/plugins/auth/base64.h b/fluent-bit/lib/monkey/plugins/auth/base64.h
new file mode 100644
index 000000000..45001d47f
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/auth/base64.h
@@ -0,0 +1,11 @@
+#ifndef AUTH_BASE64_H
+#define AUTH_BASE64_H
+
+
+unsigned char * base64_encode(const unsigned char *src, size_t len,
+ size_t *out_len);
+unsigned char *base64_decode(const unsigned char *src, size_t len,
+ size_t *out_len);
+
+
+#endif
diff --git a/fluent-bit/lib/monkey/plugins/auth/conf.c b/fluent-bit/lib/monkey/plugins/auth/conf.c
new file mode 100644
index 000000000..6dede1dd4
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/auth/conf.c
@@ -0,0 +1,244 @@
+ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_api.h>
+#include "base64.h"
+#include "auth.h"
+#include "conf.h"
+
+/*
+ * Register a users file into the main list, if the users
+ * file already exists it just return the node in question,
+ * otherwise add the node to the list and return the node
+ * created.
+ */
+static struct users_file *mk_auth_conf_add_users(char *users_path)
+{
+ struct file_info finfo;
+ struct mk_list *head;
+ struct users_file *entry;
+ struct user *cred;
+ int i, sep, len;
+ int offset = 0;
+ size_t decoded_len;
+ char *buf;
+
+ mk_list_foreach(head, &users_file_list) {
+ entry = mk_list_entry(head, struct users_file, _head);
+ if (strcmp(entry->path, users_path) == 0) {
+ return entry;
+ }
+ }
+
+ if (mk_api->file_get_info(users_path, &finfo, MK_FILE_READ) != 0) {
+ mk_warn("Auth: Invalid users file '%s'", users_path);
+ return NULL;
+ }
+
+ if (finfo.is_directory == MK_TRUE) {
+ mk_warn("Auth: Not a credentials file '%s'", users_path);
+ return NULL;
+ }
+
+ if (finfo.read_access == MK_FALSE) {
+ mk_warn("Auth: Could not read file '%s'", users_path);
+ return NULL;
+ }
+
+ /* We did not find the path in our list, let's create a new node */
+ entry = mk_api->mem_alloc(sizeof(struct users_file));
+ entry->last_updated = finfo.last_modification;
+ entry->path = users_path;
+
+ /* Read file and add users to the list */
+ mk_list_init(&entry->_users);
+
+ /* Read credentials file */
+ buf = mk_api->file_to_buffer(users_path);
+ if (!buf) {
+ mk_warn("Auth: No users loaded '%s'", users_path);
+ return NULL;
+ }
+
+ /* Read users list buffer lines */
+ len = strlen(buf);
+ for (i = 0; i < len; i++) {
+ if (buf[i] == '\n' || (i) == len -1) {
+ sep = mk_api->str_search(buf + offset, ":", 1);
+
+ if (sep >= (int)sizeof(cred->user)) {
+ mk_warn("Auth: username too long");
+ offset = i + 1;
+ continue;
+ }
+ if (i - offset - sep - 1 - 5 >= (int)sizeof(cred->passwd_raw)) {
+ mk_warn("Auth: password hash too long");
+ offset = i + 1;
+ continue;
+ }
+
+ cred = mk_api->mem_alloc(sizeof(struct user));
+
+ /* Copy username */
+ strncpy(cred->user, buf + offset, sep);
+ cred->user[sep] = '\0';
+
+ /* Copy raw password */
+ offset += sep + 1 + 5;
+ strncpy(cred->passwd_raw,
+ buf + offset,
+ i - (offset));
+ cred->passwd_raw[i - offset] = '\0';
+
+ /* Decode raw password */
+ cred->passwd_decoded = base64_decode((unsigned char *)(cred->passwd_raw),
+ strlen(cred->passwd_raw),
+ &decoded_len);
+
+ offset = i + 1;
+
+ if (!cred->passwd_decoded) {
+ mk_warn("Auth: invalid user '%s' in '%s'",
+ cred->user, users_path);
+ mk_api->mem_free(cred);
+ continue;
+ }
+ mk_list_add(&cred->_head, &entry->_users);
+ }
+ }
+ mk_api->mem_free(buf);
+
+ /* Link node to global list */
+ mk_list_add(&entry->_head, &users_file_list);
+
+ return entry;
+}
+
+/*
+ * Read all vhost configuration nodes and looks for users files under an [AUTH]
+ * section, if present, it add that file to the unique list. It parse all user's
+ * files mentioned to avoid duplicated lists in memory.
+ */
+int mk_auth_conf_init_users_list()
+{
+ /* Section data */
+ char *location;
+ char *title;
+ char *users_path;
+ /* auth vhost list */
+ struct vhost *auth_vhost;
+
+ /* vhost configuration */
+ struct mk_list *head_hosts;
+ struct mk_list *hosts = &mk_api->config->hosts;
+ struct mk_list *head_sections;
+ struct mk_vhost *entry_host;
+ struct mk_rconf_section *section;
+
+ /* vhost [AUTH] locations */
+ struct location *loc;
+
+ /* User files list */
+ struct users_file *uf;
+
+ PLUGIN_TRACE("Loading user's files");
+
+ mk_list_foreach(head_hosts, hosts) {
+ entry_host = mk_list_entry(head_hosts, struct mk_vhost, _head);
+ if (!entry_host->config) {
+ continue;
+ }
+
+ auth_vhost = mk_api->mem_alloc(sizeof(struct vhost));
+ auth_vhost->host = entry_host; /* link virtual host entry */
+ mk_list_init(&auth_vhost->locations); /* init locations list */
+
+ /*
+ * check vhost 'config' and look for [AUTH] sections, we don't use
+ * mk_config_section_get() because we can have multiple [AUTH]
+ * sections.
+ */
+ mk_list_foreach(head_sections, &entry_host->config->sections) {
+ section = mk_list_entry(head_sections, struct mk_rconf_section, _head);
+
+ if (strcasecmp(section->name, "AUTH") == 0) {
+ location = NULL;
+ title = NULL;
+ users_path = NULL;
+
+ /* Get section keys */
+ location = mk_api->config_section_get_key(section,
+ "Location",
+ MK_RCONF_STR);
+ title = mk_api->config_section_get_key(section,
+ "Title",
+ MK_RCONF_STR);
+
+ users_path = mk_api->config_section_get_key(section,
+ "Users",
+ MK_RCONF_STR);
+
+ /* get or create users file entry */
+ uf = mk_auth_conf_add_users(users_path);
+ if (!uf) {
+ continue;
+ }
+
+ /* Location node */
+ loc = mk_api->mem_alloc(sizeof(struct location));
+ mk_api->pointer_set(&loc->path, location);
+ mk_api->pointer_set(&loc->title, title);
+
+ loc->auth_http_header.data = NULL;
+ mk_api->str_build(&loc->auth_http_header.data,
+ &loc->auth_http_header.len,
+ MK_AUTH_HEADER_TITLE, title);
+
+ loc->users = uf;
+
+ /* Add new location to auth_vhost node */
+ mk_list_add(&loc->_head, &auth_vhost->locations);
+ }
+ }
+
+ /* Link auth_vhost node to global list vhosts_list */
+ mk_list_add(&auth_vhost->_head, &vhosts_list);
+ }
+
+#ifdef TRACE
+ struct mk_list *vh_head, *loc_head;
+ struct vhost *vh_entry;
+ struct location *loc_entry;
+
+ mk_list_foreach(vh_head, &vhosts_list) {
+ vh_entry = mk_list_entry(vh_head, struct vhost, _head);
+ PLUGIN_TRACE("Auth VHost: %p", vh_entry->host);
+
+ mk_list_foreach(loc_head, &vh_entry->locations) {
+ loc_entry = mk_list_entry(loc_head, struct location, _head);
+ PLUGIN_TRACE("---");
+ PLUGIN_TRACE(" location: %s", loc_entry->path);
+ PLUGIN_TRACE(" title : %s", loc_entry->title);
+ PLUGIN_TRACE(" users : %s", loc_entry->users->path);
+ }
+ }
+#endif
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/plugins/auth/conf.h b/fluent-bit/lib/monkey/plugins/auth/conf.h
new file mode 100644
index 000000000..90fd8f79a
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/auth/conf.h
@@ -0,0 +1,25 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_AUTH_CONF_H
+#define MK_AUTH_CONF_H
+
+int mk_auth_conf_init_users_list();
+
+#endif
diff --git a/fluent-bit/lib/monkey/plugins/auth/sha1.c b/fluent-bit/lib/monkey/plugins/auth/sha1.c
new file mode 100644
index 000000000..53c7946e8
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/auth/sha1.c
@@ -0,0 +1,288 @@
+/*
+ * Code adapted to fill Monkey Project requirements, no big changes
+ * just a few header files added
+ */
+
+#include <arpa/inet.h>
+#include <string.h>
+
+/*
+ * SHA1 routine optimized to do word accesses rather than byte accesses,
+ * and to avoid unnecessary copies into the context array.
+ *
+ * This was initially based on the Mozilla SHA1 implementation, although
+ * none of the original Mozilla code remains.
+ */
+
+#include "sha1.h"
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+/*
+ * Force usage of rol or ror by selecting the one with the smaller constant.
+ * It _can_ generate slightly smaller code (a constant of 1 is special), but
+ * perhaps more importantly it's possibly faster on any uarch that does a
+ * rotate with a loop.
+ */
+
+#define SHA_ASM(op, x, n) ({ unsigned int __res; __asm__(op " %1,%0":"=r" (__res):"i" (n), "0" (x)); __res; })
+#define SHA_ROL(x,n) SHA_ASM("rol", x, n)
+#define SHA_ROR(x,n) SHA_ASM("ror", x, n)
+
+#else
+
+#define SHA_ROT(X,l,r) (((X) << (l)) | ((X) >> (r)))
+#define SHA_ROL(X,n) SHA_ROT(X,n,32-(n))
+#define SHA_ROR(X,n) SHA_ROT(X,32-(n),n)
+
+#endif
+
+/*
+ * If you have 32 registers or more, the compiler can (and should)
+ * try to change the array[] accesses into registers. However, on
+ * machines with less than ~25 registers, that won't really work,
+ * and at least gcc will make an unholy mess of it.
+ *
+ * So to avoid that mess which just slows things down, we force
+ * the stores to memory to actually happen (we might be better off
+ * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as
+ * suggested by Artur Skawina - that will also make gcc unable to
+ * try to do the silly "optimize away loads" part because it won't
+ * see what the value will be).
+ *
+ * Ben Herrenschmidt reports that on PPC, the C version comes close
+ * to the optimized asm with this (ie on PPC you don't want that
+ * 'volatile', since there are lots of registers).
+ *
+ * On ARM we get the best code generation by forcing a full memory barrier
+ * between each SHA_ROUND, otherwise gcc happily get wild with spilling and
+ * the stack frame size simply explode and performance goes down the drain.
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+ #define setW(x, val) (*(volatile unsigned int *)&W(x) = (val))
+#elif defined(__GNUC__) && defined(__arm__)
+ #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0)
+#else
+ #define setW(x, val) (W(x) = (val))
+#endif
+
+/*
+ * Performance might be improved if the CPU architecture is OK with
+ * unaligned 32-bit loads and a fast ntohl() is available.
+ * Otherwise fall back to byte loads and shifts which is portable,
+ * and is faster on architectures with memory alignment issues.
+ */
+
+#if defined(__i386__) || defined(__x86_64__) || \
+ defined(_M_IX86) || defined(_M_X64) || \
+ defined(__ppc__) || defined(__ppc64__) || \
+ defined(__powerpc__) || defined(__powerpc64__) || \
+ defined(__s390__) || defined(__s390x__)
+
+#define get_be32(p) ntohl(*(unsigned int *)(p))
+#define put_be32(p, v) do { *(unsigned int *)(p) = htonl(v); } while (0)
+
+#else
+
+#define get_be32(p) ( \
+ (*((unsigned char *)(p) + 0) << 24) | \
+ (*((unsigned char *)(p) + 1) << 16) | \
+ (*((unsigned char *)(p) + 2) << 8) | \
+ (*((unsigned char *)(p) + 3) << 0) )
+#define put_be32(p, v) do { \
+ unsigned int __v = (v); \
+ *((unsigned char *)(p) + 0) = __v >> 24; \
+ *((unsigned char *)(p) + 1) = __v >> 16; \
+ *((unsigned char *)(p) + 2) = __v >> 8; \
+ *((unsigned char *)(p) + 3) = __v >> 0; } while (0)
+
+#endif
+
+/* This "rolls" over the 512-bit array */
+#define W(x) (array[(x)&15])
+
+/*
+ * Where do we get the source from? The first 16 iterations get it from
+ * the input data, the next mix it from the 512-bit array.
+ */
+#define SHA_SRC(t) get_be32(data + t)
+#define SHA_MIX(t) SHA_ROL(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1)
+
+#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \
+ unsigned int TEMP = input(t); setW(t, TEMP); \
+ E += TEMP + SHA_ROL(A,5) + (fn) + (constant); \
+ B = SHA_ROR(B, 2); } while (0)
+
+#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
+#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
+#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E )
+#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E )
+#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E )
+
+static void blk_SHA1_Block(blk_SHA_CTX *ctx, const unsigned int *data)
+{
+ unsigned int A,B,C,D,E;
+ unsigned int array[16];
+
+ A = ctx->H[0];
+ B = ctx->H[1];
+ C = ctx->H[2];
+ D = ctx->H[3];
+ E = ctx->H[4];
+
+ /* Round 1 - iterations 0-16 take their input from 'data' */
+ T_0_15( 0, A, B, C, D, E);
+ T_0_15( 1, E, A, B, C, D);
+ T_0_15( 2, D, E, A, B, C);
+ T_0_15( 3, C, D, E, A, B);
+ T_0_15( 4, B, C, D, E, A);
+ T_0_15( 5, A, B, C, D, E);
+ T_0_15( 6, E, A, B, C, D);
+ T_0_15( 7, D, E, A, B, C);
+ T_0_15( 8, C, D, E, A, B);
+ T_0_15( 9, B, C, D, E, A);
+ T_0_15(10, A, B, C, D, E);
+ T_0_15(11, E, A, B, C, D);
+ T_0_15(12, D, E, A, B, C);
+ T_0_15(13, C, D, E, A, B);
+ T_0_15(14, B, C, D, E, A);
+ T_0_15(15, A, B, C, D, E);
+
+ /* Round 1 - tail. Input from 512-bit mixing array */
+ T_16_19(16, E, A, B, C, D);
+ T_16_19(17, D, E, A, B, C);
+ T_16_19(18, C, D, E, A, B);
+ T_16_19(19, B, C, D, E, A);
+
+ /* Round 2 */
+ T_20_39(20, A, B, C, D, E);
+ T_20_39(21, E, A, B, C, D);
+ T_20_39(22, D, E, A, B, C);
+ T_20_39(23, C, D, E, A, B);
+ T_20_39(24, B, C, D, E, A);
+ T_20_39(25, A, B, C, D, E);
+ T_20_39(26, E, A, B, C, D);
+ T_20_39(27, D, E, A, B, C);
+ T_20_39(28, C, D, E, A, B);
+ T_20_39(29, B, C, D, E, A);
+ T_20_39(30, A, B, C, D, E);
+ T_20_39(31, E, A, B, C, D);
+ T_20_39(32, D, E, A, B, C);
+ T_20_39(33, C, D, E, A, B);
+ T_20_39(34, B, C, D, E, A);
+ T_20_39(35, A, B, C, D, E);
+ T_20_39(36, E, A, B, C, D);
+ T_20_39(37, D, E, A, B, C);
+ T_20_39(38, C, D, E, A, B);
+ T_20_39(39, B, C, D, E, A);
+
+ /* Round 3 */
+ T_40_59(40, A, B, C, D, E);
+ T_40_59(41, E, A, B, C, D);
+ T_40_59(42, D, E, A, B, C);
+ T_40_59(43, C, D, E, A, B);
+ T_40_59(44, B, C, D, E, A);
+ T_40_59(45, A, B, C, D, E);
+ T_40_59(46, E, A, B, C, D);
+ T_40_59(47, D, E, A, B, C);
+ T_40_59(48, C, D, E, A, B);
+ T_40_59(49, B, C, D, E, A);
+ T_40_59(50, A, B, C, D, E);
+ T_40_59(51, E, A, B, C, D);
+ T_40_59(52, D, E, A, B, C);
+ T_40_59(53, C, D, E, A, B);
+ T_40_59(54, B, C, D, E, A);
+ T_40_59(55, A, B, C, D, E);
+ T_40_59(56, E, A, B, C, D);
+ T_40_59(57, D, E, A, B, C);
+ T_40_59(58, C, D, E, A, B);
+ T_40_59(59, B, C, D, E, A);
+
+ /* Round 4 */
+ T_60_79(60, A, B, C, D, E);
+ T_60_79(61, E, A, B, C, D);
+ T_60_79(62, D, E, A, B, C);
+ T_60_79(63, C, D, E, A, B);
+ T_60_79(64, B, C, D, E, A);
+ T_60_79(65, A, B, C, D, E);
+ T_60_79(66, E, A, B, C, D);
+ T_60_79(67, D, E, A, B, C);
+ T_60_79(68, C, D, E, A, B);
+ T_60_79(69, B, C, D, E, A);
+ T_60_79(70, A, B, C, D, E);
+ T_60_79(71, E, A, B, C, D);
+ T_60_79(72, D, E, A, B, C);
+ T_60_79(73, C, D, E, A, B);
+ T_60_79(74, B, C, D, E, A);
+ T_60_79(75, A, B, C, D, E);
+ T_60_79(76, E, A, B, C, D);
+ T_60_79(77, D, E, A, B, C);
+ T_60_79(78, C, D, E, A, B);
+ T_60_79(79, B, C, D, E, A);
+
+ ctx->H[0] += A;
+ ctx->H[1] += B;
+ ctx->H[2] += C;
+ ctx->H[3] += D;
+ ctx->H[4] += E;
+}
+
+void blk_SHA1_Init(blk_SHA_CTX *ctx)
+{
+ ctx->size = 0;
+
+ /* Initialize H with the magic constants (see FIPS180 for constants) */
+ ctx->H[0] = 0x67452301;
+ ctx->H[1] = 0xefcdab89;
+ ctx->H[2] = 0x98badcfe;
+ ctx->H[3] = 0x10325476;
+ ctx->H[4] = 0xc3d2e1f0;
+}
+
+void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *data, unsigned long len)
+{
+ unsigned int lenW = ctx->size & 63;
+
+ ctx->size += len;
+
+ /* Read the data into W and process blocks as they get full */
+ if (lenW) {
+ unsigned int left = 64 - lenW;
+ if (len < left)
+ left = len;
+ memcpy(lenW + (char *)ctx->W, data, left);
+ lenW = (lenW + left) & 63;
+ len -= left;
+ data = ((const char *)data + left);
+ if (lenW)
+ return;
+ blk_SHA1_Block(ctx, ctx->W);
+ }
+ while (len >= 64) {
+ blk_SHA1_Block(ctx, data);
+ data = ((const char *)data + 64);
+ len -= 64;
+ }
+ if (len)
+ memcpy(ctx->W, data, len);
+}
+
+void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx)
+{
+ static const unsigned char pad[64] = { 0x80 };
+ unsigned int padlen[2];
+ int i;
+
+ /* Pad with a binary 1 (ie 0x80), then zeroes, then length */
+ padlen[0] = htonl((uint32_t)(ctx->size >> 29));
+ padlen[1] = htonl((uint32_t)(ctx->size << 3));
+
+ i = ctx->size & 63;
+ blk_SHA1_Update(ctx, pad, 1+ (63 & (55 - i)));
+ blk_SHA1_Update(ctx, padlen, 8);
+
+ /* Output hash */
+ for (i = 0; i < 5; i++)
+ put_be32(hashout + i*4, ctx->H[i]);
+}
diff --git a/fluent-bit/lib/monkey/plugins/auth/sha1.h b/fluent-bit/lib/monkey/plugins/auth/sha1.h
new file mode 100644
index 000000000..4a75ab351
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/auth/sha1.h
@@ -0,0 +1,22 @@
+/*
+ * SHA1 routine optimized to do word accesses rather than byte accesses,
+ * and to avoid unnecessary copies into the context array.
+ *
+ * This was initially based on the Mozilla SHA1 implementation, although
+ * none of the original Mozilla code remains.
+ */
+
+typedef struct {
+ unsigned long long size;
+ unsigned int H[5];
+ unsigned int W[16];
+} blk_SHA_CTX;
+
+void blk_SHA1_Init(blk_SHA_CTX *ctx);
+void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *dataIn, unsigned long len);
+void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx);
+
+#define SHA_CTX blk_SHA_CTX
+#define SHA1_Init blk_SHA1_Init
+#define SHA1_Update blk_SHA1_Update
+#define SHA1_Final blk_SHA1_Final
diff --git a/fluent-bit/lib/monkey/plugins/auth/tools/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/auth/tools/CMakeLists.txt
new file mode 100644
index 000000000..63b445cf7
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/auth/tools/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(src
+ ../sha1.c
+ ../base64.c
+ mk_passwd.c
+ )
+
+include_directories(../)
+add_definitions(-D_FORCE_SYSMALLOC)
+add_executable(mk_passwd ${src})
+
+if(BUILD_LOCAL)
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/")
+else()
+ install(TARGETS mk_passwd RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_SBINDIR})
+endif()
diff --git a/fluent-bit/lib/monkey/plugins/auth/tools/mk_passwd.c b/fluent-bit/lib/monkey/plugins/auth/tools/mk_passwd.c
new file mode 100644
index 000000000..6dba1d3f1
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/auth/tools/mk_passwd.c
@@ -0,0 +1,209 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#ifdef MALLOC_JEMALLOC
+#undef MALLOC_JEMALLOC
+#endif
+
+#include <monkey/monkey.h>
+#include <monkey/mk_core.h>
+
+#include <getopt.h>
+
+#include "sha1.h"
+#include "base64.h"
+
+#define MAX_LINE_LEN 256
+
+struct mk_passwd_user {
+ char *row;
+ struct mk_list _head;
+};
+
+/* Store a file as a linked list of its lines */
+static struct mk_list passwd_file;
+
+/* Load file to memory from disk
+ * If create_file == MK_TRUE, the file will be rewritten */
+void read_file(char *filename, int create_file)
+{
+ FILE *filein = fopen(filename, "r");
+ char line[MAX_LINE_LEN];
+ struct mk_passwd_user *entry;
+
+ mk_list_init(&passwd_file);
+
+ if (filein == NULL && create_file == MK_FALSE) {
+ printf("Error opening file %s\n", filename);
+ exit(1);
+ }
+
+ if (filein == NULL || create_file == MK_TRUE) {
+ if (filein != NULL)
+ fclose(filein);
+ return;
+ }
+
+ while (fgets(line, MAX_LINE_LEN, filein) != NULL) {
+ entry = malloc(sizeof(*entry));
+ entry->row = strdup(line);
+ mk_list_add(&entry->_head, &passwd_file);
+ }
+ fclose(filein);
+}
+
+/* Store data to disk */
+void dump_file(char *filename)
+{
+ FILE *fileout = fopen(filename, "w");
+ struct mk_list *it, *tmp;
+ struct mk_passwd_user *entry;
+
+ if (!fileout) {
+ printf("Error opening: %s", filename);
+ exit(EXIT_FAILURE);
+ }
+
+ mk_list_foreach_safe(it, tmp, &passwd_file) {
+ entry = mk_list_entry(it, struct mk_passwd_user, _head);
+ fprintf(fileout, "%s", entry->row);
+ mk_list_del(&entry->_head);
+ free(entry->row);
+ free(entry);
+ }
+ fclose(fileout);
+}
+
+/* Return sha1 hash of password
+ * A new line is appended at the hash */
+unsigned char *sha1_hash(const char *password)
+{
+
+ unsigned char sha_hash[20];
+ blk_SHA_CTX sha;
+
+ blk_SHA1_Init(&sha);
+ blk_SHA1_Update(&sha, password, strlen(password));
+ blk_SHA1_Final(sha_hash, &sha);
+
+ return base64_encode(sha_hash, 20, NULL);
+}
+
+void update_user(const char *username, const char *password, int create_user)
+{
+ struct mk_list *it, *tmp;
+ struct mk_passwd_user *entry;
+ unsigned char *hash_passwd;
+ int i;
+
+ mk_list_foreach_safe(it, tmp, &passwd_file) {
+ entry = mk_list_entry(it, struct mk_passwd_user, _head);
+ for (i = 0; entry->row[i] != '\0' && entry->row[i] != ':' && username[i] != '\0' && entry->row[i] == username[i]; i++);
+ if (entry->row[i] != ':' || username[i] != '\0')
+ continue;
+
+ /* Found a match */
+
+ /* Delete user */
+ if (create_user == MK_FALSE) {
+ printf("[-] Deleting user %s\n", username);
+ mk_list_del(&entry->_head);
+ free(entry->row);
+ free(entry);
+ return;
+ }
+
+ /* Update user */
+ printf("[+] Password changed for user %s\n", username);
+ hash_passwd = sha1_hash(password);
+ free(entry->row);
+ entry->row = malloc(512);
+ snprintf(entry->row, 512, "%s:{SHA1}%s", username, hash_passwd);
+ free(hash_passwd);
+
+ return;
+ }
+
+ /* Create user */
+ if (create_user == MK_TRUE) {
+ printf("[+] Adding user %s\n", username);
+ entry = malloc(sizeof(struct mk_passwd_user));
+ entry->row = malloc(512);
+ hash_passwd = sha1_hash(password);
+ snprintf(entry->row, 512, "%s:{SHA1}%s", username, hash_passwd);
+ free(hash_passwd);
+
+ mk_list_add(&entry->_head, &passwd_file);
+ }
+}
+
+static void print_help(int full_help)
+{
+ printf("Usage: mk_passwd [-c] [-D] filename username password\n");
+ if (full_help == MK_TRUE) {
+ printf("\nOptions:\n");
+ printf(" -h, --help\tshow this help message and exit\n");
+ printf(" -c\t\tCreate a new mkpasswd file, overwriting any existing file.\n");
+ printf(" -D\t\tRemove the given user from the password file.\n");
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ int create_user = MK_TRUE;
+ int create_file = MK_FALSE;
+ int show_help = MK_FALSE;
+ char *filename = NULL;
+ char *username = NULL;
+ char *password = NULL;
+
+ /* Command line options */
+ static const struct option long_opts[] = {
+ {"create", no_argument, NULL, 'c'},
+ {"delete_user", no_argument, NULL, 'D'},
+ {"help", no_argument, NULL, 'h'},
+ };
+
+ /* Parse options */
+ while ((opt = getopt_long(argc, argv, "hbDc", long_opts, NULL)) != -1) {
+ switch (opt) {
+ case 'c':
+ create_file = MK_TRUE;
+ break;
+ case 'D':
+ create_user = MK_FALSE;
+ break;
+ case 'h':
+ show_help = MK_TRUE;
+ break;
+ }
+ }
+
+ /* Retrieve filename, username and password */
+ while (optind < argc) {
+ if (filename == NULL)
+ filename = argv[optind++];
+ else if (username == NULL)
+ username = argv[optind++];
+ else if (password == NULL)
+ password = argv[optind++];
+ }
+
+ if (show_help == MK_TRUE) {
+ print_help(MK_TRUE);
+ exit(0);
+ }
+
+ /* If delete_user option is provided, do not provide a password */
+ if ((password != NULL) ^ (create_user == MK_TRUE)) {
+ print_help(MK_FALSE);
+ exit(1);
+ }
+
+ /* Process request */
+ read_file(filename, create_file);
+ update_user(username, password, create_user);
+ dump_file(filename);
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/plugins/cgi/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/cgi/CMakeLists.txt
new file mode 100644
index 000000000..121144aa1
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cgi/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(src
+ cgi.c
+ event.c
+ request.c
+ )
+
+MONKEY_PLUGIN(cgi "${src}")
diff --git a/fluent-bit/lib/monkey/plugins/cgi/cgi.c b/fluent-bit/lib/monkey/plugins/cgi/cgi.c
new file mode 100644
index 000000000..58c7a647f
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cgi/cgi.c
@@ -0,0 +1,501 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ * Copyright (C) 2012-2013, Lauri Kasanen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_stream.h>
+#include "cgi.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+
+void cgi_finish(struct cgi_request *r)
+{
+ /*
+ * Unregister & close the CGI child process pipe reader fd from the
+ * thread event loop, otherwise we may get unexpected notifications.
+ */
+ mk_api->ev_del(mk_api->sched_loop(), (struct mk_event *) r);
+ close(r->fd);
+ if (r->chunked && r->active == MK_TRUE) {
+ PLUGIN_TRACE("CGI sending Chunked EOF");
+ channel_write(r, "0\r\n\r\n", 5);
+ }
+
+ /* Try to kill any child process */
+ if (r->child > 0) {
+ kill(r->child, SIGKILL);
+ r->child = 0;
+ }
+
+ /* Invalidte our socket handler */
+ requests_by_socket[r->socket] = NULL;
+ if (r->active == MK_TRUE) {
+ mk_api->http_request_end(r->plugin, r->cs, r->hangup);
+ }
+ cgi_req_del(r);
+}
+
+int swrite(const int fd, const void *buf, const size_t count)
+{
+ ssize_t pos = count, ret = 0;
+
+ while (pos > 0 && ret >= 0) {
+ ret = write(fd, buf, pos);
+ if (ret < 0) {
+ return ret;
+ }
+
+ pos -= ret;
+ buf += ret;
+ }
+ return count;
+}
+
+int channel_write(struct cgi_request *r, void *buf, size_t count)
+{
+ int ret;
+
+ if (r->active == MK_FALSE) {
+ return -1;
+ }
+
+ MK_TRACE("channel write: %d bytes", count);
+ mk_stream_in_raw(&r->sr->stream,
+ NULL,
+ buf, count,
+ NULL, NULL);
+
+ ret = mk_api->channel_flush(r->sr->session->channel);
+ if (ret & MK_CHANNEL_ERROR) {
+ r->active = MK_FALSE;
+ cgi_finish(r);
+ }
+ return 0;
+}
+
+static void cgi_write_post(void *p)
+{
+ const struct post_t * const in = p;
+
+ swrite(in->fd, in->buf, in->len);
+ close(in->fd);
+}
+
+static int do_cgi(const char *const __restrict__ file,
+ const char *const __restrict__ url,
+ struct mk_http_request *sr,
+ struct mk_http_session *cs,
+ struct mk_plugin *plugin,
+ char *interpreter,
+ char *mimetype)
+{
+ int ret;
+ int devnull;
+ const int socket = cs->socket;
+ struct file_info finfo;
+ struct cgi_request *r = NULL;
+ struct mk_event *event;
+ char *env[30];
+ int writepipe[2], readpipe[2];
+ (void) plugin;
+
+ /* Unchanging env vars */
+ env[0] = "PATH_INFO=";
+ env[1] = "GATEWAY_INTERFACE=CGI/1.1";
+ env[2] = "REDIRECT_STATUS=200";
+ const int env_start = 3;
+ char *protocol;
+ unsigned long len;
+
+ /* Dynamic env vars */
+ unsigned short envpos = env_start;
+
+ char method[SHORTLEN];
+ char *query = NULL;
+ char request_uri[PATHLEN];
+ char script_filename[PATHLEN];
+ char script_name[PATHLEN];
+ char query_string[PATHLEN];
+ char remote_addr[INET6_ADDRSTRLEN+SHORTLEN];
+ char tmpaddr[INET6_ADDRSTRLEN], *ptr = tmpaddr;
+ char remote_port[SHORTLEN];
+ char content_length[SHORTLEN];
+ char content_type[SHORTLEN];
+ char server_software[SHORTLEN];
+ char server_protocol[SHORTLEN];
+ char http_host[SHORTLEN];
+
+ /* Check the interpreter exists */
+ if (interpreter) {
+ ret = mk_api->file_get_info(interpreter, &finfo, MK_FILE_EXEC);
+ if (ret == -1 ||
+ (finfo.is_file == MK_FALSE && finfo.is_link == MK_FALSE) ||
+ finfo.exec_access == MK_FALSE) {
+ return 500;
+ }
+ }
+
+ if (mimetype) {
+ sr->content_type.data = mimetype;
+ sr->content_type.len = strlen(mimetype);
+ }
+
+ snprintf(method, SHORTLEN, "REQUEST_METHOD=%.*s", (int) sr->method_p.len, sr->method_p.data);
+ env[envpos++] = method;
+
+ snprintf(server_software, SHORTLEN, "SERVER_SOFTWARE=%s",
+ mk_api->config->server_signature);
+ env[envpos++] = server_software;
+
+ snprintf(http_host, SHORTLEN, "HTTP_HOST=%.*s", (int) sr->host.len, sr->host.data);
+ env[envpos++] = http_host;
+
+ if (sr->protocol == MK_HTTP_PROTOCOL_11)
+ protocol = MK_HTTP_PROTOCOL_11_STR;
+ else
+ protocol = MK_HTTP_PROTOCOL_10_STR;
+
+ snprintf(server_protocol, SHORTLEN, "SERVER_PROTOCOL=%s", protocol);
+ env[envpos++] = server_protocol;
+
+ if (sr->query_string.len) {
+ query = mk_api->mem_alloc_z(sr->query_string.len + 1);
+ memcpy(query, sr->query_string.data, sr->query_string.len);
+ snprintf(request_uri, PATHLEN, "REQUEST_URI=%s?%s", url, query);
+ }
+ else {
+ snprintf(request_uri, PATHLEN, "REQUEST_URI=%s", url);
+ }
+ env[envpos++] = request_uri;
+
+ snprintf(script_filename, PATHLEN, "SCRIPT_FILENAME=%s", file);
+ env[envpos++] = script_filename;
+
+ snprintf(script_name, PATHLEN, "SCRIPT_NAME=%s", url);
+ env[envpos++] = script_name;
+
+ if (query) {
+ snprintf(query_string, PATHLEN, "QUERY_STRING=%s", query);
+ env[envpos++] = query_string;
+ mk_api->mem_free(query);
+ }
+
+ if (mk_api->socket_ip_str(socket, &ptr, INET6_ADDRSTRLEN, &len) < 0)
+ tmpaddr[0] = '\0';
+ snprintf(remote_addr, INET6_ADDRSTRLEN+SHORTLEN, "REMOTE_ADDR=%s", tmpaddr);
+ env[envpos++] = remote_addr;
+
+ snprintf(remote_port, SHORTLEN, "REMOTE_PORT=%ld", sr->port);
+ env[envpos++] = remote_port;
+
+ if (sr->data.len) {
+ snprintf(content_length, SHORTLEN, "CONTENT_LENGTH=%lu", sr->data.len);
+ env[envpos++] = content_length;
+ }
+
+ if (sr->content_type.len) {
+ snprintf(content_type, SHORTLEN, "CONTENT_TYPE=%.*s", (int)sr->content_type.len, sr->content_type.data);
+ env[envpos++] = content_type;
+ }
+
+
+ /* Must be NULL-terminated */
+ env[envpos] = NULL;
+
+ /* pipes, from monkey's POV */
+ if (pipe(writepipe) || pipe(readpipe)) {
+ mk_err("Failed to create pipe");
+ return 403;
+ }
+
+ pid_t pid = vfork();
+ if (pid < 0) {
+ mk_err("Failed to fork");
+ return 403;
+ }
+
+ /* Child */
+ if (pid == 0) {
+ close(writepipe[1]);
+ close(readpipe[0]);
+
+ /* Our stdin is the read end of monkey's writing */
+ if (dup2(writepipe[0], 0) < 0) {
+ mk_err("dup2 failed");
+ _exit(1);
+ }
+ close(writepipe[0]);
+
+ /* Our stdout is the write end of monkey's reading */
+ if (dup2(readpipe[1], 1) < 0) {
+ mk_err("dup2 failed");
+ _exit(1);
+ }
+ close(readpipe[1]);
+
+ /* Our stderr goes to /dev/null */
+ devnull = open("/dev/null", O_WRONLY);
+ if (devnull == -1) {
+ perror("open");
+ _exit(1);
+ }
+
+ if (dup2(devnull, 2) < 0) {
+ mk_err("dup2 failed");
+ _exit(1);
+ }
+ close(devnull);
+
+ char *argv[3] = { NULL };
+
+ char *tmp = mk_api->str_dup(file);
+ if (chdir(dirname(tmp)))
+ _exit(1);
+
+ char *tmp2 = mk_api->str_dup(file);
+ argv[0] = basename(tmp2);
+
+ /* Restore signals for the child */
+ signal(SIGPIPE, SIG_DFL);
+ signal(SIGCHLD, SIG_DFL);
+
+ if (!interpreter) {
+ execve(file, argv, env);
+ }
+ else {
+ argv[0] = basename(interpreter);
+ argv[1] = (char *) file;
+ execve(interpreter, argv, env);
+ }
+ /* Exec failed, return */
+ _exit(1);
+ }
+
+ /* Yay me */
+ close(writepipe[0]);
+ close(readpipe[1]);
+
+ /* If we have POST data to write, spawn a thread to do that */
+ if (sr->data.len) {
+ struct post_t p;
+ pthread_t tid;
+
+ p.fd = writepipe[1];
+ p.buf = sr->data.data;
+ p.len = sr->data.len;
+
+ ret = mk_api->worker_spawn(cgi_write_post, &p, &tid);
+ if (ret != 0) {
+ return 403;
+ }
+ }
+ else {
+ close(writepipe[1]);
+ }
+
+ r = cgi_req_create(readpipe[0], socket, plugin, sr, cs);
+ if (!r) {
+ return 403;
+ }
+ r->child = pid;
+
+ /*
+ * Hang up?: by default Monkey assumes the CGI scripts generate
+ * content dynamically (no Content-Length header), so for such HTTP/1.0
+ * clients we should close the connection as KeepAlive is not supported
+ * by specification, only on HTTP/1.1 where the Chunked Transfer encoding
+ * exists.
+ */
+ if (r->sr->protocol >= MK_HTTP_PROTOCOL_11) {
+ r->hangup = MK_FALSE;
+ }
+
+ /* Set transfer encoding */
+ if (r->sr->protocol >= MK_HTTP_PROTOCOL_11 &&
+ (r->sr->headers.status < MK_REDIR_MULTIPLE ||
+ r->sr->headers.status > MK_REDIR_USE_PROXY)) {
+ r->sr->headers.transfer_encoding = MK_HEADER_TE_TYPE_CHUNKED;
+ r->chunked = 1;
+ }
+
+ /* Register the 'request' context */
+ cgi_req_add(r);
+
+ /* Prepare the built-in event structure */
+ event = &r->event;
+ event->fd = readpipe[0];
+ event->type = MK_EVENT_CUSTOM;
+ event->mask = MK_EVENT_EMPTY;
+ event->data = r;
+ event->handler = cb_cgi_read;
+
+ /* Register the event into the worker event-loop */
+ ret = mk_api->ev_add(mk_api->sched_loop(),
+ readpipe[0],
+ MK_EVENT_CUSTOM, MK_EVENT_READ, r);
+ if (ret != 0) {
+ return 403;
+ }
+
+
+ /* XXX Fixme: this needs to be atomic */
+ requests_by_socket[socket] = r;
+ return 200;
+}
+
+int mk_cgi_plugin_init(struct plugin_api **api, char *confdir)
+{
+ struct rlimit lim;
+ (void) confdir;
+
+ mk_api = *api;
+ mk_list_init(&cgi_global_matches);
+ pthread_key_create(&cgi_request_list, NULL);
+
+ /*
+ * We try to perform some quick lookup over the list of CGI
+ * instances. We do this with a fixed length array, if you use CGI
+ * you don't care too much about performance anyways.
+ */
+ getrlimit(RLIMIT_NOFILE, &lim);
+ requests_by_socket = mk_api->mem_alloc_z(sizeof(struct cgi_request *) * lim.rlim_cur);
+
+ /* Make sure we act good if the child dies */
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGCHLD, SIG_IGN);
+
+ return 0;
+}
+
+int mk_cgi_plugin_exit()
+{
+ regfree(&match_regex);
+ mk_api->mem_free(requests_by_socket);
+
+ return 0;
+}
+
+int mk_cgi_stage30(struct mk_plugin *plugin,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ int n_params,
+ struct mk_list *params)
+{
+ char *interpreter = NULL;
+ char *mimetype = NULL;
+ struct mk_vhost_handler_param *param;
+ (void) plugin;
+
+ const char *const file = sr->real_path.data;
+
+ if (!sr->file_info.is_file) {
+ return MK_PLUGIN_RET_NOT_ME;
+ }
+
+ /* start running the CGI */
+ if (cgi_req_get(cs->socket)) {
+ PLUGIN_TRACE("Error, someone tried to retry\n");
+ return MK_PLUGIN_RET_CONTINUE;
+ }
+
+ if (n_params > 0) {
+ /* Interpreter */
+ param = mk_api->handler_param_get(0, params);
+ if (param) {
+ interpreter = param->p.data;
+ }
+
+ /* Mimetype */
+ param = mk_api->handler_param_get(0, params);
+ if (param) {
+ mimetype = param->p.data;
+ }
+ }
+
+ int status = do_cgi(file, sr->uri_processed.data,
+ sr, cs, plugin, interpreter, mimetype);
+
+ /* These are just for the other plugins, such as logger; bogus data */
+ mk_api->header_set_http_status(sr, status);
+ if (status != 200) {
+ return MK_PLUGIN_RET_CLOSE_CONX;
+ }
+
+ sr->headers.cgi = SH_CGI;
+ return MK_PLUGIN_RET_CONTINUE;
+}
+
+/*
+ * Invoked everytime a remote client drop the active connection, this
+ * callback is triggered by the Monkey Scheduler
+ */
+int mk_cgi_stage30_hangup(struct mk_plugin *plugin,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr)
+{
+ struct cgi_request *r;
+ (void) sr;
+ (void) plugin;
+
+ PLUGIN_TRACE("CGI / Parent connection closed (hangup)");
+ r = requests_by_socket[cs->socket];
+ if (!r) {
+ return -1;
+ }
+
+ r->active = MK_FALSE;
+ cgi_finish(r);
+ return 0;
+}
+
+void mk_cgi_worker_init()
+{
+ struct mk_list *list = mk_api->mem_alloc_z(sizeof(struct mk_list));
+
+ mk_list_init(list);
+ pthread_setspecific(cgi_request_list, (void *) list);
+}
+
+
+struct mk_plugin_stage mk_plugin_stage_cgi = {
+ .stage30 = &mk_cgi_stage30,
+ .stage30_hangup = &mk_cgi_stage30_hangup
+};
+
+struct mk_plugin mk_plugin_cgi = {
+ /* Identification */
+ .shortname = "cgi",
+ .name = "Common Gateway Interface",
+ .version = MK_VERSION_STR,
+ .hooks = MK_PLUGIN_STAGE,
+
+ /* Init / Exit */
+ .init_plugin = mk_cgi_plugin_init,
+ .exit_plugin = mk_cgi_plugin_exit,
+
+ /* Init Levels */
+ .master_init = NULL,
+ .worker_init = mk_cgi_worker_init,
+
+ /* Type */
+ .stage = &mk_plugin_stage_cgi
+};
diff --git a/fluent-bit/lib/monkey/plugins/cgi/cgi.h b/fluent-bit/lib/monkey/plugins/cgi/cgi.h
new file mode 100644
index 000000000..27123b7ae
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cgi/cgi.h
@@ -0,0 +1,133 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ * Copyright (C) 2012-2013, Lauri Kasanen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_CGI_H
+#define MK_CGI_H
+
+#include <monkey/mk_api.h>
+
+#include <sys/types.h>
+#include <regex.h>
+#include <signal.h>
+#include <libgen.h>
+
+enum {
+ BUFLEN = 4096,
+ PATHLEN = 1024,
+ SHORTLEN = 64
+};
+
+regex_t match_regex;
+
+struct cgi_request **requests_by_socket;
+
+struct post_t {
+ int fd;
+ void *buf;
+ unsigned long len;
+};
+
+struct cgi_match_t {
+ regex_t match;
+ char *bin;
+ mk_ptr_t content_type;
+
+ struct mk_list _head;
+};
+
+struct cgi_vhost_t {
+ struct mk_vhost *host;
+ struct mk_list matches;
+};
+
+struct cgi_vhost_t *cgi_vhosts;
+struct mk_list cgi_global_matches;
+
+
+struct cgi_request {
+ /* Built-in reference for the event loop */
+ struct mk_event event;
+
+ char in_buf[BUFLEN];
+
+ struct mk_list _head;
+
+ struct mk_plugin *plugin;
+ struct mk_http_request *sr;
+ struct mk_http_session *cs;
+
+ unsigned int in_len;
+
+ int fd; /* Pipe the CGI proc */
+ int socket; /* Client connection */
+ int hangup; /* Should close connection when done ? */
+ int active; /* Active session ? */
+ pid_t child; /* child process ID */
+ unsigned char status_done;
+ unsigned char all_headers_done;
+ unsigned char chunked;
+};
+
+/* Global list per worker */
+pthread_key_t cgi_request_list;
+
+extern struct cgi_request **requests_by_socket;
+
+void cgi_finish(struct cgi_request *r);
+
+int swrite(const int fd, const void *buf, const size_t count);
+int channel_write(struct cgi_request *r, void *buf, size_t count);
+
+struct cgi_request *cgi_req_create(int fd, int socket,
+ struct mk_plugin *plugin,
+ struct mk_http_request *sr,
+ struct mk_http_session *cs);
+void cgi_req_add(struct cgi_request *r);
+int cgi_req_del(struct cgi_request *r);
+
+// Get the CGI request by the client socket
+static inline struct cgi_request *cgi_req_get(int socket)
+{
+ struct cgi_request *r = requests_by_socket[socket];
+ return r;
+}
+
+// Get the CGI request by the CGI app's fd
+static inline struct cgi_request *cgi_req_get_by_fd(int fd)
+{
+ struct mk_list *list, *node;
+ struct cgi_request *r;
+
+ list = pthread_getspecific(cgi_request_list);
+ if (mk_list_is_empty(list) == 0)
+ return NULL;
+
+ mk_list_foreach(node, list) {
+ r = mk_list_entry(node, struct cgi_request, _head);
+ if (r->fd == fd)
+ return r;
+ }
+
+ return NULL;
+}
+
+int cb_cgi_read(void *data);
+
+#endif
diff --git a/fluent-bit/lib/monkey/plugins/cgi/event.c b/fluent-bit/lib/monkey/plugins/cgi/event.c
new file mode 100644
index 000000000..b8d395260
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cgi/event.c
@@ -0,0 +1,170 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ * Copyright (C) 2012-2013, Lauri Kasanen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "cgi.h"
+
+/*
+ * The reason for this function is that some CGI apps
+ *
+ * use LFLF and some use CRLFCRLF.
+ *
+ * If that app then sends content that has the other break
+ * in the beginning, monkey can accidentally send part of the
+ * content as headers.
+ */
+
+static char *getearliestbreak(const char buf[], const unsigned bufsize,
+ unsigned char * const advance)
+ {
+ char * const crend = memmem(buf, bufsize, MK_IOV_CRLFCRLF,
+ sizeof(MK_IOV_CRLFCRLF) - 1);
+ char * const lfend = memmem(buf, bufsize, MK_IOV_LFLF,
+ sizeof(MK_IOV_LFLF) - 1);
+
+ if (!crend && !lfend)
+ return NULL;
+
+ /* If only one found, return that one */
+ if (!crend) {
+ *advance = 2;
+ return lfend;
+ }
+ if (!lfend)
+ return crend;
+
+ /* Both found, return the earlier one - the latter one is part of content */
+ if (lfend < crend) {
+ *advance = 2;
+ return lfend;
+ }
+ return crend;
+}
+
+int process_cgi_data(struct cgi_request *r)
+{
+ int ret;
+ int len;
+ int status;
+ char *buf = r->in_buf;
+ char *outptr = r->in_buf;
+ char *end;
+ char *endl;
+ unsigned char advance;
+
+ mk_api->socket_cork_flag(r->cs->socket, TCP_CORK_OFF);
+ if (!r->status_done && r->in_len >= 8) {
+ if (memcmp(buf, "Status: ", 8) == 0) {
+ status = atoi(buf + 8);
+ mk_api->header_set_http_status(r->sr, status);
+ endl = memchr(buf + 8, '\n', r->in_len - 8);
+ if (!endl) {
+ return MK_PLUGIN_RET_EVENT_OWNED;
+ }
+ else {
+ endl++;
+ outptr = endl;
+ r->in_len -= endl - buf;
+ }
+ }
+ else if (memcmp(buf, "HTTP", 4) == 0) {
+ status = atoi(buf + 9);
+ mk_api->header_set_http_status(r->sr, status);
+
+ endl = memchr(buf + 8, '\n', r->in_len - 8);
+ if (!endl) {
+ return MK_PLUGIN_RET_EVENT_OWNED;
+ }
+ else {
+ endl++;
+ outptr = endl;
+ r->in_len -= endl - buf;
+ }
+ }
+ mk_api->header_prepare(r->plugin, r->cs, r->sr);
+ r->status_done = 1;
+ }
+
+ if (!r->all_headers_done) {
+ advance = 4;
+
+ /* Write the rest of the headers without chunking */
+ end = getearliestbreak(outptr, r->in_len, &advance);
+ if (!end) {
+ /* Let's return until we have the headers break */
+ return MK_PLUGIN_RET_EVENT_OWNED;
+ }
+ end += advance;
+ len = end - outptr;
+ channel_write(r, outptr, len);
+ outptr += len;
+ r->in_len -= len;
+
+ r->all_headers_done = 1;
+ if (r->in_len == 0) {
+ return MK_PLUGIN_RET_EVENT_OWNED;
+ }
+ }
+
+ if (r->chunked) {
+ char tmp[16];
+ len = snprintf(tmp, 16, "%x\r\n", r->in_len);
+ ret = channel_write(r, tmp, len);
+ if (ret < 0)
+ return MK_PLUGIN_RET_EVENT_CLOSE;
+ }
+
+ ret = channel_write(r, outptr, r->in_len);
+ if (ret < 0) {
+ return MK_PLUGIN_RET_EVENT_CLOSE;
+ }
+
+ r->in_len = 0;
+ if (r->chunked) {
+ channel_write(r, MK_CRLF, 2);
+ }
+ return MK_PLUGIN_RET_EVENT_OWNED;
+}
+
+int cb_cgi_read(void *data)
+{
+ int n;
+ struct cgi_request *r = data;
+
+ if (r->active == MK_FALSE) {
+ return -1;
+ }
+
+ if ((BUFLEN - r->in_len) < 1) {
+ PLUGIN_TRACE("CLOSE BY SIZE");
+ cgi_finish(r);
+ return -1;
+ }
+
+ n = read(r->fd, r->in_buf + r->in_len, BUFLEN - r->in_len);
+ PLUGIN_TRACE("FD=%i CGI READ=%d", r->fd, n);
+ if (n <= 0) {
+ /* It most of cases this means the child process finished */
+ cgi_finish(r);
+ return MK_PLUGIN_RET_EVENT_CLOSE;
+ }
+ r->in_len += n;
+ process_cgi_data(r);
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/plugins/cgi/request.c b/fluent-bit/lib/monkey/plugins/cgi/request.c
new file mode 100644
index 000000000..c51a13831
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cgi/request.c
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ * Copyright (C) 2012-2013, Lauri Kasanen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "cgi.h"
+
+struct cgi_request *cgi_req_create(int fd, int socket,
+ struct mk_plugin *plugin,
+ struct mk_http_request *sr,
+ struct mk_http_session *cs)
+{
+ struct cgi_request *cgi;
+
+ cgi = mk_api->mem_alloc_z(sizeof(struct cgi_request));
+ if (!cgi) {
+ return NULL;
+ }
+
+ cgi->fd = fd;
+ cgi->socket = socket;
+ cgi->plugin = plugin;
+ cgi->sr = sr;
+ cgi->cs = cs;
+ cgi->hangup = MK_TRUE;
+ cgi->active = MK_TRUE;
+ cgi->in_len = 0;
+
+ cgi->event.mask = MK_EVENT_EMPTY;
+ cgi->event.status = MK_EVENT_NONE;
+
+ return cgi;
+}
+
+void cgi_req_add(struct cgi_request *r)
+{
+ struct mk_list *list;
+
+ list = pthread_getspecific(cgi_request_list);
+ mk_list_add(&r->_head, list);
+}
+
+int cgi_req_del(struct cgi_request *r)
+{
+ PLUGIN_TRACE("Delete request child_fd=%i child_pid=%lu",
+ r->fd, r->child);
+
+ mk_list_del(&r->_head);
+ if (r->active == MK_FALSE) {
+ mk_api->sched_event_free(&r->event);
+ }
+ else {
+ mk_mem_free(r);
+ }
+
+ return 0;
+}
diff --git a/fluent-bit/lib/monkey/plugins/cheetah/ABOUT b/fluent-bit/lib/monkey/plugins/cheetah/ABOUT
new file mode 100644
index 000000000..229bf62c2
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cheetah/ABOUT
@@ -0,0 +1,4 @@
+Cheetah! Plugin
+===============
+This plugin provides a command line interface for Monkey,
+it works like a shell.
diff --git a/fluent-bit/lib/monkey/plugins/cheetah/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/cheetah/CMakeLists.txt
new file mode 100644
index 000000000..ca760c337
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cheetah/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(src
+ cheetah.c
+ loop.c
+ cmd.c
+ cutils.c
+ )
+
+MONKEY_PLUGIN(cheetah "${src}")
+add_subdirectory(conf)
diff --git a/fluent-bit/lib/monkey/plugins/cheetah/OPTIONAL b/fluent-bit/lib/monkey/plugins/cheetah/OPTIONAL
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cheetah/OPTIONAL
diff --git a/fluent-bit/lib/monkey/plugins/cheetah/cheetah.c b/fluent-bit/lib/monkey/plugins/cheetah/cheetah.c
new file mode 100644
index 000000000..489e73422
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cheetah/cheetah.c
@@ -0,0 +1,162 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Monkey Plugin Interface */
+#include <monkey/mk_api.h>
+
+/* Local header files */
+#include "cmd.h"
+#include "cutils.h"
+#include "cheetah.h"
+#include "loop.h"
+
+void mk_cheetah_welcome_msg()
+{
+ CHEETAH_WRITE("\n%s%s***%s Welcome to %sCheetah!%s, the %sMonkey Shell %s:) %s***%s\n",
+ ANSI_BOLD, ANSI_YELLOW,
+ ANSI_WHITE, ANSI_GREEN,
+ ANSI_WHITE, ANSI_RED, ANSI_WHITE, ANSI_YELLOW, ANSI_RESET);
+ CHEETAH_WRITE("\n << %sType 'help' or '\\h' for help%s >>\n\n",
+ ANSI_BLUE, ANSI_RESET);
+ CHEETAH_FLUSH();
+}
+
+static int mk_cheetah_config(char *path)
+{
+ unsigned long len;
+ char *listen = NULL;
+ char *default_file = NULL;
+ struct mk_rconf *conf;
+ struct mk_rconf_section *section;
+
+ /* this variable is defined in cheetah.h and points to
+ * the FILE *descriptor where to write out the data
+ */
+ cheetah_output = NULL;
+
+ /* read configuration file */
+ mk_api->str_build(&default_file, &len, "%scheetah.conf", path);
+ conf = mk_api->config_open(default_file);
+ if (!conf) {
+ return -1;
+ }
+
+ section = mk_api->config_section_get(conf, "CHEETAH");
+
+ if (!section) {
+ CHEETAH_WRITE("\nError, could not find CHEETAH tag");
+ return -1;
+ }
+
+ /* no longer needed */
+ mk_api->mem_free(default_file);
+
+ /* Listen directive */
+ listen = mk_api->config_section_get_key(section, "Listen", MK_RCONF_STR);
+
+ if (strcasecmp(listen, LISTEN_STDIN_STR) == 0) {
+ listen_mode = LISTEN_STDIN;
+ }
+ else if (strcasecmp(listen, LISTEN_SERVER_STR) == 0) {
+ listen_mode = LISTEN_SERVER;
+ }
+ else {
+ printf("\nCheetah! Error: Invalid LISTEN value");
+ return -1;
+ }
+
+ /* Cheetah cannot work in STDIN mode if Monkey is working in background */
+ if (listen_mode == LISTEN_STDIN && mk_api->config->is_daemon == MK_TRUE) {
+ printf("\nCheetah!: Forcing SERVER mode as Monkey is running in background\n");
+ fflush(stdout);
+ listen_mode = LISTEN_SERVER;
+ }
+
+ return 0;
+}
+
+static void mk_cheetah_init(void *args)
+{
+ struct mk_server *server = args;
+
+ /* Rename worker */
+ mk_api->worker_rename("monkey: cheetah");
+
+ /* Open right FDs for I/O */
+ if (listen_mode == LISTEN_STDIN) {
+ cheetah_input = stdin;
+ cheetah_output = stdout;
+ mk_cheetah_loop_stdin(server);
+ }
+ else if (listen_mode == LISTEN_SERVER) {
+ mk_cheetah_loop_server(server);
+ }
+}
+
+/* This function is called when the plugin is loaded, it must
+ * return
+ */
+int mk_cheetah_plugin_init(struct plugin_api **api, char *confdir)
+{
+ int ret;
+ mk_api = *api;
+ init_time = time(NULL);
+
+ ret = mk_cheetah_config(confdir);
+ return ret;
+}
+
+int mk_cheetah_plugin_exit()
+{
+ if (listen_mode == LISTEN_SERVER) {
+ /* Remote named pipe */
+ unlink(cheetah_server);
+ mk_api->mem_free(cheetah_server);
+ }
+
+ return 0;
+}
+
+int mk_cheetah_master_init(struct mk_server *server)
+{
+ int ret;
+ pthread_t tid;
+
+ ret = mk_api->worker_spawn(mk_cheetah_init, server, &tid);
+ if (ret != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+struct mk_plugin mk_plugin_cheetah = {
+ /* Identification */
+ .shortname = "cheetah",
+ .name = "Cheetah! Shell",
+ .version = MK_VERSION_STR,
+
+ /* Init / Exit */
+ .init_plugin = mk_cheetah_plugin_init,
+ .exit_plugin = mk_cheetah_plugin_exit,
+
+ /* Init Levels */
+ .master_init = mk_cheetah_master_init,
+ .worker_init = NULL
+};
diff --git a/fluent-bit/lib/monkey/plugins/cheetah/cheetah.h b/fluent-bit/lib/monkey/plugins/cheetah/cheetah.h
new file mode 100644
index 000000000..5bf6c14e5
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cheetah/cheetah.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_CHEETAH_H
+#define MK_CHEETAH_H
+
+/* Commands */
+#define MK_CHEETAH_CLEAR "clear"
+#define MK_CHEETAH_CLEAR_SC "\\c"
+
+#define MK_CHEETAH_CONFIG "config"
+#define MK_CHEETAH_CONFIG_SC "\\f"
+
+#define MK_CHEETAH_STATUS "status"
+#define MK_CHEETAH_STATUS_SC "\\s"
+
+#define MK_CHEETAH_HELP "help"
+#define MK_CHEETAH_HELP_SC "\\h"
+
+#define MK_CHEETAH_SHELP "?"
+#define MK_CHEETAH_SHELP_SC "\\?"
+
+#define MK_CHEETAH_UPTIME "uptime"
+#define MK_CHEETAH_UPTIME_SC "\\u"
+
+#define MK_CHEETAH_PLUGINS "plugins"
+#define MK_CHEETAH_PLUGINS_SC "\\g"
+
+#define MK_CHEETAH_VHOSTS "vhosts"
+#define MK_CHEETAH_VHOSTS_SC "\\v"
+
+#define MK_CHEETAH_WORKERS "workers"
+#define MK_CHEETAH_WORKERS_SC "\\w"
+
+#define MK_CHEETAH_QUIT "quit"
+#define MK_CHEETAH_QUIT_SC "\\q"
+
+/* Constants */
+#define MK_CHEETAH_PROMPT "%s%scheetah>%s "
+#define MK_CHEETAH_PROC_TASK "/proc/%i/task/%i/stat"
+#define MK_CHEETAH_ONEDAY 86400
+#define MK_CHEETAH_ONEHOUR 3600
+#define MK_CHEETAH_ONEMINUTE 60
+
+/* Configurarion: Listen */
+#define LISTEN_STDIN_STR "STDIN"
+#define LISTEN_SERVER_STR "SERVER"
+
+#define LISTEN_STDIN 0
+#define LISTEN_SERVER 1
+
+int listen_mode;
+
+char *cheetah_server;
+
+int cheetah_socket;
+FILE *cheetah_input;
+FILE *cheetah_output;
+
+/* functions */
+void mk_cheetah_welcome_msg();
+
+#endif
diff --git a/fluent-bit/lib/monkey/plugins/cheetah/cmd.c b/fluent-bit/lib/monkey/plugins/cheetah/cmd.c
new file mode 100644
index 000000000..6f02dad23
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cheetah/cmd.c
@@ -0,0 +1,472 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_api.h>
+
+#include <pwd.h>
+#include <ctype.h>
+
+#include "cheetah.h"
+#include "cutils.h"
+#include "cmd.h"
+
+/* strip leading and trailing space from input command line. */
+static char *strip_whitespace(char *cmd)
+{
+ char *end;
+ while (isspace(*cmd))
+ cmd++;
+ if (*cmd == 0)
+ return cmd;
+ end = cmd + strlen(cmd) - 1;
+ while (end > cmd && isspace(*end))
+ end--;
+ end++;
+ *end = '\0';
+ return cmd;
+}
+
+int mk_cheetah_cmd(char *raw_cmd, struct mk_server *server)
+{
+ char *cmd = strip_whitespace(raw_cmd);
+ if (strcmp(cmd, MK_CHEETAH_CONFIG) == 0 ||
+ strcmp(cmd, MK_CHEETAH_CONFIG_SC) == 0) {
+ mk_cheetah_cmd_config(server);
+ }
+ else if (strcmp(cmd, MK_CHEETAH_STATUS) == 0 ||
+ strcmp(cmd, MK_CHEETAH_STATUS_SC) == 0) {
+ mk_cheetah_cmd_status(server);
+ }
+ else if (strcmp(cmd, MK_CHEETAH_CLEAR) == 0 ||
+ strcmp(cmd, MK_CHEETAH_CLEAR_SC) == 0) {
+ mk_cheetah_cmd_clear();
+ }
+ else if (strcmp(cmd, MK_CHEETAH_UPTIME) == 0 ||
+ strcmp(cmd, MK_CHEETAH_UPTIME_SC) == 0) {
+ mk_cheetah_cmd_uptime(server);
+ }
+ else if (strcmp(cmd, MK_CHEETAH_PLUGINS) == 0 ||
+ strcmp(cmd, MK_CHEETAH_PLUGINS_SC) == 0) {
+ mk_cheetah_cmd_plugins(server);
+ }
+ else if (strcmp(cmd, MK_CHEETAH_WORKERS) == 0 ||
+ strcmp(cmd, MK_CHEETAH_WORKERS_SC) == 0) {
+ mk_cheetah_cmd_workers(server);
+ }
+ else if (strcmp(cmd, MK_CHEETAH_VHOSTS) == 0 ||
+ strcmp(cmd, MK_CHEETAH_VHOSTS_SC) == 0) {
+ mk_cheetah_cmd_vhosts(server);
+ }
+ else if (strcmp(cmd, MK_CHEETAH_HELP) == 0 ||
+ strcmp(cmd, MK_CHEETAH_HELP_SC) == 0 ||
+ strcmp(cmd, MK_CHEETAH_SHELP) == 0 ||
+ strcmp(cmd, MK_CHEETAH_SHELP_SC) == 0) {
+ mk_cheetah_cmd_help();
+ }
+ else if (strcmp(cmd, MK_CHEETAH_QUIT) == 0 ||
+ strcmp(cmd, MK_CHEETAH_QUIT_SC) == 0) {
+ return mk_cheetah_cmd_quit();
+ }
+ else if (strlen(cmd) == 0) {
+ return 0;
+ }
+ else {
+ CHEETAH_WRITE("Invalid command, type 'help' for a list of available commands\n");
+ }
+
+ CHEETAH_FLUSH();
+ return 0;
+}
+
+void mk_cheetah_cmd_clear()
+{
+ CHEETAH_WRITE("\033[2J\033[1;1H");
+}
+
+void mk_cheetah_cmd_uptime(struct mk_server *server)
+{
+ int days;
+ int hours;
+ int minutes;
+ int seconds;
+ long int upmind;
+ long int upminh;
+ long int uptime;
+ (void) server;
+
+ /* uptime in seconds */
+ uptime = time(NULL) - init_time;
+
+ /* days */
+ days = uptime / MK_CHEETAH_ONEDAY;
+ upmind = uptime - (days * MK_CHEETAH_ONEDAY);
+
+ /* hours */
+ hours = upmind / MK_CHEETAH_ONEHOUR;
+ upminh = upmind - hours * MK_CHEETAH_ONEHOUR;
+
+ /* minutes */
+ minutes = upminh / MK_CHEETAH_ONEMINUTE;
+ seconds = upminh - minutes * MK_CHEETAH_ONEMINUTE;
+
+ CHEETAH_WRITE
+ ("Server has been running: %i day%s, %i hour%s, %i minute%s and %i second%s\n\n",
+ days, (days > 1) ? "s" : "", hours, (hours > 1) ? "s" : "", minutes,
+ (minutes > 1) ? "s" : "", seconds, (seconds > 1) ? "s" : "");
+}
+
+void mk_cheetah_cmd_plugins_print_core(struct mk_list *list)
+{
+ struct mk_plugin *p;
+ struct mk_list *head;
+
+ CHEETAH_WRITE("\n%s[MASTER INIT]%s", ANSI_BOLD ANSI_BLUE, ANSI_RESET);
+
+ mk_list_foreach(head, list) {
+ p = mk_list_entry(head, struct mk_plugin, _head);
+
+ if (p->master_init) {
+ CHEETAH_WRITE("\n [%s] %s v%s on \"%s\"",
+ p->shortname, p->name, p->version, p->path);
+ }
+ }
+
+ CHEETAH_WRITE("\n\n%s[WORKER INIT]%s", ANSI_BOLD ANSI_BLUE, ANSI_RESET);
+
+ mk_list_foreach(head, list) {
+ p = mk_list_entry(head, struct mk_plugin, _head);
+
+ if (p->worker_init) {
+ CHEETAH_WRITE("\n [%s] %s v%s on \"%s\"",
+ p->shortname, p->name, p->version, p->path);
+ }
+ }
+
+ CHEETAH_WRITE("\n\n");
+}
+
+void mk_cheetah_cmd_plugins_print_network(struct mk_list *list)
+{
+ struct mk_plugin *p;
+ struct mk_list *head;
+
+ CHEETAH_WRITE("%s[NETWORK I/O]%s", ANSI_BOLD ANSI_RED, ANSI_RESET);
+
+ mk_list_foreach(head, list) {
+ p = mk_list_entry(head, struct mk_plugin, _head);
+ if (p->hooks & MK_PLUGIN_NETWORK_LAYER) {
+ CHEETAH_WRITE("\n [%s] %s v%s on \"%s\"",
+ p->shortname, p->name, p->version, p->path);
+ }
+ }
+
+ CHEETAH_WRITE("\n");
+}
+
+void mk_cheetah_cmd_plugins(struct mk_server *server)
+{
+ struct mk_plugin *p;
+ struct mk_plugin_stage *s;
+ struct mk_list *head;
+
+ if (mk_list_is_empty(&server->stage10_handler)) {
+ CHEETAH_WRITE("%s[%sSTAGE_10%s]%s",
+ ANSI_BOLD, ANSI_YELLOW, ANSI_WHITE, ANSI_RESET);
+ mk_list_foreach(head, &mk_api->config->stage10_handler) {
+ s = mk_list_entry(head, struct mk_plugin_stage, _head);
+ p = s->plugin;
+ CHEETAH_WRITE("\n [%s] %s v%s on \"%s\"",
+ p->shortname, p->name, p->version, p->path);
+ }
+ }
+
+ if (mk_list_is_empty(&mk_api->config->stage20_handler)) {
+ CHEETAH_WRITE("%s[%sSTAGE_20%s]%s",
+ ANSI_BOLD, ANSI_YELLOW, ANSI_WHITE, ANSI_RESET);
+ mk_list_foreach(head, &mk_api->config->stage20_handler) {
+ s = mk_list_entry(head, struct mk_plugin_stage, _head);
+ p = s->plugin;
+ CHEETAH_WRITE("\n [%s] %s v%s on \"%s\"",
+ p->shortname, p->name, p->version, p->path);
+ }
+ }
+
+ if (mk_list_is_empty(&mk_api->config->stage30_handler)) {
+ CHEETAH_WRITE("%s[%sSTAGE_30%s]%s",
+ ANSI_BOLD, ANSI_YELLOW, ANSI_WHITE, ANSI_RESET);
+ mk_list_foreach(head, &mk_api->config->stage30_handler) {
+ s = mk_list_entry(head, struct mk_plugin_stage, _head);
+ p = s->plugin;
+ CHEETAH_WRITE("\n [%s] %s v%s on \"%s\"",
+ p->shortname, p->name, p->version, p->path);
+ }
+ }
+
+ if (mk_list_is_empty(&mk_api->config->stage40_handler)) {
+ CHEETAH_WRITE("%s[%sSTAGE_40%s]%s",
+ ANSI_BOLD, ANSI_YELLOW, ANSI_WHITE, ANSI_RESET);
+ mk_list_foreach(head, &mk_api->config->stage40_handler) {
+ s = mk_list_entry(head, struct mk_plugin_stage, _head);
+ p = s->plugin;
+ CHEETAH_WRITE("\n [%s] %s v%s on \"%s\"",
+ p->shortname, p->name, p->version, p->path);
+ }
+ }
+
+ if (mk_list_is_empty(&mk_api->config->stage50_handler)) {
+ CHEETAH_WRITE("%s[%sSTAGE_50%s]%s",
+ ANSI_BOLD, ANSI_YELLOW, ANSI_WHITE, ANSI_RESET);
+ mk_list_foreach(head, &mk_api->config->stage50_handler) {
+ s = mk_list_entry(head, struct mk_plugin_stage, _head);
+ p = s->plugin;
+ CHEETAH_WRITE("\n [%s] %s v%s on \"%s\"",
+ p->shortname, p->name, p->version, p->path);
+ }
+ }
+
+ CHEETAH_WRITE("\n\n");
+}
+
+void mk_cheetah_cmd_vhosts(struct mk_server *server)
+{
+ struct mk_vhost *entry_host;
+ struct mk_vhost_alias *entry_alias;
+ struct mk_rconf_section *section;
+ struct mk_rconf_entry *entry;
+ struct mk_list *hosts = &server->hosts;
+ struct mk_list *aliases;
+ struct mk_list *head_host;
+ struct mk_list *head_alias;
+ struct mk_list *head_sections;
+ struct mk_list *head_entries;
+
+ mk_list_foreach(head_host, hosts) {
+ entry_host = mk_list_entry(head_host, struct mk_vhost, _head);
+
+ aliases = &entry_host->server_names;
+ entry_alias = mk_list_entry_first(aliases, struct mk_vhost_alias, _head);
+ CHEETAH_WRITE("%s[%sVHost '%s'%s%s]%s\n",
+ ANSI_BOLD, ANSI_YELLOW,
+ entry_alias->name, ANSI_BOLD, ANSI_WHITE, ANSI_RESET);
+
+ CHEETAH_WRITE(" - Names : ");
+ mk_list_foreach(head_alias, aliases) {
+ entry_alias = mk_list_entry(head_alias, struct mk_vhost_alias, _head);
+ CHEETAH_WRITE("%s ", entry_alias->name);
+ }
+ CHEETAH_WRITE("\n");
+
+ CHEETAH_WRITE(" - Document root : %s\n", entry_host->documentroot.data);
+ CHEETAH_WRITE(" - Config file : %s\n", entry_host->file);
+
+ if (!entry_host->config) {
+ continue;
+ }
+
+ mk_list_foreach(head_sections, &entry_host->config->sections) {
+ section = mk_list_entry(head_sections, struct mk_rconf_section, _head);
+ CHEETAH_WRITE(" %s+%s [%s]\n", ANSI_GREEN, ANSI_RESET,
+ section->name);
+
+ mk_list_foreach(head_entries, &section->entries) {
+ entry = mk_list_entry(head_entries, struct mk_rconf_entry, _head);
+ CHEETAH_WRITE(" - %11.10s : %s\n", entry->key, entry->val);
+ }
+ }
+ }
+
+ CHEETAH_WRITE("\n");
+}
+
+void mk_cheetah_cmd_workers(struct mk_server *server)
+{
+ int i;
+ unsigned long long active_connections;
+ struct mk_sched_worker *node;
+ struct mk_sched_ctx *ctx;
+
+ ctx = server->sched_ctx;
+ node = ctx->workers;
+ for (i=0; i < server->workers; i++) {
+ active_connections = (node[i].accepted_connections - node[i].closed_connections);
+
+ CHEETAH_WRITE("* Worker %i\n", node[i].idx);
+ CHEETAH_WRITE(" - Task ID : %i\n", node[i].pid);
+ CHEETAH_WRITE(" - Active Connections: %llu\n", active_connections);
+ }
+
+ CHEETAH_WRITE("\n");
+}
+
+int mk_cheetah_cmd_quit()
+{
+ CHEETAH_WRITE("Cheeta says: Good Bye!\n");
+ if (listen_mode == LISTEN_STDIN) {
+ pthread_exit(NULL);
+ return 0;
+ }
+ else {
+ return -1;
+ }
+}
+
+void mk_cheetah_cmd_help()
+{
+ CHEETAH_WRITE("List of available commands for Cheetah Shell\n");
+ CHEETAH_WRITE("\ncommand shortcut description");
+ CHEETAH_WRITE("\n----------------------------------------------------");
+ CHEETAH_WRITE("\n? (\\?) Synonym for 'help'");
+ CHEETAH_WRITE("\nconfig (\\f) Display global configuration");
+ CHEETAH_WRITE("\nplugins (\\g) List loaded plugins and associated stages");
+ CHEETAH_WRITE("\nstatus (\\s) Display general web server information");
+ CHEETAH_WRITE("\nuptime (\\u) Display how long the web server has been running");
+ CHEETAH_WRITE("\nvhosts (\\v) List virtual hosts configured");
+ CHEETAH_WRITE("\nworkers (\\w) Show thread workers information\n");
+ CHEETAH_WRITE("\nclear (\\c) Clear screen");
+ CHEETAH_WRITE("\nhelp (\\h) Print this help");
+ CHEETAH_WRITE("\nquit (\\q) Exit Cheetah shell :_(\n\n");
+}
+
+static void mk_cheetah_listen_config(struct mk_server *server)
+{
+ struct mk_list *head;
+ struct mk_config_listener *listener;
+
+ mk_list_foreach(head, &server->listeners) {
+ listener = mk_list_entry(head, struct mk_config_listener, _head);
+ CHEETAH_WRITE("\nListen on : %s:%s",
+ listener->address,
+ listener->port);
+ }
+}
+
+void mk_cheetah_cmd_config(struct mk_server *server)
+{
+ struct mk_string_line *entry;
+ struct mk_list *head;
+ struct mk_config_listener *listener;
+
+ listener = mk_list_entry_first(&server->listeners,
+ struct mk_config_listener,
+ _head);
+
+ CHEETAH_WRITE("Basic configuration");
+ CHEETAH_WRITE("\n-------------------");
+ mk_cheetah_listen_config(server);
+ CHEETAH_WRITE("\nWorkers : %i threads", mk_api->config->workers);
+ CHEETAH_WRITE("\nTimeout : %i seconds", mk_api->config->timeout);
+ CHEETAH_WRITE("\nPidFile : %s.%s",
+ mk_api->config->path_conf_pidfile,
+ listener->port);
+ CHEETAH_WRITE("\nUserDir : %s",
+ mk_api->config->conf_user_pub);
+
+
+ if (mk_list_is_empty(mk_api->config->index_files) == 0) {
+ CHEETAH_WRITE("\nIndexFile : No index files defined");
+ }
+ else {
+ CHEETAH_WRITE("\nIndexFile : ");
+ mk_list_foreach(head, mk_api->config->index_files) {
+ entry = mk_list_entry(head, struct mk_string_line, _head);
+ CHEETAH_WRITE("%s ", entry->val);
+ }
+
+ }
+
+ CHEETAH_WRITE("\nHideVersion : ");
+ if (mk_api->config->hideversion == MK_TRUE) {
+ CHEETAH_WRITE("On");
+ }
+ else {
+ CHEETAH_WRITE("Off");
+ }
+
+ CHEETAH_WRITE("\nResume : ");
+ if (mk_api->config->resume == MK_TRUE) {
+ CHEETAH_WRITE("On");
+ }
+ else {
+ CHEETAH_WRITE("Off");
+ }
+
+ CHEETAH_WRITE("\nUser : %s", mk_api->config->user);
+ CHEETAH_WRITE("\n\nAdvanced configuration");
+ CHEETAH_WRITE("\n----------------------");
+ CHEETAH_WRITE("\nKeepAlive : ");
+ if (mk_api->config->keep_alive == MK_TRUE) {
+ CHEETAH_WRITE("On");
+ }
+ else {
+ CHEETAH_WRITE("Off");
+ }
+ CHEETAH_WRITE("\nMaxKeepAliveRequest : %i req/connection",
+ mk_api->config->max_keep_alive_request);
+ CHEETAH_WRITE("\nKeepAliveTimeout : %i seconds", mk_api->config->keep_alive_timeout);
+ CHEETAH_WRITE("\nMaxRequestSize : %i KB",
+ mk_api->config->max_request_size/1024);
+ CHEETAH_WRITE("\nSymLink : ");
+ if (mk_api->config->symlink == MK_TRUE) {
+ CHEETAH_WRITE("On");
+ }
+ else {
+ CHEETAH_WRITE("Off");
+ }
+ CHEETAH_WRITE("\n\n");
+}
+
+void mk_cheetah_cmd_status(struct mk_server *server)
+{
+ int nthreads = server->workers;
+ char tmp[64];
+
+ CHEETAH_WRITE("Monkey Version : %s\n", MK_VERSION_STR);
+ CHEETAH_WRITE("Configuration path : %s\n", server->path_conf_root);
+
+ CHEETAH_WRITE("Cheetah! mode : ");
+ if (listen_mode == LISTEN_STDIN) {
+ CHEETAH_WRITE("STDIN\n");
+ }
+ else {
+ CHEETAH_WRITE("SERVER @ %s\n", cheetah_server);
+ }
+
+ CHEETAH_WRITE("Process ID : %i\n", getpid());
+ CHEETAH_WRITE("Process User : ");
+ mk_cheetah_print_running_user();
+ mk_cheetah_listen_config(server);
+
+ CHEETAH_WRITE("\n");
+ CHEETAH_WRITE("Worker Threads : %i (per configuration: %i)\n",
+ nthreads, server->workers);
+
+ CHEETAH_WRITE("Memory Allocator : ");
+#ifdef MALLOC_LIBC
+ CHEETAH_WRITE("libc, system default\n");
+#else
+ CHEETAH_WRITE("Jemalloc\n");
+#endif
+
+ if (mk_api->kernel_features_print(tmp, sizeof(tmp), server) > 0) {
+ CHEETAH_WRITE("Kernel Features : %s\n", tmp);
+ }
+
+ CHEETAH_WRITE("Events backend : %s\n", mk_api->ev_backend());
+ CHEETAH_WRITE("\n");
+}
diff --git a/fluent-bit/lib/monkey/plugins/cheetah/cmd.h b/fluent-bit/lib/monkey/plugins/cheetah/cmd.h
new file mode 100644
index 000000000..617a88be1
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cheetah/cmd.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+time_t init_time;
+
+/* commands */
+int mk_cheetah_cmd(char *cmd, struct mk_server *server);
+
+void mk_cheetah_cmd_clear();
+void mk_cheetah_cmd_uptime(struct mk_server *server);
+
+/* Plugins commands */
+void mk_cheetah_cmd_plugins_print_stage(struct mk_list *list, const char *stage,
+ int stage_bw);
+void mk_cheetah_cmd_plugins_print_core(struct mk_list *list);
+void mk_cheetah_cmd_plugins_print_network(struct mk_list *list);
+void mk_cheetah_cmd_plugins(struct mk_server *server);
+
+void mk_cheetah_cmd_vhosts(struct mk_server *server);
+void mk_cheetah_cmd_workers(struct mk_server *server);
+
+int mk_cheetah_cmd_quit();
+void mk_cheetah_cmd_help();
+void mk_cheetah_cmd_config(struct mk_server *server);
+void mk_cheetah_cmd_status(struct mk_server *server);
diff --git a/fluent-bit/lib/monkey/plugins/cheetah/conf/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/cheetah/conf/CMakeLists.txt
new file mode 100644
index 000000000..b7224f351
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cheetah/conf/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(conf_dir "${MK_PATH_CONF}/plugins/cheetah/")
+
+install(DIRECTORY DESTINATION ${conf_dir})
+
+if(BUILD_LOCAL)
+ file(COPY cheetah.conf DESTINATION ${conf_dir})
+else()
+ install(FILES cheetah.conf DESTINATION ${conf_dir})
+endif()
diff --git a/fluent-bit/lib/monkey/plugins/cheetah/conf/cheetah.conf b/fluent-bit/lib/monkey/plugins/cheetah/conf/cheetah.conf
new file mode 100644
index 000000000..d9448926e
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cheetah/conf/cheetah.conf
@@ -0,0 +1,17 @@
+# Cheetah! configuration
+# ======================
+# Cheetah! is the Monkey Sheel and in this file you can define
+# the basic setup and behavior expected.
+#
+
+[CHEETAH]
+ # Listen :
+ # --------
+ # Cheetah! listen for input commands as any shell, this can be done
+ # using the standard keyboard input or through a unix pipe where you
+ # need to connect using the Cheetah! client.
+ #
+ # The Listen directive allows you to define which input method to use.
+ # Valid values for Listen are STDIN or SERVER.
+ #
+ Listen SERVER
diff --git a/fluent-bit/lib/monkey/plugins/cheetah/cutils.c b/fluent-bit/lib/monkey/plugins/cheetah/cutils.c
new file mode 100644
index 000000000..3c0bd825f
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cheetah/cutils.c
@@ -0,0 +1,117 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_api.h>
+
+#include <pwd.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "cheetah.h"
+#include "cutils.h"
+
+void mk_cheetah_print_worker_memory_usage(pid_t pid)
+{
+ int s = 1024;
+ char *buf;
+ pid_t ppid;
+ FILE *f;
+
+ ppid = getpid();
+ buf = mk_api->mem_alloc(s);
+ sprintf(buf, MK_CHEETAH_PROC_TASK, ppid, pid);
+
+ f = fopen(buf, "r");
+ if (!f) {
+ CHEETAH_WRITE("Cannot get details\n");
+ return;
+ }
+
+ buf = fgets(buf, s, f);
+ fclose(f);
+ if (!buf) {
+ CHEETAH_WRITE("Cannot format details\n");
+ return;
+ }
+
+ CHEETAH_WRITE("\n");
+ return;
+
+/*
+ int n, c;
+ int init = 0;
+ int last = 0;
+ char *value;
+
+ while ((n = mk_api->str_search(buf + last, " ", MK_STR_SENSITIVE)) > 0) {
+ if (c == 23) {
+ value = mk_api->str_copy_substr(buf, init, last + n);
+ printf("%s\n", value);
+ mk_mem_free(buf);
+ mk_mem_free(value);
+ return;
+ }
+ init = last + n + 1;
+ last += n + 1;
+ c++;
+ }*/
+}
+
+void mk_cheetah_print_running_user()
+{
+ struct passwd pwd;
+ struct passwd *result;
+ char *buf;
+ long bufsize;
+ uid_t uid;
+
+ bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (bufsize == -1) {
+ bufsize = 16384;
+ }
+
+ buf = mk_api->mem_alloc_z(bufsize);
+ uid = getuid();
+ getpwuid_r(uid, &pwd, buf, bufsize, &result);
+
+ CHEETAH_WRITE("%s", pwd.pw_name);
+ mk_api->mem_free(buf);
+}
+
+int mk_cheetah_write(const char *format, ...)
+{
+ int len = 0;
+ char buf[1024];
+ va_list ap;
+
+ va_start(ap, format);
+ len = vsprintf(buf, format, ap);
+
+ if (listen_mode == LISTEN_STDIN) {
+ len = fprintf(cheetah_output, buf, NULL);
+ }
+ else if (listen_mode == LISTEN_SERVER) {
+ len = write(cheetah_socket, buf, len);
+ }
+
+ memset(buf, '\0', sizeof(buf));
+ va_end(ap);
+
+ return len;
+}
diff --git a/fluent-bit/lib/monkey/plugins/cheetah/cutils.h b/fluent-bit/lib/monkey/plugins/cheetah/cutils.h
new file mode 100644
index 000000000..c6948a55a
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cheetah/cutils.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_CHEETAH_CUTILS_H
+#define MK_CHEETAH_CUTILS_H
+
+#include <stdio.h>
+
+#define CHEETAH_WRITE(...) mk_cheetah_write(__VA_ARGS__);
+#define CHEETAH_FLUSH() fflush(cheetah_output);fflush(cheetah_input);
+
+void mk_cheetah_print_worker_memory_usage(pid_t pid);
+void mk_cheetah_print_running_user();
+int mk_cheetah_write(const char *format, ...);
+
+#endif
diff --git a/fluent-bit/lib/monkey/plugins/cheetah/loop.c b/fluent-bit/lib/monkey/plugins/cheetah/loop.c
new file mode 100644
index 000000000..e30f26f2c
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cheetah/loop.c
@@ -0,0 +1,149 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_api.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+/* Monkey Plugin Interface */
+#include "cheetah.h"
+#include "cutils.h"
+#include "cmd.h"
+#include "loop.h"
+
+void mk_cheetah_loop_stdin(struct mk_server *server)
+{
+ int len;
+ char cmd[200];
+ char line[200];
+ char *rcmd;
+
+ mk_cheetah_welcome_msg();
+
+ while (1) {
+ CHEETAH_WRITE(MK_CHEETAH_PROMPT, ANSI_BOLD, ANSI_GREEN, ANSI_RESET);
+
+ rcmd = fgets(line, sizeof(line), cheetah_input);
+ if (!rcmd) {
+ continue;
+ }
+
+ len = strlen(line);
+
+ if (len == 0){
+ CHEETAH_WRITE("\n");
+ mk_cheetah_cmd_quit();
+ }
+
+ strncpy(cmd, line, len - 1);
+ cmd[len - 1] = '\0';
+
+ mk_cheetah_cmd(cmd, server);
+ memset(line, '\0', sizeof(line));
+ }
+}
+
+void mk_cheetah_loop_server(struct mk_server *server)
+{
+ int n, ret;
+ int buf_len;
+ unsigned long len;
+ char buf[1024];
+ char cmd[1024];
+ int server_fd;
+ int remote_fd;
+ size_t address_length;
+ struct sockaddr_un address;
+ socklen_t socket_size = sizeof(struct sockaddr_in);
+ struct mk_config_listener *listener;
+
+ /* Create listening socket */
+ server_fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (server_fd < 0) {
+ perror("socket() failed");
+ exit(EXIT_FAILURE);
+ }
+
+ listener = mk_list_entry_first(&mk_api->config->listeners,
+ struct mk_config_listener,
+ _head);
+ cheetah_server = NULL;
+ mk_api->str_build(&cheetah_server, &len, "/tmp/cheetah.%s",
+ listener->port);
+ unlink(cheetah_server);
+
+ address.sun_family = AF_UNIX;
+ sprintf(address.sun_path, "%s", cheetah_server);
+ address_length = sizeof(address.sun_family) + len + 1;
+
+ if (bind(server_fd, (struct sockaddr *) &address, address_length) != 0) {
+ perror("bind");
+ mk_err("Cheetah: could not bind address %s", address.sun_path);
+ exit(EXIT_FAILURE);
+ }
+
+ if (listen(server_fd, 5) != 0) {
+ perror("listen");
+ exit(EXIT_FAILURE);
+ }
+
+ while (1) {
+ /* Listen for incoming connections */
+ remote_fd = accept(server_fd, (struct sockaddr *) &address, &socket_size);
+ cheetah_socket = remote_fd;
+
+ buf_len = 0;
+ memset(buf, '\0', 1024);
+
+ /* Send welcome message and prompt */
+ mk_cheetah_welcome_msg();
+ CHEETAH_WRITE(MK_CHEETAH_PROMPT, ANSI_BOLD, ANSI_GREEN, ANSI_RESET);
+
+ while (1) {
+ /* Read incoming data */
+ n = read(remote_fd, buf+buf_len, 1024 - buf_len);
+ if (n <= 0) {
+ break;
+ }
+ else {
+ buf_len += n;
+ if (buf[buf_len-1] == '\n') {
+ /* Filter command */
+ strncpy(cmd, buf, buf_len - 1);
+ cmd[buf_len - 1] = '\0';
+
+ /* Run command */
+ ret = mk_cheetah_cmd(cmd, server);
+
+ if (ret == -1) {
+ break;
+ }
+
+ /* Write prompt */
+ CHEETAH_WRITE(MK_CHEETAH_PROMPT, ANSI_BOLD, ANSI_GREEN, ANSI_RESET);
+ buf_len = 0;
+ memset(buf, '\0', 1024);
+ }
+ }
+ }
+
+ close(remote_fd);
+ }
+}
diff --git a/fluent-bit/lib/monkey/plugins/cheetah/loop.h b/fluent-bit/lib/monkey/plugins/cheetah/loop.h
new file mode 100644
index 000000000..232a00b61
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/cheetah/loop.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_CHEETAH_LOOP_H
+#define MK_CHEETAH_LOOP_H
+
+void mk_cheetah_loop_stdin();
+void mk_cheetah_loop_server();
+
+#endif
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/ABOUT b/fluent-bit/lib/monkey/plugins/dirlisting/ABOUT
new file mode 100644
index 000000000..2d71cb77e
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/dirlisting/ABOUT
@@ -0,0 +1,4 @@
+Directory Listing Plugin
+========================
+When a directory is requested, this plugin will show
+an HTML list of the available content to the client.
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/dirlisting/CMakeLists.txt
new file mode 100644
index 000000000..7432e1091
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/dirlisting/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(src
+ dirlisting.c
+ )
+
+MONKEY_PLUGIN(dirlisting "${src}")
+
+add_subdirectory(conf) \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/OPTIONAL b/fluent-bit/lib/monkey/plugins/dirlisting/OPTIONAL
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/dirlisting/OPTIONAL
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/dirlisting/conf/CMakeLists.txt
new file mode 100644
index 000000000..4faf80a4d
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(conf_dir "${MK_PATH_CONF}/plugins/dirlisting/")
+
+install(DIRECTORY DESTINATION ${conf_dir})
+
+if(BUILD_LOCAL)
+ file(COPY dirhtml.conf DESTINATION ${conf_dir})
+ file(COPY themes DESTINATION ${conf_dir})
+else()
+ install(FILES dirhtml.conf DESTINATION ${conf_dir})
+ install(DIRECTORY themes DESTINATION ${conf_dir})
+endif() \ No newline at end of file
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/dirhtml.conf b/fluent-bit/lib/monkey/plugins/dirlisting/conf/dirhtml.conf
new file mode 100644
index 000000000..c73188df2
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/dirhtml.conf
@@ -0,0 +1,2 @@
+[DIRLISTING]
+ Theme bootstrap
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/entry.theme b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/entry.theme
new file mode 100644
index 000000000..8c1ef026d
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/entry.theme
@@ -0,0 +1,5 @@
+<tr>
+ <td><a title='%_target_title_%' href='%_target_url_%'>%_target_name_%</a></td>
+ <td>%_target_time_%</td>
+ <td>%_target_size_%</td>
+</tr>
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/footer.theme b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/footer.theme
new file mode 100644
index 000000000..88290ac8b
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/footer.theme
@@ -0,0 +1,8 @@
+ <tbody>
+</table>
+</div>
+</div>
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
+</body>
+</HTML>
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/header.theme b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/header.theme
new file mode 100644
index 000000000..f7f6cfcfd
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/bootstrap/header.theme
@@ -0,0 +1,27 @@
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Index of %_html_title_%</title>
+ <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+ <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
+ <link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">
+ </head>
+ <body>
+ <div class="container">
+ <h1>Index of %_html_title_%</h1>
+ <div class="table-responsive">
+ <table class="table table-hover table-bordered">
+ <thead>
+ <tr>
+ <th>
+ Name
+ </th>
+ <th>
+ Last time modified
+ </th>
+ <th>
+ Size
+ </th>
+ </tr>
+ </thead>
+ <tbody>
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/entry.theme b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/entry.theme
new file mode 100644
index 000000000..af00e250c
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/entry.theme
@@ -0,0 +1,14 @@
+<TR>
+<TD class="row">
+ <A title='%_target_title_%' href='%_target_url_%'>
+ %_target_name_%
+ </A>
+</TD>
+<TD class="row">
+ %_target_time_%
+</TD>
+<TD class="row">
+ %_target_size_%
+ %_theme_path_%
+</TD>
+</TR>
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/footer.theme b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/footer.theme
new file mode 100644
index 000000000..c785ba97f
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/footer.theme
@@ -0,0 +1,7 @@
+</TABLE>
+
+</TD>
+</TR>
+</TABLE>
+</BODY></HTML>
+
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/header.theme b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/header.theme
new file mode 100644
index 000000000..6a11a458f
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/dirlisting/conf/themes/guineo/header.theme
@@ -0,0 +1,58 @@
+<HTML>
+ <HEAD>
+ <META http-equiv="content-type" content="text/html; charset=UTF-8">
+ <STYLE type="text/css">
+ H1.header {
+ text-align: center;
+ color: #4a77a0;
+ font-size: 12pt;
+ font-weight: bold;
+ }
+ .row {
+ color: #6c95bc;
+ font-size: 10pt;
+ background-color: #ffffff;
+ padding-left: 0.4em;
+ }
+ .title {color: #617691; font-size: 10pt; font-weight: bold;}
+
+ a:link {
+ color: #475f7e;
+ }
+ a:visited {
+ color: #ac7a2a;
+ }
+ a:hover {
+ color: #475f7e;
+ background-color: #dbdbdb;
+ text-decoration: none;
+ }
+ a:active {
+ color: #333333;
+ }
+ </STYLE>
+
+ <TITLE>Index of %_html_title_%</TITLE>
+ </HEAD>
+<BODY>
+
+<CENTER>
+<IMG src="/imgs/monkey_logo.png">
+<BR>
+<h1 class="header">Index of %_html_title_%</h1>
+<TABLE cellpadding="0" cellspacing="0" border="0" bgcolor="#000000" width="50%">
+<TR>
+<TD>
+
+<TABLE cellpadding="2" cellspacing="1" border="0" bgcolor="#e7e7e7" width="100%">
+<TR bgcolor="#ececec">
+ <TD class="title">
+ Name
+ </TD>
+ <TD class="title">
+ Last time modified
+ </TD>
+ <TD class="title">
+ Size
+ </TD>
+</TR>
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.c b/fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.c
new file mode 100644
index 000000000..1ffd3fac4
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.c
@@ -0,0 +1,949 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Some history about this plugin
+ * ------------------------------
+ * 2008 - Rewrite module, suport dynamic themes by Eduardo Silva
+ * 2008 - Felipe Astroza (max) provided the mk_dirhtml_human_readable_size_func()
+ * 2007 - Add struct client_request support by Eduardo
+ * 2002 - Original version written by Daniel R. Ome
+ */
+
+#include <monkey/mk_api.h>
+#include <monkey/mk_stream.h>
+#include "dirlisting.h"
+
+#include <time.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+const mk_ptr_t mk_dirhtml_default_mime = mk_ptr_init(MK_DIRHTML_DEFAULT_MIME);
+const mk_ptr_t mk_dir_iov_dash = mk_ptr_init("-");
+const mk_ptr_t mk_dir_iov_none = mk_ptr_init("");
+const mk_ptr_t mk_dir_iov_slash = mk_ptr_init("/");
+
+void mk_dirhtml_cb_body_rows(struct mk_stream_input *in);
+
+/* Function wrote by Max (Felipe Astroza), thanks! */
+static char *mk_dirhtml_human_readable_size(char *buf, size_t size, int len)
+{
+ unsigned long u = 1024, i;
+ static const char *__units[] = {
+ "b", "K", "M", "G",
+ "T", "P", "E", "Z", "Y", NULL
+ };
+
+ for (i = 0; __units[i] != NULL; i++) {
+ if ((size / u) == 0) {
+ break;
+ }
+ u *= 1024;
+ }
+ if (!i) {
+ snprintf(buf, size, "%lu%s", (long unsigned int) len, __units[0]);
+ }
+ else {
+ float fsize = (float) ((double) len / (u / 1024));
+ snprintf(buf, size, "%.1f%s", fsize, __units[i]);
+ }
+
+ return buf;
+}
+
+static struct mk_f_list *mk_dirhtml_create_element(char *file,
+ unsigned char type,
+ char *full_path,
+ unsigned long *list_len)
+{
+ int n;
+ struct tm *st_time;
+ struct mk_f_list *entry;
+
+ entry = mk_api->mem_alloc_z(sizeof(struct mk_f_list));
+
+ if (mk_api->file_get_info(full_path, &entry->info, MK_FILE_READ) != 0) {
+ mk_api->mem_free(entry);
+ return NULL;
+ }
+
+ strcpy(entry->name, file);
+ entry->type = type;
+
+ st_time = localtime((time_t *) & entry->info.last_modification);
+ n = strftime(entry->ft_modif, MK_DIRHTML_FMOD_LEN, "%d-%b-%G %H:%M", st_time);
+ if (n == 0) {
+ mk_mem_free(entry);
+ return NULL;
+ }
+
+ if (type != DT_DIR) {
+ mk_dirhtml_human_readable_size(entry->size,
+ sizeof(entry->size),
+ entry->info.size);
+ }
+ else {
+ entry->size[0] = '-';
+ entry->size[1] = '\0';
+ }
+
+ *list_len = *list_len + 1;
+
+ return entry;
+}
+
+static struct mk_list *mk_dirhtml_create_list(DIR * dir, char *path,
+ unsigned long *list_len)
+{
+ char full_path[PATH_MAX];
+ struct mk_list *list;
+ struct dirent *ent;
+ struct mk_f_list *entry = 0;
+
+ list = mk_api->mem_alloc(sizeof(struct mk_list));
+ mk_list_init(list);
+
+ while ((ent = readdir(dir)) != NULL) {
+ if ((ent->d_name[0] == '.') && (strcmp(ent->d_name, "..") != 0))
+ continue;
+
+ /* Look just for files and dirs */
+ if (ent->d_type != DT_REG && ent->d_type != DT_DIR
+ && ent->d_type != DT_LNK && ent->d_type != DT_UNKNOWN) {
+ continue;
+ }
+
+ snprintf(full_path, PATH_MAX, "%s%s", path, ent->d_name);
+ entry = mk_dirhtml_create_element(ent->d_name,
+ ent->d_type, full_path, list_len);
+ if (!entry) {
+ continue;
+ }
+
+ mk_list_add(&entry->_head, list);
+ }
+
+ return list;
+}
+
+/* Read dirhtml config and themes */
+int mk_dirhtml_conf(char *confdir)
+{
+ int ret = 0;
+ unsigned long len;
+ char *conf_file = NULL;
+
+ mk_api->str_build(&conf_file, &len, "%s", confdir);
+
+ /* Read configuration */
+ ret = mk_dirhtml_read_config(conf_file);
+ if (ret < 0) {
+ mk_mem_free(conf_file);
+ return -1;
+ }
+
+ /*
+ * This function will load the default theme setted in dirhtml_conf struct
+ */
+ mk_mem_free(conf_file);
+ return mk_dirhtml_theme_load();
+}
+
+/*
+ * Read the main configuration file for dirhtml: dirhtml.conf,
+ * it will alloc the dirhtml_conf struct
+*/
+int mk_dirhtml_read_config(char *path)
+{
+ unsigned long len;
+ char *default_file = NULL;
+ struct mk_rconf *conf;
+ struct mk_rconf_section *section;
+ struct file_info finfo;
+
+ mk_api->str_build(&default_file, &len, "%sdirhtml.conf", path);
+ conf = mk_api->config_open(default_file);
+ if (!conf) {
+ return -1;
+ }
+
+ section = mk_api->config_section_get(conf, "DIRLISTING");
+ if (!section) {
+ mk_err_ex(mk_api, "Could not find DIRLISTING tag in configuration file");
+ exit(EXIT_FAILURE);
+ }
+
+ /* alloc dirhtml config struct */
+ dirhtml_conf = mk_api->mem_alloc(sizeof(struct dirhtml_config));
+ dirhtml_conf->theme = mk_api->config_section_get_key(section, "Theme",
+ MK_RCONF_STR);
+ dirhtml_conf->theme_path = NULL;
+
+ mk_api->str_build(&dirhtml_conf->theme_path, &len,
+ "%sthemes/%s/", path, dirhtml_conf->theme);
+ mk_api->mem_free(default_file);
+
+ if (mk_api->file_get_info(dirhtml_conf->theme_path,
+ &finfo, MK_FILE_READ) != 0) {
+ mk_warn_ex(mk_api, "Dirlisting: cannot load theme from '%s'", dirhtml_conf->theme_path);
+ mk_warn_ex(mk_api, "Dirlisting: unloading plugin");
+ return -1;
+ }
+
+ mk_api->config_free(conf);
+ return 0;
+}
+
+int mk_dirhtml_theme_load()
+{
+ /* Data */
+ char *header, *entry, *footer;
+
+ /* Load theme files */
+ header = mk_dirhtml_load_file(MK_DIRHTML_FILE_HEADER);
+ entry = mk_dirhtml_load_file(MK_DIRHTML_FILE_ENTRY);
+ footer = mk_dirhtml_load_file(MK_DIRHTML_FILE_FOOTER);
+
+ if (!header || !entry || !footer) {
+ mk_api->mem_free(header);
+ mk_api->mem_free(entry);
+ mk_api->mem_free(footer);
+ return -1;
+ }
+
+ /* Parse themes */
+ mk_dirhtml_tpl_header = mk_dirhtml_template_create(header);
+ mk_dirhtml_tpl_entry = mk_dirhtml_template_create(entry);
+ mk_dirhtml_tpl_footer = mk_dirhtml_template_create(footer);
+
+#ifdef DEBUG_THEME
+ /* Debug data */
+ mk_dirhtml_theme_debug(&mk_dirhtml_tpl_header);
+ mk_dirhtml_theme_debug(&mk_dirhtml_tpl_entry);
+ mk_dirhtml_theme_debug(&mk_dirhtml_tpl_footer);
+
+#endif
+ mk_api->mem_free(header);
+ mk_api->mem_free(entry);
+ mk_api->mem_free(footer);
+
+ return 0;
+}
+
+#ifdef DEBUG_THEME
+int mk_dirhtml_theme_debug(struct dirhtml_template **st_tpl)
+{
+ int i = 0;
+ struct dirhtml_template *aux;
+
+ aux = *st_tpl;
+
+ printf("\n** DEBUG_THEME **");
+ fflush(stdout);
+
+ while (aux) {
+ printf("\n%i) len=%i, tag_id=%i", i, aux->len, aux->tag_id);
+ if (aux->tag_id >= 0) {
+ printf(" (%s) ", aux->tags[aux->tag_id]);
+ }
+ fflush(stdout);
+ aux = aux->next;
+ i++;
+ }
+ return 0;
+}
+#endif
+
+/* Search which tag exists first in content :
+ * ex: %_html_title_%
+ */
+static int mk_dirhtml_theme_match_tag(char *content, char *tpl[])
+{
+ int i, len, match;
+
+ for (i = 0; tpl[i]; i++) {
+ len = strlen(tpl[i]);
+ match = (int) mk_api->str_search_n(content, tpl[i], MK_STR_INSENSITIVE, len);
+ if (match >= 0) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+struct dirhtml_template *mk_dirhtml_template_create(char *content)
+{
+ int i = 0, cont_len;
+ int pos, last = 0; /* 0=search init, 1=search end */
+ int n_tags = 0, tpl_idx = 0;
+
+ char *_buf;
+ int _len;
+
+ /* Global keys */
+ char **_tpl = 0;
+
+ /* Template to return */
+ struct dirhtml_template *st_tpl = 0;
+
+ cont_len = strlen(content);
+ if (cont_len <= 0) {
+ return NULL;
+ }
+
+ /* Parsing content */
+ while (i < cont_len) {
+ pos = (int) mk_api->str_search(content + i,
+ MK_DIRHTML_TAG_INIT, MK_STR_INSENSITIVE);
+
+ if (pos < 0) {
+ break;
+ }
+
+ /* Checking global tag, if it's not found, proceed with
+ * 'entry tags'
+ */
+ _tpl = (char **) _tags_global;
+ tpl_idx = mk_dirhtml_theme_match_tag(content + i + pos, _tpl);
+
+ /* if global template do not match, use the entry tags */
+ if (tpl_idx < 0) {
+ _tpl = (char **) _tags_entry;
+ tpl_idx = mk_dirhtml_theme_match_tag(content + i + pos, _tpl);
+ }
+
+ /* if tag found is known, we add them to our list */
+ if (tpl_idx >= 0) {
+
+ _buf = mk_api->str_copy_substr(content, i, i + pos);
+ _len = strlen(_buf);
+
+ /* Dummy if/else to create or pass a created st_tpl */
+ if (!st_tpl) {
+ st_tpl = mk_dirhtml_template_list_add(NULL,
+ _buf, _len, _tpl, -1);
+ }
+ else {
+ mk_dirhtml_template_list_add(&st_tpl, _buf, _len, _tpl, -1);
+ }
+ i += (pos + strlen(_tpl[tpl_idx]));
+
+ /* This means that a value need to be replaced */
+ mk_dirhtml_template_list_add(&st_tpl, NULL, -1, _tpl, tpl_idx);
+ n_tags++;
+ }
+ else {
+ i++;
+ }
+ }
+
+ if (last < cont_len) {
+ _buf = mk_api->str_copy_substr(content, i, cont_len);
+ _len = strlen(_buf);
+
+ if (n_tags <= 0) {
+ st_tpl = mk_dirhtml_template_list_add(NULL, _buf, _len, _tpl, -1);
+ }
+ else {
+ mk_dirhtml_template_list_add(&st_tpl, _buf, _len, _tpl, -1);
+ }
+ }
+
+ return st_tpl;
+}
+
+struct dirhtml_template *mk_dirhtml_template_list_add(struct dirhtml_template **header,
+ char *buf, int len, char **tpl,
+ int tag_id)
+{
+ struct dirhtml_template *node, *aux;
+
+ node = mk_api->mem_alloc_z(sizeof(struct dirhtml_template));
+ if (!node) {
+ return NULL;
+ }
+
+ node->buf = buf;
+ node->len = len;
+ node->tag_id = tag_id;
+ node->tags = tpl;
+ node->next = NULL;
+
+ if (!header || !(*header)) {
+ return (struct dirhtml_template *) node;
+ }
+
+ aux = *header;
+ while ((*aux).next != NULL) {
+ aux = (*aux).next;
+ }
+
+ (*aux).next = node;
+ return (struct dirhtml_template *) node;
+}
+
+static int mk_dirhtml_template_len(struct dirhtml_template *tpl)
+{
+ int len = 0;
+ struct dirhtml_template *aux;
+
+ aux = tpl;
+ while (aux) {
+ len++;
+ aux = aux->next;
+ }
+
+ return len;
+}
+
+static struct mk_iov *mk_dirhtml_theme_compose(struct dirhtml_template *template,
+ struct mk_list *list)
+{
+ /*
+ * template = struct { char buf ; int len, int tag }
+ * values = struct {int tag, char *value, struct *next}
+ */
+ struct mk_iov *iov;
+ struct dirhtml_template *tpl = template;
+ struct dirhtml_value *val;
+ struct mk_list *head;
+
+ int tpl_len;
+
+ tpl_len = mk_dirhtml_template_len(template);
+
+ /* we duplicate the lenght in case we get separators */
+ iov = mk_api->iov_create(1 + tpl_len * 2, 1);
+ tpl = template;
+
+ while (tpl) {
+ /* check for dynamic value */
+ if (!tpl->buf && tpl->tag_id >= 0) {
+ mk_list_foreach(head, list) {
+ val = mk_list_entry(head, struct dirhtml_value, _head);
+ if (val->tags == tpl->tags && val->tag_id == tpl->tag_id) {
+ mk_api->iov_add(iov,
+ val->value, val->len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ val->sep.data, val->sep.len,
+ MK_FALSE);
+ break;
+ }
+ }
+ }
+ /* static */
+ else {
+ mk_api->iov_add(iov,
+ tpl->buf, tpl->len,
+ MK_FALSE);
+ }
+ tpl = tpl->next;
+ }
+
+ return iov;
+}
+
+struct dirhtml_value *mk_dirhtml_tag_assign(struct mk_list *list,
+ int tag_id, mk_ptr_t sep,
+ char *value, char **tags)
+{
+ struct dirhtml_value *aux = NULL;
+
+ aux = mk_api->mem_alloc(sizeof(struct dirhtml_value));
+ if (!aux) {
+ return NULL;
+ }
+
+ aux->tag_id = tag_id;
+ aux->value = value;
+ aux->sep = sep;
+ aux->tags = tags;
+
+ if (value) {
+ aux->len = strlen(value);
+ }
+ else {
+ aux->len = -1;
+ }
+
+ mk_list_add(&aux->_head, list);
+ return (struct dirhtml_value *) aux;
+}
+
+static void mk_dirhtml_tag_free_list(struct mk_list *list)
+{
+ struct mk_list *head;
+ struct mk_list *tmp;
+ struct dirhtml_value *target;
+
+ mk_list_foreach_safe(head, tmp, list) {
+ target = mk_list_entry(head, struct dirhtml_value, _head);
+ mk_list_del(&target->_head);
+ mk_api->mem_free(target);
+ }
+}
+
+char *mk_dirhtml_load_file(char *filename)
+{
+ char *tmp = 0, *data = 0;
+ unsigned long len;
+
+ mk_api->str_build(&tmp, &len, "%s%s", dirhtml_conf->theme_path, filename);
+
+ if (!tmp) {
+ return NULL;
+ }
+
+ data = mk_api->file_to_buffer(tmp);
+ mk_api->mem_free(tmp);
+
+ if (!data) {
+ return NULL;
+ }
+
+ return (char *) data;
+}
+
+static int mk_dirhtml_entry_cmp(const void *a, const void *b)
+{
+ struct mk_f_list *const *f_a = a;
+ struct mk_f_list *const *f_b = b;
+
+ return strcasecmp((*f_a)->name, (*f_b)->name);
+}
+
+static void mk_dirhtml_free_list(struct mk_dirhtml_request *request)
+{
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_f_list *entry;
+
+ mk_list_foreach_safe(head, tmp, request->file_list) {
+ entry = mk_list_entry(head, struct mk_f_list, _head);
+ mk_list_del(&entry->_head);
+ mk_api->mem_free(entry);
+ }
+
+ mk_api->mem_free(request->file_list);
+ mk_api->mem_free(request->toc);
+}
+
+static inline struct mk_iov *enqueue_row(int i, struct mk_dirhtml_request *request)
+{
+ mk_ptr_t sep;
+ struct mk_list list;
+ struct mk_iov *iov_entry;
+
+ /* %_target_title_% */
+ if (request->toc[i]->type == DT_DIR) {
+ sep = mk_dir_iov_slash;
+ }
+ else {
+ sep = mk_dir_iov_none;
+ }
+
+ mk_list_init(&list);
+
+ /* target title */
+ mk_dirhtml_tag_assign(&list, 0, sep,
+ request->toc[i]->name,
+ (char **) _tags_entry);
+
+ /* target url */
+ mk_dirhtml_tag_assign(&list, 1, sep,
+ request->toc[i]->name, (char **) _tags_entry);
+
+ /* target name */
+ mk_dirhtml_tag_assign(&list, 2, sep,
+ request->toc[i]->name, (char **) _tags_entry);
+
+ /* target modification time */
+ mk_dirhtml_tag_assign(&list, 3, mk_dir_iov_none,
+ request->toc[i]->ft_modif, (char **) _tags_entry);
+
+ /* target size */
+ mk_dirhtml_tag_assign(&list, 4, mk_dir_iov_none,
+ request->toc[i]->size, (char **) _tags_entry);
+
+ iov_entry = mk_dirhtml_theme_compose(mk_dirhtml_tpl_entry, &list);
+
+ /* free entry list */
+ mk_dirhtml_tag_free_list(&list);
+ return iov_entry;
+}
+
+/* Release all resources for a given Request context */
+void mk_dirhtml_cleanup(struct mk_dirhtml_request *req)
+{
+ PLUGIN_TRACE("release resources");
+
+ if (req->iov_header) {
+ mk_api->iov_free(req->iov_header);
+ req->iov_header = NULL;
+ }
+ if (req->iov_entry) {
+ mk_api->iov_free(req->iov_entry);
+ req->iov_entry = NULL;
+ }
+ if (req->iov_footer) {
+ mk_api->iov_free(req->iov_footer);
+ req->iov_footer = NULL;
+ }
+ mk_dirhtml_free_list(req);
+ closedir(req->dir);
+
+ req->sr->handler_data = NULL;
+ mk_api->mem_free(req);
+ req = NULL;
+}
+
+void mk_dirhtml_cb_complete(struct mk_stream_input *in)
+{
+ struct mk_stream *stream;
+ struct mk_dirhtml_request *req;
+
+ stream = in->stream;
+ req = stream->context;
+ if (req) {
+ mk_dirhtml_cleanup(req);
+ }
+}
+
+void mk_dirhtml_cb_error(struct mk_stream *stream, int status)
+{
+#ifndef TRACE
+ (void) status;
+#endif
+ struct mk_dirhtml_request *req = stream->context;
+
+ PLUGIN_TRACE("exception: %i", status);
+
+ if (req) {
+ mk_dirhtml_cleanup(req);
+ }
+}
+
+void mk_dirhtml_cb_chunk_body_rows(struct mk_stream_input *in, long bytes)
+{
+ (void) bytes;
+
+ mk_dirhtml_cb_body_rows(in);
+}
+
+void mk_dirhtml_cb_body_rows(struct mk_stream_input *in)
+{
+ int len;
+ char tmp[16];
+ struct mk_stream *stream = in->stream;
+ struct mk_dirhtml_request *req = stream->context;
+ void (*cb_ok)(struct mk_stream_input *) = NULL;
+
+ if (req->iov_entry) {
+ mk_api->iov_free(req->iov_entry);
+ req->iov_entry = NULL;
+ }
+
+ if (req->toc_idx >= req->toc_len) {
+ if (req->chunked) {
+ len = snprintf(tmp, sizeof(tmp), "%x\r\n",
+ (int) req->iov_footer->total_len);
+ mk_stream_in_raw(req->stream,
+ NULL,
+ tmp, len,
+ NULL, NULL);
+ cb_ok = NULL;
+ }
+ else {
+ cb_ok = mk_dirhtml_cb_complete;
+ }
+
+ mk_stream_in_iov(req->stream,
+ NULL,
+ req->iov_footer,
+ NULL, NULL);
+ if (req->chunked) {
+ mk_stream_in_raw(req->stream,
+ NULL,
+ "\r\n0\r\n\r\n", 7,
+ NULL, mk_dirhtml_cb_complete);
+ }
+
+ return;
+ }
+
+ req->iov_entry = enqueue_row(req->toc_idx, req);
+ if (req->chunked) {
+ len = snprintf(tmp, sizeof(tmp), "%x\r\n",
+ (int) req->iov_entry->total_len);
+ mk_stream_in_raw(req->stream,
+ NULL,
+ tmp, len,
+ NULL, NULL);
+ cb_ok = NULL;
+ }
+ else {
+ cb_ok = mk_dirhtml_cb_body_rows;
+ }
+
+ mk_stream_in_iov(req->stream,
+ NULL,
+ req->iov_entry,
+ NULL, cb_ok);
+
+ if (req->chunked) {
+ mk_stream_in_raw(req->stream,
+ NULL,
+ "\r\n", 2,
+ mk_dirhtml_cb_chunk_body_rows, NULL);
+ }
+ req->toc_idx++;
+}
+
+/*
+ * The HTTP Headers were sent, now start registering the
+ * rows for each directory entry.
+ */
+void cb_header_finish(struct mk_stream_input *in)
+{
+ struct mk_stream *stream = in->stream;
+ struct mk_dirhtml_request *req;
+
+ req = stream->context;
+ if (req->iov_header) {
+ mk_api->iov_free(req->iov_header);
+ req->iov_header = NULL;
+ }
+ mk_dirhtml_cb_body_rows(in);
+}
+
+static int mk_dirhtml_init(struct mk_plugin *plugin,
+ struct mk_http_session *cs, struct mk_http_request *sr)
+{
+ DIR *dir;
+ int len;
+ char tmp[16];
+ unsigned int i = 0;
+ struct mk_list *head;
+ struct mk_list list;
+ struct mk_f_list *entry;
+ struct mk_dirhtml_request *request;
+ struct mk_stream *stream;
+
+ if (!(dir = opendir(sr->real_path.data))) {
+ return -1;
+ }
+
+ /* Create the main context */
+ request = mk_api->mem_alloc(sizeof(struct mk_dirhtml_request));
+ if (!request) {
+ closedir(dir);
+ return -1;
+ }
+
+ stream = mk_stream_set(NULL, cs->channel, request,
+ NULL, NULL, mk_dirhtml_cb_error);
+ if (!stream) {
+ closedir(dir);
+ free(request);
+ return -1;
+ }
+
+ request->stream = stream;
+ request->state = MK_DIRHTML_STATE_HTTP_HEADER;
+ request->dir = dir;
+ request->toc_idx = 0;
+ request->cs = cs;
+ request->sr = sr;
+ request->toc_len = 0;
+ request->chunked = MK_FALSE;
+ request->iov_header = NULL;
+ request->iov_entry = NULL;
+ request->iov_footer = NULL;
+
+ sr->handler_data = request;
+
+ request->file_list = mk_dirhtml_create_list(dir, sr->real_path.data,
+ &request->toc_len);
+
+ /* Building headers */
+ mk_api->header_set_http_status(sr, MK_HTTP_OK);
+ sr->headers.cgi = SH_CGI;
+ sr->headers.breakline = MK_HEADER_BREAKLINE;
+ sr->headers.content_type = mk_dirhtml_default_mime;
+ sr->headers.content_length = -1;
+
+ if (sr->protocol >= MK_HTTP_PROTOCOL_11) {
+ sr->headers.transfer_encoding = MK_HEADER_TE_TYPE_CHUNKED;
+ request->chunked = MK_TRUE;
+ }
+
+ /*
+ * Creating response template
+ */
+
+ mk_list_init(&list);
+
+ /* Set %_html_title_% */
+ mk_dirhtml_tag_assign(&list, 0, mk_dir_iov_none,
+ sr->uri_processed.data,
+ (char **) _tags_global);
+
+ /* Set %_theme_path_% */
+ mk_dirhtml_tag_assign(&list, 1, mk_dir_iov_none,
+ dirhtml_conf->theme_path, (char **) _tags_global);
+
+ /* HTML Header */
+ request->iov_header = mk_dirhtml_theme_compose(mk_dirhtml_tpl_header,
+ &list);
+
+ /* HTML Footer */
+ request->iov_footer = mk_dirhtml_theme_compose(mk_dirhtml_tpl_footer,
+ &list);
+ mk_dirhtml_tag_free_list(&list);
+
+ /* Creating table of contents and sorting */
+ request->toc = mk_api->mem_alloc(sizeof(struct mk_f_list *) * request->toc_len);
+
+ i = 0;
+ mk_list_foreach(head, request->file_list) {
+ entry = mk_list_entry(head, struct mk_f_list, _head);
+ request->toc[i] = entry;
+ i++;
+ }
+
+ qsort(request->toc,
+ request->toc_len,
+ sizeof(*request->toc),
+ mk_dirhtml_entry_cmp);
+
+ /* Prepare HTTP response headers */
+ mk_api->header_prepare(plugin, cs, sr);
+
+ if (request->chunked) {
+ len = snprintf(tmp, sizeof(tmp), "%x\r\n",
+ (int) request->iov_header->total_len);
+ mk_stream_in_raw(request->stream,
+ NULL,
+ tmp, len,
+ NULL, mk_dirhtml_cb_complete);
+ }
+
+ mk_stream_in_iov(request->stream,
+ NULL,
+ request->iov_header,
+ NULL, cb_header_finish);
+
+ if (request->chunked) {
+ mk_stream_in_raw(request->stream,
+ NULL,
+ "\r\n", 2,
+ NULL, NULL);
+ }
+ return 0;
+}
+
+int mk_dirlisting_plugin_init(struct mk_plugin *plugin, char *confdir)
+{
+ mk_api = plugin->api;
+
+ return mk_dirhtml_conf(confdir);
+}
+
+int mk_dirlisting_plugin_exit(struct mk_plugin *plugin)
+{
+ (void) plugin;
+
+ mk_api->mem_free(dirhtml_conf->theme);
+ mk_api->mem_free(dirhtml_conf->theme_path);
+ mk_api->mem_free(dirhtml_conf);
+
+ return 0;
+}
+
+int mk_dirlisting_stage30(struct mk_plugin *plugin,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ int n_param,
+ struct mk_list *params)
+{
+ (void) plugin;
+ (void) n_param;
+ (void) params;
+
+ /* validate file_info */
+ if (sr->file_info.size == 0) {
+ return MK_PLUGIN_RET_NOT_ME;
+ }
+
+ /* This plugin just handle directories */
+ if (sr->file_info.is_directory == MK_FALSE) {
+ return MK_PLUGIN_RET_NOT_ME;
+ }
+
+ PLUGIN_TRACE("Dirlisting attending socket %i", cs->socket);
+ if (mk_dirhtml_init(plugin, cs, sr)) {
+ /*
+ * If we failed here, we cannot return RET_END - that causes a mk_bug.
+ * dirhtml_init only fails if opendir fails. Usually we're at full
+ * capacity then and can't open new files.
+ */
+ return MK_PLUGIN_RET_CLOSE_CONX;
+ }
+
+ return MK_PLUGIN_RET_END;
+}
+
+int mk_dirlisting_stage30_hangup(struct mk_plugin *plugin,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr)
+{
+ (void) cs;
+ (void) plugin;
+
+ if (sr->handler_data) {
+ mk_dirhtml_cleanup(sr->handler_data);
+ }
+ return 0;
+}
+
+struct mk_plugin_stage mk_plugin_stage_dirlisting = {
+ .stage30 = &mk_dirlisting_stage30,
+ .stage30_hangup = &mk_dirlisting_stage30_hangup
+};
+
+struct mk_plugin mk_plugin_dirlisting = {
+ /* Identification */
+ .shortname = "dirlisting",
+ .name = "Directory Listing",
+ .version = MK_VERSION_STR,
+ .hooks = MK_PLUGIN_STAGE,
+
+ /* Init / Exit */
+ .init_plugin = mk_dirlisting_plugin_init,
+ .exit_plugin = mk_dirlisting_plugin_exit,
+
+ /* Init Levels */
+ .master_init = NULL,
+ .worker_init = NULL,
+
+ /* Type */
+ .stage = &mk_plugin_stage_dirlisting
+};
diff --git a/fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.h b/fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.h
new file mode 100644
index 000000000..678a4887b
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/dirlisting/dirlisting.h
@@ -0,0 +1,181 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* dir_html.c */
+#ifndef MK_DIRHTML_H
+#define MK_DIRHTML_H
+
+#include <dirent.h>
+#include <limits.h>
+
+#define MK_DIRHTML_URL "/_mktheme"
+#define MK_DIRHTML_DEFAULT_MIME "Content-Type: text/html\r\n"
+
+/* For every directory requested, don't send more than
+ * this limit of entries.
+ */
+#define MK_DIRHTML_BUFFER_LIMIT 30
+#define MK_DIRHTML_BUFFER_GROW 5
+
+#define MK_HEADER_CHUNKED "Transfer-Encoding: Chunked\r\n\r\n"
+#define MK_DIRHTML_FMOD_LEN 24
+
+/* Theme files */
+#define MK_DIRHTML_FILE_HEADER "header.theme"
+#define MK_DIRHTML_FILE_ENTRY "entry.theme"
+#define MK_DIRHTML_FILE_FOOTER "footer.theme"
+
+#define MK_DIRHTML_TAG_INIT "%_"
+#define MK_DIRHTML_TAG_END "_%"
+#define MK_DIRHTML_SIZE_DIR "-"
+
+/* Stream state */
+#define MK_DIRHTML_STATE_HTTP_HEADER 0
+#define MK_DIRHTML_STATE_TPL_HEADER 1
+#define MK_DIRHTML_STATE_BODY 2
+#define MK_DIRHTML_STATE_FOOTER 3
+
+char *_tags_global[] = { "%_html_title_%",
+ "%_theme_path_%",
+ NULL
+};
+
+char *_tags_entry[] = { "%_target_title_%",
+ "%_target_url_%",
+ "%_target_name_%",
+ "%_target_time_%",
+ "%_target_size_%",
+ NULL
+};
+
+struct plugin_api *mk_api;
+
+struct mk_f_list
+{
+ char ft_modif[MK_DIRHTML_FMOD_LEN];
+ struct file_info info;
+ char name[NAME_MAX + 1]; /* The name can be up to NAME_MAX long; include NULL. */
+ char size[16];
+ unsigned char type;
+
+ struct mk_list _head;
+};
+
+/* Main configuration of dirhtml module */
+struct dirhtml_config
+{
+ char *theme;
+ char *theme_path;
+};
+
+/* Represent a request context */
+struct mk_dirhtml_request
+{
+ /* State */
+ int state;
+ int chunked;
+
+ /* Target directory */
+ DIR *dir;
+
+ /* Table of Content */
+ unsigned int toc_idx;
+ unsigned long toc_len;
+ struct mk_f_list **toc;
+ struct mk_list *file_list;
+
+ /* Stream handler */
+ struct mk_stream *stream;
+
+ /* Reference IOV stuff */
+ struct mk_iov *iov_header;
+ struct mk_iov *iov_entry;
+ struct mk_iov *iov_footer;
+
+ /* Session data */
+ struct mk_http_session *cs;
+ struct mk_http_request *sr;
+};
+
+
+extern const mk_ptr_t mk_dirhtml_default_mime;
+extern const mk_ptr_t mk_iov_dash;
+
+/* Global config */
+struct dirhtml_config *dirhtml_conf;
+
+/* Used to keep splitted content of every template */
+struct dirhtml_template
+{
+ char *buf;
+ int tag_id;
+ int len;
+ struct dirhtml_template *next;
+ char **tags; /* array of theme tags: [%_xaa__%, %_xyz_%] */
+};
+
+/* Templates for header, entries and footer */
+struct dirhtml_template *mk_dirhtml_tpl_header;
+struct dirhtml_template *mk_dirhtml_tpl_entry;
+struct dirhtml_template *mk_dirhtml_tpl_footer;
+
+struct dirhtml_value
+{
+ int tag_id;
+ mk_ptr_t sep; /* separator code after value */
+
+ /* string data */
+ int len;
+ char *value;
+
+ /* next node */
+ struct mk_list _head;
+
+ char **tags; /* array of tags which values correspond */
+};
+
+struct dirhtml_value *mk_dirhtml_value_global;
+
+/* Configuration struct */
+struct mk_config *conf;
+
+char *check_string(char *str);
+char *read_header_footer_file(char *file_path);
+
+int mk_dirhtml_conf();
+char *mk_dirhtml_load_file(char *filename);
+
+struct dirhtml_template *mk_dirhtml_template_create(char *content);
+
+struct dirhtml_template
+ *mk_dirhtml_template_list_add(struct dirhtml_template **header,
+ char *buf, int len, char **tpl, int tag);
+
+int mk_dirhtml_read_config(char *path);
+int mk_dirhtml_theme_load();
+int mk_dirhtml_theme_debug(struct dirhtml_template **st_tpl);
+
+struct dirhtml_value *mk_dirhtml_tag_assign(struct mk_list *list,
+ int tag_id, mk_ptr_t sep,
+ char *value, char **tags);
+
+struct f_list *get_dir_content(struct mk_http_request *sr, char *path);
+
+
+#endif
diff --git a/fluent-bit/lib/monkey/plugins/fastcgi/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/fastcgi/CMakeLists.txt
new file mode 100644
index 000000000..46056eead
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/fastcgi/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(src
+ fastcgi.c
+ fcgi_handler.c
+ )
+
+MONKEY_PLUGIN(fastcgi "${src}")
+add_subdirectory(conf)
diff --git a/fluent-bit/lib/monkey/plugins/fastcgi/conf/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/fastcgi/conf/CMakeLists.txt
new file mode 100644
index 000000000..0623bf68b
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/fastcgi/conf/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(conf_dir "${MK_PATH_CONF}/plugins/fastcgi/")
+
+install(DIRECTORY DESTINATION ${conf_dir})
+
+if(BUILD_LOCAL)
+ file(COPY fastcgi.conf DESTINATION ${conf_dir})
+else()
+ install(FILES fastcgi.conf DESTINATION ${conf_dir})
+endif()
diff --git a/fluent-bit/lib/monkey/plugins/fastcgi/conf/fastcgi.conf b/fluent-bit/lib/monkey/plugins/fastcgi/conf/fastcgi.conf
new file mode 100644
index 000000000..c5651c748
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/fastcgi/conf/fastcgi.conf
@@ -0,0 +1,16 @@
+# FastCGI
+# =======
+# To enable this plugin you'll need at least one [FASTCGI_SERVER].
+#
+# This configuration handles php scripts using php5-fpm running on
+# localhost or over the network.
+
+[FASTCGI_SERVER]
+ # Each server must have a unique name, this is mandatory.
+ ServerName php5-fpm1
+
+ # Depending on your version of php5-fpm, one of these should be
+ # enabled.
+ #
+ # ServerAddr 127.0.0.1:9000
+ ServerPath /var/run/php5-fpm.sock
diff --git a/fluent-bit/lib/monkey/plugins/fastcgi/fastcgi.c b/fluent-bit/lib/monkey/plugins/fastcgi/fastcgi.c
new file mode 100644
index 000000000..1c0e716a2
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/fastcgi/fastcgi.c
@@ -0,0 +1,233 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_api.h>
+
+#include "fastcgi.h"
+#include "fcgi_handler.h"
+
+static int mk_fastcgi_config(char *path)
+{
+ int ret;
+ int sep;
+ char *file = NULL;
+ char *cnf_srv_name = NULL;
+ char *cnf_srv_addr = NULL;
+ char *cnf_srv_port = NULL;
+ char *cnf_srv_path = NULL;
+ unsigned long len;
+ struct file_info finfo;
+ struct mk_rconf *conf;
+ struct mk_rconf_section *section;
+
+ mk_api->str_build(&file, &len, "%sfastcgi.conf", path);
+ conf = mk_api->config_open(file);
+ if (!conf) {
+ return -1;
+ }
+
+ section = mk_api->config_section_get(conf, "FASTCGI_SERVER");
+ if (!section) {
+ return -1;
+ }
+
+ /* Get section values */
+ cnf_srv_name = mk_api->config_section_get_key(section,
+ "ServerName",
+ MK_RCONF_STR);
+ cnf_srv_addr = mk_api->config_section_get_key(section,
+ "ServerAddr",
+ MK_RCONF_STR);
+ cnf_srv_path = mk_api->config_section_get_key(section,
+ "ServerPath",
+ MK_RCONF_STR);
+
+ /* Validations */
+ if (!cnf_srv_name) {
+ mk_warn("[fastcgi] Invalid ServerName in configuration.");
+ return -1;
+ }
+
+ /* Split the address, try to lookup the TCP port */
+ if (cnf_srv_addr) {
+ sep = mk_api->str_char_search(cnf_srv_addr, ':', strlen(cnf_srv_addr));
+ if (sep <= 0) {
+ mk_warn("[fastcgi] Missing TCP port con ServerAddress key");
+ return -1;
+ }
+
+ cnf_srv_port = mk_api->str_dup(cnf_srv_addr + sep + 1);
+ cnf_srv_addr[sep] = '\0';
+ }
+
+ /* Just one mode can exist (for now) */
+ if (cnf_srv_path && cnf_srv_addr) {
+ mk_warn("[fastcgi] Use ServerAddr or ServerPath, not both");
+ return -1;
+ }
+
+ /* Unix socket path */
+ if (cnf_srv_path) {
+ ret = mk_api->file_get_info(cnf_srv_path, &finfo, MK_FILE_READ);
+ if (ret == -1) {
+ mk_warn("[fastcgi] Cannot open unix socket: %s", cnf_srv_path);
+ return -1;
+ }
+ }
+
+ /* Set the global configuration */
+ fcgi_conf.server_name = cnf_srv_name;
+ fcgi_conf.server_addr = cnf_srv_addr;
+ fcgi_conf.server_port = cnf_srv_port;
+ fcgi_conf.server_path = cnf_srv_path;
+
+ return 0;
+}
+
+
+/* Entry point for thread/co-routine */
+static void mk_fastcgi_stage30_thread(struct mk_plugin *plugin,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ int n_params,
+ struct mk_list *params)
+{
+ struct fcgi_handler *handler;
+ (void) plugin;
+ (void) n_params;
+ (void) params;
+
+ printf("entering thread\n");
+ handler = fcgi_handler_new(cs, sr);
+ if (!handler) {
+ fprintf(stderr, "Could not create handler");
+ }
+}
+
+/* Callback handler */
+int mk_fastcgi_stage30(struct mk_plugin *plugin,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ int n_params,
+ struct mk_list *params)
+{
+ (void) n_params;
+ (void) params;
+ struct fcgi_handler *handler;
+
+ /*
+ * This plugin uses the Monkey Thread model (co-routines), for hence
+ * upon return MK_PLUGIN_RET_CONTINUE, Monkey core will create a
+ * new thread (co-routine) and defer the control to the stage30_thread
+ * callback function (mk_fastcgi_stage30_thread).
+ *
+ * We don't do any validation, so we are OK with MK_PLUGIN_RET_CONTINUE.
+ */
+
+ return MK_PLUGIN_RET_CONTINUE;
+
+ ret = mk_fastcgi_start_processing(cs, sr);
+ if (ret == 0) {
+ return MK_PLUGIN_RET_CONTINUE;
+ }
+
+ return MK_PLUGIN_RET_CONTINUE;
+}
+
+int mk_fastcgi_stage30_hangup(struct mk_plugin *plugin,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr)
+{
+ (void) plugin;
+ (void) cs;
+ struct fcgi_handler *handler;
+
+ handler = sr->handler_data;
+ if (!handler) {
+ return -1;
+ }
+
+ if (handler->hangup == MK_TRUE) {
+ return 0;
+ }
+
+ handler->active = MK_FALSE;
+ handler->hangup = MK_TRUE;
+
+ fcgi_exit(sr->handler_data);
+
+ return 0;
+}
+
+int mk_fastcgi_plugin_init(struct plugin_api **api, char *confdir)
+{
+ int ret;
+
+ mk_api = *api;
+
+ /* read global configuration */
+ ret = mk_fastcgi_config(confdir);
+ if (ret == -1) {
+ mk_warn("[fastcgi] configuration error/missing, plugin disabled.");
+ }
+ return ret;
+}
+
+int mk_fastcgi_plugin_exit()
+{
+ return 0;
+}
+
+int mk_fastcgi_master_init(struct mk_server *server)
+{
+ (void) server;
+ return 0;
+}
+
+void mk_fastcgi_worker_init()
+{
+}
+
+struct mk_plugin_stage mk_plugin_stage_fastcgi = {
+ .stage30 = &mk_fastcgi_stage30,
+ .stage30_thread = &mk_fastcgi_stage30_thread,
+ .stage30_hangup = &mk_fastcgi_stage30_hangup
+};
+
+struct mk_plugin mk_plugin_fastcgi = {
+ /* Identification */
+ .shortname = "fastcgi",
+ .name = "FastCGI Client",
+ .version = "1.0",
+ .hooks = MK_PLUGIN_STAGE,
+
+ /* Init / Exit */
+ .init_plugin = mk_fastcgi_plugin_init,
+ .exit_plugin = mk_fastcgi_plugin_exit,
+
+ /* Init Levels */
+ .master_init = mk_fastcgi_master_init,
+ .worker_init = mk_fastcgi_worker_init,
+
+ /* Type */
+ .stage = &mk_plugin_stage_fastcgi,
+
+ /* Flags */
+ .flags = MK_PLUGIN_THREAD
+};
diff --git a/fluent-bit/lib/monkey/plugins/fastcgi/fastcgi.h b/fluent-bit/lib/monkey/plugins/fastcgi/fastcgi.h
new file mode 100644
index 000000000..a367f761c
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/fastcgi/fastcgi.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_FASTCGI_H
+#define MK_FASTCGI_H
+
+struct mk_fcgi_conf {
+ char *server_name;
+
+ /* Unix Socket */
+ char *server_path;
+
+ /* TCP Server */
+ char *server_addr;
+ char *server_port;
+};
+
+struct mk_fcgi_conf fcgi_conf;
+
+#endif
diff --git a/fluent-bit/lib/monkey/plugins/fastcgi/fcgi_handler.c b/fluent-bit/lib/monkey/plugins/fastcgi/fcgi_handler.c
new file mode 100644
index 000000000..0c7881309
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/fastcgi/fcgi_handler.c
@@ -0,0 +1,967 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_api.h>
+#include <monkey/mk_net.h>
+#include <monkey/mk_stream.h>
+
+#include "fastcgi.h"
+#include "fcgi_handler.h"
+
+#define FCGI_BUF(h) (char *) h->buf_data + h->buf_len
+#define FCGI_PARAM_DYN(str) str, strlen(str), MK_FALSE
+#define FCGI_PARAM_CONST(str) str, sizeof(str) -1, MK_FALSE
+#define FCGI_PARAM_PTR(ptr) ptr.data, ptr.len, MK_FALSE
+#define FCGI_PARAM_DUP(str) mk_api->str_dup(str), strlen(str), MK_TRUE
+
+int fcgi_pad[256] = {0};
+
+static inline void fcgi_build_header(struct fcgi_record_header *rec,
+ uint8_t type, uint16_t request_id,
+ uint16_t content_length)
+{
+ rec->version = FCGI_VERSION_1;
+ rec->type = type;
+ fcgi_encode16(&rec->request_id, request_id);
+ fcgi_encode16(&rec->content_length, content_length);
+ rec->padding_length = 0;
+ rec->reserved = 0;
+}
+
+static inline void fcgi_build_request_body(struct fcgi_begin_request_body *body)
+{
+ fcgi_encode16(&body->role, FCGI_RESPONDER);
+ body->flags = 0;
+ memset(body->reserved, '\0', sizeof(body->reserved));
+}
+
+static inline size_t fcgi_write_length(char *p, size_t len)
+{
+ if (len < 127) {
+ *p++ = len;
+ return 1;
+ }
+ else{
+ *p++ = (len >> 24) | 0x80;
+ *p++ = (len >> 16) & 0xff;
+ *p++ = (len >> 8) & 0xff;
+ *p++ = (len) & 0xff;
+ return 4;
+ }
+}
+
+static inline int fcgi_add_param_empty(struct fcgi_handler *handler)
+{
+ char *p;
+
+ p = FCGI_BUF(handler);
+ fcgi_build_header((struct fcgi_record_header *) p, FCGI_PARAMS, 1, 0);
+ mk_api->iov_add(handler->iov, p,
+ sizeof(struct fcgi_record_header), MK_FALSE);
+ handler->buf_len += sizeof(struct fcgi_record_header);
+ return 0;
+}
+
+static inline int fcgi_add_param(struct fcgi_handler *handler,
+ char *key, int key_len, int key_free,
+ char *val, int val_len, int val_free)
+{
+ int ret;
+ int len;
+ int diff;
+ int padding;
+ char *p;
+ char *buf;
+ struct fcgi_record_header *h;
+
+ buf = p = (char * ) handler->buf_data + handler->buf_len;
+
+ len = key_len + val_len;
+ len += key_len > 127 ? 4 : 1;
+ len += val_len > 127 ? 4 : 1;
+
+ fcgi_build_header((struct fcgi_record_header *) p, FCGI_PARAMS, 1, len);
+ padding = ~(len - 1) & 7;
+ if (padding) {
+ h = (struct fcgi_record_header *) p;
+ h->padding_length = padding;
+ }
+
+ p += sizeof(struct fcgi_record_header);
+ p += fcgi_write_length(p, key_len);
+ p += fcgi_write_length(p, val_len);
+
+ diff = (p - buf);
+ handler->buf_len += diff;
+ ret = mk_api->iov_add(handler->iov, buf, diff, MK_FALSE);
+ if (ret == -1) {
+ return -1;
+ }
+
+ mk_api->iov_add(handler->iov, key, key_len, key_free);
+ mk_api->iov_add(handler->iov, val, val_len, val_free);
+
+ if (padding) {
+ mk_api->iov_add(handler->iov, fcgi_pad, h->padding_length, MK_FALSE);
+ }
+
+ return 0;
+}
+
+static inline int fcgi_add_param_http_header(struct fcgi_handler *handler,
+ struct mk_http_header *header)
+{
+ unsigned int i;
+ int avail;
+ int req;
+ int diff;
+ char *p;
+ char *buf;
+
+ avail = (sizeof(handler->buf_data) - handler->buf_len);
+ req = sizeof(struct fcgi_record_header) + 8;
+ req += header->key.len + 5;
+
+ if (avail < req) {
+ return -1;
+ }
+
+ buf = p = (handler->buf_data + handler->buf_len);
+ *p++ = 'H';
+ *p++ = 'T';
+ *p++ = 'T';
+ *p++ = 'P';
+ *p++ = '_';
+
+ for (i = 0; i < header->key.len; i++) {
+ if (header->key.data[i] == '-') {
+ *p++ = '_';
+ }
+ else {
+ *p++ = toupper(header->key.data[i]);
+ }
+ }
+
+ diff = (p - buf);
+ handler->buf_len += diff;
+ fcgi_add_param(handler,
+ buf, diff, MK_FALSE,
+ header->val.data, header->val.len, MK_FALSE);
+
+ return 0;
+}
+
+static inline int fcgi_add_param_net(struct fcgi_handler *handler)
+{
+ int ret;
+ const char *p;
+ char buffer[256];
+
+ /* This is to identify whether its IPV4 or IPV6 */
+ struct sockaddr_storage addr;
+ int port = 0;
+ socklen_t addr_len = sizeof(struct sockaddr_in);
+
+ ret = getsockname(handler->cs->socket, (struct sockaddr *)&addr, &addr_len);
+ if (ret == -1) {
+#ifdef TRACE
+ perror("getsockname");
+#endif
+ if (errno == EBADF) {
+ MK_TRACE("[fastcgi=%i] network connection broken",
+ handler->cs->socket);
+ }
+ return -1;
+ }
+
+ if (addr.ss_family == AF_INET) {
+ struct sockaddr_in *s = (struct sockaddr_in *)&addr;
+ port = ntohs(s->sin_port);
+ p = inet_ntop(AF_INET, &s->sin_addr, buffer, sizeof(buffer));
+ if (!p) {
+ perror("inet_ntop");
+ return -1;
+ }
+ } else { /* AF_INET6 */
+ struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
+ port = ntohs(s->sin6_port);
+ p = inet_ntop(AF_INET6, &s->sin6_addr, buffer, sizeof(buffer));
+ if (!p) {
+ perror("inet_ntop");
+ return -1;
+ }
+ }
+
+ /* Server Address */
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("SERVER_ADDR"),
+ FCGI_PARAM_DUP(buffer));
+
+ /* Server Port */
+ snprintf(buffer, 256, "%d", port);
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("SERVER_PORT"),
+ FCGI_PARAM_DUP(buffer));
+
+
+ ret = getpeername(handler->cs->socket, (struct sockaddr *)&addr, &addr_len);
+ if (ret == -1) {
+ perror("getpeername");
+ return -1;
+ }
+
+ if (addr.ss_family == AF_INET) {
+ struct sockaddr_in *s = (struct sockaddr_in *)&addr;
+ port = ntohs(s->sin_port);
+ p = inet_ntop(AF_INET, &s->sin_addr, buffer, sizeof(buffer));
+ if (!p) {
+ perror("inet_ntop");
+ return -1;
+ }
+ } else { /* AF_INET6 */
+ struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
+ port = ntohs(s->sin6_port);
+
+ if (IN6_IS_ADDR_V4MAPPED(&s->sin6_addr)) {
+ /* This is V4-Mapped-V6 - Lets convert it to plain IPV4 address.
+ * E.g. we would have received like this ::ffff:10.106.146.73.
+ * This would be converted to 10.106.146.73.
+ */
+ struct sockaddr_in addr4;
+ struct sockaddr_in *s4 = (struct sockaddr_in *)&addr4;
+ memset(&addr4, 0, sizeof(addr4));
+ addr4.sin_family = AF_INET;
+ addr4.sin_port = &s->sin6_port;
+ memcpy(&addr4.sin_addr.s_addr,
+ s->sin6_addr.s6_addr + 12,
+ sizeof(addr4.sin_addr.s_addr));
+ p = inet_ntop(AF_INET, &s4->sin_addr, buffer, sizeof(buffer));
+ if (!p) {
+ perror("inet_ntop");
+ return -1;
+ }
+ } else {
+ p = inet_ntop(AF_INET6, &s->sin6_addr, buffer, sizeof(buffer));
+ if (!p) {
+ perror("inet_ntop");
+ return -1;
+ }
+ }
+ }
+
+ /* Remote Addr */
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("REMOTE_ADDR"),
+ FCGI_PARAM_DUP(buffer));
+
+ /* Remote Port */
+ snprintf(buffer, 256, "%d", port);
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("REMOTE_PORT"),
+ FCGI_PARAM_DUP(buffer));
+
+ return 0;
+}
+
+static inline int fcgi_stdin_chunk(struct fcgi_handler *handler)
+{
+ int padding = 0;
+ uint16_t max = 65535;
+ uint16_t chunk;
+ uint64_t total;
+ char *p;
+ char *eof;
+ struct fcgi_record_header *h;
+
+ total = handler->stdin_length - handler->stdin_offset;
+ if (total > max) {
+ chunk = max;
+ }
+ else {
+ chunk = total;
+ }
+
+ p = FCGI_BUF(handler);
+ h = (struct fcgi_record_header *) p;
+ fcgi_build_header(h, FCGI_STDIN, 1, chunk);
+ h->padding_length = ~(chunk - 1) & 7;
+
+ MK_TRACE("[fastcgi] STDIN: length=%i", chunk);
+
+ mk_api->iov_add(handler->iov, p, FCGI_RECORD_HEADER_SIZE, MK_FALSE);
+ handler->buf_len += FCGI_RECORD_HEADER_SIZE;
+
+
+ if (chunk > 0) {
+ mk_api->iov_add(handler->iov,
+ handler->stdin_buffer + handler->stdin_offset,
+ chunk,
+ MK_FALSE);
+ }
+
+ if (h->padding_length > 0) {
+ mk_api->iov_add(handler->iov,
+ fcgi_pad, h->padding_length,
+ MK_FALSE);
+ }
+
+ if (handler->stdin_offset + chunk == handler->stdin_length) {
+ eof = FCGI_BUF(handler);
+ fcgi_build_header((struct fcgi_record_header *) eof, FCGI_STDIN, 1, 0);
+ mk_api->iov_add(handler->iov, eof, FCGI_RECORD_HEADER_SIZE, MK_FALSE);
+ handler->buf_len += FCGI_RECORD_HEADER_SIZE + padding;
+ }
+
+ handler->stdin_offset += chunk;
+ return 0;
+}
+
+static inline int fcgi_add_stdin(struct fcgi_handler *handler)
+{
+ uint64_t bytes = handler->sr->data.len;
+
+ if (bytes <= 0) {
+ return -1;
+ }
+
+ handler->stdin_length = bytes;
+ handler->stdin_offset = 0;
+ handler->stdin_buffer = handler->sr->data.data;
+ fcgi_stdin_chunk(handler);
+
+ return 0;
+}
+
+static int fcgi_encode_request(struct fcgi_handler *handler)
+{
+ int ret;
+ struct mk_http_header *header;
+ struct fcgi_begin_request_record *request;
+
+ MK_TRACE("ENCODE REQUEST");
+
+ request = &handler->header_request;
+ fcgi_build_header(&request->header, FCGI_BEGIN_REQUEST, 1,
+ FCGI_BEGIN_REQUEST_BODY_SIZE);
+
+ fcgi_build_request_body(&request->body);
+
+ /* BEGIN_REQUEST */
+ mk_api->iov_add(handler->iov,
+ &handler->header_request,
+ sizeof(handler->header_request),
+ MK_FALSE);
+
+ /* Server Software */
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("GATEWAY_INTERFACE"),
+ FCGI_PARAM_CONST("CGI/1.1"));
+
+ /* Server Software */
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("REDIRECT_STATUS"),
+ FCGI_PARAM_CONST("200"));
+
+ /* Server Software */
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("SERVER_SOFTWARE"),
+ FCGI_PARAM_DYN(mk_api->config->server_signature));
+
+ /* Server Name */
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("SERVER_PROTOCOL"),
+ FCGI_PARAM_CONST("HTTP/1.1"));
+
+ /* Server Name */
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("SERVER_NAME"),
+ handler->sr->host_alias->name,
+ handler->sr->host_alias->len,
+ MK_FALSE);
+
+ /* Document Root */
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("DOCUMENT_ROOT"),
+ FCGI_PARAM_PTR(handler->sr->host_conf->documentroot));
+
+ /* Network params: SERVER_ADDR, SERVER_PORT, REMOTE_ADDR & REMOTE_PORT */
+ ret = fcgi_add_param_net(handler);
+ if (ret == -1) {
+ return -1;
+ }
+
+ /* Script Filename */
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("SCRIPT_FILENAME"),
+ FCGI_PARAM_PTR(handler->sr->real_path));
+
+ /* Script Filename */
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("SCRIPT_NAME"),
+ FCGI_PARAM_PTR(handler->sr->uri_processed));
+
+ /* Request Method */
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("REQUEST_METHOD"),
+ FCGI_PARAM_PTR(handler->sr->method_p));
+
+
+ /* Request URI */
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("REQUEST_URI"),
+ FCGI_PARAM_PTR(handler->sr->uri));
+
+ /* Query String */
+ if (handler->sr->query_string.len > 0) {
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("QUERY_STRING"),
+ FCGI_PARAM_PTR(handler->sr->query_string));
+ }
+
+ /* HTTPS */
+ if (MK_SCHED_CONN_PROP(handler->cs->conn) & MK_CAP_SOCK_TLS) {
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("HTTPS"),
+ FCGI_PARAM_CONST("on"));
+ }
+
+ /* Content Length */
+ if (handler->sr->_content_length.data) {
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("CONTENT_LENGTH"),
+ FCGI_PARAM_PTR(handler->sr->_content_length));
+ }
+
+ /* Content Length */
+ header = &handler->cs->parser.headers[MK_HEADER_CONTENT_TYPE];
+ if (header->type == MK_HEADER_CONTENT_TYPE) {
+ fcgi_add_param(handler,
+ FCGI_PARAM_CONST("CONTENT_TYPE"),
+ FCGI_PARAM_PTR(header->val));
+
+ }
+
+ /* Append HTTP request headers */
+ struct mk_list *head;
+ struct mk_http_header *http_header;
+ mk_list_foreach(head, &handler->cs->parser.header_list) {
+ http_header = mk_list_entry(head, struct mk_http_header, _head);
+ fcgi_add_param_http_header(handler, http_header);
+ }
+
+ /* Append the empty params record */
+ fcgi_add_param_empty(handler);
+
+ /* Data for FCGI_STDIN */
+ fcgi_add_stdin(handler);
+
+ return 0;
+}
+
+size_t fcgi_read_header(void *p, struct fcgi_record_header *h)
+{
+ memcpy(h, p, sizeof(struct fcgi_record_header));
+ h->request_id = htons(h->request_id);
+ h->content_length = htons(h->content_length);
+
+ return sizeof(*h);
+}
+
+static inline int fcgi_buffer_consume(struct fcgi_handler *handler, size_t bytes)
+{
+ if (bytes >= handler->buf_len) {
+ handler->buf_len = 0;
+ return 0;
+ }
+
+ memmove(handler->buf_data, handler->buf_data + bytes,
+ handler->buf_len - bytes);
+ handler->buf_len -= bytes;
+ return 0;
+}
+
+static char *getearliestbreak(const char buf[], const unsigned bufsize,
+ unsigned char * const advance)
+{
+ char *crend;
+ char *lfend;
+
+ crend = memmem(buf, bufsize, "\r\n\r\n", 4);
+ lfend = memmem(buf, bufsize, "\n\n", 2);
+
+ if (!crend && !lfend)
+ return NULL;
+
+ /* If only one found, return that one */
+ if (!crend) {
+ *advance = 2;
+ return lfend;
+ }
+ if (!lfend)
+ return crend;
+
+ /* Both found, return the earlier one - the latter one is part of content */
+ if (lfend < crend) {
+ *advance = 2;
+ return lfend;
+ }
+ return crend;
+}
+
+static int fcgi_write(struct fcgi_handler *handler, char *buf, size_t len)
+{
+ mk_stream_in_raw(handler->stream,
+ NULL,
+ buf, len,
+ NULL, NULL);
+
+ if (handler->headers_set == MK_TRUE) {
+ mk_stream_in_raw(handler->stream,
+ NULL,
+ "\r\n", 2,
+ NULL, NULL);
+ }
+ return 0;
+}
+
+void fcgi_stream_eof(struct mk_stream_input *in)
+{
+ (void) in;
+ // FIXME
+ //struct fcgi_handler *handler;
+
+ //handler = stream->data;
+ //if (handler->hangup == MK_FALSE) {
+ // fcgi_exit(handler);
+ //}
+}
+
+int fcgi_exit(struct fcgi_handler *handler)
+{
+ /* Always disable any backend notification first */
+ if (handler->server_fd > 0) {
+ mk_api->ev_del(mk_api->sched_loop(), &handler->event);
+ close(handler->server_fd);
+ handler->server_fd = -1;
+ }
+
+ /*
+ * Before to exit our handler, we need to verify that our parent
+ * channel have sent the whole information, otherwise we may face
+ * some corruption. If there is still some data enqueued, just
+ * defer the exit process.
+ */
+ if (mk_channel_is_empty(handler->cs->channel) != 0 &&
+ handler->eof == MK_FALSE &&
+ handler->active == MK_TRUE) {
+ MK_TRACE("[fastcgi=%i] deferring exit, EOF stream",
+ handler->server_fd);
+
+ /* Now set an EOF stream/callback to resume the exiting process */
+ mk_stream_in_eof(handler->stream,
+ NULL,
+ fcgi_stream_eof);
+ handler->eof = MK_TRUE;
+ return 1;
+ }
+
+ MK_TRACE("[fastcgi] exiting");
+
+ if (handler->iov) {
+ mk_api->iov_free(handler->iov);
+ mk_api->sched_event_free((struct mk_event *) handler);
+ handler->iov = NULL;
+ }
+
+ if (handler->active == MK_TRUE) {
+ handler->active = MK_FALSE;
+ mk_api->http_request_end(handler->plugin, handler->cs, handler->hangup);
+ }
+
+ return 1;
+}
+
+int fcgi_error(struct fcgi_handler *handler)
+{
+ fcgi_exit(handler);
+ mk_api->http_request_error(500, handler->cs, handler->sr, handler->plugin);
+ return 0;
+}
+
+static int fcgi_response(struct fcgi_handler *handler, char *buf, size_t len)
+{
+ int status;
+ int diff;
+ int xlen;
+ char tmp[16];
+ char *p;
+ char *end;
+ size_t p_len;
+ unsigned char advance;
+
+ MK_TRACE("[fastcgi=%i] process response len=%lu",
+ handler->server_fd, len);
+
+ p = buf;
+ p_len = len;
+
+ if (len == 0 && handler->chunked && handler->headers_set == MK_TRUE) {
+ MK_TRACE("[fastcgi=%i] sending EOF", handler->server_fd);
+ mk_stream_in_raw(handler->stream,
+ NULL,
+ "0\r\n\r\n", 5,
+ NULL, NULL);
+ mk_api->channel_flush(handler->cs->channel);
+ return 0;
+ }
+
+ if (handler->headers_set == MK_FALSE) {
+ advance = 4;
+
+ if (!buf) {
+ return -1;
+ }
+
+ end = getearliestbreak(buf, len, &advance);
+ if (!end) {
+ /* we need more data */
+ return -1;
+ }
+
+ handler->sr->headers.cgi = MK_TRUE;
+ if (strncasecmp(buf, "Status: ", 8) == 0) {
+ sscanf(buf + 8, "%d", &status);
+ MK_TRACE("FastCGI status %i", status);
+ mk_api->header_set_http_status(handler->sr, status);
+ }
+ else {
+ mk_api->header_set_http_status(handler->sr, 200);
+ }
+
+ /* Set transfer encoding */
+ if (handler->sr->protocol >= MK_HTTP_PROTOCOL_11) {
+ handler->sr->headers.transfer_encoding = MK_HEADER_TE_TYPE_CHUNKED;
+ handler->chunked = MK_TRUE;
+ }
+
+ mk_api->header_prepare(handler->plugin, handler->cs, handler->sr);
+
+ diff = (end - buf) + advance;
+ fcgi_write(handler, buf, diff);
+
+ p = buf + diff;
+ p_len -= diff;
+ handler->write_rounds++;
+ handler->headers_set = MK_TRUE;
+ }
+
+ if (p_len > 0) {
+ xlen = snprintf(tmp, 16, "%x\r\n", (unsigned int) p_len);
+ mk_stream_in_raw(handler->stream,
+ NULL,
+ tmp, xlen,
+ NULL, NULL);
+ fcgi_write(handler, p, p_len);
+ }
+
+ return 0;
+}
+
+int cb_fastcgi_on_read(void *data)
+{
+ int n;
+ int ret = 0;
+ int avail;
+ char *body;
+ size_t offset;
+ struct fcgi_handler *handler = data;
+ struct fcgi_record_header header;
+
+ if (handler->active == MK_FALSE) {
+ fcgi_exit(handler);
+ return -1;
+ }
+
+ avail = FCGI_BUF_SIZE - handler->buf_len;
+ n = read(handler->server_fd, handler->buf_data + handler->buf_len, avail);
+ MK_TRACE("[fastcgi=%i] read()=%i", handler->server_fd, n);
+ if (n <= 0) {
+ MK_TRACE("[fastcgi=%i] FastCGI server ended", handler->server_fd);
+ fcgi_exit(handler);
+ return -1;
+ }
+ else {
+ handler->buf_len += n;
+ }
+
+ if ((unsigned) handler->buf_len < FCGI_RECORD_HEADER_SIZE) {
+ /* wait for more data */
+ return n;
+ }
+
+ while (1) {
+ /* decode the header */
+ fcgi_read_header(&handler->buf_data, &header);
+
+ if (header.type != FCGI_STDOUT && header.type != FCGI_STDERR &&
+ header.type != FCGI_END_REQUEST) {
+ fcgi_exit(handler);
+ return -1;
+ }
+
+ /* Check if the package is complete */
+ if (handler->buf_len < (FCGI_RECORD_HEADER_SIZE + header.content_length)) {
+ /* we need more data */
+ return n;
+ }
+
+ body = handler->buf_data + FCGI_RECORD_HEADER_SIZE;
+ switch (header.type) {
+ case FCGI_STDOUT:
+ MK_TRACE("[fastcgi=%i] FCGI_STDOUT content_length=%i",
+ handler->server_fd, header.content_length);
+ /*
+ * Issue seen with Chrome & Firefox browsers:
+ * Sometimes content length is coming as ZERO and we are encoding a
+ * HTTP response packet with ZERO size data. This makes Chrome & Firefox
+ * browsers fail to proceed furhter and subsequent content loading fails.
+ * However, IE/Safari discards the packets with ZERO size data.
+ */
+ if (0 != header.content_length) {
+ ret = fcgi_response(handler, body, header.content_length);
+ }
+ else {
+ MK_TRACE("[fastcgi=%i] ZERO byte content length in FCGI_STDOUT, discard!!",
+ handler->server_fd);
+ ret = 0;
+ }
+ break;
+ case FCGI_STDERR:
+ MK_TRACE("[fastcgi=%i] FCGI_STDERR content_length=%i",
+ handler->server_fd, header.content_length);
+ break;
+ case FCGI_END_REQUEST:
+ MK_TRACE("[fastcgi=%i] FCGI_END_REQUEST content_length=%i",
+ handler->server_fd, header.content_length);
+ ret = fcgi_response(handler, NULL, 0);
+ break;
+ default:
+ //fcgi_exit(handler);
+ return -1;
+ }
+
+ if (ret == -1) {
+ /* Missing header breaklines ? */
+ return n;
+ }
+
+ /* adjust buffer content */
+ offset = FCGI_RECORD_HEADER_SIZE +
+ header.content_length + header.padding_length;
+
+ fcgi_buffer_consume(handler, offset);
+ }
+ return n;
+}
+
+int cb_fastcgi_request_flush(void *data)
+{
+ int ret;
+ size_t count = 0;
+ struct fcgi_handler *handler = data;
+
+ ret = mk_api->channel_write(&handler->fcgi_channel, &count);
+
+ MK_TRACE("[fastcgi=%i] %lu bytes, ret=%i",
+ handler->server_fd, count, ret);
+
+ if (ret == MK_CHANNEL_DONE || ret == MK_CHANNEL_EMPTY) {
+ /* Do we have more data for the stdin ? */
+ if (handler->stdin_length - handler->stdin_offset > 0) {
+ mk_api->iov_free(handler->iov);
+ handler->iov = mk_api->iov_create(64, 0);
+ fcgi_stdin_chunk(handler);
+
+ mk_api->stream_set(&handler->fcgi_stream,
+ MK_STREAM_IOV,
+ &handler->fcgi_channel,
+ handler->iov,
+ -1,
+ handler,
+ NULL, NULL, NULL);
+ return MK_CHANNEL_FLUSH;
+ }
+
+ /* Request done, switch the event side to receive the FCGI response */
+ handler->buf_len = 0;
+ handler->event.handler = cb_fastcgi_on_read;
+ ret = mk_api->ev_add(mk_api->sched_loop(),
+ handler->server_fd,
+ MK_EVENT_CUSTOM, MK_EVENT_READ, handler);
+ if (ret == -1) {
+ goto error;
+ }
+ }
+ else if (ret == MK_CHANNEL_ERROR) {
+ fcgi_exit(handler);
+ }
+ else if (ret == MK_CHANNEL_BUSY) {
+ return -1;
+ }
+
+ return ret;
+
+ error:
+ return -1;
+}
+
+/* Callback: on connect to the backend server */
+static int fastcgi_on_connect(struct fcgi_handler *handler)
+{
+ int ret;
+ int s_err;
+ size_t count;
+ socklen_t s_len = sizeof(s_err);
+ struct mk_list *head;
+ struct mk_plugin *pio;
+ struct mk_channel *channel;
+
+ /* Convert the original request to FCGI format */
+ ret = fcgi_encode_request(handler);
+ if (ret == -1) {
+ goto error;
+ }
+
+ /* Prepare the channel */
+ channel = &handler->fcgi_channel;
+ channel->type = MK_CHANNEL_SOCKET;
+ channel->fd = handler->server_fd;
+
+ /* FIXME: Discovery process needs to be fast */
+ mk_list_foreach(head, &mk_api->config->plugins) {
+ pio = mk_list_entry(head, struct mk_plugin, _head);
+ if (strncmp(pio->shortname, "liana", 5) == 0) {
+ break;
+ }
+ pio = NULL;
+ }
+ channel->io = pio->network;
+
+ mk_list_init(&channel->streams);
+ mk_api->stream_set(&handler->fcgi_stream,
+ MK_STREAM_IOV,
+ &handler->fcgi_channel,
+ handler->iov,
+ -1,
+ handler,
+ NULL, NULL, NULL);
+
+ handler->event.handler = cb_fastcgi_request_flush;
+ handler->event.data = handler;
+
+ return 0;
+
+ error:
+ fcgi_error(handler);
+ mk_api->channel_write(handler->cs->channel, &count);
+ return 0;
+}
+
+struct fcgi_handler *fcgi_handler_new(struct mk_plugin *plugin,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr)
+{
+ int ret;
+ int entries;
+ struct fcgi_handler *h = NULL;
+ struct mk_net_connection *conn = NULL;
+
+ /* Allocate handler instance and set fields */
+ h = mk_api->mem_alloc_z(sizeof(struct fcgi_handler));
+ if (!h) {
+ return NULL;
+ }
+
+ stream = mk_stream_set(NULL, cs->channel, h,
+ NULL, NULL, NULL);
+ if (!stream) {
+ mk_api->mem_free(h);
+ return NULL;
+ }
+
+ h->stream = stream;
+ h->plugin = plugin;
+ h->cs = cs;
+ h->sr = sr;
+ h->write_rounds = 0;
+ h->active = MK_TRUE;
+ h->server_fd = -1;
+ h->eof = MK_FALSE;
+ h->stdin_length = 0;
+ h->stdin_offset = 0;
+ h->stdin_buffer = NULL;
+ h->conn = NULL;
+
+ /* Allocate enough space for our data */
+ entries = 128 + (cs->parser.header_count * 3);
+ h->iov = mk_api->iov_create(entries, 0);
+
+ /* Associate the handler with the Session Request */
+ sr->handler_data = h;
+
+ if (sr->protocol >= MK_HTTP_PROTOCOL_11) {
+ h->hangup = MK_FALSE;
+ }
+ else {
+ h->hangup = MK_TRUE;
+ }
+
+ /* Params buffer set an offset to include the header */
+ h->buf_len = FCGI_RECORD_HEADER_SIZE;
+
+ /* Request and async connection to the server */
+ if (fcgi_conf.server_addr) {
+ conn = mk_api->net_conn_create(fcgi_conf.server_addr,
+ atoi(fcgi_conf.server_port));
+ if (!conn) {
+ goto error;
+ }
+ h->conn = conn;
+ h->server_fd = conn->fd;
+ }
+ else if (fcgi_conf.server_path) {
+ /* FIXME: unix socket connection NOT FUNCTIONAL for now */
+ h->server_fd = mk_api->socket_open(fcgi_conf.server_path, MK_TRUE);
+ }
+
+ if (h->server_fd == -1) {
+ goto error;
+ }
+
+ fastcgi_on_connect(h);
+ return h;
+
+ error:
+ mk_api->iov_free(h->iov);
+ mk_api->mem_free(h);
+ sr->handler_data = NULL;
+ mk_api->http_request_error(500, cs, sr, plugin);
+
+ return NULL;
+}
diff --git a/fluent-bit/lib/monkey/plugins/fastcgi/fcgi_handler.h b/fluent-bit/lib/monkey/plugins/fastcgi/fcgi_handler.h
new file mode 100644
index 000000000..a0083ac7d
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/fastcgi/fcgi_handler.h
@@ -0,0 +1,128 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_FASTCGI_HANDLER_H
+#define MK_FASTCGI_HANDLER_H
+
+#include <monkey/mk_api.h>
+
+/*
+ * Based on the information provided by the FastCGI spec, we use the
+ * following adapted structures:
+ *
+ * http://www.fastcgi.com/drupal/node/6?q=node/22
+ */
+struct fcgi_record_header {
+ uint8_t version;
+ uint8_t type;
+ uint16_t request_id;
+ uint16_t content_length;
+ uint8_t padding_length;
+ uint8_t reserved;
+};
+
+struct fcgi_begin_request_body {
+ uint16_t role;
+ uint8_t flags;
+ uint8_t reserved[5];
+};
+
+struct fcgi_begin_request_record {
+ struct fcgi_record_header header;
+ struct fcgi_begin_request_body body;
+};
+
+#define FCGI_VERSION_1 1
+#define FCGI_RECORD_MAX_SIZE 65535
+#define FCGI_RECORD_HEADER_SIZE sizeof(struct fcgi_record_header)
+#define FCGI_BUF_SIZE FCGI_RECORD_MAX_SIZE + FCGI_RECORD_HEADER_SIZE
+#define FCGI_BEGIN_REQUEST_BODY_SIZE sizeof(struct fcgi_begin_request_body)
+#define FCGI_RESPONDER 1
+#define FCGI_AUTHORIZER 2
+#define FCGI_FILTER 3
+
+/*
+ * Values for type component of FCGI_Header
+ */
+#define FCGI_BEGIN_REQUEST 1
+#define FCGI_ABORT_REQUEST 2
+#define FCGI_END_REQUEST 3
+#define FCGI_PARAMS 4
+#define FCGI_STDIN 5
+#define FCGI_STDOUT 6
+#define FCGI_STDERR 7
+#define FCGI_DATA 8
+#define FCGI_GET_VALUES 9
+#define FCGI_GET_VALUES_RESULT 10
+
+/*
+ * FastCGI Handler context, it keeps information of states and other
+ * request/response references.
+ */
+struct fcgi_handler {
+ struct mk_event event; /* built-in event-loop data */
+
+ int server_fd; /* backend FastCGI server */
+ int chunked; /* chunked response ? */
+ int active; /* is this handler active ? */
+ int hangup; /* hangup connection once ready ? */
+ int headers_set; /* headers set ? */
+ int eof; /* exiting: MK_TRUE / MK_FALSE */
+
+ /* stdin data */
+ uint64_t stdin_length;
+ uint64_t stdin_offset;
+ char *stdin_buffer;
+
+ struct mk_http_session *cs; /* HTTP session context */
+ struct mk_http_request *sr; /* HTTP request context */
+
+ /* FastCGI */
+ struct fcgi_begin_request_record header_request;
+
+ uint64_t write_rounds;
+ unsigned int buf_len;
+ char buf_data[FCGI_BUF_SIZE];
+
+ /* Channel to stream request to the FCGI server */
+ struct mk_channel fcgi_channel;
+ struct mk_stream fcgi_stream;
+
+ struct mk_iov *iov;
+ struct mk_list _head;
+
+ /* TCP connection context */
+ struct mk_net_connection *conn;
+};
+
+static inline void fcgi_encode16(void *a, unsigned b)
+{
+ unsigned char *c = a;
+
+ c[0] = (unsigned char) (b >> 8);
+ c[1] = (unsigned char) b;
+}
+
+struct fcgi_handler *fcgi_handler_new(struct mk_plugin *plugin,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr);
+
+int fcgi_exit(struct fcgi_handler *handler);
+
+#endif
diff --git a/fluent-bit/lib/monkey/plugins/liana/ABOUT b/fluent-bit/lib/monkey/plugins/liana/ABOUT
new file mode 100644
index 000000000..1c1407ba4
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/liana/ABOUT
@@ -0,0 +1,4 @@
+Liana Plugin
+============
+Liana gives network layer to Monkey so you can build your own
+network layer for Monkey.
diff --git a/fluent-bit/lib/monkey/plugins/liana/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/liana/CMakeLists.txt
new file mode 100644
index 000000000..1f3797dcd
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/liana/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(src
+ liana.c
+)
+
+MONKEY_PLUGIN(liana "${src}")
diff --git a/fluent-bit/lib/monkey/plugins/liana/MANDATORY b/fluent-bit/lib/monkey/plugins/liana/MANDATORY
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/liana/MANDATORY
diff --git a/fluent-bit/lib/monkey/plugins/liana/Makefile.in b/fluent-bit/lib/monkey/plugins/liana/Makefile.in
new file mode 100644
index 000000000..ef9fd4fc3
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/liana/Makefile.in
@@ -0,0 +1,18 @@
+all: monkey-liana.so
+include ../Make.common
+
+CC = @echo " CC $(_PATH)/$@"; $CC
+CC_QUIET= @echo -n; $CC
+AR = @echo " AR $(_PATH)/$@"; $AR
+CFLAGS = $CFLAGS
+LDFLAGS = $LDFLAGS
+DEFS = $DEFS
+LIANA_OBJECTS = liana.o
+
+-include $(LIANA_OBJECTS:.o=.d)
+
+monkey-liana.so: $(LIANA_OBJECTS)
+ $(CC) $(CFLAGS) $(LDFLAGS) $(DEFS) -shared -o $@ $^ -lc
+
+monkey-liana.a: $(LIANA_OBJECTS)
+ $(AR) rcs $@ $(LIANA_OBJECTS)
diff --git a/fluent-bit/lib/monkey/plugins/liana/README b/fluent-bit/lib/monkey/plugins/liana/README
new file mode 100644
index 000000000..69a4760f9
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/liana/README
@@ -0,0 +1,7 @@
+Liana Networking Plugin
+=======================
+
+Liana is the base network plugin for Monkey, it provides the
+most basic socket calls such as: accept(), read(), write() etc.
+
+Without Liana do not expect a default HTTP Server working :)
diff --git a/fluent-bit/lib/monkey/plugins/liana/STATIC b/fluent-bit/lib/monkey/plugins/liana/STATIC
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/liana/STATIC
diff --git a/fluent-bit/lib/monkey/plugins/liana/liana.c b/fluent-bit/lib/monkey/plugins/liana/liana.c
new file mode 100644
index 000000000..3bfe288b8
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/liana/liana.c
@@ -0,0 +1,221 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#endif
+
+#if defined (__linux__)
+#include <sys/sendfile.h>
+#endif
+
+#include <monkey/mk_api.h>
+
+int mk_liana_plugin_init(struct mk_plugin *plugin, char *confdir)
+{
+ (void) confdir;
+ (void) plugin;
+
+ return 0;
+}
+
+int mk_liana_plugin_exit(struct mk_plugin *plugin)
+{
+ (void) plugin;
+
+ return 0;
+}
+
+int mk_liana_read(struct mk_plugin *plugin, int socket_fd, void *buf, int count)
+{
+ (void) plugin;
+
+ return recv(socket_fd, (void*)buf, count, 0);
+}
+
+int mk_liana_write(struct mk_plugin *plugin, int socket_fd, const void *buf, size_t count )
+{
+ ssize_t bytes_sent = -1;
+
+ (void) plugin;
+
+ bytes_sent = send(socket_fd, buf, count, 0);
+
+ return bytes_sent;
+}
+
+int mk_liana_writev(struct mk_plugin *plugin, int socket_fd, struct mk_iov *mk_io)
+{
+ ssize_t bytes_sent = -1;
+
+ (void) plugin;
+
+ bytes_sent = plugin->api->iov_send(socket_fd, mk_io);
+
+ return bytes_sent;
+}
+
+int mk_liana_close(struct mk_plugin *plugin, int socket_fd)
+{
+ (void) plugin;
+
+#ifdef _WIN32
+ return closesocket(socket_fd);
+#else
+ return close(socket_fd);
+#endif
+}
+
+int mk_liana_send_file(struct mk_plugin *plugin, int socket_fd, int file_fd, off_t *file_offset,
+ size_t file_count)
+{
+ ssize_t ret = -1;
+
+ (void) plugin;
+
+#if defined (__linux__)
+ ret = sendfile(socket_fd, file_fd, file_offset, file_count);
+ if (ret == -1 && errno != EAGAIN) {
+ PLUGIN_TRACE("[FD %i] error from sendfile(): %s",
+ socket_fd, strerror(errno));
+ }
+ return ret;
+#elif defined (__APPLE__)
+ off_t offset = *file_offset;
+ off_t len = (off_t) file_count;
+
+ ret = sendfile(file_fd, socket_fd, offset, &len, NULL, 0);
+ if (ret == -1 && errno != EAGAIN) {
+ PLUGIN_TRACE("[FD %i] error from sendfile(): %s",
+ socket_fd, strerror(errno));
+ }
+ else if (len > 0) {
+ *file_offset += len;
+ return len;
+ }
+ return ret;
+#elif defined (__FreeBSD__)
+ off_t offset = *file_offset;
+ off_t len = (off_t) file_count;
+
+ ret = sendfile(file_fd, socket_fd, offset, len, NULL, 0, 0);
+ if (ret == -1 && errno != EAGAIN) {
+ PLUGIN_TRACE("[FD %i] error from sendfile(): %s",
+ socket_fd, strerror(errno));
+ }
+ else if (len > 0) {
+ *file_offset += len;
+ return len;
+ }
+ return ret;
+#else
+ #pragma message ("This is a terrible sendfile \"implementation\" and just a crutch")
+
+ ssize_t bytes_written = 0;
+ ssize_t to_be_sent = -1;
+ ssize_t send_ret = -1;
+ uint8_t temporary_buffer[1024];
+
+ if (NULL != file_offset) {
+ lseek(file_fd, *file_offset, SEEK_SET);
+ }
+
+ while (1) {
+ memset(temporary_buffer, 0, sizeof(temporary_buffer));
+
+ ret = read(file_fd, temporary_buffer, sizeof(temporary_buffer));
+
+ if (0 == ret)
+ {
+ return bytes_written;
+ }
+ else if (0 > ret)
+ {
+ return -1;
+ }
+ else if (0 < ret)
+ {
+ to_be_sent = ret;
+
+ while (to_be_sent > 0)
+ {
+ send_ret = send(file_fd, &temporary_buffer[ret - to_be_sent], to_be_sent, 0);
+
+ if (-1 == send_ret)
+ {
+ if (EAGAIN != errno &&
+ EWOULDBLOCK != errno)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ bytes_written += send_ret;
+ to_be_sent -= send_ret;
+ }
+ }
+ }
+ }
+#endif
+}
+
+/* Network Layer plugin Callbacks */
+struct mk_plugin_network mk_plugin_network_liana = {
+ .read = mk_liana_read,
+ .write = mk_liana_write,
+ .writev = mk_liana_writev,
+ .close = mk_liana_close,
+ .send_file = mk_liana_send_file,
+ .buffer_size = MK_REQUEST_CHUNK
+};
+
+struct mk_plugin mk_plugin_liana = {
+ /* Identification */
+ .shortname = "liana",
+ .name = "Liana Network Layer",
+ .version = MK_VERSION_STR,
+ .hooks = MK_PLUGIN_NETWORK_LAYER,
+
+ /* Init / Exit */
+ .init_plugin = mk_liana_plugin_init,
+ .exit_plugin = mk_liana_plugin_exit,
+
+ /* Init Levels */
+ .master_init = NULL,
+ .worker_init = NULL,
+
+ /* Type */
+ .network = &mk_plugin_network_liana,
+
+ /* Capabilities */
+ .capabilities = MK_CAP_SOCK_PLAIN
+};
diff --git a/fluent-bit/lib/monkey/plugins/logger/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/logger/CMakeLists.txt
new file mode 100644
index 000000000..156a0847f
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/logger/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(src
+ pointers.c
+ logger.c
+ )
+
+# Validate splice()
+check_c_source_compiles("
+ #define _GNU_SOURCE
+ #include <stdio.h>
+ #include <fcntl.h>
+ int main() {
+ return splice(0, NULL, 1,
+ NULL, 1, SPLICE_F_MOVE);
+ }" HAVE_SPLICE)
+
+if (HAVE_SPLICE)
+ MK_DEFINITION(MK_HAVE_SPLICE)
+endif()
+
+MONKEY_PLUGIN(logger "${src}")
+add_subdirectory(conf)
diff --git a/fluent-bit/lib/monkey/plugins/logger/conf/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/logger/conf/CMakeLists.txt
new file mode 100644
index 000000000..2c4e9b069
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/logger/conf/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(conf_dir "${MK_PATH_CONF}/plugins/logger/")
+
+install(DIRECTORY DESTINATION ${conf_dir})
+configure_file(
+ "${PROJECT_SOURCE_DIR}/plugins/logger/conf/logger.conf.in"
+ "${PROJECT_BINARY_DIR}/conf/plugins/logger/logger.conf"
+ )
+
+if(NOT BUILD_LOCAL)
+ install(FILES ${PROJECT_BINARY_DIR}/conf/plugins/logger/logger.conf DESTINATION ${conf_dir})
+endif()
diff --git a/fluent-bit/lib/monkey/plugins/logger/conf/logger.conf.in b/fluent-bit/lib/monkey/plugins/logger/conf/logger.conf.in
new file mode 100644
index 000000000..5e06a8d6c
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/logger/conf/logger.conf.in
@@ -0,0 +1,22 @@
+# Logger:
+# -------
+# This plugin allows the creation of log files for each request that arrives.
+# It uses an access and error file which are defined inside every virtual
+# host file, this section set just global directives for the plugin.
+
+[LOGGER]
+ # FlushTimeout
+ # ------------
+ # This key define in seconds, the waiting time before to flush the
+ # data to the log file.
+ # Allowed values must be greater than zero (FlushTimeout > 0).
+
+ FlushTimeout 3
+
+ # MasterLog
+ # ---------
+ # This key define a master log file which is used when Monkey runs in daemon
+ # mode, so any Monkey output (stdout) will be redirected to the file
+ # specified here. The server port will be appended to the filename.
+
+ MasterLog @MK_PATH_LOG@/master.log
diff --git a/fluent-bit/lib/monkey/plugins/logger/logger.c b/fluent-bit/lib/monkey/plugins/logger/logger.c
new file mode 100644
index 000000000..4dfcfb001
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/logger/logger.c
@@ -0,0 +1,852 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <monkey/mk_api.h>
+
+/* System Headers */
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* Local Headers */
+#include "logger.h"
+#include "pointers.h"
+
+struct status_response {
+ int i_status;
+ char *s_status;
+};
+
+static struct status_response response_codes[] = {
+ /* Common matches first */
+ {200, "200"}, {404, "404"},
+
+ {100, "100"}, {101, "101"},
+ {201, "201"}, {202, "202"}, {203, "203"}, {204, "204"},
+ {205, "205"}, {206, "206"},
+ {300, "300"}, {301, "301"}, {302, "302"}, {303, "303"}, {304, "304"},
+ {305, "305"},
+ {400, "400"}, {401, "401"}, {402, "402"}, {403, "403"},
+ {405, "405"}, {406, "406"}, {407, "407"}, {408, "408"}, {409, "409"},
+ {410, "410"}, {411, "411"}, {412, "412"}, {413, "413"}, {414, "414"},
+ {415, "415"},
+ {500, "500"}, {501, "501"}, {502, "502"}, {503, "503"}, {504, "504"},
+ {505, "505"},
+};
+
+static struct log_target *mk_logger_match_by_host(struct mk_vhost *host, int is_ok)
+{
+ struct mk_list *head;
+ struct log_target *entry;
+
+ mk_list_foreach(head, &targets_list) {
+ entry = mk_list_entry(head, struct log_target, _head);
+ if (entry->host == host && entry->is_ok == is_ok) {
+ return entry;
+ }
+ }
+
+ return NULL;
+}
+
+static struct iov *mk_logger_get_cache()
+{
+ return pthread_getspecific(cache_iov);
+}
+
+static ssize_t _mk_logger_append(int pipe_fd_in,
+ int file_fd_out,
+ size_t bytes)
+{
+ ssize_t ret;
+#ifdef MK_HAVE_SPLICE
+ ret = splice(pipe_fd_in, NULL, file_fd_out,
+ NULL, bytes, SPLICE_F_MOVE);
+ return ret;
+#else
+ unsigned char buffer[4096];
+ ssize_t buffer_used;
+ size_t bytes_written = 0;
+
+ while (bytes_written < bytes) {
+ ret = read(pipe_fd_in, buffer, sizeof(buffer));
+ if (ret < 0) {
+ break;
+ }
+ buffer_used = ret;
+ ret = write(file_fd_out, buffer, buffer_used);
+ if (ret < 0) {
+ break;
+ }
+ bytes_written += ret;
+ }
+ if (ret < 0 && bytes_written == 0)
+ return -1;
+ else
+ return bytes_written;
+#endif
+}
+
+static void mk_logger_start_worker(void *args)
+{
+ int fd;
+ int bytes, err;
+ int max_events = mk_api->config->nhosts;
+ int flog;
+ int clk;
+ long slen;
+ int timeout;
+ char *target;
+ (void) args;
+ struct mk_list *head;
+ struct log_target *entry;
+ struct mk_event *event;
+ struct mk_event_loop *evl;
+
+ /* pipe_size:
+ * ----------
+ * Linux set a pipe size usingto the PAGE_SIZE,
+ * check linux/include/pipe_fs_i.h for details:
+ *
+ * #define PIPE_SIZE PAGE_SIZE
+ *
+ * In the same header file we can found that every
+ * pipe has 16 pages, so our real memory allocation
+ * is: (PAGE_SIZE*PIPE_BUFFERS)
+ */
+ long pipe_size;
+
+ /* buffer_limit:
+ * -------------
+ * it means the maximum data that a monkey log pipe can contain.
+ */
+ long buffer_limit;
+
+ mk_api->worker_rename("monkey: logger");
+
+ /* Monkey allow just 75% of a pipe capacity */
+ pipe_size = sysconf(_SC_PAGESIZE) * 16;
+ buffer_limit = (pipe_size * MK_LOGGER_PIPE_LIMIT);
+
+ /* Creating poll */
+ evl = mk_api->ev_loop_create(max_events);
+
+ /* Registering targets for virtualhosts */
+ mk_list_foreach(head, &targets_list) {
+ entry = mk_list_entry(head, struct log_target, _head);
+ event = &entry->event;
+ event->mask = MK_EVENT_EMPTY;
+ event->data = entry;
+ event->handler = NULL;
+ event->status = MK_EVENT_NONE;
+
+ /* Add access log file */
+ if (entry->pipe[0] > 0) {
+ event->fd = entry->pipe[0];
+ mk_api->ev_add(evl, entry->pipe[0],
+ MK_EVENT_CONNECTION, MK_EVENT_READ, entry);
+ }
+ }
+
+ /* Set initial timeout */
+ timeout = time(NULL) + mk_logger_timeout;
+
+ /* Reading pipe buffer */
+ while (1) {
+ usleep(1200);
+
+ /* wait for events */
+ mk_api->ev_wait(evl);
+
+ /* get current time */
+ clk = mk_api->time_unix();
+
+ /* translate the backend events triggered */
+ mk_event_foreach(event, evl) {
+ entry = (struct log_target *) event;
+ target = entry->file;
+ fd = entry->pipe[0];
+
+ err = ioctl(fd, FIONREAD, &bytes);
+ if (mk_unlikely(err == -1)){
+ perror("ioctl");
+ }
+
+ if (bytes < buffer_limit && clk <= timeout) {
+ continue;
+ }
+
+ timeout = clk + mk_logger_timeout;
+
+ flog = open(target, O_WRONLY | O_CREAT | O_CLOEXEC, 0644);
+ if (mk_unlikely(flog == -1)) {
+ mk_warn("Could not open logfile '%s' (%s)", target, strerror(errno));
+
+ int consumed = 0;
+ char buf[255];
+ do {
+ slen = read(fd, buf, 255);
+ if (slen > 0) {
+ consumed += slen;
+ }
+ else {
+ break;
+ }
+ } while (consumed < bytes);
+
+ continue;
+ }
+
+ lseek(flog, 0, SEEK_END);
+ slen = _mk_logger_append(fd, flog, bytes);
+ if (mk_unlikely(slen == -1)) {
+ mk_warn("Could not write to log file: splice() = %ld", slen);
+ }
+
+ MK_TRACE("written %i bytes", bytes);
+ close(flog);
+ }
+ }
+}
+
+static int mk_logger_read_config(char *path)
+{
+ int timeout;
+ char *logfilename = NULL;
+ unsigned long len;
+ char *default_file = NULL;
+ struct mk_rconf *conf;
+ struct mk_rconf_section *section;
+
+ mk_api->str_build(&default_file, &len, "%slogger.conf", path);
+ conf = mk_api->config_open(default_file);
+ if (!conf) {
+ return -1;
+ }
+
+ section = mk_api->config_section_get(conf, "LOGGER");
+ if (section) {
+
+ /* FlushTimeout */
+ timeout = (size_t) mk_api->config_section_get_key(section,
+ "FlushTimeout",
+ MK_RCONF_NUM);
+ if (timeout <= 0) {
+ mk_err("FlushTimeout does not have a proper value");
+ exit(EXIT_FAILURE);
+ }
+ mk_logger_timeout = timeout;
+ MK_TRACE("FlushTimeout %i seconds", mk_logger_timeout);
+
+ /* MasterLog */
+ logfilename = mk_api->config_section_get_key(section,
+ "MasterLog",
+ MK_RCONF_STR);
+ if (logfilename == NULL) {
+ mk_err("MasterLog does not have a proper value");
+ exit(EXIT_FAILURE);
+ }
+
+ mk_logger_master_path = logfilename;
+ MK_TRACE("MasterLog '%s'", mk_logger_master_path);
+ }
+
+ mk_api->mem_free(default_file);
+ mk_api->config_free(conf);
+
+ return 0;
+}
+
+static void mk_logger_print_listeners()
+{
+ struct mk_list *head;
+ struct mk_config_listener *listener;
+
+ mk_list_foreach(head, &mk_api->config->listeners) {
+ listener = mk_list_entry(head, struct mk_config_listener, _head);
+ printf(" listen on %s:%s\n",
+ listener->address,
+ listener->port);
+ }
+}
+
+static void mk_logger_print_details(void)
+{
+ time_t now;
+ struct tm *current;
+
+ now = time(NULL);
+ current = localtime(&now);
+ printf("[%i/%02i/%02i %02i:%02i:%02i] Monkey Started\n",
+ current->tm_year + 1900,
+ current->tm_mon + 1,
+ current->tm_mday,
+ current->tm_hour,
+ current->tm_min,
+ current->tm_sec);
+ printf(" version : %s\n", MK_VERSION_STR);
+ printf(" number of workers: %i\n", mk_api->config->workers);
+ mk_logger_print_listeners();
+ fflush(stdout);
+}
+
+int mk_logger_plugin_init(struct plugin_api **api, char *confdir)
+{
+ int fd;
+ mk_api = *api;
+
+ /* Specific thread key */
+ pthread_key_create(&cache_iov, NULL);
+ pthread_key_create(&cache_content_length, NULL);
+ pthread_key_create(&cache_status, NULL);
+ pthread_key_create(&cache_ip_str, NULL);
+
+ /* Global configuration */
+ mk_logger_timeout = MK_LOGGER_TIMEOUT_DEFAULT;
+ mk_logger_master_path = NULL;
+ mk_logger_read_config(confdir);
+
+ /* Check masterlog */
+ if (mk_logger_master_path) {
+ fd = open(mk_logger_master_path, O_WRONLY | O_CREAT | O_CLOEXEC, 0644);
+ if (fd == -1) {
+ mk_err("Could not open/create master logfile %s", mk_logger_master_path);
+ exit(EXIT_FAILURE);
+
+ }
+ else {
+ /* Close test FD for MasterLog */
+ close(fd);
+ }
+ }
+
+ return 0;
+}
+
+int mk_logger_plugin_exit()
+{
+ struct mk_list *head, *tmp;
+ struct log_target *entry;
+
+ mk_list_foreach_safe(head, tmp, &targets_list) {
+ entry = mk_list_entry(head, struct log_target, _head);
+ mk_list_del(&entry->_head);
+ if (entry->pipe[0] > 0) close(entry->pipe[0]);
+ if (entry->pipe[1] > 0) close(entry->pipe[1]);
+ mk_api->mem_free(entry->file);
+ mk_api->mem_free(entry);
+ }
+
+ mk_api->mem_free(mk_logger_master_path);
+
+ return 0;
+}
+
+int mk_logger_master_init(struct mk_server_config *config)
+{
+ int ret;
+ struct log_target *new;
+ struct mk_vhost *entry_host;
+ struct mk_list *hosts = &mk_api->config->hosts;
+ struct mk_list *head_host;
+ struct mk_rconf_section *section;
+ char *access_file_name = NULL;
+ char *error_file_name = NULL;
+ pthread_t tid;
+ (void) config;
+
+ /* Restore STDOUT if we are in background mode */
+ if (mk_logger_master_path != NULL && mk_api->config->is_daemon == MK_TRUE) {
+ mk_logger_master_stdout = freopen(mk_logger_master_path, "ae", stdout);
+ mk_logger_master_stderr = freopen(mk_logger_master_path, "ae", stderr);
+ mk_logger_print_details();
+ }
+
+ MK_TRACE("Reading virtual hosts");
+
+ mk_list_init(&targets_list);
+
+ mk_list_foreach(head_host, hosts) {
+ entry_host = mk_list_entry(head_host, struct mk_vhost, _head);
+
+ /* Read logger section from virtual host configuration */
+ section = mk_api->config_section_get(entry_host->config, "LOGGER");
+ if (section) {
+ /* Read configuration entries */
+ access_file_name = (char *) mk_api->config_section_get_key(section,
+ "AccessLog",
+ MK_RCONF_STR);
+ error_file_name = (char *) mk_api->config_section_get_key(section,
+ "ErrorLog",
+ MK_RCONF_STR);
+
+ if (access_file_name) {
+ new = mk_api->mem_alloc(sizeof(struct log_target));
+ new->is_ok = MK_TRUE;
+
+ /* Set access pipe */
+ if (pipe(new->pipe) < 0) {
+ mk_err("Could not create pipe");
+ exit(EXIT_FAILURE);
+ }
+ if (fcntl(new->pipe[1], F_SETFL, O_NONBLOCK) == -1) {
+ perror("fcntl");
+ }
+ if (fcntl(new->pipe[0], F_SETFD, FD_CLOEXEC) == -1) {
+ perror("fcntl");
+ }
+ if (fcntl(new->pipe[1], F_SETFD, FD_CLOEXEC) == -1) {
+ perror("fcntl");
+ }
+ new->file = access_file_name;
+ new->host = entry_host;
+ mk_list_add(&new->_head, &targets_list);
+ }
+
+ /* Set error pipe */
+ if (error_file_name) {
+ new = mk_api->mem_alloc(sizeof(struct log_target));
+ new->is_ok = MK_FALSE;
+
+ if (pipe(new->pipe) < 0) {
+ mk_err("Could not create pipe");
+ exit(EXIT_FAILURE);
+ }
+ if (fcntl(new->pipe[1], F_SETFL, O_NONBLOCK) == -1) {
+ perror("fcntl");
+ }
+ if (fcntl(new->pipe[0], F_SETFD, FD_CLOEXEC) == -1) {
+ perror("fcntl");
+ }
+ if (fcntl(new->pipe[1], F_SETFD, FD_CLOEXEC) == -1 ){
+ perror("fcntl");
+ }
+ new->file = error_file_name;
+ new->host = entry_host;
+ mk_list_add(&new->_head, &targets_list);
+
+ }
+ }
+ }
+
+ ret = mk_api->worker_spawn((void *) mk_logger_start_worker, NULL, &tid);
+ if (ret == -1) {
+ return -1;
+ }
+
+ return 0;
+}
+
+void mk_logger_worker_init()
+{
+ struct mk_iov *iov_log;
+ mk_ptr_t *content_length;
+ mk_ptr_t *status;
+ mk_ptr_t *ip_str;
+
+
+ MK_TRACE("Creating thread cache");
+
+ /* Cache iov log struct */
+ iov_log = mk_api->iov_create(15, 0);
+ pthread_setspecific(cache_iov, (void *) iov_log);
+
+ /* Cache content length */
+ content_length = mk_api->mem_alloc_z(sizeof(mk_ptr_t));
+ content_length->data = mk_api->mem_alloc_z(MK_UTILS_INT2MKP_BUFFER_LEN);
+ content_length->len = -1;
+ pthread_setspecific(cache_content_length, (void *) content_length);
+
+ /* Cahe status */
+ status = mk_api->mem_alloc_z(sizeof(mk_ptr_t));
+ status->data = mk_api->mem_alloc_z(MK_UTILS_INT2MKP_BUFFER_LEN);
+ status->len = -1;
+ pthread_setspecific(cache_status, (void *) status);
+
+ /* Cache IP address */
+ ip_str = mk_api->mem_alloc_z(sizeof(mk_ptr_t));
+ ip_str->data = mk_api->mem_alloc_z(INET6_ADDRSTRLEN + 1);
+ ip_str->len = -1;
+ pthread_setspecific(cache_ip_str, (void *) ip_str);
+}
+
+int mk_logger_stage40(struct mk_http_session *cs, struct mk_http_request *sr)
+{
+ int i, http_status, ret, tmp;
+ int array_len = ARRAY_SIZE(response_codes);
+ int access;
+ struct log_target *target;
+ struct mk_iov *iov;
+ mk_ptr_t *date;
+ mk_ptr_t *content_length;
+ mk_ptr_t *ip_str;
+ mk_ptr_t status;
+
+ /* Set response status */
+ http_status = sr->headers.status;
+
+ if (http_status < 400) {
+ access = MK_TRUE;
+ }
+ else {
+ access = MK_FALSE;
+ }
+
+ /* Look for target log file */
+ target = mk_logger_match_by_host(sr->host_conf, access);
+ if (!target) {
+ MK_TRACE("No target found");
+ return 0;
+ }
+
+ /* Get iov cache struct and reset indexes */
+ iov = (struct mk_iov *) mk_logger_get_cache();
+ iov->iov_idx = 0;
+ iov->buf_idx = 0;
+ iov->total_len = 0;
+
+ /* Format IP string */
+ ip_str = pthread_getspecific(cache_ip_str);
+ ret = mk_api->socket_ip_str(cs->socket,
+ &ip_str->data,
+ INET6_ADDRSTRLEN + 1,
+ &ip_str->len);
+ /*
+ * If the socket is not longer available ip_str can be null,
+ * so we must check this condition and return
+ */
+ if (mk_unlikely(ret < 0)) {
+ return 0;
+ }
+
+ /* Add IP to IOV */
+ mk_api->iov_add(iov,
+ ip_str->data, ip_str->len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_dash.data,
+ mk_logger_iov_dash.len,
+ MK_FALSE);
+
+ /* Date/time when object was requested */
+ date = mk_api->time_human(cs->server);
+ mk_api->iov_add(iov,
+ date->data, date->len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_space.data,
+ mk_logger_iov_space.len,
+ MK_FALSE);
+
+ /* Access Log */
+ if (http_status < 400) {
+ /* No access file defined */
+ if (!target->file) {
+ return 0;
+ }
+
+ /* HTTP Method */
+ mk_api->iov_add(iov,
+ sr->method_p.data,
+ sr->method_p.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_space.data,
+ mk_logger_iov_space.len,
+ MK_FALSE);
+
+ /* HTTP URI required */
+ mk_api->iov_add(iov,
+ sr->uri.data, sr->uri.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_space.data,
+ mk_logger_iov_space.len,
+ MK_FALSE);
+
+ /* HTTP Protocol */
+ mk_api->iov_add(iov,
+ sr->protocol_p.data, sr->protocol_p.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_space.data,
+ mk_logger_iov_space.len,
+ MK_FALSE);
+
+ /* HTTP Status code response */
+ for (i=0; i < array_len; i++) {
+ if (response_codes[i].i_status == http_status) {
+ break;
+ }
+ }
+
+ if (array_len == i) {
+ mk_api->str_itop(http_status, &status);
+ status.len -= 2;
+ }
+ else {
+ status.data = response_codes[i].s_status;
+ status.len = 3;
+ }
+ mk_api->iov_add(iov,
+ status.data,
+ status.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_space.data,
+ mk_logger_iov_space.len,
+ MK_FALSE);
+
+ /* Content Length */
+ if (sr->method != MK_METHOD_HEAD) {
+ /* Int to mk_ptr_t */
+ content_length = pthread_getspecific(cache_content_length);
+
+ tmp = sr->headers.content_length;
+ if (tmp < 0) {
+ tmp = 0;
+ }
+
+ mk_api->str_itop(tmp, content_length);
+
+ mk_api->iov_add(iov,
+ content_length->data, content_length->len - 2,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_lf.data,
+ mk_logger_iov_lf.len,
+ MK_FALSE);
+ }
+ else {
+ mk_api->iov_add(iov,
+ mk_logger_iov_empty.data,
+ mk_logger_iov_empty.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_lf.data,
+ mk_logger_iov_lf.len,
+ MK_FALSE);
+ }
+
+ /* Write iov array to pipe */
+ mk_api->iov_send(target->pipe[1], iov);
+ }
+ else {
+ if (mk_unlikely(!target->file)) {
+ return 0;
+ }
+
+ /* For unknown errors. Needs to exist until iov_send. */
+ char err_str[80];
+
+ switch (http_status) {
+ case MK_CLIENT_BAD_REQUEST:
+ mk_api->iov_add(iov,
+ error_msg_400.data,
+ error_msg_400.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_lf.data,
+ mk_logger_iov_lf.len,
+ MK_FALSE);
+ break;
+ case MK_CLIENT_FORBIDDEN:
+ mk_api->iov_add(iov,
+ error_msg_403.data,
+ error_msg_403.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_space.data,
+ mk_logger_iov_space.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ sr->uri.data,
+ sr->uri.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_lf.data,
+ mk_logger_iov_lf.len,
+ MK_FALSE);
+
+ break;
+ case MK_CLIENT_NOT_FOUND:
+ mk_api->iov_add(iov,
+ error_msg_404.data,
+ error_msg_404.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_space.data,
+ mk_logger_iov_space.len,
+ MK_FALSE);
+
+ mk_api->iov_add(iov,
+ sr->uri.data,
+ sr->uri.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_lf.data,
+ mk_logger_iov_lf.len,
+ MK_FALSE);
+
+ break;
+ case MK_CLIENT_METHOD_NOT_ALLOWED:
+ mk_api->iov_add(iov,
+ error_msg_405.data,
+ error_msg_405.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_space.data,
+ mk_logger_iov_space.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ sr->method_p.data,
+ sr->method_p.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_lf.data,
+ mk_logger_iov_lf.len,
+ MK_FALSE);
+ break;
+ case MK_CLIENT_REQUEST_TIMEOUT:
+ mk_api->iov_add(iov,
+ error_msg_408.data,
+ error_msg_408.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_lf.data,
+ mk_logger_iov_lf.len,
+ MK_FALSE);
+ break;
+ case MK_CLIENT_LENGTH_REQUIRED:
+ mk_api->iov_add(iov,
+ error_msg_411.data,
+ error_msg_411.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_lf.data,
+ mk_logger_iov_lf.len,
+ MK_FALSE);
+ break;
+ case MK_CLIENT_REQUEST_ENTITY_TOO_LARGE:
+ mk_api->iov_add(iov,
+ error_msg_413.data,
+ error_msg_413.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_lf.data,
+ mk_logger_iov_lf.len,
+ MK_FALSE);
+ break;
+ case MK_SERVER_NOT_IMPLEMENTED:
+ mk_api->iov_add(iov,
+ error_msg_501.data,
+ error_msg_501.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_space.data,
+ mk_logger_iov_space.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ sr->method_p.data,
+ sr->method_p.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_lf.data,
+ mk_logger_iov_lf.len,
+ MK_FALSE);
+ break;
+ case MK_SERVER_INTERNAL_ERROR:
+ mk_api->iov_add(iov,
+ error_msg_500.data,
+ error_msg_500.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_space.data,
+ mk_logger_iov_space.len,
+ MK_FALSE);
+ break;
+ case MK_SERVER_HTTP_VERSION_UNSUP:
+ mk_api->iov_add(iov,
+ error_msg_505.data,
+ error_msg_505.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_lf.data,
+ mk_logger_iov_lf.len,
+ MK_FALSE);
+ break;
+ default:
+ {
+ int len = snprintf(err_str, 80, "[error %u] (no description)", http_status);
+ err_str[79] = '\0';
+ if (len > 79) len = 79;
+
+ mk_api->iov_add(iov,
+ err_str,
+ len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_space.data,
+ mk_logger_iov_space.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ sr->uri.data,
+ sr->uri.len,
+ MK_FALSE);
+ mk_api->iov_add(iov,
+ mk_logger_iov_lf.data,
+ mk_logger_iov_lf.len,
+ MK_FALSE);
+ }
+ break;
+ }
+
+
+ /* Write iov array to pipe */
+ mk_api->iov_send(target->pipe[1], iov);
+ }
+
+ return 0;
+}
+
+struct mk_plugin_stage mk_plugin_stage_logger = {
+ .stage40 = &mk_logger_stage40
+};
+
+struct mk_plugin mk_plugin_logger = {
+ /* Identification */
+ .shortname = "logger",
+ .name = "Log Writer",
+ .version = MK_VERSION_STR,
+ .hooks = MK_PLUGIN_STAGE,
+
+ /* Init / Exit */
+ .init_plugin = mk_logger_plugin_init,
+ .exit_plugin = mk_logger_plugin_exit,
+
+ /* Init Levels */
+ .master_init = mk_logger_master_init,
+ .worker_init = mk_logger_worker_init,
+
+ /* Type */
+ .stage = &mk_plugin_stage_logger
+};
diff --git a/fluent-bit/lib/monkey/plugins/logger/logger.h b/fluent-bit/lib/monkey/plugins/logger/logger.h
new file mode 100644
index 000000000..6c9668bf4
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/logger/logger.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* s_log status */
+#ifndef MK_LOGGER_H
+#define MK_LOGGER_H
+
+#include <stdio.h>
+#include <monkey/mk_api.h>
+
+#define MK_LOGGER_PIPE_LIMIT 0.75
+#define MK_LOGGER_TIMEOUT_DEFAULT 3
+
+int mk_logger_timeout;
+
+/* MasterLog variables */
+char *mk_logger_master_path;
+FILE *mk_logger_master_stdout;
+FILE *mk_logger_master_stderr;
+
+pthread_key_t cache_content_length;
+pthread_key_t cache_status;
+pthread_key_t cache_ip_str;
+pthread_key_t cache_iov;
+
+struct log_target
+{
+ struct mk_event event;
+
+ /* Pipes */
+ int is_ok;
+ int pipe[2];
+ char *file;
+
+ struct mk_vhost *host;
+ struct mk_list _head;
+};
+
+struct mk_list targets_list;
+
+
+#endif
diff --git a/fluent-bit/lib/monkey/plugins/logger/pointers.c b/fluent-bit/lib/monkey/plugins/logger/pointers.c
new file mode 100644
index 000000000..11c48906a
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/logger/pointers.c
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <monkey/mk_plugin.h>
+
+#include "logger.h"
+#include "pointers.h"
+
+const mk_ptr_t mk_logger_iov_none = mk_ptr_init("");
+
+/* Writter helpers */
+const mk_ptr_t mk_logger_iov_dash = mk_ptr_init(MK_LOGGER_IOV_DASH);
+const mk_ptr_t mk_logger_iov_space = mk_ptr_init(MK_IOV_SPACE);
+const mk_ptr_t mk_logger_iov_lf = mk_ptr_init(MK_IOV_LF);
+const mk_ptr_t mk_logger_iov_empty = mk_ptr_init(MK_LOGGER_IOV_EMPTY);
+
+/* Error messages */
+const mk_ptr_t error_msg_400 = mk_ptr_init(ERROR_MSG_400);
+const mk_ptr_t error_msg_403 = mk_ptr_init(ERROR_MSG_403);
+const mk_ptr_t error_msg_404 = mk_ptr_init(ERROR_MSG_404);
+const mk_ptr_t error_msg_405 = mk_ptr_init(ERROR_MSG_405);
+const mk_ptr_t error_msg_408 = mk_ptr_init(ERROR_MSG_408);
+const mk_ptr_t error_msg_411 = mk_ptr_init(ERROR_MSG_411);
+const mk_ptr_t error_msg_413 = mk_ptr_init(ERROR_MSG_413);
+const mk_ptr_t error_msg_500 = mk_ptr_init(ERROR_MSG_500);
+const mk_ptr_t error_msg_501 = mk_ptr_init(ERROR_MSG_501);
+const mk_ptr_t error_msg_505 = mk_ptr_init(ERROR_MSG_505);
diff --git a/fluent-bit/lib/monkey/plugins/logger/pointers.h b/fluent-bit/lib/monkey/plugins/logger/pointers.h
new file mode 100644
index 000000000..d353c2583
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/logger/pointers.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MK_LOGGER_POINTERS_H
+#define MK_LOGGER_POINTERS_H
+
+#include <memory.h>
+
+/* Request error messages for log file */
+#define ERROR_MSG_400 "[error 400] Bad Request"
+#define ERROR_MSG_403 "[error 403] Forbidden"
+#define ERROR_MSG_404 "[error 404] Not Found"
+#define ERROR_MSG_405 "[error 405] Method Not Allowed"
+#define ERROR_MSG_408 "[error 408] Request Timeout"
+#define ERROR_MSG_411 "[error 411] Length Required"
+#define ERROR_MSG_413 "[error 413] Request Entity Too Large"
+#define ERROR_MSG_500 "[error 500] Internal Server Error"
+#define ERROR_MSG_501 "[error 501] Not Implemented"
+#define ERROR_MSG_505 "[error 505] HTTP Version Not Supported"
+
+#define MK_LOGGER_IOV_DASH " - "
+#define MK_LOGGER_IOV_SPACE " "
+#define MK_LOGGER_IOV_EMPTY "-"
+
+/* mk pointers for errors */
+extern const mk_ptr_t error_msg_400;
+extern const mk_ptr_t error_msg_403;
+extern const mk_ptr_t error_msg_404;
+extern const mk_ptr_t error_msg_405;
+extern const mk_ptr_t error_msg_408;
+extern const mk_ptr_t error_msg_411;
+extern const mk_ptr_t error_msg_413;
+extern const mk_ptr_t error_msg_500;
+extern const mk_ptr_t error_msg_501;
+extern const mk_ptr_t error_msg_505;
+
+/* mk pointer for IOV */
+extern const mk_ptr_t mk_logger_iov_dash;
+extern const mk_ptr_t mk_logger_iov_space;
+extern const mk_ptr_t mk_logger_iov_lf;
+extern const mk_ptr_t mk_logger_iov_empty;
+
+#endif
diff --git a/fluent-bit/lib/monkey/plugins/mandril/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/mandril/CMakeLists.txt
new file mode 100644
index 000000000..ba2e95717
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/mandril/CMakeLists.txt
@@ -0,0 +1,6 @@
+set(src
+ mandril.c
+ )
+
+MONKEY_PLUGIN(mandril "${src}")
+add_subdirectory(conf)
diff --git a/fluent-bit/lib/monkey/plugins/mandril/conf/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/mandril/conf/CMakeLists.txt
new file mode 100644
index 000000000..44e95175c
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/mandril/conf/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(conf_dir "${MK_PATH_CONF}/plugins/mandril/")
+
+install(DIRECTORY DESTINATION ${conf_dir})
+
+if(BUILD_LOCAL)
+ file(COPY mandril.conf DESTINATION ${conf_dir})
+else()
+ install(FILES mandril.conf DESTINATION ${conf_dir})
+endif()
diff --git a/fluent-bit/lib/monkey/plugins/mandril/conf/mandril.conf b/fluent-bit/lib/monkey/plugins/mandril/conf/mandril.conf
new file mode 100644
index 000000000..efeaf5d9a
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/mandril/conf/mandril.conf
@@ -0,0 +1,57 @@
+# Monkey HTTP Daemon - Mandril
+# ============================
+# Mandril Plugin provide security rules to be applied to the incomming
+# connections. If the client is rejected by some rule, it will get the
+# 403 Forbidden error status.
+#
+# It supports two restriction modes, by request URI and by IP (or network
+# range), make sure all your rules are defined under the section [RULES]:
+#
+# a) Restriction by request URI:
+#
+# You can define multiple keywords to restrict a specific incoming
+# request which hold that string. Check this example:
+#
+# [RULES]
+# URL documents
+# URL pictures
+# URL /private
+#
+# b) Restriction by IP or network range:
+#
+# Multiple rules can be defined to deny the access to specific incoming
+# clients:
+#
+# [RULES]
+# IP 10.20.1.1/24
+# IP 192.168.3.150
+#
+# In the first rule we are blocking a range of IPs from 10.20.1.1 to
+# 10.20.1.255. In the second example just one specific IP address.
+#
+# It also supports denying hotlinking from other domains.
+#
+# c)
+#
+# [RULES]
+# deny_hotlink /imgs
+#
+# This rule will prevent access to all files under /imgs if the
+# request's Referer header is not from the same domain or its
+# subdomains.
+# If the Referer header is missing, the request will be accepted.
+#
+# You can mix the rules type under the [RULE] section, so the following example
+# is totally valid:
+#
+# [RULES]
+# URL documents
+# URL pictures
+# URL /private
+# IP 10.20.1.1/24
+# IP 192.168.3.150
+#
+
+[RULES]
+ # IP 127.0.0.1
+ # URL /imgs
diff --git a/fluent-bit/lib/monkey/plugins/mandril/mandril.c b/fluent-bit/lib/monkey/plugins/mandril/mandril.c
new file mode 100644
index 000000000..e8a988d08
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/mandril/mandril.c
@@ -0,0 +1,403 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ * Copyright 2012, Sonny Karlsson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Monkey API */
+#include <monkey/mk_api.h>
+
+
+/* system */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/stat.h>
+
+#include "mandril.h"
+
+static struct mk_rconf *conf;
+
+/* Read database configuration parameters */
+static int mk_security_conf(struct mk_plugin *plugin, char *confdir)
+{
+ int n;
+ int ret = 0;
+ unsigned long len;
+ char *conf_path = NULL;
+ char *_net, *_mask;
+
+ struct mk_secure_ip_t *new_ip;
+ struct mk_secure_url_t *new_url;
+ struct mk_secure_deny_hotlink_t *new_deny_hotlink;
+
+ struct mk_rconf_section *section;
+ struct mk_rconf_entry *entry;
+ struct mk_list *head;
+
+ /* Read configuration */
+ plugin->api->str_build(&conf_path, &len, "%s/mandril.conf", confdir);
+ conf = plugin->api->config_open(conf_path);
+ if (!conf) {
+ return -1;
+ }
+
+ section = plugin->api->config_section_get(conf, "RULES");
+ if (!section) {
+ return -1;
+ }
+
+ mk_list_foreach(head, &section->entries) {
+ entry = mk_list_entry(head, struct mk_rconf_entry, _head);
+
+ /* Passing to internal struct */
+ if (strcasecmp(entry->key, "IP") == 0) {
+ new_ip = plugin->api->mem_alloc(sizeof(struct mk_secure_ip_t));
+ n = plugin->api->str_search(entry->val, "/", 1);
+
+ /* subnet */
+ if (n > 0) {
+ /* split network addr and netmask */
+ _net = plugin->api->str_copy_substr(entry->val, 0, n);
+ _mask = plugin->api->str_copy_substr(entry->val,
+ n + 1,
+ strlen(entry->val));
+
+ /* validations... */
+ if (!_net || !_mask) {
+ mk_warn_ex(plugin->api,
+ "Mandril: cannot parse entry '%s' in RULES section",
+ entry->val);
+ goto ip_next;
+ }
+
+ /* convert ip string to network address */
+ if (inet_aton(_net, &new_ip->ip) == 0) {
+ mk_warn_ex(plugin->api,
+ "Mandril: invalid ip address '%s' in RULES section",
+ entry->val);
+ goto ip_next;
+ }
+
+ /* parse mask */
+ new_ip->netmask = strtol(_mask, (char **) NULL, 10);
+ if (new_ip->netmask <= 0 || new_ip->netmask >= 32) {
+ mk_warn_ex(plugin->api,
+ "Mandril: invalid mask value '%s' in RULES section",
+ entry->val);
+ goto ip_next;
+ }
+
+ /* complete struct data */
+ new_ip->is_subnet = MK_TRUE;
+ new_ip->network = MK_NET_NETWORK(new_ip->ip.s_addr, new_ip->netmask);
+ new_ip->hostmin = MK_NET_HOSTMIN(new_ip->ip.s_addr, new_ip->netmask);
+ new_ip->hostmax = MK_NET_HOSTMAX(new_ip->ip.s_addr, new_ip->netmask);
+
+ /* link node with main list */
+ mk_list_add(&new_ip->_head, &mk_secure_ip);
+
+ /*
+ * I know, you were instructed to hate 'goto' statements!, ok, show this
+ * code to your teacher and let him blame :P
+ */
+ ip_next:
+ if (_net) {
+ plugin->api->mem_free(_net);
+ }
+ if (_mask) {
+ plugin->api->mem_free(_mask);
+ }
+ }
+ else { /* normal IP address */
+
+ /* convert ip string to network address */
+ if (inet_aton(entry->val, &new_ip->ip) == 0) {
+ mk_warn_ex(plugin->api,
+ "Mandril: invalid ip address '%s' in RULES section",
+ entry->val);
+ }
+ else {
+ new_ip->is_subnet = MK_FALSE;
+ mk_list_add(&new_ip->_head, &mk_secure_ip);
+ }
+ }
+ }
+ else if (strcasecmp(entry->key, "URL") == 0) {
+ /* simple allcotion and data association */
+ new_url = plugin->api->mem_alloc(sizeof(struct mk_secure_url_t));
+ new_url->criteria = entry->val;
+
+ /* link node with main list */
+ mk_list_add(&new_url->_head, &mk_secure_url);
+ }
+ else if (strcasecmp(entry->key, "deny_hotlink") == 0) {
+ new_deny_hotlink = plugin->api->mem_alloc(sizeof(*new_deny_hotlink));
+ new_deny_hotlink->criteria = entry->val;
+
+ mk_list_add(&new_deny_hotlink->_head, &mk_secure_deny_hotlink);
+ }
+ }
+
+ plugin->api->mem_free(conf_path);
+
+ return ret;
+}
+
+static int mk_security_check_ip(int socket)
+{
+ int network;
+ struct mk_secure_ip_t *entry;
+ struct mk_list *head;
+ struct in_addr *addr;
+ struct sockaddr_in addr_t = {0};
+ socklen_t len = sizeof(addr_t);
+
+ if (getpeername(socket, (struct sockaddr *) &addr_t, &len) != 0) {
+ perror("getpeername");
+ return -1;
+ }
+
+ addr = &(addr_t).sin_addr;
+
+ PLUGIN_TRACE("[FD %i] Mandril validating IP address", socket);
+ mk_list_foreach(head, &mk_secure_ip) {
+ entry = mk_list_entry(head, struct mk_secure_ip_t, _head);
+
+ if (entry->is_subnet == MK_TRUE) {
+ /* Validate network */
+ network = MK_NET_NETWORK(addr->s_addr, entry->netmask);
+ if (network != entry->network) {
+ continue;
+ }
+ /* Validate host range */
+ if (addr->s_addr <= entry->hostmax && addr->s_addr >= entry->hostmin) {
+ PLUGIN_TRACE("[FD %i] Mandril closing by rule in ranges", socket);
+ return -1;
+ }
+ }
+ else {
+ if (addr->s_addr == entry->ip.s_addr) {
+ PLUGIN_TRACE("[FD %i] Mandril closing by rule in IP match", socket);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Check if the incoming URL is restricted for some rule */
+static int mk_security_check_url(struct mk_plugin *plugin, mk_ptr_t url)
+{
+ int n;
+ struct mk_list *head;
+ struct mk_secure_url_t *entry;
+
+ mk_list_foreach(head, &mk_secure_url) {
+ entry = mk_list_entry(head, struct mk_secure_url_t, _head);
+ n = plugin->api->str_search_n(url.data, entry->criteria, MK_STR_INSENSITIVE, url.len);
+ if (n >= 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+mk_ptr_t parse_referer_host(struct mk_http_header *header)
+{
+ unsigned int i, beginHost, endHost;
+ mk_ptr_t host;
+
+ host.data = NULL;
+ host.len = 0;
+
+ // Find end of "protocol://"
+ for (i = 0; i < header->val.len && !(header->val.data[i] == '/' && header->val.data[i+1] == '/'); i++);
+ if (i == header->val.len) {
+ goto error;
+ }
+ beginHost = i + 2;
+
+ // Find end of any "user:password@"
+ for (; i < header->val.len && header->val.data[i] != '@'; i++);
+ if (i < header->val.len) {
+ beginHost = i + 1;
+ }
+
+ // Find end of "host", (beginning of :port or /path)
+ for (i = beginHost; i < header->val.len && header->val.data[i] != ':' && header->val.data[i] != '/'; i++);
+ endHost = i;
+
+ host.data = header->val.data + beginHost;
+ host.len = endHost - beginHost;
+ return host;
+error:
+ host.data = NULL;
+ host.len = 0;
+ return host;
+}
+
+static int mk_security_check_hotlink(struct mk_plugin *plugin,
+ mk_ptr_t url, mk_ptr_t host,
+ struct mk_http_header *referer)
+{
+ mk_ptr_t ref_host = parse_referer_host(referer);
+ unsigned int domains_matched = 0;
+ int i = 0;
+ const char *curA, *curB;
+ struct mk_list *head;
+ struct mk_secure_deny_hotlink_t *entry;
+
+ if (ref_host.data == NULL) {
+ return 0;
+ }
+ else if (host.data == NULL) {
+ mk_err_ex(plugin->api, "No host data.");
+ return -1;
+ }
+
+ mk_list_foreach(head, &mk_secure_url) {
+ entry = mk_list_entry(head, struct mk_secure_deny_hotlink_t, _head);
+ i = plugin->api->str_search_n(url.data, entry->criteria, MK_STR_INSENSITIVE, url.len);
+ if (i >= 0) {
+ break;
+ }
+ }
+ if (i < 0) {
+ return 0;
+ }
+
+ curA = host.data + host.len;
+ curB = ref_host.data + ref_host.len;
+
+ // Match backwards from root domain.
+ while (curA > host.data && curB > ref_host.data) {
+ i++;
+ curA--;
+ curB--;
+
+ if ((*curA == '.' && *curB == '.') ||
+ curA == host.data || curB == ref_host.data) {
+ if (i < 1) {
+ break;
+ }
+ else if (curA == host.data &&
+ !(curB == ref_host.data || *(curB - 1) == '.')) {
+ break;
+ }
+ else if (curB == ref_host.data &&
+ !(curA == host.data || *(curA - 1) == '.')) {
+ break;
+ }
+ else if (strncasecmp(curA, curB, i)) {
+ break;
+ }
+ domains_matched += 1;
+ i = 0;
+ }
+ }
+
+ // Block connection if none or only top domain matched.
+ return domains_matched >= 2 ? 0 : -1;
+}
+
+int mk_mandril_plugin_init(struct mk_plugin *plugin, char *confdir)
+{
+ /* Init security lists */
+ mk_list_init(&mk_secure_ip);
+ mk_list_init(&mk_secure_url);
+ mk_list_init(&mk_secure_deny_hotlink);
+
+ /* Read configuration */
+ mk_security_conf(plugin, confdir);
+
+ return 0;
+}
+
+int mk_mandril_plugin_exit()
+{
+ return 0;
+}
+
+int mk_mandril_stage10(int socket)
+{
+ /* Validate ip address with Mandril rules */
+ if (mk_security_check_ip(socket) != 0) {
+ PLUGIN_TRACE("[FD %i] Mandril close connection", socket);
+ return MK_PLUGIN_RET_CLOSE_CONX;
+ }
+
+ return MK_PLUGIN_RET_CONTINUE;
+}
+
+int mk_mandril_stage30(struct mk_plugin *p,
+ struct mk_http_session *cs,
+ struct mk_http_request *sr,
+ int n_params,
+ struct mk_list *params)
+{
+ (void) p;
+ (void) cs;
+ (void) n_params;
+ (void) params;
+
+ struct mk_http_header *header;
+
+ PLUGIN_TRACE("[FD %i] Mandril validating URL", cs->socket);
+
+ if (mk_security_check_url(p, sr->uri_processed) < 0) {
+ PLUGIN_TRACE("[FD %i] Close connection, blocked URL", cs->socket);
+ p->api->header_set_http_status(sr, MK_CLIENT_FORBIDDEN);
+ return MK_PLUGIN_RET_CLOSE_CONX;
+ }
+
+ PLUGIN_TRACE("[FD %d] Mandril validating hotlinking", cs->socket);
+
+ header = p->api->header_get(MK_HEADER_REFERER, sr, NULL, 0);
+ if (mk_security_check_hotlink(p, sr->uri_processed, sr->host, header) < 0) {
+ PLUGIN_TRACE("[FD %i] Close connection, deny hotlinking.", cs->socket);
+ p->api->header_set_http_status(sr, MK_CLIENT_FORBIDDEN);
+ return MK_PLUGIN_RET_CLOSE_CONX;
+ }
+
+ return MK_PLUGIN_RET_NOT_ME;
+}
+
+struct mk_plugin_stage mk_plugin_stage_mandril = {
+ .stage10 = &mk_mandril_stage10,
+ .stage30 = &mk_mandril_stage30
+};
+
+struct mk_plugin mk_plugin_mandril = {
+ /* Identification */
+ .shortname = "mandril",
+ .name = "Mandril Security",
+ .version = MK_VERSION_STR,
+ .hooks = MK_PLUGIN_STAGE,
+
+ /* Init / Exit */
+ .init_plugin = mk_mandril_plugin_init,
+ .exit_plugin = mk_mandril_plugin_exit,
+
+ /* Init Levels */
+ .master_init = NULL,
+ .worker_init = NULL,
+
+ /* Type */
+ .stage = &mk_plugin_stage_mandril
+};
diff --git a/fluent-bit/lib/monkey/plugins/mandril/mandril.h b/fluent-bit/lib/monkey/plugins/mandril/mandril.h
new file mode 100644
index 000000000..6cadf3857
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/mandril/mandril.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ * Copyright 2012, Sonny Karlsson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* security.c */
+#ifndef MK_SECURITY_H
+#define MK_SECURITY_H
+
+struct mk_secure_ip_t
+{
+ struct in_addr ip;
+
+ /* if subnet is true, next fields are populated */
+ int is_subnet;
+
+ int network;
+ int netmask;
+ unsigned int hostmin;
+ unsigned int hostmax;
+
+ /* list head linker */
+ struct mk_list _head;
+};
+
+struct mk_secure_url_t
+{
+ char *criteria;
+ struct mk_list _head;
+};
+
+struct mk_secure_deny_hotlink_t
+{
+ char *criteria;
+ struct mk_list _head;
+};
+
+struct mk_list mk_secure_ip;
+struct mk_list mk_secure_url;
+struct mk_list mk_secure_deny_hotlink;
+
+#endif
diff --git a/fluent-bit/lib/monkey/plugins/tls/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/tls/CMakeLists.txt
new file mode 100644
index 000000000..2bde86cac
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/tls/CMakeLists.txt
@@ -0,0 +1,17 @@
+set(src
+ tls.c
+)
+
+if(NOT WITH_MBEDTLS_SHARED)
+ option(ENABLE_TESTING OFF)
+ option(ENABLE_PROGRAMS OFF)
+ option(INSTALL_MBEDTLS_HEADERS OFF)
+ set(MK_MBEDTLS_SRC ../../deps/mbedtls-2.4.2)
+ add_subdirectory(${MK_MBEDTLS_SRC} ${CMAKE_BINARY_DIR}/mbedtls-2.4.2)
+ include_directories(${MK_MBEDTLS_SRC}/include)
+endif()
+
+MONKEY_PLUGIN(tls "${src}")
+
+MONKEY_PLUGIN_LINK_LIB(tls mbedtls)
+add_subdirectory(conf)
diff --git a/fluent-bit/lib/monkey/plugins/tls/conf/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/tls/conf/CMakeLists.txt
new file mode 100644
index 000000000..c1886d340
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/tls/conf/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(conf_dir "${MK_PATH_CONF}/plugins/tls/")
+
+install(DIRECTORY DESTINATION ${conf_dir})
+
+if(BUILD_LOCAL)
+ file(COPY tls.conf DESTINATION ${conf_dir})
+else()
+ install(FILES tls.conf DESTINATION ${conf_dir})
+endif()
diff --git a/fluent-bit/lib/monkey/plugins/tls/conf/tls.conf b/fluent-bit/lib/monkey/plugins/tls/conf/tls.conf
new file mode 100644
index 000000000..fcf00517a
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/tls/conf/tls.conf
@@ -0,0 +1,25 @@
+[TLS]
+ # If no absolute path is given, files are assumed to be located
+ # in plugin configuration directory. All files are assumed to be
+ # stored in PEM format.
+
+ # Server certificate
+ #
+ CertificateFile srv_cert.pem
+
+ # Certificate chain
+ #
+ # Not required, but can speed-up handshakes.
+ #
+ # CertificateChainFile srv_cert_chain.pem
+
+ # Server RSA key
+ #
+ RSAKeyFile rsa_key.pem
+
+ # Diffie-Hellman parameters
+ #
+ # Generate using openssl:
+ # $ openssl dhparam -out dhparam.pem 1024
+ #
+ DHParameterFile dhparam.pem
diff --git a/fluent-bit/lib/monkey/plugins/tls/tls.c b/fluent-bit/lib/monkey/plugins/tls/tls.c
new file mode 100644
index 000000000..94c2afc58
--- /dev/null
+++ b/fluent-bit/lib/monkey/plugins/tls/tls.c
@@ -0,0 +1,862 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Monkey HTTP Server
+ * ==================
+ * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <pthread.h>
+
+#include <mbedtls/version.h>
+#include <mbedtls/error.h>
+#include <mbedtls/net.h>
+#include <mbedtls/ssl.h>
+#include <mbedtls/bignum.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/certs.h>
+#include <mbedtls/x509.h>
+#include <mbedtls/ssl_cache.h>
+#include <mbedtls/pk.h>
+#include <mbedtls/dhm.h>
+#include <monkey/mk_api.h>
+
+#ifndef SENDFILE_BUF_SIZE
+#define SENDFILE_BUF_SIZE MBEDTLS_SSL_MAX_CONTENT_LEN
+#endif
+
+#ifndef POLAR_DEBUG_LEVEL
+#define POLAR_DEBUG_LEVEL 0
+#endif
+
+#if (!defined(MBEDTLS_BIGNUM_C) || !defined(MBEDTLS_ENTROPY_C) || \
+ !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_SRV_C) || \
+ !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_RSA_C) || \
+ !defined(MBEDTLS_CTR_DRBG_C))
+#error "One or more required POLARSSL modules not built."
+#endif
+
+struct polar_config {
+ char *cert_file;
+ char *cert_chain_file;
+ char *key_file;
+ char *dh_param_file;
+ int8_t check_client_cert;
+};
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+struct polar_sessions {
+ pthread_mutex_t _mutex;
+ mbedtls_ssl_cache_context cache;
+};
+
+static struct polar_sessions global_sessions = {
+ ._mutex = PTHREAD_MUTEX_INITIALIZER,
+};
+
+#endif
+
+struct polar_context_head {
+ mbedtls_ssl_context context;
+ int fd;
+ struct polar_context_head *_next;
+};
+
+struct polar_thread_context {
+
+ struct polar_context_head *contexts;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_pk_context pkey;
+ mbedtls_ssl_config conf;
+
+ struct mk_list _head;
+};
+
+struct polar_server_context {
+
+ struct polar_config config;
+ mbedtls_x509_crt cert;
+ mbedtls_x509_crt ca_cert;
+ pthread_mutex_t mutex;
+ mbedtls_dhm_context dhm;
+ mbedtls_entropy_context entropy;
+ struct polar_thread_context threads;
+};
+
+struct polar_server_context *server_context;
+static const char *my_dhm_P = MBEDTLS_DHM_RFC5114_MODP_2048_P;
+static const char *my_dhm_G = MBEDTLS_DHM_RFC5114_MODP_2048_G;
+
+static pthread_key_t local_context;
+
+/*
+ * The following function is taken from PolarSSL sources to get
+ * the number of available bytes to read from a buffer.
+ *
+ * We copy this to make it inline and avoid extra context switches
+ * on each read routine.
+ */
+static inline size_t polar_get_bytes_avail(const mbedtls_ssl_context *ssl)
+{
+ return (ssl->in_offt == NULL ? 0 : ssl->in_msglen);
+}
+
+static struct polar_thread_context *local_thread_context(void)
+{
+ return pthread_getspecific(local_context);
+}
+
+#if (POLAR_DEBUG_LEVEL > 0)
+static void polar_debug(void *ctx, int level, const char *str)
+{
+ (void)ctx;
+
+ if (level < POLAR_DEBUG_LEVEL) {
+ mk_warn("%.*s", (int)strlen(str) - 1, str);
+ }
+}
+#endif
+
+static int handle_return(int ret)
+{
+#if defined(TRACE)
+ char err_buf[72];
+ if (ret < 0) {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ PLUGIN_TRACE("[tls] SSL error: %s", err_buf);
+ }
+#endif
+ if (ret < 0) {
+ switch( ret )
+ {
+ case MBEDTLS_ERR_SSL_WANT_READ:
+ case MBEDTLS_ERR_SSL_WANT_WRITE:
+ if (errno != EAGAIN)
+ errno = EAGAIN;
+ return -1;
+ case MBEDTLS_ERR_SSL_CONN_EOF:
+ return 0;
+ default:
+ if (errno == EAGAIN)
+ errno = 0;
+ return -1;
+ }
+ }
+ else {
+ return ret;
+ }
+}
+
+static int tls_cache_get(void *p, mbedtls_ssl_session *session)
+{
+ struct polar_sessions *session_cache;
+ int ret;
+
+ session_cache = p;
+ pthread_mutex_lock(&session_cache->_mutex);
+ ret = mbedtls_ssl_cache_get(&session_cache->cache, session);
+ pthread_mutex_unlock(&session_cache->_mutex);
+
+ return ret;
+}
+
+static int tls_cache_set(void *p, const mbedtls_ssl_session *session)
+{
+ struct polar_sessions *session_cache;
+ int ret;
+
+ session_cache = p;
+ pthread_mutex_lock(&session_cache->_mutex);
+ ret = mbedtls_ssl_cache_set(&session_cache->cache, session);
+ pthread_mutex_unlock(&session_cache->_mutex);
+
+ return ret;
+}
+
+static int config_parse(const char *confdir, struct polar_config *conf)
+{
+ long unsigned int len;
+ char *conf_path = NULL;
+ char *cert_file = NULL;
+ char *cert_chain_file = NULL;
+ char *key_file = NULL;
+ char *dh_param_file = NULL;
+ int8_t check_client_cert = MK_FALSE;
+ struct mk_rconf_section *section;
+ struct mk_rconf *conf_head;
+
+ mk_api->str_build(&conf_path, &len, "%stls.conf", confdir);
+ conf_head = mk_api->config_open(conf_path);
+ mk_api->mem_free(conf_path);
+
+ if (conf_head == NULL) {
+ goto fallback;
+ }
+
+ section = mk_api->config_section_get(conf_head, "TLS");
+ if (!section) {
+ goto fallback;
+ }
+
+ cert_file = mk_api->config_section_get_key(section,
+ "CertificateFile",
+ MK_RCONF_STR);
+ cert_chain_file = mk_api->config_section_get_key(section,
+ "CertificateChainFile",
+ MK_RCONF_STR);
+ key_file = mk_api->config_section_get_key(section,
+ "RSAKeyFile",
+ MK_RCONF_STR);
+ dh_param_file = mk_api->config_section_get_key(section,
+ "DHParameterFile",
+ MK_RCONF_STR);
+
+ check_client_cert = mk_api->config_section_get_key(section,
+ "CheckClientCert",
+ MK_RCONF_BOOL);
+fallback:
+ /* Set default name if not specified */
+ if (!cert_file) {
+ mk_api->str_build(&conf->cert_file, &len,
+ "%ssrv_cert.pem", confdir);
+ }
+ else {
+ /* Set absolute path or compose a new one based on the relative */
+ if (*cert_file == '/') {
+ conf->cert_file = cert_file;
+ }
+ else {
+ mk_api->str_build(&conf->cert_file, &len,
+ "%s/%s", confdir, cert_file);
+ }
+ }
+
+ /* Set default name if not specified */
+ if (cert_chain_file) {
+ /* Set absolute path or compose a new one based on the relative */
+ if (*cert_chain_file == '/') {
+ conf->cert_chain_file = cert_chain_file;
+ }
+ else {
+ mk_api->str_build(&conf->cert_chain_file, &len,
+ "%s/%s", confdir, cert_chain_file);
+ }
+ }
+ else {
+ conf->cert_chain_file = NULL;
+ }
+
+ /* Set default name if not specified */
+ if (!key_file) {
+ mk_api->str_build(&conf->key_file, &len,
+ "%srsa.pem", confdir);
+ }
+ else {
+ /* Set absolute path or compose a new one based on the relative */
+ if (*key_file == '/') {
+ conf->key_file = key_file;
+ }
+ else {
+ mk_api->str_build(&conf->key_file, &len,
+ "%s/%s", confdir, key_file);
+ }
+ }
+
+ /* Set default name if not specified */
+ if (!dh_param_file) {
+ mk_api->str_build(&conf->dh_param_file, &len,
+ "%sdhparam.pem", confdir);
+ }
+ else {
+ /* Set absolute path or compose a new one based on the relative */
+ if (*dh_param_file == '/') {
+ conf->dh_param_file = dh_param_file;
+ }
+ else {
+ mk_api->str_build(&conf->dh_param_file, &len,
+ "%s/%s", confdir, dh_param_file);
+ }
+ }
+
+ /* Set client cert check */
+ conf->check_client_cert = check_client_cert;
+
+ if (conf_head) {
+ mk_api->config_free(conf_head);
+ }
+
+ return 0;
+}
+
+static int polar_load_certs(const struct polar_config *conf)
+{
+ char err_buf[72];
+ int ret = -1;
+
+ ret = mbedtls_x509_crt_parse_file(&server_context->cert, conf->cert_file);
+ if (ret < 0) {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ mk_warn("[tls] Load cert '%s' failed: %s",
+ conf->cert_file,
+ err_buf);
+
+#if defined(MBEDTLS_CERTS_C)
+ mk_warn("[tls] Using test certificates, "
+ "please set 'CertificateFile' in tls.conf");
+
+ ret = mbedtls_x509_crt_parse(&server_context->cert,
+ (unsigned char *)mbedtls_test_srv_crt, strlen(mbedtls_test_srv_crt));
+
+ if (ret) {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ mk_warn("[tls] Load built-in cert failed: %s", err_buf);
+ return -1;
+ }
+
+ return 0;
+#else
+ return -1;
+#endif // defined(MBEDTLS_CERTS_C)
+ }
+ else if (conf->cert_chain_file != NULL) {
+ ret = mbedtls_x509_crt_parse_file(&server_context->ca_cert,
+ conf->cert_chain_file);
+
+ if (ret) {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ mk_warn("[tls] Load cert chain '%s' failed: %s",
+ conf->cert_chain_file,
+ err_buf);
+ }
+ }
+
+ return 0;
+}
+
+static int polar_load_key(struct polar_thread_context *thread_context,
+ const struct polar_config *conf)
+{
+ char err_buf[72];
+ int ret;
+
+ assert(conf->key_file);
+
+ ret = mbedtls_pk_parse_keyfile(&thread_context->pkey, conf->key_file, NULL);
+ if (ret < 0) {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ MK_TRACE("[tls] Load key '%s' failed: %s",
+ conf->key_file,
+ err_buf);
+
+#if defined(MBEDTLS_CERTS_C)
+
+ ret = mbedtls_pk_parse_key(&thread_context->pkey,
+ (unsigned char *)mbedtls_test_srv_key,
+ strlen(mbedtls_test_srv_key), NULL, 0);
+ if (ret) {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ mk_err("[tls] Failed to load built-in RSA key: %s", err_buf);
+ return -1;
+ }
+#else
+ return -1;
+#endif // defined(MBEDTLS_CERTS_C)
+ }
+ return 0;
+}
+
+static int polar_load_dh_param(const struct polar_config *conf)
+{
+ char err_buf[72];
+ int ret;
+
+ assert(conf->dh_param_file);
+
+ ret = mbedtls_dhm_parse_dhmfile(&server_context->dhm, conf->dh_param_file);
+ if (ret < 0) {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+
+ ret = mbedtls_mpi_read_string(&server_context->dhm.P, 16, my_dhm_P);
+ if (ret < 0) {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ mk_err("[tls] Load DH parameter failed: %s", err_buf);
+ return -1;
+ }
+ ret = mbedtls_mpi_read_string(&server_context->dhm.G, 16, my_dhm_G);
+ if (ret < 0) {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ mk_err("[tls] Load DH parameter failed: %s", err_buf);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int mk_tls_init()
+{
+ pthread_key_create(&local_context, NULL);
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_init(&global_sessions.cache);
+#endif
+
+ pthread_mutex_lock(&server_context->mutex);
+ mk_list_init(&server_context->threads._head);
+ mbedtls_entropy_init(&server_context->entropy);
+ pthread_mutex_unlock(&server_context->mutex);
+
+ PLUGIN_TRACE("[tls] Load certificates.");
+ if (polar_load_certs(&server_context->config)) {
+ return -1;
+ }
+ PLUGIN_TRACE("[tls] Load DH parameters.");
+ if (polar_load_dh_param(&server_context->config)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int entropy_func_safe(void *data, unsigned char *output, size_t len)
+{
+ int ret;
+
+ pthread_mutex_lock(&server_context->mutex);
+ ret = mbedtls_entropy_func(data, output, len);
+ pthread_mutex_unlock(&server_context->mutex);
+
+ return ret;
+}
+
+static void contexts_free(struct polar_context_head *ctx)
+{
+ struct polar_context_head *cur, *next;
+
+ if (ctx != NULL) {
+ cur = ctx;
+ next = cur->_next;
+
+ for (; next; cur = next, next = next->_next) {
+ mbedtls_ssl_free(&cur->context);
+ memset(cur, 0, sizeof(*cur));
+ mk_api->mem_free(cur);
+ }
+
+ mbedtls_ssl_free(&cur->context);
+ memset(cur, 0, sizeof(*cur));
+ mk_api->mem_free(cur);
+ }
+}
+
+static void config_free(struct polar_config *conf)
+{
+ if (conf->cert_file) mk_api->mem_free(conf->cert_file);
+ if (conf->cert_chain_file) mk_api->mem_free(conf->cert_chain_file);
+ if (conf->key_file) mk_api->mem_free(conf->key_file);
+ if (conf->dh_param_file) mk_api->mem_free(conf->dh_param_file);
+}
+
+/* Contexts may be requested from outside workers on exit so we should
+ * be prepared for an empty context.
+ */
+static mbedtls_ssl_context *context_get(int fd)
+{
+ struct polar_thread_context *thctx = local_thread_context();
+ struct polar_context_head **cur = &thctx->contexts;
+
+ if (cur == NULL) {
+ return NULL;
+ }
+
+ for (; *cur; cur = &(*cur)->_next) {
+ if ((*cur)->fd == fd) {
+ return &(*cur)->context;
+ }
+ }
+
+ return NULL;
+}
+
+static mbedtls_ssl_context *context_new(int fd)
+{
+ struct polar_thread_context *thctx = local_thread_context();
+ struct polar_context_head **cur = &thctx->contexts;
+ mbedtls_ssl_context *ssl = NULL;
+ mbedtls_ssl_cache_context cache;
+
+ mbedtls_ssl_cache_init(&cache);
+
+ assert(cur != NULL);
+
+ for (; *cur; cur = &(*cur)->_next) {
+ if ((*cur)->fd == -1) {
+ break;
+ }
+ }
+
+ if (*cur == NULL) {
+ PLUGIN_TRACE("[polarssl %d] New ssl context.", fd);
+
+ *cur = mk_api->mem_alloc(sizeof(**cur));
+ if (*cur == NULL) {
+ return NULL;
+ }
+ (*cur)->_next = NULL;
+
+ ssl = &(*cur)->context;
+
+ mbedtls_ssl_init(ssl);
+ mbedtls_ssl_setup(ssl, &thctx->conf);
+
+ mbedtls_ssl_conf_session_cache(&thctx->conf,
+ &global_sessions,
+ tls_cache_get,
+ tls_cache_set);
+
+ mbedtls_ssl_set_bio(ssl, &(*cur)->fd,
+ mbedtls_net_send, mbedtls_net_recv, NULL);
+
+ mbedtls_ssl_conf_rng(&thctx->conf, mbedtls_ctr_drbg_random,
+ &thctx->ctr_drbg);
+
+#if (POLAR_DEBUG_LEVEL > 0)
+ mbedtls_ssl_conf_dbg(ssl, polar_debug, 0);
+#endif
+
+ mbedtls_ssl_conf_own_cert(&thctx->conf, &server_context->cert, &thctx->pkey);
+ mbedtls_ssl_conf_ca_chain(&thctx->conf, &server_context->ca_cert, NULL);
+ mbedtls_ssl_conf_dh_param_ctx(&thctx->conf, &server_context->dhm);
+
+ if (server_context->config.check_client_cert == MK_TRUE) {
+ mbedtls_ssl_conf_authmode(&thctx->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+ }
+ }
+ else {
+ ssl = &(*cur)->context;
+ }
+
+ (*cur)->fd = fd;
+
+ return ssl;
+}
+
+static int context_unset(int fd, mbedtls_ssl_context *ssl)
+{
+ struct polar_context_head *head;
+
+ head = container_of(ssl, struct polar_context_head, context);
+
+ if (head->fd == fd) {
+ head->fd = -1;
+ mbedtls_ssl_session_reset(ssl);
+ }
+ else {
+ mk_err("[polarssl %d] Context already unset.", fd);
+ }
+
+ return 0;
+}
+
+int mk_tls_read(int fd, void *buf, int count)
+{
+ size_t avail;
+ mbedtls_ssl_context *ssl = context_get(fd);
+
+ if (!ssl) {
+ ssl = context_new(fd);
+ }
+
+ int ret = handle_return(mbedtls_ssl_read(ssl, buf, count));
+ PLUGIN_TRACE("IN: %i SSL READ: %i ; CORE COUNT: %i",
+ ssl->in_msglen,
+ ret, count);
+
+ /* Check if the caller read less than the available data */
+ if (ret > 0) {
+ avail = polar_get_bytes_avail(ssl);
+ if (avail > 0) {
+ /*
+ * A read callback would never read in buffer more than
+ * the size specified in 'count', but it aims to return
+ * as value the total information read in the buffer plugin
+ */
+ ret += avail;
+ }
+ }
+ return ret;
+}
+
+int mk_tls_write(int fd, const void *buf, size_t count)
+{
+ mbedtls_ssl_context *ssl = context_get(fd);
+ if (!ssl) {
+ ssl = context_new(fd);
+ }
+
+ return handle_return(mbedtls_ssl_write(ssl, buf, count));
+}
+
+int mk_tls_writev(int fd, struct mk_iov *mk_io)
+{
+ mbedtls_ssl_context *ssl = context_get(fd);
+ const int iov_len = mk_io->iov_idx;
+ const struct iovec *io = mk_io->io;
+ const size_t len = mk_io->total_len;
+ unsigned char *buf;
+ size_t used = 0;
+ int ret = 0, i;
+
+ if (!ssl) {
+ ssl = context_new(fd);
+ }
+
+ buf = mk_api->mem_alloc(len);
+ if (buf == NULL) {
+ mk_err("malloc failed: %s", strerror(errno));
+ return -1;
+ }
+
+ for (i = 0; i < iov_len; i++) {
+ memcpy(buf + used, io[i].iov_base, io[i].iov_len);
+ used += io[i].iov_len;
+ }
+
+ assert(used == len);
+ ret = mbedtls_ssl_write(ssl, buf, len);
+ mk_api->mem_free(buf);
+
+ return handle_return(ret);
+}
+
+int mk_tls_send_file(int fd, int file_fd, off_t *file_offset,
+ size_t file_count)
+{
+ mbedtls_ssl_context *ssl = context_get(fd);
+ unsigned char *buf;
+ ssize_t used, remain = file_count, sent = 0;
+ int ret;
+
+ if (!ssl) {
+ ssl = context_new(fd);
+ }
+
+ buf = mk_api->mem_alloc(SENDFILE_BUF_SIZE);
+ if (buf == NULL) {
+ return -1;
+ }
+
+ do {
+ used = pread(file_fd, buf, SENDFILE_BUF_SIZE, *file_offset);
+ if (used == 0) {
+ ret = 0;
+ }
+ else if (used < 0) {
+ mk_err("[tls] Read from file failed: %s", strerror(errno));
+ ret = -1;
+ }
+ else if (remain > 0) {
+ ret = mbedtls_ssl_write(ssl, buf, used < remain ? used : remain);
+ }
+ else {
+ ret = mbedtls_ssl_write(ssl, buf, used);
+ }
+
+ if (ret > 0) {
+ if (remain > 0) {
+ remain -= ret;
+ }
+ sent += ret;
+ *file_offset += ret;
+ }
+ } while (ret > 0);
+
+ mk_api->mem_free(buf);
+
+ if (sent > 0) {
+ return sent;
+ }
+ else {
+ return handle_return(ret);
+ }
+}
+
+int mk_tls_close(int fd)
+{
+ mbedtls_ssl_context *ssl = context_get(fd);
+
+ PLUGIN_TRACE("[fd %d] Closing connection", fd);
+
+ if (ssl) {
+ mbedtls_ssl_close_notify(ssl);
+ context_unset(fd, ssl);
+ }
+
+ close(fd);
+ return 0;
+}
+
+int mk_tls_plugin_init(struct plugin_api **api, char *confdir)
+{
+ int used;
+ struct mk_list *head;
+ struct mk_config_listener *listen;
+
+ /* Evil global config stuff */
+ mk_api = *api;
+
+ /* Check if the plugin will be used by some listener */
+ used = MK_FALSE;
+ mk_list_foreach(head, &mk_api->config->listeners) {
+ listen = mk_list_entry(head, struct mk_config_listener, _head);
+ if (listen->flags & MK_CAP_SOCK_TLS) {
+ used = MK_TRUE;
+ break;
+ }
+ }
+
+ if (used) {
+ /* If it's used, load certificates.. mandatory */
+ server_context = mk_api->mem_alloc_z(sizeof(struct polar_server_context));
+ config_parse(confdir, &server_context->config);
+ return mk_tls_init();
+ }
+ else {
+ /* Plugin is not used, just unregister in silence */
+ return -2;
+ }
+}
+
+void mk_tls_worker_init(void)
+{
+ int ret;
+ struct polar_thread_context *thctx;
+ const char *pers = "monkey";
+
+ PLUGIN_TRACE("[tls] Init thread context.");
+
+ thctx = mk_api->mem_alloc(sizeof(*thctx));
+ if (thctx == NULL) {
+ goto error;
+ }
+ thctx->contexts = NULL;
+ mk_list_init(&thctx->_head);
+
+
+ /* SSL confniguration */
+ mbedtls_ssl_config_init(&thctx->conf);
+ mbedtls_ssl_config_defaults(&thctx->conf,
+ MBEDTLS_SSL_IS_SERVER,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT);
+
+ pthread_mutex_lock(&server_context->mutex);
+ mk_list_add(&thctx->_head, &server_context->threads._head);
+ pthread_mutex_unlock(&server_context->mutex);
+
+ mbedtls_ctr_drbg_init(&thctx->ctr_drbg);
+ ret = mbedtls_ctr_drbg_seed(&thctx->ctr_drbg,
+ entropy_func_safe, &server_context->entropy,
+ (const unsigned char *) pers,
+ strlen(pers));
+ if (ret != 0) {
+ goto error;
+ }
+
+ mbedtls_pk_init(&thctx->pkey);
+
+ PLUGIN_TRACE("[tls] Load RSA key.");
+ if (polar_load_key(thctx, &server_context->config)) {
+ goto error;
+ }
+
+ PLUGIN_TRACE("[tls] Set local thread context.");
+ pthread_setspecific(local_context, thctx);
+
+ return;
+
+ error:
+ exit(EXIT_FAILURE);
+}
+
+int mk_tls_plugin_exit()
+{
+ struct mk_list *cur, *tmp;
+ struct polar_thread_context *thctx;
+
+ mbedtls_x509_crt_free(&server_context->cert);
+ mbedtls_x509_crt_free(&server_context->ca_cert);
+ mbedtls_dhm_free(&server_context->dhm);
+
+ mk_list_foreach_safe(cur, tmp, &server_context->threads._head) {
+ thctx = mk_list_entry(cur, struct polar_thread_context, _head);
+ contexts_free(thctx->contexts);
+ mk_api->mem_free(thctx);
+
+ mbedtls_pk_free(&thctx->pkey);
+ }
+ pthread_mutex_destroy(&server_context->mutex);
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_free(&global_sessions.cache);
+#endif
+
+ config_free(&server_context->config);
+ mk_api->mem_free(server_context);
+
+ return 0;
+}
+
+/* Network Layer plugin Callbacks */
+struct mk_plugin_network mk_plugin_network_tls = {
+ .read = mk_tls_read,
+ .write = mk_tls_write,
+ .writev = mk_tls_writev,
+ .close = mk_tls_close,
+ .send_file = mk_tls_send_file,
+ .buffer_size = MBEDTLS_SSL_MAX_CONTENT_LEN
+};
+
+struct mk_plugin mk_plugin_tls = {
+ /* Identification */
+ .shortname = "tls",
+ .name = "SSL/TLS Network Layer",
+ .version = MK_VERSION_STR,
+ .hooks = MK_PLUGIN_NETWORK_LAYER,
+
+ /* Init / Exit */
+ .init_plugin = mk_tls_plugin_init,
+ .exit_plugin = mk_tls_plugin_exit,
+
+ /* Init Levels */
+ .master_init = NULL,
+ .worker_init = mk_tls_worker_init,
+
+ /* Type */
+ .network = &mk_plugin_network_tls,
+ .capabilities = MK_CAP_SOCK_TLS
+};
diff --git a/fluent-bit/lib/monkey/qa/README.txt b/fluent-bit/lib/monkey/qa/README.txt
new file mode 100644
index 000000000..12c8c9e41
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/README.txt
@@ -0,0 +1,20 @@
+Monkey QA Test scripts
+======================
+This QA test script package has been written by
+Carlos Ghan (charlie.brown.uy@gmail.com) and is
+maintained by the Monkey developers team.
+
+In order to run this test you will need the
+HTTP Test Tool installed in your system, you can
+get the latest version from http://htt.sf.net/
+
+Running the tests
+=================
+To run all tests:
+ ./run-tests.sh
+
+[Variables in run-tests.sh]
+CONFIG_FILE Server parameters file (don't forget to set TEST_DOC_ROOT)
+LOGFILE Log errors to this file
+STOP_AT_ERRORS Stop at first error
+WITH_COLOR Enable/Disable color in output
diff --git a/fluent-bit/lib/monkey/qa/TEMPLATE b/fluent-bit/lib/monkey/qa/TEMPLATE
new file mode 100644
index 000000000..0303d9868
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/TEMPLATE
@@ -0,0 +1,26 @@
+###############################################################################
+# DESCRIPTION
+# Test description
+#
+# AUTHOR
+# Author Name <author@email.here>
+#
+# DATE
+# Month_text Day_number Year_number
+#
+# COMMENTS
+# Anything pertinent.
+###############################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/__CONFIG b/fluent-bit/lib/monkey/qa/__CONFIG
new file mode 100644
index 000000000..74b9f117c
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/__CONFIG
@@ -0,0 +1,10 @@
+# Global server settings
+SET HOST=localhost
+SET PORT=2001
+SET HTTPVER=HTTP/1.1
+SET HTTPVER10=HTTP/1.0
+
+SET DOC_ROOT=../htdocs
+SET TEST_DOC=index.html
+
+SET TEST_LOG_LEVEL=4
diff --git a/fluent-bit/lib/monkey/qa/__MACROS b/fluent-bit/lib/monkey/qa/__MACROS
new file mode 100644
index 000000000..5e0352fef
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/__MACROS
@@ -0,0 +1,51 @@
+# ----------------------------------------------------------------------------
+# INIT: Common client-initialization
+# ----------------------------------------------------------------------------
+BLOCK INIT
+_LOG_LEVEL $TEST_LOG_LEVEL
+END
+
+
+# ----------------------------------------------------------------------------
+# FMT_DATE: Format given time in seconds to RFC 1123 format
+# Param 1: time in seconds
+# Param 2: where to store result (variable-name)
+#
+# (note: httest' STRFTIME works with msec instead of sec)
+# ----------------------------------------------------------------------------
+BLOCK FMT_DATE
+_OP $1 MUL 1000 aux
+_STRFTIME $aux "%a, %d %b %Y %H:%M:%S GMT" $2
+END
+
+
+# ----------------------------------------------------------------------------
+# TESTDOC_GETSIZE: Get TEST_DOC's file size & store it in TEST_DOC_LEN variable
+# ----------------------------------------------------------------------------
+BLOCK TESTDOC_GETSIZE
+_MATCH EXEC "(.*)" TEST_DOC_LEN
+_SH #!/bin/bash
+_SH stat -c %s $DOC_ROOT/$TEST_DOC
+_SH END
+END
+
+
+# ----------------------------------------------------------------------------
+# TESTDOC_GETEPOCH: Get TEST_DOC's Epoch time & store it in TEST_DOC_EPOCH
+# variable
+# ----------------------------------------------------------------------------
+BLOCK TESTDOC_GETEPOCH
+_MATCH EXEC "(.*)" TEST_DOC_EPOCH
+_SH #!/bin/bash
+_SH stat -c %Y $DOC_ROOT/$TEST_DOC
+_SH END
+END
+
+
+# ----------------------------------------------------------------------------
+# TESTDOC_GETDATE: Get TEST_DOC's date & store it in TEST_DOC_HTTPDATE variable
+# ----------------------------------------------------------------------------
+BLOCK TESTDOC_GETDATE
+_CALL TESTDOC_GETEPOCH
+_CALL FMT_DATE $TEST_DOC_EPOCH TEST_DOC_HTTPDATE
+END
diff --git a/fluent-bit/lib/monkey/qa/checklog b/fluent-bit/lib/monkey/qa/checklog
new file mode 100755
index 000000000..f1df314aa
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/checklog
@@ -0,0 +1,239 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2010, Eduardo Silva <edsiper@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import sys
+import re
+import getopt
+import ConfigParser
+
+RULES_PATH = 'log_rules'
+ACCESS_FILE = '../logs/access.log'
+ERROR_FILE = '../logs/error.log'
+
+class AccessRule:
+ def __init__(self,
+ ip = None, time = None,
+ method = None, uri = None,
+ protocol = None, status = None,
+ size = None):
+
+ self.type = 'access'
+ self.ip = ip
+ self.time = time
+ self.method = method
+ self.uri = uri
+ self.status = status
+ self.protocol = protocol
+ self.status = status
+
+ if size is not None:
+ if size.isdigit():
+ self.size = size
+ else:
+ if size[:8] == 'FILESIZE':
+ target = size[8:].strip()
+ self.size = os.path.getsize(target)
+ else:
+ self.size = size
+ else:
+ self.size = size
+
+class ErrorRule:
+ def __init__(self,
+ ip = None, time = None,
+ error = None, message = None):
+
+ self.type = 'error'
+ self.ip = ip
+ self.time = time
+ self.error = error
+ self.message = message
+
+class Config(ConfigParser.ConfigParser):
+ def __init__(self):
+ ConfigParser.ConfigParser.__init__(self)
+
+ def _get_value(self, section, key):
+ try:
+ value = self.get(section, key)
+ except:
+ value = None
+
+ return value
+
+ def get_rules(self, path):
+ self.read(path)
+
+ rules = []
+ for section in self.sections():
+ if section == 'access':
+ ip = self._get_value(section, 'ip')
+ time = self._get_value(section, 'time')
+ method = self._get_value(section, 'method')
+ uri = self._get_value(section, 'uri')
+ protocol = self._get_value(section, 'protocol')
+ status = self._get_value(section, 'status')
+ size = self._get_value(section, 'size')
+
+ rule = AccessRule(ip, time, method, uri, protocol, status, size)
+
+ elif section == 'error':
+ ip = self._get_value(section, 'ip')
+ time = self._get_value(section, 'time')
+ error = self._get_value(section, 'error')
+ message = self._get_value(section, 'message')
+
+ rule = ErrorRule(ip, time, error, message)
+
+ # Add rule to list
+ rules.append(rule)
+
+ return rules
+
+class Logfile:
+
+ def __init__(self):
+ self.silent_mode = False
+ self.target_logfile = None
+
+ self.check_arguments()
+
+ # Check if file exists
+ if os.path.isfile(self.target_logfile) is False:
+ # No rules exists for this test
+ if self.silent_mode is False:
+ print "No rules for target"
+ exit(2)
+
+ # Read rules
+ config = Config()
+ rules = config.get_rules(self.target_logfile)
+
+ if len(rules) == 0:
+ if self.silent_mode is False:
+ print "Error, no rules found on target file"
+ exit(2)
+
+ # Check rules
+ self.check_rules(rules)
+
+ def check_arguments(self):
+ optlist, args = getopt.getopt(sys.argv[1:], 'shl:')
+ for key, val in optlist:
+ if key == '-s':
+ self.silent_mode = True
+ elif key == '-l':
+ self.target_logfile = val
+ elif key == '-h':
+ self.help()
+
+ if self.target_logfile is None:
+ self.help()
+
+ def help(self):
+ print "** Monkey QA Checklog **"
+ print "Usage: ./checklog [-s] [-l logfile_rules]"
+ print "\nAvailable options"
+ print " -s Run checklog in silent mode, no messages to stdout"
+ print " -l logfile Specify the logfile rule"
+ print " -h Show this help"
+ print
+ exit(1)
+
+ def get_last_file_line(self, file):
+ f = open(file, 'r')
+ lines = f.readlines()
+ f.close()
+
+ if len(lines) < 1:
+
+ return None
+
+ # get last file line
+ last = lines[len(lines) - 1]
+ return last
+
+ def check_field(self, rule, log):
+ if rule is not None:
+ if str(rule) != str(log):
+ if self.silent_mode is False:
+ print "Rule does not match, expect '" + str(rule) + '\' got \'' + log + '\''
+ exit(1)
+ else:
+ return 0
+ else:
+ return 0
+
+ def check_rules(self, rules):
+ # Parse access log format, anyone is invited to fix this nasty regex
+ access_re = re.compile("^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})( - )(\[.*\])( .* ){1,4}(/.* )(.*/.* )(\d.* )(.*)\n$")
+ error_re = re.compile("^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})( - )(\[.*\])( \[.*\])(.*)$")
+
+ for r in rules:
+ if r.type == 'access':
+ line = self.get_last_file_line(ACCESS_FILE)
+ fields = access_re.split(line)
+
+ data = {'ip': fields[1],
+ 'time': fields[3],
+ 'method': fields[4].strip(),
+ 'uri': fields[5].strip(),
+ 'protocol': fields[6].strip(),
+ 'status': fields[7].strip(),
+ 'size': fields[8]
+ }
+
+ self.check_field(r.ip, data['ip'])
+ self.check_field(r.time, data['time'])
+ self.check_field(r.method, data['method'])
+ self.check_field(r.uri, data['uri'])
+ self.check_field(r.protocol, data['protocol'])
+ self.check_field(r.status, data['status'])
+ self.check_field(r.size, data['size'])
+
+ elif r.type == 'error':
+ line = self.get_last_file_line(ERROR_FILE)
+ fields = error_re.split(line)
+
+ # We always expect at least 4 fields
+ if len(fields) < 4:
+ if self.silent_mode is False:
+ print "Error: we did not find the expected fields"
+ print "Logfile line"
+ print " %s " % line
+ exit(1)
+
+ data = {'ip': fields[1],
+ 'time': fields[3],
+ 'error': fields[4].strip('[error (\d)]'),
+ 'message': fields[5].strip()
+ }
+
+ self.check_field(r.ip, data['ip'])
+ self.check_field(r.time, data['time'])
+ self.check_field(r.error, data['error'])
+ self.check_field(r.message, data['message'])
+
+
+ if self.silent_mode is False:
+ print "Check passed :)"
+
+if __name__ == '__main__':
+ Logfile()
+
diff --git a/fluent-bit/lib/monkey/qa/connection_http10_01.htt b/fluent-bit/lib/monkey/qa/connection_http10_01.htt
new file mode 100644
index 000000000..125c519ed
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/connection_http10_01.htt
@@ -0,0 +1,26 @@
+###############################################################################
+# DESCRIPTION
+# HTTP/1.0 request expect 'Connection: close'
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# March 16 2010
+#
+# COMMENTS
+# Server must return a 200 response.
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER10
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_EXPECT . "Connection: Close"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/connection_http10_02.htt b/fluent-bit/lib/monkey/qa/connection_http10_02.htt
new file mode 100644
index 000000000..be17928e9
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/connection_http10_02.htt
@@ -0,0 +1,28 @@
+###############################################################################
+# DESCRIPTION
+# HTTP/1.0 Request with 'Connection: Keep-Alive'.
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# March 16 2010
+#
+# COMMENTS
+# Do not expect header response with keep-alive header
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER10
+__Connection: Keep-Alive
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_EXPECT . "!Keep-Alive: timeout=5, max=1000"
+_EXPECT . "Connection: Keep-Alive"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/connection_http10_03.htt b/fluent-bit/lib/monkey/qa/connection_http10_03.htt
new file mode 100644
index 000000000..4fbaa7bdc
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/connection_http10_03.htt
@@ -0,0 +1,27 @@
+###############################################################################
+# DESCRIPTION
+# HTTP/1.0 Request with an invalid 'Connection' header
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# March 16 2010
+#
+# COMMENTS
+# Expect 'Connection: closed' from server
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER10
+__Connection: an invalid value
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_EXPECT . "Connection: Close"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/connection_http11_01.htt b/fluent-bit/lib/monkey/qa/connection_http11_01.htt
new file mode 100644
index 000000000..f8a32f576
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/connection_http11_01.htt
@@ -0,0 +1,27 @@
+###############################################################################
+# DESCRIPTION
+# Server must not send connection header
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# March 17 2010
+#
+# COMMENTS
+# Do not Expect 'Connection:' from server
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_EXPECT . "!Connection:"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/connection_http11_02.htt b/fluent-bit/lib/monkey/qa/connection_http11_02.htt
new file mode 100644
index 000000000..f120fbcb2
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/connection_http11_02.htt
@@ -0,0 +1,28 @@
+###############################################################################
+# DESCRIPTION
+# Server must not send connection header
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# March 17 2011
+#
+# COMMENTS
+# Do Expect 'Connection:' from server
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_EXPECT . "Connection: Close"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/connection_http11_03.htt b/fluent-bit/lib/monkey/qa/connection_http11_03.htt
new file mode 100644
index 000000000..e032a9455
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/connection_http11_03.htt
@@ -0,0 +1,30 @@
+###############################################################################
+# DESCRIPTION
+# HTTP/1.1 Request with an invalid connection header, server must
+# not send a connection header, must assume keepalive by default
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# March 17 2010
+#
+# COMMENTS
+# Do not Expect 'Connection:' header
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__Connection: an invalid value
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_EXPECT . "!Connection:"
+_EXPECT . "!Keep-Alive:"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/directory_redirect_01.htt b/fluent-bit/lib/monkey/qa/directory_redirect_01.htt
new file mode 100644
index 000000000..3af2181f9
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/directory_redirect_01.htt
@@ -0,0 +1,33 @@
+###############################################################################
+# DESCRIPTION
+# Check directory redirect
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# Jun 2 2010
+#
+# COMMENTS
+# Server must return a 301 moved permanently header.
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_CALL INIT
+_CALL TESTDOC_GETDATE
+
+_REQ $HOST $PORT
+__GET /img $HTTPVER
+__Host: $HOST:$PORT
+__If-Modified-Since: $TEST_DOC_HTTPDATE
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 301 Moved Permanently"
+_EXPECT . "Content-Length: 0"
+_EXPECT . "Location: http://$HOST:$PORT/img/
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/directory_redirect_02.htt b/fluent-bit/lib/monkey/qa/directory_redirect_02.htt
new file mode 100644
index 000000000..959a15b9e
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/directory_redirect_02.htt
@@ -0,0 +1,33 @@
+###############################################################################
+# DESCRIPTION
+# Check directory redirect, we do not set port in the Host header
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# May 19 2012
+#
+# COMMENTS
+# Server must return a 301 moved permanently header.
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_CALL INIT
+_CALL TESTDOC_GETDATE
+
+_REQ $HOST $PORT
+__GET /img $HTTPVER
+__Host: $HOST
+__If-Modified-Since: $TEST_DOC_HTTPDATE
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 301 Moved Permanently"
+_EXPECT . "Content-Length: 0"
+_EXPECT . "Location: http://$HOST/img/
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/directory_redirect_03.htt b/fluent-bit/lib/monkey/qa/directory_redirect_03.htt
new file mode 100644
index 000000000..1ff1f9321
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/directory_redirect_03.htt
@@ -0,0 +1,33 @@
+###############################################################################
+# DESCRIPTION
+# Check directory redirect, we set a different port in the Host header
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# May 19 2012
+#
+# COMMENTS
+# Server must return a 301 moved permanently header.
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_CALL INIT
+_CALL TESTDOC_GETDATE
+
+_REQ $HOST $PORT
+__GET /img $HTTPVER
+__Host: $HOST:12345
+__If-Modified-Since: $TEST_DOC_HTTPDATE
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 301 Moved Permanently"
+_EXPECT . "Content-Length: 0"
+_EXPECT . "Location: http://$HOST:12345/img/
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/docs_httest.txt b/fluent-bit/lib/monkey/qa/docs_httest.txt
new file mode 100644
index 000000000..07556c955
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/docs_httest.txt
@@ -0,0 +1,181 @@
+Global Commands
+---------------
+BLOCK <name>
+Store a block of commands to call it from a CLIENT/SERVER/BLOCK
+
+CLIENT [<number of concurrent clients>]
+Client body start, close it with END and a newline
+
+DAEMON
+Daemon body start, close it with END and a newline.
+A daemon will not join CLIENT/SERVER and could therefore be used
+for supervisor jobs
+
+END
+Close CLIENT|SERVER body
+
+EXEC <shell command>
+Execute a shell command, attention executes will not join CLIENT/SERVER
+
+GO
+Starts all client in sync mode
+
+INCLUDE <include file>
+Load and execute defined include file,
+current path is taken the callers current path
+
+SERVER [<SSL>:]<port> [<number of concurrent servers>]
+Server body start, close it with END and a newline,
+Do load server.cert.pem and server.key.pem if found in local directory,
+number of concurrent servers, -1 for unlimited,
+<SSL>: SSL, SSL2, SSL3, TLS
+
+SET <variable>=<value>
+Store a value in a global variable
+
+TIMEOUT <timeout in ms>
+Defines global socket timeout
+
+
+Local Commands
+-------------
+-__ <string>
+Send <string> to the socket with a CRLF at the end of line
+
+_- <string>
+Same like __ but no CRLF at the end of line
+
+_ADD_HEADER <header> <value>
+Add additional header to received headers to force forexample chunked encoding
+
+_BPS <n>
+Send not more than defined Bytes per second
+close body with _END BPS
+
+_CALL <name of block>
+Call a defined block
+
+_CERT <cert-file> <key-file> [<ca-cert-file>]
+Sets cert for the current ssl connection, mainly used for server cert
+
+_CHUNK
+Mark the end of a chunk block, all data after last _FLUSH are counted,
+does automatic add chunk info
+
+_CLOSE
+Close the current connection and set the connection state to CLOSED
+
+_DEBUG <string>
+Prints to stderr for debugging reasons
+
+_DOWN
+Shutdown listener
+
+_EXEC <shell command>
+Execute a shell command, _EXEC| will pipe the incoming stream on the
+socket in to the called shell command
+
+_EXIT [OK|FAILED]
+Exits with OK or FAILED default is FAILED
+
+_EXPECT . "[!]<regex>"
+Define what data we do or do not expect on a WAIT command.
+Negation with a leading '!' in the <regex>
+
+_FLUSH
+Flush the cached lines,
+the AUTO Content-Length calculation will take place here
+
+_HEADER ALLOW|FILTER <header name>
+Defines allowed headers or headers to filter,
+default all headers are allowed and no headers are filtered.
+Filter only for receive mechanisme
+
+_IF "<expression>" MATCH "[!]<regex>"
+Test if variable do or do not match the regex, close body with _END IF,
+negation with a leading '!' in the <regex>,
+<expression> must not be empty
+
+_IGNORE_ERR <regex>
+This command is Depreciated, do not use it
+Ignores errors specified in <regex>,
+i.e. ".*" would ignore all errors, only .* is implemented
+
+_LOG_LEVEL <level>
+Level is a number 0-4
+
+_LOOP <n>
+Do loop the body <n> times,
+close body with _END LOOP
+
+_MATCH (headers|body|error) "<regex>" <variable>
+Define a regex with a match which should be stored in <variable>
+
+_MATCH EXEC "<regex>" <variable>
+_EXEC algun_comando
+(No documentado; aparece en los ejemplos de la página web)
+Hace lo mismo que _MATCH pero con la salida del comando ejecutado en _EXEC
+
+_ONLY_PRINTABLE on|off
+Replace all chars below 32 and above 127 with a space
+
+_OP <left> ADD|SUB|DIV|MUL <right> <variable>
+Store evaluated expression
+
+_PIPE [chunked [<chunk_size>]]
+Start a pipe for stream the output of EXEC to the socket stream,
+wiht optional chunk support
+
+_RAND <start> <end>
+Generates a number between <start> and <end>
+
+_RECV <bytes>|POLL
+Receive an amount of bytes, either specified by a number
+or as much until socket timeout will in POLL mode
+
+_REQ <host> [<SSL>:]<port>[:<tag>] [<cert-file> <key-file> [<ca-cert-file>]]
+Start a request to defined host:port, with SSL support.
+Does only open a new connection if we are in connection state CLOSED
+<SSL>: SSL, SSL2, SSL3, TLS<tag>:Additional tag info do support multiple connection to one target
+<cert-file>, <key-file> and <ca-cert-file> are optional for client/server authentication
+
+_RES
+Wait for a connection accept
+
+_SENDFILE <file>
+Send file over http
+
+_SET <variable>=<value>
+Store a value in a local variable
+
+_SH shell script line or END
+Embedded shell script within a tmp file, execute if END is found
+
+_SLEEP <milisecond>
+Sleep for defined amount of time
+
+_SOCKSTATE <variable>
+Stores connection state CLOSED or CONNECTED in the <variable>
+
+_SYNC
+Synchronise to the next full second
+
+_TIME <variable>
+Store time in variable [ms]
+
+_TIMEOUT <miliseconds>
+Set socket timeout of current socket
+
+_UP
+Setup listener
+
+_VERIFY_PEER
+Gets peer cert and validate it
+
+_WAIT [<amount of bytes>]
+Wait for data and receive them.
+EXPECT and MATCH definitions will be checked here on the incoming data.
+Optional you could receive a specific amount of bytes
+
+_WHICH <variable>
+Stores the concurrency number of current thread
diff --git a/fluent-bit/lib/monkey/qa/error_400_test01.htt b/fluent-bit/lib/monkey/qa/error_400_test01.htt
new file mode 100644
index 000000000..e6d7e7fa0
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/error_400_test01.htt
@@ -0,0 +1,26 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 400
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# June 29 2009
+#
+# COMMENTS
+# Sending a bad request. In this case, one with missing "Host" header.
+# ("Host" header is required in HTTP v1.1)
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 400 Bad Request"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/error_404.htt b/fluent-bit/lib/monkey/qa/error_404.htt
new file mode 100644
index 000000000..2860048cb
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/error_404.htt
@@ -0,0 +1,26 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 404
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# June 29 2009
+#
+# COMMENTS
+# Requesting an inexistent object should return "Not Found"
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET /a_file_that_doesnt_exists.html $HTTPVER
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 404 Not Found"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/error_411.htt b/fluent-bit/lib/monkey/qa/error_411.htt
new file mode 100644
index 000000000..95c8d22b4
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/error_411.htt
@@ -0,0 +1,26 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 411
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# June 29 2009
+#
+# COMMENTS
+# A POST request without "Content-Length" should return "Length Required"
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__POST / $HTTPVER
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 411 Length Required"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/error_413_01.htt b/fluent-bit/lib/monkey/qa/error_413_01.htt
new file mode 100644
index 000000000..d9b519d23
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/error_413_01.htt
@@ -0,0 +1,28 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 413
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# July 11 2010
+#
+# COMMENTS
+# A POST request with a higher content-lengt header, it should
+# return "413 Request Entity Too Large"
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__POST / $HTTPVER
+__Host: $HOST
+__Content-Length: 999999999999999999999
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 413 Request Entity Too Large"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/error_413_02.htt b/fluent-bit/lib/monkey/qa/error_413_02.htt
new file mode 100644
index 000000000..7a5b6af25
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/error_413_02.htt
@@ -0,0 +1,297 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 413
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# July 11 2010
+#
+# COMMENTS
+# A very long request, it should return "413 Request Entity Too Large"
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__Header1: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+__Header2: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+__Header3: cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+__Header4: dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__HeaderD: mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
+__HeaderE: nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+__HeaderF: oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
+__Header1: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+__Header2: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+__Header3: cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+__Header4: dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__HeaderD: mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
+__HeaderE: nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+__HeaderF: oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
+__Header1: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+__Header2: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+__Header3: cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+__Header4: dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header5: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__Header6: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+__Header8: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
+__Header9: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+__Header0: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__HeaderC: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
+__HeaderA: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+__HeaderB: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 413 Request Entity Too Large"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/error_501.htt b/fluent-bit/lib/monkey/qa/error_501.htt
new file mode 100644
index 000000000..275bca4f3
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/error_501.htt
@@ -0,0 +1,26 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 501
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# June 29 2009
+#
+# COMMENTS
+# Requesting an unsupported method should return "Not Implemented"
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__1234 / $HTTPVER
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 501 Not Implemented"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/error_505.htt b/fluent-bit/lib/monkey/qa/error_505.htt
new file mode 100644
index 000000000..f50fafe3d
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/error_505.htt
@@ -0,0 +1,27 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 505
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# June 29 2009
+#
+# COMMENTS
+# Requesting an unsupported HTTP version should return "HTTP Version Not
+# Supported"
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET / HTTP/1.9
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 505 HTTP Version Not Supported"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/head_01.htt b/fluent-bit/lib/monkey/qa/head_01.htt
new file mode 100644
index 000000000..6956c4746
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/head_01.htt
@@ -0,0 +1,23 @@
+################################################################################
+# DESCRIPTION
+# HEAD method.
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# June 29 2009
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__HEAD / $HTTPVER
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_WAIT 0
+END
diff --git a/fluent-bit/lib/monkey/qa/head_02.htt b/fluent-bit/lib/monkey/qa/head_02.htt
new file mode 100644
index 000000000..149cbce9d
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/head_02.htt
@@ -0,0 +1,29 @@
+################################################################################
+# DESCRIPTION
+# HEAD method must return content length
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# February 17 2011
+#
+# COMMENTS
+# In some recent versions (0.12.x), the content-length is not being
+# sent for HEAD request method, adding this QA file to avoid regressions.
+#
+################################################################################
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__HEAD / $HTTPVER
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_EXPECT . "Content-Length"
+_EXPECT . "Content-Type"
+_WAIT 0
+END
diff --git a/fluent-bit/lib/monkey/qa/headers_case_insensitive.htt b/fluent-bit/lib/monkey/qa/headers_case_insensitive.htt
new file mode 100644
index 000000000..d2154bfaf
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/headers_case_insensitive.htt
@@ -0,0 +1,36 @@
+################################################################################
+# DESCRIPTION
+# Test that headers are treated as case insensitive. (RFC2616 Section 4.2)
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# June 29 2009
+################################################################################
+
+
+INCLUDE __CONFIG
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__HOST: $HOST
+__CONNECTION: close
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_WAIT
+_CLOSE
+
+_REQ $HOST $PORT
+__POST / $HTTPVER
+__HOST: $HOST
+__CONNECTION: close
+__CONTENT-TYPE: text/plain
+__CONTENT-LENGTH: AUTO
+__
+_-This is a test entity body.
+_EXPECT . "HTTP/1.1 200 OK"
+_WAIT
+_CLOSE
+
+END
diff --git a/fluent-bit/lib/monkey/qa/hexa.htt b/fluent-bit/lib/monkey/qa/hexa.htt
new file mode 100644
index 000000000..059df4fb8
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/hexa.htt
@@ -0,0 +1,26 @@
+################################################################################
+# DESCRIPTION
+# Test request in hexadecimal format.
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# March 16 2010
+#
+# COMMENTS
+# Simple "index.html"
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET /%69%6E%64%65%78.%68%74%6D%6C $HTTPVER
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/host_port_01.htt b/fluent-bit/lib/monkey/qa/host_port_01.htt
new file mode 100644
index 000000000..9dd58cf6b
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/host_port_01.htt
@@ -0,0 +1,27 @@
+################################################################################
+# DESCRIPTION
+# Validation for TCP port in the Host header
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# Jun 15 2012
+#
+# COMMENTS
+# It send a valid host TCP port with the max length allowed
+#
+################################################################################
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__HEAD / $HTTPVER
+__Host: $HOST:20000
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_EXPECT . "Content-Length"
+_EXPECT . "Content-Type"
+_WAIT 0
+END
diff --git a/fluent-bit/lib/monkey/qa/host_port_02.htt b/fluent-bit/lib/monkey/qa/host_port_02.htt
new file mode 100644
index 000000000..56172db6a
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/host_port_02.htt
@@ -0,0 +1,25 @@
+################################################################################
+# DESCRIPTION
+# Validation for TCP port in the Host header
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# Jun 15 2012
+#
+# COMMENTS
+# It send an invalid host TCP port, length >= 6
+#
+################################################################################
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__HEAD / $HTTPVER
+__Host: $HOST:202001
+__
+_EXPECT . "HTTP/1.1 400 Bad Request"
+_WAIT 0
+END
diff --git a/fluent-bit/lib/monkey/qa/host_port_03.htt b/fluent-bit/lib/monkey/qa/host_port_03.htt
new file mode 100644
index 000000000..f78e2ea05
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/host_port_03.htt
@@ -0,0 +1,25 @@
+################################################################################
+# DESCRIPTION
+# Validation for TCP port in the Host header
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# Jun 15 2012
+#
+# COMMENTS
+# It send a valid host TCP port using not numeric values
+#
+################################################################################
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__HEAD / $HTTPVER
+__Host: $HOST:2000a
+__
+_EXPECT . "HTTP/1.1 400 Bad Request"
+_WAIT 0
+END
diff --git a/fluent-bit/lib/monkey/qa/http_parse_01.htt b/fluent-bit/lib/monkey/qa/http_parse_01.htt
new file mode 100644
index 000000000..ec11658b7
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/http_parse_01.htt
@@ -0,0 +1,23 @@
+################################################################################
+# DESCRIPTION
+# It sends an invalid Host header
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# April 04 2012
+################################################################################
+
+
+INCLUDE __CONFIG
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: [::1]:AABB
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 400 Bad Request"
+_WAIT
+_CLOSE
+END
diff --git a/fluent-bit/lib/monkey/qa/if_modified_since_test01.htt b/fluent-bit/lib/monkey/qa/if_modified_since_test01.htt
new file mode 100644
index 000000000..3124e700d
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/if_modified_since_test01.htt
@@ -0,0 +1,32 @@
+###############################################################################
+# DESCRIPTION
+# Trivial test for If-Modified-Since header.
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# January 27 2010
+#
+# COMMENTS
+# Server must return a 304 response, since we are passing the requested file's
+# date as If-Modified-Since's parameter.
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_CALL INIT
+_CALL TESTDOC_GETDATE
+
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__If-Modified-Since: $TEST_DOC_HTTPDATE
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 304 Not Modified"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/if_modified_since_test02.htt b/fluent-bit/lib/monkey/qa/if_modified_since_test02.htt
new file mode 100644
index 000000000..45a4f87a2
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/if_modified_since_test02.htt
@@ -0,0 +1,38 @@
+###############################################################################
+# DESCRIPTION
+# Trivial test for If-Modified-Since header.
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# January 27 2010
+#
+# COMMENTS
+# Server must return a 304 response, since we are passing a date 1-week after
+# requested file's date as If-Modified-Since's parameter.
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_CALL INIT
+_CALL TESTDOC_GETEPOCH
+
+# 604800 seconds = 1 week
+_OP $TEST_DOC_EPOCH ADD 604800 TEST_DOC_EPOCH
+
+# Format date
+_CALL FMT_DATE $TEST_DOC_EPOCH TEST_DOC_HTTPDATE
+
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__If-Modified-Since: $TEST_DOC_HTTPDATE
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 304 Not Modified"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/if_modified_since_test03.htt b/fluent-bit/lib/monkey/qa/if_modified_since_test03.htt
new file mode 100644
index 000000000..90f3cd036
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/if_modified_since_test03.htt
@@ -0,0 +1,50 @@
+###############################################################################
+# DESCRIPTION
+# Test server's response against invalid If-Modified-Since header values.
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# January 27 2010
+#
+# COMMENTS
+# Server must return a 200 response (RFC 2616 Section 14.25a)
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_CALL INIT
+
+# Garbage in If-Modified-Since header
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__If-Modified-Since: i'm a bad monkey }:]
+__Connection: Keep-Alive
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_WAIT
+
+# Some invalid dates
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__If-Modified-Since: Sat, 30 Feb 2009 14:40:57 GMT
+__Connection: Keep-Alive
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_WAIT
+
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__If-Modified-Since: Sat, 21 Nov 9999 14:40:57 GMT
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 304 Not Modified"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/if_modified_since_test04.htt b/fluent-bit/lib/monkey/qa/if_modified_since_test04.htt
new file mode 100644
index 000000000..ca5e593d5
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/if_modified_since_test04.htt
@@ -0,0 +1,38 @@
+###############################################################################
+# DESCRIPTION
+# Trivial test for If-Modified-Since header.
+#
+# AUTHOR
+# Sonny Karlsson <ksonny@lotrax.org>
+#
+# DATE
+# July 10 2013
+#
+# COMMENTS
+# Server must return a 200 response, since we are passing a time 1
+# min before requested file's date as If-Modified-Since's parameter.
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_CALL INIT
+_CALL TESTDOC_GETEPOCH
+
+# Test
+_OP $TEST_DOC_EPOCH SUB 60 TEST_DOC_EPOCH
+
+# Format date
+_CALL FMT_DATE $TEST_DOC_EPOCH TEST_DOC_HTTPDATE
+
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__If-Modified-Since: $TEST_DOC_HTTPDATE
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/keepalive_01.htt b/fluent-bit/lib/monkey/qa/keepalive_01.htt
new file mode 100644
index 000000000..dd61649f1
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/keepalive_01.htt
@@ -0,0 +1,30 @@
+###############################################################################
+# DESCRIPTION
+# HTTP/1.1 Request requesting Keep-Alive, we expect the server keeps the
+# keep-alive open and send proper header responses for that.
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# February 26 2011
+#
+# COMMENTS
+# Do not Expect 'Connection: Close'
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__Connection: Keep-Alive
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_EXPECT . "!Connection: Closed"
+_WAIT
+
+END
diff --git a/fluent-bit/lib/monkey/qa/keepalive_02.htt b/fluent-bit/lib/monkey/qa/keepalive_02.htt
new file mode 100644
index 000000000..e618a01de
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/keepalive_02.htt
@@ -0,0 +1,32 @@
+###############################################################################
+# DESCRIPTION
+# HTTP/1.0 Request requesting Keep-Alive, we expect the server keeps the
+# keep-alive open and send proper header responses for that.
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# December 14 2014
+#
+# COMMENTS
+# This is a HTTP/1.0 test
+# Do not Expect 'Connection: Close'
+# Do Expect 'Connection: Keep-Alive'
+###############################################################################
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER10
+__Host: $HOST
+__Connection: Keep-Alive
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_EXPECT . "!Connection: Closed"
+_EXPECT . "Connection: Keep-Alive"
+_WAIT
+
+END
diff --git a/fluent-bit/lib/monkey/qa/last_modified_01.htt b/fluent-bit/lib/monkey/qa/last_modified_01.htt
new file mode 100644
index 000000000..dfc4c51a0
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/last_modified_01.htt
@@ -0,0 +1,30 @@
+###############################################################################
+# DESCRIPTION
+# Trivial test to check Last-Modified header
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# Jun 26 2010
+#
+# COMMENTS
+# Server must return the Last-Modified header.
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_CALL INIT
+
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_EXPECT . "Last-Modified:"
+_EXPECT . "Content-Length:"
+_WAIT 0
+END
diff --git a/fluent-bit/lib/monkey/qa/path_traversal01.htt b/fluent-bit/lib/monkey/qa/path_traversal01.htt
new file mode 100644
index 000000000..19a40abcf
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/path_traversal01.htt
@@ -0,0 +1,27 @@
+################################################################################
+# DESCRIPTION
+# Test against directory traversal (client must not be allowed to "get out" of
+# DocumentRoot.
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# March 08 2010
+#
+# COMMENTS
+# Simple "../"
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET /../conf/monkey.conf $HTTPVER
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 403 Forbidden"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/path_traversal02.htt b/fluent-bit/lib/monkey/qa/path_traversal02.htt
new file mode 100644
index 000000000..793c383a5
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/path_traversal02.htt
@@ -0,0 +1,27 @@
+################################################################################
+# DESCRIPTION
+# Test against directory traversal (client must not be allowed to "get out" of
+# DocumentRoot.
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# March 08 2010
+#
+# COMMENTS
+# Using URL-encoded hex values
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET /%2e%2e/conf/monkey.conf $HTTPVER
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 403 Forbidden"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/path_traversal03.htt b/fluent-bit/lib/monkey/qa/path_traversal03.htt
new file mode 100644
index 000000000..37e165330
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/path_traversal03.htt
@@ -0,0 +1,27 @@
+################################################################################
+# DESCRIPTION
+# Test against directory traversal (client must not be allowed to "get out" of
+# DocumentRoot.
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# March 08 2010
+#
+# COMMENTS
+# Mixing dots and %2e
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET /%2e%2e/../%2e./.%2e/../%2e%2e/../../%2e./.%2e/etc/motd $HTTPVER
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 403 Forbidden"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/post_test01.htt b/fluent-bit/lib/monkey/qa/post_test01.htt
new file mode 100644
index 000000000..856afdc5d
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/post_test01.htt
@@ -0,0 +1,26 @@
+################################################################################
+# DESCRIPTION
+# POST method.
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# June 29 2009
+###############################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__POST / $HTTPVER
+__Host: $HOST
+__Content-Type: text/plain
+__Content-Length: AUTO
+__Connection: close
+__
+_-someVariable=1234&daemon=monkeyd&SESSION=e1d83283d597ca88f599e34c8ef2e8c3
+_EXPECT . "HTTP/1.1 200 OK"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/post_test02.htt b/fluent-bit/lib/monkey/qa/post_test02.htt
new file mode 100644
index 000000000..b323be884
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/post_test02.htt
@@ -0,0 +1,33 @@
+################################################################################
+# DESCRIPTION
+# An incomplete POST request.
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# June 29 2009
+#
+# COMMENTS
+# A POST request with missing Content-Length.(Should return "Length Required")
+################################################################################
+
+# Why post_test02.htt sometimes fail ?
+# ------------------------------------
+# it fails because the httest tool catch the close connection from Monkey before it
+# finish to send the whole request, Monkey will not continue working in a request
+# which will not work properly, bad monkey >:D
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__POST / $HTTPVER
+__Host: $HOST
+__Content-Type: text/plain
+__Connection: close
+__
+_-someVariable=1234&daemon=monkeyd&SESSION=e1d83283d597ca88f599e34c8ef2e8c3
+_EXPECT . "HTTP/1.1 411 Length Required"
+_WAIT 0
+END
diff --git a/fluent-bit/lib/monkey/qa/post_test03.htt b/fluent-bit/lib/monkey/qa/post_test03.htt
new file mode 100644
index 000000000..7604c8234
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/post_test03.htt
@@ -0,0 +1,28 @@
+################################################################################
+# DESCRIPTION
+# An incomplete POST request.
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# July 25, 2010
+#
+# COMMENTS
+# A POST request with missing post data, the server must close the
+# connection due to timeout
+################################################################################
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__POST / $HTTPVER
+__Host: $HOST
+__Content-Length: 10
+__Content-Type: text/plain
+__Connection: close
+__
+_EXPECT ERROR "End of file found\(70014\)"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/protocol_01.htt b/fluent-bit/lib/monkey/qa/protocol_01.htt
new file mode 100644
index 000000000..6040a5c8f
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/protocol_01.htt
@@ -0,0 +1,26 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 400
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# June 23 2010
+#
+# COMMENTS
+# Sending a bad request. This request contain double \\ and an
+# unsupported protocol.
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET /\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ a
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 505 HTTP Version Not Supported"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/protocol_02.htt b/fluent-bit/lib/monkey/qa/protocol_02.htt
new file mode 100644
index 000000000..a94b62e20
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/protocol_02.htt
@@ -0,0 +1,25 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 400
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# June 23 2010
+#
+# COMMENTS
+# Sending protocol in lower case.
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET / http/1.0
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 505 HTTP Version Not Supported"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/protocol_03.htt b/fluent-bit/lib/monkey/qa/protocol_03.htt
new file mode 100644
index 000000000..89258ddf9
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/protocol_03.htt
@@ -0,0 +1,25 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 400
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# June 23 2010
+#
+# COMMENTS
+# Request without HTTP protocol version (nothing after URI)
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET /
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 400 Bad Request"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/protocol_04.htt b/fluent-bit/lib/monkey/qa/protocol_04.htt
new file mode 100644
index 000000000..bdbde90b1
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/protocol_04.htt
@@ -0,0 +1,25 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 400
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# June 23 2010
+#
+# COMMENTS
+# Request without HTTP protocol version
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET /
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 505 HTTP Version Not Supported"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/protocol_05.htt b/fluent-bit/lib/monkey/qa/protocol_05.htt
new file mode 100644
index 000000000..91462803f
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/protocol_05.htt
@@ -0,0 +1,25 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 400
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# June 23 2010
+#
+# COMMENTS
+# Request with a Query String without HTTP protocol version,
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET /?a=1
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 400 Bad Request"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/query.htt b/fluent-bit/lib/monkey/qa/query.htt
new file mode 100644
index 000000000..eec3bd20e
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/query.htt
@@ -0,0 +1,25 @@
+################################################################################
+# DESCRIPTION
+# A simple GET query.
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# June 29 2009
+################################################################################
+
+
+INCLUDE __CONFIG
+
+SET QUERY=server=monkeyd&version=0.10git&someVariable=someValue&num=1234
+
+CLIENT
+_REQ $HOST $PORT
+__GET /?$QUERY $HTTPVER
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/ranges_test01.htt b/fluent-bit/lib/monkey/qa/ranges_test01.htt
new file mode 100644
index 000000000..cb5b577a5
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/ranges_test01.htt
@@ -0,0 +1,37 @@
+###############################################################################
+# DESCRIPTION
+# Test partial content request. Range type: 0- (from offset 0 to end)
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# February 02 2010
+#
+# COMMENTS
+# RFC 2616 Section 14.35
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_CALL INIT
+_CALL TESTDOC_GETSIZE
+
+# Last offset = document_length - 1
+_OP $TEST_DOC_LEN SUB 1 TEST_DOC_LAST
+
+_REQ $HOST $PORT
+__GET /$TEST_DOC $HTTPVER
+__Host: $HOST
+__Range: bytes=0-
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 206 Partial Content"
+_EXPECT . "Date:"
+_EXPECT . "Content-Range: bytes 0-${TEST_DOC_LAST}/${TEST_DOC_LEN}"
+_EXPECT . "Content-Length: $TEST_DOC_LEN"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/ranges_test02.htt b/fluent-bit/lib/monkey/qa/ranges_test02.htt
new file mode 100644
index 000000000..bdad83f93
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/ranges_test02.htt
@@ -0,0 +1,37 @@
+###############################################################################
+# DESCRIPTION
+# Test partial content request. Range type: -1 (last byte)
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# February 02 2010
+#
+# COMMENTS
+# RFC 2616 Section 14.35
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+CLIENT
+_CALL INIT
+_CALL TESTDOC_GETSIZE
+
+# Last offset = document_length - 1
+_OP $TEST_DOC_LEN SUB 1 TEST_DOC_LAST
+
+_REQ $HOST $PORT
+__GET /$TEST_DOC $HTTPVER
+__Host: $HOST
+__Range: bytes=-1
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 206 Partial Content"
+_EXPECT . "Date:"
+_EXPECT . "Content-Range: bytes ${TEST_DOC_LAST}-${TEST_DOC_LAST}/${TEST_DOC_LEN}"
+_EXPECT . "Content-Length: 1"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/ranges_test03.htt b/fluent-bit/lib/monkey/qa/ranges_test03.htt
new file mode 100644
index 000000000..6cbfeee31
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/ranges_test03.htt
@@ -0,0 +1,45 @@
+###############################################################################
+# DESCRIPTION
+# Test partial content request. Range type: x-y (between offsets x and y inc.)
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# February 02 2010
+#
+# COMMENTS
+# RFC 2616 Section 14.35
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+# Start offset
+SET OFF_START=100
+
+# End offset
+SET OFF_END=200
+
+CLIENT
+_CALL INIT
+_CALL TESTDOC_GETSIZE
+
+_REQ $HOST $PORT
+__GET /$TEST_DOC $HTTPVER
+__Host: $HOST
+__Range: bytes=${OFF_START}-${OFF_END}
+__Connection: close
+__
+
+# Content length = end_offset - start_offset + 1
+_OP $OFF_END SUB $OFF_START CLEN
+_OP $CLEN ADD 1 CLEN
+
+_EXPECT . "HTTP/1.1 206 Partial Content"
+_EXPECT . "Date:"
+_EXPECT . "Content-Range: bytes ${OFF_START}-${OFF_END}/${TEST_DOC_LEN}"
+_EXPECT . "Content-Length: $CLEN"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/ranges_test04.htt b/fluent-bit/lib/monkey/qa/ranges_test04.htt
new file mode 100644
index 000000000..8bb26d073
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/ranges_test04.htt
@@ -0,0 +1,45 @@
+###############################################################################
+# DESCRIPTION
+# Test partial content request. Range type is equal to the file size.
+# We expect this test to fail from server side as the file size is an
+# invalid offset, ranges starts from byte zero.
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# Jun 19 2013
+#
+# COMMENTS
+# RFC 2616 Section 10.4.17
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+# Start offset
+SET OFF_START=79718
+
+# End offset
+SET OFF_END=79718
+
+CLIENT
+_CALL INIT
+_CALL TESTDOC_GETSIZE
+
+_REQ $HOST $PORT
+__GET /img/mk_logo.png $HTTPVER
+__Host: $HOST
+__Range: bytes=${OFF_START}-${OFF_END}
+__Connection: close
+__
+
+# Content length = end_offset - start_offset + 1
+_OP $OFF_END SUB $OFF_START CLEN
+_OP $CLEN ADD 1 CLEN
+
+_EXPECT . "416 Requested Range Not Satisfiable"
+_EXPECT . "Date:"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/ranges_test05.htt b/fluent-bit/lib/monkey/qa/ranges_test05.htt
new file mode 100644
index 000000000..0e2ab1d83
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/ranges_test05.htt
@@ -0,0 +1,46 @@
+###############################################################################
+# DESCRIPTION
+# This test request one specific byte using the ranges HTTP feature,
+# the target file is imgs/monkey_logo.png, the byte number 3 contains
+# a value of 0x47 which is the letter 'G'.
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# Jun 19 2013
+#
+# COMMENTS
+# RFC 2616 Section 10.4.17
+###############################################################################
+
+
+INCLUDE __CONFIG
+INCLUDE __MACROS
+
+# Start offset
+SET OFF_START=3
+
+# End offset
+SET OFF_END=3
+
+CLIENT
+_CALL INIT
+_CALL TESTDOC_GETSIZE
+
+_REQ $HOST $PORT
+__GET /img/mk_logo.png $HTTPVER
+__Host: $HOST
+__Range: bytes=${OFF_START}-${OFF_END}
+__Connection: close
+__
+
+# Content length = end_offset - start_offset + 1
+_OP $OFF_END SUB $OFF_START CLEN
+_OP $CLEN ADD 1 CLEN
+
+_EXPECT . "HTTP/1.1 206 Partial Content"
+_EXPECT . "Date:"
+_EXPECT . "G"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/run_tests.sh b/fluent-bit/lib/monkey/qa/run_tests.sh
new file mode 100755
index 000000000..4c0b9fa75
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/run_tests.sh
@@ -0,0 +1,119 @@
+
+#!/bin/sh
+TEST_FILES=`ls *.htt`
+TOTAL_TESTS=`echo $TEST_FILES | wc -w`
+
+# Server parameters file
+CONFIG_FILE='__CONFIG'
+
+LOGFILE='errors.log'
+
+# Clear log file
+:>$LOGFILE
+
+# Should we stop at the first error? (yes | no)
+STOP_AT_ERRORS=no
+
+# httest error code for 'Connection refused'
+CONN_REFUSED=111
+
+# Enable colors in output :) (yes | no)
+WITH_COLOR=yes
+
+# httest command
+HTTEST_CMD='httest'
+
+NTEST=1
+TESTS_FAILED=0
+TESTS_OK=0
+TESTS_AVOIDED=0
+CHECKLOGS=0
+
+if [ "$1" = "-l" ]; then
+ CHECKLOGS=1
+ TOTAL_TESTS=`expr $TOTAL_TESTS \* 2`
+fi
+
+for test_file in $TEST_FILES; do
+# echo -ne "[TEST $NTEST/$TOTAL_TESTS]\t""case: $test_file\t\t"
+ printf "[%3d/%d] %-32s " $NTEST $TOTAL_TESTS "$test_file"
+
+ OUTPUT=`$HTTEST_CMD "$test_file" 2>&1`
+ ERRCODE=$?
+
+ case $ERRCODE in
+ 0)
+ TESTS_OK=$((TESTS_OK+1))
+ [ $WITH_COLOR = yes ] && echo -n ""
+ echo -n "=> [OK]"
+ [ $WITH_COLOR = yes ] && echo -n ""
+ ;;
+
+ $CONN_REFUSED)
+ echo
+ echo "Connection refused... (Is monkey running?)" >&2
+ exit $CONN_REFUSED
+ ;;
+
+ *)
+ TESTS_FAILED=$((TESTS_FAILED+1))
+ [ $WITH_COLOR = yes ] && echo -n ""
+ echo -n "=> [FAILED]"
+ [ $WITH_COLOR = yes ] && echo -n ""
+
+ perl -e 'print "-" x 78, "\n"' >>"$LOGFILE"
+ echo "$OUTPUT" >>"$LOGFILE"
+ perl -e 'print "-" x 78, "\n"' >>"$LOGFILE"
+
+ [ $STOP_AT_ERRORS = yes ] && exit 1
+ esac
+
+ # Check for logfiles rules
+ NTEST=$((NTEST+1))
+
+ if [ $CHECKLOGS = 0 ]; then
+ echo
+ continue
+ fi
+
+ echo
+ test_file=`echo $test_file | sed 's/\.htt/\.log/g'`
+ printf "[%3d/%d] %-32s " $NTEST $TOTAL_TESTS "$test_file"
+
+ if [ ! -e "log_rules/$test_file" ]; then
+ ERRCODE=2
+ else
+ # We need to sleep for a while as Monkey needs to flush
+ # the logs, that happens every 3 seconds
+ sleep 2
+ CHECKLOG=`./checklog -l log_rules/$test_file`
+ ERRCODE=$?
+ fi
+
+ case $ERRCODE in
+ 0)
+ [ $WITH_COLOR = yes ] && echo -n ""
+ echo "=> [OK]"
+ [ $WITH_COLOR = yes ] && echo -n ""
+ TESTS_OK=$((TESTS_OK+1))
+ ;;
+ 1)
+ [ $WITH_COLOR = yes ] && echo -n ""
+ echo "=> [FAILED]"
+ echo $CHECKLOG
+ [ $WITH_COLOR = yes ] && echo -n ""
+ TESTS_FAILED=$((TESTS_FAILED+1))
+ [ $STOP_AT_ERRORS = yes ] && exit 1
+ ;;
+
+ 2) [ $WITH_COLOR = yes ] && echo -n ""
+ echo "=> [NO RULES]"
+ [ $WITH_COLOR = yes ] && echo -n ""
+ TESTS_AVOIDED=$((TESTS_AVOIDED+1))
+ ;;
+ esac
+
+ NTEST=$((NTEST+1))
+done
+
+echo -e "\n$TESTS_OK test(s) succeeded, $TESTS_FAILED test(s) failed, $TESTS_AVOIDED test(s) avoided."
diff --git a/fluent-bit/lib/monkey/qa/simple.htt b/fluent-bit/lib/monkey/qa/simple.htt
new file mode 100644
index 000000000..a1538db1b
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/simple.htt
@@ -0,0 +1,26 @@
+################################################################################
+# DESCRIPTION
+# The most basic request: GET /
+#
+# AUTHOR
+# Carlos Ghan <charlie.brown.uy@gmail.com>
+#
+# DATE
+# June 29 2009
+#
+# COMMENTS
+# This test shouldn't fail ;)
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET / $HTTPVER
+__Host: $HOST
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 200 OK"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/uri_01.htt b/fluent-bit/lib/monkey/qa/uri_01.htt
new file mode 100644
index 000000000..a7c66f51c
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/uri_01.htt
@@ -0,0 +1,26 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 400
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# June 23 2010
+#
+# COMMENTS
+# Sending a bad request. The URI should contains a / at the beginning
+# This Bug was reported by Rodrigo Escobar <ipax@dclabs.com.br>
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA HTTP/1.0
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 400 Bad Request"
+_WAIT
+END
diff --git a/fluent-bit/lib/monkey/qa/uri_02.htt b/fluent-bit/lib/monkey/qa/uri_02.htt
new file mode 100644
index 000000000..3ab165689
--- /dev/null
+++ b/fluent-bit/lib/monkey/qa/uri_02.htt
@@ -0,0 +1,27 @@
+################################################################################
+# DESCRIPTION
+# Exercise error 400
+#
+# AUTHOR
+# Eduardo Silva <edsiper@gmail.com>
+#
+# DATE
+# June 23 2010
+#
+# COMMENTS
+# Sending a bad request. This request contain double \\ and miss the protocol
+# field.
+# This Bug was reported by Rodrigo Escobar <ipax@dclabs.com.br>
+################################################################################
+
+
+INCLUDE __CONFIG
+
+CLIENT
+_REQ $HOST $PORT
+__GET /\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
+__Connection: close
+__
+_EXPECT . "HTTP/1.1 400 Bad Request"
+_WAIT
+END