Ejemplo n.º 1
0
static void app_dtor(void *obj)
{
	struct stasis_app *app = obj;
	size_t size = strlen("stasis-") + strlen(app->name) + 1;
	char context_name[size];

	ast_verb(1, "Destroying Stasis app %s\n", app->name);

	ast_assert(app->router == NULL);
	ast_assert(app->bridge_router == NULL);
	ast_assert(app->endpoint_router == NULL);

	/* If we created a context for this application, remove it */
	strcpy(context_name, "stasis-");
	strcat(context_name, app->name);
	ast_context_destroy_by_name(context_name, "res_stasis");

	ao2_cleanup(app->topic);
	app->topic = NULL;
	ao2_cleanup(app->forwards);
	app->forwards = NULL;
	ao2_cleanup(app->data);
	app->data = NULL;

	ast_json_unref(app->events_allowed);
	app->events_allowed = NULL;
	ast_json_unref(app->events_disallowed);
	app->events_disallowed = NULL;

}
Ejemplo n.º 2
0
static struct ast_json *peerstatus_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize)
{
	struct ast_endpoint_blob *obj = stasis_message_data(msg);
	struct ast_json *json_endpoint;
	struct ast_json *json_peer;
	struct ast_json *json_final;
	const struct timeval *tv = stasis_message_timestamp(msg);

	json_endpoint = ast_endpoint_snapshot_to_json(obj->snapshot, NULL);
	if (!json_endpoint) {
		return NULL;
	}

	json_peer = ast_json_object_create();
	if (!json_peer) {
		ast_json_unref(json_endpoint);
		return NULL;
	}

	/* Copy all fields from the blob */
	ast_json_object_update(json_peer, obj->blob);

	json_final = ast_json_pack("{s: s, s: o, s: o, s: o }",
		"type", "PeerStatusChange",
		"timestamp", ast_json_timeval(*tv, NULL),
		"endpoint", json_endpoint,
		"peer", json_peer);
	if (!json_final) {
		ast_json_unref(json_endpoint);
		ast_json_unref(json_peer);
	}

	return json_final;
}
struct ast_json *stasis_app_mailboxes_to_json()
{
	struct ast_json *array = ast_json_array_create();
	struct ao2_container *mailboxes;
	struct ao2_iterator iter;
	const struct ast_mwi_mailbox_object *mailbox;

	if (!array) {
		return NULL;
	}

	mailboxes = ast_mwi_mailbox_get_all();
	if (!mailboxes) {
		ast_json_unref(array);
		return NULL;
	}

	iter = ao2_iterator_init(mailboxes, 0);
	for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
		struct ast_json *appending = mailbox_to_json(mailbox);
		if (!appending || ast_json_array_append(array, appending)) {
			/* Failed to append individual mailbox to the array. Abort. */
			ast_json_unref(array);
			array = NULL;
			break;
		}
	}
	ao2_iterator_destroy(&iter);

	return array;
}
Ejemplo n.º 4
0
void ast_ari_websocket_events_event_websocket_established(
		struct ast_ari_websocket_session *ws_session, struct ast_variable *headers,
		struct ast_ari_events_event_websocket_args *args)
{
	RAII_VAR(struct event_session *, session, NULL, event_session_cleanup);
	struct ast_json *msg;
	const char *session_id;

	ast_debug(3, "/events WebSocket established\n");

	ast_assert(ws_session != NULL);

	session_id = ast_ari_websocket_session_id(ws_session);

	/* Find the event_session and update its websocket  */
	session = ao2_find(event_session_registry, session_id, OBJ_SEARCH_KEY);

	if (session) {
		ao2_unlink(event_session_registry, session);
		event_session_update_websocket(session, ws_session);
	} else {
		ast_log(LOG_WARNING,
			"Failed to locate an event session for the provided websocket session\n");
	}

	/* We don't process any input, but we'll consume it waiting for EOF */
	while ((msg = ast_ari_websocket_session_read(ws_session))) {
		ast_json_unref(msg);
	}
}
Ejemplo n.º 5
0
static void app_data_dtor(void *obj)
{
	struct app_data *actual = obj;

	ast_json_unref(actual->messages);
	actual->messages = NULL;
}
Ejemplo n.º 6
0
static struct ast_json *contactstatus_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize)
{
	struct ast_endpoint_blob *obj = stasis_message_data(msg);
	struct ast_json *json_endpoint;
	struct ast_json *json_final;
	const struct timeval *tv = stasis_message_timestamp(msg);

