Revision 0d62c4cf

b/slirp/debug.c
9 9
#include <slirp.h>
10 10

  
11 11
FILE *dfd = NULL;
12
#ifdef DEBUG
13
int dostats = 1;
14
#else
15
int dostats = 0;
16
#endif
17 12
int slirp_debug = 0;
18 13

  
19
/* Carry over one item from main.c so that the tty's restored.
20
 * Only done when the tty being used is /dev/tty --RedWolf */
21
#ifndef CONFIG_QEMU
22
extern struct termios slirp_tty_settings;
23
extern int slirp_tty_restore;
24

  
25

  
26
void
27
debug_init(file, dbg)
28
	char *file;
29
	int dbg;
30
{
31
	/* Close the old debugging file */
32
	if (dfd)
33
	   fclose(dfd);
34

  
35
	dfd = fopen(file,"w");
36
	if (dfd != NULL) {
37
#if 0
38
		fprintf(dfd,"Slirp %s - Debugging Started.\n", SLIRP_VERSION);
39
#endif
40
		fprintf(dfd,"Debugging Started level %i.\r\n",dbg);
41
		fflush(dfd);
42
		slirp_debug = dbg;
43
	} else {
44
		lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n",
45
			file, strerror(errno));
46
	}
47
}
48

  
49
/*
50
 * Dump a packet in the same format as tcpdump -x
51
 */
52
#ifdef DEBUG
53
void
54
dump_packet(dat, n)
55
	void *dat;
56
	int n;
57
{
58
	u_char *pptr = (u_char *)dat;
59
	int j,k;
60

  
61
	n /= 16;
62
	n++;
63
	DEBUG_MISC((dfd, "PACKET DUMPED: \n"));
64
	for(j = 0; j < n; j++) {
65
		for(k = 0; k < 6; k++)
66
			DEBUG_MISC((dfd, "%02x ", *pptr++));
67
		DEBUG_MISC((dfd, "\n"));
68
		fflush(dfd);
69
	}
70
}
71
#endif
72
#endif
73

  
74 14
#ifdef LOG_ENABLED
75
#if 0
76
/*
77
 * Statistic routines
78
 *
79
 * These will print statistics to the screen, the debug file (dfd), or
80
 * a buffer, depending on "type", so that the stats can be sent over
81
 * the link as well.
82
 */
83

  
84
static void
85
ttystats(ttyp)
86
	struct ttys *ttyp;
87
{
88
	struct slirp_ifstats *is = &ttyp->ifstats;
89
	char buff[512];
90

  
91
	lprint(" \r\n");
92

  
93
	if (IF_COMP & IF_COMPRESS)
94
	   strcpy(buff, "on");
95
	else if (IF_COMP & IF_NOCOMPRESS)
96
	   strcpy(buff, "off");
97
	else
98
	   strcpy(buff, "off (for now)");
99
	lprint("Unit %d:\r\n", ttyp->unit);
100
	lprint("  using %s encapsulation (VJ compression is %s)\r\n", (
101
#ifdef USE_PPP
102
	       ttyp->proto==PROTO_PPP?"PPP":
103
#endif
104
	       "SLIP"), buff);
105
	lprint("  %d baudrate\r\n", ttyp->baud);
106
	lprint("  interface is %s\r\n", ttyp->up?"up":"down");
107
	lprint("  using fd %d, guardian pid is %d\r\n", ttyp->fd, ttyp->pid);
108
#ifndef FULL_BOLT
109
	lprint("  towrite is %d bytes\r\n", ttyp->towrite);
110
#endif
111
	if (ttyp->zeros)
112
	   lprint("  %d zeros have been typed\r\n", ttyp->zeros);
113
	else if (ttyp->ones)
114
	   lprint("  %d ones have been typed\r\n", ttyp->ones);
115
	lprint("Interface stats:\r\n");
116
	lprint("  %6d output packets sent (%d bytes)\r\n", is->out_pkts, is->out_bytes);
117
	lprint("  %6d output packets dropped (%d bytes)\r\n", is->out_errpkts, is->out_errbytes);
118
	lprint("  %6d input packets received (%d bytes)\r\n", is->in_pkts, is->in_bytes);
119
	lprint("  %6d input packets dropped (%d bytes)\r\n", is->in_errpkts, is->in_errbytes);
120
	lprint("  %6d bad input packets\r\n", is->in_mbad);
121
}
122

  
123
static void
124
allttystats(void)
125
{
126
	struct ttys *ttyp;
127

  
128
	for (ttyp = ttys; ttyp; ttyp = ttyp->next)
129
	   ttystats(ttyp);
130
}
131
#endif
132

  
133 15
static void
134 16
ipstats(void)
135 17
{
......
154 36
	lprint("  %6d total packets delivered\r\n", ipstat.ips_delivered);
155 37
}
156 38

  
157
#ifndef CONFIG_QEMU
158
static void
159
vjstats(void)
160
{
161
	lprint(" \r\n");
162

  
163
	lprint("VJ compression stats:\r\n");
164

  
165
	lprint("  %6d outbound packets (%d compressed)\r\n",
166
	       comp_s.sls_packets, comp_s.sls_compressed);
167
	lprint("  %6d searches for connection stats (%d misses)\r\n",
168
	       comp_s.sls_searches, comp_s.sls_misses);
169
	lprint("  %6d inbound uncompressed packets\r\n", comp_s.sls_uncompressedin);
170
	lprint("  %6d inbound compressed packets\r\n", comp_s.sls_compressedin);
171
	lprint("  %6d inbound unknown type packets\r\n", comp_s.sls_errorin);
172
	lprint("  %6d inbound packets tossed due to error\r\n", comp_s.sls_tossed);
173
}
174
#endif
175

  
176 39
static void
177 40
tcpstats(void)
178 41
{
......
234 97
	lprint("  %6d correct ACK header predictions\r\n", tcpstat.tcps_predack);
235 98
	lprint("  %6d correct data packet header predictions\n", tcpstat.tcps_preddat);
236 99
	lprint("  %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss);
237

  
238

  
239
/*	lprint("    Packets received too short:		%d\r\n", tcpstat.tcps_rcvshort); */
240
/*	lprint("    Segments dropped due to PAWS:	%d\r\n", tcpstat.tcps_pawsdrop); */
241

  
242 100
}
243 101

  
244 102
static void
......
293 151
}
294 152
#endif
295 153

  
296
#ifndef CONFIG_QEMU
297
void
298
slirp_exit(exit_status)
299
	int exit_status;
