back to topotato report
topotato coverage report
Current view: top level - lib - stream.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 316 624 50.6 %
Date: 2023-11-16 17:19:14 Functions: 54 172 31.4 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Packet interface
       4             :  * Copyright (C) 1999 Kunihiro Ishiguro
       5             :  */
       6             : 
       7             : #include <zebra.h>
       8             : #include <stddef.h>
       9             : #include <pthread.h>
      10             : 
      11             : #include "stream.h"
      12             : #include "memory.h"
      13             : #include "network.h"
      14             : #include "prefix.h"
      15             : #include "log.h"
      16             : #include "frr_pthread.h"
      17             : #include "lib_errors.h"
      18             : 
      19          12 : DEFINE_MTYPE_STATIC(LIB, STREAM, "Stream");
      20          12 : DEFINE_MTYPE_STATIC(LIB, STREAM_FIFO, "Stream FIFO");
      21             : 
      22             : /* Tests whether a position is valid */
      23             : #define GETP_VALID(S, G) ((G) <= (S)->endp)
      24             : #define PUT_AT_VALID(S,G) GETP_VALID(S,G)
      25             : #define ENDP_VALID(S, E) ((E) <= (S)->size)
      26             : 
      27             : /* asserting sanity checks. Following must be true before
      28             :  * stream functions are called:
      29             :  *
      30             :  * Following must always be true of stream elements
      31             :  * before and after calls to stream functions:
      32             :  *
      33             :  * getp <= endp <= size
      34             :  *
      35             :  * Note that after a stream function is called following may be true:
      36             :  * if (getp == endp) then stream is no longer readable
      37             :  * if (endp == size) then stream is no longer writeable
      38             :  *
      39             :  * It is valid to put to anywhere within the size of the stream, but only
      40             :  * using stream_put..._at() functions.
      41             :  */
      42             : #define STREAM_WARN_OFFSETS(S)                                                 \
      43             :         do {                                                                   \
      44             :                 flog_warn(EC_LIB_STREAM,                                       \
      45             :                           "&(struct stream): %p, size: %lu, getp: %lu, endp: %lu", \
      46             :                           (void *)(S), (unsigned long)(S)->size,            \
      47             :                           (unsigned long)(S)->getp, (unsigned long)(S)->endp); \
      48             :                 zlog_backtrace(LOG_WARNING);                                   \
      49             :         } while (0)
      50             : 
      51             : #define STREAM_VERIFY_SANE(S)                                                  \
      52             :         do {                                                                   \
      53             :                 if (!(GETP_VALID(S, (S)->getp) && ENDP_VALID(S, (S)->endp))) { \
      54             :                         STREAM_WARN_OFFSETS(S);                                \
      55             :                 }                                                              \
      56             :                 assert(GETP_VALID(S, (S)->getp));                              \
      57             :                 assert(ENDP_VALID(S, (S)->endp));                              \
      58             :         } while (0)
      59             : 
      60             : #define STREAM_BOUND_WARN(S, WHAT)                                             \
      61             :         do {                                                                   \
      62             :                 flog_warn(EC_LIB_STREAM, "%s: Attempt to %s out of bounds",    \
      63             :                           __func__, (WHAT));                                   \
      64             :                 STREAM_WARN_OFFSETS(S);                                        \
      65             :                 assert(0);                                                     \
      66             :         } while (0)
      67             : 
      68             : #define STREAM_BOUND_WARN2(S, WHAT)                                            \
      69             :         do {                                                                   \
      70             :                 flog_warn(EC_LIB_STREAM, "%s: Attempt to %s out of bounds",    \
      71             :                           __func__, (WHAT));                                   \
      72             :                 STREAM_WARN_OFFSETS(S);                                        \
      73             :         } while (0)
      74             : 
      75             : /* XXX: Deprecated macro: do not use */
      76             : #define CHECK_SIZE(S, Z)                                                       \
      77             :         do {                                                                   \
      78             :                 if (((S)->endp + (Z)) > (S)->size) {                           \
      79             :                         flog_warn(                                             \
      80             :                                 EC_LIB_STREAM,                                 \
      81             :                                 "CHECK_SIZE: truncating requested size %lu",   \
      82             :                                 (unsigned long)(Z));                           \
      83             :                         STREAM_WARN_OFFSETS(S);                                \
      84             :                         (Z) = (S)->size - (S)->endp;                           \
      85             :                 }                                                              \
      86             :         } while (0);
      87             : 
      88             : /* Make stream buffer. */
      89         394 : struct stream *stream_new(size_t size)
      90             : {
      91         394 :         struct stream *s;
      92             : 
      93         394 :         assert(size > 0);
      94             : 
      95         394 :         s = XMALLOC(MTYPE_STREAM, sizeof(struct stream) + size);
      96             : 
      97         394 :         s->getp = s->endp = 0;
      98         394 :         s->next = NULL;
      99         394 :         s->size = size;
     100         394 :         return s;
     101             : }
     102             : 
     103             : /* Free it now. */
     104         398 : void stream_free(struct stream *s)
     105             : {
     106         398 :         if (!s)
     107             :                 return;
     108             : 
     109         394 :         XFREE(MTYPE_STREAM, s);
     110             : }
     111             : 
     112         154 : struct stream *stream_copy(struct stream *dest, const struct stream *src)
     113             : {
     114         154 :         STREAM_VERIFY_SANE(src);
     115             : 
     116         154 :         assert(dest != NULL);
     117         154 :         assert(STREAM_SIZE(dest) >= src->endp);
     118             : 
     119         154 :         dest->endp = src->endp;
     120         154 :         dest->getp = src->getp;
     121             : 
     122         154 :         memcpy(dest->data, src->data, src->endp);
     123             : 
     124         154 :         return dest;
     125             : }
     126             : 
     127         146 : struct stream *stream_dup(const struct stream *s)
     128             : {
     129         146 :         struct stream *snew;
     130             : 
     131         146 :         STREAM_VERIFY_SANE(s);
     132             : 
     133         146 :         snew = stream_new(s->endp);
     134             : 
     135         146 :         return (stream_copy(snew, s));
     136             : }
     137             : 
     138           5 : struct stream *stream_dupcat(const struct stream *s1, const struct stream *s2,
     139             :                              size_t offset)
     140             : {
     141           5 :         struct stream *new;
     142             : 
     143           5 :         STREAM_VERIFY_SANE(s1);
     144           5 :         STREAM_VERIFY_SANE(s2);
     145             : 
     146           5 :         if ((new = stream_new(s1->endp + s2->endp)) == NULL)
     147             :                 return NULL;
     148             : 
     149           5 :         memcpy(new->data, s1->data, offset);
     150           5 :         memcpy(new->data + offset, s2->data, s2->endp);
     151           5 :         memcpy(new->data + offset + s2->endp, s1->data + offset,
     152           5 :                (s1->endp - offset));
     153           5 :         new->endp = s1->endp + s2->endp;
     154           5 :         return new;
     155             : }
     156             : 
     157           0 : size_t stream_resize_inplace(struct stream **sptr, size_t newsize)
     158             : {
     159           0 :         struct stream *orig = *sptr;
     160             : 
     161           0 :         STREAM_VERIFY_SANE(orig);
     162             : 
     163           0 :         orig = XREALLOC(MTYPE_STREAM, orig, sizeof(struct stream) + newsize);
     164             : 
     165           0 :         orig->size = newsize;
     166             : 
     167           0 :         if (orig->endp > orig->size)
     168           0 :                 orig->endp = orig->size;
     169           0 :         if (orig->getp > orig->endp)
     170           0 :                 orig->getp = orig->endp;
     171             : 
     172           0 :         STREAM_VERIFY_SANE(orig);
     173             : 
     174           0 :         *sptr = orig;
     175           0 :         return orig->size;
     176             : }
     177             : 
     178         575 : size_t stream_get_getp(const struct stream *s)
     179             : {
     180         575 :         STREAM_VERIFY_SANE(s);
     181         575 :         return s->getp;
     182             : }
     183             : 
     184        1084 : size_t stream_get_endp(const struct stream *s)
     185             : {
     186        1084 :         STREAM_VERIFY_SANE(s);
     187        1084 :         return s->endp;
     188             : }
     189             : 
     190           0 : size_t stream_get_size(const struct stream *s)
     191             : {
     192           0 :         STREAM_VERIFY_SANE(s);
     193           0 :         return s->size;
     194             : }
     195             : 
     196             : /* Stream structre' stream pointer related functions.  */
     197         497 : void stream_set_getp(struct stream *s, size_t pos)
     198             : {
     199         497 :         STREAM_VERIFY_SANE(s);
     200             : 
     201         497 :         if (!GETP_VALID(s, pos)) {
     202           0 :                 STREAM_BOUND_WARN(s, "set getp");
     203             :                 pos = s->endp;
     204             :         }
     205             : 
     206         497 :         s->getp = pos;
     207         497 : }
     208             : 
     209          22 : void stream_set_endp(struct stream *s, size_t pos)
     210             : {
     211          22 :         STREAM_VERIFY_SANE(s);
     212             : 
     213          22 :         if (!ENDP_VALID(s, pos)) {
     214           0 :                 STREAM_BOUND_WARN(s, "set endp");
     215             :                 return;
     216             :         }
     217             : 
     218             :         /*
     219             :          * Make sure the current read pointer is not beyond the new endp.
     220             :          */
     221          22 :         if (s->getp > pos) {
     222           0 :                 STREAM_BOUND_WARN(s, "set endp");
     223             :                 return;
     224             :         }
     225             : 
     226          22 :         s->endp = pos;
     227          22 :         STREAM_VERIFY_SANE(s);
     228             : }
     229             : 
     230             : /* Forward pointer. */
     231          48 : void stream_forward_getp(struct stream *s, size_t size)
     232             : {
     233          48 :         STREAM_VERIFY_SANE(s);
     234             : 
     235          48 :         if (!GETP_VALID(s, s->getp + size)) {
     236           0 :                 STREAM_BOUND_WARN(s, "seek getp");
     237             :                 return;
     238             :         }
     239             : 
     240          48 :         s->getp += size;
     241             : }
     242             : 
     243           0 : bool stream_forward_getp2(struct stream *s, size_t size)
     244             : {
     245           0 :         STREAM_VERIFY_SANE(s);
     246             : 
     247           0 :         if (!GETP_VALID(s, s->getp + size))
     248             :                 return false;
     249             : 
     250           0 :         s->getp += size;
     251             : 
     252           0 :         return true;
     253             : }
     254             : 
     255           0 : void stream_rewind_getp(struct stream *s, size_t size)
     256             : {
     257           0 :         STREAM_VERIFY_SANE(s);
     258             : 
     259           0 :         if (size > s->getp || !GETP_VALID(s, s->getp - size)) {
     260           0 :                 STREAM_BOUND_WARN(s, "rewind getp");
     261             :                 return;
     262             :         }
     263             : 
     264           0 :         s->getp -= size;
     265             : }
     266             : 
     267           0 : bool stream_rewind_getp2(struct stream *s, size_t size)
     268             : {
     269           0 :         STREAM_VERIFY_SANE(s);
     270             : 
     271           0 :         if (size > s->getp || !GETP_VALID(s, s->getp - size))
     272             :                 return false;
     273             : 
     274           0 :         s->getp -= size;
     275             : 
     276           0 :         return true;
     277             : }
     278             : 
     279           0 : void stream_forward_endp(struct stream *s, size_t size)
     280             : {
     281           0 :         STREAM_VERIFY_SANE(s);
     282             : 
     283           0 :         if (!ENDP_VALID(s, s->endp + size)) {
     284           0 :                 STREAM_BOUND_WARN(s, "seek endp");
     285             :                 return;
     286             :         }
     287             : 
     288           0 :         s->endp += size;
     289             : }
     290             : 
     291           0 : bool stream_forward_endp2(struct stream *s, size_t size)
     292             : {
     293           0 :         STREAM_VERIFY_SANE(s);
     294             : 
     295           0 :         if (!ENDP_VALID(s, s->endp + size))
     296             :                 return false;
     297             : 
     298           0 :         s->endp += size;
     299             : 
     300           0 :         return true;
     301             : }
     302             : 
     303             : /* Copy from stream to destination. */
     304         195 : bool stream_get2(void *dst, struct stream *s, size_t size)
     305             : {
     306         195 :         STREAM_VERIFY_SANE(s);
     307             : 
     308         195 :         if (STREAM_READABLE(s) < size) {
     309           0 :                 STREAM_BOUND_WARN2(s, "get");
     310           0 :                 return false;
     311             :         }
     312             : 
     313         195 :         memcpy(dst, s->data + s->getp, size);
     314         195 :         s->getp += size;
     315             : 
     316         195 :         return true;
     317             : }
     318             : 
     319          24 : void stream_get(void *dst, struct stream *s, size_t size)
     320             : {
     321          24 :         STREAM_VERIFY_SANE(s);
     322             : 
     323          24 :         if (STREAM_READABLE(s) < size) {
     324           0 :                 STREAM_BOUND_WARN(s, "get");
     325             :                 return;
     326             :         }
     327             : 
     328          24 :         memcpy(dst, s->data + s->getp, size);
     329          24 :         s->getp += size;
     330             : }
     331             : 
     332             : /* Get next character from the stream. */
     333         952 : bool stream_getc2(struct stream *s, uint8_t *byte)
     334             : {
     335         952 :         STREAM_VERIFY_SANE(s);
     336             : 
     337         952 :         if (STREAM_READABLE(s) < sizeof(uint8_t)) {
     338           0 :                 STREAM_BOUND_WARN2(s, "get char");
     339           0 :                 return false;
     340             :         }
     341         952 :         *byte = s->data[s->getp++];
     342             : 
     343         952 :         return true;
     344             : }
     345             : 
     346         850 : uint8_t stream_getc(struct stream *s)
     347             : {
     348         850 :         uint8_t c;
     349             : 
     350         850 :         STREAM_VERIFY_SANE(s);
     351             : 
     352         850 :         if (STREAM_READABLE(s) < sizeof(uint8_t)) {
     353           0 :                 STREAM_BOUND_WARN(s, "get char");
     354             :                 return 0;
     355             :         }
     356         850 :         c = s->data[s->getp++];
     357             : 
     358         850 :         return c;
     359             : }
     360             : 
     361             : /* Get next character from the stream. */
     362          10 : uint8_t stream_getc_from(struct stream *s, size_t from)
     363             : {
     364          10 :         uint8_t c;
     365             : 
     366          10 :         STREAM_VERIFY_SANE(s);
     367             : 
     368          10 :         if (!GETP_VALID(s, from + sizeof(uint8_t))) {
     369           0 :                 STREAM_BOUND_WARN(s, "get char");
     370             :                 return 0;
     371             :         }
     372             : 
     373          10 :         c = s->data[from];
     374             : 
     375          10 :         return c;
     376             : }
     377             : 
     378         598 : bool stream_getw2(struct stream *s, uint16_t *word)
     379             : {
     380         598 :         STREAM_VERIFY_SANE(s);
     381             : 
     382         598 :         if (STREAM_READABLE(s) < sizeof(uint16_t)) {
     383           0 :                 STREAM_BOUND_WARN2(s, "get ");
     384           0 :                 return false;
     385             :         }
     386             : 
     387         598 :         *word = s->data[s->getp++] << 8;
     388         598 :         *word |= s->data[s->getp++];
     389             : 
     390         598 :         return true;
     391             : }
     392             : 
     393             : /* Get next word from the stream. */
     394         446 : uint16_t stream_getw(struct stream *s)
     395             : {
     396         446 :         uint16_t w;
     397             : 
     398         446 :         STREAM_VERIFY_SANE(s);
     399             : 
     400         446 :         if (STREAM_READABLE(s) < sizeof(uint16_t)) {
     401           0 :                 STREAM_BOUND_WARN(s, "get ");
     402             :                 return 0;
     403             :         }
     404             : 
     405         446 :         w = s->data[s->getp++] << 8;
     406         446 :         w |= s->data[s->getp++];
     407             : 
     408         446 :         return w;
     409             : }
     410             : 
     411             : /* Get next word from the stream. */
     412          42 : uint16_t stream_getw_from(struct stream *s, size_t from)
     413             : {
     414          42 :         uint16_t w;
     415             : 
     416          42 :         STREAM_VERIFY_SANE(s);
     417             : 
     418          42 :         if (!GETP_VALID(s, from + sizeof(uint16_t))) {
     419           0 :                 STREAM_BOUND_WARN(s, "get ");
     420             :                 return 0;
     421             :         }
     422             : 
     423          42 :         w = s->data[from++] << 8;
     424          42 :         w |= s->data[from];
     425             : 
     426          42 :         return w;
     427             : }
     428             : 
     429             : /* Get next 3-byte from the stream. */
     430           0 : uint32_t stream_get3_from(struct stream *s, size_t from)
     431             : {
     432           0 :         uint32_t l;
     433             : 
     434           0 :         STREAM_VERIFY_SANE(s);
     435             : 
     436           0 :         if (!GETP_VALID(s, from + 3)) {
     437           0 :                 STREAM_BOUND_WARN(s, "get 3byte");
     438             :                 return 0;
     439             :         }
     440             : 
     441           0 :         l = s->data[from++] << 16;
     442           0 :         l |= s->data[from++] << 8;
     443           0 :         l |= s->data[from];
     444             : 
     445           0 :         return l;
     446             : }
     447             : 
     448           4 : uint32_t stream_get3(struct stream *s)
     449             : {
     450           4 :         uint32_t l;
     451             : 
     452           4 :         STREAM_VERIFY_SANE(s);
     453             : 
     454           4 :         if (STREAM_READABLE(s) < 3) {
     455           0 :                 STREAM_BOUND_WARN(s, "get 3byte");
     456             :                 return 0;
     457             :         }
     458             : 
     459           4 :         l = s->data[s->getp++] << 16;
     460           4 :         l |= s->data[s->getp++] << 8;
     461           4 :         l |= s->data[s->getp++];
     462             : 
     463           4 :         return l;
     464             : }
     465             : 
     466             : /* Get next long word from the stream. */
     467           0 : uint32_t stream_getl_from(struct stream *s, size_t from)
     468             : {
     469           0 :         uint32_t l;
     470             : 
     471           0 :         STREAM_VERIFY_SANE(s);
     472             : 
     473           0 :         if (!GETP_VALID(s, from + sizeof(uint32_t))) {
     474           0 :                 STREAM_BOUND_WARN(s, "get long");
     475             :                 return 0;
     476             :         }
     477             : 
     478           0 :         l = (unsigned)(s->data[from++]) << 24;
     479           0 :         l |= s->data[from++] << 16;
     480           0 :         l |= s->data[from++] << 8;
     481           0 :         l |= s->data[from];
     482             : 
     483           0 :         return l;
     484             : }
     485             : 
     486             : /* Copy from stream at specific location to destination. */
     487          22 : void stream_get_from(void *dst, struct stream *s, size_t from, size_t size)
     488             : {
     489          22 :         STREAM_VERIFY_SANE(s);
     490             : 
     491          22 :         if (!GETP_VALID(s, from + size)) {
     492           0 :                 STREAM_BOUND_WARN(s, "get from");
     493             :                 return;
     494             :         }
     495             : 
     496          22 :         memcpy(dst, s->data + from, size);
     497             : }
     498             : 
     499        1187 : bool stream_getl2(struct stream *s, uint32_t *l)
     500             : {
     501        1187 :         STREAM_VERIFY_SANE(s);
     502             : 
     503        1187 :         if (STREAM_READABLE(s) < sizeof(uint32_t)) {
     504           0 :                 STREAM_BOUND_WARN2(s, "get long");
     505           0 :                 return false;
     506             :         }
     507             : 
     508        1187 :         *l = (unsigned int)(s->data[s->getp++]) << 24;
     509        1187 :         *l |= s->data[s->getp++] << 16;
     510        1187 :         *l |= s->data[s->getp++] << 8;
     511        1187 :         *l |= s->data[s->getp++];
     512             : 
     513        1187 :         return true;
     514             : }
     515             : 
     516         193 : uint32_t stream_getl(struct stream *s)
     517             : {
     518         193 :         uint32_t l;
     519             : 
     520         193 :         STREAM_VERIFY_SANE(s);
     521             : 
     522         193 :         if (STREAM_READABLE(s) < sizeof(uint32_t)) {
     523           0 :                 STREAM_BOUND_WARN(s, "get long");
     524             :                 return 0;
     525             :         }
     526             : 
     527         193 :         l = (unsigned)(s->data[s->getp++]) << 24;
     528         193 :         l |= s->data[s->getp++] << 16;
     529         193 :         l |= s->data[s->getp++] << 8;
     530         193 :         l |= s->data[s->getp++];
     531             : 
     532         193 :         return l;
     533             : }
     534             : 
     535             : /* Get next quad word from the stream. */
     536           0 : uint64_t stream_getq_from(struct stream *s, size_t from)
     537             : {
     538           0 :         uint64_t q;
     539             : 
     540           0 :         STREAM_VERIFY_SANE(s);
     541             : 
     542           0 :         if (!GETP_VALID(s, from + sizeof(uint64_t))) {
     543           0 :                 STREAM_BOUND_WARN(s, "get quad");
     544             :                 return 0;
     545             :         }
     546             : 
     547           0 :         q = ((uint64_t)s->data[from++]) << 56;
     548           0 :         q |= ((uint64_t)s->data[from++]) << 48;
     549           0 :         q |= ((uint64_t)s->data[from++]) << 40;
     550           0 :         q |= ((uint64_t)s->data[from++]) << 32;
     551           0 :         q |= ((uint64_t)s->data[from++]) << 24;
     552           0 :         q |= ((uint64_t)s->data[from++]) << 16;
     553           0 :         q |= ((uint64_t)s->data[from++]) << 8;
     554           0 :         q |= ((uint64_t)s->data[from++]);
     555             : 
     556           0 :         return q;
     557             : }
     558             : 
     559           0 : uint64_t stream_getq(struct stream *s)
     560             : {
     561           0 :         uint64_t q;
     562             : 
     563           0 :         STREAM_VERIFY_SANE(s);
     564             : 
     565           0 :         if (STREAM_READABLE(s) < sizeof(uint64_t)) {
     566           0 :                 STREAM_BOUND_WARN(s, "get quad");
     567             :                 return 0;
     568             :         }
     569             : 
     570           0 :         q = ((uint64_t)s->data[s->getp++]) << 56;
     571           0 :         q |= ((uint64_t)s->data[s->getp++]) << 48;
     572           0 :         q |= ((uint64_t)s->data[s->getp++]) << 40;
     573           0 :         q |= ((uint64_t)s->data[s->getp++]) << 32;
     574           0 :         q |= ((uint64_t)s->data[s->getp++]) << 24;
     575           0 :         q |= ((uint64_t)s->data[s->getp++]) << 16;
     576           0 :         q |= ((uint64_t)s->data[s->getp++]) << 8;
     577           0 :         q |= ((uint64_t)s->data[s->getp++]);
     578             : 
     579           0 :         return q;
     580             : }
     581             : 
     582          42 : bool stream_getq2(struct stream *s, uint64_t *q)
     583             : {
     584          42 :         STREAM_VERIFY_SANE(s);
     585             : 
     586          42 :         if (STREAM_READABLE(s) < sizeof(uint64_t)) {
     587           0 :                 STREAM_BOUND_WARN2(s, "get uint64");
     588           0 :                 return false;
     589             :         }
     590             : 
     591          42 :         *q = ((uint64_t)s->data[s->getp++]) << 56;
     592          42 :         *q |= ((uint64_t)s->data[s->getp++]) << 48;
     593          42 :         *q |= ((uint64_t)s->data[s->getp++]) << 40;
     594          42 :         *q |= ((uint64_t)s->data[s->getp++]) << 32;
     595          42 :         *q |= ((uint64_t)s->data[s->getp++]) << 24;
     596          42 :         *q |= ((uint64_t)s->data[s->getp++]) << 16;
     597          42 :         *q |= ((uint64_t)s->data[s->getp++]) << 8;
     598          42 :         *q |= ((uint64_t)s->data[s->getp++]);
     599             : 
     600          42 :         return true;
     601             : }
     602             : 
     603             : /* Get next long word from the stream. */
     604           4 : uint32_t stream_get_ipv4(struct stream *s)
     605             : {
     606           4 :         uint32_t l;
     607             : 
     608           4 :         STREAM_VERIFY_SANE(s);
     609             : 
     610           4 :         if (STREAM_READABLE(s) < sizeof(uint32_t)) {
     611           0 :                 STREAM_BOUND_WARN(s, "get ipv4");
     612             :                 return 0;
     613             :         }
     614             : 
     615           4 :         memcpy(&l, s->data + s->getp, sizeof(uint32_t));
     616           4 :         s->getp += sizeof(uint32_t);
     617             : 
     618           4 :         return l;
     619             : }
     620             : 
     621           0 : bool stream_get_ipaddr(struct stream *s, struct ipaddr *ip)
     622             : {
     623           0 :         uint16_t ipa_len = 0;
     624             : 
     625           0 :         STREAM_VERIFY_SANE(s);
     626             : 
     627             :         /* Get address type. */
     628           0 :         if (STREAM_READABLE(s) < sizeof(uint16_t)) {
     629           0 :                 STREAM_BOUND_WARN2(s, "get ipaddr");
     630           0 :                 return false;
     631             :         }
     632           0 :         ip->ipa_type = stream_getw(s);
     633             : 
     634             :         /* Get address value. */
     635           0 :         switch (ip->ipa_type) {
     636           0 :         case IPADDR_V4:
     637           0 :                 ipa_len = IPV4_MAX_BYTELEN;
     638           0 :                 break;
     639           0 :         case IPADDR_V6:
     640           0 :                 ipa_len = IPV6_MAX_BYTELEN;
     641           0 :                 break;
     642           0 :         case IPADDR_NONE:
     643           0 :                 flog_err(EC_LIB_DEVELOPMENT,
     644             :                          "%s: unknown ip address-family: %u", __func__,
     645             :                          ip->ipa_type);
     646           0 :                 return false;
     647             :         }
     648           0 :         if (STREAM_READABLE(s) < ipa_len) {
     649           0 :                 STREAM_BOUND_WARN2(s, "get ipaddr");
     650           0 :                 return false;
     651             :         }
     652           0 :         memcpy(&ip->ip, s->data + s->getp, ipa_len);
     653           0 :         s->getp += ipa_len;
     654             : 
     655           0 :         return true;
     656             : }
     657             : 
     658           0 : float stream_getf(struct stream *s)
     659             : {
     660           0 :         union {
     661             :                 float r;
     662             :                 uint32_t d;
     663             :         } u;
     664           0 :         u.d = stream_getl(s);
     665           0 :         return u.r;
     666             : }
     667             : 
     668           0 : double stream_getd(struct stream *s)
     669             : {
     670           0 :         union {
     671             :                 double r;
     672             :                 uint64_t d;
     673             :         } u;
     674           0 :         u.d = stream_getq(s);
     675           0 :         return u.r;
     676             : }
     677             : 
     678             : /* Copy from source to stream.
     679             :  *
     680             :  * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap
     681             :  * around. This should be fixed once the stream updates are working.
     682             :  *
     683             :  * stream_write() is saner
     684             :  */
     685         250 : void stream_put(struct stream *s, const void *src, size_t size)
     686             : {
     687             : 
     688             :         /* XXX: CHECK_SIZE has strange semantics. It should be deprecated */
     689         250 :         CHECK_SIZE(s, size);
     690             : 
     691         250 :         STREAM_VERIFY_SANE(s);
     692             : 
     693         250 :         if (STREAM_WRITEABLE(s) < size) {
     694           0 :                 STREAM_BOUND_WARN(s, "put");
     695             :                 return;
     696             :         }
     697             : 
     698         250 :         if (src)
     699         184 :                 memcpy(s->data + s->endp, src, size);
     700             :         else
     701          66 :                 memset(s->data + s->endp, 0, size);
     702             : 
     703         250 :         s->endp += size;
     704             : }
     705             : 
     706             : /* Put character to the stream. */
     707        1763 : int stream_putc(struct stream *s, uint8_t c)
     708             : {
     709        1763 :         STREAM_VERIFY_SANE(s);
     710             : 
     711        1763 :         if (STREAM_WRITEABLE(s) < sizeof(uint8_t)) {
     712           0 :                 STREAM_BOUND_WARN(s, "put");
     713             :                 return 0;
     714             :         }
     715             : 
     716        1763 :         s->data[s->endp++] = c;
     717        1763 :         return sizeof(uint8_t);
     718             : }
     719             : 
     720             : /* Put word to the stream. */
     721         770 : int stream_putw(struct stream *s, uint16_t w)
     722             : {
     723         770 :         STREAM_VERIFY_SANE(s);
     724             : 
     725         770 :         if (STREAM_WRITEABLE(s) < sizeof(uint16_t)) {
     726           0 :                 STREAM_BOUND_WARN(s, "put");
     727             :                 return 0;
     728             :         }
     729             : 
     730         770 :         s->data[s->endp++] = (uint8_t)(w >> 8);
     731         770 :         s->data[s->endp++] = (uint8_t)w;
     732             : 
     733         770 :         return 2;
     734             : }
     735             : 
     736             : /* Put long word to the stream. */
     737           4 : int stream_put3(struct stream *s, uint32_t l)
     738             : {
     739           4 :         STREAM_VERIFY_SANE(s);
     740             : 
     741           4 :         if (STREAM_WRITEABLE(s) < 3) {
     742           0 :                 STREAM_BOUND_WARN(s, "put");
     743             :                 return 0;
     744             :         }
     745             : 
     746           4 :         s->data[s->endp++] = (uint8_t)(l >> 16);
     747           4 :         s->data[s->endp++] = (uint8_t)(l >> 8);
     748           4 :         s->data[s->endp++] = (uint8_t)l;
     749             : 
     750           4 :         return 3;
     751             : }
     752             : 
     753             : /* Put long word to the stream. */
     754        1315 : int stream_putl(struct stream *s, uint32_t l)
     755             : {
     756        1315 :         STREAM_VERIFY_SANE(s);
     757             : 
     758        1315 :         if (STREAM_WRITEABLE(s) < sizeof(uint32_t)) {
     759           0 :                 STREAM_BOUND_WARN(s, "put");
     760             :                 return 0;
     761             :         }
     762             : 
     763        1315 :         s->data[s->endp++] = (uint8_t)(l >> 24);
     764        1315 :         s->data[s->endp++] = (uint8_t)(l >> 16);
     765        1315 :         s->data[s->endp++] = (uint8_t)(l >> 8);
     766        1315 :         s->data[s->endp++] = (uint8_t)l;
     767             : 
     768        1315 :         return 4;
     769             : }
     770             : 
     771             : /* Put quad word to the stream. */
     772          42 : int stream_putq(struct stream *s, uint64_t q)
     773             : {
     774          42 :         STREAM_VERIFY_SANE(s);
     775             : 
     776          42 :         if (STREAM_WRITEABLE(s) < sizeof(uint64_t)) {
     777           0 :                 STREAM_BOUND_WARN(s, "put quad");
     778             :                 return 0;
     779             :         }
     780             : 
     781          42 :         s->data[s->endp++] = (uint8_t)(q >> 56);
     782          42 :         s->data[s->endp++] = (uint8_t)(q >> 48);
     783          42 :         s->data[s->endp++] = (uint8_t)(q >> 40);
     784          42 :         s->data[s->endp++] = (uint8_t)(q >> 32);
     785          42 :         s->data[s->endp++] = (uint8_t)(q >> 24);
     786          42 :         s->data[s->endp++] = (uint8_t)(q >> 16);
     787          42 :         s->data[s->endp++] = (uint8_t)(q >> 8);
     788          42 :         s->data[s->endp++] = (uint8_t)q;
     789             : 
     790          42 :         return 8;
     791             : }
     792             : 
     793           0 : int stream_putf(struct stream *s, float f)
     794             : {
     795           0 :         union {
     796             :                 float i;
     797             :                 uint32_t o;
     798             :         } u;
     799           0 :         u.i = f;
     800           0 :         return stream_putl(s, u.o);
     801             : }
     802             : 
     803           0 : int stream_putd(struct stream *s, double d)
     804             : {
     805           0 :         union {
     806             :                 double i;
     807             :                 uint64_t o;
     808             :         } u;
     809           0 :         u.i = d;
     810           0 :         return stream_putq(s, u.o);
     811             : }
     812             : 
     813          32 : int stream_putc_at(struct stream *s, size_t putp, uint8_t c)
     814             : {
     815          32 :         STREAM_VERIFY_SANE(s);
     816             : 
     817          32 :         if (!PUT_AT_VALID(s, putp + sizeof(uint8_t))) {
     818           0 :                 STREAM_BOUND_WARN(s, "put");
     819             :                 return 0;
     820             :         }
     821             : 
     822          32 :         s->data[putp] = c;
     823             : 
     824          32 :         return 1;
     825             : }
     826             : 
     827         331 : int stream_putw_at(struct stream *s, size_t putp, uint16_t w)
     828             : {
     829         331 :         STREAM_VERIFY_SANE(s);
     830             : 
     831         331 :         if (!PUT_AT_VALID(s, putp + sizeof(uint16_t))) {
     832           0 :                 STREAM_BOUND_WARN(s, "put");
     833             :                 return 0;
     834             :         }
     835             : 
     836         331 :         s->data[putp] = (uint8_t)(w >> 8);
     837         331 :         s->data[putp + 1] = (uint8_t)w;
     838             : 
     839         331 :         return 2;
     840             : }
     841             : 
     842           0 : int stream_put3_at(struct stream *s, size_t putp, uint32_t l)
     843             : {
     844           0 :         STREAM_VERIFY_SANE(s);
     845             : 
     846           0 :         if (!PUT_AT_VALID(s, putp + 3)) {
     847           0 :                 STREAM_BOUND_WARN(s, "put");
     848             :                 return 0;
     849             :         }
     850           0 :         s->data[putp] = (uint8_t)(l >> 16);
     851           0 :         s->data[putp + 1] = (uint8_t)(l >> 8);
     852           0 :         s->data[putp + 2] = (uint8_t)l;
     853             : 
     854           0 :         return 3;
     855             : }
     856             : 
     857           0 : int stream_putl_at(struct stream *s, size_t putp, uint32_t l)
     858             : {
     859           0 :         STREAM_VERIFY_SANE(s);
     860             : 
     861           0 :         if (!PUT_AT_VALID(s, putp + sizeof(uint32_t))) {
     862           0 :                 STREAM_BOUND_WARN(s, "put");
     863             :                 return 0;
     864             :         }
     865           0 :         s->data[putp] = (uint8_t)(l >> 24);
     866           0 :         s->data[putp + 1] = (uint8_t)(l >> 16);
     867           0 :         s->data[putp + 2] = (uint8_t)(l >> 8);
     868           0 :         s->data[putp + 3] = (uint8_t)l;
     869             : 
     870           0 :         return 4;
     871             : }
     872             : 
     873           0 : int stream_putq_at(struct stream *s, size_t putp, uint64_t q)
     874             : {
     875           0 :         STREAM_VERIFY_SANE(s);
     876             : 
     877           0 :         if (!PUT_AT_VALID(s, putp + sizeof(uint64_t))) {
     878           0 :                 STREAM_BOUND_WARN(s, "put");
     879             :                 return 0;
     880             :         }
     881           0 :         s->data[putp] = (uint8_t)(q >> 56);
     882           0 :         s->data[putp + 1] = (uint8_t)(q >> 48);
     883           0 :         s->data[putp + 2] = (uint8_t)(q >> 40);
     884           0 :         s->data[putp + 3] = (uint8_t)(q >> 32);
     885           0 :         s->data[putp + 4] = (uint8_t)(q >> 24);
     886           0 :         s->data[putp + 5] = (uint8_t)(q >> 16);
     887           0 :         s->data[putp + 6] = (uint8_t)(q >> 8);
     888           0 :         s->data[putp + 7] = (uint8_t)q;
     889             : 
     890           0 :         return 8;
     891             : }
     892             : 
     893             : /* Put long word to the stream. */
     894           0 : int stream_put_ipv4(struct stream *s, uint32_t l)
     895             : {
     896           0 :         STREAM_VERIFY_SANE(s);
     897             : 
     898           0 :         if (STREAM_WRITEABLE(s) < sizeof(uint32_t)) {
     899           0 :                 STREAM_BOUND_WARN(s, "put");
     900             :                 return 0;
     901             :         }
     902           0 :         memcpy(s->data + s->endp, &l, sizeof(uint32_t));
     903           0 :         s->endp += sizeof(uint32_t);
     904             : 
     905           0 :         return sizeof(uint32_t);
     906             : }
     907             : 
     908             : /* Put long word to the stream. */
     909           4 : int stream_put_in_addr(struct stream *s, const struct in_addr *addr)
     910             : {
     911           4 :         STREAM_VERIFY_SANE(s);
     912             : 
     913           4 :         if (STREAM_WRITEABLE(s) < sizeof(uint32_t)) {
     914           0 :                 STREAM_BOUND_WARN(s, "put");
     915             :                 return 0;
     916             :         }
     917             : 
     918           4 :         memcpy(s->data + s->endp, addr, sizeof(uint32_t));
     919           4 :         s->endp += sizeof(uint32_t);
     920             : 
     921           4 :         return sizeof(uint32_t);
     922             : }
     923             : 
     924           0 : bool stream_put_ipaddr(struct stream *s, struct ipaddr *ip)
     925             : {
     926           0 :         stream_putw(s, ip->ipa_type);
     927             : 
     928           0 :         switch (ip->ipa_type) {
     929           0 :         case IPADDR_V4:
     930           0 :                 stream_put_in_addr(s, &ip->ipaddr_v4);
     931           0 :                 break;
     932           0 :         case IPADDR_V6:
     933           0 :                 stream_write(s, (uint8_t *)&ip->ipaddr_v6, 16);
     934           0 :                 break;
     935           0 :         case IPADDR_NONE:
     936           0 :                 flog_err(EC_LIB_DEVELOPMENT,
     937             :                          "%s: unknown ip address-family: %u", __func__,
     938             :                          ip->ipa_type);
     939           0 :                 return false;
     940             :         }
     941             : 
     942             :         return true;
     943             : }
     944             : 
     945             : /* Put in_addr at location in the stream. */
     946           0 : int stream_put_in_addr_at(struct stream *s, size_t putp,
     947             :                           const struct in_addr *addr)
     948             : {
     949           0 :         STREAM_VERIFY_SANE(s);
     950             : 
     951           0 :         if (!PUT_AT_VALID(s, putp + 4)) {
     952           0 :                 STREAM_BOUND_WARN(s, "put");
     953             :                 return 0;
     954             :         }
     955             : 
     956           0 :         memcpy(&s->data[putp], addr, 4);
     957           0 :         return 4;
     958             : }
     959             : 
     960             : /* Put in6_addr at location in the stream. */
     961          20 : int stream_put_in6_addr_at(struct stream *s, size_t putp,
     962             :                            const struct in6_addr *addr)
     963             : {
     964          20 :         STREAM_VERIFY_SANE(s);
     965             : 
     966          20 :         if (!PUT_AT_VALID(s, putp + 16)) {
     967           0 :                 STREAM_BOUND_WARN(s, "put");
     968             :                 return 0;
     969             :         }
     970             : 
     971          20 :         memcpy(&s->data[putp], addr, 16);
     972          20 :         return 16;
     973             : }
     974             : 
     975             : /* Put prefix by nlri type format. */
     976           6 : int stream_put_prefix_addpath(struct stream *s, const struct prefix *p,
     977             :                               bool addpath_capable, uint32_t addpath_tx_id)
     978             : {
     979           6 :         size_t psize;
     980           6 :         size_t psize_with_addpath;
     981             : 
     982           6 :         STREAM_VERIFY_SANE(s);
     983             : 
     984           6 :         psize = PSIZE(p->prefixlen);
     985             : 
     986           6 :         if (addpath_capable)
     987           0 :                 psize_with_addpath = psize + 4;
     988             :         else
     989             :                 psize_with_addpath = psize;
     990             : 
     991           6 :         if (STREAM_WRITEABLE(s) < (psize_with_addpath + sizeof(uint8_t))) {
     992           0 :                 STREAM_BOUND_WARN(s, "put");
     993             :                 return 0;
     994             :         }
     995             : 
     996           6 :         if (addpath_capable) {
     997           0 :                 s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 24);
     998           0 :                 s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 16);
     999           0 :                 s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 8);
    1000           0 :                 s->data[s->endp++] = (uint8_t)addpath_tx_id;
    1001             :         }
    1002             : 
    1003           6 :         s->data[s->endp++] = p->prefixlen;
    1004           6 :         memcpy(s->data + s->endp, &p->u.prefix, psize);
    1005           6 :         s->endp += psize;
    1006             : 
    1007           6 :         return psize;
    1008             : }
    1009             : 
    1010           0 : int stream_put_prefix(struct stream *s, const struct prefix *p)
    1011             : {
    1012           0 :         return stream_put_prefix_addpath(s, p, 0, 0);
    1013             : }
    1014             : 
    1015             : /* Put NLRI with label */
    1016           0 : int stream_put_labeled_prefix(struct stream *s, const struct prefix *p,
    1017             :                               mpls_label_t *label, bool addpath_capable,
    1018             :                               uint32_t addpath_tx_id)
    1019             : {
    1020           0 :         size_t psize;
    1021           0 :         size_t psize_with_addpath;
    1022           0 :         uint8_t *label_pnt = (uint8_t *)label;
    1023             : 
    1024           0 :         STREAM_VERIFY_SANE(s);
    1025             : 
    1026           0 :         psize = PSIZE(p->prefixlen);
    1027           0 :         psize_with_addpath = psize + (addpath_capable ? 4 : 0);
    1028             : 
    1029           0 :         if (STREAM_WRITEABLE(s) < (psize_with_addpath + 3)) {
    1030           0 :                 STREAM_BOUND_WARN(s, "put");
    1031             :                 return 0;
    1032             :         }
    1033             : 
    1034           0 :         if (addpath_capable) {
    1035           0 :                 s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 24);
    1036           0 :                 s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 16);
    1037           0 :                 s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 8);
    1038           0 :                 s->data[s->endp++] = (uint8_t)addpath_tx_id;
    1039             :         }
    1040             : 
    1041           0 :         stream_putc(s, (p->prefixlen + 24));
    1042           0 :         stream_putc(s, label_pnt[0]);
    1043           0 :         stream_putc(s, label_pnt[1]);
    1044           0 :         stream_putc(s, label_pnt[2]);
    1045           0 :         memcpy(s->data + s->endp, &p->u.prefix, psize);
    1046           0 :         s->endp += psize;
    1047             : 
    1048           0 :         return (psize + 3);
    1049             : }
    1050             : 
    1051             : /* Read size from fd. */
    1052           4 : int stream_read(struct stream *s, int fd, size_t size)
    1053             : {
    1054           4 :         int nbytes;
    1055             : 
    1056           4 :         STREAM_VERIFY_SANE(s);
    1057             : 
    1058           4 :         if (STREAM_WRITEABLE(s) < size) {
    1059           0 :                 STREAM_BOUND_WARN(s, "put");
    1060             :                 return 0;
    1061             :         }
    1062             : 
    1063           4 :         nbytes = readn(fd, s->data + s->endp, size);
    1064             : 
    1065           4 :         if (nbytes > 0)
    1066           4 :                 s->endp += nbytes;
    1067             : 
    1068           4 :         return nbytes;
    1069             : }
    1070             : 
    1071         624 : ssize_t stream_read_try(struct stream *s, int fd, size_t size)
    1072             : {
    1073         624 :         ssize_t nbytes;
    1074             : 
    1075         624 :         STREAM_VERIFY_SANE(s);
    1076             : 
    1077         624 :         if (STREAM_WRITEABLE(s) < size) {
    1078           0 :                 STREAM_BOUND_WARN(s, "put");
    1079             :                 /* Fatal (not transient) error, since retrying will not help
    1080             :                    (stream is too small to contain the desired data). */
    1081             :                 return -1;
    1082             :         }
    1083             : 
    1084         624 :         nbytes = read(fd, s->data + s->endp, size);
    1085         624 :         if (nbytes >= 0) {
    1086         592 :                 s->endp += nbytes;
    1087         592 :                 return nbytes;
    1088             :         }
    1089             :         /* Error: was it transient (return -2) or fatal (return -1)? */
    1090          32 :         if (ERRNO_IO_RETRY(errno))
    1091             :                 return -2;
    1092           0 :         flog_err(EC_LIB_SOCKET, "%s: read failed on fd %d: %s", __func__, fd,
    1093             :                  safe_strerror(errno));
    1094           0 :         return -1;
    1095             : }
    1096             : 
    1097             : /* Read up to size bytes into the stream from the fd, using recvmsgfrom
    1098             :  * whose arguments match the remaining arguments to this function
    1099             :  */
    1100           0 : ssize_t stream_recvfrom(struct stream *s, int fd, size_t size, int flags,
    1101             :                         struct sockaddr *from, socklen_t *fromlen)
    1102             : {
    1103           0 :         ssize_t nbytes;
    1104             : 
    1105           0 :         STREAM_VERIFY_SANE(s);
    1106             : 
    1107           0 :         if (STREAM_WRITEABLE(s) < size) {
    1108           0 :                 STREAM_BOUND_WARN(s, "put");
    1109             :                 /* Fatal (not transient) error, since retrying will not help
    1110             :                    (stream is too small to contain the desired data). */
    1111             :                 return -1;
    1112             :         }
    1113             : 
    1114           0 :         nbytes = recvfrom(fd, s->data + s->endp, size, flags, from, fromlen);
    1115           0 :         if (nbytes >= 0) {
    1116           0 :                 s->endp += nbytes;
    1117           0 :                 return nbytes;
    1118             :         }
    1119             :         /* Error: was it transient (return -2) or fatal (return -1)? */
    1120           0 :         if (ERRNO_IO_RETRY(errno))
    1121             :                 return -2;
    1122           0 :         flog_err(EC_LIB_SOCKET, "%s: read failed on fd %d: %s", __func__, fd,
    1123             :                  safe_strerror(errno));
    1124           0 :         return -1;
    1125             : }
    1126             : 
    1127             : /* Read up to smaller of size or SIZE_REMAIN() bytes to the stream, starting
    1128             :  * from endp.
    1129             :  * First iovec will be used to receive the data.
    1130             :  * Stream need not be empty.
    1131             :  */
    1132           0 : ssize_t stream_recvmsg(struct stream *s, int fd, struct msghdr *msgh, int flags,
    1133             :                        size_t size)
    1134             : {
    1135           0 :         int nbytes;
    1136           0 :         struct iovec *iov;
    1137             : 
    1138           0 :         STREAM_VERIFY_SANE(s);
    1139           0 :         assert(msgh->msg_iovlen > 0);
    1140             : 
    1141           0 :         if (STREAM_WRITEABLE(s) < size) {
    1142           0 :                 STREAM_BOUND_WARN(s, "put");
    1143             :                 /* This is a logic error in the calling code: the stream is too
    1144             :                    small
    1145             :                    to hold the desired data! */
    1146             :                 return -1;
    1147             :         }
    1148             : 
    1149           0 :         iov = &(msgh->msg_iov[0]);
    1150           0 :         iov->iov_base = (s->data + s->endp);
    1151           0 :         iov->iov_len = size;
    1152             : 
    1153           0 :         nbytes = recvmsg(fd, msgh, flags);
    1154             : 
    1155           0 :         if (nbytes > 0)
    1156           0 :                 s->endp += nbytes;
    1157             : 
    1158           0 :         return nbytes;
    1159             : }
    1160             : 
    1161             : /* Write data to buffer. */
    1162          15 : size_t stream_write(struct stream *s, const void *ptr, size_t size)
    1163             : {
    1164             : 
    1165          15 :         CHECK_SIZE(s, size);
    1166             : 
    1167          15 :         STREAM_VERIFY_SANE(s);
    1168             : 
    1169          15 :         if (STREAM_WRITEABLE(s) < size) {
    1170           0 :                 STREAM_BOUND_WARN(s, "put");
    1171             :                 return 0;
    1172             :         }
    1173             : 
    1174          15 :         memcpy(s->data + s->endp, ptr, size);
    1175          15 :         s->endp += size;
    1176             : 
    1177          15 :         return size;
    1178             : }
    1179             : 
    1180             : /* Return current read pointer.
    1181             :  * DEPRECATED!
    1182             :  * Use stream_get_pnt_to if you must, but decoding streams properly
    1183             :  * is preferred
    1184             :  */
    1185         372 : uint8_t *stream_pnt(struct stream *s)
    1186             : {
    1187         372 :         STREAM_VERIFY_SANE(s);
    1188         372 :         return s->data + s->getp;
    1189             : }
    1190             : 
    1191             : /* Check does this stream empty? */
    1192          77 : int stream_empty(struct stream *s)
    1193             : {
    1194          77 :         STREAM_VERIFY_SANE(s);
    1195             : 
    1196          77 :         return (s->endp == 0);
    1197             : }
    1198             : 
    1199             : /* Reset stream. */
    1200         535 : void stream_reset(struct stream *s)
    1201             : {
    1202         535 :         STREAM_VERIFY_SANE(s);
    1203             : 
    1204         535 :         s->getp = s->endp = 0;
    1205         535 : }
    1206             : 
    1207             : /* Write stream contens to the file discriptor. */
    1208           0 : int stream_flush(struct stream *s, int fd)
    1209             : {
    1210           0 :         int nbytes;
    1211             : 
    1212           0 :         STREAM_VERIFY_SANE(s);
    1213             : 
    1214           0 :         nbytes = write(fd, s->data + s->getp, s->endp - s->getp);
    1215             : 
    1216           0 :         return nbytes;
    1217             : }
    1218             : 
    1219           0 : void stream_hexdump(const struct stream *s)
    1220             : {
    1221           0 :         zlog_hexdump(s->data, s->endp);
    1222           0 : }
    1223             : 
    1224             : /* Stream first in first out queue. */
    1225             : 
    1226         140 : struct stream_fifo *stream_fifo_new(void)
    1227             : {
    1228         140 :         struct stream_fifo *new;
    1229             : 
    1230         140 :         new = XMALLOC(MTYPE_STREAM_FIFO, sizeof(struct stream_fifo));
    1231         140 :         stream_fifo_init(new);
    1232         140 :         return new;
    1233             : }
    1234             : 
    1235         174 : void stream_fifo_init(struct stream_fifo *fifo)
    1236             : {
    1237         174 :         memset(fifo, 0, sizeof(struct stream_fifo));
    1238         174 :         pthread_mutex_init(&fifo->mtx, NULL);
    1239         174 : }
    1240             : 
    1241             : /* Add new stream to fifo. */
    1242         778 : void stream_fifo_push(struct stream_fifo *fifo, struct stream *s)
    1243             : {
    1244             : #if defined DEV_BUILD
    1245             :         size_t max, curmax;
    1246             : #endif
    1247             : 
    1248         778 :         if (fifo->tail)
    1249         571 :                 fifo->tail->next = s;
    1250             :         else
    1251         207 :                 fifo->head = s;
    1252             : 
    1253         778 :         fifo->tail = s;
    1254         778 :         fifo->tail->next = NULL;
    1255             : #if !defined DEV_BUILD
    1256         778 :         atomic_fetch_add_explicit(&fifo->count, 1, memory_order_release);
    1257             : #else
    1258             :         max = atomic_fetch_add_explicit(&fifo->count, 1, memory_order_release);
    1259             :         curmax = atomic_load_explicit(&fifo->max_count, memory_order_relaxed);
    1260             :         if (max > curmax)
    1261             :                 atomic_store_explicit(&fifo->max_count, max,
    1262             :                                       memory_order_relaxed);
    1263             : #endif
    1264         778 : }
    1265             : 
    1266           0 : void stream_fifo_push_safe(struct stream_fifo *fifo, struct stream *s)
    1267             : {
    1268           0 :         frr_with_mutex (&fifo->mtx) {
    1269           0 :                 stream_fifo_push(fifo, s);
    1270             :         }
    1271           0 : }
    1272             : 
    1273             : /* Delete first stream from fifo. */
    1274         791 : struct stream *stream_fifo_pop(struct stream_fifo *fifo)
    1275             : {
    1276         791 :         struct stream *s;
    1277             : 
    1278         791 :         s = fifo->head;
    1279             : 
    1280         791 :         if (s) {
    1281         774 :                 fifo->head = s->next;
    1282             : 
    1283         774 :                 if (fifo->head == NULL)
    1284         203 :                         fifo->tail = NULL;
    1285             : 
    1286         774 :                 atomic_fetch_sub_explicit(&fifo->count, 1,
    1287             :                                           memory_order_release);
    1288             : 
    1289             :                 /* ensure stream is scrubbed of references to this fifo */
    1290         774 :                 s->next = NULL;
    1291             :         }
    1292             : 
    1293         791 :         return s;
    1294             : }
    1295             : 
    1296           0 : struct stream *stream_fifo_pop_safe(struct stream_fifo *fifo)
    1297             : {
    1298           0 :         struct stream *ret;
    1299             : 
    1300           0 :         frr_with_mutex (&fifo->mtx) {
    1301           0 :                 ret = stream_fifo_pop(fifo);
    1302             :         }
    1303             : 
    1304           0 :         return ret;
    1305             : }
    1306             : 
    1307         866 : struct stream *stream_fifo_head(struct stream_fifo *fifo)
    1308             : {
    1309         866 :         return fifo->head;
    1310             : }
    1311             : 
    1312           0 : struct stream *stream_fifo_head_safe(struct stream_fifo *fifo)
    1313             : {
    1314           0 :         struct stream *ret;
    1315             : 
    1316           0 :         frr_with_mutex (&fifo->mtx) {
    1317           0 :                 ret = stream_fifo_head(fifo);
    1318             :         }
    1319             : 
    1320           0 :         return ret;
    1321             : }
    1322             : 
    1323         202 : void stream_fifo_clean(struct stream_fifo *fifo)
    1324             : {
    1325         202 :         struct stream *s;
    1326         202 :         struct stream *next;
    1327             : 
    1328         206 :         for (s = fifo->head; s; s = next) {
    1329           4 :                 next = s->next;
    1330           4 :                 stream_free(s);
    1331             :         }
    1332         202 :         fifo->head = fifo->tail = NULL;
    1333         202 :         atomic_store_explicit(&fifo->count, 0, memory_order_release);
    1334         202 : }
    1335             : 
    1336           0 : void stream_fifo_clean_safe(struct stream_fifo *fifo)
    1337             : {
    1338           0 :         frr_with_mutex (&fifo->mtx) {
    1339           0 :                 stream_fifo_clean(fifo);
    1340             :         }
    1341           0 : }
    1342             : 
    1343          22 : size_t stream_fifo_count_safe(struct stream_fifo *fifo)
    1344             : {
    1345          22 :         return atomic_load_explicit(&fifo->count, memory_order_acquire);
    1346             : }
    1347             : 
    1348         166 : void stream_fifo_deinit(struct stream_fifo *fifo)
    1349             : {
    1350         166 :         stream_fifo_clean(fifo);
    1351         166 :         pthread_mutex_destroy(&fifo->mtx);
    1352         166 : }
    1353             : 
    1354         132 : void stream_fifo_free(struct stream_fifo *fifo)
    1355             : {
    1356         132 :         stream_fifo_deinit(fifo);
    1357         132 :         XFREE(MTYPE_STREAM_FIFO, fifo);
    1358         132 : }
    1359             : 
    1360           0 : void stream_pulldown(struct stream *s)
    1361             : {
    1362           0 :         size_t rlen = STREAM_READABLE(s);
    1363             : 
    1364             :         /* No more data, so just move the pointers. */
    1365           0 :         if (rlen == 0) {
    1366           0 :                 stream_reset(s);
    1367           0 :                 return;
    1368             :         }
    1369             : 
    1370             :         /* Move the available data to the beginning. */
    1371           0 :         memmove(s->data, &s->data[s->getp], rlen);
    1372           0 :         s->getp = 0;
    1373           0 :         s->endp = rlen;
    1374             : }

Generated by: LCOV version v1.16-topotato