	json_endpoint = ast_endpoint_snapshot_to_json(obj->snapshot, NULL);
	if (!json_endpoint) {
		return NULL;
	}

	json_final = ast_json_pack("{s: s, s: o, s: o, s: { s: s, s: s, s: s, s: s } } ",
		"type", "ContactStatusChange",
		"timestamp", ast_json_timeval(*tv, NULL),
		"endpoint", json_endpoint,
		"contact_info",
		"uri", ast_json_string_get(ast_json_object_get(obj->blob, "uri")),
		"contact_status", ast_json_string_get(ast_json_object_get(obj->blob, "contact_status")),
		"aor", ast_json_string_get(ast_json_object_get(obj->blob, "aor")),
		"roundtrip_usec", ast_json_string_get(ast_json_object_get(obj->blob, "roundtrip_usec")));
	if (!json_final) {
		ast_json_unref(json_endpoint);
	}

	return json_final;
}
Ejemplo n.º 7
0
/*!
 * \brief Explicitly shutdown a session.
 *
 * \details An explicit shutdown is necessary, since the \ref stasis_app has a reference
 *          to this session. We also need to be sure to null out the \c ws_session field,
 *          since the websocket is about to go away.
 *
 * \internal
 *
 * \param session  Event session object (\ref event_session).
 */
static void event_session_shutdown(struct event_session *session)
{
	struct ao2_iterator i;
	char *app;
	int j;
	SCOPED_AO2LOCK(lock, session);

	/* Clean up the websocket_apps container */
	if (session->websocket_apps) {
		i = ao2_iterator_init(session->websocket_apps, 0);
		while ((app = ao2_iterator_next(&i))) {
			stasis_app_unregister(app);
			ao2_cleanup(app);
		}
		ao2_iterator_destroy(&i);
		ao2_cleanup(session->websocket_apps);
		session->websocket_apps = NULL;
	}

	/* Clean up the message_queue container */
	for (j = 0; j < AST_VECTOR_SIZE(&session->message_queue); j++) {
		struct ast_json *msg = AST_VECTOR_GET(&session->message_queue, j);
		ast_json_unref(msg);
	}
	AST_VECTOR_FREE(&session->message_queue);

	/* Remove the handle to the underlying websocket session */
	session->ws_session = NULL;
}
Ejemplo n.º 8
0
/*!
 * \internal
 * \brief Destructor for \ref ast_multi_channel_blob objects
 */
static void multi_channel_blob_dtor(void *obj)
{
	struct ast_multi_channel_blob *multi_blob = obj;

	ao2_cleanup(multi_blob->channel_snapshots);
	ast_json_unref(multi_blob->blob);
}
Ejemplo n.º 9
0
static void sub_bridge_update_handler(void *data,
	struct stasis_subscription *sub,
	struct stasis_message *message)
{
	struct ast_json *json = NULL;
	struct stasis_app *app = data;
	struct ast_bridge_snapshot_update *update;
	const struct timeval *tv;

	update = stasis_message_data(message);

	tv = stasis_message_timestamp(message);

	if (!update->new_snapshot) {
		json = simple_bridge_event("BridgeDestroyed", update->old_snapshot, tv);
	} else if (!update->old_snapshot) {
		json = simple_bridge_event("BridgeCreated", update->new_snapshot, tv);
	} else if (update->new_snapshot && update->old_snapshot
		&& strcmp(update->new_snapshot->video_source_id, update->old_snapshot->video_source_id)) {
		json = simple_bridge_event("BridgeVideoSourceChanged", update->new_snapshot, tv);
		if (json && !ast_strlen_zero(update->old_snapshot->video_source_id)) {
			ast_json_object_set(json, "old_video_source_id",
				ast_json_string_create(update->old_snapshot->video_source_id));
		}
	}

	if (json) {
		app_send(app, json);
		ast_json_unref(json);
	}

	if (!update->new_snapshot && update->old_snapshot) {
		unsubscribe(app, "bridge", update->old_snapshot->uniqueid, 1);
	}
}
Ejemplo n.º 10
0
/*!
 * \internal
 * \c ast_ari_response destructor.
 */
