blob: 5f6317eb266ecfb5982456e6b3a0bf515a7207a3 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
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
22static int invite(struct sipsess *sess);
23
24
25static 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
38static 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
129static 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 */
181int 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}