⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sip_msg.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $Id: sip_msg.c 1121 2007-04-01 22:58:47Z bennylp $ */
/* 
 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */
#include <pjsip/sip_msg.h>
#include <pjsip/sip_parser.h>
#include <pjsip/print_util.h>
#include <pjsip/sip_errno.h>
#include <pj/string.h>
#include <pj/pool.h>
#include <pj/assert.h>

const pjsip_method 
    pjsip_invite_method	    = { PJSIP_INVITE_METHOD,	{ "INVITE",6 }	},
    pjsip_cancel_method	    = { PJSIP_CANCEL_METHOD,	{ "CANCEL",6 }	},
    pjsip_ack_method	    = { PJSIP_ACK_METHOD,	{ "ACK",3}	},
    pjsip_bye_method	    = { PJSIP_BYE_METHOD,	{ "BYE",3}	},
    pjsip_register_method   = { PJSIP_REGISTER_METHOD,	{ "REGISTER",8}	},
    pjsip_options_method    = { PJSIP_OPTIONS_METHOD,	{ "OPTIONS",7}	};

static const pj_str_t *method_names[] = 
{
    &pjsip_invite_method.name,
    &pjsip_cancel_method.name,
    &pjsip_ack_method.name,
    &pjsip_bye_method.name,
    &pjsip_register_method.name,
    &pjsip_options_method.name
};

const pj_str_t pjsip_hdr_names[] = 
{
    { "Accept",		     6 },   // PJSIP_H_ACCEPT,
    { "Accept-Encoding",    15 },   // PJSIP_H_ACCEPT_ENCODING,
    { "Accept-Language",    15 },   // PJSIP_H_ACCEPT_LANGUAGE,
    { "Alert-Info",	    10 },   // PJSIP_H_ALERT_INFO,
    { "Allow",		     5 },   // PJSIP_H_ALLOW,
    { "Authentication-Info",19 },   // PJSIP_H_AUTHENTICATION_INFO,
    { "Authorization",	    13 },   // PJSIP_H_AUTHORIZATION,
    { "Call-ID",	     7 },   // PJSIP_H_CALL_ID,
    { "Call-Info",	     9 },   // PJSIP_H_CALL_INFO,
    { "Contact",	     7 },   // PJSIP_H_CONTACT,
    { "Content-Disposition",19 },   // PJSIP_H_CONTENT_DISPOSITION,
    { "Content-Encoding",   16 },   // PJSIP_H_CONTENT_ENCODING,
    { "Content-Language",   16 },   // PJSIP_H_CONTENT_LANGUAGE,
    { "Content-Length",	    14 },   // PJSIP_H_CONTENT_LENGTH,
    { "Content-Type",	    12 },   // PJSIP_H_CONTENT_TYPE,
    { "CSeq",		     4 },   // PJSIP_H_CSEQ,
    { "Date",		     4 },   // PJSIP_H_DATE,
    { "Error-Info",	    10 },   // PJSIP_H_ERROR_INFO,
    { "Expires",	     7 },   // PJSIP_H_EXPIRES,
    { "From",		     4 },   // PJSIP_H_FROM,
    { "In-Reply-To",	    11 },   // PJSIP_H_IN_REPLY_TO,
    { "Max-Forwards",	    12 },   // PJSIP_H_MAX_FORWARDS,
    { "MIME-Version",	    12 },   // PJSIP_H_MIME_VERSION,
    { "Min-Expires",	    11 },   // PJSIP_H_MIN_EXPIRES,
    { "Organization",	    12 },   // PJSIP_H_ORGANIZATION,
    { "Priority",	     8 },   // PJSIP_H_PRIORITY,
    { "Proxy-Authenticate", 18 },   // PJSIP_H_PROXY_AUTHENTICATE,
    { "Proxy-Authorization",19 },   // PJSIP_H_PROXY_AUTHORIZATION,
    { "Proxy-Require",	    13 },   // PJSIP_H_PROXY_REQUIRE,
    { "Record-Route",	    12 },   // PJSIP_H_RECORD_ROUTE,
    { "Reply-To",	     8 },   // PJSIP_H_REPLY_TO,
    { "Require",	     7 },   // PJSIP_H_REQUIRE,
    { "Retry-After",	    11 },   // PJSIP_H_RETRY_AFTER,
    { "Route",		     5 },   // PJSIP_H_ROUTE,
    { "Server",		     6 },   // PJSIP_H_SERVER,
    { "Subject",	     7 },   // PJSIP_H_SUBJECT,
    { "Supported",	     9 },   // PJSIP_H_SUPPORTED,
    { "Timestamp",	     9 },   // PJSIP_H_TIMESTAMP,
    { "To",		     2 },   // PJSIP_H_TO,
    { "Unsupported",	    11 },   // PJSIP_H_UNSUPPORTED,
    { "User-Agent",	    10 },   // PJSIP_H_USER_AGENT,
    { "Via",		     3 },   // PJSIP_H_VIA,
    { "Warning",	     7 },   // PJSIP_H_WARNING,
    { "WWW-Authenticate",   16 },   // PJSIP_H_WWW_AUTHENTICATE,

    { "_Unknown-Header",    15 },   // PJSIP_H_OTHER,
};