static void response_free(struct ast_ari_response *resp)
{
	if (!resp) {
		return;
	}
	ast_free(resp->headers);
	ast_json_unref(resp->message);
	ast_free(resp);
}
Ejemplo n.º 11
0
/*! \brief Publish cluster discovery to \ref stasis */
static void publish_cluster_discovery_to_stasis_full(struct corosync_node *node, int joined)
{
	struct ast_json *json;
	struct ast_json_payload *payload;
	struct stasis_message *message;
	char eid[18];
	const char *addr;

	ast_eid_to_str(eid, sizeof(eid), &node->eid);
	addr = ast_sockaddr_stringify_addr(&node->addr);

	ast_log(AST_LOG_NOTICE, "Node %u (%s) at %s %s the cluster\n",
		node->id,
		eid,
		addr,
		joined ? "joined" : "left");

	json = ast_json_pack("{s: s, s: i, s: s, s: i}",
		"address", addr,
		"node_id", node->id,
		"eid", eid,
		"joined", joined);
	if (!json) {
		return;
	}

	payload = ast_json_payload_create(json);
	if (!payload) {
		ast_json_unref(json);
		return;
	}

	message = stasis_message_create(ast_cluster_discovery_type(), payload);
	if (!message) {
		ast_json_unref(json);
		ao2_ref(payload, -1);
		return;
	}

	stasis_publish(ast_system_topic(), message);
	ast_json_unref(json);
	ao2_ref(payload, -1);
	ao2_ref(message, -1);
}
Ejemplo n.º 12
0
void ast_ari_websocket_events_event_websocket_established(struct ast_ari_websocket_session *ws_session,
	struct ast_variable *headers,
	struct ast_ari_events_event_websocket_args *args)
{
	RAII_VAR(struct event_session *, session, NULL, session_cleanup);
	struct ast_json *msg;
	int res;
	size_t i;
	int (* register_handler)(const char *, stasis_app_cb handler, void *data);

	ast_debug(3, "/events WebSocket connection\n");

	session = session_create(ws_session);
	if (!session) {
		ast_ari_websocket_session_write(ws_session, ast_ari_oom_json());
		return;
	}

	if (args->subscribe_all) {
		register_handler = &stasis_app_register_all;
	} else {
		register_handler = &stasis_app_register;
	}

	res = 0;
	for (i = 0; i < args->app_count; ++i) {
		if (ast_strlen_zero(args->app[i])) {
			continue;
		}
		res |= session_register_app(session, args->app[i], register_handler);
	}

	if (ao2_container_count(session->websocket_apps) == 0) {
		RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);

		msg = ast_json_pack("{s: s, s: [s]}",
			"type", "MissingParams",
			"params", "app");
		if (!msg) {
			msg = ast_json_ref(ast_ari_oom_json());
		}

		ast_ari_websocket_session_write(session->ws_session, msg);
		return;
	}

	if (res != 0) {
		ast_ari_websocket_session_write(ws_session, ast_ari_oom_json());
		return;
	}

	/* We don't process any input, but we'll consume it waiting for EOF */
	while ((msg = ast_ari_websocket_session_read(ws_session))) {
		ast_json_unref(msg);
	}
}
Ejemplo n.º 13
0
static struct ast_json *dial_to_json(
	struct stasis_message *message,
	const struct stasis_message_sanitizer *sanitize)
{
	struct ast_multi_channel_blob *payload = stasis_message_data(message);
	struct ast_json *blob = ast_multi_channel_blob_get_json(payload);
	struct ast_json *caller_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "caller"), sanitize);
	struct ast_json *peer_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "peer"), sanitize);
	struct ast_json *forwarded_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "forwarded"), sanitize);
	struct ast_json *json;
	const struct timeval *tv = stasis_message_timestamp(message);
	int res = 0;

	json = ast_json_pack("{s: s, s: o, s: O, s: O, s: O}",
		"type", "Dial",
		"timestamp", ast_json_timeval(*tv, NULL),
		"dialstatus", ast_json_object_get(blob, "dialstatus"),
		"forward", ast_json_object_get(blob, "forward"),
		"dialstring", ast_json_object_get(blob, "dialstring"));
	if (!json) {
		ast_json_unref(caller_json);
		ast_json_unref(peer_json);
		ast_json_unref(forwarded_json);
		return NULL;
	}

	if (caller_json) {
		res |= ast_json_object_set(json, "caller", caller_json);
	}
	if (peer_json) {
		res |= ast_json_object_set(json, "peer", peer_json);
	}
	if (forwarded_json) {
		res |= ast_json_object_set(json, "forwarded", forwarded_json);
	}

	if (res) {
		ast_json_unref(json);
		return NULL;
	}

	return json;
}
Ejemplo n.º 14
0
/*! \brief Helper function which converts from a sorcery object set to a json object */
static struct ast_json *sorcery_objectset_to_json(const struct ast_variable *objectset)
{
	struct ast_json *json = ast_json_object_create();
	const struct ast_variable *field;