300
{
301
	struct ttys *ttyp;
302

  
303
	DEBUG_CALL("slirp_exit");
304
	DEBUG_ARG("exit_status = %d", exit_status);
305

  
306
	if (dostats) {
307
		lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf;
308
		if (!dfd)
309
		   debug_init("slirp_stats", 0xf);
310
		lprint_arg = (char **)&dfd;
311

  
312
		ipstats();
313
		tcpstats();
314
		udpstats();
315
		icmpstats();
316
		mbufstats();
317
		sockstats();
318
		allttystats();
319
		vjstats();
320
	}
321

  
322
	for (ttyp = ttys; ttyp; ttyp = ttyp->next)
323
	   tty_detached(ttyp, 1);
324

  
325
	if (slirp_forked) {
326
		/* Menendez time */
327
		if (kill(getppid(), SIGQUIT) < 0)
328
			lprint("Couldn't kill parent process %ld!\n",
329
			    (long) getppid());
330
    	}
331

  
332
	/* Restore the terminal if we gotta */
333
	if(slirp_tty_restore)
334
	  tcsetattr(0,TCSANOW, &slirp_tty_settings);  /* NOW DAMMIT! */
335
	exit(exit_status);
336
}
337
#endif
338

  
339 154
void
340 155
slirp_stats(void)
341 156
{
b/slirp/debug.h
9 9
#define PRN_SPRINTF	2
10 10

  
11 11
extern FILE *dfd;
12
extern FILE *lfd;
13
extern int dostats;
14 12
extern int slirp_debug;
15 13

  
16 14
#define DBG_CALL 0x1
b/slirp/if.c
36 36
{
37 37
	if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq;
38 38
	if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq;
39
        //	sl_compress_init(&comp_s);
40 39
	next_m = &if_batchq;
41 40
}
42 41

  
43
#if 0
44
/*
45
 * This shouldn't be needed since the modem is blocking and
46
 * we don't expect any signals, but what the hell..
47
 */
48
inline int
49
writen(fd, bptr, n)
50
	int fd;
51
	char *bptr;
52
	int n;
53
{
54
	int ret;
55
	int total;
56

  
57
	/* This should succeed most of the time */
58
	ret = send(fd, bptr, n,0);
59
	if (ret == n || ret <= 0)
60
	   return ret;
61

  
62
	/* Didn't write everything, go into the loop */
63
	total = ret;
64
	while (n > total) {
65
		ret = send(fd, bptr+total, n-total,0);
66
		if (ret <= 0)
67
		   return ret;
68
		total += ret;
69
	}
70
	return total;
71
}
72

  
73
/*
74
 * if_input - read() the tty, do "top level" processing (ie: check for any escapes),
75
 * and pass onto (*ttyp->if_input)
76
 *
77
 * XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet.
78
 */
79
#define INBUFF_SIZE 2048 /* XXX */
80
void
81
if_input(ttyp)
82
	struct ttys *ttyp;
83
{
84
	u_char if_inbuff[INBUFF_SIZE];
85
	int if_n;
86

  
87
	DEBUG_CALL("if_input");
88
	DEBUG_ARG("ttyp = %lx", (long)ttyp);
89

  
90
	if_n = recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE,0);
91

  
92
	DEBUG_MISC((dfd, " read %d bytes\n", if_n));
93

  
94
	if (if_n <= 0) {
95
		if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) {
96
			if (ttyp->up)
97
			   link_up--;
98
			tty_detached(ttyp, 0);
99
		}
100
		return;
101
	}
102
	if (if_n == 1) {
103
		if (*if_inbuff == '0') {
104
			ttyp->ones = 0;
105
			if (++ttyp->zeros >= 5)
106
			   slirp_exit(0);
107
			return;
108
		}
109
		if (*if_inbuff == '1') {
110
			ttyp->zeros = 0;
111
			if (++ttyp->ones >= 5)
112
			   tty_detached(ttyp, 0);
113
			return;
114
		}
115
	}
116
	ttyp->ones = ttyp->zeros = 0;
117

  
118
	(*ttyp->if_input)(ttyp, if_inbuff, if_n);
119
}
120
#endif
121

  
122 42
/*
123 43
 * if_output: Queue packet into an output queue.
124 44
 * There are 2 output queue's, if_fastq and if_batchq.
b/slirp/if.h
17 17
#define IF_MRU 1500
18 18
#define	IF_COMP IF_AUTOCOMP	/* Flags for compression */
19 19

  
20
#if 0
21
/*
22
 * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP,
23
 * and 8 bytes for PPP, but need to have it on an 8byte boundary
24
 */
25
#ifdef USE_PPP
26
#define IF_MAXLINKHDR 48
27
#else
28
#define IF_MAXLINKHDR 40
29
#endif
30
#else
31
        /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
20
/* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
32 21
#define IF_MAXLINKHDR (2 + 14 + 40)
33
#endif
34 22

  
35 23
extern int	if_queued;	/* Number of packets queued so far */
36 24

  
b/slirp/ip_icmp.c
73 73
  register struct icmp *icp;
74 74
  register struct ip *ip=mtod(m, struct ip *);
75 75
  int icmplen=ip->ip_len;
76
  /* int code; */
77 76

  
78 77
  DEBUG_CALL("icmp_input");
79 78
  DEBUG_ARG("m = %lx", (long )m);
......
102 101
  m->m_len += hlen;
103 102
  m->m_data -= hlen;
104 103

  
105
  /*	icmpstat.icps_inhist[icp->icmp_type]++; */
106
  /* code = icp->icmp_code; */
107

  
108 104
  DEBUG_ARG("icmp_type = %d", icp->icmp_type);
109 105
  switch (icp->icmp_type) {
110 106
  case ICMP_ECHO:
b/slirp/ip_input.c
165 165
	}
166 166

  
167 167
	/*
168
	 * Process options and, if not destined for us,
169
	 * ship it on.  ip_dooptions returns 1 when an
170
	 * error was detected (causing an icmp message
171
	 * to be sent and the original packet to be freed).
172
	 */
173
/* We do no IP options */
174
/*	if (hlen > sizeof (struct ip) && ip_dooptions(m))
175
 *		goto next;
176
 */
177
	/*
178 168
	 * If offset or IP_MF are set, must reassemble.
179 169
	 * Otherwise, nothing need be done.
180 170
	 * (We could look in the reassembly queue to see
......
396 386
	  q = (struct ipasfrag *)(m->m_ext + delta);
397 387
	}
398 388

  
399
	/* DEBUG_ARG("ip = %lx", (long)ip);
400
	 * ip=(struct ipasfrag *)m->m_data; */
401

  
402 389
    ip = fragtoip(q);
403 390
	ip->ip_len = next;
404 391
	ip->ip_tos &= ~1;
......
505 492
	register u_char *cp;
506 493
	register struct ip_timestamp *ipt;
507 494
	register struct in_ifaddr *ia;
508
/*	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; */
509 495
	int opt, optlen, cnt, off, code, type, forward = 0;
510 496
	struct in_addr *sin, dst;
511 497
typedef u_int32_t n_time;
......
683 669
	}
684 670
	return (0);
685 671
bad:
686
	/* ip->ip_len -= ip->ip_hl << 2;   XXX icmp_error adds in hdr length */
687

  
688
/* Not yet */
689 672
 	icmp_error(m, type, code, 0, 0);
690 673

  
691 674
	STAT(ipstat.ips_badoptions++);
b/slirp/ip_output.c
64 64
	DEBUG_ARG("so = %lx", (long)so);
65 65
	DEBUG_ARG("m0 = %lx", (long)m0);
66 66

  
67
	/* We do no options */
68
/*	if (opt) {
69
 *		m = ip_insertoptions(m, opt, &len);
70
 *		hlen = len;
71
 *	}
72
 */
73 67
	ip = mtod(m, struct ip *);
74 68
	/*
75 69
	 * Fill in IP header.
......
81 75
	STAT(ipstat.ips_localout++);
82 76

  
83 77
	/*
84
	 * Verify that we have any chance at all of being able to queue
85
	 *      the packet or packet fragments
86
	 */
87
	/* XXX Hmmm... */
88
/*	if (if_queued > IF_THRESH && towrite <= 0) {
89
 *		error = ENOBUFS;
90
 *		goto bad;
91
 *	}
92
 */
93

  
94
	/*
95 78
	 * If small enough for interface, can just send directly.
96 79
	 */
