Bug Summary

File:libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c
Location:line 1247, column 21
Description:Value stored to 'hr' during its initialization is never read

Annotated Source Code

1/*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2005 Nokia Corporation.
5 *
6 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25/**@ingroup msg_parser
26 * @CFILE msg_parser.c
27 *
28 * HTTP-like message parser engine.
29 *
30 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
31 *
32 * @date Created: Thu Oct 5 14:01:24 2000 ppessi
33 *
34 */
35
36/*#define NDEBUG*/
37
38#include "config.h"
39
40#include <stddef.h>
41#include <stdlib.h>
42#include <string.h>
43#include <stdio.h>
44#include <assert.h>
45#include <limits.h>
46#include <errno(*__errno_location ()).h>
47
48#include <stdarg.h>
49#include <sofia-sip/su_tagarg.h>
50
51#include <sofia-sip/su.h>
52#include <sofia-sip/su_alloc.h>
53
54#include "msg_internal.h"
55#include "sofia-sip/msg_header.h"
56#include "sofia-sip/bnf.h"
57#include "sofia-sip/msg_parser.h"
58#include "sofia-sip/msg_mclass.h"
59#include "sofia-sip/msg_mclass_hash.h"
60#include "sofia-sip/msg_mime.h"
61
62#if HAVE_FUNC1
63#elif HAVE_FUNCTION1
64#define __func__ __FUNCTION__
65#else
66static char const __func__[] = "msg_parser";
67#endif
68
69static int _msg_header_add_dup_as(msg_t *msg,
70 msg_pub_t *pub,
71 msg_hclass_t *hc,
72 msg_header_t const *src);
73
74static void msg_insert_chain(msg_t *msg, msg_pub_t *pub, int prepend,
75 msg_header_t **head, msg_header_t *h);
76static void msg_insert_here_in_chain(msg_t *msg,
77 msg_header_t **prev,
78 msg_header_t *h);
79su_inlinestatic inline msg_header_t *msg_chain_remove(msg_t *msg, msg_header_t *h);
80
81#ifndef NDEBUG
82static int msg_chain_loop(msg_header_t const *h);
83static int msg_chain_errors(msg_header_t const *h);
84#endif
85
86/* ====================================================================== */
87/* Message properties */
88
89/** Get message flags. */
90unsigned msg_get_flags(msg_t const *msg, unsigned mask)
91{
92 return msg ? msg->m_object->msg_flags & mask : 0;
93}
94
95/** Set message flags. */
96unsigned msg_set_flags(msg_t *msg, unsigned mask)
97{
98 return msg ? msg->m_object->msg_flags |= mask : 0;
99}
100
101/** Clear message flags. */
102unsigned msg_zap_flags(msg_t *msg, unsigned mask)
103{
104 return msg ? msg->m_object->msg_flags &= ~mask : 0;
105}
106
107/** Test if streaming is in progress. */
108int msg_is_streaming(msg_t const *msg)
109{
110 return msg && msg->m_streaming != 0;
111}
112
113/** Enable/disable streaming */
114void msg_set_streaming(msg_t *msg, enum msg_streaming_status what)
115{
116 if (msg)
117 msg->m_streaming = what != 0;
118}
119
120/* ---------------------------------------------------------------------- */
121
122/** Test if header is not in the chain */
123#define msg_header_is_removed(h)((h)->sh_common->h_prev == ((void*)0)) ((h)->sh_prevsh_common->h_prev == NULL((void*)0))
124
125su_inlinestatic inline int msg_is_request(msg_header_t const *h)
126{
127 return h->sh_classsh_common->h_class->hc_hash == msg_request_hash;
128}
129
130su_inlinestatic inline int msg_is_status(msg_header_t const *h)
131{
132 return h->sh_classsh_common->h_class->hc_hash == msg_status_hash;
133}
134
135/* ====================================================================== */
136/* Message buffer management */
137
138/** Allocate a buffer of @a size octets, with slack of #msg_min_size. */
139void *msg_buf_alloc(msg_t *msg, usize_t size)
140{
141 struct msg_mbuffer_s *mb = msg->m_buffer;
142 size_t room = mb->mb_size - mb->mb_commit - mb->mb_used;
143 size_t target_size;
144
145 if (mb->mb_data && room >= (unsigned)size)
146 return mb->mb_data + mb->mb_used + mb->mb_commit;
147
148 target_size =
149 msg_min_size * ((size + mb->mb_commit) / msg_min_size + 1) - mb->mb_commit;
150
151 return msg_buf_exact(msg, target_size);
152}
153
154/** Allocate a buffer exactly of @a size octets, without any slack. */
155void *msg_buf_exact(msg_t *msg, usize_t size)
156{
157 struct msg_mbuffer_s *mb = msg->m_buffer;
158 size_t room = mb->mb_size - mb->mb_commit - mb->mb_used;
159 char *buffer;
160 int realloc;
161
162 if (mb->mb_data && room >= (unsigned)size)
163 return mb->mb_data + mb->mb_used + mb->mb_commit;
164
165 size += mb->mb_commit;
166
167 if (msg->m_maxsize && msg->m_size + size > msg->m_maxsize + 1) {
168 msg->m_object->msg_flags |= MSG_FLG_TOOLARGE;
169 errno(*__errno_location ()) = msg->m_errno = ENOBUFS105;
170 return NULL((void*)0);
171 }
172
173 realloc = !mb->mb_used && !msg->m_set_buffer;
174
175 if (realloc)
176 buffer = su_realloc(msg->m_home, mb->mb_data, size);
177 else
178 buffer = su_alloc(msg->m_home, size);
179
180 if (!buffer)
181 return NULL((void*)0);
182
183 if (!realloc && mb->mb_commit && mb->mb_data)
184 memcpy(buffer, mb->mb_data + mb->mb_used, mb->mb_commit);
185
186 msg->m_set_buffer = 0;
187
188 mb->mb_data = buffer;
189 mb->mb_size = size;
190 mb->mb_used = 0;
191
192 return buffer + mb->mb_commit;
193}
194
195/** Commit data into buffer. */
196usize_t msg_buf_commit(msg_t *msg, usize_t size, int eos)
197{
198 if (msg) {
199 struct msg_mbuffer_s *mb = msg->m_buffer;
200 assert(mb->mb_used + mb->mb_commit + size <= mb->mb_size)((mb->mb_used + mb->mb_commit + size <= mb->mb_size
) ? (void) (0) : __assert_fail ("mb->mb_used + mb->mb_commit + size <= mb->mb_size"
, "msg_parser.c", 200, __PRETTY_FUNCTION__))
;
201
202 mb->mb_commit += size;
203 mb->mb_eos = eos;
204
205 if (mb->mb_used == 0 && !msg->m_chunk && !msg->m_set_buffer) {
206 size_t slack = mb->mb_size - mb->mb_commit;
207
208 if (eos || slack >= msg_min_size) {
209 /* realloc and cut down buffer */
210 size_t new_size;
211 void *new_data;
212
213 if (eos)
214 new_size = mb->mb_commit + 1;
215 else
216 new_size = mb->mb_commit + msg_min_size;
217
218 new_data = su_realloc(msg->m_home, mb->mb_data, new_size);
219 if (new_data) {
220 mb->mb_data = new_data, mb->mb_size = new_size;
221 }
222 }
223 }
224 }
225 return 0;
226}
227
228/** Get length of committed data */
229usize_t msg_buf_committed(msg_t const *msg)
230{
231 if (msg)
232 return msg->m_buffer->mb_commit;
233 else
234 return 0;
235}
236
237/** Get committed data */
238void *msg_buf_committed_data(msg_t const *msg)
239{
240 return msg && msg->m_buffer->mb_data ?
241 msg->m_buffer->mb_data + msg->m_buffer->mb_used
242 : NULL((void*)0);
243}
244
245usize_t msg_buf_size(msg_t const *msg)
246{
247 assert(msg)((msg) ? (void) (0) : __assert_fail ("msg", "msg_parser.c", 247
, __PRETTY_FUNCTION__))
;
248 if (msg) {
249 struct msg_mbuffer_s const *mb = msg->m_buffer;
250 return mb->mb_size - mb->mb_commit - mb->mb_used;
251 }
252 else
253 return 0;
254}
255
256su_inlinestatic inline
257void msg_buf_used(msg_t *msg, usize_t used)
258{
259 msg->m_size += used;
260 msg->m_buffer->mb_used += used;
261 if (msg->m_buffer->mb_commit > used)
262 msg->m_buffer->mb_commit -= used;
263 else
264 msg->m_buffer->mb_commit = 0;
265}
266
267/** Set buffer. */
268void msg_buf_set(msg_t *msg, void *b, usize_t size)
269{
270 if (msg) {
271 struct msg_mbuffer_s *mb = msg->m_buffer;
272
273 assert(!msg->m_set_buffer)((!msg->m_set_buffer) ? (void) (0) : __assert_fail ("!msg->m_set_buffer"
, "msg_parser.c", 273, __PRETTY_FUNCTION__))
; /* This can be set only once */
274
275 mb->mb_data = b;
276 mb->mb_size = size;
277 mb->mb_used = 0;
278 mb->mb_commit = 0;
279 mb->mb_eos = 0;
280
281 msg->m_set_buffer = 1;
282 }
283}
284
285/** Move unparsed data from src to dst */
286void *msg_buf_move(msg_t *dst, msg_t const *src)
287{
288 void *retval;
289 struct msg_mbuffer_s *db = dst->m_buffer;
290 struct msg_mbuffer_s const *sb = src->m_buffer;
291
292 if (!dst || !src)
293 return NULL((void*)0);
294
295 if (sb->mb_eos)
296 retval = msg_buf_exact(dst, sb->mb_commit + 1);
297 else
298 retval = msg_buf_alloc(dst, sb->mb_commit + 1);
299
300 if (retval == NULL((void*)0))
301 return NULL((void*)0);
302
303 memcpy(retval, sb->mb_data + sb->mb_used, sb->mb_commit);
304
305 db->mb_commit += sb->mb_commit;
306 db->mb_eos = sb->mb_eos;
307
308 return retval;
309}
310
311/**Obtain I/O vector for receiving the data.
312 *
313 * @relatesalso msg_s
314 *
315 * Allocate buffers for receiving @a n bytes
316 * of data available from network. Function returns the buffers in the I/O vector
317 * @a vec. The @a vec is allocated by the caller, the available length is
318 * given as @a veclen. If the protocol is message-oriented like UDP or SCTP
319 * and the available data ends at message boundary, the caller should set
320 * the @a exact as 1. Otherwise some extra buffer (known as @em slack) is
321 * allocated).
322 *
323 * Currently, the msg_recv_iovec() allocates receive buffers in at most two
324 * blocks, so the caller should allocate at least two elements for the I/O
325 * vector @a vec.
326 *
327 * @param[in] msg message object
328 * @param[out] vec I/O vector
329 * @param[in] veclen available length of @a vec
330 * @param[in] n number of possibly available bytes
331 * @param[in] exact true if data ends at message boundary
332 *
333 * @return
334 * The length of I/O vector to
335 * receive data, 0 if there are not enough buffers, or -1 upon an error.
336 *
337 * @sa msg_iovec(), su_vrecv()
338 */
339issize_t msg_recv_iovec(msg_t *msg, msg_iovec_t vec[], isize_t veclen,
340 usize_t n, int exact)
341{
342 size_t i = 0;
343 size_t len = 0;
344 msg_payload_t *chunk;
345 char *buf;
346
347 if (n == 0)
348 return 0;
349
350 if (veclen == 0)
351 vec = NULL((void*)0);
352
353 for (chunk = msg->m_chunk; chunk; chunk = MSG_CHUNK_NEXT(chunk)((chunk)->pl_next)) {
354 buf = MSG_CHUNK_BUFFER(chunk)((char *)chunk->pl_common->h_data + (chunk)->pl_common
->h_len)
;
355 len = MSG_CHUNK_AVAIL(chunk)((chunk)->pl_len + ((chunk)->pl_data - (char *)chunk->
pl_common->h_data) - (chunk)->pl_common->h_len)
;
356
357 if (len == 0)
358 continue;
359 if (!buf)
360 break;
361
362#if SU_HAVE_WINSOCK
363 /* WSABUF has u_long */
364 if (len > SU_IOVECLEN_MAX(18446744073709551615UL))
365 len = SU_IOVECLEN_MAX(18446744073709551615UL);
366#endif
367 if (len > n)
368 len = n;
369 if (vec)
370 vec[i].mv_basesiv_base = buf, vec[i].mv_lensiv_len = (su_ioveclen_t)len;
371 i++;
372 if (len == n)
373 return i;
374 if (i == veclen)
375 vec = NULL((void*)0);
376 n -= len;
377 }
378
379 if (!chunk && msg->m_chunk && msg_get_flags(msg, MSG_FLG_FRAGS)) {
380 /*
381 * If the m_chunk is the last fragment for this message,
382 * receive rest of the data to the next message
383 */
384 if (msg->m_next == NULL((void*)0))
385 msg->m_next = msg_create(msg->m_class, msg->m_oflags);
386 if (msg->m_next) {
387 msg->m_next->m_maxsize = msg->m_maxsize;
388 msg_addr_copy(msg->m_next, msg);
389 }
390 msg = msg->m_next;
391 if (msg == NULL((void*)0))
392 return 0;
393 }
394
395 if (exact)
396 buf = msg_buf_exact(msg, n + 1), len = n;
397 else if (chunk && len > n && !msg_get_flags(msg, MSG_FLG_CHUNKING))
398 buf = msg_buf_exact(msg, len + 1);
399 else
400 buf = msg_buf_alloc(msg, n + 1), len = msg_buf_size(msg);
401
402 if (buf == NULL((void*)0))
403 return -1;
404
405 if (vec)
406 vec[i].mv_basesiv_base = buf, vec[i].mv_lensiv_len = (su_ioveclen_t)n;
407
408 if (chunk) {
409 assert(chunk->pl_data == NULL)((chunk->pl_data == ((void*)0)) ? (void) (0) : __assert_fail
("chunk->pl_data == ((void*)0)", "msg_parser.c", 409, __PRETTY_FUNCTION__
))
; assert(chunk->pl_common->h_len == 0)((chunk->pl_common->h_len == 0) ? (void) (0) : __assert_fail
("chunk->pl_common->h_len == 0", "msg_parser.c", 409, __PRETTY_FUNCTION__
))
;
410
411 chunk->pl_common->h_data = chunk->pl_data = buf;
412
413 if (len < MSG_CHUNK_AVAIL(chunk)((chunk)->pl_len + ((chunk)->pl_data - (char *)chunk->
pl_common->h_data) - (chunk)->pl_common->h_len)
) {
414 msg_header_t *h = (void*)chunk;
415 h->sh_succsh_common->h_succ = msg_header_alloc(msg_home(msg)((su_home_t*)(msg)), h->sh_classsh_common->h_class, 0);
416 if (!h->sh_succsh_common->h_succ)
417 return -1;
418 h->sh_succsh_common->h_succ->sh_prevsh_common->h_prev = &h->sh_succsh_common->h_succ;
419 chunk->pl_next = (msg_payload_t *)h->sh_succsh_common->h_succ;
420 chunk->pl_next->pl_len = chunk->pl_len - len;
421 chunk->pl_len = len;
422 }
423 else if (len > MSG_CHUNK_AVAIL(chunk)((chunk)->pl_len + ((chunk)->pl_data - (char *)chunk->
pl_common->h_data) - (chunk)->pl_common->h_len)
) {
424 len = MSG_CHUNK_AVAIL(chunk)((chunk)->pl_len + ((chunk)->pl_data - (char *)chunk->
pl_common->h_data) - (chunk)->pl_common->h_len)
;
425 }
426
427 msg_buf_used(msg, len);
428 }
429
430 return i + 1;
431
432#if 0
433 if ((msg->m_ssize || msg->m_stream)
434 /* && msg_get_flags(msg, MSG_FLG_BODY) */) {
435 /* Streaming */
436 msg_buffer_t *b, *b0;
437
438 /* Calculate available size of current buffers */
439 for (b = msg->m_stream, len = 0; b && n > len; b = b->b_next)
440 len += b->b_avail - b->b_size;
441
442 /* Allocate new buffers */
443 if (n > len && msg_buf_external(msg, n, 0) < 0)
444 return -1;
445
446 for (b0 = msg->m_stream; b0; b0 = b0->b_next)
447 if (b0->b_avail != b0->b_size)
448 break;
449
450 for (b = b0; b && n > 0; i++, b = b->b_next) {
451 len = b->b_size - b->b_avail;
452 len = n < len ? n : len;
453 if (vec && i < veclen)
454 vec[i].mv_basesiv_base = b->b_data + b->b_avail, vec[i].mv_lensiv_len = len;
455 else
456 vec = NULL((void*)0);
457 n -= len;
458 }
459
460 return i + 1;
461 }
462#endif
463}
464
465
466/** Obtain a buffer for receiving data.
467 *
468 * @relatesalso msg_s
469 */
470issize_t msg_recv_buffer(msg_t *msg, void **return_buffer)
471{
472 void *buffer;
473
474 if (!msg)
475 return -1;
476
477 if (return_buffer == NULL((void*)0))
478 return_buffer = &buffer;
479
480 if (msg->m_chunk) {
481 msg_payload_t *pl;
482
483 for (pl = msg->m_chunk; pl; pl = pl->pl_next) {
484 size_t n = MSG_CHUNK_AVAIL(pl)((pl)->pl_len + ((pl)->pl_data - (char *)pl->pl_common
->h_data) - (pl)->pl_common->h_len)
;
485 if (n) {
486 *return_buffer = MSG_CHUNK_BUFFER(pl)((char *)pl->pl_common->h_data + (pl)->pl_common->
h_len)
;
487 return n;
488 }
489 }
490
491 return 0;
492 }
493
494 if (msg_get_flags(msg, MSG_FLG_FRAGS)) {
495 /* Message is complete */
496 return 0;
497 }
498 else if ((*return_buffer = msg_buf_alloc(msg, 2))) {
499 return msg_buf_size(msg) - 1;
500 }
501 else {
502 return -1;
503 }
504}
505
506
507
508/**Commit @a n bytes of buffers.
509 *
510 * @relatesalso msg_s
511 *
512 * The function msg_recv_commit() is called after @a n bytes of data has
513 * been received to the message buffers and the parser can extract the
514 * received data.
515 *
516 * @param msg pointer to message object
517 * @param n number of bytes received
518 * @param eos true if stream is complete
519 *
520 * @note The @a eos should be always true for message-based transports. It
521 * should also be true when a stram oin stream-based transport ends, for
522 * instance, when TCP FIN is received.
523 *
524 * @retval 0 when successful
525 * @retval -1 upon an error.
526 */
527isize_t msg_recv_commit(msg_t *msg, usize_t n, int eos)
528{
529 msg_payload_t *pl;
530
531 if (eos)
532 msg->m_buffer->mb_eos = 1;
533
534 for (pl = msg->m_chunk; pl; pl = pl->pl_next) {
535 size_t len = MSG_CHUNK_AVAIL(pl)((pl)->pl_len + ((pl)->pl_data - (char *)pl->pl_common
->h_data) - (pl)->pl_common->h_len)
;
536
537 if (n <= len)
538 len = n;
539
540 pl->pl_common->h_len += len;
541
542 n -= len;
543
544 if (n == 0)
545 return 0;
546 }
547
548 if (msg->m_chunk && msg->m_next)
549 msg = msg->m_next;
550
551 return msg_buf_commit(msg, n, eos);
552}
553
554/**Get a next message of the stream.
555 *
556 * @relatesalso msg_s
557 *
558 * When parsing a transport stream, only the first message in the stream is
559 * created with msg_create(). The rest of the messages should be created
560 * with msg_next() after previous message has been completely received and
561 * parsed.
562 *
563 */
564msg_t *msg_next(msg_t *msg)
565{
566 msg_t *next;
567 usize_t n;
568
569 if (msg && msg->m_next) {
570 next = msg->m_next;
571 msg->m_next = NULL((void*)0);
572 return next;
573 }
574
575 if ((n = msg_buf_committed(msg))) {
576 if (msg_buf_move(next = msg_create(msg->m_class, msg->m_oflags), msg)) {
577 msg_addr_copy(next, msg);
578 return next;
579 }
580 /* How to indicate error? */
581 msg_destroy(next);
582 }
583
584 return NULL((void*)0);
585}
586
587/** Set next message of the stream.
588 *
589 * @relatesalso msg_s
590 */
591int msg_set_next(msg_t *msg, msg_t *next)
592{
593 if (!msg || (next && next->m_next))
594 return -1;
595
596 if (msg->m_next && next)
597 next->m_next = msg->m_next;
598
599 msg->m_next = next;
600
601 return 0;
602}
603
604/** Clear committed data.
605 *
606 * @relatesalso msg_s
607 */
608void msg_clear_committed(msg_t *msg)
609{
610 if (msg) {
611 usize_t n = msg_buf_committed(msg);
612
613 if (n)
614 msg_buf_used(msg, n);
615 }
616}
617
618#if 0
619struct sigcomp_udvm;
620
621struct sigcomp_udvm *msg_get_udvm(msg_t *msg);
622struct sigcomp_udvm *msg_set_udvm(msg_t *msg, struct sigcomp_udvm *);
623
624/** Save UDVM. */
625struct sigcomp_udvm *msg_set_udvm(msg_t *msg, struct sigcomp_udvm *udvm)
626{
627 struct sigcomp_udvm *prev = NULL((void*)0);
628
629 if (msg) {
630 prev = msg->m_udvm;
631 msg->m_udvm = udvm;
632 }
633
634 return prev;
635}
636
637/** Get saved UDVM */
638struct sigcomp_udvm *msg_get_udvm(msg_t *msg)
639{
640 return msg ? msg->m_udvm : NULL((void*)0);
641}
642
643#endif
644
645/** Mark message as complete.
646 *
647 * @relatesalso msg_s
648 */
649unsigned msg_mark_as_complete(msg_t *msg, unsigned mask)
650{
651 if (msg) {
652 msg->m_streaming = 0;
653 return msg->m_object->msg_flags |= mask | MSG_FLG_COMPLETE;
654 }
655 else {
656 return 0;
657 }
658}
659
660/** Return true if message is complete.
661 *
662 * @relatesalso msg_s
663 */
664int msg_is_complete(msg_t const *msg)
665{
666 return msg && MSG_IS_COMPLETE(msg->m_object)(((msg->m_object)->msg_flags & MSG_FLG_COMPLETE) !=
0)
;
667}
668
669/** Return true if message has parsing errors.
670 *
671 * @relatesalso msg_s
672*/
673int msg_has_error(msg_t const *msg)
674{
675 return msg->m_object->msg_flags & MSG_FLG_ERROR;
676}
677
678/**Total size of message.
679 *
680 * @relatesalso msg_s
681 */
682usize_t msg_size(msg_t const *msg)
683{
684 return msg ? msg->m_size : 0;
685}
686
687/** Set the maximum size of a message.
688 *
689 * @relatesalso msg_s
690 *
691 * The function msg_maxsize() sets the maximum buffer size of a message. It
692 * returns the previous maximum size. If the @a maxsize is 0, maximum size
693 * is not set, but the current maximum size is returned.
694 *
695 * If the message size exceeds maxsize, msg_errno() returns ENOBUFS,
696 * MSG_FLG_TOOLARGE and MSG_FLG_ERROR flags are set.
697 */
698usize_t msg_maxsize(msg_t *msg, usize_t maxsize)
699{
700 usize_t retval = 0;
701
702 if (msg) {
703 retval = msg->m_maxsize;
704 if (maxsize)
705 msg->m_maxsize = maxsize;
706 }
707
708 return retval;
709}
710
711/**Set the size of next fragment.
712 *
713 * @relatesalso msg_s
714 *
715 * The function msg_streaming_size() sets the size of the message body for
716 * streaming.
717 */
718int msg_streaming_size(msg_t *msg, usize_t ssize)
719{
720 if (!msg)
721 return -1;
722
723 msg->m_ssize = ssize;
724
725 return 0;
726}
727
728/**Allocate a list of external buffers.
729 *
730 * @relatesalso msg_s
731 *
732 * The function msg_buf_external() allocates at most msg_n_fragments
733 * external buffers for the message body.
734 *
735 * @return The function msg_buf_external() returns number of allocated
736 * buffers, or -1 upon an error.
737 */
738issize_t msg_buf_external(msg_t *msg,
739 usize_t N,
740 usize_t blocksize)
741{
742 msg_buffer_t *ext = NULL((void*)0), *b, **bb;
743 size_t i, I;
744
745 assert(N <= 128 * 1024)((N <= 128 * 1024) ? (void) (0) : __assert_fail ("N <= 128 * 1024"
, "msg_parser.c", 745, __PRETTY_FUNCTION__))
;
746
747 if (msg == NULL((void*)0))
748 return -1;
749 if (blocksize == 0)
750 blocksize = msg_min_block;
751 if (N == 0)
752 N = blocksize;
753 if (N > blocksize * msg_n_fragments)
754 N = blocksize * msg_n_fragments;
755 if (N > msg->m_ssize)
756 N = msg->m_ssize;
757
758 I = (N + blocksize - 1) / blocksize; assert(I <= msg_n_fragments)((I <= msg_n_fragments) ? (void) (0) : __assert_fail ("I <= msg_n_fragments"
, "msg_parser.c", 758, __PRETTY_FUNCTION__))
;
759
760 for (i = 0, bb = &ext; i < I; i++) {
761 *bb = su_zalloc(msg_home(msg)((su_home_t*)(msg)), sizeof **bb);
762 if (!*bb)
763 break;
764 bb = &(*bb)->b_next;
765 }
766
767 if (i == I)
768 for (b = ext, i = 0; b; b = b->b_next, i++) {
769 b->b_data = su_alloc(msg_home(msg)((su_home_t*)(msg)), b->b_size = blocksize);
770 if (!b->b_data)
771 break;
772 }
773
774 if (i == I) {
775 /* Successful return */
776 for (bb = &msg->m_stream; *bb; bb = &(*bb)->b_next)
777 ;
778
779 *bb = ext;
780
781 if (msg->m_ssize != MSG_SSIZE_MAX((2147483647 *2U +1U)))
782 for (b = ext; b; b = b->b_next) {
783 if (msg->m_ssize < b->b_size) {
784 b->b_size = msg->m_ssize;
785 }
786 msg->m_ssize -= b->b_size;
787 }
788
789 return i;
790 }
791
792 for (b = ext; b; b = ext) {
793 ext = b->b_next;
794 su_free(msg_home(msg)((su_home_t*)(msg)), b->b_data);
795 su_free(msg_home(msg)((su_home_t*)(msg)), b);
796 }
797
798 return -1;
799}
800
801int msg_unref_external(msg_t *msg, msg_buffer_t *b)
802{
803 if (msg && b) {
804 su_free(msg_home(msg)((su_home_t*)(msg)), b->b_data);
805 su_free(msg_home(msg)((su_home_t*)(msg)), b);
806 return 0;
807 }
808 errno(*__errno_location ()) = EINVAL22;
809 return -1;
810}
811
812/* ====================================================================== */
813/* Parsing messages */
814
815su_inlinestatic inline int extract_incomplete_chunks(msg_t *, int eos);
816static issize_t extract_first(msg_t *, msg_pub_t *,
817 char b[], isize_t bsiz, int eos);
818su_inlinestatic inline issize_t extract_next(msg_t *, msg_pub_t *, char *, isize_t bsiz,
819 int eos, int copy);
820static issize_t extract_header(msg_t *, msg_pub_t*,
821 char b[], isize_t bsiz, int eos, int copy);
822static msg_header_t *header_parse(msg_t *, msg_pub_t *, msg_href_t const *,
823 char s[], isize_t slen, int copy_buffer);
824static msg_header_t *error_header_parse(msg_t *msg, msg_pub_t *mo,
825 msg_href_t const *hr);
826su_inlinestatic inline issize_t
827extract_trailers(msg_t *msg, msg_pub_t *mo,
828 char *b, isize_t bsiz, int eos, int copy);
829
830/** Calculate length of line ending (0, 1 or 2). @internal */
831#define CRLF_TEST(b)((b)[0] == '\r' ? ((b)[1] == '\n') + 1 : (b)[0] =='\n') ((b)[0] == '\r' ? ((b)[1] == '\n') + 1 : (b)[0] =='\n')
832
833su_inlinestatic inline void
834append_parsed(msg_t *msg, msg_pub_t *mo, msg_href_t const *hr, msg_header_t *h,
835 int always_into_chain);
836
837/**Extract and parse a message from internal buffer.
838 *
839 * @relatesalso msg_s
840 *
841 * This function parses the internal buffer and adds the parsed fragments to
842 * the message object. It marks the successfully parsed data as extracted.
843 *
844 * @param msg message to be parsed
845 *
846 * @retval positive if a complete message was parsed
847 * @retval 0 if message was incomplete
848 * @retval negative if an error occurred
849 */
850int msg_extract(msg_t *msg)
851{
852 msg_pub_t *mo = msg_object(msg);
853 msg_mclass_t const *mc;
854 char *b;
855 ssize_t m;
856 size_t bsiz;
857 int eos;
858
859 if (!msg || !msg->m_buffer->mb_data)
860 return -1;
861
862 assert(mo)((mo) ? (void) (0) : __assert_fail ("mo", "msg_parser.c", 862
, __PRETTY_FUNCTION__))
;
863
864 mc = msg->m_class;
865 mo = msg->m_object;
866 eos = msg->m_buffer->mb_eos;
867
868 if (msg->m_chunk) {
869 int incomplete = extract_incomplete_chunks(msg, eos);
870 if (incomplete < 1 || MSG_IS_COMPLETE(mo)(((mo)->msg_flags & MSG_FLG_COMPLETE) != 0))
871 return incomplete;
872 }
873
874 if (mo->msg_flags & MSG_FLG_TRAILERS)
875 msg_set_streaming(msg, (enum msg_streaming_status)0);
876
877 if (msg->m_buffer->mb_used + msg->m_buffer->mb_commit ==
878 msg->m_buffer->mb_size)
879 /* Why? When? */
880 return 0;
881
882 assert(msg->m_buffer->mb_used + msg->m_buffer->mb_commit <((msg->m_buffer->mb_used + msg->m_buffer->mb_commit
< msg->m_buffer->mb_size) ? (void) (0) : __assert_fail
("msg->m_buffer->mb_used + msg->m_buffer->mb_commit < msg->m_buffer->mb_size"
, "msg_parser.c", 883, __PRETTY_FUNCTION__))
883 msg->m_buffer->mb_size)((msg->m_buffer->mb_used + msg->m_buffer->mb_commit
< msg->m_buffer->mb_size) ? (void) (0) : __assert_fail
("msg->m_buffer->mb_used + msg->m_buffer->mb_commit < msg->m_buffer->mb_size"
, "msg_parser.c", 883, __PRETTY_FUNCTION__))
;
884
885 m = 0;
886
887 b = msg->m_buffer->mb_data + msg->m_buffer->mb_used;
888 bsiz = msg->m_buffer->mb_commit;
889 b[bsiz] = '\0';
890
891 while (msg->m_buffer->mb_commit > 0) {
892 int flags = mo->msg_flags;
893 int copy = MSG_IS_EXTRACT_COPY(flags)((((flags)) & (MSG_FLG_EXTRACT_COPY)) == MSG_FLG_EXTRACT_COPY
)
;
894
895 if (flags & MSG_FLG_COMPLETE)
896 break;
897
898 if (flags & MSG_FLG_TRAILERS)
899 m = extract_trailers(msg, mo, b, bsiz, eos, copy);
900 else if (flags & MSG_FLG_BODY)
901 m = mc->mc_extract_body(msg, mo, b, bsiz, eos);
902 else if (flags & MSG_FLG_HEADERS)
903 m = extract_next(msg, mo, b, bsiz, eos, copy);
904 else
905 m = extract_first(msg, mo, b, bsiz, eos);
906
907 if (m <= 0 || msg->m_chunk)
908 break;
909
910 b += m;
911 bsiz -= m;
912
913 msg_buf_used(msg, (size_t)m);
914 }
915
916 if (eos && bsiz == 0)
917 msg_mark_as_complete(msg, 0);
918
919 if (m < 0 || (mo->msg_flags & MSG_FLG_ERROR)) {
920 msg_mark_as_complete(msg, MSG_FLG_ERROR);
921 return -1;
922 }
923 else if (!MSG_IS_COMPLETE(mo)(((mo)->msg_flags & MSG_FLG_COMPLETE) != 0))
924 return 0;
925 else if (!(mo->msg_flags & MSG_FLG_HEADERS)) {
926 msg_mark_as_complete(msg, MSG_FLG_ERROR);
927 return -1;
928 }
929 else
930 return 1;
931}
932
933static
934issize_t extract_first(msg_t *msg, msg_pub_t *mo, char b[], isize_t bsiz, int eos)
935{
936 /* First line */
937 size_t k, l, m, n, xtra;
938 int crlf;
939 msg_header_t *h;
940 msg_href_t const *hr;
941 msg_mclass_t const *mc = msg->m_class;
942
943 for (k = 0; IS_LWS(b[k])((b[k]) == ' ' || (b[k]) == '\t' || (b[k]) == '\r' || (b[k]) ==
'\n')
; k++) /* Skip whitespace */
944 ;
945 if (!b[k]) return k;
946
947 /* If first token contains no /, this is request, otherwise status line */
948 l = span_token(b + k) + k;
949 if (b[l] != '/')
950 hr = mc->mc_request;
951 else
952 hr = mc->mc_status;
953
954 n = span_non_crlf(b + l)__extension__ ({ char __r0, __r1, __r2; (__builtin_constant_p
("\r" "\n") && ((size_t)(const void *)(("\r" "\n") +
1) - (size_t)(const void *)("\r" "\n") == 1) ? ((__builtin_constant_p
(b + l) && ((size_t)(const void *)((b + l) + 1) - (size_t
)(const void *)(b + l) == 1)) ? __builtin_strcspn (b + l, "\r"
"\n") : ((__r0 = ((const char *) ("\r" "\n"))[0], __r0 == '\0'
) ? strlen (b + l) : ((__r1 = ((const char *) ("\r" "\n"))[1]
, __r1 == '\0') ? __strcspn_c1 (b + l, __r0) : ((__r2 = ((const
char *) ("\r" "\n"))[2], __r2 == '\0') ? __strcspn_c2 (b + l
, __r0, __r1) : (((const char *) ("\r" "\n"))[3] == '\0' ? __strcspn_c3
(b + l, __r0, __r1, __r2) : __builtin_strcspn (b + l, "\r" "\n"
)))))) : __builtin_strcspn (b + l, "\r" "\n")); })
+ l;
955 if (!b[n])
956 return eos ? -1 : 0;
957 crlf = CRLF_TEST(b + n)((b + n)[0] == '\r' ? ((b + n)[1] == '\n') + 1 : (b + n)[0] ==
'\n')
;
958
959 for (m = n + crlf; IS_WS(b[m])((b[m]) == ' ' || (b[m]) == '\t'); m++)
960 ;
961 /* In order to skip possible whitespace after first line, we don't parse
962 first line until first non-ws char from next one has been received */
963 if (!b[m] && !eos)
964 return 0;
965
966 xtra = MSG_IS_EXTRACT_COPY(mo->msg_flags)((((mo->msg_flags)) & (MSG_FLG_EXTRACT_COPY)) == MSG_FLG_EXTRACT_COPY
)
? n + 1 - k : 0;
967 if (!(h = msg_header_alloc(msg_home(msg)((su_home_t*)(msg)), hr->hr_class, xtra)))
968 return -1;
969
970 if (xtra) {
971 char *bb = memcpy(MSG_HEADER_DATA(h)((char *)(h) + (h)->sh_common->h_class->hc_size), b, xtra - 1);
972 h->sh_datash_common->h_data = b, h->sh_lensh_common->h_len = n + crlf;
973 b = bb; n = xtra - 1;
974 }
975 else {
976 b = b + k; n = n - k;
977 }
978
979 b[n] = 0;
980
981 if (hr->hr_class->hc_parse(msg_home(msg)((su_home_t*)(msg)), h, b, n) < 0)
982 return -1;
983
984 assert(hr->hr_offset)((hr->hr_offset) ? (void) (0) : __assert_fail ("hr->hr_offset"
, "msg_parser.c", 984, __PRETTY_FUNCTION__))
;
985
986 append_parsed(msg, mo, hr, h, 1);
987
988 mo->msg_flags |= MSG_FLG_HEADERS;
989
990 return m;
991}
992
993/* Extract header or message body */
994su_inlinestatic inline issize_t
995extract_next(msg_t *msg, msg_pub_t *mo, char *b, isize_t bsiz,
996 int eos, int copy)
997{
998 if (IS_CRLF(b[0])((b[0]) == '\r' || (b[0]) == '\n'))
999 return msg->m_class->mc_extract_body(msg, mo, b, bsiz, eos);
1000 else
1001 return extract_header(msg, mo, b, bsiz, eos, copy);
1002}
1003
1004/** Extract a header. */
1005issize_t msg_extract_header(msg_t *msg, msg_pub_t *mo,
1006 char b[], isize_t bsiz, int eos)
1007{
1008 return extract_header(msg, mo, b, bsiz, eos, 0);
1009}
1010
1011/** Extract a header from buffer @a b.
1012 */
1013static
1014issize_t
1015extract_header(msg_t *msg, msg_pub_t *mo, char *b, isize_t bsiz, int eos,
1016 int copy_buffer)
1017{
1018 size_t len, m;
1019 size_t name_len = 0, xtra;
1020 isize_t n = 0;
1021 int crlf = 0, name_len_set = 0;
1022 int error = 0;
1023 msg_header_t *h;
1024 msg_href_t const *hr;
1025 msg_mclass_t const *mc = msg->m_class;
1026
1027 hr = msg_find_hclass(mc, b, &n); /* Get header name */
1028 error = n == 0;
1029 if (hr == NULL((void*)0)) /* Panic */
1030 return -1;
1031
1032 xtra = span_ws(b + n)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" " "\t") && ((size_t)(const void *)((" " "\t") + 1
) - (size_t)(const void *)(" " "\t") == 1) ? ((__builtin_constant_p
(b + n) && ((size_t)(const void *)((b + n) + 1) - (size_t
)(const void *)(b + n) == 1)) ? __builtin_strspn (b + n, " " "\t"
) : ((__a0 = ((const char *) (" " "\t"))[0], __a0 == '\0') ? (
(void) (b + n), (size_t) 0) : ((__a1 = ((const char *) (" " "\t"
))[1], __a1 == '\0') ? __strspn_c1 (b + n, __a0) : ((__a2 = (
(const char *) (" " "\t"))[2], __a2 == '\0') ? __strspn_c2 (b
+ n, __a0, __a1) : (((const char *) (" " "\t"))[3] == '\0' ?
__strspn_c3 (b + n, __a0, __a1, __a2) : __builtin_strspn (b +
n, " " "\t")))))) : __builtin_strspn (b + n, " " "\t")); })
;
1033
1034 /* Find next crlf which is not followed by whitespace */
1035 do {
1036 n += xtra + crlf;
1037 if (!eos && bsiz == n)
1038 return 0;
1039 m = span_non_crlf(b + n)__extension__ ({ char __r0, __r1, __r2; (__builtin_constant_p
("\r" "\n") && ((size_t)(const void *)(("\r" "\n") +
1) - (size_t)(const void *)("\r" "\n") == 1) ? ((__builtin_constant_p
(b + n) && ((size_t)(const void *)((b + n) + 1) - (size_t
)(const void *)(b + n) == 1)) ? __builtin_strcspn (b + n, "\r"
"\n") : ((__r0 = ((const char *) ("\r" "\n"))[0], __r0 == '\0'
) ? strlen (b + n) : ((__r1 = ((const char *) ("\r" "\n"))[1]
, __r1 == '\0') ? __strcspn_c1 (b + n, __r0) : ((__r2 = ((const
char *) ("\r" "\n"))[2], __r2 == '\0') ? __strcspn_c2 (b + n
, __r0, __r1) : (((const char *) ("\r" "\n"))[3] == '\0' ? __strcspn_c3
(b + n, __r0, __r1, __r2) : __builtin_strcspn (b + n, "\r" "\n"
)))))) : __builtin_strcspn (b + n, "\r" "\n")); })
;
1040 if (!name_len_set && m)
1041 name_len = n, name_len_set = 1; /* First non-ws after COLON */
1042 n += m;
1043 crlf = CRLF_TEST(b + n)((b + n)[0] == '\r' ? ((b + n)[1] == '\n') + 1 : (b + n)[0] ==
'\n')
;
1044 xtra = span_ws(b + n + crlf)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" " "\t") && ((size_t)(const void *)((" " "\t") + 1
) - (size_t)(const void *)(" " "\t") == 1) ? ((__builtin_constant_p
(b + n + crlf) && ((size_t)(const void *)((b + n + crlf
) + 1) - (size_t)(const void *)(b + n + crlf) == 1)) ? __builtin_strspn
(b + n + crlf, " " "\t") : ((__a0 = ((const char *) (" " "\t"
))[0], __a0 == '\0') ? ((void) (b + n + crlf), (size_t) 0) : (
(__a1 = ((const char *) (" " "\t"))[1], __a1 == '\0') ? __strspn_c1
(b + n + crlf, __a0) : ((__a2 = ((const char *) (" " "\t"))[
2], __a2 == '\0') ? __strspn_c2 (b + n + crlf, __a0, __a1) : (
((const char *) (" " "\t"))[3] == '\0' ? __strspn_c3 (b + n +
crlf, __a0, __a1, __a2) : __builtin_strspn (b + n + crlf, " "
"\t")))))) : __builtin_strspn (b + n + crlf, " " "\t")); })
;
1045 }
1046 while (xtra);
1047
1048 if (!eos && bsiz == n + crlf)
1049 return 0;
1050
1051 if (hr->hr_class->hc_hash == msg_unknown_hash)
1052 name_len = 0, name_len_set = 1;
1053
1054 if (error) {
1055 msg->m_extract_err |= hr->hr_flags;
1056 if (hr->hr_class->hc_critical)
1057 mo->msg_flags |= MSG_FLG_ERROR;
1058 hr = mc->mc_error;
1059 copy_buffer = 1;
1060 h = error_header_parse(msg, mo, hr);
1061 }
1062 else {
1063 if (!name_len_set)
1064 /* Empty header - nothing but name, COLON and LWS */
1065 name_len = n;
1066 else
1067 /* Strip extra whitespace at the end of header */
1068 while (n > name_len && IS_LWS(b[n - 1])((b[n - 1]) == ' ' || (b[n - 1]) == '\t' || (b[n - 1]) == '\r'
|| (b[n - 1]) == '\n')
)
1069 n--, crlf++;
1070
1071 h = header_parse(msg, mo, hr, b + name_len, n - name_len, copy_buffer);
1072 }
1073
1074 if (h == NULL((void*)0))
1075 return -1;
1076
1077 len = n + crlf;
1078
1079 /*
1080 * If the header contains multiple header fields, set the pointer to the
1081 * encodeded data correctly
1082 */
1083 while (h) {
1084 if (copy_buffer)
1085 h->sh_datash_common->h_data = b, h->sh_lensh_common->h_len = len;
1086 b += len, len = 0;
1087 if (h->sh_succsh_common->h_succ)
1088 assert(&h->sh_succ == h->sh_succ->sh_prev)((&h->sh_common->h_succ == h->sh_common->h_succ
->sh_common->h_prev) ? (void) (0) : __assert_fail ("&h->sh_common->h_succ == h->sh_common->h_succ->sh_common->h_prev"
, "msg_parser.c", 1088, __PRETTY_FUNCTION__))
;
1089 h = h->sh_nextsh_header_next->shn_next;
1090 }
1091
1092 return n + crlf;
1093}
1094
1095static
1096msg_header_t *header_parse(msg_t *msg, msg_pub_t *mo,
1097 msg_href_t const *hr,
1098 char s[], isize_t slen,
1099 int copy_buffer)
1100{
1101 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
1102 msg_header_t *h, **hh;
1103 msg_hclass_t *hc = hr->hr_class;
1104 int n;
1105 int add_to_list, clear = 0;
1106
1107 hh = (msg_header_t **)((char *)mo + hr->hr_offset);
1108
1109 add_to_list = (hc->hc_kind == msg_kind_list && !copy_buffer && *hh);
1110
1111 if (add_to_list)
1112 h = *hh;
1113 else
1114 h = msg_header_alloc(home, hc, copy_buffer ? slen + 1 : 0);
1115
1116 if (!h)
1117 return NULL((void*)0);
1118
1119 if (copy_buffer)
1120 s = memcpy(MSG_HEADER_DATA(h)((char *)(h) + (h)->sh_common->h_class->hc_size), s, slen);
1121
1122 s[slen] = '\0';
1123
1124 if (hc->hc_kind == msg_kind_list && *hh) {
1125 n = hc->hc_parse(home, *hh, s, slen);
1126 /* Clear if adding new header disturbs existing headers */
1127 clear = *hh != h && !copy_buffer;
1128 if (clear)
1129 msg_fragment_clear((*hh)->sh_common);
1130 }
1131 else
1132 n = hc->hc_parse(home, h, s, slen);
1133
1134 if (n < 0) {
1135 msg->m_extract_err |= hr->hr_flags;
1136
1137 if (hc->hc_critical)
1138 mo->msg_flags |= MSG_FLG_ERROR;
1139
1140 clear = 0;
1141
1142 if (!add_to_list) {
1143 /* XXX - This should be done by msg_header_free_all() */
1144 msg_header_t *h_next;
1145 msg_param_t *h_params;
1146 msg_error_t *er;
1147
1148 while (h) {
1149 h_next = h->sh_nextsh_header_next->shn_next;
1150 if (hc->hc_params) {
1151 h_params = *(msg_param_t **)((char *)h + hc->hc_params);
1152 if (h_params)
1153 su_free(home, h_params);
1154 }
1155 su_free(home, h);
1156 h = h_next;
1157 }
1158 /* XXX - This should be done by msg_header_free_all() */
1159 hr = msg->m_class->mc_error;
1160 h = msg_header_alloc(home, hr->hr_class, 0);
1161 er = (msg_error_t *)h;
1162
1163 if (!er)
1164 return NULL((void*)0);
1165
1166 er->er_name = hc->hc_name;
1167 hh = (msg_header_t **)((char *)mo + hr->hr_offset);
1168 }
1169 }
1170
1171 if (clear)
1172 for (hh = &(*hh)->sh_nextsh_header_next->shn_next; *hh; *hh = (*hh)->sh_nextsh_header_next->shn_next)
1173 msg_chain_remove(msg, *hh);
1174 else if (h != *hh)
1175 append_parsed(msg, mo, hr, h, 0);
1176
1177 return h;
1178}
1179
1180static
1181msg_header_t *error_header_parse(msg_t *msg, msg_pub_t *mo,
1182 msg_href_t const *hr)
1183{
1184 msg_header_t *h;
1185
1186 h = msg_header_alloc(msg_home(msg)((su_home_t*)(msg)), hr->hr_class, 0);
1187 if (h)
1188 append_parsed(msg, mo, hr, h, 0);
1189
1190 return h;
1191}
1192
1193
1194/** Complete this header field and parse next header field.
1195 *
1196 * This function completes parsing a multi-field header like @Accept,
1197 * @Contact, @Via or @Warning. It scans for the next header field and
1198 * if one is found, it calls the parsing function recursively.
1199 *
1200 * @param home memory home used ot allocate
1201 * new header structures and parameter lists
1202 * @param prev pointer to header structure already parsed
1203 * @param s header content to parse; should point to the area after
1204 * current header field (either end of line or to a comma
1205 * separating header fields)
1206 * @param slen ignored
1207 *
1208 * @since New in @VERSION_1_12_4.
1209 *
1210 * @retval >= 0 when successful
1211 * @retval -1 upon an error
1212 */
1213issize_t msg_parse_next_field(su_home_t *home, msg_header_t *prev,
1214 char *s, isize_t slen)
1215{
1216 msg_hclass_t *hc = prev->sh_classsh_common->h_class;
1217 msg_header_t *h;
1218 char *end = s + slen;
1219
1220 if (*s && *s != ',')
1221 return -1;
1222
1223 if (msg_header_update_params(prev->sh_common, 0) < 0)
1224 return -1;
1225
1226 while (*s == ',') /* Skip comma and following whitespace */
1227 *s = '\0', s += span_lws(s + 1) + 1;
1228
1229 if (*s == 0)
1230 return 0;
1231
1232 h = msg_header_alloc(home, hc, 0);
1233 if (!h)
1234 return -1;
1235
1236 prev->sh_succsh_common->h_succ = h, h->sh_prevsh_common->h_prev = &prev->sh_succsh_common->h_succ;
1237 prev->sh_nextsh_header_next->shn_next = h;
1238
1239 return hc->hc_parse(home, h, s, end - s);
1240}
1241
1242
1243/** Decode a message header. */
1244msg_header_t *msg_header_d(su_home_t *home, msg_t const *msg, char const *b)
1245{
1246 msg_mclass_t const *mc = msg->m_class;
1247 msg_href_t const *hr = mc->mc_unknown;
Value stored to 'hr' during its initialization is never read
1248 isize_t n; /* Length of header contents */
1249 isize_t name_len, xtra;
1250 msg_header_t *h;
1251 char *bb;
1252
1253 n = strlen(b);
1254 hr = msg_find_hclass(mc, b, &name_len);
1255 if (hr == NULL((void*)0))
1256 return NULL((void*)0);
1257
1258 /* Strip extra whitespace at the end and begin of header */
1259 while (n > name_len && IS_LWS(b[n - 1])((b[n - 1]) == ' ' || (b[n - 1]) == '\t' || (b[n - 1]) == '\r'
|| (b[n - 1]) == '\n')
)
1260 n--;
1261 if (name_len < n && IS_LWS(b[name_len])((b[name_len]) == ' ' || (b[name_len]) == '\t' || (b[name_len
]) == '\r' || (b[name_len]) == '\n')
)
1262 name_len++;
1263
1264 xtra = (n - name_len);
1265 if (!(h = msg_header_alloc(home, hr->hr_class, xtra + 1)))
1266 return NULL((void*)0);
1267
1268 bb = memcpy(MSG_HEADER_DATA(h)((char *)(h) + (h)->sh_common->h_class->hc_size), b + name_len, xtra), bb[xtra] = 0;
1269
1270 if (hr->hr_class->hc_parse(home, h, bb, xtra) >= 0)
1271 return h;
1272
1273 hr = mc->mc_unknown;
1274 su_free(home, h);
1275 if (!(h = msg_header_alloc(home, hr->hr_class, n + 1)))
1276 return NULL((void*)0);
1277 bb = memcpy(MSG_HEADER_DATA(h)((char *)(h) + (h)->sh_common->h_class->hc_size), b, n), bb[n] = 0;
1278 if (hr->hr_class->hc_parse(home, h, bb, n) < 0)
1279 su_free(home, h), h = NULL((void*)0);
1280
1281 return h;
1282}
1283
1284/** Extract a separator line */
1285issize_t msg_extract_separator(msg_t *msg, msg_pub_t *mo,
1286 char b[], isize_t bsiz, int eos)
1287{
1288 msg_mclass_t const *mc = msg->m_class;
1289 msg_href_t const *hr = mc->mc_separator;
1290 int l = CRLF_TEST(b)((b)[0] == '\r' ? ((b)[1] == '\n') + 1 : (b)[0] =='\n'); /* Separator length */
1291 msg_header_t *h;
1292
1293 /* Even if a single CR *may* be a payload separator we cannot be sure */
1294 if (l == 0 || (!eos && bsiz == 1 && b[0] == '\r'))
1295 return 0;
1296
1297 /* Separator */
1298 if (!(h = msg_header_alloc(msg_home(msg)((su_home_t*)(msg)), hr->hr_class, 0)))
1299 return -1;
1300 if (hr->hr_class->hc_parse(msg_home(msg)((su_home_t*)(msg)), h, b, l) < 0)
1301 return -1;
1302
1303 h->sh_datash_common->h_data = b, h->sh_lensh_common->h_len = l;
1304
1305 append_parsed(msg, mo, hr, h, 0);
1306
1307 return l;
1308}
1309
1310su_inlinestatic inline msg_header_t **msg_chain_tail(msg_t const *msg);
1311
1312/** Extract a message body of @a body_len bytes.
1313 */
1314issize_t msg_extract_payload(msg_t *msg, msg_pub_t *mo,
1315 msg_header_t **return_payload,
1316 usize_t body_len,
1317 char b[], isize_t bsiz,
1318 int eos)
1319{
1320 msg_mclass_t const *mc;
1321 msg_href_t const *hr;
1322 msg_header_t *h, *h0;
1323 msg_payload_t *pl;
1324 char *x;
1325
1326 if (msg == NULL((void*)0) || mo == NULL((void*)0))
1327 return -1;
1328
1329 assert(!msg->m_chunk)((!msg->m_chunk) ? (void) (0) : __assert_fail ("!msg->m_chunk"
, "msg_parser.c", 1329, __PRETTY_FUNCTION__))
;
1330 mc = msg->m_class;
1331 hr = mc->mc_payload;
1332
1333 if (return_payload == NULL((void*)0))
1334 return_payload = &h0;
1335 *return_payload = NULL((void*)0);
1336
1337 assert(body_len > 0)((body_len > 0) ? (void) (0) : __assert_fail ("body_len > 0"
, "msg_parser.c", 1337, __PRETTY_FUNCTION__))
;
1338
1339 /* Allocate header structure for payload */
1340 if (!(h = msg_header_alloc(msg_home(msg)((su_home_t*)(msg)), hr->hr_class, 0)))
1341 return -1;
1342
1343 append_parsed(msg, mo, hr, h, 0);
1344 pl = (msg_payload_t*)h;
1345 *return_payload = h;
1346
1347 if (bsiz >= body_len) {
1348 /* We have a complete body. */
1349 h->sh_datash_common->h_data = b, h->sh_lensh_common->h_len = body_len;
1350 pl->pl_data = b, pl->pl_len = body_len;
1351 return body_len;
1352 }
1353
1354 if (msg->m_maxsize != 0 && body_len > msg->m_maxsize) {
1355 mo->msg_flags |= MSG_FLG_TOOLARGE;
1356 return -1;
1357 }
1358
1359 assert(msg->m_buffer->mb_commit == bsiz)((msg->m_buffer->mb_commit == bsiz) ? (void) (0) : __assert_fail
("msg->m_buffer->mb_commit == bsiz", "msg_parser.c", 1359
, __PRETTY_FUNCTION__))
;
1360 assert(b == msg->m_buffer->mb_data + msg->m_buffer->mb_used)((b == msg->m_buffer->mb_data + msg->m_buffer->mb_used
) ? (void) (0) : __assert_fail ("b == msg->m_buffer->mb_data + msg->m_buffer->mb_used"
, "msg_parser.c", 1360, __PRETTY_FUNCTION__))
;
1361
1362 if (msg->m_buffer->mb_used + body_len <= msg->m_buffer->mb_size) {
1363 /* We don't have a complete body, but we have big enough buffer for it. */
1364 msg->m_chunk = pl;
1365
1366 h->sh_datash_common->h_data = b, h->sh_lensh_common->h_len = bsiz;
1367 pl->pl_data = b, pl->pl_len = body_len;
1368
1369 if (msg->m_buffer->mb_used + body_len < msg->m_buffer->mb_size)
1370 /* NUL-terminate payload */
1371 b[body_len++] = '\0';
1372
1373 /* Mark the rest of the body as used in the buffer */
1374 /* msg_buf_commit(msg, body_len - bsiz, eos); */
1375 msg_buf_used(msg, body_len);
1376
1377 return bsiz;
1378 }
1379
1380 /* We don't have big enough buffer for body. */
1381
1382 if (msg_get_flags(msg, MSG_FLG_CHUNKING)) {
1383 /* Application supports chunking, use multiple chunks for payload */
1384 usize_t current, rest;
1385
1386 current = msg->m_buffer->mb_size - msg->m_buffer->mb_used;
1387 rest = body_len - current;
1388
1389 /* Use all the data from our current buffer */
1390 msg_buf_used(msg, current);
1391
1392 msg->m_chunk = pl;
1393
1394 h->sh_datash_common->h_data = b, h->sh_lensh_common->h_len = bsiz;
1395 pl->pl_data = b, pl->pl_len = current;
1396
1397 for (;current < body_len; current += rest) {
1398 msg_header_t *h0 = h;
1399
1400 /* Allocate header structure for next payload chunk */
1401 if (!(h = msg_header_alloc(msg_home(msg)((su_home_t*)(msg)), hr->hr_class, 0)))
1402 return -1;
1403 if (msg->m_chain)
1404 msg_insert_here_in_chain(msg, msg_chain_tail(msg), h);
1405 h0->sh_nextsh_header_next->shn_next = h;
1406
1407 rest = body_len - current;
1408
1409 if (!msg->m_streaming) {
1410 x = msg_buf_exact(msg, rest);
1411 if (x == NULL((void*)0)) {
1412 mo->msg_flags |= MSG_FLG_TOOLARGE;
1413 return -1;
1414 }
1415 }
1416 else {
1417 x = NULL((void*)0);
1418 }
1419
1420 if (x) {
1421 /* Mark the just-allocated buffer as used */
1422 rest = msg->m_buffer->mb_size - msg->m_buffer->mb_used;
1423 msg_buf_used(msg, rest);
1424 }
1425
1426 pl = h->sh_payload;
1427
1428 h->sh_lensh_common->h_len = 0, pl->pl_len = rest;
1429 h->sh_datash_common->h_data = x, pl->pl_data = x;
1430 }
1431 }
1432 else {
1433 /* No chunking.
1434 *
1435 * Allocate a single buffer that contains enough free space for body.
1436 *
1437 * msg_buf_exact() also copies committed but un-used data
1438 * from the old buffer (b[0] .. b[bsiz])
1439 * to the new buffer (x[-bsiz-1]..b[-1])
1440 */
1441 if (!(x = msg_buf_exact(msg, body_len - bsiz + 1))) {
1442 if (mo->msg_flags & MSG_FLG_TOOLARGE) {
1443 msg_mark_as_complete(msg, MSG_FLG_TRUNC);
1444 return bsiz;
1445 }
1446 return -1;
1447 }
1448
1449 /* Fake un-received data as already received and then use it */
1450 /* msg_buf_commit(msg, body_len - bsiz + 1, eos); */
1451 msg_buf_used(msg, body_len + 1);
1452
1453 msg->m_chunk = h->sh_payload;
1454
1455 x -= bsiz; /* Start of un-used data */
1456 x[body_len] = '\0';
1457
1458 h->sh_datash_common->h_data = x, h->sh_lensh_common->h_len = bsiz;
1459 pl->pl_data = x, pl->pl_len = body_len;
1460
1461 assert(MSG_CHUNK_AVAIL(pl) == body_len - bsiz)((((pl)->pl_len + ((pl)->pl_data - (char *)pl->pl_common
->h_data) - (pl)->pl_common->h_len) == body_len - bsiz
) ? (void) (0) : __assert_fail ("((pl)->pl_len + ((pl)->pl_data - (char *)pl->pl_common->h_data) - (pl)->pl_common->h_len) == body_len - bsiz"
, "msg_parser.c", 1461, __PRETTY_FUNCTION__))
;
1462 }
1463
1464 return bsiz;
1465}
1466
1467/** Extract incomplete chunks.
1468 */
1469su_inlinestatic inline
1470int extract_incomplete_chunks(msg_t *msg, int eos)
1471{
1472 msg_payload_t *chunk;
1473
1474 for (chunk = msg->m_chunk; chunk; chunk = MSG_CHUNK_NEXT(chunk)((chunk)->pl_next)) {
1475 if (MSG_CHUNK_AVAIL(chunk)((chunk)->pl_len + ((chunk)->pl_data - (char *)chunk->
pl_common->h_data) - (chunk)->pl_common->h_len)
!= 0)
1476 break;
1477
1478 /* The incomplete payload fragment is now complete */
1479 assert(MSG_CHUNK_BUFFER(chunk) == chunk->pl_data + chunk->pl_len)((((char *)chunk->pl_common->h_data + (chunk)->pl_common
->h_len) == chunk->pl_data + chunk->pl_len) ? (void)
(0) : __assert_fail ("((char *)chunk->pl_common->h_data + (chunk)->pl_common->h_len) == chunk->pl_data + chunk->pl_len"
, "msg_parser.c", 1479, __PRETTY_FUNCTION__))
;
1480
1481 msg->m_size += chunk->pl_common->h_len;
1482 }
1483
1484 msg->m_chunk = chunk;
1485
1486 if (chunk) {
1487 if (eos) {
1488 msg_mark_as_complete(msg, MSG_FLG_TRUNC);
1489 return 1;
1490 }
1491 }
1492 else {
1493 if (msg_get_flags(msg, MSG_FLG_FRAGS))
1494 msg_mark_as_complete(msg, 0);
1495 }
1496
1497 /**@retval 1 when message is complete
1498 * @retval 0 when message is incomplete
1499 * @retval -1 upon an error
1500 */
1501 return chunk == NULL((void*)0);
1502}
1503
1504/* Extract trailers */
1505su_inlinestatic inline issize_t
1506extract_trailers(msg_t *msg, msg_pub_t *mo,
1507 char *b, isize_t bsiz, int eos, int copy)
1508{
1509 if (IS_CRLF(b[0])((b[0]) == '\r' || (b[0]) == '\n')) {
1510 msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
1511 return CRLF_TEST(b)((b)[0] == '\r' ? ((b)[1] == '\n') + 1 : (b)[0] =='\n');
1512 }
1513 else
1514 return extract_header(msg, mo, b, bsiz, eos, copy);
1515}
1516
1517/* ====================================================================== */
1518/* Preparing (printing/encoding) a message structure for sending */
1519
1520/* Internal prototypes */
1521su_inlinestatic inline size_t
1522msg_header_name_e(char b[], size_t bsiz, msg_header_t const *h, int flags);
1523static size_t msg_header_prepare(msg_mclass_t const *, int flags,
1524 msg_header_t *h, msg_header_t **return_next,
1525 char *b, size_t bsiz);
1526
1527/**Encode all message fragments.
1528 *
1529 * @relatesalso msg_s
1530 *
1531 * The function msg_prepare() prepares a message for sending. It encodes all
1532 * serialized fragments in the message. You have to call msg_serialize()
1533 * before calling msg_headers_prepare() in order to make sure that all the
1534 * heades and other message fragments are included in the chain.
1535 *
1536 * After encoding, the msg_common_s::h_data field will point to the encoding
1537 * result of size msg_common_s::h_len bytes in in each fragment.
1538 *
1539 * When multiple header fields are represented as a comma-separated list
1540 * within a single header line, the first fragment in the header will
1541 * contain all the text belonging to the header. The rest of the header
1542 * fields will have zero-length encoding with msg_common_s::h_data that
1543 * points to the end of the line.
1544 *
1545 * @return Total size of the encoded message in bytes, or -1 upon an error.
1546 *
1547 * @sa msg_extract(), msg_serialize()
1548 */
1549int msg_prepare(msg_t *msg)
1550{
1551 int total;
1552
1553 assert(msg->m_chain)((msg->m_chain) ? (void) (0) : __assert_fail ("msg->m_chain"
, "msg_parser.c", 1553, __PRETTY_FUNCTION__))
;
1554 assert(msg_chain_errors(msg->m_chain) == 0)((msg_chain_errors(msg->m_chain) == 0) ? (void) (0) : __assert_fail
("msg_chain_errors(msg->m_chain) == 0", "msg_parser.c", 1554
, __PRETTY_FUNCTION__))
;
1555
1556 /* Get rid of data that was received but not yet used (parsed) */
1557 msg_clear_committed(msg);
1558
1559 total = msg_headers_prepare(msg, msg->m_chain, msg_object(msg)->msg_flags);
1560
1561 if (total != -1) {
1562 msg->m_size = total;
1563 msg->m_prepared = 1;
1564 }
1565
1566 return total;
1567}
1568
1569/** Clear 'prepared' flag. */
1570void msg_unprepare(msg_t *msg)
1571{
1572 if (msg) msg->m_prepared = 0;
1573}
1574
1575/** Return true if message is prepared. */
1576int msg_is_prepared(msg_t const *msg)
1577{
1578 return msg && msg->m_prepared;
1579}
1580
1581/**Encode headers in chain.
1582 *
1583 * The function msg_headers_prepare() encodes all the headers in the header
1584 * chain. You have to call msg_serialize() before calling
1585 * msg_headers_prepare() in order to make sure that all the heades and other
1586 * message fragments are included in the chain.
1587 *
1588 * @return
1589 * The size of all the headers in chain, or -1 upon an error.
1590 */
1591issize_t msg_headers_prepare(msg_t *msg, msg_header_t *headers, int flags)
1592{
1593 msg_mclass_t const *mc = msg->m_class;
1594 msg_header_t *h, *next;
1595 ssize_t n = 0;
1596 size_t bsiz = 0, used = 0;
1597 char *b;
1598 size_t total = 0;
1599
1600 b = msg_buf_alloc(msg, msg_min_size);
1601 bsiz = msg_buf_size(msg);
1602
1603 if (!b)
1604 return -1;
1605
1606 for (h = headers; h;) {
1607
1608 if (h->sh_datash_common->h_data) {
1609 total += h->sh_lensh_common->h_len;
1610 h = h->sh_succsh_common->h_succ;
1611 continue;
1612 }
1613
1614 for (next = h->sh_succsh_common->h_succ; next; next = next->sh_succsh_common->h_succ)
1615 if (next->sh_classsh_common->h_class != h->sh_classsh_common->h_class || next->sh_datash_common->h_data)
1616 break;
1617
1618 n = msg_header_prepare(mc, flags, h, &next, b, bsiz - used);
1619
1620 if (n == (ssize_t)-1) {
1621 errno(*__errno_location ()) = EINVAL22;
1622 return -1;
1623 }
1624
1625 if (used + n >= bsiz) {
1626 /* Allocate next buffer */
1627 if ((b = msg_buf_alloc(msg, n + 1)) == NULL((void*)0))
1628 return -1;
1629 bsiz = msg_buf_size(msg); used = 0;
1630 continue;
1631 }
1632
1633 h->sh_datash_common->h_data = b, h->sh_lensh_common->h_len = n;
1634
1635 for (h = h->sh_succsh_common->h_succ; h != next; h = h->sh_succsh_common->h_succ)
1636 h->sh_datash_common->h_data = b + n, h->sh_lensh_common->h_len = 0;
1637
1638 msg_buf_used(msg, n);
1639
1640 total += n;
1641 used += n;
1642 b += n;
1643 }
1644
1645 return total;
1646}
1647
1648/** Encode a header or a list of headers */
1649static
1650size_t msg_header_prepare(msg_mclass_t const *mc, int flags,
1651 msg_header_t *h, msg_header_t **return_next,
1652 char *b, size_t bsiz)
1653{
1654 msg_header_t *h0, *next;
1655 msg_hclass_t *hc;
1656 char const *s;
1657 size_t n; ssize_t m;
1658 int compact, one_line_list, comma_list;
1659
1660 assert(h)((h) ? (void) (0) : __assert_fail ("h", "msg_parser.c", 1660,
__PRETTY_FUNCTION__))
; assert(h->sh_class)((h->sh_common->h_class) ? (void) (0) : __assert_fail (
"h->sh_common->h_class", "msg_parser.c", 1660, __PRETTY_FUNCTION__
))
;
1661
1662 hc = h->sh_classsh_common->h_class;
1663 compact = MSG_IS_COMPACT(flags)((((flags)) & (MSG_FLG_COMPACT)) == MSG_FLG_COMPACT);
1664 one_line_list = hc->hc_kind == msg_kind_apndlist;
1665 comma_list = compact || one_line_list || MSG_IS_COMMA_LISTS(flags)((((flags)) & (MSG_FLG_COMMA_LISTS)) == MSG_FLG_COMMA_LISTS
)
;
1666
1667 for (h0 = h, n = 0; ; h = next) {
1668 next = h->sh_succsh_common->h_succ;
1669
1670 if (h == h0 && hc->hc_name && hc->hc_name[0])
1671 n += msg_header_name_e(b + n, bsiz >= n ? bsiz - n : 0, h, flags);
1672
1673 if ((m = hc->hc_print(b + n, bsiz >= n ? bsiz - n : 0, h, flags)) == -1) {
1674 if (bsiz >= n + 64)
1675 m = 2 * (bsiz - n);
1676 else
1677 m = 128;
1678 }
1679
1680 n += m;
1681
1682 if (hc->hc_name) {
1683 if (!hc->hc_name[0] || !comma_list || !next || next == *return_next)
1684 s = CRLF"\r" "\n", m = 2;
1685 /* Else encode continuation */
1686 else if (compact)
1687 s = ",", m = 1;
1688 else if (one_line_list)
1689 s = ", ", m = 2;
1690 else
1691 s = "," CRLF"\r" "\n" "\t", m = 4;
1692
1693 if (bsiz > n + m)
1694 memcpy(b + n, s, m);
1695 n += m;
1696 }
1697
1698 if (!comma_list || !next || next == *return_next)
1699 break;
1700 }
1701
1702 *return_next = next;
1703
1704 return n;
1705}
1706
1707/** Encode a header.
1708 *
1709 * The function msg_header_e() encodes a header field in the buffer @a
1710 * b[]. The encoding includes its name and trailing CRLF. The function
1711 * returns the length of the encoding in bytes, excluding the final @c NUL.
1712 * The buffer @a b must be large enough for whole encoding, including the
1713 * final @c NUL.
1714 *
1715 * The @a flags parameter define how the encoding is done. If the flags
1716 * specify @c MSG_DO_COMPACT, the encoding is compact (short form with
1717 * minimal whitespace).
1718 */
1719issize_t msg_header_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
1720{
1721 size_t n, m;
1722
1723 assert(h)((h) ? (void) (0) : __assert_fail ("h", "msg_parser.c", 1723,
__PRETTY_FUNCTION__))
; assert(h->sh_class)((h->sh_common->h_class) ? (void) (0) : __assert_fail (
"h->sh_common->h_class", "msg_parser.c", 1723, __PRETTY_FUNCTION__
))
;
1724
1725 if (h == NULL((void*)0) || h->sh_classsh_common->h_class == NULL((void*)0))
1726 return -1;
1727
1728 n = msg_header_name_e(b, bsiz, h, flags);
1729 m = h->sh_classsh_common->h_class->hc_print(b + n, bsiz > n ? bsiz - n : 0, h, flags);
1730 if (h->sh_classsh_common->h_class->hc_name) {
1731 /* Ordinary header */
1732 if (bsiz > n + m + strlen(CRLF"\r" "\n"))
1733 strcpy(b + n + m, CRLF"\r" "\n");
1734 return n + m + strlen(CRLF"\r" "\n");
1735 }
1736 else
1737 return m;
1738}
1739
1740/** Encode header name */
1741su_inlinestatic inline
1742size_t
1743msg_header_name_e(char b[], size_t bsiz, msg_header_t const *h, int flags)
1744{
1745 int compact = MSG_IS_COMPACT(flags)((((flags)) & (MSG_FLG_COMPACT)) == MSG_FLG_COMPACT);
1746 char const *name;
1747 size_t n, n2;
1748
1749 if (compact && h->sh_classsh_common->h_class->hc_short[0])
1750 name = h->sh_classsh_common->h_class->hc_short, n = 1;
1751 else
1752 name = h->sh_classsh_common->h_class->hc_name, n = h->sh_classsh_common->h_class->hc_len;
1753
1754 if (!name || !name[0])
1755 return 0;
1756
1757 n2 = compact ? n + 1 : n + 2;
1758
1759 if (n2 < bsiz) {
1760 memcpy(b, name, n);
1761 b[n++] = ':';
1762 if (!compact)
1763 b[n++] = ' ';
1764 b[n++] = '\0';
1765 }
1766
1767 return n2;
1768}
1769
1770/** Convert a message to a string.
1771 *
1772 * A message is encoded and the encoding result is returned as a string.
1773 * Because the message may contain binary payload (or NUL in headers), the
1774 * message length is returned separately in @a *return_len, too.
1775 *
1776 * Note that the message is serialized as a side effect.
1777 *
1778 * @param home memory home used to allocate the string
1779 * @param msg message to encode
1780 * @param pub message object to encode (may be NULL)
1781 * @param flags flags used when encoding
1782 * @param return_len return-value parameter for encoded message length
1783 *
1784 * @return Encoding result as a C string.
1785 *
1786 * @since New in @VERSION_1_12_4
1787 *
1788 * @sa msg_make(), msg_prepare(), msg_serialize().
1789 */
1790char *msg_as_string(su_home_t *home, msg_t *msg, msg_pub_t *pub, int flags,
1791 size_t *return_len)
1792{
1793 msg_mclass_t const *mc = msg->m_class;
1794 msg_header_t *h, *next;
1795 ssize_t n = 0;
1796 size_t bsiz = 0, used = 0;
1797 char *b, *b2;
1798
1799 if (pub == NULL((void*)0))
1800 pub = msg->m_object;
1801
1802 if (msg_serialize(msg, pub) < 0)
1803 return NULL((void*)0);
1804
1805 if (return_len == NULL((void*)0))
1806 return_len = &used;
1807
1808 b = su_alloc(home, bsiz = msg_min_size);
1809
1810 if (!b)
1811 return NULL((void*)0);
1812
1813 if (pub == msg->m_object)
1814 h = msg->m_chain;
1815 else
1816 h = pub->msg_common->h_succ;
1817
1818 while (h) {
1819 for (next = h->sh_succsh_common->h_succ; next; next = next->sh_succsh_common->h_succ)
1820 if (next->sh_classsh_common->h_class != h->sh_classsh_common->h_class)
1821 break;
1822
1823 n = msg_header_prepare(mc, flags, h, &next, b + used, bsiz - used);
1824
1825 if (n == -1) {
1826 errno(*__errno_location ()) = EINVAL22;
1827 su_free(home, b);
1828 return NULL((void*)0);
1829 }
1830
1831 if (bsiz > used + n) {
1832 used += n;
1833 h = next;
1834 }
1835 else {
1836 /* Realloc */
1837 if (h->sh_succsh_common->h_succ)
1838 bsiz = (used + n + msg_min_size) / msg_min_size * msg_min_size;
1839 else
1840 bsiz = used + n + 1;
1841
1842 if (bsiz < msg_min_size) {
1843 errno(*__errno_location ()) = ENOMEM12;
1844 su_free(home, b);
1845 return NULL((void*)0);
1846 }
1847
1848 b2 = su_realloc(home, b, bsiz);
1849
1850 if (b2 == NULL((void*)0)) {
1851 errno(*__errno_location ()) = ENOMEM12;
1852 su_free(home, b);
1853 return NULL((void*)0);
1854 }
1855
1856 b = b2;
1857
1858 continue;
1859 }
1860 }
1861
1862 *return_len = used;
1863
1864 b[used] = '\0'; /* NUL terminate */
1865
1866 return su_realloc(home, b, used + 1);
1867}
1868
1869/* ====================================================================== */
1870/* Handling header chain */
1871
1872su_inlinestatic inline void serialize_first(msg_t *msg, msg_header_t *h);
1873static msg_header_t **serialize_one(msg_t *msg, msg_header_t *h,
1874 msg_header_t **prev);
1875
1876/** Return head of the fragment chain */
1877msg_header_t **msg_chain_head(msg_t const *msg)
1878{
1879 return msg ? (msg_header_t **)&msg->m_chain : NULL((void*)0);
1880}
1881
1882su_inlinestatic inline msg_header_t **_msg_chain_head(msg_t const *msg)
1883{
1884 return msg ? (msg_header_t **)&msg->m_chain : NULL((void*)0);
1885}
1886
1887/** Return tail of the fragment chain */
1888su_inlinestatic inline msg_header_t **msg_chain_tail(msg_t const *msg)
1889{
1890 return msg ? msg->m_tail : NULL((void*)0);
1891}
1892
1893/** Serialize headers into the fragment chain.
1894 *
1895 * The msg_serialize() collects the headers and other message components in
1896 * the fragment chain. It should be called before msg_prepare().
1897 *
1898 * @relatesalso msg_s
1899 *
1900 * @param msg pointer to message object
1901 * @param pub public message structure
1902 *
1903 * @retval 0 when successful
1904 * @retval -1 upon an error
1905 */
1906int msg_serialize(msg_t *msg, msg_pub_t *pub)
1907{
1908 msg_header_t *h, **hh, **end;
1909 msg_header_t **separator;
1910 msg_header_t **payload;
1911 msg_header_t **multipart;
1912 msg_mclass_t const *mc;
1913 msg_header_t **tail, ***ptail;
1914
1915 if (!msg)
1916 return errno(*__errno_location ()) = EINVAL22, -1;
1917 if (pub == NULL((void*)0))
1918 pub = msg->m_object;
1919
1920 /* There must be a first line */
1921 if (pub->msg_request)
1922 h = pub->msg_request;
1923 else if (pub->msg_status)
1924 h = pub->msg_status;
1925 else
1926 return errno(*__errno_location ()) = EINVAL22, -1;
1927
1928 serialize_first(msg, h);
1929
1930 mc = msg->m_class;
1931 separator = (msg_header_t **)((char *)pub + mc->mc_separator->hr_offset);
1932 payload = (msg_header_t **)((char *)pub + mc->mc_payload->hr_offset);
1933 if (mc->mc_multipart->hr_class)
1934 multipart = (msg_header_t **)((char *)pub + mc->mc_multipart->hr_offset);
1935 else
1936 multipart = NULL((void*)0);
1937
1938 /* Find place to insert headers: before separator, payload and multipart */
1939 if (*separator && !msg_header_is_removed(*separator)((*separator)->sh_common->h_prev == ((void*)0)))
1940 ptail = &(*separator)->sh_prevsh_common->h_prev;
1941 else if (*payload && !msg_header_is_removed(*payload)((*payload)->sh_common->h_prev == ((void*)0)))
1942 ptail = &(*payload)->sh_prevsh_common->h_prev;
1943 else if (multipart && *multipart && !msg_header_is_removed(*multipart)((*multipart)->sh_common->h_prev == ((void*)0)))
1944 ptail = &(*multipart)->sh_prevsh_common->h_prev;
1945 else
1946 ptail = &msg->m_tail;
1947
1948 tail = *ptail;
1949
1950 end = (msg_header_t **)((char *)pub + pub->msg_size);
1951
1952 for (hh = pub->msg_headers; hh < end; hh++) {
1953 if (!*hh)
1954 continue;
1955 if (hh == separator || hh == payload || hh == multipart)
1956 continue;
1957 tail = serialize_one(msg, *hh, tail);
1958 }
1959
1960 /* Serialize separator, payload and multipart last */
1961 if (*separator)
1962 tail = serialize_one(msg, *separator, tail);
1963
1964 *ptail = tail;
1965
1966 /* Payload comes after separator but before multipart */
1967 if (ptail != &(*separator)->sh_prevsh_common->h_prev)
1968 ;
1969 else if (*payload && !msg_header_is_removed(*payload)((*payload)->sh_common->h_prev == ((void*)0)))
1970 ptail = &(*payload)->sh_prevsh_common->h_prev;
1971 else if (multipart && *multipart && !msg_header_is_removed(*multipart)((*multipart)->sh_common->h_prev == ((void*)0)))
1972 ptail = &(*multipart)->sh_prevsh_common->h_prev;
1973 else
1974 ptail = &msg->m_tail;
1975
1976 tail = *ptail;
1977
1978 if (*payload) {
1979 tail = serialize_one(msg, *payload, tail);
1980 *ptail = tail;
1981 }
1982
1983 if (multipart && *multipart) {
1984 msg_header_t *last;
1985
1986 last = msg_multipart_serialize(tail, (msg_multipart_t *)*multipart);
1987
1988 msg->m_tail = &last->sh_succsh_common->h_succ;
1989 }
1990
1991 assert(msg->m_chain && msg_chain_errors(msg->m_chain) == 0)((msg->m_chain && msg_chain_errors(msg->m_chain
) == 0) ? (void) (0) : __assert_fail ("msg->m_chain && msg_chain_errors(msg->m_chain) == 0"
, "msg_parser.c", 1991, __PRETTY_FUNCTION__))
;
1992
1993 return 0;
1994}
1995
1996su_inlinestatic inline
1997void serialize_first(msg_t *msg, msg_header_t *h)
1998{
1999 if (msg_header_is_removed(h)((h)->sh_common->h_prev == ((void*)0))) {
2000 if ((h->sh_succsh_common->h_succ = msg->m_chain))
2001 h->sh_succsh_common->h_succ->sh_prevsh_common->h_prev = &h->sh_succsh_common->h_succ;
2002 else
2003 msg->m_tail = &h->sh_succsh_common->h_succ;
2004 *(h->sh_prevsh_common->h_prev = &msg->m_chain) = h;
2005 }
2006}
2007
2008static
2009msg_header_t **serialize_one(msg_t *msg, msg_header_t *h, msg_header_t **prev)
2010{
2011 msg_header_t *last;
2012 msg_header_t *succ = *prev;
2013
2014 if (msg_header_is_removed(h)((h)->sh_common->h_prev == ((void*)0))) {
2015 /* Add the first header in the list to the chain */
2016 *prev = h; h->sh_prevsh_common->h_prev = prev;
2017 for (last = h; last->sh_succsh_common->h_succ; last = last->sh_succsh_common->h_succ) {
2018 /* Ensure that chain is connected */
2019 assert(last->sh_next == last->sh_succ)((last->sh_header_next->shn_next == last->sh_common->
h_succ) ? (void) (0) : __assert_fail ("last->sh_header_next->shn_next == last->sh_common->h_succ"
, "msg_parser.c", 2019, __PRETTY_FUNCTION__))
;
2020 assert(last->sh_succ->sh_prev = &last->sh_succ)((last->sh_common->h_succ->sh_common->h_prev = &
last->sh_common->h_succ) ? (void) (0) : __assert_fail (
"last->sh_common->h_succ->sh_common->h_prev = &last->sh_common->h_succ"
, "msg_parser.c", 2020, __PRETTY_FUNCTION__))
;
2021 }
2022 prev = &last->sh_succsh_common->h_succ;
2023 }
2024
2025 if ((h = h->sh_nextsh_header_next->shn_next)) {
2026 assert(!msg_is_single(h))((!msg_is_single(h)) ? (void) (0) : __assert_fail ("!msg_is_single(h)"
, "msg_parser.c", 2026, __PRETTY_FUNCTION__))
;
2027
2028 if (msg_is_single(h)) {
2029 for (; h; h = h->sh_nextsh_header_next->shn_next)
2030 if (!msg_header_is_removed(h)((h)->sh_common->h_prev == ((void*)0)))
2031 msg_chain_remove(msg, h);
2032 }
2033 /* Add the rest of the headers in the list to the chain */
2034 else for (; h; h = h->sh_nextsh_header_next->shn_next) {
2035 if (msg_header_is_removed(h)((h)->sh_common->h_prev == ((void*)0))) {
2036 *prev = h; h->sh_prevsh_common->h_prev = prev;
2037 for (;h->sh_succsh_common->h_succ; h = h->sh_succsh_common->h_succ)
2038 assert(h->sh_succ == h->sh_next)((h->sh_common->h_succ == h->sh_header_next->shn_next
) ? (void) (0) : __assert_fail ("h->sh_common->h_succ == h->sh_header_next->shn_next"
, "msg_parser.c", 2038, __PRETTY_FUNCTION__))
;
2039 prev = &h->sh_succsh_common->h_succ;
2040 }
2041 }
2042 }
2043
2044 *prev = succ;
2045
2046 return prev;
2047}
2048
2049/**Fill an I/O vector with message contents.
2050 *
2051 * @relatesalso msg_s
2052 *
2053 * Calculate number of entries in the I/O vector
2054 * required to send a message @a msg. It also fills in the I/O vector array,
2055 * if it is provided by the caller and it is large enough.
2056 *
2057 * @param msg pointer to message object
2058 * @param vec I/O vector (may be NULL)
2059 * @param veclen length of I/O vector in @a vec
2060 *
2061 * @return
2062 * Number of entries of I/O
2063 * vector required by @a msg, or 0 upon an error.
2064 *
2065 * @note The caller should check that the I/O vector @a vec has enough
2066 * entries. If the @a vec is too short, it should allocate big enough
2067 * vector and re-invoke msg_iovec().
2068 *
2069 * @sa msg_recv_iovec(), su_vsend()
2070 */
2071isize_t msg_iovec(msg_t *msg, msg_iovec_t vec[], isize_t veclen)
2072{
2073 size_t len = 0, n = 0;
2074 char const *p = NULL((void*)0);
2075 msg_header_t *h;
2076
2077 size_t total = 0;
2078
2079 if (veclen <= 0)
2080 veclen = 0;
2081
2082 for (h = msg->m_chain; h; h = h->sh_succsh_common->h_succ) {
2083 if (h->sh_datash_common->h_data != p) {
2084 p = h->sh_datash_common->h_data; len = h->sh_lensh_common->h_len;
2085
2086 if (p == NULL((void*)0))
2087 return 0;
2088
2089 if (vec && n != veclen)
2090 /* new iovec entry */
2091 vec[n].mv_basesiv_base = (void *)p, vec[n].mv_lensiv_len = (su_ioveclen_t)len;
2092 else
2093 vec = NULL((void*)0);
2094
2095 p += len; n++;
2096 }
2097 else {
2098 /* extend old entry */
2099 len = h->sh_lensh_common->h_len;
2100 if (vec)
2101 vec[n-1].mv_lensiv_len += (su_ioveclen_t)len;
2102 p += len;
2103 }
2104
2105 total += len;
2106 }
2107
2108 msg->m_size = total;
2109
2110 return n;
2111}
2112
2113/** Insert a header to existing header chain.
2114 *
2115 * Headers are either inserted just before the payload, or after the first
2116 * line, depending on their type.
2117 *
2118 * @param[in] msg message object
2119 * @param[in,out] pub public message structure
2120 * @param prepend if true, add before same type of headers (instead after them)
2121 * @param head head of chain
2122 * @param h header to insert
2123 *
2124 */
2125static
2126void msg_insert_chain(msg_t *msg,
2127 msg_pub_t *pub,
2128 int prepend,
2129 msg_header_t **head,
2130 msg_header_t *h)
2131{
2132 msg_mclass_t const *mc;
2133 msg_header_t **hh;
2134 msg_header_t **separator;
2135 msg_header_t **payload;
2136
2137 assert(msg && pub && head && h)((msg && pub && head && h) ? (void) (
0) : __assert_fail ("msg && pub && head && h"
, "msg_parser.c", 2137, __PRETTY_FUNCTION__))
;
2138
2139 mc = msg->m_class;
2140 separator = (msg_header_t **)((char *)pub + mc->mc_separator->hr_offset);
2141 payload = (msg_header_t **)((char *)pub + mc->mc_payload->hr_offset);
2142
2143 if (msg_is_request(h)) {
2144 if (pub->msg_status)
2145 pub->msg_status = NULL((void*)0);
2146 hh = head;
2147 }
2148 else if (msg_is_status(h)) {
2149 if (pub->msg_request)
2150 pub->msg_request = NULL((void*)0);
2151 hh = head;
2152 }
2153 else if (msg_is_payload(h)) {
2154 /* Append */
2155 hh = msg_chain_tail(msg);
2156 }
2157 else if (prepend) {
2158 if (!msg_is_request(*head) && !msg_is_status(*head))
2159 hh = head;
2160 else
2161 hh = &((*head)->sh_succsh_common->h_succ);
2162 }
2163 /* Append headers before separator or payload */
2164 else if (*separator && (*separator)->sh_prevsh_common->h_prev)
2165 hh = (*separator)->sh_prevsh_common->h_prev;
2166 else if (*payload && (*payload)->sh_prevsh_common->h_prev)
2167 hh = (*payload)->sh_prevsh_common->h_prev;
2168 else
2169 hh = msg_chain_tail(msg);
2170
2171 msg_insert_here_in_chain(msg, hh, h);
2172}
2173
2174/** Insert one or more message header to the chain.
2175 *
2176 * The function msg_insert_here_in_chain() appends message header to the
2177 * chain of headers after the given header.
2178 *
2179 * @param msg message
2180 * @param prev pointer to h_succ of previous fragment in the list
2181 * @param h header to be inserted.
2182 *
2183 * @return The pointer to the last header inserted.
2184 */
2185static
2186void msg_insert_here_in_chain(msg_t *msg,
2187 msg_header_t **prev,
2188 msg_header_t *h)
2189{
2190 if (h) {
2191 msg_header_t *last, *next;
2192 assert(h->sh_prev == NULL)((h->sh_common->h_prev == ((void*)0)) ? (void) (0) : __assert_fail
("h->sh_common->h_prev == ((void*)0)", "msg_parser.c",
2192, __PRETTY_FUNCTION__))
;
2193 assert(prev)((prev) ? (void) (0) : __assert_fail ("prev", "msg_parser.c",
2193, __PRETTY_FUNCTION__))
;
2194 assert(!msg_chain_errors(h))((!msg_chain_errors(h)) ? (void) (0) : __assert_fail ("!msg_chain_errors(h)"
, "msg_parser.c", 2194, __PRETTY_FUNCTION__))
;
2195
2196 for (last = h; last->sh_succsh_common->h_succ; last = last->sh_succsh_common->h_succ)
2197 ;
2198
2199 last->sh_succsh_common->h_succ = next = *prev;
2200 *prev = h;
2201 h->sh_prevsh_common->h_prev = prev;
2202 if (next)
2203 next->sh_prevsh_common->h_prev = &last->sh_succsh_common->h_succ;
2204 else
2205 msg->m_tail = &last->sh_succsh_common->h_succ;
2206
2207 assert(msg->m_chain && msg_chain_errors(msg->m_chain) == 0)((msg->m_chain && msg_chain_errors(msg->m_chain
) == 0) ? (void) (0) : __assert_fail ("msg->m_chain && msg_chain_errors(msg->m_chain) == 0"
, "msg_parser.c", 2207, __PRETTY_FUNCTION__))
;
2208 }
2209}
2210
2211/**
2212 * Remove a message from header chain.
2213 *
2214 * The function @c msg_chain_remove() removes a message header from the header
2215 * chain.
2216 *
2217 * @param msg pointer to the message
2218 * @param h pointer to the header in the list to be removed
2219 *
2220 * @return The pointer to the header just removed.
2221 */
2222su_inlinestatic inline
2223msg_header_t *msg_chain_remove(msg_t *msg, msg_header_t *h)
2224{
2225 if (h) {
2226 if (h->sh_prevsh_common->h_prev) {
2227 assert(*h->sh_prev == h)((*h->sh_common->h_prev == h) ? (void) (0) : __assert_fail
("*h->sh_common->h_prev == h", "msg_parser.c", 2227, __PRETTY_FUNCTION__
))
;
2228 assert(h->sh_succ == NULL || h->sh_succ->sh_prev == &h->sh_succ)((h->sh_common->h_succ == ((void*)0) || h->sh_common
->h_succ->sh_common->h_prev == &h->sh_common->
h_succ) ? (void) (0) : __assert_fail ("h->sh_common->h_succ == ((void*)0) || h->sh_common->h_succ->sh_common->h_prev == &h->sh_common->h_succ"
, "msg_parser.c", 2228, __PRETTY_FUNCTION__))
;
2229
2230 *h->sh_prevsh_common->h_prev = h->sh_succsh_common->h_succ;
2231 }
2232
2233 if (h->sh_succsh_common->h_succ)
2234 h->sh_succsh_common->h_succ->sh_prevsh_common->h_prev = h->sh_prevsh_common->h_prev;
2235 else if (msg && h->sh_prevsh_common->h_prev)
2236 msg->m_tail = h->sh_prevsh_common->h_prev;
2237
2238 h->sh_succsh_common->h_succ = NULL((void*)0); h->sh_prevsh_common->h_prev = NULL((void*)0);
2239
2240 if (msg)
2241 assert(msg_chain_errors(msg->m_chain) == 0)((msg_chain_errors(msg->m_chain) == 0) ? (void) (0) : __assert_fail
("msg_chain_errors(msg->m_chain) == 0", "msg_parser.c", 2241
, __PRETTY_FUNCTION__))
;
2242 }
2243 return h;
2244}
2245
2246#ifndef NDEBUG
2247/**Check if header chain contains any loops.
2248 *
2249 * @return
2250 * Return 0 if no loop, -1 otherwise.
2251 */
2252static
2253int msg_chain_loop(msg_header_t const *h)
2254{
2255 msg_header_t const *h2;
2256
2257 if (!h) return 0;
2258
2259 for (h2 = h->sh_succsh_common->h_succ; h && h2 && h2->sh_succsh_common->h_succ; h = h->sh_succsh_common->h_succ) {
2260 if (h == h2 || h == h2->sh_succsh_common->h_succ)
2261 return 1;
2262
2263 h2 = h2->sh_succsh_common->h_succ->sh_succsh_common->h_succ;
2264
2265 if (h == h2)
2266 return 1;
2267 }
2268
2269 return 0;
2270}
2271
2272/** Check header chain consistency.
2273 *
2274 * @return
2275 * Return 0 if consistent, number of errors otherwise.
2276 */
2277static
2278int msg_chain_errors(msg_header_t const *h)
2279{
2280 if (msg_chain_loop(h))
2281 return -1;
2282
2283 for (; h; h = h->sh_succsh_common->h_succ) {
2284 if (h->sh_succsh_common->h_succ && h->sh_succsh_common->h_succ->sh_prevsh_common->h_prev != &h->sh_succsh_common->h_succ)
2285 return -1;
2286 if (h->sh_prevsh_common->h_prev && h != (*h->sh_prevsh_common->h_prev))
2287 return -1;
2288 }
2289
2290 return 0;
2291}
2292#endif
2293
2294/* ====================================================================== */
2295/* Handling message structure - allocating, adding and removing headers */
2296
2297/** Allocate a header structure
2298 *
2299 * The msg_header_alloc() function allocates a generic MO header structure
2300 * and returns a pointer to it.
2301 *
2302 * @param home memory home
2303 * @param hc header class
2304 * @param extra amount of extra memory to be allocated after header structure
2305 *
2306 * @return
2307 * A pointer to the newly created header object, or @c NULL upon an error.
2308 */
2309msg_header_t *msg_header_alloc(su_home_t *home,
2310 msg_hclass_t *hc,
2311 isize_t extra)
2312{
2313 isize_t size = hc->hc_size;
2314 msg_header_t *h = su_alloc(home, size + extra);
2315
2316 if (h) {
2317 memset(h, 0, size);
2318 h->sh_classsh_common->h_class = hc;
2319 }
2320
2321 return h;
2322}
2323
2324/**Add a (list of) header(s) to the header structure and fragment chain.
2325 *
2326 * The function @c msg_header_add() adds a header or list of headers into
2327 * the given place within the message structure. It also inserts the headers
2328 * into the the message fragment chain, if it exists.
2329 *
2330 * If the header is a prepend header, the new header is inserted before
2331 * existing headers of the same class. If the header is an append header,
2332 * the new header is inserted after existing headers of the same class. If
2333 * the header is a singleton, existing headers of the same class are
2334 * removed. If the header is a list header, the values in the new header are
2335 * added to the existing list.
2336 *
2337 * @param msg message owning the fragment chain
2338 * @param pub public message structure
2339 * @param hh place in message structure to which header is added
2340 * @param h list of header(s) to be added
2341 */
2342int msg_header_add(msg_t *msg,
2343 msg_pub_t *pub,
2344 msg_header_t **hh,
2345 msg_header_t *h)
2346{
2347 msg_header_t **head, *old = NULL((void*)0), *end;
2348
2349 if (msg == NULL((void*)0) || h == NULL((void*)0) || h == MSG_HEADER_NONE((msg_header_t *)-1) || hh == NULL((void*)0))
2350 return -1;
2351 if (pub == NULL((void*)0))
2352 pub = msg->m_object;
2353
2354 head = _msg_chain_head(msg);
2355
2356 if (*head) {
2357 msg_header_t *sh, **prev;
2358
2359 for (sh = h, prev = NULL((void*)0); sh; sh = sh->sh_nextsh_header_next->shn_next) {
2360 sh->sh_succsh_common->h_succ = sh->sh_nextsh_header_next->shn_next;
2361 sh->sh_prevsh_common->h_prev = prev;
2362 prev = &sh->sh_succsh_common->h_succ;
2363 }
2364 }
2365
2366 switch (h->sh_classsh_common->h_class->hc_kind) {
2367 case msg_kind_single:
2368 case msg_kind_list:
2369 old = (*hh);
2370 break;
2371 case msg_kind_append:
2372 case msg_kind_apndlist:
2373 while (*hh)
2374 hh = &(*hh)->sh_nextsh_header_next->shn_next;
2375 break;
2376 case msg_kind_prepend:
2377 for (end = h; end->sh_nextsh_header_next->shn_next; end = end->sh_nextsh_header_next->shn_next)
2378 ;
2379 end->sh_nextsh_header_next->shn_next = *hh;
2380 }
2381
2382 if (*head) {
2383 /* Insert into existing fragment chain */
2384 msg_insert_chain(msg, pub, msg_is_prepend(h), head, h);
2385
2386 /* Remove replaced fragment */
2387 if (old)
2388 msg_chain_remove(msg, old);
2389 }
2390
2391 /* Insert into header list */
2392 *hh = h;
2393
2394 return 0;
2395}
2396
2397/**Prepend a (list of) header(s) to the header structure and fragment chain.
2398 *
2399 * The function @c msg_header_prepend() adds a header or list of headers into
2400 * the given place within the message structure. It also inserts the headers
2401 * into the the message fragment chain, if it exists.
2402 *
2403 * Unlike msg_header_add(), msg_header_prepend() always inserts header @a h
2404 * before other headers of the same class. If the header is a singleton,
2405 * existing headers of the same class are removed. If the header is a list
2406 * header, the values in the new header are prepended to the existing list.
2407 *
2408 * @param msg message owning the fragment chain
2409 * @param pub public message structure
2410 * @param hh place in message structure to which header is added
2411 * @param h list of header(s) to be added
2412 */
2413int msg_header_prepend(msg_t *msg,
2414 msg_pub_t *pub,
2415 msg_header_t **hh,
2416 msg_header_t *h)
2417{
2418 msg_header_t **head, *old = NULL((void*)0), *end;
2419
2420 assert(msg && pub)((msg && pub) ? (void) (0) : __assert_fail ("msg && pub"
, "msg_parser.c", 2420, __PRETTY_FUNCTION__))
;
2421
2422 if (msg == NULL((void*)0) || h == NULL((void*)0) || h == MSG_HEADER_NONE((msg_header_t *)-1) || hh == NULL((void*)0))
2423 return -1;
2424 if (pub == NULL((void*)0))
2425 pub = msg->m_object;
2426
2427 head = _msg_chain_head(msg);
2428
2429 if (*head) {
2430 msg_header_t *sh, **prev;
2431
2432 for (sh = h, prev = NULL((void*)0); sh; sh = sh->sh_nextsh_header_next->shn_next) {
2433 sh->sh_succsh_common->h_succ = sh->sh_nextsh_header_next->shn_next;
2434 sh->sh_prevsh_common->h_prev = prev;
2435 prev = &sh->sh_succsh_common->h_succ;
2436 }
2437 }
2438
2439 switch (h->sh_classsh_common->h_class->hc_kind) {
2440 case msg_kind_single:
2441 case msg_kind_list:
2442 old = (*hh);
2443 break;
2444 case msg_kind_append:
2445 case msg_kind_apndlist:
2446 case msg_kind_prepend:
2447 for (end = h; end->sh_nextsh_header_next->shn_next; end = end->sh_nextsh_header_next->shn_next)
2448 ;
2449 end->sh_nextsh_header_next->shn_next = *hh;
2450 break;
2451 }
2452
2453 if (*head) {
2454 /* Insert into existing fragment chain */
2455 msg_insert_chain(msg, pub, 1, head, h);
2456
2457 /* Remove replaced fragment */
2458 if (old)
2459 msg_chain_remove(msg, old);
2460 }
2461
2462 /* Insert into header list */
2463 *hh = h;
2464
2465 return 0;
2466}
2467
2468
2469/** Find place to insert header of the class @a hc. */
2470msg_header_t **
2471msg_hclass_offset(msg_mclass_t const *mc, msg_pub_t const *mo, msg_hclass_t *hc)
2472{
2473 assert(mc && hc)((mc && hc) ? (void) (0) : __assert_fail ("mc && hc"
, "msg_parser.c", 2473, __PRETTY_FUNCTION__))
;
2474
2475 if (mc == NULL((void*)0) || hc == NULL((void*)0))
2476 return NULL((void*)0);
2477
2478 if (hc->hc_hash > 0) {
2479 unsigned j, N = mc->mc_hash_size;
2480 for (j = hc->hc_hash % N; mc->mc_hash[j].hr_class; j = (j + 1) % N)
2481 if (mc->mc_hash[j].hr_class == hc) {
2482 return (msg_header_t **)((char *)mo + mc->mc_hash[j].hr_offset);
2483 }
2484 } else {
2485 /* Header has no name. */
2486 if (hc->hc_hash == mc->mc_request[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_request[0].hr_offset);
2487 if (hc->hc_hash == mc->mc_status[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_status[0].hr_offset);
2488 if (hc->hc_hash == mc->mc_separator[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_separator[0].hr_offset);
2489 if (hc->hc_hash == mc->mc_payload[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_payload[0].hr_offset);
2490 if (hc->hc_hash == mc->mc_unknown[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_unknown[0].hr_offset);
2491 if (hc->hc_hash == mc->mc_error[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_error[0].hr_offset);
2492 if (hc->hc_hash == mc->mc_multipart[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_multipart[0].hr_offset);
2493 }
2494
2495 return NULL((void*)0);
2496}
2497
2498/** Append a parsed header object into the message structure */
2499su_inlinestatic inline void
2500append_parsed(msg_t *msg, msg_pub_t *mo, msg_href_t const *hr, msg_header_t *h,
2501 int always_into_chain)
2502{
2503 msg_header_t **hh;
2504
2505 assert(msg)((msg) ? (void) (0) : __assert_fail ("msg", "msg_parser.c", 2505
, __PRETTY_FUNCTION__))
; assert(hr->hr_offset)((hr->hr_offset) ? (void) (0) : __assert_fail ("hr->hr_offset"
, "msg_parser.c", 2505, __PRETTY_FUNCTION__))
;
2506
2507 hh = (msg_header_t **)((char *)mo + hr->hr_offset);
2508
2509 if (msg->m_chain || always_into_chain)
2510 msg_insert_here_in_chain(msg, msg_chain_tail(msg), h);
2511
2512 if (*hh && msg_is_single(h)) {
2513 /* If there is multiple instances of single headers,
2514 put the extra headers into the list of erroneous headers */
2515 msg_error_t **e;
2516
2517 for (e = &mo->msg_error; *e; e = &(*e)->er_next)
2518 ;
2519 *e = (msg_error_t *)h;
2520
2521 msg->m_extract_err |= hr->hr_flags;
2522 if (hr->hr_class->hc_critical)
2523 mo->msg_flags |= MSG_FLG_ERROR;
2524
2525 return;
2526 }
2527
2528 while (*hh)
2529 hh = &(*hh)->sh_nextsh_header_next->shn_next;
2530 *hh = h;
2531}
2532
2533static int _msg_header_add_list_items(msg_t *msg,
2534 msg_header_t **hh,
2535 msg_header_t const *src);
2536
2537/**Duplicate and add a (list of) header(s) to the message.
2538 *
2539 * The function @c msg_header_add_dup() duplicates and adds a (list of)
2540 * header(s) into a message structure.
2541 *
2542 * When inserting headers into the fragment chain, a request (or status) is
2543 * inserted first and replaces the existing request (or status). Other
2544 * headers are inserted after the request or status.
2545 *
2546 * If the header is a singleton, existing headers with the same class are
2547 * removed.
2548 *
2549 * @param msg message owning the fragment chain
2550 * @param pub public message structure to which header is added
2551 * @param src list of header(s) to be added
2552 */
2553int msg_header_add_dup(msg_t *msg,
2554 msg_pub_t *pub,
2555 msg_header_t const *src)
2556{
2557 msg_header_t *h, **hh = NULL((void*)0);
2558 msg_hclass_t *hc = NULL((void*)0);
2559
2560 if (msg == NULL((void*)0))
2561 return -1;
2562 if (src == NULL((void*)0) || src == MSG_HEADER_NONE((msg_header_t *)-1))
2563 return 0;
2564 if (pub == NULL((void*)0))
2565 pub = msg->m_object;
2566
2567 for ( ;src; src = src->sh_nextsh_header_next->shn_next) {
2568 assert(src->sh_class)((src->sh_common->h_class) ? (void) (0) : __assert_fail
("src->sh_common->h_class", "msg_parser.c", 2568, __PRETTY_FUNCTION__
))
;
2569
2570 if (!src->sh_classsh_common->h_class)
2571 return -1;
2572
2573 if (hc != src->sh_classsh_common->h_class)
2574 hh = msg_hclass_offset(msg->m_class, pub, hc = src->sh_classsh_common->h_class);
2575
2576 if (hh == NULL((void*)0))
2577 return -1;
2578
2579 if (!*hh || hc->hc_kind != msg_kind_list) {
2580 int size = hc->hc_size;
2581 isize_t xtra = hc->hc_dxtra(src, size) - size;
2582 char *end;
2583
2584 if (!(h = msg_header_alloc(msg_home(msg)((su_home_t*)(msg)), hc, xtra)))
2585 return -1; /* error */
2586
2587 if (!(end = hc->hc_dup_one(h, src, (char *)h + size, xtra)))
2588 return -1; /* error */
2589
2590 if (hc->hc_update)
2591 msg_header_update_params(h->sh_common, 0);
2592
2593 assert(end == (char *)h + size + xtra)((end == (char *)h + size + xtra) ? (void) (0) : __assert_fail
("end == (char *)h + size + xtra", "msg_parser.c", 2593, __PRETTY_FUNCTION__
))
;
2594
2595 if (msg_header_add(msg, pub, hh, h) < 0)
2596 return -1;
2597
2598 hh = &h->sh_nextsh_header_next->shn_next;
2599 }
2600 else {
2601 if (_msg_header_add_list_items(msg, hh, src) < 0)
2602 break;
2603 }
2604 }
2605
2606 if (src)
2607 return -1;
2608
2609 return 0;
2610}
2611
2612/**Duplicate a header as a given type and add the duplicate into message.
2613 *
2614 * The function @c msg_header_add_dup_as() duplicates a header as a instance
2615 * of the given header class. It adds the new copy into the message.
2616 *
2617 * When inserting headers into the fragment chain, a request (or status) is
2618 * inserted first and replaces the existing request (or status). Other
2619 * headers are inserted after the request or status.
2620 *
2621 * If the header is a singleton, existing headers with the same class are
2622 * removed.
2623 *
2624 * @param msg message owning the fragment chain
2625 * @param pub public message structure to which header is added
2626 * @param hc header class for header target type
2627 * @param src list of header(s) to be duplicated and added
2628 */
2629int msg_header_add_dup_as(msg_t *msg,
2630 msg_pub_t *pub,
2631 msg_hclass_t *hc,
2632 msg_header_t const *src)
2633{
2634 if (msg == NULL((void*)0) || hc == NULL((void*)0))
2635 return -1;
2636 if (src == NULL((void*)0) || src == MSG_HEADER_NONE((msg_header_t *)-1))
2637 return 0;
2638 if (pub == NULL((void*)0))
2639 pub = msg->m_object;
2640
2641 return _msg_header_add_dup_as(msg, pub, hc, src);
2642}
2643
2644/** Duplicate and add a (list of) header to a message */
2645static
2646int _msg_header_add_dup_as(msg_t *msg,
2647 msg_pub_t *pub,
2648 msg_hclass_t *hc,
2649 msg_header_t const *src)
2650{
2651 msg_header_t *h, **hh;
2652
2653 hh = msg_hclass_offset(msg->m_class, pub, hc);
2654
2655 if (hh == NULL((void*)0))
2656 return -1;
2657
2658 if (*hh && hc->hc_kind == msg_kind_list)
2659 return _msg_header_add_list_items(msg, hh, src);
2660
2661 if (!(h = msg_header_dup_as(msg_home(msg)((su_home_t*)(msg)), hc, src)))
2662 return -1;
2663
2664 return msg_header_add(msg, pub, hh, h);
2665}
2666
2667/* Add list items */
2668static int _msg_header_add_list_items(msg_t *msg,
2669 msg_header_t **hh,
2670 msg_header_t const *src)
2671{
2672 msg_header_t *h = *hh;
2673 msg_param_t **s = msg_header_params(src->sh_common);
2674
2675 if (!s || !*s)
2676 return 0;
2677
2678 msg_fragment_clear(h->sh_common);
2679
2680 /* Remove empty headers */
2681 for (hh = &h->sh_nextsh_header_next->shn_next; *hh; *hh = (*hh)->sh_nextsh_header_next->shn_next)
2682 msg_chain_remove(msg, *hh);
2683
2684 if (msg_header_join_items(msg_home(msg)((su_home_t*)(msg)), h->sh_common, src->sh_common, 1)
2685 < 0)
2686 return -1;
2687
2688 return 0;
2689}
2690
2691/** Parse a string as a given header field and add result to the message. */
2692int msg_header_add_make(msg_t *msg,
2693 msg_pub_t *pub,
2694 msg_hclass_t *hc,
2695 char const *s)
2696{
2697 msg_header_t *h, **hh;
2698
2699 if (msg == NULL((void*)0))
2700 return -1;
2701 if (pub == NULL((void*)0))
2702 pub = msg->m_object;
2703
2704 hh = msg_hclass_offset(msg->m_class, pub, hc);
2705
2706 if (hh == NULL((void*)0))
2707 return -1;
2708
2709 if (!s)
2710 return 0;
2711
2712 if (*hh && hc->hc_kind == msg_kind_list) {
2713 /* Add list items */
2714 msg_header_t *h = *hh;
2715 msg_param_t **d;
2716 char *s0;
2717
2718 skip_lws(&s)(*(&s) += span_lws(*(&s)));
2719
2720 d = msg_header_params(h->sh_common); assert(d)((d) ? (void) (0) : __assert_fail ("d", "msg_parser.c", 2720,
__PRETTY_FUNCTION__))
;
2721
2722 msg_fragment_clear(h->sh_common);
2723
2724 /* Remove empty headers */
2725 for (hh = &h->sh_nextsh_header_next->shn_next; *hh; *hh = (*hh)->sh_nextsh_header_next->shn_next)
2726 msg_chain_remove(msg, *hh);
2727
2728 s0 = su_strdup(msg_home(msg)((su_home_t*)(msg)), s);
2729
2730 if (!s0 || msg_commalist_d(msg_home(msg)((su_home_t*)(msg)), &s0, d, msg_token_scan) < 0)
2731 return -1;
2732
2733 return 0;
2734 }
2735
2736 if (!(h = msg_header_make(msg_home(msg)((su_home_t*)(msg)), hc, s)))
2737 return -1;
2738
2739 return msg_header_add(msg, pub, hh, h);
2740}
2741
2742/** Add formatting result to message.
2743 *
2744 * Parse result from printf-formatted params as a given header field and add
2745 * result to the message.
2746 *
2747 * @NEW_1_12_10
2748 */
2749int msg_header_add_format(msg_t *msg,
2750 msg_pub_t *pub,
2751 msg_hclass_t *hc,
2752 char const *fmt,
2753 ...)
2754{
2755 msg_header_t *h, **hh;
2756 va_list va;
2757
2758 if (msg == NULL((void*)0))
2759 return -1;
2760 if (pub == NULL((void*)0))
2761 pub = msg->m_object;
2762
2763 hh = msg_hclass_offset(msg->m_class, pub, hc);
2764
2765 if (hh == NULL((void*)0))
2766 return -1;
2767
2768 if (!fmt)
2769 return 0;
2770
2771 va_start(va, fmt)__builtin_va_start(va, fmt);
2772 h = msg_header_vformat(msg_home(msg)((su_home_t*)(msg)), hc, fmt, va);
2773 va_end(va)__builtin_va_end(va);
2774
2775 if (!h)
2776 return -1;
2777
2778 return msg_header_add(msg, pub, hh, h);
2779}
2780
2781
2782/**Add string contents to message.
2783 *
2784 * Duplicate a string containing headers (or a message body, if the string
2785 * starts with linefeed), parse it and add resulting header objects to the
2786 * message object.
2787 *
2788 * @param msg message object
2789 * @param pub message header structure where heades are added (may be NULL)
2790 * @param str string to be copied and parsed (not modified, may be NULL)
2791 *
2792 * @retval 0 when succesful
2793 * @retval -1 upon an error
2794 */
2795int msg_header_add_str(msg_t *msg,
2796 msg_pub_t *pub,
2797 char const *str)
2798{
2799 char *s;
2800
2801 if (!msg)
2802 return -1;
2803 if (!str)
2804 return 0;
2805
2806 s = su_strdup(msg_home(msg)((su_home_t*)(msg)), str);
2807
2808 if (s == NULL((void*)0))
2809 return -1;
2810
2811 return msg_header_parse_str(msg, pub, s);
2812}
2813
2814/**Add string to message.
2815 *
2816 * Parse a string containing headers (or a message body, if the string
2817 * starts with linefeed) and add resulting header objects to the message
2818 * object.
2819 *
2820 * @param msg message object
2821 * @param pub message header structure where heades are added (may be NULL)
2822 * @param s string to be parsed (and modified)
2823 *
2824 * @retval 0 when succesful
2825 * @retval -1 upon an error
2826 *
2827 * @sa msg_header_add_str(), url_headers_as_string()
2828 *
2829 * @since New in @VERSION_1_12_4.
2830 */
2831int msg_header_parse_str(msg_t *msg,
2832 msg_pub_t *pub,
2833 char *s)
2834{
2835 if (!msg)
2836 return -1;
2837
2838 if (pub == NULL((void*)0))
2839 pub = msg->m_object;
2840
2841 if (s) {
2842 size_t ssiz = strlen(s), used = 0;
2843 ssize_t n = 1;
2844
2845 while (ssiz > used) {
2846 if (IS_CRLF(s[used])((s[used]) == '\r' || (s[used]) == '\n'))
2847 break;
2848 n = msg_extract_header(msg, pub, s + used, ssiz - used, 1);
2849 if (n <= 0)
2850 break;
2851 used += n;
2852 }
2853
2854 if (n > 0 && ssiz > used) {
2855 used += CRLF_TEST(s + used)((s + used)[0] == '\r' ? ((s + used)[1] == '\n') + 1 : (s + used
)[0] =='\n')
;
2856 if (ssiz > used)
2857 msg_extract_payload(msg, pub, NULL((void*)0), ssiz - used,
2858 s + used, ssiz - used, 1);
2859 }
2860
2861 if (n <= 0)
2862 return -1;
2863 }
2864
2865 return 0;
2866}
2867
2868/** Insert a (list of) header(s) to the fragment chain.
2869 *
2870 * The function @c msg_header_insert() inserts header or list of headers
2871 * into a message structure. It also inserts them into the the message
2872 * fragment chain, if it exists.
2873 *
2874 * When inserting headers into the fragment chain, a request (or status) is
2875 * inserted first and replaces the existing request (or status). Other
2876 * headers are inserted after the request or status.
2877 *
2878 * If there can be only one header field of this type (hc_kind is
2879 * msg_kind_single), existing header objects with the same class are
2880 * removed.
2881 *
2882 * @param msg message object owning the fragment chain
2883 * @param pub public message structure to which header is added
2884 * @param h list of header(s) to be added
2885 */
2886int msg_header_insert(msg_t *msg, msg_pub_t *pub, msg_header_t *h)
2887{
2888 msg_header_t **hh;
2889
2890 assert(msg)((msg) ? (void) (0) : __assert_fail ("msg", "msg_parser.c", 2890
, __PRETTY_FUNCTION__))
;
2891
2892 if (msg == NULL((void*)0) || h == NULL((void*)0) || h == MSG_HEADER_NONE((msg_header_t *)-1) ||
2893 h->sh_classsh_common->h_class == NULL((void*)0))
2894 return -1;
2895 if (pub == NULL((void*)0))
2896 pub = msg->m_object;
2897
2898 hh = msg_hclass_offset(msg->m_class, pub, h->sh_classsh_common->h_class);
2899
2900 return msg_header_add(msg, pub, hh, h);
2901}
2902
2903/**Remove a header from the header structure and fragment chain.
2904 *
2905 * The function @c msg_header_remove() removes a header from a message
2906 * structure. It also removes the message from the message fragment chain
2907 * and clears the encoding of other headers objects that share same
2908 * encoding.
2909 *
2910 * @param msg message owning the fragment chain
2911 * @param pub public message structure to which header is added
2912 * @param h header to be removed
2913 */
2914int msg_header_remove(msg_t *msg, msg_pub_t *pub, msg_header_t *h)
2915{
2916 msg_header_t **hh, **hh0;
2917
2918 if (msg == NULL((void*)0) || h == NULL((void*)0) || h == MSG_HEADER_NONE((msg_header_t *)-1) ||
2919 h->sh_classsh_common->h_class == NULL((void*)0))
2920 return -1;
2921 if (pub == NULL((void*)0))
2922 pub = msg->m_object;
2923
2924 /* First, remove from public structure (msg_pub_t) */
2925 hh0 = msg_hclass_offset(msg->m_class, pub, h->sh_classsh_common->h_class);
2926 if (!hh0)
2927 return -1;
2928
2929 for (hh = hh0; *hh; hh = &(*hh)->sh_nextsh_header_next->shn_next) {
2930 if (*hh == h) {
2931 *hh = h->sh_nextsh_header_next->shn_next;
2932 break;
2933 }
2934 }
2935
2936 if (h->sh_datash_common->h_data) {
2937 void const *data = (char *)h->sh_datash_common->h_data + h->sh_lensh_common->h_len;
2938 for (hh = hh0; *hh; hh = &(*hh)->sh_nextsh_header_next->shn_next) {
2939 if (data == (char *)(*hh)->sh_datash_common->h_data + (*hh)->sh_lensh_common->h_len) {
2940 (*hh)->sh_datash_common->h_data = NULL((void*)0), (*hh)->sh_lensh_common->h_len = 0;
2941 }
2942 }
2943 }
2944
2945 msg_chain_remove(msg, h);
2946
2947 return 0;
2948}
2949
2950
2951/**Remove a header list from the header structure and fragment chain.
2952 *
2953 * The function @c msg_header_remove_all() removes a list of headers from a
2954 * message structure. It also removes the message from the message fragment
2955 * chain and clears the encoding of other headers objects that share same
2956 * encoding.
2957 *
2958 * @param msg message owning the fragment chain
2959 * @param pub public message structure to which header is added
2960 * @param h header list to be removed
2961 */
2962int msg_header_remove_all(msg_t *msg, msg_pub_t *pub, msg_header_t *h)
2963{
2964 msg_header_t **hh, **hh0;
2965 void const *data;
2966
2967 if (msg == NULL((void*)0) || h == NULL((void*)0) || h == MSG_HEADER_NONE((msg_header_t *)-1) ||
2968 h->sh_classsh_common->h_class == NULL((void*)0))
2969 return -1;
2970 if (pub == NULL((void*)0))
2971 pub = msg->m_object;
2972
2973 hh0 = msg_hclass_offset(msg->m_class, pub, h->sh_classsh_common->h_class);
2974 if (!hh0)
2975 return -1;
2976
2977 data = (char *)h->sh_datash_common->h_data + h->sh_lensh_common->h_len;
2978
2979 /* First, remove from public structure (msg_pub_t) */
2980 for (hh = hh0; *hh; hh = &(*hh)->sh_nextsh_header_next->shn_next) {
2981 if (*hh == h) {
2982 break;
2983 }
2984 if (data && data == (char *)(*hh)->sh_datash_common->h_data + (*hh)->sh_lensh_common->h_len) {
2985 h->sh_datash_common->h_data = NULL((void*)0), h->sh_lensh_common->h_len = 0;
2986 (*hh)->sh_datash_common->h_data = NULL((void*)0), (*hh)->sh_lensh_common->h_len = 0;
2987 }
2988 }
2989
2990 /* Remove from header chain */
2991 while (h) {
2992 h->sh_datash_common->h_data = NULL((void*)0), h->sh_lensh_common->h_len = 0;
2993 msg_chain_remove(msg, h);
2994 h = h->sh_nextsh_header_next->shn_next;
2995 }
2996
2997 *hh = NULL((void*)0);
2998
2999 return 0;
3000}
3001
3002
3003/** Replace a header item with a (list of) header(s).
3004 *
3005 * The function @c msg_header_replace() removes a header structure from
3006 * message and replaces it with a new one or a list of headers. It inserts
3007 * the new headers into the the message fragment chain, if it exists.
3008 *
3009 * @param msg message object owning the fragment chain
3010 * @param pub public message structure to which header is added
3011 * @param replaced old header to be removed
3012 * @param h list of header(s) to be added
3013 */
3014int msg_header_replace(msg_t *msg,
3015 msg_pub_t *pub,
3016 msg_header_t *replaced,
3017 msg_header_t *h)
3018{
3019 msg_header_t *h0, *last, **hh, **hh0;
3020
3021 if (msg == NULL((void*)0) || replaced == NULL((void*)0))
3022 return -1;
3023 if (h == NULL((void*)0) || h == MSG_HEADER_NONE((msg_header_t *)-1) || h->sh_classsh_common->h_class == NULL((void*)0))
3024 return msg_header_remove(msg, pub, replaced);
3025 if (pub == NULL((void*)0))
3026 pub = msg->m_object;
3027
3028 hh = hh0 = msg_hclass_offset(msg->m_class, pub, h->sh_classsh_common->h_class);
3029 if (hh == NULL((void*)0))
3030 return -1;
3031 if (replaced == NULL((void*)0))
3032 return msg_header_add(msg, pub, hh, h);
3033
3034 assert(h->sh_prev == NULL)((h->sh_common->h_prev == ((void*)0)) ? (void) (0) : __assert_fail
("h->sh_common->h_prev == ((void*)0)", "msg_parser.c",
3034, __PRETTY_FUNCTION__))
; /* Must not be in existing chain! */
3035
3036 for (last = h; last->sh_nextsh_header_next->shn_next; last = last->sh_nextsh_header_next->shn_next) {
3037 if ((last->sh_succsh_common->h_succ = last->sh_nextsh_header_next->shn_next))
3038 last->sh_nextsh_header_next->shn_next->sh_prevsh_common->h_prev = &last->sh_succsh_common->h_succ;
3039 }
3040
3041 for (h0 = *hh; h0; hh = &h0->sh_nextsh_header_next->shn_next, h0 = *hh) {
3042 if (replaced == h0)
3043 break;
3044 }
3045
3046 if (h0 == NULL((void*)0))
3047 return -1;
3048
3049 *hh = h; /* Replace in list */
3050 last->sh_nextsh_header_next->shn_next = replaced->sh_nextsh_header_next->shn_next;
3051
3052 if (replaced->sh_prevsh_common->h_prev) {
3053 *replaced->sh_prevsh_common->h_prev = h;
3054 h->sh_prevsh_common->h_prev = replaced->sh_prevsh_common->h_prev;
3055 if ((last->sh_succsh_common->h_succ = replaced->sh_succsh_common->h_succ))
3056 last->sh_succsh_common->h_succ->sh_prevsh_common->h_prev = &last->sh_succsh_common->h_succ;
3057 if (msg->m_tail == &replaced->sh_succsh_common->h_succ)
3058 msg->m_tail = &last->sh_succsh_common->h_succ;
3059 }
3060
3061 assert(msg->m_tail != &replaced->sh_succ)((msg->m_tail != &replaced->sh_common->h_succ) ?
(void) (0) : __assert_fail ("msg->m_tail != &replaced->sh_common->h_succ"
, "msg_parser.c", 3061, __PRETTY_FUNCTION__))
;
3062
3063 replaced->sh_nextsh_header_next->shn_next = NULL((void*)0);
3064 replaced->sh_prevsh_common->h_prev = NULL((void*)0);
3065 replaced->sh_succsh_common->h_succ = NULL((void*)0);
3066
3067 if (replaced->sh_datash_common->h_data) {
3068 /* Remove cached encoding if it is shared with more than one header fragments */
3069 int cleared = 0;
3070 void const *data = (char *)replaced->sh_datash_common->h_data + replaced->sh_lensh_common->h_len;
3071
3072 for (hh = hh0; *hh; hh = &(*hh)->sh_nextsh_header_next->shn_next) {
3073 if (data == (char *)(*hh)->sh_datash_common->h_data + (*hh)->sh_lensh_common->h_len) {
3074 (*hh)->sh_datash_common->h_data = NULL((void*)0), (*hh)->sh_lensh_common->h_len = 0, cleared = 1;
3075 }
3076 }
3077
3078 if (cleared)
3079 replaced->sh_datash_common->h_data = NULL((void*)0), replaced->sh_lensh_common->h_len = 0;
3080 }
3081
3082 return 0;
3083}
3084
3085/** Free a header structure */
3086void msg_header_free(su_home_t *home, msg_header_t *h)
3087{
3088 su_free(home, h);
3089}
3090
3091/** Free a (list of) header structures */
3092void msg_header_free_all(su_home_t *home, msg_header_t *h)
3093{
3094 msg_header_t *h_next;
3095
3096 while (h) {
3097 h_next = h->sh_nextsh_header_next->shn_next;
3098 su_free(home, h);
3099 h = h_next;
3100 }
3101}