コード例 #1
0
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;
}
コード例 #2
0
ファイル: format.c プロジェクト: asterisk/asterisk
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;
}
コード例 #3
0
ファイル: app.c プロジェクト: lyx2014/Asterisk
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;
	}
}
コード例 #4
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;
}
コード例 #5
0
ファイル: app.c プロジェクト: lyx2014/Asterisk
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;
	}
}
コード例 #6
0
ファイル: pjsip_distributor.c プロジェクト: scudella/asterisk
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);
}
コード例 #7
0
ファイル: control.c プロジェクト: vzar/asterisk
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;
}
コード例 #8
0
ファイル: named_locks.c プロジェクト: GGGO/asterisk
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;
}
コード例 #9
0
ファイル: stasis.c プロジェクト: GGGO/asterisk
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;
}
コード例 #10
0
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;
}
コード例 #11
0
ファイル: app.c プロジェクト: lyx2014/Asterisk
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;
	}
}
コード例 #12
0
ファイル: app.c プロジェクト: roramirez/asterisk
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;
}
コード例 #13
0
ファイル: app.c プロジェクト: roramirez/asterisk
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;
}
コード例 #14
0
ファイル: app.c プロジェクト: roramirez/asterisk
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;
}
コード例 #15
0
ファイル: codec.c プロジェクト: GGGO/asterisk
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;
}
コード例 #16
0
ファイル: res_corosync.c プロジェクト: neonecosystem/asterisk
/*! \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();
}
コード例 #17
0
ファイル: control.c プロジェクト: hardikk/asterisk
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;
}
コード例 #18
0
ファイル: stasis_cache.c プロジェクト: aderbas/asterisk
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;
}
コード例 #19
0
ファイル: res_pjsip_mwi.c プロジェクト: juned/asterisk
/*! \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;
}
コード例 #20
0
ファイル: pjsip_distributor.c プロジェクト: scudella/asterisk
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;
}
コード例 #21
0
ファイル: config_transport.c プロジェクト: GGGO/asterisk
/*! \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;
}