	for (field = objectset; field; field = field->next) {
		struct ast_json *value = ast_json_string_create(field->value);

		if (!value) {
			ast_json_unref(json);
			return NULL;
		} else if (ast_json_object_set(json, field->name, value)) {
			ast_json_unref(json);
			return NULL;
		}
	}

	return json;
}
Ejemplo n.º 15
0
struct ast_json *app_to_json(const struct stasis_app *app)
{
	struct ast_json *json;
	struct ast_json *channels;
	struct ast_json *bridges;
	struct ast_json *endpoints;
	struct ao2_iterator i;
	struct app_forwards *forwards;

	json = ast_json_pack("{s: s, s: [], s: [], s: []}",
		"name", app->name,
		"channel_ids", "bridge_ids", "endpoint_ids");
	if (!json) {
		return NULL;
	}
	channels = ast_json_object_get(json, "channel_ids");
	bridges = ast_json_object_get(json, "bridge_ids");
	endpoints = ast_json_object_get(json, "endpoint_ids");

	i = ao2_iterator_init(app->forwards, 0);
	while ((forwards = ao2_iterator_next(&i))) {
		struct ast_json *array = NULL;
		int append_res;

		switch (forwards->forward_type) {
		case FORWARD_CHANNEL:
			array = channels;
			break;
		case FORWARD_BRIDGE:
			array = bridges;
			break;
		case FORWARD_ENDPOINT:
			array = endpoints;
			break;
		}

		/* If forward_type value is unexpected this will safely return an error. */
		append_res = ast_json_array_append(array, ast_json_string_create(forwards->id));
		ao2_ref(forwards, -1);

		if (append_res != 0) {
			ast_log(LOG_ERROR, "Error building response\n");
			ao2_iterator_destroy(&i);
			ast_json_unref(json);

			return NULL;
		}
	}
	ao2_iterator_destroy(&i);

	return json;
}
Ejemplo n.º 16
0
/*!
 * \internal
 * \brief Destructor for \ref ast_multi_object_blob objects
 */
static void multi_object_blob_dtor(void *obj)
{
	struct ast_multi_object_blob *multi = obj;
	int type;
	int i;

	for (type = 0; type < STASIS_UMOS_MAX; ++type) {
		for (i = 0; i < AST_VECTOR_SIZE(&multi->snapshots[type]); ++i) {
			ao2_cleanup(AST_VECTOR_GET(&multi->snapshots[type], i));
		}
		AST_VECTOR_FREE(&multi->snapshots[type]);
	}
	ast_json_unref(multi->blob);
}
Ejemplo n.º 17
0
static void return_sorcery_object(struct ast_sorcery *sorcery, void *sorcery_obj,
	struct ast_ari_response *response)
{
	RAII_VAR(struct ast_json *, return_set, NULL, ast_json_unref);
	struct ast_variable *change_set;
	struct ast_variable *it_change_set;

	return_set = ast_json_array_create();
	if (!return_set) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	/* Note that we can't use the sorcery JSON change set directly,
	 * as it will hand us back an Object (with fields), and we need
	 * a more generic representation of whatever the API call asked
	 * for, i.e., a list of tuples.
	 */
	change_set = ast_sorcery_objectset_create(sorcery, sorcery_obj);
	if (!change_set) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	for (it_change_set = change_set; it_change_set; it_change_set = it_change_set->next) {
		struct ast_json *tuple;

		tuple = ast_json_pack("{s: s, s: s}",
			"attribute", it_change_set->name,
			"value", it_change_set->value);
		if (!tuple) {
			ast_variables_destroy(change_set);
			ast_ari_response_alloc_failed(response);
			return;
		}

		if (ast_json_array_append(return_set, tuple)) {
			ast_json_unref(tuple);
			ast_variables_destroy(change_set);
			ast_ari_response_alloc_failed(response);
			return;
		}
	}
	ast_variables_destroy(change_set);

