Squashed 'third_party/rawrtc/re/' changes from f3163ce8b..9384f3a5f

9384f3a5f Merge branch 'meson' into rawrtc-patched
9283ee693 Fix version
d9708ac30 Merge branch 'meson' into rawrtc-patched
f0cd32702 Remove unneeded define
bd224386a Rename library to avoid clashes
66b398f16 Fix comment
fe728e6db Fix 'fallthrough' warnings
f0da48e84 Generate pkg-config file
520a6c4b1 Allow to use as a Meson subproject
06786bb40 Update Meson build files
1f5b2b0f3 Fix Windows dependencies
a812e4ae4 Enhance ifaddrs.h check for Android
bf45d1b85 Enhance resolv.h check for Android
5183ad041 Add minimum Meson version
b2aed7ca6 Add Meson build system support
4681816b6 Merge branch 'master' into rawrtc-patched
7d837903a Merge branch 'tls-set-dh-params' into rawrtc-patched
485ee70f7 Merge branch 'support-fmt-h' into rawrtc-patched
954b25444 Merge branch 'pipe-epoll-fix' into rawrtc-patched
3a376df0c Merge branch 'dtls-socketless' into rawrtc-patched
7b52ff035 Merge branch 'dtls-configurable-headroom' into rawrtc-patched
762f98f51 Merge branch 'master' into rawrtc-patched
4deed71e1 Fix use `long` for `SSL_CTX_set_ecdh_auto` and `SSL_CTX_set_tmp_ecdh` return values
8c9828284 Explicitly use `long` as value for `SSL_CTX_set_ecdh_auto` call
3d990f602 Add the possibility to set Diffie-Hellman parameters Add `tls_set_dh_params_pem` and `tls_set_dh_params_der` function
631c8802b Handle %h prefixed (short) types in formatter functions
9db018131 Raise FD_EXCEPT on EPOLLHUP (fixes closed pipes)
97f455c17 Make headroom of an outgoing DTLS packet configurable
53ee9fab4 Return whether the packet has been handled in `dtls_receive`.
fcb10a0f1 Make it possible to create a DTLS socket without having an UDP socket underneath. Add `dtls_send_h` and `dtls_mtu_h` for DTLS in UDP socketless mode Add `dtls_socketless` and `dtls_receive` function Add `sendh` and `mtuh` fields to `struct dtls_socket`
9d1ba44a9 Merge branch 'dtls-configurable-headroom' into rawrtc-patched
3a6d31425 Make headroom of an outgoing DTLS packet configurable
6c90041a1 Merge branch 'dtls-socketless' into rawrtc-patched
244e02fbe Return whether the packet has been handled in `dtls_receive`.
cf8bceafa Merge branch 'master' into rawrtc-patched
f01cf0c84 Merge branch 'sdp-media-exclude-ldir' into rawrtc-patched
640b305c2 Merge branch 'sdp-media-address' into rawrtc-patched
ab1d110a4 Merge branch 'dtls-socketless' into rawrtc-patched
96110a7b8 Merge branch 'pipe-epoll-fix' into rawrtc-patched
0616c5ed5 Allow to exclude direction attribute
625c78750 Allow 'c='-line in SPD media to be explicitly set to unspecified
e2c464edb Allow 'c='-line in SPD media to be explicitly set to unspecified
57ca16a93 Make it possible to create a DTLS socket without having an UDP socket underneath. Add `dtls_send_h` and `dtls_mtu_h` for DTLS in UDP socketless mode Add `dtls_socketless` and `dtls_receive` function Add `sendh` and `mtuh` fields to `struct dtls_socket`
1c365017a Raise FD_EXCEPT on EPOLLHUP (fixes closed pipes)
585f196d9 Merge branch 'makefile-improvements' into rawrtc-patched
93b3fa3d9 Remove `install-static` target
728577bba Use `PREFIX ?= ...` instead of `ifndef`
3844e14f2 Less code duplication
c12309ad6 Use `PREFIX ?= ...` instead of `ifndef`
35f6d0bfc Less code duplication
6f1f67a56 Merge branch 'sdp-media-exclude-ldir' into rawrtc-patched
8aca84a34 Allow to exclude direction attribute
c70962258 Merge branch 'sdp-media-address' into rawrtc-patched
5bedf3b2c Allow 'c='-line in SPD media to be explicitly set to unspecified
d52e2df85 Merge branch 'support-fmt-h' into rawrtc-patched
ecc1a62f5 Handle %h prefixed (short) types in formatter functions
12ae81dc4 Merge branch 'tls-set-dh-params' into rawrtc-patched
3762eb8d0 Fix use `long` for `SSL_CTX_set_ecdh_auto` and `SSL_CTX_set_tmp_ecdh` return values
0fc077c02 Merge branch 'tls-set-dh-params' into rawrtc-patched
6abcc92ed Explicitly use `long` as value for `SSL_CTX_set_ecdh_auto` call
adbe6a67b Merge branch 'makefile-improvements' into rawrtc-patched
29b5a2b75 Remove `OPENSSL_SYSROOT` (`SYSROOT_ALT` should be sufficient)
df950db68 Merge branch 'makefile-improvements' into rawrtc-patched
0071283e0 Fix add include and libs directory when using `OPENSSL_SYSROOT`
114883ed2 Merge branch 'makefile-improvements' into rawrtc-patched
24ac34c83 Print OpenSSL sysroot on make info
b614d2eac Merge branch 'makefile-improvements' into rawrtc-patched
69da9f16f Add install-static option to Makefile
0ac7a62e2 Merge branch 'tls-set-dh-params' into rawrtc-patched
00a094574 Merge branch 'pipe-epoll-fix' into rawrtc-patched
8bf8b729b Merge branch 'dtls-socketless' into rawrtc-patched
ddc1ab1c9 Add Libs.private to pkg-config file Allow users to specify `PREFIX` in Makefile Allow users to specify the OpenSSL sysroot as `OPENSSL_SYSROOT` in Makefile
f05afb5be Add the possibility to set Diffie-Hellman parameters Add `tls_set_dh_params_pem` and `tls_set_dh_params_der` function
b3beb212e Raise FD_EXCEPT on EPOLLHUP (fixes closed pipes)
d7ee97f18 Make it possible to create a DTLS socket without having an UDP socket underneath. Add `dtls_send_h` and `dtls_mtu_h` for DTLS in UDP socketless mode Add `dtls_socketless` and `dtls_receive` function Add `sendh` and `mtuh` fields to `struct dtls_socket`

Change-Id: I389057b1a1e5685528a8bee9b65c03f3e083ef98
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: 9384f3a5f38a03c871270fda566045b3bf57bbee
diff --git a/include/meson.build b/include/meson.build
new file mode 100644
index 0000000..c9e1b30
--- /dev/null
+++ b/include/meson.build
@@ -0,0 +1,52 @@
+includes = files([
+    're.h',
+    're_aes.h',
+    're_base64.h',
+    're_bfcp.h',
+    're_bitv.h',
+    're_conf.h',
+    're_crc32.h',
+    're_dbg.h',
+    're_dns.h',
+    're_fmt.h',
+    're_hash.h',
+    're_hmac.h',
+    're_httpauth.h',
+    're_http.h',
+    're_ice.h',
+    're_jbuf.h',
+    're_json.h',
+    're_list.h',
+    're_lock.h',
+    're_main.h',
+    're_mbuf.h',
+    're_md5.h',
+    're_mem.h',
+    're_mod.h',
+    're_mqueue.h',
+    're_msg.h',
+    're_natbd.h',
+    're_net.h',
+    're_odict.h',
+    're_rtmp.h',
+    're_rtp.h',
+    're_sa.h',
+    're_sdp.h',
+    're_sha.h',
+    're_sipevent.h',
+    're_sip.h',
+    're_sipreg.h',
+    're_sipsess.h',
+    're_srtp.h',
+    're_stun.h',
+    're_sys.h',
+    're_tcp.h',
+    're_telev.h',
+    're_tls.h',
+    're_tmr.h',
+    're_turn.h',
+    're_types.h',
+    're_udp.h',
+    're_uri.h',
+    're_websock.h',
+])
diff --git a/include/re_sdp.h b/include/re_sdp.h
index f34bab5..457cb4d 100644
--- a/include/re_sdp.h
+++ b/include/re_sdp.h
@@ -99,6 +99,7 @@
 void sdp_media_set_lport_rtcp(struct sdp_media *m, uint16_t port);
 void sdp_media_set_laddr_rtcp(struct sdp_media *m, const struct sa *laddr);
 void sdp_media_set_ldir(struct sdp_media *m, enum sdp_dir dir);
