blob: ff505eb7284ce62da1c29f9bb38482f7ff73cf5c [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file sipsess/sess.c SIP Session Core
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
21static int internal_offer_handler(struct mbuf **descp,
22 const struct sip_msg *msg, void *arg)
23{
24 (void)descp;
25 (void)msg;
26 (void)arg;
27
28 return ENOSYS;
29}
30
31
32static int internal_answer_handler(const struct sip_msg *msg, void *arg)
33{
34 (void)msg;
35 (void)arg;
36
37 return ENOSYS;
38}
39
40
41static void internal_progress_handler(const struct sip_msg *msg, void *arg)
42{
43 (void)msg;
44 (void)arg;
45}
46
47
48static void internal_establish_handler(const struct sip_msg *msg, void *arg)
49{
50 (void)msg;
51 (void)arg;
52}
53
54
55static void internal_close_handler(int err, const struct sip_msg *msg,
56 void *arg)
57{
58 (void)err;
59 (void)msg;
60 (void)arg;
61}
62
63
64static bool termwait(struct sipsess *sess)
65{
66 bool wait = false;
67
68 sess->terminated = 1;
69 sess->offerh = internal_offer_handler;
70 sess->answerh = internal_answer_handler;
71 sess->progrh = internal_progress_handler;
72 sess->estabh = internal_establish_handler;
73 sess->infoh = NULL;
74 sess->referh = NULL;
75 sess->closeh = internal_close_handler;
76 sess->arg = sess;
77
78 tmr_cancel(&sess->tmr);
79
80 if (sess->st) {
81 (void)sip_treply(&sess->st, sess->sip, sess->msg,
82 486, "Busy Here");
83 }
84
85 if (sess->req) {
86 sip_request_cancel(sess->req);
87 mem_ref(sess);
88 wait = true;
89 }
90
91 if (sess->replyl.head) {
92 mem_ref(sess);
93 wait = true;
94 }
95
96 if (sess->requestl.head) {
97 mem_ref(sess);
98 wait = true;
99 }
100
101 return wait;
102}
103
104
105static bool terminate(struct sipsess *sess)
106{
107 sess->terminated = 2;
108
109 if (!sess->established || sess->peerterm)
110 return false;
111
112 if (sipsess_bye(sess, true))
113 return false;
114
115 mem_ref(sess);
116 return true;
117}
118
119
120static void destructor(void *arg)
121{
122 struct sipsess *sess = arg;
123
124 switch (sess->terminated) {
125
126 case 0:
127 if (termwait(sess))
128 return;
129
130 /*@fallthrough@*/
131
132 case 1:
133 if (terminate(sess))
134 return;
135 break;
136 }
137
138 hash_unlink(&sess->he);
139 tmr_cancel(&sess->tmr);
140 list_flush(&sess->replyl);
141 list_flush(&sess->requestl);
142 mem_deref((void *)sess->msg);
143 mem_deref(sess->req);
144 mem_deref(sess->dlg);
145 mem_deref(sess->auth);
146 mem_deref(sess->cuser);
147 mem_deref(sess->ctype);
148 mem_deref(sess->close_hdrs);
149 mem_deref(sess->hdrs);
150 mem_deref(sess->desc);
151 mem_deref(sess->sock);
152 mem_deref(sess->sip);
153 mem_deref(sess->st);
154}
155
156
157int sipsess_alloc(struct sipsess **sessp, struct sipsess_sock *sock,
158 const char *cuser, const char *ctype, struct mbuf *desc,
159 sip_auth_h *authh, void *aarg, bool aref,
160 sipsess_offer_h *offerh, sipsess_answer_h *answerh,
161 sipsess_progr_h *progrh, sipsess_estab_h *estabh,
162 sipsess_info_h *infoh, sipsess_refer_h *referh,
163 sipsess_close_h *closeh, void *arg)
164{
165 struct sipsess *sess;
166 int err;
167
168 sess = mem_zalloc(sizeof(*sess), destructor);
169 if (!sess)
170 return ENOMEM;
171
172 err = sip_auth_alloc(&sess->auth, authh, aarg, aref);
173 if (err)
174 goto out;
175
176 err = str_dup(&sess->cuser, cuser);
177 if (err)
178 goto out;
179
180 err = str_dup(&sess->ctype, ctype);
181 if (err)
182 goto out;
183
184 sess->sock = mem_ref(sock);
185 sess->desc = mem_ref(desc);
186 sess->sip = mem_ref(sock->sip);
187 sess->offerh = offerh ? offerh : internal_offer_handler;
188 sess->answerh = answerh ? answerh : internal_answer_handler;
189 sess->progrh = progrh ? progrh : internal_progress_handler;
190 sess->estabh = estabh ? estabh : internal_establish_handler;
191 sess->infoh = infoh;
192 sess->referh = referh;
193 sess->closeh = closeh ? closeh : internal_close_handler;
194 sess->arg = arg;
195
196 out:
197 if (err)
198 mem_deref(sess);
199 else
200 *sessp = sess;
201
202 return err;
203}
204
205
206void sipsess_terminate(struct sipsess *sess, int err,
207 const struct sip_msg *msg)
208{
209 sipsess_close_h *closeh;
210 void *arg;
211
212 if (sess->terminated)
213 return;
214
215 closeh = sess->closeh;
216 arg = sess->arg;
217
218 if (!termwait(sess))
219 (void)terminate(sess);
220
221 closeh(err, msg, arg);
222}
223
224
225/**
226 * Get the SIP dialog from a SIP Session
227 *
228 * @param sess SIP Session
229 *
230 * @return SIP Dialog object
231 */
232struct sip_dialog *sipsess_dialog(const struct sipsess *sess)
233{
234 return sess ? sess->dlg : NULL;
235}
236
237
238/**
239 * Set extra SIP headers for inclusion in Session "close" messages
240 * like BYE and 200 OK. Multiple headers can be included.
241 *
242 * @param sess SIP Session
243 * @param hdrs Formatted strings with extra SIP Headers
244 *
245 * @return 0 if success, otherwise errorcode
246 */
247int sipsess_set_close_headers(struct sipsess *sess, const char *hdrs, ...)
248{
249 int err = 0;
250 va_list ap;
251
252 if (!sess)
253 return EINVAL;
254
255 sess->close_hdrs = mem_deref(sess->close_hdrs);
256
257 if (hdrs) {
258 va_start(ap, hdrs);
259 err = re_vsdprintf(&sess->close_hdrs, hdrs, ap);
260 va_end(ap);
261 }
262
263 return err;
264}