openat: don’t close (-1)
[gnulib.git] / lib / nonblocking.c
blob73f3b61403ad81886354bfb1e758c81994b9955d
1 /* Non-blocking I/O for pipe or socket descriptors.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc.
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.
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.
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/>. */
17 #include <config.h>
19 /* Specification. */
20 #include "nonblocking.h"
22 #include <errno.h>
24 #if defined _WIN32 && ! defined __CYGWIN__
25 /* Native Windows API. */
27 # include <sys/ioctl.h>
28 # include <sys/socket.h>
29 # include <unistd.h>
31 /* Get declarations of the native Windows API functions. */
32 # define WIN32_LEAN_AND_MEAN
33 # include <windows.h>
35 # if GNULIB_MSVC_NOTHROW
36 # include "msvc-nothrow.h"
37 # else
38 # include <io.h>
39 # endif
41 /* Don't assume that UNICODE is not defined. */
42 # undef GetNamedPipeHandleState
43 # define GetNamedPipeHandleState GetNamedPipeHandleStateA
45 int
46 get_nonblocking_flag (int desc)
48 HANDLE h = (HANDLE) _get_osfhandle (desc);
49 if (h == INVALID_HANDLE_VALUE)
51 errno = EBADF;
52 return -1;
54 if (GetFileType (h) == FILE_TYPE_PIPE)
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;
66 else
67 /* The native Windows API does not support non-blocking on regular
68 files. */
69 return 0;
72 int
73 set_nonblocking_flag (int desc, bool value)
75 HANDLE h = (HANDLE) _get_osfhandle (desc);
76 if (h == INVALID_HANDLE_VALUE)
78 errno = EBADF;
79 return -1;
81 if (GetFileType (h) == FILE_TYPE_PIPE)
83 /* h is a pipe or socket. */
84 DWORD state;
85 if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0))
87 /* h is a pipe. */
88 if ((state & PIPE_NOWAIT) != 0)
90 if (value)
91 return 0;
92 state &= ~PIPE_NOWAIT;
94 else
96 if (!value)
97 return 0;
98 state |= PIPE_NOWAIT;
100 if (SetNamedPipeHandleState (h, &state, NULL, NULL))
101 return 0;
102 errno = EINVAL;
103 return -1;
105 else
107 /* h is a socket. */
108 int v = value;
109 return ioctl (desc, FIONBIO, &v);
112 else
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;
123 #else
124 /* Unix API. */
126 # include <fcntl.h>
128 # if GNULIB_defined_O_NONBLOCK
129 # error Please port nonblocking to your platform
130 # endif
132 /* We don't need the gnulib replacement of fcntl() here. */
133 # undef fcntl
136 get_nonblocking_flag (int desc)
138 int fcntl_flags;
140 fcntl_flags = fcntl (desc, F_GETFL, 0);
141 if (fcntl_flags < 0)
142 return -1;
143 return (fcntl_flags & O_NONBLOCK) != 0;
147 set_nonblocking_flag (int desc, bool value)
149 int fcntl_flags;
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);
163 #endif