misc.c 10.1 KB
Newer Older
B
bellard 已提交
1 2
/*
 * Copyright (c) 1995 Danny Gasparovski.
3
 *
B
bellard 已提交
4 5 6 7 8
 * Please read the file COPYRIGHT for the
 * terms and conditions of the copyright.
 */

#include <slirp.h>
9 10 11
#include <libslirp.h>

#include "monitor.h"
B
bellard 已提交
12

13 14 15 16
#ifdef DEBUG
int slirp_debug = DBG_CALL|DBG_MISC|DBG_ERROR;
#endif

B
bellard 已提交
17 18 19 20 21 22
struct quehead {
	struct quehead *qh_link;
	struct quehead *qh_rlink;
};

inline void
23
insque(void *a, void *b)
B
bellard 已提交
24 25 26 27 28 29 30 31 32 33 34
{
	register struct quehead *element = (struct quehead *) a;
	register struct quehead *head = (struct quehead *) b;
	element->qh_link = head->qh_link;
	head->qh_link = (struct quehead *)element;
	element->qh_rlink = (struct quehead *)head;
	((struct quehead *)(element->qh_link))->qh_rlink
	= (struct quehead *)element;
}

inline void
35
remque(void *a)
B
bellard 已提交
36 37 38 39 40 41 42
{
  register struct quehead *element = (struct quehead *) a;
  ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
  ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
  element->qh_rlink = NULL;
}

43 44
int add_exec(struct ex_list **ex_ptr, int do_pty, char *exec,
             struct in_addr addr, int port)
B
bellard 已提交
45 46
{
	struct ex_list *tmp_ptr;
47

B
bellard 已提交
48 49
	/* First, check if the port is "bound" */
	for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
50 51 52
		if (port == tmp_ptr->ex_fport &&
		    addr.s_addr == tmp_ptr->ex_addr.s_addr)
			return -1;
B
bellard 已提交
53
	}
54

B
bellard 已提交
55 56 57 58 59
	tmp_ptr = *ex_ptr;
	*ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list));
	(*ex_ptr)->ex_fport = port;
	(*ex_ptr)->ex_addr = addr;
	(*ex_ptr)->ex_pty = do_pty;
60
	(*ex_ptr)->ex_exec = (do_pty == 3) ? exec : strdup(exec);
B
bellard 已提交
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
	(*ex_ptr)->ex_next = tmp_ptr;
	return 0;
}

#ifndef HAVE_STRERROR

/*
 * For systems with no strerror
 */

extern int sys_nerr;
extern char *sys_errlist[];

char *
strerror(error)
	int error;
{
	if (error < sys_nerr)
	   return sys_errlist[error];
	else
	   return "Unknown error.";
}

#endif


B
bellard 已提交
87 88 89
#ifdef _WIN32

int
90
fork_exec(struct socket *so, const char *ex, int do_pty)
B
bellard 已提交
91 92 93 94 95 96 97
{
    /* not implemented */
    return 0;
}

#else

B
bellard 已提交
98 99 100 101 102 103
/*
 * XXX This is ugly
 * We create and bind a socket, then fork off to another
 * process, which connects to this socket, after which we
 * exec the wanted program.  If something (strange) happens,
 * the accept() call could block us forever.
104
 *
B
bellard 已提交
105 106 107 108 109
 * do_pty = 0   Fork/exec inetd style
 * do_pty = 1   Fork/exec using slirp.telnetd
 * do_ptr = 2   Fork/exec using pty
 */
int
110
fork_exec(struct socket *so, const char *ex, int do_pty)
B
bellard 已提交
111 112 113
{
	int s;
	struct sockaddr_in addr;
114
	socklen_t addrlen = sizeof(addr);
B
bellard 已提交
115
	int opt;
116
	const char *argv[256];
B
bellard 已提交
117 118
	/* don't want to clobber the original */
	char *bptr;
119
	const char *curarg;
120
	int c, i, ret;
121
	pid_t pid;
122

B
bellard 已提交
123 124 125 126
	DEBUG_CALL("fork_exec");
	DEBUG_ARG("so = %lx", (long)so);
	DEBUG_ARG("ex = %lx", (long)ex);
	DEBUG_ARG("do_pty = %lx", (long)do_pty);
127

B
bellard 已提交
128
	if (do_pty == 2) {
129
                return 0;
B
bellard 已提交
130 131 132 133
	} else {
		addr.sin_family = AF_INET;
		addr.sin_port = 0;
		addr.sin_addr.s_addr = INADDR_ANY;
134

K
Kevin Wolf 已提交
135
		if ((s = qemu_socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
B
bellard 已提交
136 137 138
		    bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
		    listen(s, 1) < 0) {
			lprint("Error: inet socket: %s\n", strerror(errno));
B
bellard 已提交
139
			closesocket(s);
140

B
bellard 已提交
141 142 143
			return 0;
		}
	}
144

145 146
	pid = fork();
	switch(pid) {
B
bellard 已提交
147 148 149 150
	 case -1:
		lprint("Error: fork failed: %s\n", strerror(errno));
		close(s);
		return 0;
151

B
bellard 已提交
152
	 case 0:
153 154
                setsid();

B
bellard 已提交
155
		/* Set the DISPLAY */
156 157 158 159 160 161 162 163 164 165 166
                getsockname(s, (struct sockaddr *)&addr, &addrlen);
                close(s);
                /*
                 * Connect to the socket
                 * XXX If any of these fail, we're in trouble!
                 */
                s = qemu_socket(AF_INET, SOCK_STREAM, 0);
                addr.sin_addr = loopback_addr;
                do {
                    ret = connect(s, (struct sockaddr *)&addr, addrlen);
                } while (ret < 0 && errno == EINTR);
167

B
bellard 已提交
168 169 170
		dup2(s, 0);
		dup2(s, 1);
		dup2(s, 2);
171
		for (s = getdtablesize() - 1; s >= 3; s--)
B
bellard 已提交
172
		   close(s);
173

B
bellard 已提交
174
		i = 0;
175
		bptr = g_strdup(ex); /* No need to free() this */
B
bellard 已提交
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
		if (do_pty == 1) {
			/* Setup "slirp.telnetd -x" */
			argv[i++] = "slirp.telnetd";
			argv[i++] = "-x";
			argv[i++] = bptr;
		} else
		   do {
			/* Change the string into argv[] */
			curarg = bptr;
			while (*bptr != ' ' && *bptr != (char)0)
			   bptr++;
			c = *bptr;
			*bptr++ = (char)0;
			argv[i++] = strdup(curarg);
		   } while (c);
191

192
                argv[i] = NULL;
193
		execvp(argv[0], (char **)argv);
194

B
bellard 已提交
195
		/* Ooops, failed, let's tell the user why */
196 197
        fprintf(stderr, "Error: execvp of %s failed: %s\n",
                argv[0], strerror(errno));
B
bellard 已提交
198 199
		close(0); close(1); close(2); /* XXX */
		exit(1);
200

B
bellard 已提交
201
	 default:
202
		qemu_add_child_watch(pid);
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
                /*
                 * XXX this could block us...
                 * XXX Should set a timer here, and if accept() doesn't
                 * return after X seconds, declare it a failure
                 * The only reason this will block forever is if socket()
                 * of connect() fail in the child process
                 */
                do {
                    so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
                } while (so->s < 0 && errno == EINTR);
                closesocket(s);
                opt = 1;
                setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int));
                opt = 1;
                setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int));
B
bellard 已提交
218
		fd_nonblock(so->s);
219

B
bellard 已提交
220
		/* Append the telnet options now */
221
                if (so->so_m != NULL && do_pty == 1)  {
B
bellard 已提交
222
			sbappend(so, so->so_m);
223
                        so->so_m = NULL;
B
bellard 已提交
224
		}
225

B
bellard 已提交
226 227 228 229 230 231 232 233 234 235 236
		return 1;
	}
}
#endif

#ifndef HAVE_STRDUP
char *
strdup(str)
	const char *str;
{
	char *bptr;
237

B
bellard 已提交
238 239
	bptr = (char *)malloc(strlen(str)+1);
	strcpy(bptr, str);
240

B
bellard 已提交
241 242 243 244
	return bptr;
}
#endif

A
aliguori 已提交
245
#include "monitor.h"
246

247 248 249 250 251
void lprint(const char *format, ...)
{
    va_list args;

    va_start(args, format);
252
    monitor_vprintf(default_mon, format, args);
253 254
    va_end(args);
}
B
bellard 已提交
255 256

void
257
u_sleep(int usec)
B
bellard 已提交
258 259 260
{
	struct timeval t;
	fd_set fdset;
261

B
bellard 已提交
262
	FD_ZERO(&fdset);
263

B
bellard 已提交
264 265
	t.tv_sec = 0;
	t.tv_usec = usec * 1000;
266

B
bellard 已提交
267 268 269 270 271 272 273 274
	select(0, &fdset, &fdset, &fdset, &t);
}

/*
 * Set fd blocking and non-blocking
 */

void
275
fd_nonblock(int fd)
B
bellard 已提交
276 277
{
#ifdef FIONBIO
B
blueswir1 已提交
278
#ifdef _WIN32
B
Blue Swirl 已提交
279
        unsigned long opt = 1;
B
blueswir1 已提交
280 281 282
#else
        int opt = 1;
#endif
283

B
bellard 已提交
284
	ioctlsocket(fd, FIONBIO, &opt);
B
bellard 已提交
285 286
#else
	int opt;
287

B
bellard 已提交
288 289 290 291 292 293 294
	opt = fcntl(fd, F_GETFL, 0);
	opt |= O_NONBLOCK;
	fcntl(fd, F_SETFL, opt);
#endif
}

void
295
fd_block(int fd)
B
bellard 已提交
296 297
{
#ifdef FIONBIO
B
Blue Swirl 已提交
298 299 300
#ifdef _WIN32
        unsigned long opt = 0;
#else
B
bellard 已提交
301
	int opt = 0;
B
Blue Swirl 已提交
302
#endif
303

B
bellard 已提交
304
	ioctlsocket(fd, FIONBIO, &opt);
B
bellard 已提交
305 306
#else
	int opt;
307

B
bellard 已提交
308 309 310 311 312 313
	opt = fcntl(fd, F_GETFL, 0);
	opt &= ~O_NONBLOCK;
	fcntl(fd, F_SETFL, opt);
#endif
}

314
void slirp_connection_info(Slirp *slirp, Monitor *mon)
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
{
    const char * const tcpstates[] = {
        [TCPS_CLOSED]       = "CLOSED",
        [TCPS_LISTEN]       = "LISTEN",
        [TCPS_SYN_SENT]     = "SYN_SENT",
        [TCPS_SYN_RECEIVED] = "SYN_RCVD",
        [TCPS_ESTABLISHED]  = "ESTABLISHED",
        [TCPS_CLOSE_WAIT]   = "CLOSE_WAIT",
        [TCPS_FIN_WAIT_1]   = "FIN_WAIT_1",
        [TCPS_CLOSING]      = "CLOSING",
        [TCPS_LAST_ACK]     = "LAST_ACK",
        [TCPS_FIN_WAIT_2]   = "FIN_WAIT_2",
        [TCPS_TIME_WAIT]    = "TIME_WAIT",
    };
    struct in_addr dst_addr;
    struct sockaddr_in src;
    socklen_t src_len;
    uint16_t dst_port;
    struct socket *so;
    const char *state;
    char buf[20];
    int n;

    monitor_printf(mon, "  Protocol[State]    FD  Source Address  Port   "
                        "Dest. Address  Port RecvQ SendQ\n");

341
    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
        if (so->so_state & SS_HOSTFWD) {
            state = "HOST_FORWARD";
        } else if (so->so_tcpcb) {
            state = tcpstates[so->so_tcpcb->t_state];
        } else {
            state = "NONE";
        }
        if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) {
            src_len = sizeof(src);
            getsockname(so->s, (struct sockaddr *)&src, &src_len);
            dst_addr = so->so_laddr;
            dst_port = so->so_lport;
        } else {
            src.sin_addr = so->so_laddr;
            src.sin_port = so->so_lport;
            dst_addr = so->so_faddr;
            dst_port = so->so_fport;
        }
        n = snprintf(buf, sizeof(buf), "  TCP[%s]", state);
        memset(&buf[n], ' ', 19 - n);
        buf[19] = 0;
        monitor_printf(mon, "%s %3d %15s %5d ", buf, so->s,
                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
                       ntohs(src.sin_port));
        monitor_printf(mon, "%15s %5d %5d %5d\n",
                       inet_ntoa(dst_addr), ntohs(dst_port),
                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
    }

371
    for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) {
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
        if (so->so_state & SS_HOSTFWD) {
            n = snprintf(buf, sizeof(buf), "  UDP[HOST_FORWARD]");
            src_len = sizeof(src);
            getsockname(so->s, (struct sockaddr *)&src, &src_len);
            dst_addr = so->so_laddr;
            dst_port = so->so_lport;
        } else {
            n = snprintf(buf, sizeof(buf), "  UDP[%d sec]",
                         (so->so_expire - curtime) / 1000);
            src.sin_addr = so->so_laddr;
            src.sin_port = so->so_lport;
            dst_addr = so->so_faddr;
            dst_port = so->so_fport;
        }
        memset(&buf[n], ' ', 19 - n);
        buf[19] = 0;
        monitor_printf(mon, "%s %3d %15s %5d ", buf, so->s,
                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
                       ntohs(src.sin_port));
        monitor_printf(mon, "%15s %5d %5d %5d\n",
                       inet_ntoa(dst_addr), ntohs(dst_port),
                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
    }
395 396 397 398 399 400 401 402 403 404 405 406 407

    for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) {
        n = snprintf(buf, sizeof(buf), "  ICMP[%d sec]",
                     (so->so_expire - curtime) / 1000);
        src.sin_addr = so->so_laddr;
        dst_addr = so->so_faddr;
        memset(&buf[n], ' ', 19 - n);
        buf[19] = 0;
        monitor_printf(mon, "%s %3d %15s  -    ", buf, so->s,
                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*");
        monitor_printf(mon, "%15s  -    %5d %5d\n", inet_ntoa(dst_addr),
                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
    }
408
}