root / slirp / misc.c @ 4d54ec78
History | View | Annotate | Download (9.6 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 |
pid_t pid; |
123 |
|
124 |
DEBUG_CALL("fork_exec");
|
125 |
DEBUG_ARG("so = %lx", (long)so); |
126 |
DEBUG_ARG("ex = %lx", (long)ex); |
127 |
DEBUG_ARG("do_pty = %lx", (long)do_pty); |
128 |
|
129 |
if (do_pty == 2) { |
130 |
return 0; |
131 |
} else {
|
132 |
addr.sin_family = AF_INET; |
133 |
addr.sin_port = 0;
|
134 |
addr.sin_addr.s_addr = INADDR_ANY; |
135 |
|
136 |
if ((s = qemu_socket(AF_INET, SOCK_STREAM, 0)) < 0 || |
137 |
bind(s, (struct sockaddr *)&addr, addrlen) < 0 || |
138 |
listen(s, 1) < 0) { |
139 |
lprint("Error: inet socket: %s\n", strerror(errno));
|
140 |
closesocket(s); |
141 |
|
142 |
return 0; |
143 |
} |
144 |
} |
145 |
|
146 |
pid = fork(); |
147 |
switch(pid) {
|
148 |
case -1: |
149 |
lprint("Error: fork failed: %s\n", strerror(errno));
|
150 |
close(s); |
151 |
if (do_pty == 2) |
152 |
close(master); |
153 |
return 0; |
154 |
|
155 |
case 0: |
156 |
/* Set the DISPLAY */
|
157 |
if (do_pty == 2) { |
158 |
(void) close(master);
|
159 |
#ifdef TIOCSCTTY /* XXXXX */ |
160 |
(void) setsid();
|
161 |
ioctl(s, TIOCSCTTY, (char *)NULL); |
162 |
#endif
|
163 |
} else {
|
164 |
getsockname(s, (struct sockaddr *)&addr, &addrlen);
|
165 |
close(s); |
166 |
/*
|
167 |
* Connect to the socket
|
168 |
* XXX If any of these fail, we're in trouble!
|
169 |
*/
|
170 |
s = qemu_socket(AF_INET, SOCK_STREAM, 0);
|
171 |
addr.sin_addr = loopback_addr; |
172 |
do {
|
173 |
ret = connect(s, (struct sockaddr *)&addr, addrlen);
|
174 |
} while (ret < 0 && errno == EINTR); |
175 |
} |
176 |
|
177 |
dup2(s, 0);
|
178 |
dup2(s, 1);
|
179 |
dup2(s, 2);
|
180 |
for (s = getdtablesize() - 1; s >= 3; s--) |
181 |
close(s); |
182 |
|
183 |
i = 0;
|
184 |
bptr = qemu_strdup(ex); /* No need to free() this */
|
185 |
if (do_pty == 1) { |
186 |
/* Setup "slirp.telnetd -x" */
|
187 |
argv[i++] = "slirp.telnetd";
|
188 |
argv[i++] = "-x";
|
189 |
argv[i++] = bptr; |
190 |
} else
|
191 |
do {
|
192 |
/* Change the string into argv[] */
|
193 |
curarg = bptr; |
194 |
while (*bptr != ' ' && *bptr != (char)0) |
195 |
bptr++; |
196 |
c = *bptr; |
197 |
*bptr++ = (char)0; |
198 |
argv[i++] = strdup(curarg); |
199 |
} while (c);
|
200 |
|
201 |
argv[i] = NULL;
|
202 |
execvp(argv[0], (char **)argv); |
203 |
|
204 |
/* Ooops, failed, let's tell the user why */
|
205 |
fprintf(stderr, "Error: execvp of %s failed: %s\n",
|
206 |
argv[0], strerror(errno));
|
207 |
close(0); close(1); close(2); /* XXX */ |
208 |
exit(1);
|
209 |
|
210 |
default:
|
211 |
qemu_add_child_watch(pid); |
212 |
if (do_pty == 2) { |
213 |
close(s); |
214 |
so->s = master; |
215 |
} else {
|
216 |
/*
|
217 |
* XXX this could block us...
|
218 |
* XXX Should set a timer here, and if accept() doesn't
|
219 |
* return after X seconds, declare it a failure
|
220 |
* The only reason this will block forever is if socket()
|
221 |
* of connect() fail in the child process
|
222 |
*/
|
223 |
do {
|
224 |
so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
|
225 |
} while (so->s < 0 && errno == EINTR); |
226 |
closesocket(s); |
227 |
opt = 1;
|
228 |
setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); |
229 |
opt = 1;
|
230 |
setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); |
231 |
} |
232 |
fd_nonblock(so->s); |
233 |
|
234 |
/* Append the telnet options now */
|
235 |
if (so->so_m != NULL && do_pty == 1) { |
236 |
sbappend(so, so->so_m); |
237 |
so->so_m = NULL;
|
238 |
} |
239 |
|
240 |
return 1; |
241 |
} |
242 |
} |
243 |
#endif
|
244 |
|
245 |
#ifndef HAVE_STRDUP
|
246 |
char *
|
247 |
strdup(str) |
248 |
const char *str; |
249 |
{ |
250 |
char *bptr;
|
251 |
|
252 |
bptr = (char *)malloc(strlen(str)+1); |
253 |
strcpy(bptr, str); |
254 |
|
255 |
return bptr;
|
256 |
} |
257 |
#endif
|
258 |
|
259 |
#include "monitor.h" |
260 |
|
261 |
void lprint(const char *format, ...) |
262 |
{ |
263 |
va_list args; |
264 |
|
265 |
va_start(args, format); |
266 |
monitor_vprintf(default_mon, format, args); |
267 |
va_end(args); |
268 |
} |
269 |
|
270 |
void
|
271 |
u_sleep(int usec)
|
272 |
{ |
273 |
struct timeval t;
|
274 |
fd_set fdset; |
275 |
|
276 |
FD_ZERO(&fdset); |
277 |
|
278 |
t.tv_sec = 0;
|
279 |
t.tv_usec = usec * 1000;
|
280 |
|
281 |
select(0, &fdset, &fdset, &fdset, &t);
|
282 |
} |
283 |
|
284 |
/*
|
285 |
* Set fd blocking and non-blocking
|
286 |
*/
|
287 |
|
288 |
void
|
289 |
fd_nonblock(int fd)
|
290 |
{ |
291 |
#ifdef FIONBIO
|
292 |
#ifdef _WIN32
|
293 |
unsigned long opt = 1; |
294 |
#else
|
295 |
int opt = 1; |
296 |
#endif
|
297 |
|
298 |
ioctlsocket(fd, FIONBIO, &opt); |
299 |
#else
|
300 |
int opt;
|
301 |
|
302 |
opt = fcntl(fd, F_GETFL, 0);
|
303 |
opt |= O_NONBLOCK; |
304 |
fcntl(fd, F_SETFL, opt); |
305 |
#endif
|
306 |
} |
307 |
|
308 |
void
|
309 |
fd_block(int fd)
|
310 |
{ |
311 |
#ifdef FIONBIO
|
312 |
#ifdef _WIN32
|
313 |
unsigned long opt = 0; |
314 |
#else
|
315 |
int opt = 0; |
316 |
#endif
|
317 |
|
318 |
ioctlsocket(fd, FIONBIO, &opt); |
319 |
#else
|
320 |
int opt;
|
321 |
|
322 |
opt = fcntl(fd, F_GETFL, 0);
|
323 |
opt &= ~O_NONBLOCK; |
324 |
fcntl(fd, F_SETFL, opt); |
325 |
#endif
|
326 |
} |
327 |
|
328 |
void slirp_connection_info(Slirp *slirp, Monitor *mon)
|
329 |
{ |
330 |
const char * const tcpstates[] = { |
331 |
[TCPS_CLOSED] = "CLOSED",
|
332 |
[TCPS_LISTEN] = "LISTEN",
|
333 |
[TCPS_SYN_SENT] = "SYN_SENT",
|
334 |
[TCPS_SYN_RECEIVED] = "SYN_RCVD",
|
335 |
[TCPS_ESTABLISHED] = "ESTABLISHED",
|
336 |
[TCPS_CLOSE_WAIT] = "CLOSE_WAIT",
|
337 |
[TCPS_FIN_WAIT_1] = "FIN_WAIT_1",
|
338 |
[TCPS_CLOSING] = "CLOSING",
|
339 |
[TCPS_LAST_ACK] = "LAST_ACK",
|
340 |
[TCPS_FIN_WAIT_2] = "FIN_WAIT_2",
|
341 |
[TCPS_TIME_WAIT] = "TIME_WAIT",
|
342 |
}; |
343 |
struct in_addr dst_addr;
|
344 |
struct sockaddr_in src;
|
345 |
socklen_t src_len; |
346 |
uint16_t dst_port; |
347 |
struct socket *so;
|
348 |
const char *state; |
349 |
char buf[20]; |
350 |
int n;
|
351 |
|
352 |
monitor_printf(mon, " Protocol[State] FD Source Address Port "
|
353 |
"Dest. Address Port RecvQ SendQ\n");
|
354 |
|
355 |
for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
|
356 |
if (so->so_state & SS_HOSTFWD) {
|
357 |
state = "HOST_FORWARD";
|
358 |
} else if (so->so_tcpcb) { |
359 |
state = tcpstates[so->so_tcpcb->t_state]; |
360 |
} else {
|
361 |
state = "NONE";
|
362 |
} |
363 |
if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) {
|
364 |
src_len = sizeof(src);
|
365 |
getsockname(so->s, (struct sockaddr *)&src, &src_len);
|
366 |
dst_addr = so->so_laddr; |
367 |
dst_port = so->so_lport; |
368 |
} else {
|
369 |
src.sin_addr = so->so_laddr; |
370 |
src.sin_port = so->so_lport; |
371 |
dst_addr = so->so_faddr; |
372 |
dst_port = so->so_fport; |
373 |
} |
374 |
n = snprintf(buf, sizeof(buf), " TCP[%s]", state); |
375 |
memset(&buf[n], ' ', 19 - n); |
376 |
buf[19] = 0; |
377 |
monitor_printf(mon, "%s %3d %15s %5d ", buf, so->s,
|
378 |
src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
|
379 |
ntohs(src.sin_port)); |
380 |
monitor_printf(mon, "%15s %5d %5d %5d\n",
|
381 |
inet_ntoa(dst_addr), ntohs(dst_port), |
382 |
so->so_rcv.sb_cc, so->so_snd.sb_cc); |
383 |
} |
384 |
|
385 |
for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) {
|
386 |
if (so->so_state & SS_HOSTFWD) {
|
387 |
n = snprintf(buf, sizeof(buf), " UDP[HOST_FORWARD]"); |
388 |
src_len = sizeof(src);
|
389 |
getsockname(so->s, (struct sockaddr *)&src, &src_len);
|
390 |
dst_addr = so->so_laddr; |
391 |
dst_port = so->so_lport; |
392 |
} else {
|
393 |
n = snprintf(buf, sizeof(buf), " UDP[%d sec]", |
394 |
(so->so_expire - curtime) / 1000);
|
395 |
src.sin_addr = so->so_laddr; |
396 |
src.sin_port = so->so_lport; |
397 |
dst_addr = so->so_faddr; |
398 |
dst_port = so->so_fport; |
399 |
} |
400 |
memset(&buf[n], ' ', 19 - n); |
401 |
buf[19] = 0; |
402 |
monitor_printf(mon, "%s %3d %15s %5d ", buf, so->s,
|
403 |
src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
|
404 |
ntohs(src.sin_port)); |
405 |
monitor_printf(mon, "%15s %5d %5d %5d\n",
|
406 |
inet_ntoa(dst_addr), ntohs(dst_port), |
407 |
so->so_rcv.sb_cc, so->so_snd.sb_cc); |
408 |
} |
409 |
} |