/*
  This file is part of libmicrohttpd
  Copyright (C) 2014-2023 Karlson2k (Evgeny Grin)

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*/

/**
 * @file microhttpd/mhd_sockets.c
 * @brief  Header for platform-independent sockets abstraction
 * @author Karlson2k (Evgeny Grin)
 *
 * Provides basic abstraction for sockets.
 * Any functions can be implemented as macro on some platforms
 * unless explicitly marked otherwise.
 * Any function argument can be skipped in macro, so avoid
 * variable modification in function parameters.
 */

#ifndef MHD_SOCKETS_H
#define MHD_SOCKETS_H 1
#include "mhd_options.h"

#include <errno.h>
#ifdef HAVE_STDBOOL_H
#include <stdbool.h>
#endif /* HAVE_STDBOOL_H */
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <fcntl.h>
#ifdef HAVE_STDDEF_H
#include <stddef.h>
#endif /* HAVE_STDDEF_H */
#if defined(_MSC_FULL_VER) && ! defined(_SSIZE_T_DEFINED)
#  include <stdint.h>
#  define _SSIZE_T_DEFINED
typedef intptr_t ssize_t;
#endif /* !_SSIZE_T_DEFINED */

#if ! defined(MHD_POSIX_SOCKETS) && ! defined(MHD_WINSOCK_SOCKETS)
#  if ! defined(_WIN32) || defined(__CYGWIN__)
#    define MHD_POSIX_SOCKETS 1
#  else  /* defined(_WIN32) && !defined(__CYGWIN__) */
#    define MHD_WINSOCK_SOCKETS 1
#  endif /* defined(_WIN32) && !defined(__CYGWIN__) */
#endif /* !MHD_POSIX_SOCKETS && !MHD_WINSOCK_SOCKETS */

/*
 * MHD require headers that define socket type, socket basic functions
 * (socket(), accept(), listen(), bind(), send(), recv(), select()), socket
 * parameters like SOCK_CLOEXEC, SOCK_NONBLOCK, additional socket functions
 * (poll(), epoll(), accept4()), struct timeval and other types, required
 * for socket function.
 */
#if defined(MHD_POSIX_SOCKETS)
#  ifdef HAVE_SYS_TYPES_H
#    include <sys/types.h> /* required on old platforms */
#  endif
#  ifdef HAVE_SYS_TIME_H
#    include <sys/time.h>
#  endif
#  ifdef HAVE_TIME_H
#    include <time.h>
#  endif
#  ifdef HAVE_STRING_H
#    include <string.h> /* for strerror() */
#  endif
#  ifdef HAVE_SYS_SOCKET_H
#    include <sys/socket.h>
#  endif
#  if defined(__VXWORKS__) || defined(__vxworks) || defined(OS_VXWORKS)
#    include <strings.h>  /* required for FD_SET (bzero() function) */
#    ifdef HAVE_SOCKLIB_H
#      include <sockLib.h>
#    endif /* HAVE_SOCKLIB_H */
#    ifdef HAVE_INETLIB_H
#      include <inetLib.h>
#    endif /* HAVE_INETLIB_H */
#  endif /* __VXWORKS__ || __vxworks || OS_VXWORKS */
#  ifdef HAVE_NETINET_IN_H
#    include <netinet/in.h>
#  endif /* HAVE_NETINET_IN_H */
#  ifdef HAVE_ARPA_INET_H
#    include <arpa/inet.h>
#  endif
#  ifdef HAVE_NET_IF_H
#    include <net/if.h>
#  endif
#  ifdef HAVE_NETDB_H
#    include <netdb.h>
#  endif
#  ifdef HAVE_SYS_SELECT_H
#    include <sys/select.h>
#  endif
#  ifdef EPOLL_SUPPORT
#    include <sys/epoll.h>
#  endif
#  ifdef HAVE_NETINET_TCP_H
/* for TCP_FASTOPEN and TCP_CORK */
#    include <netinet/tcp.h>
#  endif
#elif defined(MHD_WINSOCK_SOCKETS)
#  ifndef WIN32_LEAN_AND_MEAN
#    define WIN32_LEAN_AND_MEAN 1
#  endif /* !WIN32_LEAN_AND_MEAN */
#  include <winsock2.h>
#  include <ws2tcpip.h>
#endif /* MHD_WINSOCK_SOCKETS */

#if defined(HAVE_POLL_H) && defined(HAVE_POLL)
#  include <poll.h>
#endif


#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <sys/param.h> /* For __FreeBSD_version */
#endif /* __FreeBSD__ */

#include "mhd_limits.h"

#ifdef _MHD_FD_SETSIZE_IS_DEFAULT
#  define _MHD_SYS_DEFAULT_FD_SETSIZE FD_SETSIZE
#else  /* ! _MHD_FD_SETSIZE_IS_DEFAULT */
#  ifndef MHD_SYS_FD_SETSIZE_
#    include "sysfdsetsize.h"
#    define _MHD_SYS_DEFAULT_FD_SETSIZE get_system_fdsetsize_value ()
#  else  /* MHD_SYS_FD_SETSIZE_ */
#    define _MHD_SYS_DEFAULT_FD_SETSIZE MHD_SYS_FD_SETSIZE_
#  endif /* MHD_SYS_FD_SETSIZE_ */
#endif /* ! _MHD_FD_SETSIZE_IS_DEFAULT */