static pj_str_t status_phrase[710];
static int print_media_type(char *buf, const pjsip_media_type *media);

static int init_status_phrase()
{
    int i;
    pj_str_t default_reason_phrase = { "Default status message", 22};

    for (i=0; i<PJ_ARRAY_SIZE(status_phrase); ++i)
	status_phrase[i] = default_reason_phrase;

    pj_strset2( &status_phrase[100], "Trying");
    pj_strset2( &status_phrase[180], "Ringing");
    pj_strset2( &status_phrase[181], "Call Is Being Forwarded");
    pj_strset2( &status_phrase[182], "Queued");
    pj_strset2( &status_phrase[183], "Session Progress");

    pj_strset2( &status_phrase[200], "OK");
    pj_strset2( &status_phrase[202], "Accepted");

    pj_strset2( &status_phrase[300], "Multiple Choices");
    pj_strset2( &status_phrase[301], "Moved Permanently");
    pj_strset2( &status_phrase[302], "Moved Temporarily");
    pj_strset2( &status_phrase[305], "Use Proxy");
    pj_strset2( &status_phrase[380], "Alternative Service");

    pj_strset2( &status_phrase[400], "Bad Request");
    pj_strset2( &status_phrase[401], "Unauthorized");
    pj_strset2( &status_phrase[402], "Payment Required");
    pj_strset2( &status_phrase[403], "Forbidden");
    pj_strset2( &status_phrase[404], "Not Found");
    pj_strset2( &status_phrase[405], "Method Not Allowed");
    pj_strset2( &status_phrase[406], "Not Acceptable");
    pj_strset2( &status_phrase[407], "Proxy Authentication Required");
    pj_strset2( &status_phrase[408], "Request Timeout");
    pj_strset2( &status_phrase[410], "Gone");
    pj_strset2( &status_phrase[413], "Request Entity Too Large");
    pj_strset2( &status_phrase[414], "Request URI Too Long");
    pj_strset2( &status_phrase[415], "Unsupported Media Type");
    pj_strset2( &status_phrase[416], "Unsupported URI Scheme");
    pj_strset2( &status_phrase[420], "Bad Extension");
    pj_strset2( &status_phrase[421], "Extension Required");
    pj_strset2( &status_phrase[422], "Session Timer Too Small");
    pj_strset2( &status_phrase[423], "Interval Too Brief");
    pj_strset2( &status_phrase[480], "Temporarily Unavailable");
    pj_strset2( &status_phrase[481], "Call/Transaction Does Not Exist");
    pj_strset2( &status_phrase[482], "Loop Detected");
    pj_strset2( &status_phrase[483], "Too Many Hops");
    pj_strset2( &status_phrase[484], "Address Incompleted");
    pj_strset2( &status_phrase[485], "Ambiguous");
    pj_strset2( &status_phrase[486], "Busy Here");
    pj_strset2( &status_phrase[487], "Request Terminated");
    pj_strset2( &status_phrase[488], "Not Acceptable Here");
    pj_strset2( &status_phrase[489], "Bad Event");
    pj_strset2( &status_phrase[490], "Request Updated");
    pj_strset2( &status_phrase[491], "Request Pending");
    pj_strset2( &status_phrase[493], "Undecipherable");

    pj_strset2( &status_phrase[500], "Internal Server Error");
    pj_strset2( &status_phrase[501], "Not Implemented");
    pj_strset2( &status_phrase[502], "Bad Gateway");
    pj_strset2( &status_phrase[503], "Service Unavailable");
    pj_strset2( &status_phrase[504], "Server Timeout");
    pj_strset2( &status_phrase[505], "Version Not Supported");
    pj_strset2( &status_phrase[513], "Message Too Large");
    pj_strset2( &status_phrase[580], "Precondition Failure");

    pj_strset2( &status_phrase[600], "Busy Everywhere");
    pj_strset2( &status_phrase[603], "Decline");
    pj_strset2( &status_phrase[604], "Does Not Exist Anywhere");
    pj_strset2( &status_phrase[606], "Not Acceptable");

    pj_strset2( &status_phrase[701], "No response from destination server");
    pj_strset2( &status_phrase[702], "Unable to resolve destination server");
    pj_strset2( &status_phrase[703], "Error sending message to destination server");

    return 1;
}