	ast_ari_response_ok(response, ast_json_ref(return_set));
}
Ejemplo n.º 18
0
static int app_event_filter_set(struct stasis_app *app,	struct ast_json **member,
	struct ast_json *filter, const char *filter_type)
{
	if (filter && ast_json_typeof(filter) == AST_JSON_OBJECT) {
		if (!ast_json_object_size(filter)) {
			/* If no filters are specified then reset this filter type */
			filter = NULL;
		} else {
			/* Otherwise try to get the filter array for this type */
			filter = ast_json_object_get(filter, filter_type);
			if (!filter) {
				/* A filter type exists, but not this one, so don't update */
				return 0;
			}
		}
	}

	/* At this point the filter object should be an array */
	if (filter && ast_json_typeof(filter) != AST_JSON_ARRAY) {
		ast_log(LOG_ERROR, "Invalid json type event filter - app: %s, filter: %s\n",
				app->name, filter_type);
		return -1;
	}

	if (filter) {
		/* Confirm that at least the type names are specified */
		struct ast_json *obj;
		int i;

		for (i = 0; i < ast_json_array_size(filter) &&
				 (obj = ast_json_array_get(filter, i)); ++i) {

			if (ast_strlen_zero(ast_json_object_string_get(obj, "type"))) {
				ast_log(LOG_ERROR, "Filter event must have a type - app: %s, "
						"filter: %s\n",	app->name, filter_type);
				return -1;
			}
		}
	}

	ao2_lock(app);
	ast_json_unref(*member);
	*member = filter ? ast_json_ref(filter) : NULL;
	ao2_unlock(app);

	return 0;
}
Ejemplo n.º 19
0
static int message_received_handler(const char *endpoint_id, struct ast_json *json_msg, void *pvt)
{
	struct ast_endpoint_snapshot *snapshot;
	struct ast_json *json_endpoint;
	struct ast_json *message;
	struct stasis_app *app = pvt;
	char *tech;
	char *resource;

	tech = ast_strdupa(endpoint_id);
	resource = strchr(tech, '/');
	if (resource) {
		resource[0] = '\0';
		resource++;
	}

	if (ast_strlen_zero(tech) || ast_strlen_zero(resource)) {
		return -1;
	}

	snapshot = ast_endpoint_latest_snapshot(tech, resource);
	if (!snapshot) {
		return -1;
	}

	json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
	ao2_ref(snapshot, -1);
	if (!json_endpoint) {
		return -1;
	}

	message = ast_json_pack("{s: s, s: o, s: o, s: o}",
		"type", "TextMessageReceived",
		"timestamp", ast_json_timeval(ast_tvnow(), NULL),
		"endpoint", json_endpoint,
		"message", ast_json_ref(json_msg));
	if (message) {
		app_send(app, message);
		ast_json_unref(message);
	}

	return 0;
}
Ejemplo n.º 20
0
/*!
 * \brief Updates the websocket session for an \ref event_session.
 *
 * \details The websocket for the given \ref event_session will be updated to the value
 *          of the \c ws_session argument.
 *
 *          If the value of the \c ws_session is not \c NULL and there are messages in the
 *          event session's \c message_queue, the messages are dispatched and removed from
 *          the queue.
 *
 * \internal
 *
 * \param session     The event session object to update (\ref event_session).
 * \param ws_session  Handle to the underlying websocket session
 *                    (\ref ast_ari_websocket_session).
 */
static void event_session_update_websocket(
		struct event_session *session, struct ast_ari_websocket_session *ws_session)
{
	int i;

	ast_assert(session != NULL);

	ao2_lock(session);

	session->ws_session = ws_session;

	for (i = 0; i < AST_VECTOR_SIZE(&session->message_queue); i++) {
		struct ast_json *msg = AST_VECTOR_GET(&session->message_queue, i);
		ast_ari_websocket_session_write(session->ws_session, msg);
		ast_json_unref(msg);
	}

	AST_VECTOR_RESET(&session->message_queue, AST_VECTOR_ELEM_CLEANUP_NOOP);
	ao2_unlock(session);
}
Ejemplo n.º 21
0
static int unload_module(void)
{
    ast_ari_cli_unregister();

    if (is_enabled()) {
        ast_debug(3, "Disabling ARI\n");
        ast_http_uri_unlink(&http_uri);
    }

    ast_ari_config_destroy();

    ao2_cleanup(root_handler);
    root_handler = NULL;
    ast_mutex_destroy(&root_handler_lock);

    ast_json_unref(oom_json);
    oom_json = NULL;

    return 0;
}
Ejemplo n.º 22
0
static void sub_default_handler(void *data, struct stasis_subscription *sub,
	struct stasis_message *message)
{
	struct stasis_app *app = data;
	struct ast_json *json;