#ifndef MHD_PANIC
#  include <stdio.h>
#  include <stdlib.h>
/* Simple implementation of MHD_PANIC, to be used outside lib */
#  define MHD_PANIC(msg) \
    do { fprintf (stderr,           \
                  "Abnormal termination at %d line in file %s: %s\n", \
                  (int) __LINE__, __FILE__, msg); abort (); \
} while (0)
#endif /* ! MHD_PANIC */

#ifndef MHD_SOCKET_DEFINED
/**
 * MHD_socket is type for socket FDs
 */
#  if defined(MHD_POSIX_SOCKETS)
typedef int MHD_socket;
#    define MHD_INVALID_SOCKET (-1)
#  elif defined(MHD_WINSOCK_SOCKETS)
typedef SOCKET MHD_socket;
#    define MHD_INVALID_SOCKET (INVALID_SOCKET)
#  endif /* MHD_WINSOCK_SOCKETS */

#  define MHD_SOCKET_DEFINED 1
#endif /* ! MHD_SOCKET_DEFINED */

#ifdef SOCK_CLOEXEC
#  define SOCK_CLOEXEC_OR_ZERO SOCK_CLOEXEC
#else  /* ! SOCK_CLOEXEC */
#  define SOCK_CLOEXEC_OR_ZERO 0
#endif /* ! SOCK_CLOEXEC */

#ifdef HAVE_SOCK_NONBLOCK
#  define SOCK_NONBLOCK_OR_ZERO SOCK_NONBLOCK
#else  /* ! HAVE_SOCK_NONBLOCK */
#  define SOCK_NONBLOCK_OR_ZERO 0
#endif /* ! HAVE_SOCK_NONBLOCK */

#ifdef SOCK_NOSIGPIPE
#  define SOCK_NOSIGPIPE_OR_ZERO SOCK_NOSIGPIPE
#else  /* ! HAVE_SOCK_NONBLOCK */
#  define SOCK_NOSIGPIPE_OR_ZERO 0
#endif /* ! HAVE_SOCK_NONBLOCK */

#ifdef MSG_NOSIGNAL
#  define MSG_NOSIGNAL_OR_ZERO MSG_NOSIGNAL
#else  /* ! MSG_NOSIGNAL */
#  define MSG_NOSIGNAL_OR_ZERO 0
#endif /* ! MSG_NOSIGNAL */

#if ! defined(SHUT_WR) && defined(SD_SEND)
#  define SHUT_WR SD_SEND
#endif
#if ! defined(SHUT_RD) && defined(SD_RECEIVE)
#  define SHUT_RD SD_RECEIVE
#endif
#if ! defined(SHUT_RDWR) && defined(SD_BOTH)
#  define SHUT_RDWR SD_BOTH
#endif

#if defined(HAVE_ACCEPT4) && (defined(HAVE_SOCK_NONBLOCK) || \
  defined(SOCK_CLOEXEC) || defined(SOCK_NOSIGPIPE))
#  define USE_ACCEPT4 1
#endif

#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
  defined(__OpenBSD__) || defined(__NetBSD__) || \
  defined(MHD_WINSOCK_SOCKETS) || defined(__MACH__) || defined(__sun) || \
  defined(SOMEBSD)
/* Most of OSes inherit nonblocking setting from the listen socket */
#define MHD_ACCEPT_INHERIT_NONBLOCK 1
#endif

#if defined(HAVE_EPOLL_CREATE1) && defined(EPOLL_CLOEXEC)
#  define USE_EPOLL_CREATE1 1
#endif /* HAVE_EPOLL_CREATE1 && EPOLL_CLOEXEC */

#ifdef TCP_FASTOPEN
/**
 * Default TCP fastopen queue size.
 */
#define MHD_TCP_FASTOPEN_QUEUE_SIZE_DEFAULT 10
#endif


#if defined(TCP_CORK)
/**
 * Value of TCP_CORK or TCP_NOPUSH
 */
#define MHD_TCP_CORK_NOPUSH TCP_CORK
#elif defined(TCP_NOPUSH)
/**
 * Value of TCP_CORK or TCP_NOPUSH
 */
#define MHD_TCP_CORK_NOPUSH TCP_NOPUSH
#endif /* TCP_NOPUSH */


#ifdef MHD_TCP_CORK_NOPUSH
#ifdef __linux__
/**
 * Indicate that reset of TCP_CORK / TCP_NOPUSH push data to the network
 */
#define _MHD_CORK_RESET_PUSH_DATA 1
/**
 * Indicate that reset of TCP_CORK / TCP_NOPUSH push data to the network
 * even if TCP_CORK/TCP_NOPUSH was in switched off state.
 */
#define _MHD_CORK_RESET_PUSH_DATA_ALWAYS 1
#endif /* __linux__ */
#if (defined(__FreeBSD__) && \
  ((__FreeBSD__ + 0) >= 5 || (__FreeBSD_version + 0) >= 450000)) || \
  (defined(__FreeBSD_kernel_version) && \
  (__FreeBSD_kernel_version + 0) >= 450000)
/* FreeBSD pushes data to the network with reset of TCP_NOPUSH
 * starting from version 4.5. */
/**
 * Indicate that reset of TCP_CORK / TCP_NOPUSH push data to the network
 */
