📄 sip_basic.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE sip_basic.c * @brief Basic SIP headers. * * Implementation of header classes for basic SIP headers, like request and * status lines, payload, @CallID, @CSeq, @Contact, @ContentLength, @Date, * @Expires, @From, @Route, @RecordRoute, @To, and @Via. * * @author Pekka Pessi <Pekka.Pessi@nokia.com>. * * @date Created: Tue Jun 13 02:57:51 2000 ppessi */#include "config.h"/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */#define MSG_PUB_T struct sip_s#define MSG_HDR_T union sip_header_u#include <sofia-sip/su_alloc.h>#include <sofia-sip/string0.h>#include "sofia-sip/sip_parser.h"#include <sofia-sip/sip_util.h>#include <sofia-sip/sip_status.h>#include <sofia-sip/msg_date.h>#include <sofia-sip/su_uniqueid.h>#include <stddef.h>#include <stdlib.h>#include <assert.h>#include <stdio.h>#include <stdarg.h>#include <limits.h>/* ====================================================================== *//**@SIP_HEADER sip_request Request Line * * The request line is first line in a SIP request message. Its syntax defined * in @RFC3261 as follows: * * @code * Request-Line = Method SP Request-URI SP SIP-Version CRLF * Request-URI = SIP-URI / SIPS-URI / absoluteURI * absoluteURI = scheme ":" ( hier-part / opaque-part ) * hier-part = ( net-path / abs-path ) [ "?" query ] * net-path = "//" authority [ abs-path ] * abs-path = "/" path-segments * opaque-part = uric-no-slash *uric * uric = reserved / unreserved / escaped * uric-no-slash = unreserved / escaped / ";" / "?" / ":" / "@" * / "&" / "=" / "+" / "$" / "," * path-segments = segment *( "/" segment ) * segment = *pchar *( ";" param ) * param = *pchar * pchar = unreserved / escaped / * ":" / "@" / "&" / "=" / "+" / "$" / "," * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) * authority = srvr / reg-name * srvr = [ [ userinfo "@" ] hostport ] * reg-name = 1*( unreserved / escaped / "$" / "," * / ";" / ":" / "@" / "&" / "=" / "+" ) * query = *uric * SIP-Version = "SIP" "/" 1*DIGIT "." 1*DIGIT * @endcode * * The parsed request-line is stored in #sip_request_t structure. *//**@ingroup sip_request * @typedef typedef struct sip_request_s sip_request_t; * * The structure #sip_request_t contains representation of SIP request line. * * The #sip_request_t is defined as follows: * @code * typedef struct sip_request_s { * sip_common_t rq_common[1]; // Common fragment info * sip_unknown_t *rq_next; // Link to next (dummy) * sip_method_t rq_method; // Method enum * char const *rq_method_name; // Method name * url_t rq_url[1]; // RequestURI * char const *rq_version; // Protocol version * } sip_request_t; * @endcode */#define sip_request_insert msg_request_insertstatic msg_xtra_f sip_request_dup_xtra;static msg_dup_f sip_request_dup_one;#define sip_request_update NULLmsg_hclass_t sip_request_class[] = SIP_HEADER_CLASS(request, NULL, "", rq_common, single_critical, request);/**Parse @ref sip_request "request line" from a a SIP message. */issize_t sip_request_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen){ sip_request_t *rq = (sip_request_t *)h; char *uri, *version; if (msg_firstline_d(s, &uri, &version) < 0 || !uri || !version || (rq->rq_method = sip_method_d(&s, &rq->rq_method_name)) < 0 || *s || url_d(rq->rq_url, uri) < 0 || sip_version_d(&version, &rq->rq_version) < 0 || *version) return -1; return 0;}/**Encode @ref sip_request "request line" of a a SIP message. */issize_t sip_request_e(char b[], isize_t bsiz, sip_header_t const *h, int flags){ sip_request_t const *rq = (sip_request_t *)h; return snprintf(b, bsiz, "%s " URL_FORMAT_STRING " %s" CRLF, rq->rq_method_name, URL_PRINT_ARGS(rq->rq_url), rq->rq_version);}isize_t sip_request_dup_xtra(sip_header_t const *h, isize_t offset){ sip_request_t const *rq = (sip_request_t *)h; offset += url_xtra(rq->rq_url); if (!rq->rq_method) offset += MSG_STRING_SIZE(rq->rq_method_name); offset += sip_version_xtra(rq->rq_version); return offset;}/** Duplicate one request header. */char *sip_request_dup_one(sip_header_t *dst, sip_header_t const *src, char *b, isize_t xtra){ sip_request_t *rq = (sip_request_t *)dst; sip_request_t const *o = (sip_request_t *)src; char *end = b + xtra; URL_DUP(b, end, rq->rq_url, o->rq_url); if (!(rq->rq_method = o->rq_method)) MSG_STRING_DUP(b, rq->rq_method_name, o->rq_method_name); else rq->rq_method_name = o->rq_method_name; sip_version_dup(&b, &rq->rq_version, o->rq_version); assert(b <= end); return b;}/**@ingroup sip_request * * Create a @ref sip_request "request line" object. * * Create a request line object with * method enum @a method, method name @a name, request URI @a uri, and * protocol version @a version. The memory for the header object is * allocated from the memory home @a home. * * @param home memory home used to allocate #sip_request_t object * @param method method enum * @param name method name (required if method is not well-known) * @param uri request URI * @param version version string (defaults to "SIP/2.0" if NULL) * * @par Example * The following code fragment creates an OPTIONS request object: * @code * sip_request_t *rq; * rq = sip_request_create(home, SIP_METHOD_OPTIONS, requestURI, NULL); * @endcode * @note * If you provide an non-NULL @a version string, it is not copied. The * version string @b MUST remain constant. */sip_request_t *sip_request_create(su_home_t *home, sip_method_t method, char const *name, url_string_t const *uri, char const *version){ size_t xtra; sip_request_t *rq; if (method) name = sip_method_name(method, name); if (!name) return NULL; if (!method) method = sip_method_code(name); xtra = url_xtra(uri->us_url) + (method ? 0 : strlen(name) + 1); rq = (sip_request_t *)sip_header_alloc(home, sip_request_class, xtra); if (rq) { char *b = (char *)(rq + 1), *end = b + xtra; rq->rq_method = method; rq->rq_method_name = name; if (!method) MSG_STRING_DUP(b, rq->rq_method_name, name); URL_DUP(b, end, rq->rq_url, uri->us_url); rq->rq_version = version ? version : SIP_VERSION_CURRENT; assert(b == end); } return rq;}/* ====================================================================== *//**@SIP_HEADER sip_status Status Line * * The status line is first line in a response message. It is defined in * @RFC3261 as follows: * * @code * Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF * Status-Code = Informational * / Redirection * / Success * / Client-Error * / Server-Error * / Global-Failure * / extension-code * extension-code = 3DIGIT * Reason-Phrase = *(reserved / unreserved / escaped * / UTF8-NONASCII / UTF8-CONT / SP / HTAB) * @endcode * * The parsed status line is stored in #sip_status_t structure. *//**@ingroup sip_status * @typedef typedef struct sip_status_s sip_status_t; * * The structure #sip_status_t contains representation of SIP * @ref sip_status "status line". * * The #sip_status_t is defined as follows: * @code * typedef struct sip_status_s { * sip_common_t st_common[1]; // Common fragment info * sip_unknown_t *st_next; // Link to next (dummy) * char const *st_version; // Protocol version * int st_status; // Status code * char const *st_phrase; // Status phrase * } sip_status_t; * @endcode */static msg_xtra_f sip_status_dup_xtra;static msg_dup_f sip_status_dup_one;#define sip_status_insert msg_status_insert#define sip_status_update NULLmsg_hclass_t sip_status_class[] = SIP_HEADER_CLASS(status, NULL, "", st_common, single_critical, status);/** Parse status line */issize_t sip_status_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen){ sip_status_t *st = (sip_status_t *)h; char *status, *phrase; unsigned long code; if (msg_firstline_d(s, &status, &phrase) < 0 || sip_version_d(&s, &st->st_version) < 0 || *s || (code = strtoul(status, &status, 10)) >= INT_MAX || *status) return -1; st->st_status = code; st->st_phrase = phrase; return 0;}issize_t sip_status_e(char b[], isize_t bsiz, sip_header_t const *h, int flags){ sip_status_t const *st = (sip_status_t *)h; int status; assert(sip_is_status(h)); status = st->st_status; if (status > 999 || status < 100) status = 0; return snprintf(b, bsiz, "%s %03u %s" CRLF, st->st_version, status, st->st_phrase);}/** Extra size of a #sip_status_t object. */isize_t sip_status_dup_xtra(sip_header_t const *h, isize_t offset){ sip_status_t const *st = (sip_status_t *)h; offset += sip_version_xtra(st->st_version); offset += MSG_STRING_SIZE(st->st_phrase); return offset;}/** Duplicate one status header. */char *sip_status_dup_one(sip_header_t *dst, sip_header_t const *src, char *b, isize_t xtra){ sip_status_t *st = (sip_status_t *)dst; sip_status_t const *o = (sip_status_t *)src; char *end = b + xtra; sip_version_dup(&b, &st->st_version, o->st_version); st->st_status = o->st_status; MSG_STRING_DUP(b, st->st_phrase, o->st_phrase); assert(b <= end); (void)end; return b;}/**@ingroup sip_status * * Create a @ref sip_status "status line" object. * * @param home memory home used to allocate #sip_status_t object * @param status status code (in range 100 - 699) * @param phrase status phrase (may be NULL) * @param version version string (defaults to "SIP/2.0" if NULL) * * @note * If you provide an non-NULL @a version string, it is not copied. The * string @b MUST remain constant. * * @return * A pointer to newly created @ref sip_status "status line" * structure when successful, or NULL upon an error. */sip_status_t *sip_status_create(su_home_t *home, unsigned status, char const *phrase, char const *version){ sip_status_t *st; if (status < 100 || status > 699) return NULL; if (phrase == NULL && (phrase = sip_status_phrase(status)) == NULL) phrase = ""; if ((st = (sip_status_t *)sip_header_alloc(home, sip_status_class, 0))) { st->st_status = status; st->st_phrase = phrase; st->st_version = version ? version : SIP_VERSION_CURRENT; } return st;}/* ====================================================================== *//**@SIP_HEADER sip_payload Message Body * * The payload structure contains the optional message body. The message * body stored in the #sip_payload_t structure has no internal structure, * but it is accessed as a byte array. Use @ref sdp_parser "SDP parser" to * parse SDP content, for instance. * * The message body is stored in a #sip_payload_t structure. *//**@ingroup sip_payload * @typedef typedef struct sip_payload_s sip_payload_t; * * The structure #sip_payload_t contains representation of SIP message payload. * * The #sip_payload_t is defined as follows: * @code * typedef struct sip_payload_s { * msg_common_t pl_common[1]; // Common fragment info * msg_header_t *pl_next; // Next payload (if multipart message) * char *pl_data; // Data - may contain NUL * unsigned pl_len; // Length of message payload * } sip_payload_t; * @endcode */#define sip_payload_d msg_payload_d#define sip_payload_e msg_payload_e#define sip_payload_dup_xtra msg_payload_dup_xtra #define sip_payload_dup_one msg_payload_dup_one#define sip_payload_update NULLmsg_hclass_t sip_payload_class[] = SIP_HEADER_CLASS(payload, NULL, "", pl_common, single, payload);/**@ingroup sip_payload * * Create a @ref sip_payload "SIP payload" structure. * * Create a new SIP payload structure. it * copies the given data to the the payload data, and NUL terminates it (it * allocates one extra byte for NUL). If a NULL pointer is given as @a data, * sip_payload_create() allocates and zeroes a data buffer of @a len bytes. * * @param home memory home * @param data payload data * @param len payload length * * @return A pointer to newly created * payload structure, if successful, and NULL upon an error. */ sip_payload_t *sip_payload_create(su_home_t *home, void const *data, isize_t len){ msg_hclass_t *hc = sip_payload_class; sip_header_t *h = sip_header_alloc(home, hc, len + 1); sip_payload_t *pl = (sip_payload_t *)h; if (pl) { char *b = sip_header_data(h); if (data) { memcpy(b, data, len); b[len] = 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -