Merge "Fix seg fault in starter_cmd"
diff --git a/aos/network/www/aos_plotter.ts b/aos/network/www/aos_plotter.ts
index 35c27a7..59db9d9 100644
--- a/aos/network/www/aos_plotter.ts
+++ b/aos/network/www/aos_plotter.ts
@@ -141,9 +141,15 @@
 }
 
 class MessageLine {
+  private _lastNumMessages: number = 0;
   constructor(
       public readonly messages: MessageHandler, public readonly line: Line,
       public readonly field: string[]) {}
+  hasUpdate(): boolean {
+    const updated = this._lastNumMessages != this.messages.numMessages();
+    this._lastNumMessages = this.messages.numMessages();
+    return updated;
+  }
 }
 
 class AosPlot {
@@ -172,7 +178,7 @@
     // is a relatively expensive call, we don't want to do it any more than
     // necessary.
     for (const line of this.lines) {
-      if (line.messages.numMessages() * 2 != line.line.getPoints().length) {
+      if (line.hasUpdate()) {
         line.line.setPoints(line.messages.getField(line.field));
       }
     }
diff --git a/third_party/rawrtc/rawrtc-data-channel/BUILD b/third_party/rawrtc/rawrtc-data-channel/BUILD
index 096024a..500ad8b 100644
--- a/third_party/rawrtc/rawrtc-data-channel/BUILD
+++ b/third_party/rawrtc/rawrtc-data-channel/BUILD
@@ -25,6 +25,10 @@
         "-Wno-cast-qual",
         "-Wno-cast-align",
         "-Wno-missing-braces",
+        "-DUSE_OPENSSL",
+        "-DHAVE_INET6",
+        "-DHAVE_STDBOOL_H",
+        "-DHAVE_INTTYPES_H",
     ],
     defines = [
         "RAWRTCDC_HAVE_SCTP_REDIRECT_TRANSPORT=0",
@@ -34,6 +38,6 @@
     visibility = ["//visibility:public"],
     deps = [
         "@com_github_rawrtc_rawrtc_common//:rawrtcc",
-        "@com_github_rawrtc_usrsctp//:usrsctp_crc32",
+        "@com_github_rawrtc_usrsctp//:usrsctp",
     ],
 )
diff --git a/third_party/rawrtc/rawrtc/BUILD b/third_party/rawrtc/rawrtc/BUILD
index df14384..77416d8 100644
--- a/third_party/rawrtc/rawrtc/BUILD
+++ b/third_party/rawrtc/rawrtc/BUILD
@@ -21,6 +21,11 @@
         "-Wno-cast-qual",
         "-Wno-missing-braces",
         "-Iexternal/com_github_rawrtc_rawrtc/",
+        "-DUSE_OPENSSL",
+        #"-DUSE_ZLIB",
+        "-DHAVE_INET6",
+        "-DHAVE_STDBOOL_H",
+        "-DHAVE_INTTYPES_H",
     ],
     includes = ["include/"],
     local_defines = [
@@ -32,3 +37,29 @@
         "@com_github_rawrtc_rawrtc_data_channel//:rawrtcdc",
     ],
 )
+
+cc_binary(
+    name = "peer-connection",
+    srcs = [
+        "tools/helper/common.c",
+        "tools/helper/common.h",
+        "tools/helper/handler.c",
+        "tools/helper/handler.h",
+        "tools/helper/parameters.c",
+        "tools/helper/parameters.h",
+        "tools/helper/utils.c",
+        "tools/helper/utils.h",
+        "tools/peer-connection.c",
+    ],
+    copts = [
+        "-Wno-missing-braces",
+        "-Wno-incompatible-pointer-types-discards-qualifiers",
+    ] + compiler_select({
+        "clang": [],
+        "gcc": [
+            "-Wno-discarded-qualifiers",
+        ],
+    }),
+    includes = ["tools"],
+    deps = [":rawrtc"],
+)
diff --git a/third_party/rawrtc/re/BUILD b/third_party/rawrtc/re/BUILD
index af720c5..63efff7 100644
--- a/third_party/rawrtc/re/BUILD
+++ b/third_party/rawrtc/re/BUILD
@@ -13,7 +13,9 @@
             "src/hmac/apple/**",
             "src/hmac/hmac.c",
             "src/mqueue/win32/**",
