Skip to content

Commit 83281ca

Browse files
committed
b2b_sdp_demux: fix CANCEL handling concurrency
Thanks go to Suchi Sahoo from Five9 for reporting it
1 parent 87661e1 commit 83281ca

File tree

1 file changed

+64
-23
lines changed

1 file changed

+64
-23
lines changed

modules/b2b_sdp_demux/b2b_sdp_demux.c

Lines changed: 64 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ static struct b2b_sdp_stream *b2b_sdp_stream_raw_new(struct b2b_sdp_client *clie
207207
#define B2B_SDP_CLIENT_EARLY (1<<0)
208208
#define B2B_SDP_CLIENT_STARTED (1<<1)
209209
#define B2B_SDP_CLIENT_PENDING (1<<2)
210-
#define B2B_SDP_CLIENT_REPL (1<<3)
210+
#define B2B_SDP_CLIENT_REPL (1<<3)
211+
#define B2B_SDP_CLIENT_CANCEL (1<<4)
211212

212213
struct b2b_sdp_client {
213214
unsigned int flags;
@@ -393,27 +394,17 @@ static struct b2b_sdp_client *b2b_sdp_client_new(struct b2b_sdp_ctx *ctx)
393394
return client;
394395
}
395396

396-
static void b2b_sdp_client_terminate(struct b2b_sdp_client *client, str *key)
397+
static void b2b_sdp_client_end(struct b2b_sdp_client *client, str *key, int send_cancel)
397398
{
398399
str method;
399400
b2b_req_data_t req_data;
400-
int send_cancel = 0;
401-
if (!key || key->len == 0) {
402-
LM_WARN("cannot terminate non-started client\n");
403-
return;
404-
}
405-
lock_get(&client->ctx->lock);
406-
send_cancel = (client->flags & B2B_SDP_CLIENT_EARLY);
407-
if (!send_cancel && !(client->flags & B2B_SDP_CLIENT_STARTED)) {
408-
lock_release(&client->ctx->lock);
409-
goto delete;
410-
}
411-
client->flags &= ~(B2B_SDP_CLIENT_EARLY|B2B_SDP_CLIENT_STARTED);
412-
lock_release(&client->ctx->lock);
413-
if (send_cancel)
401+
402+
if (send_cancel) {
414403
init_str(&method, CANCEL);
415-
else
404+
client->flags |= B2B_SDP_CLIENT_CANCEL;
405+
} else {
416406
init_str(&method, BYE);
407+
}
417408

418409
memset(&req_data, 0, sizeof(b2b_req_data_t));
419410
req_data.no_cb = 1; /* do not call callback */
@@ -425,8 +416,26 @@ static void b2b_sdp_client_terminate(struct b2b_sdp_client *client, str *key)
425416
LM_INFO("[%.*s][%.*s] client request %.*s sent\n",
426417
client->ctx->callid.len, client->ctx->callid.s,
427418
key->len, key->s, method.len, method.s);
428-
delete:
429-
b2b_api.entity_delete(B2B_CLIENT, key, client->dlginfo, 1, 1);
419+
}
420+
421+
static void b2b_sdp_client_terminate(struct b2b_sdp_client *client, str *key)
422+
{
423+
int send_cancel = 0;
424+
if (!key || key->len == 0) {
425+
LM_WARN("cannot terminate non-started client\n");
426+
return;
427+
}
428+
lock_get(&client->ctx->lock);
429+
send_cancel = (client->flags & B2B_SDP_CLIENT_EARLY);
430+
b2b_sdp_client_end(client, key, send_cancel);
431+
if (!send_cancel && !(client->flags & B2B_SDP_CLIENT_STARTED)) {
432+
lock_release(&client->ctx->lock);
433+
return;
434+
}
435+
client->flags &= ~(B2B_SDP_CLIENT_EARLY|B2B_SDP_CLIENT_STARTED);
436+
lock_release(&client->ctx->lock);
437+
if (!send_cancel)
438+
b2b_api.entity_delete(B2B_CLIENT, key, client->dlginfo, 1, 1);
430439
}
431440

432441
static void b2b_sdp_client_free(void *param)
@@ -866,6 +875,11 @@ static int b2b_sdp_client_reinvite(struct sip_msg *msg, struct b2b_sdp_client *c
866875
}
867876
lock_get(&client->ctx->lock);
868877
if (client->flags & B2B_SDP_CLIENT_PENDING) {
878+
if ((client->flags & B2B_SDP_CLIENT_CANCEL) ||
879+
(client->ctx->flags & B2B_SDP_CTX_CANCELLED)) {
880+
LM_INFO("call already cancelled!\n");
881+
goto end;
882+
}
869883
LM_INFO("we still have pending requests!\n");
870884
code = 491;
871885
goto end;
@@ -929,6 +943,14 @@ static void b2b_sdp_client_release_streams(struct b2b_sdp_client *client)
929943
}
930944
}
931945

