diff --git a/rem/aumix/aumix.c b/rem/aumix/aumix.c index e034f3f2b..e7f0ced50 100644 --- a/rem/aumix/aumix.c +++ b/rem/aumix/aumix.c @@ -62,7 +62,11 @@ static void destructor(void *arg) { struct aumix *mix = arg; - if (mix->run) { + mtx_lock(&mix->mutex); + bool run = mix->run; + mtx_unlock(&mix->mutex); + + if (run) { mtx_lock(&mix->mutex); mix->run = false; diff --git a/src/main/main.c b/src/main/main.c index 1e6af642b..923988341 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -571,7 +571,7 @@ static int poll_setup(struct re *re) /** * Listen for events on a file descriptor * - * @param fhs File descriptor handler struct pointer (don't use mem_deref(), + * @param fhsp File descriptor handler struct pointer (don't use mem_deref(), * use fd_close() instead) * @param fd File descriptor * @param flags Wanted event flags diff --git a/src/sip/dialog.c b/src/sip/dialog.c index 4585e22b6..79f9bcfa1 100644 --- a/src/sip/dialog.c +++ b/src/sip/dialog.c @@ -35,6 +35,7 @@ struct sip_dialog { uint32_t lseq; uint32_t rseq; size_t cpos; + size_t rpos; enum sip_transp tp; uint32_t srcport; }; @@ -118,6 +119,7 @@ int sip_dialog_alloc(struct sip_dialog **dlgp, if (i == 0) rend = dlg->mb->pos - 2; } + dlg->rpos = dlg->mb->pos; err |= mbuf_printf(dlg->mb, "To: <%s>\r\n", to_uri); dlg->cpos = dlg->mb->pos; err |= mbuf_printf(dlg->mb, "From: %s%s%s<%s>;tag=%016llx\r\n", @@ -231,7 +233,9 @@ int sip_dialog_accept(struct sip_dialog **dlgp, const struct sip_msg *msg) err |= sip_msg_hdr_apply(msg, true, SIP_HDR_RECORD_ROUTE, record_route_handler, &renc) ? ENOMEM : 0; + dlg->rpos = dlg->mb->pos; err |= mbuf_printf(dlg->mb, "To: %r\r\n", &msg->from.val); + dlg->cpos = dlg->mb->pos; err |= mbuf_printf(dlg->mb, "From: %r;tag=%016llx\r\n", &msg->to.val, msg->tag); if (err) @@ -304,10 +308,12 @@ int sip_dialog_create(struct sip_dialog *dlg, const struct sip_msg *msg) err |= sip_msg_hdr_apply(msg, msg->req, SIP_HDR_RECORD_ROUTE, record_route_handler, &renc) ? ENOMEM : 0; + dlg->rpos = renc.mb->pos; err |= mbuf_printf(renc.mb, "To: %r\r\n", msg->req ? &msg->from.val : &msg->to.val); dlg->mb->pos = dlg->cpos; + dlg->cpos = renc.mb->pos; err |= mbuf_write_mem(renc.mb, mbuf_buf(dlg->mb), mbuf_get_left(dlg->mb)); dlg->mb->pos = 0; @@ -344,7 +350,6 @@ int sip_dialog_create(struct sip_dialog *dlg, const struct sip_msg *msg) dlg->rtag = mem_ref(rtag); dlg->uri = mem_ref(uri); dlg->rseq = msg->req ? msg->cseq.num : 0; - dlg->cpos = 0; dlg->tp = msg->tp; out: @@ -462,6 +467,9 @@ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg) { const struct sip_hdr *contact; struct sip_addr addr; + struct mbuf *mb; + struct pl pl; + size_t cpos; char *uri; int err; @@ -479,10 +487,34 @@ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg) if (err) return err; + mb = mbuf_alloc(512); + if (!mb) + return ENOMEM; + + err = mbuf_write_mem(mb, mbuf_buf(dlg->mb), dlg->rpos); + err |= mbuf_printf(mb, "To: %r\r\n", + msg->req ? &msg->from.val : &msg->to.val); + cpos = mb->pos; + err |= mbuf_write_mem(mb, mbuf_buf(dlg->mb) + dlg->cpos, + mbuf_get_left(dlg->mb) - dlg->cpos); + + if (err) + goto out; + + dlg->cpos = cpos; + mb->pos = 0; + + mem_deref(dlg->rtag); + err = pl_strdup(&dlg->rtag, msg->req ? &msg->from.tag : &msg->to.tag); + if (err) + return err; + + mem_deref(dlg->mb); + dlg->mb = mem_ref(mb); + if (dlg->route.scheme.p == dlg->uri) { struct uri tmp; - struct pl pl; pl_set_str(&pl, uri); err = uri_decode(&tmp, &pl); @@ -491,11 +523,17 @@ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg) dlg->route = tmp; } + else { + pl.p = (const char *)mbuf_buf(dlg->mb) + ROUTE_OFFSET; + pl.l = dlg->rpos - ROUTE_OFFSET; + err = sip_addr_decode(&addr, &pl); + dlg->route = addr.uri; + } mem_deref(dlg->uri); dlg->uri = mem_ref(uri); - out: + mem_deref(mb); mem_deref(uri); return err; diff --git a/src/sipsess/connect.c b/src/sipsess/connect.c index 7a67d1e13..a27d323ba 100644 --- a/src/sipsess/connect.c +++ b/src/sipsess/connect.c @@ -103,7 +103,8 @@ static void invite_resp_handler(int err, const struct sip_msg *msg, void *arg) goto out; } - if (pl_isset(&msg->to.tag)) { + contact = sip_msg_hdr(msg, SIP_HDR_CONTACT); + if (pl_isset(&msg->to.tag) && contact) { err = sip_dialog_established(sess->dlg) ? sip_dialog_update(sess->dlg, msg) : sip_dialog_create(sess->dlg, msg); diff --git a/test/sipsess.c b/test/sipsess.c index c0051fb0b..ae7613207 100644 --- a/test/sipsess.c +++ b/test/sipsess.c @@ -40,12 +40,25 @@ enum connect_action { }; +enum answer_action { + ANSW_NONE = 0, + ANSW_CANCEL = 1, +}; + + +enum offer_action { + OFFER_NONE = 0, + OFFER_ANSW = 1, +}; + + struct test { struct sip *sip; struct sipsess_sock *sock; struct sipsess *a; struct sipsess *b; struct tmr ans_tmr; + struct tmr ack_tmr; bool estab_a; bool estab_b; bool answr_a; @@ -54,15 +67,20 @@ struct test { bool progr_b; bool offer_a; bool offer_b; + bool ack_a; + bool ack_b; enum rel100_mode rel100_a; enum rel100_mode rel100_b; enum sdp_neg_state sdp_state; enum rel100_state rel100_state_a; enum rel100_state rel100_state_b; enum connect_action conn_action; + enum offer_action offer_action; + enum answer_action answ_action; prack_func *prack_action; int progr_ret_code; int answ_ret_code; + int ack_cnt; bool upd_a; bool upd_b; struct mbuf *desc; @@ -119,6 +137,34 @@ static void exit_handler(void *arg) } +static void check_ack(void *arg) +{ + struct test *test = arg; + bool ack_a = sipsess_ack_pending(test->a); + bool ack_b = sipsess_ack_pending(test->b); + + test->ack_a |= ack_a; + test->ack_b |= ack_b; + + if (ack_a || ack_b) + tmr_start(&test->ack_tmr, 1, check_ack, test); + else + stop_test(); +} + + +static void wait_for_ack(struct test *test) +{ + test->ack_a = sipsess_ack_pending(test->a); + test->ack_b = sipsess_ack_pending(test->b); + + if (!test->ack_a && !test->ack_b) + return; + + tmr_start(&test->ack_tmr, 1, check_ack, test); +} + + static void send_answer_b(void *arg) { struct test *test = arg; @@ -131,21 +177,37 @@ static void send_answer_b(void *arg) } -static void send_update_a(void *arg) +static int make_sdp(struct mbuf **mbp, const char *sdp) { - struct test *test = arg; struct mbuf *desc; int err; - desc = mbuf_alloc(sizeof(sdp_a)); - if (!desc) { - err = ENOMEM; - goto out; - } - err = mbuf_write_str(desc, sdp_a); + desc = mbuf_alloc(strlen(sdp) + 1); + if (!desc) + return ENOMEM; + + err = mbuf_write_str(desc, sdp); TEST_ERR(err); mbuf_set_pos(desc, 0); +out: + if (err) + mem_deref(desc); + else + *mbp = desc; + + return err; +} + + +static void send_update_a(void *arg) +{ + struct test *test = arg; + struct mbuf *desc; + int err; + + err = make_sdp(&desc, sdp_a); + TEST_ERR(err); err = sipsess_modify(test->a, desc); TEST_ERR(err); @@ -164,16 +226,9 @@ static void send_update_b(void *arg) struct mbuf *desc; int err; - desc = mbuf_alloc(sizeof(sdp_b)); - if (!desc) { - err = ENOMEM; - goto out; - } - err = mbuf_write_str(desc, sdp_b); + err = make_sdp(&desc, sdp_b); TEST_ERR(err); - mbuf_set_pos(desc, 0); - err = sipsess_modify(test->b, desc); TEST_ERR(err); @@ -210,17 +265,9 @@ static int desc_handler_a(struct mbuf **descp, const struct sa *src, (void)dst; (void)arg; - desc = mbuf_alloc(sizeof(sdp_a)); - if (!desc) { - err = ENOMEM; - goto out; - } - - err = mbuf_write_str(desc, sdp_a); - if (err) - goto out; + err = make_sdp(&desc, sdp_a); + TEST_ERR(err); - mbuf_set_pos(desc, 0); *descp = desc; out: @@ -251,8 +298,8 @@ static int offer_handler_b(struct mbuf **descp, const struct sip_msg *msg, void *arg) { struct test *test = arg; - (void)descp; (void)msg; + int err = 0; if (test->sdp_state == INITIAL || test->sdp_state == EARLY_CONFIRMED) test->sdp_state = OFFER_RECEIVED; @@ -262,7 +309,13 @@ static int offer_handler_b(struct mbuf **descp, const struct sip_msg *msg, test->offer_b = true; - return 0; + if (test->offer_action == OFFER_ANSW) { + err = make_sdp(descp, sdp_b); + TEST_ERR(err); + } + +out: + return err; } @@ -288,6 +341,9 @@ static int answer_handler_a(const struct sip_msg *msg, void *arg) tmr_start(&test->ans_tmr, 0, send_answer_b, test); } + if (test->answ_action == ANSW_CANCEL) + wait_for_ack(test); + return 0; } @@ -393,19 +449,9 @@ static void conn_handler(const struct sip_msg *msg, void *arg) 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; - } + err = make_sdp(&desc, sdp_b); + TEST_ERR(err); - mbuf_set_pos(desc, 0); test->desc = desc; if (test->conn_action & CONN_PROGRESS @@ -561,12 +607,10 @@ int test_sipsess(void) estab_handler_a, NULL, NULL, close_handler, &test, NULL); mem_deref(callid); - if (err) - goto out; + TEST_ERR(err); err = re_main_timeout(200); - if (err) - goto out; + TEST_ERR(err); if (test.err) { err = test.err; @@ -580,6 +624,29 @@ int test_sipsess(void) ASSERT_TRUE(test.answr_a); ASSERT_TRUE(!test.offer_b); + /* test re-invite with wait for ACK */ + test.sdp_state = INITIAL; + test.answ_action = ANSW_CANCEL; + test.offer_action = OFFER_ANSW; + err = make_sdp(&test.desc, sdp_a); + TEST_ERR(err); + err = sipsess_modify(test.a, test.desc); + TEST_ERR(err); + test.desc = mem_deref(test.desc); + + err = re_main_timeout(200); + TEST_ERR(err); + + if (test.err) { + err = test.err; + goto out; + } + + ASSERT_TRUE(test.ack_b); + ASSERT_TRUE(!sipsess_ack_pending(test.a)); + ASSERT_TRUE(!sipsess_ack_pending(test.b)); + ASSERT_TRUE(test.sdp_state == ANSWER_RECEIVED); + out: test.a = mem_deref(test.a); test.b = mem_deref(test.b);