|
|
@ -56,47 +56,37 @@ static int persistent_endpoint_cmp(void *obj, void *arg, int flags)
|
|
|
|
return !strcmp(ast_endpoint_get_resource(persistent1->endpoint), id) ? CMP_MATCH | CMP_STOP : 0;
|
|
|
|
return !strcmp(ast_endpoint_get_resource(persistent1->endpoint), id) ? CMP_MATCH | CMP_STOP : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*! \brief Structure for communicating contact status to
|
|
|
|
|
|
|
|
* persistent_endpoint_update_state from the contact/contact_status
|
|
|
|
|
|
|
|
* observers.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct sip_contact_status {
|
|
|
|
|
|
|
|
char *uri;
|
|
|
|
|
|
|
|
enum ast_sip_contact_status_type status;
|
|
|
|
|
|
|
|
int64_t rtt;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*! \brief Callback function for changing the state of an endpoint */
|
|
|
|
/*! \brief Callback function for changing the state of an endpoint */
|
|
|
|
static int persistent_endpoint_update_state(void *obj, void *arg, void *data, int flags)
|
|
|
|
static int persistent_endpoint_update_state(void *obj, void *arg, int flags)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct sip_persistent_endpoint *persistent = obj;
|
|
|
|
struct sip_persistent_endpoint *persistent = obj;
|
|
|
|
struct ast_endpoint *endpoint = persistent->endpoint;
|
|
|
|
struct ast_endpoint *endpoint = persistent->endpoint;
|
|
|
|
char *aor = arg;
|
|
|
|
struct ast_sip_contact_status *status = arg;
|
|
|
|
struct sip_contact_status *status = data;
|
|
|
|
|
|
|
|
struct ao2_container *contacts;
|
|
|
|
struct ao2_container *contacts;
|
|
|
|
struct ast_json *blob;
|
|
|
|
struct ast_json *blob;
|
|
|
|
struct ao2_iterator i;
|
|
|
|
struct ao2_iterator i;
|
|
|
|
struct ast_sip_contact *contact;
|
|
|
|
struct ast_sip_contact *contact;
|
|
|
|
enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE;
|
|
|
|
enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE;
|
|
|
|
|
|
|
|
|
|
|
|
if (!ast_strlen_zero(aor)) {
|
|
|
|
if (status) {
|
|
|
|
if (!strstr(persistent->aors, aor)) {
|
|
|
|
char rtt[32];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If the status' aor isn't one of the endpoint's, we skip */
|
|
|
|
|
|
|
|
if (!strstr(persistent->aors, status->aor)) {
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
snprintf(rtt, sizeof(rtt), "%" PRId64, status->rtt);
|
|
|
|
char rtt[32];
|
|
|
|
blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
|
|
|
|
snprintf(rtt, 31, "%" PRId64, status->rtt);
|
|
|
|
"contact_status", ast_sip_get_contact_status_label(status->status),
|
|
|
|
blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
|
|
|
|
"aor", status->aor,
|
|
|
|
"contact_status", ast_sip_get_contact_status_label(status->status),
|
|
|
|
"uri", status->uri,
|
|
|
|
"aor", aor,
|
|
|
|
"roundtrip_usec", rtt,
|
|
|
|
"uri", status->uri,
|
|
|
|
"endpoint_name", ast_endpoint_get_resource(endpoint));
|
|
|
|
"roundtrip_usec", rtt,
|
|
|
|
ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob);
|
|
|
|
"endpoint_name", ast_endpoint_get_resource(endpoint));
|
|
|
|
ast_json_unref(blob);
|
|
|
|
ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob);
|
|
|
|
|
|
|
|
ast_json_unref(blob);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Find all the contacts for this endpoint. If ANY are available,
|
|
|
|
/* Find all the contacts for this endpoint. If ANY are available,
|
|
|
|
* mark the endpoint as ONLINE.
|
|
|
|
* mark the endpoint as ONLINE.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
@ -142,57 +132,50 @@ static int persistent_endpoint_update_state(void *obj, void *arg, void *data, in
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*! \brief Function called when stuff relating to a contact happens (created/deleted) */
|
|
|
|
/*! \brief Function called when a contact is created */
|
|
|
|
static void persistent_endpoint_contact_created_observer(const void *object)
|
|
|
|
static void persistent_endpoint_contact_created_observer(const void *object)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const struct ast_sip_contact *contact = object;
|
|
|
|
const struct ast_sip_contact *contact = object;
|
|
|
|
char *id = ast_strdupa(ast_sorcery_object_get_id(contact));
|
|
|
|
struct ast_sip_contact_status *contact_status;
|
|
|
|
char *aor = NULL;
|
|
|
|
|
|
|
|
char *contact_uri = NULL;
|
|
|
|
contact_status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
|
|
|
|
struct sip_contact_status status;
|
|
|
|
ast_sorcery_object_get_id(contact));
|
|
|
|
|
|
|
|
if (!contact_status) {
|
|
|
|
aor = id;
|
|
|
|
ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n",
|
|
|
|
/* Dynamic contacts are delimited with ";@" and static ones with "@@" */
|
|
|
|
contact->aor, contact->uri);
|
|
|
|
if ((contact_uri = strstr(id, ";@")) || (contact_uri = strstr(id, "@@"))) {
|
|
|
|
return;
|
|
|
|
*contact_uri = '\0';
|
|
|
|
|
|
|
|
contact_uri += 2;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
contact_uri = id;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_string_field_set(contact_status, uri, contact->uri);
|
|
|
|
|
|
|
|
|
|
|
|
status.uri = contact_uri;
|
|
|
|
contact_status->status = CREATED;
|
|
|
|
status.status = CREATED;
|
|
|
|
|
|
|
|
status.rtt = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ast_verb(1, "Contact %s/%s has been created\n", aor, contact_uri);
|
|
|
|
ast_verb(1, "Contact %s/%s has been created\n",contact->aor, contact->uri);
|
|
|
|
|
|
|
|
|
|
|
|
ao2_callback_data(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor, &status);
|
|
|
|
ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status);
|
|
|
|
|
|
|
|
ao2_cleanup(contact_status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*! \brief Function called when stuff relating to a contact happens (created/deleted) */
|
|
|
|
/*! \brief Function called when a contact is deleted */
|
|
|
|
static void persistent_endpoint_contact_deleted_observer(const void *object)
|
|
|
|
static void persistent_endpoint_contact_deleted_observer(const void *object)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
char *id = ast_strdupa(ast_sorcery_object_get_id(object));
|
|
|
|
const struct ast_sip_contact *contact = object;
|
|
|
|
char *aor = NULL;
|
|
|
|
struct ast_sip_contact_status *contact_status;
|
|
|
|
char *contact_uri = NULL;
|
|
|
|
|
|
|
|
struct sip_contact_status status;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
aor = id;
|
|
|
|
contact_status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
|
|
|
|
/* Dynamic contacts are delimited with ";@" and static ones with "@@" */
|
|
|
|
ast_sorcery_object_get_id(contact));
|
|
|
|
if ((contact_uri = strstr(id, ";@")) || (contact_uri = strstr(id, "@@"))) {
|
|
|
|
if (!contact_status) {
|
|
|
|
*contact_uri = '\0';
|
|
|
|
ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n",
|
|
|
|
contact_uri += 2;
|
|
|
|
contact->aor, contact->uri);
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
contact_uri = id;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_string_field_set(contact_status, uri, contact->uri);
|
|
|
|
|
|
|
|
|
|
|
|
ast_verb(1, "Contact %s/%s has been deleted\n", aor, contact_uri);
|
|
|
|
contact_status->status = REMOVED;
|
|
|
|
|
|
|
|
|
|
|
|
status.uri = contact_uri;
|
|
|
|
ast_verb(1, "Contact %s/%s has been deleted\n", contact->aor, contact->uri);
|
|
|
|
status.status = REMOVED;
|
|
|
|
|
|
|
|
status.rtt = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ao2_callback_data(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor, &status);
|
|
|
|
ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status);
|
|
|
|
|
|
|
|
ao2_cleanup(contact_status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*! \brief Observer for contacts so state can be updated on respective endpoints */
|
|
|
|
/*! \brief Observer for contacts so state can be updated on respective endpoints */
|
|
|
@ -201,36 +184,23 @@ static const struct ast_sorcery_observer state_contact_observer = {
|
|
|
|
.deleted = persistent_endpoint_contact_deleted_observer,
|
|
|
|
.deleted = persistent_endpoint_contact_deleted_observer,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*! \brief Function called when stuff relating to a contact status happens (updated) */
|
|
|
|
/*! \brief Function called when a contact_status is updated */
|
|
|
|
static void persistent_endpoint_contact_status_observer(const void *object)
|
|
|
|
static void persistent_endpoint_contact_status_observer(const void *object)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const struct ast_sip_contact_status *contact_status = object;
|
|
|
|
struct ast_sip_contact_status *contact_status = (struct ast_sip_contact_status *)object;
|
|
|
|
char *id = ast_strdupa(ast_sorcery_object_get_id(object));
|
|
|
|
|
|
|
|
char *aor = NULL;
|
|
|
|
|
|
|
|
char *contact_uri = NULL;
|
|
|
|
|
|
|
|
struct sip_contact_status status;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If rtt_start is set (this is the outgoing OPTIONS), ignore. */
|
|
|
|
/* If rtt_start is set (this is the outgoing OPTIONS), ignore. */
|
|
|
|
if (contact_status->rtt_start.tv_sec > 0) {
|
|
|
|
if (contact_status->rtt_start.tv_sec > 0) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
aor = id;
|
|
|
|
|
|
|
|
/* Dynamic contacts are delimited with ";@" and static ones with "@@" */
|
|
|
|
|
|
|
|
if ((contact_uri = strstr(id, ";@")) || (contact_uri = strstr(id, "@@"))) {
|
|
|
|
|
|
|
|
*contact_uri = '\0';
|
|
|
|
|
|
|
|
contact_uri += 2;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
contact_uri = id;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (contact_status->status == contact_status->last_status) {
|
|
|
|
if (contact_status->status == contact_status->last_status) {
|
|
|
|
ast_debug(3, "Contact %s status didn't change: %s, RTT: %.3f msec\n",
|
|
|
|
ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n",
|
|
|
|
contact_uri, ast_sip_get_contact_status_label(contact_status->status),
|
|
|
|
contact_status->aor, contact_status->uri, ast_sip_get_contact_status_label(contact_status->status),
|
|
|
|
contact_status->rtt / 1000.0);
|
|
|
|
contact_status->rtt / 1000.0);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
ast_verb(1, "Contact %s/%s is now %s. RTT: %.3f msec\n", aor, contact_uri,
|
|
|
|
ast_verb(1, "Contact %s/%s is now %s. RTT: %.3f msec\n", contact_status->aor, contact_status->uri,
|
|
|
|
ast_sip_get_contact_status_label(contact_status->status),
|
|
|
|
ast_sip_get_contact_status_label(contact_status->status),
|
|
|
|
contact_status->rtt / 1000.0);
|
|
|
|
contact_status->rtt / 1000.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -241,11 +211,7 @@ static void persistent_endpoint_contact_status_observer(const void *object)
|
|
|
|
ast_sorcery_object_get_id(contact_status),
|
|
|
|
ast_sorcery_object_get_id(contact_status),
|
|
|
|
ast_sip_get_contact_status_label(contact_status->status));
|
|
|
|
ast_sip_get_contact_status_label(contact_status->status));
|
|
|
|
|
|
|
|
|
|
|
|
status.uri = contact_uri;
|
|
|
|
ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status);
|
|
|
|
status.status = contact_status->status;
|
|
|
|
|
|
|
|
status.rtt = contact_status->rtt;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ao2_callback_data(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor, &status);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*! \brief Observer for contacts so state can be updated on respective endpoints */
|
|
|
|
/*! \brief Observer for contacts so state can be updated on respective endpoints */
|
|
|
@ -1085,7 +1051,7 @@ static struct ast_endpoint *persistent_endpoint_find_or_create(const struct ast_
|
|
|
|
if (ast_strlen_zero(persistent->aors)) {
|
|
|
|
if (ast_strlen_zero(persistent->aors)) {
|
|
|
|
ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_UNKNOWN);
|
|
|
|
ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_UNKNOWN);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
persistent_endpoint_update_state(persistent, NULL, NULL, 0);
|
|
|
|
persistent_endpoint_update_state(persistent, NULL, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ao2_link_flags(persistent_endpoints, persistent, OBJ_NOLOCK);
|
|
|
|
ao2_link_flags(persistent_endpoints, persistent, OBJ_NOLOCK);
|
|
|
|