blob: 651628cd2366dd173aff7cf606bdb4cea810ab01 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
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
23static 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
61static 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 */
86int 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 */
146void 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 */
173int 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 */
191int 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 */
226int 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}