diff --git a/include/re_main.h b/include/re_main.h index cc9ac4ba..0199c707 100644 --- a/include/re_main.h +++ b/include/re_main.h @@ -4,6 +4,9 @@ * Copyright (C) 2010 Creytiv.com */ +#ifdef HAVE_LIBUV +#include +#endif enum { #ifndef FD_READ @@ -41,6 +44,9 @@ int libre_init(void); void libre_close(void); int re_main(re_signal_h *signalh); +#if HAVE_LIBUV +int re_main_uvloop (uv_loop_t* loop, re_signal_h *signalh ); +#endif void re_cancel(void); int re_debug(struct re_printf *pf, void *unused); @@ -59,11 +65,13 @@ enum poll_method { METHOD_SELECT, METHOD_EPOLL, METHOD_KQUEUE, + METHOD_LIBUV, /* sep */ METHOD_MAX }; int poll_method_set(enum poll_method method); +enum poll_method poll_method_get (void); enum poll_method poll_method_best(void); const char *poll_method_name(enum poll_method method); int poll_method_type(enum poll_method *method, const struct pl *name); diff --git a/include/re_sdp.h b/include/re_sdp.h index f34bab5d..457cb4d9 100644 --- a/include/re_sdp.h +++ b/include/re_sdp.h @@ -99,6 +99,7 @@ void sdp_media_set_lbandwidth(struct sdp_media *m, enum sdp_bandwidth type, 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 05b3c930..09ad0280 100644 --- a/include/re_tls.h +++ b/include/re_tls.h @@ -54,6 +54,8 @@ int tls_srtp_keyinfo(const struct tls_conn *tc, enum srtp_suite *suite, 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 @@ int tls_start_tcp(struct tls_conn **ptc, struct tls *tls, /* 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 @@ struct dtls_sock; 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 @@ int dtls_accept(struct tls_conn **ptc, struct tls *tls, 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/include/re_tmr.h b/include/re_tmr.h index b399fb17..8cd86c19 100644 --- a/include/re_tmr.h +++ b/include/re_tmr.h @@ -4,6 +4,9 @@ * Copyright (C) 2010 Creytiv.com */ +#ifdef HAVE_LIBUV +#include +#endif /** * Defines the timeout handler @@ -18,6 +21,9 @@ struct tmr { tmr_h *th; /**< Timeout handler */ void *arg; /**< Handler argument */ uint64_t jfs; /**< Jiffies for timeout */ +#ifdef HAVE_LIBUV + uv_timer_t* uv_timer; /**< libbuv handler */ +#endif }; diff --git a/mk/re.mk b/mk/re.mk index efb35c99..c7ef07aa 100644 --- a/mk/re.mk +++ b/mk/re.mk @@ -491,6 +491,15 @@ CFLAGS += -DUSE_ZLIB LIBS += -lz endif +USE_LIBUV := $(shell [ -f $(SYSROOT)/include/uv.h ] || \ + [ -f $(SYSROOT)/local/include/uv.h ] || \ + [ -f $(SYSROOT_ALT)/include/uv.h ] && echo "yes") + +ifneq ($(USE_LIBUV),) +CFLAGS += -D_XOPEN_SOURCE=600 -DHAVE_LIBUV +LIBS += -luv +endif + ifneq ($(OS),win32) @@ -687,6 +696,7 @@ info: @echo " USE_DTLS: $(USE_DTLS)" @echo " USE_DTLS_SRTP: $(USE_DTLS_SRTP)" @echo " USE_ZLIB: $(USE_ZLIB)" + @echo " USE_LIBUV: $(USE_LIBUV)" @echo " GCOV: $(GCOV)" @echo " GPROF: $(GPROF)" @echo " CROSS_COMPILE: $(CROSS_COMPILE)" diff --git a/src/fmt/print.c b/src/fmt/print.c index 85e9ebf9..c0247b49 100644 --- a/src/fmt/print.c +++ b/src/fmt/print.c @@ -303,6 +303,11 @@ int re_vhprintf(const char *fmt, va_list ap, re_vprintf_h *vph, void *arg) } 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/main/main.c b/src/main/main.c index 762b0b4f..a087d9f7 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -47,7 +47,9 @@ #include #include #endif - +#ifdef HAVE_LIBUV +#include +#endif #define DEBUG_MODULE "main" #define DEBUG_LEVEL 5 @@ -91,6 +93,9 @@ struct re { int flags; /**< Polling flags (Read, Write, etc.) */ fd_h *fh; /**< Event handler */ void *arg; /**< Handler argument */ +#ifdef HAVE_LIBUV + uv_poll_t uv_poll; /**< libuv handler */ +#endif } *fhs; int maxfds; /**< Maximum number of polling fds */ int nfds; /**< Number of active file descriptors */ @@ -113,6 +118,11 @@ struct re { struct kevent *evlist; int kqfd; #endif + +#ifdef HAVE_LIBUV + bool uv_loop_is_external; + uv_loop_t *uv_loop; +#endif #ifdef HAVE_PTHREAD pthread_mutex_t mutex; /**< Mutex for thread synchronization */ @@ -140,6 +150,10 @@ static struct re global_re = { NULL, -1, #endif +#ifdef HAVE_LIBUV + false, + NULL, +#endif #ifdef HAVE_PTHREAD #if MAIN_DEBUG && defined (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP) PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, @@ -372,6 +386,70 @@ static int set_kqueue_fds(struct re *re, int fd, int flags) } #endif +#ifdef HAVE_LIBUV + +static void libuv_fd_close (uv_handle_t* handle) { + +} + +static void connection_poll_cb(uv_poll_t* handle, int status, int events) +{ + + struct re *re = re_get(); + int fd = (int) handle->data; + int flags = 0; + + if (status < 0) + flags |= FD_EXCEPT; + if (events & UV_READABLE) + flags |= FD_READ; + if (events & UV_WRITABLE) + flags |= FD_WRITE; + + re->fhs[fd].fh(flags, re->fhs[fd].arg); + +} + +static int set_libuv_fds(struct re *re, int fd, int flags) +{ + int events = 0; + int err = 0; + + if (re->uv_loop == NULL) { + return EBADFD; + } + + uv_poll_t* uv_poll = &re->fhs[fd].uv_poll; + + DEBUG_INFO("set_libuv_fds: fd=%d flags=0x%02x\n", fd, flags); + + if (flags) { + + uv_poll->data = (void*)fd; + + if (flags & FD_READ) + events |= UV_READABLE; + if (flags & FD_WRITE) + events |= UV_WRITABLE; +// if (flags & FD_EXCEPT) + + if (uv_poll_init_socket (re->uv_loop, uv_poll, fd) != 0) { + err = 1; + } else if (uv_poll_start (uv_poll, events, connection_poll_cb) != 0) { + err = 2; + } + + } + else { + uv_poll_stop (uv_poll); +// if (!uv_is_closing((uv_handle_t *) uv_poll)) { +// uv_close ((uv_handle_t *) uv_poll, libuv_fd_close); +// } + } + + return err; +} +#endif /** * Rebuild the file descriptor mapping table. This must be done whenever @@ -407,6 +485,11 @@ static int rebuild_fds(struct re *re) break; #endif +#ifdef HAVE_LIBUV + case METHOD_LIBUV: + err = set_libuv_fds(re, i, re->fhs[i].flags); + break; +#endif default: break; } @@ -483,6 +566,18 @@ static int poll_init(struct re *re) break; #endif + +#ifdef HAVE_LIBUV + case METHOD_LIBUV: + + if (re->uv_loop == NULL) { + re->uv_loop = malloc(sizeof *re->uv_loop); + if (!re->uv_loop) + return errno; + uv_loop_init (re->uv_loop); + } + break; +#endif default: break; @@ -521,6 +616,16 @@ static void poll_close(struct re *re) re->evlist = mem_deref(re->evlist); #endif + +#ifdef HAVE_LIBUV + if (re->uv_loop != NULL && !re->uv_loop_is_external) { + uv_stop (re->uv_loop); +// if (uv_loop_close (re->uv_loop) != UV_EBUSY) { +// free (re->uv_loop); +// re->uv_loop = NULL; +// } + } +#endif } @@ -618,6 +723,14 @@ int fd_listen(int fd, int flags, fd_h *fh, void *arg) err = set_kqueue_fds(re, fd, flags); break; #endif + +#ifdef HAVE_LIBUV + case METHOD_LIBUV: + if (re->uv_loop == NULL) + return EBADFD; + err = set_libuv_fds(re, fd, flags); + break; +#endif default: break; @@ -729,7 +842,19 @@ static int fd_poll(struct re *re) } break; #endif - + +#ifdef HAVE_LIBUV + case METHOD_LIBUV: { + if (re->uv_loop == NULL) { + DEBUG_WARNING("no uv_loop\n"); + } else if (!re->uv_loop_is_external) { + int pending = uv_run (re->uv_loop, UV_RUN_NOWAIT); + } + n = 0; + } + break; +#endif + default: (void)to; DEBUG_WARNING("no polling method set\n"); @@ -786,6 +911,8 @@ static int fd_poll(struct re *re) flags |= FD_WRITE; if (re->events[i].events & EPOLLERR) flags |= FD_EXCEPT; + if (re->events[i].events & EPOLLHUP) + flags |= FD_EXCEPT; if (!flags) { DEBUG_WARNING("epoll: no flags fd=%d\n", fd); @@ -830,6 +957,12 @@ static int fd_poll(struct re *re) } break; #endif +#ifdef HAVE_LIBUV + case METHOD_LIBUV: { + // noop + } + break; +#endif default: return EINVAL; @@ -986,11 +1119,17 @@ int re_main(re_signal_h *signalh) if (EBADF == err) continue; #endif - break; } - - tmr_poll(&re->tmrl); +#ifdef HAVE_LIBUV + switch (re->method) { + case METHOD_LIBUV: + break; + default: + tmr_poll(&re->tmrl); + break; + } +#endif } re_unlock(re); @@ -1000,6 +1139,16 @@ int re_main(re_signal_h *signalh) return err; } +int re_main_uvloop (uv_loop_t* loop, re_signal_h *signalh) { + + struct re *re = re_get(); + re->uv_loop_is_external = true; + re->uv_loop = loop; + + return re_main (signalh); + +} + /** * Cancel the main polling loop @@ -1036,6 +1185,10 @@ int re_debug(struct re_printf *pf, void *unused) return err; } +enum poll_method poll_method_get () { + struct re *re = re_get(); + return re->method; +} /** * Set async I/O polling method. This function can also be called while the @@ -1077,6 +1230,10 @@ int poll_method_set(enum poll_method method) #ifdef HAVE_KQUEUE case METHOD_KQUEUE: break; +#endif +#ifdef HAVE_LIBUV + case METHOD_LIBUV: + break; #endif default: DEBUG_WARNING("poll method not supported: '%s'\n", @@ -1212,3 +1369,18 @@ struct list *tmrl_get(void) { return &re_get()->tmrl; } + +#ifdef HAVE_LIBUV +/** + * Get the uv_loop for this thread + * + * @return uv_loop_t* + * + * @note only used by tmr module + */ +uv_loop_t* get_libuv_loop(void); +uv_loop_t* get_libuv_loop(void) { + return re_get()->uv_loop; +} + +#endif diff --git a/src/main/method.c b/src/main/method.c index d4fc1fba..6644b211 100644 --- a/src/main/method.c +++ b/src/main/method.c @@ -14,6 +14,7 @@ static const char str_poll[] = "poll"; /**< POSIX.1-2001 poll */ static const char str_select[] = "select"; /**< POSIX.1-2001 select */ static const char str_epoll[] = "epoll"; /**< Linux epoll */ static const char str_kqueue[] = "kqueue"; +static const char str_libuv[] = "libuv"; /** @@ -49,6 +50,11 @@ enum poll_method poll_method_best(void) m = METHOD_SELECT; } #endif +#ifdef HAVE_LIBUV + if (METHOD_NULL == m) { + m = METHOD_LIBUV; + } +#endif return m; } @@ -69,6 +75,7 @@ const char *poll_method_name(enum poll_method method) case METHOD_SELECT: return str_select; case METHOD_EPOLL: return str_epoll; case METHOD_KQUEUE: return str_kqueue; + case METHOD_LIBUV: return str_libuv; default: return "???"; } } @@ -95,6 +102,8 @@ int poll_method_type(enum poll_method *method, const struct pl *name) *method = METHOD_EPOLL; else if (0 == pl_strcasecmp(name, str_kqueue)) *method = METHOD_KQUEUE; + else if (0 == pl_strcasecmp(name, str_libuv)) + *method = METHOD_LIBUV; else return ENOENT; diff --git a/src/sdp/media.c b/src/sdp/media.c index 07ce3a27..05e769c9 100644 --- a/src/sdp/media.c +++ b/src/sdp/media.c @@ -446,6 +446,7 @@ void sdp_media_set_laddr(struct sdp_media *m, const struct sa *laddr) if (!m || !laddr) return; + m->flags |= MEDIA_LADDR_SET; m->laddr = *laddr; } @@ -512,6 +513,25 @@ void sdp_media_set_ldir(struct sdp_media *m, enum sdp_dir dir) } +/** + * 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 * diff --git a/src/sdp/msg.c b/src/sdp/msg.c index c1a8bbce..82b89055 100644 --- a/src/sdp/msg.c +++ b/src/sdp/msg.c @@ -398,7 +398,7 @@ static int media_encode(const struct sdp_media *m, struct mbuf *mb, bool offer) 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 @@ static int media_encode(const struct sdp_media *m, struct mbuf *mb, bool offer) 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 f0588d1f..604082a5 100644 --- a/src/sdp/sdp.h +++ b/src/sdp/sdp.h @@ -10,6 +10,11 @@ enum { 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_session { struct sdp_media { struct le le; + uint8_t flags; struct list lfmtl; struct list rfmtl; struct list lattrl; diff --git a/src/tls/openssl/tls.c b/src/tls/openssl/tls.c index d84e65f3..bc855b13 100644 --- a/src/tls/openssl/tls.c +++ b/src/tls/openssl/tls.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -853,6 +855,158 @@ int tls_set_ciphers(struct tls *tls, const char *cipherv[], size_t count) } +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.h b/src/tls/openssl/tls.h index 2c621d54..927fb2ed 100644 --- a/src/tls/openssl/tls.h +++ b/src/tls/openssl/tls.h @@ -19,7 +19,8 @@ #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ - !defined(LIBRESSL_VERSION_NUMBER) + !defined(LIBRESSL_VERSION_NUMBER) && \ + !defined(OPENSSL_IS_BORINGSSL) #define SSL_state SSL_get_state #define SSL_ST_OK TLS_ST_OK #endif diff --git a/src/tls/openssl/tls_udp.c b/src/tls/openssl/tls_udp.c index 4ec81a30..669c6cf7 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 dtls_sock { 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 @@ static int bio_write(BIO *b, const char *buf, int len) 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 @@ static long bio_ctrl(BIO *b, int cmd, long num, void *ptr) #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 struct tls_conn *conn_lookup(struct dtls_sock *sock, } +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; @@ -782,6 +802,20 @@ static bool recv_handler(struct sa *src, struct mbuf *mb, void *arg) } +/** + * 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 * @@ -827,8 +861,57 @@ int dtls_listen(struct dtls_sock **sockp, const struct sa *laddr, 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 @@ void dtls_set_mtu(struct dtls_sock *sock, size_t mtu) } +/* + * 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/tmr.c b/src/tmr/tmr.c index 73083f16..9e59f269 100644 --- a/src/tmr/tmr.c +++ b/src/tmr/tmr.c @@ -21,7 +21,10 @@ #include #include #include - +#ifdef HAVE_LIBUV +#include +#include +#endif #define DEBUG_MODULE "tmr" #define DEBUG_LEVEL 5 @@ -38,7 +41,10 @@ enum { }; extern struct list *tmrl_get(void); - +#ifdef HAVE_LIBUV +void libuv_timer_handler (uv_timer_t* handler); +extern uv_loop_t* get_libuv_loop(void); +#endif static bool inspos_handler(struct le *le, void *arg) { @@ -224,6 +230,27 @@ void tmr_init(struct tmr *tmr) memset(tmr, 0, sizeof(*tmr)); } +#ifdef HAVE_LIBUV + +static void libuv_timer_close (uv_handle_t* handle) { + free (handle); +} + +void libuv_timer_handler (uv_timer_t* handler) { + + struct tmr *tmr = ((uv_timer_t*)handler)->data; + + if (tmr != NULL) { + if (tmr->th != NULL) { + tmr->th (tmr->arg); + tmr->th = NULL; + } + uv_close((uv_handle_t *)tmr->uv_timer, libuv_timer_close); + tmr->uv_timer = NULL; + } +} + +#endif /** * Start a timer @@ -235,6 +262,41 @@ void tmr_init(struct tmr *tmr) */ void tmr_start(struct tmr *tmr, uint64_t delay, tmr_h *th, void *arg) { + +#ifdef HAVE_LIBUV + if (poll_method_get() == METHOD_LIBUV) { + + if (!tmr) + return; + + tmr->th = th; + tmr->arg = arg; + + if (th != NULL) { + + uv_loop_t* loop = get_libuv_loop(); + if (tmr->uv_timer == NULL) { + uv_timer_t* handler = (uv_timer_t*) malloc (sizeof(uv_timer_t)); + if (loop != NULL) { + handler->data = tmr; + uv_timer_init (loop, handler); + tmr->uv_timer = handler; + } + } + tmr->jfs = uv_now(loop) + delay; + uv_timer_start (tmr->uv_timer, libuv_timer_handler, delay, 0); + } else { + if (tmr->uv_timer != NULL) { + uv_timer_stop (tmr->uv_timer); + uv_close((uv_handle_t *)tmr->uv_timer, libuv_timer_close); + tmr->uv_timer = NULL; + } + } + + return; + } +#endif + struct list *tmrl = tmrl_get(); struct le *le; @@ -294,11 +356,19 @@ void tmr_cancel(struct tmr *tmr) */ uint64_t tmr_get_expire(const struct tmr *tmr) { - uint64_t jfs; - + uint64_t jfs; + if (!tmr || !tmr->th) return 0; +#ifdef HAVE_LIBUV + if (poll_method_get() == METHOD_LIBUV) { + uv_loop_t* loop = get_libuv_loop(); + jfs = uv_now(loop); + return (tmr->jfs > jfs) ? (tmr->jfs - jfs) : 0; + } +#endif + jfs = tmr_jiffies(); return (tmr->jfs > jfs) ? (tmr->jfs - jfs) : 0;