diff options
Diffstat (limited to 'sockets.h')
-rw-r--r-- | sockets.h | 328 |
1 files changed, 288 insertions, 40 deletions
@@ -13,44 +13,278 @@ #ifndef QEMU_SOCKET_H #define QEMU_SOCKET_H +#include <stddef.h> +#include <stdint.h> +#include <errno.h> + +/* we're going to hide the implementation details of sockets behind + * a simple wrapper interface declared here. + * + * all socket operations set the global 'errno' variable on error. + * this is unlike Winsock which instead modifies another internal + * variable accessed through WSAGetLastError() and WSASetLastError() + */ + +/* the wrapper will convert any Winsock error message into an errno + * code for you. There are however a few standard Unix error codes + * that are not defined by the MS C library headers, so we add them + * here. We use the official Winsock error codes, which are documented + * even though we don't want to include the Winsock headers + */ #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <winsock2.h> -#include <ws2tcpip.h> +# ifndef EINTR +# define EINTR 10004 +# endif +# ifndef EWOULDBLOCK +# define EWOULDBLOCK 10035 +# endif +# ifndef EINPROGRESS +# define EINPROGRESS 10036 +# endif +# ifndef EDESTADDRREQ +# define EDESTADDRREQ 10039 +# endif +# ifndef EMSGSIZE +# define EMSGSIZE 10040 +# endif +# ifndef EPROTOTYPE +# define EPROTOTYPE 10041 +# endif +# ifndef ENOPROTOOPT +# define ENOPROTOOPT 10042 +# endif +# ifndef EADDRINUSE +# define EADDRINUSE 10048 +# endif +# ifndef EADDRNOTAVAIL +# define EADDRNOTAVAIL 10049 +# endif +# ifndef ENETDOWN +# define ENETDOWN 10050 +# endif +# ifndef ENETUNREACH +# define ENETUNREACH 10051 +# endif +# ifndef ENETRESET +# define ENETRESET 10052 +# endif +# ifndef ECONNABORTED +# define ECONNABORTED 10053 +# endif +# ifndef ECONNRESET +# define ECONNRESET 10054 +# endif +# ifndef ENOBUFS +# define ENOBUFS 10055 +# endif +# ifndef EISCONN +# define EISCONN 10056 +# endif +# ifndef ENOTCONN +# define ENOTCONN 10057 +# endif +# ifndef ESHUTDOWN +# define ESHUTDOWN 10058 +# endif +# ifndef ETOOMANYREFS +# define ETOOMANYREFS 10059 +# endif +# ifndef ETIMEDOUT +# define ETIMEDOUT 10060 +# endif +# ifndef ECONNREFUSED +# define ECONNREFUSED 10061 +# endif +# ifndef ELOOP +# define ELOOP 10062 +# endif +# ifndef EHOSTDOWN +# define EHOSTDOWN 10064 +# endif +# ifndef EHOSTUNREACH +# define EHOSTUNREACH 10065 +# endif +#endif /* _WIN32 */ -#define socket_errno WSAGetLastError() -#define socket_errstr() socket_strerr() +/* Define 'errno_str' as a handy macro to return the string + * corresponding to a given errno code. On Unix, this is + * equivalent to strerror(errno), but on Windows, this will + * take care of Winsock-originated errors as well. + */ +#ifdef _WIN32 + extern const char* _errno_str(void); +# define errno_str _errno_str() +#else +# define errno_str strerror(errno) +#endif -#undef EINTR -#define EWOULDBLOCK WSAEWOULDBLOCK -#define EINTR WSAEINTR -#define EINPROGRESS WSAEINPROGRESS +/* always enable IPv6 sockets for now. + * the QEMU internal router is not capable of + * supporting them, but we plan to replace it + * with something better in the future. + */ +#define HAVE_IN6_SOCKETS 1 -extern const char* socket_strerr(void); +/* Unix sockets are not available on Win32 */ +#ifndef _WIN32 +# define HAVE_UNIX_SOCKETS 1 +#endif -#else +/* initialize the socket sub-system. this must be called before + * using any of the declarations below. + */ +int socket_init( void ); + +/* return the name of the current host */ +char* host_name( void ); + +/* supported socket types */ +typedef enum { + SOCKET_DGRAM = 0, + SOCKET_STREAM +} SocketType; + +/* supported socket families */ +typedef enum { + SOCKET_UNSPEC, + SOCKET_INET, + SOCKET_IN6, + SOCKET_UNIX +} SocketFamily; -/* if this code is included from slirp/ sources, don't include the - * system header files because this might conflict with some of the - * slirp definitions +/* Generic socket address structure. Note that for Unix + * sockets, the path is stored in a heap-allocated block, + * unless the 'owner' field is cleared. If this is the case, */ -#include <errno.h> -#ifndef SLIRP_COMPILATION -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <netdb.h> +typedef struct { + SocketFamily family; + union { + struct { + uint16_t port; + uint32_t address; + } inet; + struct { + uint16_t port; + uint8_t address[16]; + } in6; + struct { + int owner; + const char* path; + } _unix; + } u; +} SockAddress; + +#define SOCK_ADDRESS_INET_ANY 0x00000000 +#define SOCK_ADDRESS_INET_LOOPBACK 0x7f000001 + +/* initialize a new IPv4 socket address, the IP address and port are + * in host endianess. + */ +void sock_address_init_inet( SockAddress* a, uint32_t ip, uint16_t port ); + +/* Initialize an IPv6 socket address, the address is in network order + * and the port in host endianess. + */ +#if HAVE_IN6_SOCKETS +void sock_address_init_in6 ( SockAddress* a, const uint8_t* ip6[16], uint16_t port ); #endif -#define socket_errno errno -#define socket_errstr() strerror(errno) +/* Intialize a Unix socket address, this will copy the 'path' string into the + * heap. You need to call sock_address_done() to release the copy + */ +#if HAVE_UNIX_SOCKETS +void sock_address_init_unix( SockAddress* a, const char* path ); +#endif -#endif /* !_WIN32 */ +/* Finalize a socket address, only needed for now for Unix addresses */ +void sock_address_done( SockAddress* a ); -int socket_init( void ); +int sock_address_equal( const SockAddress* a, const SockAddress* b ); + +/* THIS SHOULD DISAPPEAR SOON - TRANSITIONAL HELPER */ +int sock_address_to_bsd( const SockAddress* a, void* sa, size_t* salen ); +int sock_address_from_bsd( SockAddress* a, const void* sa, size_t salen ); +int sock_address_to_inet( SockAddress* a, int *paddr_ip, int *paddr_port ); + +/* return a static string describing the address */ +const char* sock_address_to_string( const SockAddress* a ); + +/* return the port number of a given socket address, or -1 if it's a Unix one */ +int sock_address_get_port( const SockAddress* a ); + +/* return the inet address, or -1 if it's not SOCKET_INET */ +int sock_address_get_ip( const SockAddress* a ); + +/* bufprint a socket address into a human-readable string */ +char* bufprint_sock_address( char* p, char* end, const SockAddress* a ); + +/* resolve a hostname or decimal IPv4/IPv6 address into a socket address. + * returns 0 on success, or -1 on failure */ +int sock_address_init_resolve( SockAddress* a, const char* hostname, uint16_t port, int preferIn6 ); + +/* create a new socket, return the socket number of -1 on failure */ +int socket_create( SocketFamily family, SocketType type ); + +/* create a new socket intended for IPv4 communication. returns the socket number, + * or -1 on failure. + */ +int socket_create_inet( SocketType type ); + +/* create a new socket intended for IPv6 communication. returns the socket number, + * or -1 on failure. + */ +#if HAVE_IN6_SOCKETS +int socket_create_in6 ( SocketType type ); +#endif + +/* create a unix/local domain socket. returns the socket number, + * or -1 on failure. + */ +#if HAVE_UNIX_SOCKETS +int socket_create_unix( SocketType type ); +#endif + +/* return the type of a given socket */ +SocketType socket_get_type(int fd); + +/* set SO_REUSEADDR on Unix, SO_EXCLUSIVEADDR on Windows */ +int socket_set_xreuseaddr(int fd); + +/* set socket in non-blocking mode */ +int socket_set_nonblock(int fd); + +/* set socket in blocking mode */ +int socket_set_blocking(int fd); + +/* disable the TCP Nagle algorithm for lower latency */ +int socket_set_lowlatency(int fd); + +/* send OOB data inline for this socket */ +int socket_set_oobinline(int fd); + +/* close an opened socket. Note that this is unlike the Unix 'close' because: + * - it will properly shutdown the socket in the background + * - it does not modify errno + */ +void socket_close( int fd ); -int socket_get_type(int fd); +/* the following functions are equivalent to the BSD sockets ones + */ +int socket_recv ( int fd, void* buf, int buflen ); +int socket_recvfrom( int fd, void* buf, int buflen, SockAddress* from ); + +int socket_send ( int fd, const void* buf, int buflen ); +int socket_send_oob( int fd, const void* buf, int buflen ); +int socket_sendto( int fd, const void* buf, int buflen, const SockAddress* to ); + +int socket_connect( int fd, const SockAddress* address ); +int socket_bind( int fd, const SockAddress* address ); +int socket_get_address( int fd, SockAddress* address ); +int socket_listen( int fd, int backlog ); +int socket_accept( int fd, SockAddress* address ); + +/* returns the number of bytes that can be read from a socket */ +int socket_can_read( int fd ); /* this call creates a pair of non-blocking sockets connected * to each other. this is equivalent to calling the Unix function: @@ -61,22 +295,36 @@ int socket_get_type(int fd); */ int socket_pair(int *fd1, int *fd2); -/* set SO_REUSEADDR on Unix, SO_EXCLUSIVEADDR on Windows */ -int socket_set_xreuseaddr(int fd); -int socket_set_nonblock(int fd); -int socket_set_blocking(int fd); -int socket_set_lowlatency(int fd); -int socket_set_oobinline(int fd); -void socket_close(int fd); +/* create a server socket listening on the host's loopback interface */ +int socket_loopback_server( int port, SocketType type ); -int socket_loopback_server( int port, int type ); -int socket_loopback_client( int port, int type ); -#ifndef _WIN32 -int socket_unix_server( const char* name, int type ); -int socket_unix_client( const char* name, int type ); +/* connect to a port on the host's loopback interface */ +int socket_loopback_client( int port, SocketType type ); + +/* create a server socket listening to a Unix domain path */ +#if HAVE_UNIX_SOCKETS +int socket_unix_server( const char* name, SocketType type ); #endif -int socket_network_client( const char* host, int port, int type ); -int socket_anyaddr_server( int port, int type ); + +/* create a Unix sockets and connects it to a Unix server */ +#if HAVE_UNIX_SOCKETS +int socket_unix_client( const char* name, SocketType type ); +#endif + +/* create an IPv4 client socket and connect it to a given host */ +int socket_network_client( const char* host, int port, SocketType type ); + +/* create an IPv4 socket and binds it to a given port of the host's interface */ +int socket_anyaddr_server( int port, SocketType type ); + +/* accept a connection from the host's any interface, return the new socket + * descriptor or -1 */ int socket_accept_any( int server_fd ); + +int socket_mcast_inet_add_membership( int s, uint32_t ip ); +int socket_mcast_inet_drop_membership( int s, uint32_t ip ); +int socket_mcast_inet_set_loop( int s, int enabled ); +int socket_mcast_inet_set_ttl( int s, int ttl ); + #endif /* QEMU_SOCKET_H */ |