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; }
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; }
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); } }
static void app_data_dtor(void *obj) { struct app_data *actual = obj; ast_json_unref(actual->messages); actual->messages = NULL; }
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; }
/*! * \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; }
/*! * \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); }
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); } }
/*! * \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); }
/*! \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); }
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); } }
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; }
/*! \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; }
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; }
/*! * \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); }
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)); }
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; }
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; }
/*! * \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); }
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; }
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); }
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); }
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); } }
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); } }
/*! * \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; }
static void endpoint_blob_dtor(void *obj) { struct ast_endpoint_blob *event = obj; ao2_cleanup(event->snapshot); ast_json_unref(event->blob); }
static void channel_blob_dtor(void *obj) { struct ast_channel_blob *event = obj; ao2_cleanup(event->snapshot); ast_json_unref(event->blob); }
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; }
static void json_payload_destructor(void *obj) { struct ast_json_payload *payload = obj; ast_json_unref(payload->json); }