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