97 80
	if ((u_int16_t)ip->ip_len <= IF_MTU) {
......
142 125
	  mhip = mtod(m, struct ip *);
143 126
	  *mhip = *ip;
144 127

  
145
		/* No options */
146
/*		if (hlen > sizeof (struct ip)) {
147
 *			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
148
 *			mhip->ip_hl = mhlen >> 2;
149
 *		}
150
 */
151 128
	  m->m_len = mhlen;
152 129
	  mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
153 130
	  if (ip->ip_off & IP_MF)
b/slirp/libslirp.h
1 1
#ifndef _LIBSLIRP_H
2 2
#define _LIBSLIRP_H
3 3

  
4
#ifdef __cplusplus
5
extern "C" {
6
#endif
7

  
8 4
#include <qemu-common.h>
9 5

  
10 6
void slirp_init(int restricted, struct in_addr vnetwork,
......
37 33
                       const uint8_t *buf, int size);
38 34
size_t slirp_socket_can_recv(struct in_addr guest_addr, int guest_port);
39 35

  
40
#ifdef __cplusplus
41
}
42
#endif
43

  
44 36
#endif
b/slirp/mbuf.c
141 141
        if (m->m_flags & M_EXT) {
142 142
	  datasize = m->m_data - m->m_ext;
143 143
	  m->m_ext = (char *)realloc(m->m_ext,size);
144
/*		if (m->m_ext == NULL)
145
 *			return (struct mbuf *)NULL;
146
 */
147 144
	  m->m_data = m->m_ext + datasize;
148 145
        } else {
149 146
	  char *dat;
150 147
	  datasize = m->m_data - m->m_dat;
151 148
	  dat = (char *)malloc(size);
152
/*		if (dat == NULL)
153
 *			return (struct mbuf *)NULL;
154
 */
155 149
	  memcpy(dat, m->m_dat, m->m_size);
156 150

  
157 151
	  m->m_ext = dat;
b/slirp/mbuf.h
41 41
/*
42 42
 * Macros for type conversion
43 43
 * mtod(m,t) -	convert mbuf pointer to data pointer of correct type
44
 * dtom(x) -	convert data pointer within mbuf to mbuf pointer (XXX)
45 44
 */
46 45
#define mtod(m,t)	((t)(m)->m_data)
47
/* #define	dtom(x)		((struct mbuf *)((int)(x) & ~(M_SIZE-1))) */
48 46

  
49 47
/* XXX About mbufs for slirp:
50 48
 * Only one mbuf is ever used in a chain, for each "cell" of data.
b/slirp/misc.c
12 12

  
13 13
u_int curtime, time_fasttimo, last_slowtimo;
14 14

  
15
#if 0
16
int x_port = -1;
17
int x_display = 0;
18
int x_screen = 0;
19

  
20
int
21
show_x(buff, inso)
22
	char *buff;
23
	struct socket *inso;
24
{
25
	if (x_port < 0) {
26
		lprint("X Redir: X not being redirected.\r\n");
27
	} else {
28
		lprint("X Redir: In sh/bash/zsh/etc. type: DISPLAY=%s:%d.%d; export DISPLAY\r\n",
29
		      inet_ntoa(our_addr), x_port, x_screen);
30
		lprint("X Redir: In csh/tcsh/etc. type:    setenv DISPLAY %s:%d.%d\r\n",
31
		      inet_ntoa(our_addr), x_port, x_screen);
32
		if (x_display)
33
		   lprint("X Redir: Redirecting to display %d\r\n", x_display);
34
	}
35

  
36
	return CFG_OK;
37
}
38

  
39

  
40
/*
41
 * XXX Allow more than one X redirection?
42
 */
43
void
44
redir_x(inaddr, start_port, display, screen)
45
	u_int32_t inaddr;
46
	int start_port;
47
	int display;
48
	int screen;
49
{
50
	int i;
51

  
52
	if (x_port >= 0) {
53
		lprint("X Redir: X already being redirected.\r\n");
54
		show_x(0, 0);
55
	} else {
56
		for (i = 6001 + (start_port-1); i <= 6100; i++) {
57
			if (solisten(htons(i), inaddr, htons(6000 + display), 0)) {
58
				/* Success */
59
				x_port = i - 6000;
60
				x_display = display;
61
				x_screen = screen;
62
				show_x(0, 0);
63
				return;
64
			}
65
		}
66
		lprint("X Redir: Error: Couldn't redirect a port for X. Weird.\r\n");
67
	}
68
}
69
#endif
70

  
71 15
/*
72 16
 * Get our IP address and put it in our_addr
73 17
 */
......
109 53
  ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
110 54
  ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
111 55
  element->qh_rlink = NULL;
112
  /*  element->qh_link = NULL;  TCP FIN1 crashes if you do this.  Why ? */
113 56
}
114 57

  
115
/* #endif */
116

  
117

  
118 58
int add_exec(struct ex_list **ex_ptr, int do_pty, char *exec,
119 59
             struct in_addr addr, int port)
120 60
{
......
170 110

  
171 111
#else
172 112

  
173
#ifndef CONFIG_QEMU
174
int
175
slirp_openpty(amaster, aslave)
176
     int *amaster, *aslave;
177
{
178
	register int master, slave;
179

  
180
#ifdef HAVE_GRANTPT
181
	char *ptr;
182

  
183
	if ((master = open("/dev/ptmx", O_RDWR)) < 0 ||
184
	    grantpt(master) < 0 ||
185
	    unlockpt(master) < 0 ||
186
	    (ptr = ptsname(master)) == NULL)  {
187
		close(master);
188
		return -1;
189
	}
190

  
191
	if ((slave = open(ptr, O_RDWR)) < 0 ||
192
	    ioctl(slave, I_PUSH, "ptem") < 0 ||
193
	    ioctl(slave, I_PUSH, "ldterm") < 0 ||
194
	    ioctl(slave, I_PUSH, "ttcompat") < 0) {
195
		close(master);
196
		close(slave);
197
		return -1;
198
	}
199

  
200
	*amaster = master;
201
	*aslave = slave;
202
	return 0;
203

  
204
#else
205

  
206
	static char line[] = "/dev/ptyXX";
207
	register const char *cp1, *cp2;
208

  
209
	for (cp1 = "pqrsPQRS"; *cp1; cp1++) {
210
		line[8] = *cp1;
211
		for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) {
212
			line[9] = *cp2;
213
			if ((master = open(line, O_RDWR, 0)) == -1) {
214
				if (errno == ENOENT)
215
				   return (-1);    /* out of ptys */
216
			} else {
217
				line[5] = 't';
218
				/* These will fail */
219
				(void) chown(line, getuid(), 0);
220
				(void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
221
#ifdef HAVE_REVOKE
222
				(void) revoke(line);
223
#endif
224
				if ((slave = open(line, O_RDWR, 0)) != -1) {
225
					*amaster = master;
226
					*aslave = slave;
227
					return 0;
228
				}
229
				(void) close(master);
230
				line[5] = 'p';
231
			}
232
		}
233
	}
234
	errno = ENOENT; /* out of ptys */
235
	return (-1);
236
#endif
237
}
238
#endif
239

  
240 113
/*
241 114
 * XXX This is ugly
242 115
 * We create and bind a socket, then fork off to another
......
257 130
	int opt;
258 131
        int master = -1;
259 132
	const char *argv[256];
260
#if 0
261
	char buff[256];
262
#endif
263 133
	/* don't want to clobber the original */
264 134
	char *bptr;
265 135
	const char *curarg;
......
271 141
	DEBUG_ARG("do_pty = %lx", (long)do_pty);
272 142

  
273 143
	if (do_pty == 2) {
274
#if 0
275
		if (slirp_openpty(&master, &s) == -1) {
276
			lprint("Error: openpty failed: %s\n", strerror(errno));
277
			return 0;
278
		}
279
#else
280 144
                return 0;
281
#endif
282 145
	} else {
283 146
		addr.sin_family = AF_INET;
284 147
		addr.sin_port = 0;
......
324 187
                        } while (ret < 0 && errno == EINTR);
325 188
		}
326 189

  
327
#if 0
328
		if (x_port >= 0) {
329
#ifdef HAVE_SETENV
330
			sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
331
			setenv("DISPLAY", buff, 1);
332
#else
333
			sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
334
			putenv(buff);
335
#endif
336
		}
337
#endif
338 190
		dup2(s, 0);
339 191
		dup2(s, 1);
340 192
		dup2(s, 2);
......
422 274
}
423 275
#endif
424 276

  
425
#if 0
426
void
427
snooze_hup(num)
428
	int num;
