300 lines
8.6 KiB
Diff
300 lines
8.6 KiB
Diff
diff -ru diald-1.0.orig/buffer.c diald-1.0/buffer.c
|
|
--- diald-1.0.orig/buffer.c 2001-06-16 15:51:39.000000000 -0400
|
|
+++ diald-1.0/buffer.c 2005-10-04 10:38:22.331362000 -0400
|
|
@@ -3,6 +3,7 @@
|
|
*
|
|
* Copyright (c) 1994, 1995, 1996 Eric Schenk.
|
|
* Copyright (c) 1999 Mike Jagdis.
|
|
+ * Copyright (c) 2002 Jason Turner.
|
|
* All rights reserved. Please see the file LICENSE which should be
|
|
* distributed with this software for terms of use.
|
|
*/
|
|
@@ -11,90 +12,195 @@
|
|
|
|
#include <diald.h>
|
|
|
|
+#define BUFFER_CHUNK_SIZE_MAX 4096
|
|
|
|
-#define B(i) buffer[(i)%buffer_size]
|
|
-
|
|
-static int oldsize = 0;
|
|
-static unsigned char *buffer = 0;
|
|
-static int head = 0;
|
|
-static int used = 0;
|
|
-static int tail = 0;
|
|
+#ifndef UINT_MAX
|
|
+#define UINT_MAX (~0U)
|
|
+#endif
|
|
|
|
-void buffer_init(int *var, char **argv)
|
|
-{
|
|
- buffer_size = atoi(*argv);
|
|
- if (buffer_size != oldsize) {
|
|
- if (buffer)
|
|
- free(buffer);
|
|
- buffer = malloc(buffer_size);
|
|
- oldsize = buffer_size;
|
|
+struct bpkt_hdr { /* Buffered packet header */
|
|
+ unsigned long expires; /* When it expires in uptime secs */
|
|
+ unsigned int len; /* Length of following packet,
|
|
+ * up to BUFFER_CHUNK_SIZE_MAX */
|
|
+};
|
|
+
|
|
+static char *buffer = 0; /* start address of ring buffer */
|
|
+static char *buffer_end = 0; /* end address (+1) of ring buffer */
|
|
+static unsigned int true_size = 0; /* actual size of buffer */
|
|
+static unsigned int used = 0; /* bytes used */
|
|
+static unsigned int head = 0; /* read offset */
|
|
+static unsigned int tail = 0; /* write offset */
|
|
+
|
|
+/* buffer_setup()
|
|
+ * Create/recreate/delete the buffer and setup pointers.
|
|
+ * Returns the actual buffer size.
|
|
+ * The buffer_size variable is declared in diald.h and is given an initial
|
|
+ * value in options.c .
|
|
+ */
|
|
+static unsigned int buffer_setup() {
|
|
+ if ( buffer_size < 0 || buffer_size > UINT_MAX ) {
|
|
+ mon_syslog(LOG_ERR,"Ignoring invalid buffer_size request.");
|
|
+ } else {
|
|
+ /* discard existing buffer and any contents */
|
|
+ if (buffer) {
|
|
+ free(buffer);
|
|
+ buffer = 0;
|
|
+ }
|
|
+ true_size = 0; used = 0; head = 0; tail = 0;
|
|
+ if (buffer_size) {
|
|
+ /* create new buffer */
|
|
+ if (buffer = malloc(buffer_size)) {
|
|
+ true_size = buffer_size;
|
|
+ buffer_end = buffer + true_size;
|
|
+ } else {
|
|
+ mon_syslog(LOG_ERR, "Out of memory! Cannot create ring buffer.");
|
|
+ /* This is not fatal. diald will run fine without the buffer. */
|
|
+ }
|
|
+ }
|
|
}
|
|
+ return true_size;
|
|
}
|
|
|
|
+/* buffer_check()
|
|
+ * If there is no buffer_size param in the config file, the buffer is not
|
|
+ * initially set up!
|
|
+ * So call this from forward_buffer() and buffer_packet()
|
|
+ */
|
|
static void buffer_check()
|
|
{
|
|
- if (!buffer) {
|
|
- buffer = malloc(buffer_size);
|
|
- oldsize = buffer_size;
|
|
+ if (buffer)
|
|
+ return;
|
|
+ if (!buffer_setup()) {
|
|
+ /* if we cannot create a buffer, then disable the feature to avoid
|
|
+ * repeated calls. */
|
|
+ buffer_packets = 0;
|
|
+ mon_syslog(LOG_WARNING,"No buffer: buffer-packets feature disabled.");
|
|
}
|
|
}
|
|
|
|
+/* buffer_write()
|
|
+ * Write data to the ring buffer, adjust tail offset and space used
|
|
+ * Should not be called unless sure there is enough free space
|
|
+ */
|
|
+static void buffer_write(unsigned int count, char *pkt) {
|
|
+ char *write_ptr = buffer + tail;
|
|
+
|
|
+ if (write_ptr + count > buffer_end) {
|
|
+ unsigned int count2end = buffer_end - write_ptr;
|
|
+ memcpy(write_ptr, pkt, count2end);
|
|
+ memcpy(buffer, pkt + count2end, count - count2end);
|
|
+ } else {
|
|
+ memcpy(write_ptr, pkt, count);
|
|
+ }
|
|
+ tail = (tail+count)%true_size;
|
|
+ used += count;
|
|
+}
|
|
|
|
-void buffer_packet(unsigned int len,unsigned char *pkt)
|
|
+/* buffer_read()
|
|
+ * Read bytes from ring buffer. Do not delete.
|
|
+ * Should not be called unless used is positive.
|
|
+ */
|
|
+static void buffer_read(unsigned int count, char *pkt) {
|
|
+ char *read_ptr = buffer + head;
|
|
+
|
|
+ if (read_ptr + count > buffer_end) {
|
|
+ unsigned int count2end = buffer_end - read_ptr;
|
|
+ memcpy(pkt, read_ptr, count2end);
|
|
+ memcpy(pkt + count2end, buffer, count - count2end);
|
|
+ } else {
|
|
+ memcpy(pkt, read_ptr, count);
|
|
+ }
|
|
+}
|
|
+
|
|
+/* buffer_dispose()
|
|
+ * Delete from ring buffer by adjusting read offset
|
|
+ */
|
|
+static void buffer_dispose(unsigned int count) {
|
|
+ head = (head+count)%true_size;
|
|
+ used -= count;
|
|
+}
|
|
+
|
|
+/* externally linked functions */
|
|
+
|
|
+/* buffer_init()
|
|
+ * This is called when reading the config file or command line options.
|
|
+ * There will be at least one argument, but the arg was not checked to be a
|
|
+ * numeric string.
|
|
+ */
|
|
+void buffer_init(int *var, char **argv)
|
|
+{
|
|
+ buffer_size = strtol(*argv, NULL, 0);
|
|
+ if (buffer_size != true_size)
|
|
+ buffer_setup();
|
|
+}
|
|
+
|
|
+/* buffer_packet()
|
|
+ * Place packet into the ring.
|
|
+ */
|
|
+void buffer_packet(unsigned int len, unsigned char *pkt)
|
|
{
|
|
- unsigned int clen;
|
|
- unsigned long stamp;
|
|
+ struct bpkt_hdr pkt_hdr;
|
|
unsigned long ctime = timestamp();
|
|
+ unsigned int space_needed = len + sizeof(struct bpkt_hdr);
|
|
+
|
|
+ if (len > BUFFER_CHUNK_SIZE_MAX) {
|
|
+ mon_syslog(LOG_WARNING, "Packet too large to buffer: %d", len);
|
|
+ return;
|
|
+ }
|
|
|
|
buffer_check();
|
|
- if (len+6 > buffer_size) {
|
|
+
|
|
+ if (space_needed > true_size) {
|
|
mon_syslog(LOG_NOTICE,
|
|
"Can't buffer packet of length %d, buffer too small",
|
|
len);
|
|
return;
|
|
}
|
|
+
|
|
+ /* TODO
|
|
+ * Add buffer filtering ?
|
|
+ * eg. ntp packets do not fare well to long delays
|
|
+ * The expires time could also be different for each packet.
|
|
+ */
|
|
+
|
|
if (buffer_fifo_dispose) {
|
|
/* toss from the front of the buffer till we have space */
|
|
- while (used+len+6 > buffer_size) {
|
|
- clen = (B(head)<<8) | B(head+1);
|
|
- head = (head+6+clen)%buffer_size;
|
|
- used -= (6+clen);
|
|
+ while (used + space_needed > true_size) {
|
|
+ buffer_read(sizeof(struct bpkt_hdr), (char *)&pkt_hdr);
|
|
+ buffer_dispose(sizeof(struct bpkt_hdr) + pkt_hdr.len);
|
|
}
|
|
} else {
|
|
+ /* toss out expired packets from front of buffer
|
|
+ * Any expired packets in the middle will be killed when forwarding
|
|
+ */
|
|
for (;;) {
|
|
- clen = (B(head)<<8) | B(head+1);
|
|
- stamp = (B(head+2)<<24) | (B(head+3)<<16) | (B(head+4)<<8) | B(head+5);
|
|
- if (stamp+buffer_timeout >= ctime)
|
|
+ if (!used)
|
|
+ break;
|
|
+ buffer_read(sizeof(struct bpkt_hdr), (char *)&pkt_hdr);
|
|
+ if (pkt_hdr.expires >= ctime)
|
|
break;
|
|
- head = (head+6+clen)%buffer_size;
|
|
- used -= (6+clen);
|
|
+ buffer_dispose(sizeof(struct bpkt_hdr) + pkt_hdr.len);
|
|
}
|
|
}
|
|
- if (used+len+6 <= buffer_size) {
|
|
- used = used + 6 + len;
|
|
- B(tail) = (len>>8)&0xff;
|
|
- B(tail+1) = len&0xff;
|
|
- B(tail+2) = (ctime>>24)&0xff;
|
|
- B(tail+3) = (ctime>>16)&0xff;
|
|
- B(tail+4) = (ctime>>8)&0xff;
|
|
- B(tail+5) = ctime&0xff;
|
|
- tail = (tail+6)%buffer_size;
|
|
- while (len--) {
|
|
- buffer[tail] = *pkt++;
|
|
- tail = (tail+1)%buffer_size;
|
|
- }
|
|
+ if (used + space_needed <= true_size) {
|
|
+ pkt_hdr.len = len;
|
|
+ pkt_hdr.expires = ctime + buffer_timeout;
|
|
+ buffer_write(sizeof(struct bpkt_hdr), (char *)&pkt_hdr);
|
|
+ buffer_write(len, pkt);
|
|
} else {
|
|
mon_syslog(LOG_NOTICE,
|
|
"Can't buffer packet of length %d, only %d bytes available.",
|
|
- len,buffer_size-(used+6));
|
|
+ len, true_size - ( used + sizeof(struct bpkt_hdr) ) );
|
|
}
|
|
}
|
|
|
|
+/* forward_buffer()
|
|
+ * Clears ring buffer and sends unexpired packets on their way.
|
|
+ */
|
|
void forward_buffer()
|
|
{
|
|
+ struct bpkt_hdr pkt_hdr;
|
|
int forwarding = 0;
|
|
- unsigned int clen, i;
|
|
- unsigned long stamp;
|
|
unsigned long ctime = timestamp();
|
|
struct sockaddr_pkt sp;
|
|
#ifdef HAVE_AF_PACKET
|
|
@@ -102,7 +208,7 @@
|
|
#endif
|
|
struct sockaddr *to;
|
|
size_t to_len;
|
|
- unsigned char pkt[4096];
|
|
+ char pkt[BUFFER_CHUNK_SIZE_MAX];
|
|
|
|
#ifdef __linux__
|
|
/* If we are using dynamic addresses we need to know whether we
|
|
@@ -141,19 +247,19 @@
|
|
}
|
|
|
|
while (used > 0) {
|
|
- clen = (B(head)<<8) | B(head+1);
|
|
- stamp = (B(head+2)<<24) | (B(head+3)<<16) | (B(head+4)<<8) | B(head+5);
|
|
- if (stamp+buffer_timeout >= ctime) {
|
|
+ buffer_read(sizeof(struct bpkt_hdr), (char *)&pkt_hdr);
|
|
+ buffer_dispose(sizeof(struct bpkt_hdr));
|
|
+ if (pkt_hdr.expires >= ctime) {
|
|
unsigned short wprot;
|
|
- unsigned char *dpkt;
|
|
+ char *dpkt;
|
|
unsigned int dlen;
|
|
|
|
- for (i = 0; i < clen; i++)
|
|
- pkt[i] = B(head+6+i);
|
|
+ buffer_read(pkt_hdr.len, pkt);
|
|
|
|
+ /* strip off the protocol from the raw packet */
|
|
wprot = *(unsigned short *)pkt;
|
|
dpkt = pkt + sizeof(unsigned short);
|
|
- dlen = clen - sizeof(unsigned short);
|
|
+ dlen = pkt_hdr.len - sizeof(unsigned short);
|
|
|
|
/* If we are using dynamic addresses and forwarding traffic
|
|
* we send the packet back in to the kernel on the proxy so
|
|
@@ -180,7 +286,6 @@
|
|
mon_syslog(LOG_ERR,"Error forwarding data packet to physical device from buffer: %m");
|
|
}
|
|
}
|
|
- head = (head+6+clen)%buffer_size;
|
|
- used -= (6+clen);
|
|
+ buffer_dispose(pkt_hdr.len);
|
|
}
|
|
}
|