Annotation of embedaddon/quagga/lib/stream.c, revision 1.1.1.1

1.1       misho       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
                     18:  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
                     19:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
                     20:  * 02111-1307, USA.  
                     21:  */
                     22: 
                     23: #include <stddef.h>
                     24: #include <zebra.h>
                     25: 
                     26: #include "stream.h"
                     27: #include "memory.h"
                     28: #include "network.h"
                     29: #include "prefix.h"
                     30: #include "log.h"
                     31: 
                     32: /* Tests whether a position is valid */ 
                     33: #define GETP_VALID(S,G) \
                     34:   ((G) <= (S)->endp)
                     35: #define PUT_AT_VALID(S,G) GETP_VALID(S,G)
                     36: #define ENDP_VALID(S,E) \
                     37:   ((E) <= (S)->size)
                     38: 
                     39: /* asserting sanity checks. Following must be true before
                     40:  * stream functions are called:
                     41:  *
                     42:  * Following must always be true of stream elements
                     43:  * before and after calls to stream functions:
                     44:  *
                     45:  * getp <= endp <= size
                     46:  *
                     47:  * Note that after a stream function is called following may be true:
                     48:  * if (getp == endp) then stream is no longer readable
                     49:  * if (endp == size) then stream is no longer writeable
                     50:  *
                     51:  * It is valid to put to anywhere within the size of the stream, but only
                     52:  * using stream_put..._at() functions.
                     53:  */
                     54: #define STREAM_WARN_OFFSETS(S) \
                     55:   zlog_warn ("&(struct stream): %p, size: %lu, endp: %lu, getp: %lu\n", \
                     56:              (S), \
                     57:              (unsigned long) (S)->size, \
                     58:              (unsigned long) (S)->getp, \
                     59:              (unsigned long) (S)->endp)\
                     60: 
                     61: #define STREAM_VERIFY_SANE(S) \
                     62:   do { \
                     63:     if ( !(GETP_VALID(S, (S)->getp)) && ENDP_VALID(S, (S)->endp) ) \
                     64:       STREAM_WARN_OFFSETS(S); \
                     65:     assert ( GETP_VALID(S, (S)->getp) ); \
                     66:     assert ( ENDP_VALID(S, (S)->endp) ); \
                     67:   } while (0)
                     68: 
                     69: #define STREAM_BOUND_WARN(S, WHAT) \
                     70:   do { \
                     71:     zlog_warn ("%s: Attempt to %s out of bounds", __func__, (WHAT)); \
                     72:     STREAM_WARN_OFFSETS(S); \
                     73:     assert (0); \
                     74:   } while (0)
                     75: 
                     76: /* XXX: Deprecated macro: do not use */
                     77: #define CHECK_SIZE(S, Z) \
                     78:   do { \
                     79:     if (((S)->endp + (Z)) > (S)->size) \
                     80:       { \
                     81:         zlog_warn ("CHECK_SIZE: truncating requested size %lu\n", \
                     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: struct stream *
                     90: stream_new (size_t size)
                     91: {
                     92:   struct stream *s;
                     93: 
                     94:   assert (size > 0);
                     95:   
                     96:   if (size == 0)
                     97:     {
                     98:       zlog_warn ("stream_new(): called with 0 size!");
                     99:       return NULL;
                    100:     }
                    101:   
                    102:   s = XCALLOC (MTYPE_STREAM, sizeof (struct stream));
                    103: 
                    104:   if (s == NULL)
                    105:     return s;
                    106:   
                    107:   if ( (s->data = XMALLOC (MTYPE_STREAM_DATA, size)) == NULL)
                    108:     {
                    109:       XFREE (MTYPE_STREAM, s);
                    110:       return NULL;
                    111:     }
                    112:   
                    113:   s->size = size;
                    114:   return s;
                    115: }
                    116: 
                    117: /* Free it now. */
                    118: void
                    119: stream_free (struct stream *s)
                    120: {
                    121:   if (!s)
                    122:     return;
                    123:   
                    124:   XFREE (MTYPE_STREAM_DATA, s->data);
                    125:   XFREE (MTYPE_STREAM, s);
                    126: }
                    127: 
                    128: struct stream *
                    129: stream_copy (struct stream *new, struct stream *src)
                    130: {
                    131:   STREAM_VERIFY_SANE (src);
                    132:   
                    133:   assert (new != NULL);
                    134:   assert (STREAM_SIZE(new) >= src->endp);
                    135: 
                    136:   new->endp = src->endp;
                    137:   new->getp = src->getp;
                    138:   
                    139:   memcpy (new->data, src->data, src->endp);
                    140:   
                    141:   return new;
                    142: }
                    143: 
                    144: struct stream *
                    145: stream_dup (struct stream *s)
                    146: {
                    147:   struct stream *new;
                    148: 
                    149:   STREAM_VERIFY_SANE (s);
                    150: 
                    151:   if ( (new = stream_new (s->endp)) == NULL)
                    152:     return NULL;
                    153: 
                    154:   return (stream_copy (new, s));
                    155: }
                    156: 
                    157: size_t
                    158: stream_resize (struct stream *s, size_t newsize)
                    159: {
                    160:   u_char *newdata;
                    161:   STREAM_VERIFY_SANE (s);
                    162:   
                    163:   newdata = XREALLOC (MTYPE_STREAM_DATA, s->data, newsize);
                    164:   
                    165:   if (newdata == NULL)
                    166:     return s->size;
                    167:   
                    168:   s->data = newdata;
                    169:   s->size = newsize;
                    170:   
                    171:   if (s->endp > s->size)
                    172:     s->endp = s->size;
                    173:   if (s->getp > s->endp)
                    174:     s->getp = s->endp;
                    175:   
                    176:   STREAM_VERIFY_SANE (s);
                    177:   
                    178:   return s->size;
                    179: }
                    180: 
                    181: size_t
                    182: stream_get_getp (struct stream *s)
                    183: {
                    184:   STREAM_VERIFY_SANE(s);
                    185:   return s->getp;
                    186: }
                    187: 
                    188: size_t
                    189: stream_get_endp (struct stream *s)
                    190: {
                    191:   STREAM_VERIFY_SANE(s);
                    192:   return s->endp;
                    193: }
                    194: 
                    195: size_t
                    196: stream_get_size (struct stream *s)
                    197: {
                    198:   STREAM_VERIFY_SANE(s);
                    199:   return s->size;
                    200: }
                    201: 
                    202: /* Stream structre' stream pointer related functions.  */
                    203: void
                    204: stream_set_getp (struct stream *s, size_t pos)
                    205: {
                    206:   STREAM_VERIFY_SANE(s);
                    207:   
                    208:   if (!GETP_VALID (s, pos))
                    209:     {
                    210:       STREAM_BOUND_WARN (s, "set getp");
                    211:       pos = s->endp;
                    212:     }
                    213: 
                    214:   s->getp = pos;
                    215: }
                    216: 
                    217: /* Forward pointer. */
                    218: void
                    219: stream_forward_getp (struct stream *s, size_t size)
                    220: {
                    221:   STREAM_VERIFY_SANE(s);
                    222:   
                    223:   if (!GETP_VALID (s, s->getp + size))
                    224:     {
                    225:       STREAM_BOUND_WARN (s, "seek getp");
                    226:       return;
                    227:     }
                    228:   
                    229:   s->getp += size;
                    230: }
                    231: 
                    232: void
                    233: stream_forward_endp (struct stream *s, size_t size)
                    234: {
                    235:   STREAM_VERIFY_SANE(s);
                    236:   
                    237:   if (!ENDP_VALID (s, s->endp + size))
                    238:     {
                    239:       STREAM_BOUND_WARN (s, "seek endp");
                    240:       return;
                    241:     }
                    242:   
                    243:   s->endp += size;
                    244: }
                    245: 
                    246: /* Copy from stream to destination. */
                    247: void
                    248: stream_get (void *dst, struct stream *s, size_t size)
                    249: {
                    250:   STREAM_VERIFY_SANE(s);
                    251:   
                    252:   if (STREAM_READABLE(s) < size)
                    253:     {
                    254:       STREAM_BOUND_WARN (s, "get");
                    255:       return;
                    256:     }
                    257:   
                    258:   memcpy (dst, s->data + s->getp, size);
                    259:   s->getp += size;
                    260: }
                    261: 
                    262: /* Get next character from the stream. */
                    263: u_char
                    264: stream_getc (struct stream *s)
                    265: {
                    266:   u_char c;
                    267:   
                    268:   STREAM_VERIFY_SANE (s);
                    269: 
                    270:   if (STREAM_READABLE(s) < sizeof (u_char))
                    271:     {
                    272:       STREAM_BOUND_WARN (s, "get char");
                    273:       return 0;
                    274:     }
                    275:   c = s->data[s->getp++];
                    276:   
                    277:   return c;
                    278: }
                    279: 
                    280: /* Get next character from the stream. */
                    281: u_char
                    282: stream_getc_from (struct stream *s, size_t from)
                    283: {
                    284:   u_char c;
                    285: 
                    286:   STREAM_VERIFY_SANE(s);
                    287:   
                    288:   if (!GETP_VALID (s, from + sizeof (u_char)))
                    289:     {
                    290:       STREAM_BOUND_WARN (s, "get char");
                    291:       return 0;
                    292:     }
                    293:   
                    294:   c = s->data[from];
                    295:   
                    296:   return c;
                    297: }
                    298: 
                    299: /* Get next word from the stream. */
                    300: u_int16_t
                    301: stream_getw (struct stream *s)
                    302: {
                    303:   u_int16_t w;
                    304: 
                    305:   STREAM_VERIFY_SANE (s);
                    306: 
                    307:   if (STREAM_READABLE (s) < sizeof (u_int16_t))
                    308:     {
                    309:       STREAM_BOUND_WARN (s, "get ");
                    310:       return 0;
                    311:     }
                    312:   
                    313:   w = s->data[s->getp++] << 8;
                    314:   w |= s->data[s->getp++];
                    315:   
                    316:   return w;
                    317: }
                    318: 
                    319: /* Get next word from the stream. */
                    320: u_int16_t
                    321: stream_getw_from (struct stream *s, size_t from)
                    322: {
                    323:   u_int16_t w;
                    324: 
                    325:   STREAM_VERIFY_SANE(s);
                    326:   
                    327:   if (!GETP_VALID (s, from + sizeof (u_int16_t)))
                    328:     {
                    329:       STREAM_BOUND_WARN (s, "get ");
                    330:       return 0;
                    331:     }
                    332:   
                    333:   w = s->data[from++] << 8;
                    334:   w |= s->data[from];
                    335:   
                    336:   return w;
                    337: }
                    338: 
                    339: /* Get next long word from the stream. */
                    340: u_int32_t
                    341: stream_getl_from (struct stream *s, size_t from)
                    342: {
                    343:   u_int32_t l;
                    344: 
                    345:   STREAM_VERIFY_SANE(s);
                    346:   
                    347:   if (!GETP_VALID (s, from + sizeof (u_int32_t)))
                    348:     {
                    349:       STREAM_BOUND_WARN (s, "get long");
                    350:       return 0;
                    351:     }
                    352:   
                    353:   l  = s->data[from++] << 24;
                    354:   l |= s->data[from++] << 16;
                    355:   l |= s->data[from++] << 8;
                    356:   l |= s->data[from];
                    357:   
                    358:   return l;
                    359: }
                    360: 
                    361: u_int32_t
                    362: stream_getl (struct stream *s)
                    363: {
                    364:   u_int32_t l;
                    365: 
                    366:   STREAM_VERIFY_SANE(s);
                    367:   
                    368:   if (STREAM_READABLE (s) < sizeof (u_int32_t))
                    369:     {
                    370:       STREAM_BOUND_WARN (s, "get long");
                    371:       return 0;
                    372:     }
                    373:   
                    374:   l  = s->data[s->getp++] << 24;
                    375:   l |= s->data[s->getp++] << 16;
                    376:   l |= s->data[s->getp++] << 8;
                    377:   l |= s->data[s->getp++];
                    378:   
                    379:   return l;
                    380: }
                    381: 
                    382: /* Get next quad word from the stream. */
                    383: uint64_t
                    384: stream_getq_from (struct stream *s, size_t from)
                    385: {
                    386:   uint64_t q;
                    387: 
                    388:   STREAM_VERIFY_SANE(s);
                    389:   
                    390:   if (!GETP_VALID (s, from + sizeof (uint64_t)))
                    391:     {
                    392:       STREAM_BOUND_WARN (s, "get quad");
                    393:       return 0;
                    394:     }
                    395:   
                    396:   q  = ((uint64_t) s->data[from++]) << 56;
                    397:   q |= ((uint64_t) s->data[from++]) << 48;
                    398:   q |= ((uint64_t) s->data[from++]) << 40;
                    399:   q |= ((uint64_t) s->data[from++]) << 32;  
                    400:   q |= ((uint64_t) s->data[from++]) << 24;
                    401:   q |= ((uint64_t) s->data[from++]) << 16;
                    402:   q |= ((uint64_t) s->data[from++]) << 8;
                    403:   q |= ((uint64_t) s->data[from++]);
                    404:   
                    405:   return q;
                    406: }
                    407: 
                    408: uint64_t
                    409: stream_getq (struct stream *s)
                    410: {
                    411:   uint64_t q;
                    412: 
                    413:   STREAM_VERIFY_SANE(s);
                    414:   
                    415:   if (STREAM_READABLE (s) < sizeof (uint64_t))
                    416:     {
                    417:       STREAM_BOUND_WARN (s, "get quad");
                    418:       return 0;
                    419:     }
                    420:   
                    421:   q  = ((uint64_t) s->data[s->getp++]) << 56;
                    422:   q |= ((uint64_t) s->data[s->getp++]) << 48;
                    423:   q |= ((uint64_t) s->data[s->getp++]) << 40;
                    424:   q |= ((uint64_t) s->data[s->getp++]) << 32;  
                    425:   q |= ((uint64_t) s->data[s->getp++]) << 24;
                    426:   q |= ((uint64_t) s->data[s->getp++]) << 16;
                    427:   q |= ((uint64_t) s->data[s->getp++]) << 8;
                    428:   q |= ((uint64_t) s->data[s->getp++]);
                    429:   
                    430:   return q;
                    431: }
                    432: 
                    433: /* Get next long word from the stream. */
                    434: u_int32_t
                    435: stream_get_ipv4 (struct stream *s)
                    436: {
                    437:   u_int32_t l;
                    438: 
                    439:   STREAM_VERIFY_SANE(s);
                    440:   
                    441:   if (STREAM_READABLE (s) < sizeof(u_int32_t))
                    442:     {
                    443:       STREAM_BOUND_WARN (s, "get ipv4");
                    444:       return 0;
                    445:     }
                    446:   
                    447:   memcpy (&l, s->data + s->getp, sizeof(u_int32_t));
                    448:   s->getp += sizeof(u_int32_t);
                    449: 
                    450:   return l;
                    451: }
                    452: 
                    453: /* Copy to source to stream.
                    454:  *
                    455:  * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap
                    456:  * around. This should be fixed once the stream updates are working.
                    457:  *
                    458:  * stream_write() is saner
                    459:  */
                    460: void
                    461: stream_put (struct stream *s, const void *src, size_t size)
                    462: {
                    463: 
                    464:   /* XXX: CHECK_SIZE has strange semantics. It should be deprecated */
                    465:   CHECK_SIZE(s, size);
                    466:   
                    467:   STREAM_VERIFY_SANE(s);
                    468:   
                    469:   if (STREAM_WRITEABLE (s) < size)
                    470:     {
                    471:       STREAM_BOUND_WARN (s, "put");
                    472:       return;
                    473:     }
                    474:   
                    475:   if (src)
                    476:     memcpy (s->data + s->endp, src, size);
                    477:   else
                    478:     memset (s->data + s->endp, 0, size);
                    479: 
                    480:   s->endp += size;
                    481: }
                    482: 
                    483: /* Put character to the stream. */
                    484: int
                    485: stream_putc (struct stream *s, u_char c)
                    486: {
                    487:   STREAM_VERIFY_SANE(s);
                    488:   
                    489:   if (STREAM_WRITEABLE (s) < sizeof(u_char))
                    490:     {
                    491:       STREAM_BOUND_WARN (s, "put");
                    492:       return 0;
                    493:     }
                    494:   
                    495:   s->data[s->endp++] = c;
                    496:   return sizeof (u_char);
                    497: }
                    498: 
                    499: /* Put word to the stream. */
                    500: int
                    501: stream_putw (struct stream *s, u_int16_t w)
                    502: {
                    503:   STREAM_VERIFY_SANE (s);
                    504: 
                    505:   if (STREAM_WRITEABLE (s) < sizeof (u_int16_t))
                    506:     {
                    507:       STREAM_BOUND_WARN (s, "put");
                    508:       return 0;
                    509:     }
                    510:   
                    511:   s->data[s->endp++] = (u_char)(w >>  8);
                    512:   s->data[s->endp++] = (u_char) w;
                    513: 
                    514:   return 2;
                    515: }
                    516: 
                    517: /* Put long word to the stream. */
                    518: int
                    519: stream_putl (struct stream *s, u_int32_t l)
                    520: {
                    521:   STREAM_VERIFY_SANE (s);
                    522: 
                    523:   if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
                    524:     {
                    525:       STREAM_BOUND_WARN (s, "put");
                    526:       return 0;
                    527:     }
                    528:   
                    529:   s->data[s->endp++] = (u_char)(l >> 24);
                    530:   s->data[s->endp++] = (u_char)(l >> 16);
                    531:   s->data[s->endp++] = (u_char)(l >>  8);
                    532:   s->data[s->endp++] = (u_char)l;
                    533: 
                    534:   return 4;
                    535: }
                    536: 
                    537: /* Put quad word to the stream. */
                    538: int
                    539: stream_putq (struct stream *s, uint64_t q)
                    540: {
                    541:   STREAM_VERIFY_SANE (s);
                    542: 
                    543:   if (STREAM_WRITEABLE (s) < sizeof (uint64_t))
                    544:     {
                    545:       STREAM_BOUND_WARN (s, "put quad");
                    546:       return 0;
                    547:     }
                    548:   
                    549:   s->data[s->endp++] = (u_char)(q >> 56);
                    550:   s->data[s->endp++] = (u_char)(q >> 48);
                    551:   s->data[s->endp++] = (u_char)(q >> 40);
                    552:   s->data[s->endp++] = (u_char)(q >> 32);
                    553:   s->data[s->endp++] = (u_char)(q >> 24);
                    554:   s->data[s->endp++] = (u_char)(q >> 16);
                    555:   s->data[s->endp++] = (u_char)(q >>  8);
                    556:   s->data[s->endp++] = (u_char)q;
                    557: 
                    558:   return 8;
                    559: }
                    560: 
                    561: int
                    562: stream_putc_at (struct stream *s, size_t putp, u_char c)
                    563: {
                    564:   STREAM_VERIFY_SANE(s);
                    565:   
                    566:   if (!PUT_AT_VALID (s, putp + sizeof (u_char)))
                    567:     {
                    568:       STREAM_BOUND_WARN (s, "put");
                    569:       return 0;
                    570:     }
                    571:   
                    572:   s->data[putp] = c;
                    573:   
                    574:   return 1;
                    575: }
                    576: 
                    577: int
                    578: stream_putw_at (struct stream *s, size_t putp, u_int16_t w)
                    579: {
                    580:   STREAM_VERIFY_SANE(s);
                    581:   
                    582:   if (!PUT_AT_VALID (s, putp + sizeof (u_int16_t)))
                    583:     {
                    584:       STREAM_BOUND_WARN (s, "put");
                    585:       return 0;
                    586:     }
                    587:   
                    588:   s->data[putp] = (u_char)(w >>  8);
                    589:   s->data[putp + 1] = (u_char) w;
                    590:   
                    591:   return 2;
                    592: }
                    593: 
                    594: int
                    595: stream_putl_at (struct stream *s, size_t putp, u_int32_t l)
                    596: {
                    597:   STREAM_VERIFY_SANE(s);
                    598:   
                    599:   if (!PUT_AT_VALID (s, putp + sizeof (u_int32_t)))
                    600:     {
                    601:       STREAM_BOUND_WARN (s, "put");
                    602:       return 0;
                    603:     }
                    604:   s->data[putp] = (u_char)(l >> 24);
                    605:   s->data[putp + 1] = (u_char)(l >> 16);
                    606:   s->data[putp + 2] = (u_char)(l >>  8);
                    607:   s->data[putp + 3] = (u_char)l;
                    608:   
                    609:   return 4;
                    610: }
                    611: 
                    612: int
                    613: stream_putq_at (struct stream *s, size_t putp, uint64_t q)
                    614: {
                    615:   STREAM_VERIFY_SANE(s);
                    616:   
                    617:   if (!PUT_AT_VALID (s, putp + sizeof (uint64_t)))
                    618:     {
                    619:       STREAM_BOUND_WARN (s, "put");
                    620:       return 0;
                    621:     }
                    622:   s->data[putp] =     (u_char)(q >> 56);
                    623:   s->data[putp + 1] = (u_char)(q >> 48);
                    624:   s->data[putp + 2] = (u_char)(q >> 40);
                    625:   s->data[putp + 3] = (u_char)(q >> 32);
                    626:   s->data[putp + 4] = (u_char)(q >> 24);
                    627:   s->data[putp + 5] = (u_char)(q >> 16);
                    628:   s->data[putp + 6] = (u_char)(q >>  8);
                    629:   s->data[putp + 7] = (u_char)q;
                    630:   
                    631:   return 8;
                    632: }
                    633: 
                    634: /* Put long word to the stream. */
                    635: int
                    636: stream_put_ipv4 (struct stream *s, u_int32_t l)
                    637: {
                    638:   STREAM_VERIFY_SANE(s);
                    639:   
                    640:   if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
                    641:     {
                    642:       STREAM_BOUND_WARN (s, "put");
                    643:       return 0;
                    644:     }
                    645:   memcpy (s->data + s->endp, &l, sizeof (u_int32_t));
                    646:   s->endp += sizeof (u_int32_t);
                    647: 
                    648:   return sizeof (u_int32_t);
                    649: }
                    650: 
                    651: /* Put long word to the stream. */
                    652: int
                    653: stream_put_in_addr (struct stream *s, struct in_addr *addr)
                    654: {
                    655:   STREAM_VERIFY_SANE(s);
                    656:   
                    657:   if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
                    658:     {
                    659:       STREAM_BOUND_WARN (s, "put");
                    660:       return 0;
                    661:     }
                    662: 
                    663:   memcpy (s->data + s->endp, addr, sizeof (u_int32_t));
                    664:   s->endp += sizeof (u_int32_t);
                    665: 
                    666:   return sizeof (u_int32_t);
                    667: }
                    668: 
                    669: /* Put prefix by nlri type format. */
                    670: int
                    671: stream_put_prefix (struct stream *s, struct prefix *p)
                    672: {
                    673:   size_t psize;
                    674:   
                    675:   STREAM_VERIFY_SANE(s);
                    676:   
                    677:   psize = PSIZE (p->prefixlen);
                    678:   
                    679:   if (STREAM_WRITEABLE (s) < psize)
                    680:     {
                    681:       STREAM_BOUND_WARN (s, "put");
                    682:       return 0;
                    683:     }
                    684:   
                    685:   stream_putc (s, p->prefixlen);
                    686:   memcpy (s->data + s->endp, &p->u.prefix, psize);
                    687:   s->endp += psize;
                    688:   
                    689:   return psize;
                    690: }
                    691: 
                    692: /* Read size from fd. */
                    693: int
                    694: stream_read (struct stream *s, int fd, size_t size)
                    695: {
                    696:   int nbytes;
                    697: 
                    698:   STREAM_VERIFY_SANE(s);
                    699:   
                    700:   if (STREAM_WRITEABLE (s) < size)
                    701:     {
                    702:       STREAM_BOUND_WARN (s, "put");
                    703:       return 0;
                    704:     }
                    705:   
                    706:   nbytes = readn (fd, s->data + s->endp, size);
                    707: 
                    708:   if (nbytes > 0)
                    709:     s->endp += nbytes;
                    710:   
                    711:   return nbytes;
                    712: }
                    713: 
                    714: /* Read size from fd. */
                    715: int
                    716: stream_read_unblock (struct stream *s, int fd, size_t size)
                    717: {
                    718:   int nbytes;
                    719:   int val;
                    720:   
                    721:   STREAM_VERIFY_SANE(s);
                    722:   
                    723:   if (STREAM_WRITEABLE (s) < size)
                    724:     {
                    725:       STREAM_BOUND_WARN (s, "put");
                    726:       return 0;
                    727:     }
                    728:   
                    729:   val = fcntl (fd, F_GETFL, 0);
                    730:   fcntl (fd, F_SETFL, val|O_NONBLOCK);
                    731:   nbytes = read (fd, s->data + s->endp, size);
                    732:   fcntl (fd, F_SETFL, val);
                    733: 
                    734:   if (nbytes > 0)
                    735:     s->endp += nbytes;
                    736:   
                    737:   return nbytes;
                    738: }
                    739: 
                    740: ssize_t
                    741: stream_read_try(struct stream *s, int fd, size_t size)
                    742: {
                    743:   ssize_t nbytes;
                    744: 
                    745:   STREAM_VERIFY_SANE(s);
                    746:   
                    747:   if (STREAM_WRITEABLE(s) < size)
                    748:     {
                    749:       STREAM_BOUND_WARN (s, "put");
                    750:       /* Fatal (not transient) error, since retrying will not help
                    751:          (stream is too small to contain the desired data). */
                    752:       return -1;
                    753:     }
                    754: 
                    755:   if ((nbytes = read(fd, s->data + s->endp, size)) >= 0)
                    756:     {
                    757:       s->endp += nbytes;
                    758:       return nbytes;
                    759:     }
                    760:   /* Error: was it transient (return -2) or fatal (return -1)? */
                    761:   if (ERRNO_IO_RETRY(errno))
                    762:     return -2;
                    763:   zlog_warn("%s: read failed on fd %d: %s", __func__, fd, safe_strerror(errno));
                    764:   return -1;
                    765: }
                    766: 
                    767: /* Read up to size bytes into the stream from the fd, using recvmsgfrom
                    768:  * whose arguments match the remaining arguments to this function
                    769:  */
                    770: ssize_t 
                    771: stream_recvfrom (struct stream *s, int fd, size_t size, int flags,
                    772:                  struct sockaddr *from, socklen_t *fromlen)                     
                    773: {
                    774:   ssize_t nbytes;
                    775: 
                    776:   STREAM_VERIFY_SANE(s);
                    777:   
                    778:   if (STREAM_WRITEABLE(s) < size)
                    779:     {
                    780:       STREAM_BOUND_WARN (s, "put");
                    781:       /* Fatal (not transient) error, since retrying will not help
                    782:          (stream is too small to contain the desired data). */
                    783:       return -1;
                    784:     }
                    785: 
                    786:   if ((nbytes = recvfrom (fd, s->data + s->endp, size, 
                    787:                           flags, from, fromlen)) >= 0)
                    788:     {
                    789:       s->endp += nbytes;
                    790:       return nbytes;
                    791:     }
                    792:   /* Error: was it transient (return -2) or fatal (return -1)? */
                    793:   if (ERRNO_IO_RETRY(errno))
                    794:     return -2;
                    795:   zlog_warn("%s: read failed on fd %d: %s", __func__, fd, safe_strerror(errno));
                    796:   return -1;
                    797: }
                    798: 
                    799: /* Read up to smaller of size or SIZE_REMAIN() bytes to the stream, starting
                    800:  * from endp.
                    801:  * First iovec will be used to receive the data.
                    802:  * Stream need not be empty.
                    803:  */
                    804: ssize_t
                    805: stream_recvmsg (struct stream *s, int fd, struct msghdr *msgh, int flags, 
                    806:                 size_t size)
                    807: {
                    808:   int nbytes;
                    809:   struct iovec *iov;
                    810:   
                    811:   STREAM_VERIFY_SANE(s);
                    812:   assert (msgh->msg_iovlen > 0);  
                    813:   
                    814:   if (STREAM_WRITEABLE (s) < size)
                    815:     {
                    816:       STREAM_BOUND_WARN (s, "put");
                    817:       /* This is a logic error in the calling code: the stream is too small
                    818:          to hold the desired data! */
                    819:       return -1;
                    820:     }
                    821:   
                    822:   iov = &(msgh->msg_iov[0]);
                    823:   iov->iov_base = (s->data + s->endp);
                    824:   iov->iov_len = size;
                    825:   
                    826:   nbytes = recvmsg (fd, msgh, flags);
                    827:   
                    828:   if (nbytes > 0)
                    829:     s->endp += nbytes;
                    830:   
                    831:   return nbytes;
                    832: }
                    833:   
                    834: /* Write data to buffer. */
                    835: size_t
                    836: stream_write (struct stream *s, const void *ptr, size_t size)
                    837: {
                    838: 
                    839:   CHECK_SIZE(s, size);
                    840: 
                    841:   STREAM_VERIFY_SANE(s);
                    842:   
                    843:   if (STREAM_WRITEABLE (s) < size)
                    844:     {
                    845:       STREAM_BOUND_WARN (s, "put");
                    846:       return 0;
                    847:     }
                    848:   
                    849:   memcpy (s->data + s->endp, ptr, size);
                    850:   s->endp += size;
                    851: 
                    852:   return size;
                    853: }
                    854: 
                    855: /* Return current read pointer. 
                    856:  * DEPRECATED!
                    857:  * Use stream_get_pnt_to if you must, but decoding streams properly
                    858:  * is preferred
                    859:  */
                    860: u_char *
                    861: stream_pnt (struct stream *s)
                    862: {
                    863:   STREAM_VERIFY_SANE(s);
                    864:   return s->data + s->getp;
                    865: }
                    866: 
                    867: /* Check does this stream empty? */
                    868: int
                    869: stream_empty (struct stream *s)
                    870: {
                    871:   STREAM_VERIFY_SANE(s);
                    872: 
                    873:   return (s->endp == 0);
                    874: }
                    875: 
                    876: /* Reset stream. */
                    877: void
                    878: stream_reset (struct stream *s)
                    879: {
                    880:   STREAM_VERIFY_SANE (s);
                    881: 
                    882:   s->getp = s->endp = 0;
                    883: }
                    884: 
                    885: /* Write stream contens to the file discriptor. */
                    886: int
                    887: stream_flush (struct stream *s, int fd)
                    888: {
                    889:   int nbytes;
                    890:   
                    891:   STREAM_VERIFY_SANE(s);
                    892:   
                    893:   nbytes = write (fd, s->data + s->getp, s->endp - s->getp);
                    894:   
                    895:   return nbytes;
                    896: }
                    897: 
                    898: /* Stream first in first out queue. */
                    899: 
                    900: struct stream_fifo *
                    901: stream_fifo_new (void)
                    902: {
                    903:   struct stream_fifo *new;
                    904:  
                    905:   new = XCALLOC (MTYPE_STREAM_FIFO, sizeof (struct stream_fifo));
                    906:   return new;
                    907: }
                    908: 
                    909: /* Add new stream to fifo. */
                    910: void
                    911: stream_fifo_push (struct stream_fifo *fifo, struct stream *s)
                    912: {
                    913:   if (fifo->tail)
                    914:     fifo->tail->next = s;
                    915:   else
                    916:     fifo->head = s;
                    917:      
                    918:   fifo->tail = s;
                    919: 
                    920:   fifo->count++;
                    921: }
                    922: 
                    923: /* Delete first stream from fifo. */
                    924: struct stream *
                    925: stream_fifo_pop (struct stream_fifo *fifo)
                    926: {
                    927:   struct stream *s;
                    928:   
                    929:   s = fifo->head; 
                    930: 
                    931:   if (s)
                    932:     { 
                    933:       fifo->head = s->next;
                    934: 
                    935:       if (fifo->head == NULL)
                    936:        fifo->tail = NULL;
                    937:     }
                    938: 
                    939:   fifo->count--;
                    940: 
                    941:   return s; 
                    942: }
                    943: 
                    944: /* Return first fifo entry. */
                    945: struct stream *
                    946: stream_fifo_head (struct stream_fifo *fifo)
                    947: {
                    948:   return fifo->head;
                    949: }
                    950: 
                    951: void
                    952: stream_fifo_clean (struct stream_fifo *fifo)
                    953: {
                    954:   struct stream *s;
                    955:   struct stream *next;
                    956: 
                    957:   for (s = fifo->head; s; s = next)
                    958:     {
                    959:       next = s->next;
                    960:       stream_free (s);
                    961:     }
                    962:   fifo->head = fifo->tail = NULL;
                    963:   fifo->count = 0;
                    964: }
                    965: 
                    966: void
                    967: stream_fifo_free (struct stream_fifo *fifo)
                    968: {
                    969:   stream_fifo_clean (fifo);
                    970:   XFREE (MTYPE_STREAM_FIFO, fifo);
                    971: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>