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

📄 msg_parser.c

📁 this is simple sip stack.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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);static 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)static inline int msg_is_request(msg_header_t const *h){  return h->sh_class->hc_hash == msg_request_hash;}static 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, unsigned size){  struct msg_mbuffer_s *mb = msg->m_buffer;  unsigned room = mb->mb_size - mb->mb_commit - mb->mb_used;  int 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, unsigned size){  struct msg_mbuffer_s *mb = msg->m_buffer;  unsigned 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. */unsigned msg_buf_commit(msg_t *msg, unsigned 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 */unsigned 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;}unsigned 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;}static inlinevoid msg_buf_used(msg_t *msg, unsigned 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, unsigned 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 iovec for receiving the data. * * @relates msg_s * * The function msg_recv_iovec() allocates buffers for receiving @a n bytes * of data available from network. It 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 buffers in at most two blocks, * so the caller should allocate at least two elements for the I/O vector @a * vec. * * @param msg     message object [IN] * @param vec     I/O vector [OUT] * @param veclen  available length of @a vec [IN] * @param n       number of available bytes燵IN] * @param exact   true if data ends at message boundary [IN] * * @return * The function msg_recv_iovec() returns the length of I/O vector to * receive data, 0 if there are not enough buffers, or -1 upon an error. */int msg_recv_iovec(msg_t *msg, msg_iovec_t vec[], int veclen,		   unsigned n, int exact){  int i = 0;  msg_payload_t *chunk;  unsigned len = 0;  char *buf;  if (n == 0)    return 0;  if (veclen == 0)    vec = NULL;  for (chunk = msg->m_chunk; chunk; chunk = MSG_CHUNK_NEXT(chunk)) {    buf = MSG_CHUNK_BUFFER(chunk);    len = MSG_CHUNK_AVAIL(chunk);    if (len == 0)      continue;    if (!buf)      break;    if (len > n)      len = n;    if (vec)      vec[i].mv_base = buf, vec[i].mv_len = len;    i++;    if (len == n)      return i;    if (i == veclen)      vec = NULL;    n -= len;  }  if (!chunk && msg->m_chunk && msg_get_flags(msg, MSG_FLG_FRAGS)) {    /*     * If the m_chunk is the last fragment for this message,     * receive rest of the data to the next message     */    if (msg->m_next == NULL)      msg->m_next = msg_create(msg->m_class, msg->m_oflags);    if (msg->m_next) {      msg->m_next->m_maxsize = msg->m_maxsize;      msg_addr_copy(msg->m_next, msg);    }    msg = msg->m_next;    if (msg == NULL)      return 0;  }  if (exact)    buf = msg_buf_exact(msg, n + 1), len = n;  else if (chunk && len > n && !msg_get_flags(msg, MSG_FLG_CHUNKING))    buf = msg_buf_exact(msg, len + 1);  else    buf = msg_buf_alloc(msg, n + 1), len = msg_buf_size(msg);  if (buf == NULL)    return -1;  if (vec)    vec[i].mv_base = buf, vec[i].mv_len = n;  if (chunk) {    assert(chunk->pl_data == NULL); assert(chunk->pl_common->h_len == 0);    chunk->pl_common->h_data = chunk->pl_data = buf;    if (len < MSG_CHUNK_AVAIL(chunk)) {      msg_header_t *h = (void*)chunk;      h->sh_succ = msg_header_alloc(msg_home(msg), h->sh_class, 0);      if (!h->sh_succ)	return -1;      h->sh_succ->sh_prev = &h->sh_succ;      chunk->pl_next = (msg_payload_t *)h->sh_succ;      chunk->pl_next->pl_len = chunk->pl_len - len;      chunk->pl_len = len;    }    else if (len > MSG_CHUNK_AVAIL(chunk)) {      len = MSG_CHUNK_AVAIL(chunk);    }    msg_buf_used(msg, len);  }  return i + 1;#if 0  if ((msg->m_ssize || msg->m_stream)      /* && msg_get_flags(msg, MSG_FLG_BODY) */) {    /* Streaming */    msg_buffer_t *b, *b0;    /* Calculate available size of current buffers */    for (b = msg->m_stream, len = 0; b && n > len; b = b->b_next)      len += b->b_avail - b->b_size;    /* Allocate new buffers */    if (n > len && msg_buf_external(msg, n, 0) < 0)      return -1;    for (b0 = msg->m_stream; b0; b0 = b0->b_next)      if (b0->b_avail != b0->b_size)	break;    for (b = b0; b && n > 0; i++, b = b->b_next) {      len = b->b_size - b->b_avail;      len = n < len ? n : len;      if (vec && i < veclen)	vec[i].mv_base = b->b_data + b->b_avail, vec[i].mv_len = len;      else	vec = NULL;      n -= len;    }    return i + 1;  }#endif}/** Obtain a buffer for receiving data */int msg_recv_buffer(msg_t *msg, void **return_buffer){  void *buffer;  if (!msg)    return -1;  if (return_buffer == NULL)    return_buffer = &buffer;  if (msg->m_chunk) {    msg_payload_t *pl;    for (pl = msg->m_chunk; pl; pl = pl->pl_next) {      unsigned n = MSG_CHUNK_AVAIL(pl);      if (n) {	*return_buffer = MSG_CHUNK_BUFFER(pl);	return n;      }    }    return 0;  }  if (msg_get_flags(msg, MSG_FLG_FRAGS)) {    /* Message is complete */    return 0;  }  else if ((*return_buffer = msg_buf_alloc(msg, 2))) {    return msg_buf_size(msg) - 1;  }  else {    return -1;  }}/**Commit @a n bytes of buffers. * * @relates msg_s * * The function msg_recv_commit() is called after @a n bytes of data has * been received to the message buffers and the parser can extract the * received data. * * @param msg pointer to message object * @param n   number of bytes received * @param eos true if stream is complete * * @note The @a eos should be always true for message-based transports. It * should also be true when a stram oin stream-based transport ends, for * instance, when TCP FIN is received. * * @retval 0 when successful * @retval -1 upon an error. */int msg_recv_commit(msg_t *msg, unsigned n, int eos){  msg_payload_t *pl;  if (eos)    msg->m_buffer->mb_eos = 1;  for (pl = msg->m_chunk; pl; pl = pl->pl_next) {    unsigned len = MSG_CHUNK_AVAIL(pl);    if (n <= len)      len = n;    pl->pl_common->h_len += len;    n -= len;    if (n == 0)      return 0;  }  if (msg->m_chunk && msg->m_next)    msg = msg->m_next;  return msg_buf_commit(msg, n, eos);}/**Get a next message of the stream. *

⌨️ 快捷键说明

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