misc.c 9.6 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
        int master = -1;
117
	const char *argv[256];
B
bellard 已提交
118 119
	/* don't want to clobber the original */
	char *bptr;
120
	const char *curarg;
121
	int c, i, ret;
122
	pid_t pid;
123

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

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

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

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

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

B
bellard 已提交
155
	 case 0:
156 157
                setsid();

B
bellard 已提交
158 159 160 161 162 163 164 165 166 167 168 169 170
		/* Set the DISPLAY */
		if (do_pty == 2) {
			(void) close(master);
#ifdef TIOCSCTTY /* XXXXX */
			ioctl(s, TIOCSCTTY, (char *)NULL);
#endif
		} else {
			getsockname(s, (struct sockaddr *)&addr, &addrlen);
			close(s);
			/*
			 * Connect to the socket
			 * XXX If any of these fail, we're in trouble!
	 		 */
K
Kevin Wolf 已提交
171
			s = qemu_socket(AF_INET, SOCK_STREAM, 0);
B
bellard 已提交
172
			addr.sin_addr = loopback_addr;
173 174 175
                        do {
                            ret = connect(s, (struct sockaddr *)&addr, addrlen);
                        } while (ret < 0 && errno == EINTR);
B
bellard 已提交
176
		}
177

B
bellard 已提交
178 179 180
		dup2(s, 0);
		dup2(s, 1);
		dup2(s, 2);
181
		for (s = getdtablesize() - 1; s >= 3; s--)
B
bellard 已提交
182
		   close(s);
183

B
bellard 已提交
184
		i = 0;
185
		bptr = qemu_strdup(ex); /* No need to free() this */
B
bellard 已提交
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
		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);
201

202
                argv[i] = NULL;
203
		execvp(argv[0], (char **)argv);
204

B
bellard 已提交
205
		/* Ooops, failed, let's tell the user why */
206 207
        fprintf(stderr, "Error: execvp of %s failed: %s\n",
                argv[0], strerror(errno));
B
bellard 已提交
208 209
		close(0); close(1); close(2); /* XXX */
		exit(1);
210

B
bellard 已提交
211
	 default:
212
		qemu_add_child_watch(pid);
B
bellard 已提交
213 214 215 216 217 218 219 220 221 222 223
		if (do_pty == 2) {
			close(s);
			so->s = master;
		} else {
			/*
			 * 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
		 	 */
224 225 226 227
                        do {
                            so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
                        } while (so->s < 0 && errno == EINTR);
                        closesocket(s);
B
bellard 已提交
228 229 230 231 232 233
			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));
		}
		fd_nonblock(so->s);
234

B
bellard 已提交
235
		/* Append the telnet options now */
236
                if (so->so_m != NULL && do_pty == 1)  {
B
bellard 已提交
237
			sbappend(so, so->so_m);
238
                        so->so_m = NULL;
B
bellard 已提交
239
		}
240

B
bellard 已提交
241 242 243 244 245 246 247 248 249 250 251
		return 1;
	}
}
#endif

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

B
bellard 已提交
253 254
	bptr = (char *)malloc(strlen(str)+1);
	strcpy(bptr, str);
255

B
bellard 已提交
256 257 258 259
	return bptr;
}
#endif

A
aliguori 已提交
260
#include "monitor.h"
261

262 263 264 265 266
void lprint(const char *format, ...)
{
    va_list args;

    va_start(args, format);
267
    monitor_vprintf(default_mon, format, args);
268 269
    va_end(args);
}
B
bellard 已提交
270 271

void
272
u_sleep(int usec)
B
bellard 已提交
273 274 275
{
	struct timeval t;
	fd_set fdset;
276

B
bellard 已提交
277
	FD_ZERO(&fdset);
278

B
bellard 已提交
279 280
	t.tv_sec = 0;
	t.tv_usec = usec * 1000;
281

B
bellard 已提交
282 283 284 285 286 287 288 289
	select(0, &fdset, &fdset, &fdset, &t);
}

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

void
290
fd_nonblock(int fd)
B
bellard 已提交
291 292
{
#ifdef FIONBIO
B
blueswir1 已提交
293
#ifdef _WIN32
B
Blue Swirl 已提交
294
        unsigned long opt = 1;
B
blueswir1 已提交
295 296 297
#else
        int opt = 1;
#endif
298

B
bellard 已提交
299
	ioctlsocket(fd, FIONBIO, &opt);
B
bellard 已提交
300 301
#else
	int opt;
302

B
bellard 已提交
303 304 305 306 307 308 309
	opt = fcntl(fd, F_GETFL, 0);
	opt |= O_NONBLOCK;
	fcntl(fd, F_SETFL, opt);
#endif
}

void
310
fd_block(int fd)
B
bellard 已提交
311 312
{
#ifdef FIONBIO
B
Blue Swirl 已提交
313 314 315
#ifdef _WIN32
        unsigned long opt = 0;
#else
B
bellard 已提交
316
	int opt = 0;
B
Blue Swirl 已提交
317
#endif
318

B
bellard 已提交
319
	ioctlsocket(fd, FIONBIO, &opt);
B
bellard 已提交
320 321
#else
	int opt;
322

B
bellard 已提交
323 324 325 326 327 328
	opt = fcntl(fd, F_GETFL, 0);
	opt &= ~O_NONBLOCK;
	fcntl(fd, F_SETFL, opt);
#endif
}

329
void slirp_connection_info(Slirp *slirp, Monitor *mon)
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
{
    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");

356
    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
        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);
    }

386
    for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) {
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
        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);
    }
}