diff --git a/include/juice/juice.h b/include/juice/juice.h index 594b5dde..95cf9e72 100644 --- a/include/juice/juice.h +++ b/include/juice/juice.h @@ -64,6 +64,16 @@ typedef void (*juice_cb_gathering_done_t)(juice_agent_t *agent, void *user_ptr); typedef void (*juice_cb_recv_t)(juice_agent_t *agent, const char *data, size_t size, void *user_ptr); +typedef struct juice_mux_incoming { + const char *local_ufrag; + const char *remote_ufrag; + + const char *address; + uint16_t port; +} juice_mux_incoming_t; + +typedef void (*juice_cb_mux_incoming_t)(const juice_mux_incoming_t *info, void *user_ptr); + typedef struct juice_turn_server { const char *host; const char *username; @@ -118,6 +128,8 @@ JUICE_EXPORT int juice_get_selected_addresses(juice_agent_t *agent, char *local, char *remote, size_t remote_size); JUICE_EXPORT int juice_set_local_ice_attributes(juice_agent_t *agent, const char *ufrag, const char *pwd); JUICE_EXPORT const char *juice_state_to_string(juice_state_t state); +JUICE_EXPORT int juice_mux_listen(const char *bind_address, int local_port, juice_cb_mux_incoming_t cb, void *user_ptr); +JUICE_EXPORT int juice_mux_stop_listen(const char *bind_address, int local_port); // ICE server diff --git a/src/conn.c b/src/conn.c index 4d7893a0..da383c43 100644 --- a/src/conn.c +++ b/src/conn.c @@ -108,7 +108,7 @@ static void release_registry(conn_mode_entry_t *entry) { // registry must be locked - if (registry->agents_count == 0) { + if (registry->agents_count == 0 && registry->cb_mux_incoming == NULL) { JLOG_DEBUG("No connection left, destroying connections registry"); mutex_unlock(®istry->mutex); @@ -247,3 +247,59 @@ int conn_get_addrs(juice_agent_t *agent, addr_record_t *records, size_t size) { return get_mode_entry(agent)->get_addrs_func(agent, records, size); } + +int juice_mux_stop_listen(const char *bind_address, int local_port) { + (void)bind_address; + (void)local_port; + + conn_mode_entry_t *entry = &mode_entries[JUICE_CONCURRENCY_MODE_MUX]; + + mutex_lock(&entry->mutex); + + conn_registry_t *registry = entry->registry; + if (!registry) { + mutex_unlock(&entry->mutex); + return -1; + } + + mutex_lock(®istry->mutex); + + registry->cb_mux_incoming = NULL; + registry->mux_incoming_user_ptr = NULL; + conn_mux_interrupt_registry(registry); + + release_registry(entry); + + mutex_unlock(&entry->mutex); + + return 0; +} + +int juice_mux_listen(const char *bind_address, int local_port, juice_cb_mux_incoming_t cb, void *user_ptr) +{ + conn_mode_entry_t *entry = &mode_entries[JUICE_CONCURRENCY_MODE_MUX]; + + udp_socket_config_t config; + config.bind_address = bind_address; + config.port_begin = config.port_end = local_port; + + mutex_lock(&entry->mutex); + + if (entry->registry) { + mutex_unlock(&entry->mutex); + JLOG_DEBUG("juice_mux_listen needs to be called before establishing any mux connection."); + return -1; + } + + conn_registry_t *registry = acquire_registry(entry, &config); + mutex_unlock(&entry->mutex); + + if (!registry) + return -2; + + registry->cb_mux_incoming = cb; + registry->mux_incoming_user_ptr = user_ptr; + mutex_unlock(®istry->mutex); + + return 0; +} diff --git a/src/conn.h b/src/conn.h index 4aec7d0c..5986c1c3 100644 --- a/src/conn.h +++ b/src/conn.h @@ -30,6 +30,8 @@ typedef struct conn_registry { juice_agent_t **agents; int agents_size; int agents_count; + juice_cb_mux_incoming_t cb_mux_incoming; + void *mux_incoming_user_ptr; } conn_registry_t; int conn_create(juice_agent_t *agent, udp_socket_config_t *config); diff --git a/src/conn_mux.c b/src/conn_mux.c index a783b3f8..ea1da9aa 100644 --- a/src/conn_mux.c +++ b/src/conn_mux.c @@ -243,6 +243,8 @@ int conn_mux_prepare(conn_registry_t *registry, struct pollfd *pfd, timestamp_t } int count = registry->agents_count; + if (registry->cb_mux_incoming) + ++count; mutex_unlock(®istry->mutex); return count; } @@ -295,6 +297,25 @@ static juice_agent_t *lookup_agent(conn_registry_t *registry, char *buf, size_t } } + if (registry->cb_mux_incoming) { + JLOG_DEBUG("Found STUN request with unknown ICE ufrag"); + char host[ADDR_MAX_NUMERICHOST_LEN]; + if (getnameinfo((const struct sockaddr *)&src->addr, src->len, host, ADDR_MAX_NUMERICHOST_LEN, NULL, 0, NI_NUMERICHOST)) { + JLOG_ERROR("getnameinfo failed, errno=%d", sockerrno); + return NULL; + } + + juice_mux_incoming_t incoming_info; + + incoming_info.local_ufrag = local_ufrag; + incoming_info.remote_ufrag = separator + 1; + incoming_info.address = host; + incoming_info.port = addr_get_port((struct sockaddr *)src); + + registry->cb_mux_incoming(&incoming_info, registry->mux_incoming_user_ptr); + + return NULL; + } } else { if (!STUN_IS_RESPONSE(msg.msg_class)) { JLOG_INFO("Got unexpected STUN message from unknown source address"); @@ -479,14 +500,7 @@ void conn_mux_unlock(juice_agent_t *agent) { mutex_unlock(®istry->mutex); } -int conn_mux_interrupt(juice_agent_t *agent) { - conn_impl_t *conn_impl = agent->conn_impl; - conn_registry_t *registry = conn_impl->registry; - - mutex_lock(®istry->mutex); - conn_impl->next_timestamp = current_timestamp(); - mutex_unlock(®istry->mutex); - +int conn_mux_interrupt_registry(conn_registry_t *registry) { JLOG_VERBOSE("Interrupting connections thread"); registry_impl_t *registry_impl = registry->impl; @@ -502,6 +516,17 @@ int conn_mux_interrupt(juice_agent_t *agent) { return 0; } +int conn_mux_interrupt(juice_agent_t *agent) { + conn_impl_t *conn_impl = agent->conn_impl; + conn_registry_t *registry = conn_impl->registry; + + mutex_lock(®istry->mutex); + conn_impl->next_timestamp = current_timestamp(); + mutex_unlock(®istry->mutex); + + return conn_mux_interrupt_registry(registry); +} + int conn_mux_send(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size, int ds) { conn_impl_t *conn_impl = agent->conn_impl; diff --git a/src/conn_mux.h b/src/conn_mux.h index 9519f066..68b51b67 100644 --- a/src/conn_mux.h +++ b/src/conn_mux.h @@ -24,6 +24,7 @@ int conn_mux_init(juice_agent_t *agent, conn_registry_t *registry, udp_socket_co void conn_mux_cleanup(juice_agent_t *agent); void conn_mux_lock(juice_agent_t *agent); void conn_mux_unlock(juice_agent_t *agent); +int conn_mux_interrupt_registry(conn_registry_t *registry); int conn_mux_interrupt(juice_agent_t *agent); int conn_mux_send(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size, int ds);