#define _MHD_CORK_RESET_PUSH_DATA 1
#endif /* __FreeBSD_version >= 450000 */
#ifdef __OpenBSD__
/* OpenBSD took implementation from FreeBSD */
/**
 * Indicate that reset of TCP_CORK / TCP_NOPUSH push data to the network
 */
#define _MHD_CORK_RESET_PUSH_DATA 1
#endif /* __OpenBSD__ */
#endif /* MHD_TCP_CORK_NOPUSH */

#ifdef __linux__
/**
 * Indicate that set of TCP_NODELAY push data to the network
 */
#define _MHD_NODELAY_SET_PUSH_DATA 1
/**
 * Indicate that set of TCP_NODELAY push data to the network even
 * if TCP_DELAY was already set and regardless of TCP_CORK / TCP_NOPUSH state
 */
#define _MHD_NODELAY_SET_PUSH_DATA_ALWAYS 1
#endif /* __linux__ */

#ifdef MSG_MORE
#ifdef __linux__
/* MSG_MORE signal kernel to buffer outbond data and works like
 * TCP_CORK per call without actually setting TCP_CORK value.
 * It's known to work on Linux. Add more OSes if they are compatible. */
/**
 * Indicate MSG_MORE is usable for buffered send().
 */
#define MHD_USE_MSG_MORE 1
#endif /* __linux__ */
#endif /* MSG_MORE */


/**
 * MHD_SCKT_OPT_BOOL_ is type for bool parameters for setsockopt()/getsockopt()
 */
#ifdef MHD_POSIX_SOCKETS
typedef int MHD_SCKT_OPT_BOOL_;
#else /* MHD_WINSOCK_SOCKETS */
typedef BOOL MHD_SCKT_OPT_BOOL_;
#endif /* MHD_WINSOCK_SOCKETS */

/**
 * MHD_SCKT_SEND_SIZE_ is type used to specify size for send and recv
 * functions
 */
#if ! defined(MHD_WINSOCK_SOCKETS)
typedef size_t MHD_SCKT_SEND_SIZE_;
#else
typedef int MHD_SCKT_SEND_SIZE_;
#endif

/**
 * MHD_SCKT_SEND_MAX_SIZE_ is maximum send()/recv() size value.
 */
#if ! defined(MHD_WINSOCK_SOCKETS)
#  define MHD_SCKT_SEND_MAX_SIZE_ SSIZE_MAX
#else
#  define MHD_SCKT_SEND_MAX_SIZE_ INT_MAX
#endif

/**
 * MHD_socket_close_(fd) close any FDs (non-W32) / close only socket
 * FDs (W32).  Note that on HP-UNIX, this function may leak the FD if
 * errno is set to EINTR.  Do not use HP-UNIX.
 *
 * @param fd descriptor to close
 * @return boolean true on success (error codes like EINTR and EIO are
 *         counted as success, only EBADF counts as an error!),
 *         boolean false otherwise.
 */
#if ! defined(MHD_WINSOCK_SOCKETS)
#  define MHD_socket_close_(fd) ((0 == close ((fd))) || (EBADF != errno))
#else
#  define MHD_socket_close_(fd) (0 == closesocket ((fd)))
#endif

/**
 * MHD_socket_close_chk_(fd) close socket and abort execution
 * if error is detected.
 * @param fd socket to close
 */
#define MHD_socket_close_chk_(fd) do {        \
    if (! MHD_socket_close_ (fd))               \
      MHD_PANIC (_ ("Close socket failed.\n")); \
} while (0)


/**
 * MHD_send4_ is a wrapper for system's send()
 * @param s the socket to use
 * @param b the buffer with data to send
 * @param l the length of data in @a b
 * @param f the additional flags
 * @return ssize_t type value
 */
#define MHD_send4_(s,b,l,f) \
  ((ssize_t) send ((s),(const void*) (b),(MHD_SCKT_SEND_SIZE_) (l), \
                   ((MSG_NOSIGNAL_OR_ZERO) | (f))))


/**
 * MHD_send_ is a simple wrapper for system's send()
 * @param s the socket to use
 * @param b the buffer with data to send
 * @param l the length of data in @a b
 * @return ssize_t type value
 */
#define MHD_send_(s,b,l) MHD_send4_((s),(b),(l), 0)


/**
 * MHD_recv_ is wrapper for system's recv()
 * @param s the socket to use
 * @param b the buffer for data to receive
 * @param l the length of @a b
 * @return ssize_t type value
 */
#define MHD_recv_(s,b,l) \
  ((ssize_t) recv ((s),(void*) (b),(MHD_SCKT_SEND_SIZE_) (l), 0))


/**
 * Check whether FD can be added to fd_set with specified FD_SETSIZE.
 * @param fd   the fd to check
 * @param pset the pointer to fd_set to check or NULL to check
 *             whether FD can be used with fd_sets.
 * @param setsize the value of FD_SETSIZE.
 * @return boolean true if FD can be added to fd_set,
 *         boolean false otherwise.
 */
#if defined(MHD_POSIX_SOCKETS)
#  define MHD_SCKT_FD_FITS_FDSET_SETSIZE_(fd,pset,setsize) \
    ((fd) < ((MHD_socket) (setsize)))
#elif defined(MHD_WINSOCK_SOCKETS)
#  define MHD_SCKT_FD_FITS_FDSET_SETSIZE_(fd,pset,setsize) \
   ( ((void*) (pset)==  (void*) 0) || \
     (((fd_set*) (pset))->fd_count < ((unsigned) setsize)) || \
     (FD_ISSET ((fd), (pset))) )
