diff options
Diffstat (limited to 'res')
-rw-r--r-- | res/res_config_odbc.c | 1 | ||||
-rw-r--r-- | res/res_odbc.c | 16 | ||||
-rw-r--r-- | res/res_pjsip.c | 12 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 65 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_options.c | 84 | ||||
-rw-r--r-- | res/res_pjsip_exten_state.c | 10 | ||||
-rw-r--r-- | res/res_sorcery_realtime.c | 2 |
7 files changed, 141 insertions, 49 deletions
diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c index 37c6d3ff9..26aa17b17 100644 --- a/res/res_config_odbc.c +++ b/res/res_config_odbc.c @@ -137,6 +137,7 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data) if (!ast_strlen_zero(cps->extra)) { const char *newval = cps->extra; + ast_debug(1, "Parameter %d = '%s'\n", x, newval); if (strchr(newval, ';') || strchr(newval, '^')) { ENCODE_CHUNK(encodebuf, newval); ast_string_field_set(cps, encoding[x], encodebuf); diff --git a/res/res_odbc.c b/res/res_odbc.c index a89c95492..bd64b9fef 100644 --- a/res/res_odbc.c +++ b/res/res_odbc.c @@ -744,6 +744,22 @@ static int aoro2_class_cb(void *obj, void *arg, int flags) return 0; } +unsigned int ast_odbc_get_max_connections(const char *name) +{ + struct odbc_class *class; + unsigned int max_connections; + + class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name); + if (!class) { + return 0; + } + + max_connections = class->maxconnections; + ao2_ref(class, -1); + + return max_connections; +} + /* * \brief Determine if the connection has died. * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index d99c1cf84..af2f93749 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -900,6 +900,15 @@ mask with a slash ('/') </para></description> </configOption> + <configOption name="subscribe_context"> + <synopsis>Context for incoming MESSAGE requests.</synopsis> + <description><para> + If specified, incoming SUBSCRIBE requests will be searched for the matching + extension in the indicated context. + If no <replaceable>subscribe_context</replaceable> is specified, + then the <replaceable>context</replaceable> setting is used. + </para></description> + </configOption> </configObject> <configObject name="auth"> <synopsis>Authentication type</synopsis> @@ -1964,6 +1973,9 @@ <parameter name="ActiveChannels"> <para>The number of active channels associated with this endpoint.</para> </parameter> + <parameter name="SubscribeContext"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='subscribe_context']/synopsis/node())"/></para> + </parameter> </syntax> </managerEventInstance> </managerEvent> diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 8a5ff416a..4d3fb6583 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -105,6 +105,40 @@ static void endpoint_update_state(struct ast_endpoint *endpoint, enum ast_endpoi ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_endpoint_get_resource(endpoint)); } +static void endpoint_publish_contact_status(struct ast_endpoint *endpoint, struct ast_sip_contact_status *contact) +{ + struct ast_json *blob; + char rtt[32]; + + snprintf(rtt, sizeof(rtt), "%" PRId64, contact->rtt); + blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", + "contact_status", ast_sip_get_contact_status_label(contact->status), + "aor", contact->aor, + "uri", contact->uri, + "roundtrip_usec", rtt, + "endpoint_name", ast_endpoint_get_resource(endpoint)); + if (blob) { + ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob); + ast_json_unref(blob); + } +} + +/*! \brief Callback function for publishing the status of an endpoint */ +static int persistent_endpoint_publish_status(void *obj, void *arg, int flags) +{ + struct sip_persistent_endpoint *persistent = obj; + struct ast_endpoint *endpoint = persistent->endpoint; + struct ast_sip_contact_status *status = arg; + + /* If the status' aor isn't one of the endpoint's, we skip */ + if (!strstr(persistent->aors, status->aor)) { + return 0; + } + + endpoint_publish_contact_status(endpoint, status); + return 0; +} + /*! \brief Callback function for changing the state of an endpoint */ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) { @@ -112,30 +146,17 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) struct ast_endpoint *endpoint = persistent->endpoint; struct ast_sip_contact_status *status = arg; struct ao2_container *contacts; - struct ast_json *blob; struct ao2_iterator i; struct ast_sip_contact *contact; enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE; - if (status) { - char rtt[32]; - - /* If the status' aor isn't one of the endpoint's, we skip */ - if (!strstr(persistent->aors, status->aor)) { - return 0; - } - - snprintf(rtt, sizeof(rtt), "%" PRId64, status->rtt); - blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", - "contact_status", ast_sip_get_contact_status_label(status->status), - "aor", status->aor, - "uri", status->uri, - "roundtrip_usec", rtt, - "endpoint_name", ast_endpoint_get_resource(endpoint)); - ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob); - ast_json_unref(blob); + /* If the status' aor isn't one of the endpoint's, we skip */ + if (!strstr(persistent->aors, status->aor)) { + return 0; } + endpoint_publish_contact_status(endpoint, status); + /* Find all the contacts for this endpoint. If ANY are available, * mark the endpoint as ONLINE. */ @@ -222,6 +243,13 @@ static void persistent_endpoint_contact_status_observer(const void *object) { struct ast_sip_contact_status *contact_status = (struct ast_sip_contact_status *)object; + if (contact_status->refresh) { + /* We are only re-publishing the contact status. */ + ao2_callback(persistent_endpoints, OBJ_NODATA, + persistent_endpoint_publish_status, contact_status); + return; + } + /* If rtt_start is set (this is the outgoing OPTIONS), ignore. */ if (contact_status->rtt_start.tv_sec > 0) { return; @@ -1859,6 +1887,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_deny", "", endpoint_acl_handler, NULL, NULL, 0, 0); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_permit", "", endpoint_acl_handler, NULL, NULL, 0, 0); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_acl", "", endpoint_acl_handler, contact_acl_to_str, NULL, 0, 0); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "subscribe_context", "", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct ast_sip_endpoint, subscription.context)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index dc3bce06f..808ee171a 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -43,7 +43,6 @@ static const char *status_map [] = { [UNKNOWN] = "Unknown", [CREATED] = "Created", [REMOVED] = "Removed", - [UPDATED] = "Updated", }; static const char *short_status_map [] = { @@ -52,7 +51,6 @@ static const char *short_status_map [] = { [UNKNOWN] = "Unknown", [CREATED] = "Created", [REMOVED] = "Removed", - [UPDATED] = "Updated", }; const char *ast_sip_get_contact_status_label(const enum ast_sip_contact_status_type status) @@ -157,7 +155,7 @@ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const * \brief Update an ast_sip_contact_status's elements. */ static void update_contact_status(const struct ast_sip_contact *contact, - enum ast_sip_contact_status_type value) + enum ast_sip_contact_status_type value, int is_contact_refresh) { RAII_VAR(struct ast_sip_contact_status *, status, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_contact_status *, update, NULL, ao2_cleanup); @@ -169,6 +167,26 @@ static void update_contact_status(const struct ast_sip_contact *contact, return; } + if (is_contact_refresh + && status->status == CREATED) { + /* + * The contact status hasn't been updated since creation + * and we don't want to re-send a created status. + */ + if (contact->qualify_frequency + || status->rtt_start.tv_sec > 0) { + /* Ignore, the status will change soon. */ + return; + } + + /* + * Convert to a regular contact status update + * because the status may never change. + */ + is_contact_refresh = 0; + value = UNKNOWN; + } + update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(status)); if (!update) { @@ -178,22 +196,35 @@ static void update_contact_status(const struct ast_sip_contact *contact, } ast_string_field_set(update, uri, contact->uri); - update->last_status = status->status; - update->status = value; - - /* if the contact is available calculate the rtt as - the diff between the last start time and "now" */ - update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0 ? - ast_tvdiff_us(ast_tvnow(), status->rtt_start) : 0; - update->rtt_start = ast_tv(0, 0); - - ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT", - "Contact: %s\r\n" - "Status: %s\r\n" - "RTT: %" PRId64, - ast_sorcery_object_get_id(update), - ast_sip_get_contact_status_label(update->status), - update->rtt); + + if (is_contact_refresh) { + /* Copy everything just to set the refresh flag. */ + update->status = status->status; + update->last_status = status->last_status; + update->rtt = status->rtt; + update->rtt_start = status->rtt_start; + update->refresh = 1; + } else { + update->last_status = status->status; + update->status = value; + + /* + * if the contact is available calculate the rtt as + * the diff between the last start time and "now" + */ + update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0 + ? ast_tvdiff_us(ast_tvnow(), status->rtt_start) + : 0; + update->rtt_start = ast_tv(0, 0); + + ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT", + "Contact: %s\r\n" + "Status: %s\r\n" + "RTT: %" PRId64, + ast_sorcery_object_get_id(update), + ast_sip_get_contact_status_label(update->status), + update->rtt); + } if (ast_sorcery_update(ast_sip_get_sorcery(), update)) { ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n", @@ -306,10 +337,10 @@ static void qualify_contact_cb(void *token, pjsip_event *e) /* Fall through */ case PJSIP_EVENT_TRANSPORT_ERROR: case PJSIP_EVENT_TIMER: - update_contact_status(contact, UNAVAILABLE); + update_contact_status(contact, UNAVAILABLE, 0); break; case PJSIP_EVENT_RX_MSG: - update_contact_status(contact, AVAILABLE); + update_contact_status(contact, AVAILABLE, 0); break; } ao2_cleanup(contact); @@ -365,7 +396,7 @@ static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_con != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to send request to qualify contact %s\n", contact->uri); - update_contact_status(contact, UNAVAILABLE); + update_contact_status(contact, UNAVAILABLE, 0); ao2_ref(contact, -1); return -1; } @@ -525,7 +556,7 @@ static void qualify_and_schedule(struct ast_sip_contact *contact) schedule_qualify(contact, contact->qualify_frequency * 1000); } else { - update_contact_status(contact, UNKNOWN); + update_contact_status(contact, UNKNOWN, 0); } } @@ -544,8 +575,7 @@ static void contact_created(const void *obj) */ static void contact_updated(const void *obj) { - update_contact_status((struct ast_sip_contact *) obj, UPDATED); - qualify_and_schedule((struct ast_sip_contact *) obj); + update_contact_status(obj, AVAILABLE, 1); } /*! @@ -574,8 +604,8 @@ static void contact_deleted(const void *obj) static const struct ast_sorcery_observer contact_observer = { .created = contact_created, + .updated = contact_updated, .deleted = contact_deleted, - .updated = contact_updated }; static pj_bool_t options_start(void) @@ -1051,7 +1081,7 @@ static void qualify_and_schedule_contact(struct ast_sip_contact *contact) if (contact->qualify_frequency) { schedule_qualify(contact, initial_interval); } else { - update_contact_status(contact, UNKNOWN); + update_contact_status(contact, UNKNOWN, 0); } } diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c index 25b9bf1fe..9bb53bfe3 100644 --- a/res/res_pjsip_exten_state.c +++ b/res/res_pjsip_exten_state.c @@ -412,9 +412,11 @@ static void subscription_shutdown(struct ast_sip_subscription *sub) static int new_subscribe(struct ast_sip_endpoint *endpoint, const char *resource) { - if (!ast_exists_extension(NULL, endpoint->context, resource, PRIORITY_HINT, NULL)) { + const char *context = S_OR(endpoint->subscription.context, endpoint->context); + + if (!ast_exists_extension(NULL, context, resource, PRIORITY_HINT, NULL)) { ast_log(LOG_NOTICE, "Extension state subscription failed: Extension %s does not exist in context '%s' or has no associated hint\n", - resource, endpoint->context); + resource, context); return 404; } @@ -432,7 +434,9 @@ static int subscription_established(struct ast_sip_subscription *sip_sub) return -1; } - ast_copy_string(exten_state_sub->context, endpoint->context, sizeof(exten_state_sub->context)); + ast_copy_string(exten_state_sub->context, + S_OR(endpoint->subscription.context, endpoint->context), + sizeof(exten_state_sub->context)); ast_copy_string(exten_state_sub->exten, resource, sizeof(exten_state_sub->exten)); if ((exten_state_sub->id = ast_extension_state_add_destroy_extended( diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c index abf2840fb..4023654ab 100644 --- a/res/res_sorcery_realtime.c +++ b/res/res_sorcery_realtime.c @@ -271,7 +271,7 @@ static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data return -1; } - return (ast_update_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) <= 0) ? -1 : 0; + return (ast_update_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) < 0) ? -1 : 0; } static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object) |