svn cleanup
[anytun.git] / openvpn / buffer.c
blobcfff06ed21e6773d8488180bad30e842847db294
1 /*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
8 * Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #ifdef WIN32
26 #include "config-win32.h"
27 #else
28 #include "config.h"
29 #endif
31 #include "syshead.h"
33 #include "common.h"
34 #include "buffer.h"
35 #include "error.h"
36 #include "mtu.h"
37 #include "thread.h"
39 #include "memdbg.h"
41 struct buffer
42 #ifdef DMALLOC
43 alloc_buf_debug (size_t size, const char *file, int line)
44 #else
45 alloc_buf (size_t size)
46 #endif
48 #ifdef DMALLOC
49 return alloc_buf_gc_debug (size, NULL, file, line);
50 #else
51 return alloc_buf_gc (size, NULL);
52 #endif
55 struct buffer
56 #ifdef DMALLOC
57 alloc_buf_gc_debug (size_t size, struct gc_arena *gc, const char *file, int line)
58 #else
59 alloc_buf_gc (size_t size, struct gc_arena *gc)
60 #endif
62 struct buffer buf;
63 buf.capacity = (int)size;
64 buf.offset = 0;
65 buf.len = 0;
66 #ifdef DMALLOC
67 buf.data = (uint8_t *) gc_malloc_debug (size, false, gc, file, line);
68 #else
69 buf.data = (uint8_t *) gc_malloc (size, false, gc);
70 #endif
71 if (size)
72 *buf.data = 0;
73 return buf;
76 struct buffer
77 #ifdef DMALLOC
78 clone_buf_debug (const struct buffer* buf, const char *file, int line)
79 #else
80 clone_buf (const struct buffer* buf)
81 #endif
83 struct buffer ret;
84 ret.capacity = buf->capacity;
85 ret.offset = buf->offset;
86 ret.len = buf->len;
87 #ifdef DMALLOC
88 ret.data = (uint8_t *) openvpn_dmalloc (file, line, buf->capacity);
89 #else
90 ret.data = (uint8_t *) malloc (buf->capacity);
91 #endif
92 check_malloc_return (ret.data);
93 memcpy (BPTR (&ret), BPTR (buf), BLEN (buf));
94 return ret;
97 #ifdef BUF_INIT_TRACKING
99 bool
100 buf_init_debug (struct buffer *buf, int offset, const char *file, int line)
102 buf->debug_file = file;
103 buf->debug_line = line;
104 return buf_init_dowork (buf, offset);
107 static inline int
108 buf_debug_line (const struct buffer *buf)
110 return buf->debug_line;
113 static const char *
114 buf_debug_file (const struct buffer *buf)
116 return buf->debug_file;
119 #else
121 #define buf_debug_line(buf) 0
122 #define buf_debug_file(buf) "[UNDEF]"
124 #endif
126 void
127 buf_clear (struct buffer *buf)
129 if (buf->capacity > 0)
130 memset (buf->data, 0, buf->capacity);
131 buf->len = 0;
132 buf->offset = 0;
135 bool
136 buf_assign (struct buffer *dest, const struct buffer *src)
138 if (!buf_init (dest, src->offset))
139 return false;
140 return buf_write (dest, BPTR (src), BLEN (src));
143 struct buffer
144 clear_buf ()
146 struct buffer buf;
147 CLEAR (buf);
148 return buf;
151 void
152 free_buf (struct buffer *buf)
154 if (buf->data)
155 free (buf->data);
156 CLEAR (*buf);
160 * Return a buffer for write that is a subset of another buffer
162 struct buffer
163 buf_sub (struct buffer *buf, int size, bool prepend)
165 struct buffer ret;
166 uint8_t *data;
168 CLEAR (ret);
169 data = prepend ? buf_prepend (buf, size) : buf_write_alloc (buf, size);
170 if (data)
172 ret.capacity = size;
173 ret.data = data;
175 return ret;
179 * printf append to a buffer with overflow check
181 void
182 buf_printf (struct buffer *buf, const char *format, ...)
184 if (buf_defined (buf))
186 va_list arglist;
187 uint8_t *ptr = BEND (buf);
188 int cap = buf_forward_capacity (buf);
190 if (cap > 0)
192 va_start (arglist, format);
193 vsnprintf ((char *)ptr, cap, format, arglist);
194 va_end (arglist);
195 *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */
196 buf->len += (int) strlen ((char *)ptr);
202 * This is necessary due to certain buggy implementations of snprintf,
203 * that don't guarantee null termination for size > 0.
206 int openvpn_snprintf(char *str, size_t size, const char *format, ...)
208 va_list arglist;
209 int ret = 0;
210 if (size > 0)
212 va_start (arglist, format);
213 ret = vsnprintf (str, size, format, arglist);
214 va_end (arglist);
215 str[size - 1] = 0;
217 return ret;
221 * write a string to the end of a buffer that was
222 * truncated by buf_printf
224 void
225 buf_catrunc (struct buffer *buf, const char *str)
227 if (buf_forward_capacity (buf) <= 1)
229 int len = (int) strlen (str) + 1;
230 if (len < buf_forward_capacity_total (buf))
232 strncpynt ((char *)(buf->data + buf->capacity - len), str, len);
238 * convert a multi-line output to one line
240 void
241 convert_to_one_line (struct buffer *buf)
243 uint8_t *cp = BPTR(buf);
244 int len = BLEN(buf);
245 while (len--)
247 if (*cp == '\n')
248 *cp = '|';
249 ++cp;
253 /* NOTE: requires that string be null terminated */
254 void
255 buf_write_string_file (const struct buffer *buf, const char *filename, int fd)
257 const int len = strlen ((char *) BPTR (buf));
258 const int size = write (fd, BPTR (buf), len);
259 if (size != len)
260 msg (M_ERR, "Write error on file '%s'", filename);
264 * Garbage collection
267 void *
268 #ifdef DMALLOC
269 gc_malloc_debug (size_t size, bool clear, struct gc_arena *a, const char *file, int line)
270 #else
271 gc_malloc (size_t size, bool clear, struct gc_arena *a)
272 #endif
274 void *ret;
275 if (a)
277 struct gc_entry *e;
278 #ifdef DMALLOC
279 e = (struct gc_entry *) openvpn_dmalloc (file, line, size + sizeof (struct gc_entry));
280 #else
281 e = (struct gc_entry *) malloc (size + sizeof (struct gc_entry));
282 #endif
283 check_malloc_return (e);
284 ret = (char *) e + sizeof (struct gc_entry);
285 /*mutex_lock_static (L_GC_MALLOC);*/
286 e->next = a->list;
287 a->list = e;
288 /*mutex_unlock_static (L_GC_MALLOC);*/
290 else
292 #ifdef DMALLOC
293 ret = openvpn_dmalloc (file, line, size);
294 #else
295 ret = malloc (size);
296 #endif
297 check_malloc_return (ret);
299 #ifndef ZERO_BUFFER_ON_ALLOC
300 if (clear)
301 #endif
302 memset (ret, 0, size);
303 return ret;
306 void
307 x_gc_free (struct gc_arena *a)
309 struct gc_entry *e;
310 /*mutex_lock_static (L_GC_MALLOC);*/
311 e = a->list;
312 a->list = NULL;
313 /*mutex_unlock_static (L_GC_MALLOC);*/
315 while (e != NULL)
317 struct gc_entry *next = e->next;
318 free (e);
319 e = next;
324 * Hex dump -- Output a binary buffer to a hex string and return it.
327 char *
328 format_hex_ex (const uint8_t *data, int size, int maxoutput,
329 int space_break, const char* separator,
330 struct gc_arena *gc)
332 struct buffer out = alloc_buf_gc (maxoutput ? maxoutput :
333 ((size * 2) + (size / space_break) * (int) strlen (separator) + 2),
334 gc);
335 int i;
336 for (i = 0; i < size; ++i)
338 if (separator && i && !(i % space_break))
339 buf_printf (&out, "%s", separator);
340 buf_printf (&out, "%02x", data[i]);
342 buf_catrunc (&out, "[more...]");
343 return (char *)out.data;
347 * remove specific trailing character
350 void
351 buf_rmtail (struct buffer *buf, uint8_t remove)
353 uint8_t *cp = BLAST(buf);
354 if (cp && *cp == remove)
356 *cp = '\0';
357 --buf->len;
362 * force a null termination even it requires
363 * truncation of the last char.
365 void
366 buf_null_terminate (struct buffer *buf)
368 char *last = (char *) BLAST (buf);
369 if (last && *last == '\0') /* already terminated? */
370 return;
372 if (!buf_safe (buf, 1)) /* make space for trailing null */
373 buf_inc_len (buf, -1);
375 buf_write_u8 (buf, 0);
379 * Remove trailing \r and \n chars and ensure
380 * null termination.
382 void
383 buf_chomp (struct buffer *buf)
385 while (true)
387 char *last = (char *) BLAST (buf);
388 if (!last)
389 break;
390 if (char_class (*last, CC_CRLF|CC_NULL))
392 if (!buf_inc_len (buf, -1))
393 break;
395 else
396 break;
398 buf_null_terminate (buf);
402 * like buf_null_terminate, but operate on strings
404 void
405 string_null_terminate (char *str, int len, int capacity)
407 ASSERT (len >= 0 && len <= capacity && capacity > 0);
408 if (len < capacity)
409 *(str + len) = '\0';
410 else if (len == capacity)
411 *(str + len - 1) = '\0';
415 * Remove trailing \r and \n chars.
417 void
418 chomp (char *str)
420 bool modified;
421 do {
422 const int len = strlen (str);
423 modified = false;
424 if (len > 0)
426 char *cp = str + (len - 1);
427 if (*cp == '\n' || *cp == '\r')
429 *cp = '\0';
430 modified = true;
433 } while (modified);
437 * Allocate a string
439 char *
440 #ifdef DMALLOC
441 string_alloc_debug (const char *str, struct gc_arena *gc, const char *file, int line)
442 #else
443 string_alloc (const char *str, struct gc_arena *gc)
444 #endif
446 if (str)
448 const int n = strlen (str) + 1;
449 char *ret;
451 #ifdef DMALLOC
452 ret = (char *) gc_malloc_debug (n, false, gc, file, line);
453 #else
454 ret = (char *) gc_malloc (n, false, gc);
455 #endif
456 memcpy (ret, str, n);
457 return ret;
459 else
460 return NULL;
464 * Allocate a string inside a buffer
466 struct buffer
467 #ifdef DMALLOC
468 string_alloc_buf_debug (const char *str, struct gc_arena *gc, const char *file, int line)
469 #else
470 string_alloc_buf (const char *str, struct gc_arena *gc)
471 #endif
473 struct buffer buf;
475 ASSERT (str);
477 #ifdef DMALLOC
478 buf_set_read (&buf, (uint8_t*) string_alloc_debug (str, gc, file, line), strlen (str) + 1);
479 #else
480 buf_set_read (&buf, (uint8_t*) string_alloc (str, gc), strlen (str) + 1);
481 #endif
483 if (buf.len > 0) /* Don't count trailing '\0' as part of length */
484 --buf.len;
486 return buf;
490 * String comparison
493 bool
494 buf_string_match_head_str (const struct buffer *src, const char *match)
496 const int size = strlen (match);
497 if (size < 0 || size > src->len)
498 return false;
499 return memcmp (BPTR (src), match, size) == 0;
502 bool
503 buf_string_compare_advance (struct buffer *src, const char *match)
505 if (buf_string_match_head_str (src, match))
507 buf_advance (src, strlen (match));
508 return true;
510 else
511 return false;
515 buf_substring_len (const struct buffer *buf, int delim)
517 int i = 0;
518 struct buffer tmp = *buf;
519 int c;
521 while ((c = buf_read_u8 (&tmp)) >= 0)
523 ++i;
524 if (c == delim)
525 return i;
527 return -1;
531 * String parsing
534 bool
535 buf_parse (struct buffer *buf, const int delim, char *line, const int size)
537 bool eol = false;
538 int n = 0;
539 int c;
541 ASSERT (size > 0);
545 c = buf_read_u8 (buf);
546 if (c < 0)
547 eol = true;
548 if (c <= 0 || c == delim)
549 c = 0;
550 if (n >= size)
551 break;
552 line[n++] = c;
554 while (c);
556 line[size-1] = '\0';
557 return !(eol && !strlen (line));
561 * Classify and mutate strings based on character types.
564 bool
565 char_class (const char c, const unsigned int flags)
567 if (!flags)
568 return false;
569 if (flags & CC_ANY)
570 return true;
572 if ((flags & CC_NULL) && c == '\0')
573 return true;
575 if ((flags & CC_ALNUM) && isalnum (c))
576 return true;
577 if ((flags & CC_ALPHA) && isalpha (c))
578 return true;
579 if ((flags & CC_ASCII) && isascii (c))
580 return true;
581 if ((flags & CC_CNTRL) && iscntrl (c))
582 return true;
583 if ((flags & CC_DIGIT) && isdigit (c))
584 return true;
585 if ((flags & CC_PRINT) && isprint (c))
586 return true;
587 if ((flags & CC_PUNCT) && ispunct (c))
588 return true;
589 if ((flags & CC_SPACE) && isspace (c))
590 return true;
591 if ((flags & CC_XDIGIT) && isxdigit (c))
592 return true;
594 if ((flags & CC_BLANK) && (c == ' ' || c == '\t'))
595 return true;
596 if ((flags & CC_NEWLINE) && c == '\n')
597 return true;
598 if ((flags & CC_CR) && c == '\r')
599 return true;
601 if ((flags & CC_BACKSLASH) && c == '\\')
602 return true;
603 if ((flags & CC_UNDERBAR) && c == '_')
604 return true;
605 if ((flags & CC_DASH) && c == '-')
606 return true;
607 if ((flags & CC_DOT) && c == '.')
608 return true;
609 if ((flags & CC_COMMA) && c == ',')
610 return true;
611 if ((flags & CC_COLON) && c == ':')
612 return true;
613 if ((flags & CC_SLASH) && c == '/')
614 return true;
615 if ((flags & CC_SINGLE_QUOTE) && c == '\'')
616 return true;
617 if ((flags & CC_DOUBLE_QUOTE) && c == '\"')
618 return true;
619 if ((flags & CC_REVERSE_QUOTE) && c == '`')
620 return true;
621 if ((flags & CC_AT) && c == '@')
622 return true;
623 if ((flags & CC_EQUAL) && c == '=')
624 return true;
626 return false;
629 static inline bool
630 char_inc_exc (const char c, const unsigned int inclusive, const unsigned int exclusive)
632 return char_class (c, inclusive) && !char_class (c, exclusive);
635 bool
636 string_class (const char *str, const unsigned int inclusive, const unsigned int exclusive)
638 char c;
639 ASSERT (str);
640 while ((c = *str++))
642 if (!char_inc_exc (c, inclusive, exclusive))
643 return false;
645 return true;
649 * Modify string in place.
650 * Guaranteed to not increase string length.
652 bool
653 string_mod (char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
655 const char *in = str;
656 bool ret = true;
658 ASSERT (str);
660 while (true)
662 char c = *in++;
663 if (c)
665 if (!char_inc_exc (c, inclusive, exclusive))
667 c = replace;
668 ret = false;
670 if (c)
671 *str++ = c;
673 else
675 *str = '\0';
676 break;
679 return ret;
682 const char *
683 string_mod_const (const char *str,
684 const unsigned int inclusive,
685 const unsigned int exclusive,
686 const char replace,
687 struct gc_arena *gc)
689 if (str)
691 char *buf = string_alloc (str, gc);
692 string_mod (buf, inclusive, exclusive, replace);
693 return buf;
695 else
696 return NULL;
699 #ifdef CHARACTER_CLASS_DEBUG
701 #define CC_INCLUDE (CC_PRINT)
702 #define CC_EXCLUDE (0)
703 #define CC_REPLACE ('.')
705 void
706 character_class_debug (void)
708 char buf[256];
710 while (fgets (buf, sizeof (buf), stdin) != NULL)
712 string_mod (buf, CC_INCLUDE, CC_EXCLUDE, CC_REPLACE);
713 printf ("%s", buf);
717 #endif
719 #ifdef VERIFY_ALIGNMENT
720 void
721 valign4 (const struct buffer *buf, const char *file, const int line)
723 if (buf && buf->len)
725 int msglevel = D_ALIGN_DEBUG;
726 const unsigned int u = (unsigned int) BPTR (buf);
728 if (u & (PAYLOAD_ALIGN-1))
729 msglevel = D_ALIGN_ERRORS;
731 msg (msglevel, "%sAlignment at %s/%d ptr=" ptr_format " OLC=%d/%d/%d I=%s/%d",
732 (msglevel == D_ALIGN_ERRORS) ? "ERROR: " : "",
733 file,
734 line,
735 (ptr_type)buf->data,
736 buf->offset,
737 buf->len,
738 buf->capacity,
739 buf_debug_file (buf),
740 buf_debug_line (buf));
743 #endif