summaryrefslogtreecommitdiff
path: root/main/rtp_engine.c
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2017-03-22 16:05:49 -0500
committerRichard Mudgett <rmudgett@digium.com>2017-04-19 13:40:57 -0500
commitd165079cbcb51c94ce729b97f25b42cdbd7b443e (patch)
tree4aa762d04c6f313acd7b3d5333af1d6dfcbcc1d7 /main/rtp_engine.c
parentb84abac1449c56d6c9f781525a533691b326ad8c (diff)
rtp_engine/res_rtp_asterisk: Fix RTP struct reentrancy crashes.
The struct ast_rtp_instance has historically been indirectly protected from reentrancy issues by the channel lock because early channel drivers held the lock for really long times. Holding the channel lock for such a long time has caused many deadlock problems in the past. Along comes chan_pjsip/res_pjsip which doesn't necessarily hold the channel lock because sometimes there may not be an associated channel created yet or the channel pointer isn't available. In the case of ASTERISK-26835 a pjsip serializer thread was processing a message's SDP body while another thread was reading a RTP packet from the socket. Both threads wound up changing the rtp->rtcp->local_addr_str string and interfering with each other. The classic reentrancy problem resulted in a crash. In the case of ASTERISK-26853 a pjsip serializer thread was processing a message's SDP body while another thread was reading a RTP packet from the socket. Both threads wound up processing ICE candidates in PJPROJECT and interfering with each other. The classic reentrancy problem resulted in a crash. * rtp_engine.c: Make the ast_rtp_instance_xxx() calls lock the RTP instance struct. * rtp_engine.c: Make ICE and DTLS wrapper functions to lock the RTP instance struct for the API call. * res_rtp_asterisk.c: Lock the RTP instance to prevent a reentrancy problem with rtp->rtcp->local_addr_str in the scheduler thread running ast_rtcp_write(). * res_rtp_asterisk.c: Avoid deadlock when local RTP bridging in bridge_p2p_rtp_write() because there are two RTP instance structs involved. * res_rtp_asterisk.c: Avoid deadlock when trying to stop scheduler callbacks. We cannot hold the instance lock when trying to stop a scheduler callback. * res_rtp_asterisk.c: Remove the lock in struct dtls_details and use the struct ast_rtp_instance ao2 object lock instead. The lock was used to synchronize two threads to prevent a race condition between starting and stopping a timeout timer. The race condition is no longer present between dtls_perform_handshake() and __rtp_recvfrom() because the instance lock prevents these functions from overlapping each other with regards to the timeout timer. * res_rtp_asterisk.c: Remove the lock in struct ast_rtp and use the struct ast_rtp_instance ao2 object lock instead. The lock was used to synchronize two threads using a condition signal to know when TURN negotiations complete. * res_rtp_asterisk.c: Avoid deadlock when trying to stop the TURN ioqueue_worker_thread(). We cannot hold the instance lock when trying to create or shut down the worker thread without a risk of deadlock. This patch exposed a race condition between a PJSIP serializer thread setting up an ICE session in ice_create() and another thread reading RTP packets. * res_rtp_asterisk.c:ice_create(): Set the new rtp->ice pointer after we have re-locked the RTP instance to prevent the other thread from trying to process ICE packets on an incomplete ICE session setup. A similar race condition is between a PJSIP serializer thread resetting up an ICE session in ice_create() and the timer_worker_thread() processing the completion of the previous ICE session. * res_rtp_asterisk.c:ast_rtp_on_ice_complete(): Protect against an uninitialized/null remote_address after calling update_address_with_ice_candidate(). * res_rtp_asterisk.c: Eliminate the chance of ice_reset_session() destroying and setting the rtp->ice pointer to NULL while other threads are using it by adding an ao2 wrapper around the PJPROJECT ice pointer. Now when we have to unlock the RTP instance object to call a PJPROJECT ICE function we will hold a ref to the wrapper. Also added some rtp->ice NULL checks after we relock the RTP instance and have to do something with the ICE structure. ASTERISK-26835 #close ASTERISK-26853 #close Change-Id: I780b39ec935dcefcce880d50c1a7261744f1d1b4
Diffstat (limited to 'main/rtp_engine.c')
-rw-r--r--main/rtp_engine.c507
1 files changed, 472 insertions, 35 deletions
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 00f9d595f..0a2e84fcd 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -388,9 +388,14 @@ static void instance_destructor(void *obj)
struct ast_rtp_instance *instance = obj;
/* Pass us off to the engine to destroy */
- if (instance->data && instance->engine->destroy(instance)) {
- ast_debug(1, "Engine '%s' failed to destroy RTP instance '%p'\n", instance->engine->name, instance);
- return;
+ if (instance->data) {
+ /*
+ * Lock in case the RTP engine has other threads that
+ * need synchronization with the destruction.
+ */
+ ao2_lock(instance);
+ instance->engine->destroy(instance);
+ ao2_unlock(instance);
}
if (instance->srtp) {
@@ -465,12 +470,20 @@ struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name,
ast_debug(1, "Using engine '%s' for RTP instance '%p'\n", engine->name, instance);
- /* And pass it off to the engine to setup */
+ /*
+ * And pass it off to the engine to setup
+ *
+ * Lock in case the RTP engine has other threads that
+ * need synchronization with the construction.
+ */
+ ao2_lock(instance);
if (instance->engine->new(instance, sched, &address, data)) {
ast_debug(1, "Engine '%s' failed to setup RTP instance '%p'\n", engine->name, instance);
+ ao2_unlock(instance);
ao2_ref(instance, -1);
return NULL;
}
+ ao2_unlock(instance);
ast_debug(1, "RTP instance '%p' is setup and ready to go\n", instance);
@@ -499,31 +512,48 @@ void *ast_rtp_instance_get_data(struct ast_rtp_instance *instance)
int ast_rtp_instance_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
{
- return instance->engine->write(instance, frame);
+ int res;
+
+ ao2_lock(instance);
+ res = instance->engine->write(instance, frame);
+ ao2_unlock(instance);
+ return res;
}
struct ast_frame *ast_rtp_instance_read(struct ast_rtp_instance *instance, int rtcp)
{
- return instance->engine->read(instance, rtcp);
+ struct ast_frame *frame;
+
+ ao2_lock(instance);
+ frame = instance->engine->read(instance, rtcp);
+ ao2_unlock(instance);
+ return frame;
}
int ast_rtp_instance_set_local_address(struct ast_rtp_instance *instance,
const struct ast_sockaddr *address)
{
+ ao2_lock(instance);
ast_sockaddr_copy(&instance->local_address, address);
+ ao2_unlock(instance);
return 0;
}
-int ast_rtp_instance_set_incoming_source_address(struct ast_rtp_instance *instance,
- const struct ast_sockaddr *address)
+static void rtp_instance_set_incoming_source_address_nolock(struct ast_rtp_instance *instance,
+ const struct ast_sockaddr *address)
{
ast_sockaddr_copy(&instance->incoming_source_address, address);
-
- /* moo */
-
if (instance->engine->remote_address_set) {
instance->engine->remote_address_set(instance, &instance->incoming_source_address);
}
+}
+
+int ast_rtp_instance_set_incoming_source_address(struct ast_rtp_instance *instance,
+ const struct ast_sockaddr *address)
+{
+ ao2_lock(instance);
+ rtp_instance_set_incoming_source_address_nolock(instance, address);
+ ao2_unlock(instance);
return 0;
}
@@ -531,18 +561,26 @@ int ast_rtp_instance_set_incoming_source_address(struct ast_rtp_instance *instan
int ast_rtp_instance_set_requested_target_address(struct ast_rtp_instance *instance,
const struct ast_sockaddr *address)
{
+ ao2_lock(instance);
+
ast_sockaddr_copy(&instance->requested_target_address, address);
+ rtp_instance_set_incoming_source_address_nolock(instance, address);
+
+ ao2_unlock(instance);
- return ast_rtp_instance_set_incoming_source_address(instance, address);
+ return 0;
}
int ast_rtp_instance_get_and_cmp_local_address(struct ast_rtp_instance *instance,
struct ast_sockaddr *address)
{
+ ao2_lock(instance);
if (ast_sockaddr_cmp(address, &instance->local_address) != 0) {
ast_sockaddr_copy(address, &instance->local_address);
+ ao2_unlock(instance);
return 1;
}
+ ao2_unlock(instance);
return 0;
}
@@ -550,16 +588,21 @@ int ast_rtp_instance_get_and_cmp_local_address(struct ast_rtp_instance *instance
void ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance,
struct ast_sockaddr *address)
{
+ ao2_lock(instance);
ast_sockaddr_copy(address, &instance->local_address);
+ ao2_unlock(instance);
}
int ast_rtp_instance_get_and_cmp_requested_target_address(struct ast_rtp_instance *instance,
struct ast_sockaddr *address)
{
+ ao2_lock(instance);
if (ast_sockaddr_cmp(address, &instance->requested_target_address) != 0) {
ast_sockaddr_copy(address, &instance->requested_target_address);
+ ao2_unlock(instance);
return 1;
}
+ ao2_unlock(instance);
return 0;
}
@@ -567,43 +610,63 @@ int ast_rtp_instance_get_and_cmp_requested_target_address(struct ast_rtp_instanc
void ast_rtp_instance_get_incoming_source_address(struct ast_rtp_instance *instance,
struct ast_sockaddr *address)
{
+ ao2_lock(instance);
ast_sockaddr_copy(address, &instance->incoming_source_address);
+ ao2_unlock(instance);
}
void ast_rtp_instance_get_requested_target_address(struct ast_rtp_instance *instance,
struct ast_sockaddr *address)
{
+ ao2_lock(instance);
ast_sockaddr_copy(address, &instance->requested_target_address);
+ ao2_unlock(instance);
}
void ast_rtp_instance_set_extended_prop(struct ast_rtp_instance *instance, int property, void *value)
{
if (instance->engine->extended_prop_set) {
+ ao2_lock(instance);
instance->engine->extended_prop_set(instance, property, value);
+ ao2_unlock(instance);
}
}
void *ast_rtp_instance_get_extended_prop(struct ast_rtp_instance *instance, int property)
{
+ void *prop;
+
if (instance->engine->extended_prop_get) {
- return instance->engine->extended_prop_get(instance, property);
+ ao2_lock(instance);
+ prop = instance->engine->extended_prop_get(instance, property);
+ ao2_unlock(instance);
+ } else {
+ prop = NULL;
}
- return NULL;
+ return prop;
}
void ast_rtp_instance_set_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value)
{
+ ao2_lock(instance);
instance->properties[property] = value;
if (instance->engine->prop_set) {
instance->engine->prop_set(instance, property, value);
}
+ ao2_unlock(instance);
}
int ast_rtp_instance_get_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property)
{
- return instance->properties[property];
+ int prop;
+
+ ao2_lock(instance);
+ prop = instance->properties[property];
+ ao2_unlock(instance);
+
+ return prop;
}
struct ast_rtp_codecs *ast_rtp_instance_get_codecs(struct ast_rtp_instance *instance)
@@ -654,9 +717,12 @@ void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp
if (instance && instance->engine && instance->engine->payload_set) {
int i;
+
+ ao2_lock(instance);
for (i = 0; i < AST_RTP_MAX_PT; i++) {
instance->engine->payload_set(instance, i, 0, NULL, 0);
}
+ ao2_unlock(instance);
}
}
@@ -771,7 +837,9 @@ static void rtp_codecs_payloads_copy_rx(struct ast_rtp_codecs *src, struct ast_r
rtp_codecs_payload_replace_rx(dest, idx, type);
if (instance && instance->engine && instance->engine->payload_set) {
+ ao2_lock(instance);
instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code);
+ ao2_unlock(instance);
}
}
}
@@ -859,7 +927,9 @@ static void rtp_codecs_payloads_copy_tx(struct ast_rtp_codecs *src, struct ast_r
AST_VECTOR_REPLACE(&dest->payload_mapping_tx, idx, type);
if (instance && instance->engine && instance->engine->payload_set) {
+ ao2_lock(instance);
instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code);
+ ao2_unlock(instance);
}
}
}
@@ -927,7 +997,9 @@ void ast_rtp_codecs_payloads_xover(struct ast_rtp_codecs *src, struct ast_rtp_co
rtp_codecs_payload_replace_rx(dest, idx, type);
if (instance && instance->engine && instance->engine->payload_set) {
+ ao2_lock(instance);
instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code);
+ ao2_unlock(instance);
}
}
@@ -969,7 +1041,9 @@ void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct as
AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type);
if (instance && instance->engine && instance->engine->payload_set) {
+ ao2_lock(instance);
instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code);
+ ao2_unlock(instance);
}
} else {
ao2_ref(new_type, -1);
@@ -1045,7 +1119,9 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type);
if (instance && instance->engine && instance->engine->payload_set) {
+ ao2_lock(instance);
instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code);
+ ao2_unlock(instance);
}
} else {
ao2_ref(new_type, -1);
@@ -1084,7 +1160,9 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp
}
if (instance && instance->engine && instance->engine->payload_set) {
+ ao2_lock(instance);
instance->engine->payload_set(instance, payload, 0, NULL, 0);
+ ao2_unlock(instance);
}
ast_rwlock_unlock(&codecs->codecs_lock);
@@ -1676,57 +1754,127 @@ char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, struct ast_format_cap *
int ast_rtp_instance_dtmf_begin(struct ast_rtp_instance *instance, char digit)
{
- return instance->engine->dtmf_begin ? instance->engine->dtmf_begin(instance, digit) : -1;
+ int res;
+
+ if (instance->engine->dtmf_begin) {
+ ao2_lock(instance);
+ res = instance->engine->dtmf_begin(instance, digit);
+ ao2_unlock(instance);
+ } else {
+ res = -1;
+ }
+ return res;
}
int ast_rtp_instance_dtmf_end(struct ast_rtp_instance *instance, char digit)
{
- return instance->engine->dtmf_end ? instance->engine->dtmf_end(instance, digit) : -1;
+ int res;
+
+ if (instance->engine->dtmf_end) {
+ ao2_lock(instance);
+ res = instance->engine->dtmf_end(instance, digit);
+ ao2_unlock(instance);
+ } else {
+ res = -1;
+ }
+ return res;
}
+
int ast_rtp_instance_dtmf_end_with_duration(struct ast_rtp_instance *instance, char digit, unsigned int duration)
{
- return instance->engine->dtmf_end_with_duration ? instance->engine->dtmf_end_with_duration(instance, digit, duration) : -1;
+ int res;
+
+ if (instance->engine->dtmf_end_with_duration) {
+ ao2_lock(instance);
+ res = instance->engine->dtmf_end_with_duration(instance, digit, duration);
+ ao2_unlock(instance);
+ } else {
+ res = -1;
+ }
+ return res;
}
int ast_rtp_instance_dtmf_mode_set(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode)
{
- return (!instance->engine->dtmf_mode_set || instance->engine->dtmf_mode_set(instance, dtmf_mode)) ? -1 : 0;
+ int res;
+
+ if (instance->engine->dtmf_mode_set) {
+ ao2_lock(instance);
+ res = instance->engine->dtmf_mode_set(instance, dtmf_mode);
+ ao2_unlock(instance);
+ } else {
+ res = -1;
+ }
+ return res;
}
enum ast_rtp_dtmf_mode ast_rtp_instance_dtmf_mode_get(struct ast_rtp_instance *instance)
{
- return instance->engine->dtmf_mode_get ? instance->engine->dtmf_mode_get(instance) : 0;
+ int res;
+
+ if (instance->engine->dtmf_mode_get) {
+ ao2_lock(instance);
+ res = instance->engine->dtmf_mode_get(instance);
+ ao2_unlock(instance);
+ } else {
+ res = 0;
+ }
+ return res;
}
void ast_rtp_instance_update_source(struct ast_rtp_instance *instance)
{
if (instance->engine->update_source) {
+ ao2_lock(instance);
instance->engine->update_source(instance);
+ ao2_unlock(instance);
}
}
void ast_rtp_instance_change_source(struct ast_rtp_instance *instance)
{
if (instance->engine->change_source) {
+ ao2_lock(instance);
instance->engine->change_source(instance);
+ ao2_unlock(instance);
}
}
int ast_rtp_instance_set_qos(struct ast_rtp_instance *instance, int tos, int cos, const char *desc)
{
- return instance->engine->qos ? instance->engine->qos(instance, tos, cos, desc) : -1;
+ int res;
+
+ if (instance->engine->qos) {
+ ao2_lock(instance);
+ res = instance->engine->qos(instance, tos, cos, desc);
+ ao2_unlock(instance);
+ } else {
+ res = -1;
+ }
+ return res;
}
void ast_rtp_instance_stop(struct ast_rtp_instance *instance)
{
if (instance->engine->stop) {
+ ao2_lock(instance);
instance->engine->stop(instance);
+ ao2_unlock(instance);
}
}
int ast_rtp_instance_fd(struct ast_rtp_instance *instance, int rtcp)
{
- return instance->engine->fd ? instance->engine->fd(instance, rtcp) : -1;
+ int res;
+
+ if (instance->engine->fd) {
+ ao2_lock(instance);
+ res = instance->engine->fd(instance, rtcp);
+ ao2_unlock(instance);
+ } else {
+ res = -1;
+ }
+ return res;
}
struct ast_rtp_glue *ast_rtp_instance_get_glue(const char *type)
@@ -1759,12 +1907,19 @@ static void unref_instance_cond(struct ast_rtp_instance **instance)
struct ast_rtp_instance *ast_rtp_instance_get_bridged(struct ast_rtp_instance *instance)
{
- return instance->bridged;
+ struct ast_rtp_instance *bridged;
+
+ ao2_lock(instance);
+ bridged = instance->bridged;
+ ao2_unlock(instance);
+ return bridged;
}
void ast_rtp_instance_set_bridged(struct ast_rtp_instance *instance, struct ast_rtp_instance *bridged)
{
+ ao2_lock(instance);
instance->bridged = bridged;
+ ao2_unlock(instance);
}
void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c_dst, struct ast_channel *c_src)
@@ -1936,17 +2091,44 @@ done:
int ast_rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations)
{
- return instance->engine->red_init ? instance->engine->red_init(instance, buffer_time, payloads, generations) : -1;
+ int res;
+
+ if (instance->engine->red_init) {
+ ao2_lock(instance);
+ res = instance->engine->red_init(instance, buffer_time, payloads, generations);
+ ao2_unlock(instance);
+ } else {
+ res = -1;
+ }
+ return res;
}
int ast_rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame)
{
- return instance->engine->red_buffer ? instance->engine->red_buffer(instance, frame) : -1;
+ int res;
+
+ if (instance->engine->red_buffer) {
+ ao2_lock(instance);
+ res = instance->engine->red_buffer(instance, frame);
+ ao2_unlock(instance);
+ } else {
+ res = -1;
+ }
+ return res;
}
int ast_rtp_instance_get_stats(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat)
{
- return instance->engine->get_stat ? instance->engine->get_stat(instance, stats, stat) : -1;
+ int res;
+
+ if (instance->engine->get_stat) {
+ ao2_lock(instance);
+ res = instance->engine->get_stat(instance, stats, stat);
+ ao2_unlock(instance);
+ } else {
+ res = -1;
+ }
+ return res;
}
char *ast_rtp_instance_get_quality(struct ast_rtp_instance *instance, enum ast_rtp_instance_stat_field field, char *buf, size_t size)
@@ -2051,14 +2233,33 @@ void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_in
int ast_rtp_instance_set_read_format(struct ast_rtp_instance *instance, struct ast_format *format)
{
- return instance->engine->set_read_format ? instance->engine->set_read_format(instance, format) : -1;
+ int res;
+
+ if (instance->engine->set_read_format) {
+ ao2_lock(instance);
+ res = instance->engine->set_read_format(instance, format);
+ ao2_unlock(instance);
+ } else {
+ res = -1;
+ }
+ return res;
}
int ast_rtp_instance_set_write_format(struct ast_rtp_instance *instance, struct ast_format *format)
{
- return instance->engine->set_write_format ? instance->engine->set_write_format(instance, format) : -1;
+ int res;
+
+ if (instance->engine->set_read_format) {
+ ao2_lock(instance);
+ res = instance->engine->set_write_format(instance, format);
+ ao2_unlock(instance);
+ } else {
+ res = -1;
+ }
+ return res;
}
+/* XXX Nothing calls this */
int ast_rtp_instance_make_compatible(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_channel *peer)
{
struct ast_rtp_glue *glue;
@@ -2089,6 +2290,10 @@ int ast_rtp_instance_make_compatible(struct ast_channel *chan, struct ast_rtp_in
return -1;
}
+ /*
+ * XXX Good thing nothing calls this function because we would need
+ * deadlock avoidance to get the two instance locks.
+ */
res = instance->engine->make_compatible(chan, instance, peer, peer_instance);
ast_channel_unlock(peer);
@@ -2102,7 +2307,9 @@ int ast_rtp_instance_make_compatible(struct ast_channel *chan, struct ast_rtp_in
void ast_rtp_instance_available_formats(struct ast_rtp_instance *instance, struct ast_format_cap *to_endpoint, struct ast_format_cap *to_asterisk, struct ast_format_cap *result)
{
if (instance->engine->available_formats) {
+ ao2_lock(instance);
instance->engine->available_formats(instance, to_endpoint, to_asterisk, result);
+ ao2_unlock(instance);
if (ast_format_cap_count(result)) {
return;
}
@@ -2113,7 +2320,16 @@ void ast_rtp_instance_available_formats(struct ast_rtp_instance *instance, struc
int ast_rtp_instance_activate(struct ast_rtp_instance *instance)
{
- return instance->engine->activate ? instance->engine->activate(instance) : 0;
+ int res;
+
+ if (instance->engine->activate) {
+ ao2_lock(instance);
+ res = instance->engine->activate(instance);
+ ao2_unlock(instance);
+ } else {
+ res = 0;
+ }
+ return res;
}
void ast_rtp_instance_stun_request(struct ast_rtp_instance *instance,
@@ -2219,29 +2435,250 @@ struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance, in
{
if (rtcp && instance->rtcp_srtp) {
return instance->rtcp_srtp;
- }
- else {
+ } else {
return instance->srtp;
}
}
int ast_rtp_instance_sendcng(struct ast_rtp_instance *instance, int level)
{
+ int res;
+
if (instance->engine->sendcng) {
- return instance->engine->sendcng(instance, level);
+ ao2_lock(instance);
+ res = instance->engine->sendcng(instance, level);
+ ao2_unlock(instance);
+ } else {
+ res = -1;
}
+ return res;
+}
- return -1;
+static void rtp_ice_wrap_set_authentication(struct ast_rtp_instance *instance, const char *ufrag, const char *password)
+{
+ ao2_lock(instance);
+ instance->engine->ice->set_authentication(instance, ufrag, password);
+ ao2_unlock(instance);
+}
+
+static void rtp_ice_wrap_add_remote_candidate(struct ast_rtp_instance *instance, const struct ast_rtp_engine_ice_candidate *candidate)
+{
+ ao2_lock(instance);
+ instance->engine->ice->add_remote_candidate(instance, candidate);
+ ao2_unlock(instance);
+}
+
+static void rtp_ice_wrap_start(struct ast_rtp_instance *instance)
+{
+ ao2_lock(instance);
+ instance->engine->ice->start(instance);
+ ao2_unlock(instance);
+}
+
+static void rtp_ice_wrap_stop(struct ast_rtp_instance *instance)
+{
+ ao2_lock(instance);
+ instance->engine->ice->stop(instance);
+ ao2_unlock(instance);
+}
+
+static const char *rtp_ice_wrap_get_ufrag(struct ast_rtp_instance *instance)
+{
+ const char *ufrag;
+
+ ao2_lock(instance);
+ ufrag = instance->engine->ice->get_ufrag(instance);
+ ao2_unlock(instance);
+ return ufrag;
+}
+
+static const char *rtp_ice_wrap_get_password(struct ast_rtp_instance *instance)
+{
+ const char *password;
+
+ ao2_lock(instance);
+ password = instance->engine->ice->get_password(instance);
+ ao2_unlock(instance);
+ return password;
+}
+
+static struct ao2_container *rtp_ice_wrap_get_local_candidates(struct ast_rtp_instance *instance)
+{
+ struct ao2_container *local_candidates;
+
+ ao2_lock(instance);
+ local_candidates = instance->engine->ice->get_local_candidates(instance);
+ ao2_unlock(instance);
+ return local_candidates;
+}
+
+static void rtp_ice_wrap_ice_lite(struct ast_rtp_instance *instance)
+{
+ ao2_lock(instance);
+ instance->engine->ice->ice_lite(instance);
+ ao2_unlock(instance);
+}
+
+static void rtp_ice_wrap_set_role(struct ast_rtp_instance *instance,
+ enum ast_rtp_ice_role role)
+{
+ ao2_lock(instance);
+ instance->engine->ice->set_role(instance, role);
+ ao2_unlock(instance);
+}
+
+static void rtp_ice_wrap_turn_request(struct ast_rtp_instance *instance,
+ enum ast_rtp_ice_component_type component, enum ast_transport transport,
+ const char *server, unsigned int port, const char *username, const char *password)
+{
+ ao2_lock(instance);
+ instance->engine->ice->turn_request(instance, component, transport, server, port,
+ username, password);
+ ao2_unlock(instance);
+}
+
+static void rtp_ice_wrap_change_components(struct ast_rtp_instance *instance,
+ int num_components)
+{
+ ao2_lock(instance);
+ instance->engine->ice->change_components(instance, num_components);
+ ao2_unlock(instance);
}
+static struct ast_rtp_engine_ice rtp_ice_wrappers = {
+ .set_authentication = rtp_ice_wrap_set_authentication,
+ .add_remote_candidate = rtp_ice_wrap_add_remote_candidate,
+ .start = rtp_ice_wrap_start,
+ .stop = rtp_ice_wrap_stop,
+ .get_ufrag = rtp_ice_wrap_get_ufrag,
+ .get_password = rtp_ice_wrap_get_password,
+ .get_local_candidates = rtp_ice_wrap_get_local_candidates,
+ .ice_lite = rtp_ice_wrap_ice_lite,
+ .set_role = rtp_ice_wrap_set_role,
+ .turn_request = rtp_ice_wrap_turn_request,
+ .change_components = rtp_ice_wrap_change_components,
+};
+
struct ast_rtp_engine_ice *ast_rtp_instance_get_ice(struct ast_rtp_instance *instance)
{
- return instance->engine->ice;
+ if (instance->engine->ice) {
+ return &rtp_ice_wrappers;
+ }
+ /* ICE not available */
+ return NULL;
+}
+
+static int rtp_dtls_wrap_set_configuration(struct ast_rtp_instance *instance,
+ const struct ast_rtp_dtls_cfg *dtls_cfg)
+{
+ int set_configuration;
+
+ ao2_lock(instance);
+ set_configuration = instance->engine->dtls->set_configuration(instance, dtls_cfg);
+ ao2_unlock(instance);
+ return set_configuration;
+}
+
+static int rtp_dtls_wrap_active(struct ast_rtp_instance *instance)
+{
+ int active;
+
+ ao2_lock(instance);
+ active = instance->engine->dtls->active(instance);
+ ao2_unlock(instance);
+ return active;
+}
+
+static void rtp_dtls_wrap_stop(struct ast_rtp_instance *instance)
+{
+ ao2_lock(instance);
+ instance->engine->dtls->stop(instance);
+ ao2_unlock(instance);
+}
+
+static void rtp_dtls_wrap_reset(struct ast_rtp_instance *instance)
+{
+ ao2_lock(instance);
+ instance->engine->dtls->reset(instance);
+ ao2_unlock(instance);
+}
+
+static enum ast_rtp_dtls_connection rtp_dtls_wrap_get_connection(struct ast_rtp_instance *instance)
+{
+ enum ast_rtp_dtls_connection get_connection;
+
+ ao2_lock(instance);
+ get_connection = instance->engine->dtls->get_connection(instance);
+ ao2_unlock(instance);
+ return get_connection;
}
+static enum ast_rtp_dtls_setup rtp_dtls_wrap_get_setup(struct ast_rtp_instance *instance)
+{
+ enum ast_rtp_dtls_setup get_setup;
+
+ ao2_lock(instance);
+ get_setup = instance->engine->dtls->get_setup(instance);
+ ao2_unlock(instance);
+ return get_setup;
+}
+
+static void rtp_dtls_wrap_set_setup(struct ast_rtp_instance *instance,
+ enum ast_rtp_dtls_setup setup)
+{
+ ao2_lock(instance);
+ instance->engine->dtls->set_setup(instance, setup);
+ ao2_unlock(instance);
+}
+
+static void rtp_dtls_wrap_set_fingerprint(struct ast_rtp_instance *instance,
+ enum ast_rtp_dtls_hash hash, const char *fingerprint)
+{
+ ao2_lock(instance);
+ instance->engine->dtls->set_fingerprint(instance, hash, fingerprint);
+ ao2_unlock(instance);
+}
+
+static enum ast_rtp_dtls_hash rtp_dtls_wrap_get_fingerprint_hash(struct ast_rtp_instance *instance)
+{
+ enum ast_rtp_dtls_hash get_fingerprint_hash;
+
+ ao2_lock(instance);
+ get_fingerprint_hash = instance->engine->dtls->get_fingerprint_hash(instance);
+ ao2_unlock(instance);
+ return get_fingerprint_hash;
+}
+
+static const char *rtp_dtls_wrap_get_fingerprint(struct ast_rtp_instance *instance)
+{
+ const char *get_fingerprint;
+
+ ao2_lock(instance);
+ get_fingerprint = instance->engine->dtls->get_fingerprint(instance);
+ ao2_unlock(instance);
+ return get_fingerprint;
+}
+
+static struct ast_rtp_engine_dtls rtp_dtls_wrappers = {
+ .set_configuration = rtp_dtls_wrap_set_configuration,
+ .active = rtp_dtls_wrap_active,
+ .stop = rtp_dtls_wrap_stop,
+ .reset = rtp_dtls_wrap_reset,
+ .get_connection = rtp_dtls_wrap_get_connection,
+ .get_setup = rtp_dtls_wrap_get_setup,
+ .set_setup = rtp_dtls_wrap_set_setup,
+ .set_fingerprint = rtp_dtls_wrap_set_fingerprint,
+ .get_fingerprint_hash = rtp_dtls_wrap_get_fingerprint_hash,
+ .get_fingerprint = rtp_dtls_wrap_get_fingerprint,
+};
+
struct ast_rtp_engine_dtls *ast_rtp_instance_get_dtls(struct ast_rtp_instance *instance)
{
- return instance->engine->dtls;
+ if (instance->engine->dtls) {
+ return &rtp_dtls_wrappers;
+ }
+ /* DTLS not available */
+ return NULL;
}
int ast_rtp_dtls_cfg_parse(struct ast_rtp_dtls_cfg *dtls_cfg, const char *name, const char *value)