/* 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.
*/
/* headers to use the BSD sockets */
#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
#  ifndef EINTR
#    define EINTR        10004
#  endif
#  ifndef EWOULDBLOCK
#    define EWOULDBLOCK  10035
#  endif
#  ifndef EINPROGRESS
#    define EINPROGRESS  10036
#  endif
#  ifndef EALREADY
#    define EALREADY     10037
#  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 EAFNOSUPPORT
#    define EAFNOSUPPORT 10047
#  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 '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

/* 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

/* Unix sockets are not available on Win32 */
#ifndef _WIN32
#  define  HAVE_UNIX_SOCKETS  1
#endif

/* 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;

/* 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,
 */
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

/* 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

/* Finalize a socket address, only needed for now for Unix addresses */
void  sock_address_done( SockAddress*  a );

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 );

static __inline__
SocketFamily  sock_address_get_family( const SockAddress*  a )
{
    return a->family;
}

/* 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 );

/* set the port number of a given socket address, don't do anything for Unix ones */
void  sock_address_set_port( SockAddress*  a, uint16_t  port );

/* return the path of a given Unix socket, returns NULL for non-Unix ones */
const char*  sock_address_get_path( 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. Note that the values or errno
 * set by this function are the following:
 *
 *   EINVAL    : invalid argument
 *   EHOSTDOWN : could not reach DNS server
 *   ENOENT    : no host with this name, or host doesn't have any IP address
 *   ENOMEM    : not enough memory to perform request
 */
int   sock_address_init_resolve( SockAddress*  a,
                                 const char*   hostname,
                                 uint16_t      port,
                                 int           preferIn6 );

int  sock_address_get_numeric_info( SockAddress*  a,
                                    char*         host,
                                    size_t        hostlen,
                                    char*         serv,
                                    size_t        servlen );

/* Support for listing all socket addresses of a given host */
enum {
    SOCKET_LIST_PASSIVE    = (1 << 0),
    SOCKET_LIST_FORCE_INET = (1 << 1),
    SOCKET_LIST_FORCE_IN6  = (1 << 2)
};

/* resolve a host and service/port name into a list of SockAddress objects.
 * returns a NULL-terminated array of SockAddress pointers on success,
 * or NULL in case of failure, with the value of errno set to one of the
 * following:
 *
 *    EINVAL    : invalid argument
 *    EHOSTDOWN : could not reach DNS server
 *    ENOENT    : no host with this name, or host doesn't have IP address
 *    ENOMEM    : not enough memory to perform request
 *
 * other system-level errors can also be set depending on the host sockets
 * implementation.
 *
 * This function loops on EINTR so the caller shouldn't have to check for it.
 */
SockAddress**  sock_address_list_create( const char*  hostname,
                                         const char*  port,
                                         unsigned     flags );

void sock_address_list_free( SockAddress**  list );

/* 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_nodelay(int fd);

/* send OOB data inline for this socket */
int  socket_set_oobinline(int  fd);

/* force listening to IPv6 interfaces only */
int  socket_set_ipv6only(int  fd);

/* retrieve last socket error code */
int  socket_get_error(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 );

/* 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_get_peer_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:
 * socketpair(AF_LOCAL,SOCK_STREAM,0,&fds)
 *
 * on Windows, this will use a pair of TCP loopback sockets instead
 * returns 0 on success, -1 on error.
 */
int  socket_pair(int  *fd1, int *fd2);

/* create a server socket listening on the host's loopback interface */
int  socket_loopback_server( int  port, SocketType  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

/* 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 */