root / slirp / misc.c @ d8bcbabf
History | View | Annotate | Download (10.3 kB)
1 |
/*
|
---|---|
2 |
* Copyright (c) 1995 Danny Gasparovski.
|
3 |
*
|
4 |
* Please read the file COPYRIGHT for the
|
5 |
* terms and conditions of the copyright.
|
6 |
*/
|
7 |
|
8 |
#include <slirp.h> |
9 |
#include <libslirp.h> |
10 |
|
11 |
#include "monitor.h" |
12 |
|
13 |
#ifdef DEBUG
|
14 |
int slirp_debug = DBG_CALL|DBG_MISC|DBG_ERROR;
|
15 |
#endif
|
16 |
|
17 |
struct quehead {
|
18 |
struct quehead *qh_link;
|
19 |
struct quehead *qh_rlink;
|
20 |
}; |
21 |
|
22 |
inline void |
23 |
insque(void *a, void *b) |
24 |
{ |
25 |
register struct quehead *element = (struct quehead *) a; |
26 |
register struct quehead *head = (struct quehead *) b; |
27 |
element->qh_link = head->qh_link; |
28 |
head->qh_link = (struct quehead *)element;
|
29 |
element->qh_rlink = (struct quehead *)head;
|
30 |
((struct quehead *)(element->qh_link))->qh_rlink
|
31 |
= (struct quehead *)element;
|
32 |
} |
33 |
|
34 |
inline void |
35 |
remque(void *a)
|
36 |
{ |
37 |
register struct quehead *element = (struct quehead *) a; |
38 |
((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
|
39 |
((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
|
40 |
element->qh_rlink = NULL;
|
41 |
} |
42 |
|
43 |
int add_exec(struct ex_list **ex_ptr, int do_pty, char *exec, |
44 |
struct in_addr addr, int port) |
45 |
{ |
46 |
struct ex_list *tmp_ptr;
|
47 |
|
48 |
/* First, check if the port is "bound" */
|
49 |
for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
|
50 |
if (port == tmp_ptr->ex_fport &&
|
51 |
addr.s_addr == tmp_ptr->ex_addr.s_addr) |
52 |
return -1; |
53 |
} |
54 |
|
55 |
tmp_ptr = *ex_ptr; |
56 |
*ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list)); |
57 |
(*ex_ptr)->ex_fport = port; |
58 |
(*ex_ptr)->ex_addr = addr; |
59 |
(*ex_ptr)->ex_pty = do_pty; |
60 |
(*ex_ptr)->ex_exec = (do_pty == 3) ? exec : strdup(exec);
|
61 |
(*ex_ptr)->ex_next = tmp_ptr; |
62 |
return 0; |
63 |
} |
64 |
|
65 |
#ifndef HAVE_STRERROR
|
66 |
|
67 |
/*
|
68 |
* For systems with no strerror
|
69 |
*/
|
70 |
|
71 |
extern int sys_nerr; |
72 |
extern char *sys_errlist[]; |
73 |
|
74 |
char *
|
75 |
strerror(error) |
76 |
int error;
|
77 |
{ |
78 |
if (error < sys_nerr)
|
79 |
return sys_errlist[error];
|
80 |
else
|
81 |
return "Unknown error."; |
82 |
} |
83 |
|
84 |
#endif
|
85 |
|
86 |
|
87 |
#ifdef _WIN32
|
88 |
|
89 |
int
|
90 |
fork_exec(struct socket *so, const char *ex, int do_pty) |
91 |
{ |
92 |
/* not implemented */
|
93 |
return 0; |
94 |
} |
95 |
|
96 |
#else
|
97 |
|
98 |
/*
|
99 |
* XXX This is ugly
|
100 |
* We create and bind a socket, then fork off to another
|
101 |
* process, which connects to this socket, after which we
|
102 |
* exec the wanted program. If something (strange) happens,
|
103 |
* the accept() call could block us forever.
|
104 |
*
|
105 |
* do_pty = 0 Fork/exec inetd style
|
106 |
* do_pty = 1 Fork/exec using slirp.telnetd
|
107 |
* do_ptr = 2 Fork/exec using pty
|
108 |
*/
|
109 |
int
|
110 |
fork_exec(struct socket *so, const char *ex, int do_pty) |
111 |
{ |
112 |
int s;
|
113 |
struct sockaddr_in addr;
|
114 |
socklen_t addrlen = sizeof(addr);
|
115 |
int opt;
|
116 |
int master = -1; |
117 |
const char *argv[256]; |
118 |
/* don't want to clobber the original */
|
119 |
char *bptr;
|
120 |
const char *curarg; |
121 |
int c, i, ret;
|
122 |
|
123 |
DEBUG_CALL("fork_exec");
|
124 |
DEBUG_ARG("so = %lx", (long)so); |
125 |
DEBUG_ARG("ex = %lx", (long)ex); |
126 |
DEBUG_ARG("do_pty = %lx", (long)do_pty); |
127 |
|
128 |
if (do_pty == 2) { |
129 |
return 0; |
130 |
} else {
|
131 |
addr.sin_family = AF_INET; |
132 |
addr.sin_port = 0;
|
133 |
addr.sin_addr.s_addr = INADDR_ANY; |
134 |
|
135 |
if ((s = qemu_socket(AF_INET, SOCK_STREAM, 0)) < 0 || |
136 |
bind(s, (struct sockaddr *)&addr, addrlen) < 0 || |
137 |
listen(s, 1) < 0) { |
138 |
lprint("Error: inet socket: %s\n", strerror(errno));
|
139 |
closesocket(s); |
140 |
|
141 |
return 0; |
142 |
} |
143 |
} |
144 |
|
145 |
switch(fork()) {
|
146 |
case -1: |
147 |
lprint("Error: fork failed: %s\n", strerror(errno));
|
148 |
close(s); |
149 |
if (do_pty == 2) |
150 |
close(master); |
151 |
return 0; |
152 |
|
153 |
case 0: |
154 |
/* Set the DISPLAY */
|
155 |
if (do_pty == 2) { |
156 |
(void) close(master);
|
157 |
#ifdef TIOCSCTTY /* XXXXX */ |
158 |
(void) setsid();
|
159 |
ioctl(s, TIOCSCTTY, (char *)NULL); |
160 |
#endif
|
161 |
} else {
|
162 |
getsockname(s, (struct sockaddr *)&addr, &addrlen);
|
163 |
close(s); |
164 |
/*
|
165 |
* Connect to the socket
|
166 |
* XXX If any of these fail, we're in trouble!
|
167 |
*/
|
168 |
s = qemu_socket(AF_INET, SOCK_STREAM, 0);
|
169 |
addr.sin_addr = loopback_addr; |
170 |
do {
|
171 |
ret = connect(s, (struct sockaddr *)&addr, addrlen);
|
172 |
} while (ret < 0 && errno == EINTR); |
173 |
} |
174 |
|
175 |
dup2(s, 0);
|
176 |
dup2(s, 1);
|
177 |
dup2(s, 2);
|
178 |
for (s = getdtablesize() - 1; s >= 3; s--) |
179 |
close(s); |
180 |
|
181 |
i = 0;
|
182 |
bptr = strdup(ex); /* No need to free() this */
|
183 |
if (do_pty == 1) { |
184 |
/* Setup "slirp.telnetd -x" */
|
185 |
argv[i++] = "slirp.telnetd";
|
186 |
argv[i++] = "-x";
|
187 |
argv[i++] = bptr; |
188 |
} else
|
189 |
do {
|
190 |
/* Change the string into argv[] */
|
191 |
curarg = bptr; |
192 |
while (*bptr != ' ' && *bptr != (char)0) |
193 |
bptr++; |
194 |
c = *bptr; |
195 |
*bptr++ = (char)0; |
196 |
argv[i++] = strdup(curarg); |
197 |
} while (c);
|
198 |
|
199 |
argv[i] = NULL;
|
200 |
execvp(argv[0], (char **)argv); |
201 |
|
202 |
/* Ooops, failed, let's tell the user why */
|
203 |
{ |
204 |
char buff[256]; |
205 |
|
206 |
snprintf(buff, sizeof(buff),
|
207 |
"Error: execvp of %s failed: %s\n",
|
208 |
argv[0], strerror(errno));
|
209 |
write(2, buff, strlen(buff)+1); |
210 |
} |
211 |
close(0); close(1); close(2); /* XXX */ |
212 |
exit(1);
|
213 |
|
214 |
default:
|
215 |
if (do_pty == 2) { |
216 |
close(s); |
217 |
so->s = master; |
218 |
} else {
|
219 |
/*
|
220 |
* XXX this could block us...
|
221 |
* XXX Should set a timer here, and if accept() doesn't
|
222 |
* return after X seconds, declare it a failure
|
223 |
* The only reason this will block forever is if socket()
|
224 |
* of connect() fail in the child process
|
225 |
*/
|
226 |
do {
|
227 |
so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
|
228 |
} while (so->s < 0 && errno == EINTR); |
229 |
closesocket(s); |
230 |
opt = 1;
|
231 |
setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); |
232 |
opt = 1;
|
233 |
setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); |
234 |
} |
235 |
fd_nonblock(so->s); |
236 |
|
237 |
/* Append the telnet options now */
|
238 |
if (so->so_m != NULL && do_pty == 1) { |
239 |
sbappend(so, so->so_m); |
240 |
so->so_m = NULL;
|
241 |
} |
242 |
|
243 |
return 1; |
244 |
} |
245 |
} |
246 |
#endif
|
247 |
|
248 |
#ifndef HAVE_STRDUP
|
249 |
char *
|
250 |
strdup(str) |
251 |
const char *str; |
252 |
{ |
253 |
char *bptr;
|
254 |
|
255 |
bptr = (char *)malloc(strlen(str)+1); |
256 |
strcpy(bptr, str); |
257 |
|
258 |
return bptr;
|
259 |
} |
260 |
#endif
|
261 |
|
262 |
#include "monitor.h" |
263 |
|
264 |
void lprint(const char *format, ...) |
265 |
{ |
266 |
va_list args; |
267 |
|
268 |
va_start(args, format); |
269 |
monitor_vprintf(cur_mon, format, args); |
270 |
va_end(args); |
271 |
} |
272 |
|
273 |
#ifdef BAD_SPRINTF
|
274 |
|
275 |
#undef vsprintf
|
276 |
#undef sprintf
|
277 |
|
278 |
/*
|
279 |
* Some BSD-derived systems have a sprintf which returns char *
|
280 |
*/
|
281 |
|
282 |
int
|
283 |
vsprintf_len(string, format, args) |
284 |
char *string;
|
285 |
const char *format; |
286 |
va_list args; |
287 |
{ |
288 |
vsprintf(string, format, args); |
289 |
return strlen(string);
|
290 |
} |
291 |
|
292 |
int
|
293 |
#ifdef __STDC__
|
294 |
sprintf_len(char *string, const char *format, ...) |
295 |
#else
|
296 |
sprintf_len(va_alist) va_dcl |
297 |
#endif
|
298 |
{ |
299 |
va_list args; |
300 |
#ifdef __STDC__
|
301 |
va_start(args, format); |
302 |
#else
|
303 |
char *string;
|
304 |
char *format;
|
305 |
va_start(args); |
306 |
string = va_arg(args, char *);
|
307 |
format = va_arg(args, char *);
|
308 |
#endif
|
309 |
vsprintf(string, format, args); |
310 |
return strlen(string);
|
311 |
} |
312 |
|
313 |
#endif
|
314 |
|
315 |
void
|
316 |
u_sleep(int usec)
|
317 |
{ |
318 |
struct timeval t;
|
319 |
fd_set fdset; |
320 |
|
321 |
FD_ZERO(&fdset); |
322 |
|
323 |
t.tv_sec = 0;
|
324 |
t.tv_usec = usec * 1000;
|
325 |
|
326 |
select(0, &fdset, &fdset, &fdset, &t);
|
327 |
} |
328 |
|
329 |
/*
|
330 |
* Set fd blocking and non-blocking
|
331 |
*/
|
332 |
|
333 |
void
|
334 |
fd_nonblock(int fd)
|
335 |
{ |
336 |
#ifdef FIONBIO
|
337 |
#ifdef _WIN32
|
338 |
unsigned long opt = 1; |
339 |
#else
|
340 |
int opt = 1; |
341 |
#endif
|
342 |
|
343 |
ioctlsocket(fd, FIONBIO, &opt); |
344 |
#else
|
345 |
int opt;
|
346 |
|
347 |
opt = fcntl(fd, F_GETFL, 0);
|
348 |
opt |= O_NONBLOCK; |
349 |
fcntl(fd, F_SETFL, opt); |
350 |
#endif
|
351 |
} |
352 |
|
353 |
void
|
354 |
fd_block(int fd)
|
355 |
{ |
356 |
#ifdef FIONBIO
|
357 |
#ifdef _WIN32
|
358 |
unsigned long opt = 0; |
359 |
#else
|
360 |
int opt = 0; |
361 |
#endif
|
362 |
|
363 |
ioctlsocket(fd, FIONBIO, &opt); |
364 |
#else
|
365 |
int opt;
|
366 |
|
367 |
opt = fcntl(fd, F_GETFL, 0);
|
368 |
opt &= ~O_NONBLOCK; |
369 |
fcntl(fd, F_SETFL, opt); |
370 |
#endif
|
371 |
} |
372 |
|
373 |
void slirp_connection_info(Slirp *slirp, Monitor *mon)
|
374 |
{ |
375 |
const char * const tcpstates[] = { |
376 |
[TCPS_CLOSED] = "CLOSED",
|
377 |
[TCPS_LISTEN] = "LISTEN",
|
378 |
[TCPS_SYN_SENT] = "SYN_SENT",
|
379 |
[TCPS_SYN_RECEIVED] = "SYN_RCVD",
|
380 |
[TCPS_ESTABLISHED] = "ESTABLISHED",
|
381 |
[TCPS_CLOSE_WAIT] = "CLOSE_WAIT",
|
382 |
[TCPS_FIN_WAIT_1] = "FIN_WAIT_1",
|
383 |
[TCPS_CLOSING] = "CLOSING",
|
384 |
[TCPS_LAST_ACK] = "LAST_ACK",
|
385 |
[TCPS_FIN_WAIT_2] = "FIN_WAIT_2",
|
386 |
[TCPS_TIME_WAIT] = "TIME_WAIT",
|
387 |
}; |
388 |
struct in_addr dst_addr;
|
389 |
struct sockaddr_in src;
|
390 |
socklen_t src_len; |
391 |
uint16_t dst_port; |
392 |
struct socket *so;
|
393 |
const char *state; |
394 |
char buf[20]; |
395 |
int n;
|
396 |
|
397 |
monitor_printf(mon, " Protocol[State] FD Source Address Port "
|
398 |
"Dest. Address Port RecvQ SendQ\n");
|
399 |
|
400 |
for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
|
401 |
if (so->so_state & SS_HOSTFWD) {
|
402 |
state = "HOST_FORWARD";
|
403 |
} else if (so->so_tcpcb) { |
404 |
state = tcpstates[so->so_tcpcb->t_state]; |
405 |
} else {
|
406 |
state = "NONE";
|
407 |
} |
408 |
if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) {
|
409 |
src_len = sizeof(src);
|
410 |
getsockname(so->s, (struct sockaddr *)&src, &src_len);
|
411 |
dst_addr = so->so_laddr; |
412 |
dst_port = so->so_lport; |
413 |
} else {
|
414 |
src.sin_addr = so->so_laddr; |
415 |
src.sin_port = so->so_lport; |
416 |
dst_addr = so->so_faddr; |
417 |
dst_port = so->so_fport; |
418 |
} |
419 |
n = snprintf(buf, sizeof(buf), " TCP[%s]", state); |
420 |
memset(&buf[n], ' ', 19 - n); |
421 |
buf[19] = 0; |
422 |
monitor_printf(mon, "%s %3d %15s %5d ", buf, so->s,
|
423 |
src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
|
424 |
ntohs(src.sin_port)); |
425 |
monitor_printf(mon, "%15s %5d %5d %5d\n",
|
426 |
inet_ntoa(dst_addr), ntohs(dst_port), |
427 |
so->so_rcv.sb_cc, so->so_snd.sb_cc); |
428 |
} |
429 |
|
430 |
for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) {
|
431 |
if (so->so_state & SS_HOSTFWD) {
|
432 |
n = snprintf(buf, sizeof(buf), " UDP[HOST_FORWARD]"); |
433 |
src_len = sizeof(src);
|
434 |
getsockname(so->s, (struct sockaddr *)&src, &src_len);
|
435 |
dst_addr = so->so_laddr; |
436 |
dst_port = so->so_lport; |
437 |
} else {
|
438 |
n = snprintf(buf, sizeof(buf), " UDP[%d sec]", |
439 |
(so->so_expire - curtime) / 1000);
|
440 |
src.sin_addr = so->so_laddr; |
441 |
src.sin_port = so->so_lport; |
442 |
dst_addr = so->so_faddr; |
443 |
dst_port = so->so_fport; |
444 |
} |
445 |
memset(&buf[n], ' ', 19 - n); |
446 |
buf[19] = 0; |
447 |
monitor_printf(mon, "%s %3d %15s %5d ", buf, so->s,
|
448 |
src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
|
449 |
ntohs(src.sin_port)); |
450 |
monitor_printf(mon, "%15s %5d %5d %5d\n",
|
451 |
inet_ntoa(dst_addr), ntohs(dst_port), |
452 |
so->so_rcv.sb_cc, so->so_snd.sb_cc); |
453 |
} |
454 |
} |