|
|
1.1 ! root 1: #include "slirp.h" ! 2: ! 3: /* host address */ ! 4: struct in_addr our_addr; ! 5: /* host dns address */ ! 6: struct in_addr dns_addr; ! 7: /* host loopback address */ ! 8: struct in_addr loopback_addr; ! 9: ! 10: /* address for slirp virtual addresses */ ! 11: struct in_addr special_addr; ! 12: /* virtual address alias for host */ ! 13: struct in_addr alias_addr; ! 14: ! 15: const uint8_t special_ethaddr[6] = { ! 16: 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 ! 17: }; ! 18: ! 19: uint8_t client_ethaddr[6]; ! 20: ! 21: int do_slowtimo; ! 22: int link_up; ! 23: struct timeval tt; ! 24: FILE *lfd; ! 25: struct ex_list *exec_list; ! 26: ! 27: /* XXX: suppress those select globals */ ! 28: fd_set *global_readfds, *global_writefds, *global_xfds; ! 29: ! 30: char slirp_hostname[33]; ! 31: ! 32: #ifdef _WIN32 ! 33: ! 34: static int get_dns_addr(struct in_addr *pdns_addr) ! 35: { ! 36: FIXED_INFO *FixedInfo=NULL; ! 37: ULONG BufLen; ! 38: DWORD ret; ! 39: IP_ADDR_STRING *pIPAddr; ! 40: struct in_addr tmp_addr; ! 41: ! 42: FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); ! 43: BufLen = sizeof(FIXED_INFO); ! 44: ! 45: if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) { ! 46: if (FixedInfo) { ! 47: GlobalFree(FixedInfo); ! 48: FixedInfo = NULL; ! 49: } ! 50: FixedInfo = GlobalAlloc(GPTR, BufLen); ! 51: } ! 52: ! 53: if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) { ! 54: printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret ); ! 55: if (FixedInfo) { ! 56: GlobalFree(FixedInfo); ! 57: FixedInfo = NULL; ! 58: } ! 59: return -1; ! 60: } ! 61: ! 62: pIPAddr = &(FixedInfo->DnsServerList); ! 63: inet_aton(pIPAddr->IpAddress.String, &tmp_addr); ! 64: *pdns_addr = tmp_addr; ! 65: #if 0 ! 66: printf( "DNS Servers:\n" ); ! 67: printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String ); ! 68: ! 69: pIPAddr = FixedInfo -> DnsServerList.Next; ! 70: while ( pIPAddr ) { ! 71: printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String ); ! 72: pIPAddr = pIPAddr ->Next; ! 73: } ! 74: #endif ! 75: if (FixedInfo) { ! 76: GlobalFree(FixedInfo); ! 77: FixedInfo = NULL; ! 78: } ! 79: return 0; ! 80: } ! 81: ! 82: #else ! 83: ! 84: static int get_dns_addr(struct in_addr *pdns_addr) ! 85: { ! 86: char buff[512]; ! 87: char buff2[256+1]; ! 88: FILE *f; ! 89: int found = 0; ! 90: struct in_addr tmp_addr; ! 91: ! 92: f = fopen("/etc/resolv.conf", "r"); ! 93: if (!f) ! 94: return -1; ! 95: ! 96: lprint("IP address of your DNS(s): "); ! 97: while (fgets(buff, 512, f) != NULL) { ! 98: if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) { ! 99: if (!inet_aton(buff2, &tmp_addr)) ! 100: continue; ! 101: if (tmp_addr.s_addr == loopback_addr.s_addr) ! 102: tmp_addr = our_addr; ! 103: /* If it's the first one, set it to dns_addr */ ! 104: if (!found) ! 105: *pdns_addr = tmp_addr; ! 106: else ! 107: lprint(", "); ! 108: if (++found > 3) { ! 109: lprint("(more)"); ! 110: break; ! 111: } else ! 112: lprint("%s", inet_ntoa(tmp_addr)); ! 113: } ! 114: } ! 115: fclose(f); ! 116: if (!found) ! 117: return -1; ! 118: return 0; ! 119: } ! 120: ! 121: #endif ! 122: ! 123: #ifdef _WIN32 ! 124: static void slirp_cleanup(void) ! 125: { ! 126: WSACleanup(); ! 127: } ! 128: #endif ! 129: ! 130: int slirp_init(void) ! 131: { ! 132: // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); ! 133: ! 134: #ifdef _WIN32 ! 135: { ! 136: WSADATA Data; ! 137: WSAStartup(MAKEWORD(2,0), &Data); ! 138: atexit(slirp_cleanup); ! 139: } ! 140: #endif ! 141: ! 142: link_up = 1; ! 143: ! 144: if_init(); ! 145: ip_init(); ! 146: ! 147: /* Initialise mbufs *after* setting the MTU */ ! 148: m_init(); ! 149: ! 150: /* set default addresses */ ! 151: inet_aton("127.0.0.1", &loopback_addr); ! 152: ! 153: if (get_dns_addr(&dns_addr) < 0) ! 154: return -1; ! 155: ! 156: inet_aton(CTL_SPECIAL, &special_addr); ! 157: alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); ! 158: getouraddr(); ! 159: return 0; ! 160: } ! 161: ! 162: #define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) ! 163: #define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) ! 164: #define UPD_NFDS(x) if (nfds < (x)) nfds = (x) ! 165: ! 166: /* ! 167: * curtime kept to an accuracy of 1ms ! 168: */ ! 169: #ifdef _WIN32 ! 170: static void updtime(void) ! 171: { ! 172: struct _timeb tb; ! 173: ! 174: _ftime(&tb); ! 175: curtime = (u_int)tb.time * (u_int)1000; ! 176: curtime += (u_int)tb.millitm; ! 177: } ! 178: #else ! 179: static void updtime(void) ! 180: { ! 181: gettimeofday(&tt, 0); ! 182: ! 183: curtime = (u_int)tt.tv_sec * (u_int)1000; ! 184: curtime += (u_int)tt.tv_usec / (u_int)1000; ! 185: ! 186: if ((tt.tv_usec % 1000) >= 500) ! 187: curtime++; ! 188: } ! 189: #endif ! 190: ! 191: int slirp_select_fill(int *pnfds, ! 192: fd_set *readfds, fd_set *writefds, fd_set *xfds) ! 193: { ! 194: struct socket *so, *so_next; ! 195: int nfds; ! 196: int timeout, tmp_time; ! 197: ! 198: /* fail safe */ ! 199: global_readfds = NULL; ! 200: global_writefds = NULL; ! 201: global_xfds = NULL; ! 202: ! 203: nfds = *pnfds; ! 204: /* ! 205: * First, TCP sockets ! 206: */ ! 207: do_slowtimo = 0; ! 208: if (link_up) { ! 209: /* ! 210: * *_slowtimo needs calling if there are IP fragments ! 211: * in the fragment queue, or there are TCP connections active ! 212: */ ! 213: do_slowtimo = ((tcb.so_next != &tcb) || ! 214: (&ipq.ip_link != ipq.ip_link.next)); ! 215: ! 216: for (so = tcb.so_next; so != &tcb; so = so_next) { ! 217: so_next = so->so_next; ! 218: ! 219: /* ! 220: * See if we need a tcp_fasttimo ! 221: */ ! 222: if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) ! 223: time_fasttimo = curtime; /* Flag when we want a fasttimo */ ! 224: ! 225: /* ! 226: * NOFDREF can include still connecting to local-host, ! 227: * newly socreated() sockets etc. Don't want to select these. ! 228: */ ! 229: if (so->so_state & SS_NOFDREF || so->s == -1) ! 230: continue; ! 231: ! 232: /* ! 233: * Set for reading sockets which are accepting ! 234: */ ! 235: if (so->so_state & SS_FACCEPTCONN) { ! 236: FD_SET(so->s, readfds); ! 237: UPD_NFDS(so->s); ! 238: continue; ! 239: } ! 240: ! 241: /* ! 242: * Set for writing sockets which are connecting ! 243: */ ! 244: if (so->so_state & SS_ISFCONNECTING) { ! 245: FD_SET(so->s, writefds); ! 246: UPD_NFDS(so->s); ! 247: continue; ! 248: } ! 249: ! 250: /* ! 251: * Set for writing if we are connected, can send more, and ! 252: * we have something to send ! 253: */ ! 254: if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { ! 255: FD_SET(so->s, writefds); ! 256: UPD_NFDS(so->s); ! 257: } ! 258: ! 259: /* ! 260: * Set for reading (and urgent data) if we are connected, can ! 261: * receive more, and we have room for it XXX /2 ? ! 262: */ ! 263: if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) { ! 264: FD_SET(so->s, readfds); ! 265: FD_SET(so->s, xfds); ! 266: UPD_NFDS(so->s); ! 267: } ! 268: } ! 269: ! 270: /* ! 271: * UDP sockets ! 272: */ ! 273: for (so = udb.so_next; so != &udb; so = so_next) { ! 274: so_next = so->so_next; ! 275: ! 276: /* ! 277: * See if it's timed out ! 278: */ ! 279: if (so->so_expire) { ! 280: if (so->so_expire <= curtime) { ! 281: udp_detach(so); ! 282: continue; ! 283: } else ! 284: do_slowtimo = 1; /* Let socket expire */ ! 285: } ! 286: ! 287: /* ! 288: * When UDP packets are received from over the ! 289: * link, they're sendto()'d straight away, so ! 290: * no need for setting for writing ! 291: * Limit the number of packets queued by this session ! 292: * to 4. Note that even though we try and limit this ! 293: * to 4 packets, the session could have more queued ! 294: * if the packets needed to be fragmented ! 295: * (XXX <= 4 ?) ! 296: */ ! 297: if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { ! 298: FD_SET(so->s, readfds); ! 299: UPD_NFDS(so->s); ! 300: } ! 301: } ! 302: } ! 303: ! 304: /* ! 305: * Setup timeout to use minimum CPU usage, especially when idle ! 306: */ ! 307: ! 308: timeout = -1; ! 309: ! 310: /* ! 311: * If a slowtimo is needed, set timeout to 5ms from the last ! 312: * slow timeout. If a fast timeout is needed, set timeout within ! 313: * 2ms of when it was requested. ! 314: */ ! 315: # define SLOW_TIMO 5 ! 316: # define FAST_TIMO 2 ! 317: if (do_slowtimo) { ! 318: timeout = (SLOW_TIMO - (curtime - last_slowtimo)) * 1000; ! 319: if (timeout < 0) ! 320: timeout = 0; ! 321: else if (timeout > (SLOW_TIMO * 1000)) ! 322: timeout = SLOW_TIMO * 1000; ! 323: ! 324: /* Can only fasttimo if we also slowtimo */ ! 325: if (time_fasttimo) { ! 326: tmp_time = (FAST_TIMO - (curtime - time_fasttimo)) * 1000; ! 327: if (tmp_time < 0) ! 328: tmp_time = 0; ! 329: ! 330: /* Choose the smallest of the 2 */ ! 331: if (tmp_time < timeout) ! 332: timeout = tmp_time; ! 333: } ! 334: } ! 335: *pnfds = nfds; ! 336: ! 337: /* ! 338: * Adjust the timeout to make the minimum timeout ! 339: * 2ms (XXX?) to lessen the CPU load ! 340: */ ! 341: if (timeout < (FAST_TIMO * 1000)) ! 342: timeout = FAST_TIMO * 1000; ! 343: ! 344: return timeout; ! 345: } ! 346: ! 347: void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) ! 348: { ! 349: struct socket *so, *so_next; ! 350: int ret; ! 351: ! 352: global_readfds = readfds; ! 353: global_writefds = writefds; ! 354: global_xfds = xfds; ! 355: ! 356: /* Update time */ ! 357: updtime(); ! 358: ! 359: /* ! 360: * See if anything has timed out ! 361: */ ! 362: if (link_up) { ! 363: if (time_fasttimo && ((curtime - time_fasttimo) >= FAST_TIMO)) { ! 364: tcp_fasttimo(); ! 365: time_fasttimo = 0; ! 366: } ! 367: if (do_slowtimo && ((curtime - last_slowtimo) >= SLOW_TIMO)) { ! 368: ip_slowtimo(); ! 369: tcp_slowtimo(); ! 370: last_slowtimo = curtime; ! 371: } ! 372: } ! 373: ! 374: /* ! 375: * Check sockets ! 376: */ ! 377: if (link_up) { ! 378: /* ! 379: * Check TCP sockets ! 380: */ ! 381: for (so = tcb.so_next; so != &tcb; so = so_next) { ! 382: so_next = so->so_next; ! 383: ! 384: /* ! 385: * FD_ISSET is meaningless on these sockets ! 386: * (and they can crash the program) ! 387: */ ! 388: if (so->so_state & SS_NOFDREF || so->s == -1) ! 389: continue; ! 390: ! 391: /* ! 392: * Check for URG data ! 393: * This will soread as well, so no need to ! 394: * test for readfds below if this succeeds ! 395: */ ! 396: if (FD_ISSET(so->s, xfds)) ! 397: sorecvoob(so); ! 398: /* ! 399: * Check sockets for reading ! 400: */ ! 401: else if (FD_ISSET(so->s, readfds)) { ! 402: /* ! 403: * Check for incoming connections ! 404: */ ! 405: if (so->so_state & SS_FACCEPTCONN) { ! 406: tcp_connect(so); ! 407: continue; ! 408: } /* else */ ! 409: ret = soread(so); ! 410: ! 411: /* Output it if we read something */ ! 412: if (ret > 0) ! 413: tcp_output(sototcpcb(so)); ! 414: } ! 415: ! 416: /* ! 417: * Check sockets for writing ! 418: */ ! 419: if (FD_ISSET(so->s, writefds)) { ! 420: /* ! 421: * Check for non-blocking, still-connecting sockets ! 422: */ ! 423: if (so->so_state & SS_ISFCONNECTING) { ! 424: /* Connected */ ! 425: so->so_state &= ~SS_ISFCONNECTING; ! 426: ! 427: ret = send(so->s, (char*)&ret, 0, 0); ! 428: if (ret < 0) { ! 429: /* XXXXX Must fix, zero bytes is a NOP */ ! 430: int error = WSAGetLastError(); ! 431: if (error == EAGAIN || error == WSAEWOULDBLOCK || ! 432: error == WSAEINPROGRESS || error == WSAENOTCONN) ! 433: continue; ! 434: ! 435: /* else failed */ ! 436: so->so_state = SS_NOFDREF; ! 437: } ! 438: /* else so->so_state &= ~SS_ISFCONNECTING; */ ! 439: ! 440: /* ! 441: * Continue tcp_input ! 442: */ ! 443: tcp_input((struct mbuf *)NULL, sizeof(struct ip), so); ! 444: /* continue; */ ! 445: } ! 446: else ! 447: ret = sowrite(so); ! 448: /* ! 449: * XXXXX If we wrote something (a lot), there ! 450: * could be a need for a window update. ! 451: * In the worst case, the remote will send ! 452: * a window probe to get things going again ! 453: */ ! 454: } ! 455: ! 456: /* ! 457: * Probe a still-connecting, non-blocking socket ! 458: * to check if it's still alive ! 459: */ ! 460: #ifdef PROBE_CONN ! 461: if (so->so_state & SS_ISFCONNECTING) { ! 462: ret = recv(so->s, (char *)&ret, 0, 0); ! 463: ! 464: if (ret < 0) { ! 465: /* XXX */ ! 466: int error = WSAGetLastError(); ! 467: if (error == EAGAIN || error == WSAEWOULDBLOCK || ! 468: error == WSAEINPROGRESS || error == WSAENOTCONN) ! 469: continue; /* Still connecting, continue */ ! 470: ! 471: /* else failed */ ! 472: so->so_state = SS_NOFDREF; ! 473: ! 474: /* tcp_input will take care of it */ ! 475: } ! 476: else { ! 477: ret = send(so->s, &ret, 0, 0); ! 478: if (ret < 0) { ! 479: /* XXX */ ! 480: int error = WSAGetLastError(); ! 481: if (error == EAGAIN || error == WSAEWOULDBLOCK || ! 482: error == WSAEINPROGRESS || error == WSAENOTCONN) ! 483: continue; ! 484: /* else failed */ ! 485: so->so_state = SS_NOFDREF; ! 486: } ! 487: else ! 488: so->so_state &= ~SS_ISFCONNECTING; ! 489: ! 490: } ! 491: tcp_input((struct mbuf *)NULL, sizeof(struct ip), so); ! 492: } /* SS_ISFCONNECTING */ ! 493: #endif ! 494: } ! 495: ! 496: /* ! 497: * Now UDP sockets. ! 498: * Incoming packets are sent straight away, they're not buffered. ! 499: * Incoming UDP data isn't buffered either. ! 500: */ ! 501: for (so = udb.so_next; so != &udb; so = so_next) { ! 502: so_next = so->so_next; ! 503: ! 504: if (so->s != -1 && FD_ISSET(so->s, readfds)) { ! 505: sorecvfrom(so); ! 506: } ! 507: } ! 508: } ! 509: ! 510: /* ! 511: * See if we can start outputting ! 512: */ ! 513: if (if_queued && link_up) ! 514: if_start(); ! 515: ! 516: /* clear global file descriptor sets. ! 517: * these reside on the stack in vl.c ! 518: * so they're unusable if we're not in ! 519: * slirp_select_fill or slirp_select_poll. ! 520: */ ! 521: global_readfds = NULL; ! 522: global_writefds = NULL; ! 523: global_xfds = NULL; ! 524: } ! 525: ! 526: #define ETH_ALEN 6 ! 527: #define ETH_HLEN 14 ! 528: ! 529: #define ETH_P_IP 0x0800 /* Internet Protocol packet */ ! 530: #define ETH_P_ARP 0x0806 /* Address Resolution packet */ ! 531: ! 532: #define ARPOP_REQUEST 1 /* ARP request */ ! 533: #define ARPOP_REPLY 2 /* ARP reply */ ! 534: ! 535: struct ethhdr ! 536: { ! 537: unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ ! 538: unsigned char h_source[ETH_ALEN]; /* source ether addr */ ! 539: unsigned short h_proto; /* packet type ID field */ ! 540: }; ! 541: ! 542: struct arphdr ! 543: { ! 544: unsigned short ar_hrd; /* format of hardware address */ ! 545: unsigned short ar_pro; /* format of protocol address */ ! 546: unsigned char ar_hln; /* length of hardware address */ ! 547: unsigned char ar_pln; /* length of protocol address */ ! 548: unsigned short ar_op; /* ARP opcode (command) */ ! 549: ! 550: /* ! 551: * Ethernet looks like this : This bit is variable sized however... ! 552: */ ! 553: unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ ! 554: unsigned char ar_sip[4]; /* sender IP address */ ! 555: unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ ! 556: unsigned char ar_tip[4]; /* target IP address */ ! 557: }; ! 558: ! 559: static void arp_input(const uint8_t *pkt, int pkt_len) ! 560: { ! 561: const struct ethhdr *eh = (const struct ethhdr *)pkt; ! 562: const struct arphdr *ah = (const struct arphdr *)(pkt + ETH_HLEN); ! 563: uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)]; ! 564: struct ethhdr *reh = (struct ethhdr *)arp_reply; ! 565: struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN); ! 566: int ar_op; ! 567: struct ex_list *ex_ptr; ! 568: ! 569: ar_op = ntohs(ah->ar_op); ! 570: switch(ar_op) { ! 571: case ARPOP_REQUEST: ! 572: if (!memcmp(ah->ar_tip, &special_addr, 3)) { ! 573: if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS) ! 574: goto arp_ok; ! 575: for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { ! 576: if (ex_ptr->ex_addr == ah->ar_tip[3]) ! 577: goto arp_ok; ! 578: } ! 579: return; ! 580: arp_ok: ! 581: /* XXX: make an ARP request to have the client address */ ! 582: memcpy(client_ethaddr, eh->h_source, ETH_ALEN); ! 583: ! 584: /* ARP request for alias/dns mac address */ ! 585: memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN); ! 586: memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1); ! 587: reh->h_source[5] = ah->ar_tip[3]; ! 588: reh->h_proto = htons(ETH_P_ARP); ! 589: ! 590: rah->ar_hrd = htons(1); ! 591: rah->ar_pro = htons(ETH_P_IP); ! 592: rah->ar_hln = ETH_ALEN; ! 593: rah->ar_pln = 4; ! 594: rah->ar_op = htons(ARPOP_REPLY); ! 595: memcpy(rah->ar_sha, reh->h_source, ETH_ALEN); ! 596: memcpy(rah->ar_sip, ah->ar_tip, 4); ! 597: memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN); ! 598: memcpy(rah->ar_tip, ah->ar_sip, 4); ! 599: slirp_output(arp_reply, sizeof(arp_reply)); ! 600: } ! 601: break; ! 602: default: ! 603: break; ! 604: } ! 605: } ! 606: ! 607: void slirp_input(const uint8_t *pkt, int pkt_len) ! 608: { ! 609: struct mbuf *m; ! 610: int proto; ! 611: ! 612: if (pkt_len < ETH_HLEN) ! 613: return; ! 614: ! 615: proto = (pkt[12] << 8) | pkt[13]; ! 616: switch(proto) { ! 617: case ETH_P_ARP: ! 618: arp_input(pkt, pkt_len); ! 619: break; ! 620: case ETH_P_IP: ! 621: m = m_get(); ! 622: if (!m) ! 623: return; ! 624: /* Note: we add to align the IP header */ ! 625: m->m_len = pkt_len + 2; ! 626: memcpy(m->m_data + 2, pkt, pkt_len); ! 627: ! 628: m->m_data += 2 + ETH_HLEN; ! 629: m->m_len -= 2 + ETH_HLEN; ! 630: ! 631: ip_input(m); ! 632: break; ! 633: default: ! 634: break; ! 635: } ! 636: } ! 637: ! 638: /* output the IP packet to the ethernet device */ ! 639: void if_encap(const uint8_t *ip_data, int ip_data_len) ! 640: { ! 641: uint8_t buf[1600]; ! 642: struct ethhdr *eh = (struct ethhdr *)buf; ! 643: ! 644: if (ip_data_len + ETH_HLEN > sizeof(buf)) ! 645: return; ! 646: ! 647: memcpy(eh->h_dest, client_ethaddr, ETH_ALEN); ! 648: memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1); ! 649: /* XXX: not correct */ ! 650: eh->h_source[5] = CTL_ALIAS; ! 651: eh->h_proto = htons(ETH_P_IP); ! 652: memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len); ! 653: slirp_output(buf, ip_data_len + ETH_HLEN); ! 654: } ! 655: ! 656: int slirp_redir(int is_udp, int host_port, ! 657: struct in_addr guest_addr, int guest_port) ! 658: { ! 659: if (is_udp) { ! 660: if (!udp_listen(htons(host_port), guest_addr.s_addr, ! 661: htons(guest_port), 0)) ! 662: return -1; ! 663: } else { ! 664: if (!solisten(htons(host_port), guest_addr.s_addr, ! 665: htons(guest_port), 0)) ! 666: return -1; ! 667: } ! 668: return 0; ! 669: } ! 670: ! 671: int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, ! 672: int guest_port) ! 673: { ! 674: return add_exec(&exec_list, do_pty, args, ! 675: addr_low_byte, htons(guest_port)); ! 676: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.