1  /* Non-blocking I/O for pipe or socket descriptors.
       2     Copyright (C) 2011-2023 Free Software Foundation, Inc.
       3  
       4     This file is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU Lesser General Public License as
       6     published by the Free Software Foundation; either version 2.1 of the
       7     License, or (at your option) any later version.
       8  
       9     This file is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include <config.h>
      18  
      19  /* Specification.  */
      20  #include "nonblocking.h"
      21  
      22  #include <errno.h>
      23  
      24  #if defined _WIN32 && ! defined __CYGWIN__
      25  /* Native Windows API.  */
      26  
      27  # include <sys/ioctl.h>
      28  # include <sys/socket.h>
      29  # include <unistd.h>
      30  
      31  /* Get declarations of the native Windows API functions.  */
      32  # define WIN32_LEAN_AND_MEAN
      33  # include <windows.h>
      34  
      35  # if GNULIB_MSVC_NOTHROW
      36  #  include "msvc-nothrow.h"
      37  # else
      38  #  include <io.h>
      39  # endif
      40  
      41  /* Don't assume that UNICODE is not defined.  */
      42  # undef GetNamedPipeHandleState
      43  # define GetNamedPipeHandleState GetNamedPipeHandleStateA
      44  
      45  int
      46  get_nonblocking_flag (int desc)
      47  {
      48    HANDLE h = (HANDLE) _get_osfhandle (desc);
      49    if (h == INVALID_HANDLE_VALUE)
      50      {
      51        errno = EBADF;
      52        return -1;
      53      }
      54    if (GetFileType (h) == FILE_TYPE_PIPE)
      55      {
      56        /* h is a pipe or socket.  */
      57        DWORD state;
      58        if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0))
      59          /* h is a pipe.  */
      60          return (state & PIPE_NOWAIT) != 0;
      61        else
      62          /* h is a socket.  */
      63          errno = ENOSYS;
      64          return -1;
      65      }
      66    else
      67      /* The native Windows API does not support non-blocking on regular
      68         files.  */
      69      return 0;
      70  }
      71  
      72  int
      73  set_nonblocking_flag (int desc, bool value)
      74  {
      75    HANDLE h = (HANDLE) _get_osfhandle (desc);
      76    if (h == INVALID_HANDLE_VALUE)
      77      {
      78        errno = EBADF;
      79        return -1;
      80      }
      81    if (GetFileType (h) == FILE_TYPE_PIPE)
      82      {
      83        /* h is a pipe or socket.  */
      84        DWORD state;
      85        if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0))
      86          {
      87            /* h is a pipe.  */
      88            if ((state & PIPE_NOWAIT) != 0)
      89              {
      90                if (value)
      91                  return 0;
      92                state &= ~PIPE_NOWAIT;
      93              }
      94            else
      95              {
      96                if (!value)
      97                  return 0;
      98                state |= PIPE_NOWAIT;
      99              }
     100            if (SetNamedPipeHandleState (h, &state, NULL, NULL))
     101              return 0;
     102            errno = EINVAL;
     103            return -1;
     104          }
     105        else
     106          {
     107            /* h is a socket.  */
     108            int v = value;
     109            return ioctl (desc, FIONBIO, &v);
     110          }
     111      }
     112    else
     113      {
     114        /* The native Windows API does not support non-blocking on regular
     115           files.  */
     116        if (!value)
     117          return 0;
     118        errno = ENOTSUP;
     119        return -1;
     120      }
     121  }
     122  
     123  #else
     124  /* Unix API.  */
     125  
     126  # include <fcntl.h>
     127  
     128  # if GNULIB_defined_O_NONBLOCK
     129  #  error Please port nonblocking to your platform
     130  # endif
     131  
     132  /* We don't need the gnulib replacement of fcntl() here.  */
     133  # undef fcntl
     134  
     135  int
     136  get_nonblocking_flag (int desc)
     137  {
     138    int fcntl_flags;
     139  
     140    fcntl_flags = fcntl (desc, F_GETFL, 0);
     141    if (fcntl_flags < 0)
     142      return -1;
     143    return (fcntl_flags & O_NONBLOCK) != 0;
     144  }
     145  
     146  int
     147  set_nonblocking_flag (int desc, bool value)
     148  {
     149    int fcntl_flags;
     150  
     151    fcntl_flags = fcntl (desc, F_GETFL, 0);
     152    if (fcntl_flags < 0)
     153      return -1;
     154    if (((fcntl_flags & O_NONBLOCK) != 0) == value)
     155      return 0;
     156    if (value)
     157      fcntl_flags |= O_NONBLOCK;
     158    else
     159      fcntl_flags &= ~O_NONBLOCK;
     160    return fcntl (desc, F_SETFL, fcntl_flags);
     161  }
     162  
     163  #endif