nonblocking: new module
[gnulib.git] / lib / nonblocking.c
1 /* Non-blocking I/O for pipe or socket descriptors.
2    Copyright (C) 2011 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 Woe32 API.  */
26
27 # include <sys/socket.h>
28 # include <unistd.h>
29
30 /* Get declarations of the Win32 API functions.  */
31 # define WIN32_LEAN_AND_MEAN
32 # include <windows.h>
33
34 int
35 get_nonblocking_flag (int desc)
36 {
37   HANDLE h = (HANDLE) _get_osfhandle (desc);
38   if (GetFileType (h) == FILE_TYPE_PIPE)
39     {
40       /* h is a pipe or socket.  */
41       DWORD state;
42       if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0))
43         /* h is a pipe.  */
44         return (state & PIPE_NOWAIT) != 0;
45       else
46         /* h is a socket.  */
47         errno = ENOSYS;
48         return -1;
49     }
50   else
51     /* Win32 does not support non-blocking on regular files.  */
52     return 0;
53 }
54
55 int
56 set_nonblocking_flag (int desc, bool value)
57 {
58   HANDLE h = (HANDLE) _get_osfhandle (desc);
59   if (GetFileType (h) == FILE_TYPE_PIPE)
60     {
61       /* h is a pipe or socket.  */
62       DWORD state;
63       if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0))
64         {
65           /* h is a pipe.  */
66           if ((state & PIPE_NOWAIT) != 0)
67             {
68               if (value)
69                 return 0;
70               state &= ~PIPE_NOWAIT;
71             }
72           else
73             {
74               if (!value)
75                 return 0;
76               state |= PIPE_NOWAIT;
77             }
78           if (SetNamedPipeHandleState (h, &state, NULL, NULL))
79             return 0;
80           errno = EINVAL;
81           return -1;
82         }
83       else
84         {
85           /* h is a socket.  */
86           int v = value;
87           return ioctl (desc, FIONBIO, &v);
88         }
89     }
90   else
91     {
92       /* Win32 does not support non-blocking on regular files.  */
93       errno = ENOTSUP;
94       return -1;
95     }
96 }
97
98 #else
99 /* Unix API.  */
100
101 # include <fcntl.h>
102
103 # if !O_NONBLOCK
104 #  error Please port nonblocking to your platform
105 # endif
106
107 /* We don't need the gnulib replacement of fcntl() here.  */
108 # undef fcntl
109
110 int
111 get_nonblocking_flag (int desc)
112 {
113   int fcntl_flags;
114
115   fcntl_flags = fcntl (desc, F_GETFL, 0);
116   if (fcntl_flags < 0)
117     return -1;
118   return (fcntl_flags & O_NONBLOCK) != 0;
119 }
120
121 int
122 set_nonblocking_flag (int desc, bool value)
123 {
124   int fcntl_flags;
125
126   fcntl_flags = fcntl (desc, F_GETFL, 0);
127   if (fcntl_flags < 0)
128     return -1;
129   if (((fcntl_flags & O_NONBLOCK) != 0) == value)
130     return 0;
131   if (value)
132     fcntl_flags |= O_NONBLOCK;
133   else
134     fcntl_flags &= ~O_NONBLOCK;
135   return fcntl (desc, F_SETFL, fcntl_flags);
136 }
137
138 #endif