	/* The dial type can be converted to JSON so it will always be passed
	 * here.
	 */
	if (stasis_message_type(message) == ast_channel_dial_type()) {
		call_forwarded_handler(app, message);
	}

	/* By default, send any message that has a JSON representation */
	json = stasis_message_to_json(message, stasis_app_get_sanitizer());
	if (!json) {
		return;
	}

	app_send(app, json);
	ast_json_unref(json);
}
Ejemplo n.º 23
0
void app_update(struct stasis_app *app, stasis_app_cb handler, void *data)
{
	ao2_lock(app);
	if (app->handler && app->data) {
		struct ast_json *msg;

		ast_verb(1, "Replacing Stasis app '%s'\n", app->name);

		msg = ast_json_pack("{s: s, s: s}",
			"type", "ApplicationReplaced",
			"application", app->name);
		if (msg) {
			app_send(app, msg);
			ast_json_unref(msg);
		}
	} else {
		ast_verb(1, "Activating Stasis app '%s'\n", app->name);
	}

	app->handler = handler;
	ao2_replace(app->data, data);
	ao2_unlock(app);
}
Ejemplo n.º 24
0
static void sub_channel_update_handler(void *data,
	struct stasis_subscription *sub,
	struct stasis_message *message)
{
	struct stasis_app *app = data;
	struct ast_channel_snapshot_update *update = stasis_message_data(message);
	int i;

	for (i = 0; i < ARRAY_LEN(channel_monitors); ++i) {
		struct ast_json *msg;

		msg = channel_monitors[i](update->old_snapshot, update->new_snapshot,
			stasis_message_timestamp(message));
		if (msg) {
			app_send(app, msg);
			ast_json_unref(msg);
		}
	}

	if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
		unsubscribe(app, "channel", update->new_snapshot->base->uniqueid, 1);
	}
}
Ejemplo n.º 25
0
static void sub_endpoint_update_handler(void *data,
	struct stasis_subscription *sub,
	struct stasis_message *message)
{
	struct stasis_app *app = data;
	struct stasis_cache_update *update;
	struct ast_endpoint_snapshot *new_snapshot;
	struct ast_endpoint_snapshot *old_snapshot;
	const struct timeval *tv;

	ast_assert(stasis_message_type(message) == stasis_cache_update_type());

	update = stasis_message_data(message);

	ast_assert(update->type == ast_endpoint_snapshot_type());

	new_snapshot = stasis_message_data(update->new_snapshot);
	old_snapshot = stasis_message_data(update->old_snapshot);

	if (new_snapshot) {
		struct ast_json *json;

		tv = stasis_message_timestamp(update->new_snapshot);

		json = simple_endpoint_event("EndpointStateChange", new_snapshot, tv);
		if (!json) {
			return;
		}

		app_send(app, json);
		ast_json_unref(json);
	}

	if (!new_snapshot && old_snapshot) {
		unsubscribe(app, "endpoint", old_snapshot->id, 1);
	}
}
Ejemplo n.º 26
0
/*!
 * \internal
 * \brief ARI HTTP handler.
 *
 * This handler takes the HTTP request and turns it into the appropriate
 * RESTful request (conversion to JSON, routing, etc.)
 *
 * \param ser TCP session.
 * \param urih URI handler.
 * \param uri URI requested.
 * \param method HTTP method.
 * \param get_params HTTP \c GET params.
 * \param headers HTTP headers.
 */
static int ast_ari_callback(struct ast_tcptls_session_instance *ser,
                            const struct ast_http_uri *urih,
                            const char *uri,
                            enum ast_http_method method,
                            struct ast_variable *get_params,
                            struct ast_variable *headers)
{
    RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
    RAII_VAR(struct ast_str *, response_body, ast_str_create(256), ast_free);
    RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
    struct ast_ari_response response = {};
    RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy);

    if (!response_body) {
        ast_http_request_close_on_completion(ser);
        ast_http_error(ser, 500, "Server Error", "Out of memory");
        return 0;
    }

    response.headers = ast_str_create(40);
    if (!response.headers) {
        ast_http_request_close_on_completion(ser);
        ast_http_error(ser, 500, "Server Error", "Out of memory");
        return 0;
    }

    conf = ast_ari_config_get();
    if (!conf || !conf->general) {
        ast_free(response.headers);
        ast_http_request_close_on_completion(ser);
        ast_http_error(ser, 500, "Server Error", "URI handler config missing");
        return 0;
    }

    process_cors_request(headers, &response);

    /* Process form data from a POST. It could be mixed with query
     * parameters, which seems a bit odd. But it's allowed, so that's okay
     * with us.
     */
    post_vars = ast_http_get_post_vars(ser, headers);
    if (!post_vars) {
        switch (errno) {
        case EFBIG:
            ast_ari_response_error(&response, 413,
                                   "Request Entity Too Large",
                                   "Request body too large");
            goto request_failed;
        case ENOMEM:
            ast_http_request_close_on_completion(ser);
            ast_ari_response_error(&response, 500,
                                   "Internal Server Error",
                                   "Out of memory");
            goto request_failed;
        case EIO:
            ast_ari_response_error(&response, 400,
                                   "Bad Request", "Error parsing request body");
            goto request_failed;
        }
    }
    if (get_params == NULL) {
        get_params = post_vars;
    } else if (get_params && post_vars) {
        /* Has both post_vars and get_params */
        struct ast_variable *last_var = post_vars;
        while (last_var->next) {
            last_var = last_var->next;
        }
        /* The duped get_params will get freed when post_vars gets
         * ast_variables_destroyed.
         */
        last_var->next = ast_variables_dup(get_params);
        get_params = post_vars;
    }

    user = authenticate_user(get_params, headers);
    if (response.response_code > 0) {
        /* POST parameter processing error. Do nothing. */
    } else if (!user) {
        /* Per RFC 2617, section 1.2: The 401 (Unauthorized) response
         * message is used by an origin server to challenge the
         * authorization of a user agent. This response MUST include a
         * WWW-Authenticate header field containing at least one
         * challenge applicable to the requested resource.
         */
        ast_ari_response_error(&response, 401, "Unauthorized", "Authentication required");

        /* Section 1.2:
         *   realm       = "realm" "=" realm-value
         *   realm-value = quoted-string
         * Section 2:
         *   challenge   = "Basic" realm
         */
        ast_str_append(&response.headers, 0,
                       "WWW-Authenticate: Basic realm=\"%s\"\r\n",
                       conf->general->auth_realm);
    } else if (!ast_fully_booted) {
        ast_http_request_close_on_completion(ser);
        ast_ari_response_error(&response, 503, "Service Unavailable", "Asterisk not booted");
    } else if (user->read_only && method != AST_HTTP_GET && method != AST_HTTP_OPTIONS) {
        ast_ari_response_error(&response, 403, "Forbidden", "Write access denied");
    } else if (ast_ends_with(uri, "/")) {
        remove_trailing_slash(uri, &response);
    } else if (ast_begins_with(uri, "api-docs/")) {
        /* Serving up API docs */
        if (method != AST_HTTP_GET) {
            ast_ari_response_error(&response, 405, "Method Not Allowed", "Unsupported method");
        } else {
            /* Skip the api-docs prefix */
            ast_ari_get_docs(strchr(uri, '/') + 1, headers, &response);
        }
    } else {
        /* Other RESTful resources */
        ast_ari_invoke(ser, uri, method, get_params, headers,
                       &response);
    }

    if (response.no_response) {
        /* The handler indicates no further response is necessary.
         * Probably because it already handled it */
        ast_free(response.headers);
        return 0;
    }

request_failed:
    /* If you explicitly want to have no content, set message to
     * ast_json_null().
     */
    ast_assert(response.message != NULL);
    ast_assert(response.response_code > 0);

    /* response.message could be NULL, in which case the empty response_body
     * is correct
     */
    if (response.message && !ast_json_is_null(response.message)) {
        ast_str_append(&response.headers, 0,
                       "Content-type: application/json\r\n");
        if (ast_json_dump_str_format(response.message, &response_body,
                                     conf->general->format) != 0) {
            /* Error encoding response */
            response.response_code = 500;
            response.response_text = "Internal Server Error";
            ast_str_set(&response_body, 0, "%s", "");
            ast_str_set(&response.headers, 0, "%s", "");
        }
    }

    ast_debug(3, "Examining ARI response:\n%d %s\n%s\n%s\n", response.response_code,
              response.response_text, ast_str_buffer(response.headers), ast_str_buffer(response_body));
    ast_http_send(ser, method, response.response_code,
                  response.response_text, response.headers, response_body,
                  0, 0);
    /* ast_http_send takes ownership, so we don't have to free them */
    response_body = NULL;

    ast_json_unref(response.message);
    return 0;
}
Ejemplo n.º 27
0
static void endpoint_blob_dtor(void *obj)
{
	struct ast_endpoint_blob *event = obj;
	ao2_cleanup(event->snapshot);
	ast_json_unref(event->blob);
}
Ejemplo n.º 28
0
static void channel_blob_dtor(void *obj)
{
	struct ast_channel_blob *event = obj;
	ao2_cleanup(event->snapshot);
	ast_json_unref(event->blob);
}
Ejemplo n.º 29
0
static int beanstalk_put(struct ast_cdr *cdr) {
	struct ast_tm timeresult;
	char strAnswerTime[80] = "";
	char strStartTime[80];
	char strEndTime[80];
	char *cdr_buffer;
	int bs_id;
	int bs_socket;
	struct ast_json *t_cdr_json;

	if (!enablecdr) {
		return 0;
	}

	ast_rwlock_rdlock(&config_lock);
	bs_socket = bs_connect(bs_host, bs_port);

	if (bs_use(bs_socket, bs_tube) != BS_STATUS_OK) {
		ast_log(LOG_ERROR, "Connection to Beanstalk tube %s @ %s:%d had failed", bs_tube, bs_host, bs_port);
		ast_rwlock_unlock(&config_lock);
		return 0;
	}

	ast_localtime(&cdr->start, &timeresult, NULL);
	ast_strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult);

	if (cdr->answer.tv_sec) {
		ast_localtime(&cdr->answer, &timeresult, NULL);
		ast_strftime(strAnswerTime, sizeof(strAnswerTime), DATE_FORMAT, &timeresult);
	}

	ast_localtime(&cdr->end, &timeresult, NULL);
	ast_strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult);

	ast_rwlock_unlock(&config_lock);

	t_cdr_json = ast_json_pack("{s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:i, s:i, s:s, s:s, s:s, s:s}",
							   "AccountCode", S_OR(cdr->accountcode, ""),
							   "Source", S_OR(cdr->src, ""),
							   "Destination", S_OR(cdr->dst, ""),
							   "DestinationContext", S_OR(cdr->dcontext, ""),
							   "CallerID", S_OR(cdr->clid, ""),
							   "Channel", S_OR(cdr->channel, ""),
							   "DestinationChannel", S_OR(cdr->dstchannel, ""),
							   "LastApplication", S_OR(cdr->lastapp, ""),
							   "LastData", S_OR(cdr->lastdata, ""),
							   "StartTime", S_OR(strStartTime, ""),
							   "AnswerTime", S_OR(strAnswerTime, ""),
							   "EndTime", S_OR(strEndTime, ""),
							   "Duration", cdr->duration,
							   "Billsec", cdr->billsec,
							   "Disposition", S_OR(ast_cdr_disp2str(cdr->disposition), ""),
							   "AMAFlags", S_OR(ast_channel_amaflags2string(cdr->amaflags), ""),
							   "UniqueID", S_OR(cdr->uniqueid, ""),
							   "UserField", S_OR(cdr->userfield, ""));

	cdr_buffer = ast_json_dump_string(t_cdr_json);

	ast_json_unref(t_cdr_json);

	bs_id = bs_put(bs_socket, priority, BEANSTALK_JOB_DELAY, BEANSTALK_JOB_TTR, cdr_buffer, strlen(cdr_buffer));

	if (bs_id > 0) {
		ast_log(LOG_DEBUG, "Successfully created job %d with %s\n", bs_id, cdr_buffer);
	} else {
		ast_log(LOG_ERROR, "CDR job creation failed for %s\n", cdr_buffer);
	}

	bs_disconnect(bs_socket);
	ast_json_free(cdr_buffer);
	return 0;
}
Ejemplo n.º 30
0
static void json_payload_destructor(void *obj)
{
	struct ast_json_payload *payload = obj;
	ast_json_unref(payload->json);
}