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 <zebra.h>
24
25#include "stream.h"
26#include "memory.h"
27#include "network.h"
28#include "prefix.h"
29
30
31/*A macro to check pointers in order to not
32  go behind the allocated mem block
33  S -- stream reference
34  Z -- size of data to be written
35*/
36
37#define CHECK_SIZE(S, Z) \
38	if (((S)->putp + (Z)) > (S)->size) \
39           (Z) = (S)->size - (S)->putp;
40
41/* Stream is fixed length buffer for network output/input. */
42
43/* Make stream buffer. */
44struct stream *
45stream_new (size_t size)
46{
47  struct stream *s;
48
49  s = XCALLOC (MTYPE_STREAM, sizeof (struct stream));
50
51  s->data = XCALLOC (MTYPE_STREAM_DATA, size);
52  s->size = size;
53  return s;
54}
55
56/* Free it now. */
57void
58stream_free (struct stream *s)
59{
60  XFREE (MTYPE_STREAM_DATA, s->data);
61  XFREE (MTYPE_STREAM, s);
62}
63#ifdef FOX_SUPPORT
64
65unsigned long
66stream_get_getp (struct stream *s)
67{
68  return s->getp;
69}
70
71unsigned long
72stream_get_putp (struct stream *s)
73{
74  return s->putp;
75}
76#endif /* FOX_SUPPORT */
77unsigned long
78stream_get_endp (struct stream *s)
79{
80  return s->endp;
81}
82#ifdef FOX_SUPPORT
83unsigned long
84stream_get_size (struct stream *s)
85{
86  return s->size;
87}
88
89/* Stream structre' stream pointer related functions.  */
90void
91stream_set_getp (struct stream *s, unsigned long pos)
92{
93  s->getp = pos;
94}
95
96void
97stream_set_putp (struct stream *s, unsigned long pos)
98{
99  s->putp = pos;
100}
101#endif /* FOX_SUPPORT */
102/* Forward pointer. */
103void
104stream_forward (struct stream *s, int size)
105{
106  s->getp += size;
107}
108
109/* Copy from stream to destination. */
110void
111stream_get (void *dst, struct stream *s, size_t size)
112{
113  memcpy (dst, s->data + s->getp, size);
114  s->getp += size;
115}
116
117/* Get next character from the stream. */
118u_char
119stream_getc (struct stream *s)
120{
121  u_char c;
122
123  c = s->data[s->getp];
124  s->getp++;
125  return c;
126}
127
128#ifdef FOX_SUPPORT
129/* Get next character from the stream. */
130u_char
131stream_getc_from (struct stream *s, unsigned long from)
132{
133  u_char c;
134
135  c = s->data[from];
136  return c;
137}
138#endif /* FOX_SUPPORT */
139/* Get next word from the stream. */
140u_int16_t
141stream_getw (struct stream *s)
142{
143  u_int16_t w;
144
145  w = s->data[s->getp++] << 8;
146  w |= s->data[s->getp++];
147  return w;
148}
149
150#ifdef FOX_SUPPORT
151/* Get next word from the stream. */
152u_int16_t
153stream_getw_from (struct stream *s, unsigned long from)
154{
155  u_int16_t w;
156
157  w = s->data[from++] << 8;
158  w |= s->data[from];
159  return w;
160}
161#endif /* FOX_SUPPORT */
162
163/* Get next long word from the stream. */
164u_int32_t
165stream_getl (struct stream *s)
166{
167  u_int32_t l;
168
169  l  = s->data[s->getp++] << 24;
170  l |= s->data[s->getp++] << 16;
171  l |= s->data[s->getp++] << 8;
172  l |= s->data[s->getp++];
173  return l;
174}
175
176/* Get next long word from the stream. */
177u_int32_t
178stream_get_ipv4 (struct stream *s)
179{
180  u_int32_t l;
181
182  memcpy (&l, s->data + s->getp, 4);
183  s->getp += 4;
184
185  return l;
186}
187
188/* Copy to source to stream. */
189void
190stream_put (struct stream *s, void *src, size_t size)
191{
192
193  CHECK_SIZE(s, size);
194
195  if (src)
196    memcpy (s->data + s->putp, src, size);
197  else
198    memset (s->data + s->putp, 0, size);
199
200  s->putp += size;
201  if (s->putp > s->endp)
202    s->endp = s->putp;
203}
204
205/* Put character to the stream. */
206int
207stream_putc (struct stream *s, u_char c)
208{
209  if (s->putp >= s->size) return 0;
210
211  s->data[s->putp] = c;
212  s->putp++;
213  if (s->putp > s->endp)
214    s->endp = s->putp;
215  return 1;
216}
217
218/* Put word to the stream. */
219int
220stream_putw (struct stream *s, u_int16_t w)
221{
222  if ((s->size - s->putp) < 2) return 0;
223
224  s->data[s->putp++] = (u_char)(w >>  8);
225  s->data[s->putp++] = (u_char) w;
226
227  if (s->putp > s->endp)
228    s->endp = s->putp;
229  return 2;
230}
231
232/* Put long word to the stream. */
233int
234stream_putl (struct stream *s, u_int32_t l)
235{
236  if ((s->size - s->putp) < 4) return 0;
237
238  s->data[s->putp++] = (u_char)(l >> 24);
239  s->data[s->putp++] = (u_char)(l >> 16);
240  s->data[s->putp++] = (u_char)(l >>  8);
241  s->data[s->putp++] = (u_char)l;
242
243  if (s->putp > s->endp)
244    s->endp = s->putp;
245  return 4;
246}
247
248int
249stream_putc_at (struct stream *s, unsigned long putp, u_char c)
250{
251  s->data[putp] = c;
252  return 1;
253}
254
255int
256stream_putw_at (struct stream *s, unsigned long putp, u_int16_t w)
257{
258  s->data[putp] = (u_char)(w >>  8);
259  s->data[putp + 1] = (u_char) w;
260  return 2;
261}
262#ifdef FOX_SUPPORT
263int
264stream_putl_at (struct stream *s, unsigned long putp, u_int32_t l)
265{
266  s->data[putp] = (u_char)(l >> 24);
267  s->data[putp + 1] = (u_char)(l >> 16);
268  s->data[putp + 2] = (u_char)(l >>  8);
269  s->data[putp + 3] = (u_char)l;
270  return 4;
271}
272#endif /* FOX_SUPPORT */
273/* Put long word to the stream. */
274int
275stream_put_ipv4 (struct stream *s, u_int32_t l)
276{
277  if ((s->size - s->putp) < 4)
278    return 0;
279
280  memcpy (s->data + s->putp, &l, 4);
281  s->putp += 4;
282
283  if (s->putp > s->endp)
284    s->endp = s->putp;
285  return 4;
286}
287
288/* Put long word to the stream. */
289int
290stream_put_in_addr (struct stream *s, struct in_addr *addr)
291{
292  if ((s->size - s->putp) < 4)
293    return 0;
294
295  memcpy (s->data + s->putp, addr, 4);
296  s->putp += 4;
297
298  if (s->putp > s->endp)
299    s->endp = s->putp;
300  return 4;
301}
302
303#ifdef FOX_SUPPORT
304/* Put prefix by nlri type format. */
305int
306stream_put_prefix (struct stream *s, struct prefix *p)
307{
308  u_char psize;
309
310  psize = PSIZE (p->prefixlen);
311
312  if ((s->size - s->putp) < psize) return 0;
313
314  stream_putc (s, p->prefixlen);
315  memcpy (s->data + s->putp, &p->u.prefix, psize);
316  s->putp += psize;
317
318  if (s->putp > s->endp)
319    s->endp = s->putp;
320
321  return psize;
322}
323#endif /* FOX_SUPPORT */
324
325/* Read size from fd. */
326int
327stream_read (struct stream *s, int fd, size_t size)
328{
329  int nbytes;
330
331  nbytes = readn (fd, s->data + s->putp, size);
332
333  if (nbytes > 0)
334    {
335      s->putp += nbytes;
336      s->endp += nbytes;
337    }
338  return nbytes;
339}
340#ifdef FOX_SUPPORT
341/* Read size from fd. */
342int
343stream_read_unblock (struct stream *s, int fd, size_t size)
344{
345  int nbytes;
346  int val;
347
348  val = fcntl (fd, F_GETFL, 0);
349  fcntl (fd, F_SETFL, val|O_NONBLOCK);
350  nbytes = read (fd, s->data + s->putp, size);
351  fcntl (fd, F_SETFL, val);
352
353  if (nbytes > 0)
354    {
355      s->putp += nbytes;
356      s->endp += nbytes;
357    }
358  return nbytes;
359}
360#endif /* FOX_SUPPORT */
361/* Write data to buffer. */
362int
363stream_write (struct stream *s, u_char *ptr, size_t size)
364{
365
366  CHECK_SIZE(s, size);
367
368  memcpy (s->data + s->putp, ptr, size);
369  s->putp += size;
370  if (s->putp > s->endp)
371    s->endp = s->putp;
372  return size;
373}
374#ifdef FOX_SUPPORT
375/* Return current read pointer. */
376u_char *
377stream_pnt (struct stream *s)
378{
379  return s->data + s->getp;
380}
381
382/* Check does this stream empty? */
383int
384stream_empty (struct stream *s)
385{
386  if (s->putp == 0 && s->endp == 0 && s->getp == 0)
387    return 1;
388  else
389    return 0;
390}
391#endif /* FOX_SUPPORT */
392/* Reset stream. */
393void
394stream_reset (struct stream *s)
395{
396  s->putp = 0;
397  s->endp = 0;
398  s->getp = 0;
399}
400
401/* Write stream contens to the file discriptor. */
402int
403stream_flush (struct stream *s, int fd)
404{
405  int nbytes;
406
407  nbytes = write (fd, s->data + s->getp, s->endp - s->getp);
408
409  return nbytes;
410}
411
412#ifdef FOX_SUPPORT
413/* Stream first in first out queue. */
414
415struct stream_fifo *
416stream_fifo_new ()
417{
418  struct stream_fifo *new;
419
420  new = XCALLOC (MTYPE_STREAM_FIFO, sizeof (struct stream_fifo));
421  return new;
422}
423
424/* Add new stream to fifo. */
425void
426stream_fifo_push (struct stream_fifo *fifo, struct stream *s)
427{
428  if (fifo->tail)
429    fifo->tail->next = s;
430  else
431    fifo->head = s;
432
433  fifo->tail = s;
434
435  fifo->count++;
436}
437
438/* Delete first stream from fifo. */
439struct stream *
440stream_fifo_pop (struct stream_fifo *fifo)
441{
442  struct stream *s;
443
444  s = fifo->head;
445
446  if (s)
447    {
448      fifo->head = s->next;
449
450      if (fifo->head == NULL)
451	fifo->tail = NULL;
452    }
453
454  fifo->count--;
455
456  return s;
457}
458
459/* Return first fifo entry. */
460struct stream *
461stream_fifo_head (struct stream_fifo *fifo)
462{
463  return fifo->head;
464}
465
466void
467stream_fifo_clean (struct stream_fifo *fifo)
468{
469  struct stream *s;
470  struct stream *next;
471
472  for (s = fifo->head; s; s = next)
473    {
474      next = s->next;
475      stream_free (s);
476    }
477  fifo->head = fifo->tail = NULL;
478  fifo->count = 0;
479}
480
481void
482stream_fifo_free (struct stream_fifo *fifo)
483{
484  stream_fifo_clean (fifo);
485  XFREE (MTYPE_STREAM_FIFO, fifo);
486}
487
488#endif /* FOX_SUPPORT */
489