///////////////////////////////////////////////////////////////////////////////
/*
 * Method.
 */

PJ_DEF(void) pjsip_method_init( pjsip_method *m, 
			        pj_pool_t *pool, 
			        const pj_str_t *str)
{
    pj_str_t dup;
    pjsip_method_init_np(m, pj_strdup(pool, &dup, str));
}

PJ_DEF(void) pjsip_method_set( pjsip_method *m, pjsip_method_e me )
{
    pj_assert(me < PJSIP_OTHER_METHOD);
    m->id = me;
    m->name = *method_names[me];
}

PJ_DEF(void) pjsip_method_init_np(pjsip_method *m,
				  pj_str_t *str)
{
    int i;
    for (i=0; i<PJ_ARRAY_SIZE(method_names); ++i) {
	if (pj_memcmp(str->ptr, method_names[i]->ptr, str->slen)==0 || 
	    pj_stricmp(str, method_names[i])==0) 
	{
	    m->id = (pjsip_method_e)i;
	    m->name = *method_names[i];
	    return;
	}
    }
    m->id = PJSIP_OTHER_METHOD;
    m->name = *str;
}

PJ_DEF(void) pjsip_method_copy( pj_pool_t *pool,
				pjsip_method *method,
				const pjsip_method *rhs )
{
    method->id = rhs->id;
    if (rhs->id != PJSIP_OTHER_METHOD) {
	method->name = rhs->name;
    } else {
	pj_strdup(pool, &method->name, &rhs->name);
    }
}


PJ_DEF(int) pjsip_method_cmp( const pjsip_method *m1, const pjsip_method *m2)
{
    if (m1->id == m2->id) {
	if (m1->id != PJSIP_OTHER_METHOD)
	    return 0;
	/* Method comparison is case sensitive! */
	return pj_strcmp(&m1->name, &m2->name);
    }
    
    return ( m1->id < m2->id ) ? -1 : 1;
}

///////////////////////////////////////////////////////////////////////////////
/*
 * Message.
 */

PJ_DEF(pjsip_msg*) pjsip_msg_create( pj_pool_t *pool, pjsip_msg_type_e type)
{
    pjsip_msg *msg = pj_pool_alloc(pool, sizeof(pjsip_msg));
    pj_list_init(&msg->hdr);
    msg->type = type;
    msg->body = NULL;
    return msg;
}

PJ_DEF(pjsip_msg*) pjsip_msg_clone( pj_pool_t *pool, const pjsip_msg *src)
{
    pjsip_msg *dst;
    const pjsip_hdr *sh;

    dst = pjsip_msg_create(pool, src->type);

    /* Clone request/status line */
    if (src->type == PJSIP_REQUEST_MSG) {
	pjsip_method_copy(pool, &dst->line.req.method, &src->line.req.method);
	dst->line.req.uri = pjsip_uri_clone(pool, src->line.req.uri);
    } else {
	dst->line.status.code = src->line.status.code;
	pj_strdup(pool, &dst->line.status.reason, &src->line.status.reason);
    }

    /* Clone headers */
    sh = src->hdr.next;
    while (sh != &src->hdr) {
	pjsip_hdr *dh = pjsip_hdr_clone(pool, sh);
	pjsip_msg_add_hdr(dst, dh);
	sh = sh->next;
    }

    /* Clone message body */
    if (src->body) {
	dst->body = pjsip_msg_body_clone(pool, src->body);
    }

    return dst;
}

PJ_DEF(void*)  pjsip_msg_find_hdr( const pjsip_msg *msg, 
				   pjsip_hdr_e hdr_type, const void *start)
{
    const pjsip_hdr *hdr=start, *end=&msg->hdr;

    if (hdr == NULL) {
	hdr = msg->hdr.next;
    }
    for (; hdr!=end; hdr = hdr->next) {
	if (hdr->type == hdr_type)
	    return (void*)hdr;
    }
    return NULL;
}

PJ_DEF(void*)  pjsip_msg_find_hdr_by_name( const pjsip_msg *msg, 
					   const pj_str_t *name, 
					   const void *start)
{
    const pjsip_hdr *hdr=start, *end=&msg->hdr;

    if (hdr == NULL) {
	hdr = msg->hdr.next;
    }
    for (; hdr!=end; hdr = hdr->next) {
	if (hdr->type < PJSIP_H_OTHER) {
	    if (pj_stricmp(&pjsip_hdr_names[hdr->type], name) == 0)
		return (void*)hdr;
	} else {
	    if (pj_stricmp(&hdr->name, name) == 0)
		return (void*)hdr;
	}
    }
    return NULL;
}

