File: Pctest.cc

package info (click to toggle)
pchar 1.5-2
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 644 kB
  • ctags: 402
  • sloc: cpp: 6,096; sh: 2,510; makefile: 192
file content (265 lines) | stat: -rw-r--r-- 5,753 bytes parent folder | download | duplicates (5)
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
static char rcsid[] = "$Id: Pctest.cc 1082 2005-02-12 19:40:04Z bmah $";
//
// $Id: Pctest.cc 1082 2005-02-12 19:40:04Z bmah $
//
// Pctest.cc
// Bruce A. Mah <bmah@acm.org>
//
// This work was first produced by an employee of Sandia National
// Laboratories under a contract with the U.S. Department of Energy.
// Sandia National Laboratories dedicates whatever right, title or
// interest it may have in this software to the public. Although no
// license from Sandia is needed to copy and use this software,
// copying and using the software might infringe the rights of
// others. This software is provided as-is. SANDIA DISCLAIMS ANY
// WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
//
// Placeholder for virtual base class of tests.
//

#include <stdio.h>

#ifdef STDC_HEADERS
#include <stdlib.h>
#include <string.h>
#endif /* STDC_HEADERS */

#ifdef HAVE_UNISTD_H
#include <sys/types.h>
#endif /* HAVE_UNISTD_H */

#include <sys/socket.h>
#include <sys/time.h>

#ifdef HAVE_PCAP
#include <pcap.h>
#ifdef __OpenBSD__
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#else
#include <net/ethernet.h>
#endif
#ifdef HAVE_BPF
#include <sys/ioctl.h>
#endif /* HAVE_BPF */
#endif /* HAVE_PCAP */

#include "Pctest.h"

//
// Pctest::Pctest
//
// Pctest constructor
//
Pctest::Pctest()
{
    initialized = 0;
    TimeSyscall(syscallTime);
    
    IF_DEBUG(3, fprintf(stderr, "syscallTime.tv_usec = %ld\n", syscallTime.tv_usec));
    
#ifdef HAVE_PCAP
    // If we're running with pcap enabled, set this up.
    extern bool PcapFlag;
    extern char PcapErrBuf[];
    extern char *Interface;
    extern unsigned int Mtu;
    extern unsigned int Timeout;

    int fileno;

    if (PcapFlag) {
	if (Interface == NULL) {
	    Interface = pcap_lookupdev(PcapErrBuf);
	    if (Interface == NULL) {
		fprintf(stderr, "%s\n", PcapErrBuf);
		exit(1);
	    }
	}

	pc = pcap_open_live(Interface, Mtu, 0, 1000 * Timeout, PcapErrBuf);
	if (pc == NULL) {
	    fprintf(stderr, "%s\n", PcapErrBuf);
	    exit(1);
	}

	if (pcap_lookupnet(Interface, &netp, &maskp, PcapErrBuf) < 0) {
	    fprintf(stderr, "%s\n", PcapErrBuf);
	    exit(1);
	}

	fileno = pcap_fileno(pc);
	if (fileno < 0) {
	    fprintf(stderr, "pcap_fileno() failed\n");
	    exit(1);
	}

#ifdef HAVE_BPF
	// Set "immediate" mode in BPF.  We need this to avoid libpcap
	// waiting the entire timeout period before passing any received
	// packets to us.
	u_int immediate = 1;
	if (ioctl(fileno, BIOCIMMEDIATE, &immediate) < 0) {
	    perror("ioctl(BIOCIMMEDIATE)");
	    exit(1);
	}
#endif /* HAVE_BPF */
    }
#endif /* HAVE_PCAP */
}

//
// Pctest::~Pctest
//
// Pctest destructor
//
Pctest::~Pctest() {
#ifdef HAVE_PCAP
    extern bool PcapFlag;

    if (PcapFlag) {
	if (pc != NULL) {
	    pcap_close(pc);
	}
    }
#endif /* HAVE_PCAP */
}

//
// Pctest::TimeSyscall
//
// Input:  None
//
// Output:  timeval to hold gettimeofday overhead
//
// Determine the gettimeofday() syscall overhead.  Probably this is going
// to be negligible compared to the data we're getting back from the
// network.
//
void Pctest::TimeSyscall(struct timeval &diff)
{
    struct timeval t1, t2;

    gettimeofday(&t1, NULL);
    gettimeofday(&t2, NULL);
    
    diff.tv_sec = t2.tv_sec - t1.tv_sec;
    diff.tv_usec = t2.tv_usec - t1.tv_usec;
    if (diff.tv_usec < 0) {
	diff.tv_usec += 1000000;
	diff.tv_sec--;
    }
    
}

//
// Pctest::GeneratePayload
//
// Input:  Number of bytes to get
//
// Output:  Pointer to payload (owned by caller, NULL if an error)
//
// Generate a random number of bytes in a heap-allocated buffer.
// for use as a payload.  Having random data in the packet will hopefully
// defeat link-level compression.
//
char *Pctest::GeneratePayload(int size)
{
    char *buf;
    int i;

    if (size <= 0) {
	return NULL;
    }

    buf = new char[size];
    if (buf == NULL) {
	return buf;
    }
    for (i = 0; i < size; i++) {
	buf[i] = random() & 0xff;
    }
    return buf;
}

//
// Pctest::InCksum
//
// Input:  addr, len (buffer to checksum)
//
// Output:  IP checksum for this buffer in return value
//
// Compute IP checksum for a buffer.  It's put here because it's fairly
// general-purpose, and both the IPv4 and IPv6 tests could potentially
// make use of it.  RFC 1071 has implementation notes, and we use
// the sample implementation (essentially unmodified) therein.
//
u_short
Pctest::InCksum(u_short *addr, int len)
{
    register int sum = 0;
    u_short checksum;
    
    while (len > 1)  {
	sum += *addr++;
	len -= 2;
    }
    
    // Add left-over byte, if any
    if (len > 0) {
	sum += * (u_char *) addr;
    }
    
    // fold 32-bit sum to 16 bits
    while (sum >> 16) {
	sum = (sum & 0xffff) + (sum >> 16);
    }
    
    checksum = ~sum;
    return(checksum);
}

#ifdef HAVE_PCAP
//
// Pctest::callback
//
// Inputs:  Object pointer, pcap_pkthdr pointer, pointer to packet
// data.
//
// Outputs:  None.
//
// pcap callback routine.
//
// XXX This function needs some work.  It only deals with Ethernet-
// like datalinks.  We need something like what tcpdump's packet-
// printing does.
//
void 
Pctest::callback(u_char *puc, 
		 const struct pcap_pkthdr *ph, 
		 const u_char *pd) {
    
    Pctest *obj = (Pctest *) puc;
    obj->tvAfter.tv_sec = ph->ts.tv_sec;
    obj->tvAfter.tv_usec = ph->ts.tv_usec;
    obj->packetLength = ph->len;
    obj->packet = (u_char *) pd; // we need to compute an offset to this

    switch (pcap_datalink(obj->pc)) {
    case DLT_NULL:
	break;

    case DLT_EN10MB:
	obj->packetLength -= sizeof(struct ether_header);
	obj->packet += sizeof(struct ether_header);
	break;

    default:
	fprintf(stderr, "Unknown datalink layer %d\n", pcap_datalink(obj->pc));
	exit(1);
	break;
    }

}
#endif /* HAVE_PCAP */