1 /**
2  * @file sip.c  SIP 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_sys.h>
15 #include <re_tmr.h>
16 #include <re_udp.h>
17 #include <re_stun.h>
18 #include <re_msg.h>
19 #include <re_sip.h>
20 #include "sip.h"
21 
22 
destructor(void * arg)23 static void destructor(void *arg)
24 {
25 	struct sip *sip = arg;
26 
27 	if (sip->closing) {
28 		sip->closing = false;
29 		mem_ref(sip);
30 		if (sip->exith)
31 			sip->exith(sip->arg);
32 		return;
33 	}
34 
35 	sip_request_close(sip);
36 	sip_request_close(sip);
37 
38 	hash_flush(sip->ht_ctrans);
39 	mem_deref(sip->ht_ctrans);
40 
41 	hash_flush(sip->ht_strans);
42 	hash_clear(sip->ht_strans_mrg);
43 	mem_deref(sip->ht_strans);
44 	mem_deref(sip->ht_strans_mrg);
45 
46 	hash_flush(sip->ht_conn);
47 	mem_deref(sip->ht_conn);
48 
49 	hash_flush(sip->ht_udpconn);
50 	mem_deref(sip->ht_udpconn);
51 
52 	list_flush(&sip->transpl);
53 	list_flush(&sip->lsnrl);
54 
55 	mem_deref(sip->software);
56 	mem_deref(sip->dnsc);
57 	mem_deref(sip->stun);
58 }
59 
60 
lsnr_destructor(void * arg)61 static void lsnr_destructor(void *arg)
62 {
63 	struct sip_lsnr *lsnr = arg;
64 
65 	if (lsnr->lsnrp)
66 		*lsnr->lsnrp = NULL;
67 
68 	list_unlink(&lsnr->le);
69 }
70 
71 
72 /**
73  * Allocate a SIP stack instance
74  *
75  * @param sipp     Pointer to allocated SIP stack
76  * @param dnsc     DNS Client (optional)
77  * @param ctsz     Size of client transactions hashtable (power of 2)
78  * @param stsz     Size of server transactions hashtable (power of 2)
79  * @param tcsz     Size of SIP transport hashtable (power of 2)
80  * @param software Software identifier
81  * @param exith    SIP-stack exit handler
82  * @param arg      Handler argument
83  *
84  * @return 0 if success, otherwise errorcode
85  */
sip_alloc(struct sip ** sipp,struct dnsc * dnsc,uint32_t ctsz,uint32_t stsz,uint32_t tcsz,const char * software,sip_exit_h * exith,void * arg)86 int sip_alloc(struct sip **sipp, struct dnsc *dnsc, uint32_t ctsz,
87 	      uint32_t stsz, uint32_t tcsz, const char *software,
88 	      sip_exit_h *exith, void *arg)
89 {
90 	struct sip *sip;
91 	int err;
92 
93 	if (!sipp)
94 		return EINVAL;
95 
96 	sip = mem_zalloc(sizeof(*sip), destructor);
97 	if (!sip)
98 		return ENOMEM;
99 
100 	err = sip_transp_init(sip, tcsz);
101 	if (err)
102 		goto out;
103 
104 	err = sip_ctrans_init(sip, ctsz);
105 	if (err)
106 		goto out;
107 
108 	err = sip_strans_init(sip, stsz);
109 	if (err)
110 		goto out;
111 
112 	err = hash_alloc(&sip->ht_udpconn, tcsz);
113 	if (err)
114 		goto out;
115 
116 	err = stun_alloc(&sip->stun, NULL, NULL, NULL);
117 	if (err)
118 		goto out;
119 
120 	if (software) {
121 		err = str_dup(&sip->software, software);
122 		if (err)
123 			goto out;
124 	}
125 
126 	sip->dnsc  = mem_ref(dnsc);
127 	sip->exith = exith;
128 	sip->arg   = arg;
129 
130  out:
131 	if (err)
132 		mem_deref(sip);
133 	else
134 		*sipp = sip;
135 
136 	return err;
137 }
138 
139 
140 /**
141  * Close the SIP stack instance
142  *
143  * @param sip   SIP stack instance
144  * @param force Don't wait for transactions to complete
145  */
sip_close(struct sip * sip,bool force)146 void sip_close(struct sip *sip, bool force)
147 {
148 	if (!sip)
149 		return;
150 
151 	if (force) {
152 		sip_request_close(sip);
153 		sip_request_close(sip);
154 	}
155 	else if (!sip->closing) {
156 		sip->closing = true;
157 		mem_deref(sip);
158 	}
159 }
160 
161 
162 /**
163  * Send a SIP message
164  *
165  * @param sip  SIP stack instance
166  * @param sock Optional socket to send from
167  * @param tp   SIP transport
168  * @param dst  Destination network address
169  * @param mb   Buffer containing SIP message
170  *
171  * @return 0 if success, otherwise errorcode
172  */
sip_send(struct sip * sip,void * sock,enum sip_transp tp,const struct sa * dst,struct mbuf * mb)173 int sip_send(struct sip *sip, void *sock, enum sip_transp tp,
174 	     const struct sa *dst, struct mbuf *mb)
175 {
176 	return sip_transp_send(NULL, sip, sock, tp, dst, mb, NULL, NULL);
177 }
178 
179 
180 /**
181  * Listen for incoming SIP Requests and SIP Responses
182  *
183  * @param lsnrp Pointer to allocated listener
184  * @param sip   SIP stack instance
185  * @param req   True for Request, false for Response
186  * @param msgh  SIP message handler
187  * @param arg   Handler argument
188  *
189  * @return 0 if success, otherwise errorcode
190  */
sip_listen(struct sip_lsnr ** lsnrp,struct sip * sip,bool req,sip_msg_h * msgh,void * arg)191 int sip_listen(struct sip_lsnr **lsnrp, struct sip *sip, bool req,
192 	       sip_msg_h *msgh, void *arg)
193 {
194 	struct sip_lsnr *lsnr;
195 
196 	if (!sip || !msgh)
197 		return EINVAL;
198 
199 	lsnr = mem_zalloc(sizeof(*lsnr), lsnr_destructor);
200 	if (!lsnr)
201 		return ENOMEM;
202 
203 	list_append(&sip->lsnrl, &lsnr->le, lsnr);
204 
205 	lsnr->msgh = msgh;
206 	lsnr->arg = arg;
207 	lsnr->req = req;
208 
209 	if (lsnrp) {
210 		lsnr->lsnrp = lsnrp;
211 		*lsnrp = lsnr;
212 	}
213 
214 	return 0;
215 }
216 
217 
218 /**
219  * Print debug information about the SIP stack
220  *
221  * @param pf  Print function for debug output
222  * @param sip SIP stack instance
223  *
224  * @return 0 if success, otherwise errorcode
225  */
sip_debug(struct re_printf * pf,const struct sip * sip)226 int sip_debug(struct re_printf *pf, const struct sip *sip)
227 {
228 	int err;
229 
230 	if (!sip)
231 		return 0;
232 
233 	err  = sip_transp_debug(pf, sip);
234 	err |= sip_ctrans_debug(pf, sip);
235 	err |= sip_strans_debug(pf, sip);
236 
237 	return err;
238 }
239