429
{
430
	int s, ret;
431
#ifndef NO_UNIX_SOCKETS
432
	struct sockaddr_un sock_un;
433
#endif
434
	struct sockaddr_in sock_in;
435
	char buff[256];
436

  
437
	ret = -1;
438
	if (slirp_socket_passwd) {
439
		s = socket(AF_INET, SOCK_STREAM, 0);
440
		if (s < 0)
441
		   slirp_exit(1);
442
		sock_in.sin_family = AF_INET;
443
		sock_in.sin_addr.s_addr = slirp_socket_addr;
444
		sock_in.sin_port = htons(slirp_socket_port);
445
		if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0)
446
		   slirp_exit(1); /* just exit...*/
447
		sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit);
448
		write(s, buff, strlen(buff)+1);
449
	}
450
#ifndef NO_UNIX_SOCKETS
451
	  else {
452
		s = socket(AF_UNIX, SOCK_STREAM, 0);
453
		if (s < 0)
454
		   slirp_exit(1);
455
		sock_un.sun_family = AF_UNIX;
456
		strcpy(sock_un.sun_path, socket_path);
457
		if (connect(s, (struct sockaddr *)&sock_un,
458
			      sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0)
459
		   slirp_exit(1);
460
		sprintf(buff, "kill none:%d", slirp_socket_unit);
461
		write(s, buff, strlen(buff)+1);
462
	}
463
#endif
464
	slirp_exit(0);
465
}
466

  
467

  
468
void
469
snooze()
470
{
471
	sigset_t s;
472
	int i;
473

  
474
	/* Don't need our data anymore */
475
	/* XXX This makes SunOS barf */
476
/*	brk(0); */
477

  
478
	/* Close all fd's */
479
	for (i = 255; i >= 0; i--)
480
	   close(i);
481

  
482
	signal(SIGQUIT, slirp_exit);
483
	signal(SIGHUP, snooze_hup);
484
	sigemptyset(&s);
485

  
486
	/* Wait for any signal */
487
	sigsuspend(&s);
488

  
489
	/* Just in case ... */
490
	exit(255);
491
}
492

  
493
void
494
relay(s)
495
	int s;
496
{
497
	char buf[8192];
498
	int n;
499
	fd_set readfds;
500
	struct ttys *ttyp;
501

  
502
	/* Don't need our data anymore */
503
	/* XXX This makes SunOS barf */
504
/*	brk(0); */
505

  
506
	signal(SIGQUIT, slirp_exit);
507
	signal(SIGHUP, slirp_exit);
508
        signal(SIGINT, slirp_exit);
509
	signal(SIGTERM, slirp_exit);
510

  
511
	/* Fudge to get term_raw and term_restore to work */
512
	if (NULL == (ttyp = tty_attach (0, slirp_tty))) {
513
         lprint ("Error: tty_attach failed in misc.c:relay()\r\n");
514
         slirp_exit (1);
515
    }
516
	ttyp->fd = 0;
517
	ttyp->flags |= TTY_CTTY;
518
	term_raw(ttyp);
519

  
520
	while (1) {
521
		FD_ZERO(&readfds);
522

  
523
		FD_SET(0, &readfds);
524
		FD_SET(s, &readfds);
525

  
526
		n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0);
527

  
528
		if (n <= 0)
529
		   slirp_exit(0);
530

  
531
		if (FD_ISSET(0, &readfds)) {
532
			n = read(0, buf, 8192);
533
			if (n <= 0)
534
			   slirp_exit(0);
535
			n = writen(s, buf, n);
536
			if (n <= 0)
537
			   slirp_exit(0);
538
		}
539

  
540
		if (FD_ISSET(s, &readfds)) {
541
			n = read(s, buf, 8192);
542
			if (n <= 0)
543
			   slirp_exit(0);
544
			n = writen(0, buf, n);
545
			if (n <= 0)
546
			   slirp_exit(0);
547
		}
548
	}
549

  
550
	/* Just in case.... */
551
	exit(1);
552
}
553
#endif
554

  
555
#ifdef CONFIG_QEMU
556 277
#include "monitor.h"
557 278

  
558 279
void lprint(const char *format, ...)
......
563 284
    monitor_vprintf(cur_mon, format, args);
564 285
    va_end(args);
565 286
}
566
#else
567
int (*lprint_print) _P((void *, const char *, va_list));
568
char *lprint_ptr, *lprint_ptr2, **lprint_arg;
569

  
570
void
571
#ifdef __STDC__
572
lprint(const char *format, ...)
573
#else
574
lprint(va_alist) va_dcl
575
#endif
576
{
577
	va_list args;
578

  
579
#ifdef __STDC__
580
        va_start(args, format);
581
#else
582
        char *format;
583
        va_start(args);
584
        format = va_arg(args, char *);
585
#endif
586
#if 0
587
	/* If we're printing to an sbuf, make sure there's enough room */
588
	/* XXX +100? */
589
	if (lprint_sb) {
590
		if ((lprint_ptr - lprint_sb->sb_wptr) >=
591
		    (lprint_sb->sb_datalen - (strlen(format) + 100))) {
592
			int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data;
593
			int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data;
594
			int deltap = lprint_ptr -         lprint_sb->sb_data;
595

  
596
			lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data,
597
							     lprint_sb->sb_datalen + TCP_SNDSPACE);
598

  
599
			/* Adjust all values */
600
			lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw;
601
			lprint_sb->sb_rptr = lprint_sb->sb_data + deltar;
602
			lprint_ptr =         lprint_sb->sb_data + deltap;
603

  
604
			lprint_sb->sb_datalen += TCP_SNDSPACE;
605
		}
606
	}
607
#endif
608
	if (lprint_print)
609
	   lprint_ptr += (*lprint_print)(*lprint_arg, format, args);
610

  
611
	/* Check if they want output to be logged to file as well */
612
	if (lfd) {
613
		/*
614
		 * Remove \r's
615
		 * otherwise you'll get ^M all over the file
616
		 */
617
		int len = strlen(format);
618
		char *bptr1, *bptr2;
619

  
620
		bptr1 = bptr2 = strdup(format);
621

  
622
		while (len--) {
623
			if (*bptr1 == '\r')
624
			   memcpy(bptr1, bptr1+1, len+1);
625
			else
626
			   bptr1++;
627
		}
628
		vfprintf(lfd, bptr2, args);
629
		free(bptr2);
630
	}