+void sdp_media_ldir_exclude(struct sdp_media *m, bool exclude);
 int  sdp_media_set_lattr(struct sdp_media *m, bool replace,
 			 const char *name, const char *value, ...);
 void sdp_media_del_lattr(struct sdp_media *m, const char *name);
diff --git a/include/re_tls.h b/include/re_tls.h
index 05b3c93..09ad028 100644
--- a/include/re_tls.h
+++ b/include/re_tls.h
@@ -54,6 +54,8 @@
 		     uint8_t *srv_key, size_t srv_key_size);
 const char *tls_cipher_name(const struct tls_conn *tc);
 int tls_set_ciphers(struct tls *tls, const char *cipherv[], size_t count);
+int tls_set_dh_params_pem(struct tls *tls, const char *pem, size_t len);
+int tls_set_dh_params_der(struct tls *tls, const uint8_t *der, size_t len);
 int tls_set_servername(struct tls_conn *tc, const char *servername);
 
 
@@ -66,6 +68,9 @@
 /* UDP (DTLS) */
 
 typedef void (dtls_conn_h)(const struct sa *peer, void *arg);
+typedef int (dtls_send_h)(struct tls_conn *tc, const struct sa *dst,
+		struct mbuf *mb, void *arg);
+typedef size_t (dtls_mtu_h)(struct tls_conn *tc, void *arg);
 typedef void (dtls_estab_h)(void *arg);
 typedef void (dtls_recv_h)(struct mbuf *mb, void *arg);
 typedef void (dtls_close_h)(int err, void *arg);
@@ -75,8 +80,13 @@
 int dtls_listen(struct dtls_sock **sockp, const struct sa *laddr,
 		struct udp_sock *us, uint32_t htsize, int layer,
 		dtls_conn_h *connh, void *arg);
+int dtls_socketless(struct dtls_sock **sockp, uint32_t htsize,
+		dtls_conn_h *connh, dtls_send_h *sendh, dtls_mtu_h *mtuh,
+		void *arg);
 struct udp_sock *dtls_udp_sock(struct dtls_sock *sock);
 void dtls_set_mtu(struct dtls_sock *sock, size_t mtu);
+size_t dtls_headroom(struct dtls_sock *sock);
+void dtls_set_headroom(struct dtls_sock *sock, size_t headroom);
 int dtls_connect(struct tls_conn **ptc, struct tls *tls,
 		 struct dtls_sock *sock, const struct sa *peer,
 		 dtls_estab_h *estabh, dtls_recv_h *recvh,
@@ -86,6 +96,7 @@
 		dtls_estab_h *estabh, dtls_recv_h *recvh,
 		dtls_close_h *closeh, void *arg);
 int dtls_send(struct tls_conn *tc, struct mbuf *mb);