-            "src/tls/openssl/**",
+            "src/sha/**",
+            "src/md5/**",
+            "src/ice/ice.c",
             "src/dns/win32/**",
             "src/mod/win32/**",
             "src/lock/lock.c",
@@ -27,6 +29,7 @@
     copts = compiler_select({
         "clang": [
             "-Wno-incompatible-pointer-types-discards-qualifiers",
+            "-Wno-macro-redefined",
         ],
         "gcc": [
             "-Wno-discarded-qualifiers",
@@ -40,6 +43,38 @@
         "-Wno-cast-qual",
         "-Wno-cast-align",
         "-Wno-implicit-function-declaration",
+        "-DUSE_OPENSSL",
+        "-DUSE_TLS",
+        "-DUSE_OPENSSL_DTLS",
+        "-DUSE_DTLS",
+        "-DUSE_OPENSSL_SRTP",
+        "-DUSE_DTLS_SRTP",
+        #"-DUSE_ZLIB",
+        "-DHAVE_INET6",
+        "-DHAVE_SELECT",
+        "-DHAVE_STDBOOL_H",
+        "-DHAVE_INTTYPES_H",
+        "-DHAVE_NET_ROUTE_H",
+        "-DHAVE_SYS_SYSCTL_H",
+        "-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",
+        "-DHAVE_PTHREAD",
+        "-DHAVE_GETIFADDRS",
+        "-DHAVE_DLFCN",
+        "-DHAVE_EPOLL",
+        "-DHAVE_RESOLV",
+        "-DHAVE_POLL",
+        "-DHAVE_INET_PTON",
+        "-DHAVE_ROUTE_LIST",
     ],
     defines = ["HAVE_INTTYPES_H"],
     includes = ["include/"],
diff --git a/third_party/rawrtc/re/include/meson.build b/third_party/rawrtc/re/include/meson.build
new file mode 100644
index 0000000..c9e1b30
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/include/re_sdp.h b/third_party/rawrtc/re/include/re_sdp.h
index f34bab5..457cb4d 100644
--- a/third_party/rawrtc/re/include/re_sdp.h
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/include/re_tls.h b/third_party/rawrtc/re/include/re_tls.h
index 05b3c93..09ad028 100644
--- a/third_party/rawrtc/re/include/re_tls.h
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/meson.build b/third_party/rawrtc/re/meson.build
new file mode 100644
index 0000000..2757cff
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/aes/meson.build b/third_party/rawrtc/re/src/aes/meson.build
new file mode 100644
index 0000000..6f869ca
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/base64/meson.build b/third_party/rawrtc/re/src/base64/meson.build
new file mode 100644
index 0000000..5b6f4ff
--- /dev/null
+++ b/third_party/rawrtc/re/src/base64/meson.build
@@ -0,0 +1 @@
+sources += files('b64.c')
diff --git a/third_party/rawrtc/re/src/bfcp/meson.build b/third_party/rawrtc/re/src/bfcp/meson.build
new file mode 100644
index 0000000..8e333b0
--- /dev/null
+++ b/third_party/rawrtc/re/src/bfcp/meson.build
@@ -0,0 +1,7 @@
+sources += files([
+    'attr.c',
+    'conn.c',
+    'msg.c',
+    'reply.c',
+    'request.c',
+])
diff --git a/third_party/rawrtc/re/src/conf/meson.build b/third_party/rawrtc/re/src/conf/meson.build
new file mode 100644
index 0000000..ea1c1cfc
--- /dev/null
+++ b/third_party/rawrtc/re/src/conf/meson.build
@@ -0,0 +1 @@
+sources += files('conf.c')
diff --git a/third_party/rawrtc/re/src/crc32/meson.build b/third_party/rawrtc/re/src/crc32/meson.build
new file mode 100644
index 0000000..f073ff7
--- /dev/null
+++ b/third_party/rawrtc/re/src/crc32/meson.build
@@ -0,0 +1,3 @@
+if not zlib_dep.found()
+    sources += files('crc32.c')
+endif
diff --git a/third_party/rawrtc/re/src/dbg/meson.build b/third_party/rawrtc/re/src/dbg/meson.build
new file mode 100644
index 0000000..7c71321
--- /dev/null
+++ b/third_party/rawrtc/re/src/dbg/meson.build
@@ -0,0 +1 @@
+sources += files('dbg.c')
diff --git a/third_party/rawrtc/re/src/dns/meson.build b/third_party/rawrtc/re/src/dns/meson.build
new file mode 100644
index 0000000..cfd6aa0
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/fmt/meson.build b/third_party/rawrtc/re/src/fmt/meson.build
new file mode 100644
index 0000000..bcc4750
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/fmt/print.c b/third_party/rawrtc/re/src/fmt/print.c
index 85e9ebf..c0247b4 100644
--- a/third_party/rawrtc/re/src/fmt/print.c
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/hash/func.c b/third_party/rawrtc/re/src/hash/func.c
index 3943c94..f379904 100644
--- a/third_party/rawrtc/re/src/hash/func.c
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/hash/meson.build b/third_party/rawrtc/re/src/hash/meson.build
new file mode 100644
index 0000000..57d8c12
--- /dev/null
+++ b/third_party/rawrtc/re/src/hash/meson.build
@@ -0,0 +1,4 @@
+sources += files([
+    'hash.c',
+    'func.c',
+])
diff --git a/third_party/rawrtc/re/src/hmac/meson.build b/third_party/rawrtc/re/src/hmac/meson.build
new file mode 100644
index 0000000..7a7293a
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/http/meson.build b/third_party/rawrtc/re/src/http/meson.build
new file mode 100644
index 0000000..3ee5939
--- /dev/null
+++ b/third_party/rawrtc/re/src/http/meson.build
@@ -0,0 +1,7 @@
+sources += files([
+    'auth.c',
+    'chunk.c',
+    'client.c',
+    'msg.c',
+    'server.c',
+])
diff --git a/third_party/rawrtc/re/src/httpauth/meson.build b/third_party/rawrtc/re/src/httpauth/meson.build
new file mode 100644
index 0000000..2ad5862
--- /dev/null
+++ b/third_party/rawrtc/re/src/httpauth/meson.build
@@ -0,0 +1,4 @@
+sources += files([
+    'basic.c',
+    'digest.c',
+])
diff --git a/third_party/rawrtc/re/src/ice/meson.build b/third_party/rawrtc/re/src/ice/meson.build
new file mode 100644
index 0000000..be63f72
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/jbuf/meson.build b/third_party/rawrtc/re/src/jbuf/meson.build
new file mode 100644
index 0000000..1b11bc8
--- /dev/null
+++ b/third_party/rawrtc/re/src/jbuf/meson.build
@@ -0,0 +1 @@
+sources += files('jbuf.c')
diff --git a/third_party/rawrtc/re/src/json/meson.build b/third_party/rawrtc/re/src/json/meson.build
new file mode 100644
index 0000000..f5461df
--- /dev/null
+++ b/third_party/rawrtc/re/src/json/meson.build
@@ -0,0 +1,5 @@
+sources += files([
+    'decode.c',
+    'decode_odict.c',
+    'encode.c',
+])
diff --git a/third_party/rawrtc/re/src/list/meson.build b/third_party/rawrtc/re/src/list/meson.build
new file mode 100644
index 0000000..2027364
--- /dev/null
+++ b/third_party/rawrtc/re/src/list/meson.build
@@ -0,0 +1 @@
+sources += files('list.c')
diff --git a/third_party/rawrtc/re/src/lock/meson.build b/third_party/rawrtc/re/src/lock/meson.build
new file mode 100644
index 0000000..bd400bd
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/main/main.c b/third_party/rawrtc/re/src/main/main.c
index b90c139..0243b4b 100644
--- a/third_party/rawrtc/re/src/main/main.c
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/main/meson.build b/third_party/rawrtc/re/src/main/meson.build
new file mode 100644
index 0000000..f0a5b98
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/mbuf/meson.build b/third_party/rawrtc/re/src/mbuf/meson.build
new file mode 100644
index 0000000..eaec9d1
--- /dev/null
+++ b/third_party/rawrtc/re/src/mbuf/meson.build
@@ -0,0 +1 @@
+sources += files('mbuf.c')
diff --git a/third_party/rawrtc/re/src/md5/meson.build b/third_party/rawrtc/re/src/md5/meson.build
new file mode 100644
index 0000000..547a2fc
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/mem/meson.build b/third_party/rawrtc/re/src/mem/meson.build
new file mode 100644
index 0000000..3e15795
--- /dev/null
+++ b/third_party/rawrtc/re/src/mem/meson.build
@@ -0,0 +1,4 @@
+sources += files([
+    'mem.c',
+    'secure.c',
+])
diff --git a/third_party/rawrtc/re/src/meson.build b/third_party/rawrtc/re/src/meson.build
new file mode 100644
index 0000000..aa5ff49
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/mod/meson.build b/third_party/rawrtc/re/src/mod/meson.build
new file mode 100644
index 0000000..eb9a306
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/mqueue/meson.build b/third_party/rawrtc/re/src/mqueue/meson.build
new file mode 100644
index 0000000..65d6d5b
--- /dev/null
+++ b/third_party/rawrtc/re/src/mqueue/meson.build
@@ -0,0 +1,5 @@
+sources += files('mqueue.c')
+
+if system == 'windows'
+    sources += files('win32/pipe.c')
+endif
diff --git a/third_party/rawrtc/re/src/msg/meson.build b/third_party/rawrtc/re/src/msg/meson.build
new file mode 100644
index 0000000..a70396e
--- /dev/null
+++ b/third_party/rawrtc/re/src/msg/meson.build
@@ -0,0 +1,4 @@
+sources += files([
+    'ctype.c',
+    'param.c',
+])
diff --git a/third_party/rawrtc/re/src/natbd/meson.build b/third_party/rawrtc/re/src/natbd/meson.build
new file mode 100644
index 0000000..523d452
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/net/meson.build b/third_party/rawrtc/re/src/net/meson.build
new file mode 100644
index 0000000..1408fed
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/odict/meson.build b/third_party/rawrtc/re/src/odict/meson.build
new file mode 100644
index 0000000..8ac0cde
--- /dev/null
+++ b/third_party/rawrtc/re/src/odict/meson.build
@@ -0,0 +1,6 @@
+sources += files([
+    'entry.c',
+    'odict.c',
+    'type.c',
+    'get.c',
+])
diff --git a/third_party/rawrtc/re/src/rtmp/meson.build b/third_party/rawrtc/re/src/rtmp/meson.build
new file mode 100644
index 0000000..78a6214
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/rtp/meson.build b/third_party/rawrtc/re/src/rtp/meson.build
new file mode 100644
index 0000000..0fc1506
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/sa/meson.build b/third_party/rawrtc/re/src/sa/meson.build
new file mode 100644
index 0000000..92e8cbe
--- /dev/null
+++ b/third_party/rawrtc/re/src/sa/meson.build
@@ -0,0 +1,6 @@
+sources += files([
+    'ntop.c',
+    'printaddr.c',
+    'pton.c',
+    'sa.c',
+])
diff --git a/third_party/rawrtc/re/src/sdp/media.c b/third_party/rawrtc/re/src/sdp/media.c
index 07ce3a2..05e769c 100644
--- a/third_party/rawrtc/re/src/sdp/media.c
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/sdp/meson.build b/third_party/rawrtc/re/src/sdp/meson.build
new file mode 100644
index 0000000..03b62dd
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/sdp/msg.c b/third_party/rawrtc/re/src/sdp/msg.c
index c1a8bbc..82b8905 100644
--- a/third_party/rawrtc/re/src/sdp/msg.c
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/sdp/sdp.h b/third_party/rawrtc/re/src/sdp/sdp.h
index f0588d1..604082a 100644
--- a/third_party/rawrtc/re/src/sdp/sdp.h
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/sha/meson.build b/third_party/rawrtc/re/src/sha/meson.build
new file mode 100644
index 0000000..387b6b5
--- /dev/null
+++ b/third_party/rawrtc/re/src/sha/meson.build
@@ -0,0 +1,3 @@
+if not openssl_dep.found()
+    sources += files('sha1.c')
+endif
diff --git a/third_party/rawrtc/re/src/sip/meson.build b/third_party/rawrtc/re/src/sip/meson.build
new file mode 100644
index 0000000..f80c6e9
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/sipevent/meson.build b/third_party/rawrtc/re/src/sipevent/meson.build
new file mode 100644
index 0000000..543aa84
--- /dev/null
+++ b/third_party/rawrtc/re/src/sipevent/meson.build
@@ -0,0 +1,6 @@
+sources += files([
+    'listen.c',
+    'msg.c',
+    'notify.c',
+    'subscribe.c',
+])
diff --git a/third_party/rawrtc/re/src/sipreg/meson.build b/third_party/rawrtc/re/src/sipreg/meson.build
new file mode 100644
index 0000000..0e7bb02
--- /dev/null
+++ b/third_party/rawrtc/re/src/sipreg/meson.build
@@ -0,0 +1 @@
+sources += files('reg.c')
diff --git a/third_party/rawrtc/re/src/sipsess/meson.build b/third_party/rawrtc/re/src/sipsess/meson.build
new file mode 100644
index 0000000..4731317
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/srtp/meson.build b/third_party/rawrtc/re/src/srtp/meson.build
new file mode 100644
index 0000000..eb56909
--- /dev/null
+++ b/third_party/rawrtc/re/src/srtp/meson.build
@@ -0,0 +1,7 @@
+sources += files([
+    'misc.c',
+    'replay.c',
+    'srtcp.c',
+    'srtp.c',
+    'stream.c',
+])
diff --git a/third_party/rawrtc/re/src/stun/meson.build b/third_party/rawrtc/re/src/stun/meson.build
new file mode 100644
index 0000000..5f0a018
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/sys/meson.build b/third_party/rawrtc/re/src/sys/meson.build
new file mode 100644
index 0000000..7ffb335
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/tcp/meson.build b/third_party/rawrtc/re/src/tcp/meson.build
new file mode 100644
index 0000000..344d6ee
--- /dev/null
+++ b/third_party/rawrtc/re/src/tcp/meson.build
@@ -0,0 +1,4 @@
+sources += files([
+    'tcp.c',
+    'tcp_high.c',
+])
diff --git a/third_party/rawrtc/re/src/telev/meson.build b/third_party/rawrtc/re/src/telev/meson.build
new file mode 100644
index 0000000..e785374
--- /dev/null
+++ b/third_party/rawrtc/re/src/telev/meson.build
@@ -0,0 +1 @@
+sources += files('telev.c')
diff --git a/third_party/rawrtc/re/src/tls/meson.build b/third_party/rawrtc/re/src/tls/meson.build
new file mode 100644
index 0000000..2fc61e8
--- /dev/null
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/tls/openssl/tls.c b/third_party/rawrtc/re/src/tls/openssl/tls.c
index d84e65f..bc855b1 100644
--- a/third_party/rawrtc/re/src/tls/openssl/tls.c
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/tls/openssl/tls.h b/third_party/rawrtc/re/src/tls/openssl/tls.h
index 2c621d5..c0c4d51 100644
--- a/third_party/rawrtc/re/src/tls/openssl/tls.h
+++ b/third_party/rawrtc/re/src/tls/openssl/tls.h
@@ -20,9 +20,11 @@
 
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
 	!defined(LIBRESSL_VERSION_NUMBER)
+#ifndef OPENSSL_IS_BORINGSSL
 #define SSL_state SSL_get_state
 #define SSL_ST_OK TLS_ST_OK
 #endif
+#endif
 
 
 struct tls {
diff --git a/third_party/rawrtc/re/src/tls/openssl/tls_udp.c b/third_party/rawrtc/re/src/tls/openssl/tls_udp.c
index 4ec81a3..669c6cf 100644
--- a/third_party/rawrtc/re/src/tls/openssl/tls_udp.c
+++ b/third_party/rawrtc/re/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/third_party/rawrtc/re/src/tmr/meson.build b/third_party/rawrtc/re/src/tmr/meson.build
new file mode 100644
index 0000000..9e9fb4a
--- /dev/null
+++ b/third_party/rawrtc/re/src/tmr/meson.build
@@ -0,0 +1 @@
+sources += files('tmr.c')
diff --git a/third_party/rawrtc/re/src/turn/meson.build b/third_party/rawrtc/re/src/turn/meson.build
new file mode 100644
index 0000000..4d0b6c5
--- /dev/null
+++ b/third_party/rawrtc/re/src/turn/meson.build
@@ -0,0 +1,5 @@
+sources += files([
+    'chan.c',
+    'perm.c',
+    'turnc.c',
+])
diff --git a/third_party/rawrtc/re/src/udp/meson.build b/third_party/rawrtc/re/src/udp/meson.build
new file mode 100644
index 0000000..7dabb52
--- /dev/null
+++ b/third_party/rawrtc/re/src/udp/meson.build
@@ -0,0 +1,4 @@
+sources += files([
+    'udp.c',
+    'mcast.c',
+])
diff --git a/third_party/rawrtc/re/src/uri/meson.build b/third_party/rawrtc/re/src/uri/meson.build
new file mode 100644
index 0000000..b0b67fe
--- /dev/null
+++ b/third_party/rawrtc/re/src/uri/meson.build
@@ -0,0 +1,5 @@
+sources += files([
+    'uri.c',
+    'ucmp.c',
+    'uric.c',
+])
diff --git a/third_party/rawrtc/re/src/websock/meson.build b/third_party/rawrtc/re/src/websock/meson.build
new file mode 100644
index 0000000..ca078d3
--- /dev/null
+++ b/third_party/rawrtc/re/src/websock/meson.build
@@ -0,0 +1 @@
+sources += files('websock.c')
diff --git a/third_party/rawrtc/usrsctp/BUILD b/third_party/rawrtc/usrsctp/BUILD
index 7704bb9..654d29b 100644
--- a/third_party/rawrtc/usrsctp/BUILD
+++ b/third_party/rawrtc/usrsctp/BUILD
@@ -1,21 +1,63 @@
-# usrsctp is only actually being used for the CRC function, and getting
-# the entire library building was being obnoxious.
+load("@//tools/build_rules:select.bzl", "compiler_select")
+
 cc_library(
-    name = "usrsctp_crc32",
-    srcs = ["usrsctplib/netinet/sctp_crc32.c"],
+    name = "usrsctp",
+    srcs = [
+        "usrsctplib/netinet/sctp_asconf.c",
+        "usrsctplib/netinet/sctp_auth.c",
+        "usrsctplib/netinet/sctp_bsd_addr.c",
+        "usrsctplib/netinet/sctp_callout.c",
+        "usrsctplib/netinet/sctp_cc_functions.c",
+        "usrsctplib/netinet/sctp_crc32.c",
+        "usrsctplib/netinet/sctp_indata.c",
+        "usrsctplib/netinet/sctp_input.c",
+        "usrsctplib/netinet/sctp_output.c",
+        "usrsctplib/netinet/sctp_pcb.c",
+        "usrsctplib/netinet/sctp_peeloff.c",
+        "usrsctplib/netinet/sctp_sha1.c",
+        "usrsctplib/netinet/sctp_ss_functions.c",
+        "usrsctplib/netinet/sctp_sysctl.c",
+        "usrsctplib/netinet/sctp_timer.c",
+        "usrsctplib/netinet/sctp_userspace.c",
+        "usrsctplib/netinet/sctp_usrreq.c",
+        "usrsctplib/netinet/sctputil.c",
+        "usrsctplib/netinet6/sctp6_usrreq.c",
+        "usrsctplib/user_environment.c",
+        "usrsctplib/user_mbuf.c",
+        "usrsctplib/user_recv_thread.c",
+        "usrsctplib/user_socket.c",
+    ],
     hdrs = glob(["usrsctplib/**/*.h"]),
     copts = [
         "-Wno-cast-qual",
         "-Wno-cast-align",
         "-Wno-unused-parameter",
         "-Wno-incompatible-pointer-types-discards-qualifiers",
+        "-D__Userspace_os_Linux",
+        "-D__Userspace__",
+        "-D_GNU_SOURCE",
+        "-DSCTP_DEBUG",
+        "-DSCTP_SIMPLE_ALLOCATOR",
+        "-DINET",
+        "-DINET6",
+        "-DSCTP_PROCESS_LEVEL_LOCKS",
+        "-DHAVE_SYS_QUEUE_H",
+        "-DHAVE_STDATOMIC_H",
+        "-DHAVE_NETINET_IP_ICMP_H",
+        "-DHAVE_LINUX_RTNETLINK_H",
+        "-DHAVE_LINUX_IF_ADDR_H",
+        "-Wno-address-of-packed-member",
+    ] + compiler_select({
+        "clang": [],
+        "gcc": [
+            "-Wno-discarded-qualifiers",
+        ],
+    }),
+    includes = [
+        "usrsctplib/",
+        "usrsctplib/netinet",
+        "usrsctplib/netinet6",
     ],
-    defines = [
-        "__Userspace_os_Linux",
-        "__Userspace__",
-        "SCTP_SIMPLE_ALLOCATOR",
-    ],
-    includes = ["usrsctplib/"],
     target_compatible_with = ["@platforms//os:linux"],
     visibility = ["//visibility:public"],
 )
diff --git a/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctp_constants.h b/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctp_constants.h
index e275dd9..57240cd 100755
--- a/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctp_constants.h
+++ b/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctp_constants.h
@@ -778,7 +778,7 @@
 #define SCTP_DEFAULT_SPLIT_POINT_MIN 2904
 
 /* Maximum length of diagnostic information in error causes */
-#define SCTP_DIAG_INFO_LEN 64
+#define SCTP_DIAG_INFO_LEN 128
 
 /* ABORT CODES and other tell-tale location
  * codes are generated by adding the below
diff --git a/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctp_pcb.c b/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctp_pcb.c
index ec3ff6d..ca84395 100755
--- a/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctp_pcb.c
+++ b/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctp_pcb.c
@@ -6845,7 +6845,7 @@
 	TAILQ_INIT(&SCTP_BASE_INFO(callqueue));
 #endif
 #if defined(__Userspace__)
-	mbuf_init(NULL);
+	usrsctpmbuf_init(NULL);
 	atomic_init();
 #if defined(THREAD_SUPPORT) && (defined(INET) || defined(INET6))
 	recv_thread_init();
diff --git a/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctputil.c b/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctputil.c
index 87e7774..5ac93d5 100755
--- a/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctputil.c
+++ b/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctputil.c
@@ -5013,7 +5013,7 @@
  */
 
 struct mbuf *
-sctp_generate_cause(uint16_t code, char *info)
+sctp_generate_cause(uint16_t code, const char *info)
 {
 	struct mbuf *m;
 	struct sctp_gen_error_cause *cause;
diff --git a/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctputil.h b/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctputil.h
index 7746d54..1babe19 100755
--- a/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctputil.h
+++ b/third_party/rawrtc/usrsctp/usrsctplib/netinet/sctputil.h
@@ -281,7 +281,7 @@
 #endif
 );
 
-struct mbuf *sctp_generate_cause(uint16_t, char *);
+struct mbuf *sctp_generate_cause(uint16_t, const char *);
 struct mbuf *sctp_generate_no_user_data_cause(uint32_t);
 
 void sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
diff --git a/third_party/rawrtc/usrsctp/usrsctplib/user_mbuf.c b/third_party/rawrtc/usrsctp/usrsctplib/user_mbuf.c
index 9a82746..232d74e 100755
--- a/third_party/rawrtc/usrsctp/usrsctplib/user_mbuf.c
+++ b/third_party/rawrtc/usrsctp/usrsctplib/user_mbuf.c
@@ -121,7 +121,7 @@
 	mbuf_mb_args.type = type;
 #endif
 	/* Mbuf master zone, zone_mbuf, has already been
-	 * created in mbuf_init() */
+	 * created in usrsctpmbuf_init() */
 	mret = SCTP_ZONE_GET(zone_mbuf, struct mbuf);
 #if defined(SCTP_SIMPLE_ALLOCATOR)
 	mb_ctor_mbuf(mret, &mbuf_mb_args, 0);
@@ -328,11 +328,11 @@
 /************ End functions to substitute umem_cache_alloc and umem_cache_free **************/
 
 /* __Userspace__
- * TODO: mbuf_init must be called in the initialization routines
+ * TODO: usrsctpmbuf_init must be called in the initialization routines
  * of userspace stack.
  */
 void
-mbuf_init(void *dummy)
+usrsctpmbuf_init(void *dummy)
 {
 
 	/*
diff --git a/third_party/rawrtc/usrsctp/usrsctplib/user_mbuf.h b/third_party/rawrtc/usrsctp/usrsctplib/user_mbuf.h
index 7893ea9..64a0ac3 100755
--- a/third_party/rawrtc/usrsctp/usrsctplib/user_mbuf.h
+++ b/third_party/rawrtc/usrsctp/usrsctplib/user_mbuf.h
@@ -58,7 +58,7 @@
 
 
 /* mbuf initialization function */
-void mbuf_init(void *);
+void usrsctpmbuf_init(void *);
 
 #define	M_MOVE_PKTHDR(to, from)	m_move_pkthdr((to), (from))
 #define	MGET(m, how, type)	((m) = m_get((how), (type)))
diff --git a/y2020/control_loops/drivetrain/localizer.cc b/y2020/control_loops/drivetrain/localizer.cc
index 32c8834..1cab511 100644
--- a/y2020/control_loops/drivetrain/localizer.cc
+++ b/y2020/control_loops/drivetrain/localizer.cc
@@ -224,7 +224,9 @@
     const Eigen::Matrix<float, 4, 4> H_field_target =
         FlatbufferToTransformationMatrix(*vision_result->field_to_target());
     // Back out the robot position that is implied by the current camera
-    // reading.
+    // reading. Note that the Pose object ignores any roll/pitch components, so
+    // if the camera's extrinsics for pitch/roll are off, this should just
+    // ignore it.
     const Pose measured_pose(H_field_target *
                              (H_robot_camera * H_camera_target).inverse());
     // This "Z" is the robot pose directly implied by the camera results.
@@ -234,7 +236,11 @@
                                        measured_pose.rel_pos().y(),
                                        measured_pose.rel_theta());
     // Pose of the target in the robot frame.
-    Pose pose_robot_target(H_robot_camera * H_camera_target);
+    // Note that we use measured_pose's transformation matrix rather than just
+    // doing H_robot_camera * H_camera_target because measured_pose ignores
+    // pitch/roll.
+    Pose pose_robot_target(measured_pose.AsTransformationMatrix().inverse() *
+                           H_field_target);
     // TODO(james): Figure out how to properly handle calculating the
     // noise. Currently, the values are deliberately tuned so that image updates
     // will not be trusted overly much. In theory, we should probably also be