James Kuszmaul | 82f6c04 | 2021-01-17 11:30:16 -0800 | [diff] [blame^] | 1 | /** |
| 2 | * @file connect.c SIP Session Connect |
| 3 | * |
| 4 | * Copyright (C) 2010 Creytiv.com |
| 5 | */ |
| 6 | #include <string.h> |
| 7 | #include <re_types.h> |
| 8 | #include <re_mem.h> |
| 9 | #include <re_mbuf.h> |
| 10 | #include <re_sa.h> |
| 11 | #include <re_list.h> |
| 12 | #include <re_hash.h> |
| 13 | #include <re_fmt.h> |
| 14 | #include <re_uri.h> |
| 15 | #include <re_tmr.h> |
| 16 | #include <re_msg.h> |
| 17 | #include <re_sip.h> |
| 18 | #include <re_sipsess.h> |
| 19 | #include "sipsess.h" |
| 20 | |
| 21 | |
| 22 | static int invite(struct sipsess *sess); |
| 23 | |
| 24 | |
| 25 | static int send_handler(enum sip_transp tp, const struct sa *src, |
| 26 | const struct sa *dst, struct mbuf *mb, void *arg) |
| 27 | { |
| 28 | struct sip_contact contact; |
| 29 | struct sipsess *sess = arg; |
| 30 | (void)dst; |
| 31 | |
| 32 | sip_contact_set(&contact, sess->cuser, src, tp); |
| 33 | |
| 34 | return mbuf_printf(mb, "%H", sip_contact_print, &contact); |
| 35 | } |
| 36 | |
| 37 | |
| 38 | static void invite_resp_handler(int err, const struct sip_msg *msg, void *arg) |
| 39 | { |
| 40 | struct sipsess *sess = arg; |
| 41 | struct mbuf *desc = NULL; |
| 42 | |
| 43 | if (err || sip_request_loops(&sess->ls, msg->scode)) |
| 44 | goto out; |
| 45 | |
| 46 | if (msg->scode < 200) { |
| 47 | sess->progrh(msg, sess->arg); |
| 48 | return; |
| 49 | } |
| 50 | else if (msg->scode < 300) { |
| 51 | |
| 52 | sess->hdrs = mem_deref(sess->hdrs); |
| 53 | |
| 54 | err = sip_dialog_create(sess->dlg, msg); |
| 55 | if (err) |
| 56 | goto out; |
| 57 | |
| 58 | if (sess->sent_offer) |
| 59 | err = sess->answerh(msg, sess->arg); |
| 60 | else { |
| 61 | sess->modify_pending = false; |
| 62 | err = sess->offerh(&desc, msg, sess->arg); |
| 63 | } |
| 64 | |
| 65 | err |= sipsess_ack(sess->sock, sess->dlg, msg->cseq.num, |
| 66 | sess->auth, sess->ctype, desc); |
| 67 | |
| 68 | sess->established = true; |
| 69 | mem_deref(desc); |
| 70 | |
| 71 | if (err || sess->terminated) |
| 72 | goto out; |
| 73 | |
| 74 | if (sess->modify_pending) |
| 75 | (void)sipsess_reinvite(sess, true); |
| 76 | else |
| 77 | sess->desc = mem_deref(sess->desc); |
| 78 | |
| 79 | sess->estabh(msg, sess->arg); |
| 80 | return; |
| 81 | } |
| 82 | else if (msg->scode < 400) { |
| 83 | |
| 84 | /* Redirect to first Contact */ |
| 85 | |
| 86 | if (sess->terminated) |
| 87 | goto out; |
| 88 | |
| 89 | err = sip_dialog_update(sess->dlg, msg); |
| 90 | if (err) |
| 91 | goto out; |
| 92 | |
| 93 | err = invite(sess); |
| 94 | if (err) |
| 95 | goto out; |
| 96 | |
| 97 | return; |
| 98 | } |
| 99 | else { |
| 100 | if (sess->terminated) |
| 101 | goto out; |
| 102 | |
| 103 | switch (msg->scode) { |
| 104 | |
| 105 | case 401: |
| 106 | case 407: |
| 107 | err = sip_auth_authenticate(sess->auth, msg); |
| 108 | if (err) { |
| 109 | err = (err == EAUTH) ? 0 : err; |
| 110 | break; |
| 111 | } |
| 112 | |
| 113 | err = invite(sess); |
| 114 | if (err) |
| 115 | break; |
| 116 | |
| 117 | return; |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | out: |
| 122 | if (!sess->terminated) |
| 123 | sipsess_terminate(sess, err, msg); |
| 124 | else |
| 125 | mem_deref(sess); |
| 126 | } |
| 127 | |
| 128 | |
| 129 | static int invite(struct sipsess *sess) |
| 130 | { |
| 131 | sess->sent_offer = sess->desc ? true : false; |
| 132 | sess->modify_pending = false; |
| 133 | |
| 134 | return sip_drequestf(&sess->req, sess->sip, true, "INVITE", |
| 135 | sess->dlg, 0, sess->auth, |
| 136 | send_handler, invite_resp_handler, sess, |
| 137 | "%b" |
| 138 | "%s%s%s" |
| 139 | "Content-Length: %zu\r\n" |
| 140 | "\r\n" |
| 141 | "%b", |
| 142 | sess->hdrs ? mbuf_buf(sess->hdrs) : NULL, |
| 143 | sess->hdrs ? mbuf_get_left(sess->hdrs) :(size_t)0, |
| 144 | sess->desc ? "Content-Type: " : "", |
| 145 | sess->desc ? sess->ctype : "", |
| 146 | sess->desc ? "\r\n" : "", |
| 147 | sess->desc ? mbuf_get_left(sess->desc) :(size_t)0, |
| 148 | sess->desc ? mbuf_buf(sess->desc) : NULL, |
| 149 | sess->desc ? mbuf_get_left(sess->desc):(size_t)0); |
| 150 | } |
| 151 | |
| 152 | |
| 153 | /** |
| 154 | * Connect to a remote SIP useragent |
| 155 | * |
| 156 | * @param sessp Pointer to allocated SIP Session |
| 157 | * @param sock SIP Session socket |
| 158 | * @param to_uri To SIP uri |
| 159 | * @param from_name From display name |
| 160 | * @param from_uri From SIP uri |
| 161 | * @param cuser Contact username or URI |
| 162 | * @param routev Outbound route vector |
| 163 | * @param routec Outbound route vector count |
| 164 | * @param ctype Session content-type |
| 165 | * @param desc Content description (e.g. SDP) |
| 166 | * @param authh SIP Authentication handler |
| 167 | * @param aarg Authentication handler argument |
| 168 | * @param aref True to mem_ref() aarg |
| 169 | * @param offerh Session offer handler |
| 170 | * @param answerh Session answer handler |
| 171 | * @param progrh Session progress handler |
| 172 | * @param estabh Session established handler |
| 173 | * @param infoh Session info handler |
| 174 | * @param referh Session refer handler |
| 175 | * @param closeh Session close handler |
| 176 | * @param arg Handler argument |
| 177 | * @param fmt Formatted strings with extra SIP Headers |
| 178 | * |
| 179 | * @return 0 if success, otherwise errorcode |
| 180 | */ |
| 181 | int sipsess_connect(struct sipsess **sessp, struct sipsess_sock *sock, |
| 182 | const char *to_uri, const char *from_name, |
| 183 | const char *from_uri, const char *cuser, |
| 184 | const char *routev[], uint32_t routec, |
| 185 | const char *ctype, struct mbuf *desc, |
| 186 | sip_auth_h *authh, void *aarg, bool aref, |
| 187 | sipsess_offer_h *offerh, sipsess_answer_h *answerh, |
| 188 | sipsess_progr_h *progrh, sipsess_estab_h *estabh, |
| 189 | sipsess_info_h *infoh, sipsess_refer_h *referh, |
| 190 | sipsess_close_h *closeh, void *arg, const char *fmt, ...) |
| 191 | { |
| 192 | struct sipsess *sess; |
| 193 | int err; |
| 194 | |
| 195 | if (!sessp || !sock || !to_uri || !from_uri || !cuser || !ctype) |
| 196 | return EINVAL; |
| 197 | |
| 198 | err = sipsess_alloc(&sess, sock, cuser, ctype, desc, authh, aarg, aref, |
| 199 | offerh, answerh, progrh, estabh, infoh, referh, |
| 200 | closeh, arg); |
| 201 | if (err) |
| 202 | return err; |
| 203 | |
| 204 | /* Custom SIP headers */ |
| 205 | if (fmt) { |
| 206 | va_list ap; |
| 207 | |
| 208 | sess->hdrs = mbuf_alloc(256); |
| 209 | if (!sess->hdrs) { |
| 210 | err = ENOMEM; |
| 211 | goto out; |
| 212 | } |
| 213 | |
| 214 | va_start(ap, fmt); |
| 215 | err = mbuf_vprintf(sess->hdrs, fmt, ap); |
| 216 | sess->hdrs->pos = 0; |
| 217 | va_end(ap); |
| 218 | |
| 219 | if (err) |
| 220 | goto out; |
| 221 | } |
| 222 | |
| 223 | sess->owner = true; |
| 224 | |
| 225 | err = sip_dialog_alloc(&sess->dlg, to_uri, to_uri, from_name, |
| 226 | from_uri, routev, routec); |
| 227 | if (err) |
| 228 | goto out; |
| 229 | |
| 230 | hash_append(sock->ht_sess, |
| 231 | hash_joaat_str(sip_dialog_callid(sess->dlg)), |
| 232 | &sess->he, sess); |
| 233 | |
| 234 | err = invite(sess); |
| 235 | if (err) |
| 236 | goto out; |
| 237 | |
| 238 | out: |
| 239 | if (err) |
| 240 | mem_deref(sess); |
| 241 | else |
| 242 | *sessp = sess; |
| 243 | |
| 244 | return err; |
| 245 | } |