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 +#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); } }