New module 'msvc-nothrow'. Makes _get_osfhandle safe on MSVC 9.
[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/ioctl.h>
28 # include <sys/socket.h>
29 # include <unistd.h>
30
31 /* Get declarations of the Win32 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     /* Win32 does not support non-blocking on regular files.  */
60     return 0;
61 }
62
63 int
64 set_nonblocking_flag (int desc, bool value)
65 {
66   HANDLE h = (HANDLE) _get_osfhandle (desc);
67   if (h == INVALID_HANDLE_VALUE)
68     {
69       errno = EBADF;
70       return -1;
71     }
72   if (GetFileType (h) == FILE_TYPE_PIPE)
73     {
74       /* h is a pipe or socket.  */
75       DWORD state;
76       if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0))
77         {
78           /* h is a pipe.  */
79           if ((state & PIPE_NOWAIT) != 0)
80             {
81               if (value)
82                 return 0;
83               state &= ~PIPE_NOWAIT;
84             }
85           else
86             {
87               if (!value)
88                 return 0;
89               state |= PIPE_NOWAIT;
90             }
91           if (SetNamedPipeHandleState (h, &state, NULL, NULL))
92             return 0;
93           errno = EINVAL;
94           return -1;
95         }
96       else
97         {
98           /* h is a socket.  */
99           int v = value;
100           return ioctl (desc, FIONBIO, &v);
101         }
102     }
103   else
104     {
105       /* Win32 does not support non-blocking on regular files.  */
106       if (!value)
107         return 0;
108       errno = ENOTSUP;
109       return -1;
110     }
111 }
112
113 #else
114 /* Unix API.  */
115
116 # include <fcntl.h>
117
118 # if GNULIB_defined_O_NONBLOCK
119 #  error Please port nonblocking to your platform
120 # endif
121
122 /* We don't need the gnulib replacement of fcntl() here.  */
123 # undef fcntl
124
125 int
126 get_nonblocking_flag (int desc)
127 {
128   int fcntl_flags;
129
130   fcntl_flags = fcntl (desc, F_GETFL, 0);
131   if (fcntl_flags < 0)
132     return -1;
133   return (fcntl_flags & O_NONBLOCK) != 0;
134 }
135
136 int
137 set_nonblocking_flag (int desc, bool value)
138 {
139   int fcntl_flags;
140
141   fcntl_flags = fcntl (desc, F_GETFL, 0);
142   if (fcntl_flags < 0)
143     return -1;
144   if (((fcntl_flags & O_NONBLOCK) != 0) == value)
145     return 0;
146   if (value)
147     fcntl_flags |= O_NONBLOCK;
148   else
149     fcntl_flags &= ~O_NONBLOCK;
150   return fcntl (desc, F_SETFL, fcntl_flags);
151 }
152
153 #endif