1 /**
2 * @file modify.c SIP Session Modify
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6 #include <re_types.h>
7 #include <re_mem.h>
8 #include <re_mbuf.h>
9 #include <re_sa.h>
10 #include <re_list.h>
11 #include <re_hash.h>
12 #include <re_fmt.h>
13 #include <re_uri.h>
14 #include <re_tmr.h>
15 #include <re_msg.h>
16 #include <re_sip.h>
17 #include <re_sipsess.h>
18 #include "sipsess.h"
19
20
tmr_handler(void * arg)21 static void tmr_handler(void *arg)
22 {
23 struct sipsess *sess = arg;
24
25 (void)sipsess_reinvite(sess, true);
26 }
27
28
reinvite_resp_handler(int err,const struct sip_msg * msg,void * arg)29 static void reinvite_resp_handler(int err, const struct sip_msg *msg,
30 void *arg)
31 {
32 struct sipsess *sess = arg;
33 const struct sip_hdr *hdr;
34 struct mbuf *desc = NULL;
35
36 if (err || sip_request_loops(&sess->ls, msg->scode))
37 goto out;
38
39 if (msg->scode < 200) {
40 return;
41 }
42 else if (msg->scode < 300) {
43
44 (void)sip_dialog_update(sess->dlg, msg);
45
46 if (sess->sent_offer)
47 (void)sess->answerh(msg, sess->arg);
48 else {
49 sess->modify_pending = false;
50 (void)sess->offerh(&desc, msg, sess->arg);
51 }
52
53 (void)sipsess_ack(sess->sock, sess->dlg, msg->cseq.num,
54 sess->auth, sess->ctype, desc);
55 mem_deref(desc);
56 }
57 else {
58 if (sess->terminated)
59 goto out;
60
61 switch (msg->scode) {
62
63 case 401:
64 case 407:
65 err = sip_auth_authenticate(sess->auth, msg);
66 if (err) {
67 err = (err == EAUTH) ? 0 : err;
68 break;
69 }
70
71 err = sipsess_reinvite(sess, false);
72 if (err)
73 break;
74
75 return;
76
77 case 408:
78 case 481:
79 sipsess_terminate(sess, 0, msg);
80 return;
81
82 case 491:
83 tmr_start(&sess->tmr, sess->owner ? 3000 : 1000,
84 tmr_handler, sess);
85 return;
86
87 case 500:
88 hdr = sip_msg_hdr(msg, SIP_HDR_RETRY_AFTER);
89 if (!hdr)
90 break;
91
92 tmr_start(&sess->tmr, pl_u32(&hdr->val) * 1000,
93 tmr_handler, sess);
94 return;
95 }
96 }
97 out:
98 if (sess->terminated)
99 mem_deref(sess);
100 else if (err == ETIMEDOUT)
101 sipsess_terminate(sess, err, NULL);
102 else if (sess->modify_pending)
103 (void)sipsess_reinvite(sess, true);
104 else
105 sess->desc = mem_deref(sess->desc);
106 }
107
108
send_handler(enum sip_transp tp,const struct sa * src,const struct sa * dst,struct mbuf * mb,void * arg)109 static int send_handler(enum sip_transp tp, const struct sa *src,
110 const struct sa *dst, struct mbuf *mb, void *arg)
111 {
112 struct sip_contact contact;
113 struct sipsess *sess = arg;
114 (void)dst;
115
116 sip_contact_set(&contact, sess->cuser, src, tp);
117
118 return mbuf_printf(mb, "%H", sip_contact_print, &contact);
119 }
120
121
sipsess_reinvite(struct sipsess * sess,bool reset_ls)122 int sipsess_reinvite(struct sipsess *sess, bool reset_ls)
123 {
124 if (sess->req)
125 return EPROTO;
126
127 sess->sent_offer = sess->desc ? true : false;
128 sess->modify_pending = false;
129
130 if (reset_ls)
131 sip_loopstate_reset(&sess->ls);
132
133 return sip_drequestf(&sess->req, sess->sip, true, "INVITE",
134 sess->dlg, 0, sess->auth,
135 send_handler, reinvite_resp_handler, sess,
136 "%s%s%s"
137 "Content-Length: %zu\r\n"
138 "\r\n"
139 "%b",
140 sess->desc ? "Content-Type: " : "",
141 sess->desc ? sess->ctype : "",
142 sess->desc ? "\r\n" : "",
143 sess->desc ? mbuf_get_left(sess->desc) :(size_t)0,
144 sess->desc ? mbuf_buf(sess->desc) : NULL,
145 sess->desc ? mbuf_get_left(sess->desc):(size_t)0);
146 }
147
148
149 /**
150 * Modify an established SIP Session sending Re-INVITE or UPDATE
151 *
152 * @param sess SIP Session
153 * @param desc Content description (e.g. SDP)
154 *
155 * @return 0 if success, otherwise errorcode
156 */
sipsess_modify(struct sipsess * sess,struct mbuf * desc)157 int sipsess_modify(struct sipsess *sess, struct mbuf *desc)
158 {
159 if (!sess || sess->st || sess->terminated)
160 return EINVAL;
161
162 mem_deref(sess->desc);
163 sess->desc = mem_ref(desc);
164
165 if (sess->req || sess->tmr.th || sess->replyl.head) {
166 sess->modify_pending = true;
167 return 0;
168 }
169
170 return sipsess_reinvite(sess, true);
171 }
172