+bool dtls_receive(struct dtls_sock *sock, struct sa *src, struct mbuf *mb);
 void dtls_set_handlers(struct tls_conn *tc, dtls_estab_h *estabh,
 		       dtls_recv_h *recvh, dtls_close_h *closeh, void *arg);
 const struct sa *dtls_peer(const struct tls_conn *tc);
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..2757cff
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,373 @@
+# Project definition
+project('rawrre', 'c',
+    version: '0.6.0',
+    default_options: ['c_std=c99'],
+    meson_version: '>=0.46.0')
+
+# Set compiler warning flags
+compiler = meson.get_compiler('c')
+compiler_args = compiler.get_supported_arguments([
+    '-Wall',
+    '-Wmissing-declarations',
+    '-Wmissing-prototypes',
+    '-Wstrict-prototypes',
+    '-Wbad-function-cast',
+    '-Wsign-compare',
+    '-Wnested-externs',
+    '-Wshadow',
+    '-Waggregate-return',
+    '-Wcast-align',
+    '-Wextra',
+    '-Wold-style-definition',
+    '-Wdeclaration-after-statement',
+    '-Wuninitialized',  # TODO: Only when optimising? But why?
+    '-Wshorten-64-to-32',  # Apple-specific
+    '-pedantic',
+])
+add_project_arguments(compiler_args, language: 'c')
+
+# TODO: Include -g flag for extra debug stuff?
+# TODO: Optimise for speed or size?
+
+# Configuration
+# TODO: Generate a configuration file instead of defining? Would simplify the
+#       configuration.
+#       This would allow projects depending on this able to import those
+#       defines, too.
+compile_args = []
+configuration = configuration_data()
+
+# OS
+system = host_machine.system()
+add_project_arguments('-DOS="@0@"'.format(system), language: 'c')
+configuration.set_quoted('OS', system)
+if system == 'darwin'
+    add_project_arguments('-DDARWIN', language: 'c')
+    configuration.set('DARWIN', 1)
+elif system == 'dragonfly'
+    add_project_arguments('-DDRAGONFLY', language: 'c')
+    configuration.set('DRAGONFLY', 1)
+elif system == 'freebsd'
+    add_project_arguments('-DFREEBSD', language: 'c')
+    configuration.set('FREEBSD', 1)
+elif system == 'gnu'
+    add_project_arguments('-DGNU', language: 'c')
+    configuration.set('GNU', 1)
+elif system == 'gnu/kfreebsd'
+    add_project_arguments(
+        '-DKFREEBSD',
+        '-D_GNU_SOURCE',
+        language: 'c')
+    configuration.set('GNU', 1)
+    configuration.set('_GNU_SOURCE', 1)
+elif system == 'linux'
+    add_project_arguments('-DLINUX', language: 'c')
+    configuration.set('LINUX', 1)
+elif system == 'netbsd'
+    add_project_arguments('-DDNETBSD', language: 'c')
+    configuration.set('NETBSD', 1)
+elif system == 'sunos'
+    add_project_arguments('-DSOLARIS', language: 'c')
+    configuration.set('SOLARIS', 1)
+    compile_args += '-DSOLARIS'
+elif system == 'windows'
+    add_project_arguments('-DWIN32', language: 'c')
+    configuration.set('WIN32', 1)
+    compile_args += '-DWIN32'
+else
+    warning('Unhandled OS: @0@'.format(system))
+endif
+
+# Architecture
+cpu = host_machine.cpu()
+add_project_arguments('-DARCH="@0@"'.format(cpu), language: 'c')
+configuration.set_quoted('ARCH', cpu)
+
+# Dependency: Threads
+# TODO: Make this overridable
+thread_dep = dependency('threads', required: false)
+
+# Dependency: OpenSSL
+openssl_dep = dependency('openssl', version: '>=0.9.8', required: false)
+# TODO: Make this overridable
+if openssl_dep.found()
+    add_project_arguments(
+        '-DUSE_OPENSSL',
+        '-DUSE_TLS',
+        language: 'c')
+    configuration.set('USE_OPENSSL', 1)
+    configuration.set('USE_TLS', 1)
+    compile_args += '-DUSE_OPENSSL'
+
+    # Check for DTLS
+    if compiler.has_header('openssl/dtls1.h')
+        add_project_arguments(
+            '-DUSE_OPENSSL_DTLS',
+            '-DUSE_DTLS',
+            language: 'c')
+        configuration.set('USE_OPENSSL_DTLS', 1)
+        configuration.set('USE_DTLS', 1)
+    endif
+
+    # Check for SRTP
+    if compiler.has_header('openssl/srtp.h')
+        add_project_arguments(
+            '-DUSE_OPENSSL_SRTP',
+            '-DUSE_DTLS_SRTP',
+            language: 'c')
+        configuration.set('USE_OPENSSL_SRTP', 1)
+        configuration.set('USE_DTLS_SRTP', 1)
+    endif
+endif
+
+# Dependency: zlib
+# TODO: Make this overridable
+# TODO: Arbitrary version, ask maintainers
+zlib_dep = dependency('zlib', version: '>=1.2.8', required: false)
+if zlib_dep.found()
+    add_project_arguments('-DUSE_ZLIB', language: 'c')
+    configuration.set('USE_ZLIB', 1)
+    compile_args += '-DUSE_ZLIB'
+endif
+
+# Dependencies list
+dependencies = [
+    thread_dep,
+    openssl_dep,
+    zlib_dep,
+]
+
+# Features: Common
+add_project_arguments(
+    '-DHAVE_INET6',
+    '-DHAVE_SELECT',
+    '-DHAVE_STDBOOL_H',
+    language: 'c')
+configuration.set('HAVE_INET6', 1)
+configuration.set('HAVE_SELECT', 1)
+configuration.set('HAVE_STDBOOL_H', 1)
+compile_args += [
+    '-DHAVE_INET6',
+    '-DHAVE_STDBOOL_H',
+]
+
+# Features: Check for fixed size integer types
+if compiler.has_header('inttypes.h')
+    add_project_arguments('-DHAVE_INTTYPES_H', language: 'c')
+    configuration.set('HAVE_INTTYPES_H', 1)
+    compile_args += '-DHAVE_INTTYPES_H'
+endif
+
+# Features: Check for route
+have_net_route = compiler.has_header('net/route.h')
+if have_net_route
+    add_project_arguments('-DHAVE_NET_ROUTE_H', language: 'c')
+    configuration.set('HAVE_NET_ROUTE_H', 1)
+endif
+
+# Features: Check for sysctl
+have_sysctl = compiler.has_header('sys/sysctl.h')
+if have_sysctl
+    add_project_arguments('-DHAVE_SYS_SYSCTL_H', language: 'c')
+    configuration.set('HAVE_SYS_SYSCTL_H', 1)
+endif
+
+# Features: OS-specific
+if system == 'windows'
+    # Windows
+    add_project_arguments(
+        '-DHAVE_IO_H',
+        '-D_WIN32_WINNT=0x0501',
+        '-D__ssize_t_defined',
+        language: 'c')
+    configuration.set('HAVE_IO_H', 1)
+    configuration.set('_WIN32_WINNT', 0x0501)
+    configuration.set('__ssize_t_defined', 1)
+    compile_args += '-D__ssize_t_defined'
+
+    # Additional linking
+    dependencies += compiler.find_library('wsock32', required: true)
+    dependencies += compiler.find_library('ws2_32', required: true)
+    dependencies += compiler.find_library('iphlpapi', required: true)
+
+    # TODO: APP_LFLAGS	+= -Wl,--export-all-symbols
+else
+    # UNIX
+    add_project_arguments(
+        '-DHAVE_FORK',
+        '-DHAVE_INET_NTOP',
+        '-DHAVE_PWD_H',
+        '-DHAVE_SELECT_H',
+        '-DHAVE_SETRLIMIT',
+        '-DHAVE_SIGNAL',
+        '-DHAVE_STRERROR_R',
+        '-DHAVE_STRINGS_H',
+        '-DHAVE_SYS_TIME_H',
+        '-DHAVE_UNAME',
+        '-DHAVE_UNISTD_H',
+        language: 'c')
+    configuration.set('HAVE_FORK', 1)
+    configuration.set('HAVE_INET_NTOP', 1)
+    configuration.set('HAVE_PWD_H', 1)
+    configuration.set('HAVE_SELECT_H', 1)
+    configuration.set('HAVE_SETRLIMIT', 1)
+    configuration.set('HAVE_SIGNAL', 1)
+    configuration.set('HAVE_STRERROR_R', 1)
+    configuration.set('HAVE_STRINGS_H', 1)
+    configuration.set('HAVE_SYS_TIME_H', 1)
+    configuration.set('HAVE_UNAME', 1)
+    configuration.set('HAVE_UNISTD_H', 1)
+
+    # Solaris requires some additional linking
+    if system == 'sunos'
+        dependencies += compiler.find_library('socket', required: true)
+        dependencies += compiler.find_library('nsl', required: true)
+    endif
+
+    # Check for pthread
+    if compiler.has_header('pthread.h')
+        add_project_arguments('-DHAVE_PTHREAD', language: 'c')
+        configuration.set('HAVE_PTHREAD', 1)
+    endif
+
+    # Check for ifaddrs
+    ifaddrs_prefix = '''
+    #include <sys/socket.h>
+    #define __USE_MISC 1   /**< Use MISC code */
+    #include <net/if.h>
+    #include <ifaddrs.h>
+    '''
+    if compiler.has_function('getifaddrs', prefix: ifaddrs_prefix)
+        add_project_arguments('-DHAVE_GETIFADDRS', language: 'c')
+        configuration.set('HAVE_GETIFADDRS', 1)
+    endif
+
+    # Check for dlfcn
+    if compiler.has_header('dlfcn.h')
+        # Linux, GNU and Solaris require linking
+        if system == 'linux' or system == 'gnu' or system == 'sunos'
+            dependencies += compiler.find_library('dl', required: true)
+        endif
+        add_project_link_arguments('-rdynamic', language: 'c')
+        add_project_arguments('-DHAVE_DLFCN', language: 'c')
+        configuration.set('HAVE_DLFCN', 1)
+    endif
+
+    # Check for epoll
+    if compiler.has_header('sys/epoll.h')
+        add_project_arguments('-DHAVE_EPOLL', language: 'c')
+        configuration.set('HAVE_EPOLL', 1)
+    endif
+
+    # Check for resolv
+    resolv_prefix = '''
+    #define _BSD_SOURCE 1
+    #define _DEFAULT_SOURCE 1
+    #include <sys/types.h>
+    #include <netinet/in.h>
+    #include <arpa/nameser.h>
+    #include <resolv.h>
+    '''
+    if compiler.has_type('struct __res_state', prefix: resolv_prefix)
+        # OSX/iOS and Solaris require linking
+        if system == 'darwin' or system == 'sunos'
+            dependencies += compiler.find_library('resolv', required: true)
+        endif
+        add_project_arguments('-DHAVE_RESOLV', language: 'c')
+        configuration.set('HAVE_RESOLV', 1)
+    endif
+
+    # Check for kqueue
+    kqueue_prefix = '''
+    #include <sys/types.h>
+    #include <sys/event.h>
+    #include <sys/time.h>
+    '''
+    if compiler.has_function('kqueue', prefix: kqueue_prefix)
+        add_project_arguments('-DHAVE_KQUEUE', language: 'c')
+        configuration.set('HAVE_KQUEUE', 1)
+    endif
+
+    # Check for arc4random
+    if compiler.has_function('arc4random', prefix: '#include <stdlib.h>')
+        add_project_arguments('-DHAVE_ARC4RANDOM', language: 'c')
+        configuration.set('HAVE_ARC4RANDOM', 1)
+    endif
+
+    # Features OSX/iOS is lacking
+    if not (system == 'darwin')
+        # OSX/iOS's poll() does not support devices
+        add_project_arguments(
+            '-DHAVE_POLL',
+            '-DHAVE_INET_PTON',
+            language: 'c')
+        configuration.set('HAVE_POLL', 1)
+        configuration.set('HAVE_INET_PTON', 1)
+    endif
+endif
+
+# Features: Routing for Linux and *BSD
+if system == 'linux' or (have_sysctl and have_net_route)
+    add_project_arguments('-DHAVE_ROUTE_LIST', language: 'c')
+    configuration.set('HAVE_ROUTE_LIST', 1)
+endif
+
+# Version
+version = meson.project_version()
+version_array = version.split('.')
+add_project_arguments(
+    '-DVERSION="@0@"'.format(version),
+    '-DVER_MAJOR=@0@'.format(version_array[0]),
+    '-DVER_MINOR=@0@'.format(version_array[1]),
+    '-DVER_PATCH=@0@'.format(version_array[2]),
+    language: 'c')
+configuration.set_quoted('VERSION', version)
+configuration.set('VER_MAJOR', version_array[0])
+configuration.set('VER_MINOR', version_array[1])
+configuration.set('VER_PATCH', version_array[2])
+
+# TODO: Define 'RELEASE' when using build type 'release'
+#       Also, compile_args += '-DMBUF_DEBUG=1' in that case
+# TODO: Check if we need to do anything for gcov
+# TODO: Check if we need to do anything for GNU profiling
+# TODO: Port packaging section
+# TODO: Port clang section
+# TODO: Port documentation section
+
+# Includes
+include_dir = include_directories('include')
+subdir('include')
+
+# Sources & Modules
+# TODO: Make which to build configurable
+subdir('src')
+
+# Build library
+re = library(meson.project_name(), sources,
+    dependencies: dependencies,
+    include_directories: include_dir,
+    install: true,
+    version: version)
+
+# Install headers
+install_headers(includes, subdir: 're')
+
+# Declare dependency
+re_dep = declare_dependency(
+    compile_args: compile_args,
+    include_directories: include_dir,
+    link_with: re)
+
+# Generate pkg-config file
+pkg = import('pkgconfig')
+description = '''Generic library for real-time communications with
+                 async IO support'''
+description = ' '.join(description.split())
+pkg.generate(re,
+    name: 'libre',
+    description: description,
+    url: 'http://www.creytiv.com/re.html',
+    extra_cflags: compile_args,  # https://github.com/creytiv/re/issues/167
+    subdirs: 're')
+
+# TODO: Ensure 'install' has the same result as when invoking 'make'
diff --git a/src/aes/meson.build b/src/aes/meson.build
new file mode 100644
index 0000000..6f869ca
--- /dev/null
+++ b/src/aes/meson.build
@@ -0,0 +1,6 @@
+# TODO: What about apple/aes.c?
+if openssl_dep.found()
+    sources += files('openssl/aes.c')
+else
+    sources += files('stub.c')
+endif
diff --git a/src/base64/meson.build b/src/base64/meson.build
new file mode 100644
index 0000000..5b6f4ff
--- /dev/null
+++ b/src/base64/meson.build
@@ -0,0 +1 @@
+sources += files('b64.c')
diff --git a/src/bfcp/meson.build b/src/bfcp/meson.build
new file mode 100644
index 0000000..8e333b0
--- /dev/null
+++ b/src/bfcp/meson.build
@@ -0,0 +1,7 @@
+sources += files([
+    'attr.c',
+    'conn.c',
+    'msg.c',
+    'reply.c',
+    'request.c',
+])
diff --git a/src/conf/meson.build b/src/conf/meson.build
new file mode 100644
index 0000000..ea1c1cfc
--- /dev/null
+++ b/src/conf/meson.build
@@ -0,0 +1 @@
+sources += files('conf.c')
diff --git a/src/crc32/meson.build b/src/crc32/meson.build
new file mode 100644
index 0000000..f073ff7
--- /dev/null
+++ b/src/crc32/meson.build
@@ -0,0 +1,3 @@
+if not zlib_dep.found()
+    sources += files('crc32.c')
+endif
diff --git a/src/dbg/meson.build b/src/dbg/meson.build
new file mode 100644
index 0000000..7c71321
--- /dev/null
+++ b/src/dbg/meson.build
@@ -0,0 +1 @@
+sources += files('dbg.c')
diff --git a/src/dns/meson.build b/src/dns/meson.build
new file mode 100644
index 0000000..cfd6aa0
--- /dev/null
+++ b/src/dns/meson.build
@@ -0,0 +1,23 @@
+sources += files([
+    'client.c',
+    'cstr.c',
+    'dname.c',
+    'hdr.c',
+    'ns.c',
+    'rr.c',
+    'rrlist.c',
+])
+
+if configuration.has('HAVE_RESOLV')
+    sources += files('res.c')
+endif
+
+if system == 'windows'
+    sources += files('win32/srv.c')
+elif system == 'darwin'
+    sources += files('darwin/srv.c')
+    dependencies += dependency(
+        'appleframeworks',
+        modules: ['SystemConfiguration', 'CoreFoundation'],
+        required: true)
+endif
diff --git a/src/fmt/meson.build b/src/fmt/meson.build
new file mode 100644
index 0000000..bcc4750
--- /dev/null
+++ b/src/fmt/meson.build
@@ -0,0 +1,12 @@
+sources += files([
+    'ch.c',
+    'hexdump.c',
+    'pl.c',
+    'print.c',
+    'prm.c',
+    'regex.c',
+    'str.c',
+    'str_error.c',
+    'time.c',
+    'unicode.c',
+])
diff --git a/src/fmt/print.c b/src/fmt/print.c
index 85e9ebf..c0247b4 100644
--- a/src/fmt/print.c
+++ b/src/fmt/print.c
@@ -303,6 +303,11 @@
 			}
 			break;
 
