📄 msg_parser.c
字号:
int msg_header_e(char b[], int bsiz, msg_header_t const *h, int flags){ int n, m; assert(h); assert(h->sh_class); if (h == NULL || h->sh_class == NULL) return -1; n = msg_header_name_e(b, bsiz, h, flags); m = h->sh_class->hc_print(b + n, bsiz > n ? bsiz - n : 0, h, flags); if (h->sh_class->hc_name) { /* Ordinary header */ if (bsiz > n + m + strlen(CRLF)) strcpy(b + n + m, CRLF); return n + m + strlen(CRLF); } else return m;}/** Encode header name */static inlineintmsg_header_name_e(char b[], int bsiz, msg_header_t const *h, int flags){ int compact = MSG_IS_COMPACT(flags); char const *name; int n, n2; if (compact && h->sh_class->hc_short[0]) name = h->sh_class->hc_short, n = 1; else name = h->sh_class->hc_name, n = h->sh_class->hc_len; if (!name || !name[0]) return 0; n2 = compact ? n + 1 : n + 2; if (n2 < bsiz) { memcpy(b, name, n); b[n++] = ':'; if (!compact) b[n++] = ' '; b[n++] = '\0'; } return n2;}/* ====================================================================== *//* Handling header chain */static inline void serialize_first(msg_t *msg, msg_header_t *h);static msg_header_t **serialize_one(msg_t *msg, msg_header_t *h, msg_header_t **prev);/** Return head of the fragment chain */msg_header_t **msg_chain_head(msg_t const *msg){ return msg ? (msg_header_t **)&msg->m_chain : NULL;}static inline msg_header_t **_msg_chain_head(msg_t const *msg){ return msg ? (msg_header_t **)&msg->m_chain : NULL;}/** Return tail of the fragment chain */static inline msg_header_t **msg_chain_tail(msg_t const *msg){ return msg ? msg->m_tail : NULL;}/** Serialize headers into the fragment chain. * * The msg_serialize() collects the headers and other message components in * the fragment chain. It should be called before msg_prepare(). * * @relates msg_s * * @param msg pointer to message object * @param pub public message structure * * @retval 0 when successful * @retval -1 upon an error */int msg_serialize(msg_t *msg, msg_pub_t *pub){ msg_header_t *h, **hh, **end; msg_header_t **separator; msg_header_t **payload; msg_header_t **multipart; msg_mclass_t const *mc = msg->m_class; msg_header_t **tail, ***ptail; if (!msg) return errno = EINVAL, -1; if (pub == NULL) pub = msg->m_object; /* There must be a first line */ if (pub->msg_request) h = pub->msg_request; else if (pub->msg_status) h = pub->msg_status; else return errno = EINVAL, -1; serialize_first(msg, h); separator = (msg_header_t **)((char *)pub + mc->mc_separator->hr_offset); payload = (msg_header_t **)((char *)pub + mc->mc_payload->hr_offset); if (mc->mc_multipart->hr_class) multipart = (msg_header_t **)((char *)pub + mc->mc_multipart->hr_offset); else multipart = NULL; /* Find place to insert headers: before separator, payload and multipart */ if (*separator && !msg_header_is_removed(*separator)) ptail = &(*separator)->sh_prev; else if (*payload && !msg_header_is_removed(*payload)) ptail = &(*payload)->sh_prev; else if (multipart && *multipart && !msg_header_is_removed(*multipart)) ptail = &(*multipart)->sh_prev; else ptail = &msg->m_tail; tail = *ptail; end = (msg_header_t **)((char *)pub + pub->msg_size); for (hh = pub->msg_headers; hh < end; hh++) { if (!*hh) continue; if (hh == separator || hh == payload || hh == multipart) continue; tail = serialize_one(msg, *hh, tail); } /* Serialize separator, payload and multipart last */ if (*separator) tail = serialize_one(msg, *separator, tail); *ptail = tail; /* Payload comes after separator but before multipart */ if (ptail != &(*separator)->sh_prev) ; else if (*payload && !msg_header_is_removed(*payload)) ptail = &(*payload)->sh_prev; else if (multipart && *multipart && !msg_header_is_removed(*multipart)) ptail = &(*multipart)->sh_prev; else ptail = &msg->m_tail; tail = *ptail; if (*payload) { tail = serialize_one(msg, *payload, tail); *ptail = tail; } if (multipart && *multipart) { msg_header_t *last; last = msg_multipart_serialize(tail, (msg_multipart_t *)*multipart); msg->m_tail = &last->sh_succ; } assert(msg->m_chain && msg_chain_errors(msg->m_chain) == 0); return 0;}static inlinevoid serialize_first(msg_t *msg, msg_header_t *h){ if (msg_header_is_removed(h)) { if ((h->sh_succ = msg->m_chain)) h->sh_succ->sh_prev = &h->sh_succ; else msg->m_tail = &h->sh_succ; *(h->sh_prev = &msg->m_chain) = h; }}staticmsg_header_t **serialize_one(msg_t *msg, msg_header_t *h, msg_header_t **prev){ msg_header_t *last; msg_header_t *succ = *prev; if (msg_header_is_removed(h)) { /* Add the first header in the list to the chain */ *prev = h; h->sh_prev = prev; for (last = h; last->sh_succ; last = last->sh_succ) { /* Ensure that chain is connected */ assert(last->sh_next == last->sh_succ); assert(last->sh_succ->sh_prev = &last->sh_succ); } prev = &last->sh_succ; } if ((h = h->sh_next)) { assert(!msg_is_single(h)); if (msg_is_single(h)) { for (; h; h = h->sh_next) if (!msg_header_is_removed(h)) msg_chain_remove(msg, h); } /* Add the rest of the headers in the list to the chain */ else for (; h; h = h->sh_next) { if (msg_header_is_removed(h)) { *prev = h; h->sh_prev = prev; for (;h->sh_succ; h = h->sh_succ) assert(h->sh_succ == h->sh_next); prev = &h->sh_succ; } } } *prev = succ; return prev;}/**Fill an I/O vector with message contents. * * The function msg_iovec() calculates number of entries in the I/O vector * required to send a message @a msg. It also fills in the I/O vector array, * if it is provided by the caller and it is large enough. * * @param msg * @param vec * @param veclen * * @return * The function msg_iovec() returns the number of entries in I/O * vector required by @a msg, or 0 upon an error. * * @note The caller should check that the I/O vector @a vec has enough * entries. If the @a vec is too short, it should allocate big enough * vector and re-invoke msg_iovec(). */int msg_iovec(msg_t *msg, msg_iovec_t vec[], int veclen){ int len = 0, n = 0; char const *p = NULL; msg_header_t *h; unsigned total = 0; if (veclen <= 0) veclen = 0; for (h = msg->m_chain; h; h = h->sh_succ) { if (h->sh_data != p) { p = h->sh_data; len = h->sh_len; if (p == NULL) return 0; if (vec && n != veclen) /* new iovec entry */ vec[n].mv_base = (void *)p, vec[n].mv_len = len; else vec = NULL; p += len; n++; } else { /* extend old entry */ len = h->sh_len; if (vec) vec[n-1].mv_len += len; p += len; } total += len; } msg->m_size = total; assert(n > 0); return n;}/** Insert a header to existing header chain. * * Headers are either inserted just before the payload, or after the first * line, depending on their type. * * @param msg message object [IN] * @param pub public message structure [IN/OUT] * @param prepend if true, add before same type of headers (instead after them) * @param head head of chain * @param h header to insert * */staticvoid msg_insert_chain(msg_t *msg, msg_pub_t *pub, int prepend, msg_header_t **head, msg_header_t *h){ msg_mclass_t const *mc = msg->m_class; msg_header_t **hh; msg_header_t **separator; msg_header_t **payload; assert(msg && pub && head && h); separator = (msg_header_t **)((char *)pub + mc->mc_separator->hr_offset); payload = (msg_header_t **)((char *)pub + mc->mc_payload->hr_offset); if (msg_is_request(h)) { if (pub->msg_status) pub->msg_status = NULL; hh = head; } else if (msg_is_status(h)) { if (pub->msg_request) pub->msg_request = NULL; hh = head; } else if (msg_is_payload(h)) { /* Append */ hh = msg_chain_tail(msg); } else if (prepend) { if (!msg_is_request(*head) && !msg_is_status(*head)) hh = head; else hh = &((*head)->sh_succ); } /* Append headers before separator or payload */ else if (*separator && (*separator)->sh_prev) hh = (*separator)->sh_prev; else if (*payload && (*payload)->sh_prev) hh = (*payload)->sh_prev; else hh = msg_chain_tail(msg); msg_insert_here_in_chain(msg, hh, h);}/** Insert one or more message header to the chain. * * The function msg_insert_here_in_chain() appends message header to the * chain of headers after the given header. * * @param msg message * @param prev pointer to h_succ of previous fragment in the list * @param h header to be inserted. * * @return The pointer to the last header inserted. */staticvoid msg_insert_here_in_chain(msg_t *msg, msg_header_t **prev, msg_header_t *h){ if (h) { msg_header_t *last, *next; assert(h->sh_prev == NULL); assert(prev); assert(!msg_chain_errors(h)); for (last = h; last->sh_succ; last = last->sh_succ) ; last->sh_succ = next = *prev; *prev = h; h->sh_prev = prev; if (next) next->sh_prev = &last->sh_succ; else msg->m_tail = &last->sh_succ; assert(msg->m_chain && msg_chain_errors(msg->m_chain) == 0); }}/** * Remove a message from header chain. * * The function @c msg_chain_remove() removes a message header from the header * chain. * * @param msg pointer to the message * @param h pointer to the header in the list to be removed * * @return The pointer to the header just removed. */static inlinemsg_header_t *msg_chain_remove(msg_t *msg, msg_header_t *h){ if (h) { if (h->sh_prev) { assert(*h->sh_prev == h); assert(h->sh_succ == NULL || h->sh_succ->sh_prev == &h->sh_succ); *h->sh_prev = h->sh_succ; } if (h->sh_succ) h->sh_succ->sh_prev = h->sh_prev; else if (msg && h->sh_prev) msg->m_tail = h->sh_prev; h->sh_succ = NULL; h->sh_prev = NULL; if (msg) assert(msg_chain_errors(msg->m_chain) == 0); } return h;}#ifndef NDEBUG/**Check if header chain contains any loops. * * @return * Return 0 if no loop, -1 otherwise. */staticint msg_chain_loop(msg_header_t const *h){ msg_header_t const *h2; if (!h) return 0; for (h2 = h->sh_succ; h && h2 && h2->sh_succ; h = h->sh_succ) { if (h == h2 || h == h2->sh_succ) return 1; h2 = h2->sh_succ->sh_succ; if (h == h2) return 1; } return 0;}/** Check header chain consistency. * * @return * Return 0 if consistent, number of errors otherwise. */staticint msg_chain_errors(msg_header_t const *h){ if (msg_chain_loop(h)) return -1; for (; h; h = h->sh_succ) { if (h->sh_succ && h->sh_succ->sh_prev != &h->sh_succ) return -1; if (h->sh_prev && h != (*h->sh_prev)) return -1; } return 0;}#endif/* ====================================================================== *//* Handling message structure - allocating, adding and removing headers *//** Allocate a header structure * * The msg_header_alloc() function allocates a generic MO header structure * and returns a pointer to it. * * @param home memory home * @param hc header class * @param extra amount of extra memory to be allocated after header structure * * @return * A pointer to the newly created header object, or @c NULL upon an error. */msg_header_t *msg_header_alloc(su_home_t *home, msg_hclass_t *hc, int extra){ int size = hc->hc_size; msg_header_t *h = su_alloc(home, size + extra); if (h) { memset(h, 0, size); h->sh_class = hc; } return h;}/**Add a (list of) header(s) to the header structure and fragment chain. * * The function @c msg_header_add() adds a header or list of headers into * the given place within the message structure. It also inserts the headers * into the the message fragment chain, if it exists. * * If the header is a prepend header, the new header is inserted before * existing headers of the same class. If the header is an append header, * the new header is inserted after existing headers of the same class. If * the header is a singleton, existing headers of the same class are * removed. If the header is a list header, the values in the new header are * added to the existing list. * * @param msg message owning the fragment chain * @param pub public message structure * @param hh place in message structure to which header is added * @param h list of header(s) to be added */int msg_header_add(msg_t *msg, msg_pub_t *pub, msg_header_t **hh, msg_header_t *h){ msg_header_t **head, *old = NULL, *end; if (msg == NULL || h == NULL || h == MSG_HEADER_NONE || hh == NULL) return -1; if (pub == NULL) pub = msg->m_object; head = _msg_chain_head(msg); if (*head) { msg_header_t *sh, **prev; for (sh = h, prev = NULL; sh; sh = sh->sh_next) { sh->sh_succ = sh->sh_next; sh->sh_prev = prev; prev = &sh->sh_succ; } } switch (h->sh_class->hc_kind) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -