xref: /illumos-gate/usr/src/lib/libsip/common/sip_dialog_ui.c (revision 7247f8883be6bcac5fe4735b6f87f873387dbbef)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdlib.h>
30 #include <assert.h>
31 #include <errno.h>
32 #include <pthread.h>
33 #include <sip.h>
34 
35 #include "sip_msg.h"
36 #include "sip_miscdefs.h"
37 #include "sip_parse_uri.h"
38 #include "sip_dialog.h"
39 
40 /*
41  * Create a request using the state maintained in the dialog.
42  */
43 sip_msg_t
44 sip_create_dialog_req(sip_method_t method, sip_dialog_t dialog,
45     char *transport, char *sent_by, int sent_by_port, char *via_param,
46     uint32_t maxforward, int cseq)
47 {
48 	_sip_dialog_t	*_dialog;
49 	sip_msg_t	sip_msg;
50 	char		*uri;
51 	int		oldseq = 0;
52 
53 	if (!sip_manage_dialog || dialog == NULL || transport == NULL ||
54 	    sent_by == NULL) {
55 		return (NULL);
56 	}
57 	if ((sip_msg = sip_new_msg()) == NULL)
58 		return (NULL);
59 	_dialog = (_sip_dialog_t *)dialog;
60 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
61 	/*
62 	 * Depending on the route set, if any, the request URI could either
63 	 * be the contact URI or the 1st URI from the route set.
64 	 */
65 	uri = (char *)sip_dialog_req_uri(_dialog);
66 	if (uri == NULL)
67 		goto err_ret;
68 	if (sip_add_request_line(sip_msg, method, uri) != 0) {
69 		free(uri);
70 		goto err_ret;
71 	}
72 	free(uri);
73 	if (sip_copy_header(sip_msg, _dialog->sip_dlg_local_uri_tag, NULL) != 0)
74 		goto err_ret;
75 	if (sip_copy_header(sip_msg, _dialog->sip_dlg_remote_uri_tag, NULL) !=
76 	    0) {
77 		goto err_ret;
78 	}
79 	if (sip_add_via(sip_msg, transport, sent_by, sent_by_port, via_param) !=
80 	    0) {
81 		goto err_ret;
82 	}
83 	if (sip_add_maxforward(sip_msg, maxforward) != 0)
84 		goto err_ret;
85 	if (sip_copy_header(sip_msg, _dialog->sip_dlg_call_id, NULL) != 0)
86 		goto err_ret;
87 	if (cseq < 0) {
88 		if (_dialog->sip_dlg_local_cseq == 0)
89 			_dialog->sip_dlg_local_cseq = 1;
90 		oldseq = _dialog->sip_dlg_local_cseq;
91 		cseq = ++_dialog->sip_dlg_local_cseq;
92 	}
93 	if (sip_add_cseq(sip_msg, method, cseq) != 0) {
94 		_dialog->sip_dlg_local_cseq = oldseq;
95 		goto err_ret;
96 	}
97 	/*
98 	 * The route set, even if empty, overrides any pre-existing route set.
99 	 * If the route set is empty, the UAC MUST NOT add a Route header
100 	 * field to the request.
101 	 */
102 	(void) sip_delete_header_by_name(sip_msg, SIP_ROUTE);
103 
104 	if (_dialog->sip_dlg_route_set != NULL) {
105 		if (sip_copy_header(sip_msg, _dialog->sip_dlg_route_set,
106 		    NULL) != 0) {
107 			_dialog->sip_dlg_local_cseq = oldseq;
108 			goto err_ret;
109 		}
110 	}
111 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
112 	return (sip_msg);
113 err_ret:
114 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
115 	sip_free_msg(sip_msg);
116 	return (NULL);
117 }
118 
119 /*
120  * Get the Dialog method
121  */
122 int
123 sip_get_dialog_method(sip_dialog_t dialog, int *error)
124 {
125 	_sip_dialog_t	*_dialog;
126 
127 	if (error != NULL)
128 		*error = 0;
129 	if (!sip_manage_dialog) {
130 		if (error != NULL)
131 			*error = EINVAL;
132 		return (0);
133 	}
134 	if (dialog == NULL) {
135 		if (error != NULL)
136 			*error = EINVAL;
137 		return (0);
138 	}
139 	_dialog = (_sip_dialog_t *)dialog;
140 	return (_dialog->sip_dlg_method);
141 }
142 
143 /*
144  * Get the Dialog state
145  */
146 int
147 sip_get_dialog_state(sip_dialog_t dialog, int *error)
148 {
149 	_sip_dialog_t	*_dialog;
150 
151 	if (error != NULL)
152 		*error = 0;
153 	if (!sip_manage_dialog) {
154 		if (error != NULL)
155 			*error = EINVAL;
156 		return (0);
157 	}
158 	if (dialog == NULL) {
159 		if (error != NULL)
160 			*error = EINVAL;
161 		return (0);
162 	}
163 	_dialog = (_sip_dialog_t *)dialog;
164 	return (_dialog->sip_dlg_state);
165 }
166 
167 /*
168  * Return the dialog callid
169  */
170 const sip_str_t *
171 sip_get_dialog_callid(sip_dialog_t dialog, int *error)
172 {
173 	_sip_dialog_t		*_dialog;
174 	const struct sip_value	*val;
175 	const sip_str_t		*callid = NULL;
176 
177 	if (error != NULL)
178 		*error = 0;
179 	if (!sip_manage_dialog || dialog == NULL) {
180 		if (error != NULL)
181 			*error = EINVAL;
182 		return (NULL);
183 	}
184 	_dialog = (_sip_dialog_t *)dialog;
185 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
186 	if (dialog->sip_dlg_call_id != NULL) {
187 		val = sip_get_header_value(_dialog->sip_dlg_call_id, error);
188 		if (val == NULL) {
189 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
190 			return (NULL);
191 		}
192 		callid = &((sip_hdr_value_t *)val)->str_val;
193 	}
194 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
195 	return (callid);
196 }
197 
198 /*
199  * Return the dialog localtag.
200  */
201 const sip_str_t *
202 sip_get_dialog_local_tag(sip_dialog_t dialog, int *error)
203 {
204 	_sip_dialog_t		*_dialog;
205 	const sip_str_t		*ltag = NULL;
206 	const struct sip_value	*val;
207 
208 	if (error != NULL)
209 		*error = 0;
210 	if (!sip_manage_dialog || dialog == NULL) {
211 		if (error != NULL)
212 			*error = EINVAL;
213 		return (NULL);
214 	}
215 	_dialog = (_sip_dialog_t *)dialog;
216 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
217 	if (dialog->sip_dlg_local_uri_tag != NULL) {
218 		val = sip_get_header_value(_dialog->sip_dlg_local_uri_tag,
219 		    error);
220 		if (val == NULL) {
221 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
222 			return (NULL);
223 		}
224 		ltag = sip_get_param_value((sip_header_value_t)val, "tag",
225 		    error);
226 	}
227 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
228 	return (ltag);
229 }
230 
231 /*
232  * Return the dialog remotetag
233  */
234 const sip_str_t *
235 sip_get_dialog_remote_tag(sip_dialog_t dialog, int *error)
236 {
237 	_sip_dialog_t		*_dialog;
238 	const sip_str_t		*ttag = NULL;
239 	const struct sip_value	*val;
240 
241 	if (error != NULL)
242 		*error = 0;
243 	if (!sip_manage_dialog || dialog == NULL) {
244 		if (error != NULL)
245 			*error = EINVAL;
246 		return (NULL);
247 	}
248 	_dialog = (_sip_dialog_t *)dialog;
249 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
250 	if (dialog->sip_dlg_remote_uri_tag != NULL) {
251 		val = sip_get_header_value(_dialog->sip_dlg_remote_uri_tag,
252 		    error);
253 		if (val == NULL) {
254 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
255 			return (NULL);
256 		}
257 		ttag = sip_get_param_value((sip_header_value_t)val, "tag",
258 		    error);
259 	}
260 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
261 
262 	return (ttag);
263 }
264 
265 /*
266  * Return the dialog localuri.
267  */
268 const struct sip_uri *
269 sip_get_dialog_local_uri(sip_dialog_t dialog, int *error)
270 {
271 	_sip_dialog_t		*_dialog;
272 	const _sip_uri_t	*luri = NULL;
273 	const struct sip_value	*val;
274 
275 	if (error != NULL)
276 		*error = 0;
277 	if (!sip_manage_dialog || dialog == NULL) {
278 		if (error != NULL)
279 			*error = EINVAL;
280 		return (NULL);
281 	}
282 	_dialog = (_sip_dialog_t *)dialog;
283 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
284 	if (dialog->sip_dlg_local_uri_tag != NULL) {
285 		val = sip_get_header_value(_dialog->sip_dlg_local_uri_tag,
286 		    error);
287 		if (val == NULL) {
288 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
289 			return (NULL);
290 		}
291 		luri = val->sip_value_parse_uri;
292 	}
293 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
294 
295 	return ((sip_uri_t)luri);
296 }
297 
298 /*
299  * Return the dialog remoteuri.
300  */
301 const struct sip_uri *
302 sip_get_dialog_remote_uri(sip_dialog_t dialog, int *error)
303 {
304 	_sip_dialog_t		*_dialog;
305 	const _sip_uri_t	*ruri = NULL;
306 	const struct sip_value	*val;
307 
308 	if (error != NULL)
309 		*error = 0;
310 	if (!sip_manage_dialog || dialog == NULL) {
311 		if (error != NULL)
312 			*error = EINVAL;
313 		return (NULL);
314 	}
315 	_dialog = (_sip_dialog_t *)dialog;
316 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
317 	if (dialog->sip_dlg_remote_uri_tag != NULL) {
318 		val = sip_get_header_value(dialog->sip_dlg_remote_uri_tag,
319 		    error);
320 		if (val == NULL) {
321 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
322 			return (NULL);
323 		}
324 		ruri = val->sip_value_parse_uri;
325 	}
326 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
327 	return ((sip_uri_t)ruri);
328 }
329 
330 /*
331  * Return the dialog remotetarg.
332  */
333 const struct sip_uri *
334 sip_get_dialog_remote_target_uri(sip_dialog_t dialog, int *error)
335 {
336 	_sip_dialog_t		*_dialog;
337 	const struct sip_uri	*rtarg = NULL;
338 	const struct sip_value	*val;
339 
340 	if (error != NULL)
341 		*error = 0;
342 	if (!sip_manage_dialog || dialog == NULL) {
343 		if (error != NULL)
344 			*error = EINVAL;
345 		return (NULL);
346 	}
347 	_dialog = (_sip_dialog_t *)dialog;
348 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
349 	if (dialog->sip_dlg_remote_target != NULL) {
350 		val = sip_get_header_value(_dialog->sip_dlg_remote_target,
351 		    error);
352 		if (val == NULL) {
353 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
354 			return (NULL);
355 		}
356 		rtarg = val->sip_value_parse_uri;
357 	}
358 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
359 
360 	return ((sip_uri_t)rtarg);
361 }
362 
363 /*
364  * Return the dialog route set
365  */
366 const sip_str_t *
367 sip_get_dialog_route_set(sip_dialog_t dialog, int *error)
368 {
369 	_sip_dialog_t		*_dialog;
370 
371 	if (error != NULL)
372 		*error = 0;
373 	if (!sip_manage_dialog || dialog == NULL) {
374 		if (error != NULL)
375 			*error = EINVAL;
376 		return (NULL);
377 	}
378 	_dialog = (_sip_dialog_t *)dialog;
379 	if (_dialog->sip_dlg_rset.sip_str_len > 0)
380 		return (&_dialog->sip_dlg_rset);
381 	return (NULL);
382 }
383 
384 /*
385  * Return the dialog secure
386  */
387 boolean_t
388 sip_is_dialog_secure(sip_dialog_t dialog, int *error)
389 {
390 	_sip_dialog_t	*_dialog;
391 	boolean_t	issecure;
392 
393 	if (error != NULL)
394 		*error = 0;
395 	if (!sip_manage_dialog || dialog == NULL) {
396 		if (error != NULL)
397 			*error = EINVAL;
398 		return (B_FALSE);
399 	}
400 	_dialog = (_sip_dialog_t *)dialog;
401 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
402 	issecure = _dialog->sip_dlg_secure;
403 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
404 	return (issecure);
405 }
406 
407 /*
408  * Return the dialog local cseq
409  */
410 uint32_t
411 sip_get_dialog_local_cseq(sip_dialog_t dialog, int *error)
412 {
413 	_sip_dialog_t	*_dialog;
414 	uint32_t	cseq;
415 
416 	if (error != NULL)
417 		*error = 0;
418 	if (!sip_manage_dialog || dialog == NULL) {
419 		if (error != NULL)
420 			*error = EINVAL;
421 		return (0);
422 	}
423 	_dialog = (_sip_dialog_t *)dialog;
424 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
425 	cseq = _dialog->sip_dlg_local_cseq;
426 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
427 	return (cseq);
428 }
429 
430 /*
431  * Return the dialog remote cseq
432  */
433 uint32_t
434 sip_get_dialog_remote_cseq(sip_dialog_t dialog, int *error)
435 {
436 	_sip_dialog_t	*_dialog;
437 	uint32_t	cseq;
438 
439 	if (error != NULL)
440 		*error = 0;
441 	if (!sip_manage_dialog || dialog == NULL) {
442 		if (error != NULL)
443 			*error = EINVAL;
444 		return (0);
445 	}
446 	_dialog = (_sip_dialog_t *)dialog;
447 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
448 	cseq = _dialog->sip_dlg_remote_cseq;
449 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
450 	return (cseq);
451 }
452 
453 /*
454  * Return the dialog type
455  */
456 int
457 sip_get_dialog_type(sip_dialog_t dialog, int *error)
458 {
459 	_sip_dialog_t	*_dialog;
460 	int		type;
461 
462 	if (error != NULL)
463 		*error = 0;
464 	if (!sip_manage_dialog || dialog == NULL) {
465 		if (error != NULL)
466 			*error = EINVAL;
467 		return (-1);
468 	}
469 	_dialog = (_sip_dialog_t *)dialog;
470 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
471 	type = _dialog->sip_dlg_type;
472 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
473 	return (type);
474 }
475 
476 
477 /*
478  * Partial dialog ?
479  */
480 boolean_t
481 sip_incomplete_dialog(sip_dialog_t dialog)
482 {
483 	_sip_dialog_t	*_dialog;
484 	boolean_t	isnew;
485 
486 	if (!sip_manage_dialog || dialog == NULL)
487 		return (B_FALSE);
488 	_dialog = (_sip_dialog_t *)dialog;
489 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
490 	isnew = _dialog->sip_dlg_state == SIP_DLG_NEW;
491 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
492 	return (isnew);
493 }
494 
495 /*
496  * Hold dialog
497  */
498 void
499 sip_hold_dialog(sip_dialog_t dialog)
500 {
501 	_sip_dialog_t	*_dialog;
502 
503 	if (!sip_manage_dialog || dialog == NULL)
504 		return;
505 	_dialog = (_sip_dialog_t *)dialog;
506 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
507 	SIP_DLG_REFCNT_INCR(_dialog);
508 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
509 }
510 
511 /*
512  * Release dialog
513  */
514 void
515 sip_release_dialog(sip_dialog_t dialog)
516 {
517 	_sip_dialog_t	*_dialog;
518 
519 	if (!sip_manage_dialog || dialog == NULL)
520 		return;
521 	_dialog = (_sip_dialog_t *)dialog;
522 	SIP_DLG_REFCNT_DECR(_dialog);
523 }
524 
525 /*
526  * Delete a dialog
527  */
528 void
529 sip_delete_dialog(sip_dialog_t dialog)
530 {
531 	if (!sip_manage_dialog || dialog == NULL)
532 		return;
533 	sip_dialog_terminate(dialog, NULL);
534 }
535