Annotation of embedaddon/quagga/lib/stream.c, revision 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>