File: buffer.c

package info (click to toggle)
diald 0.16.5-2
  • links: PTS
  • area: main
  • in suites: hamm
  • size: 716 kB
  • ctags: 805
  • sloc: ansic: 5,438; tcl: 510; perl: 479; sh: 284; makefile: 166
file content (132 lines) | stat: -rw-r--r-- 3,525 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * buffer.c - Packet buffering code.
 *
 * Copyright (c) 1994, 1995, 1996 Eric Schenk.
 * All rights reserved. Please see the file LICENSE which should be
 * distributed with this software for terms of use.
 *
 * FIXME: This stuff should probably record the protocol that the
 * packet came in over so that we can use that info when forwarding
 * the packet. (It may not always be coming in over IP!)
 */

#include "diald.h"
#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;

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;
    }
}

static void buffer_check()
{
    if (!buffer) {
	buffer = malloc(buffer_size);
	oldsize = buffer_size;
    }
}


void buffer_packet(unsigned int len,unsigned char *pkt)
{
    unsigned int clen;
    unsigned long stamp;
    unsigned long ctime = timestamp();

    buffer_check();
    if (len+6 > buffer_size) {
	syslog(LOG_ERR,"Can't buffer packet of length %d, buffer to small.",
	    len);
	return;
    }
    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);
	}
    } else {
	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)
		break;
	    head = (head+6+clen)%buffer_size;
	    used -= (6+clen);
	}
    }
    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;
	}
    } else {
	syslog(LOG_ERR,
	    "Can't buffer packet of length %d, only %d bytes available.",
	    len,buffer_size-(used+6));
    }
}

void forward_buffer()
{
    unsigned int clen, i;
    unsigned long stamp;
    unsigned long ctime = timestamp();
    struct SOCKADDR to;
    unsigned char pkt[4096];

    buffer_check();

    memset(&to,0,sizeof(to));
#ifdef HAS_SOCKADDR_PKT
    to.spkt_family = AF_INET;
    strcpy(to.spkt_device,snoop_dev);
    to.spkt_protocol = htons(ETH_P_IP);
#else
    to.sa_family = AF_INET;
    strcpy(to.sa_data,snoop_dev);
#endif

    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) {
	    for (i = 0; i < clen; i++)
		pkt[i] = B(head+6+i);
	    /* Subtle point here: normally we forward packets on the
	     *	"fwdfd" socket pointer. If we do this here, then
	     * the packet we foward will get seen by the filter again.
             * Since we've already seen these packets once, we don't
             * care to see them again. If instead we forward them
             * on the snoopfd (which points to the same device),
             * then we will never get them back on snoopfd.
             */
	    if (sendto(snoopfd,pkt,clen,0,(struct sockaddr *)&to,sizeof(struct SOCKADDR)) < 0) {
		syslog(LOG_ERR,"Error forwarding data packet to physical device from buffer: %m");
	    }
	}
	head = (head+6+clen)%buffer_size;
	used -= (6+clen);
    }
}