OpenVPN
buffer.c
Go to the documentation of this file.
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.
7 *
8 * Copyright (C) 2002-2024 OpenVPN Inc <sales@openvpn.net>
9 *
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.
13 *
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.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "syshead.h"
29
30#include "common.h"
31#include "buffer.h"
32#include "error.h"
33#include "mtu.h"
34#include "misc.h"
35
36#include "memdbg.h"
37
38#include <wchar.h>
39
40size_t
41array_mult_safe(const size_t m1, const size_t m2, const size_t extra)
42{
43 const size_t limit = 0xFFFFFFFF;
44 unsigned long long res = (unsigned long long)m1 * (unsigned long long)m2 + (unsigned long long)extra;
45 if (unlikely(m1 > limit) || unlikely(m2 > limit) || unlikely(extra > limit) || unlikely(res > (unsigned long long)limit))
46 {
47 msg(M_FATAL, "attempted allocation of excessively large array");
48 }
49 return (size_t) res;
50}
51
52void
53buf_size_error(const size_t size)
54{
55 msg(M_FATAL, "fatal buffer size error, size=%lu", (unsigned long)size);
56}
57
58struct buffer
60alloc_buf_debug(size_t size, const char *file, int line)
61#else
62alloc_buf(size_t size)
63#endif
64{
65 struct buffer buf;
66
67 if (!buf_size_valid(size))
68 {
69 buf_size_error(size);
70 }
71 buf.capacity = (int)size;
72 buf.offset = 0;
73 buf.len = 0;
74#ifdef DMALLOC
75 buf.data = openvpn_dmalloc(file, line, size);
76#else
77 buf.data = calloc(1, size);
78#endif
80
81 return buf;
82}
83
84struct buffer
86alloc_buf_gc_debug(size_t size, struct gc_arena *gc, const char *file, int line)
87#else
88alloc_buf_gc(size_t size, struct gc_arena *gc)
89#endif
90{
91 struct buffer buf;
92 if (!buf_size_valid(size))
93 {
94 buf_size_error(size);
95 }
96 buf.capacity = (int)size;
97 buf.offset = 0;
98 buf.len = 0;
99#ifdef DMALLOC
100 buf.data = (uint8_t *) gc_malloc_debug(size, false, gc, file, line);
101#else
102 buf.data = (uint8_t *) gc_malloc(size, false, gc);
103#endif
104 if (size)
105 {
106 *buf.data = 0;
107 }
108 return buf;
109}
110
111struct buffer
113clone_buf_debug(const struct buffer *buf, const char *file, int line)
114#else
115clone_buf(const struct buffer *buf)
116#endif
117{
118 struct buffer ret;
119 ret.capacity = buf->capacity;
120 ret.offset = buf->offset;
121 ret.len = buf->len;
122#ifdef DMALLOC
123 ret.data = (uint8_t *) openvpn_dmalloc(file, line, buf->capacity);
124#else
125 ret.data = (uint8_t *) malloc(buf->capacity);
126#endif
128 memcpy(BPTR(&ret), BPTR(buf), BLEN(buf));
129 return ret;
130}
131
132#ifdef BUF_INIT_TRACKING
133
134bool
135buf_init_debug(struct buffer *buf, int offset, const char *file, int line)
136{
137 buf->debug_file = file;
138 buf->debug_line = line;
139 return buf_init_dowork(buf, offset);
140}
141
142static inline int
143buf_debug_line(const struct buffer *buf)
144{
145 return buf->debug_line;
146}
147
148static const char *
149buf_debug_file(const struct buffer *buf)
150{
151 return buf->debug_file;
152}
153
154#else /* ifdef BUF_INIT_TRACKING */
155
156#define buf_debug_line(buf) 0
157#define buf_debug_file(buf) "[UNDEF]"
158
159#endif /* ifdef BUF_INIT_TRACKING */
160
161void
162buf_clear(struct buffer *buf)
163{
164 if (buf->capacity > 0)
165 {
166 secure_memzero(buf->data, buf->capacity);
167 }
168 buf->len = 0;
169 buf->offset = 0;
170}
171
172bool
173buf_assign(struct buffer *dest, const struct buffer *src)
174{
175 if (!buf_init(dest, src->offset))
176 {
177 return false;
178 }
179 return buf_write(dest, BPTR(src), BLEN(src));
180}
181
182void
183free_buf(struct buffer *buf)
184{
185 free(buf->data);
186 CLEAR(*buf);
187}
188
189static void
190free_buf_gc(struct buffer *buf, struct gc_arena *gc)
191{
192 if (gc)
193 {
194 struct gc_entry **e = &gc->list;
195
196 while (*e)
197 {
198 /* check if this object is the one we want to delete */
199 if ((uint8_t *)(*e + 1) == buf->data)
200 {
201 struct gc_entry *to_delete = *e;
202
203 /* remove element from linked list and free it */
204 *e = (*e)->next;
205 free(to_delete);
206
207 break;
208 }
209
210 e = &(*e)->next;
211 }
212 }
213
214 CLEAR(*buf);
215}
216
217/*
218 * Return a buffer for write that is a subset of another buffer
219 */
220struct buffer
221buf_sub(struct buffer *buf, int size, bool prepend)
222{
223 struct buffer ret;
224 uint8_t *data;
225
226 CLEAR(ret);
227 data = prepend ? buf_prepend(buf, size) : buf_write_alloc(buf, size);
228 if (data)
229 {
230 ret.capacity = size;
231 ret.data = data;
232 }
233 return ret;
234}
235
236/*
237 * printf append to a buffer with overflow check
238 */
239bool
240buf_printf(struct buffer *buf, const char *format, ...)
241{
242 int ret = false;
243 if (buf_defined(buf))
244 {
246 uint8_t *ptr = BEND(buf);
247 int cap = buf_forward_capacity(buf);
248
249 if (cap > 0)
250 {
251 int stat;
253 stat = vsnprintf((char *)ptr, cap, format, arglist);
255 *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */
256 buf->len += (int) strlen((char *)ptr);
257 if (stat >= 0 && stat < cap)
258 {
259 ret = true;
260 }
261 }
262 }
263 return ret;
264}
265
266bool
267buf_puts(struct buffer *buf, const char *str)
268{
269 int ret = false;
270 uint8_t *ptr = BEND(buf);
271 int cap = buf_forward_capacity(buf);
272 if (cap > 0)
273 {
274 strncpynt((char *)ptr, str, cap);
275 *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */
276 buf->len += (int) strlen((char *)ptr);
277 ret = true;
278 }
279 return ret;
280}
281
282/*
283 * write a string to the end of a buffer that was
284 * truncated by buf_printf
285 */
286void
287buf_catrunc(struct buffer *buf, const char *str)
288{
289 if (buf_forward_capacity(buf) <= 1)
290 {
291 size_t len = strlen(str) + 1;
293 {
294 memcpy(buf->data + buf->capacity - len, str, len);
295 }
296 }
297}
298
299bool
300buffer_write_file(const char *filename, const struct buffer *buf)
301{
302 bool ret = false;
303 int fd = platform_open(filename, O_CREAT | O_TRUNC | O_WRONLY,
304 S_IRUSR | S_IWUSR);
305 if (fd == -1)
306 {
307 msg(M_ERRNO, "Cannot open file '%s' for write", filename);
308 return false;
309 }
310
311 const ssize_t size = write(fd, BPTR(buf), BLEN(buf));
312 if (size != BLEN(buf))
313 {
314 msg(M_ERRNO, "Write error on file '%s'", filename);
315 goto cleanup;
316 }
317
318 ret = true;
319cleanup:
320 if (close(fd) < 0)
321 {
322 msg(M_ERRNO, "Close error on file %s", filename);
323 ret = false;
324 }
325 return ret;
326}
327
328/*
329 * Garbage collection
330 */
331
332void *
333#ifdef DMALLOC
334gc_malloc_debug(size_t size, bool clear, struct gc_arena *a, const char *file, int line)
335#else
336gc_malloc(size_t size, bool clear, struct gc_arena *a)
337#endif
338{
339 void *ret;
340 if (a)
341 {
342 struct gc_entry *e;
343#ifdef DMALLOC
344 e = (struct gc_entry *) openvpn_dmalloc(file, line, size + sizeof(struct gc_entry));
345#else
346 e = (struct gc_entry *) malloc(size + sizeof(struct gc_entry));
347#endif
349 ret = (char *) e + sizeof(struct gc_entry);
350 e->next = a->list;
351 a->list = e;
352 }
353 else
354 {
355#ifdef DMALLOC
356 ret = openvpn_dmalloc(file, line, size);
357#else
358 ret = malloc(size);
359#endif
361 }
362#ifndef ZERO_BUFFER_ON_ALLOC
363 if (clear)
364#endif
365 memset(ret, 0, size);
366 return ret;
367}
368
369void *
370gc_realloc(void *ptr, size_t size, struct gc_arena *a)
371{
372 void *ret = realloc(ptr, size);
374 if (a)
375 {
376 if (ptr && ptr != ret)
377 {
378 /* find the old entry and modify it if realloc changed
379 * the pointer */
380 struct gc_entry_special *e = NULL;
381 for (e = a->list_special; e != NULL; e = e->next)
382 {
383 if (e->addr == ptr)
384 {
385 break;
386 }
387 }
388 ASSERT(e);
389 ASSERT(e->addr == ptr);
390 e->addr = ret;
391 }
392 else if (!ptr)
393 {
394 /* sets e->addr to newptr */
395 gc_addspecial(ret, free, a);
396 }
397 }
398
399 return ret;
400}
401
402void
404{
405 struct gc_entry *e;
406 e = a->list;
407 a->list = NULL;
408
409 while (e != NULL)
410 {
411 struct gc_entry *next = e->next;
412 free(e);
413 e = next;
414 }
415}
416
417/*
418 * Functions to handle special objects in gc_entries
419 */
420
421void
423{
424 struct gc_entry_special *e;
425 e = a->list_special;
426 a->list_special = NULL;
427
428 while (e != NULL)
429 {
430 struct gc_entry_special *next = e->next;
431 e->free_fnc(e->addr);
432 free(e);
433 e = next;
434 }
435}
436
437void
438gc_addspecial(void *addr, void (*free_function)(void *), struct gc_arena *a)
439{
440 ASSERT(a);
441 struct gc_entry_special *e;
442#ifdef DMALLOC
443 e = (struct gc_entry_special *) openvpn_dmalloc(file, line, sizeof(struct gc_entry_special));
444#else
445 e = (struct gc_entry_special *) malloc(sizeof(struct gc_entry_special));
446#endif
448 e->free_fnc = free_function;
449 e->addr = addr;
450
451 e->next = a->list_special;
452 a->list_special = e;
453}
454
455
456/*
457 * Transfer src arena to dest, resetting src to an empty arena.
458 */
459void
460gc_transfer(struct gc_arena *dest, struct gc_arena *src)
461{
462 if (dest && src)
463 {
464 struct gc_entry *e = src->list;
465 if (e)
466 {
467 while (e->next != NULL)
468 {
469 e = e->next;
470 }
471 e->next = dest->list;
472 dest->list = src->list;
473 src->list = NULL;
474 }
475 }
476}
477
478/*
479 * Hex dump -- Output a binary buffer to a hex string and return it.
480 */
481
482char *
483format_hex_ex(const uint8_t *data, int size, int maxoutput,
484 unsigned int space_break_flags, const char *separator,
485 struct gc_arena *gc)
486{
487 const size_t bytes_per_hexblock = space_break_flags & FHE_SPACE_BREAK_MASK;
488 const size_t separator_len = separator ? strlen(separator) : 0;
489 static_assert(INT_MAX <= SIZE_MAX, "Code assumes INT_MAX <= SIZE_MAX");
490 const size_t out_len = maxoutput > 0 ? maxoutput :
491 ((size * 2) + ((size / bytes_per_hexblock) * separator_len) + 2);
492
493 struct buffer out = alloc_buf_gc(out_len, gc);
494 for (int i = 0; i < size; ++i)
495 {
496 if (separator && i && !(i % bytes_per_hexblock))
497 {
498 buf_printf(&out, "%s", separator);
499 }
501 {
502 buf_printf(&out, "%02X", data[i]);
503 }
504 else
505 {
506 buf_printf(&out, "%02x", data[i]);
507 }
508 }
509 buf_catrunc(&out, "[more...]");
510 return (char *)out.data;
511}
512
513/*
514 * remove specific trailing character
515 */
516
517void
519{
520 uint8_t *cp = BLAST(buf);
521 if (cp && *cp == remove)
522 {
523 *cp = '\0';
524 --buf->len;
525 }
526}
527
528/*
529 * force a null termination even it requires
530 * truncation of the last char.
531 */
532void
534{
535 char *last = (char *) BLAST(buf);
536 if (last && *last == '\0') /* already terminated? */
537 {
538 return;
539 }
540
541 if (!buf_safe(buf, 1)) /* make space for trailing null */
542 {
543 buf_inc_len(buf, -1);
544 }
545
546 buf_write_u8(buf, 0);
547}
548
549/*
550 * Remove trailing \r and \n chars and ensure
551 * null termination.
552 */
553void
554buf_chomp(struct buffer *buf)
555{
556 while (true)
557 {
558 char *last = (char *) BLAST(buf);
559 if (!last)
560 {
561 break;
562 }
563 if (char_class(*last, CC_CRLF|CC_NULL))
564 {
565 if (!buf_inc_len(buf, -1))
566 {
567 break;
568 }
569 }
570 else
571 {
572 break;
573 }
574 }
576}
577
578const char *
580{
581 while (*str)
582 {
583 const char c = *str;
584 if (!(c == ' ' || c == '\t'))
585 {
586 break;
587 }
588 ++str;
589 }
590 return str;
591}
592
593/*
594 * like buf_null_terminate, but operate on strings
595 */
596void
598{
600 if (len < capacity)
601 {
602 *(str + len) = '\0';
603 }
604 else if (len == capacity)
605 {
606 *(str + len - 1) = '\0';
607 }
608}
609
610/*
611 * Remove trailing \r and \n chars.
612 */
613void
614chomp(char *str)
615{
616 rm_trailing_chars(str, "\r\n");
617}
618
619/*
620 * Remove trailing chars
621 */
622void
624{
625 bool modified;
626 do
627 {
628 const size_t len = strlen(str);
629 modified = false;
630 if (len > 0)
631 {
632 char *cp = str + (len - 1);
633 if (strchr(what_to_delete, *cp) != NULL)
634 {
635 *cp = '\0';
636 modified = true;
637 }
638 }
639 } while (modified);
640}
641
642/*
643 * Allocate a string
644 */
645char *
646#ifdef DMALLOC
647string_alloc_debug(const char *str, struct gc_arena *gc, const char *file, int line)
648#else
649string_alloc(const char *str, struct gc_arena *gc)
650#endif
651{
652 if (str)
653 {
654 const size_t n = strlen(str) + 1;
655 char *ret;
656
657 if (gc)
658 {
659#ifdef DMALLOC
660 ret = (char *) gc_malloc_debug(n, false, gc, file, line);
661#else
662 ret = (char *) gc_malloc(n, false, gc);
663#endif
664 }
665 else
666 {
667 /* If there are no garbage collector available, it's expected
668 * that the caller cleans up afterwards. This is coherent with the
669 * earlier behaviour when gc_malloc() would be called with gc == NULL
670 */
671#ifdef DMALLOC
672 ret = openvpn_dmalloc(file, line, n);
673#else
674 ret = calloc(1, n);
675#endif
677 }
678 memcpy(ret, str, n);
679 return ret;
680 }
681 else
682 {
683 return NULL;
684 }
685}
686
687/*
688 * Erase all characters in a string
689 */
690void
692{
693 if (str)
694 {
696 }
697}
698
699/*
700 * Return the length of a string array
701 */
702int
703string_array_len(const char **array)
704{
705 int i = 0;
706 if (array)
707 {
708 while (array[i])
709 {
710 ++i;
711 }
712 }
713 return i;
714}
715
716char *
717print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
718{
719 struct buffer out = alloc_buf_gc(256, gc);
720 int i = 0;
721 for (;; )
722 {
723 const char *cp = *p++;
724 if (!cp)
725 {
726 break;
727 }
728 if (i)
729 {
730 buf_printf(&out, " ");
731 }
732 if (flags & PA_BRACKET)
733 {
734 buf_printf(&out, "[%s]", cp);
735 }
736 else
737 {
738 buf_printf(&out, "%s", cp);
739 }
740 ++i;
741 }
742 return BSTR(&out);
743}
744
745/*
746 * Allocate a string inside a buffer
747 */
748struct buffer
750string_alloc_buf_debug(const char *str, struct gc_arena *gc, const char *file, int line)
751#else
752string_alloc_buf(const char *str, struct gc_arena *gc)
753#endif
754{
755 struct buffer buf;
756
757 ASSERT(str);
758
759#ifdef DMALLOC
760 buf_set_read(&buf, (uint8_t *) string_alloc_debug(str, gc, file, line), strlen(str) + 1);
761#else
762 buf_set_read(&buf, (uint8_t *) string_alloc(str, gc), strlen(str) + 1);
763#endif
764
765 if (buf.len > 0) /* Don't count trailing '\0' as part of length */
766 {
767 --buf.len;
768 }
769
770 return buf;
771}
772
773/*
774 * String comparison
775 */
776
777bool
778buf_string_match_head_str(const struct buffer *src, const char *match)
779{
780 const size_t size = strlen(match);
781 if (size > src->len)
782 {
783 return false;
784 }
785 return memcmp(BPTR(src), match, size) == 0;
786}
787
788bool
790{
792 {
793 buf_advance(src, (int)strlen(match));
794 return true;
795 }
796 else
797 {
798 return false;
799 }
800}
801
802int
803buf_substring_len(const struct buffer *buf, int delim)
804{
805 int i = 0;
806 struct buffer tmp = *buf;
807 int c;
808
809 while ((c = buf_read_u8(&tmp)) >= 0)
810 {
811 ++i;
812 if (c == delim)
813 {
814 return i;
815 }
816 }
817 return -1;
818}
819
820/*
821 * String parsing
822 */
823
824bool
825buf_parse(struct buffer *buf, const int delim, char *line, const int size)
826{
827 bool eol = false;
828 int n = 0;
829 int c;
830
831 ASSERT(size > 0);
832
833 do
834 {
835 c = buf_read_u8(buf);
836 if (c < 0)
837 {
838 eol = true;
839 }
840 if (c <= 0 || c == delim)
841 {
842 c = 0;
843 }
844 if (n >= size)
845 {
846 break;
847 }
848 line[n++] = (char)c;
849 }
850 while (c);
851
852 line[size-1] = '\0';
853 return !(eol && !strlen(line));
854}
855
856/*
857 * Print a string which might be NULL
858 */
859const char *
860np(const char *str)
861{
862 if (str)
863 {
864 return str;
865 }
866 else
867 {
868 return "[NULL]";
869 }
870}
871
872/*
873 * Classify and mutate strings based on character types.
874 */
875
876bool
877char_class(const unsigned char c, const unsigned int flags)
878{
879 if (!flags)
880 {
881 return false;
882 }
883 if (flags & CC_ANY)
884 {
885 return true;
886 }
887
888 if ((flags & CC_NULL) && c == '\0')
889 {
890 return true;
891 }
892
893 if ((flags & CC_ALNUM) && isalnum(c))
894 {
895 return true;
896 }
897 if ((flags & CC_ALPHA) && isalpha(c))
898 {
899 return true;
900 }
901 if ((flags & CC_ASCII) && isascii(c))
902 {
903 return true;
904 }
905 if ((flags & CC_CNTRL) && iscntrl(c))
906 {
907 return true;
908 }
909 if ((flags & CC_DIGIT) && isdigit(c))
910 {
911 return true;
912 }
913 if ((flags & CC_PRINT) && (c >= 32 && c != 127)) /* allow ascii non-control and UTF-8, consider DEL to be a control */
914 {
915 return true;
916 }
917 if ((flags & CC_PUNCT) && ispunct(c))
918 {
919 return true;
920 }
921 if ((flags & CC_SPACE) && isspace(c))
922 {
923 return true;
924 }
925 if ((flags & CC_XDIGIT) && isxdigit(c))
926 {
927 return true;
928 }
929
930 if ((flags & CC_BLANK) && (c == ' ' || c == '\t'))
931 {
932 return true;
933 }
934 if ((flags & CC_NEWLINE) && c == '\n')
935 {
936 return true;
937 }
938 if ((flags & CC_CR) && c == '\r')
939 {
940 return true;
941 }
942
943 if ((flags & CC_BACKSLASH) && c == '\\')
944 {
945 return true;
946 }
947 if ((flags & CC_UNDERBAR) && c == '_')
948 {
949 return true;
950 }
951 if ((flags & CC_DASH) && c == '-')
952 {
953 return true;
954 }
955 if ((flags & CC_DOT) && c == '.')
956 {
957 return true;
958 }
959 if ((flags & CC_COMMA) && c == ',')
960 {
961 return true;
962 }
963 if ((flags & CC_COLON) && c == ':')
964 {
965 return true;
966 }
967 if ((flags & CC_SLASH) && c == '/')
968 {
969 return true;
970 }
971 if ((flags & CC_SINGLE_QUOTE) && c == '\'')
972 {
973 return true;
974 }
975 if ((flags & CC_DOUBLE_QUOTE) && c == '\"')
976 {
977 return true;
978 }
979 if ((flags & CC_REVERSE_QUOTE) && c == '`')
980 {
981 return true;
982 }
983 if ((flags & CC_AT) && c == '@')
984 {
985 return true;
986 }
987 if ((flags & CC_EQUAL) && c == '=')
988 {
989 return true;
990 }
991 if ((flags & CC_LESS_THAN) && c == '<')
992 {
993 return true;
994 }
995 if ((flags & CC_GREATER_THAN) && c == '>')
996 {
997 return true;
998 }
999 if ((flags & CC_PIPE) && c == '|')
1000 {
1001 return true;
1002 }
1003 if ((flags & CC_QUESTION_MARK) && c == '?')
1004 {
1005 return true;
1006 }
1007 if ((flags & CC_ASTERISK) && c == '*')
1008 {
1009 return true;
1010 }
1011
1012 return false;
1013}
1014
1015static inline bool
1016char_inc_exc(const char c, const unsigned int inclusive, const unsigned int exclusive)
1017{
1018 return char_class(c, inclusive) && !char_class(c, exclusive);
1019}
1020
1021bool
1022string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive)
1023{
1024 char c;
1025 ASSERT(str);
1026 while ((c = *str++))
1027 {
1029 {
1030 return false;
1031 }
1032 }
1033 return true;
1034}
1035
1036/*
1037 * Modify string in place.
1038 * Guaranteed to not increase string length.
1039 */
1040bool
1041string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
1042{
1043 const char *in = str;
1044 bool ret = true;
1045
1046 ASSERT(str);
1047
1048 while (true)
1049 {
1050 char c = *in++;
1051 if (c)
1052 {
1054 {
1055 c = replace;
1056 ret = false;
1057 }
1058 if (c)
1059 {
1060 *str++ = c;
1061 }
1062 }
1063 else
1064 {
1065 *str = '\0';
1066 break;
1067 }
1068 }
1069 return ret;
1070}
1071
1072bool
1073string_check_buf(struct buffer *buf, const unsigned int inclusive, const unsigned int exclusive)
1074{
1075 ASSERT(buf);
1076
1077 for (int i = 0; i < BLEN(buf); i++)
1078 {
1079 char c = BSTR(buf)[i];
1080
1082 {
1083 return false;
1084 }
1085 }
1086 return true;
1087}
1088
1089const char *
1091 const unsigned int inclusive,
1092 const unsigned int exclusive,
1093 const char replace,
1094 struct gc_arena *gc)
1095{
1096 if (str)
1097 {
1098 char *buf = string_alloc(str, gc);
1100 return buf;
1101 }
1102 else
1103 {
1104 return NULL;
1105 }
1106}
1107
1108void
1109string_replace_leading(char *str, const char match, const char replace)
1110{
1111 ASSERT(match != '\0');
1112 while (*str)
1113 {
1114 if (*str == match)
1115 {
1116 *str = replace;
1117 }
1118 else
1119 {
1120 break;
1121 }
1122 ++str;
1123 }
1124}
1125
1126#ifdef VERIFY_ALIGNMENT
1127void
1128valign4(const struct buffer *buf, const char *file, const int line)
1129{
1130 if (buf && buf->len)
1131 {
1132 int msglevel = D_ALIGN_DEBUG;
1133 const unsigned int u = (unsigned int) BPTR(buf);
1134
1135 if (u & (PAYLOAD_ALIGN-1))
1136 {
1137 msglevel = D_ALIGN_ERRORS;
1138 }
1139
1140 msg(msglevel, "%sAlignment at %s/%d ptr=" ptr_format " OLC=%d/%d/%d I=%s/%d",
1141 (msglevel == D_ALIGN_ERRORS) ? "ERROR: " : "",
1142 file,
1143 line,
1144 (ptr_type)buf->data,
1145 buf->offset,
1146 buf->len,
1147 buf->capacity,
1148 buf_debug_file(buf),
1149 buf_debug_line(buf));
1150 }
1151}
1152#endif /* ifdef VERIFY_ALIGNMENT */
1153
1154/*
1155 * struct buffer_list
1156 */
1157struct buffer_list *
1159{
1160 struct buffer_list *ret;
1161 ALLOC_OBJ_CLEAR(ret, struct buffer_list);
1162 ret->size = 0;
1163 return ret;
1164}
1165
1166void
1168{
1169 if (ol)
1170 {
1172 free(ol);
1173 }
1174}
1175
1176bool
1178{
1179 return ol && ol->head != NULL;
1180}
1181
1182void
1184{
1185 struct buffer_entry *e = ol->head;
1186 while (e)
1187 {
1188 struct buffer_entry *next = e->next;
1189 free_buf(&e->buf);
1190 free(e);
1191 e = next;
1192 }
1193 ol->head = ol->tail = NULL;
1194 ol->size = 0;
1195}
1196
1197void
1198buffer_list_push(struct buffer_list *ol, const char *str)
1199{
1200 if (str)
1201 {
1202 const size_t len = strlen((const char *)str);
1203 struct buffer_entry *e = buffer_list_push_data(ol, str, len+1);
1204 if (e)
1205 {
1206 e->buf.len = (int)len; /* Don't count trailing '\0' as part of length */
1207 }
1208 }
1209}
1210
1211struct buffer_entry *
1212buffer_list_push_data(struct buffer_list *ol, const void *data, size_t size)
1213{
1214 struct buffer_entry *e = NULL;
1215 if (data)
1216 {
1217 ALLOC_OBJ_CLEAR(e, struct buffer_entry);
1218
1219 ++ol->size;
1220 if (ol->tail)
1221 {
1222 ASSERT(ol->head);
1223 ol->tail->next = e;
1224 }
1225 else
1226 {
1227 ASSERT(!ol->head);
1228 ol->head = e;
1229 }
1230 e->buf = alloc_buf(size);
1231 memcpy(e->buf.data, data, size);
1232 e->buf.len = (int)size;
1233 ol->tail = e;
1234 }
1235 return e;
1236}
1237
1238struct buffer *
1240{
1241 if (ol && ol->head)
1242 {
1243 return &ol->head->buf;
1244 }
1245 else
1246 {
1247 return NULL;
1248 }
1249}
1250
1251void
1253 const char *sep)
1254{
1255 const size_t sep_len = strlen(sep);
1256 struct buffer_entry *more = bl->head;
1257 size_t size = 0;
1258 int count = 0;
1259 for (count = 0; more; ++count)
1260 {
1261 size_t extra_len = BLEN(&more->buf) + sep_len;
1262 if (size + extra_len > max_len)
1263 {
1264 break;
1265 }
1266
1267 size += extra_len;
1268 more = more->next;
1269 }
1270
1271 if (count >= 2)
1272 {
1273 struct buffer_entry *f;
1274 ALLOC_OBJ_CLEAR(f, struct buffer_entry);
1275 f->buf = alloc_buf(size + 1); /* prevent 0-byte malloc */
1276
1277 struct buffer_entry *e = bl->head;
1278 for (size_t i = 0; e && i < count; ++i)
1279 {
1280 struct buffer_entry *next = e->next;
1281 buf_copy(&f->buf, &e->buf);
1282 buf_write(&f->buf, sep, sep_len);
1283 free_buf(&e->buf);
1284 free(e);
1285 e = next;
1286 }
1287 bl->head = f;
1288 bl->size -= count - 1;
1289 f->next = more;
1290 if (!more)
1291 {
1292 bl->tail = f;
1293 }
1294 }
1295}
1296
1297void
1298buffer_list_aggregate(struct buffer_list *bl, const size_t max)
1299{
1301}
1302
1303void
1305{
1306 if (ol && ol->head)
1307 {
1308 struct buffer_entry *e = ol->head->next;
1309 free_buf(&ol->head->buf);
1310 free(ol->head);
1311 ol->head = e;
1312 --ol->size;
1313 if (!e)
1314 {
1315 ol->tail = NULL;
1316 }
1317 }
1318}
1319
1320void
1322{
1323 if (ol->head)
1324 {
1325 struct buffer *buf = &ol->head->buf;
1326 ASSERT(buf_advance(buf, n));
1327 if (!BLEN(buf))
1328 {
1330 }
1331 }
1332}
1333
1334struct buffer_list *
1335buffer_list_file(const char *fn, int max_line_len)
1336{
1337 FILE *fp = platform_fopen(fn, "r");
1338 struct buffer_list *bl = NULL;
1339
1340 if (fp)
1341 {
1342 char *line = (char *) malloc(max_line_len);
1343 if (line)
1344 {
1345 bl = buffer_list_new();
1346 while (fgets(line, max_line_len, fp) != NULL)
1347 {
1348 buffer_list_push(bl, line);
1349 }
1350 free(line);
1351 }
1352 fclose(fp);
1353 }
1354 return bl;
1355}
1356
1357struct buffer
1359{
1360 struct buffer ret = { 0 };
1361
1362 platform_stat_t file_stat = { 0 };
1363 if (platform_stat(filename, &file_stat) < 0)
1364 {
1365 return ret;
1366 }
1367
1368 FILE *fp = platform_fopen(filename, "r");
1369 if (!fp)
1370 {
1371 return ret;
1372 }
1373
1374 const size_t size = file_stat.st_size;
1375 ret = alloc_buf_gc(size + 1, gc); /* space for trailing \0 */
1376 size_t read_size = fread(BPTR(&ret), 1, size, fp);
1377 if (read_size == 0)
1378 {
1379 free_buf_gc(&ret, gc);
1380 goto cleanup;
1381 }
1382 ASSERT(buf_inc_len(&ret, (int)read_size));
1383 buf_null_terminate(&ret);
1384
1385cleanup:
1386 fclose(fp);
1387 return ret;
1388}
bool buffer_list_defined(const struct buffer_list *ol)
Checks if the list is valid and non-empty.
Definition buffer.c:1177
bool buf_string_compare_advance(struct buffer *src, const char *match)
Definition buffer.c:789
struct buffer_entry * buffer_list_push_data(struct buffer_list *ol, const void *data, size_t size)
Allocates and appends a new buffer containing data of length size.
Definition buffer.c:1212
void rm_trailing_chars(char *str, const char *what_to_delete)
Definition buffer.c:623
void string_null_terminate(char *str, int len, int capacity)
Definition buffer.c:597
void buffer_list_advance(struct buffer_list *ol, int n)
Definition buffer.c:1321
void free_buf(struct buffer *buf)
Definition buffer.c:183
void buffer_list_aggregate_separator(struct buffer_list *bl, const size_t max_len, const char *sep)
Aggregates as many buffers as possible from bl in a new buffer of maximum length max_len .
Definition buffer.c:1252
static bool char_inc_exc(const char c, const unsigned int inclusive, const unsigned int exclusive)
Definition buffer.c:1016
void buf_clear(struct buffer *buf)
Definition buffer.c:162
void buffer_list_reset(struct buffer_list *ol)
Empty the list ol and frees all the contained buffers.
Definition buffer.c:1183
static void free_buf_gc(struct buffer *buf, struct gc_arena *gc)
Definition buffer.c:190
const char * skip_leading_whitespace(const char *str)
Definition buffer.c:579
void buffer_list_aggregate(struct buffer_list *bl, const size_t max)
Aggregates as many buffers as possible from bl in a new buffer of maximum length max_len .
Definition buffer.c:1298
struct buffer clone_buf(const struct buffer *buf)
Definition buffer.c:115
void x_gc_freespecial(struct gc_arena *a)
Definition buffer.c:422
bool buffer_write_file(const char *filename, const struct buffer *buf)
Write buffer contents to file.
Definition buffer.c:300
void buf_catrunc(struct buffer *buf, const char *str)
Definition buffer.c:287
#define buf_debug_file(buf)
Definition buffer.c:157
void buffer_list_pop(struct buffer_list *ol)
Definition buffer.c:1304
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:240
void string_replace_leading(char *str, const char match, const char replace)
Definition buffer.c:1109
bool buf_puts(struct buffer *buf, const char *str)
Definition buffer.c:267
struct buffer_list * buffer_list_file(const char *fn, int max_line_len)
Definition buffer.c:1335
void string_clear(char *str)
Definition buffer.c:691
#define buf_debug_line(buf)
Definition buffer.c:156
void gc_transfer(struct gc_arena *dest, struct gc_arena *src)
Definition buffer.c:460
bool string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive)
Definition buffer.c:1022
char * print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
Definition buffer.c:717
void buf_null_terminate(struct buffer *buf)
Definition buffer.c:533
struct buffer buf_sub(struct buffer *buf, int size, bool prepend)
Definition buffer.c:221
void * gc_realloc(void *ptr, size_t size, struct gc_arena *a)
allows to realloc a pointer previously allocated by gc_malloc or gc_realloc
Definition buffer.c:370
char * format_hex_ex(const uint8_t *data, int size, int maxoutput, unsigned int space_break_flags, const char *separator, struct gc_arena *gc)
Definition buffer.c:483
struct buffer_list * buffer_list_new(void)
Allocate an empty buffer list of capacity max_size.
Definition buffer.c:1158
void chomp(char *str)
Definition buffer.c:614
struct buffer * buffer_list_peek(struct buffer_list *ol)
Retrieve the head buffer.
Definition buffer.c:1239
const char * np(const char *str)
Definition buffer.c:860
bool string_check_buf(struct buffer *buf, const unsigned int inclusive, const unsigned int exclusive)
Check a buffer if it only consists of allowed characters.
Definition buffer.c:1073
size_t array_mult_safe(const size_t m1, const size_t m2, const size_t extra)
Definition buffer.c:41
void buffer_list_free(struct buffer_list *ol)
Frees a buffer list and all the buffers in it.
Definition buffer.c:1167
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition buffer.c:336
bool buf_assign(struct buffer *dest, const struct buffer *src)
Definition buffer.c:173
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:88
bool string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
Modifies a string in place by replacing certain classes of characters of it with a specified characte...
Definition buffer.c:1041
struct buffer alloc_buf(size_t size)
Definition buffer.c:62
const char * string_mod_const(const char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace, struct gc_arena *gc)
Returns a copy of a string with certain classes of characters of it replaced with a specified charact...
Definition buffer.c:1090
void gc_addspecial(void *addr, void(*free_function)(void *), struct gc_arena *a)
Definition buffer.c:438
int string_array_len(const char **array)
Definition buffer.c:703
struct buffer buffer_read_from_file(const char *filename, struct gc_arena *gc)
buffer_read_from_file - copy the content of a file into a buffer
Definition buffer.c:1358
void buf_rmtail(struct buffer *buf, uint8_t remove)
Definition buffer.c:518
bool buf_parse(struct buffer *buf, const int delim, char *line, const int size)
Definition buffer.c:825
void buf_size_error(const size_t size)
Definition buffer.c:53
char * string_alloc(const char *str, struct gc_arena *gc)
Definition buffer.c:649
struct buffer string_alloc_buf(const char *str, struct gc_arena *gc)
Definition buffer.c:752
void buffer_list_push(struct buffer_list *ol, const char *str)
Allocates and appends a new buffer containing str as data to ol.
Definition buffer.c:1198
void x_gc_free(struct gc_arena *a)
Definition buffer.c:403
void buf_chomp(struct buffer *buf)
Definition buffer.c:554
bool char_class(const unsigned char c, const unsigned int flags)
Definition buffer.c:877
bool buf_string_match_head_str(const struct buffer *src, const char *match)
Definition buffer.c:778
int buf_substring_len(const struct buffer *buf, int delim)
Definition buffer.c:803
#define CC_COMMA
comma
Definition buffer.h:904
#define BEND(buf)
Definition buffer.h:125
#define CC_DASH
dash
Definition buffer.h:902
static bool buf_size_valid(const size_t size)
Definition buffer.h:285
#define CC_DOUBLE_QUOTE
double quote
Definition buffer.h:908
#define BLAST(buf)
Definition buffer.h:126
#define CC_BLANK
space or tab
Definition buffer.h:896
static bool buf_init_dowork(struct buffer *buf, int offset)
Definition buffer.h:319
#define CC_PIPE
pipe
Definition buffer.h:914
#define BSTR(buf)
Definition buffer.h:129
static bool buf_copy(struct buffer *dest, const struct buffer *src)
Definition buffer.h:712
#define CC_ANY
any character
Definition buffer.h:883
#define BPTR(buf)
Definition buffer.h:124
#define CC_AT
at sign
Definition buffer.h:910
#define CC_XDIGIT
hex digit isxdigit()
Definition buffer.h:894
#define CC_COLON
colon
Definition buffer.h:905
#define CC_SINGLE_QUOTE
single quote
Definition buffer.h:907
static bool buf_inc_len(struct buffer *buf, int inc)
Definition buffer.h:590
#define CC_DIGIT
digit isdigit()
Definition buffer.h:890
#define PA_BRACKET
Definition buffer.h:144
#define CC_DOT
dot
Definition buffer.h:903
#define CC_CRLF
carriage return or newline
Definition buffer.h:920
static bool buf_safe(const struct buffer *buf, size_t len)
Definition buffer.h:520
#define CC_ASTERISK
asterisk
Definition buffer.h:916
#define CC_ALPHA
alphabetic isalpha()
Definition buffer.h:887
static bool buf_advance(struct buffer *buf, int size)
Definition buffer.h:618
#define CC_NEWLINE
newline
Definition buffer.h:897
static void buf_set_read(struct buffer *buf, const uint8_t *data, size_t size)
Definition buffer.h:348
static int buf_forward_capacity(const struct buffer *buf)
Definition buffer.h:541
static void secure_memzero(void *data, size_t len)
Securely zeroise memory.
Definition buffer.h:414
static uint8_t * buf_write_alloc(struct buffer *buf, size_t size)
Definition buffer.h:635
#define CC_REVERSE_QUOTE
reverse quote
Definition buffer.h:909
#define CC_SPACE
whitespace isspace()
Definition buffer.h:893
#define CC_ASCII
ASCII character.
Definition buffer.h:888
static bool buf_write(struct buffer *dest, const void *src, size_t size)
Definition buffer.h:668
static uint8_t * buf_prepend(struct buffer *buf, int size)
Definition buffer.h:606
#define CC_BACKSLASH
backslash
Definition buffer.h:900
#define CC_CNTRL
control character iscntrl()
Definition buffer.h:889
#define CC_LESS_THAN
less than sign
Definition buffer.h:912
static bool buf_write_u8(struct buffer *dest, uint8_t data)
Definition buffer.h:692
static int buf_read_u8(struct buffer *buf)
Definition buffer.h:790
#define BLEN(buf)
Definition buffer.h:127
#define CC_CR
carriage return
Definition buffer.h:898
#define CC_SLASH
slash
Definition buffer.h:906
#define CC_UNDERBAR
underscore
Definition buffer.h:901
#define CC_GREATER_THAN
greater than sign
Definition buffer.h:913
static void strncpynt(char *dest, const char *src, size_t maxlen)
Definition buffer.h:361
static void check_malloc_return(void *p)
Definition buffer.h:1103
#define CC_NULL
null character \0
Definition buffer.h:884
#define CC_PRINT
printable (>= 32, != 127)
Definition buffer.h:891
#define CC_QUESTION_MARK
question mark
Definition buffer.h:915
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition buffer.h:1060
static bool buf_defined(const struct buffer *buf)
Definition buffer.h:228
#define CC_ALNUM
alphanumeric isalnum()
Definition buffer.h:886
#define buf_init(buf, offset)
Definition buffer.h:209
#define CC_EQUAL
equal sign
Definition buffer.h:911
#define FHE_SPACE_BREAK_MASK
Definition buffer.h:497
#define CC_PUNCT
punctuation ispunct()
Definition buffer.h:892
#define FHE_CAPS
Definition buffer.h:498
static int buf_forward_capacity_total(const struct buffer *buf)
Definition buffer.h:559
unsigned long ptr_type
Definition common.h:58
#define ptr_format
Definition common.h:49
#define D_ALIGN_ERRORS
Definition errlevel.h:70
#define D_ALIGN_DEBUG
Definition errlevel.h:142
@ write
#define PAYLOAD_ALIGN
Definition mtu.h:91
#define CLEAR(x)
Definition basic.h:33
#define M_FATAL
Definition error.h:89
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
#define M_ERRNO
Definition error.h:94
FILE * platform_fopen(const char *path, const char *mode)
Definition platform.c:501
int platform_open(const char *path, int flags, int mode)
Definition platform.c:514
int platform_stat(const char *path, platform_stat_t *buf)
Definition platform.c:527
struct _stat platform_stat_t
Definition platform.h:142
Definition buffer.h:1115
struct buffer_entry * next
Definition buffer.h:1117
struct buffer buf
Definition buffer.h:1116
struct buffer_entry * tail
Definition buffer.h:1123
struct buffer_entry * head
Definition buffer.h:1122
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
int capacity
Size in bytes of memory allocated by malloc().
Definition buffer.h:62
uint8_t * data
Pointer to the allocated memory.
Definition buffer.h:68
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
int offset
Offset in bytes of the actual content within the allocated memory.
Definition buffer.h:64
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
struct gc_entry_special * list_special
Definition buffer.h:120
struct gc_entry * list
First element of the linked list of gc_entry structures.
Definition buffer.h:118
Garbage collection entry for a specially allocated structure that needs a custom free function to be ...
Definition buffer.h:99
void(* free_fnc)(void *)
Definition buffer.h:101
void * addr
Definition buffer.h:102
struct gc_entry_special * next
Definition buffer.h:100
Garbage collection entry for one dynamically allocated block of memory.
Definition buffer.h:88
struct gc_entry * next
Pointer to the next item in the linked list.
Definition buffer.h:89
#define unlikely(x)
Definition syshead.h:36
static int cleanup(void **state)
struct gc_arena gc
Definition test_ssl.c:155