James Kuszmaul | 82f6c04 | 2021-01-17 11:30:16 -0800 | [diff] [blame^] | 1 | /** |
| 2 | * @file accept.c SIP Session Accept |
| 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 | |
| 21 | static void cancel_handler(void *arg) |
| 22 | { |
| 23 | struct sipsess *sess = arg; |
| 24 | |
| 25 | (void)sip_treply(&sess->st, sess->sip, sess->msg, |
| 26 | 487, "Request Terminated"); |
| 27 | |
| 28 | sess->peerterm = true; |
| 29 | |
| 30 | if (sess->terminated) |
| 31 | return; |
| 32 | |
| 33 | sipsess_terminate(sess, ECONNRESET, NULL); |
| 34 | } |
| 35 | |
| 36 | |
| 37 | /** |
| 38 | * Accept an incoming SIP Session connection |
| 39 | * |
| 40 | * @param sessp Pointer to allocated SIP Session |
| 41 | * @param sock SIP Session socket |
| 42 | * @param msg Incoming SIP message |
| 43 | * @param scode Response status code |
| 44 | * @param reason Response reason phrase |
| 45 | * @param cuser Contact username or URI |
| 46 | * @param ctype Session content-type |
| 47 | * @param desc Content description (e.g. SDP) |
| 48 | * @param authh SIP Authentication handler |
| 49 | * @param aarg Authentication handler argument |
| 50 | * @param aref True to mem_ref() aarg |
| 51 | * @param offerh Session offer handler |
| 52 | * @param answerh Session answer handler |
| 53 | * @param estabh Session established handler |
| 54 | * @param infoh Session info handler |
| 55 | * @param referh Session refer handler |
| 56 | * @param closeh Session close handler |
| 57 | * @param arg Handler argument |
| 58 | * @param fmt Formatted strings with extra SIP Headers |
| 59 | * |
| 60 | * @return 0 if success, otherwise errorcode |
| 61 | */ |
| 62 | int sipsess_accept(struct sipsess **sessp, struct sipsess_sock *sock, |
| 63 | const struct sip_msg *msg, uint16_t scode, |
| 64 | const char *reason, const char *cuser, const char *ctype, |
| 65 | struct mbuf *desc, |
| 66 | sip_auth_h *authh, void *aarg, bool aref, |
| 67 | sipsess_offer_h *offerh, sipsess_answer_h *answerh, |
| 68 | sipsess_estab_h *estabh, sipsess_info_h *infoh, |
| 69 | sipsess_refer_h *referh, sipsess_close_h *closeh, |
| 70 | void *arg, const char *fmt, ...) |
| 71 | { |
| 72 | struct sipsess *sess; |
| 73 | va_list ap; |
| 74 | int err; |
| 75 | |
| 76 | if (!sessp || !sock || !msg || scode < 101 || scode > 299 || |
| 77 | !cuser || !ctype) |
| 78 | return EINVAL; |
| 79 | |
| 80 | err = sipsess_alloc(&sess, sock, cuser, ctype, NULL, authh, aarg, aref, |
| 81 | offerh, answerh, NULL, estabh, infoh, referh, |
| 82 | closeh, arg); |
| 83 | if (err) |
| 84 | return err; |
| 85 | |
| 86 | err = sip_dialog_accept(&sess->dlg, msg); |
| 87 | if (err) |
| 88 | goto out; |
| 89 | |
| 90 | hash_append(sock->ht_sess, |
| 91 | hash_joaat_str(sip_dialog_callid(sess->dlg)), |
| 92 | &sess->he, sess); |
| 93 | |
| 94 | sess->msg = mem_ref((void *)msg); |
| 95 | |
| 96 | err = sip_strans_alloc(&sess->st, sess->sip, msg, cancel_handler, |
| 97 | sess); |
| 98 | if (err) |
| 99 | goto out; |
| 100 | |
| 101 | va_start(ap, fmt); |
| 102 | |
| 103 | if (scode >= 200) |
| 104 | err = sipsess_reply_2xx(sess, msg, scode, reason, desc, |
| 105 | fmt, &ap); |
| 106 | else { |
| 107 | struct sip_contact contact; |
| 108 | |
| 109 | sip_contact_set(&contact, sess->cuser, &msg->dst, msg->tp); |
| 110 | |
| 111 | err = sip_treplyf(&sess->st, NULL, sess->sip, |
| 112 | msg, true, scode, reason, |
| 113 | "%H" |
| 114 | "%v" |
| 115 | "%s%s%s" |
| 116 | "Content-Length: %zu\r\n" |
| 117 | "\r\n" |
| 118 | "%b", |
| 119 | sip_contact_print, &contact, |
| 120 | fmt, &ap, |
| 121 | desc ? "Content-Type: " : "", |
| 122 | desc ? sess->ctype : "", |
| 123 | desc ? "\r\n" : "", |
| 124 | desc ? mbuf_get_left(desc) : (size_t)0, |
| 125 | desc ? mbuf_buf(desc) : NULL, |
| 126 | desc ? mbuf_get_left(desc) : (size_t)0); |
| 127 | } |
| 128 | |
| 129 | va_end(ap); |
| 130 | |
| 131 | if (err) |
| 132 | goto out; |
| 133 | |
| 134 | out: |
| 135 | if (err) |
| 136 | mem_deref(sess); |
| 137 | else |
| 138 | *sessp = sess; |
| 139 | |
| 140 | return err; |
| 141 | } |
| 142 | |
| 143 | |
| 144 | /** |
| 145 | * Send progress response |
| 146 | * |
| 147 | * @param sess SIP Session |
| 148 | * @param scode Response status code |
| 149 | * @param reason Response reason phrase |
| 150 | * @param desc Content description (e.g. SDP) |
| 151 | * @param fmt Formatted strings with extra SIP Headers |
| 152 | * |
| 153 | * @return 0 if success, otherwise errorcode |
| 154 | */ |
| 155 | int sipsess_progress(struct sipsess *sess, uint16_t scode, const char *reason, |
| 156 | struct mbuf *desc, const char *fmt, ...) |
| 157 | { |
| 158 | struct sip_contact contact; |
| 159 | va_list ap; |
| 160 | int err; |
| 161 | |
| 162 | if (!sess || !sess->st || !sess->msg || scode < 101 || scode > 199) |
| 163 | return EINVAL; |
| 164 | |
| 165 | va_start(ap, fmt); |
| 166 | |
| 167 | sip_contact_set(&contact, sess->cuser, &sess->msg->dst, sess->msg->tp); |
| 168 | |
| 169 | err = sip_treplyf(&sess->st, NULL, sess->sip, sess->msg, true, |
| 170 | scode, reason, |
| 171 | "%H" |
| 172 | "%v" |
| 173 | "%s%s%s" |
| 174 | "Content-Length: %zu\r\n" |
| 175 | "\r\n" |
| 176 | "%b", |
| 177 | sip_contact_print, &contact, |
| 178 | fmt, &ap, |
| 179 | desc ? "Content-Type: " : "", |
| 180 | desc ? sess->ctype : "", |
| 181 | desc ? "\r\n" : "", |
| 182 | desc ? mbuf_get_left(desc) : (size_t)0, |
| 183 | desc ? mbuf_buf(desc) : NULL, |
| 184 | desc ? mbuf_get_left(desc) : (size_t)0); |
| 185 | |
| 186 | va_end(ap); |
| 187 | |
| 188 | return err; |
| 189 | } |
| 190 | |
| 191 | |
| 192 | /** |
| 193 | * Answer an incoming SIP Session connection |
| 194 | * |
| 195 | * @param sess SIP Session |
| 196 | * @param scode Response status code |
| 197 | * @param reason Response reason phrase |
| 198 | * @param desc Content description (e.g. SDP) |
| 199 | * @param fmt Formatted strings with extra SIP Headers |
| 200 | * |
| 201 | * @return 0 if success, otherwise errorcode |
| 202 | */ |
| 203 | int sipsess_answer(struct sipsess *sess, uint16_t scode, const char *reason, |
| 204 | struct mbuf *desc, const char *fmt, ...) |
| 205 | { |
| 206 | va_list ap; |
| 207 | int err; |
| 208 | |
| 209 | if (!sess || !sess->st || !sess->msg || scode < 200 || scode > 299) |
| 210 | return EINVAL; |
| 211 | |
| 212 | va_start(ap, fmt); |
| 213 | err = sipsess_reply_2xx(sess, sess->msg, scode, reason, desc, |
| 214 | fmt, &ap); |
| 215 | va_end(ap); |
| 216 | |
| 217 | return err; |
| 218 | } |
| 219 | |
| 220 | |
| 221 | /** |
| 222 | * Reject an incoming SIP Session connection |
| 223 | * |
| 224 | * @param sess SIP Session |
| 225 | * @param scode Response status code |
| 226 | * @param reason Response reason phrase |
| 227 | * @param fmt Formatted strings with extra SIP Headers |
| 228 | * |
| 229 | * @return 0 if success, otherwise errorcode |
| 230 | */ |
| 231 | int sipsess_reject(struct sipsess *sess, uint16_t scode, const char *reason, |
| 232 | const char *fmt, ...) |
| 233 | { |
| 234 | va_list ap; |
| 235 | int err; |
| 236 | |
| 237 | if (!sess || !sess->st || !sess->msg || scode < 300) |
| 238 | return EINVAL; |
| 239 | |
| 240 | va_start(ap, fmt); |
| 241 | err = sip_treplyf(&sess->st, NULL, sess->sip, sess->msg, false, |
| 242 | scode, reason, fmt ? "%v" : NULL, fmt, &ap); |
| 243 | va_end(ap); |
| 244 | |
| 245 | return err; |
| 246 | } |