James Kuszmaul | 82f6c04 | 2021-01-17 11:30:16 -0800 | [diff] [blame^] | 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 | |
| 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 | |
| 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 | */ |
| 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 | */ |
| 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 | */ |
| 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 | */ |
| 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 | */ |
| 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 | } |