Skip to content

Commit

Permalink
sipsess: refactor and simplify SDP negotiation state
Browse files Browse the repository at this point in the history
The SDP negotiation state is now tracked in a single enum which is used
as a state machine to keep track of the current state of the SDP
negotiation.
  • Loading branch information
maximilianfridrich committed Nov 27, 2023
1 parent f10f2fc commit 811668a
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 124 deletions.
10 changes: 10 additions & 0 deletions include/re_sipsess.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
struct sipsess_sock;
struct sipsess;

/* SDP Negotiation state */
enum sdp_neg_state {
SDP_NEG_NONE = 0,
SDP_NEG_LOCAL_OFFER = 1, /** SDP offer sent */
SDP_NEG_REMOTE_OFFER = 2, /** SDP offer received */
SDP_NEG_PREVIEW_ANSWER = 6, /** SDP preview answer sent */
SDP_NEG_DONE = 8 /** SDP negotiation done */
};


typedef void (sipsess_conn_h)(const struct sip_msg *msg, void *arg);
typedef int (sipsess_desc_h)(struct mbuf **descp, const struct sa *src,
Expand Down Expand Up @@ -74,3 +83,4 @@ void sipsess_close_all(struct sipsess_sock *sock);
struct sip_dialog *sipsess_dialog(const struct sipsess *sess);
void sipsess_abort(struct sipsess *sess);
bool sipsess_ack_pending(const struct sipsess *sess);
enum sdp_neg_state sipsess_sdp_neg_state(const struct sipsess *sess);
3 changes: 3 additions & 0 deletions src/sipsess/accept.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ int sipsess_accept(struct sipsess **sessp, struct sipsess_sock *sock,
if (err)
goto out;

if (mbuf_get_left(msg->mb))
sess->neg_state = SDP_NEG_REMOTE_OFFER;

va_start(ap, fmt);

if (scode > 100 && scode < 200) {
Expand Down
70 changes: 50 additions & 20 deletions src/sipsess/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ static int send_handler(enum sip_transp tp, struct sa *src,
*contp = cont;

out:
sess->sent_offer = desc != NULL;
if (desc)
sess->neg_state = SDP_NEG_LOCAL_OFFER;

mem_deref(desc);
return err;
}
Expand All @@ -89,16 +91,10 @@ static void invite_resp_handler(int err, const struct sip_msg *msg, void *arg)
if (!msg || err || sip_request_loops(&sess->ls, msg->scode))
goto out;

sdp = mbuf_get_left(msg->mb) > 0;

if (msg->scode < 200) {
sess->progrh(msg, sess->arg);
sdp = mbuf_get_left(msg->mb) > 0;

if (sdp && sess->sent_offer) {
sess->awaiting_answer = false;
err = sess->answerh(msg, sess->arg);
if (err)
goto out;
}

if (pl_isset(&msg->to.tag)) {
err = sip_dialog_established(sess->dlg) ?
Expand All @@ -108,19 +104,40 @@ static void invite_resp_handler(int err, const struct sip_msg *msg, void *arg)
goto out;
}

if (sdp && sess->neg_state == SDP_NEG_LOCAL_OFFER) {
err = sess->answerh(msg, sess->arg);
if (err)
goto out;
}

if (sip_msg_hdr_has_value(msg, SIP_HDR_REQUIRE, "100rel")
&& sess->rel100_supported) {
if (sdp && !sess->sent_offer) {
sess->modify_pending = false;
err = sess->offerh(&desc, msg, sess->arg);

if (sess->neg_state == SDP_NEG_NONE && !sdp)
goto out;

if (sdp) {
if (sess->neg_state == SDP_NEG_LOCAL_OFFER) {
sess->neg_state = SDP_NEG_DONE;
}
else if (sess->neg_state == SDP_NEG_NONE) {
sess->neg_state = SDP_NEG_REMOTE_OFFER;
err = sess->offerh(&desc, msg,
sess->arg);
}
}

err |= sipsess_prack(sess, msg->cseq.num, msg->rel_seq,
&msg->cseq.met, desc);
mem_deref(desc);
sess->desc = mem_deref(sess->desc);
if (err)
goto out;

if (sess->neg_state == SDP_NEG_REMOTE_OFFER
&& mbuf_get_left(desc))
sess->neg_state = SDP_NEG_DONE;

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

return;
Expand All @@ -135,15 +152,28 @@ static void invite_resp_handler(int err, const struct sip_msg *msg, void *arg)
if (err)
goto out;

if (sess->sent_offer)
err = sess->answerh(msg, sess->arg);
else {
sess->modify_pending = false;
err = sess->offerh(&desc, msg, sess->arg);
if (sdp) {
if (sess->neg_state == SDP_NEG_LOCAL_OFFER) {
sess->neg_state = SDP_NEG_DONE;
err = sess->answerh(msg, sess->arg);
}
else if (sess->neg_state == SDP_NEG_NONE) {
sess->neg_state = SDP_NEG_REMOTE_OFFER;
err = sess->offerh(&desc, msg, sess->arg);
}
}

err |= sipsess_ack(sess->sock, sess->dlg, msg->cseq.num,
sess->auth, sess->ctype, desc);
sess->auth, sess->ctype, desc);
if (err)
goto out;

if (sess->neg_state == SDP_NEG_NONE && !sdp)
goto out;

if (sess->neg_state == SDP_NEG_REMOTE_OFFER
&& mbuf_get_left(desc))
sess->neg_state = SDP_NEG_DONE;

sess->established = true;
mem_deref(desc);
Expand Down
50 changes: 30 additions & 20 deletions src/sipsess/listen.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,13 @@ static void bye_handler(struct sipsess_sock *sock, const struct sip_msg *msg)
static void ack_handler(struct sipsess_sock *sock, const struct sip_msg *msg)
{
struct sipsess *sess;
bool awaiting_answer;
int err = 0;

sess = sipsess_find(sock, msg);
if (!sess)
return;

if (sipsess_reply_ack(sess, msg, &awaiting_answer))
if (sipsess_reply_ack(sess, msg))
return;

if (sess->terminated) {
Expand All @@ -146,8 +145,12 @@ static void ack_handler(struct sipsess_sock *sock, const struct sip_msg *msg)
return;
}

if (awaiting_answer) {
sess->awaiting_answer = false;
if (sess->neg_state == SDP_NEG_LOCAL_OFFER) {
if (!mbuf_get_left(msg->mb)) {
sipsess_terminate(sess, EPROTO, NULL);
return;
}
sess->neg_state = SDP_NEG_DONE;
err = sess->answerh(msg, sess->arg);
}

Expand All @@ -169,15 +172,14 @@ static void ack_handler(struct sipsess_sock *sock, const struct sip_msg *msg)

static void prack_handler(struct sipsess_sock *sock, const struct sip_msg *msg)
{
bool sdp;
struct sipsess *sess;
struct mbuf *desc = NULL;
bool awaiting_answer = false;
bool awaiting_prack = false;

sess = sipsess_find(sock, msg);

if (!sess || sipsess_reply_prack(sess, msg, &awaiting_answer,
&awaiting_prack)) {
if (!sess || sipsess_reply_prack(sess, msg, &awaiting_prack)) {
(void)sip_reply(sock->sip, msg, 481,
"Transaction Does Not Exist");
return;
Expand All @@ -192,22 +194,28 @@ static void prack_handler(struct sipsess_sock *sock, const struct sip_msg *msg)
return;
}

sdp = mbuf_get_left(msg->mb);

if (awaiting_prack) {
sess->awaiting_prack = false;
sess->refresh_allowed = true;
--sess->prack_waiting_cnt;
}

if (sess->prackh)
sess->prackh(msg, sess->arg);

if (awaiting_answer) {
sess->awaiting_answer = false;
if (sess->neg_state == SDP_NEG_LOCAL_OFFER) {
if (!sdp) {
sipsess_terminate(sess, EPROTO, NULL);
return;
}
sess->neg_state = SDP_NEG_DONE;
(void)sess->answerh(msg, sess->arg);
}
else if (msg && mbuf_get_left(msg->mb)) {
else if (sess->neg_state == SDP_NEG_DONE && sdp) {
sess->neg_state = SDP_NEG_REMOTE_OFFER;
(void)sess->offerh(&desc, msg, sess->arg);
}

if (sess->prackh)
sess->prackh(msg, sess->arg);

(void)sipsess_reply_2xx(sess, msg, 200, "OK", desc, NULL, NULL);

mem_deref(desc);
Expand All @@ -219,7 +227,7 @@ static void target_refresh_handler(struct sipsess_sock *sock,
{
struct sip *sip = sock->sip;
bool is_invite;
bool got_offer;
bool sdp;
struct sipsess *sess;
struct mbuf *desc = NULL;
char m[256];
Expand All @@ -232,14 +240,15 @@ static void target_refresh_handler(struct sipsess_sock *sock,
}

is_invite = !pl_strcmp(&msg->met, "INVITE");
got_offer = (mbuf_get_left(msg->mb) > 0);
sdp = (mbuf_get_left(msg->mb) > 0);

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

if ((is_invite && sess->st) || sess->awaiting_answer) {
if ((is_invite && sess->st)
|| (sdp && sess->neg_state == SDP_NEG_LOCAL_OFFER)) {
(void)sip_treplyf(NULL, NULL, sip, msg, false,
500, "Server Internal Error",
"Retry-After: 5\r\n"
Expand All @@ -253,12 +262,13 @@ static void target_refresh_handler(struct sipsess_sock *sock,
return;
}

if (got_offer && !sipsess_refresh_allowed(sess)) {
if (sdp && !sipsess_refresh_allowed(sess)) {
(void)sip_reply(sip, msg, 488, "Not Acceptable Here");
return;
}

if (is_invite || got_offer) {
if (sdp) {
sess->neg_state = SDP_NEG_REMOTE_OFFER;
err = sess->offerh(&desc, msg, sess->arg);
if (err) {
(void)sip_reply(sip, msg, 488,
Expand Down
77 changes: 50 additions & 27 deletions src/sipsess/modify.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,48 @@ static void reinvite_resp_handler(int err, const struct sip_msg *msg,
struct sipsess *sess = arg;
const struct sip_hdr *hdr;
struct mbuf *desc = NULL;
bool sdp;

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

sdp = mbuf_get_left(msg->mb) > 0;

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);
if (sdp) {
if (sess->neg_state == SDP_NEG_LOCAL_OFFER) {
sess->neg_state = SDP_NEG_DONE;
err = sess->answerh(msg, sess->arg);
}
else if (sess->neg_state == SDP_NEG_NONE) {
sess->neg_state = SDP_NEG_REMOTE_OFFER;
err = sess->offerh(&desc, msg, sess->arg);
}

if (err)
goto out;
}

(void)sipsess_ack(sess->sock, sess->dlg, msg->cseq.num,
err = sipsess_ack(sess->sock, sess->dlg, msg->cseq.num,
sess->auth, sess->ctype, desc);
if (err)
goto out;

if (sess->neg_state == SDP_NEG_REMOTE_OFFER
&& mbuf_get_left(desc))
sess->neg_state = SDP_NEG_DONE;

mem_deref(desc);
}
else {
sess->neg_state = SDP_NEG_DONE;

if (sess->terminated)
goto out;

Expand Down Expand Up @@ -126,28 +143,35 @@ static int send_handler(enum sip_transp tp, struct sa *src,

int sipsess_reinvite(struct sipsess *sess, bool reset_ls)
{
int err;

if (sess->req)
return EPROTO;

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, "INVITE",
sess->dlg, 0, sess->auth,
send_handler, reinvite_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);
err = sip_drequestf(&sess->req, sess->sip, true, "INVITE",
sess->dlg, 0, sess->auth,
send_handler, reinvite_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);

if (!err) {
sess->modify_pending = false;
if (sess->desc)
sess->neg_state = SDP_NEG_LOCAL_OFFER;
}

return err;
}


Expand All @@ -161,12 +185,11 @@ int sipsess_reinvite(struct sipsess *sess, bool reset_ls)
*/
int sipsess_modify(struct sipsess *sess, struct mbuf *desc)
{
if (!sess || sess->terminated || sess->awaiting_answer
|| !sip_dialog_established(sess->dlg))
if (!sess || sess->terminated || !sip_dialog_established(sess->dlg))
return EINVAL;

if (!sess->established && !sess->refresh_allowed
&& mbuf_get_left(desc))
if (mbuf_get_left(desc) && (sess->neg_state != SDP_NEG_DONE
&& sess->neg_state != SDP_NEG_NONE))
return EPROTO;

mem_deref(sess->desc);
Expand Down
Loading

0 comments on commit 811668a

Please sign in to comment.