libc: make stdio_impl.h an internal libc header
[unleashed/tickless.git] / usr / src / lib / libsip / common / sip_msg.c
blob355adafb279c1518a5b20c665b937e9de7ddc6ab
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <stdio.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <pthread.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sip.h>
35 #include "sip_msg.h"
36 #include "sip_miscdefs.h"
37 #include "sip_parse_generic.h"
40 * Response consists of SIP version, response code, response phrase and CRLF.
42 #define SIP_RESPONSE "%s %d %s%s"
44 void sip_free_content(_sip_msg_t *);
47 * Allocate a new sip msg struct.
49 sip_msg_t
50 sip_new_msg()
52 _sip_msg_t *sip_msg;
54 sip_msg = calloc(1, sizeof (_sip_msg_t));
55 if (sip_msg != NULL) {
56 sip_msg->sip_msg_ref_cnt = 1;
57 (void) pthread_mutex_init(&sip_msg->sip_msg_mutex, NULL);
59 return ((sip_msg_t)sip_msg);
63 * Free all resources. The lock is taken by SIP_MSG_REFCNT_DECR. The
64 * thread that decrements the last refcount should take care that
65 * the message is not accessible to other threads before doing so.
66 * Else, if the message is still accessible to others, it is
67 * possible that the other thread could be waiting to take the
68 * lock when we proceed to destroy it.
70 void
71 sip_destroy_msg(_sip_msg_t *_sip_msg)
73 #ifdef __solaris__
74 assert(mutex_held(&_sip_msg->sip_msg_mutex));
75 #endif
76 (void) sip_delete_start_line_locked(_sip_msg);
77 assert(_sip_msg->sip_msg_ref_cnt == 0);
78 sip_delete_all_headers((sip_msg_t)_sip_msg);
79 sip_free_content(_sip_msg);
80 free(_sip_msg->sip_msg_buf);
82 free(_sip_msg->sip_msg_old_buf);
84 while (_sip_msg->sip_msg_req_res != NULL) {
85 sip_message_type_t *sip_msg_type_ptr;
87 sip_msg_type_ptr = _sip_msg->sip_msg_req_res->sip_next;
88 if (_sip_msg->sip_msg_req_res->is_request) {
89 sip_request_t *reqline;
91 reqline = &_sip_msg->sip_msg_req_res->U.sip_request;
92 if (reqline->sip_parse_uri != NULL) {
93 sip_free_parsed_uri(reqline->sip_parse_uri);
94 reqline->sip_parse_uri = NULL;
97 free(_sip_msg->sip_msg_req_res);
98 _sip_msg->sip_msg_req_res = sip_msg_type_ptr;
100 (void) pthread_mutex_destroy(&_sip_msg->sip_msg_mutex);
101 free(_sip_msg);
105 * Free a sip msg struct.
107 void
108 sip_free_msg(sip_msg_t sip_msg)
110 if (sip_msg == NULL)
111 return;
113 SIP_MSG_REFCNT_DECR((_sip_msg_t *)sip_msg);
117 * Hold a sip msg struct.
119 void
120 sip_hold_msg(sip_msg_t sip_msg)
123 if (sip_msg == NULL)
124 return;
126 SIP_MSG_REFCNT_INCR((_sip_msg_t *)sip_msg);
130 * Clone a message
132 sip_msg_t
133 sip_clone_msg(sip_msg_t sip_msg)
135 _sip_msg_t *new_msg;
136 _sip_msg_t *_sip_msg;
137 sip_content_t *sip_content;
138 sip_content_t *msg_content;
139 sip_content_t *new_content = NULL;
140 int len;
142 if (sip_msg == NULL)
143 return (NULL);
144 new_msg = (_sip_msg_t *)sip_new_msg();
145 if (new_msg == NULL)
146 return (NULL);
147 _sip_msg = (_sip_msg_t *)sip_msg;
149 * Get start line
151 if (sip_copy_start_line(_sip_msg, new_msg) != 0) {
152 sip_free_msg((sip_msg_t)new_msg);
153 return (NULL);
155 if (sip_copy_all_headers(_sip_msg, new_msg) != 0) {
156 sip_free_msg((sip_msg_t)new_msg);
157 return (NULL);
159 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
160 sip_content = _sip_msg->sip_msg_content;
161 while (sip_content != NULL) {
162 msg_content = calloc(1, sizeof (sip_content_t));
163 if (msg_content == NULL) {
164 sip_free_msg((sip_msg_t)new_msg);
165 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
166 return (NULL);
168 len = sip_content->sip_content_end -
169 sip_content->sip_content_start;
170 msg_content->sip_content_start = malloc(len + 1);
171 if (msg_content->sip_content_start == NULL) {
172 sip_free_msg((sip_msg_t)new_msg);
173 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
174 return (NULL);
176 (void) strncpy(msg_content->sip_content_start,
177 sip_content->sip_content_start, len);
178 msg_content->sip_content_start[len] = '\0';
179 msg_content->sip_content_current =
180 msg_content->sip_content_start;
181 msg_content->sip_content_end = msg_content->sip_content_start +
182 len;
183 msg_content->sip_content_allocated = B_TRUE;
184 new_msg->sip_msg_content_len += len;
185 new_msg->sip_msg_len += len;
186 if (new_msg->sip_msg_content == NULL)
187 new_msg->sip_msg_content = msg_content;
188 else
189 new_content->sip_content_next = msg_content;
190 new_content = msg_content;
191 sip_content = sip_content->sip_content_next;
193 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
195 * Since this is a new message, no threads should be referring
196 * to this, so it is not necessary to take the lock, however,
197 * since sip_msg_to_msgbuf() expects the lock to be held, we'll
198 * take it here.
200 (void) pthread_mutex_lock(&new_msg->sip_msg_mutex);
201 new_msg->sip_msg_buf = sip_msg_to_msgbuf((sip_msg_t)new_msg, NULL);
202 if (new_msg->sip_msg_buf == NULL) {
203 (void) pthread_mutex_unlock(&new_msg->sip_msg_mutex);
204 sip_free_msg((sip_msg_t)new_msg);
205 return (NULL);
207 new_msg->sip_msg_cannot_be_modified = B_TRUE;
208 (void) pthread_mutex_unlock(&new_msg->sip_msg_mutex);
210 return ((sip_msg_t)new_msg);
214 * Return the SIP message as a string. Caller frees the string
216 char *
217 sip_msg_to_str(sip_msg_t sip_msg, int *error)
219 _sip_msg_t *msg;
220 char *msgstr;
222 if (sip_msg == NULL) {
223 if (error != NULL)
224 *error = EINVAL;
225 return (NULL);
227 msg = (_sip_msg_t *)sip_msg;
228 (void) pthread_mutex_lock(&msg->sip_msg_mutex);
229 msgstr = sip_msg_to_msgbuf(msg, error);
230 (void) pthread_mutex_unlock(&msg->sip_msg_mutex);
231 return (msgstr);
235 * Given a message generate a string that includes all the headers and the
236 * content.
238 char *
239 sip_msg_to_msgbuf(_sip_msg_t *msg, int *error)
241 _sip_header_t *header;
242 int len = 0;
243 char *p;
244 char *e;
245 sip_content_t *sip_content;
246 #ifdef _DEBUG
247 int tlen = 0;
248 int clen = 0;
249 #endif
251 if (error != NULL)
252 *error = 0;
254 if (msg == NULL) {
255 if (error != NULL)
256 *error = EINVAL;
257 return (NULL);
259 #ifdef __solaris__
260 assert(mutex_held(&msg->sip_msg_mutex));
261 #endif
263 p = (char *)malloc(msg->sip_msg_len + 1);
264 if (p == NULL) {
265 if (error != 0)
266 *error = ENOMEM;
267 return (NULL);
269 e = p;
272 * Get the start line
274 if (msg->sip_msg_start_line != NULL) {
275 len = msg->sip_msg_start_line->sip_hdr_end -
276 msg->sip_msg_start_line->sip_hdr_start;
277 (void) strncpy(e, msg->sip_msg_start_line->sip_hdr_start, len);
278 e += len;
279 #ifdef _DEBUG
280 tlen += len;
281 #endif
283 header = sip_search_for_header(msg, NULL, NULL);
284 while (header != NULL) {
285 if (header->sip_header_state != SIP_HEADER_DELETED) {
286 if (header->sip_header_state ==
287 SIP_HEADER_DELETED_VAL) {
288 len = sip_copy_values(e, header);
289 } else {
290 len = header->sip_hdr_end -
291 header->sip_hdr_start;
292 (void) strncpy(e, header->sip_hdr_start, len);
294 #ifdef _DEBUG
295 tlen += len;
296 assert(tlen <= msg->sip_msg_len);
297 #endif
299 header = sip_search_for_header(msg, NULL, header);
300 e += len;
302 sip_content = msg->sip_msg_content;
303 while (sip_content != NULL) {
304 len = sip_content->sip_content_end -
305 sip_content->sip_content_start;
306 #ifdef _DEBUG
307 clen += len;
308 assert(clen <= msg->sip_msg_content_len);
309 tlen += len;
310 assert(tlen <= msg->sip_msg_len);
311 #endif
312 (void) strncpy(e, sip_content->sip_content_start, len);
313 e += len;
314 sip_content = sip_content->sip_content_next;
316 p[msg->sip_msg_len] = '\0';
317 return (p);
321 * This is called just before sending the message to the transport. It
322 * creates the sip_msg_buf from the SIP headers.
325 sip_adjust_msgbuf(_sip_msg_t *msg)
327 _sip_header_t *header;
328 int ret;
329 #ifdef _DEBUG
330 int tlen = 0;
331 int clen = 0;
332 #endif
334 if (msg == NULL)
335 return (EINVAL);
337 (void) pthread_mutex_lock(&msg->sip_msg_mutex);
338 if ((msg->sip_msg_buf != NULL) && (!msg->sip_msg_modified)) {
340 * We could just be forwarding the message we
341 * received.
343 (void) pthread_mutex_unlock(&msg->sip_msg_mutex);
344 return (0);
348 * We are sending a new message or a message that we received
349 * but have modified it. We keep the old
350 * msgbuf till the message is freed as some
351 * headers still point to it.
354 assert(msg->sip_msg_old_buf == NULL);
355 msg->sip_msg_old_buf = msg->sip_msg_buf;
357 * We add the content-length header here, if it has not
358 * already been added.
360 header = sip_search_for_header(msg, SIP_CONTENT_LENGTH, NULL);
361 if (header != NULL) {
363 * Mark the previous header as deleted.
365 header->sip_header_state = SIP_HEADER_DELETED;
366 header->sip_hdr_sipmsg->sip_msg_len -= header->sip_hdr_end -
367 header->sip_hdr_start;
369 (void) pthread_mutex_unlock(&msg->sip_msg_mutex);
370 ret = sip_add_content_length(msg, msg->sip_msg_content_len);
371 if (ret != 0) {
372 (void) pthread_mutex_unlock(&msg->sip_msg_mutex);
373 return (ret);
375 (void) pthread_mutex_lock(&msg->sip_msg_mutex);
376 msg->sip_msg_modified = B_FALSE;
378 msg->sip_msg_buf = sip_msg_to_msgbuf((sip_msg_t)msg, &ret);
379 if (msg->sip_msg_buf == NULL) {
380 (void) pthread_mutex_unlock(&msg->sip_msg_mutex);
381 return (ret);
384 * Once the message has been sent it can not be modified
385 * any furthur as we keep a pointer to it for retransmission
387 msg->sip_msg_cannot_be_modified = B_TRUE;
389 (void) pthread_mutex_unlock(&msg->sip_msg_mutex);
390 return (0);
394 * Copy header values into ptr
397 sip_copy_values(char *ptr, _sip_header_t *header)
399 sip_header_value_t value;
400 int tlen = 0;
401 int len = 0;
402 boolean_t first = B_TRUE;
403 char *p = ptr;
404 char *s;
405 boolean_t crlf_present = B_FALSE;
407 if (sip_parse_goto_values(header) != 0)
408 return (0);
410 len = header->sip_hdr_current - header->sip_hdr_start;
411 (void) strncpy(p, header->sip_hdr_start, len);
412 tlen += len;
413 p += len;
414 value = header->sip_hdr_parsed->value;
415 while (value != NULL) {
416 if (value->value_state != SIP_VALUE_DELETED) {
417 crlf_present = B_FALSE;
418 len = value->value_end - value->value_start;
419 if (first) {
420 (void) strncpy(p, value->value_start, len);
421 first = B_FALSE;
422 } else {
423 s = value->value_start;
424 while (*s != SIP_COMMA)
425 s--;
426 len += value->value_start - s;
427 (void) strncpy(p, s, len);
429 tlen += len;
430 p += len;
431 s = value->value_end;
432 while (s != value->value_start) {
433 if (*s == '\r' && strncmp(s, SIP_CRLF,
434 strlen(SIP_CRLF)) == 0) {
435 crlf_present = B_TRUE;
436 break;
438 s--;
440 } else {
441 if (value->next == NULL && !first && !crlf_present) {
442 s = value->value_end;
443 while (*s != '\r')
444 s--;
445 len = value->value_end - s;
446 (void) strncpy(p, s, len);
447 tlen += len;
448 p += len;
451 value = value->next;
453 return (tlen);
458 * Add content (message body) to sip_msg
461 sip_add_content(sip_msg_t sip_msg, char *content)
463 size_t len;
464 sip_content_t **loc;
465 sip_content_t *msg_content;
466 _sip_msg_t *_sip_msg;
468 if (sip_msg == NULL || content == NULL || strlen(content) == 0)
469 return (EINVAL);
470 len = strlen(content);
471 _sip_msg = (_sip_msg_t *)sip_msg;
472 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
474 if (_sip_msg->sip_msg_cannot_be_modified) {
475 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
476 return (ENOTSUP);
479 msg_content = calloc(1, sizeof (sip_content_t));
480 if (msg_content == NULL) {
481 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
482 return (ENOMEM);
484 msg_content->sip_content_start = malloc(strlen(content) + 1);
485 if (msg_content->sip_content_start == NULL) {
486 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
487 free(msg_content);
488 return (ENOMEM);
490 (void) strncpy(msg_content->sip_content_start, content,
491 strlen(content));
492 msg_content->sip_content_start[strlen(content)] = '\0';
493 msg_content->sip_content_current = msg_content->sip_content_start;
494 msg_content->sip_content_end = msg_content->sip_content_start +
495 strlen(msg_content->sip_content_start);
496 msg_content->sip_content_allocated = B_TRUE;
498 loc = &_sip_msg->sip_msg_content;
499 while (*loc != NULL)
500 loc = &((*loc)->sip_content_next);
501 *loc = msg_content;
503 _sip_msg->sip_msg_content_len += len;
504 _sip_msg->sip_msg_len += len;
505 if (_sip_msg->sip_msg_buf != NULL)
506 _sip_msg->sip_msg_modified = B_TRUE;
507 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
508 return (0);
512 * Free the message content
514 void
515 sip_free_content(_sip_msg_t *sip_msg)
517 sip_content_t *content;
519 if (sip_msg == NULL)
520 return;
521 content = sip_msg->sip_msg_content;
522 while (content != NULL) {
523 sip_content_t *content_tmp;
525 content_tmp = content;
526 content = content->sip_content_next;
527 if (content_tmp->sip_content_allocated)
528 free(content_tmp->sip_content_start);
529 free(content_tmp);
531 sip_msg->sip_msg_content = NULL;
536 * Add a response line to sip_response
539 sip_add_response_line(sip_msg_t sip_response, int response, char *response_code)
541 _sip_header_t *new_header;
542 int header_size;
543 _sip_msg_t *_sip_response;
544 int ret;
546 if (sip_response == NULL || response < 0 || response_code == NULL)
547 return (EINVAL);
548 _sip_response = (_sip_msg_t *)sip_response;
549 (void) pthread_mutex_lock(&_sip_response->sip_msg_mutex);
550 if (_sip_response->sip_msg_cannot_be_modified) {
551 (void) pthread_mutex_unlock(&_sip_response->sip_msg_mutex);
552 return (ENOTSUP);
554 header_size = strlen(SIP_VERSION) + SIP_SPACE_LEN +
555 SIP_SIZE_OF_STATUS_CODE + SIP_SPACE_LEN + strlen(response_code) +
556 strlen(SIP_CRLF);
558 new_header = sip_new_header(header_size);
559 if (new_header == NULL) {
560 (void) pthread_mutex_unlock(&_sip_response->sip_msg_mutex);
561 return (ENOMEM);
563 new_header->sip_hdr_sipmsg = _sip_response;
565 (void) snprintf(new_header->sip_hdr_start, header_size + 1,
566 SIP_RESPONSE, SIP_VERSION, response, response_code, SIP_CRLF);
568 new_header->sip_hdr_next = _sip_response->sip_msg_start_line;
569 _sip_response->sip_msg_start_line = new_header;
570 _sip_response->sip_msg_len += header_size;
571 ret = sip_parse_first_line(_sip_response->sip_msg_start_line,
572 &_sip_response->sip_msg_req_res);
573 if (_sip_response->sip_msg_buf != NULL)
574 _sip_response->sip_msg_modified = B_TRUE;
575 (void) pthread_mutex_unlock(&_sip_response->sip_msg_mutex);
576 return (ret);
580 * create a response based on the sip_request.
581 * Copies Call-ID, CSeq, From, To and Via headers from the request.
583 sip_msg_t
584 sip_create_response(sip_msg_t sip_request, int response, char *response_code,
585 char *totag, char *mycontact)
587 _sip_msg_t *new_msg;
588 _sip_msg_t *_sip_request;
589 boolean_t ttag_present;
591 if (sip_request == NULL || response_code == NULL)
592 return (NULL);
594 ttag_present = sip_get_to_tag(sip_request, NULL) != NULL;
596 new_msg = (_sip_msg_t *)sip_new_msg();
597 if (new_msg == NULL)
598 return (NULL);
599 _sip_request = (_sip_msg_t *)sip_request;
601 (void) pthread_mutex_lock(&_sip_request->sip_msg_mutex);
604 * Add response line.
606 if (sip_add_response_line(new_msg, response, response_code) != 0)
607 goto error;
610 * Copy Via headers
612 if (_sip_find_and_copy_all_header(_sip_request, new_msg, SIP_VIA) != 0)
613 goto error;
616 * Copy From header.
618 if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_FROM,
619 NULL, B_FALSE)) {
620 goto error;
623 * Copy To header. If To tag is present, copy it, if not then
624 * add one if the repsonse is not provisional.
626 if (ttag_present || (totag == NULL && response == SIP_TRYING)) {
627 if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_TO,
628 NULL, B_FALSE)) {
629 goto error;
631 } else {
632 char *xtra_param;
633 boolean_t tag_alloc = B_FALSE;
634 int taglen;
636 if (totag == NULL) {
637 totag = sip_guid();
638 if (totag == NULL)
639 goto error;
640 tag_alloc = B_TRUE;
642 taglen = strlen(SIP_TAG) + strlen(totag) + 1;
643 xtra_param = (char *)malloc(taglen);
644 if (xtra_param == NULL) {
645 if (tag_alloc)
646 free(totag);
647 goto error;
649 (void) snprintf(xtra_param, taglen, "%s%s", SIP_TAG, totag);
650 if (tag_alloc)
651 free(totag);
652 if (_sip_find_and_copy_header(_sip_request, new_msg,
653 SIP_TO, xtra_param, B_FALSE)) {
654 free(xtra_param);
655 goto error;
657 free(xtra_param);
661 * Copy Call-ID header.
663 if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_CALL_ID, NULL,
664 B_FALSE)) {
665 goto error;
668 * Copy CSEQ header
670 if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_CSEQ, NULL,
671 B_FALSE)) {
672 goto error;
675 * Copy RECORD-ROUTE header, if present.
677 if (sip_search_for_header(_sip_request, SIP_RECORD_ROUTE, NULL) !=
678 NULL) {
679 if (_sip_find_and_copy_all_header(_sip_request, new_msg,
680 SIP_RECORD_ROUTE) != 0) {
681 goto error;
684 if (mycontact != NULL) {
685 if (sip_add_contact(new_msg, NULL, mycontact, B_FALSE,
686 NULL) != 0) {
687 goto error;
690 (void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex);
691 return ((sip_msg_t)new_msg);
692 error:
693 sip_free_msg((sip_msg_t)new_msg);
694 (void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex);
695 return (NULL);
699 * NON OK ACK : MUST contain values for the Call-ID, From, and Request-URI
700 * that are equal to the values of those header fields in the orig request
701 * passed to the transport. The To header field in the ACK MUST equal the To
702 * header field in the response being acknowledged. The ACK MUST contain the
703 * top Via header field of the original request. The CSeq header field in
704 * the ACK MUST contain the same value for the sequence number as was
705 * present in the original request, but the method parameter MUST be equal
706 * to "ACK".
709 sip_create_nonOKack(sip_msg_t request, sip_msg_t response, sip_msg_t ack_msg)
711 int seqno;
712 char *uri;
713 _sip_msg_t *_request;
714 _sip_msg_t *_response;
715 _sip_msg_t *_ack_msg;
716 int ret;
718 if (request == NULL || response == NULL || ack_msg == NULL ||
719 request == ack_msg) {
720 return (EINVAL);
722 _request = (_sip_msg_t *)request;
723 _response = (_sip_msg_t *)response;
724 _ack_msg = (_sip_msg_t *)ack_msg;
726 (void) pthread_mutex_lock(&_request->sip_msg_mutex);
727 if (_request->sip_msg_req_res == NULL) {
728 if ((ret = sip_parse_first_line(_request->sip_msg_start_line,
729 &_request->sip_msg_req_res)) != 0) {
730 (void) pthread_mutex_unlock(&_request->sip_msg_mutex);
731 return (ret);
734 if (_request->sip_msg_req_res->U.sip_request.sip_request_uri.
735 sip_str_ptr == NULL) {
736 (void) pthread_mutex_unlock(&_request->sip_msg_mutex);
737 return (EINVAL);
739 uri = (char *)malloc(_request->sip_msg_req_res->U.sip_request.
740 sip_request_uri.sip_str_len + 1);
741 if (uri == NULL) {
742 (void) pthread_mutex_unlock(&_request->sip_msg_mutex);
743 return (EINVAL);
745 (void) strncpy(uri,
746 _request->sip_msg_req_res->U.sip_request.sip_request_uri.
747 sip_str_ptr, _request->sip_msg_req_res->U.sip_request.
748 sip_request_uri.sip_str_len);
749 uri[_request->sip_msg_req_res->U.sip_request.
750 sip_request_uri.sip_str_len] = '\0';
751 if ((ret = sip_add_request_line(_ack_msg, ACK, uri)) != 0) {
752 (void) pthread_mutex_unlock(&_request->sip_msg_mutex);
753 return (ret);
755 free(uri);
756 if ((ret = _sip_find_and_copy_header(_request, _ack_msg, SIP_VIA,
757 NULL, B_TRUE)) != 0) {
758 (void) pthread_mutex_unlock(&_request->sip_msg_mutex);
759 return (ret);
761 (void) _sip_find_and_copy_header(_request, _ack_msg,
762 SIP_MAX_FORWARDS, NULL, B_TRUE);
764 (void) pthread_mutex_lock(&_response->sip_msg_mutex);
765 if ((ret = _sip_find_and_copy_header(_response, _ack_msg, SIP_TO,
766 NULL, B_TRUE)) != 0) {
767 (void) pthread_mutex_unlock(&_response->sip_msg_mutex);
768 return (ret);
770 (void) pthread_mutex_unlock(&_response->sip_msg_mutex);
771 if ((ret = _sip_find_and_copy_header(_request, _ack_msg, SIP_FROM,
772 NULL, B_TRUE)) != 0) {
773 (void) pthread_mutex_unlock(&_request->sip_msg_mutex);
774 return (ret);
776 if ((ret = _sip_find_and_copy_header(_request, _ack_msg, SIP_CALL_ID,
777 NULL, B_TRUE)) != 0) {
778 (void) pthread_mutex_unlock(&_request->sip_msg_mutex);
779 return (ret);
781 (void) pthread_mutex_unlock(&_request->sip_msg_mutex);
782 seqno = sip_get_callseq_num(_request, &ret);
783 if (ret != 0)
784 return (ret);
785 if ((ret = sip_add_cseq(_ack_msg, ACK, seqno)) != 0)
786 return (ret);
787 if ((ret = sip_adjust_msgbuf(_ack_msg)) != 0)
788 return (ret);
789 return (0);
793 * This is a 2XX ACK, for others ACK is constructed differently,
794 * esp. the branch id is retained.
797 sip_create_OKack(sip_msg_t response, sip_msg_t ack_msg, char *transport,
798 char *sent_by, int sent_by_port, char *via_params)
800 int seqno;
801 char *uri;
802 sip_parsed_header_t *parsed_header;
803 sip_hdr_value_t *contact_value;
804 _sip_header_t *header;
805 _sip_msg_t *_response;
806 _sip_msg_t *_ack_msg;
807 int ret;
809 if (response == NULL || response == NULL || transport == NULL)
810 return (EINVAL);
811 _response = (_sip_msg_t *)response;
812 _ack_msg = (_sip_msg_t *)ack_msg;
815 * Get URI from the response, Contact field
817 (void) pthread_mutex_lock(&_response->sip_msg_mutex);
818 if ((header = sip_search_for_header(_response, SIP_CONTACT,
819 NULL)) == NULL) {
820 (void) pthread_mutex_unlock(&_response->sip_msg_mutex);
821 return (EINVAL);
823 if ((ret = sip_parse_cftr_header(header, (void *)&parsed_header)) !=
824 0) {
825 (void) pthread_mutex_unlock(&_response->sip_msg_mutex);
826 return (ret);
828 contact_value = (sip_hdr_value_t *)parsed_header->value;
829 if (contact_value->cftr_uri.sip_str_ptr == NULL) {
830 (void) pthread_mutex_unlock(&_response->sip_msg_mutex);
831 return (EINVAL);
833 uri = (char *)malloc(contact_value->cftr_uri.sip_str_len + 1);
834 if (uri == NULL) {
835 (void) pthread_mutex_unlock(&_response->sip_msg_mutex);
836 return (ENOMEM);
838 (void) strncpy(uri, contact_value->cftr_uri.sip_str_ptr,
839 contact_value->cftr_uri.sip_str_len);
840 uri[contact_value->cftr_uri.sip_str_len] = '\0';
841 if ((ret = sip_add_request_line(_ack_msg, ACK, uri)) != 0) {
842 (void) pthread_mutex_unlock(&_response->sip_msg_mutex);
843 return (ret);
845 free(uri);
846 if ((ret = sip_add_via(_ack_msg, transport, sent_by, sent_by_port,
847 via_params)) != 0) {
848 (void) pthread_mutex_unlock(&_response->sip_msg_mutex);
849 return (ret);
852 if ((ret = _sip_find_and_copy_header(_response, _ack_msg, SIP_TO,
853 NULL, B_TRUE)) != 0) {
854 (void) pthread_mutex_unlock(&_response->sip_msg_mutex);
855 return (ret);
857 if ((ret = _sip_find_and_copy_header(_response, _ack_msg, SIP_FROM,
858 NULL, B_TRUE)) != 0) {
859 (void) pthread_mutex_unlock(&_response->sip_msg_mutex);
860 return (ret);
862 if ((ret = _sip_find_and_copy_header(_response, _ack_msg, SIP_CALL_ID,
863 NULL, B_TRUE)) != 0) {
864 (void) pthread_mutex_unlock(&_response->sip_msg_mutex);
865 return (ret);
868 * Copy Max-Forward if present
870 if (sip_search_for_header(_response, SIP_MAX_FORWARDS, NULL) != NULL) {
871 if ((ret = _sip_find_and_copy_header(_response, _ack_msg,
872 SIP_MAX_FORWARDS, NULL, B_TRUE)) != 0) {
873 (void) pthread_mutex_unlock(&_response->sip_msg_mutex);
874 return (ret);
877 (void) pthread_mutex_unlock(&_response->sip_msg_mutex);
878 seqno = sip_get_callseq_num(_response, &ret);
879 if (ret != 0)
880 return (ret);
881 if ((ret = sip_add_cseq(_ack_msg, ACK, seqno)) != 0)
882 return (ret);
884 return (0);
888 * Request-Line = Method SP Request-URI SP SIP-Version CRLF
891 sip_add_request_line(sip_msg_t sip_request, sip_method_t method,
892 char *request_uri)
894 _sip_header_t *new_header;
895 int header_size;
896 _sip_msg_t *_sip_request;
898 if (method < INVITE || method >= MAX_SIP_METHODS ||
899 request_uri == NULL || sip_request == NULL) {
900 return (EINVAL);
903 _sip_request = (_sip_msg_t *)sip_request;
904 (void) pthread_mutex_lock(&_sip_request->sip_msg_mutex);
905 if (_sip_request->sip_msg_cannot_be_modified) {
906 (void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex);
907 return (ENOTSUP);
910 header_size = strlen(sip_methods[method].name) + SIP_SPACE_LEN +
911 strlen(request_uri) + SIP_SPACE_LEN + strlen(SIP_VERSION) +
912 strlen(SIP_CRLF);
914 new_header = sip_new_header(header_size);
915 if (new_header == NULL) {
916 (void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex);
917 return (ENOMEM);
919 new_header->sip_hdr_sipmsg = _sip_request;
921 (void) snprintf(new_header->sip_hdr_start, header_size + 1,
922 "%s %s %s%s", sip_methods[method].name, request_uri,
923 SIP_VERSION, SIP_CRLF);
925 new_header->sip_hdr_next = _sip_request->sip_msg_start_line;
926 _sip_request->sip_msg_start_line = new_header;
927 _sip_request->sip_msg_len += header_size;
928 (void) sip_parse_first_line(_sip_request->sip_msg_start_line,
929 &_sip_request->sip_msg_req_res);
930 if (_sip_request->sip_msg_buf != NULL)
931 _sip_request->sip_msg_modified = B_TRUE;
932 (void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex);
933 return (0);