+		case 'h':
+			lenmod = LENMOD_NONE;
+			fm = true;
+			break;
+
 		case 'H':
 			ph     = va_arg(ap, re_printf_h *);
 			ph_arg = va_arg(ap, void *);
diff --git a/src/hash/func.c b/src/hash/func.c
index 3943c94..f379904 100644
--- a/src/hash/func.c
+++ b/src/hash/func.c
@@ -312,20 +312,19 @@
 			k += 12;
 		}
 
-		/* all the case statements fall through */
 		switch (length) {
 
-		case 12: c+=((uint32_t)k[11])<<24;
-		case 11: c+=((uint32_t)k[10])<<16;
-		case 10: c+=((uint32_t)k[9])<<8;
-		case 9 : c+=k[8];
-		case 8 : b+=((uint32_t)k[7])<<24;
-		case 7 : b+=((uint32_t)k[6])<<16;
-		case 6 : b+=((uint32_t)k[5])<<8;
-		case 5 : b+=k[4];
-		case 4 : a+=((uint32_t)k[3])<<24;
-		case 3 : a+=((uint32_t)k[2])<<16;
-		case 2 : a+=((uint32_t)k[1])<<8;
+		case 12: c+=((uint32_t)k[11])<<24; /* fall through */
+		case 11: c+=((uint32_t)k[10])<<16; /* fall through */
+		case 10: c+=((uint32_t)k[9])<<8;   /* fall through */
+		case 9 : c+=k[8];                  /* fall through */
+		case 8 : b+=((uint32_t)k[7])<<24;  /* fall through */
+		case 7 : b+=((uint32_t)k[6])<<16;  /* fall through */
+		case 6 : b+=((uint32_t)k[5])<<8;   /* fall through */
+		case 5 : b+=k[4];                  /* fall through */
+		case 4 : a+=((uint32_t)k[3])<<24;  /* fall through */
+		case 3 : a+=((uint32_t)k[2])<<16;  /* fall through */
+		case 2 : a+=((uint32_t)k[1])<<8;   /* fall through */
 		case 1 : a+=k[0];
 			break;
 		case 0 : return c;
diff --git a/src/hash/meson.build b/src/hash/meson.build
new file mode 100644
index 0000000..57d8c12
--- /dev/null
+++ b/src/hash/meson.build
@@ -0,0 +1,4 @@
+sources += files([
+    'hash.c',
+    'func.c',
+])
diff --git a/src/hmac/meson.build b/src/hmac/meson.build
new file mode 100644
index 0000000..7a7293a
--- /dev/null
+++ b/src/hmac/meson.build
@@ -0,0 +1,8 @@
+sources += files('hmac_sha1.c')
+
+# TODO: What about apple/hmac.c?
+if openssl_dep.found()
+    sources += files('openssl/hmac.c')
+else
+    sources += files('hmac.c')
+endif
diff --git a/src/http/meson.build b/src/http/meson.build
new file mode 100644
index 0000000..3ee5939
--- /dev/null
+++ b/src/http/meson.build
@@ -0,0 +1,7 @@
+sources += files([
+    'auth.c',
+    'chunk.c',
+    'client.c',
+    'msg.c',
+    'server.c',
+])
diff --git a/src/httpauth/meson.build b/src/httpauth/meson.build
new file mode 100644
index 0000000..2ad5862
--- /dev/null
+++ b/src/httpauth/meson.build
@@ -0,0 +1,4 @@
+sources += files([
+    'basic.c',
+    'digest.c',
+])
diff --git a/src/ice/meson.build b/src/ice/meson.build
new file mode 100644
index 0000000..be63f72
--- /dev/null
+++ b/src/ice/meson.build
@@ -0,0 +1,12 @@
+sources += files([
+    'cand.c',
+    'candpair.c',
+    'chklist.c',
+    'comp.c',
+    'connchk.c',
+    'icem.c',
+    'icesdp.c',
+    'icestr.c',
+    'stunsrv.c',
+    'util.c',
+])
diff --git a/src/jbuf/meson.build b/src/jbuf/meson.build
new file mode 100644
index 0000000..1b11bc8
--- /dev/null
+++ b/src/jbuf/meson.build
@@ -0,0 +1 @@
+sources += files('jbuf.c')
diff --git a/src/json/meson.build b/src/json/meson.build
new file mode 100644
index 0000000..f5461df
--- /dev/null
+++ b/src/json/meson.build
@@ -0,0 +1,5 @@
+sources += files([
+    'decode.c',
+    'decode_odict.c',
+    'encode.c',
+])
diff --git a/src/list/meson.build b/src/list/meson.build
new file mode 100644
index 0000000..2027364
--- /dev/null
+++ b/src/list/meson.build
@@ -0,0 +1 @@
+sources += files('list.c')
diff --git a/src/lock/meson.build b/src/lock/meson.build
new file mode 100644
index 0000000..bd400bd
--- /dev/null
+++ b/src/lock/meson.build
@@ -0,0 +1,8 @@
+# TODO: What about lock.c?
+if configuration.has('HAVE_PTHREAD')
+    sources += files('rwlock.c')
+endif
+
+if system == 'windows'
+    sources += files('win32/lock.c')
+endif
diff --git a/src/main/main.c b/src/main/main.c
index b90c139..0243b4b 100644
--- a/src/main/main.c
+++ b/src/main/main.c
@@ -786,6 +786,8 @@
 				flags |= FD_WRITE;
 			if (re->events[i].events & (EPOLLERR|EPOLLHUP))
 				flags |= FD_EXCEPT;
+			if (re->events[i].events & EPOLLHUP)
+				flags |= FD_EXCEPT;
 
 			if (!flags) {
 				DEBUG_WARNING("epoll: no flags fd=%d\n", fd);
diff --git a/src/main/meson.build b/src/main/meson.build
new file mode 100644
index 0000000..f0a5b98
--- /dev/null
+++ b/src/main/meson.build
@@ -0,0 +1,13 @@
+sources += files([
+    'init.c',
+    'main.c',
+    'method.c',
+])
+
+if configuration.has('HAVE_EPOLL')
+    sources += files('epoll.c')
+endif
+
+if openssl_dep.found()
+    sources += files('openssl.c')
+endif
diff --git a/src/mbuf/meson.build b/src/mbuf/meson.build
new file mode 100644
index 0000000..eaec9d1
--- /dev/null
+++ b/src/mbuf/meson.build
@@ -0,0 +1 @@
+sources += files('mbuf.c')
diff --git a/src/md5/meson.build b/src/md5/meson.build
new file mode 100644
index 0000000..547a2fc
--- /dev/null
+++ b/src/md5/meson.build
@@ -0,0 +1,5 @@
+if not openssl_dep.found()
+    sources += files('md5.c')
+endif
+
+sources += files('wrap.c')
diff --git a/src/mem/meson.build b/src/mem/meson.build
new file mode 100644
index 0000000..3e15795
--- /dev/null
+++ b/src/mem/meson.build
@@ -0,0 +1,4 @@
+sources += files([
+    'mem.c',
+    'secure.c',
+])
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 0000000..aa5ff49
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,50 @@
+sources = []
+
+# Modules
+subdir('aes')
+subdir('base64')
+subdir('bfcp')
+subdir('conf')
+subdir('crc32')
+subdir('dbg')
+subdir('dns')
+subdir('fmt')
+subdir('hash')
+subdir('hmac')
+subdir('http')
+subdir('httpauth')
+subdir('ice')
+subdir('jbuf')
+subdir('json')
+subdir('list')
+subdir('lock')
+subdir('main')
+subdir('mbuf')
+subdir('md5')
+subdir('mem')
+subdir('mod')
+subdir('mqueue')
+subdir('msg')
+subdir('natbd')
+subdir('net')
+subdir('odict')
+subdir('rtmp')
+subdir('rtp')
+subdir('sa')
+subdir('sdp')
+subdir('sha')
+subdir('sip')
+subdir('sipevent')
+subdir('sipreg')
+subdir('sipsess')
+subdir('srtp')
+subdir('stun')
+subdir('sys')
+subdir('tcp')
+subdir('telev')
+subdir('tls')
+subdir('tmr')
+subdir('turn')
+subdir('udp')
+subdir('uri')
+subdir('websock')
diff --git a/src/mod/meson.build b/src/mod/meson.build
new file mode 100644
index 0000000..eb9a306
--- /dev/null
+++ b/src/mod/meson.build
@@ -0,0 +1,9 @@
+sources += files('mod.c')
+
+if configuration.has('HAVE_DLFCN')
+    sources += files('dl.c')
+endif
+
+if system == 'windows'
+    sources += files('win32/dll.c')
+endif
diff --git a/src/mqueue/meson.build b/src/mqueue/meson.build
new file mode 100644
index 0000000..65d6d5b
--- /dev/null
+++ b/src/mqueue/meson.build
@@ -0,0 +1,5 @@
+sources += files('mqueue.c')
+
+if system == 'windows'
+    sources += files('win32/pipe.c')
+endif
diff --git a/src/msg/meson.build b/src/msg/meson.build
new file mode 100644
index 0000000..a70396e
--- /dev/null
+++ b/src/msg/meson.build
@@ -0,0 +1,4 @@
+sources += files([
+    'ctype.c',
+    'param.c',
+])
diff --git a/src/natbd/meson.build b/src/natbd/meson.build
new file mode 100644
index 0000000..523d452
--- /dev/null
+++ b/src/natbd/meson.build
@@ -0,0 +1,8 @@
+sources += files([
+    'filtering.c',
+    'genalg.c',
+    'hairpinning.c',
+    'lifetime.c',
+    'mapping.c',
+    'natstr.c',
+])
diff --git a/src/net/meson.build b/src/net/meson.build
new file mode 100644
index 0000000..1408fed
--- /dev/null
+++ b/src/net/meson.build
@@ -0,0 +1,26 @@
+sources += files([
+    'if.c',
+    'net.c',
+    'netstr.c',
+    'rt.c',
+    'sock.c',
+    'sockopt.c',
+])
+
+if system == 'windows'
+    sources += files('win32/wif.c')
+else
+    sources += files('posix/pif.c')
+endif
+
+if configuration.has('HAVE_ROUTE_LIST')
+    if system == 'linux'
+        sources += files('linux/rt.c')
+    else
+        sources += files('bsd/brt.c')
+    endif
+endif
+
+if configuration.has('HAVE_GETIFADDRS')
+    sources += files('ifaddrs.c')
+endif
diff --git a/src/odict/meson.build b/src/odict/meson.build
new file mode 100644
index 0000000..8ac0cde
--- /dev/null
+++ b/src/odict/meson.build
@@ -0,0 +1,6 @@
+sources += files([
+    'entry.c',
+    'odict.c',
+    'type.c',
+    'get.c',
+])
diff --git a/src/rtmp/meson.build b/src/rtmp/meson.build
new file mode 100644
index 0000000..78a6214
--- /dev/null
+++ b/src/rtmp/meson.build
@@ -0,0 +1,12 @@
+sources += files([
+    'amf.c',
+    'amf_dec.c',
+    'amf_enc.c',
+    'chunk.c',
+    'conn.c',
+    'control.c',
+    'ctrans.c',
+    'dechunk.c',
+    'hdr.c',
+    'stream.c',
+])
diff --git a/src/rtp/meson.build b/src/rtp/meson.build
new file mode 100644
index 0000000..0fc1506
--- /dev/null
+++ b/src/rtp/meson.build
@@ -0,0 +1,12 @@
+sources += files([
+    'fb.c',
+    'member.c',
+    'ntp.c',
+    'pkt.c',
+    'rr.c',
+    'rtcp.c',
+    'rtp.c',
+    'sdes.c',
+    'sess.c',
+    'source.c',
+])
diff --git a/src/sa/meson.build b/src/sa/meson.build
new file mode 100644
index 0000000..92e8cbe
--- /dev/null
+++ b/src/sa/meson.build
@@ -0,0 +1,6 @@
+sources += files([
+    'ntop.c',
+    'printaddr.c',
+    'pton.c',
+    'sa.c',
+])
diff --git a/src/sdp/media.c b/src/sdp/media.c
index 07ce3a2..05e769c 100644
--- a/src/sdp/media.c
+++ b/src/sdp/media.c
@@ -446,6 +446,7 @@
 	if (!m || !laddr)
 		return;
 
+	m->flags |= MEDIA_LADDR_SET;
 	m->laddr = *laddr;
 }
 
@@ -513,6 +514,25 @@
 
 
 /**
+ * Set whether the local direction flag of an SDP media line should be excluded
+ * when encoding. Defaults to false.
+ *
+ * @param m       SDP Media line
+ * @param exclude Exclude direction flag
+ */
+void sdp_media_ldir_exclude(struct sdp_media *m, bool exclude)
+{
+	if (!m)
+		return;
+
+	if (exclude)
+		m->flags |= MEDIA_LDIR_EXCLUDE;
+	else
+		m->flags &= ~MEDIA_LDIR_EXCLUDE;
+}
+
+
+/**
  * Set a local attribute of an SDP Media line
  *
  * @param m       SDP Media line
diff --git a/src/sdp/meson.build b/src/sdp/meson.build
new file mode 100644
index 0000000..03b62dd
--- /dev/null
+++ b/src/sdp/meson.build
@@ -0,0 +1,9 @@
+sources += files([
+    'attr.c',
+    'format.c',
+    'media.c',
+    'msg.c',
+    'session.c',
+    'str.c',
+    'util.c',
+])
diff --git a/src/sdp/msg.c b/src/sdp/msg.c
index c1a8bbc..82b8905 100644
--- a/src/sdp/msg.c
+++ b/src/sdp/msg.c
@@ -398,7 +398,7 @@
 
 	err |= mbuf_write_str(mb, "\r\n");
 
-	if (sa_isset(&m->laddr, SA_ADDR)) {
+	if (m->flags & MEDIA_LADDR_SET) {
 		const int ipver = sa_af(&m->laddr) == AF_INET ? 4 : 6;
 		err |= mbuf_printf(mb, "c=IN IP%d %j\r\n", ipver, &m->laddr);
 	}
@@ -443,8 +443,10 @@
 		err |= mbuf_printf(mb, "a=rtcp:%u\r\n",
 				   sa_port(&m->laddr_rtcp));
 
-	err |= mbuf_printf(mb, "a=%s\r\n",
-			   sdp_dir_name(offer ? m->ldir : m->ldir & m->rdir));
+	if (!(m->flags & MEDIA_LDIR_EXCLUDE))
+		err |= mbuf_printf(mb, "a=%s\r\n",
+				   sdp_dir_name(offer ? m->ldir :
+						m->ldir & m->rdir));
 
 	for (le = m->lattrl.head; le; le = le->next)
 		err |= mbuf_printf(mb, "%H", sdp_attr_print, le->data);
diff --git a/src/sdp/sdp.h b/src/sdp/sdp.h
index f0588d1..604082a 100644
--- a/src/sdp/sdp.h
+++ b/src/sdp/sdp.h
@@ -10,6 +10,11 @@
 	RTP_DYNPT_END   = 127,
 };
 
+enum {
+	MEDIA_LADDR_SET = 1<<0,
+	MEDIA_LDIR_EXCLUDE = 1<<1,
+};
+
 
 struct sdp_session {
 	struct list lmedial;
@@ -27,6 +32,7 @@
 
 struct sdp_media {
 	struct le le;
+	uint8_t flags;
 	struct list lfmtl;
 	struct list rfmtl;
 	struct list lattrl;
diff --git a/src/sha/meson.build b/src/sha/meson.build
new file mode 100644
index 0000000..387b6b5
--- /dev/null
+++ b/src/sha/meson.build
@@ -0,0 +1,3 @@
+if not openssl_dep.found()
+    sources += files('sha1.c')
+endif
diff --git a/src/sip/meson.build b/src/sip/meson.build
new file mode 100644
index 0000000..f80c6e9
--- /dev/null
+++ b/src/sip/meson.build
@@ -0,0 +1,17 @@
+sources += files([
+    'addr.c',
+    'auth.c',
+    'contact.c',
+    'cseq.c',
+    'ctrans.c',
+    'dialog.c',
+    'keepalive.c',
+    'keepalive_udp.c',
+    'msg.c',
+    'reply.c',
+    'request.c',
+    'sip.c',
+    'strans.c',
+    'transp.c',
+    'via.c',
+])
diff --git a/src/sipevent/meson.build b/src/sipevent/meson.build
new file mode 100644
index 0000000..543aa84
--- /dev/null
+++ b/src/sipevent/meson.build
@@ -0,0 +1,6 @@
+sources += files([
+    'listen.c',
+    'msg.c',
+    'notify.c',
+    'subscribe.c',
+])
diff --git a/src/sipreg/meson.build b/src/sipreg/meson.build
new file mode 100644
index 0000000..0e7bb02
--- /dev/null
+++ b/src/sipreg/meson.build
@@ -0,0 +1 @@
+sources += files('reg.c')
diff --git a/src/sipsess/meson.build b/src/sipsess/meson.build
new file mode 100644
index 0000000..4731317
--- /dev/null
+++ b/src/sipsess/meson.build
@@ -0,0 +1,12 @@
+sources += files([
+    'sess.c',
+    'accept.c',
+    'ack.c',
+    'close.c',
+    'connect.c',
+    'info.c',
+    'listen.c',
+    'modify.c',
+    'reply.c',
+    'request.c',
+])
diff --git a/src/srtp/meson.build b/src/srtp/meson.build
new file mode 100644
index 0000000..eb56909
--- /dev/null
+++ b/src/srtp/meson.build
@@ -0,0 +1,7 @@
+sources += files([
+    'misc.c',
+    'replay.c',
+    'srtcp.c',
+    'srtp.c',
+    'stream.c',
+])
diff --git a/src/stun/meson.build b/src/stun/meson.build
new file mode 100644
index 0000000..5f0a018
--- /dev/null
+++ b/src/stun/meson.build
@@ -0,0 +1,14 @@
+sources += files([
+    'addr.c',
+    'attr.c',
+    'ctrans.c',
+    'dnsdisc.c',
+    'hdr.c',
+    'ind.c',
+    'keepalive.c',
+    'msg.c',
+    'rep.c',
+    'req.c',
+    'stun.c',
+    'stunstr.c',
+])
diff --git a/src/sys/meson.build b/src/sys/meson.build
new file mode 100644
index 0000000..7ffb335
--- /dev/null
+++ b/src/sys/meson.build
@@ -0,0 +1,8 @@
+sources += files([
+    'daemon.c',
+    'endian.c',
+    'fs.c',
+    'rand.c',
+    'sleep.c',
+    'sys.c',
+])
diff --git a/src/tcp/meson.build b/src/tcp/meson.build
new file mode 100644
index 0000000..344d6ee
--- /dev/null
+++ b/src/tcp/meson.build
@@ -0,0 +1,4 @@
+sources += files([
+    'tcp.c',
+    'tcp_high.c',
+])
diff --git a/src/telev/meson.build b/src/telev/meson.build
new file mode 100644
index 0000000..e785374
--- /dev/null
+++ b/src/telev/meson.build
@@ -0,0 +1 @@
+sources += files('telev.c')
diff --git a/src/tls/meson.build b/src/tls/meson.build
new file mode 100644
index 0000000..2fc61e8
--- /dev/null
+++ b/src/tls/meson.build
@@ -0,0 +1,7 @@
+if openssl_dep.found()
+    sources += files([
+        'openssl/tls.c',
+        'openssl/tls_tcp.c',
+        'openssl/tls_udp.c',
+    ])
+endif
diff --git a/src/tls/openssl/tls.c b/src/tls/openssl/tls.c
index d84e65f..bc855b1 100644
--- a/src/tls/openssl/tls.c
+++ b/src/tls/openssl/tls.c
@@ -10,6 +10,8 @@
 #include <openssl/bn.h>
 #include <openssl/evp.h>
 #include <openssl/x509.h>
+#include <openssl/dh.h>
+#include <openssl/ec.h>
 #include <re_types.h>
 #include <re_fmt.h>
 #include <re_mem.h>
@@ -853,6 +855,158 @@
 }
 
 
+static int set_dh_params(struct tls *tls, DH *dh)
+{
+	int codes;
+	long r;
+#if OPENSSL_VERSION_NUMBER < 0x1000200fL
+	EC_KEY *ec_key;
+#endif
+
+	if (!DH_check(dh, &codes))
+		return ENOMEM;
+	if (codes) {
+#if defined(DH_CHECK_P_NOT_PRIME)
+		if (codes & DH_CHECK_P_NOT_PRIME)
+			DEBUG_WARNING("set_dh_params: p is not prime\n");
+#endif
+#if defined(DH_CHECK_P_NOT_SAFE_PRIME)
+		if (codes & DH_CHECK_P_NOT_SAFE_PRIME)
+			DEBUG_WARNING("set_dh_params: p is not safe prime\n");
+#endif
+#if defined(DH_UNABLE_TO_CHECK_GENERATOR)
+		if (codes & DH_UNABLE_TO_CHECK_GENERATOR)
+			DEBUG_WARNING("set_dh_params: generator g "
+			              "cannot be checked\n");
+#endif
+#if defined(DH_NOT_SUITABLE_GENERATOR)
+		if (codes & DH_NOT_SUITABLE_GENERATOR)
+			DEBUG_WARNING("set_dh_params: generator g "
+			              "is not suitable\n");
+#endif
+#if defined(DH_CHECK_Q_NOT_PRIME)
+		if (codes & DH_CHECK_Q_NOT_PRIME)
+			DEBUG_WARNING("set_dh_params: q is not prime\n");
+#endif
+#if defined(DH_CHECK_INVALID_Q_VALUE)
+		if (codes & DH_CHECK_INVALID_Q_VALUE)
+			DEBUG_WARNING("set_dh_params: q is invalid\n");
+#endif
+#if defined(DH_CHECK_INVALID_J_VALUE)
+		if (codes & DH_CHECK_INVALID_J_VALUE)
+			DEBUG_WARNING("set_dh_params: j is invalid\n");
+#endif
+		return EINVAL;
+	}
+
+	if (!SSL_CTX_set_tmp_dh(tls->ctx, dh)) {
+		DEBUG_WARNING("set_dh_params: set_tmp_dh failed\n");
+		return ENOMEM;
+	}
+
+#if OPENSSL_VERSION_NUMBER >= 0x1000200fL
+	r = SSL_CTX_set_ecdh_auto(tls->ctx, (long) 1);
+	if (!r) {
+		DEBUG_WARNING("set_dh_params: set_ecdh_auto failed\n");
+		return ENOMEM;
+	}
+#else
+	ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+	if (!ec_key)
+		return ENOMEM;
+	r = SSL_CTX_set_tmp_ecdh(tls->ctx, ec_key);
+	EC_KEY_free(ec_key);
+	if (!r) {
+		DEBUG_WARNING("set_dh_params: set_tmp_ecdh failed\n");
+		return ENOMEM;
+	}
+#endif
+
+	return 0;
+}
+
+
+/**
+ * Set Diffie-Hellman parameters on a TLS context
+ *
+ * @param tls TLS Context
+ * @param pem Diffie-Hellman parameters in PEM format
+ * @param len Length of PEM string
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int tls_set_dh_params_pem(struct tls *tls, const char *pem, size_t len)
+{
+	BIO *bio = NULL;
+	DH *dh = NULL;
+	int err = ENOMEM;
+
+	if (!tls || !pem || !len)
+		return EINVAL;
+
+	bio = BIO_new_mem_buf((char *)pem, (int)len);
+	if (!bio)
+		goto out;
+
+	dh = PEM_read_bio_DHparams(bio, NULL, 0, NULL);
+	if (!dh)
+		goto out;
+
+	err = set_dh_params(tls, dh);
+	if (err)
+		goto out;
+
+	err = 0;
+
+ out:
+	if (dh)
+		DH_free(dh);
+	if (bio)
+		BIO_free(bio);
+	if (err)
+		ERR_clear_error();
+
+	return err;
+}
+
+
+/**
+ * Set Diffie-Hellman parameters on a TLS context
+ *
+ * @param tls TLS Context
+ * @param der Diffie-Hellman parameters in DER format
+ * @param len Length of DER bytes
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int tls_set_dh_params_der(struct tls *tls, const uint8_t *der, size_t len)
+{
+	DH *dh = NULL;
+	int err = ENOMEM;
+
+	if (!tls || !der || !len)
+		return EINVAL;
+
+	dh = d2i_DHparams(NULL, &der, len);
+	if (!dh)
+		goto out;
+
+	err = set_dh_params(tls, dh);
+	if (err)
+		goto out;
+
+	err = 0;
+
+ out:
+	if (dh)
+		DH_free(dh);
+	if (err)
+		ERR_clear_error();
+
+	return err;
+}
+
+
 /**
  * Set the server name on a TLS Connection, using TLS SNI extension.
  *
diff --git a/src/tls/openssl/tls_udp.c b/src/tls/openssl/tls_udp.c
index 4ec81a3..669c6cf 100644
--- a/src/tls/openssl/tls_udp.c
+++ b/src/tls/openssl/tls_udp.c
@@ -27,8 +27,9 @@
 
 
 enum {
-	MTU_DEFAULT  = 1400,
-	MTU_FALLBACK = 548,
+	MTU_DEFAULT      = 1400,
+	MTU_FALLBACK     = 548,
+	HEADROOM_DEFAULT = 4,
 };
 
 
@@ -39,8 +40,11 @@
 	struct hash *ht;
 	struct mbuf *mb;
 	dtls_conn_h *connh;
+	dtls_send_h *sendh;
+	dtls_mtu_h *mtuh;
 	void *arg;
 	size_t mtu;
+	size_t headroom;
 };
 
 
@@ -109,18 +113,17 @@
 	struct tls_conn *tc = b->ptr;
 #endif
 	struct mbuf *mb;
-	enum {SPACE = 4};
 	int err;
 
-	mb = mbuf_alloc(SPACE + len);
+	mb = mbuf_alloc(tc->sock->headroom + len);
 	if (!mb)
 		return -1;
 
-	mb->pos = SPACE;
+	mb->pos = tc->sock->headroom;
 	(void)mbuf_write_mem(mb, (void *)buf, len);
-	mb->pos = SPACE;
+	mb->pos = tc->sock->headroom;
 
-	err = udp_send_helper(tc->sock->us, &tc->peer, mb, tc->sock->uh);
+	err = tc->sock->sendh(tc, &tc->peer, mb, tc->arg);
 
 	mem_deref(mb);
 
@@ -146,7 +149,17 @@
 
 #if defined (BIO_CTRL_DGRAM_QUERY_MTU)
 	case BIO_CTRL_DGRAM_QUERY_MTU:
-		return tc ? tc->sock->mtu : MTU_DEFAULT;
+		if (tc) {
+			if (tc->sock->mtuh) {
+				return tc->sock->mtuh(tc, tc->arg);
+			}
+			else {
+				return tc->sock->mtu;
+			}
+		}
+		else {
+			return MTU_DEFAULT;
+		}
 #endif
 
 #if defined (BIO_CTRL_DGRAM_GET_FALLBACK_MTU)
@@ -750,6 +763,13 @@
 }
 
 
+static int send_handler(struct tls_conn *tc, const struct sa *dst,
+		struct mbuf *mb, void *arg) {
+	(void)arg;
+	return udp_send_helper(tc->sock->us, dst, mb, tc->sock->uh);
+}
+
+
 static bool recv_handler(struct sa *src, struct mbuf *mb, void *arg)
 {
 	struct dtls_sock *sock = arg;
@@ -783,6 +803,20 @@
 
 
 /**
+ * Feed data to a DTLS socket
+ *
+ * @param sock DTLS socket
+ * @param src  Source address
+ * @param mb   Buffer to receive
+ *
+ * @return whether the packet has been handled.
+ */
+bool dtls_receive(struct dtls_sock *sock, struct sa *src, struct mbuf *mb) {
+	return recv_handler(src, mb, sock);
+}
+
+
+/**
  * Create DTLS Socket
  *
  * @param sockp  Pointer to returned DTLS Socket
@@ -827,8 +861,57 @@
 	if (err)
 		goto out;
 
+	sock->mtu      = MTU_DEFAULT;
+	sock->headroom = HEADROOM_DEFAULT;
+	sock->connh    = connh;
+	sock->sendh    = send_handler;
+	sock->arg      = arg;
+
+ out:
+	if (err)
+		mem_deref(sock);
+	else
+		*sockp = sock;
+
+	return err;
+}
+
+
+/**
+ * Create a DTLS Socket without using an UDP socket underneath
+ *
+ * @param sockp  Pointer to returned DTLS Socket
+ * @param htsize Connection hash table size. Set to 0 if one DTLS session shall
+ * be used for all peers.
+ * @param connh  Connect handler
+ * @param sendh  Send handler
+ * @param mtuh   MTU handler
+ * @param arg    Handler argument
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int dtls_socketless(struct dtls_sock **sockp, uint32_t htsize,
+		dtls_conn_h *connh, dtls_send_h *sendh, dtls_mtu_h *mtuh,
+		void *arg)
+{
+	struct dtls_sock *sock;
+	int err;
+
+	if (!sockp || !sendh)
+		return EINVAL;
+
+	sock = mem_zalloc(sizeof(*sock), sock_destructor);
+	if (!sock)
+		return ENOMEM;
+
+	err = hash_alloc(&sock->ht, hash_valid_size(htsize));
+	if (err)
+		goto out;
+
 	sock->mtu   = MTU_DEFAULT;
 	sock->connh = connh;
+	sock->sendh = sendh;
+	sock->mtuh  = mtuh;
 	sock->arg   = arg;
 
  out:
@@ -869,6 +952,34 @@
 }
 
 
+/*
+ * Get headroom of a DTLS Socket
+ *
+ * @param sock DTLS Socket
+ *
+ * @return Headroom value.
+ */
+size_t dtls_headroom(struct dtls_sock *sock)
+{
+	return sock ? sock->headroom : 0;
+}
+
+
+/**
+ * Set headroom on a DTLS Socket
+ *
+ * @param sock     DTLS Socket
+ * @param headroom Headroom value
+ */
+void dtls_set_headroom(struct dtls_sock *sock, size_t headroom)
+{
+	if (!sock)
+		return;
+
+	sock->headroom = headroom;
+}
+
+
 void dtls_recv_packet(struct dtls_sock *sock, const struct sa *src,
 		      struct mbuf *mb)
 {
diff --git a/src/tmr/meson.build b/src/tmr/meson.build
new file mode 100644
index 0000000..9e9fb4a
--- /dev/null
+++ b/src/tmr/meson.build
@@ -0,0 +1 @@
+sources += files('tmr.c')
diff --git a/src/turn/meson.build b/src/turn/meson.build
new file mode 100644
index 0000000..4d0b6c5
--- /dev/null
+++ b/src/turn/meson.build
@@ -0,0 +1,5 @@
+sources += files([
+    'chan.c',
+    'perm.c',
+    'turnc.c',
+])
diff --git a/src/udp/meson.build b/src/udp/meson.build
new file mode 100644
index 0000000..7dabb52
--- /dev/null
+++ b/src/udp/meson.build
@@ -0,0 +1,4 @@
+sources += files([
+    'udp.c',
+    'mcast.c',
+])
diff --git a/src/uri/meson.build b/src/uri/meson.build
new file mode 100644
index 0000000..b0b67fe
--- /dev/null
+++ b/src/uri/meson.build
@@ -0,0 +1,5 @@
+sources += files([
+    'uri.c',
+    'ucmp.c',
+    'uric.c',
+])
diff --git a/src/websock/meson.build b/src/websock/meson.build
new file mode 100644
index 0000000..ca078d3
--- /dev/null
+++ b/src/websock/meson.build
@@ -0,0 +1 @@
+sources += files('websock.c')