From f721e3ac031f892af46f255a47d7f54a91317b30 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 18:28:35 -0800 Subject: auto import from //depot/cupcake/@135843 --- sockets.c | 1269 ------------------------------------------------------------- 1 file changed, 1269 deletions(-) delete mode 100644 sockets.c (limited to 'sockets.c') diff --git a/sockets.c b/sockets.c deleted file mode 100644 index 62c1ee3..0000000 --- a/sockets.c +++ /dev/null @@ -1,1269 +0,0 @@ -/* 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 "sockets.h" -#include "qemu-common.h" -#include -#include -#include "qemu_debug.h" -#include -#include -#include "android/utils/path.h" - -#ifdef _WIN32 -# define xxWIN32_LEAN_AND_MEAN -# include -# include -# include -#else /* !_WIN32 */ -# include -# include -# include -# include -# include -# if HAVE_UNIX_SOCKETS -# include -# 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 { _ret = (_cmd); } while ( _ret < 0 && errno == EINTR ) -#endif - -#ifdef _WIN32 - -#include - -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,EAGAIN,"resource temporarily unavailable") \ - EE(WSAEINPROGRESS,EAGAIN,"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 */ - - 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 = ""; - - for ( ; werr->string; werr++ ) { - if (werr->winsock == winsock_error) { - result = werr->string; - break; - } - } - - if (result == NULL) - result = 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 -1; - } -} - -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) -1; - } -} - -#if 0 -static int -socket_type_check( SocketType type ) -{ - return (type == SOCKET_DGRAM || type == SOCKET_STREAM); -} -#endif - -/* 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) - return buf; - if (buf+1 == end) - c = 0; - *buf++ = (char) c; - 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 - -int -sock_address_to_bsd( const SockAddress* a, void* paddress, size_t *psize ) -{ - switch (a->family) { - case SOCKET_INET: - { - struct sockaddr_in* dst = (struct sockaddr_in*) paddress; - - *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 = (struct sockaddr_in6*) paddress; - - *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 = (struct sockaddr_un*) paddress; - - if (slen >= UNIX_PATH_MAX) - return -1; - - memset( paddress, 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; -} - -int -sock_address_to_inet( SockAddress* a, int *paddr_ip, int *paddr_port ) -{ - struct sockaddr addr; - socklen_t addrlen; - - if (a->family != SOCKET_INET) { - return _set_errno(EINVAL); - } - - if (sock_address_to_bsd(a, &addr, &addrlen) < 0) - return -1; - - *paddr_ip = ntohl(((struct sockaddr_in*)&addr)->sin_addr.s_addr); - *paddr_port = ntohs(((struct sockaddr_in*)&addr)->sin_port); - - return 0; -} - -int -sock_address_from_bsd( SockAddress* a, const void* from, size_t fromlen ) -{ - switch (((struct sockaddr*)from)->sa_family) { - case AF_INET: - { - struct sockaddr_in* src = (struct sockaddr_in*) 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: - { - struct sockaddr_in6* src = (struct sockaddr_in6*) 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: - { - struct sockaddr_un* src = (struct sockaddr_un*) 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; - - if (getaddrinfo(hostname, NULL, hints, &res) < 0) { - return _fix_errno(); - } - - ret = sock_address_from_bsd( a, res->ai_addr, res->ai_addrlen ); - freeaddrinfo(res); - - /* 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: ; - } - - 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) -{ - struct sockaddr sa; - socklen_t salen; - - if (sock_address_to_bsd(to, &sa, &salen) < 0) - return -1; - - SOCKET_CALL(sendto(fd, buf, buflen, 0, &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) -{ - struct sockaddr sa; - socklen_t salen = sizeof(sa); - int ret; - - QSOCKET_CALL(ret,recvfrom(fd,buf,len,0,&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 ) -{ - struct sockaddr addr; - socklen_t addrlen; - - if (sock_address_to_bsd(address, &addr, &addrlen) < 0) - return -1; - - SOCKET_CALL(connect(fd,&addr,addrlen)); -} - -int -socket_bind( int fd, const SockAddress* address ) -{ - struct sockaddr addr; - socklen_t addrlen; - - if (sock_address_to_bsd(address, &addr, &addrlen) < 0) - return -1; - - SOCKET_CALL(bind(fd, &addr, addrlen)); -} - -int -socket_get_address( int fd, SockAddress* address ) -{ - struct sockaddr addr; - socklen_t addrlen = sizeof(addr); - int ret; - - QSOCKET_CALL(ret, getsockname(fd, &addr, &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 ) -{ - struct sockaddr addr; - socklen_t addrlen = sizeof(addr); - int ret; - - QSOCKET_CALL(ret, accept(fd, &addr, &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; -} - -SocketType socket_get_type(int fd) -{ - int opt = -1; - int optlen = sizeof(opt); - getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&opt, (void*)&optlen ); - - return socket_type_from_bsd(opt); -} - -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); -} - - -#ifdef _WIN32 -#include - -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 - -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) { - dprint("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) { - dprint("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) { - dprint( "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) { - dprint( "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; -} -- cgit v1.1