631
	va_end(args);
632
}
633

  
634
void
635
add_emu(buff)
636
	char *buff;
637
{
638
	u_int lport, fport;
639
	u_int8_t tos = 0, emu = 0;
640
	char buff1[256], buff2[256], buff4[128];
641
	char *buff3 = buff4;
642
	struct emu_t *emup;
643
	struct socket *so;
644

  
645
	if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) {
646
		lprint("Error: Bad arguments\r\n");
647
		return;
648
	}
649

  
650
	if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) {
651
		lport = 0;
652
		if (sscanf(buff1, "%d", &fport) != 1) {
653
			lprint("Error: Bad first argument\r\n");
654
			return;
655
		}
656
	}
657

  
658
	if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) {
659
		buff3 = 0;
660
		if (sscanf(buff2, "%256s", buff1) != 1) {
661
			lprint("Error: Bad second argument\r\n");
662
			return;
663
		}
664
	}
665

  
666
	if (buff3) {
667
		if (strcmp(buff3, "lowdelay") == 0)
668
		   tos = IPTOS_LOWDELAY;
669
		else if (strcmp(buff3, "throughput") == 0)
670
		   tos = IPTOS_THROUGHPUT;
671
		else {
672
			lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n");
673
			return;
674
		}
675
	}
676

  
677
	if (strcmp(buff1, "ftp") == 0)
678
	   emu = EMU_FTP;
679
	else if (strcmp(buff1, "irc") == 0)
680
	   emu = EMU_IRC;
681
	else if (strcmp(buff1, "none") == 0)
682
	   emu = EMU_NONE; /* ie: no emulation */
683
	else {
684
		lprint("Error: Unknown service\r\n");
685
		return;
686
	}
687

  
688
	/* First, check that it isn't already emulated */
689
	for (emup = tcpemu; emup; emup = emup->next) {
690
		if (emup->lport == lport && emup->fport == fport) {
691
			lprint("Error: port already emulated\r\n");
692
			return;
693
		}
694
	}
695

  
696
	/* link it */
697
	emup = (struct emu_t *)malloc(sizeof (struct emu_t));
698
	emup->lport = (u_int16_t)lport;
699
	emup->fport = (u_int16_t)fport;
700
	emup->tos = tos;
701
	emup->emu = emu;
702
	emup->next = tcpemu;
703
	tcpemu = emup;
704

  
705
	/* And finally, mark all current sessions, if any, as being emulated */
706
	for (so = tcb.so_next; so != &tcb; so = so->so_next) {
707
		if ((lport && lport == ntohs(so->so_lport)) ||
708
		    (fport && fport == ntohs(so->so_fport))) {
709
			if (emu)
710
			   so->so_emu = emu;
711
			if (tos)
712
			   so->so_iptos = tos;
713
		}
714
	}
715

  
716
	lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport);
717
}
718
#endif
719 287

  
720 288
#ifdef BAD_SPRINTF
721 289

  
......
817 385
#endif
818 386
}
819 387

  
820

  
821
#if 0
822
/*
823
 * invoke RSH
824
 */
825
int
826
rsh_exec(so,ns, user, host, args)
827
	struct socket *so;
828
	struct socket *ns;
829
	char *user;
830
	char *host;
831
	char *args;
832
{
833
	int fd[2];
834
	int fd0[2];
835
	int s;
836
	char buff[256];
837

  
838
	DEBUG_CALL("rsh_exec");
839
	DEBUG_ARG("so = %lx", (long)so);
840

  
841
	if (pipe(fd)<0) {
842
          lprint("Error: pipe failed: %s\n", strerror(errno));
843
          return 0;
844
	}
845
/* #ifdef HAVE_SOCKETPAIR */
846
#if 1
847
        if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) {
848
          close(fd[0]);
849
          close(fd[1]);
850
          lprint("Error: openpty failed: %s\n", strerror(errno));
851
          return 0;
852
        }
853
#else
854
        if (slirp_openpty(&fd0[0], &fd0[1]) == -1) {
855
          close(fd[0]);
856
          close(fd[1]);
857
          lprint("Error: openpty failed: %s\n", strerror(errno));
858
          return 0;
859
        }
860
#endif
861

  
862
	switch(fork()) {
863
	 case -1:
864
           lprint("Error: fork failed: %s\n", strerror(errno));
865
           close(fd[0]);
866
           close(fd[1]);
867
           close(fd0[0]);
868
           close(fd0[1]);
869
           return 0;
870

  
871
	 case 0:
872
           close(fd[0]);
873
           close(fd0[0]);
874

  
875
		/* Set the DISPLAY */
876
           if (x_port >= 0) {
877
#ifdef HAVE_SETENV
878
             sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
879
             setenv("DISPLAY", buff, 1);
880
#else
881
             sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
882
             putenv(buff);
883
#endif
884
           }
885

  
886
           dup2(fd0[1], 0);
887
           dup2(fd0[1], 1);
888
           dup2(fd[1], 2);
889
           for (s = 3; s <= 255; s++)
890
             close(s);
891

  
892
           execlp("rsh","rsh","-l", user, host, args, NULL);
893

  
894
           /* Ooops, failed, let's tell the user why */
895

  
896
           sprintf(buff, "Error: execlp of %s failed: %s\n",
897
                   "rsh", strerror(errno));
898
           write(2, buff, strlen(buff)+1);
899
           close(0); close(1); close(2); /* XXX */
900
           exit(1);
901

  
902
        default:
903
          close(fd[1]);
904
          close(fd0[1]);
905
          ns->s=fd[0];
906
          so->s=fd0[0];
907

  
908
          return 1;
909
	}
