Bug Summary

File:msg/msg_parser.c
Warning:line 1920, column 7
Access to field 'msg_request' results in a dereference of a null pointer (loaded from variable 'pub')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name msg_parser.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib/llvm-7/lib/clang/7.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -I ./../url -I ../url -I ./../bnf -I ../bnf -I ./../su -I ../su -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/msg -ferror-limit 19 -fmessage-length 0 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -o /drone/src/scan-build/2021-08-26-205203-363-1 -x c msg_parser.c -faddrsig
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)((void) sizeof ((mb->mb_used + mb->mb_commit + size <=
mb->mb_size) ? 1 : 0), __extension__ ({ if (mb->mb_used
+ mb->mb_commit + size <= mb->mb_size) ; else __assert_fail
("mb->mb_used + mb->mb_commit + size <= mb->mb_size"
, "msg_parser.c", 200, __extension__ __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)((void) sizeof ((msg) ? 1 : 0), __extension__ ({ if (msg) ; else
__assert_fail ("msg", "msg_parser.c", 247, __extension__ __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)((void) sizeof ((!msg->m_set_buffer) ? 1 : 0), __extension__
({ if (!msg->m_set_buffer) ; else __assert_fail ("!msg->m_set_buffer"
, "msg_parser.c", 273, __extension__ __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)((void) sizeof ((chunk->pl_data == ((void*)0)) ? 1 : 0), __extension__
({ if (chunk->pl_data == ((void*)0)) ; else __assert_fail
("chunk->pl_data == NULL", "msg_parser.c", 409, __extension__
__PRETTY_FUNCTION__); }))
; assert(chunk->pl_common->h_len == 0)((void) sizeof ((chunk->pl_common->h_len == 0) ? 1 : 0)
, __extension__ ({ if (chunk->pl_common->h_len == 0) ; else
__assert_fail ("chunk->pl_common->h_len == 0", "msg_parser.c"
, 409, __extension__ __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)((void) sizeof ((N <= 128 * 1024) ? 1 : 0), __extension__ (
{ if (N <= 128 * 1024) ; else __assert_fail ("N <= 128 * 1024"
, "msg_parser.c", 745, __extension__ __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)((void) sizeof ((I <= msg_n_fragments) ? 1 : 0), __extension__
({ if (I <= msg_n_fragments) ; else __assert_fail ("I <= msg_n_fragments"
, "msg_parser.c", 758, __extension__ __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)((void) sizeof ((mo) ? 1 : 0), __extension__ ({ if (mo) ; else
__assert_fail ("mo", "msg_parser.c", 862, __extension__ __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 <((void) sizeof ((msg->m_buffer->mb_used + msg->m_buffer
->mb_commit < msg->m_buffer->mb_size) ? 1 : 0), __extension__
({ if (msg->m_buffer->mb_used + msg->m_buffer->mb_commit
< msg->m_buffer->mb_size) ; else __assert_fail ("msg->m_buffer->mb_used + msg->m_buffer->mb_commit < msg->m_buffer->mb_size"
, "msg_parser.c", 883, __extension__ __PRETTY_FUNCTION__); })
)
883 msg->m_buffer->mb_size)((void) sizeof ((msg->m_buffer->mb_used + msg->m_buffer
->mb_commit < msg->m_buffer->mb_size) ? 1 : 0), __extension__
({ if (msg->m_buffer->mb_used + msg->m_buffer->mb_commit
< msg->m_buffer->mb_size) ; else __assert_fail ("msg->m_buffer->mb_used + msg->m_buffer->mb_commit < msg->m_buffer->mb_size"
, "msg_parser.c", 883, __extension__ __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)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)((void) sizeof ((hr->hr_offset) ? 1 : 0), __extension__ ({
if (hr->hr_offset) ; else __assert_fail ("hr->hr_offset"
, "msg_parser.c", 984, __extension__ __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)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)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)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)((void) sizeof ((&h->sh_common->h_succ == h->sh_common
->h_succ->sh_common->h_prev) ? 1 : 0), __extension__
({ if (&h->sh_common->h_succ == h->sh_common->
h_succ->sh_common->h_prev) ; else __assert_fail ("&h->sh_succ == h->sh_succ->sh_prev"
, "msg_parser.c", 1088, __extension__ __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;
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)((void) sizeof ((!msg->m_chunk) ? 1 : 0), __extension__ ({
if (!msg->m_chunk) ; else __assert_fail ("!msg->m_chunk"
, "msg_parser.c", 1329, __extension__ __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)((void) sizeof ((body_len > 0) ? 1 : 0), __extension__ ({ if
(body_len > 0) ; else __assert_fail ("body_len > 0", "msg_parser.c"
, 1337, __extension__ __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)((void) sizeof ((msg->m_buffer->mb_commit == bsiz) ? 1 :
0), __extension__ ({ if (msg->m_buffer->mb_commit == bsiz
) ; else __assert_fail ("msg->m_buffer->mb_commit == bsiz"
, "msg_parser.c", 1359, __extension__ __PRETTY_FUNCTION__); }
))
;
1360 assert(b == msg->m_buffer->mb_data + msg->m_buffer->mb_used)((void) sizeof ((b == msg->m_buffer->mb_data + msg->
m_buffer->mb_used) ? 1 : 0), __extension__ ({ if (b == msg
->m_buffer->mb_data + msg->m_buffer->mb_used) ; else
__assert_fail ("b == msg->m_buffer->mb_data + msg->m_buffer->mb_used"
, "msg_parser.c", 1360, __extension__ __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
1388 /* Use all the data from our current buffer */
1389 msg_buf_used(msg, current);
1390
1391 msg->m_chunk = pl;
1392
1393 h->sh_datash_common->h_data = b, h->sh_lensh_common->h_len = bsiz;
1394 pl->pl_data = b, pl->pl_len = current;
1395
1396 for (;current < body_len; current += rest) {
1397 msg_header_t *h0 = h;
1398
1399 /* Allocate header structure for next payload chunk */
1400 if (!(h = msg_header_alloc(msg_home(msg)((su_home_t*)(msg)), hr->hr_class, 0)))
1401 return -1;
1402 if (msg->m_chain)
1403 msg_insert_here_in_chain(msg, msg_chain_tail(msg), h);
1404 h0->sh_nextsh_header_next->shn_next = h;
1405
1406 rest = body_len - current;
1407
1408 if (!msg->m_streaming) {
1409 x = msg_buf_exact(msg, rest);
1410 if (x == NULL((void*)0)) {
1411 mo->msg_flags |= MSG_FLG_TOOLARGE;
1412 return -1;
1413 }
1414 }
1415 else {
1416 x = NULL((void*)0);
1417 }
1418
1419 if (x) {
1420 /* Mark the just-allocated buffer as used */
1421 rest = msg->m_buffer->mb_size - msg->m_buffer->mb_used;
1422 msg_buf_used(msg, rest);
1423 }
1424
1425 pl = h->sh_payload;
1426
1427 h->sh_lensh_common->h_len = 0, pl->pl_len = rest;
1428 h->sh_datash_common->h_data = x, pl->pl_data = x;
1429 }
1430 }
1431 else {
1432 /* No chunking.
1433 *
1434 * Allocate a single buffer that contains enough free space for body.
1435 *
1436 * msg_buf_exact() also copies committed but un-used data
1437 * from the old buffer (b[0] .. b[bsiz])
1438 * to the new buffer (x[-bsiz-1]..b[-1])
1439 */
1440 if (!(x = msg_buf_exact(msg, body_len - bsiz + 1))) {
1441 if (mo->msg_flags & MSG_FLG_TOOLARGE) {
1442 msg_mark_as_complete(msg, MSG_FLG_TRUNC);
1443 return bsiz;
1444 }
1445 return -1;
1446 }
1447
1448 /* Fake un-received data as already received and then use it */
1449 /* msg_buf_commit(msg, body_len - bsiz + 1, eos); */
1450 msg_buf_used(msg, body_len + 1);
1451
1452 msg->m_chunk = h->sh_payload;
1453
1454 x -= bsiz; /* Start of un-used data */
1455 x[body_len] = '\0';
1456
1457 h->sh_datash_common->h_data = x, h->sh_lensh_common->h_len = bsiz;
1458 pl->pl_data = x, pl->pl_len = body_len;
1459
1460 assert(MSG_CHUNK_AVAIL(pl) == body_len - bsiz)((void) sizeof ((((pl)->pl_len + ((pl)->pl_data - (char
*)pl->pl_common->h_data) - (pl)->pl_common->h_len
) == body_len - bsiz) ? 1 : 0), __extension__ ({ if (((pl)->
pl_len + ((pl)->pl_data - (char *)pl->pl_common->h_data
) - (pl)->pl_common->h_len) == body_len - bsiz) ; else __assert_fail
("MSG_CHUNK_AVAIL(pl) == body_len - bsiz", "msg_parser.c", 1460
, __extension__ __PRETTY_FUNCTION__); }))
;
1461 }
1462
1463 return bsiz;
1464}
1465
1466/** Extract incomplete chunks.
1467 */
1468su_inlinestatic inline
1469int extract_incomplete_chunks(msg_t *msg, int eos)
1470{
1471 msg_payload_t *chunk;
1472
1473 for (chunk = msg->m_chunk; chunk; chunk = MSG_CHUNK_NEXT(chunk)((chunk)->pl_next)) {
1474 if (MSG_CHUNK_AVAIL(chunk)((chunk)->pl_len + ((chunk)->pl_data - (char *)chunk->
pl_common->h_data) - (chunk)->pl_common->h_len)
!= 0)
1475 break;
1476
1477 /* The incomplete payload fragment is now complete */
1478 assert(MSG_CHUNK_BUFFER(chunk) == chunk->pl_data + chunk->pl_len)((void) sizeof ((((char *)chunk->pl_common->h_data + (chunk
)->pl_common->h_len) == chunk->pl_data + chunk->pl_len
) ? 1 : 0), __extension__ ({ if (((char *)chunk->pl_common
->h_data + (chunk)->pl_common->h_len) == chunk->pl_data
+ chunk->pl_len) ; else __assert_fail ("MSG_CHUNK_BUFFER(chunk) == chunk->pl_data + chunk->pl_len"
, "msg_parser.c", 1478, __extension__ __PRETTY_FUNCTION__); }
))
;
1479
1480 msg->m_size += chunk->pl_common->h_len;
1481 }
1482
1483 msg->m_chunk = chunk;
1484
1485 if (chunk) {
1486 if (eos) {
1487 msg_mark_as_complete(msg, MSG_FLG_TRUNC);
1488 return 1;
1489 }
1490 }
1491 else {
1492 if (msg_get_flags(msg, MSG_FLG_FRAGS))
1493 msg_mark_as_complete(msg, 0);
1494 }
1495
1496 /**@retval 1 when message is complete
1497 * @retval 0 when message is incomplete
1498 * @retval -1 upon an error
1499 */
1500 return chunk == NULL((void*)0);
1501}
1502
1503/* Extract trailers */
1504su_inlinestatic inline issize_t
1505extract_trailers(msg_t *msg, msg_pub_t *mo,
1506 char *b, isize_t bsiz, int eos, int copy)
1507{
1508 if (IS_CRLF(b[0])((b[0]) == '\r' || (b[0]) == '\n')) {
1509 msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
1510 return CRLF_TEST(b)((b)[0] == '\r' ? ((b)[1] == '\n') + 1 : (b)[0] =='\n');
1511 }
1512 else
1513 return extract_header(msg, mo, b, bsiz, eos, copy);
1514}
1515
1516/* ====================================================================== */
1517/* Preparing (printing/encoding) a message structure for sending */
1518
1519/* Internal prototypes */
1520su_inlinestatic inline size_t
1521msg_header_name_e(char b[], size_t bsiz, msg_header_t const *h, int flags);
1522static size_t msg_header_prepare(msg_mclass_t const *, int flags,
1523 msg_header_t *h, msg_header_t **return_next,
1524 char *b, size_t bsiz);
1525
1526/**Encode all message fragments.
1527 *
1528 * @relatesalso msg_s
1529 *
1530 * The function msg_prepare() prepares a message for sending. It encodes all
1531 * serialized fragments in the message. You have to call msg_serialize()
1532 * before calling msg_headers_prepare() in order to make sure that all the
1533 * heades and other message fragments are included in the chain.
1534 *
1535 * After encoding, the msg_common_s::h_data field will point to the encoding
1536 * result of size msg_common_s::h_len bytes in in each fragment.
1537 *
1538 * When multiple header fields are represented as a comma-separated list
1539 * within a single header line, the first fragment in the header will
1540 * contain all the text belonging to the header. The rest of the header
1541 * fields will have zero-length encoding with msg_common_s::h_data that
1542 * points to the end of the line.
1543 *
1544 * @return Total size of the encoded message in bytes, or -1 upon an error.
1545 *
1546 * @sa msg_extract(), msg_serialize()
1547 */
1548int msg_prepare(msg_t *msg)
1549{
1550 int total;
1551
1552 assert(msg->m_chain)((void) sizeof ((msg->m_chain) ? 1 : 0), __extension__ ({ if
(msg->m_chain) ; else __assert_fail ("msg->m_chain", "msg_parser.c"
, 1552, __extension__ __PRETTY_FUNCTION__); }))
;
1553 assert(msg_chain_errors(msg->m_chain) == 0)((void) sizeof ((msg_chain_errors(msg->m_chain) == 0) ? 1 :
0), __extension__ ({ if (msg_chain_errors(msg->m_chain) ==
0) ; else __assert_fail ("msg_chain_errors(msg->m_chain) == 0"
, "msg_parser.c", 1553, __extension__ __PRETTY_FUNCTION__); }
))
;
1554
1555 /* Get rid of data that was received but not yet used (parsed) */
1556 msg_clear_committed(msg);
1557
1558 total = msg_headers_prepare(msg, msg->m_chain, msg_object(msg)->msg_flags);
1559
1560 if (total != -1) {
1561 msg->m_size = total;
1562 msg->m_prepared = 1;
1563 }
1564
1565 return total;
1566}
1567
1568/** Clear 'prepared' flag. */
1569void msg_unprepare(msg_t *msg)
1570{
1571 if (msg) msg->m_prepared = 0;
1572}
1573
1574/** Return true if message is prepared. */
1575int msg_is_prepared(msg_t const *msg)
1576{
1577 return msg && msg->m_prepared;
1578}
1579
1580/**Encode headers in chain.
1581 *
1582 * The function msg_headers_prepare() encodes all the headers in the header
1583 * chain. You have to call msg_serialize() before calling
1584 * msg_headers_prepare() in order to make sure that all the heades and other
1585 * message fragments are included in the chain.
1586 *
1587 * @return
1588 * The size of all the headers in chain, or -1 upon an error.
1589 */
1590issize_t msg_headers_prepare(msg_t *msg, msg_header_t *headers, int flags)
1591{
1592 msg_mclass_t const *mc = msg->m_class;
1593 msg_header_t *h, *next;
1594 ssize_t n = 0;
1595 size_t bsiz = 0, used = 0;
1596 char *b;
1597 size_t total = 0;
1598
1599 b = msg_buf_alloc(msg, msg_min_size);
1600 bsiz = msg_buf_size(msg);
1601
1602 if (!b)
1603 return -1;
1604
1605 for (h = headers; h;) {
1606
1607 if (h->sh_datash_common->h_data) {
1608 total += h->sh_lensh_common->h_len;
1609 h = h->sh_succsh_common->h_succ;
1610 continue;
1611 }
1612
1613 for (next = h->sh_succsh_common->h_succ; next; next = next->sh_succsh_common->h_succ)
1614 if (next->sh_classsh_common->h_class != h->sh_classsh_common->h_class || next->sh_datash_common->h_data)
1615 break;
1616
1617 n = msg_header_prepare(mc, flags, h, &next, b, bsiz - used);
1618
1619 if (n == (ssize_t)-1) {
1620 errno(*__errno_location ()) = EINVAL22;
1621 return -1;
1622 }
1623
1624 if (used + n >= bsiz) {
1625 /* Allocate next buffer */
1626 if ((b = msg_buf_alloc(msg, n + 1)) == NULL((void*)0))
1627 return -1;
1628 bsiz = msg_buf_size(msg); used = 0;
1629 continue;
1630 }
1631
1632 h->sh_datash_common->h_data = b, h->sh_lensh_common->h_len = n;
1633
1634 for (h = h->sh_succsh_common->h_succ; h != next; h = h->sh_succsh_common->h_succ)
1635 h->sh_datash_common->h_data = b + n, h->sh_lensh_common->h_len = 0;
1636
1637 msg_buf_used(msg, n);
1638
1639 total += n;
1640 used += n;
1641 b += n;
1642 }
1643
1644 return total;
1645}
1646
1647/** Encode a header or a list of headers */
1648static
1649size_t msg_header_prepare(msg_mclass_t const *mc, int flags,
1650 msg_header_t *h, msg_header_t **return_next,
1651 char *b, size_t bsiz)
1652{
1653 msg_header_t *h0, *next;
1654 msg_hclass_t *hc;
1655 char const *s;
1656 size_t n; ssize_t m;
1657 int compact, one_line_list, comma_list;
1658
1659 assert(h)((void) sizeof ((h) ? 1 : 0), __extension__ ({ if (h) ; else __assert_fail
("h", "msg_parser.c", 1659, __extension__ __PRETTY_FUNCTION__
); }))
; assert(h->sh_class)((void) sizeof ((h->sh_common->h_class) ? 1 : 0), __extension__
({ if (h->sh_common->h_class) ; else __assert_fail ("h->sh_class"
, "msg_parser.c", 1659, __extension__ __PRETTY_FUNCTION__); }
))
;
1660
1661 hc = h->sh_classsh_common->h_class;
1662 compact = MSG_IS_COMPACT(flags)((((flags)) & (MSG_FLG_COMPACT)) == MSG_FLG_COMPACT);
1663 one_line_list = hc->hc_kind == msg_kind_apndlist;
1664 comma_list = compact || one_line_list || MSG_IS_COMMA_LISTS(flags)((((flags)) & (MSG_FLG_COMMA_LISTS)) == MSG_FLG_COMMA_LISTS
)
;
1665
1666 for (h0 = h, n = 0; ; h = next) {
1667 next = h->sh_succsh_common->h_succ;
1668
1669 if (h == h0 && hc->hc_name && hc->hc_name[0])
1670 n += msg_header_name_e(b + n, bsiz >= n ? bsiz - n : 0, h, flags);
1671
1672 if ((m = hc->hc_print(b + n, bsiz >= n ? bsiz - n : 0, h, flags)) == -1) {
1673 if (bsiz >= n + 64)
1674 m = 2 * (bsiz - n);
1675 else
1676 m = 128;
1677 }
1678
1679 n += m;
1680
1681 if (hc->hc_name) {
1682 if (!hc->hc_name[0] || !comma_list || !next || next == *return_next)
1683 s = CRLF"\r" "\n", m = 2;
1684 /* Else encode continuation */
1685 else if (compact)
1686 s = ",", m = 1;
1687 else if (one_line_list)
1688 s = ", ", m = 2;
1689 else
1690 s = "," CRLF"\r" "\n" "\t", m = 4;
1691
1692 if (bsiz > n + m)
1693 memcpy(b + n, s, m);
1694 n += m;
1695 }
1696
1697 if (!comma_list || !next || next == *return_next)
1698 break;
1699 }
1700
1701 *return_next = next;
1702
1703 return n;
1704}
1705
1706/** Encode a header.
1707 *
1708 * The function msg_header_e() encodes a header field in the buffer @a
1709 * b[]. The encoding includes its name and trailing CRLF. The function
1710 * returns the length of the encoding in bytes, excluding the final @c NUL.
1711 * The buffer @a b must be large enough for whole encoding, including the
1712 * final @c NUL.
1713 *
1714 * The @a flags parameter define how the encoding is done. If the flags
1715 * specify @c MSG_DO_COMPACT, the encoding is compact (short form with
1716 * minimal whitespace).
1717 */
1718issize_t msg_header_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
1719{
1720 size_t n, m;
1721
1722 assert(h)((void) sizeof ((h) ? 1 : 0), __extension__ ({ if (h) ; else __assert_fail
("h", "msg_parser.c", 1722, __extension__ __PRETTY_FUNCTION__
); }))
; assert(h->sh_class)((void) sizeof ((h->sh_common->h_class) ? 1 : 0), __extension__
({ if (h->sh_common->h_class) ; else __assert_fail ("h->sh_class"
, "msg_parser.c", 1722, __extension__ __PRETTY_FUNCTION__); }
))
;
1723
1724 if (h == NULL((void*)0) || h->sh_classsh_common->h_class == NULL((void*)0))
1725 return -1;
1726
1727 n = msg_header_name_e(b, bsiz, h, flags);
1728 m = h->sh_classsh_common->h_class->hc_print(b + n, bsiz > n ? bsiz - n : 0, h, flags);
1729 if (h->sh_classsh_common->h_class->hc_name) {
1730 /* Ordinary header */
1731 if (bsiz > n + m + strlen(CRLF"\r" "\n"))
1732 strcpy(b + n + m, CRLF"\r" "\n");
1733 return n + m + strlen(CRLF"\r" "\n");
1734 }
1735 else
1736 return m;
1737}
1738
1739/** Encode header name */
1740su_inlinestatic inline
1741size_t
1742msg_header_name_e(char b[], size_t bsiz, msg_header_t const *h, int flags)
1743{
1744 int compact = MSG_IS_COMPACT(flags)((((flags)) & (MSG_FLG_COMPACT)) == MSG_FLG_COMPACT);
1745 char const *name;
1746 size_t n, n2;
1747
1748 if (compact && h->sh_classsh_common->h_class->hc_short[0])
1749 name = h->sh_classsh_common->h_class->hc_short, n = 1;
1750 else
1751 name = h->sh_classsh_common->h_class->hc_name, n = h->sh_classsh_common->h_class->hc_len;
1752
1753 if (!name || !name[0])
1754 return 0;
1755
1756 n2 = compact ? n + 1 : n + 2;
1757
1758 if (n2 < bsiz) {
1759 memcpy(b, name, n);
1760 b[n++] = ':';
1761 if (!compact)
1762 b[n++] = ' ';
1763 b[n++] = '\0';
1764 }
1765
1766 return n2;
1767}
1768
1769/** Convert a message to a string.
1770 *
1771 * A message is encoded and the encoding result is returned as a string.
1772 * Because the message may contain binary payload (or NUL in headers), the
1773 * message length is returned separately in @a *return_len, too.
1774 *
1775 * Note that the message is serialized as a side effect.
1776 *
1777 * @param home memory home used to allocate the string
1778 * @param msg message to encode
1779 * @param pub message object to encode (may be NULL)
1780 * @param flags flags used when encoding
1781 * @param return_len return-value parameter for encoded message length
1782 *
1783 * @return Encoding result as a C string.
1784 *
1785 * @since New in @VERSION_1_12_4
1786 *
1787 * @sa msg_make(), msg_prepare(), msg_serialize().
1788 */
1789char *msg_as_string(su_home_t *home, msg_t *msg, msg_pub_t *pub, int flags,
1790 size_t *return_len)
1791{
1792 msg_mclass_t const *mc = msg->m_class;
1793 msg_header_t *h, *next;
1794 ssize_t n = 0;
1795 size_t bsiz = 0, used = 0;
1796 char *b, *b2;
1797
1798 if (pub == NULL((void*)0))
1
Assuming 'pub' is equal to NULL
2
Taking true branch
1799 pub = msg->m_object;
1800
1801 if (msg_serialize(msg, pub) < 0)
3
Calling 'msg_serialize'
1802 return NULL((void*)0);
1803
1804 if (return_len == NULL((void*)0))
1805 return_len = &used;
1806
1807 b = su_alloc(home, bsiz = msg_min_size);
1808
1809 if (!b)
1810 return NULL((void*)0);
1811
1812 if (pub == msg->m_object)
1813 h = msg->m_chain;
1814 else
1815 h = pub->msg_common->h_succ;
1816
1817 while (h) {
1818 for (next = h->sh_succsh_common->h_succ; next; next = next->sh_succsh_common->h_succ)
1819 if (next->sh_classsh_common->h_class != h->sh_classsh_common->h_class)
1820 break;
1821
1822 n = msg_header_prepare(mc, flags, h, &next, b + used, bsiz - used);
1823
1824 if (n == -1) {
1825 errno(*__errno_location ()) = EINVAL22;
1826 su_free(home, b);
1827 return NULL((void*)0);
1828 }
1829
1830 if (bsiz > used + n) {
1831 used += n;
1832 h = next;
1833 }
1834 else {
1835 /* Realloc */
1836 if (h->sh_succsh_common->h_succ)
1837 bsiz = (used + n + msg_min_size) / msg_min_size * msg_min_size;
1838 else
1839 bsiz = used + n + 1;
1840
1841 if (bsiz < msg_min_size) {
1842 errno(*__errno_location ()) = ENOMEM12;
1843 su_free(home, b);
1844 return NULL((void*)0);
1845 }
1846
1847 b2 = su_realloc(home, b, bsiz);
1848
1849 if (b2 == NULL((void*)0)) {
1850 errno(*__errno_location ()) = ENOMEM12;
1851 su_free(home, b);
1852 return NULL((void*)0);
1853 }
1854
1855 b = b2;
1856
1857 continue;
1858 }
1859 }
1860
1861 *return_len = used;
1862
1863 b[used] = '\0'; /* NUL terminate */
1864
1865 return su_realloc(home, b, used + 1);
1866}
1867
1868/* ====================================================================== */
1869/* Handling header chain */
1870
1871su_inlinestatic inline void serialize_first(msg_t *msg, msg_header_t *h);
1872static msg_header_t **serialize_one(msg_t *msg, msg_header_t *h,
1873 msg_header_t **prev);
1874
1875/** Return head of the fragment chain */
1876msg_header_t **msg_chain_head(msg_t const *msg)
1877{
1878 return msg ? (msg_header_t **)&msg->m_chain : NULL((void*)0);
1879}
1880
1881su_inlinestatic inline msg_header_t **_msg_chain_head(msg_t const *msg)
1882{
1883 return msg ? (msg_header_t **)&msg->m_chain : NULL((void*)0);
1884}
1885
1886/** Return tail of the fragment chain */
1887su_inlinestatic inline msg_header_t **msg_chain_tail(msg_t const *msg)
1888{
1889 return msg ? msg->m_tail : NULL((void*)0);
1890}
1891
1892/** Serialize headers into the fragment chain.
1893 *
1894 * The msg_serialize() collects the headers and other message components in
1895 * the fragment chain. It should be called before msg_prepare().
1896 *
1897 * @relatesalso msg_s
1898 *
1899 * @param msg pointer to message object
1900 * @param pub public message structure
1901 *
1902 * @retval 0 when successful
1903 * @retval -1 upon an error
1904 */
1905int msg_serialize(msg_t *msg, msg_pub_t *pub)
1906{
1907 msg_header_t *h, **hh, **end;
1908 msg_header_t **separator;
1909 msg_header_t **payload;
1910 msg_header_t **multipart;
1911 msg_mclass_t const *mc;
1912 msg_header_t **tail, ***ptail;
1913
1914 if (!msg)
4
Taking false branch
1915 return errno(*__errno_location ()) = EINVAL22, -1;
1916 if (pub == NULL((void*)0))
5
Assuming 'pub' is equal to NULL
6
Taking true branch
1917 pub = msg->m_object;
7
Null pointer value stored to 'pub'
1918
1919 /* There must be a first line */
1920 if (pub->msg_request)
8
Access to field 'msg_request' results in a dereference of a null pointer (loaded from variable 'pub')
1921 h = pub->msg_request;
1922 else if (pub->msg_status)
1923 h = pub->msg_status;
1924 else
1925 return errno(*__errno_location ()) = EINVAL22, -1;
1926
1927 serialize_first(msg, h);
1928
1929 mc = msg->m_class;
1930 separator = (msg_header_t **)((char *)pub + mc->mc_separator->hr_offset);
1931 payload = (msg_header_t **)((char *)pub + mc->mc_payload->hr_offset);
1932 if (mc->mc_multipart->hr_class)
1933 multipart = (msg_header_t **)((char *)pub + mc->mc_multipart->hr_offset);
1934 else
1935 multipart = NULL((void*)0);
1936
1937 /* Find place to insert headers: before separator, payload and multipart */
1938 if (*separator && !msg_header_is_removed(*separator)((*separator)->sh_common->h_prev == ((void*)0)))
1939 ptail = &(*separator)->sh_prevsh_common->h_prev;
1940 else if (*payload && !msg_header_is_removed(*payload)((*payload)->sh_common->h_prev == ((void*)0)))
1941 ptail = &(*payload)->sh_prevsh_common->h_prev;
1942 else if (multipart && *multipart && !msg_header_is_removed(*multipart)((*multipart)->sh_common->h_prev == ((void*)0)))
1943 ptail = &(*multipart)->sh_prevsh_common->h_prev;
1944 else
1945 ptail = &msg->m_tail;
1946
1947 tail = *ptail;
1948
1949 end = (msg_header_t **)((char *)pub + pub->msg_size);
1950
1951 for (hh = pub->msg_headers; hh < end; hh++) {
1952 if (!*hh)
1953 continue;
1954 if (hh == separator || hh == payload || hh == multipart)
1955 continue;
1956 tail = serialize_one(msg, *hh, tail);
1957 }
1958
1959 /* Serialize separator, payload and multipart last */
1960 if (*separator)
1961 tail = serialize_one(msg, *separator, tail);
1962
1963 *ptail = tail;
1964
1965 /* Payload comes after separator but before multipart */
1966 if (ptail != &(*separator)->sh_prevsh_common->h_prev)
1967 ;
1968 else if (*payload && !msg_header_is_removed(*payload)((*payload)->sh_common->h_prev == ((void*)0)))
1969 ptail = &(*payload)->sh_prevsh_common->h_prev;
1970 else if (multipart && *multipart && !msg_header_is_removed(*multipart)((*multipart)->sh_common->h_prev == ((void*)0)))
1971 ptail = &(*multipart)->sh_prevsh_common->h_prev;
1972 else
1973 ptail = &msg->m_tail;
1974
1975 tail = *ptail;
1976
1977 if (*payload) {
1978 tail = serialize_one(msg, *payload, tail);
1979 *ptail = tail;
1980 }
1981
1982 if (multipart && *multipart) {
1983 msg_header_t *last;
1984
1985 last = msg_multipart_serialize(tail, (msg_multipart_t *)*multipart);
1986
1987 msg->m_tail = &last->sh_succsh_common->h_succ;
1988 }
1989
1990 assert(msg->m_chain && msg_chain_errors(msg->m_chain) == 0)((void) sizeof ((msg->m_chain && msg_chain_errors(
msg->m_chain) == 0) ? 1 : 0), __extension__ ({ if (msg->
m_chain && msg_chain_errors(msg->m_chain) == 0) ; else
__assert_fail ("msg->m_chain && msg_chain_errors(msg->m_chain) == 0"
, "msg_parser.c", 1990, __extension__ __PRETTY_FUNCTION__); }
))
;
1991
1992 return 0;
1993}
1994
1995su_inlinestatic inline
1996void serialize_first(msg_t *msg, msg_header_t *h)
1997{
1998 if (msg_header_is_removed(h)((h)->sh_common->h_prev == ((void*)0))) {
1999 if ((h->sh_succsh_common->h_succ = msg->m_chain))
2000 h->sh_succsh_common->h_succ->sh_prevsh_common->h_prev = &h->sh_succsh_common->h_succ;
2001 else
2002 msg->m_tail = &h->sh_succsh_common->h_succ;
2003 *(h->sh_prevsh_common->h_prev = &msg->m_chain) = h;
2004 }
2005}
2006
2007static
2008msg_header_t **serialize_one(msg_t *msg, msg_header_t *h, msg_header_t **prev)
2009{
2010 msg_header_t *last;
2011 msg_header_t *succ = *prev;
2012
2013 if (msg_header_is_removed(h)((h)->sh_common->h_prev == ((void*)0))) {
2014 /* Add the first header in the list to the chain */
2015 *prev = h; h->sh_prevsh_common->h_prev = prev;
2016 for (last = h; last->sh_succsh_common->h_succ; last = last->sh_succsh_common->h_succ) {
2017 /* Ensure that chain is connected */
2018 assert(last->sh_next == last->sh_succ)((void) sizeof ((last->sh_header_next->shn_next == last
->sh_common->h_succ) ? 1 : 0), __extension__ ({ if (last
->sh_header_next->shn_next == last->sh_common->h_succ
) ; else __assert_fail ("last->sh_next == last->sh_succ"
, "msg_parser.c", 2018, __extension__ __PRETTY_FUNCTION__); }
))
;
2019 assert(last->sh_succ->sh_prev == &last->sh_succ)((void) sizeof ((last->sh_common->h_succ->sh_common->
h_prev == &last->sh_common->h_succ) ? 1 : 0), __extension__
({ if (last->sh_common->h_succ->sh_common->h_prev
== &last->sh_common->h_succ) ; else __assert_fail (
"last->sh_succ->sh_prev == &last->sh_succ", "msg_parser.c"
, 2019, __extension__ __PRETTY_FUNCTION__); }))
;
2020 }
2021 prev = &last->sh_succsh_common->h_succ;
2022 }
2023
2024 if ((h = h->sh_nextsh_header_next->shn_next)) {
2025 assert(!msg_is_single(h))((void) sizeof ((!msg_is_single(h)) ? 1 : 0), __extension__ (
{ if (!msg_is_single(h)) ; else __assert_fail ("!msg_is_single(h)"
, "msg_parser.c", 2025, __extension__ __PRETTY_FUNCTION__); }
))
;
2026
2027 if (msg_is_single(h)) {
2028 for (; h; h = h->sh_nextsh_header_next->shn_next)
2029 if (!msg_header_is_removed(h)((h)->sh_common->h_prev == ((void*)0)))
2030 msg_chain_remove(msg, h);
2031 }
2032 /* Add the rest of the headers in the list to the chain */
2033 else for (; h; h = h->sh_nextsh_header_next->shn_next) {
2034 if (msg_header_is_removed(h)((h)->sh_common->h_prev == ((void*)0))) {
2035 *prev = h; h->sh_prevsh_common->h_prev = prev;
2036 for (;h->sh_succsh_common->h_succ; h = h->sh_succsh_common->h_succ)
2037 assert(h->sh_succ == h->sh_next)((void) sizeof ((h->sh_common->h_succ == h->sh_header_next
->shn_next) ? 1 : 0), __extension__ ({ if (h->sh_common
->h_succ == h->sh_header_next->shn_next) ; else __assert_fail
("h->sh_succ == h->sh_next", "msg_parser.c", 2037, __extension__
__PRETTY_FUNCTION__); }))
;
2038 prev = &h->sh_succsh_common->h_succ;
2039 }
2040 }
2041 }
2042
2043 *prev = succ;
2044
2045 return prev;
2046}
2047
2048/**Fill an I/O vector with message contents.
2049 *
2050 * @relatesalso msg_s
2051 *
2052 * Calculate number of entries in the I/O vector
2053 * required to send a message @a msg. It also fills in the I/O vector array,
2054 * if it is provided by the caller and it is large enough.
2055 *
2056 * @param msg pointer to message object
2057 * @param vec I/O vector (may be NULL)
2058 * @param veclen length of I/O vector in @a vec
2059 *
2060 * @return
2061 * Number of entries of I/O
2062 * vector required by @a msg, or 0 upon an error.
2063 *
2064 * @note The caller should check that the I/O vector @a vec has enough
2065 * entries. If the @a vec is too short, it should allocate big enough
2066 * vector and re-invoke msg_iovec().
2067 *
2068 * @sa msg_recv_iovec(), su_vsend()
2069 */
2070isize_t msg_iovec(msg_t *msg, msg_iovec_t vec[], isize_t veclen)
2071{
2072 size_t len = 0, n = 0;
2073 char const *p = NULL((void*)0);
2074 msg_header_t *h;
2075
2076 size_t total = 0;
2077
2078 if (veclen <= 0)
2079 veclen = 0;
2080
2081 for (h = msg->m_chain; h; h = h->sh_succsh_common->h_succ) {
2082 if (h->sh_datash_common->h_data != p) {
2083 p = h->sh_datash_common->h_data; len = h->sh_lensh_common->h_len;
2084
2085 if (p == NULL((void*)0))
2086 return 0;
2087
2088 if (vec && n != veclen)
2089 /* new iovec entry */
2090 vec[n].mv_basesiv_base = (void *)p, vec[n].mv_lensiv_len = (su_ioveclen_t)len;
2091 else
2092 vec = NULL((void*)0);
2093
2094 p += len; n++;
2095 }
2096 else {
2097 /* extend old entry */
2098 len = h->sh_lensh_common->h_len;
2099 if (vec)
2100 vec[n-1].mv_lensiv_len += (su_ioveclen_t)len;
2101 p += len;
2102 }
2103
2104 total += len;
2105 }
2106
2107 msg->m_size = total;
2108
2109 return n;
2110}
2111
2112/** Insert a header to existing header chain.
2113 *
2114 * Headers are either inserted just before the payload, or after the first
2115 * line, depending on their type.
2116 *
2117 * @param[in] msg message object
2118 * @param[in,out] pub public message structure
2119 * @param prepend if true, add before same type of headers (instead after them)
2120 * @param head head of chain
2121 * @param h header to insert
2122 *
2123 */
2124static
2125void msg_insert_chain(msg_t *msg,
2126 msg_pub_t *pub,
2127 int prepend,
2128 msg_header_t **head,
2129 msg_header_t *h)
2130{
2131 msg_mclass_t const *mc;
2132 msg_header_t **hh;
2133 msg_header_t **separator;
2134 msg_header_t **payload;
2135
2136 assert(msg && pub && head && h)((void) sizeof ((msg && pub && head &&
h) ? 1 : 0), __extension__ ({ if (msg && pub &&
head && h) ; else __assert_fail ("msg && pub && head && h"
, "msg_parser.c", 2136, __extension__ __PRETTY_FUNCTION__); }
))
;
2137
2138 mc = msg->m_class;
2139 separator = (msg_header_t **)((char *)pub + mc->mc_separator->hr_offset);
2140 payload = (msg_header_t **)((char *)pub + mc->mc_payload->hr_offset);
2141
2142 if (msg_is_request(h)) {
2143 if (pub->msg_status)
2144 pub->msg_status = NULL((void*)0);
2145 hh = head;
2146 }
2147 else if (msg_is_status(h)) {
2148 if (pub->msg_request)
2149 pub->msg_request = NULL((void*)0);
2150 hh = head;
2151 }
2152 else if (msg_is_payload(h)) {
2153 /* Append */
2154 hh = msg_chain_tail(msg);
2155 }
2156 else if (prepend) {
2157 if (!msg_is_request(*head) && !msg_is_status(*head))
2158 hh = head;
2159 else
2160 hh = &((*head)->sh_succsh_common->h_succ);
2161 }
2162 /* Append headers before separator or payload */
2163 else if (*separator && (*separator)->sh_prevsh_common->h_prev)
2164 hh = (*separator)->sh_prevsh_common->h_prev;
2165 else if (*payload && (*payload)->sh_prevsh_common->h_prev)
2166 hh = (*payload)->sh_prevsh_common->h_prev;
2167 else
2168 hh = msg_chain_tail(msg);
2169
2170 msg_insert_here_in_chain(msg, hh, h);
2171}
2172
2173/** Insert one or more message header to the chain.
2174 *
2175 * The function msg_insert_here_in_chain() appends message header to the
2176 * chain of headers after the given header.
2177 *
2178 * @param msg message
2179 * @param prev pointer to h_succ of previous fragment in the list
2180 * @param h header to be inserted.
2181 *
2182 * @return The pointer to the last header inserted.
2183 */
2184static
2185void msg_insert_here_in_chain(msg_t *msg,
2186 msg_header_t **prev,
2187 msg_header_t *h)
2188{
2189 if (h) {
2190 msg_header_t *last, *next;
2191 assert(h->sh_prev == NULL)((void) sizeof ((h->sh_common->h_prev == ((void*)0)) ? 1
: 0), __extension__ ({ if (h->sh_common->h_prev == ((void
*)0)) ; else __assert_fail ("h->sh_prev == NULL", "msg_parser.c"
, 2191, __extension__ __PRETTY_FUNCTION__); }))
;
2192 assert(prev)((void) sizeof ((prev) ? 1 : 0), __extension__ ({ if (prev) ;
else __assert_fail ("prev", "msg_parser.c", 2192, __extension__
__PRETTY_FUNCTION__); }))
;
2193 assert(!msg_chain_errors(h))((void) sizeof ((!msg_chain_errors(h)) ? 1 : 0), __extension__
({ if (!msg_chain_errors(h)) ; else __assert_fail ("!msg_chain_errors(h)"
, "msg_parser.c", 2193, __extension__ __PRETTY_FUNCTION__); }
))
;
2194
2195 for (last = h; last->sh_succsh_common->h_succ; last = last->sh_succsh_common->h_succ)
2196 ;
2197
2198 last->sh_succsh_common->h_succ = next = *prev;
2199 *prev = h;
2200 h->sh_prevsh_common->h_prev = prev;
2201 if (next)
2202 next->sh_prevsh_common->h_prev = &last->sh_succsh_common->h_succ;
2203 else
2204 msg->m_tail = &last->sh_succsh_common->h_succ;
2205
2206 assert(msg->m_chain && msg_chain_errors(msg->m_chain) == 0)((void) sizeof ((msg->m_chain && msg_chain_errors(
msg->m_chain) == 0) ? 1 : 0), __extension__ ({ if (msg->
m_chain && msg_chain_errors(msg->m_chain) == 0) ; else
__assert_fail ("msg->m_chain && msg_chain_errors(msg->m_chain) == 0"
, "msg_parser.c", 2206, __extension__ __PRETTY_FUNCTION__); }
))
;
2207 }
2208}
2209
2210/**
2211 * Remove a message from header chain.
2212 *
2213 * The function @c msg_chain_remove() removes a message header from the header
2214 * chain.
2215 *
2216 * @param msg pointer to the message
2217 * @param h pointer to the header in the list to be removed
2218 *
2219 * @return The pointer to the header just removed.
2220 */
2221su_inlinestatic inline
2222msg_header_t *msg_chain_remove(msg_t *msg, msg_header_t *h)
2223{
2224 if (h) {
2225 if (h->sh_prevsh_common->h_prev) {
2226 assert(*h->sh_prev == h)((void) sizeof ((*h->sh_common->h_prev == h) ? 1 : 0), __extension__
({ if (*h->sh_common->h_prev == h) ; else __assert_fail
("*h->sh_prev == h", "msg_parser.c", 2226, __extension__ __PRETTY_FUNCTION__
); }))
;
2227 assert(h->sh_succ == NULL || h->sh_succ->sh_prev == &h->sh_succ)((void) sizeof ((h->sh_common->h_succ == ((void*)0) || h
->sh_common->h_succ->sh_common->h_prev == &h->
sh_common->h_succ) ? 1 : 0), __extension__ ({ if (h->sh_common
->h_succ == ((void*)0) || h->sh_common->h_succ->sh_common
->h_prev == &h->sh_common->h_succ) ; else __assert_fail
("h->sh_succ == NULL || h->sh_succ->sh_prev == &h->sh_succ"
, "msg_parser.c", 2227, __extension__ __PRETTY_FUNCTION__); }
))
;
2228
2229 *h->sh_prevsh_common->h_prev = h->sh_succsh_common->h_succ;
2230 }
2231
2232 if (h->sh_succsh_common->h_succ)
2233 h->sh_succsh_common->h_succ->sh_prevsh_common->h_prev = h->sh_prevsh_common->h_prev;
2234 else if (msg && h->sh_prevsh_common->h_prev)
2235 msg->m_tail = h->sh_prevsh_common->h_prev;
2236
2237 h->sh_succsh_common->h_succ = NULL((void*)0); h->sh_prevsh_common->h_prev = NULL((void*)0);
2238
2239 if (msg)
2240 assert(msg_chain_errors(msg->m_chain) == 0)((void) sizeof ((msg_chain_errors(msg->m_chain) == 0) ? 1 :
0), __extension__ ({ if (msg_chain_errors(msg->m_chain) ==
0) ; else __assert_fail ("msg_chain_errors(msg->m_chain) == 0"
, "msg_parser.c", 2240, __extension__ __PRETTY_FUNCTION__); }
))
;
2241 }
2242 return h;
2243}
2244
2245#ifndef NDEBUG
2246/**Check if header chain contains any loops.
2247 *
2248 * @return
2249 * Return 0 if no loop, -1 otherwise.
2250 */
2251static
2252int msg_chain_loop(msg_header_t const *h)
2253{
2254 msg_header_t const *h2;
2255
2256 if (!h) return 0;
2257
2258 for (h2 = h->sh_succsh_common->h_succ; h && h2 && h2->sh_succsh_common->h_succ; h = h->sh_succsh_common->h_succ) {
2259 if (h == h2 || h == h2->sh_succsh_common->h_succ)
2260 return 1;
2261
2262 h2 = h2->sh_succsh_common->h_succ->sh_succsh_common->h_succ;
2263
2264 if (h == h2)
2265 return 1;
2266 }
2267
2268 return 0;
2269}
2270
2271/** Check header chain consistency.
2272 *
2273 * @return
2274 * Return 0 if consistent, number of errors otherwise.
2275 */
2276static
2277int msg_chain_errors(msg_header_t const *h)
2278{
2279 if (msg_chain_loop(h))
2280 return -1;
2281
2282 for (; h; h = h->sh_succsh_common->h_succ) {
2283 if (h->sh_succsh_common->h_succ && h->sh_succsh_common->h_succ->sh_prevsh_common->h_prev != &h->sh_succsh_common->h_succ)
2284 return -1;
2285 if (h->sh_prevsh_common->h_prev && h != (*h->sh_prevsh_common->h_prev))
2286 return -1;
2287 }
2288
2289 return 0;
2290}
2291#endif
2292
2293/* ====================================================================== */
2294/* Handling message structure - allocating, adding and removing headers */
2295
2296/** Allocate a header structure
2297 *
2298 * The msg_header_alloc() function allocates a generic MO header structure
2299 * and returns a pointer to it.
2300 *
2301 * @param home memory home
2302 * @param hc header class
2303 * @param extra amount of extra memory to be allocated after header structure
2304 *
2305 * @return
2306 * A pointer to the newly created header object, or @c NULL upon an error.
2307 */
2308msg_header_t *msg_header_alloc(su_home_t *home,
2309 msg_hclass_t *hc,
2310 isize_t extra)
2311{
2312 isize_t size = hc->hc_size;
2313 msg_header_t *h = su_alloc(home, size + extra);
2314
2315 if (h) {
2316 memset(h, 0, size);
2317 h->sh_classsh_common->h_class = hc;
2318 }
2319
2320 return h;
2321}
2322
2323/**Add a (list of) header(s) to the header structure and fragment chain.
2324 *
2325 * The function @c msg_header_add() adds a header or list of headers into
2326 * the given place within the message structure. It also inserts the headers
2327 * into the the message fragment chain, if it exists.
2328 *
2329 * If the header is a prepend header, the new header is inserted before
2330 * existing headers of the same class. If the header is an append header,
2331 * the new header is inserted after existing headers of the same class. If
2332 * the header is a singleton, existing headers of the same class are
2333 * removed. If the header is a list header, the values in the new header are
2334 * added to the existing list.
2335 *
2336 * @param msg message owning the fragment chain
2337 * @param pub public message structure
2338 * @param hh place in message structure to which header is added
2339 * @param h list of header(s) to be added
2340 */
2341int msg_header_add(msg_t *msg,
2342 msg_pub_t *pub,
2343 msg_header_t **hh,
2344 msg_header_t *h)
2345{
2346 msg_header_t **head, *old = NULL((void*)0), *end;
2347
2348 if (msg == NULL((void*)0) || h == NULL((void*)0) || h == MSG_HEADER_NONE((msg_header_t *)-1) || hh == NULL((void*)0))
2349 return -1;
2350 if (pub == NULL((void*)0))
2351 pub = msg->m_object;
2352
2353 head = _msg_chain_head(msg);
2354
2355 if (*head) {
2356 msg_header_t *sh, **prev;
2357
2358 for (sh = h, prev = NULL((void*)0); sh; sh = sh->sh_nextsh_header_next->shn_next) {
2359 sh->sh_succsh_common->h_succ = sh->sh_nextsh_header_next->shn_next;
2360 sh->sh_prevsh_common->h_prev = prev;
2361 prev = &sh->sh_succsh_common->h_succ;
2362 }
2363 }
2364
2365 switch (h->sh_classsh_common->h_class->hc_kind) {
2366 case msg_kind_single:
2367 case msg_kind_list:
2368 old = (*hh);
2369 break;
2370 case msg_kind_append:
2371 case msg_kind_apndlist:
2372 while (*hh)
2373 hh = &(*hh)->sh_nextsh_header_next->shn_next;
2374 break;
2375 case msg_kind_prepend:
2376 for (end = h; end->sh_nextsh_header_next->shn_next; end = end->sh_nextsh_header_next->shn_next)
2377 ;
2378 end->sh_nextsh_header_next->shn_next = *hh;
2379 }
2380
2381 if (*head) {
2382 /* Insert into existing fragment chain */
2383 msg_insert_chain(msg, pub, msg_is_prepend(h), head, h);
2384
2385 /* Remove replaced fragment */
2386 if (old)
2387 msg_chain_remove(msg, old);
2388 }
2389
2390 /* Insert into header list */
2391 *hh = h;
2392
2393 return 0;
2394}
2395
2396/**Prepend a (list of) header(s) to the header structure and fragment chain.
2397 *
2398 * The function @c msg_header_prepend() adds a header or list of headers into
2399 * the given place within the message structure. It also inserts the headers
2400 * into the the message fragment chain, if it exists.
2401 *
2402 * Unlike msg_header_add(), msg_header_prepend() always inserts header @a h
2403 * before other headers of the same class. If the header is a singleton,
2404 * existing headers of the same class are removed. If the header is a list
2405 * header, the values in the new header are prepended to the existing list.
2406 *
2407 * @param msg message owning the fragment chain
2408 * @param pub public message structure
2409 * @param hh place in message structure to which header is added
2410 * @param h list of header(s) to be added
2411 */
2412int msg_header_prepend(msg_t *msg,
2413 msg_pub_t *pub,
2414 msg_header_t **hh,
2415 msg_header_t *h)
2416{
2417 msg_header_t **head, *old = NULL((void*)0), *end;
2418
2419 assert(msg && pub)((void) sizeof ((msg && pub) ? 1 : 0), __extension__ (
{ if (msg && pub) ; else __assert_fail ("msg && pub"
, "msg_parser.c", 2419, __extension__ __PRETTY_FUNCTION__); }
))
;
2420
2421 if (msg == NULL((void*)0) || h == NULL((void*)0) || h == MSG_HEADER_NONE((msg_header_t *)-1) || hh == NULL((void*)0))
2422 return -1;
2423 if (pub == NULL((void*)0))
2424 pub = msg->m_object;
2425
2426 head = _msg_chain_head(msg);
2427
2428 if (*head) {
2429 msg_header_t *sh, **prev;
2430
2431 for (sh = h, prev = NULL((void*)0); sh; sh = sh->sh_nextsh_header_next->shn_next) {
2432 sh->sh_succsh_common->h_succ = sh->sh_nextsh_header_next->shn_next;
2433 sh->sh_prevsh_common->h_prev = prev;
2434 prev = &sh->sh_succsh_common->h_succ;
2435 }
2436 }
2437
2438 switch (h->sh_classsh_common->h_class->hc_kind) {
2439 case msg_kind_single:
2440 case msg_kind_list:
2441 old = (*hh);
2442 break;
2443 case msg_kind_append:
2444 case msg_kind_apndlist:
2445 case msg_kind_prepend:
2446 for (end = h; end->sh_nextsh_header_next->shn_next; end = end->sh_nextsh_header_next->shn_next)
2447 ;
2448 end->sh_nextsh_header_next->shn_next = *hh;
2449 break;
2450 }
2451
2452 if (*head) {
2453 /* Insert into existing fragment chain */
2454 msg_insert_chain(msg, pub, 1, head, h);
2455
2456 /* Remove replaced fragment */
2457 if (old)
2458 msg_chain_remove(msg, old);
2459 }
2460
2461 /* Insert into header list */
2462 *hh = h;
2463
2464 return 0;
2465}
2466
2467
2468/** Find place to insert header of the class @a hc. */
2469msg_header_t **
2470msg_hclass_offset(msg_mclass_t const *mc, msg_pub_t const *mo, msg_hclass_t *hc)
2471{
2472 assert(mc && hc)((void) sizeof ((mc && hc) ? 1 : 0), __extension__ ({
if (mc && hc) ; else __assert_fail ("mc && hc"
, "msg_parser.c", 2472, __extension__ __PRETTY_FUNCTION__); }
))
;
2473
2474 if (mc == NULL((void*)0) || hc == NULL((void*)0))
2475 return NULL((void*)0);
2476
2477 if (hc->hc_hash > 0) {
2478 unsigned j, N = mc->mc_hash_size;
2479 for (j = hc->hc_hash % N; mc->mc_hash[j].hr_class; j = (j + 1) % N)
2480 if (mc->mc_hash[j].hr_class == hc) {
2481 return (msg_header_t **)((char *)mo + mc->mc_hash[j].hr_offset);
2482 }
2483 } else {
2484 /* Header has no name. */
2485 if (hc->hc_hash == mc->mc_request[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_request[0].hr_offset);
2486 if (hc->hc_hash == mc->mc_status[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_status[0].hr_offset);
2487 if (hc->hc_hash == mc->mc_separator[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_separator[0].hr_offset);
2488 if (hc->hc_hash == mc->mc_payload[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_payload[0].hr_offset);
2489 if (hc->hc_hash == mc->mc_unknown[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_unknown[0].hr_offset);
2490 if (hc->hc_hash == mc->mc_error[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_error[0].hr_offset);
2491 if (hc->hc_hash == mc->mc_multipart[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_multipart[0].hr_offset);
2492 }
2493
2494 return NULL((void*)0);
2495}
2496
2497/** Append a parsed header object into the message structure */
2498su_inlinestatic inline void
2499append_parsed(msg_t *msg, msg_pub_t *mo, msg_href_t const *hr, msg_header_t *h,
2500 int always_into_chain)
2501{
2502 msg_header_t **hh;
2503
2504 assert(msg)((void) sizeof ((msg) ? 1 : 0), __extension__ ({ if (msg) ; else
__assert_fail ("msg", "msg_parser.c", 2504, __extension__ __PRETTY_FUNCTION__
); }))
; assert(hr->hr_offset)((void) sizeof ((hr->hr_offset) ? 1 : 0), __extension__ ({
if (hr->hr_offset) ; else __assert_fail ("hr->hr_offset"
, "msg_parser.c", 2504, __extension__ __PRETTY_FUNCTION__); }
))
;
2505
2506 hh = (msg_header_t **)((char *)mo + hr->hr_offset);
2507
2508 if (msg->m_chain || always_into_chain)
2509 msg_insert_here_in_chain(msg, msg_chain_tail(msg), h);
2510
2511 if (*hh && msg_is_single(h)) {
2512 /* If there is multiple instances of single headers,
2513 put the extra headers into the list of erroneous headers */
2514 msg_error_t **e;
2515
2516 for (e = &mo->msg_error; *e; e = &(*e)->er_next)
2517 ;
2518 *e = (msg_error_t *)h;
2519
2520 msg->m_extract_err |= hr->hr_flags;
2521 if (hr->hr_class->hc_critical)
2522 mo->msg_flags |= MSG_FLG_ERROR;
2523
2524 return;
2525 }
2526
2527 while (*hh)
2528 hh = &(*hh)->sh_nextsh_header_next->shn_next;
2529 *hh = h;
2530}
2531
2532static int _msg_header_add_list_items(msg_t *msg,
2533 msg_header_t **hh,
2534 msg_header_t const *src);
2535
2536/**Duplicate and add a (list of) header(s) to the message.
2537 *
2538 * The function @c msg_header_add_dup() duplicates and adds a (list of)
2539 * header(s) into a message structure.
2540 *
2541 * When inserting headers into the fragment chain, a request (or status) is
2542 * inserted first and replaces the existing request (or status). Other
2543 * headers are inserted after the request or status.
2544 *
2545 * If the header is a singleton, existing headers with the same class are
2546 * removed.
2547 *
2548 * @param msg message owning the fragment chain
2549 * @param pub public message structure to which header is added
2550 * @param src list of header(s) to be added
2551 */
2552int msg_header_add_dup(msg_t *msg,
2553 msg_pub_t *pub,
2554 msg_header_t const *src)
2555{
2556 msg_header_t *h, **hh = NULL((void*)0);
2557 msg_hclass_t *hc = NULL((void*)0);
2558
2559 if (msg == NULL((void*)0))
2560 return -1;
2561 if (src == NULL((void*)0) || src == MSG_HEADER_NONE((msg_header_t *)-1))
2562 return 0;
2563 if (pub == NULL((void*)0))
2564 pub = msg->m_object;
2565
2566 for ( ;src; src = src->sh_nextsh_header_next->shn_next) {
2567 assert(src->sh_class)((void) sizeof ((src->sh_common->h_class) ? 1 : 0), __extension__
({ if (src->sh_common->h_class) ; else __assert_fail (
"src->sh_class", "msg_parser.c", 2567, __extension__ __PRETTY_FUNCTION__
); }))
;
2568
2569 if (!src->sh_classsh_common->h_class)
2570 return -1;
2571
2572 if (hc != src->sh_classsh_common->h_class)
2573 hh = msg_hclass_offset(msg->m_class, pub, hc = src->sh_classsh_common->h_class);
2574
2575 if (hh == NULL((void*)0))
2576 return -1;
2577
2578 if (!*hh || hc->hc_kind != msg_kind_list) {
2579 int size = hc->hc_size;
2580 isize_t xtra = hc->hc_dxtra(src, size) - size;
2581 char *end;
2582
2583 if (!(h = msg_header_alloc(msg_home(msg)((su_home_t*)(msg)), hc, xtra)))
2584 return -1; /* error */
2585
2586 if (!(end = hc->hc_dup_one(h, src, (char *)h + size, xtra)))
2587 return -1; /* error */
2588
2589 if (hc->hc_update)
2590 msg_header_update_params(h->sh_common, 0);
2591
2592 assert(end == (char *)h + size + xtra)((void) sizeof ((end == (char *)h + size + xtra) ? 1 : 0), __extension__
({ if (end == (char *)h + size + xtra) ; else __assert_fail (
"end == (char *)h + size + xtra", "msg_parser.c", 2592, __extension__
__PRETTY_FUNCTION__); }))
;
2593
2594 if (msg_header_add(msg, pub, hh, h) < 0)
2595 return -1;
2596
2597 hh = &h->sh_nextsh_header_next->shn_next;
2598 }
2599 else {
2600 if (_msg_header_add_list_items(msg, hh, src) < 0)
2601 break;
2602 }
2603 }
2604
2605 if (src)
2606 return -1;
2607
2608 return 0;
2609}
2610
2611/**Duplicate a header as a given type and add the duplicate into message.
2612 *
2613 * The function @c msg_header_add_dup_as() duplicates a header as a instance
2614 * of the given header class. It adds the new copy into the message.
2615 *
2616 * When inserting headers into the fragment chain, a request (or status) is
2617 * inserted first and replaces the existing request (or status). Other
2618 * headers are inserted after the request or status.
2619 *
2620 * If the header is a singleton, existing headers with the same class are
2621 * removed.
2622 *
2623 * @param msg message owning the fragment chain
2624 * @param pub public message structure to which header is added
2625 * @param hc header class for header target type
2626 * @param src list of header(s) to be duplicated and added
2627 */
2628int msg_header_add_dup_as(msg_t *msg,
2629 msg_pub_t *pub,
2630 msg_hclass_t *hc,
2631 msg_header_t const *src)
2632{
2633 if (msg == NULL((void*)0) || hc == NULL((void*)0))
2634 return -1;
2635 if (src == NULL((void*)0) || src == MSG_HEADER_NONE((msg_header_t *)-1))
2636 return 0;
2637 if (pub == NULL((void*)0))
2638 pub = msg->m_object;
2639
2640 return _msg_header_add_dup_as(msg, pub, hc, src);
2641}
2642
2643/** Duplicate and add a (list of) header to a message */
2644static
2645int _msg_header_add_dup_as(msg_t *msg,
2646 msg_pub_t *pub,
2647 msg_hclass_t *hc,
2648 msg_header_t const *src)
2649{
2650 msg_header_t *h, **hh;
2651
2652 hh = msg_hclass_offset(msg->m_class, pub, hc);
2653
2654 if (hh == NULL((void*)0))
2655 return -1;
2656
2657 if (*hh && hc->hc_kind == msg_kind_list)
2658 return _msg_header_add_list_items(msg, hh, src);
2659
2660 if (!(h = msg_header_dup_as(msg_home(msg)((su_home_t*)(msg)), hc, src)))
2661 return -1;
2662
2663 return msg_header_add(msg, pub, hh, h);
2664}
2665
2666/* Add list items */
2667static int _msg_header_add_list_items(msg_t *msg,
2668 msg_header_t **hh,
2669 msg_header_t const *src)
2670{
2671 msg_header_t *h = *hh;
2672 msg_param_t **s = msg_header_params(src->sh_common);
2673
2674 if (!s || !*s)
2675 return 0;
2676
2677 msg_fragment_clear(h->sh_common);
2678
2679 /* Remove empty headers */
2680 for (hh = &h->sh_nextsh_header_next->shn_next; *hh; *hh = (*hh)->sh_nextsh_header_next->shn_next)
2681 msg_chain_remove(msg, *hh);
2682
2683 if (msg_header_join_items(msg_home(msg)((su_home_t*)(msg)), h->sh_common, src->sh_common, 1)
2684 < 0)
2685 return -1;
2686
2687 return 0;
2688}
2689
2690/** Parse a string as a given header field and add result to the message. */
2691int msg_header_add_make(msg_t *msg,
2692 msg_pub_t *pub,
2693 msg_hclass_t *hc,
2694 char const *s)
2695{
2696 msg_header_t *h, **hh;
2697
2698 if (msg == NULL((void*)0))
2699 return -1;
2700 if (pub == NULL((void*)0))
2701 pub = msg->m_object;
2702
2703 hh = msg_hclass_offset(msg->m_class, pub, hc);
2704
2705 if (hh == NULL((void*)0))
2706 return -1;
2707
2708 if (!s)
2709 return 0;
2710
2711 if (*hh && hc->hc_kind == msg_kind_list) {
2712 /* Add list items */
2713 msg_header_t *h = *hh;
2714 msg_param_t **d;
2715 char *s0;
2716
2717 skip_lws(&s)(*(&s) += span_lws(*(&s)));
2718
2719 d = msg_header_params(h->sh_common); assert(d)((void) sizeof ((d) ? 1 : 0), __extension__ ({ if (d) ; else __assert_fail
("d", "msg_parser.c", 2719, __extension__ __PRETTY_FUNCTION__
); }))
;
2720
2721 msg_fragment_clear(h->sh_common);
2722
2723 /* Remove empty headers */
2724 for (hh = &h->sh_nextsh_header_next->shn_next; *hh; *hh = (*hh)->sh_nextsh_header_next->shn_next)
2725 msg_chain_remove(msg, *hh);
2726
2727 s0 = su_strdup(msg_home(msg)((su_home_t*)(msg)), s);
2728
2729 if (!s0 || msg_commalist_d(msg_home(msg)((su_home_t*)(msg)), &s0, d, msg_token_scan) < 0)
2730 return -1;
2731
2732 return 0;
2733 }
2734
2735 if (!(h = msg_header_make(msg_home(msg)((su_home_t*)(msg)), hc, s)))
2736 return -1;
2737
2738 return msg_header_add(msg, pub, hh, h);
2739}
2740
2741/** Add formatting result to message.
2742 *
2743 * Parse result from printf-formatted params as a given header field and add
2744 * result to the message.
2745 *
2746 * @NEW_1_12_10
2747 */
2748int msg_header_add_format(msg_t *msg,
2749 msg_pub_t *pub,
2750 msg_hclass_t *hc,
2751 char const *fmt,
2752 ...)
2753{
2754 msg_header_t *h, **hh;
2755 va_list va;
2756
2757 if (msg == NULL((void*)0))
2758 return -1;
2759 if (pub == NULL((void*)0))
2760 pub = msg->m_object;
2761
2762 hh = msg_hclass_offset(msg->m_class, pub, hc);
2763
2764 if (hh == NULL((void*)0))
2765 return -1;
2766
2767 if (!fmt)
2768 return 0;
2769
2770 va_start(va, fmt)__builtin_va_start(va, fmt);
2771 h = msg_header_vformat(msg_home(msg)((su_home_t*)(msg)), hc, fmt, va);
2772 va_end(va)__builtin_va_end(va);
2773
2774 if (!h)
2775 return -1;
2776
2777 return msg_header_add(msg, pub, hh, h);
2778}
2779
2780
2781/**Add string contents to message.
2782 *
2783 * Duplicate a string containing headers (or a message body, if the string
2784 * starts with linefeed), parse it and add resulting header objects to the
2785 * message object.
2786 *
2787 * @param msg message object
2788 * @param pub message header structure where heades are added (may be NULL)
2789 * @param str string to be copied and parsed (not modified, may be NULL)
2790 *
2791 * @retval 0 when succesful
2792 * @retval -1 upon an error
2793 */
2794int msg_header_add_str(msg_t *msg,
2795 msg_pub_t *pub,
2796 char const *str)
2797{
2798 char *s;
2799
2800 if (!msg)
2801 return -1;
2802 if (!str)
2803 return 0;
2804
2805 s = su_strdup(msg_home(msg)((su_home_t*)(msg)), str);
2806
2807 if (s == NULL((void*)0))
2808 return -1;
2809
2810 return msg_header_parse_str(msg, pub, s);
2811}
2812
2813/**Add string to message.
2814 *
2815 * Parse a string containing headers (or a message body, if the string
2816 * starts with linefeed) and add resulting header objects to the message
2817 * object.
2818 *
2819 * @param msg message object
2820 * @param pub message header structure where heades are added (may be NULL)
2821 * @param s string to be parsed (and modified)
2822 *
2823 * @retval 0 when succesful
2824 * @retval -1 upon an error
2825 *
2826 * @sa msg_header_add_str(), url_headers_as_string()
2827 *
2828 * @since New in @VERSION_1_12_4.
2829 */
2830int msg_header_parse_str(msg_t *msg,
2831 msg_pub_t *pub,
2832 char *s)
2833{
2834 if (!msg)
2835 return -1;
2836
2837 if (pub == NULL((void*)0))
2838 pub = msg->m_object;
2839
2840 if (s) {
2841 size_t ssiz = strlen(s), used = 0;
2842 ssize_t n = 1;
2843
2844 while (ssiz > used) {
2845 if (IS_CRLF(s[used])((s[used]) == '\r' || (s[used]) == '\n'))
2846 break;
2847 n = msg_extract_header(msg, pub, s + used, ssiz - used, 1);
2848 if (n <= 0)
2849 break;
2850 used += n;
2851 }
2852
2853 if (n > 0 && ssiz > used) {
2854 used += CRLF_TEST(s + used)((s + used)[0] == '\r' ? ((s + used)[1] == '\n') + 1 : (s + used
)[0] =='\n')
;
2855 if (ssiz > used)
2856 msg_extract_payload(msg, pub, NULL((void*)0), ssiz - used,
2857 s + used, ssiz - used, 1);
2858 }
2859
2860 if (n <= 0)
2861 return -1;
2862 }
2863
2864 return 0;
2865}
2866
2867/** Insert a (list of) header(s) to the fragment chain.
2868 *
2869 * The function @c msg_header_insert() inserts header or list of headers
2870 * into a message structure. It also inserts them into the the message
2871 * fragment chain, if it exists.
2872 *
2873 * When inserting headers into the fragment chain, a request (or status) is
2874 * inserted first and replaces the existing request (or status). Other
2875 * headers are inserted after the request or status.
2876 *
2877 * If there can be only one header field of this type (hc_kind is
2878 * msg_kind_single), existing header objects with the same class are
2879 * removed.
2880 *
2881 * @param msg message object owning the fragment chain
2882 * @param pub public message structure to which header is added
2883 * @param h list of header(s) to be added
2884 */
2885int msg_header_insert(msg_t *msg, msg_pub_t *pub, msg_header_t *h)
2886{
2887 msg_header_t **hh;
2888
2889 assert(msg)((void) sizeof ((msg) ? 1 : 0), __extension__ ({ if (msg) ; else
__assert_fail ("msg", "msg_parser.c", 2889, __extension__ __PRETTY_FUNCTION__
); }))
;
2890
2891 if (msg == NULL((void*)0) || h == NULL((void*)0) || h == MSG_HEADER_NONE((msg_header_t *)-1) ||
2892 h->sh_classsh_common->h_class == NULL((void*)0))
2893 return -1;
2894 if (pub == NULL((void*)0))
2895 pub = msg->m_object;
2896
2897 hh = msg_hclass_offset(msg->m_class, pub, h->sh_classsh_common->h_class);
2898
2899 return msg_header_add(msg, pub, hh, h);
2900}
2901
2902/**Remove a header from the header structure and fragment chain.
2903 *
2904 * The function @c msg_header_remove() removes a header from a message
2905 * structure. It also removes the message from the message fragment chain
2906 * and clears the encoding of other headers objects that share same
2907 * encoding.
2908 *
2909 * @param msg message owning the fragment chain
2910 * @param pub public message structure to which header is added
2911 * @param h header to be removed
2912 */
2913int msg_header_remove(msg_t *msg, msg_pub_t *pub, msg_header_t *h)
2914{
2915 msg_header_t **hh, **hh0;
2916
2917 if (msg == NULL((void*)0) || h == NULL((void*)0) || h == MSG_HEADER_NONE((msg_header_t *)-1) ||
2918 h->sh_classsh_common->h_class == NULL((void*)0))
2919 return -1;
2920 if (pub == NULL((void*)0))
2921 pub = msg->m_object;
2922
2923 /* First, remove from public structure (msg_pub_t) */
2924 hh0 = msg_hclass_offset(msg->m_class, pub, h->sh_classsh_common->h_class);
2925 if (!hh0)
2926 return -1;
2927
2928 for (hh = hh0; *hh; hh = &(*hh)->sh_nextsh_header_next->shn_next) {
2929 if (*hh == h) {
2930 *hh = h->sh_nextsh_header_next->shn_next;
2931 break;
2932 }
2933 }
2934
2935 if (h->sh_datash_common->h_data) {
2936 void const *data = (char *)h->sh_datash_common->h_data + h->sh_lensh_common->h_len;
2937 for (hh = hh0; *hh; hh = &(*hh)->sh_nextsh_header_next->shn_next) {
2938 if (data == (char *)(*hh)->sh_datash_common->h_data + (*hh)->sh_lensh_common->h_len) {
2939 (*hh)->sh_datash_common->h_data = NULL((void*)0), (*hh)->sh_lensh_common->h_len = 0;
2940 }
2941 }
2942 }
2943
2944 msg_chain_remove(msg, h);
2945
2946 return 0;
2947}
2948
2949
2950/**Remove a header list from the header structure and fragment chain.
2951 *
2952 * The function @c msg_header_remove_all() removes a list of headers from a
2953 * message structure. It also removes the message from the message fragment
2954 * chain and clears the encoding of other headers objects that share same
2955 * encoding.
2956 *
2957 * @param msg message owning the fragment chain
2958 * @param pub public message structure to which header is added
2959 * @param h header list to be removed
2960 */
2961int msg_header_remove_all(msg_t *msg, msg_pub_t *pub, msg_header_t *h)
2962{
2963 msg_header_t **hh, **hh0;
2964 void const *data;
2965
2966 if (msg == NULL((void*)0) || h == NULL((void*)0) || h == MSG_HEADER_NONE((msg_header_t *)-1) ||
2967 h->sh_classsh_common->h_class == NULL((void*)0))
2968 return -1;
2969 if (pub == NULL((void*)0))
2970 pub = msg->m_object;
2971
2972 hh0 = msg_hclass_offset(msg->m_class, pub, h->sh_classsh_common->h_class);
2973 if (!hh0)
2974 return -1;
2975
2976 data = (char *)h->sh_datash_common->h_data + h->sh_lensh_common->h_len;
2977
2978 /* First, remove from public structure (msg_pub_t) */
2979 for (hh = hh0; *hh; hh = &(*hh)->sh_nextsh_header_next->shn_next) {
2980 if (*hh == h) {
2981 break;
2982 }
2983 if (data && data == (char *)(*hh)->sh_datash_common->h_data + (*hh)->sh_lensh_common->h_len) {
2984 h->sh_datash_common->h_data = NULL((void*)0), h->sh_lensh_common->h_len = 0;
2985 (*hh)->sh_datash_common->h_data = NULL((void*)0), (*hh)->sh_lensh_common->h_len = 0;
2986 }
2987 }
2988
2989 /* Remove from header chain */
2990 while (h) {
2991 h->sh_datash_common->h_data = NULL((void*)0), h->sh_lensh_common->h_len = 0;
2992 msg_chain_remove(msg, h);
2993 h = h->sh_nextsh_header_next->shn_next;
2994 }
2995
2996 *hh = NULL((void*)0);
2997
2998 return 0;
2999}
3000
3001
3002/** Replace a header item with a (list of) header(s).
3003 *
3004 * The function @c msg_header_replace() removes a header structure from
3005 * message and replaces it with a new one or a list of headers. It inserts
3006 * the new headers into the the message fragment chain, if it exists.
3007 *
3008 * @param msg message object owning the fragment chain
3009 * @param pub public message structure to which header is added
3010 * @param replaced old header to be removed
3011 * @param h list of header(s) to be added
3012 */
3013int msg_header_replace(msg_t *msg,
3014 msg_pub_t *pub,
3015 msg_header_t *replaced,
3016 msg_header_t *h)
3017{
3018 msg_header_t *h0, *last, **hh, **hh0;
3019
3020 if (msg == NULL((void*)0) || replaced == NULL((void*)0))
3021 return -1;
3022 if (h == NULL((void*)0) || h == MSG_HEADER_NONE((msg_header_t *)-1) || h->sh_classsh_common->h_class == NULL((void*)0))
3023 return msg_header_remove(msg, pub, replaced);
3024 if (pub == NULL((void*)0))
3025 pub = msg->m_object;
3026
3027 hh = hh0 = msg_hclass_offset(msg->m_class, pub, h->sh_classsh_common->h_class);
3028 if (hh == NULL((void*)0))
3029 return -1;
3030 if (replaced == NULL((void*)0))
3031 return msg_header_add(msg, pub, hh, h);
3032
3033 assert(h->sh_prev == NULL)((void) sizeof ((h->sh_common->h_prev == ((void*)0)) ? 1
: 0), __extension__ ({ if (h->sh_common->h_prev == ((void
*)0)) ; else __assert_fail ("h->sh_prev == NULL", "msg_parser.c"
, 3033, __extension__ __PRETTY_FUNCTION__); }))
; /* Must not be in existing chain! */
3034
3035 for (last = h; last->sh_nextsh_header_next->shn_next; last = last->sh_nextsh_header_next->shn_next) {
3036 if ((last->sh_succsh_common->h_succ = last->sh_nextsh_header_next->shn_next))
3037 last->sh_nextsh_header_next->shn_next->sh_prevsh_common->h_prev = &last->sh_succsh_common->h_succ;
3038 }
3039
3040 for (h0 = *hh; h0; hh = &h0->sh_nextsh_header_next->shn_next, h0 = *hh) {
3041 if (replaced == h0)
3042 break;
3043 }
3044
3045 if (h0 == NULL((void*)0))
3046 return -1;
3047
3048 *hh = h; /* Replace in list */
3049 last->sh_nextsh_header_next->shn_next = replaced->sh_nextsh_header_next->shn_next;
3050
3051 if (replaced->sh_prevsh_common->h_prev) {
3052 *replaced->sh_prevsh_common->h_prev = h;
3053 h->sh_prevsh_common->h_prev = replaced->sh_prevsh_common->h_prev;
3054 if ((last->sh_succsh_common->h_succ = replaced->sh_succsh_common->h_succ))
3055 last->sh_succsh_common->h_succ->sh_prevsh_common->h_prev = &last->sh_succsh_common->h_succ;
3056 if (msg->m_tail == &replaced->sh_succsh_common->h_succ)
3057 msg->m_tail = &last->sh_succsh_common->h_succ;
3058 }
3059
3060 assert(msg->m_tail != &replaced->sh_succ)((void) sizeof ((msg->m_tail != &replaced->sh_common
->h_succ) ? 1 : 0), __extension__ ({ if (msg->m_tail !=
&replaced->sh_common->h_succ) ; else __assert_fail
("msg->m_tail != &replaced->sh_succ", "msg_parser.c"
, 3060, __extension__ __PRETTY_FUNCTION__); }))
;
3061
3062 replaced->sh_nextsh_header_next->shn_next = NULL((void*)0);
3063 replaced->sh_prevsh_common->h_prev = NULL((void*)0);
3064 replaced->sh_succsh_common->h_succ = NULL((void*)0);
3065
3066 if (replaced->sh_datash_common->h_data) {
3067 /* Remove cached encoding if it is shared with more than one header fragments */
3068 int cleared = 0;
3069 void const *data = (char *)replaced->sh_datash_common->h_data + replaced->sh_lensh_common->h_len;
3070
3071 for (hh = hh0; *hh; hh = &(*hh)->sh_nextsh_header_next->shn_next) {
3072 if (data == (char *)(*hh)->sh_datash_common->h_data + (*hh)->sh_lensh_common->h_len) {
3073 (*hh)->sh_datash_common->h_data = NULL((void*)0), (*hh)->sh_lensh_common->h_len = 0, cleared = 1;
3074 }
3075 }
3076
3077 if (cleared)
3078 replaced->sh_datash_common->h_data = NULL((void*)0), replaced->sh_lensh_common->h_len = 0;
3079 }
3080
3081 return 0;
3082}
3083
3084/** Free a header structure */
3085void msg_header_free(su_home_t *home, msg_header_t *h)
3086{
3087 su_free(home, h);
3088}
3089
3090/** Free a (list of) header structures */
3091void msg_header_free_all(su_home_t *home, msg_header_t *h)
3092{
3093 msg_header_t *h_next;
3094
3095 while (h) {
3096 h_next = h->sh_nextsh_header_next->shn_next;
3097 su_free(home, h);
3098 h = h_next;
3099 }
3100}