#endif

/**
 * Check whether FD can be added to fd_set with current FD_SETSIZE.
 * @param fd   the fd to check
 * @param pset the pointer to fd_set to check or NULL to check
 *             whether FD can be used with fd_sets.
 * @return boolean true if FD can be added to fd_set,
 *         boolean false otherwise.
 */
#define MHD_SCKT_FD_FITS_FDSET_(fd,pset) \
  MHD_SCKT_FD_FITS_FDSET_SETSIZE_ ((fd), (pset), FD_SETSIZE)

/**
 * Add FD to fd_set with specified FD_SETSIZE.
 * @param fd   the fd to add
 * @param pset the valid pointer to fd_set.
 * @param setsize the value of FD_SETSIZE.
 * @note  To work on W32 with value of FD_SETSIZE different from currently defined value,
 *        system definition of FD_SET() is not used.
 */
#if defined(MHD_POSIX_SOCKETS)
#  define MHD_SCKT_ADD_FD_TO_FDSET_SETSIZE_(fd,pset,setsize) \
  FD_SET ((fd), (pset))
#elif defined(MHD_WINSOCK_SOCKETS)
#  define MHD_SCKT_ADD_FD_TO_FDSET_SETSIZE_(fd,pset,setsize)                \
  do {                                                                      \
    u_int _i_ = 0;                                                          \
    fd_set*const _s_ = (fd_set*) (pset);                                    \
    while ((_i_ < _s_->fd_count) && ((fd) != _s_->fd_array [_i_])) {++_i_;} \
    if ((_i_ == _s_->fd_count)) {_s_->fd_array [_s_->fd_count ++] = (fd);}  \
  } while (0)
#endif

/* MHD_SYS_select_ is wrapper macro for system select() function */
#if ! defined(MHD_WINSOCK_SOCKETS)
#  define MHD_SYS_select_(n,r,w,e,t) select ((n),(r),(w),(e),(t))
#else
#  define MHD_SYS_select_(n,r,w,e,t) \
  ( ( (((void*) (r) == (void*) 0) || ((fd_set*) (r))->fd_count == 0) &&  \
      (((void*) (w) == (void*) 0) || ((fd_set*) (w))->fd_count == 0) &&  \
      (((void*) (e) == (void*) 0) || ((fd_set*) (e))->fd_count == 0) ) ? \
    ( ((void*) (t) == (void*) 0) ? 0 :                                   \
      (Sleep ((DWORD)((struct timeval*) (t))->tv_sec * 1000              \
              + (DWORD)((struct timeval*) (t))->tv_usec / 1000), 0) ) :  \
    (select ((int) 0,(r),(w),(e),(t))) )
#endif

#if defined(HAVE_POLL)
/* MHD_sys_poll_ is wrapper macro for system poll() function */
#  if ! defined(MHD_WINSOCK_SOCKETS)
#    define MHD_sys_poll_ poll
#  else  /* MHD_WINSOCK_SOCKETS */
#    define MHD_sys_poll_ WSAPoll
#  endif /* MHD_WINSOCK_SOCKETS */

#  ifdef POLLPRI
#    define MHD_POLLPRI_OR_ZERO POLLPRI
#  else  /* ! POLLPRI */
#    define MHD_POLLPRI_OR_ZERO 0
#  endif /* ! POLLPRI */
#  ifdef POLLRDBAND
#    define MHD_POLLRDBAND_OR_ZERO POLLRDBAND
#  else  /* ! POLLRDBAND */
#    define MHD_POLLRDBAND_OR_ZERO 0
#  endif /* ! POLLRDBAND */
#  ifdef POLLNVAL
#    define MHD_POLLNVAL_OR_ZERO POLLNVAL
#  else  /* ! POLLNVAL */
#    define MHD_POLLNVAL_OR_ZERO 0
#  endif /* ! POLLNVAL */

/* MHD_POLL_EVENTS_ERR_DISC is 'events' mask for errors and disconnect.
 * Note: Out-of-band data is treated as error. */
#  if defined(_WIN32) && ! defined(__CYGWIN__)
#    define MHD_POLL_EVENTS_ERR_DISC POLLRDBAND
#  elif defined(__linux__)
#    define MHD_POLL_EVENTS_ERR_DISC POLLPRI
#  else /* ! __linux__ */
#    define MHD_POLL_EVENTS_ERR_DISC \
       (MHD_POLLPRI_OR_ZERO | MHD_POLLRDBAND_OR_ZERO)
#  endif /* ! __linux__ */
/* MHD_POLL_REVENTS_ERR_DISC is 'revents' mask for errors and disconnect.
 * Note: Out-of-band data is treated as error. */
#  define MHD_POLL_REVENTS_ERR_DISC \
  (MHD_POLLPRI_OR_ZERO | MHD_POLLRDBAND_OR_ZERO | MHD_POLLNVAL_OR_ZERO \
   | POLLERR | POLLHUP)
/* MHD_POLL_REVENTS_ERRROR is 'revents' mask for errors.
 * Note: Out-of-band data is treated as error. */
#  define MHD_POLL_REVENTS_ERRROR \
  (MHD_POLLPRI_OR_ZERO | MHD_POLLRDBAND_OR_ZERO | MHD_POLLNVAL_OR_ZERO \
   | POLLERR)
#endif /* HAVE_POLL */

#define MHD_SCKT_MISSING_ERR_CODE_ 31450

#if defined(MHD_POSIX_SOCKETS)
#  if defined(EAGAIN)
#    define MHD_SCKT_EAGAIN_      EAGAIN
#  elif defined(EWOULDBLOCK)
#    define MHD_SCKT_EAGAIN_      EWOULDBLOCK
#  else  /* !EAGAIN && !EWOULDBLOCK */
#    define MHD_SCKT_EAGAIN_      MHD_SCKT_MISSING_ERR_CODE_
#  endif /* !EAGAIN && !EWOULDBLOCK */
#  if defined(EWOULDBLOCK)
#    define MHD_SCKT_EWOULDBLOCK_ EWOULDBLOCK
#  elif defined(EAGAIN)
#    define MHD_SCKT_EWOULDBLOCK_ EAGAIN
#  else  /* !EWOULDBLOCK && !EAGAIN */
#    define MHD_SCKT_EWOULDBLOCK_ MHD_SCKT_MISSING_ERR_CODE_
#  endif /* !EWOULDBLOCK && !EAGAIN */
#  ifdef EINTR
#    define MHD_SCKT_EINTR_       EINTR
#  else  /* ! EINTR */
#    define MHD_SCKT_EINTR_       MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! EINTR */
#  ifdef ECONNRESET
#    define MHD_SCKT_ECONNRESET_  ECONNRESET
#  else  /* ! ECONNRESET */
#    define MHD_SCKT_ECONNRESET_  MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! ECONNRESET */
#  ifdef ECONNABORTED
#    define MHD_SCKT_ECONNABORTED_  ECONNABORTED
#  else  /* ! ECONNABORTED */
#    define MHD_SCKT_ECONNABORTED_  MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! ECONNABORTED */
#  ifdef ENOTCONN
#    define MHD_SCKT_ENOTCONN_    ENOTCONN
#  else  /* ! ENOTCONN */
#    define MHD_SCKT_ENOTCONN_    MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! ENOTCONN */
#  ifdef EMFILE
#    define MHD_SCKT_EMFILE_      EMFILE
#  else  /* ! EMFILE */
#    define MHD_SCKT_EMFILE_      MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! EMFILE */
#  ifdef ENFILE
#    define MHD_SCKT_ENFILE_      ENFILE
#  else  /* ! ENFILE */
#    define MHD_SCKT_ENFILE_      MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! ENFILE */
#  ifdef ENOMEM
#    define MHD_SCKT_ENOMEM_      ENOMEM
#  else  /* ! ENOMEM */
#    define MHD_SCKT_ENOMEM_      MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! ENOMEM */
#  ifdef ENOBUFS
#    define MHD_SCKT_ENOBUFS_     ENOBUFS
#  else  /* ! ENOBUFS */
#    define MHD_SCKT_ENOBUFS_     MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! ENOBUFS */
#  ifdef EBADF
#    define MHD_SCKT_EBADF_       EBADF
#  else  /* ! EBADF */
#    define MHD_SCKT_EBADF_       MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! EBADF */
#  ifdef ENOTSOCK
#    define MHD_SCKT_ENOTSOCK_    ENOTSOCK
#  else  /* ! ENOTSOCK */
#    define MHD_SCKT_ENOTSOCK_    MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! ENOTSOCK */
#  ifdef EINVAL
#    define MHD_SCKT_EINVAL_      EINVAL
#  else  /* ! EINVAL */
#    define MHD_SCKT_EINVAL_      MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! EINVAL */
#  ifdef EPIPE
#    define MHD_SCKT_EPIPE_       EPIPE
#  else  /* ! EPIPE */
#    define MHD_SCKT_EPIPE_       MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! EPIPE */
#  ifdef EFAULT
#    define MHD_SCKT_EFAUL_       EFAULT
#  else  /* ! EFAULT */
#    define MHD_SCKT_EFAUL_       MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! EFAULT */
#  ifdef ENOSYS
#    define MHD_SCKT_ENOSYS_      ENOSYS
#  else  /* ! ENOSYS */
#    define MHD_SCKT_ENOSYS_      MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! ENOSYS */
#  ifdef ENOPROTOOPT
#    define MHD_SCKT_ENOPROTOOPT_      ENOPROTOOPT
#  else  /* ! ENOPROTOOPT */
#    define MHD_SCKT_ENOPROTOOPT_      MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! ENOPROTOOPT */
#  ifdef ENOTSUP
#    define MHD_SCKT_ENOTSUP_     ENOTSUP
#  else  /* ! ENOTSUP */
#    define MHD_SCKT_ENOTSUP_     MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! ENOTSUP */
#  ifdef EOPNOTSUPP
#    define MHD_SCKT_EOPNOTSUPP_  EOPNOTSUPP
#  else  /* ! EOPNOTSUPP */
#    define MHD_SCKT_EOPNOTSUPP_  MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! EOPNOTSUPP */
#  ifdef EACCES
#    define MHD_SCKT_EACCESS_     EACCES
#  else  /* ! EACCES */
#    define MHD_SCKT_EACCESS_     MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! EACCES */
#  ifdef ENETDOWN
#    define MHD_SCKT_ENETDOWN_    ENETDOWN
#  else  /* ! ENETDOWN */
#    define MHD_SCKT_ENETDOWN_    MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! ENETDOWN */
#  ifdef EALREADY
#    define MHD_SCKT_EALREADY_    EALREADY
#  else  /* ! EALREADY */
#    define MHD_SCKT_EALREADY_    MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! EALREADY */
#  ifdef EINPROGRESS
#    define MHD_SCKT_EINPROGRESS_ EINPROGRESS
#  else  /* ! EINPROGRESS */
#    define MHD_SCKT_EINPROGRESS_ MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! EINPROGRESS */
#  ifdef EISCONN
#    define MHD_SCKT_EISCONN_     EISCONN
#  else  /* ! EISCONN */
#    define MHD_SCKT_EISCONN_     MHD_SCKT_MISSING_ERR_CODE_
#  endif /* ! EISCONN */
#elif defined(MHD_WINSOCK_SOCKETS)
#  define MHD_SCKT_EAGAIN_        WSAEWOULDBLOCK
#  define MHD_SCKT_EWOULDBLOCK_   WSAEWOULDBLOCK
#  define MHD_SCKT_EINTR_         WSAEINTR
#  define MHD_SCKT_ECONNRESET_    WSAECONNRESET
#  define MHD_SCKT_ECONNABORTED_  WSAECONNABORTED
#  define MHD_SCKT_ENOTCONN_      WSAENOTCONN
#  define MHD_SCKT_EMFILE_        WSAEMFILE
#  define MHD_SCKT_ENFILE_        MHD_SCKT_MISSING_ERR_CODE_
#  define MHD_SCKT_ENOMEM_        MHD_SCKT_MISSING_ERR_CODE_
#  define MHD_SCKT_ENOBUFS_       WSAENOBUFS
#  define MHD_SCKT_EBADF_         WSAEBADF
#  define MHD_SCKT_ENOTSOCK_      WSAENOTSOCK
#  define MHD_SCKT_EINVAL_        WSAEINVAL
#  define MHD_SCKT_EPIPE_         WSAESHUTDOWN
#  define MHD_SCKT_EFAUL_         WSAEFAULT
#  define MHD_SCKT_ENOSYS_        MHD_SCKT_MISSING_ERR_CODE_
#  define MHD_SCKT_ENOPROTOOPT_   WSAENOPROTOOPT
#  define MHD_SCKT_ENOTSUP_       MHD_SCKT_MISSING_ERR_CODE_
#  define MHD_SCKT_EOPNOTSUPP_    WSAEOPNOTSUPP
#  define MHD_SCKT_EACCESS_       WSAEACCES
#  define MHD_SCKT_ENETDOWN_      WSAENETDOWN
#  define MHD_SCKT_EALREADY_      WSAEALREADY
#  define MHD_SCKT_EINPROGRESS_   WSAEINPROGRESS
#  define MHD_SCKT_EISCONN_       WSAEISCONN
#endif

