📄 msg_parser.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 * *//**@ingroup msg_parser * @CFILE msg_parser.c * * HTTP-like message parser engine. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Thu Oct 5 14:01:24 2000 ppessi * *//*#define NDEBUG*/#include "config.h"#include <stddef.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#include <assert.h>#include <limits.h>#include <errno.h>#include <stdarg.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/su.h>#include <sofia-sip/su_alloc.h>#include "msg_internal.h"#include "sofia-sip/msg_header.h"#include "sofia-sip/bnf.h"#include "sofia-sip/msg_parser.h"#include "sofia-sip/msg_mclass.h"#include "sofia-sip/msg_mclass_hash.h"#include "sofia-sip/msg_mime.h"#if HAVE_FUNC#elif HAVE_FUNCTION#define __func__ __FUNCTION__#elsestatic char const __func__[] = "msg_parser";#endifstatic int _msg_header_add_dup_as(msg_t *msg, msg_pub_t *pub, msg_hclass_t *hc, msg_header_t const *src);static void msg_insert_chain(msg_t *msg, msg_pub_t *pub, int prepend, msg_header_t **head, msg_header_t *h);static void msg_insert_here_in_chain(msg_t *msg, msg_header_t **prev, msg_header_t *h);su_inline msg_header_t *msg_chain_remove(msg_t *msg, msg_header_t *h);#ifndef NDEBUGstatic int msg_chain_loop(msg_header_t const *h);static int msg_chain_errors(msg_header_t const *h);#endif/* ====================================================================== *//* Message properties *//** Get message flags. */unsigned msg_get_flags(msg_t const *msg, unsigned mask){ return msg ? msg->m_object->msg_flags & mask : 0;}/** Set message flags. */unsigned msg_set_flags(msg_t *msg, unsigned mask){ return msg ? msg->m_object->msg_flags |= mask : 0;}/** Clear message flags. */unsigned msg_zap_flags(msg_t *msg, unsigned mask){ return msg ? msg->m_object->msg_flags &= ~mask : 0;}/** Test if streaming is in progress. */int msg_is_streaming(msg_t const *msg){ return msg && msg->m_streaming != 0;}/** Enable/disable streaming */void msg_set_streaming(msg_t *msg, enum msg_streaming_status what){ if (msg) msg->m_streaming = what != 0;}/* ---------------------------------------------------------------------- *//** Test if header is not in the chain */#define msg_header_is_removed(h) ((h)->sh_prev == NULL)su_inline int msg_is_request(msg_header_t const *h){ return h->sh_class->hc_hash == msg_request_hash;}su_inline int msg_is_status(msg_header_t const *h){ return h->sh_class->hc_hash == msg_status_hash;}/* ====================================================================== *//* Message buffer management *//** Allocate a buffer of @a size octets, with slack of #msg_min_size. */void *msg_buf_alloc(msg_t *msg, usize_t size){ struct msg_mbuffer_s *mb = msg->m_buffer; size_t room = mb->mb_size - mb->mb_commit - mb->mb_used; size_t target_size; if (mb->mb_data && room >= (unsigned)size) return mb->mb_data + mb->mb_used + mb->mb_commit; target_size = msg_min_size * ((size + mb->mb_commit) / msg_min_size + 1) - mb->mb_commit; return msg_buf_exact(msg, target_size);}/** Allocate a buffer exactly of @a size octets, without any slack. */void *msg_buf_exact(msg_t *msg, usize_t size){ struct msg_mbuffer_s *mb = msg->m_buffer; size_t room = mb->mb_size - mb->mb_commit - mb->mb_used; char *buffer; int realloc; if (mb->mb_data && room >= (unsigned)size) return mb->mb_data + mb->mb_used + mb->mb_commit; size += mb->mb_commit; if (msg->m_maxsize && msg->m_size + size > msg->m_maxsize + 1) { msg->m_object->msg_flags |= MSG_FLG_TOOLARGE; errno = msg->m_errno = ENOBUFS; return NULL; } realloc = !mb->mb_used && !msg->m_set_buffer; if (realloc) buffer = su_realloc(msg->m_home, mb->mb_data, size); else buffer = su_alloc(msg->m_home, size); if (!buffer) return NULL; if (!realloc && mb->mb_commit && mb->mb_data) memcpy(buffer, mb->mb_data + mb->mb_used, mb->mb_commit); msg->m_set_buffer = 0; mb->mb_data = buffer; mb->mb_size = size; mb->mb_used = 0; return buffer + mb->mb_commit;}/** Commit data into buffer. */usize_t msg_buf_commit(msg_t *msg, usize_t size, int eos){ if (msg) { struct msg_mbuffer_s *mb = msg->m_buffer; assert(mb->mb_used + mb->mb_commit + size <= mb->mb_size); mb->mb_commit += size; mb->mb_eos = eos; if (mb->mb_used == 0 && !msg->m_chunk && !msg->m_set_buffer) { size_t slack = mb->mb_size - mb->mb_commit; if (eos || slack >= msg_min_size) { /* realloc and cut down buffer */ size_t new_size; void *new_data; if (eos) new_size = mb->mb_commit + 1; else new_size = mb->mb_commit + msg_min_size; new_data = su_realloc(msg->m_home, mb->mb_data, new_size); if (new_data) { mb->mb_data = new_data, mb->mb_size = new_size; } } } } return 0;}/** Get length of committed data */usize_t msg_buf_committed(msg_t const *msg){ if (msg) return msg->m_buffer->mb_commit; else return 0;}/** Get committed data */void *msg_buf_committed_data(msg_t const *msg){ return msg && msg->m_buffer->mb_data ? msg->m_buffer->mb_data + msg->m_buffer->mb_used : NULL;}usize_t msg_buf_size(msg_t const *msg){ assert(msg); if (msg) { struct msg_mbuffer_s const *mb = msg->m_buffer; return mb->mb_size - mb->mb_commit - mb->mb_used; } else return 0;}su_inlinevoid msg_buf_used(msg_t *msg, usize_t used){ msg->m_size += used; msg->m_buffer->mb_used += used; if (msg->m_buffer->mb_commit > used) msg->m_buffer->mb_commit -= used; else msg->m_buffer->mb_commit = 0;}/** Set buffer. */void msg_buf_set(msg_t *msg, void *b, usize_t size){ if (msg) { struct msg_mbuffer_s *mb = msg->m_buffer; assert(!msg->m_set_buffer); /* This can be set only once */ mb->mb_data = b; mb->mb_size = size; mb->mb_used = 0; mb->mb_commit = 0; mb->mb_eos = 0; msg->m_set_buffer = 1; }}/** Move unparsed data from src to dst */void *msg_buf_move(msg_t *dst, msg_t const *src){ void *retval; struct msg_mbuffer_s *db = dst->m_buffer; struct msg_mbuffer_s const *sb = src->m_buffer; if (!dst || !src) return NULL; if (sb->mb_eos) retval = msg_buf_exact(dst, sb->mb_commit + 1); else retval = msg_buf_alloc(dst, sb->mb_commit + 1); if (retval == NULL) return NULL; memcpy(retval, sb->mb_data + sb->mb_used, sb->mb_commit); db->mb_commit += sb->mb_commit; db->mb_eos = sb->mb_eos; return retval;}/**Obtain I/O vector for receiving the data. * * @relatesalso msg_s * * Allocate buffers for receiving @a n bytes * of data available from network. Function returns the buffers in the I/O vector * @a vec. The @a vec is allocated by the caller, the available length is * given as @a veclen. If the protocol is message-oriented like UDP or SCTP * and the available data ends at message boundary, the caller should set * the @a exact as 1. Otherwise some extra buffer (known as @em slack) is * allocated). * * Currently, the msg_recv_iovec() allocates receive buffers in at most two * blocks, so the caller should allocate at least two elements for the I/O * vector @a vec. * * @param[in] msg message object * @param[out] vec I/O vector * @param[in] veclen available length of @a vec * @param[in] n number of possibly available bytes
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -