Skip to content

Commit

Permalink
sip: add RFC 3311 support
Browse files Browse the repository at this point in the history
  • Loading branch information
maximilianfridrich committed Jul 13, 2022
1 parent 26ce397 commit 4a1cb92
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 8 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ legend:
* [RFC 2915](https://tools.ietf.org/html/rfc2915) - The Naming Authority Pointer (NAPTR) DNS Resource Record
* [RFC 3261](https://tools.ietf.org/html/rfc3261) - SIP: Session Initiation Protocol
* [RFC 3262](https://tools.ietf.org/html/rfc3262) - SIP Reliability of Provisional Responses
* [RFC 3311](https://tools.ietf.org/html/rfc3311) - The SIP UPDATE Method
* [RFC 3263](https://tools.ietf.org/html/rfc3263) - Locating SIP Servers
* [RFC 3264](https://tools.ietf.org/html/rfc3264) - An Offer/Answer Model with SDP
* [RFC 3265](https://tools.ietf.org/html/rfc3265) - SIP-Specific Event Notification
Expand Down
51 changes: 51 additions & 0 deletions src/sipsess/listen.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,53 @@ static void reinvite_handler(struct sipsess_sock *sock,
}


static void update_handler(struct sipsess_sock *sock,
const struct sip_msg *msg)
{
struct sip *sip = sock->sip;
struct sipsess *sess;
struct mbuf *desc;
char m[256];
int err;

sess = sipsess_find(sock, msg);
if (!sess || sess->terminated) {
(void)sip_treply(NULL, sip, msg, 481, "Call Does Not Exist");
return;
}

if (!sip_dialog_rseq_valid(sess->dlg, msg)) {
(void)sip_treply(NULL, sip, msg, 500, "Server Internal Error");
return;
}

if (sess->awaiting_answer) {
(void)sip_treplyf(NULL, NULL, sip, msg, false,
500, "Server Internal Error",
"Retry-After: 5\r\n"
"Content-Length: 0\r\n"
"\r\n");
return;
}

err = sess->offerh(&desc, msg, sess->arg);
if (err) {
(void)sip_reply(sip, msg, 488, str_error(err, m, sizeof(m)));
return;
}

(void)sip_dialog_update(sess->dlg, msg);
(void)sipsess_reply_2xx(sess, msg, 200, "OK", desc, NULL, NULL);

/* pending modifications considered outdated;
* sdp may have changed in above exchange */
sess->desc = mem_deref(sess->desc);
sess->modify_pending = false;
tmr_cancel(&sess->tmr);
mem_deref(desc);
}


static void invite_handler(struct sipsess_sock *sock,
const struct sip_msg *msg)
{
Expand All @@ -297,6 +344,10 @@ static bool request_handler(const struct sip_msg *msg, void *arg)

return true;
}
else if (!pl_strcmp(&msg->met, "UPDATE")) {
update_handler(sock, msg);
return true;
}
else if (!pl_strcmp(&msg->met, "ACK")) {
ack_handler(sock, msg);
return true;
Expand Down
110 changes: 107 additions & 3 deletions src/sipsess/modify.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,82 @@ static void reinvite_resp_handler(int err, const struct sip_msg *msg,
}


static void update_resp_handler(int err, const struct sip_msg *msg, void *arg)
{
struct sipsess *sess = arg;
const struct sip_hdr *hdr;
struct mbuf *desc = NULL;

if (err || sip_request_loops(&sess->ls, msg->scode))
goto out;

if (msg->scode < 200) {
return;
}
else if (msg->scode < 300) {
(void)sip_dialog_update(sess->dlg, msg);

if (sess->sent_offer)
(void)sess->answerh(msg, sess->arg);
else {
sess->modify_pending = false;
(void)sess->offerh(&desc, msg, sess->arg);
}

mem_deref(desc);
}
else {
if (sess->terminated)
goto out;

switch (msg->scode) {

case 401:
case 407:
err = sip_auth_authenticate(sess->auth, msg);
if (err) {
err = (err == EAUTH) ? 0 : err;
break;
}

err = sipsess_update(sess, false);
if (err)
break;

return;

case 408:
case 481:
sipsess_terminate(sess, 0, msg);
return;

case 491:
tmr_start(&sess->tmr, sess->owner ? 3000 : 1000,
tmr_handler, sess);
return;

case 500:
hdr = sip_msg_hdr(msg, SIP_HDR_RETRY_AFTER);
if (!hdr)
break;

tmr_start(&sess->tmr, pl_u32(&hdr->val) * 1000,
tmr_handler, sess);
return;
}
}
out:
if (sess->terminated)
mem_deref(sess);
else if (err == ETIMEDOUT)
sipsess_terminate(sess, err, NULL);
else if (sess->modify_pending)
(void)sipsess_update(sess, true);
else
sess->desc = mem_deref(sess->desc);
}


static int send_handler(enum sip_transp tp, struct sa *src,
const struct sa *dst, struct mbuf *mb,
struct mbuf **contp, void *arg)
Expand Down Expand Up @@ -148,6 +224,30 @@ int sipsess_reinvite(struct sipsess *sess, bool reset_ls)
}


int sipsess_update(struct sipsess *sess, bool reset_ls)
{
sess->sent_offer = sess->desc ? true : false;
sess->modify_pending = false;

if (reset_ls)
sip_loopstate_reset(&sess->ls);

return sip_drequestf(&sess->req, sess->sip, true, "UPDATE",
sess->dlg, 0, sess->auth,
send_handler, update_resp_handler, sess,
"%s%s%s"
"Content-Length: %zu\r\n"
"\r\n"
"%b",
sess->desc ? "Content-Type: " : "",
sess->desc ? sess->ctype : "",
sess->desc ? "\r\n" : "",
sess->desc ? mbuf_get_left(sess->desc) :(size_t)0,
sess->desc ? mbuf_buf(sess->desc) : NULL,
sess->desc ? mbuf_get_left(sess->desc):(size_t)0);
}


/**
* Modify an established SIP Session sending Re-INVITE or UPDATE
*
Expand All @@ -158,16 +258,20 @@ int sipsess_reinvite(struct sipsess *sess, bool reset_ls)
*/
int sipsess_modify(struct sipsess *sess, struct mbuf *desc)
{
if (!sess || sess->st || sess->terminated)
if (!sess || (sess->st && sess->established) || sess->terminated)
return EINVAL;

mem_deref(sess->desc);
sess->desc = mem_ref(desc);

if (sess->req || sess->tmr.th || sess->replyl.head) {
if (sess->tmr.th || sess->replyl.head ||
(sess->req && sess->established)) {
sess->modify_pending = true;
return 0;
}

return sipsess_reinvite(sess, true);
if (sess->established)
return sipsess_reinvite(sess, true);
else
return sipsess_update(sess, true);
}
10 changes: 5 additions & 5 deletions src/sipsess/reply.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,10 @@ int sipsess_reply_2xx(struct sipsess *sess, const struct sip_msg *msg,
struct sipsess_reply *reply = NULL;
struct sip_contact contact;
int err = ENOMEM;
bool is_prack = !pl_strcmp(&msg->met, "PRACK");
bool non_invite = !pl_strcmp(&msg->met, "PRACK")
|| !pl_strcmp(&msg->met, "UPDATE");

if (!is_prack) {
if (!non_invite) {
reply = mem_zalloc(sizeof(*reply), destructor);
if (!reply)
goto out;
Expand All @@ -106,8 +107,7 @@ int sipsess_reply_2xx(struct sipsess *sess, const struct sip_msg *msg,
}

sip_contact_set(&contact, sess->cuser, &msg->dst, msg->tp);

err = sip_treplyf(is_prack ? NULL : &sess->st,
err = sip_treplyf(non_invite ? NULL : &sess->st,
reply ? &reply->mb : NULL, sess->sip,
msg, true, scode, reason,
"%H"
Expand Down Expand Up @@ -140,7 +140,7 @@ int sipsess_reply_2xx(struct sipsess *sess, const struct sip_msg *msg,

out:
if (err) {
if (!is_prack)
if (!non_invite)
sess->st = mem_deref(sess->st);

mem_deref(reply);
Expand Down
1 change: 1 addition & 0 deletions src/sipsess/sipsess.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ int sipsess_reply_1xx(struct sipsess *sess, const struct sip_msg *msg,
int sipsess_reply_ack(struct sipsess *sess, const struct sip_msg *msg,
bool *awaiting_answer);
int sipsess_reinvite(struct sipsess *sess, bool reset_ls);
int sipsess_update(struct sipsess *sess, bool reset_ls);
int sipsess_bye(struct sipsess *sess, bool reset_ls);
int sipsess_request_alloc(struct sipsess_request **reqp, struct sipsess *sess,
const char *ctype, struct mbuf *body,
Expand Down

0 comments on commit 4a1cb92

Please sign in to comment.