/**
 * MHD_socket_error_ return system native error code for last socket error.
 * @return system error code for last socket error.
 */
#if defined(MHD_POSIX_SOCKETS)
#  define MHD_socket_get_error_() (errno)
#elif defined(MHD_WINSOCK_SOCKETS)
#  define MHD_socket_get_error_() WSAGetLastError ()
#endif

#ifdef MHD_WINSOCK_SOCKETS
/* POSIX-W32 sockets compatibility functions */

/**
 * Return pointer to string description of specified WinSock error
 * @param err the WinSock error code.
 * @return pointer to string description of specified WinSock error.
 */
const char *MHD_W32_strerror_winsock_ (int err);

#endif /* MHD_WINSOCK_SOCKETS */

/* MHD_socket_last_strerr_ is description string of specified socket error code */
#if defined(MHD_POSIX_SOCKETS)
#  define MHD_socket_strerr_(err) strerror ((err))
#elif defined(MHD_WINSOCK_SOCKETS)
#  define MHD_socket_strerr_(err) MHD_W32_strerror_winsock_ ((err))
#endif

/* MHD_socket_last_strerr_ is description string of last errno (non-W32) /
 *                            description string of last socket error (W32) */
#define MHD_socket_last_strerr_() MHD_socket_strerr_ (MHD_socket_get_error_ ())

/**
 * MHD_socket_fset_error_() set socket system native error code.
 */
#if defined(MHD_POSIX_SOCKETS)
#  define MHD_socket_fset_error_(err) (errno = (err))
#elif defined(MHD_WINSOCK_SOCKETS)
#  define MHD_socket_fset_error_(err) (WSASetLastError ((err)))
#endif

/**
 * MHD_socket_try_set_error_() set socket system native error code if
 * specified code is defined on system.
 * @return non-zero if specified @a err code is defined on system
 *         and error was set;
 *         zero if specified @a err code is not defined on system
 *         and error was not set.
 */
#define MHD_socket_try_set_error_(err) \
  ( (MHD_SCKT_MISSING_ERR_CODE_ != (err)) ? \
      (MHD_socket_fset_error_ ((err)), ! 0) : 0)

/**
 * MHD_socket_set_error_() set socket system native error code to
 * specified code or replacement code if specified code is not
 * defined on system.
 */
#if defined(MHD_POSIX_SOCKETS)
#  if defined(ENOSYS)
#    define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
                                         (errno = ENOSYS) : (errno = (err)) )
#  elif defined(EOPNOTSUPP)
#    define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
                                         (errno = EOPNOTSUPP) : (errno = \
                                                                   (err)) )
