diff --git a/include/re_sip.h b/include/re_sip.h index a00ae551f..a78f0660b 100644 --- a/include/re_sip.h +++ b/include/re_sip.h @@ -271,6 +271,8 @@ typedef bool(sip_msg_h)(const struct sip_msg *msg, void *arg); typedef int(sip_send_h)(enum sip_transp tp, struct sa *src, const struct sa *dst, struct mbuf *mb, struct mbuf **contp, void *arg); +typedef int(sip_conn_h)(struct sa *src, const struct sa *dst, struct mbuf *mb, + void *arg); typedef void(sip_resp_h)(int err, const struct sip_msg *msg, void *arg); typedef void(sip_cancel_h)(void *arg); typedef void(sip_exit_h)(void *arg); @@ -298,6 +300,9 @@ int sip_listen(struct sip_lsnr **lsnrp, struct sip *sip, bool req, int sip_debug(struct re_printf *pf, const struct sip *sip); int sip_send(struct sip *sip, void *sock, enum sip_transp tp, const struct sa *dst, struct mbuf *mb); +int sip_send_conn(struct sip *sip, void *sock, enum sip_transp tp, + const struct sa *dst, struct mbuf *mb, + sip_conn_h *connh, void *arg); void sip_set_trace_handler(struct sip *sip, sip_trace_h *traceh); diff --git a/src/sip/ctrans.c b/src/sip/ctrans.c index 10b5f28d0..f1abbf0de 100644 --- a/src/sip/ctrans.c +++ b/src/sip/ctrans.c @@ -46,6 +46,7 @@ struct sip_ctrans { char *met; char *branch; char *host; + sip_conn_h *connh; sip_resp_h *resph; void *arg; enum sip_transp tp; @@ -178,6 +179,18 @@ static void tmr_handler(void *arg) } +static int connect_handler(struct sa *src, const struct sa *dst, + struct mbuf *mb, void *arg) +{ + struct sip_ctrans *ct = arg; + + if (ct->connh) + return ct->connh(src, dst, mb, ct->arg); + + return 0; +} + + static void retransmit_handler(void *arg) { struct sip_ctrans *ct = arg; @@ -207,7 +220,8 @@ static void retransmit_handler(void *arg) tmr_start(&ct->tmre, timeout, retransmit_handler, ct); err = sip_transp_send(&ct->qent, ct->sip, NULL, ct->tp, &ct->dst, - ct->host, ct->mb, transport_handler, ct); + ct->host, ct->mb, connect_handler, + transport_handler, ct); if (err) { terminate(ct, err); mem_deref(ct); @@ -312,6 +326,7 @@ static bool response_handler(const struct sip_msg *msg, void *arg) int sip_ctrans_request(struct sip_ctrans **ctp, struct sip *sip, enum sip_transp tp, const struct sa *dst, char *met, char *branch, char *host, struct mbuf *mb, + sip_conn_h *connh, sip_resp_h *resph, void *arg) { struct sip_ctrans *ct; @@ -335,11 +350,12 @@ int sip_ctrans_request(struct sip_ctrans **ctp, struct sip *sip, ct->tp = tp; ct->sip = sip; ct->state = ct->invite ? CALLING : TRYING; + ct->connh = connh; ct->resph = resph ? resph : dummy_handler; ct->arg = arg; err = sip_transp_send(&ct->qent, sip, NULL, tp, dst, host, mb, - transport_handler, ct); + connect_handler, transport_handler, ct); if (err) goto out; @@ -389,7 +405,7 @@ int sip_ctrans_cancel(struct sip_ctrans *ct) goto out; err = sip_ctrans_request(NULL, ct->sip, ct->tp, &ct->dst, cancel, - ct->branch, NULL, mb, NULL, NULL); + ct->branch, NULL, mb, NULL, NULL, NULL); if (err) goto out; diff --git a/src/sip/request.c b/src/sip/request.c index 3e16721c4..390f64141 100644 --- a/src/sip/request.c +++ b/src/sip/request.c @@ -31,6 +31,7 @@ struct sip_request { char *met; char *uri; char *host; + char *branch; struct mbuf *mb; sip_send_h *sendh; sip_resp_h *resph; @@ -88,6 +89,7 @@ static void destructor(void *arg) mem_deref(req->met); mem_deref(req->uri); mem_deref(req->host); + mem_deref(req->branch); mem_deref(req->mb); } @@ -158,62 +160,94 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) } -static int request(struct sip_request *req, enum sip_transp tp, - const struct sa *dst) +static int connect_handler(struct sa *src, const struct sa *dst, + struct mbuf *mb, void *arg) { + struct sip_request *req = arg; struct mbuf *mbs = NULL; - struct mbuf *mb = NULL; struct mbuf *cont = NULL; - char *branch = NULL; - int err = ENOMEM; struct sa laddr; + int err; - req->provrecv = false; - - branch = mem_alloc(24, NULL); - mbs = mbuf_alloc(256); - mb = mbuf_alloc(1024); - - if (!branch || !mb) - goto out; - - (void)re_snprintf(branch, 24, "z9hG4bK%016llx", rand_u64()); + if (!sa_isset(src, SA_ALL)) + return EINVAL; - err = sip_transp_laddr(req->sip, &laddr, tp, dst); + err = sip_transp_laddr(req->sip, &laddr, req->tp, dst); if (err) goto out; - err = req->sendh ? req->sendh(tp, &laddr, dst, mbs, &cont, req->arg) : - 0; + mbuf_set_posend(mb, 0, 0); + mbs = mbuf_alloc(256); + if (!mbs) + return ENOMEM; + + err = req->sendh ? req->sendh(req->tp, &laddr, dst, mbs, &cont, + req->arg) : 0; if (err) goto out; mbuf_set_pos(mbs, 0); err = mbuf_printf(mb, "%s %s SIP/2.0\r\n", req->met, req->uri); err |= mbuf_printf(mb, "Via: SIP/2.0/%s %J;branch=%s;rport\r\n", - sip_transp_name(tp), &laddr, branch); + sip_transp_name(req->tp), src, req->branch); err |= mbuf_write_mem(mb, mbuf_buf(mbs), mbuf_get_left(mbs)); err |= mbuf_write_mem(mb, mbuf_buf(req->mb), mbuf_get_left(req->mb)); - err |= cont ? mbuf_write_mem(mb, mbuf_buf(cont), mbuf_get_left(cont)) : - 0; - mem_deref(cont); + if (cont) { + err |= mbuf_write_mem(mb, mbuf_buf(cont), mbuf_get_left(cont)); + mem_deref(cont); + } + if (err) goto out; mb->pos = 0; - if (!req->stateful) - err = sip_send(req->sip, NULL, tp, dst, mb); - else +out: + if (err) + mbuf_reset(mb); + + mem_deref(mbs); + return err; +} + + +static int request(struct sip_request *req, enum sip_transp tp, + const struct sa *dst) +{ + struct mbuf *mb = NULL; + int err = ENOMEM; + struct sa laddr; + + req->provrecv = false; + + mem_deref(req->branch); + (void)re_sdprintf(&req->branch, "z9hG4bK%016llx", rand_u64()); + mb = mbuf_alloc(1024); + if (!req->branch || !mb) + goto out; + + + if (!req->branch || !mb) + goto out; + + err = sip_transp_laddr(req->sip, &laddr, tp, dst); + if (err) + goto out; + + if (!req->stateful) { + err = sip_send_conn(req->sip, NULL, tp, dst, mb, + connect_handler, req); + } + else { err = sip_ctrans_request(&req->ct, req->sip, tp, dst, req->met, - branch, req->host, mb, - response_handler, req); + req->branch, req->host, mb, + connect_handler, response_handler, + req); + } if (err) goto out; out: - mem_deref(branch); - mem_deref(mbs); mem_deref(mb); return err; diff --git a/src/sip/sip.c b/src/sip/sip.c index 0b6073f15..987d8b257 100644 --- a/src/sip/sip.c +++ b/src/sip/sip.c @@ -196,6 +196,28 @@ void sip_close(struct sip *sip, bool force) } +/** + * Send a SIP message and use given SIP connected handler + * + * @param sip SIP stack instance + * @param sock Optional socket to send from + * @param tp SIP transport + * @param dst Destination network address + * @param mb Buffer containing SIP message + * @param connh SIP connected handler + * @param arg Handler argument + * + * @return 0 if success, otherwise errorcode + */ +int sip_send_conn(struct sip *sip, void *sock, enum sip_transp tp, + const struct sa *dst, struct mbuf *mb, + sip_conn_h *connh, void *arg) +{ + return sip_transp_send(NULL, sip, sock, tp, dst, NULL, mb, connh, NULL, + arg); +} + + /** * Send a SIP message * @@ -210,7 +232,8 @@ void sip_close(struct sip *sip, bool force) int sip_send(struct sip *sip, void *sock, enum sip_transp tp, const struct sa *dst, struct mbuf *mb) { - return sip_transp_send(NULL, sip, sock, tp, dst, NULL, mb, NULL, NULL); + return sip_transp_send(NULL, sip, sock, tp, dst, NULL, mb, NULL, NULL, + NULL); } diff --git a/src/sip/sip.h b/src/sip/sip.h index 8fcf2defa..9f19383f3 100644 --- a/src/sip/sip.h +++ b/src/sip/sip.h @@ -55,6 +55,7 @@ struct sip_ctrans; int sip_ctrans_request(struct sip_ctrans **ctp, struct sip *sip, enum sip_transp tp, const struct sa *dst, char *met, char *branch, char *host, struct mbuf *mb, + sip_conn_h *connh, sip_resp_h *resph, void *arg); int sip_ctrans_cancel(struct sip_ctrans *ct); int sip_ctrans_init(struct sip *sip, uint32_t sz); @@ -74,7 +75,8 @@ typedef void(sip_transp_h)(int err, void *arg); int sip_transp_init(struct sip *sip, uint32_t sz); int sip_transp_send(struct sip_connqent **qentp, struct sip *sip, void *sock, enum sip_transp tp, const struct sa *dst, char *host, - struct mbuf *mb, sip_transp_h *transph, void *arg); + struct mbuf *mb, sip_conn_h *connh, sip_transp_h *transph, + void *arg); bool sip_transp_supported(struct sip *sip, enum sip_transp tp, int af); const char *sip_transp_srvid(enum sip_transp tp); bool sip_transp_reliable(enum sip_transp tp); diff --git a/src/sip/transp.c b/src/sip/transp.c index 7ea425e01..eb7717b3e 100644 --- a/src/sip/transp.c +++ b/src/sip/transp.c @@ -734,7 +734,7 @@ static uint32_t get_hash_of_fromhdr(struct mbuf *mb) static int conn_send(struct sip_connqent **qentp, struct sip *sip, bool secure, const struct sa *dst, char *host, struct mbuf *mb, - sip_transp_h *transph, void *arg) + sip_conn_h *connh, sip_transp_h *transph, void *arg) { struct sip_conn *conn, *new_conn = NULL; struct sip_conncfg *conncfg; @@ -747,6 +747,9 @@ static int conn_send(struct sip_connqent **qentp, struct sip *sip, bool secure, conn = conn_find(sip, dst, secure); if (conn) { + if (connh) + err = connh(&conn->laddr, dst, mb, arg); + if (!conn->established) goto enqueue; @@ -789,6 +792,9 @@ static int conn_send(struct sip_connqent **qentp, struct sip *sip, bool secure, if (err) goto out; + if (connh) + err = connh(&conn->laddr, dst, mb, arg); + (void)tcp_conn_settos(conn->tc, sip->tos); #ifdef USE_TLS if (secure) { @@ -1410,12 +1416,14 @@ void sip_transp_flush(struct sip *sip) int sip_transp_send(struct sip_connqent **qentp, struct sip *sip, void *sock, enum sip_transp tp, const struct sa *dst, char *host, - struct mbuf *mb, sip_transp_h *transph, void *arg) + struct mbuf *mb, sip_conn_h *connh, sip_transp_h *transph, + void *arg) { const struct sip_transport *transp; struct sip_conn *conn; bool secure = false; struct sa dsttmp; + struct sa laddr; int err; if (!sip || !dst || !mb) @@ -1431,6 +1439,13 @@ int sip_transp_send(struct sip_connqent **qentp, struct sip *sip, void *sock, switch (tp) { case SIP_TRANSP_UDP: + err = sip_transp_laddr(sip, &laddr, tp, dst); + if (err) + return err; + + if (connh) + connh(&laddr, dst, mb, arg); + if (!sock) { transp = transp_find(sip, tp, sa_af(&dsttmp), &dsttmp); if (!transp) @@ -1452,6 +1467,11 @@ int sip_transp_send(struct sip_connqent **qentp, struct sip *sip, void *sock, conn = sock; if (conn && conn->tc) { + if (connh) { + err = connh(&conn->laddr, dst, mb, arg); + if (err) + return err; + } trace_send(sip, tp, conn, &dsttmp, mb); @@ -1459,7 +1479,7 @@ int sip_transp_send(struct sip_connqent **qentp, struct sip *sip, void *sock, } else err = conn_send(qentp, sip, secure, &dsttmp, host, mb, - transph, arg); + connh, transph, arg); break; case SIP_TRANSP_WSS: @@ -1467,6 +1487,16 @@ int sip_transp_send(struct sip_connqent **qentp, struct sip *sip, void *sock, /*@fallthrough@*/ case SIP_TRANSP_WS: + /*TODO: Ideally connh should be called if the websocket was + * opened and the source port is known. As a workaround the + * listen port is used for Contact and Via headers */ + err = sip_transp_laddr(sip, &laddr, tp, dst); + if (err) + return err; + + if (connh) + connh(&laddr, dst, mb, arg); + conn = sock; if (conn && conn->websock_conn) {