maint: update copyright
[gnulib.git] / lib / nonblocking.c
1 /* Non-blocking I/O for pipe or socket descriptors.
2    Copyright (C) 2011-2014 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program 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 General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://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 __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 # include "msvc-nothrow.h"
36
37 int
38 get_nonblocking_flag (int desc)
39 {
40   HANDLE h = (HANDLE) _get_osfhandle (desc);
41   if (h == INVALID_HANDLE_VALUE)
42     {
43       errno = EBADF;
44       return -1;
45     }
46   if (GetFileType (h) == FILE_TYPE_PIPE)
47     {
48       /* h is a pipe or socket.  */
49       DWORD state;
50       if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0))
51         /* h is a pipe.  */
52         return (state & PIPE_NOWAIT) != 0;
53       else
54         /* h is a socket.  */
55         errno = ENOSYS;
56         return -1;
57     }
58   else
59     /* The native Windows API does not support non-blocking on regular
60        files.  */
61     return 0;
62 }
63
64 int
65 set_nonblocking_flag (int desc, bool value)
66 {
67   HANDLE h = (HANDLE) _get_osfhandle (desc);
68   if (h == INVALID_HANDLE_VALUE)
69     {
70       errno = EBADF;
71       return -1;
72     }
73   if (GetFileType (h) == FILE_TYPE_PIPE)
74     {
75       /* h is a pipe or socket.  */
76       DWORD state;
77       if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0))
78         {
79           /* h is a pipe.  */
80           if ((state & PIPE_NOWAIT) != 0)
81             {
82               if (value)
83                 return 0;
84               state &= ~PIPE_NOWAIT;
85             }
86           else
87             {
88               if (!value)
89                 return 0;
90               state |= PIPE_NOWAIT;
91             }
92           if (SetNamedPipeHandleState (h, &state, NULL, NULL))
93             return 0;
94           errno = EINVAL;
95           return -1;
96         }
97       else
98         {
99           /* h is a socket.  */
100           int v = value;
101           return ioctl (desc, FIONBIO, &v);
102         }
103     }
104   else
105     {
106       /* The native Windows API does not support non-blocking on regular
107          files.  */
108       if (!value)
109         return 0;
110       errno = ENOTSUP;
111       return -1;
112     }
113 }
114
115 #else
116 /* Unix API.  */
117
118 # include <fcntl.h>
119
120 # if GNULIB_defined_O_NONBLOCK
121 #  error Please port nonblocking to your platform
122 # endif
123
124 /* We don't need the gnulib replacement of fcntl() here.  */
125 # undef fcntl
126
127 int
128 get_nonblocking_flag (int desc)
129 {
130   int fcntl_flags;
131
132   fcntl_flags = fcntl (desc, F_GETFL, 0);
133   if (fcntl_flags < 0)
134     return -1;
135   return (fcntl_flags & O_NONBLOCK) != 0;
136 }
137
138 int
139 set_nonblocking_flag (int desc, bool value)
140 {
141   int fcntl_flags;
142
143   fcntl_flags = fcntl (desc, F_GETFL, 0);
144   if (fcntl_flags < 0)
145     return -1;
146   if (((fcntl_flags & O_NONBLOCK) != 0) == value)
147     return 0;
148   if (value)
149     fcntl_flags |= O_NONBLOCK;
150   else
151     fcntl_flags &= ~O_NONBLOCK;
152   return fcntl (desc, F_SETFL, fcntl_flags);
153 }
154
155 #endif