/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include "sip_msg.h" #include "sip_miscdefs.h" #include "sip_parse_generic.h" /* * Response consists of SIP version, response code, response phrase and CRLF. */ #define SIP_RESPONSE "%s %d %s%s" void sip_free_content(_sip_msg_t *); /* * Allocate a new sip msg struct. */ sip_msg_t sip_new_msg() { _sip_msg_t *sip_msg; sip_msg = calloc(1, sizeof (_sip_msg_t)); if (sip_msg != NULL) { sip_msg->sip_msg_ref_cnt = 1; (void) pthread_mutex_init(&sip_msg->sip_msg_mutex, NULL); } return ((sip_msg_t)sip_msg); } /* * Free all resources. The lock is taken by SIP_MSG_REFCNT_DECR. The * thread that decrements the last refcount should take care that * the message is not accessible to other threads before doing so. * Else, if the message is still accessible to others, it is * possible that the other thread could be waiting to take the * lock when we proceed to destroy it. */ void sip_destroy_msg(_sip_msg_t *_sip_msg) { #ifdef __solaris__ assert(mutex_held(&_sip_msg->sip_msg_mutex)); #endif (void) sip_delete_start_line_locked(_sip_msg); assert(_sip_msg->sip_msg_ref_cnt == 0); sip_delete_all_headers((sip_msg_t)_sip_msg); sip_free_content(_sip_msg); if (_sip_msg->sip_msg_buf != NULL) free(_sip_msg->sip_msg_buf); if (_sip_msg->sip_msg_old_buf != NULL) free(_sip_msg->sip_msg_old_buf); while (_sip_msg->sip_msg_req_res != NULL) { sip_message_type_t *sip_msg_type_ptr; sip_msg_type_ptr = _sip_msg->sip_msg_req_res->sip_next; if (_sip_msg->sip_msg_req_res->is_request) { sip_request_t *reqline; reqline = &_sip_msg->sip_msg_req_res->U.sip_request; if (reqline->sip_parse_uri != NULL) { sip_free_parsed_uri(reqline->sip_parse_uri); reqline->sip_parse_uri = NULL; } } free(_sip_msg->sip_msg_req_res); _sip_msg->sip_msg_req_res = sip_msg_type_ptr; } (void) pthread_mutex_destroy(&_sip_msg->sip_msg_mutex); free(_sip_msg); } /* * Free a sip msg struct. */ void sip_free_msg(sip_msg_t sip_msg) { if (sip_msg == NULL) return; SIP_MSG_REFCNT_DECR((_sip_msg_t *)sip_msg); } /* * Hold a sip msg struct. */ void sip_hold_msg(sip_msg_t sip_msg) { if (sip_msg == NULL) return; SIP_MSG_REFCNT_INCR((_sip_msg_t *)sip_msg); } /* * Clone a message */ sip_msg_t sip_clone_msg(sip_msg_t sip_msg) { _sip_msg_t *new_msg; _sip_msg_t *_sip_msg; sip_content_t *sip_content; sip_content_t *msg_content; sip_content_t *new_content = NULL; int len; if (sip_msg == NULL) return (NULL); new_msg = (_sip_msg_t *)sip_new_msg(); if (new_msg == NULL) return (NULL); _sip_msg = (_sip_msg_t *)sip_msg; /* * Get start line */ if (sip_copy_start_line(_sip_msg, new_msg) != 0) { sip_free_msg((sip_msg_t)new_msg); return (NULL); } if (sip_copy_all_headers(_sip_msg, new_msg) != 0) { sip_free_msg((sip_msg_t)new_msg); return (NULL); } (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); sip_content = _sip_msg->sip_msg_content; while (sip_content != NULL) { msg_content = calloc(1, sizeof (sip_content_t)); if (msg_content == NULL) { sip_free_msg((sip_msg_t)new_msg); (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); return (NULL); } len = sip_content->sip_content_end - sip_content->sip_content_start; msg_content->sip_content_start = malloc(len + 1); if (msg_content->sip_content_start == NULL) { sip_free_msg((sip_msg_t)new_msg); (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); return (NULL); } (void) strncpy(msg_content->sip_content_start, sip_content->sip_content_start, len); msg_content->sip_content_start[len] = '\0'; msg_content->sip_content_current = msg_content->sip_content_start; msg_content->sip_content_end = msg_content->sip_content_start + len; msg_content->sip_content_allocated = B_TRUE; new_msg->sip_msg_content_len += len; new_msg->sip_msg_len += len; if (new_msg->sip_msg_content == NULL) new_msg->sip_msg_content = msg_content; else new_content->sip_content_next = msg_content; new_content = msg_content; sip_content = sip_content->sip_content_next; } (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); /* * Since this is a new message, no threads should be referring * to this, so it is not necessary to take the lock, however, * since sip_msg_to_msgbuf() expects the lock to be held, we'll * take it here. */ (void) pthread_mutex_lock(&new_msg->sip_msg_mutex); new_msg->sip_msg_buf = sip_msg_to_msgbuf((sip_msg_t)new_msg, NULL); if (new_msg->sip_msg_buf == NULL) { (void) pthread_mutex_unlock(&new_msg->sip_msg_mutex); sip_free_msg((sip_msg_t)new_msg); return (NULL); } new_msg->sip_msg_cannot_be_modified = B_TRUE; (void) pthread_mutex_unlock(&new_msg->sip_msg_mutex); return ((sip_msg_t)new_msg); } /* * Return the SIP message as a string. Caller frees the string */ char * sip_msg_to_str(sip_msg_t sip_msg, int *error) { _sip_msg_t *msg; char *msgstr; if (sip_msg == NULL) { if (error != NULL) *error = EINVAL; return (NULL); } msg = (_sip_msg_t *)sip_msg; (void) pthread_mutex_lock(&msg->sip_msg_mutex); msgstr = sip_msg_to_msgbuf(msg, error); (void) pthread_mutex_unlock(&msg->sip_msg_mutex); return (msgstr); } /* * Given a message generate a string that includes all the headers and the * content. */ char * sip_msg_to_msgbuf(_sip_msg_t *msg, int *error) { _sip_header_t *header; int len = 0; char *p; char *e; sip_content_t *sip_content; #ifdef _DEBUG int tlen = 0; int clen = 0; #endif if (error != NULL) *error = 0; if (msg == NULL) { if (error != NULL) *error = EINVAL; return (NULL); } #ifdef __solaris__ assert(mutex_held(&msg->sip_msg_mutex)); #endif p = (char *)malloc(msg->sip_msg_len + 1); if (p == NULL) { if (error != 0) *error = ENOMEM; return (NULL); } e = p; /* * Get the start line */ if (msg->sip_msg_start_line != NULL) { len = msg->sip_msg_start_line->sip_hdr_end - msg->sip_msg_start_line->sip_hdr_start; (void) strncpy(e, msg->sip_msg_start_line->sip_hdr_start, len); e += len; #ifdef _DEBUG tlen += len; #endif } header = sip_search_for_header(msg, NULL, NULL); while (header != NULL) { if (header->sip_header_state != SIP_HEADER_DELETED) { if (header->sip_header_state == SIP_HEADER_DELETED_VAL) { len = sip_copy_values(e, header); } else { len = header->sip_hdr_end - header->sip_hdr_start; (void) strncpy(e, header->sip_hdr_start, len); } #ifdef _DEBUG tlen += len; assert(tlen <= msg->sip_msg_len); #endif } header = sip_search_for_header(msg, NULL, header); e += len; } sip_content = msg->sip_msg_content; while (sip_content != NULL) { len = sip_content->sip_content_end - sip_content->sip_content_start; #ifdef _DEBUG clen += len; assert(clen <= msg->sip_msg_content_len); tlen += len; assert(tlen <= msg->sip_msg_len); #endif (void) strncpy(e, sip_content->sip_content_start, len); e += len; sip_content = sip_content->sip_content_next; } p[msg->sip_msg_len] = '\0'; return (p); } /* * This is called just before sending the message to the transport. It * creates the sip_msg_buf from the SIP headers. */ int sip_adjust_msgbuf(_sip_msg_t *msg) { _sip_header_t *header; int ret; #ifdef _DEBUG int tlen = 0; int clen = 0; #endif if (msg == NULL) return (EINVAL); (void) pthread_mutex_lock(&msg->sip_msg_mutex); if ((msg->sip_msg_buf != NULL) && (!msg->sip_msg_modified)) { /* * We could just be forwarding the message we * received. */ (void) pthread_mutex_unlock(&msg->sip_msg_mutex); return (0); } /* * We are sending a new message or a message that we received * but have modified it. We keep the old * msgbuf till the message is freed as some * headers still point to it. */ assert(msg->sip_msg_old_buf == NULL); msg->sip_msg_old_buf = msg->sip_msg_buf; /* * We add the content-length header here, if it has not * already been added. */ header = sip_search_for_header(msg, SIP_CONTENT_LENGTH, NULL); if (header != NULL) { /* * Mark the previous header as deleted. */ header->sip_header_state = SIP_HEADER_DELETED; header->sip_hdr_sipmsg->sip_msg_len -= header->sip_hdr_end - header->sip_hdr_start; } (void) pthread_mutex_unlock(&msg->sip_msg_mutex); ret = sip_add_content_length(msg, msg->sip_msg_content_len); if (ret != 0) { (void) pthread_mutex_unlock(&msg->sip_msg_mutex); return (ret); } (void) pthread_mutex_lock(&msg->sip_msg_mutex); msg->sip_msg_modified = B_FALSE; msg->sip_msg_buf = sip_msg_to_msgbuf((sip_msg_t)msg, &ret); if (msg->sip_msg_buf == NULL) { (void) pthread_mutex_unlock(&msg->sip_msg_mutex); return (ret); } /* * Once the message has been sent it can not be modified * any furthur as we keep a pointer to it for retransmission */ msg->sip_msg_cannot_be_modified = B_TRUE; (void) pthread_mutex_unlock(&msg->sip_msg_mutex); return (0); } /* * Copy header values into ptr */ int sip_copy_values(char *ptr, _sip_header_t *header) { sip_header_value_t value; int tlen = 0; int len = 0; boolean_t first = B_TRUE; char *p = ptr; char *s; boolean_t crlf_present = B_FALSE; if (sip_parse_goto_values(header) != 0) return (0); len = header->sip_hdr_current - header->sip_hdr_start; (void) strncpy(p, header->sip_hdr_start, len); tlen += len; p += len; value = header->sip_hdr_parsed->value; while (value != NULL) { if (value->value_state != SIP_VALUE_DELETED) { crlf_present = B_FALSE; len = value->value_end - value->value_start; if (first) { (void) strncpy(p, value->value_start, len); first = B_FALSE; } else { s = value->value_start; while (*s != SIP_COMMA) s--; len += value->value_start - s; (void) strncpy(p, s, len); } tlen += len; p += len; s = value->value_end; while (s != value->value_start) { if (*s == '\r' && strncmp(s, SIP_CRLF, strlen(SIP_CRLF)) == 0) { crlf_present = B_TRUE; break; } s--; } } else { if (value->next == NULL && !first && !crlf_present) { s = value->value_end; while (*s != '\r') s--; len = value->value_end - s; (void) strncpy(p, s, len); tlen += len; p += len; } } value = value->next; } return (tlen); } /* * Add content (message body) to sip_msg */ int sip_add_content(sip_msg_t sip_msg, char *content) { size_t len; sip_content_t **loc; sip_content_t *msg_content; _sip_msg_t *_sip_msg; if (sip_msg == NULL || content == NULL || strlen(content) == 0) return (EINVAL); len = strlen(content); _sip_msg = (_sip_msg_t *)sip_msg; (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); if (_sip_msg->sip_msg_cannot_be_modified) { (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); return (ENOTSUP); } msg_content = calloc(1, sizeof (sip_content_t)); if (msg_content == NULL) { (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); return (ENOMEM); } msg_content->sip_content_start = malloc(strlen(content) + 1); if (msg_content->sip_content_start == NULL) { (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); free(msg_content); return (ENOMEM); } (void) strncpy(msg_content->sip_content_start, content, strlen(content)); msg_content->sip_content_start[strlen(content)] = '\0'; msg_content->sip_content_current = msg_content->sip_content_start; msg_content->sip_content_end = msg_content->sip_content_start + strlen(msg_content->sip_content_start); msg_content->sip_content_allocated = B_TRUE; loc = &_sip_msg->sip_msg_content; while (*loc != NULL) loc = &((*loc)->sip_content_next); *loc = msg_content; _sip_msg->sip_msg_content_len += len; _sip_msg->sip_msg_len += len; if (_sip_msg->sip_msg_buf != NULL) _sip_msg->sip_msg_modified = B_TRUE; (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); return (0); } /* * Free the message content */ void sip_free_content(_sip_msg_t *sip_msg) { sip_content_t *content; if (sip_msg == NULL) return; content = sip_msg->sip_msg_content; while (content != NULL) { sip_content_t *content_tmp; content_tmp = content; content = content->sip_content_next; if (content_tmp->sip_content_allocated) free(content_tmp->sip_content_start); free(content_tmp); } sip_msg->sip_msg_content = NULL; } /* * Add a response line to sip_response */ int sip_add_response_line(sip_msg_t sip_response, int response, char *response_code) { _sip_header_t *new_header; int header_size; _sip_msg_t *_sip_response; int ret; if (sip_response == NULL || response < 0 || response_code == NULL) return (EINVAL); _sip_response = (_sip_msg_t *)sip_response; (void) pthread_mutex_lock(&_sip_response->sip_msg_mutex); if (_sip_response->sip_msg_cannot_be_modified) { (void) pthread_mutex_unlock(&_sip_response->sip_msg_mutex); return (ENOTSUP); } header_size = strlen(SIP_VERSION) + SIP_SPACE_LEN + SIP_SIZE_OF_STATUS_CODE + SIP_SPACE_LEN + strlen(response_code) + strlen(SIP_CRLF); new_header = sip_new_header(header_size); if (new_header == NULL) { (void) pthread_mutex_unlock(&_sip_response->sip_msg_mutex); return (ENOMEM); } new_header->sip_hdr_sipmsg = _sip_response; (void) snprintf(new_header->sip_hdr_start, header_size + 1, SIP_RESPONSE, SIP_VERSION, response, response_code, SIP_CRLF); new_header->sip_hdr_next = _sip_response->sip_msg_start_line; _sip_response->sip_msg_start_line = new_header; _sip_response->sip_msg_len += header_size; ret = sip_parse_first_line(_sip_response->sip_msg_start_line, &_sip_response->sip_msg_req_res); if (_sip_response->sip_msg_buf != NULL) _sip_response->sip_msg_modified = B_TRUE; (void) pthread_mutex_unlock(&_sip_response->sip_msg_mutex); return (ret); } /* * create a response based on the sip_request. * Copies Call-ID, CSeq, From, To and Via headers from the request. */ sip_msg_t sip_create_response(sip_msg_t sip_request, int response, char *response_code, char *totag, char *mycontact) { _sip_msg_t *new_msg; _sip_msg_t *_sip_request; boolean_t ttag_present; if (sip_request == NULL || response_code == NULL) return (NULL); ttag_present = sip_get_to_tag(sip_request, NULL) != NULL; new_msg = (_sip_msg_t *)sip_new_msg(); if (new_msg == NULL) return (NULL); _sip_request = (_sip_msg_t *)sip_request; (void) pthread_mutex_lock(&_sip_request->sip_msg_mutex); /* * Add response line. */ if (sip_add_response_line(new_msg, response, response_code) != 0) goto error; /* * Copy Via headers */ if (_sip_find_and_copy_all_header(_sip_request, new_msg, SIP_VIA) != 0) goto error; /* * Copy From header. */ if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_FROM, NULL, B_FALSE)) { goto error; } /* * Copy To header. If To tag is present, copy it, if not then * add one if the repsonse is not provisional. */ if (ttag_present || (totag == NULL && response == SIP_TRYING)) { if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_TO, NULL, B_FALSE)) { goto error; } } else { char *xtra_param; boolean_t tag_alloc = B_FALSE; int taglen; if (totag == NULL) { totag = sip_guid(); if (totag == NULL) goto error; tag_alloc = B_TRUE; } taglen = strlen(SIP_TAG) + strlen(totag) + 1; xtra_param = (char *)malloc(taglen); if (xtra_param == NULL) { if (tag_alloc) free(totag); goto error; } (void) snprintf(xtra_param, taglen, "%s%s", SIP_TAG, totag); if (tag_alloc) free(totag); if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_TO, xtra_param, B_FALSE)) { free(xtra_param); goto error; } free(xtra_param); } /* * Copy Call-ID header. */ if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_CALL_ID, NULL, B_FALSE)) { goto error; } /* * Copy CSEQ header */ if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_CSEQ, NULL, B_FALSE)) { goto error; } /* * Copy RECORD-ROUTE header, if present. */ if (sip_search_for_header(_sip_request, SIP_RECORD_ROUTE, NULL) != NULL) { if (_sip_find_and_copy_all_header(_sip_request, new_msg, SIP_RECORD_ROUTE) != 0) { goto error; } } if (mycontact != NULL) { if (sip_add_contact(new_msg, NULL, mycontact, B_FALSE, NULL) != 0) { goto error; } } (void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex); return ((sip_msg_t)new_msg); error: sip_free_msg((sip_msg_t)new_msg); (void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex); return (NULL); } /* * NON OK ACK : MUST contain values for the Call-ID, From, and Request-URI * that are equal to the values of those header fields in the orig request * passed to the transport. The To header field in the ACK MUST equal the To * header field in the response being acknowledged. The ACK MUST contain the * top Via header field of the original request. The CSeq header field in * the ACK MUST contain the same value for the sequence number as was * present in the original request, but the method parameter MUST be equal * to "ACK". */ int sip_create_nonOKack(sip_msg_t request, sip_msg_t response, sip_msg_t ack_msg) { int seqno; char *uri; _sip_msg_t *_request; _sip_msg_t *_response; _sip_msg_t *_ack_msg; int ret; if (request == NULL || response == NULL || ack_msg == NULL || request == ack_msg) { return (EINVAL); } _request = (_sip_msg_t *)request; _response = (_sip_msg_t *)response; _ack_msg = (_sip_msg_t *)ack_msg; (void) pthread_mutex_lock(&_request->sip_msg_mutex); if (_request->sip_msg_req_res == NULL) { if ((ret = sip_parse_first_line(_request->sip_msg_start_line, &_request->sip_msg_req_res)) != 0) { (void) pthread_mutex_unlock(&_request->sip_msg_mutex); return (ret); } } if (_request->sip_msg_req_res->U.sip_request.sip_request_uri. sip_str_ptr == NULL) { (void) pthread_mutex_unlock(&_request->sip_msg_mutex); return (EINVAL); } uri = (char *)malloc(_request->sip_msg_req_res->U.sip_request. sip_request_uri.sip_str_len + 1); if (uri == NULL) { (void) pthread_mutex_unlock(&_request->sip_msg_mutex); return (EINVAL); } (void) strncpy(uri, _request->sip_msg_req_res->U.sip_request.sip_request_uri. sip_str_ptr, _request->sip_msg_req_res->U.sip_request. sip_request_uri.sip_str_len); uri[_request->sip_msg_req_res->U.sip_request. sip_request_uri.sip_str_len] = '\0'; if ((ret = sip_add_request_line(_ack_msg, ACK, uri)) != 0) { (void) pthread_mutex_unlock(&_request->sip_msg_mutex); return (ret); } free(uri); if ((ret = _sip_find_and_copy_header(_request, _ack_msg, SIP_VIA, NULL, B_TRUE)) != 0) { (void) pthread_mutex_unlock(&_request->sip_msg_mutex); return (ret); } (void) _sip_find_and_copy_header(_request, _ack_msg, SIP_MAX_FORWARDS, NULL, B_TRUE); (void) pthread_mutex_lock(&_response->sip_msg_mutex); if ((ret = _sip_find_and_copy_header(_response, _ack_msg, SIP_TO, NULL, B_TRUE)) != 0) { (void) pthread_mutex_unlock(&_response->sip_msg_mutex); return (ret); } (void) pthread_mutex_unlock(&_response->sip_msg_mutex); if ((ret = _sip_find_and_copy_header(_request, _ack_msg, SIP_FROM, NULL, B_TRUE)) != 0) { (void) pthread_mutex_unlock(&_request->sip_msg_mutex); return (ret); } if ((ret = _sip_find_and_copy_header(_request, _ack_msg, SIP_CALL_ID, NULL, B_TRUE)) != 0) { (void) pthread_mutex_unlock(&_request->sip_msg_mutex); return (ret); } (void) pthread_mutex_unlock(&_request->sip_msg_mutex); seqno = sip_get_callseq_num(_request, &ret); if (ret != 0) return (ret); if ((ret = sip_add_cseq(_ack_msg, ACK, seqno)) != 0) return (ret); if ((ret = sip_adjust_msgbuf(_ack_msg)) != 0) return (ret); return (0); } /* * This is a 2XX ACK, for others ACK is constructed differently, * esp. the branch id is retained. */ int sip_create_OKack(sip_msg_t response, sip_msg_t ack_msg, char *transport, char *sent_by, int sent_by_port, char *via_params) { int seqno; char *uri; sip_parsed_header_t *parsed_header; sip_hdr_value_t *contact_value; _sip_header_t *header; _sip_msg_t *_response; _sip_msg_t *_ack_msg; int ret; if (response == NULL || response == NULL || transport == NULL) return (EINVAL); _response = (_sip_msg_t *)response; _ack_msg = (_sip_msg_t *)ack_msg; /* * Get URI from the response, Contact field */ (void) pthread_mutex_lock(&_response->sip_msg_mutex); if ((header = sip_search_for_header(_response, SIP_CONTACT, NULL)) == NULL) { (void) pthread_mutex_unlock(&_response->sip_msg_mutex); return (EINVAL); } if ((ret = sip_parse_cftr_header(header, (void *)&parsed_header)) != 0) { (void) pthread_mutex_unlock(&_response->sip_msg_mutex); return (ret); } contact_value = (sip_hdr_value_t *)parsed_header->value; if (contact_value->cftr_uri.sip_str_ptr == NULL) { (void) pthread_mutex_unlock(&_response->sip_msg_mutex); return (EINVAL); } uri = (char *)malloc(contact_value->cftr_uri.sip_str_len + 1); if (uri == NULL) { (void) pthread_mutex_unlock(&_response->sip_msg_mutex); return (ENOMEM); } (void) strncpy(uri, contact_value->cftr_uri.sip_str_ptr, contact_value->cftr_uri.sip_str_len); uri[contact_value->cftr_uri.sip_str_len] = '\0'; if ((ret = sip_add_request_line(_ack_msg, ACK, uri)) != 0) { (void) pthread_mutex_unlock(&_response->sip_msg_mutex); return (ret); } free(uri); if ((ret = sip_add_via(_ack_msg, transport, sent_by, sent_by_port, via_params)) != 0) { (void) pthread_mutex_unlock(&_response->sip_msg_mutex); return (ret); } if ((ret = _sip_find_and_copy_header(_response, _ack_msg, SIP_TO, NULL, B_TRUE)) != 0) { (void) pthread_mutex_unlock(&_response->sip_msg_mutex); return (ret); } if ((ret = _sip_find_and_copy_header(_response, _ack_msg, SIP_FROM, NULL, B_TRUE)) != 0) { (void) pthread_mutex_unlock(&_response->sip_msg_mutex); return (ret); } if ((ret = _sip_find_and_copy_header(_response, _ack_msg, SIP_CALL_ID, NULL, B_TRUE)) != 0) { (void) pthread_mutex_unlock(&_response->sip_msg_mutex); return (ret); } /* * Copy Max-Forward if present */ if (sip_search_for_header(_response, SIP_MAX_FORWARDS, NULL) != NULL) { if ((ret = _sip_find_and_copy_header(_response, _ack_msg, SIP_MAX_FORWARDS, NULL, B_TRUE)) != 0) { (void) pthread_mutex_unlock(&_response->sip_msg_mutex); return (ret); } } (void) pthread_mutex_unlock(&_response->sip_msg_mutex); seqno = sip_get_callseq_num(_response, &ret); if (ret != 0) return (ret); if ((ret = sip_add_cseq(_ack_msg, ACK, seqno)) != 0) return (ret); return (0); } /* * Request-Line = Method SP Request-URI SP SIP-Version CRLF */ int sip_add_request_line(sip_msg_t sip_request, sip_method_t method, char *request_uri) { _sip_header_t *new_header; int header_size; _sip_msg_t *_sip_request; if (method < INVITE || method >= MAX_SIP_METHODS || request_uri == NULL || sip_request == NULL) { return (EINVAL); } _sip_request = (_sip_msg_t *)sip_request; (void) pthread_mutex_lock(&_sip_request->sip_msg_mutex); if (_sip_request->sip_msg_cannot_be_modified) { (void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex); return (ENOTSUP); } header_size = strlen(sip_methods[method].name) + SIP_SPACE_LEN + strlen(request_uri) + SIP_SPACE_LEN + strlen(SIP_VERSION) + strlen(SIP_CRLF); new_header = sip_new_header(header_size); if (new_header == NULL) { (void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex); return (ENOMEM); } new_header->sip_hdr_sipmsg = _sip_request; (void) snprintf(new_header->sip_hdr_start, header_size + 1, "%s %s %s%s", sip_methods[method].name, request_uri, SIP_VERSION, SIP_CRLF); new_header->sip_hdr_next = _sip_request->sip_msg_start_line; _sip_request->sip_msg_start_line = new_header; _sip_request->sip_msg_len += header_size; (void) sip_parse_first_line(_sip_request->sip_msg_start_line, &_sip_request->sip_msg_req_res); if (_sip_request->sip_msg_buf != NULL) _sip_request->sip_msg_modified = B_TRUE; (void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex); return (0); }