FS-5106 fire an event when a sip client doesn't respond to option-ping
When all-reg-options-ping is enabled, this adds a new custom event to mod_sofia (sofia::sip_user_state), which is fired when a client stops responding to such ping packets (or when it is reachable again). Add two needed new columns to the sip_registrations table: - ping_status, which is "Reachable" or "Unreachable" depending on the client status; - ping_count, which tracks the number of ping responses received and is used to provide some kind of hysteresis to avoid firing the event in case of transitory network failures. Then ping_count is checked against two threshold values, sip-user-ping-min and sip-user-ping-max in a similar fashion as the ping-{max,min} options for the gateways. These two values are configurable in the profile's xml configuration file. Also, if unregister-on-options-fail is enabled, the client is unregistered based on the number of OPTIONS failure which is also checked against the sip-user-ping-{min,max} values.
This commit is contained in:
parent
dac4afbfdb
commit
5653551904
|
@ -2418,6 +2418,7 @@ static int show_reg_callback(void *pArg, int argc, char **argv, char **columnNam
|
||||||
"Contact: \t%s\n"
|
"Contact: \t%s\n"
|
||||||
"Agent: \t%s\n"
|
"Agent: \t%s\n"
|
||||||
"Status: \t%s(%s) EXP(%s) EXPSECS(%d)\n"
|
"Status: \t%s(%s) EXP(%s) EXPSECS(%d)\n"
|
||||||
|
"Ping-Status:\t%s\n"
|
||||||
"Host: \t%s\n"
|
"Host: \t%s\n"
|
||||||
"IP: \t%s\n"
|
"IP: \t%s\n"
|
||||||
"Port: \t%s\n"
|
"Port: \t%s\n"
|
||||||
|
@ -2425,9 +2426,9 @@ static int show_reg_callback(void *pArg, int argc, char **argv, char **columnNam
|
||||||
"Auth-Realm: \t%s\n"
|
"Auth-Realm: \t%s\n"
|
||||||
"MWI-Account:\t%s@%s\n\n",
|
"MWI-Account:\t%s@%s\n\n",
|
||||||
switch_str_nil(argv[0]), switch_str_nil(argv[1]), switch_str_nil(argv[2]), switch_str_nil(argv[3]),
|
switch_str_nil(argv[0]), switch_str_nil(argv[1]), switch_str_nil(argv[2]), switch_str_nil(argv[3]),
|
||||||
switch_str_nil(argv[7]), switch_str_nil(argv[4]), switch_str_nil(argv[5]), exp_buf, exp_secs, switch_str_nil(argv[11]),
|
switch_str_nil(argv[7]), switch_str_nil(argv[4]), switch_str_nil(argv[5]), exp_buf, exp_secs, switch_str_nil(argv[18]),
|
||||||
switch_str_nil(argv[12]), switch_str_nil(argv[13]), switch_str_nil(argv[14]), switch_str_nil(argv[15]),
|
switch_str_nil(argv[11]), switch_str_nil(argv[12]), switch_str_nil(argv[13]), switch_str_nil(argv[14]),
|
||||||
switch_str_nil(argv[16]), switch_str_nil(argv[17]));
|
switch_str_nil(argv[15]), switch_str_nil(argv[16]), switch_str_nil(argv[17]));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2459,6 +2460,7 @@ static int show_reg_callback_xml(void *pArg, int argc, char **argv, char **colum
|
||||||
cb->stream->write_function(cb->stream, " <agent>%s</agent>\n", switch_amp_encode(switch_str_nil(argv[7]), xmlbuf, buflen));
|
cb->stream->write_function(cb->stream, " <agent>%s</agent>\n", switch_amp_encode(switch_str_nil(argv[7]), xmlbuf, buflen));
|
||||||
cb->stream->write_function(cb->stream, " <status>%s(%s) exp(%s) expsecs(%d)</status>\n", switch_str_nil(argv[4]), switch_str_nil(argv[5]),
|
cb->stream->write_function(cb->stream, " <status>%s(%s) exp(%s) expsecs(%d)</status>\n", switch_str_nil(argv[4]), switch_str_nil(argv[5]),
|
||||||
exp_buf, exp_secs);
|
exp_buf, exp_secs);
|
||||||
|
cb->stream->write_function(cb->stream, " <ping-status>%s</ping-status>\n", switch_str_nil(argv[18]));
|
||||||
cb->stream->write_function(cb->stream, " <host>%s</host>\n", switch_str_nil(argv[11]));
|
cb->stream->write_function(cb->stream, " <host>%s</host>\n", switch_str_nil(argv[11]));
|
||||||
cb->stream->write_function(cb->stream, " <network-ip>%s</network-ip>\n", switch_str_nil(argv[12]));
|
cb->stream->write_function(cb->stream, " <network-ip>%s</network-ip>\n", switch_str_nil(argv[12]));
|
||||||
cb->stream->write_function(cb->stream, " <network-port>%s</network-port>\n", switch_str_nil(argv[13]));
|
cb->stream->write_function(cb->stream, " <network-port>%s</network-port>\n", switch_str_nil(argv[13]));
|
||||||
|
@ -2682,19 +2684,19 @@ static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t
|
||||||
if (!sql && argv[2] && !strcasecmp(argv[2], "pres") && argv[3]) {
|
if (!sql && argv[2] && !strcasecmp(argv[2], "pres") && argv[3]) {
|
||||||
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
||||||
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
||||||
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host"
|
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status"
|
||||||
" from sip_registrations where profile_name='%q' and presence_hosts like '%%%q%%'", profile->name, argv[3]);
|
" from sip_registrations where profile_name='%q' and presence_hosts like '%%%q%%'", profile->name, argv[3]);
|
||||||
}
|
}
|
||||||
if (!sql && argv[2] && !strcasecmp(argv[2], "reg") && argv[3]) {
|
if (!sql && argv[2] && !strcasecmp(argv[2], "reg") && argv[3]) {
|
||||||
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
||||||
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
||||||
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host"
|
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host, ping_status"
|
||||||
" from sip_registrations where profile_name='%q' and contact like '%%%q%%'", profile->name, argv[3]);
|
" from sip_registrations where profile_name='%q' and contact like '%%%q%%'", profile->name, argv[3]);
|
||||||
}
|
}
|
||||||
if (!sql && argv[2] && !strcasecmp(argv[2], "reg")) {
|
if (!sql && argv[2] && !strcasecmp(argv[2], "reg")) {
|
||||||
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
||||||
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
||||||
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host"
|
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status"
|
||||||
" from sip_registrations where profile_name='%q'", profile->name);
|
" from sip_registrations where profile_name='%q'", profile->name);
|
||||||
}
|
}
|
||||||
if (!sql && argv[2] && !strcasecmp(argv[2], "user") && argv[3]) {
|
if (!sql && argv[2] && !strcasecmp(argv[2], "user") && argv[3]) {
|
||||||
|
@ -2721,7 +2723,7 @@ static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t
|
||||||
|
|
||||||
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
||||||
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
||||||
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host"
|
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status"
|
||||||
" from sip_registrations where profile_name='%q' and %s", profile->name, sqlextra);
|
" from sip_registrations where profile_name='%q' and %s", profile->name, sqlextra);
|
||||||
switch_safe_free(dup);
|
switch_safe_free(dup);
|
||||||
switch_safe_free(sqlextra);
|
switch_safe_free(sqlextra);
|
||||||
|
@ -2965,21 +2967,21 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl
|
||||||
|
|
||||||
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
||||||
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
||||||
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host"
|
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status"
|
||||||
" from sip_registrations where profile_name='%q' and presence_hosts like '%%%q%%'", profile->name, argv[3]);
|
" from sip_registrations where profile_name='%q' and presence_hosts like '%%%q%%'", profile->name, argv[3]);
|
||||||
}
|
}
|
||||||
if (!sql && argv[2] && !strcasecmp(argv[2], "reg") && argv[3]) {
|
if (!sql && argv[2] && !strcasecmp(argv[2], "reg") && argv[3]) {
|
||||||
|
|
||||||
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
||||||
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
||||||
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host"
|
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status"
|
||||||
" from sip_registrations where profile_name='%q' and contact like '%%%q%%'", profile->name, argv[3]);
|
" from sip_registrations where profile_name='%q' and contact like '%%%q%%'", profile->name, argv[3]);
|
||||||
}
|
}
|
||||||
if (!sql && argv[2] && !strcasecmp(argv[2], "reg")) {
|
if (!sql && argv[2] && !strcasecmp(argv[2], "reg")) {
|
||||||
|
|
||||||
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
||||||
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
||||||
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host"
|
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status"
|
||||||
" from sip_registrations where profile_name='%q'", profile->name);
|
" from sip_registrations where profile_name='%q'", profile->name);
|
||||||
}
|
}
|
||||||
if (!sql && argv[2] && !strcasecmp(argv[2], "user") && argv[3]) {
|
if (!sql && argv[2] && !strcasecmp(argv[2], "user") && argv[3]) {
|
||||||
|
@ -3006,7 +3008,7 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl
|
||||||
|
|
||||||
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
|
||||||
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
"rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
|
||||||
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host"
|
"network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status"
|
||||||
" from sip_registrations where profile_name='%q' and %s", profile->name, sqlextra);
|
" from sip_registrations where profile_name='%q' and %s", profile->name, sqlextra);
|
||||||
switch_safe_free(dup);
|
switch_safe_free(dup);
|
||||||
switch_safe_free(sqlextra);
|
switch_safe_free(sqlextra);
|
||||||
|
|
|
@ -84,6 +84,7 @@ typedef struct private_object private_object_t;
|
||||||
#define MY_EVENT_UNREGISTER "sofia::unregister"
|
#define MY_EVENT_UNREGISTER "sofia::unregister"
|
||||||
#define MY_EVENT_EXPIRE "sofia::expire"
|
#define MY_EVENT_EXPIRE "sofia::expire"
|
||||||
#define MY_EVENT_GATEWAY_STATE "sofia::gateway_state"
|
#define MY_EVENT_GATEWAY_STATE "sofia::gateway_state"
|
||||||
|
#define MY_EVENT_SIP_USER_STATE "sofia::sip_user_state"
|
||||||
#define MY_EVENT_NOTIFY_REFER "sofia::notify_refer"
|
#define MY_EVENT_NOTIFY_REFER "sofia::notify_refer"
|
||||||
#define MY_EVENT_REINVITE "sofia::reinvite"
|
#define MY_EVENT_REINVITE "sofia::reinvite"
|
||||||
#define MY_EVENT_GATEWAY_ADD "sofia::gateway_add"
|
#define MY_EVENT_GATEWAY_ADD "sofia::gateway_add"
|
||||||
|
@ -426,6 +427,13 @@ typedef enum {
|
||||||
SOFIA_GATEWAY_INVALID
|
SOFIA_GATEWAY_INVALID
|
||||||
} sofia_gateway_status_t;
|
} sofia_gateway_status_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SOFIA_REG_REACHABLE,
|
||||||
|
SOFIA_REG_UNREACHABLE,
|
||||||
|
|
||||||
|
SOFIA_REG_INVALID
|
||||||
|
} sofia_sip_user_status_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SUB_STATE_UNSUBED,
|
SUB_STATE_UNSUBED,
|
||||||
SUB_STATE_TRYING,
|
SUB_STATE_TRYING,
|
||||||
|
@ -603,6 +611,8 @@ struct sofia_profile {
|
||||||
char *challenge_realm;
|
char *challenge_realm;
|
||||||
char *pnp_prov_url;
|
char *pnp_prov_url;
|
||||||
char *pnp_notify_profile;
|
char *pnp_notify_profile;
|
||||||
|
int sip_user_ping_max;
|
||||||
|
int sip_user_ping_min;
|
||||||
sofia_cid_type_t cid_type;
|
sofia_cid_type_t cid_type;
|
||||||
switch_core_media_dtmf_t dtmf_type;
|
switch_core_media_dtmf_t dtmf_type;
|
||||||
int auto_restart;
|
int auto_restart;
|
||||||
|
@ -1124,6 +1134,9 @@ void sofia_profile_destroy(sofia_profile_t *profile);
|
||||||
switch_status_t sip_dig_function(_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream);
|
switch_status_t sip_dig_function(_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream);
|
||||||
const char *sofia_gateway_status_name(sofia_gateway_status_t status);
|
const char *sofia_gateway_status_name(sofia_gateway_status_t status);
|
||||||
void sofia_reg_fire_custom_gateway_state_event(sofia_gateway_t *gateway, int status, const char *phrase);
|
void sofia_reg_fire_custom_gateway_state_event(sofia_gateway_t *gateway, int status, const char *phrase);
|
||||||
|
const char *sofia_sip_user_status_name(sofia_sip_user_status_t status);
|
||||||
|
void sofia_reg_fire_custom_sip_user_state_event(sofia_profile_t *profile, const char *sip_user, const char *contact,
|
||||||
|
const char* from_user, const char* from_host, const char *call_id, sofia_sip_user_status_t status, int options_res, const char *phrase);
|
||||||
uint32_t sofia_reg_reg_count(sofia_profile_t *profile, const char *user, const char *host);
|
uint32_t sofia_reg_reg_count(sofia_profile_t *profile, const char *user, const char *host);
|
||||||
char *sofia_media_get_multipart(switch_core_session_t *session, const char *prefix, const char *sdp, char **mp_type);
|
char *sofia_media_get_multipart(switch_core_session_t *session, const char *prefix, const char *sdp, char **mp_type);
|
||||||
int sofia_glue_tech_simplify(private_object_t *tech_pvt);
|
int sofia_glue_tech_simplify(private_object_t *tech_pvt);
|
||||||
|
|
|
@ -2477,11 +2477,11 @@ void event_handler(switch_event_t *event)
|
||||||
sql = switch_mprintf("insert into sip_registrations "
|
sql = switch_mprintf("insert into sip_registrations "
|
||||||
"(call_id, sip_user, sip_host, presence_hosts, contact, status, rpid, expires,"
|
"(call_id, sip_user, sip_host, presence_hosts, contact, status, rpid, expires,"
|
||||||
"user_agent, server_user, server_host, profile_name, hostname, network_ip, network_port, sip_username, sip_realm,"
|
"user_agent, server_user, server_host, profile_name, hostname, network_ip, network_port, sip_username, sip_realm,"
|
||||||
"mwi_user, mwi_host, orig_server_host, orig_hostname) "
|
"mwi_user, mwi_host, orig_server_host, orig_hostname, ping_status, ping_count) "
|
||||||
"values ('%q','%q','%q','%q','%q','Registered','%q',%ld, '%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q')",
|
"values ('%q','%q','%q','%q','%q','Registered','%q',%ld, '%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q', '%q', %d)",
|
||||||
call_id, from_user, from_host, presence_hosts, contact_str, rpid, expires, user_agent, to_user, guess_ip4,
|
call_id, from_user, from_host, presence_hosts, contact_str, rpid, expires, user_agent, to_user, guess_ip4,
|
||||||
profile_name, mod_sofia_globals.hostname, network_ip, network_port, username, realm, mwi_user, mwi_host,
|
profile_name, mod_sofia_globals.hostname, network_ip, network_port, username, realm, mwi_user, mwi_host,
|
||||||
orig_server_host, orig_hostname);
|
orig_server_host, orig_hostname, "Reachable", 0);
|
||||||
|
|
||||||
if (sql) {
|
if (sql) {
|
||||||
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
|
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
|
||||||
|
@ -2495,6 +2495,33 @@ void event_handler(switch_event_t *event)
|
||||||
end:
|
end:
|
||||||
switch_safe_free(fixed_contact_str);
|
switch_safe_free(fixed_contact_str);
|
||||||
switch_safe_free(dup_mwi_account);
|
switch_safe_free(dup_mwi_account);
|
||||||
|
} else if ((subclass = switch_event_get_header_nil(event, "orig-event-subclass")) && !strcasecmp(subclass, MY_EVENT_SIP_USER_STATE)) {
|
||||||
|
char *profile_name = switch_event_get_header_nil(event, "orig-profile-name");
|
||||||
|
char *from_user = switch_event_get_header_nil(event, "orig-from-user");
|
||||||
|
char *from_host = switch_event_get_header_nil(event, "orig-from-host");
|
||||||
|
const char *call_id = switch_event_get_header_nil(event, "orig-call-id");
|
||||||
|
char *ping_status = switch_event_get_header_nil(event, "orig-Ping-Status");
|
||||||
|
sofia_profile_t *profile = NULL;
|
||||||
|
|
||||||
|
if (!profile_name || !(profile = sofia_glue_find_profile(profile_name))) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n");
|
||||||
|
} else {
|
||||||
|
if (!strcmp(ping_status, "REACHABLE")) {
|
||||||
|
sql = switch_mprintf("update sip_registrations set ping_status='%s' where sip_user='%s' and sip_host='%s' and call_id='%q'",
|
||||||
|
"Reachable", from_user, from_host, call_id);
|
||||||
|
} else {
|
||||||
|
sql = switch_mprintf("update sip_registrations set ping_status='%s' where sip_user='%s' and sip_host='%s' and call_id='%q'",
|
||||||
|
"Unreachable", from_user, from_host, call_id);
|
||||||
|
}
|
||||||
|
if (sql) {
|
||||||
|
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Propagating sip_user_state for %s@%s. Ping-Status: %s\n", from_user, from_host, ping_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profile) {
|
||||||
|
sofia_glue_release_profile(profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4014,6 +4041,9 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
|
||||||
|
|
||||||
profile->user_agent = switch_core_sprintf(profile->pool, "FreeSWITCH-mod_sofia/%s", switch_version_full());
|
profile->user_agent = switch_core_sprintf(profile->pool, "FreeSWITCH-mod_sofia/%s", switch_version_full());
|
||||||
|
|
||||||
|
profile->sip_user_ping_max = 3;
|
||||||
|
profile->sip_user_ping_min = 1;
|
||||||
|
|
||||||
profile->name = switch_core_strdup(profile->pool, xprofilename);
|
profile->name = switch_core_strdup(profile->pool, xprofilename);
|
||||||
switch_snprintf(url, sizeof(url), "sofia_reg_%s", xprofilename);
|
switch_snprintf(url, sizeof(url), "sofia_reg_%s", xprofilename);
|
||||||
|
|
||||||
|
@ -4772,6 +4802,10 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
|
||||||
} else {
|
} else {
|
||||||
sofia_clear_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL);
|
sofia_clear_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL);
|
||||||
}
|
}
|
||||||
|
} else if (!strcasecmp(var, "sip-user-ping-max")) {
|
||||||
|
profile->sip_user_ping_max = atoi(val);
|
||||||
|
} else if (!strcasecmp(var, "sip-user-ping-min")) {
|
||||||
|
profile->sip_user_ping_min = atoi(val);
|
||||||
} else if (!strcasecmp(var, "require-secure-rtp")) {
|
} else if (!strcasecmp(var, "require-secure-rtp")) {
|
||||||
if (switch_true(val)) {
|
if (switch_true(val)) {
|
||||||
sofia_set_pflag(profile, PFLAG_SECURE);
|
sofia_set_pflag(profile, PFLAG_SECURE);
|
||||||
|
@ -5545,6 +5579,44 @@ const char *sofia_gateway_status_name(sofia_gateway_status_t status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *sofia_sip_user_status_name(sofia_sip_user_status_t status)
|
||||||
|
{
|
||||||
|
static const char *status_names[] = { "UNREACHABLE", "REACHABLE", NULL };
|
||||||
|
|
||||||
|
if (status < SOFIA_REG_INVALID) {
|
||||||
|
return status_names[status];
|
||||||
|
} else {
|
||||||
|
return "INVALID";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cb_helper_sip_user_status {
|
||||||
|
char *status;
|
||||||
|
size_t status_len;
|
||||||
|
|
||||||
|
char *contact;
|
||||||
|
size_t contact_len;
|
||||||
|
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
int sofia_sip_user_status_callback(void *pArg, int argc, char **argv, char **columnNames)
|
||||||
|
{
|
||||||
|
struct cb_helper_sip_user_status *cbt = (struct cb_helper_sip_user_status *) pArg;
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "expected 3 arguments from query, instead got %d\n", argc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_copy_string(cbt->status, argv[0], cbt->status_len);
|
||||||
|
cbt->count = (argv[1] && switch_is_number(argv[1])) ? atoi(argv[1]) : 0;
|
||||||
|
|
||||||
|
switch_copy_string(cbt->contact, argv[2], cbt->contact_len);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void sofia_handle_sip_r_options(switch_core_session_t *session, int status,
|
static void sofia_handle_sip_r_options(switch_core_session_t *session, int status,
|
||||||
char const *phrase,
|
char const *phrase,
|
||||||
nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
|
nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
|
||||||
|
@ -5608,18 +5680,85 @@ static void sofia_handle_sip_r_options(switch_core_session_t *session, int statu
|
||||||
gateway->ping = switch_epoch_time_now(NULL) + gateway->ping_freq;
|
gateway->ping = switch_epoch_time_now(NULL) + gateway->ping_freq;
|
||||||
sofia_reg_release_gateway(gateway);
|
sofia_reg_release_gateway(gateway);
|
||||||
gateway->pinging = 0;
|
gateway->pinging = 0;
|
||||||
} else if (sofia_test_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL) && (status != 200 && status != 486) &&
|
} else if (sip && sip->sip_to && sip->sip_call_id && sip->sip_call_id->i_id && strchr(sip->sip_call_id->i_id, '_')) {
|
||||||
sip && sip->sip_to && sip->sip_call_id && sip->sip_call_id->i_id && strchr(sip->sip_call_id->i_id, '_')) {
|
|
||||||
char *sql;
|
|
||||||
time_t now = switch_epoch_time_now(NULL);
|
|
||||||
const char *call_id = strchr(sip->sip_call_id->i_id, '_') + 1;
|
const char *call_id = strchr(sip->sip_call_id->i_id, '_') + 1;
|
||||||
|
char *sql;
|
||||||
|
struct cb_helper_sip_user_status sip_user_status;
|
||||||
|
char ping_status[255] = "";
|
||||||
|
char sip_contact[1024] = "";
|
||||||
|
int sip_user_ping_min = profile->sip_user_ping_min;
|
||||||
|
int sip_user_ping_max = profile->sip_user_ping_max;
|
||||||
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Expire registration '%s@%s' due to options failure\n",
|
char *sip_user = switch_mprintf("%s@%s", sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host);
|
||||||
sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host);
|
|
||||||
|
sip_user_status.status = ping_status;
|
||||||
|
sip_user_status.status_len = sizeof(ping_status);
|
||||||
|
sip_user_status.contact = sip_contact;
|
||||||
|
sip_user_status.contact_len = sizeof(sip_contact);
|
||||||
|
sql = switch_mprintf("select ping_status, ping_count, contact from sip_registrations where sip_user='%s' and sip_host='%s' and call_id='%q'",
|
||||||
|
sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host, call_id);
|
||||||
|
sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_sip_user_status_callback, &sip_user_status);
|
||||||
|
switch_safe_free(sql);
|
||||||
|
|
||||||
|
if (status != 200 && status != 486) {
|
||||||
|
sip_user_status.count--;
|
||||||
|
if (sip_user_status.count >= 0) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Ping to sip user '%s@%s' failed with code %d - count %d, state %s\n",
|
||||||
|
sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host, status, sip_user_status.count, sip_user_status.status);
|
||||||
|
sql = switch_mprintf("update sip_registrations set ping_count=%d where sip_user='%s' and sip_host='%s' and call_id='%q'", sip_user_status.count,
|
||||||
|
sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host, call_id);
|
||||||
|
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
|
||||||
|
switch_safe_free(sql);
|
||||||
|
}
|
||||||
|
if (sip_user_status.count < sip_user_ping_min) {
|
||||||
|
if (strcmp(sip_user_status.status, "Unreachable")) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Sip user '%s@%s' is now Unreachable\n",
|
||||||
|
sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host);
|
||||||
|
sql = switch_mprintf("update sip_registrations set ping_status='Unreachable' where sip_user='%s' and sip_host='%s' and call_id='%q'",
|
||||||
|
sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host, call_id);
|
||||||
|
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
|
||||||
|
switch_safe_free(sql);
|
||||||
|
sofia_reg_fire_custom_sip_user_state_event(profile, sip_user, sip_user_status.contact, sip->sip_to->a_url->url_user,
|
||||||
|
sip->sip_to->a_url->url_host, call_id, SOFIA_REG_REACHABLE, status, phrase);
|
||||||
|
|
||||||
|
if (sofia_test_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL)) {
|
||||||
|
time_t now = switch_epoch_time_now(NULL);
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Expire sip user '%s@%s' due to options failure\n",
|
||||||
|
sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host);
|
||||||
|
|
||||||
|
sql = switch_mprintf("update sip_registrations set expires=%ld where sip_user='%s' and sip_host='%s' and call_id='%q'",
|
||||||
|
(long) now, sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host, call_id);
|
||||||
|
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
|
||||||
|
switch_safe_free(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sip_user_status.count++;
|
||||||
|
if (sip_user_status.count <= sip_user_ping_max) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Ping to sip user '%s@%s' succeeded with code %d - count %d, state %s\n",
|
||||||
|
sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host, status, sip_user_status.count, sip_user_status.status);
|
||||||
|
sql = switch_mprintf("update sip_registrations set ping_count=%d where sip_user='%s' and sip_host='%s' and call_id='%q'", sip_user_status.count,
|
||||||
|
sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host, call_id);
|
||||||
|
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
|
||||||
|
switch_safe_free(sql);
|
||||||
|
}
|
||||||
|
if (sip_user_status.count >= sip_user_ping_min) {
|
||||||
|
if (strcmp(sip_user_status.status, "Reachable")) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Sip user '%s@%s' is now Reachable\n",
|
||||||
|
sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host);
|
||||||
|
sql = switch_mprintf("update sip_registrations set ping_status='Reachable' where sip_user='%s' and sip_host='%s' and call_id='%q'",
|
||||||
|
sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host, call_id);
|
||||||
|
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
|
||||||
|
switch_safe_free(sql);
|
||||||
|
sofia_reg_fire_custom_sip_user_state_event(profile, sip_user, sip_user_status.contact, sip->sip_to->a_url->url_user,
|
||||||
|
sip->sip_to->a_url->url_host, call_id, SOFIA_REG_UNREACHABLE, status, phrase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_safe_free(sip_user);
|
||||||
|
|
||||||
sql = switch_mprintf("update sip_registrations set expires=%ld where sip_user='%s' and sip_host='%s' and call_id='%q'",
|
|
||||||
(long) now, sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host, call_id);
|
|
||||||
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1984,6 +1984,8 @@ int sofia_glue_init_sql(sofia_profile_t *profile)
|
||||||
" presence_hosts VARCHAR(255),\n"
|
" presence_hosts VARCHAR(255),\n"
|
||||||
" contact VARCHAR(1024),\n"
|
" contact VARCHAR(1024),\n"
|
||||||
" status VARCHAR(255),\n"
|
" status VARCHAR(255),\n"
|
||||||
|
" ping_status VARCHAR(255),\n"
|
||||||
|
" ping_count INTEGER,\n"
|
||||||
" rpid VARCHAR(255),\n"
|
" rpid VARCHAR(255),\n"
|
||||||
" expires BIGINT,\n"
|
" expires BIGINT,\n"
|
||||||
" user_agent VARCHAR(255),\n"
|
" user_agent VARCHAR(255),\n"
|
||||||
|
@ -2116,6 +2118,7 @@ int sofia_glue_init_sql(sofia_profile_t *profile)
|
||||||
"create index sr_expires on sip_registrations (expires)",
|
"create index sr_expires on sip_registrations (expires)",
|
||||||
"create index sr_hostname on sip_registrations (hostname)",
|
"create index sr_hostname on sip_registrations (hostname)",
|
||||||
"create index sr_status on sip_registrations (status)",
|
"create index sr_status on sip_registrations (status)",
|
||||||
|
"create index sr_ping_status on sip_registrations (ping_status)",
|
||||||
"create index sr_network_ip on sip_registrations (network_ip)",
|
"create index sr_network_ip on sip_registrations (network_ip)",
|
||||||
"create index sr_network_port on sip_registrations (network_port)",
|
"create index sr_network_port on sip_registrations (network_port)",
|
||||||
"create index sr_sip_username on sip_registrations (sip_username)",
|
"create index sr_sip_username on sip_registrations (sip_username)",
|
||||||
|
@ -2194,6 +2197,9 @@ int sofia_glue_init_sql(sofia_profile_t *profile)
|
||||||
|
|
||||||
|
|
||||||
switch_cache_db_test_reactive(dbh, test_sql, "drop table sip_registrations", reg_sql);
|
switch_cache_db_test_reactive(dbh, test_sql, "drop table sip_registrations", reg_sql);
|
||||||
|
|
||||||
|
switch_cache_db_test_reactive(dbh, "select ping_count from sip_registrations", NULL, "alter table sip_registrations add column ping_count INTEGER default 0");
|
||||||
|
switch_cache_db_test_reactive(dbh, "select ping_status from sip_registrations", NULL, "alter table sip_registrations add column ping_status VARCHAR(255) default \"Reachable\"");
|
||||||
|
|
||||||
test2 = switch_mprintf("%s;%s", test_sql, test_sql);
|
test2 = switch_mprintf("%s;%s", test_sql, test_sql);
|
||||||
|
|
||||||
|
|
|
@ -161,6 +161,26 @@ void sofia_reg_fire_custom_gateway_state_event(sofia_gateway_t *gateway, int sta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sofia_reg_fire_custom_sip_user_state_event(sofia_profile_t *profile, const char *sip_user, const char *contact,
|
||||||
|
const char* from_user, const char* from_host, const char *call_id, sofia_sip_user_status_t status, int options_res, const char *phrase)
|
||||||
|
{
|
||||||
|
switch_event_t *s_event;
|
||||||
|
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_SIP_USER_STATE) == SWITCH_STATUS_SUCCESS) {
|
||||||
|
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "sip_contact", contact);
|
||||||
|
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", profile->name);
|
||||||
|
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "sip_user", sip_user);
|
||||||
|
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-user", from_user);
|
||||||
|
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-host", from_host);
|
||||||
|
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "call-id", call_id);
|
||||||
|
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "Ping-Status", sofia_sip_user_status_name(status));
|
||||||
|
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "Status", "%d", options_res);
|
||||||
|
if (!zstr(phrase)) {
|
||||||
|
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "Phrase", phrase);
|
||||||
|
}
|
||||||
|
switch_event_fire(&s_event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void sofia_reg_unregister(sofia_profile_t *profile)
|
void sofia_reg_unregister(sofia_profile_t *profile)
|
||||||
{
|
{
|
||||||
sofia_gateway_t *gateway_ptr;
|
sofia_gateway_t *gateway_ptr;
|
||||||
|
@ -830,7 +850,7 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot)
|
||||||
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,rpid,"
|
sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,rpid,"
|
||||||
"expires,user_agent,server_user,server_host,profile_name"
|
"expires,user_agent,server_user,server_host,profile_name"
|
||||||
" from sip_registrations where hostname='%s' and "
|
" from sip_registrations where hostname='%s' and "
|
||||||
"profile_name='%s'", mod_sofia_globals.hostname, profile->name);
|
"profile_name='%s' and orig_hostname='%s'", mod_sofia_globals.hostname, profile->name, mod_sofia_globals.hostname);
|
||||||
|
|
||||||
sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_reg_nat_callback, profile);
|
sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_reg_nat_callback, profile);
|
||||||
switch_safe_free(sql);
|
switch_safe_free(sql);
|
||||||
|
@ -847,7 +867,7 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot)
|
||||||
"expires,user_agent,server_user,server_host,profile_name"
|
"expires,user_agent,server_user,server_host,profile_name"
|
||||||
" from sip_registrations where (status like '%%NAT%%' "
|
" from sip_registrations where (status like '%%NAT%%' "
|
||||||
"or contact like '%%fs_nat=yes%%') and hostname='%s' "
|
"or contact like '%%fs_nat=yes%%') and hostname='%s' "
|
||||||
"and profile_name='%s'", mod_sofia_globals.hostname, profile->name);
|
"and profile_name='%s' and orig_hostname='%s'", mod_sofia_globals.hostname, profile->name, mod_sofia_globals.hostname);
|
||||||
|
|
||||||
sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_reg_nat_callback, profile);
|
sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_reg_nat_callback, profile);
|
||||||
switch_safe_free(sql);
|
switch_safe_free(sql);
|
||||||
|
@ -1805,12 +1825,12 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
|
||||||
sql = switch_mprintf("insert into sip_registrations "
|
sql = switch_mprintf("insert into sip_registrations "
|
||||||
"(call_id,sip_user,sip_host,presence_hosts,contact,status,rpid,expires,"
|
"(call_id,sip_user,sip_host,presence_hosts,contact,status,rpid,expires,"
|
||||||
"user_agent,server_user,server_host,profile_name,hostname,network_ip,network_port,sip_username,sip_realm,"
|
"user_agent,server_user,server_host,profile_name,hostname,network_ip,network_port,sip_username,sip_realm,"
|
||||||
"mwi_user,mwi_host, orig_server_host, orig_hostname, sub_host) "
|
"mwi_user,mwi_host, orig_server_host, orig_hostname, sub_host, ping_status, ping_count) "
|
||||||
"values ('%q','%q', '%q','%q','%q','%q', '%q', %ld, '%q', '%q', '%q', '%q', '%q', '%q', '%q','%q','%q','%q','%q','%q','%q','%q')",
|
"values ('%q','%q', '%q','%q','%q','%q', '%q', %ld, '%q', '%q', '%q', '%q', '%q', '%q', '%q','%q','%q','%q','%q','%q','%q','%q', '%q', %d)",
|
||||||
call_id, to_user, reg_host, profile->presence_hosts ? profile->presence_hosts : "",
|
call_id, to_user, reg_host, profile->presence_hosts ? profile->presence_hosts : "",
|
||||||
contact_str, reg_desc, rpid, (long) reg_time + (long) exptime + profile->sip_expires_late_margin,
|
contact_str, reg_desc, rpid, (long) reg_time + (long) exptime + profile->sip_expires_late_margin,
|
||||||
agent, from_user, guess_ip4, profile->name, mod_sofia_globals.hostname, network_ip, network_port_c, username, realm,
|
agent, from_user, guess_ip4, profile->name, mod_sofia_globals.hostname, network_ip, network_port_c, username, realm,
|
||||||
mwi_user, mwi_host, guess_ip4, mod_sofia_globals.hostname, sub_host);
|
mwi_user, mwi_host, guess_ip4, mod_sofia_globals.hostname, sub_host, "Reachable", 0);
|
||||||
} else {
|
} else {
|
||||||
sql = switch_mprintf("update sip_registrations set call_id='%q',"
|
sql = switch_mprintf("update sip_registrations set call_id='%q',"
|
||||||
"sub_host='%q', network_ip='%q',network_port='%q',"
|
"sub_host='%q', network_ip='%q',network_port='%q',"
|
||||||
|
|
Loading…
Reference in New Issue