From 19b4512869b3b2f66c2b02ee27b5cb59bc0e8b13 Mon Sep 17 00:00:00 2001 From: Maximilian Fridrich Date: Thu, 7 Sep 2023 11:30:15 +0200 Subject: [PATCH] dialog: fix rtags of forking INVITE with 100rel --- src/sip/dialog.c | 47 +++++++- test/sipsess.c | 291 +++++++++++++++++++++++++++++++++++++++++++++-- test/test.c | 1 + test/test.h | 1 + 4 files changed, 329 insertions(+), 11 deletions(-) diff --git a/src/sip/dialog.c b/src/sip/dialog.c index 4585e22b6..9b1d4942b 100644 --- a/src/sip/dialog.c +++ b/src/sip/dialog.c @@ -462,7 +462,9 @@ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg) { const struct sip_hdr *contact; struct sip_addr addr; - char *uri; + struct route_enc renc; + struct pl pl; + char *uri, *rtag = NULL; int err; if (!dlg || !msg) @@ -475,14 +477,46 @@ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg) if (sip_addr_decode(&addr, &contact->val)) return EBADMSG; + renc.mb = mbuf_alloc(512); + if (!renc.mb) + return ENOMEM; + err = pl_strdup(&uri, &addr.auri); if (err) return err; - if (dlg->route.scheme.p == dlg->uri) { + err = pl_strdup(&rtag, msg->req ? &msg->from.tag : &msg->to.tag); + if (err) + goto out; + + renc.end = 0; + + err |= sip_msg_hdr_apply(msg, msg->req, SIP_HDR_RECORD_ROUTE, + record_route_handler, &renc) ? ENOMEM : 0; + err |= mbuf_printf(renc.mb, "To: %r\r\n", + msg->req ? &msg->from.val : &msg->to.val); + + dlg->mb->pos = dlg->cpos; + err |= mbuf_write_mem(renc.mb, mbuf_buf(dlg->mb), + mbuf_get_left(dlg->mb)); + dlg->mb->pos = 0; + + if (err) + goto out; + + renc.mb->pos = 0; + + if (renc.end) { + pl.p = (const char *)mbuf_buf(renc.mb) + ROUTE_OFFSET; + pl.l = renc.end - ROUTE_OFFSET; + err = sip_addr_decode(&addr, &pl); + if (err) + goto out; + dlg->route = addr.uri; + } + else { struct uri tmp; - struct pl pl; pl_set_str(&pl, uri); err = uri_decode(&tmp, &pl); @@ -492,11 +526,18 @@ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg) dlg->route = tmp; } + mem_deref(dlg->mb); mem_deref(dlg->uri); + mem_deref(dlg->rtag); + + dlg->mb = mem_ref(renc.mb); dlg->uri = mem_ref(uri); + dlg->rtag = mem_ref(rtag); out: + mem_deref(renc.mb); mem_deref(uri); + mem_deref(rtag); return err; } diff --git a/test/sipsess.c b/test/sipsess.c index c0051fb0b..87100766e 100644 --- a/test/sipsess.c +++ b/test/sipsess.c @@ -45,6 +45,7 @@ struct test { struct sipsess_sock *sock; struct sipsess *a; struct sipsess *b; + struct sipsess *c; struct tmr ans_tmr; bool estab_a; bool estab_b; @@ -60,7 +61,8 @@ struct test { enum rel100_state rel100_state_a; enum rel100_state rel100_state_b; enum connect_action conn_action; - prack_func *prack_action; + prack_func *prack_action_b; + prack_func *prack_action_c; int progr_ret_code; int answ_ret_code; bool upd_a; @@ -69,6 +71,8 @@ struct test { bool blind_transfer; uint16_t altaddr_port; int err; + char *rtag_b; + char *rtag_c; }; @@ -324,6 +328,12 @@ static void progr_handler_a(const struct sip_msg *msg, void *arg) (void)msg; test->progr_a = true; + + if (test->rtag_b) { + pl_strdup(&test->rtag_c,&msg->to.tag); + } else { + pl_strdup(&test->rtag_b, &msg->to.tag); + } } @@ -335,8 +345,42 @@ static void prack_handler(const struct sip_msg *msg, void *arg) if (test->sdp_state == ANSWER_RECEIVED) test->sdp_state = EARLY_CONFIRMED; - if (test->prack_action) - tmr_start(&test->ans_tmr, 0, test->prack_action, test); + if (test->prack_action_b) + tmr_start(&test->ans_tmr, 0, test->prack_action_b, test); +} + + +static void prack_handler_fork_b(const struct sip_msg *msg, void *arg) +{ + int err; + struct test *test = arg; + (void)msg; + + if (test->sdp_state == ANSWER_RECEIVED) + test->sdp_state = EARLY_CONFIRMED; + + if ((err = pl_strcmp(&msg->to.tag, test->rtag_b))) + abort_test(test, err); + + if (test->prack_action_b) + tmr_start(&test->ans_tmr, 0, test->prack_action_b, test); +} + + +static void prack_handler_fork_c(const struct sip_msg *msg, void *arg) +{ + int err; + struct test *test = arg; + (void)msg; + + if (test->sdp_state == ANSWER_RECEIVED) + test->sdp_state = EARLY_CONFIRMED; + + if ((err = pl_strcmp(&msg->to.tag, test->rtag_c))) + abort_test(test, err); + + if (test->prack_action_c) + tmr_start(&test->ans_tmr, 0, test->prack_action_c, test); } @@ -374,6 +418,127 @@ static void close_handler(int err, const struct sip_msg *msg, void *arg) } +static void conn_handler_fork(const struct sip_msg *msg, void *arg) +{ + struct test *test = arg; + struct mbuf *desc; + struct sip_msg *msg2 = (struct sip_msg *)msg; + int err; + char *hdrs = test->rel100_b == REL100_REQUIRED ? + "Require: 100rel\r\n" : ""; + + if (mbuf_get_left(msg->mb)) { + test->sdp_state = OFFER_RECEIVED; + test->offer_b = true; + } + + if (sip_msg_hdr_has_value(msg, SIP_HDR_SUPPORTED, "100rel")) + test->rel100_state_b |= REL100_SUPPORTED; + + if (sip_msg_hdr_has_value(msg, SIP_HDR_REQUIRE, "100rel")) + test->rel100_state_b |= REL100_REQUIRE; + + desc = mbuf_alloc(sizeof(sdp_b)); + if (!desc) { + abort_test(test, ENOMEM); + return; + } + + err = mbuf_write_str(desc, sdp_b); + if (err) { + abort_test(test, err); + return; + } + + mbuf_set_pos(desc, 0); + test->desc = desc; + + if (test->conn_action & CONN_PROGRESS + || test->conn_action & CONN_PROGR_ANS) { + err = sipsess_accept(&test->b, test->sock, msg, 183, + "Progress", test->rel100_b, "b", + "application/sdp", desc, NULL, NULL, false, + offer_handler_b, answer_handler_b, + estab_handler_b, NULL, NULL, close_handler, + test, hdrs); + + if (err != test->progr_ret_code) { + test->progr_ret_code = err; + goto out; + } + + err = sipsess_set_prack_handler(test->b, prack_handler_fork_b); + if (err) + abort_test(test, err); + + msg2->tag = rand_u64(); + err = sipsess_accept(&test->c, test->sock, msg2, 183, + "Progress", test->rel100_b, "c", + "application/sdp", desc, NULL, NULL, false, + offer_handler_b, answer_handler_b, + estab_handler_b, NULL, NULL, close_handler, + test, hdrs); + + if (err != test->progr_ret_code) { + test->progr_ret_code = err; + goto out; + } + + err = sipsess_set_prack_handler(test->c, prack_handler_fork_c); + if (err) + abort_test(test, err); + + if (err) + mem_deref(desc); + + } + + if (test->conn_action & CONN_PROGR_ANS) { + err = sipsess_answer(test->b, 200, "Answering", NULL, NULL); + if (err != test->answ_ret_code) { + test->answ_ret_code = err; + goto out; + } + + err = sipsess_answer(test->c, 200, "Answering", NULL, NULL); + if (err != test->answ_ret_code) { + test->answ_ret_code = err; + goto out; + } + } + else if (test->conn_action & CONN_ANSWER) { + err = sipsess_accept(&test->b, test->sock, msg, 200, "OK", + test->rel100_b, "b", "application/sdp", + NULL, NULL, NULL, false, offer_handler_b, + answer_handler_b, estab_handler_b, NULL, NULL, + close_handler, test, hdrs); + if (err != test->answ_ret_code) { + test->answ_ret_code = err; + goto out; + } + + err = sipsess_accept(&test->c, test->sock, msg, 200, "OK", + test->rel100_b, "b", "application/sdp", + NULL, NULL, NULL, false, offer_handler_b, + answer_handler_b, estab_handler_b, NULL, NULL, + close_handler, test, hdrs); + if (err != test->answ_ret_code) { + test->answ_ret_code = err; + goto out; + } + } + + if (test->conn_action & (CONN_ANSWER | CONN_PROGR_ANS | CONN_BUSY)) + mem_deref(desc); + + return; + +out: + mem_deref(desc); + abort_test(test, err); +} + + static void conn_handler(const struct sip_msg *msg, void *arg) { struct test *test = arg; @@ -583,6 +748,8 @@ int test_sipsess(void) out: test.a = mem_deref(test.a); test.b = mem_deref(test.b); + mem_deref(test.rtag_b); + mem_deref(test.rtag_c); sipsess_close_all(test.sock); test.sock = mem_deref(test.sock); @@ -654,6 +821,8 @@ int test_sipsess_reject(void) out: test.a = mem_deref(test.a); test.b = mem_deref(test.b); + mem_deref(test.rtag_b); + mem_deref(test.rtag_c); sipsess_close_all(test.sock); test.sock = mem_deref(test.sock); @@ -743,6 +912,8 @@ int test_sipsess_blind_transfer(void) out: test.a = mem_deref(test.a); test.b = mem_deref(test.b); + mem_deref(test.rtag_b); + mem_deref(test.rtag_c); sipsess_close_all(test.sock); test.sock = mem_deref(test.sock); @@ -767,7 +938,7 @@ int test_sipsess_100rel_caller_require(void) test.rel100_a = REL100_REQUIRED; test.rel100_b = REL100_ENABLED; test.conn_action = CONN_PROGRESS; - test.prack_action = send_answer_b; + test.prack_action_b = send_answer_b; err = sip_alloc(&test.sip, NULL, 32, 32, 32, "retest", exit_handler, NULL); @@ -825,6 +996,8 @@ int test_sipsess_100rel_caller_require(void) tmr_cancel(&test.ans_tmr); test.a = mem_deref(test.a); test.b = mem_deref(test.b); + mem_deref(test.rtag_b); + mem_deref(test.rtag_c); sipsess_close_all(test.sock); test.sock = mem_deref(test.sock); @@ -852,7 +1025,7 @@ int test_sipsess_100rel_supported(void) test.rel100_a = REL100_ENABLED; test.rel100_b = REL100_ENABLED; test.conn_action = CONN_PROGRESS; - test.prack_action = send_answer_b; + test.prack_action_b = send_answer_b; err = sip_alloc(&test.sip, NULL, 32, 32, 32, "retest", exit_handler, NULL); @@ -912,6 +1085,8 @@ int test_sipsess_100rel_supported(void) tmr_cancel(&test.ans_tmr); test.a = mem_deref(test.a); test.b = mem_deref(test.b); + mem_deref(test.rtag_b); + mem_deref(test.rtag_c); sipsess_close_all(test.sock); test.sock = mem_deref(test.sock); @@ -940,7 +1115,7 @@ int test_sipsess_100rel_answer_not_allowed(void) test.rel100_b = REL100_ENABLED; test.conn_action = CONN_PROGR_ANS; test.answ_ret_code = EINVAL; - test.prack_action = send_answer_b; + test.prack_action_b = send_answer_b; err = sip_alloc(&test.sip, NULL, 32, 32, 32, "retest", exit_handler, NULL); @@ -992,6 +1167,8 @@ int test_sipsess_100rel_answer_not_allowed(void) tmr_cancel(&test.ans_tmr); test.a = mem_deref(test.a); test.b = mem_deref(test.b); + mem_deref(test.rtag_b); + mem_deref(test.rtag_c); sipsess_close_all(test.sock); test.sock = mem_deref(test.sock); @@ -1066,6 +1243,8 @@ int test_sipsess_100rel_420(void) tmr_cancel(&test.ans_tmr); test.a = mem_deref(test.a); test.b = mem_deref(test.b); + mem_deref(test.rtag_b); + mem_deref(test.rtag_c); sipsess_close_all(test.sock); test.sock = mem_deref(test.sock); @@ -1139,6 +1318,8 @@ int test_sipsess_100rel_421(void) tmr_cancel(&test.ans_tmr); test.a = mem_deref(test.a); test.b = mem_deref(test.b); + mem_deref(test.rtag_b); + mem_deref(test.rtag_c); sipsess_close_all(test.sock); test.sock = mem_deref(test.sock); @@ -1165,7 +1346,7 @@ int test_sipsess_update_uac(void) test.rel100_a = REL100_ENABLED; test.rel100_b = REL100_ENABLED; test.conn_action = CONN_PROGRESS; - test.prack_action = send_update_a; + test.prack_action_b = send_update_a; err = sip_alloc(&test.sip, NULL, 32, 32, 32, "retest", exit_handler, NULL); @@ -1223,6 +1404,8 @@ int test_sipsess_update_uac(void) tmr_cancel(&test.ans_tmr); test.a = mem_deref(test.a); test.b = mem_deref(test.b); + mem_deref(test.rtag_b); + mem_deref(test.rtag_c); sipsess_close_all(test.sock); test.sock = mem_deref(test.sock); @@ -1252,7 +1435,7 @@ int test_sipsess_update_uas(void) test.rel100_a = REL100_ENABLED; test.rel100_b = REL100_ENABLED; test.conn_action = CONN_PROGRESS; - test.prack_action = send_update_b; + test.prack_action_b = send_update_b; err = sip_alloc(&test.sip, NULL, 32, 32, 32, "retest", exit_handler, NULL); @@ -1310,6 +1493,8 @@ int test_sipsess_update_uas(void) tmr_cancel(&test.ans_tmr); test.a = mem_deref(test.a); test.b = mem_deref(test.b); + mem_deref(test.rtag_b); + mem_deref(test.rtag_c); sipsess_close_all(test.sock); test.sock = mem_deref(test.sock); @@ -1393,6 +1578,8 @@ int test_sipsess_update_no_sdp(void) tmr_cancel(&test.ans_tmr); test.a = mem_deref(test.a); test.b = mem_deref(test.b); + mem_deref(test.rtag_b); + mem_deref(test.rtag_c); sipsess_close_all(test.sock); test.sock = mem_deref(test.sock); @@ -1405,3 +1592,91 @@ int test_sipsess_update_no_sdp(void) return err; } + + +int test_sipsess_100rel_forking(void) +{ + struct test test; + struct sa laddr; + char to_uri[256]; + int err; + uint16_t port; + char *callid; + + memset(&test, 0, sizeof(test)); + + test.rel100_a = REL100_REQUIRED; + test.rel100_b = REL100_ENABLED; + test.conn_action = CONN_PROGRESS; + test.prack_action_b = send_answer_b; + + err = sip_alloc(&test.sip, NULL, 32, 32, 32, + "retest", exit_handler, NULL); + TEST_ERR(err); + + (void)sa_set_str(&laddr, "127.0.0.1", 0); + err = sip_transp_add(test.sip, SIP_TRANSP_UDP, &laddr); + TEST_ERR(err); + + err = sip_transp_laddr(test.sip, &laddr, SIP_TRANSP_UDP, NULL); + TEST_ERR(err); + + port = sa_port(&laddr); + + err = sipsess_listen(&test.sock, test.sip, 32, conn_handler_fork, + &test); + TEST_ERR(err); + + err = str_x64dup(&callid, rand_u64()); + TEST_ERR(err); + + /* Connect to "b" */ + (void)re_snprintf(to_uri, sizeof(to_uri), "sip:b@127.0.0.1:%u", port); + err = sipsess_connect(&test.a, test.sock, to_uri, NULL, + "sip:a@127.0.0.1", "a", NULL, 0, + "application/sdp", NULL, NULL, false, + callid, desc_handler_a, + offer_handler_a, answer_handler_a, + progr_handler_a, estab_handler_a, NULL, + NULL, close_handler, &test, + "Require: 100rel\r\n"); + mem_deref(callid); + TEST_ERR(err); + + err = re_main_timeout(200); + TEST_ERR(err); + + if (test.err) { + err = test.err; + TEST_ERR(err); + } + + /* okay here -- verify */ + ASSERT_TRUE(test.estab_a); + ASSERT_TRUE(test.estab_b); + ASSERT_TRUE(test.desc); + ASSERT_TRUE(test.offer_b); + ASSERT_TRUE(!test.answr_b); + ASSERT_TRUE(test.progr_a); + ASSERT_TRUE(test.rel100_state_b & REL100_REQUIRE); + ASSERT_TRUE((test.rel100_state_b & REL100_SUPPORTED) == 0); + ASSERT_TRUE(test.sdp_state == EARLY_CONFIRMED); + +out: + tmr_cancel(&test.ans_tmr); + test.a = mem_deref(test.a); + test.b = mem_deref(test.b); + test.c = mem_deref(test.c); + mem_deref(test.rtag_b); + mem_deref(test.rtag_c); + + sipsess_close_all(test.sock); + test.sock = mem_deref(test.sock); + + sip_close(test.sip, false); + test.sip = mem_deref(test.sip); + + mem_deref(test.desc); + + return err; +} diff --git a/test/test.c b/test/test.c index 92afbebc4..746b1af6f 100644 --- a/test/test.c +++ b/test/test.c @@ -192,6 +192,7 @@ static const struct test tests[] = { TEST(test_sipsess_100rel_answer_not_allowed), TEST(test_sipsess_100rel_420), TEST(test_sipsess_100rel_421), + TEST(test_sipsess_100rel_forking), TEST(test_sipsess_update_uac), TEST(test_sipsess_update_uas), TEST(test_sipsess_update_no_sdp), diff --git a/test/test.h b/test/test.h index 5f92e98d7..9669828d9 100644 --- a/test/test.h +++ b/test/test.h @@ -308,6 +308,7 @@ int test_sipsess_100rel_supported(void); int test_sipsess_100rel_answer_not_allowed(void); int test_sipsess_100rel_420(void); int test_sipsess_100rel_421(void); +int test_sipsess_100rel_forking(void); int test_sipsess_update_uac(void); int test_sipsess_update_uas(void); int test_sipsess_update_no_sdp(void);