Blame gnulib/tests/sockets.c

Packit Service a2ae7a
/* sockets.c --- wrappers for Windows socket functions
Packit Service a2ae7a
Packit Service a2ae7a
   Copyright (C) 2008-2019 Free Software Foundation, Inc.
Packit Service a2ae7a
Packit Service a2ae7a
   This program is free software: you can redistribute it and/or modify
Packit Service a2ae7a
   it under the terms of the GNU General Public License as published by
Packit Service a2ae7a
   the Free Software Foundation; either version 3 of the License, or
Packit Service a2ae7a
   (at your option) any later version.
Packit Service a2ae7a
Packit Service a2ae7a
   This program is distributed in the hope that it will be useful,
Packit Service a2ae7a
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2ae7a
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2ae7a
   GNU General Public License for more details.
Packit Service a2ae7a
Packit Service a2ae7a
   You should have received a copy of the GNU General Public License
Packit Service a2ae7a
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service a2ae7a
Packit Service a2ae7a
/* Written by Simon Josefsson */
Packit Service a2ae7a
Packit Service a2ae7a
#include <config.h>
Packit Service a2ae7a
Packit Service a2ae7a
/* Specification.  */
Packit Service a2ae7a
#include "sockets.h"
Packit Service a2ae7a
Packit Service a2ae7a
#if WINDOWS_SOCKETS
Packit Service a2ae7a
Packit Service a2ae7a
/* This includes winsock2.h on MinGW. */
Packit Service a2ae7a
# include <sys/socket.h>
Packit Service a2ae7a
Packit Service a2ae7a
# include "fd-hook.h"
Packit Service a2ae7a
# if GNULIB_MSVC_NOTHROW
Packit Service a2ae7a
#  include "msvc-nothrow.h"
Packit Service a2ae7a
# else
Packit Service a2ae7a
#  include <io.h>
Packit Service a2ae7a
# endif
Packit Service a2ae7a
Packit Service a2ae7a
/* Get set_winsock_errno, FD_TO_SOCKET etc. */
Packit Service a2ae7a
# include "w32sock.h"
Packit Service a2ae7a
Packit Service a2ae7a
static int
Packit Service a2ae7a
close_fd_maybe_socket (const struct fd_hook *remaining_list,
Packit Service a2ae7a
                       gl_close_fn primary,
Packit Service a2ae7a
                       int fd)
Packit Service a2ae7a
{
Packit Service a2ae7a
  /* Note about multithread-safety: There is a race condition where, between
Packit Service a2ae7a
     our calls to closesocket() and the primary close(), some other thread
Packit Service a2ae7a
     could make system calls that allocate precisely the same HANDLE value
Packit Service a2ae7a
     as sock; then the primary close() would call CloseHandle() on it.  */
Packit Service a2ae7a
  SOCKET sock;
Packit Service a2ae7a
  WSANETWORKEVENTS ev;
Packit Service a2ae7a
Packit Service a2ae7a
  /* Test whether fd refers to a socket.  */
Packit Service a2ae7a
  sock = FD_TO_SOCKET (fd);
Packit Service a2ae7a
  ev.lNetworkEvents = 0xDEADBEEF;
Packit Service a2ae7a
  WSAEnumNetworkEvents (sock, NULL, &ev;;
Packit Service a2ae7a
  if (ev.lNetworkEvents != 0xDEADBEEF)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* fd refers to a socket.  */
Packit Service a2ae7a
      /* FIXME: other applications, like squid, use an undocumented
Packit Service a2ae7a
         _free_osfhnd free function.  But this is not enough: The 'osfile'
Packit Service a2ae7a
         flags for fd also needs to be cleared, but it is hard to access it.
Packit Service a2ae7a
         Instead, here we just close twice the file descriptor.  */
Packit Service a2ae7a
      if (closesocket (sock))
Packit Service a2ae7a
        {
Packit Service a2ae7a
          set_winsock_errno ();
Packit Service a2ae7a
          return -1;
Packit Service a2ae7a
        }
Packit Service a2ae7a
      else
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* This call frees the file descriptor and does a
Packit Service a2ae7a
             CloseHandle ((HANDLE) _get_osfhandle (fd)), which fails.  */
Packit Service a2ae7a
          _close (fd);
Packit Service a2ae7a
          return 0;
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
  else
Packit Service a2ae7a
    /* Some other type of file descriptor.  */
Packit Service a2ae7a
    return execute_close_hooks (remaining_list, primary, fd);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
static int
Packit Service a2ae7a
ioctl_fd_maybe_socket (const struct fd_hook *remaining_list,
Packit Service a2ae7a
                       gl_ioctl_fn primary,
Packit Service a2ae7a
                       int fd, int request, void *arg)
Packit Service a2ae7a
{
Packit Service a2ae7a
  SOCKET sock;
Packit Service a2ae7a
  WSANETWORKEVENTS ev;
Packit Service a2ae7a
Packit Service a2ae7a
  /* Test whether fd refers to a socket.  */
Packit Service a2ae7a
  sock = FD_TO_SOCKET (fd);
Packit Service a2ae7a
  ev.lNetworkEvents = 0xDEADBEEF;
Packit Service a2ae7a
  WSAEnumNetworkEvents (sock, NULL, &ev;;
Packit Service a2ae7a
  if (ev.lNetworkEvents != 0xDEADBEEF)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* fd refers to a socket.  */
Packit Service a2ae7a
      if (ioctlsocket (sock, request, arg) < 0)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          set_winsock_errno ();
Packit Service a2ae7a
          return -1;
Packit Service a2ae7a
        }
Packit Service a2ae7a
      else
Packit Service a2ae7a
        return 0;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  else
Packit Service a2ae7a
    /* Some other type of file descriptor.  */
Packit Service a2ae7a
    return execute_ioctl_hooks (remaining_list, primary, fd, request, arg);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
static struct fd_hook fd_sockets_hook;
Packit Service a2ae7a
Packit Service a2ae7a
static int initialized_sockets_version /* = 0 */;
Packit Service a2ae7a
Packit Service a2ae7a
#endif /* WINDOWS_SOCKETS */
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
gl_sockets_startup (int version _GL_UNUSED)
Packit Service a2ae7a
{
Packit Service a2ae7a
#if WINDOWS_SOCKETS
Packit Service a2ae7a
  if (version > initialized_sockets_version)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      WSADATA data;
Packit Service a2ae7a
      int err;
Packit Service a2ae7a
Packit Service a2ae7a
      err = WSAStartup (version, &data);
Packit Service a2ae7a
      if (err != 0)
Packit Service a2ae7a
        return 1;
Packit Service a2ae7a
Packit Service a2ae7a
      if (data.wVersion != version)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          WSACleanup ();
Packit Service a2ae7a
          return 2;
Packit Service a2ae7a
        }
Packit Service a2ae7a
Packit Service a2ae7a
      if (initialized_sockets_version == 0)
Packit Service a2ae7a
        register_fd_hook (close_fd_maybe_socket, ioctl_fd_maybe_socket,
Packit Service a2ae7a
                          &fd_sockets_hook);
Packit Service a2ae7a
Packit Service a2ae7a
      initialized_sockets_version = version;
Packit Service a2ae7a
    }
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
gl_sockets_cleanup (void)
Packit Service a2ae7a
{
Packit Service a2ae7a
#if WINDOWS_SOCKETS
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  initialized_sockets_version = 0;
Packit Service a2ae7a
Packit Service a2ae7a
  unregister_fd_hook (&fd_sockets_hook);
Packit Service a2ae7a
Packit Service a2ae7a
  err = WSACleanup ();
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return 1;
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}