diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 55f4e4a5ec657a017e3bf75299ad71fd1c968dd3 (patch) | |
tree | 550ce922ea0e125ac6a9738210ce2939bf2fe901 /slirp/slirp.c | |
parent | 413f05aaf54fa08c0ae7e997327a4f4a473c0a8d (diff) | |
download | external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.zip external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.tar.gz external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.tar.bz2 |
Initial Contribution
Diffstat (limited to 'slirp/slirp.c')
-rw-r--r-- | slirp/slirp.c | 540 |
1 files changed, 312 insertions, 228 deletions
diff --git a/slirp/slirp.c b/slirp/slirp.c index 6ba753e..d6eaac4 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -1,9 +1,17 @@ #include "slirp.h" +#include "proxy_common.h" +#include "android_utils.h" /* for dprint */ +#include "android.h" + +#define D(...) VERBOSE_PRINT(slirp,__VA_ARGS__) +#define DN(...) do { if (VERBOSE_CHECK(slirp)) dprintn(__VA_ARGS__); } while (0) /* host address */ struct in_addr our_addr; /* host dns address */ -struct in_addr dns_addr; +struct in_addr dns_addr[DNS_ADDR_MAX]; +int dns_addr_count; + /* host loopback address */ struct in_addr loopback_addr; @@ -12,36 +20,50 @@ struct in_addr special_addr; /* virtual address alias for host */ struct in_addr alias_addr; -const uint8_t special_ethaddr[6] = { +const uint8_t special_ethaddr[6] = { 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 }; -uint8_t client_ethaddr[6]; +uint8_t client_ethaddr[6] = { + 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 +}; int do_slowtimo; int link_up; struct timeval tt; FILE *lfd; -struct ex_list *exec_list; /* XXX: suppress those select globals */ fd_set *global_readfds, *global_writefds, *global_xfds; char slirp_hostname[33]; +int slirp_add_dns_server(struct in_addr new_dns_addr) +{ + if (dns_addr_count >= DNS_ADDR_MAX) + return -1; + + dns_addr[dns_addr_count++] = new_dns_addr; + return 0; +} + + #ifdef _WIN32 -static int get_dns_addr(struct in_addr *pdns_addr) +int slirp_get_system_dns_servers() { FIXED_INFO *FixedInfo=NULL; ULONG BufLen; DWORD ret; IP_ADDR_STRING *pIPAddr; struct in_addr tmp_addr; - + + if (dns_addr_count > 0) + return dns_addr_count; + FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); BufLen = sizeof(FIXED_INFO); - + if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) { if (FixedInfo) { GlobalFree(FixedInfo); @@ -49,7 +71,7 @@ static int get_dns_addr(struct in_addr *pdns_addr) } FixedInfo = GlobalAlloc(GPTR, BufLen); } - + if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) { printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret ); if (FixedInfo) { @@ -58,84 +80,114 @@ static int get_dns_addr(struct in_addr *pdns_addr) } return -1; } - + + D( "DNS Servers:"); pIPAddr = &(FixedInfo->DnsServerList); - inet_aton(pIPAddr->IpAddress.String, &tmp_addr); - *pdns_addr = tmp_addr; -#if 0 - printf( "DNS Servers:\n" ); - printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String ); - - pIPAddr = FixedInfo -> DnsServerList.Next; - while ( pIPAddr ) { - printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String ); - pIPAddr = pIPAddr ->Next; + while (pIPAddr && dns_addr_count < DNS_ADDR_MAX) { + D( " %s", pIPAddr->IpAddress.String ); + inet_aton(pIPAddr->IpAddress.String, &tmp_addr); + if (tmp_addr.s_addr == loopback_addr.s_addr) + tmp_addr = our_addr; + if (dns_addr_count < DNS_ADDR_MAX) + dns_addr[dns_addr_count++] = tmp_addr; + pIPAddr = pIPAddr->Next; } -#endif + if (FixedInfo) { GlobalFree(FixedInfo); FixedInfo = NULL; } - return 0; + if (dns_addr_count <= 0) + return -1; + + return dns_addr_count; } #else -static int get_dns_addr(struct in_addr *pdns_addr) +int slirp_get_system_dns_servers(void) { char buff[512]; char buff2[256]; FILE *f; - int found = 0; struct in_addr tmp_addr; - + + if (dns_addr_count > 0) + return dns_addr_count; + +#ifdef CONFIG_DARWIN + /* on Darwin /etc/resolv.conf is a symlink to /private/var/run/resolv.conf + * in some siutations, the symlink can be destroyed and the system will not + * re-create it. Darwin-aware applications will continue to run, but "legacy" + * Unix ones will not. + */ + f = fopen("/private/var/run/resolv.conf", "r"); + if (!f) + f = fopen("/etc/resolv.conf", "r"); /* desperate attempt to sanity */ +#else f = fopen("/etc/resolv.conf", "r"); +#endif if (!f) return -1; - lprint("IP address of your DNS(s): "); + DN("emulator: IP address of your DNS(s): "); while (fgets(buff, 512, f) != NULL) { if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) { if (!inet_aton(buff2, &tmp_addr)) continue; if (tmp_addr.s_addr == loopback_addr.s_addr) tmp_addr = our_addr; - /* If it's the first one, set it to dns_addr */ - if (!found) - *pdns_addr = tmp_addr; - else - lprint(", "); - if (++found > 3) { - lprint("(more)"); + if (dns_addr_count < DNS_ADDR_MAX) { + dns_addr[dns_addr_count++] = tmp_addr; + if (dns_addr_count > 1) + DN(", "); + DN("%s", inet_ntoa(tmp_addr)); + } else { + DN("(more)"); break; - } else - lprint("%s", inet_ntoa(tmp_addr)); + } } } + DN("\n"); fclose(f); - if (!found) + + if (!dns_addr_count) return -1; - return 0; + + return dns_addr_count; } #endif -#ifdef _WIN32 -void slirp_cleanup(void) -{ - WSACleanup(); -} -#endif +extern void slirp_init_shapers(); void slirp_init(void) { - // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); - -#ifdef _WIN32 +#if DEBUG + int slirp_logmask = 0; + char slirp_logfile[512]; + { - WSADATA Data; - WSAStartup(MAKEWORD(2,0), &Data); - atexit(slirp_cleanup); + const char* env = getenv( "ANDROID_SLIRP_LOGMASK" ); + if (env != NULL) + slirp_logmask = atoi(env); + else if (VERBOSE_CHECK(slirp)) + slirp_logmask = DEBUG_DEFAULT; + } + + { + char* p = slirp_logfile; + char* end = p + sizeof(slirp_logfile); + + p = bufprint_temp_file( p, end, "slirp.log" ); + if (p >= end) { + dprint( "cannot create slirp log file in temporary directory" ); + slirp_logmask = 0; + } + } + if (slirp_logmask) { + dprint( "sending slirp logs with mask %x to %s", slirp_logmask, slirp_logfile ); + debug_init( slirp_logfile, slirp_logmask ); } #endif @@ -145,19 +197,24 @@ void slirp_init(void) ip_init(); /* Initialise mbufs *after* setting the MTU */ - m_init(); + mbuf_init(); /* set default addresses */ inet_aton("127.0.0.1", &loopback_addr); - if (get_dns_addr(&dns_addr) < 0) { - dns_addr = loopback_addr; - fprintf (stderr, "Warning: No DNS servers found\n"); + if (dns_addr_count == 0) { + if (slirp_get_system_dns_servers() < 0) { + dns_addr[0] = loopback_addr; + dns_addr_count = 1; + fprintf (stderr, "Warning: No DNS servers found\n"); + } } inet_aton(CTL_SPECIAL, &special_addr); alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); getouraddr(); + + slirp_init_shapers(); } #define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) @@ -180,16 +237,16 @@ static void updtime(void) static void updtime(void) { gettimeofday(&tt, 0); - + curtime = (u_int)tt.tv_sec * (u_int)1000; curtime += (u_int)tt.tv_usec / (u_int)1000; - + if ((tt.tv_usec % 1000) >= 500) curtime++; } #endif -void slirp_select_fill(int *pnfds, +void slirp_select_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds) { struct socket *so, *so_next; @@ -201,143 +258,158 @@ void slirp_select_fill(int *pnfds, global_readfds = NULL; global_writefds = NULL; global_xfds = NULL; - + nfds = *pnfds; - /* - * First, TCP sockets - */ - do_slowtimo = 0; - if (link_up) { - /* - * *_slowtimo needs calling if there are IP fragments - * in the fragment queue, or there are TCP connections active - */ - do_slowtimo = ((tcb.so_next != &tcb) || - ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next)); - - for (so = tcb.so_next; so != &tcb; so = so_next) { - so_next = so->so_next; - - /* - * See if we need a tcp_fasttimo - */ - if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) - time_fasttimo = curtime; /* Flag when we want a fasttimo */ - - /* - * NOFDREF can include still connecting to local-host, - * newly socreated() sockets etc. Don't want to select these. - */ - if (so->so_state & SS_NOFDREF || so->s == -1) - continue; - - /* - * Set for reading sockets which are accepting - */ - if (so->so_state & SS_FACCEPTCONN) { + /* + * First, TCP sockets + */ + do_slowtimo = 0; + if (link_up) { + /* + * *_slowtimo needs calling if there are IP fragments + * in the fragment queue, or there are TCP connections active + */ + do_slowtimo = ((tcb.so_next != &tcb) || + ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next)); + + for (so = tcb.so_next; so != &tcb; so = so_next) { + so_next = so->so_next; + + /* + * See if we need a tcp_fasttimo + */ + if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) + time_fasttimo = curtime; /* Flag when we want a fasttimo */ + + /* + * NOFDREF can include still connecting to local-host, + * newly socreated() sockets etc. Don't want to select these. + */ + if (so->so_state & SS_NOFDREF || so->s == -1) + continue; + + /* + * don't register proxified socked connections here + */ + if ((so->so_state & SS_PROXIFIED) != 0) + continue; + + /* + * Set for reading sockets which are accepting + */ + if (so->so_state & SS_FACCEPTCONN) { FD_SET(so->s, readfds); - UPD_NFDS(so->s); - continue; - } - - /* - * Set for writing sockets which are connecting - */ - if (so->so_state & SS_ISFCONNECTING) { - FD_SET(so->s, writefds); - UPD_NFDS(so->s); - continue; - } - - /* - * Set for writing if we are connected, can send more, and - * we have something to send - */ - if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { - FD_SET(so->s, writefds); - UPD_NFDS(so->s); - } - - /* - * Set for reading (and urgent data) if we are connected, can - * receive more, and we have room for it XXX /2 ? - */ - if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) { - FD_SET(so->s, readfds); - FD_SET(so->s, xfds); - UPD_NFDS(so->s); - } - } - - /* - * UDP sockets - */ - for (so = udb.so_next; so != &udb; so = so_next) { - so_next = so->so_next; - - /* - * See if it's timed out - */ - if (so->so_expire) { - if (so->so_expire <= curtime) { - udp_detach(so); - continue; - } else - do_slowtimo = 1; /* Let socket expire */ - } - - /* - * When UDP packets are received from over the - * link, they're sendto()'d straight away, so - * no need for setting for writing - * Limit the number of packets queued by this session - * to 4. Note that even though we try and limit this - * to 4 packets, the session could have more queued - * if the packets needed to be fragmented - * (XXX <= 4 ?) - */ - if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { - FD_SET(so->s, readfds); - UPD_NFDS(so->s); - } - } - } - - /* - * Setup timeout to use minimum CPU usage, especially when idle - */ - - /* - * First, see the timeout needed by *timo - */ - timeout.tv_sec = 0; - timeout.tv_usec = -1; - /* - * If a slowtimo is needed, set timeout to 500ms from the last - * slow timeout. If a fast timeout is needed, set timeout within - * 200ms of when it was requested. - */ - if (do_slowtimo) { - /* XXX + 10000 because some select()'s aren't that accurate */ - timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000; - if (timeout.tv_usec < 0) - timeout.tv_usec = 0; - else if (timeout.tv_usec > 510000) - timeout.tv_usec = 510000; - - /* Can only fasttimo if we also slowtimo */ - if (time_fasttimo) { - tmp_time = (200 - (curtime - time_fasttimo)) * 1000; - if (tmp_time < 0) - tmp_time = 0; - - /* Choose the smallest of the 2 */ - if (tmp_time < timeout.tv_usec) - timeout.tv_usec = (u_int)tmp_time; - } - } + UPD_NFDS(so->s); + continue; + } + + /* + * Set for writing sockets which are connecting + */ + if (so->so_state & SS_ISFCONNECTING) { + FD_SET(so->s, writefds); + UPD_NFDS(so->s); + continue; + } + + /* + * Set for writing if we are connected, can send more, and + * we have something to send + */ + if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { + FD_SET(so->s, writefds); + UPD_NFDS(so->s); + } + + /* + * Set for reading (and urgent data) if we are connected, can + * receive more, and we have room for it XXX /2 ? + */ + if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) { + FD_SET(so->s, readfds); + FD_SET(so->s, xfds); + UPD_NFDS(so->s); + } + } + + /* + * UDP sockets + */ + for (so = udb.so_next; so != &udb; so = so_next) { + so_next = so->so_next; + + if ((so->so_state & SS_PROXIFIED) != 0) + continue; + + /* + * See if it's timed out + */ + if (so->so_expire) { + if (so->so_expire <= curtime) { + udp_detach(so); + continue; + } else + do_slowtimo = 1; /* Let socket expire */ + } + + /* + * When UDP packets are received from over the + * link, they're sendto()'d straight away, so + * no need for setting for writing + * Limit the number of packets queued by this session + * to 4. Note that even though we try and limit this + * to 4 packets, the session could have more queued + * if the packets needed to be fragmented + * (XXX <= 4 ?) + */ + if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { + FD_SET(so->s, readfds); + UPD_NFDS(so->s); + } + } + } + + /* + * Setup timeout to use minimum CPU usage, especially when idle + */ + + /* + * First, see the timeout needed by *timo + */ + timeout.tv_sec = 0; + timeout.tv_usec = -1; + /* + * If a slowtimo is needed, set timeout to 500ms from the last + * slow timeout. If a fast timeout is needed, set timeout within + * 200ms of when it was requested. + */ + if (do_slowtimo) { + /* XXX + 10000 because some select()'s aren't that accurate */ + timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000; + if (timeout.tv_usec < 0) + timeout.tv_usec = 0; + else if (timeout.tv_usec > 510000) + timeout.tv_usec = 510000; + + /* Can only fasttimo if we also slowtimo */ + if (time_fasttimo) { + tmp_time = (200 - (curtime - time_fasttimo)) * 1000; + if (tmp_time < 0) + tmp_time = 0; + + /* Choose the smallest of the 2 */ + if (tmp_time < timeout.tv_usec) + timeout.tv_usec = (u_int)tmp_time; + } + } + + /* + * now, the proxified sockets + */ + proxy_manager_select_fill(&nfds, readfds, writefds, xfds); + *pnfds = nfds; -} +} void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) { @@ -350,9 +422,9 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) /* Update time */ updtime(); - + /* - * See if anything has timed out + * See if anything has timed out */ if (link_up) { if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) { @@ -365,7 +437,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) last_slowtimo = curtime; } } - + /* * Check sockets */ @@ -375,14 +447,21 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) */ for (so = tcb.so_next; so != &tcb; so = so_next) { so_next = so->so_next; - + /* * FD_ISSET is meaningless on these sockets * (and they can crash the program) */ if (so->so_state & SS_NOFDREF || so->s == -1) continue; - + + /* + * proxified sockets are polled later in this + * function. + */ + if ((so->so_state & SS_PROXIFIED) != 0) + continue; + /* * Check for URG data * This will soread as well, so no need to @@ -402,12 +481,12 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) continue; } /* else */ ret = soread(so); - + /* Output it if we read something */ if (ret > 0) tcp_output(sototcpcb(so)); } - + /* * Check sockets for writing */ @@ -418,34 +497,34 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) if (so->so_state & SS_ISFCONNECTING) { /* Connected */ so->so_state &= ~SS_ISFCONNECTING; - - ret = send(so->s, &ret, 0, 0); + + ret = send(so->s, (char*)&ret, 0, 0); if (ret < 0) { /* XXXXX Must fix, zero bytes is a NOP */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == ENOTCONN) continue; - + /* else failed */ so->so_state = SS_NOFDREF; } /* else so->so_state &= ~SS_ISFCONNECTING; */ - + /* * Continue tcp_input */ - tcp_input((struct mbuf *)NULL, sizeof(struct ip), so); + tcp_input((MBuf )NULL, sizeof(struct ip), so); /* continue; */ } else ret = sowrite(so); /* - * XXXXX If we wrote something (a lot), there + * XXXXX If we wrote something (a lot), there * could be a need for a window update. * In the worst case, the remote will send * a window probe to get things going again */ } - + /* * Probe a still-connecting, non-blocking socket * to check if it's still alive @@ -453,16 +532,16 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) #ifdef PROBE_CONN if (so->so_state & SS_ISFCONNECTING) { ret = recv(so->s, (char *)&ret, 0,0); - + if (ret < 0) { /* XXX */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == ENOTCONN) continue; /* Still connecting, continue */ - + /* else failed */ so->so_state = SS_NOFDREF; - + /* tcp_input will take care of it */ } else { ret = send(so->s, &ret, 0,0); @@ -475,13 +554,13 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) so->so_state = SS_NOFDREF; } else so->so_state &= ~SS_ISFCONNECTING; - + } - tcp_input((struct mbuf *)NULL, sizeof(struct ip),so); + tcp_input((MBuf )NULL, sizeof(struct ip),so); } /* SS_ISFCONNECTING */ #endif } - + /* * Now UDP sockets. * Incoming packets are sent straight away, they're not buffered. @@ -489,13 +568,21 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) */ for (so = udb.so_next; so != &udb; so = so_next) { so_next = so->so_next; - + + if ((so->so_state & SS_PROXIFIED) != 0) + continue; + if (so->s != -1 && FD_ISSET(so->s, readfds)) { sorecvfrom(so); } } } - + + /* + * Now the proxified sockets + */ + proxy_manager_poll(readfds, writefds, xfds); + /* * See if we can start outputting */ @@ -521,7 +608,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) #define ARPOP_REQUEST 1 /* ARP request */ #define ARPOP_REPLY 2 /* ARP reply */ -struct ethhdr +struct ethhdr { unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ unsigned char h_source[ETH_ALEN]; /* source ether addr */ @@ -553,18 +640,13 @@ void arp_input(const uint8_t *pkt, int pkt_len) struct ethhdr *reh = (struct ethhdr *)arp_reply; struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN); int ar_op; - struct ex_list *ex_ptr; ar_op = ntohs(ah->ar_op); switch(ar_op) { case ARPOP_REQUEST: if (!memcmp(ah->ar_tip, &special_addr, 3)) { - if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS) + if ( CTL_IS_DNS(ah->ar_tip[3]) || ah->ar_tip[3] == CTL_ALIAS) goto arp_ok; - for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { - if (ex_ptr->ex_addr == ah->ar_tip[3]) - goto arp_ok; - } return; arp_ok: /* XXX: make an ARP request to have the client address */ @@ -595,19 +677,19 @@ void arp_input(const uint8_t *pkt, int pkt_len) void slirp_input(const uint8_t *pkt, int pkt_len) { - struct mbuf *m; + MBuf m; int proto; if (pkt_len < ETH_HLEN) return; - + proto = ntohs(*(uint16_t *)(pkt + 12)); switch(proto) { case ETH_P_ARP: arp_input(pkt, pkt_len); break; case ETH_P_IP: - m = m_get(); + m = mbuf_alloc(); if (!m) return; /* Note: we add to align the IP header */ @@ -642,24 +724,26 @@ void if_encap(const uint8_t *ip_data, int ip_data_len) slirp_output(buf, ip_data_len + ETH_HLEN); } -int slirp_redir(int is_udp, int host_port, +int slirp_redir(int is_udp, int host_port, struct in_addr guest_addr, int guest_port) { if (is_udp) { - if (!udp_listen(htons(host_port), guest_addr.s_addr, + if (!udp_listen(htons(host_port), guest_addr.s_addr, htons(guest_port), 0)) return -1; } else { - if (!solisten(htons(host_port), guest_addr.s_addr, + if (!solisten(htons(host_port), guest_addr.s_addr, htons(guest_port), 0)) return -1; } return 0; } -int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, - int guest_port) +int slirp_unredir(int is_udp, int host_port) { - return add_exec(&exec_list, do_pty, (char *)args, - addr_low_byte, htons(guest_port)); + if (is_udp) + return udp_unlisten( host_port ); + else + return sounlisten( host_port ); } + |