1 /* buffer.c
2 *
3 * Wiretap Library
4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8 #include "config.h"
9 #define WS_LOG_DOMAIN LOG_DOMAIN_WSUTIL
10
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "buffer.h"
15 #include <wsutil/ws_assert.h>
16 #include <wsutil/wslog.h>
17
18 #define SMALL_BUFFER_SIZE (2 * 1024) /* Everyone still uses 1500 byte frames, right? */
19 static GPtrArray *small_buffers = NULL; /* Guaranteed to be at least SMALL_BUFFER_SIZE */
20 /* XXX - Add medium and large buffers? */
21
22 /* Initializes a buffer with a certain amount of allocated space */
23 void
ws_buffer_init(Buffer * buffer,gsize space)24 ws_buffer_init(Buffer* buffer, gsize space)
25 {
26 ws_assert(buffer);
27 if (G_UNLIKELY(!small_buffers)) small_buffers = g_ptr_array_sized_new(1024);
28
29 if (space <= SMALL_BUFFER_SIZE) {
30 if (small_buffers->len > 0) {
31 buffer->data = (guint8*) g_ptr_array_remove_index(small_buffers, small_buffers->len - 1);
32 ws_assert(buffer->data);
33 } else {
34 buffer->data = (guint8*)g_malloc(SMALL_BUFFER_SIZE);
35 }
36 buffer->allocated = SMALL_BUFFER_SIZE;
37 } else {
38 buffer->data = (guint8*)g_malloc(space);
39 buffer->allocated = space;
40 }
41 buffer->start = 0;
42 buffer->first_free = 0;
43 }
44
45 /* Frees the memory used by a buffer */
46 void
ws_buffer_free(Buffer * buffer)47 ws_buffer_free(Buffer* buffer)
48 {
49 ws_assert(buffer);
50 if (buffer->allocated == SMALL_BUFFER_SIZE) {
51 ws_assert(buffer->data);
52 g_ptr_array_add(small_buffers, buffer->data);
53 } else {
54 g_free(buffer->data);
55 }
56 buffer->allocated = 0;
57 buffer->data = NULL;
58 }
59
60 /* Assures that there are 'space' bytes at the end of the used space
61 so that another routine can copy directly into the buffer space. After
62 doing that, the routine will also want to run
63 ws_buffer_increase_length(). */
64 void
ws_buffer_assure_space(Buffer * buffer,gsize space)65 ws_buffer_assure_space(Buffer* buffer, gsize space)
66 {
67 ws_assert(buffer);
68 gsize available_at_end = buffer->allocated - buffer->first_free;
69 gsize space_used;
70 gboolean space_at_beginning;
71
72 /* If we've got the space already, good! */
73 if (space <= available_at_end) {
74 return;
75 }
76
77 /* Maybe we don't have the space available at the end, but we would
78 if we moved the used space back to the beginning of the
79 allocation. The buffer could have become fragmented through lots
80 of calls to ws_buffer_remove_start(). I'm using buffer->start as the
81 same as 'available_at_start' in this comparison. */
82
83 /* or maybe there's just no more room. */
84
85 space_at_beginning = buffer->start >= space;
86 if (space_at_beginning || buffer->start > 0) {
87 space_used = buffer->first_free - buffer->start;
88 /* this memory copy better be safe for overlapping memory regions! */
89 memmove(buffer->data, buffer->data + buffer->start, space_used);
90 buffer->start = 0;
91 buffer->first_free = space_used;
92 }
93 /*if (buffer->start >= space) {*/
94 if (space_at_beginning) {
95 return;
96 }
97
98 /* We'll allocate more space */
99 buffer->allocated += space + 1024;
100 buffer->data = (guint8*)g_realloc(buffer->data, buffer->allocated);
101 }
102
103 void
ws_buffer_append(Buffer * buffer,guint8 * from,gsize bytes)104 ws_buffer_append(Buffer* buffer, guint8 *from, gsize bytes)
105 {
106 ws_assert(buffer);
107 ws_buffer_assure_space(buffer, bytes);
108 memcpy(buffer->data + buffer->first_free, from, bytes);
109 buffer->first_free += bytes;
110 }
111
112 void
ws_buffer_remove_start(Buffer * buffer,gsize bytes)113 ws_buffer_remove_start(Buffer* buffer, gsize bytes)
114 {
115 ws_assert(buffer);
116 if (buffer->start + bytes > buffer->first_free) {
117 ws_error("ws_buffer_remove_start trying to remove %" G_GINT64_MODIFIER "u bytes. s=%" G_GINT64_MODIFIER "u ff=%" G_GINT64_MODIFIER "u!\n",
118 (guint64)bytes, (guint64)buffer->start,
119 (guint64)buffer->first_free);
120 /** ws_error() does an abort() and thus never returns **/
121 }
122 buffer->start += bytes;
123
124 if (buffer->start == buffer->first_free) {
125 buffer->start = 0;
126 buffer->first_free = 0;
127 }
128 }
129
130
131 #ifndef SOME_FUNCTIONS_ARE_DEFINES
132 void
ws_buffer_clean(Buffer * buffer)133 ws_buffer_clean(Buffer* buffer)
134 {
135 ws_assert(buffer);
136 ws_buffer_remove_start(buffer, ws_buffer_length(buffer));
137 }
138 #endif
139
140 #ifndef SOME_FUNCTIONS_ARE_DEFINES
141 void
ws_buffer_increase_length(Buffer * buffer,gsize bytes)142 ws_buffer_increase_length(Buffer* buffer, gsize bytes)
143 {
144 ws_assert(buffer);
145 buffer->first_free += bytes;
146 }
147 #endif
148
149 #ifndef SOME_FUNCTIONS_ARE_DEFINES
150 gsize
ws_buffer_length(Buffer * buffer)151 ws_buffer_length(Buffer* buffer)
152 {
153 ws_assert(buffer);
154 return buffer->first_free - buffer->start;
155 }
156 #endif
157
158 #ifndef SOME_FUNCTIONS_ARE_DEFINES
159 guint8 *
ws_buffer_start_ptr(Buffer * buffer)160 ws_buffer_start_ptr(Buffer* buffer)
161 {
162 ws_assert(buffer);
163 return buffer->data + buffer->start;
164 }
165 #endif
166
167 #ifndef SOME_FUNCTIONS_ARE_DEFINES
168 guint8 *
ws_buffer_end_ptr(Buffer * buffer)169 ws_buffer_end_ptr(Buffer* buffer)
170 {
171 ws_assert(buffer);
172 return buffer->data + buffer->first_free;
173 }
174 #endif
175
176 #ifndef SOME_FUNCTIONS_ARE_DEFINES
177 void
ws_buffer_append_buffer(Buffer * buffer,Buffer * src_buffer)178 ws_buffer_append_buffer(Buffer* buffer, Buffer* src_buffer)
179 {
180 ws_assert(buffer);
181 ws_buffer_append(buffer, ws_buffer_start_ptr(src_buffer), ws_buffer_length(src_buffer));
182 }
183 #endif
184
185 void
ws_buffer_cleanup(void)186 ws_buffer_cleanup(void)
187 {
188 if (small_buffers) {
189 g_ptr_array_set_free_func(small_buffers, g_free);
190 g_ptr_array_free(small_buffers, TRUE);
191 small_buffers = NULL;
192 }
193 }
194
195 /*
196 * Editor modelines - https://www.wireshark.org/tools/modelines.html
197 *
198 * Local variables:
199 * c-basic-offset: 8
200 * tab-width: 8
201 * indent-tabs-mode: t
202 * End:
203 *
204 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
205 * :indentSize=8:tabSize=8:noTabs=false:
206 */
207