Skip to content

Commit

Permalink
b2b_entities: properly handle BYE while another request is pending
Browse files Browse the repository at this point in the history
Instead of rejecting the BYE with 491, first complete the transactions on the
UAS side with 200 OK for the BYE and 487 for the other pending transaction.
Also, mark the tuple for deletion at b2b_logic level and send a BYE to
the peer entity after completing any UAC transcations on this side.

Credits to David Escartin from Sonoc for reporting.

(cherry picked from commit da6975f)
  • Loading branch information
rvlad-patrascu committed Feb 6, 2023
1 parent 7a46b45 commit cc2683f
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 10 deletions.
3 changes: 3 additions & 0 deletions modules/b2b_entities/b2be_load.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@

#define B2B_NOTIFY_FL_TERMINATED (1<<0)
#define B2B_NOTIFY_FL_ACK_NEG (1<<1)
/* entity has been terminated on the spot when receiving a BYE request
* while another transaction was ongoing(no final reply sent) */
#define B2B_NOTIFY_FL_TERM_BYE (1<<2)

#define B2B_MAX_PREFIX_LEN 5
#define B2B_MAX_KEY_SIZE (B2B_MAX_PREFIX_LEN+4+10+10+INT2STR_MAX_LEN)
Expand Down
51 changes: 41 additions & 10 deletions modules/b2b_entities/dlg.c
Original file line number Diff line number Diff line change
Expand Up @@ -1139,17 +1139,46 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam)
/* there is another transaction for which no reply
* was sent out */
{
/* send reply */
LM_DBG("Received another request when the previous "
"one was in process\n");
str text = str_init("Request Pending");
if(tmb.t_reply_with_body( tm_tran, 491,
&text, 0, 0, &to_tag) < 0)
{
LM_ERR("failed to send reply with tm\n");
if (method_value != METHOD_BYE) {
/* send reply */
LM_DBG("Received another request when the previous "
"one was in process\n");
str text = str_init("Request Pending");
if(tmb.t_reply_with_body( tm_tran, 491,
&text, 0, 0, &to_tag) < 0)
{
LM_ERR("failed to send reply with tm\n");
}
LM_DBG("Sent reply [491] and unreffed the cell %p\n",
tm_tran);
} else {
LM_DBG("Received BYE while another request "
"was in process\n");
str text_ok = str_init("OK");
if(tmb.t_reply_with_body( tm_tran, 200,
&text_ok, 0, 0, &to_tag) < 0)
{
LM_ERR("failed to send reply with tm\n");
}
LM_DBG("Sent reply [200] and unreffed the cell %p\n",
tm_tran);
tmb.unref_cell(tm_tran);

str text_term = str_init("Request Terminated");
if(tmb.t_reply_with_body(dlg->uas_tran, 487,
&text_term, 0, 0, &to_tag) < 0)
{
LM_ERR("failed to send reply with tm\n");
}
LM_DBG("Sent reply [487] and unreffed the cell %p\n",
dlg->uas_tran);

tmb.unref_cell(dlg->uas_tran);
dlg->uas_tran = NULL;

b2b_cb_flags |= B2B_NOTIFY_FL_TERM_BYE;
goto run_cb;
}
LM_DBG("Sent reply [491] and unreffed the cell %p\n",
tm_tran);
}
tmb.unref_cell(tm_tran); /* for t_newtran() */
B2BE_LOCK_RELEASE(table, hash_index);
Expand All @@ -1173,6 +1202,8 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam)
}
}

run_cb:

b2b_cback = dlg->b2b_cback;
if(dlg->logic_key.s)
{
Expand Down
60 changes: 60 additions & 0 deletions modules/b2b_logic/logic.c
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,32 @@ do{ \
b2bl_htable[cur_route_ctx.hash_index].locked_by = -1; \
}while(0)

static int ack_and_term_entity(b2bl_tuple_t *tuple, b2bl_entity_id_t *entity,
unsigned int statuscode)
{
b2b_req_data_t req_data;

if (statuscode >= 200 && statuscode < 300) {
memset(&req_data, 0, sizeof(b2b_req_data_t));
PREP_REQ_DATA(entity);
req_data.method = &str_init("ACK");
b2bl_htable[tuple->hash_index].locked_by = process_no;
b2b_api.send_request(&req_data);
b2bl_htable[tuple->hash_index].locked_by = -1;
}

memset(&req_data, 0, sizeof(b2b_req_data_t));
PREP_REQ_DATA(entity);
req_data.method = &str_init("BYE");
b2bl_htable[tuple->hash_index].locked_by = process_no;
b2b_api.send_request(&req_data);
b2bl_htable[tuple->hash_index].locked_by = -1;

entity->disconnected = 1;

return 0;
}

int _b2b_handle_reply(struct sip_msg *msg, b2bl_tuple_t *tuple,
b2bl_entity_id_t *entity, b2bl_entity_id_t **entity_head)
{
Expand Down Expand Up @@ -933,6 +959,16 @@ int _b2b_handle_reply(struct sip_msg *msg, b2bl_tuple_t *tuple,
goto done;
}

if (peer->flags & ENTITY_FL_TERM_BYE) {
/* if not already terminated in BYE processing */
if (!entity->disconnected) {
ack_and_term_entity(tuple, entity, statuscode);
b2b_mark_todel(tuple);
}

goto done;
}

switch (method_value)
{
case METHOD_BYE:
Expand Down Expand Up @@ -1155,6 +1191,7 @@ int _b2b_handle_reply(struct sip_msg *msg, b2bl_tuple_t *tuple,
}

done:

if (tuple)
cur_route_ctx.flags |= B2BL_RT_DO_UPDATE;
done1:
Expand Down Expand Up @@ -1217,6 +1254,11 @@ int b2b_logic_notify_reply(int src, struct sip_msg* msg, str* key, str* body, st
}
}

if (msg->first_line.u.reply.statuscode >= 200) {
entity->flags |= ENTITY_FL_REPLY_RECEIVED;
entity->last_rcv_code = msg->first_line.u.reply.statuscode;
}

/* if a disconnected entity -> do nothing */
if(entity->disconnected)
{
Expand Down Expand Up @@ -1370,6 +1412,8 @@ int _b2b_pass_request(struct sip_msg *msg, b2bl_tuple_t *tuple,
LM_ERR("Sending request failed [%.*s]\n", peer->key.len, peer->key.s);
}
b2bl_htable[cur_route_ctx.hash_index].locked_by = -1;
if (request_id != B2B_ACK)
peer->flags &= ~ENTITY_FL_REPLY_RECEIVED;
peer = peer->next;
}

Expand Down Expand Up @@ -1465,6 +1509,9 @@ int b2b_logic_notify_request(int src, struct sip_msg* msg, str* key, str* body,
LM_DBG("ACK for a negative reply\n");
break;
case B2B_BYE:
if (flags & B2B_NOTIFY_FL_TERM_BYE)
break;

/* BYE already sent to this entity but we got no reply */
memset(&rpl_data, 0, sizeof(b2b_rpl_data_t));
PREP_RPL_DATA(entity);
Expand Down Expand Up @@ -1499,6 +1546,19 @@ int b2b_logic_notify_request(int src, struct sip_msg* msg, str* key, str* body,

switch (request_id) {
case B2B_BYE:
if (flags & B2B_NOTIFY_FL_TERM_BYE) {
entity->flags |= ENTITY_FL_TERM_BYE;

/* if peer has already received a reply, terminate entity here */
if (peer && !peer->disconnected &&
(peer->flags & ENTITY_FL_REPLY_RECEIVED)) {
ack_and_term_entity(tuple, peer, peer->last_rcv_code);
b2b_mark_todel(tuple);
}

goto done;
}

entity->disconnected = 1;
if(cbf && (tuple->cb.mask&B2B_BYE_CB))
{
Expand Down
7 changes: 7 additions & 0 deletions modules/b2b_logic/records.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
#include "b2b_logic.h"
#include "b2b_load.h"

/* flags used for terminating an entity after it's peer
* has already been terminated from b2b_entities; see B2B_NOTIFY_FL_TERM_BYE */
#define ENTITY_FL_TERM_BYE (1<<0)
#define ENTITY_FL_REPLY_RECEIVED (1<<1)

typedef struct b2bl_entity_id
{
str scenario_id;
Expand All @@ -50,6 +55,8 @@ typedef struct b2bl_entity_id
int disconnected;
int state;
int init_maxfwd;
unsigned int flags;
unsigned int last_rcv_code;
unsigned short no;
unsigned short sdp_type;
enum b2b_entity_type type;
Expand Down

0 comments on commit cc2683f

Please sign in to comment.