📄 sip_msg.c
字号:
/* * 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 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */#pragma ident "@(#)sip_msg.c 1.58 06/08/16 SMI"#include"sip_msg.h"#include "sip_miscdefs.h"#include "sip_parse_generic.h"#define SIP_RESPONSE "%s %d %s%s"#define SIP_REQUEST "%s %s%s"/* list of sent-by values registered by the UA */sent_by_list_t *sip_sent_by = NULL;int sip_sent_by_count = 0;static int sip_add_name_aspec(_sip_msg_t *, char *, char *, char *, boolean_t, char *, char *);/* Allocate a new sip msg struct. */sip_msg_tsip_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);}/* Copy header values into ptr */intsip_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 *e; 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) { len = value->value_end - value->value_start; if (first) { (void) strncpy(p, value->value_start, len); first = B_FALSE; } else { e = value->value_start; while (*e != SIP_COMMA) e--; len += value->value_start - e; (void) strncpy(p, e, len); } tlen += len; p += len; } value = value->next; } return (tlen);}/* Returns number of bytes in the given int */static intsip_num_of_bytes(int num){ int num_of_bytes = 0; do { num_of_bytes += 1; num = num / 10; } while (num > 0); return (num_of_bytes);}/* * This is called just before sending the message to the transport. It * creates the sip_msg_buf from the SIP headers. */intsip_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_lock(&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);}/* Free the message content */voidsip_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;}/* Free all resources */voidsip_destroy_msg(_sip_msg_t *_sip_msg){ (void) sip_delete_start_line(_sip_msg); (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 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_type_ptr->is_request) { sip_request_t *reqline; reqline = &sip_msg_type_ptr->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_unlock(&_sip_msg->sip_msg_mutex); free(_sip_msg);}/* Free a sip msg struct. */voidsip_free_msg(sip_msg_t sip_msg){ _sip_msg_t *msg; if (sip_msg == NULL) return; msg = (_sip_msg_t *)sip_msg; SIP_MSG_REFCNT_DECR(msg);}/* Hold a sip msg struct. */voidsip_hold_msg(sip_msg_t sip_msg){ _sip_msg_t *msg; if (sip_msg == NULL) return; msg = (_sip_msg_t *)sip_msg; SIP_MSG_REFCNT_INCR(msg);}/* Check if the message can be modified. */boolean_tsip_ok_to_modify_message(_sip_msg_t *_sip_msg){ if (_sip_msg == NULL) return (B_FALSE);#ifdef __solaris__ assert(mutex_held(&_sip_msg->sip_msg_mutex));#endif if (_sip_msg->sip_msg_cannot_be_modified) return (B_FALSE); if (_sip_msg->sip_msg_buf != NULL) _sip_msg->sip_msg_modified = B_TRUE; return (B_TRUE);}/* Add a response line to sip_response */intsip_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_ok_to_modify_message(_sip_response)) { (void) pthread_mutex_unlock(&_sip_response->sip_msg_mutex); return (ENOTSUP); } header_size = strlen(SIP_VERSION) + SIP_SPACE + SIP_SIZE_OF_STATUS_CODE + SIP_SPACE + 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); (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_tsip_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)) { 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)) { 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)) { 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)) goto error; /* * Copy CSEQ header */ if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_CSEQ, NULL)) 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);}/* Add quotes to the give str and return the quoted string */static char *sip_add_aquot_to_str(char *str, boolean_t *alloc){ char *new_str; char *tmp = str; int size; while (isspace(*tmp)) tmp++; *alloc = B_FALSE; if (*tmp != SIP_LAQUOT) { size = strlen(str) + 2 * sizeof (char); new_str = calloc(1, size + 1); if (new_str == NULL) return (NULL); new_str[0] = SIP_LAQUOT; new_str[1] = '\0'; (void) strncat(new_str, str, strlen(str)); (void) strncat(new_str, ">", 1); new_str[size] = '\0'; *alloc = B_TRUE; return (new_str); } return (str);}/* Add an empty header */static intsip_add_empty_hdr(sip_msg_t sip_msg, char *hdr_name){ _sip_header_t *new_header; int header_size; _sip_msg_t *_sip_msg; int csize = sizeof (char); if (sip_msg == NULL || hdr_name == NULL) return (EINVAL); _sip_msg = (_sip_msg_t *)sip_msg; (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); if (!sip_ok_to_modify_message(_sip_msg)) { (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); return (ENOTSUP); } header_size = strlen(hdr_name) + SIP_SPACE + csize; new_header = sip_new_header(header_size); if (new_header == NULL) { (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); return (ENOMEM); } (void) snprintf(new_header->sip_hdr_start, header_size + 1, "%s %c", hdr_name, SIP_HCOLON); _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, hdr_name); (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); return (0);}/* Generic function to add a header with two strings to message */static intsip_add_2strs_to_msg(sip_msg_t sip_msg, char *hdr_name, char *str1, boolean_t qstr1, char *str2, char *plist, char sep)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -