1 |
diff -ru diald-1.0.orig/buffer.c diald-1.0/buffer.c |
2 |
--- diald-1.0.orig/buffer.c 2001-06-16 15:51:39.000000000 -0400 |
3 |
+++ diald-1.0/buffer.c 2005-10-04 10:38:22.331362000 -0400 |
4 |
@@ -3,6 +3,7 @@ |
5 |
* |
6 |
* Copyright (c) 1994, 1995, 1996 Eric Schenk. |
7 |
* Copyright (c) 1999 Mike Jagdis. |
8 |
+ * Copyright (c) 2002 Jason Turner. |
9 |
* All rights reserved. Please see the file LICENSE which should be |
10 |
* distributed with this software for terms of use. |
11 |
*/ |
12 |
@@ -11,90 +12,195 @@ |
13 |
|
14 |
#include <diald.h> |
15 |
|
16 |
+#define BUFFER_CHUNK_SIZE_MAX 4096 |
17 |
|
18 |
-#define B(i) buffer[(i)%buffer_size] |
19 |
- |
20 |
-static int oldsize = 0; |
21 |
-static unsigned char *buffer = 0; |
22 |
-static int head = 0; |
23 |
-static int used = 0; |
24 |
-static int tail = 0; |
25 |
+#ifndef UINT_MAX |
26 |
+#define UINT_MAX (~0U) |
27 |
+#endif |
28 |
|
29 |
-void buffer_init(int *var, char **argv) |
30 |
-{ |
31 |
- buffer_size = atoi(*argv); |
32 |
- if (buffer_size != oldsize) { |
33 |
- if (buffer) |
34 |
- free(buffer); |
35 |
- buffer = malloc(buffer_size); |
36 |
- oldsize = buffer_size; |
37 |
+struct bpkt_hdr { /* Buffered packet header */ |
38 |
+ unsigned long expires; /* When it expires in uptime secs */ |
39 |
+ unsigned int len; /* Length of following packet, |
40 |
+ * up to BUFFER_CHUNK_SIZE_MAX */ |
41 |
+}; |
42 |
+ |
43 |
+static char *buffer = 0; /* start address of ring buffer */ |
44 |
+static char *buffer_end = 0; /* end address (+1) of ring buffer */ |
45 |
+static unsigned int true_size = 0; /* actual size of buffer */ |
46 |
+static unsigned int used = 0; /* bytes used */ |
47 |
+static unsigned int head = 0; /* read offset */ |
48 |
+static unsigned int tail = 0; /* write offset */ |
49 |
+ |
50 |
+/* buffer_setup() |
51 |
+ * Create/recreate/delete the buffer and setup pointers. |
52 |
+ * Returns the actual buffer size. |
53 |
+ * The buffer_size variable is declared in diald.h and is given an initial |
54 |
+ * value in options.c . |
55 |
+ */ |
56 |
+static unsigned int buffer_setup() { |
57 |
+ if ( buffer_size < 0 || buffer_size > UINT_MAX ) { |
58 |
+ mon_syslog(LOG_ERR,"Ignoring invalid buffer_size request."); |
59 |
+ } else { |
60 |
+ /* discard existing buffer and any contents */ |
61 |
+ if (buffer) { |
62 |
+ free(buffer); |
63 |
+ buffer = 0; |
64 |
+ } |
65 |
+ true_size = 0; used = 0; head = 0; tail = 0; |
66 |
+ if (buffer_size) { |
67 |
+ /* create new buffer */ |
68 |
+ if (buffer = malloc(buffer_size)) { |
69 |
+ true_size = buffer_size; |
70 |
+ buffer_end = buffer + true_size; |
71 |
+ } else { |
72 |
+ mon_syslog(LOG_ERR, "Out of memory! Cannot create ring buffer."); |
73 |
+ /* This is not fatal. diald will run fine without the buffer. */ |
74 |
+ } |
75 |
+ } |
76 |
} |
77 |
+ return true_size; |
78 |
} |
79 |
|
80 |
+/* buffer_check() |
81 |
+ * If there is no buffer_size param in the config file, the buffer is not |
82 |
+ * initially set up! |
83 |
+ * So call this from forward_buffer() and buffer_packet() |
84 |
+ */ |
85 |
static void buffer_check() |
86 |
{ |
87 |
- if (!buffer) { |
88 |
- buffer = malloc(buffer_size); |
89 |
- oldsize = buffer_size; |
90 |
+ if (buffer) |
91 |
+ return; |
92 |
+ if (!buffer_setup()) { |
93 |
+ /* if we cannot create a buffer, then disable the feature to avoid |
94 |
+ * repeated calls. */ |
95 |
+ buffer_packets = 0; |
96 |
+ mon_syslog(LOG_WARNING,"No buffer: buffer-packets feature disabled."); |
97 |
} |
98 |
} |
99 |
|
100 |
+/* buffer_write() |
101 |
+ * Write data to the ring buffer, adjust tail offset and space used |
102 |
+ * Should not be called unless sure there is enough free space |
103 |
+ */ |
104 |
+static void buffer_write(unsigned int count, char *pkt) { |
105 |
+ char *write_ptr = buffer + tail; |
106 |
+ |
107 |
+ if (write_ptr + count > buffer_end) { |
108 |
+ unsigned int count2end = buffer_end - write_ptr; |
109 |
+ memcpy(write_ptr, pkt, count2end); |
110 |
+ memcpy(buffer, pkt + count2end, count - count2end); |
111 |
+ } else { |
112 |
+ memcpy(write_ptr, pkt, count); |
113 |
+ } |
114 |
+ tail = (tail+count)%true_size; |
115 |
+ used += count; |
116 |
+} |
117 |
|
118 |
-void buffer_packet(unsigned int len,unsigned char *pkt) |
119 |
+/* buffer_read() |
120 |
+ * Read bytes from ring buffer. Do not delete. |
121 |
+ * Should not be called unless used is positive. |
122 |
+ */ |
123 |
+static void buffer_read(unsigned int count, char *pkt) { |
124 |
+ char *read_ptr = buffer + head; |
125 |
+ |
126 |
+ if (read_ptr + count > buffer_end) { |
127 |
+ unsigned int count2end = buffer_end - read_ptr; |
128 |
+ memcpy(pkt, read_ptr, count2end); |
129 |
+ memcpy(pkt + count2end, buffer, count - count2end); |
130 |
+ } else { |
131 |
+ memcpy(pkt, read_ptr, count); |
132 |
+ } |
133 |
+} |
134 |
+ |
135 |
+/* buffer_dispose() |
136 |
+ * Delete from ring buffer by adjusting read offset |
137 |
+ */ |
138 |
+static void buffer_dispose(unsigned int count) { |
139 |
+ head = (head+count)%true_size; |
140 |
+ used -= count; |
141 |
+} |
142 |
+ |
143 |
+/* externally linked functions */ |
144 |
+ |
145 |
+/* buffer_init() |
146 |
+ * This is called when reading the config file or command line options. |
147 |
+ * There will be at least one argument, but the arg was not checked to be a |
148 |
+ * numeric string. |
149 |
+ */ |
150 |
+void buffer_init(int *var, char **argv) |
151 |
+{ |
152 |
+ buffer_size = strtol(*argv, NULL, 0); |
153 |
+ if (buffer_size != true_size) |
154 |
+ buffer_setup(); |
155 |
+} |
156 |
+ |
157 |
+/* buffer_packet() |
158 |
+ * Place packet into the ring. |
159 |
+ */ |
160 |
+void buffer_packet(unsigned int len, unsigned char *pkt) |
161 |
{ |
162 |
- unsigned int clen; |
163 |
- unsigned long stamp; |
164 |
+ struct bpkt_hdr pkt_hdr; |
165 |
unsigned long ctime = timestamp(); |
166 |
+ unsigned int space_needed = len + sizeof(struct bpkt_hdr); |
167 |
+ |
168 |
+ if (len > BUFFER_CHUNK_SIZE_MAX) { |
169 |
+ mon_syslog(LOG_WARNING, "Packet too large to buffer: %d", len); |
170 |
+ return; |
171 |
+ } |
172 |
|
173 |
buffer_check(); |
174 |
- if (len+6 > buffer_size) { |
175 |
+ |
176 |
+ if (space_needed > true_size) { |
177 |
mon_syslog(LOG_NOTICE, |
178 |
"Can't buffer packet of length %d, buffer too small", |
179 |
len); |
180 |
return; |
181 |
} |
182 |
+ |
183 |
+ /* TODO |
184 |
+ * Add buffer filtering ? |
185 |
+ * eg. ntp packets do not fare well to long delays |
186 |
+ * The expires time could also be different for each packet. |
187 |
+ */ |
188 |
+ |
189 |
if (buffer_fifo_dispose) { |
190 |
/* toss from the front of the buffer till we have space */ |
191 |
- while (used+len+6 > buffer_size) { |
192 |
- clen = (B(head)<<8) | B(head+1); |
193 |
- head = (head+6+clen)%buffer_size; |
194 |
- used -= (6+clen); |
195 |
+ while (used + space_needed > true_size) { |
196 |
+ buffer_read(sizeof(struct bpkt_hdr), (char *)&pkt_hdr); |
197 |
+ buffer_dispose(sizeof(struct bpkt_hdr) + pkt_hdr.len); |
198 |
} |
199 |
} else { |
200 |
+ /* toss out expired packets from front of buffer |
201 |
+ * Any expired packets in the middle will be killed when forwarding |
202 |
+ */ |
203 |
for (;;) { |
204 |
- clen = (B(head)<<8) | B(head+1); |
205 |
- stamp = (B(head+2)<<24) | (B(head+3)<<16) | (B(head+4)<<8) | B(head+5); |
206 |
- if (stamp+buffer_timeout >= ctime) |
207 |
+ if (!used) |
208 |
+ break; |
209 |
+ buffer_read(sizeof(struct bpkt_hdr), (char *)&pkt_hdr); |
210 |
+ if (pkt_hdr.expires >= ctime) |
211 |
break; |
212 |
- head = (head+6+clen)%buffer_size; |
213 |
- used -= (6+clen); |
214 |
+ buffer_dispose(sizeof(struct bpkt_hdr) + pkt_hdr.len); |
215 |
} |
216 |
} |
217 |
- if (used+len+6 <= buffer_size) { |
218 |
- used = used + 6 + len; |
219 |
- B(tail) = (len>>8)&0xff; |
220 |
- B(tail+1) = len&0xff; |
221 |
- B(tail+2) = (ctime>>24)&0xff; |
222 |
- B(tail+3) = (ctime>>16)&0xff; |
223 |
- B(tail+4) = (ctime>>8)&0xff; |
224 |
- B(tail+5) = ctime&0xff; |
225 |
- tail = (tail+6)%buffer_size; |
226 |
- while (len--) { |
227 |
- buffer[tail] = *pkt++; |
228 |
- tail = (tail+1)%buffer_size; |
229 |
- } |
230 |
+ if (used + space_needed <= true_size) { |
231 |
+ pkt_hdr.len = len; |
232 |
+ pkt_hdr.expires = ctime + buffer_timeout; |
233 |
+ buffer_write(sizeof(struct bpkt_hdr), (char *)&pkt_hdr); |
234 |
+ buffer_write(len, pkt); |
235 |
} else { |
236 |
mon_syslog(LOG_NOTICE, |
237 |
"Can't buffer packet of length %d, only %d bytes available.", |
238 |
- len,buffer_size-(used+6)); |
239 |
+ len, true_size - ( used + sizeof(struct bpkt_hdr) ) ); |
240 |
} |
241 |
} |
242 |
|
243 |
+/* forward_buffer() |
244 |
+ * Clears ring buffer and sends unexpired packets on their way. |
245 |
+ */ |
246 |
void forward_buffer() |
247 |
{ |
248 |
+ struct bpkt_hdr pkt_hdr; |
249 |
int forwarding = 0; |
250 |
- unsigned int clen, i; |
251 |
- unsigned long stamp; |
252 |
unsigned long ctime = timestamp(); |
253 |
struct sockaddr_pkt sp; |
254 |
#ifdef HAVE_AF_PACKET |
255 |
@@ -102,7 +208,7 @@ |
256 |
#endif |
257 |
struct sockaddr *to; |
258 |
size_t to_len; |
259 |
- unsigned char pkt[4096]; |
260 |
+ char pkt[BUFFER_CHUNK_SIZE_MAX]; |
261 |
|
262 |
#ifdef __linux__ |
263 |
/* If we are using dynamic addresses we need to know whether we |
264 |
@@ -141,19 +247,19 @@ |
265 |
} |
266 |
|
267 |
while (used > 0) { |
268 |
- clen = (B(head)<<8) | B(head+1); |
269 |
- stamp = (B(head+2)<<24) | (B(head+3)<<16) | (B(head+4)<<8) | B(head+5); |
270 |
- if (stamp+buffer_timeout >= ctime) { |
271 |
+ buffer_read(sizeof(struct bpkt_hdr), (char *)&pkt_hdr); |
272 |
+ buffer_dispose(sizeof(struct bpkt_hdr)); |
273 |
+ if (pkt_hdr.expires >= ctime) { |
274 |
unsigned short wprot; |
275 |
- unsigned char *dpkt; |
276 |
+ char *dpkt; |
277 |
unsigned int dlen; |
278 |
|
279 |
- for (i = 0; i < clen; i++) |
280 |
- pkt[i] = B(head+6+i); |
281 |
+ buffer_read(pkt_hdr.len, pkt); |
282 |
|
283 |
+ /* strip off the protocol from the raw packet */ |
284 |
wprot = *(unsigned short *)pkt; |
285 |
dpkt = pkt + sizeof(unsigned short); |
286 |
- dlen = clen - sizeof(unsigned short); |
287 |
+ dlen = pkt_hdr.len - sizeof(unsigned short); |
288 |
|
289 |
/* If we are using dynamic addresses and forwarding traffic |
290 |
* we send the packet back in to the kernel on the proxy so |
291 |
@@ -180,7 +286,6 @@ |
292 |
mon_syslog(LOG_ERR,"Error forwarding data packet to physical device from buffer: %m"); |
293 |
} |
294 |
} |
295 |
- head = (head+6+clen)%buffer_size; |
296 |
- used -= (6+clen); |
297 |
+ buffer_dispose(pkt_hdr.len); |
298 |
} |
299 |
} |