hitch  1.5.2
About: Hitch is a libev-based high performance SSL/TLS proxy that terminates TLS/SSL connections and forwards the unencrypted traffic to some backend.
  Fossies Dox: hitch-1.5.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

vsb.c
Go to the documentation of this file.
1 /*-
2  * Copyright (c) 2000-2008 Poul-Henning Kamp
3  * Copyright (c) 2000-2008 Dag-Erling Coïdan Smørgrav
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer
11  * in this position and unchanged.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27 __FBSDID("$FreeBSD: head/sys/kern/subr_vsb.c 222004 2011-05-17 06:36:32Z phk $")
28  */
29 
30 #include "config.h"
31 
32 #include <ctype.h>
33 #include <errno.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include "vas.h"
40 #include "vsb.h"
41 
42 #define KASSERT(e, m) assert(e)
43 #define SBMALLOC(size) malloc(size)
44 #define SBFREE(buf) free(buf)
45 
46 #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
47 
48 /*
49  * Predicates
50  */
51 #define VSB_ISDYNAMIC(s) ((s)->s_flags & VSB_DYNAMIC)
52 #define VSB_ISDYNSTRUCT(s) ((s)->s_flags & VSB_DYNSTRUCT)
53 #define VSB_HASROOM(s) ((s)->s_len < (s)->s_size - 1)
54 #define VSB_FREESPACE(s) ((s)->s_size - ((s)->s_len + 1))
55 #define VSB_CANEXTEND(s) ((s)->s_flags & VSB_AUTOEXTEND)
56 
57 /*
58  * Set / clear flags
59  */
60 #define VSB_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0)
61 #define VSB_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0)
62 
63 #define VSB_MINEXTENDSIZE 16 /* Should be power of 2. */
64 
65 #ifdef PAGE_SIZE
66 #define VSB_MAXEXTENDSIZE PAGE_SIZE
67 #define VSB_MAXEXTENDINCR PAGE_SIZE
68 #else
69 #define VSB_MAXEXTENDSIZE 4096
70 #define VSB_MAXEXTENDINCR 4096
71 #endif
72 
73 /*
74  * Debugging support
75  */
76 #if !defined(NDEBUG)
77 static void
78 _assert_VSB_integrity(const char *fun, const struct vsb *s)
79 {
80 
81  (void)fun;
82  (void)s;
83  KASSERT(s != NULL,
84  ("%s called with a NULL vsb pointer", fun));
85  KASSERT(s->magic == VSB_MAGIC,
86  ("%s called wih an bogus vsb pointer", fun));
87  KASSERT(s->s_buf != NULL,
88  ("%s called with uninitialized or corrupt vsb", fun));
89  KASSERT(s->s_len < s->s_size,
90  ("wrote past end of vsb (%d >= %d)", s->s_len, s->s_size));
91 }
92 
93 static void
94 _assert_VSB_state(const char *fun, const struct vsb *s, int state)
95 {
96 
97  (void)fun;
98  (void)s;
99  (void)state;
100  KASSERT((s->s_flags & VSB_FINISHED) == state,
101  ("%s called with %sfinished or corrupt vsb", fun,
102  (state ? "un" : "")));
103 }
104 #define assert_VSB_integrity(s) _assert_VSB_integrity(__func__, (s))
105 #define assert_VSB_state(s, i) _assert_VSB_state(__func__, (s), (i))
106 #else
107 #define assert_VSB_integrity(s) do { } while (0)
108 #define assert_VSB_state(s, i) do { } while (0)
109 #endif
110 
111 #ifdef CTASSERT
112 CTASSERT(powerof2(VSB_MAXEXTENDSIZE));
113 CTASSERT(powerof2(VSB_MAXEXTENDINCR));
114 #endif
115 
116 static int
117 VSB_extendsize(int size)
118 {
119  int newsize;
120 
121  if (size < (int)VSB_MAXEXTENDSIZE) {
122  newsize = VSB_MINEXTENDSIZE;
123  while (newsize < size)
124  newsize *= 2;
125  } else {
126  newsize = roundup2(size, VSB_MAXEXTENDINCR);
127  }
128  KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size));
129  return (newsize);
130 }
131 
132 /*
133  * Extend an vsb.
134  */
135 static int
136 VSB_extend(struct vsb *s, int addlen)
137 {
138  char *newbuf;
139  int newsize;
140 
141  if (!VSB_CANEXTEND(s))
142  return (-1);
143  newsize = VSB_extendsize(s->s_size + addlen);
144  if (VSB_ISDYNAMIC(s))
145  newbuf = realloc(s->s_buf, newsize);
146  else
147  newbuf = SBMALLOC(newsize);
148  if (newbuf == NULL)
149  return (-1);
150  if (!VSB_ISDYNAMIC(s)) {
151  memcpy(newbuf, s->s_buf, s->s_size);
153  }
154  s->s_buf = newbuf;
155  s->s_size = newsize;
156  return (0);
157 }
158 
159 static void
160 _vsb_indent(struct vsb *s)
161 {
162  if (s->s_indent == 0 || s->s_error != 0 ||
163  (s->s_len > 0 && s->s_buf[s->s_len - 1] != '\n'))
164  return;
165  if (VSB_FREESPACE(s) <= s->s_indent &&
166  VSB_extend(s, s->s_indent) < 0) {
167  s->s_error = ENOMEM;
168  return;
169  }
170  memset(s->s_buf + s->s_len, ' ', s->s_indent);
171  s->s_len += s->s_indent;
172 }
173 
174 /*
175  * Initialize the internals of an vsb.
176  * If buf is non-NULL, it points to a static or already-allocated string
177  * big enough to hold at least length characters.
178  */
179 static struct vsb *
180 VSB_newbuf(struct vsb *s, char *buf, int length, int flags)
181 {
182 
183  memset(s, 0, sizeof(*s));
184  s->magic = VSB_MAGIC;
185  s->s_flags = flags;
186  s->s_size = length;
187  s->s_buf = buf;
188 
189  if ((s->s_flags & VSB_AUTOEXTEND) == 0) {
190  KASSERT(s->s_size > 1,
191  ("attempt to create a too small vsb"));
192  }
193 
194  if (s->s_buf != NULL)
195  return (s);
196 
197  if ((flags & VSB_AUTOEXTEND) != 0)
198  s->s_size = VSB_extendsize(s->s_size);
199 
200  s->s_buf = SBMALLOC(s->s_size);
201  if (s->s_buf == NULL)
202  return (NULL);
204  return (s);
205 }
206 
207 /*
208  * Initialize an vsb.
209  * If buf is non-NULL, it points to a static or already-allocated string
210  * big enough to hold at least length characters.
211  */
212 struct vsb *
213 VSB_new(struct vsb *s, char *buf, int length, int flags)
214 {
215 
216  KASSERT(length >= 0,
217  ("attempt to create an vsb of negative length (%d)", length));
218  KASSERT((flags & ~VSB_USRFLAGMSK) == 0,
219  ("%s called with invalid flags", __func__));
220 
221  flags &= VSB_USRFLAGMSK;
222  if (s != NULL)
223  return (VSB_newbuf(s, buf, length, flags));
224 
225  s = SBMALLOC(sizeof(*s));
226  if (s == NULL)
227  return (NULL);
228  if (VSB_newbuf(s, buf, length, flags) == NULL) {
229  SBFREE(s);
230  return (NULL);
231  }
233  return (s);
234 }
235 
236 /*
237  * Clear an vsb and reset its position.
238  */
239 void
240 VSB_clear(struct vsb *s)
241 {
242 
244  /* don't care if it's finished or not */
245 
247  s->s_error = 0;
248  s->s_len = 0;
249  s->s_indent = 0;
250 }
251 
252 /*
253  * Append a byte to an vsb. This is the core function for appending
254  * to an vsb and is the main place that deals with extending the
255  * buffer and marking overflow.
256  */
257 static void
258 VSB_put_byte(struct vsb *s, int c)
259 {
260 
262  assert_VSB_state(s, 0);
263 
264  if (s->s_error != 0)
265  return;
266  _vsb_indent(s);
267  if (VSB_FREESPACE(s) <= 0) {
268  if (VSB_extend(s, 1) < 0)
269  s->s_error = ENOMEM;
270  if (s->s_error != 0)
271  return;
272  }
273  s->s_buf[s->s_len++] = (char)c;
274 }
275 
276 /*
277  * Append a byte string to an vsb.
278  */
279 int
280 VSB_bcat(struct vsb *s, const void *buf, ssize_t len)
281 {
283  assert_VSB_state(s, 0);
284 
285  assert(len >= 0);
286  if (s->s_error != 0)
287  return (-1);
288  if (len == 0)
289  return (0);
290  _vsb_indent(s);
291  if (len > VSB_FREESPACE(s)) {
292  if (VSB_extend(s, len - VSB_FREESPACE(s)) < 0)
293  s->s_error = ENOMEM;
294  if (s->s_error != 0)
295  return (-1);
296  }
297  memcpy(s->s_buf + s->s_len, buf, len);
298  s->s_len += len;
299  return (0);
300 }
301 
302 /*
303  * Append a string to an vsb.
304  */
305 int
306 VSB_cat(struct vsb *s, const char *str)
307 {
308 
310  assert_VSB_state(s, 0);
311 
312  if (s->s_error != 0)
313  return (-1);
314 
315  while (*str != '\0') {
316  VSB_put_byte(s, *str++);
317  if (s->s_error != 0)
318  return (-1);
319  }
320  return (0);
321 }
322 
323 /*
324  * Format the given argument list and append the resulting string to an vsb.
325  */
326 int
327 VSB_vprintf(struct vsb *s, const char *fmt, va_list ap)
328 {
329  va_list ap_copy;
330  int len;
331 
333  assert_VSB_state(s, 0);
334 
335  KASSERT(fmt != NULL,
336  ("%s called with a NULL format string", __func__));
337 
338  if (s->s_error != 0)
339  return (-1);
340  _vsb_indent(s);
341 
342  /*
343  * For the moment, there is no way to get vsnprintf(3) to hand
344  * back a character at a time, to push everything into
345  * VSB_putc_func() as was done for the kernel.
346  *
347  * In userspace, while drains are useful, there's generally
348  * not a problem attempting to malloc(3) on out of space. So
349  * expand a userland vsb if there is not enough room for the
350  * data produced by VSB_[v]printf(3).
351  */
352 
353  do {
354  va_copy(ap_copy, ap);
355  len = vsnprintf(&s->s_buf[s->s_len], VSB_FREESPACE(s) + 1,
356  fmt, ap_copy);
357  if (len < 0) {
358  s->s_error = errno;
359  return (-1);
360  }
361  va_end(ap_copy);
362  } while (len > VSB_FREESPACE(s) &&
363  VSB_extend(s, len - VSB_FREESPACE(s)) == 0);
364 
365  /*
366  * s->s_len is the length of the string, without the terminating nul.
367  * When updating s->s_len, we must subtract 1 from the length that
368  * we passed into vsnprintf() because that length includes the
369  * terminating nul.
370  *
371  * vsnprintf() returns the amount that would have been copied,
372  * given sufficient space, so don't over-increment s_len.
373  */
374  if (VSB_FREESPACE(s) < len)
375  len = VSB_FREESPACE(s);
376  s->s_len += len;
377  if (!VSB_HASROOM(s) && !VSB_CANEXTEND(s))
378  s->s_error = ENOMEM;
379 
380  KASSERT(s->s_len < s->s_size,
381  ("wrote past end of vsb (%d >= %d)", s->s_len, s->s_size));
382 
383  if (s->s_error != 0)
384  return (-1);
385  return (0);
386 }
387 
388 /*
389  * Format the given arguments and append the resulting string to an vsb.
390  */
391 int
392 VSB_printf(struct vsb *s, const char *fmt, ...)
393 {
394  va_list ap;
395  int result;
396 
397  va_start(ap, fmt);
398  result = VSB_vprintf(s, fmt, ap);
399  va_end(ap);
400  return (result);
401 }
402 
403 /*
404  * Append a character to an vsb.
405  */
406 int
407 VSB_putc(struct vsb *s, int c)
408 {
409 
410  VSB_put_byte(s, c);
411  if (s->s_error != 0)
412  return (-1);
413  return (0);
414 }
415 
416 /*
417  * Check if an vsb has an error.
418  */
419 int
420 VSB_error(const struct vsb *s)
421 {
422 
423  return (s->s_error);
424 }
425 
426 /*
427  * Finish off an vsb.
428  */
429 int
430 VSB_finish(struct vsb *s)
431 {
432 
434  assert_VSB_state(s, 0);
435 
436  s->s_buf[s->s_len] = '\0';
438  errno = s->s_error;
439  if (s->s_error)
440  return (-1);
441  return (0);
442 }
443 
444 /*
445  * Return a pointer to the vsb data.
446  */
447 char *
448 VSB_data(const struct vsb *s)
449 {
450 
453 
454  return (s->s_buf);
455 }
456 
457 /*
458  * Return the length of the vsb data.
459  */
460 ssize_t
461 VSB_len(const struct vsb *s)
462 {
463 
465  /* don't care if it's finished or not */
466 
467  if (s->s_error != 0)
468  return (-1);
469  return (s->s_len);
470 }
471 
472 /*
473  * Clear an vsb, free its buffer if necessary.
474  */
475 void
476 VSB_delete(struct vsb *s)
477 {
478  int isdyn;
479 
481  /* don't care if it's finished or not */
482 
483  if (VSB_ISDYNAMIC(s))
484  SBFREE(s->s_buf);
485  isdyn = VSB_ISDYNSTRUCT(s);
486  memset(s, 0, sizeof(*s));
487  if (isdyn)
488  SBFREE(s);
489 }
490 
491 /*
492  * Quote a string
493  */
494 void
495 VSB_quote(struct vsb *s, const char *p, int len, int how)
496 {
497  const char *q;
498  int quote = 0;
499 
500  (void)how; /* For future enhancements */
501  if (len == -1)
502  len = strlen(p);
503 
504  for (q = p; q < p + len; q++) {
505  if (!isgraph(*q) || *q == '"' || *q == '\\') {
506  quote++;
507  break;
508  }
509  }
510  if (!quote) {
511  (void)VSB_bcat(s, p, len);
512  return;
513  }
514  (void)VSB_putc(s, '"');
515  for (q = p; q < p + len; q++) {
516  switch (*q) {
517  case ' ':
518  (void)VSB_putc(s, *q);
519  break;
520  case '\\':
521  case '"':
522  (void)VSB_putc(s, '\\');
523  (void)VSB_putc(s, *q);
524  break;
525  case '\n':
526  if (how & VSB_QUOTE_NONL)
527  (void)VSB_cat(s, "\n");
528  else
529  (void)VSB_cat(s, "\\n");
530  break;
531  case '\r':
532  (void)VSB_cat(s, "\\r");
533  break;
534  case '\t':
535  (void)VSB_cat(s, "\\t");
536  break;
537  default:
538  if (isgraph(*q))
539  (void)VSB_putc(s, *q);
540  else
541  (void)VSB_printf(s, "\\%o", *q & 0xff);
542  break;
543  }
544  }
545  (void)VSB_putc(s, '"');
546 }
547 
548 /*
549  * Indentation
550  */
551 
552 void
553 VSB_indent(struct vsb * s, int i)
554 {
555 
557  if (s->s_indent + i < 0)
558  s->s_error = EINVAL;
559  else
560  s->s_indent += i;
561 }
vas.h
VSB_SETFLAG
#define VSB_SETFLAG(s, f)
Definition: vsb.c:60
vsb.h
vsb::s_indent
int s_indent
Definition: vsb.h:51
vsb
Definition: vsb.h:37
VSB_MAXEXTENDSIZE
#define VSB_MAXEXTENDSIZE
Definition: vsb.c:69
VSB_extendsize
static int VSB_extendsize(int size)
Definition: vsb.c:117
vsb::magic
unsigned magic
Definition: vsb.h:38
VSB_vprintf
int VSB_vprintf(struct vsb *s, const char *fmt, va_list ap)
Definition: vsb.c:327
_vsb_indent
static void _vsb_indent(struct vsb *s)
Definition: vsb.c:160
VSB_cat
int VSB_cat(struct vsb *s, const char *str)
Definition: vsb.c:306
VSB_error
int VSB_error(const struct vsb *s)
Definition: vsb.c:420
vsb::s_len
ssize_t s_len
Definition: vsb.h:43
VSB_ISDYNSTRUCT
#define VSB_ISDYNSTRUCT(s)
Definition: vsb.c:52
vsb::s_size
ssize_t s_size
Definition: vsb.h:42
VSB_CLEARFLAG
#define VSB_CLEARFLAG(s, f)
Definition: vsb.c:61
VSB_FINISHED
#define VSB_FINISHED
Definition: vsb.h:48
vsb::s_error
int s_error
Definition: vsb.h:40
assert_VSB_state
#define assert_VSB_state(s, i)
Definition: vsb.c:105
VSB_extend
static int VSB_extend(struct vsb *s, int addlen)
Definition: vsb.c:136
VSB_AUTOEXTEND
#define VSB_AUTOEXTEND
Definition: vsb.h:45
VSB_MINEXTENDSIZE
#define VSB_MINEXTENDSIZE
Definition: vsb.c:63
VSB_putc
int VSB_putc(struct vsb *s, int c)
Definition: vsb.c:407
VSB_clear
void VSB_clear(struct vsb *s)
Definition: vsb.c:240
assert_VSB_integrity
#define assert_VSB_integrity(s)
Definition: vsb.c:104
vsb::s_buf
char * s_buf
Definition: vsb.h:41
assert
#define assert(e)
Definition: vas.h:55
VSB_indent
void VSB_indent(struct vsb *s, int i)
Definition: vsb.c:553
VSB_newbuf
static struct vsb * VSB_newbuf(struct vsb *s, char *buf, int length, int flags)
Definition: vsb.c:180
VSB_ISDYNAMIC
#define VSB_ISDYNAMIC(s)
Definition: vsb.c:51
VSB_quote
void VSB_quote(struct vsb *s, const char *p, int len, int how)
Definition: vsb.c:495
KASSERT
#define KASSERT(e, m)
Definition: vsb.c:42
SBMALLOC
#define SBMALLOC(size)
Definition: vsb.c:43
vsb::s_flags
int s_flags
Definition: vsb.h:50
VSB_new
struct vsb * VSB_new(struct vsb *s, char *buf, int length, int flags)
Definition: vsb.c:213
VSB_delete
void VSB_delete(struct vsb *s)
Definition: vsb.c:476
VSB_MAXEXTENDINCR
#define VSB_MAXEXTENDINCR
Definition: vsb.c:70
_assert_VSB_state
static void _assert_VSB_state(const char *fun, const struct vsb *s, int state)
Definition: vsb.c:94
VSB_printf
int VSB_printf(struct vsb *s, const char *fmt,...)
Definition: vsb.c:392
VSB_data
char * VSB_data(const struct vsb *s)
Definition: vsb.c:448
VSB_QUOTE_NONL
#define VSB_QUOTE_NONL
Definition: vsb.h:77
VSB_bcat
int VSB_bcat(struct vsb *s, const void *buf, ssize_t len)
Definition: vsb.c:280
VSB_DYNAMIC
#define VSB_DYNAMIC
Definition: vsb.h:47
VSB_HASROOM
#define VSB_HASROOM(s)
Definition: vsb.c:53
SBFREE
#define SBFREE(buf)
Definition: vsb.c:44
VSB_FREESPACE
#define VSB_FREESPACE(s)
Definition: vsb.c:54
VSB_put_byte
static void VSB_put_byte(struct vsb *s, int c)
Definition: vsb.c:258
VSB_DYNSTRUCT
#define VSB_DYNSTRUCT
Definition: vsb.h:49
VSB_finish
int VSB_finish(struct vsb *s)
Definition: vsb.c:430
VSB_CANEXTEND
#define VSB_CANEXTEND(s)
Definition: vsb.c:55
VSB_len
ssize_t VSB_len(const struct vsb *s)
Definition: vsb.c:461
VSB_MAGIC
#define VSB_MAGIC
Definition: vsb.h:39
roundup2
#define roundup2(x, y)
Definition: vsb.c:46
_assert_VSB_integrity
static void _assert_VSB_integrity(const char *fun, const struct vsb *s)
Definition: vsb.c:78
VSB_USRFLAGMSK
#define VSB_USRFLAGMSK
Definition: vsb.h:46