Blame gl/tests/sockets.c

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