#  elif defined(EFAULT)
#    define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
                                         (errno = EFAULT) : (errno = (err)) )
#  elif defined(EINVAL)
#    define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
                                         (errno = EINVAL) : (errno = (err)) )
#  else  /* !EOPNOTSUPP && !EFAULT && !EINVAL */
#    warning \
  No suitable replacement for missing socket error code is found. Edit this file and add replacement code which is defined on system.
#    define MHD_socket_set_error_(err) (errno = (err))
#  endif /* !EOPNOTSUPP && !EFAULT && !EINVAL*/
#elif defined(MHD_WINSOCK_SOCKETS)
#  define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
                                       (WSASetLastError ((WSAEOPNOTSUPP))) : \
                                       (WSASetLastError ((err))) )
#endif

/**
 * Check whether given socket error is equal to specified system
 * native MHD_SCKT_E*_ code.
 * If platform don't have specific error code, result is
 * always boolean false.
 * @return boolean true if @a code is real error code and
 *         @a err equals to MHD_SCKT_E*_ @a code;
 *         boolean false otherwise
 */
#define MHD_SCKT_ERR_IS_(err,code) \
  ( (MHD_SCKT_MISSING_ERR_CODE_ != (code)) && ((code) == (err)) )

/**
 * Check whether last socket error is equal to specified system
 * native MHD_SCKT_E*_ code.
 * If platform don't have specific error code, result is
 * always boolean false.
 * @return boolean true if @a code is real error code and
 *         last socket error equals to MHD_SCKT_E*_ @a code;
 *         boolean false otherwise
 */
#define MHD_SCKT_LAST_ERR_IS_(code) \
  MHD_SCKT_ERR_IS_ (MHD_socket_get_error_ (), (code))

/* Specific error code checks */

/**
 * Check whether given socket error is equal to system's
 * socket error codes for EINTR.
 * @return boolean true if @a err is equal to sockets' EINTR code;
 *         boolean false otherwise.
 */
#define MHD_SCKT_ERR_IS_EINTR_(err) MHD_SCKT_ERR_IS_ ((err),MHD_SCKT_EINTR_)

/**
 * Check whether given socket error is equal to system's
 * socket error codes for EAGAIN or EWOULDBLOCK.
 * @return boolean true if @a err is equal to sockets' EAGAIN or EWOULDBLOCK codes;
 *         boolean false otherwise.
 */
#if MHD_SCKT_EAGAIN_ == MHD_SCKT_EWOULDBLOCK_
#  define MHD_SCKT_ERR_IS_EAGAIN_(err) MHD_SCKT_ERR_IS_ ((err),MHD_SCKT_EAGAIN_)
#else  /* MHD_SCKT_EAGAIN_ != MHD_SCKT_EWOULDBLOCK_ */
#  define MHD_SCKT_ERR_IS_EAGAIN_(err) \
  ( MHD_SCKT_ERR_IS_ ((err), MHD_SCKT_EAGAIN_) || \
    MHD_SCKT_ERR_IS_ ((err), MHD_SCKT_EWOULDBLOCK_) )
#endif /* MHD_SCKT_EAGAIN_ != MHD_SCKT_EWOULDBLOCK_ */

/**
 * Check whether given socket error is any kind of "low resource" error.
 * @return boolean true if @a err is any kind of "low resource" error,
 *         boolean false otherwise.
 */
#define MHD_SCKT_ERR_IS_LOW_RESOURCES_(err) \
  ( MHD_SCKT_ERR_IS_ ((err), MHD_SCKT_EMFILE_) || \
    MHD_SCKT_ERR_IS_ ((err), MHD_SCKT_ENFILE_) || \
    MHD_SCKT_ERR_IS_ ((err), MHD_SCKT_ENOMEM_) || \
    MHD_SCKT_ERR_IS_ ((err), MHD_SCKT_ENOBUFS_) )

/**
 * Check whether is given socket error is type of "incoming connection
 * was disconnected before 'accept()' is called".
 * @return boolean true is @a err match described socket error code,
 *         boolean false otherwise.
 */
#if defined(MHD_POSIX_SOCKETS)
#  define MHD_SCKT_ERR_IS_DISCNN_BEFORE_ACCEPT_(err) \
  MHD_SCKT_ERR_IS_ ((err), MHD_SCKT_ECONNABORTED_)
#elif defined(MHD_WINSOCK_SOCKETS)
#  define MHD_SCKT_ERR_IS_DISCNN_BEFORE_ACCEPT_(err) \
  MHD_SCKT_ERR_IS_ ((err), MHD_SCKT_ECONNRESET_)
#endif

/**
 * Check whether is given socket error is type of "connection was terminated
 * by remote side".
 * @return boolean true is @a err match described socket error code,
 *         boolean false otherwise.
 */
#define MHD_SCKT_ERR_IS_REMOTE_DISCNN_(err) \
  ( MHD_SCKT_ERR_IS_ ((err), MHD_SCKT_ECONNRESET_) || \
    MHD_SCKT_ERR_IS_ ((err), MHD_SCKT_ECONNABORTED_) )

/* Specific error code set */

/**
 * Set socket's error code to ENOMEM or equivalent if ENOMEM is not
 * available on platform.
 */
