Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions modules/dialog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,32 @@ modparam("dialog", "options_ping_interval", 20)
```


#### options_ping_max_retries (integer)


The number of additional in-dialog OPTIONS pings to send when the
previous OPTIONS transaction times out, before declaring the dialog leg
unreachable. Retries are sent immediately after each transaction timeout,
without waiting for the next `options_ping_interval` tick. The retry counter
is maintained independently for each dialog leg and is reset by any final
response other than 408 or 481. A 481 response is considered definitive and
is not retried.

The maximum time needed to detect an unreachable peer is approximately
`(options_ping_max_retries + 1) * fr_timeout`, where `fr_timeout` is configured
by the "tm" module.


*Default value is "0" (no additional retries).*


```opensips title="Set options_ping_max_retries parameter"
...
modparam("dialog", "options_ping_max_retries", 2)
...
```


#### reinvite_ping_interval (integer)


Expand Down
7 changes: 7 additions & 0 deletions modules/dialog/dialog.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ static char* profiles_nv_s = NULL;
int dlg_bulk_del_no = 1; /* delete one by one */
int seq_match_mode = SEQ_MATCH_FALLBACK;
int options_ping_interval = 30; /* seconds */
int options_ping_max_retries = 0; /* extra OPTIONS pings to send on timeout before declaring leg dead */
int reinvite_ping_interval = 300; /* seconds */
int dlg_del_delay = 0; /* in seconds, default off */
str dlg_extra_hdrs = {NULL,0};
Expand Down Expand Up @@ -310,6 +311,7 @@ static const param_export_t mod_params[]={
{ "rr_param", STR_PARAM, &rr_param.s },
{ "default_timeout", INT_PARAM, &default_timeout },
{ "options_ping_interval", INT_PARAM, &options_ping_interval },
{ "options_ping_max_retries", INT_PARAM, &options_ping_max_retries },
{ "reinvite_ping_interval",INT_PARAM, &reinvite_ping_interval },
{ "delete_delay", INT_PARAM, &dlg_del_delay },
{ "dlg_extra_hdrs", STR_PARAM, &dlg_extra_hdrs.s },
Expand Down Expand Up @@ -805,6 +807,11 @@ static int mod_init(void)
return -1;
}

if (options_ping_max_retries < 0) {
LM_ERR("Negative options_ping_max_retries not accepted!!\n");
return -1;
}

/* update the len of the extra headers */
if (dlg_extra_hdrs.s)
dlg_extra_hdrs.len = strlen(dlg_extra_hdrs.s);
Expand Down
1 change: 1 addition & 0 deletions modules/dialog/dlg_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ struct dlg_leg {
struct dlg_leg_cseq_map *cseq_maps; /* used when translating ACKs */
char reply_received;
char reinvite_confirmed;
unsigned char ping_retries; /* failed OPTIONS pings since last success */
const struct socket_info *bind_addr;
};

Expand Down
39 changes: 39 additions & 0 deletions modules/dialog/dlg_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ struct dlg_reinvite_ping_timer *reinvite_ping_timer=0;
str options_str=str_init("OPTIONS");
str invite_str=str_init("INVITE");

extern int options_ping_max_retries;

/* forward declarations for OPTIONS ping retry from inside the reply callback */
void reply_from_caller(struct cell* t, int type, struct tmcb_params* ps);
void reply_from_callee(struct cell* t, int type, struct tmcb_params* ps);
void unref_dlg_cb(void *dlg);

/* for the dlg timer, there are 3 possible states :
* prev=next=0 -> dialog not in timer list
* prev=0 -> dialog expired
Expand Down Expand Up @@ -765,6 +772,36 @@ int dlg_handle_seq_reply(struct dlg_cell *dlg, struct sip_msg* rpl,
LM_DBG("Status Code received = [%d]\n", statuscode);

if (rpl == FAKED_REPLY || statuscode == 408) {
/* OPTIONS ping timeout: optionally retry immediately before giving up.
* Re-INVITE ping path is unchanged. */
if (!is_reinvite_rpl &&
dlg->legs[leg].ping_retries < (unsigned char)options_ping_max_retries) {
dlg_request_callback *cb;

dlg->legs[leg].ping_retries++;
LM_INFO("OPTIONS ping timeout on %s leg, retry %u/%d, "
"ci: [%.*s]\n",
leg == DLG_CALLER_LEG ? "caller" : "callee",
dlg->legs[leg].ping_retries, options_ping_max_retries,
dlg->callid.len, dlg->callid.s);

/* clear the gate so a new in-flight ping can be tracked */
*ping_status = DLG_PING_SUCCESS;

cb = (leg == DLG_CALLER_LEG) ? reply_from_caller : reply_from_callee;
ref_dlg(dlg, 1);
if (send_leg_msg(dlg, &options_str, other_leg(dlg, leg), leg,
0, 0, cb, dlg, unref_dlg_cb,
&dlg->legs[leg].reply_received) < 0) {
LM_ERR("failed to send OPTIONS retry on %s leg\n",
leg == DLG_CALLER_LEG ? "caller" : "callee");
unref_dlg(dlg, 1);
/* leave ping_retries as-is; the next interval-driven ping
* will continue from the current retry count */
}
return 0;
}

/* timeout occurred, nothing else to do now
* next time timer fires, it will detect ping reply was not received
*/
Expand All @@ -788,6 +825,8 @@ int dlg_handle_seq_reply(struct dlg_cell *dlg, struct sip_msg* rpl,
}

*ping_status = DLG_PING_SUCCESS;
if (!is_reinvite_rpl)
dlg->legs[leg].ping_retries = 0;
if (is_reinvite_rpl && statuscode < 300 && send_leg_msg(dlg, &ack,
other_leg(dlg, leg), leg, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
LM_ERR("cannot send ACK message!\n");
Expand Down