Skip to content

Commit

Permalink
sip: use source port for Via header (#824)
Browse files Browse the repository at this point in the history
* sip: add connection handler for TCP

The added connection handler is called when a TCP connection is about to be
established and there was already a socket opened. At this point in time there
is also a source TCP port which should be used in the Via header.

In request.c the connect_handler() encodes the Via header with correct TCP
source port.

* sip: keep API sip_send() unchanged, add new sip_send_conn()

* sip: use re_sdprintf for branch
  • Loading branch information
cspiel1 authored Jun 19, 2023
1 parent 7e8bec6 commit 5c709fc
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 37 deletions.
5 changes: 5 additions & 0 deletions include/re_sip.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);


Expand Down
22 changes: 19 additions & 3 deletions src/sip/ctrans.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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;

Expand Down
92 changes: 63 additions & 29 deletions src/sip/request.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down
25 changes: 24 additions & 1 deletion src/sip/sip.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -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);
}


Expand Down
4 changes: 3 additions & 1 deletion src/sip/sip.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
36 changes: 33 additions & 3 deletions src/sip/transp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -1452,21 +1467,36 @@ 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);

err = tcp_send(conn->tc, mb);
}
else
err = conn_send(qentp, sip, secure, &dsttmp, host, mb,
transph, arg);
connh, transph, arg);
break;

case SIP_TRANSP_WSS:
secure = true;
/*@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) {

Expand Down

0 comments on commit 5c709fc

Please sign in to comment.