PJ_DEF(void*) pjsip_msg_find_remove_hdr( pjsip_msg *msg, 
				         pjsip_hdr_e hdr_type, void *start)
{
    pjsip_hdr *hdr = pjsip_msg_find_hdr(msg, hdr_type, start);
    if (hdr) {
	pj_list_erase(hdr);
    }
    return hdr;
}

PJ_DEF(pj_ssize_t) pjsip_msg_print( const pjsip_msg *msg, 
				    char *buf, pj_size_t size)
{
    char *p=buf, *end=buf+size;
    int len;
    pjsip_hdr *hdr;
    pj_str_t clen_hdr =  { "Content-Length: ", 16};

    /* Get a wild guess on how many bytes are typically needed.
     * We'll check this later in detail, but this serves as a quick check.
     */
    if (size < 256)
	return -1;

    /* Print request line or status line depending on message type */
    if (msg->type == PJSIP_REQUEST_MSG) {
	pjsip_uri *uri;

	/* Add method. */
	len = msg->line.req.method.name.slen;
	pj_memcpy(p, msg->line.req.method.name.ptr, len);
	p += len;
	*p++ = ' ';

	/* Add URI */
	uri = pjsip_uri_get_uri(msg->line.req.uri);
	len = pjsip_uri_print( PJSIP_URI_IN_REQ_URI, uri, p, end-p);
	if (len < 1)
	    return -1;
	p += len;

	/* Add ' SIP/2.0' */
	if (end-p < 16)
	    return -1;
	pj_memcpy(p, " SIP/2.0\r\n", 10);
	p += 10;

    } else {

	/* Add 'SIP/2.0 ' */
	pj_memcpy(p, "SIP/2.0 ", 8);
	p += 8;

	/* Add status code. */
	len = pj_utoa(msg->line.status.code, p);
	p += len;
	*p++ = ' ';

	/* Add reason text. */
	len = msg->line.status.reason.slen;
	pj_memcpy(p, msg->line.status.reason.ptr, len );
	p += len;

	/* Add newline. */
	*p++ = '\r';
	*p++ = '\n';
    }

    /* Print each of the headers. */
    for (hdr=msg->hdr.next; hdr!=&msg->hdr; hdr=hdr->next) {
	len = (*hdr->vptr->print_on)(hdr, p, end-p);
	if (len < 1)
	    return -1;
	p += len;

	if (p+3 >= end)
	    return -1;

	*p++ = '\r';
	*p++ = '\n';
    }

    /* Process message body. */
    if (msg->body) {
	enum { CLEN_SPACE = 5 };
	char *clen_pos = NULL;

	/* Automaticly adds Content-Type and Content-Length headers, only
	 * if content_type is set in the message body.
	 */
	if (msg->body->content_type.type.slen) {
	    pj_str_t ctype_hdr = { "Content-Type: ", 14};
	    const pjsip_media_type *media = &msg->body->content_type;

	    /* Add Content-Type header. */
	    if ( (end-p) < 24 + media->type.slen + media->subtype.slen + 
			   media->param.slen) 
	    {
		return -1;
	    }
	    pj_memcpy(p, ctype_hdr.ptr, ctype_hdr.slen);
	    p += ctype_hdr.slen;
	    p += print_media_type(p, media);
	    *p++ = '\r';
	    *p++ = '\n';

	    /* Add Content-Length header. */
	    if ((end-p) < clen_hdr.slen + 12 + 2) {
		return -1;
	    }
	    pj_memcpy(p, clen_hdr.ptr, clen_hdr.slen);
	    p += clen_hdr.slen;
	    
	    /* Print blanks after "Content-Length:", this is where we'll put
	     * the content length value after we know the length of the
	     * body.
	     */
	    pj_memset(p, ' ', CLEN_SPACE);
	    clen_pos = p;
	    p += CLEN_SPACE;
	    *p++ = '\r';
	    *p++ = '\n';
	}
	
	/* Add blank newline. */
	*p++ = '\r';
	*p++ = '\n';

	/* Print the message body itself. */
	len = (*msg->body->print_body)(msg->body, p, end-p);
	if (len < 0) {
	    return -1;
	}
	p += len;

	/* Now that we have the length of the body, print this to the
	 * Content-Length header.
	 */
	if (clen_pos) {
	    char tmp[16];
	    len = pj_utoa(len, tmp);
	    if (len > CLEN_SPACE) len = CLEN_SPACE;
	    pj_memcpy(clen_pos+CLEN_SPACE-len, tmp, len);
	}

    } else {
	/* There's no message body.
	 * Add Content-Length with zero value.
	 */
	if ((end-p) < clen_hdr.slen+8) {
	    return -1;
	}
	pj_memcpy(p, clen_hdr.ptr, clen_hdr.slen);
	p += clen_hdr.slen;
	*p++ = ' ';
	*p++ = '0';
	*p++ = '\r';

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -