Move net.h to include/net/
+ Move net-android.c and net.c to net/
+ Rename net-checksum.c to net/checksum.c
+ Move sockets.h and shaper.h to include/android/
and sockets.c + shaper.c to android/
+ Move vgafont.h to ui/
Change-Id: I2659a919a316d3f95aac0f9924833eeee4cb5592
diff --git a/android/adb-server.c b/android/adb-server.c
index 41b2ffd..bc7baa1 100644
--- a/android/adb-server.c
+++ b/android/adb-server.c
@@ -15,7 +15,7 @@
*/
#include "qemu-common.h"
-#include "sockets.h"
+#include "android/sockets.h"
#include "iolooper.h"
#include "android/async-utils.h"
#include "android/utils/debug.h"
diff --git a/android/async-utils.h b/android/async-utils.h
index 30dfbe3..da5e506 100644
--- a/android/async-utils.h
+++ b/android/async-utils.h
@@ -17,7 +17,7 @@
#define ANDROID_ASYNC_UTILS_H
#include "android/looper.h"
-#include "sockets.h"
+#include "android/sockets.h"
/* A set of useful data types to perform asynchronous operations.
*
diff --git a/android/console.c b/android/console.c
index 07a59d2..51209cf 100644
--- a/android/console.c
+++ b/android/console.c
@@ -21,14 +21,14 @@
*
*/
-#include "sockets.h"
+#include "android/sockets.h"
#include "qemu-char.h"
#include "sysemu.h"
#include "android/android.h"
#include "cpu.h"
#include "hw/goldfish_device.h"
#include "hw/power_supply.h"
-#include "shaper.h"
+#include "android/shaper.h"
#include "modem_driver.h"
#include "android/gps.h"
#include "android/globals.h"
@@ -37,7 +37,7 @@
#include "android/utils/stralloc.h"
#include "android/config/config.h"
#include "tcpdump.h"
-#include "net.h"
+#include "net/net.h"
#include "monitor.h"
#include <stdlib.h>
diff --git a/android/core-init-utils.c b/android/core-init-utils.c
index 97d5f05..aa676f8 100644
--- a/android/core-init-utils.c
+++ b/android/core-init-utils.c
@@ -19,7 +19,7 @@
#include <stdlib.h>
#include <errno.h>
#include "qemu-common.h"
-#include "sockets.h"
+#include "android/sockets.h"
#include "android/android.h"
#include "android/core-init-utils.h"
#include "android/utils/bufprint.h"
diff --git a/android/hw-pipe-net.c b/android/hw-pipe-net.c
index 1c71f18..f1c1411 100644
--- a/android/hw-pipe-net.c
+++ b/android/hw-pipe-net.c
@@ -18,7 +18,7 @@
* guest clients to directly connect to a TCP port through /dev/qemu_pipe.
*/
-#include "sockets.h"
+#include "android/sockets.h"
#include "android/utils/assert.h"
#include "android/utils/panic.h"
#include "android/utils/system.h"
diff --git a/android/looper-generic.c b/android/looper-generic.c
index ddc0824..9fd4f0b 100644
--- a/android/looper-generic.c
+++ b/android/looper-generic.c
@@ -16,7 +16,7 @@
#include "android/utils/system.h"
#include "android/looper.h"
#include "iolooper.h"
-#include "sockets.h"
+#include "android/sockets.h"
#include <inttypes.h>
#include <limits.h>
#include <errno.h>
diff --git a/android/looper-qemu.c b/android/looper-qemu.c
index 6ea64ca..df40afe 100644
--- a/android/looper-qemu.c
+++ b/android/looper-qemu.c
@@ -17,7 +17,7 @@
#include "qemu-common.h"
#include "qemu/timer.h"
#include "qemu-char.h"
-#include "sockets.h" /* for socket_set_nonblock() */
+#include "android/sockets.h" /* for socket_set_nonblock() */
/**********************************************************************
**********************************************************************
diff --git a/android/main.c b/android/main.c
index 1ca94df..757a05f 100644
--- a/android/main.c
+++ b/android/main.c
@@ -18,7 +18,7 @@
#include <process.h>
#endif
-#include "sockets.h"
+#include "android/sockets.h"
#include "android/android.h"
#include "qemu-common.h"
diff --git a/android/protocol/attach-ui-impl.h b/android/protocol/attach-ui-impl.h
index 3adc83a..db63955 100644
--- a/android/protocol/attach-ui-impl.h
+++ b/android/protocol/attach-ui-impl.h
@@ -13,7 +13,7 @@
#ifndef _ANDROID_PROTOCOL_ATTACH_UI_IMPL_H
#define _ANDROID_PROTOCOL_ATTACH_UI_IMPL_H
-#include "sockets.h"
+#include "android/sockets.h"
/*
* Contains the UI-side implementation of the "attach-ui" service that is
diff --git a/android/protocol/core-commands-proxy.h b/android/protocol/core-commands-proxy.h
index 4283296..289421f 100644
--- a/android/protocol/core-commands-proxy.h
+++ b/android/protocol/core-commands-proxy.h
@@ -13,7 +13,7 @@
#ifndef _ANDROID_PROTOCOL_CORE_COMMANDS_PROXY_H
#define _ANDROID_PROTOCOL_CORE_COMMANDS_PROXY_H
-#include "sockets.h"
+#include "android/sockets.h"
/*
* Contains the UI-side implementation of the "ui-core-control" service that is
diff --git a/android/protocol/core-connection.c b/android/protocol/core-connection.c
index 6de5386..35f4d6a 100644
--- a/android/protocol/core-connection.c
+++ b/android/protocol/core-connection.c
@@ -12,7 +12,7 @@
#include <unistd.h>
-#include "sockets.h"
+#include "android/sockets.h"
#include "qemu-common.h"
#include "errno.h"
#include "iolooper.h"
diff --git a/android/protocol/ui-commands-impl.h b/android/protocol/ui-commands-impl.h
index f575bd0..717f6b6 100644
--- a/android/protocol/ui-commands-impl.h
+++ b/android/protocol/ui-commands-impl.h
@@ -13,7 +13,7 @@
#ifndef _ANDROID_PROTOCOL_UI_COMMANDS_IMPL_H
#define _ANDROID_PROTOCOL_UI_COMMANDS_IMPL_H
-#include "sockets.h"
+#include "android/sockets.h"
#include "android/looper.h"
#include "android/protocol/ui-commands.h"
diff --git a/android/shaper.c b/android/shaper.c
new file mode 100644
index 0000000..4dbb8ea
--- /dev/null
+++ b/android/shaper.c
@@ -0,0 +1,590 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/shaper.h"
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include <stdlib.h>
+
+#define SHAPER_CLOCK rt_clock
+#define SHAPER_CLOCK_UNIT 1000.
+
+static int
+_packet_is_internal( const uint8_t* data, size_t size )
+{
+ const uint8_t* end = data + size;
+
+ /* must have room for Mac + IP header */
+ if (data + 40 > end)
+ return 0;
+
+ if (data[12] != 0x08 || data[13] != 0x00 )
+ return 0;
+
+ /* must have valid IP header */
+ data += 14;
+ if ((data[0] >> 4) != 4 || (data[0] & 15) < 5)
+ return 0;
+
+ /* internal if both source and dest addresses are in 10.x.x.x */
+ return ( data[12] == 10 && data[16] == 10);
+}
+
+/* here's how we implement network shaping. we want to limit the network
+ * rate to a given constant MAX_RATE expressed as bits/second. this means
+ * that it takes 1/MAX_RATE seconds to send a single bit, and count*8/MAX_RATE
+ * seconds to send 'count' bytes.
+ *
+ * we're going to implement a scheme where, when we send a packet of
+ * 'count' bytes, no other packet will go through in the same direction for
+ * at least 'count*8/MAX_RATE' seconds. any successive packet that is "sent"
+ * in this interval is placed in a queue, associated to a timer
+ *
+ * there are different (queue/timer/rate) values for the input and output
+ * direction of the user vlan.
+ */
+typedef struct QueuedPacketRec_ {
+ int64_t expiration;
+ struct QueuedPacketRec_* next;
+ size_t size;
+ void* opaque;
+ void* data;
+} QueuedPacketRec, *QueuedPacket;
+
+
+static QueuedPacket
+queued_packet_create( const void* data,
+ size_t size,
+ void* opaque,
+ int do_copy )
+{
+ QueuedPacket packet;
+ size_t packet_size = sizeof(*packet);
+
+ if (do_copy)
+ packet_size += size;
+
+ packet = qemu_malloc(packet_size);
+ packet->next = NULL;
+ packet->expiration = 0;
+ packet->size = (size_t)size;
+ packet->opaque = opaque;
+
+ if (do_copy) {
+ packet->data = (void*)(packet+1);
+ memcpy( (char*)packet->data, (char*)data, packet->size );
+ } else {
+ packet->data = (void*)data;
+ }
+ return packet;
+}
+
+static void
+queued_packet_free( QueuedPacket packet )
+{
+ if (packet) {
+ qemu_free( packet );
+ }
+}
+
+typedef struct NetShaperRec_ {
+ QueuedPacket packets; /* list of queued packets, ordered by expiration date */
+ int num_packets;
+ int active; /* is this shaper active ? */
+ int64_t block_until;
+ double max_rate; /* max rate expressed in bytes/second */
+ double inv_rate; /* inverse of max rate */
+ QEMUTimer* timer; /* QEMU timer */
+
+ int do_copy;
+ NetShaperSendFunc send_func;
+
+} NetShaperRec;
+
+
+void
+netshaper_destroy( NetShaper shaper )
+{
+ if (shaper) {
+ shaper->active = 0;
+
+ while (shaper->packets) {
+ QueuedPacket packet = shaper->packets;
+ shaper->packets = packet->next;
+ packet->next = NULL;
+ queued_packet_free(packet);
+ }
+
+ qemu_del_timer(shaper->timer);
+ qemu_free_timer(shaper->timer);
+ shaper->timer = NULL;
+ qemu_free(shaper);
+ }
+}
+
+/* this function is called when the shaper's timer expires */
+static void
+netshaper_expires( NetShaper shaper )
+{
+ QueuedPacket packet;
+
+ while ((packet = shaper->packets) != NULL) {
+ int64_t now = qemu_get_clock_ms( SHAPER_CLOCK );
+
+ if (packet->expiration > now)
+ break;
+
+ shaper->packets = packet->next;
+ shaper->send_func( packet->data, packet->size, packet->opaque );
+ queued_packet_free(packet);
+ shaper->num_packets--;
+ }
+
+ /* reprogram timer if needed */
+ if (shaper->packets) {
+ shaper->block_until = shaper->packets->expiration;
+ qemu_mod_timer( shaper->timer, shaper->block_until );
+ } else {
+ shaper->block_until = -1;
+ }
+}
+
+
+NetShaper
+netshaper_create( int do_copy,
+ NetShaperSendFunc send_func )
+{
+ NetShaper shaper = qemu_malloc(sizeof(*shaper));
+
+ shaper->active = 0;
+ shaper->packets = NULL;
+ shaper->num_packets = 0;
+ shaper->timer = qemu_new_timer_ms( SHAPER_CLOCK,
+ (QEMUTimerCB*) netshaper_expires,
+ shaper );
+ shaper->send_func = send_func;
+ shaper->max_rate = 1e6;
+ shaper->inv_rate = 0.;
+
+ shaper->block_until = -1; /* magic value, means to not block */
+
+ return shaper;
+}
+
+void
+netshaper_set_rate( NetShaper shaper,
+ double rate )
+{
+ /* send all current packets when changing the rate */
+ while (shaper->packets) {
+ QueuedPacket packet = shaper->packets;
+ shaper->packets = packet->next;
+ shaper->send_func(packet->data, packet->size, packet->opaque);
+ qemu_free(packet);
+ shaper->num_packets = 0;
+ }
+
+ shaper->max_rate = rate;
+ if (rate > 1.) {
+ shaper->inv_rate = (8.*SHAPER_CLOCK_UNIT)/rate; /* qemu_get_clock returns time in ms */
+ shaper->active = 1; /* for the real-time clock */
+ } else {
+ shaper->active = 0;
+ }
+
+ shaper->block_until = -1;
+}
+
+void
+netshaper_send_aux( NetShaper shaper,
+ void* data,
+ size_t size,
+ void* opaque )
+{
+ int64_t now;
+
+ if (!shaper->active || _packet_is_internal(data, size)) {
+ shaper->send_func( data, size, opaque );
+ return;
+ }
+
+ now = qemu_get_clock_ms( SHAPER_CLOCK );
+ if (now >= shaper->block_until) {
+ shaper->send_func( data, size, opaque );
+ shaper->block_until = now + size*shaper->inv_rate;
+ //fprintf(stderr, "NETSHAPER: block for %.2fms\n", (shaper->block_until - now)*1.0 );
+ return;
+ }
+
+ /* create new packet, add it to the queue */
+ {
+ QueuedPacket packet;
+
+ packet = queued_packet_create( data, size, opaque, shaper->do_copy );
+
+ packet->expiration = shaper->block_until;
+
+ {
+ QueuedPacket *pnode, node;
+
+ pnode = &shaper->packets;
+ for (;;) {
+ node = *pnode;
+ if (node == NULL || node->expiration > packet->expiration )
+ break;
+ pnode = &node->next;
+ }
+ packet->next = *pnode;
+ *pnode = packet;
+
+ if (packet == shaper->packets)
+ qemu_mod_timer( shaper->timer, packet->expiration );
+ }
+ shaper->num_packets += 1;
+ }
+ shaper->block_until += size*shaper->inv_rate;
+ //fprintf(stderr, "NETSHAPER: block2 for %.2fms\n", (shaper->block_until - now)*1.0 );
+}
+
+void
+netshaper_send( NetShaper shaper,
+ void* data,
+ size_t size )
+{
+ netshaper_send_aux(shaper, data, size, NULL);
+}
+
+
+int
+netshaper_can_send( NetShaper shaper )
+{
+ int64_t now;
+
+ if (!shaper->active || shaper->block_until < 0)
+ return 1;
+
+ if (shaper->packets)
+ return 0;
+
+ now = qemu_get_clock_ms( SHAPER_CLOCK );
+ return (now >= shaper->block_until);
+}
+
+
+
+
+
+
+/* this type is used to model a session connection/state
+ * if session->packet is != NULL, then the connection is delayed
+ */
+typedef struct SessionRec_ {
+ int64_t expiration;
+ struct SessionRec_* next;
+ unsigned src_ip;
+ unsigned dst_ip;
+ unsigned short src_port;
+ unsigned short dst_port;
+ uint8_t protocol;
+ QueuedPacket packet;
+
+} SessionRec, *Session;
+
+#define _PROTOCOL_TCP 6
+#define _PROTOCOL_UDP 17
+
+
+
+static void
+session_free( Session session )
+{
+ if (session) {
+ if (session->packet) {
+ queued_packet_free(session->packet);
+ session->packet = NULL;
+ }
+ qemu_free( session );
+ }
+}
+
+
+#if 0 /* useful for debugging */
+static const char*
+session_to_string( Session session )
+{
+ static char temp[256];
+ const char* format = (session->protocol == _PROTOCOL_TCP) ? "TCP" : "UDP";
+ sprintf( temp, "%s[%d.%d.%d.%d:%d / %d.%d.%d.%d:%d]", format,
+ (session->src_ip >> 24) & 255, (session->src_ip >> 16) & 255,
+ (session->src_ip >> 8) & 255, (session->src_ip) & 255, session->src_port,
+ (session->dst_ip >> 24) & 255, (session->dst_ip >> 16) & 255,
+ (session->dst_ip >> 8) & 255, (session->dst_ip) & 255, session->dst_port);
+
+ return temp;
+}
+#endif
+
+/* returns TRUE if this corresponds to a SYN packet */
+int
+_packet_SYN_flags( const void* _data, size_t size, Session info )
+{
+ const uint8_t* data = (const uint8_t*)_data;
+ const uint8_t* end = data + size;
+
+ /* enough room for a Ethernet MAC packet ? */
+ if (data + 14 > end - 4)
+ return 0;
+
+ /* is it an IP packet ? */
+ if (data[12] != 0x8 || data[13] != 0)
+ return 0;
+
+ data += 14;
+ end -= 4;
+
+ if (data + 20 > end)
+ return 0;
+
+ /* IP version must be 4, and the header length in words at least 5 */
+ if ((data[0] & 0xF) < 5 || (data[0] >> 4) != 4)
+ return 0;
+
+ /* time-to-live must be > 0 */
+ if (data[8] == 0)
+ return 0;
+
+ /* must be TCP or UDP packet */
+ if (data[9] != _PROTOCOL_TCP && data[9] != _PROTOCOL_UDP)
+ return 0;
+
+ info->protocol = data[9];
+ info->src_ip = (data[12] << 24) | (data[13] << 16) | (data[14] << 8) | data[15];
+ info->dst_ip = (data[16] << 24) | (data[17] << 16) | (data[18] << 8) | data[19];
+
+ data += 4*(data[0] & 15);
+ if (data + 20 > end)
+ return 0;
+
+ info->src_port = (unsigned short)((data[0] << 8) | data[1]);
+ info->dst_port = (unsigned short)((data[2] << 8) | data[3]);
+
+ return (data[13] & 0x1f);
+}
+
+
+typedef struct NetDelayRec_
+{
+ Session sessions;
+ int num_sessions;
+ QEMUTimer* timer;
+ int active;
+ int min_ms;
+ int max_ms;
+
+ NetShaperSendFunc send_func;
+
+} NetDelayRec;
+
+
+static Session*
+netdelay_lookup_session( NetDelay delay, Session info )
+{
+ Session* pnode = &delay->sessions;
+ Session node;
+
+ for (;;) {
+ node = *pnode;
+ if (node == NULL)
+ break;
+
+ if (node->src_ip == info->src_ip &&
+ node->dst_ip == info->dst_ip &&
+ node->src_port == info->src_port &&
+ node->dst_port == info->dst_port &&
+ node->protocol == info->protocol )
+ break;
+
+ pnode = &node->next;
+ }
+ return pnode;
+}
+
+
+
+/* called by the delay's timer on expiration */
+static void
+netdelay_expires( NetDelay delay )
+{
+ Session session;
+ int64_t now = qemu_get_clock_ms( SHAPER_CLOCK );
+ int rearm = 0;
+ int64_t rearm_time = 0;
+
+ for (session = delay->sessions; session != NULL; session = session->next)
+ {
+ QueuedPacket packet = session->packet;
+
+ if (packet == NULL)
+ continue;
+
+ if (session->expiration <= now) {
+ /* send the SYN packet now */
+ //fprintf(stderr, "NetDelay:RST: sending creation for %s\n", session_to_string(session) );
+ delay->send_func( packet->data, packet->size, packet->opaque );
+ session->packet = NULL;
+ queued_packet_free( packet );
+ } else {
+ if (!rearm) {
+ rearm = 1;
+ rearm_time = session->expiration;
+ }
+ else if ( session->expiration < rearm_time )
+ rearm_time = session->expiration;
+ }
+ }
+
+ if (rearm)
+ qemu_mod_timer( delay->timer, rearm_time );
+}
+
+
+NetDelay
+netdelay_create( NetShaperSendFunc send_func )
+{
+ NetDelay delay = qemu_malloc(sizeof(*delay));
+
+ delay->sessions = NULL;
+ delay->num_sessions = 0;
+ delay->timer = qemu_new_timer_ms( SHAPER_CLOCK,
+ (QEMUTimerCB*) netdelay_expires,
+ delay );
+ delay->active = 0;
+ delay->min_ms = 0;
+ delay->max_ms = 0;
+
+ delay->send_func = send_func;
+
+ return delay;
+}
+
+
+void
+netdelay_set_latency( NetDelay delay, int min_ms, int max_ms )
+{
+ /* when changing the latency, accept all sessions */
+ while (delay->sessions) {
+ Session session = delay->sessions;
+ delay->sessions = session->next;
+ session->next = NULL;
+ if (session->packet) {
+ QueuedPacket packet = session->packet;
+ delay->send_func( packet->data, packet->size, packet->opaque );
+ }
+ session_free(session);
+ delay->num_sessions--;
+ }
+
+ delay->min_ms = min_ms;
+ delay->max_ms = max_ms;
+ delay->active = (min_ms <= max_ms) && min_ms > 0;
+}
+
+void
+netdelay_send( NetDelay delay, const void* data, size_t size )
+{
+ netdelay_send_aux(delay, data, size, NULL);
+}
+
+
+void
+netdelay_send_aux( NetDelay delay, const void* data, size_t size, void* opaque )
+{
+ if (delay->active && !_packet_is_internal(data, size)) {
+ SessionRec info[1];
+ int flags;
+
+ flags = _packet_SYN_flags( data, size, info );
+ if ((flags & 0x05) != 0)
+ { /* FIN or RST: drop connection */
+ Session* lookup = netdelay_lookup_session( delay, info );
+ Session session = *lookup;
+ if (session != NULL) {
+ //fprintf(stderr, "NetDelay:RST: dropping %s\n", session_to_string(info) );
+
+ *lookup = session->next;
+ session_free( session );
+ delay->num_sessions -= 1;
+ }
+ }
+ else if ((flags & 0x12) == 0x02)
+ {
+ /* SYN: create connection */
+ Session* lookup = netdelay_lookup_session( delay, info );
+ Session session = *lookup;
+
+ if (session != NULL) {
+ if (session->packet != NULL) {
+ /* this is a SYN re-transmission, since we didn't
+ * send the original SYN packet yet, just eat this one
+ */
+ //fprintf(stderr, "NetDelay:RST: swallow SYN re-send for %s\n", session_to_string(info) );
+ return;
+ }
+ } else {
+ /* establish a new session slightly in the future */
+ int latency = delay->min_ms;
+ int range = delay->max_ms - delay->min_ms;
+
+ if (range > 0)
+ latency += rand() % range;
+
+ //fprintf(stderr, "NetDelay:RST: delay creation for %s\n", session_to_string(info) );
+ session = qemu_malloc( sizeof(*session) );
+
+ session->next = delay->sessions;
+ delay->sessions = session;
+ delay->num_sessions += 1;
+
+ session->expiration = qemu_get_clock_ms( SHAPER_CLOCK ) + latency;
+
+ session->src_ip = info->src_ip;
+ session->dst_ip = info->dst_ip;
+ session->src_port = info->src_port;
+ session->dst_port = info->dst_port;
+ session->protocol = info->protocol;
+
+ session->packet = queued_packet_create( data, size, opaque, 1 );
+
+ netdelay_expires(delay);
+ return;
+ }
+ }
+ }
+
+ delay->send_func( (void*)data, size, opaque );
+}
+
+
+void
+netdelay_destroy( NetDelay delay )
+{
+ if (delay) {
+ while (delay->sessions) {
+ Session session = delay->sessions;
+ delay->sessions = session->next;
+ session_free(session);
+ delay->num_sessions -= 1;
+ }
+ delay->active = 0;
+ qemu_free( delay );
+ }
+}
+
diff --git a/android/sockets.c b/android/sockets.c
new file mode 100644
index 0000000..2250ee8
--- /dev/null
+++ b/android/sockets.c
@@ -0,0 +1,1568 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifdef __linux__ /* Recent versions of glibc only define EAI_NODATA, which is an
+ extension to the POSIX standard, if _GNU_SOURCE is defined. */
+# define _GNU_SOURCE 1
+#endif
+
+#include "android/sockets.h"
+#include <fcntl.h>
+#include <stddef.h>
+#include "qemu_debug.h"
+#include "qemu-char.h"
+#include <stdlib.h>
+#include <string.h>
+#include "android/utils/path.h"
+#include "android/utils/debug.h"
+#include "android/utils/misc.h"
+#include "android/utils/system.h"
+
+#define D(...) VERBOSE_PRINT(socket,__VA_ARGS__)
+
+#ifdef _WIN32
+# define xxWIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#else /* !_WIN32 */
+# include <sys/ioctl.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <netinet/tcp.h>
+# include <netdb.h>
+# if HAVE_UNIX_SOCKETS
+# include <sys/un.h>
+# ifndef UNIX_PATH_MAX
+# define UNIX_PATH_MAX (sizeof(((struct sockaddr_un*)0)->sun_path)-1)
+# endif
+# endif
+#endif /* !_WIN32 */
+
+
+
+/* QSOCKET_CALL is used to deal with the fact that EINTR happens pretty
+ * easily in QEMU since we use SIGALRM to implement periodic timers
+ */
+#ifdef _WIN32
+# define QSOCKET_CALL(_ret,_cmd) \
+ do { _ret = (_cmd); } while ( _ret < 0 && WSAGetLastError() == WSAEINTR )
+#else
+# define QSOCKET_CALL(_ret,_cmd) \
+ do { \
+ errno = 0; \
+ do { _ret = (_cmd); } while ( _ret < 0 && errno == EINTR ); \
+ } while (0);
+#endif
+
+#ifdef _WIN32
+
+#include <errno.h>
+
+static int winsock_error;
+
+#define WINSOCK_ERRORS_LIST \
+ EE(WSA_INVALID_HANDLE,EINVAL,"invalid handle") \
+ EE(WSA_NOT_ENOUGH_MEMORY,ENOMEM,"not enough memory") \
+ EE(WSA_INVALID_PARAMETER,EINVAL,"invalid parameter") \
+ EE(WSAEINTR,EINTR,"interrupted function call") \
+ EE(WSAEALREADY,EALREADY,"operation already in progress") \
+ EE(WSAEBADF,EBADF,"bad file descriptor") \
+ EE(WSAEACCES,EACCES,"permission denied") \
+ EE(WSAEFAULT,EFAULT,"bad address") \
+ EE(WSAEINVAL,EINVAL,"invalid argument") \
+ EE(WSAEMFILE,EMFILE,"too many opened files") \
+ EE(WSAEWOULDBLOCK,EWOULDBLOCK,"resource temporarily unavailable") \
+ EE(WSAEINPROGRESS,EINPROGRESS,"operation now in progress") \
+ EE(WSAEALREADY,EAGAIN,"operation already in progress") \
+ EE(WSAENOTSOCK,EBADF,"socket operation not on socket") \
+ EE(WSAEDESTADDRREQ,EDESTADDRREQ,"destination address required") \
+ EE(WSAEMSGSIZE,EMSGSIZE,"message too long") \
+ EE(WSAEPROTOTYPE,EPROTOTYPE,"wrong protocol type for socket") \
+ EE(WSAENOPROTOOPT,ENOPROTOOPT,"bad protocol option") \
+ EE(WSAEADDRINUSE,EADDRINUSE,"address already in use") \
+ EE(WSAEADDRNOTAVAIL,EADDRNOTAVAIL,"cannot assign requested address") \
+ EE(WSAENETDOWN,ENETDOWN,"network is down") \
+ EE(WSAENETUNREACH,ENETUNREACH,"network unreachable") \
+ EE(WSAENETRESET,ENETRESET,"network dropped connection on reset") \
+ EE(WSAECONNABORTED,ECONNABORTED,"software caused connection abort") \
+ EE(WSAECONNRESET,ECONNRESET,"connection reset by peer") \
+ EE(WSAENOBUFS,ENOBUFS,"no buffer space available") \
+ EE(WSAEISCONN,EISCONN,"socket is already connected") \
+ EE(WSAENOTCONN,ENOTCONN,"socket is not connected") \
+ EE(WSAESHUTDOWN,ESHUTDOWN,"cannot send after socket shutdown") \
+ EE(WSAETOOMANYREFS,ETOOMANYREFS,"too many references") \
+ EE(WSAETIMEDOUT,ETIMEDOUT,"connection timed out") \
+ EE(WSAECONNREFUSED,ECONNREFUSED,"connection refused") \
+ EE(WSAELOOP,ELOOP,"cannot translate name") \
+ EE(WSAENAMETOOLONG,ENAMETOOLONG,"name too long") \
+ EE(WSAEHOSTDOWN,EHOSTDOWN,"host is down") \
+ EE(WSAEHOSTUNREACH,EHOSTUNREACH,"no route to host") \
+
+typedef struct {
+ int winsock;
+ int unix;
+ const char* string;
+} WinsockError;
+
+static const WinsockError _winsock_errors[] = {
+#define EE(w,u,s) { w, u, s },
+ WINSOCK_ERRORS_LIST
+#undef EE
+ { -1, -1, NULL }
+};
+
+/* this function reads the latest winsock error code and updates
+ * errno to a matching value. It also returns the new value of
+ * errno.
+ */
+static int
+fix_errno( void )
+{
+ const WinsockError* werr = _winsock_errors;
+ int unix = EINVAL; /* generic error code */
+
+ winsock_error = WSAGetLastError();
+
+ for ( ; werr->string != NULL; werr++ ) {
+ if (werr->winsock == winsock_error) {
+ unix = werr->unix;
+ break;
+ }
+ }
+ errno = unix;
+ return -1;
+}
+
+static int
+set_errno( int code )
+{
+ winsock_error = -1;
+ errno = code;
+ return -1;
+}
+
+/* this function returns a string describing the latest Winsock error */
+const char*
+_errno_str(void)
+{
+ const WinsockError* werr = _winsock_errors;
+ const char* result = NULL;
+
+ for ( ; werr->string; werr++ ) {
+ if (werr->winsock == winsock_error) {
+ result = werr->string;
+ break;
+ }
+ }
+
+ if (result == NULL) {
+ result = tempstr_format(
+ "Unkown socket error (Winsock=0x%08x) errno=%d: %s",
+ winsock_error, errno, strerror(errno));
+ }
+ return result;
+}
+#else
+static int
+fix_errno( void )
+{
+ return -1;
+}
+
+static int
+set_errno( int code )
+{
+ errno = code;
+ return -1;
+}
+#endif
+
+/* socket types */
+
+static int
+socket_family_to_bsd( SocketFamily family )
+{
+ switch (family) {
+ case SOCKET_INET: return AF_INET;
+ case SOCKET_IN6: return AF_INET6;
+#if HAVE_UNIX_SOCKETS
+ case SOCKET_UNIX: return AF_LOCAL;
+#endif
+ default: return -1;
+ }
+}
+
+static int
+socket_type_to_bsd( SocketType type )
+{
+ switch (type) {
+ case SOCKET_DGRAM: return SOCK_DGRAM;
+ case SOCKET_STREAM: return SOCK_STREAM;
+ default: return 0;
+ }
+}
+
+static SocketType
+socket_type_from_bsd( int type )
+{
+ switch (type) {
+ case SOCK_DGRAM: return SOCKET_DGRAM;
+ case SOCK_STREAM: return SOCKET_STREAM;
+ default: return (SocketType) SOCKET_UNSPEC;
+ }
+}
+
+#if 0
+static int
+socket_type_check( SocketType type )
+{
+ return (type == SOCKET_DGRAM || type == SOCKET_STREAM);
+}
+#endif
+
+typedef union {
+ struct sockaddr sa[1];
+ struct sockaddr_in in[1];
+#if HAVE_IN6_SOCKETS
+ struct sockaddr_in6 in6[1];
+#endif
+#if HAVE_UNIX_SOCKETS
+ struct sockaddr_un un[1];
+#endif
+} sockaddr_storage;
+
+/* socket addresses */
+
+void
+sock_address_init_inet( SockAddress* a, uint32_t ip, uint16_t port )
+{
+ a->family = SOCKET_INET;
+ a->u.inet.port = port;
+ a->u.inet.address = ip;
+}
+
+void
+sock_address_init_in6 ( SockAddress* a, const uint8_t* ip6[16], uint16_t port )
+{
+ a->family = SOCKET_IN6;
+ a->u.in6.port = port;
+ memcpy( a->u.in6.address, ip6, sizeof(a->u.in6.address) );
+}
+
+void
+sock_address_init_unix( SockAddress* a, const char* path )
+{
+ a->family = SOCKET_UNIX;
+ a->u._unix.path = strdup(path ? path : "");
+ a->u._unix.owner = 1;
+}
+
+void sock_address_done( SockAddress* a )
+{
+ if (a->family == SOCKET_UNIX && a->u._unix.owner) {
+ a->u._unix.owner = 0;
+ free((char*)a->u._unix.path);
+ }
+}
+
+static char*
+format_char( char* buf, char* end, int c )
+{
+ if (buf < end) {
+ if (buf+1 == end) {
+ *buf++ = 0;
+ } else {
+ *buf++ = (char) c;
+ *buf = 0;
+ }
+ }
+ return buf;
+}
+
+static char*
+format_str( char* buf, char* end, const char* str )
+{
+ int len = strlen(str);
+ int avail = end - buf;
+
+ if (len > avail)
+ len = avail;
+
+ memcpy( buf, str, len );
+ buf += len;
+
+ if (buf == end)
+ buf[-1] = 0;
+ else
+ buf[0] = 0;
+
+ return buf;
+}
+
+static char*
+format_unsigned( char* buf, char* end, unsigned val )
+{
+ char temp[16];
+ int nn;
+
+ for ( nn = 0; val != 0; nn++ ) {
+ int rem = val % 10;
+ temp[nn] = '0'+rem;
+ val /= 10;
+ }
+
+ if (nn == 0)
+ temp[nn++] = '0';
+
+ while (nn > 0)
+ buf = format_char(buf, end, temp[--nn]);
+
+ return buf;
+}
+
+static char*
+format_hex( char* buf, char* end, unsigned val, int ndigits )
+{
+ int shift = 4*ndigits;
+ static const char hex[16] = "0123456789abcdef";
+
+ while (shift >= 0) {
+ buf = format_char(buf, end, hex[(val >> shift) & 15]);
+ shift -= 4;
+ }
+ return buf;
+}
+
+static char*
+format_ip4( char* buf, char* end, uint32_t ip )
+{
+ buf = format_unsigned( buf, end, (unsigned)(ip >> 24) );
+ buf = format_char( buf, end, '.');
+ buf = format_unsigned( buf, end, (unsigned)((ip >> 16) & 255));
+ buf = format_char( buf, end, '.');
+ buf = format_unsigned( buf, end, (unsigned)((ip >> 8) & 255));
+ buf = format_char( buf, end, '.');
+ buf = format_unsigned( buf, end, (unsigned)(ip & 255));
+ return buf;
+}
+
+static char*
+format_ip6( char* buf, char* end, const uint8_t* ip6 )
+{
+ int nn;
+ for (nn = 0; nn < 8; nn++) {
+ int val = (ip6[0] << 16) | ip6[1];
+ ip6 += 2;
+ if (nn > 0)
+ buf = format_char(buf, end, ':');
+ if (val == 0)
+ continue;
+ buf = format_hex(buf, end, val, 4);
+ }
+ return buf;
+}
+
+const char*
+sock_address_to_string( const SockAddress* a )
+{
+ static char buf0[MAX_PATH];
+ char *buf = buf0, *end = buf + sizeof(buf0);
+
+ switch (a->family) {
+ case SOCKET_INET:
+ buf = format_ip4( buf, end, a->u.inet.address );
+ buf = format_char( buf, end, ':' );
+ buf = format_unsigned( buf, end, (unsigned) a->u.inet.port );
+ break;
+
+ case SOCKET_IN6:
+ buf = format_ip6( buf, end, a->u.in6.address );
+ buf = format_char( buf, end, ':' );
+ buf = format_unsigned( buf, end, (unsigned) a->u.in6.port );
+ break;
+
+ case SOCKET_UNIX:
+ buf = format_str( buf, end, a->u._unix.path );
+ break;
+
+ default:
+ return NULL;
+ }
+
+ return buf0;
+}
+
+int
+sock_address_equal( const SockAddress* a, const SockAddress* b )
+{
+ if (a->family != b->family)
+ return 0;
+
+ switch (a->family) {
+ case SOCKET_INET:
+ return (a->u.inet.address == b->u.inet.address &&
+ a->u.inet.port == b->u.inet.port);
+
+ case SOCKET_IN6:
+ return (!memcmp(a->u.in6.address, b->u.in6.address, 16) &&
+ a->u.in6.port == b->u.in6.port);
+
+ case SOCKET_UNIX:
+ return (!strcmp(a->u._unix.path, b->u._unix.path));
+
+ default:
+ return 0;
+ }
+}
+
+int
+sock_address_get_port( const SockAddress* a )
+{
+ switch (a->family) {
+ case SOCKET_INET:
+ return a->u.inet.port;
+ case SOCKET_IN6:
+ return a->u.in6.port;
+ default:
+ return -1;
+ }
+}
+
+void
+sock_address_set_port( SockAddress* a, uint16_t port )
+{
+ switch (a->family) {
+ case SOCKET_INET:
+ a->u.inet.port = port;
+ break;
+ case SOCKET_IN6:
+ a->u.in6.port = port;
+ break;
+ default:
+ ;
+ }
+}
+
+const char*
+sock_address_get_path( const SockAddress* a )
+{
+ if (a->family == SOCKET_UNIX)
+ return a->u._unix.path;
+ else
+ return NULL;
+}
+
+int
+sock_address_get_ip( const SockAddress* a )
+{
+ if (a->family == SOCKET_INET)
+ return a->u.inet.address;
+
+ return -1;
+}
+
+#if 0
+char*
+bufprint_sock_address( char* p, char* end, const SockAddress* a )
+{
+ switch (a->family) {
+ case SOCKET_INET:
+ {
+ uint32_t ip = a->u.inet.address;
+
+ return bufprint( p, end, "%d.%d.%d.%d:%d",
+ (ip >> 24) & 255, (ip >> 16) & 255,
+ (ip >> 8) & 255, ip & 255,
+ a->u.inet.port );
+ }
+ case SOCKET_IN6:
+ {
+ int nn = 0;
+ const char* column = "";
+ const uint8_t* tab = a->u.in6.address;
+ for (nn = 0; nn < 16; nn += 2) {
+ p = bufprint(p, end, "%s%04x", column, (tab[n] << 8) | tab[n+1]);
+ column = ":";
+ }
+ return bufprint(p, end, ":%d", a->u.in6.port);
+ }
+ case SOCKET_UNIX:
+ {
+ return bufprint(p, end, "%s", a->u._unix.path);
+ }
+ default:
+ return p;
+ }
+}
+#endif
+
+static int
+sock_address_to_bsd( const SockAddress* a, sockaddr_storage* paddress, socklen_t *psize )
+{
+ switch (a->family) {
+ case SOCKET_INET:
+ {
+ struct sockaddr_in* dst = paddress->in;
+
+ *psize = sizeof(*dst);
+
+ memset( paddress, 0, *psize );
+
+ dst->sin_family = AF_INET;
+ dst->sin_port = htons(a->u.inet.port);
+ dst->sin_addr.s_addr = htonl(a->u.inet.address);
+ }
+ break;
+
+#if HAVE_IN6_SOCKETS
+ case SOCKET_IN6:
+ {
+ struct sockaddr_in6* dst = paddress->in6;
+
+ *psize = sizeof(*dst);
+
+ memset( paddress, 0, *psize );
+
+ dst->sin6_family = AF_INET6;
+ dst->sin6_port = htons(a->u.in6.port);
+ memcpy( dst->sin6_addr.s6_addr, a->u.in6.address, 16 );
+ }
+ break;
+#endif /* HAVE_IN6_SOCKETS */
+
+#if HAVE_UNIX_SOCKETS
+ case SOCKET_UNIX:
+ {
+ int slen = strlen(a->u._unix.path);
+ struct sockaddr_un* dst = paddress->un;
+
+ if (slen >= UNIX_PATH_MAX)
+ return -1;
+
+ memset( dst, 0, sizeof(*dst) );
+
+ dst->sun_family = AF_LOCAL;
+ memcpy( dst->sun_path, a->u._unix.path, slen );
+ dst->sun_path[slen] = 0;
+
+ *psize = (char*)&dst->sun_path[slen+1] - (char*)dst;
+ }
+ break;
+#endif /* HAVE_UNIX_SOCKETS */
+
+ default:
+ return set_errno(EINVAL);
+ }
+
+ return 0;
+}
+
+static int
+sock_address_from_bsd( SockAddress* a, const void* from, size_t fromlen )
+{
+ switch (((struct sockaddr *)from)->sa_family) {
+ case AF_INET:
+ {
+ const struct sockaddr_in* src = from;
+
+ if (fromlen < sizeof(*src))
+ return set_errno(EINVAL);
+
+ a->family = SOCKET_INET;
+ a->u.inet.port = ntohs(src->sin_port);
+ a->u.inet.address = ntohl(src->sin_addr.s_addr);
+ }
+ break;
+
+#ifdef HAVE_IN6_SOCKETS
+ case AF_INET6:
+ {
+ const struct sockaddr_in6* src = from;
+
+ if (fromlen < sizeof(*src))
+ return set_errno(EINVAL);
+
+ a->family = SOCKET_IN6;
+ a->u.in6.port = ntohs(src->sin6_port);
+ memcpy(a->u.in6.address, src->sin6_addr.s6_addr, 16);
+ }
+ break;
+#endif
+
+#ifdef HAVE_UNIX_SOCKETS
+ case AF_LOCAL:
+ {
+ const struct sockaddr_un* src = from;
+ char* end;
+
+ if (fromlen < sizeof(*src))
+ return set_errno(EINVAL);
+
+ /* check that the path is zero-terminated */
+ end = memchr(src->sun_path, 0, UNIX_PATH_MAX);
+ if (end == NULL)
+ return set_errno(EINVAL);
+
+ a->family = SOCKET_UNIX;
+ a->u._unix.owner = 1;
+ a->u._unix.path = strdup(src->sun_path);
+ }
+ break;
+#endif
+
+ default:
+ return set_errno(EINVAL);
+ }
+ return 0;
+}
+
+
+int
+sock_address_init_resolve( SockAddress* a, const char* hostname, uint16_t port, int preferIn6 )
+{
+ struct addrinfo hints[1];
+ struct addrinfo* res;
+ int ret;
+
+ memset(hints, 0, sizeof(hints));
+ hints->ai_family = preferIn6 ? AF_INET6 : AF_UNSPEC;
+
+ ret = getaddrinfo(hostname, NULL, hints, &res);
+ if (ret != 0) {
+ int err;
+
+ switch (ret) {
+ case EAI_AGAIN: /* server is down */
+ case EAI_FAIL: /* server is sick */
+ err = EHOSTDOWN;
+ break;
+
+/* NOTE that in x86_64-w64-mingw32 both EAI_NODATA and EAI_NONAME are the same */
+#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
+ case EAI_NODATA:
+#endif
+ case EAI_NONAME:
+ err = ENOENT;
+ break;
+
+ case EAI_MEMORY:
+ err = ENOMEM;
+ break;
+
+ default:
+ err = EINVAL;
+ }
+ return set_errno(err);
+ }
+
+ /* Parse the returned list of addresses. */
+ {
+ struct addrinfo* res_ipv4 = NULL;
+ struct addrinfo* res_ipv6 = NULL;
+ struct addrinfo* r;
+
+ /* If preferIn6 is false, we stop on the first IPv4 address,
+ * otherwise, we stop on the first IPv6 one
+ */
+ for (r = res; r != NULL; r = r->ai_next) {
+ if (r->ai_family == AF_INET && res_ipv4 == NULL) {
+ res_ipv4 = r;
+ if (!preferIn6)
+ break;
+ }
+ else if (r->ai_family == AF_INET6 && res_ipv6 == NULL) {
+ res_ipv6 = r;
+ if (preferIn6)
+ break;
+ }
+ }
+
+ /* Select the best address in 'r', which will be NULL
+ * if there is no corresponding address.
+ */
+ if (preferIn6) {
+ r = res_ipv6;
+ if (r == NULL)
+ r = res_ipv4;
+ } else {
+ r = res_ipv4;
+ if (r == NULL)
+ r = res_ipv6;
+ }
+
+ if (r == NULL) {
+ ret = set_errno(ENOENT);
+ goto Exit;
+ }
+
+ /* Convert to a SockAddress */
+ ret = sock_address_from_bsd( a, r->ai_addr, r->ai_addrlen );
+ if (ret < 0)
+ goto Exit;
+ }
+
+ /* need to set the port */
+ switch (a->family) {
+ case SOCKET_INET: a->u.inet.port = port; break;
+ case SOCKET_IN6: a->u.in6.port = port; break;
+ default: ;
+ }
+
+Exit:
+ freeaddrinfo(res);
+ return ret;
+}
+
+/* The Winsock headers for mingw lack some definitions */
+#ifndef AI_ADDRCONFIG
+# define AI_ADDRCONFIG 0
+#endif
+
+SockAddress**
+sock_address_list_create( const char* hostname,
+ const char* port,
+ unsigned flags )
+{
+ SockAddress** list = NULL;
+ SockAddress* addr;
+ int nn, count, ret;
+ struct addrinfo ai, *res, *e;
+
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_flags |= AI_ADDRCONFIG;
+ ai.ai_family = PF_UNSPEC;
+
+ if (flags & SOCKET_LIST_FORCE_INET)
+ ai.ai_family = PF_INET;
+ else if (flags & SOCKET_LIST_FORCE_IN6)
+ ai.ai_family = PF_INET6;
+
+ if (flags & SOCKET_LIST_PASSIVE)
+ ai.ai_flags |= AI_PASSIVE;
+ else
+ ai.ai_flags |= AI_CANONNAME;
+
+ if (flags & SOCKET_LIST_DGRAM)
+ ai.ai_socktype = SOCK_DGRAM;
+
+ while (1) {
+ struct addrinfo hints = ai;
+
+ ret = getaddrinfo(hostname, port, &hints, &res);
+ if (ret == 0)
+ break;
+
+ switch (ret) {
+#ifdef EAI_ADDRFAMILY
+ case EAI_ADDRFAMILY:
+#endif
+ case EAI_NODATA:
+ set_errno(ENOENT);
+ break;
+ case EAI_FAMILY:
+ set_errno(EAFNOSUPPORT);
+ break;
+ case EAI_AGAIN:
+ set_errno(EAGAIN);
+ break;
+#ifdef EAI_SYSTEM
+ case EAI_SYSTEM:
+ if (errno == EINTR)
+ continue;
+ break;
+#endif
+ default:
+ set_errno(EINVAL);
+ }
+ return NULL;
+ }
+
+ /* allocate result list */
+ for (count = 0, e = res; e != NULL; e = e->ai_next)
+ count += 1;
+
+ AARRAY_NEW(list, count+1);
+ AARRAY_NEW(addr, count);
+
+ for (nn = 0, e = res; e != NULL; e = e->ai_next) {
+
+ ret = sock_address_from_bsd(addr, e->ai_addr, e->ai_addrlen);
+ if (ret < 0)
+ continue;
+
+ list[nn++] = addr++;
+ }
+ list[nn] = NULL;
+ freeaddrinfo(res);
+ return list;
+}
+
+SockAddress**
+sock_address_list_create2(const char* host_and_port, unsigned flags )
+{
+ char host_name[512];
+ const char* actual_host_name = "localhost";
+ // Parse host and port name.
+ const char* port_name = strchr(host_and_port, ':');
+ if (port_name != NULL) {
+ int to_copy = MIN(sizeof(host_name)-1, port_name - host_and_port);
+ if (to_copy != 0) {
+ memcpy(host_name, host_and_port, to_copy);
+ host_name[to_copy] = '\0';
+ actual_host_name = host_name;
+ port_name++;
+ } else {
+ return NULL;
+ }
+ } else {
+ port_name = host_and_port;
+ }
+ // Make sure that port_name is not empty.
+ if (port_name[0] == '\0') {
+ return NULL;
+ }
+ return sock_address_list_create(actual_host_name, port_name, flags);
+}
+
+void
+sock_address_list_free( SockAddress** list )
+{
+ int nn;
+ SockAddress* addr;
+
+ if (list == NULL)
+ return;
+
+ addr = list[0];
+ for (nn = 0; list[nn] != NULL; nn++) {
+ sock_address_done(list[nn]);
+ list[nn] = NULL;
+ }
+ AFREE(addr);
+ AFREE(list);
+}
+
+int
+sock_address_get_numeric_info( SockAddress* a,
+ char* host,
+ size_t hostlen,
+ char* serv,
+ size_t servlen )
+{
+ struct sockaddr* saddr;
+ socklen_t slen;
+ int ret;
+
+ switch (a->family) {
+ case SOCKET_INET:
+ saddr = (struct sockaddr*) &a->u.inet.address;
+ slen = sizeof(a->u.inet.address);
+ break;
+
+#if HAVE_IN6_SOCKET
+ case SOCKET_IN6:
+ saddr = (struct sockaddr*) &a->u.in6.address;
+ slen = sizeof(a->u.in6.address);
+ break;
+#endif
+ default:
+ return set_errno(EINVAL);
+ }
+
+ ret = getnameinfo( saddr, slen, host, hostlen, serv, servlen,
+ NI_NUMERICHOST | NI_NUMERICSERV );
+
+ switch (ret) {
+ case 0:
+ break;
+ case EAI_AGAIN:
+ ret = EAGAIN;
+ break;
+ default:
+ ret = EINVAL;
+ }
+ return ret;
+}
+
+int
+socket_create( SocketFamily family, SocketType type )
+{
+ int ret;
+ int sfamily = socket_family_to_bsd(family);
+ int stype = socket_type_to_bsd(type);
+
+ if (sfamily < 0 || stype < 0) {
+ return set_errno(EINVAL);
+ }
+
+ QSOCKET_CALL(ret, socket(sfamily, stype, 0));
+ if (ret < 0)
+ return fix_errno();
+
+ return ret;
+}
+
+
+int
+socket_create_inet( SocketType type )
+{
+ return socket_create( SOCKET_INET, type );
+}
+
+#if HAVE_IN6_SOCKETS
+int
+socket_create_in6 ( SocketType type )
+{
+ return socket_create( SOCKET_IN6, type );
+}
+#endif
+
+#if HAVE_UNIX_SOCKETS
+int
+socket_create_unix( SocketType type )
+{
+ return socket_create( SOCKET_UNIX, type );
+}
+#endif
+
+int socket_can_read(int fd)
+{
+#ifdef _WIN32
+ unsigned long opt;
+
+ if (ioctlsocket(fd, FIONREAD, &opt) < 0)
+ return 0;
+
+ return opt;
+#else
+ int opt;
+
+ if (ioctl(fd, FIONREAD, &opt) < 0)
+ return 0;
+
+ return opt;
+#endif
+}
+
+#define SOCKET_CALL(cmd) \
+ int ret; \
+ QSOCKET_CALL(ret, (cmd)); \
+ if (ret < 0) \
+ return fix_errno(); \
+ return ret; \
+
+int
+socket_send(int fd, const void* buf, int buflen)
+{
+ SOCKET_CALL(send(fd, buf, buflen, 0))
+}
+
+int
+socket_send_oob( int fd, const void* buf, int buflen )
+{
+ SOCKET_CALL(send(fd, buf, buflen, MSG_OOB));
+}
+
+int
+socket_sendto(int fd, const void* buf, int buflen, const SockAddress* to)
+{
+ sockaddr_storage sa;
+ socklen_t salen;
+
+ if (sock_address_to_bsd(to, &sa, &salen) < 0)
+ return -1;
+
+ SOCKET_CALL(sendto(fd, buf, buflen, 0, sa.sa, salen));
+}
+
+int
+socket_recv(int fd, void* buf, int len)
+{
+ SOCKET_CALL(recv(fd, buf, len, 0));
+}
+
+int
+socket_recvfrom(int fd, void* buf, int len, SockAddress* from)
+{
+ sockaddr_storage sa;
+ socklen_t salen = sizeof(sa);
+ int ret;
+
+ QSOCKET_CALL(ret,recvfrom(fd,buf,len,0,sa.sa,&salen));
+ if (ret < 0)
+ return fix_errno();
+
+ if (sock_address_from_bsd(from, &sa, salen) < 0)
+ return -1;
+
+ return ret;
+}
+
+int
+socket_connect( int fd, const SockAddress* address )
+{
+ sockaddr_storage addr;
+ socklen_t addrlen;
+
+ if (sock_address_to_bsd(address, &addr, &addrlen) < 0)
+ return -1;
+
+ SOCKET_CALL(connect(fd,addr.sa,addrlen));
+}
+
+int
+socket_bind( int fd, const SockAddress* address )
+{
+ sockaddr_storage addr;
+ socklen_t addrlen;
+
+ if (sock_address_to_bsd(address, &addr, &addrlen) < 0)
+ return -1;
+
+ SOCKET_CALL(bind(fd, addr.sa, addrlen));
+}
+
+int
+socket_get_address( int fd, SockAddress* address )
+{
+ sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ int ret;
+
+ QSOCKET_CALL(ret, getsockname(fd, addr.sa, &addrlen));
+ if (ret < 0)
+ return fix_errno();
+
+ return sock_address_from_bsd(address, &addr, addrlen);
+}
+
+int
+socket_get_peer_address( int fd, SockAddress* address )
+{
+ sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ int ret;
+
+ QSOCKET_CALL(ret, getpeername(fd, addr.sa, &addrlen));
+ if (ret < 0)
+ return fix_errno();
+
+ return sock_address_from_bsd(address, &addr, addrlen);
+}
+
+int
+socket_listen( int fd, int backlog )
+{
+ SOCKET_CALL(listen(fd, backlog));
+}
+
+int
+socket_accept( int fd, SockAddress* address )
+{
+ sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ int ret;
+
+ QSOCKET_CALL(ret, accept(fd, addr.sa, &addrlen));
+ if (ret < 0)
+ return fix_errno();
+
+ if (address) {
+ if (sock_address_from_bsd(address, &addr, addrlen) < 0) {
+ socket_close(ret);
+ return -1;
+ }
+ }
+ return ret;
+}
+
+static int
+socket_getoption(int fd, int domain, int option, int defaut)
+{
+ int ret;
+ while (1) {
+#ifdef _WIN32
+ DWORD opt = (DWORD)-1;
+#else
+ int opt = -1;
+#endif
+ socklen_t optlen = sizeof(opt);
+ ret = getsockopt(fd, domain, option, (char*)&opt, &optlen);
+ if (ret == 0)
+ return (int)opt;
+ if (errno != EINTR)
+ return defaut;
+ }
+#undef OPT_CAST
+}
+
+
+SocketType socket_get_type(int fd)
+{
+ int so_type = socket_getoption(fd, SOL_SOCKET, SO_TYPE, -1);
+ return socket_type_from_bsd(so_type);
+}
+
+int socket_set_nonblock(int fd)
+{
+#ifdef _WIN32
+ unsigned long opt = 1;
+ return ioctlsocket(fd, FIONBIO, &opt);
+#else
+ int flags = fcntl(fd, F_GETFL);
+ return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+#endif
+}
+
+int socket_set_blocking(int fd)
+{
+#ifdef _WIN32
+ unsigned long opt = 0;
+ return ioctlsocket(fd, FIONBIO, &opt);
+#else
+ int flags = fcntl(fd, F_GETFL);
+ return fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+#endif
+}
+
+static int
+socket_setoption(int fd, int domain, int option, int _flag)
+{
+#ifdef _WIN32
+ DWORD flag = (DWORD) _flag;
+#else
+ int flag = _flag;
+#endif
+ return setsockopt( fd, domain, option, (const char*)&flag, sizeof(flag) );
+}
+
+int socket_set_xreuseaddr(int fd)
+{
+#ifdef _WIN32
+ /* on Windows, SO_REUSEADDR is used to indicate that several programs can
+ * bind to the same port. this is completely different from the Unix
+ * semantics. instead of SO_EXCLUSIVEADDR to ensure that explicitely prevent
+ * this.
+ */
+ return socket_setoption(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, 1);
+#else
+ return socket_setoption(fd, SOL_SOCKET, SO_REUSEADDR, 1);
+#endif
+}
+
+
+int socket_set_oobinline(int fd)
+{
+ return socket_setoption(fd, SOL_SOCKET, SO_OOBINLINE, 1);
+}
+
+
+int socket_set_nodelay(int fd)
+{
+ return socket_setoption(fd, IPPROTO_TCP, TCP_NODELAY, 1);
+}
+
+int socket_set_ipv6only(int fd)
+{
+/* IPV6_ONLY is only supported since Vista on Windows,
+ * and the Mingw headers lack its definition anyway.
+ */
+#if defined(_WIN32) && !defined(IPV6_V6ONLY)
+ return 0;
+#else
+ return socket_setoption(fd, IPPROTO_IPV6, IPV6_V6ONLY, 1);
+#endif
+}
+
+
+int socket_get_error(int fd)
+{
+ return socket_getoption(fd, SOL_SOCKET, SO_ERROR, -1);
+}
+
+#ifdef _WIN32
+#include <stdlib.h>
+
+static void socket_cleanup(void)
+{
+ WSACleanup();
+}
+
+int socket_init(void)
+{
+ WSADATA Data;
+ int ret, err;
+
+ ret = WSAStartup(MAKEWORD(2,2), &Data);
+ if (ret != 0) {
+ err = WSAGetLastError();
+ return -1;
+ }
+ atexit(socket_cleanup);
+ return 0;
+}
+
+#else /* !_WIN32 */
+
+int socket_init(void)
+{
+ return 0; /* nothing to do on Unix */
+}
+
+#endif /* !_WIN32 */
+
+#ifdef _WIN32
+
+static void
+socket_close_handler( void* _fd )
+{
+ int fd = (int)_fd;
+ int ret;
+ char buff[64];
+
+ /* we want to drain the read side of the socket before closing it */
+ do {
+ ret = recv( fd, buff, sizeof(buff), 0 );
+ } while (ret < 0 && WSAGetLastError() == WSAEINTR);
+
+ if (ret < 0 && WSAGetLastError() == EWOULDBLOCK)
+ return;
+
+ qemu_set_fd_handler( fd, NULL, NULL, NULL );
+ closesocket( fd );
+}
+
+void
+socket_close( int fd )
+{
+ int old_errno = errno;
+
+ shutdown( fd, SD_BOTH );
+ /* we want to drain the socket before closing it */
+ qemu_set_fd_handler( fd, socket_close_handler, NULL, (void*)fd );
+
+ errno = old_errno;
+}
+
+#else /* !_WIN32 */
+
+#include <unistd.h>
+
+void
+socket_close( int fd )
+{
+ int old_errno = errno;
+
+ shutdown( fd, SHUT_RDWR );
+ close( fd );
+
+ errno = old_errno;
+}
+
+#endif /* !_WIN32 */
+
+
+static int
+socket_bind_server( int s, const SockAddress* to, SocketType type )
+{
+ socket_set_xreuseaddr(s);
+
+ if (socket_bind(s, to) < 0) {
+ D("could not bind server socket address %s: %s",
+ sock_address_to_string(to), errno_str);
+ goto FAIL;
+ }
+
+ if (type == SOCKET_STREAM) {
+ if (socket_listen(s, 4) < 0) {
+ D("could not listen server socket %s: %s",
+ sock_address_to_string(to), errno_str);
+ goto FAIL;
+ }
+ }
+ return s;
+
+FAIL:
+ socket_close(s);
+ return -1;
+}
+
+
+static int
+socket_connect_client( int s, const SockAddress* to )
+{
+ if (socket_connect(s, to) < 0) {
+ D( "could not connect client socket to %s: %s\n",
+ sock_address_to_string(to), errno_str );
+ socket_close(s);
+ return -1;
+ }
+
+ socket_set_nonblock( s );
+ return s;
+}
+
+
+static int
+socket_in_server( int address, int port, SocketType type )
+{
+ SockAddress addr;
+ int s;
+
+ sock_address_init_inet( &addr, address, port );
+ s = socket_create_inet( type );
+ if (s < 0)
+ return -1;
+
+ return socket_bind_server( s, &addr, type );
+}
+
+
+static int
+socket_in_client( SockAddress* to, SocketType type )
+{
+ int s;
+
+ s = socket_create_inet( type );
+ if (s < 0) return -1;
+
+ return socket_connect_client( s, to );
+}
+
+
+int
+socket_loopback_server( int port, SocketType type )
+{
+ return socket_in_server( SOCK_ADDRESS_INET_LOOPBACK, port, type );
+}
+
+int
+socket_loopback_client( int port, SocketType type )
+{
+ SockAddress addr;
+
+ sock_address_init_inet( &addr, SOCK_ADDRESS_INET_LOOPBACK, port );
+ return socket_in_client( &addr, type );
+}
+
+
+int
+socket_network_client( const char* host, int port, SocketType type )
+{
+ SockAddress addr;
+
+ if (sock_address_init_resolve( &addr, host, port, 0) < 0)
+ return -1;
+
+ return socket_in_client( &addr, type );
+}
+
+
+int
+socket_anyaddr_server( int port, SocketType type )
+{
+ return socket_in_server( SOCK_ADDRESS_INET_ANY, port, type );
+}
+
+int
+socket_accept_any( int server_fd )
+{
+ int fd;
+
+ QSOCKET_CALL(fd, accept( server_fd, NULL, 0 ));
+ if (fd < 0) {
+ D( "could not accept client connection from fd %d: %s",
+ server_fd, errno_str );
+ return -1;
+ }
+
+ /* set to non-blocking */
+ socket_set_nonblock( fd );
+ return fd;
+}
+
+
+#if HAVE_UNIX_SOCKETS
+
+int
+socket_unix_server( const char* name, SocketType type )
+{
+ SockAddress addr;
+ int s, ret;
+
+ s = socket_create_unix( type );
+ if (s < 0)
+ return -1;
+
+ sock_address_init_unix( &addr, name );
+
+ do {
+ ret = unlink( name );
+ } while (ret < 0 && errno == EINTR);
+
+ ret = socket_bind_server( s, &addr, type );
+
+ sock_address_done( &addr );
+ return ret;
+}
+
+int
+socket_unix_client( const char* name, SocketType type )
+{
+ SockAddress addr;
+ int s, ret;
+
+ s = socket_create_unix(type);
+ if (s < 0)
+ return -1;
+
+ sock_address_init_unix( &addr, name );
+
+ ret = socket_connect_client( s, &addr );
+
+ sock_address_done( &addr );
+ return ret;
+}
+
+#endif /* HAVE_UNIX_SOCKETS */
+
+
+
+int
+socket_pair(int *fd1, int *fd2)
+{
+#ifndef _WIN32
+ int fds[2];
+ int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+
+ if (!ret) {
+ socket_set_nonblock(fds[0]);
+ socket_set_nonblock(fds[1]);
+ *fd1 = fds[0];
+ *fd2 = fds[1];
+ }
+ return ret;
+#else /* _WIN32 */
+ /* on Windows, select() only works with network sockets, which
+ * means we absolutely cannot use Win32 PIPEs to implement
+ * socket pairs with the current event loop implementation.
+ * We're going to do like Cygwin: create a random pair
+ * of localhost TCP sockets and connect them together
+ */
+ int s0, s1, s2, port;
+ struct sockaddr_in sockin;
+ socklen_t len;
+
+ /* first, create the 'server' socket.
+ * a port number of 0 means 'any port between 1024 and 5000.
+ * see Winsock bind() documentation for details */
+ s0 = socket_loopback_server( 0, SOCK_STREAM );
+ if (s0 < 0)
+ return -1;
+
+ /* now connect a client socket to it, we first need to
+ * extract the server socket's port number */
+ len = sizeof sockin;
+ if (getsockname(s0, (struct sockaddr*) &sockin, &len) < 0) {
+ closesocket (s0);
+ return -1;
+ }
+
+ port = ntohs(sockin.sin_port);
+ s2 = socket_loopback_client( port, SOCK_STREAM );
+ if (s2 < 0) {
+ closesocket(s0);
+ return -1;
+ }
+
+ /* we need to accept the connection on the server socket
+ * this will create the second socket for the pair
+ */
+ len = sizeof sockin;
+ s1 = accept(s0, (struct sockaddr*) &sockin, &len);
+ if (s1 == INVALID_SOCKET) {
+ closesocket (s0);
+ closesocket (s2);
+ return -1;
+ }
+ socket_set_nonblock(s1);
+
+ /* close server socket */
+ closesocket(s0);
+ *fd1 = s1;
+ *fd2 = s2;
+ return 0;
+#endif /* _WIN32 */
+}
+
+
+
+int
+socket_mcast_inet_add_membership( int s, uint32_t ip )
+{
+ struct ip_mreq imr;
+
+ imr.imr_multiaddr.s_addr = htonl(ip);
+ imr.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ if ( setsockopt( s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (const char *)&imr,
+ sizeof(struct ip_mreq)) < 0 )
+ {
+ return fix_errno();
+ }
+ return 0;
+}
+
+int
+socket_mcast_inet_drop_membership( int s, uint32_t ip )
+{
+ struct ip_mreq imr;
+
+ imr.imr_multiaddr.s_addr = htonl(ip);
+ imr.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ if ( setsockopt( s, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ (const char *)&imr,
+ sizeof(struct ip_mreq)) < 0 )
+ {
+ return fix_errno();
+ }
+ return 0;
+}
+
+int
+socket_mcast_inet_set_loop( int s, int enabled )
+{
+ return socket_setoption( s, IPPROTO_IP, IP_MULTICAST_LOOP, !!enabled );
+}
+
+int
+socket_mcast_inet_set_ttl( int s, int ttl )
+{
+ return socket_setoption( s, IPPROTO_IP, IP_MULTICAST_TTL, ttl );
+}
+
+
+char*
+host_name( void )
+{
+ static char buf[256]; /* 255 is the max host name length supported by DNS */
+ int ret;
+
+ QSOCKET_CALL(ret, gethostname(buf, sizeof(buf)));
+
+ if (ret < 0)
+ return "localhost";
+ else
+ return buf;
+}
diff --git a/android/sync-utils.c b/android/sync-utils.c
index 617ba8b..cab0fa6 100644
--- a/android/sync-utils.c
+++ b/android/sync-utils.c
@@ -22,7 +22,7 @@
#include "qemu-common.h"
#include "errno.h"
#include "iolooper.h"
-#include "sockets.h"
+#include "android/sockets.h"
#include "android/utils/debug.h"
#include "android/sync-utils.h"
#include "android/utils/system.h"
diff --git a/android/sync-utils.h b/android/sync-utils.h
index bb54f3c..adb68a7 100644
--- a/android/sync-utils.h
+++ b/android/sync-utils.h
@@ -23,7 +23,7 @@
#define ANDROID_SYNC_UTILS_H
#include "android/android.h"
-#include "sockets.h"
+#include "android/sockets.h"
/* Descriptor for a connected non-blocking socket providing synchronous I/O */
typedef struct SyncSocket SyncSocket;