#if MHD_SCKT_MISSING_ERR_CODE_ != MHD_SCKT_ENOMEM_
#  define MHD_socket_set_error_to_ENOMEM() \
  MHD_socket_set_error_ (MHD_SCKT_ENOMEM_)
#elif MHD_SCKT_MISSING_ERR_CODE_ != MHD_SCKT_ENOBUFS_
#  define MHD_socket_set_error_to_ENOMEM() \
  MHD_socket_set_error_ (MHD_SCKT_ENOBUFS_)
#else
#  warning \
  No suitable replacement for ENOMEM error codes is found. Edit this file and add replacement code which is defined on system.
#  define MHD_socket_set_error_to_ENOMEM() MHD_socket_set_error_ ( \
    MHD_SCKT_ENOMEM_)
#endif

/* Socket functions */

#if defined(AF_LOCAL)
#  define MHD_SCKT_LOCAL AF_LOCAL
#elif defined(AF_UNIX)
#  define MHD_SCKT_LOCAL AF_UNIX
#endif /* AF_UNIX */

#if defined(MHD_POSIX_SOCKETS) && defined(MHD_SCKT_LOCAL)
#  define MHD_socket_pair_(fdarr) \
    (! socketpair (MHD_SCKT_LOCAL, SOCK_STREAM, 0, (fdarr)))
#  if defined(HAVE_SOCK_NONBLOCK)
#    define MHD_socket_pair_nblk_(fdarr) \
      (! socketpair (MHD_SCKT_LOCAL, SOCK_STREAM | SOCK_NONBLOCK, 0, (fdarr)))
#  endif /* HAVE_SOCK_NONBLOCK*/
#elif defined(MHD_WINSOCK_SOCKETS)
/**
 * Create pair of mutually connected TCP/IP sockets on loopback address
 * @param sockets_pair array to receive resulted sockets
 * @param non_blk if set to non-zero value, sockets created in non-blocking mode
 *                otherwise sockets will be in blocking mode
 * @return non-zero if succeeded, zero otherwise
 */
int MHD_W32_socket_pair_ (SOCKET sockets_pair[2], int non_blk);

#  define MHD_socket_pair_(fdarr) MHD_W32_socket_pair_ ((fdarr), 0)
#  define MHD_socket_pair_nblk_(fdarr) MHD_W32_socket_pair_ ((fdarr), 1)
#endif

/**
 * Add @a fd to the @a set.  If @a fd is
 * greater than @a max_fd, set @a max_fd to @a fd.
 *
 * @param fd file descriptor to add to the @a set
 * @param set set to modify
 * @param max_fd maximum value to potentially update
 * @param fd_setsize value of FD_SETSIZE
 * @return non-zero if succeeded, zero otherwise
 */
int
MHD_add_to_fd_set_ (MHD_socket fd,
                    fd_set *set,
                    MHD_socket *max_fd,
                    int fd_setsize);


/**
 * Change socket options to be non-blocking.
 *
 * @param sock socket to manipulate
 * @return non-zero if succeeded, zero otherwise
 */
int
MHD_socket_nonblocking_ (MHD_socket sock);


/**
 * Disable Nagle's algorithm on @a sock.  This is what we do by default for
 * all TCP sockets in MHD, unless the platform does not support the MSG_MORE
 * or MSG_CORK or MSG_NOPUSH options.
 *
 * @param sock socket to manipulate
 * @param on value to use
 * @return 0 on success
 */
int
MHD_socket_set_nodelay_ (MHD_socket sock,
                         bool on);

/**
 * Change socket options to be non-inheritable.
 *
 * @param sock socket to manipulate
 * @return non-zero if succeeded, zero otherwise
 * @warning Does not set socket error on W32.
 */
int
MHD_socket_noninheritable_ (MHD_socket sock);


#if defined(SOL_SOCKET) && defined(SO_NOSIGPIPE)
static const int _MHD_socket_int_one = 1;
/**
 * Change socket options to no signal on remote disconnect.
 *
 * @param sock socket to manipulate
 * @return non-zero if succeeded, zero otherwise
 */
#define MHD_socket_nosignal_(sock) \
  (! setsockopt ((sock),SOL_SOCKET,SO_NOSIGPIPE,&_MHD_socket_int_one, \
                 sizeof(_MHD_socket_int_one)))
#endif /* SOL_SOCKET && SO_NOSIGPIPE */


#if defined(MHD_socket_nosignal_) || defined(MSG_NOSIGNAL)
/**
 * Indicate that SIGPIPE can be suppressed by MHD for normal send() by flags
 * or socket options.
 * If this macro is undefined, MHD cannot suppress SIGPIPE for socket functions
 * so sendfile() or writev() calls are avoided in application threads.
 */
#define MHD_SEND_SPIPE_SUPPRESS_POSSIBLE   1
#endif /* MHD_WINSOCK_SOCKETS || MHD_socket_nosignal_ || MSG_NOSIGNAL */

#if ! defined(MHD_WINSOCK_SOCKETS)
/**
 * Indicate that suppression of SIGPIPE is required.
 */
#define MHD_SEND_SPIPE_SUPPRESS_NEEDED     1
#endif

/**
 * Create a listen socket, with noninheritable flag if possible.
 *
 * @param pf protocol family to use
 * @return created socket or MHD_INVALID_SOCKET in case of errors
 */
MHD_socket
MHD_socket_create_listen_ (int pf);


#endif /* ! MHD_SOCKETS_H */
