static void *pthread_timer_open(void) { struct pthread_timer *timer; if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) { errno = ENOMEM; return NULL; } timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1; timer->state = TIMER_STATE_IDLE; if (ast_pipe_nonblock(timer->pipe)) { ao2_ref(timer, -1); return NULL; } ao2_lock(pthread_timers); if (!ao2_container_count(pthread_timers)) { ast_mutex_lock(&timing_thread.lock); ast_cond_signal(&timing_thread.cond); ast_mutex_unlock(&timing_thread.lock); } ao2_link_flags(pthread_timers, timer, OBJ_NOLOCK); ao2_unlock(pthread_timers); return timer; }
int __ast_format_interface_register(const char *codec, const struct ast_format_interface *interface, struct ast_module *mod) { SCOPED_AO2WRLOCK(lock, interfaces); struct format_interface *format_interface; if (!interface->format_clone || !interface->format_destroy) { ast_log(LOG_ERROR, "Format interface for codec '%s' does not implement required callbacks\n", codec); return -1; } format_interface = ao2_find(interfaces, codec, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (format_interface) { ast_log(LOG_ERROR, "A format interface is already present for codec '%s'\n", codec); ao2_ref(format_interface, -1); return -1; } format_interface = ao2_alloc_options(sizeof(*format_interface) + strlen(codec) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!format_interface) { return -1; } format_interface->interface = interface; strcpy(format_interface->codec, codec); /* Safe */ /* Once registered a format interface cannot be unregistered. */ ast_module_shutdown_ref(mod); ao2_link_flags(interfaces, format_interface, OBJ_NOLOCK); ao2_ref(format_interface, -1); ast_verb(2, "Registered format interface for codec '%s'\n", codec); return 0; }
int app_subscribe_channel(struct stasis_app *app, struct ast_channel *chan) { int res; if (!app || !chan) { return -1; } else { RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup); SCOPED_AO2LOCK(lock, app->forwards); forwards = ao2_find(app->forwards, ast_channel_uniqueid(chan), OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!forwards) { /* Forwards not found, create one */ forwards = forwards_create_channel(app, chan); if (!forwards) { return -1; } res = ao2_link_flags(app->forwards, forwards, OBJ_NOLOCK); if (!res) { return -1; } } ++forwards->interested; ast_debug(3, "Channel '%s' is %d interested in %s\n", ast_channel_uniqueid(chan), forwards->interested, app->name); return 0; } }
int AST_OPTIONAL_API_NAME(ast_websocket_add_protocol)(const char *name, ast_websocket_callback callback) { struct websocket_protocol *protocol; ao2_lock(protocols); /* Ensure a second protocol handler is not registered for the same protocol */ if ((protocol = ao2_find(protocols, name, OBJ_KEY | OBJ_NOLOCK))) { ao2_ref(protocol, -1); ao2_unlock(protocols); return -1; } if (!(protocol = ao2_alloc(sizeof(*protocol), protocol_destroy_fn))) { ao2_unlock(protocols); return -1; } if (!(protocol->name = ast_strdup(name))) { ao2_ref(protocol, -1); ao2_unlock(protocols); return -1; } protocol->callback = callback; ao2_link_flags(protocols, protocol, OBJ_NOLOCK); ao2_unlock(protocols); ao2_ref(protocol, -1); ast_verb(2, "WebSocket registered sub-protocol '%s'\n", name); return 0; }
int app_subscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge) { if (!app || !bridge) { return -1; } else { RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup); SCOPED_AO2LOCK(lock, app->forwards); forwards = ao2_find(app->forwards, bridge->uniqueid, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!forwards) { /* Forwards not found, create one */ forwards = forwards_create_bridge(app, bridge); if (!forwards) { return -1; } ao2_link_flags(app->forwards, forwards, OBJ_NOLOCK); } ++forwards->interested; ast_debug(3, "Bridge '%s' is %d interested in %s\n", bridge->uniqueid, forwards->interested, app->name); return 0; } }
void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint) { struct distributor_dialog_data *dist; ao2_wrlock(dialog_associations); dist = ao2_find(dialog_associations, dlg, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!dist) { if (endpoint) { dist = ao2_alloc(sizeof(*dist), NULL); if (dist) { dist->dlg = dlg; dist->endpoint = endpoint; ao2_link_flags(dialog_associations, dist, OBJ_NOLOCK); ao2_ref(dist, -1); } } } else { ao2_lock(dist); dist->endpoint = endpoint; if (!dist->serializer && !dist->endpoint) { ao2_unlink_flags(dialog_associations, dist, OBJ_NOLOCK); } ao2_unlock(dist); ao2_ref(dist, -1); } ao2_unlock(dialog_associations); }
static struct stasis_app_command *exec_command_on_condition( struct stasis_app_control *control, stasis_app_command_cb command_fn, void *data, app_command_can_exec_cb can_exec_fn) { int retval; struct stasis_app_command *command; command_fn = command_fn ? : noop_cb; command = command_create(command_fn, data); if (!command) { return NULL; } ao2_lock(control->command_queue); if (can_exec_fn && (retval = can_exec_fn(control))) { ao2_unlock(control->command_queue); command_complete(command, retval); return command; } ao2_link_flags(control->command_queue, command, OBJ_NOLOCK); ast_cond_signal(&control->wait_cond); ao2_unlock(control->command_queue); return command; }
struct ast_named_lock *__ast_named_lock_get(const char *filename, int lineno, const char *func, enum ast_named_lock_type lock_type, const char *keyspace, const char *key) { struct ast_named_lock *lock = NULL; int concat_key_buff_len = strlen(keyspace) + strlen(key) + 2; char *concat_key = ast_alloca(concat_key_buff_len); sprintf(concat_key, "%s-%s", keyspace, key); /* Safe */ ao2_lock(named_locks); lock = ao2_find(named_locks, concat_key, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (lock) { ao2_unlock(named_locks); ast_assert((ao2_options_get(lock) & AO2_ALLOC_OPT_LOCK_MASK) == lock_type); return lock; } lock = ao2_alloc_options(sizeof(*lock) + concat_key_buff_len, NULL, lock_type); if (lock) { strcpy(lock->key, concat_key); /* Safe */ ao2_link_flags(named_locks, lock, OBJ_NOLOCK); } ao2_unlock(named_locks); return lock; }
struct stasis_topic *stasis_topic_pool_get_topic(struct stasis_topic_pool *pool, const char *topic_name) { RAII_VAR(struct topic_pool_entry *, topic_pool_entry, NULL, ao2_cleanup); SCOPED_AO2LOCK(topic_container_lock, pool->pool_container); topic_pool_entry = ao2_find(pool->pool_container, topic_name, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (topic_pool_entry) { return topic_pool_entry->topic; } topic_pool_entry = topic_pool_entry_alloc(); if (!topic_pool_entry) { return NULL; } topic_pool_entry->topic = stasis_topic_create(topic_name); if (!topic_pool_entry->topic) { return NULL; } topic_pool_entry->forward = stasis_forward_all(topic_pool_entry->topic, pool->pool_topic); if (!topic_pool_entry->forward) { return NULL; } if (!ao2_link_flags(pool->pool_container, topic_pool_entry, OBJ_NOLOCK)) { return NULL; } return topic_pool_entry->topic; }
int ast_format_cache_set(struct ast_format *format) { SCOPED_AO2WRLOCK(lock, formats); struct ast_format *old_format; ast_assert(format != NULL); if (ast_strlen_zero(ast_format_get_name(format))) { return -1; } old_format = ao2_find(formats, ast_format_get_name(format), OBJ_SEARCH_KEY | OBJ_NOLOCK); if (old_format) { ao2_unlink_flags(formats, old_format, OBJ_NOLOCK); } ao2_link_flags(formats, format, OBJ_NOLOCK); set_cached_format(ast_format_get_name(format), format); ast_verb(2, "%s cached format with name '%s'\n", old_format ? "Updated" : "Created", ast_format_get_name(format)); ao2_cleanup(old_format); return 0; }
int app_subscribe_endpoint(struct stasis_app *app, struct ast_endpoint *endpoint) { if (!app || !endpoint) { return -1; } else { RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup); SCOPED_AO2LOCK(lock, app->forwards); forwards = ao2_find(app->forwards, ast_endpoint_get_id(endpoint), OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!forwards) { /* Forwards not found, create one */ forwards = forwards_create_endpoint(app, endpoint); if (!forwards) { return -1; } ao2_link_flags(app->forwards, forwards, OBJ_NOLOCK); /* Subscribe for messages */ messaging_app_subscribe_endpoint(app->name, endpoint, &message_received_handler, app); } ++forwards->interested; ast_debug(3, "Endpoint '%s' is %d interested in %s\n", ast_endpoint_get_id(endpoint), forwards->interested, app->name); return 0; } }
int app_subscribe_endpoint(struct stasis_app *app, struct ast_endpoint *endpoint) { struct app_forwards *forwards; if (!app) { return -1; } ao2_lock(app->forwards); /* If subscribed to all, don't subscribe again */ forwards = ao2_find(app->forwards, ENDPOINT_ALL, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (forwards) { ao2_unlock(app->forwards); ao2_ref(forwards, -1); return 0; } forwards = ao2_find(app->forwards, endpoint ? ast_endpoint_get_id(endpoint) : ENDPOINT_ALL, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!forwards) { int res; /* Forwards not found, create one */ forwards = forwards_create_endpoint(app, endpoint); if (!forwards) { ao2_unlock(app->forwards); return -1; } res = ao2_link_flags(app->forwards, forwards, OBJ_NOLOCK); if (!res) { ao2_unlock(app->forwards); ao2_ref(forwards, -1); return -1; } /* Subscribe for messages */ messaging_app_subscribe_endpoint(app->name, endpoint, &message_received_handler, app); } ++forwards->interested; ast_debug(3, "Endpoint '%s' is %d interested in %s\n", endpoint ? ast_endpoint_get_id(endpoint) : "ALL", forwards->interested, app->name); ao2_unlock(app->forwards); ao2_ref(forwards, -1); return 0; }
int app_subscribe_channel(struct stasis_app *app, struct ast_channel *chan) { struct app_forwards *forwards; if (!app) { return -1; } ao2_lock(app->forwards); /* If subscribed to all, don't subscribe again */ forwards = ao2_find(app->forwards, CHANNEL_ALL, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (forwards) { ao2_unlock(app->forwards); ao2_ref(forwards, -1); return 0; } forwards = ao2_find(app->forwards, chan ? ast_channel_uniqueid(chan) : CHANNEL_ALL, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!forwards) { int res; /* Forwards not found, create one */ forwards = forwards_create_channel(app, chan); if (!forwards) { ao2_unlock(app->forwards); return -1; } res = ao2_link_flags(app->forwards, forwards, OBJ_NOLOCK); if (!res) { ao2_unlock(app->forwards); ao2_ref(forwards, -1); return -1; } } ++forwards->interested; ast_debug(3, "Channel '%s' is %d interested in %s\n", chan ? ast_channel_uniqueid(chan) : "ALL", forwards->interested, app->name); ao2_unlock(app->forwards); ao2_ref(forwards, -1); return 0; }
int app_subscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge) { struct app_forwards *forwards; if (!app) { return -1; } ao2_lock(app->forwards); /* If subscribed to all, don't subscribe again */ forwards = ao2_find(app->forwards, BRIDGE_ALL, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (forwards) { ao2_unlock(app->forwards); ao2_ref(forwards, -1); return 0; } forwards = ao2_find(app->forwards, bridge ? bridge->uniqueid : BRIDGE_ALL, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!forwards) { int res; /* Forwards not found, create one */ forwards = forwards_create_bridge(app, bridge); if (!forwards) { ao2_unlock(app->forwards); return -1; } res = ao2_link_flags(app->forwards, forwards, OBJ_NOLOCK); if (!res) { ao2_unlock(app->forwards); ao2_ref(forwards, -1); return -1; } } ++forwards->interested; ast_debug(3, "Bridge '%s' is %d interested in %s\n", bridge ? bridge->uniqueid : "ALL", forwards->interested, app->name); ao2_unlock(app->forwards); ao2_ref(forwards, -1); return 0; }
int __ast_codec_register(struct ast_codec *codec, struct ast_module *mod) { SCOPED_AO2WRLOCK(lock, codecs); struct ast_codec *codec_new; /* Some types have specific requirements */ if (codec->type == AST_MEDIA_TYPE_UNKNOWN) { ast_log(LOG_ERROR, "A media type must be specified for codec '%s'\n", codec->name); return -1; } else if (codec->type == AST_MEDIA_TYPE_AUDIO) { if (!codec->sample_rate) { ast_log(LOG_ERROR, "A sample rate must be specified for codec '%s' of type '%s'\n", codec->name, ast_codec_media_type2str(codec->type)); return -1; } } codec_new = ao2_find(codecs, codec, OBJ_SEARCH_OBJECT | OBJ_NOLOCK); if (codec_new) { ast_log(LOG_ERROR, "A codec with name '%s' of type '%s' and sample rate '%u' is already registered\n", codec->name, ast_codec_media_type2str(codec->type), codec->sample_rate); ao2_ref(codec_new, -1); return -1; } codec_new = ao2_t_alloc_options(sizeof(*codec_new), codec_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, "")); if (!codec_new) { ast_log(LOG_ERROR, "Could not allocate a codec with name '%s' of type '%s' and sample rate '%u'\n", codec->name, ast_codec_media_type2str(codec->type), codec->sample_rate); return -1; } *codec_new = *codec; codec_new->id = codec_id++; ao2_link_flags(codecs, codec_new, OBJ_NOLOCK); /* Once registered a codec can not be unregistered, and the module must persist until shutdown */ ast_module_shutdown_ref(mod); ast_verb(2, "Registered '%s' codec '%s' at sample rate '%u' with id '%u'\n", ast_codec_media_type2str(codec->type), codec->name, codec->sample_rate, codec_new->id); ao2_ref(codec_new, -1); return 0; }
/*! \brief Publish a received cluster discovery \ref ast_event to \ref stasis */ static void publish_cluster_discovery_to_stasis(struct ast_event *event) { struct corosync_node *node; int id = ast_event_get_ie_uint(event, AST_EVENT_IE_NODE_ID); struct ast_eid *event_eid; ast_assert(ast_event_get_type(event) == AST_EVENT_CLUSTER_DISCOVERY); event_eid = (struct ast_eid *)ast_event_get_ie_raw(event, AST_EVENT_IE_EID); if (!ast_eid_cmp(&ast_eid_default, event_eid)) { /* Don't feed events back in that originated locally. */ return; } ao2_lock(nodes); node = ao2_find(nodes, &id, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (node) { /* We already know about this node */ ao2_unlock(nodes); ao2_ref(node, -1); return; } node = corosync_node_alloc(event); if (!node) { ao2_unlock(nodes); return; } ao2_link_flags(nodes, node, OBJ_NOLOCK); ao2_unlock(nodes); publish_cluster_discovery_to_stasis_full(node, 1); ao2_ref(node, -1); /* * When we get news that someone else has joined, we need to let them * know we exist as well. */ send_cluster_notify(); }
static struct stasis_app_command *exec_command( struct stasis_app_control *control, stasis_app_command_cb command_fn, void *data) { RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup); command_fn = command_fn ? : noop_cb; command = command_create(command_fn, data); if (!command) { return NULL; } ao2_lock(control->command_queue); ao2_link_flags(control->command_queue, command, OBJ_NOLOCK); ast_cond_signal(&control->wait_cond); ao2_unlock(control->command_queue); ao2_ref(command, +1); return command; }
static struct stasis_message *cache_put(struct stasis_cache *cache, struct stasis_message_type *type, const char *id, struct stasis_message *new_snapshot) { RAII_VAR(struct cache_entry *, new_entry, NULL, ao2_cleanup); RAII_VAR(struct cache_entry *, cached_entry, NULL, ao2_cleanup); struct stasis_message *old_snapshot = NULL; ast_assert(cache->entries != NULL); ast_assert(new_snapshot == NULL || type == stasis_message_type(new_snapshot)); new_entry = cache_entry_create(type, id, new_snapshot); if (new_snapshot == NULL) { /* Remove entry from cache */ cached_entry = ao2_find(cache->entries, new_entry, OBJ_POINTER | OBJ_UNLINK); if (cached_entry) { old_snapshot = cached_entry->snapshot; cached_entry->snapshot = NULL; } } else { /* Insert/update cache */ SCOPED_AO2LOCK(lock, cache->entries); cached_entry = ao2_find(cache->entries, new_entry, OBJ_POINTER | OBJ_NOLOCK); if (cached_entry) { /* Update cache. Because objects are moving, no need to update refcounts. */ old_snapshot = cached_entry->snapshot; cached_entry->snapshot = new_entry->snapshot; new_entry->snapshot = NULL; } else { /* Insert into the cache */ ao2_link_flags(cache->entries, new_entry, OBJ_NOLOCK); } } return old_snapshot; }
/*! \note Called with the unsolicited_mwi conainer lock held. */ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags) { RAII_VAR(struct mwi_subscription *, aggregate_sub, NULL, ao2_cleanup); struct ast_sip_endpoint *endpoint = obj; char *endpoint_aors, *aor_name, *mailboxes, *mailbox; struct ao2_container *contacts = NULL; if (ast_strlen_zero(endpoint->subscription.mwi.mailboxes)) { return 0; } endpoint_aors = ast_strdupa(endpoint->aors); while ((aor_name = strsep(&endpoint_aors, ","))) { RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup); if (!aor) { continue; } contacts = ast_sip_location_retrieve_aor_contacts(aor); if (!contacts || (ao2_container_count(contacts) == 0)) { ao2_cleanup(contacts); contacts = NULL; continue; } break; } if (!contacts) { return 0; } ao2_ref(contacts, -1); if (endpoint->subscription.mwi.aggregate) { aggregate_sub = mwi_subscription_alloc(endpoint, 0, NULL); if (!aggregate_sub) { return 0; } } mailboxes = ast_strdupa(endpoint->subscription.mwi.mailboxes); while ((mailbox = strsep(&mailboxes, ","))) { struct mwi_subscription *sub = aggregate_sub ?: mwi_subscription_alloc(endpoint, 0, NULL); struct mwi_stasis_subscription *mwi_stasis_sub; mwi_stasis_sub = mwi_stasis_subscription_alloc(mailbox, sub); if (mwi_stasis_sub) { ao2_link(sub->stasis_subs, mwi_stasis_sub); ao2_ref(mwi_stasis_sub, -1); } if (!aggregate_sub && sub) { ao2_link_flags(unsolicited_mwi, sub, OBJ_NOLOCK); ao2_ref(sub, -1); } } if (aggregate_sub) { ao2_link_flags(unsolicited_mwi, aggregate_sub, OBJ_NOLOCK); } return 0; }
static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata) { struct ast_sip_endpoint *endpoint; struct unidentified_request *unid; int is_ack = rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD; endpoint = rdata->endpt_info.mod_data[endpoint_mod.id]; if (endpoint) { /* * ao2_find with OBJ_UNLINK always write locks the container before even searching * for the object. Since the majority case is that the object won't be found, do * the find without OBJ_UNLINK to prevent the unnecessary write lock, then unlink * if needed. */ unid = ao2_find(unidentified_requests, rdata->pkt_info.src_name, OBJ_SEARCH_KEY); if (unid) { ao2_unlink(unidentified_requests, unid); ao2_ref(unid, -1); } apply_acls(rdata); return PJ_FALSE; } endpoint = ast_sip_identify_endpoint(rdata); if (endpoint) { unid = ao2_find(unidentified_requests, rdata->pkt_info.src_name, OBJ_SEARCH_KEY); if (unid) { ao2_unlink(unidentified_requests, unid); ao2_ref(unid, -1); } } if (!endpoint) { /* always use an artificial endpoint - per discussion no reason to have "alwaysauthreject" as an option. It is felt using it was a bug fix and it is not needed since we are not worried about breaking old stuff and we really don't want to enable the discovery of SIP accounts */ endpoint = ast_sip_get_artificial_endpoint(); } /* endpoint ref held by mod_data[] */ rdata->endpt_info.mod_data[endpoint_mod.id] = endpoint; if (endpoint == artificial_endpoint && !is_ack) { char name[AST_UUID_STR_LEN] = ""; pjsip_uri *from = rdata->msg_info.from->uri; if (PJSIP_URI_SCHEME_IS_SIP(from) || PJSIP_URI_SCHEME_IS_SIPS(from)) { pjsip_sip_uri *sip_from = pjsip_uri_get_uri(from); ast_copy_pj_str(name, &sip_from->user, sizeof(name)); } unid = ao2_find(unidentified_requests, rdata->pkt_info.src_name, OBJ_SEARCH_KEY); if (unid) { check_endpoint(rdata, unid, name); ao2_ref(unid, -1); } else if (using_auth_username) { ao2_wrlock(unidentified_requests); /* Checking again with the write lock held allows us to eliminate the DUPS_REPLACE and sort_fn */ unid = ao2_find(unidentified_requests, rdata->pkt_info.src_name, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (unid) { check_endpoint(rdata, unid, name); } else { unid = ao2_alloc_options(sizeof(*unid) + strlen(rdata->pkt_info.src_name) + 1, NULL, AO2_ALLOC_OPT_LOCK_RWLOCK); if (!unid) { ao2_unlock(unidentified_requests); pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); return PJ_TRUE; } strcpy(unid->src_name, rdata->pkt_info.src_name); /* Safe */ unid->first_seen = ast_tvnow(); unid->count = 1; ao2_link_flags(unidentified_requests, unid, OBJ_NOLOCK); } ao2_ref(unid, -1); ao2_unlock(unidentified_requests); } else { log_failed_request(rdata, "No matching endpoint found", 0, 0); ast_sip_report_invalid_endpoint(name, rdata); } } apply_acls(rdata); return PJ_FALSE; }
/*! \brief Apply handler for transports */ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) { struct ast_sip_transport *transport = obj; const char *transport_id = ast_sorcery_object_get_id(obj); RAII_VAR(struct ao2_container *, states, transport_states, states_cleanup); RAII_VAR(struct internal_state *, temp_state, NULL, ao2_cleanup); RAII_VAR(struct internal_state *, perm_state, NULL, ao2_cleanup); RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy); pj_status_t res = -1; int i; #define BIND_TRIES 3 #define BIND_DELAY_US 100000 if (!states) { return -1; } /* * transport_apply gets called for EVERY retrieval of a transport when using realtime. * We need to prevent multiple threads from trying to mess with underlying transports * at the same time. The container is the only thing we have to lock on. */ ao2_wrlock(states); temp_state = internal_state_alloc(transport); if (!temp_state) { ast_log(LOG_ERROR, "Transport '%s' failed to allocate memory\n", transport_id); return -1; } perm_state = find_internal_state_by_transport(transport); if (perm_state) { ast_sorcery_diff(sorcery, perm_state->transport, transport, &changes); if (!changes && !has_state_changed(perm_state->state, temp_state->state)) { /* In case someone is using the deprecated fields, reset them */ transport->state = perm_state->state; copy_state_to_transport(transport); ao2_replace(perm_state->transport, transport); return 0; } if (!transport->allow_reload) { if (!perm_state->change_detected) { perm_state->change_detected = 1; ast_log(LOG_WARNING, "Transport '%s' is not reloadable, maintaining previous values\n", transport_id); } /* In case someone is using the deprecated fields, reset them */ transport->state = perm_state->state; copy_state_to_transport(transport); ao2_replace(perm_state->transport, transport); return 0; } } if (temp_state->state->host.addr.sa_family != PJ_AF_INET && temp_state->state->host.addr.sa_family != PJ_AF_INET6) { ast_log(LOG_ERROR, "Transport '%s' could not be started as binding not specified\n", transport_id); return -1; } /* Set default port if not present */ if (!pj_sockaddr_get_port(&temp_state->state->host)) { pj_sockaddr_set_port(&temp_state->state->host, (transport->type == AST_TRANSPORT_TLS) ? 5061 : 5060); } /* Now that we know what address family we can set up a dnsmgr refresh for the external media address if present */ if (!ast_strlen_zero(transport->external_signaling_address)) { if (temp_state->state->host.addr.sa_family == pj_AF_INET()) { temp_state->state->external_address.ss.ss_family = AF_INET; } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) { temp_state->state->external_address.ss.ss_family = AF_INET6; } else { ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n", transport_id); return -1; } if (ast_dnsmgr_lookup(transport->external_signaling_address, &temp_state->state->external_address, &temp_state->state->external_address_refresher, NULL) < 0) { ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", transport_id); return -1; } } if (transport->type == AST_TRANSPORT_UDP) { for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { if (perm_state && perm_state->state && perm_state->state->transport) { pjsip_udp_transport_pause(perm_state->state->transport, PJSIP_UDP_TRANSPORT_DESTROY_SOCKET); usleep(BIND_DELAY_US); } if (temp_state->state->host.addr.sa_family == pj_AF_INET()) { res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(), &temp_state->state->host.ipv4, NULL, transport->async_operations, &temp_state->state->transport); } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) { res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(), &temp_state->state->host.ipv6, NULL, transport->async_operations, &temp_state->state->transport); } } if (res == PJ_SUCCESS && (transport->tos || transport->cos)) { pj_sock_t sock; pj_qos_params qos_params; sock = pjsip_udp_transport_get_socket(temp_state->state->transport); pj_sock_get_qos_params(sock, &qos_params); set_qos(transport, &qos_params); pj_sock_set_qos_params(sock, &qos_params); } } else if (transport->type == AST_TRANSPORT_TCP) { pjsip_tcp_transport_cfg cfg; pjsip_tcp_transport_cfg_default(&cfg, temp_state->state->host.addr.sa_family); cfg.bind_addr = temp_state->state->host; cfg.async_cnt = transport->async_operations; set_qos(transport, &cfg.qos_params); for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { if (perm_state && perm_state->state && perm_state->state->factory && perm_state->state->factory->destroy) { perm_state->state->factory->destroy(perm_state->state->factory); usleep(BIND_DELAY_US); } res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &temp_state->state->factory); } } else if (transport->type == AST_TRANSPORT_TLS) { if (transport->async_operations > 1 && ast_compare_versions(pj_get_version(), "2.5.0") < 0) { ast_log(LOG_ERROR, "Transport: %s: When protocol=tls and pjproject version < 2.5.0, async_operations can't be > 1\n", ast_sorcery_object_get_id(obj)); return -1; } temp_state->state->tls.password = pj_str((char*)transport->password); set_qos(transport, &temp_state->state->tls.qos_params); for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { if (perm_state && perm_state->state && perm_state->state->factory && perm_state->state->factory->destroy) { perm_state->state->factory->destroy(perm_state->state->factory); usleep(BIND_DELAY_US); } res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &temp_state->state->tls, &temp_state->state->host, NULL, transport->async_operations, &temp_state->state->factory); } } else if ((transport->type == AST_TRANSPORT_WS) || (transport->type == AST_TRANSPORT_WSS)) { if (transport->cos || transport->tos) { ast_log(LOG_WARNING, "TOS and COS values ignored for websocket transport\n"); } res = PJ_SUCCESS; } if (res != PJ_SUCCESS) { char msg[PJ_ERR_MSG_SIZE]; pj_strerror(res, msg, sizeof(msg)); ast_log(LOG_ERROR, "Transport '%s' could not be started: %s\n", ast_sorcery_object_get_id(obj), msg); return -1; } copy_state_to_transport(transport); if (perm_state) { ao2_unlink_flags(states, perm_state, OBJ_NOLOCK); } ao2_link_flags(states, temp_state, OBJ_NOLOCK); return 0; }