📄 sip_msg.c
字号:
/* $Id: sip_msg.c 1219 2007-04-28 15:35:01Z 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 + -