back to topotato report
topotato coverage report
Current view: top level - lib - stream.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 382 624 61.2 %
Date: 2023-02-24 14:41:08 Functions: 62 87 71.3 %

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

Generated by: LCOV version v1.16-topotato