910
}
911
#endif
912

  
913 388
void slirp_connection_info(Monitor *mon)
914 389
{
915 390
    const char * const tcpstates[] = {
b/slirp/misc.h
19 19
extern struct ex_list *exec_list;
20 20
extern u_int time_fasttimo, last_slowtimo;
21 21

  
22
extern int (*lprint_print) _P((void *, const char *, va_list));
23
extern char *lprint_ptr, *lprint_ptr2, **lprint_arg;
24
extern struct sbuf *lprint_sb;
25

  
26 22
#ifndef HAVE_STRDUP
27 23
char *strdup _P((const char *));
28 24
#endif
......
63 59
	struct emu_t *next;
64 60
};
65 61

  
66
#ifndef CONFIG_QEMU
67
extern struct emu_t *tcpemu;
68
#endif
69

  
70 62
extern int x_port, x_server, x_display;
71 63

  
72 64
int show_x _P((char *, struct socket *));
b/slirp/sbuf.c
9 9

  
10 10
static void sbappendsb(struct sbuf *sb, struct mbuf *m);
11 11

  
12
/* Done as a macro in socket.h */
13
/* int
14
 * sbspace(struct sockbuff *sb)
15
 * {
16
 *	return SB_DATALEN - sb->sb_cc;
17
 * }
18
 */
19

  
20 12
void
21 13
sbfree(struct sbuf *sb)
22 14
{
b/slirp/slirp.c
55 55
static int do_slowtimo;
56 56
int link_up;
57 57
struct timeval tt;
58
FILE *lfd;
59 58
struct ex_list *exec_list;
60 59

  
61 60
/* XXX: suppress those select globals */
......
96 95
    pIPAddr = &(FixedInfo->DnsServerList);
97 96
    inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
98 97
    *pdns_addr = tmp_addr;
99
#if 0
100
    printf( "DNS Servers:\n" );
101
    printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String );
102

  
103
    pIPAddr = FixedInfo -> DnsServerList.Next;
104
    while ( pIPAddr ) {
105
            printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String );
106
            pIPAddr = pIPAddr ->Next;
107
    }
108
#endif
109 98
    if (FixedInfo) {
110 99
        GlobalFree(FixedInfo);
111 100
        FixedInfo = NULL;
......
179 168
                const char *bootfile, struct in_addr vdhcp_start,
180 169
                struct in_addr vnameserver)
181 170
{
182
    //    debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
183

  
184 171
#ifdef _WIN32
185 172
    WSADATA Data;
186 173

  
b/slirp/slirp.h
1 1
#ifndef __COMMON_H__
2 2
#define __COMMON_H__
3 3

  
4
#define CONFIG_QEMU
5

  
6 4
//#define DEBUG 1
7 5

  
8 6
// Uncomment the following line to enable SLIRP statistics printing in Qemu
......
14 12
#define STAT(expr) do { } while(0)
15 13
#endif
16 14

  
17
#ifndef CONFIG_QEMU
18
#include "version.h"
19
#endif
20 15
#include "config-host.h"
21 16
#include "slirp_config.h"
22 17

  
......
223 218
#include "tftp.h"
224 219
#include "libslirp.h"
225 220

  
226
extern struct ttys *ttys_unit[MAX_INTERFACES];
227

  
228 221
#ifndef NULL
229 222
#define NULL (void *)0
230 223
#endif
b/slirp/socket.c
15 15
static void sofcantrcvmore(struct socket *so);
16 16
static void sofcantsendmore(struct socket *so);
17 17

  
18
#if 0
19
static void
20
so_init()
21
{
22
	/* Nothing yet */
23
}
24
#endif
25

  
26 18
struct socket *
27 19
solookup(struct socket *head, struct in_addr laddr, u_int lport,
28 20
         struct in_addr faddr, u_int fport)
......
526 518
		so->so_expire = curtime + SO_EXPIRE;
527 519
	    }
528 520

  
529
	    /*		if (m->m_len == len) {
530
	     *			m_inc(m, MINCSIZE);
531
	     *			m->m_len = 0;
532
	     *		}
533
	     */
534

  
535 521
	    /*
536 522
	     * If this packet was destined for CTL_ADDR,
537 523
	     * make it look like that's where it came from, done by udp_output
......
604 590
	DEBUG_ARG("flags = %x", flags);
605 591

  
606 592
	if ((so = socreate()) == NULL) {
607
	  /* free(so);      Not sofree() ??? free(NULL) == NOP */
608 593
	  return NULL;
609 594
	}
610 595

  
......
659 644
	return so;
660 645
}
661 646

  
662
#if 0
663
/*
664
 * Data is available in so_rcv
665
 * Just write() the data to the socket
666
 * XXX not yet...
667
 */
668
static void
669
sorwakeup(so)
670
	struct socket *so;
671
{
672
/*	sowrite(so); */
673
/*	FD_CLR(so->s,&writefds); */
674
}
675

  
676
/*
677
 * Data has been freed in so_snd
678
 * We have room for a read() if we want to
679
 * For now, don't read, it'll be done in the main loop
680
 */
681
static void
682
sowwakeup(so)
683
	struct socket *so;
684
{
685
	/* Nothing, yet */
686
}
687
#endif
688

  
689 647
/*
690 648
 * Various session state calls
691 649
 * XXX Should be #define's
......
746 704
	}
747 705
}
748 706

  
749
void
750
soisfdisconnected(struct socket *so)
751
{
752
/*	so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */
753
/*	close(so->s); */
754
/*	so->so_state = SS_ISFDISCONNECTED; */
755
	/*
756
	 * XXX Do nothing ... ?
757
	 */
758
}
759

  
760 707
/*
761 708
 * Set write drain mode
762 709
 * Set CANTSENDMORE once all data has been write()n
b/slirp/socket.h
5 5
 * terms and conditions of the copyright.
6 6
 */