946+
static void b2b_sdp_client_destroy(struct b2b_sdp_client *client)
947+
{
948+
b2b_sdp_client_release_streams(client);
949+
b2b_sdp_client_release(client, 0);
950+
b2b_api.entity_delete(B2B_CLIENT, &client->b2b_key, client->dlginfo, 1, 1);
951+
}
952+
953+
932954
static void b2b_sdp_client_remove(struct b2b_sdp_client *client)
933955
{
934956
struct b2b_sdp_ctx *ctx = client->ctx;
@@ -1216,6 +1238,13 @@ static int b2b_sdp_client_reply_invite(struct sip_msg *msg, struct b2b_sdp_clien
12161238
client->flags &= ~(B2B_SDP_CLIENT_EARLY|B2B_SDP_CLIENT_PENDING);
12171239

12181240
if (msg != FAKED_REPLY && msg->REPLY_STATUS < 300) {
1241+
if (ctx->flags & B2B_SDP_CTX_CANCELLED) {
1242+
LM_DBG("contex already CANCELLED!\n");
1243+
if (!(client->flags & B2B_SDP_CLIENT_CANCEL))
1244+
b2b_sdp_client_end(client, &client->b2b_key, 0);
1245+
b2b_sdp_client_destroy(client);
1246+
goto release;
1247+
}
12191248
body = get_body_part(msg, TYPE_APPLICATION, SUBTYPE_SDP);
12201249
if (body && b2b_sdp_client_sync(client, body) >= 0) {
12211250
ctx->success_no++;
@@ -1226,9 +1255,7 @@ static int b2b_sdp_client_reply_invite(struct sip_msg *msg, struct b2b_sdp_clien
12261255
} else {
12271256
if (!(client->flags & B2B_SDP_CLIENT_STARTED)) {
12281257
/* client was not started, thus this is a final negative reply */
1229-
b2b_sdp_client_release_streams(client);
1230-
b2b_sdp_client_release(client, 0);
1231-
b2b_api.entity_delete(B2B_CLIENT, &client->b2b_key, client->dlginfo, 1, 1);
1258+
b2b_sdp_client_destroy(client);
12321259
}
12331260
}
12341261
body = NULL;
@@ -1255,6 +1282,7 @@ static int b2b_sdp_client_reply_invite(struct sip_msg *msg, struct b2b_sdp_clien
12551282
if (b2b_sdp_reply(&ctx->b2b_key, ctx->dlginfo, B2B_SERVER, METHOD_INVITE, 200, body) < 0)
12561283
LM_CRIT("could not answer B2B call!\n");
12571284
pkg_free(body->s);
1285+
ret = 1;
12581286
} else if (ret == -2) {
12591287
b2b_sdp_reply(&ctx->b2b_key, ctx->dlginfo, B2B_SERVER, METHOD_INVITE, 503, NULL);
12601288
}
@@ -1539,10 +1567,23 @@ static int b2b_sdp_server_invite(struct sip_msg *msg, struct b2b_sdp_ctx *ctx)
15391567

15401568
static int b2b_sdp_server_cancel(struct sip_msg *msg, struct b2b_sdp_ctx *ctx)
15411569
{
1570+
int send_cancel;
1571+
struct list_head *it;
1572+
struct b2b_sdp_client *client;
1573+
15421574
/* respond to the initial INVITE */
15431575
b2b_sdp_reply(&ctx->b2b_key, ctx->dlginfo, B2B_SERVER,
15441576
METHOD_INVITE, 487, NULL);
1545-
b2b_sdp_ctx_release(ctx, 0);
1577+
/* we need to cancel each pending client */
1578+
lock_get(&ctx->lock);
1579+
list_for_each(it, &ctx->clients) {
1580+
client = list_entry(it, struct b2b_sdp_client, list);
1581+
if (!client->b2b_key.len)
1582+
continue;
1583+
send_cancel = (client->flags & B2B_SDP_CLIENT_EARLY);
1584+
b2b_sdp_client_end(client, &client->b2b_key, send_cancel);
1585+
}
1586+
lock_release(&ctx->lock);
15461587
return 0;
15471588
}
15481589

0 commit comments

Comments
 (0)