7 7

  
8
/* MINE */
9

  
10 8
#ifndef _SLIRP_SOCKET_H_
11 9
#define _SLIRP_SOCKET_H_
12 10

  
......
64 62
#define SS_ISFCONNECTED		0x004	/* Socket is connected to peer */
65 63
#define SS_FCANTRCVMORE		0x008	/* Socket can't receive more from peer (for half-closes) */
66 64
#define SS_FCANTSENDMORE	0x010	/* Socket can't send more to peer (for half-closes) */
67
/* #define SS_ISFDISCONNECTED	0x020*/	/* Socket has disconnected from peer, in 2MSL state */
68 65
#define SS_FWDRAIN		0x040	/* We received a FIN, drain data and set SS_FCANTSENDMORE */
69 66

  
70 67
#define SS_CTL			0x080
......
89 86
struct socket * tcp_listen _P((u_int32_t, u_int, u_int32_t, u_int, int));
90 87
void soisfconnecting _P((register struct socket *));
91 88
void soisfconnected _P((register struct socket *));
92
void soisfdisconnected _P((struct socket *));
93 89
void sofwdrain _P((struct socket *));
94 90
struct iovec; /* For win32 */
95 91
size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
b/slirp/tcp.h
113 113
#undef TCP_NODELAY
114 114
#define	TCP_NODELAY	0x01	/* don't delay send to coalesce packets */
115 115
#undef TCP_MAXSEG
116
/* #define	TCP_MAXSEG	0x02 */	/* set maximum segment size */
117 116

  
118 117
/*
119 118
 * TCP FSM state definitions.
b/slirp/tcp_input.c
81 81
		       if (tcp_emu((so),(m))) sbappend((so), (m)); \
82 82
	       } else \
83 83
	       	       sbappend((so), (m)); \
84
/*               sorwakeup(so); */ \
85 84
	} else {\
86 85
               (flags) = tcp_reass((tp), (ti), (m)); \
87 86
               tp->t_flags |= TF_ACKNOW; \
......
101 100
			if (tcp_emu((so),(m))) sbappend(so, (m)); \
102 101
		} else \
103 102
			sbappend((so), (m)); \
104
/*		sorwakeup(so); */ \
105 103
	} else { \
106 104
		(flags) = tcp_reass((tp), (ti), (m)); \
107 105
		tp->t_flags |= TF_ACKNOW; \
......
211 209
		remque(tcpiphdr2qlink(ti));
212 210
		m = ti->ti_mbuf;
213 211
		ti = tcpiphdr_next(ti);
214
/*		if (so->so_state & SS_FCANTRCVMORE) */
215 212
		if (so->so_state & SS_FCANTSENDMORE)
216 213
			m_freem(m);
217 214
		else {
......
221 218
				sbappend(so, m);
222 219
		}
223 220
	} while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);
224
/*	sorwakeup(so); */
225 221
	return (flags);
226 222
}
227 223

  
......
241 237
	register int tiflags;
242 238
        struct socket *so = NULL;
243 239
	int todrop, acked, ourfinisacked, needoutput = 0;
244
/*	int dropsocket = 0; */
245 240
	int iss = 0;
246 241
	u_long tiwin;
247 242
	int ret;
248
/*	int ts_present = 0; */
249 243
    struct ex_list *ex_ptr;
250 244

  
251 245
	DEBUG_CALL("tcp_input");
......
300 294
	ti->ti_x1 = 0;
301 295
	ti->ti_len = htons((u_int16_t)tlen);
302 296
	len = sizeof(struct ip ) + tlen;
303
	/* keep checksum for ICMP reply
304
	 * ti->ti_sum = cksum(m, len);
305
	 * if (ti->ti_sum) { */
306 297
	if(cksum(m, len)) {
307 298
	  STAT(tcpstat.tcps_rcvbadsum++);
308 299
	  goto drop;
......
322 313
	if (off > sizeof (struct tcphdr)) {
323 314
	  optlen = off - sizeof (struct tcphdr);
324 315
	  optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
325

  
326
		/*
327
		 * Do quick retrieval of timestamp options ("options
328
		 * prediction?").  If timestamp is the only option and it's
329
		 * formatted as recommended in RFC 1323 appendix A, we
330
		 * quickly get the values now and not bother calling
331
		 * tcp_dooptions(), etc.
332
		 */
333
/*		if ((optlen == TCPOLEN_TSTAMP_APPA ||
334
 *		     (optlen > TCPOLEN_TSTAMP_APPA &&
335
 *			optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) &&
336
 *		     *(u_int32_t *)optp == htonl(TCPOPT_TSTAMP_HDR) &&
337
 *		     (ti->ti_flags & TH_SYN) == 0) {
338
 *			ts_present = 1;
339
 *			ts_val = ntohl(*(u_int32_t *)(optp + 4));
340
 *			ts_ecr = ntohl(*(u_int32_t *)(optp + 8));
341
 *			optp = NULL;   / * we've parsed the options * /
342
 *		}
343
 */
344 316
	}
345 317
	tiflags = ti->ti_flags;
346 318

  
......
411 383
	  sbreserve(&so->so_snd, TCP_SNDSPACE);
412 384
	  sbreserve(&so->so_rcv, TCP_RCVSPACE);
413 385

  
414
	  /*		tcp_last_so = so; */  /* XXX ? */
415
	  /*		tp = sototcpcb(so);    */
416

  
417 386
	  so->so_laddr = ti->ti_src;
418 387
	  so->so_lport = ti->ti_sport;
419 388
	  so->so_faddr = ti->ti_dst;
......
442 411
	if (tp->t_state == TCPS_CLOSED)
443 412
		goto drop;
444 413

  
445
	/* Unscale the window into a 32-bit value. */
446
/*	if ((tiflags & TH_SYN) == 0)
447
 *		tiwin = ti->ti_win << tp->snd_scale;
448
 *	else
449
 */
450
		tiwin = ti->ti_win;
414
	tiwin = ti->ti_win;
451 415

  
452 416
	/*
453 417
	 * Segment received on connection.
......
465 429
	 */
466 430
	if (optp && tp->t_state != TCPS_LISTEN)
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff