Chris@16
|
1 //
|
Chris@16
|
2 // detail/impl/descriptor_ops.ipp
|
Chris@16
|
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
Chris@16
|
4 //
|
Chris@101
|
5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
Chris@16
|
6 //
|
Chris@16
|
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9 //
|
Chris@16
|
10
|
Chris@16
|
11 #ifndef BOOST_ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
|
Chris@16
|
12 #define BOOST_ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
|
Chris@16
|
13
|
Chris@16
|
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
15 # pragma once
|
Chris@16
|
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/asio/detail/config.hpp>
|
Chris@16
|
19 #include <cerrno>
|
Chris@16
|
20 #include <boost/asio/detail/descriptor_ops.hpp>
|
Chris@16
|
21 #include <boost/asio/error.hpp>
|
Chris@16
|
22
|
Chris@16
|
23 #if !defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
24 && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
|
Chris@16
|
25 && !defined(__CYGWIN__)
|
Chris@16
|
26
|
Chris@16
|
27 #include <boost/asio/detail/push_options.hpp>
|
Chris@16
|
28
|
Chris@16
|
29 namespace boost {
|
Chris@16
|
30 namespace asio {
|
Chris@16
|
31 namespace detail {
|
Chris@16
|
32 namespace descriptor_ops {
|
Chris@16
|
33
|
Chris@16
|
34 int open(const char* path, int flags, boost::system::error_code& ec)
|
Chris@16
|
35 {
|
Chris@16
|
36 errno = 0;
|
Chris@16
|
37 int result = error_wrapper(::open(path, flags), ec);
|
Chris@16
|
38 if (result >= 0)
|
Chris@16
|
39 ec = boost::system::error_code();
|
Chris@16
|
40 return result;
|
Chris@16
|
41 }
|
Chris@16
|
42
|
Chris@16
|
43 int close(int d, state_type& state, boost::system::error_code& ec)
|
Chris@16
|
44 {
|
Chris@16
|
45 int result = 0;
|
Chris@16
|
46 if (d != -1)
|
Chris@16
|
47 {
|
Chris@16
|
48 errno = 0;
|
Chris@16
|
49 result = error_wrapper(::close(d), ec);
|
Chris@16
|
50
|
Chris@16
|
51 if (result != 0
|
Chris@16
|
52 && (ec == boost::asio::error::would_block
|
Chris@16
|
53 || ec == boost::asio::error::try_again))
|
Chris@16
|
54 {
|
Chris@16
|
55 // According to UNIX Network Programming Vol. 1, it is possible for
|
Chris@16
|
56 // close() to fail with EWOULDBLOCK under certain circumstances. What
|
Chris@16
|
57 // isn't clear is the state of the descriptor after this error. The one
|
Chris@16
|
58 // current OS where this behaviour is seen, Windows, says that the socket
|
Chris@16
|
59 // remains open. Therefore we'll put the descriptor back into blocking
|
Chris@16
|
60 // mode and have another attempt at closing it.
|
Chris@16
|
61 #if defined(__SYMBIAN32__)
|
Chris@16
|
62 int flags = ::fcntl(d, F_GETFL, 0);
|
Chris@16
|
63 if (flags >= 0)
|
Chris@16
|
64 ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK);
|
Chris@16
|
65 #else // defined(__SYMBIAN32__)
|
Chris@16
|
66 ioctl_arg_type arg = 0;
|
Chris@16
|
67 ::ioctl(d, FIONBIO, &arg);
|
Chris@16
|
68 #endif // defined(__SYMBIAN32__)
|
Chris@16
|
69 state &= ~non_blocking;
|
Chris@16
|
70
|
Chris@16
|
71 errno = 0;
|
Chris@16
|
72 result = error_wrapper(::close(d), ec);
|
Chris@16
|
73 }
|
Chris@16
|
74 }
|
Chris@16
|
75
|
Chris@16
|
76 if (result == 0)
|
Chris@16
|
77 ec = boost::system::error_code();
|
Chris@16
|
78 return result;
|
Chris@16
|
79 }
|
Chris@16
|
80
|
Chris@16
|
81 bool set_user_non_blocking(int d, state_type& state,
|
Chris@16
|
82 bool value, boost::system::error_code& ec)
|
Chris@16
|
83 {
|
Chris@16
|
84 if (d == -1)
|
Chris@16
|
85 {
|
Chris@16
|
86 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
87 return false;
|
Chris@16
|
88 }
|
Chris@16
|
89
|
Chris@16
|
90 errno = 0;
|
Chris@16
|
91 #if defined(__SYMBIAN32__)
|
Chris@16
|
92 int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec);
|
Chris@16
|
93 if (result >= 0)
|
Chris@16
|
94 {
|
Chris@16
|
95 errno = 0;
|
Chris@16
|
96 int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
|
Chris@16
|
97 result = error_wrapper(::fcntl(d, F_SETFL, flag), ec);
|
Chris@16
|
98 }
|
Chris@16
|
99 #else // defined(__SYMBIAN32__)
|
Chris@16
|
100 ioctl_arg_type arg = (value ? 1 : 0);
|
Chris@16
|
101 int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec);
|
Chris@16
|
102 #endif // defined(__SYMBIAN32__)
|
Chris@16
|
103
|
Chris@16
|
104 if (result >= 0)
|
Chris@16
|
105 {
|
Chris@16
|
106 ec = boost::system::error_code();
|
Chris@16
|
107 if (value)
|
Chris@16
|
108 state |= user_set_non_blocking;
|
Chris@16
|
109 else
|
Chris@16
|
110 {
|
Chris@16
|
111 // Clearing the user-set non-blocking mode always overrides any
|
Chris@16
|
112 // internally-set non-blocking flag. Any subsequent asynchronous
|
Chris@16
|
113 // operations will need to re-enable non-blocking I/O.
|
Chris@16
|
114 state &= ~(user_set_non_blocking | internal_non_blocking);
|
Chris@16
|
115 }
|
Chris@16
|
116 return true;
|
Chris@16
|
117 }
|
Chris@16
|
118
|
Chris@16
|
119 return false;
|
Chris@16
|
120 }
|
Chris@16
|
121
|
Chris@16
|
122 bool set_internal_non_blocking(int d, state_type& state,
|
Chris@16
|
123 bool value, boost::system::error_code& ec)
|
Chris@16
|
124 {
|
Chris@16
|
125 if (d == -1)
|
Chris@16
|
126 {
|
Chris@16
|
127 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
128 return false;
|
Chris@16
|
129 }
|
Chris@16
|
130
|
Chris@16
|
131 if (!value && (state & user_set_non_blocking))
|
Chris@16
|
132 {
|
Chris@16
|
133 // It does not make sense to clear the internal non-blocking flag if the
|
Chris@16
|
134 // user still wants non-blocking behaviour. Return an error and let the
|
Chris@16
|
135 // caller figure out whether to update the user-set non-blocking flag.
|
Chris@16
|
136 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
137 return false;
|
Chris@16
|
138 }
|
Chris@16
|
139
|
Chris@16
|
140 errno = 0;
|
Chris@16
|
141 #if defined(__SYMBIAN32__)
|
Chris@16
|
142 int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec);
|
Chris@16
|
143 if (result >= 0)
|
Chris@16
|
144 {
|
Chris@16
|
145 errno = 0;
|
Chris@16
|
146 int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
|
Chris@16
|
147 result = error_wrapper(::fcntl(d, F_SETFL, flag), ec);
|
Chris@16
|
148 }
|
Chris@16
|
149 #else // defined(__SYMBIAN32__)
|
Chris@16
|
150 ioctl_arg_type arg = (value ? 1 : 0);
|
Chris@16
|
151 int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec);
|
Chris@16
|
152 #endif // defined(__SYMBIAN32__)
|
Chris@16
|
153
|
Chris@16
|
154 if (result >= 0)
|
Chris@16
|
155 {
|
Chris@16
|
156 ec = boost::system::error_code();
|
Chris@16
|
157 if (value)
|
Chris@16
|
158 state |= internal_non_blocking;
|
Chris@16
|
159 else
|
Chris@16
|
160 state &= ~internal_non_blocking;
|
Chris@16
|
161 return true;
|
Chris@16
|
162 }
|
Chris@16
|
163
|
Chris@16
|
164 return false;
|
Chris@16
|
165 }
|
Chris@16
|
166
|
Chris@16
|
167 std::size_t sync_read(int d, state_type state, buf* bufs,
|
Chris@16
|
168 std::size_t count, bool all_empty, boost::system::error_code& ec)
|
Chris@16
|
169 {
|
Chris@16
|
170 if (d == -1)
|
Chris@16
|
171 {
|
Chris@16
|
172 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
173 return 0;
|
Chris@16
|
174 }
|
Chris@16
|
175
|
Chris@16
|
176 // A request to read 0 bytes on a stream is a no-op.
|
Chris@16
|
177 if (all_empty)
|
Chris@16
|
178 {
|
Chris@16
|
179 ec = boost::system::error_code();
|
Chris@16
|
180 return 0;
|
Chris@16
|
181 }
|
Chris@16
|
182
|
Chris@16
|
183 // Read some data.
|
Chris@16
|
184 for (;;)
|
Chris@16
|
185 {
|
Chris@16
|
186 // Try to complete the operation without blocking.
|
Chris@16
|
187 errno = 0;
|
Chris@16
|
188 signed_size_type bytes = error_wrapper(::readv(
|
Chris@16
|
189 d, bufs, static_cast<int>(count)), ec);
|
Chris@16
|
190
|
Chris@16
|
191 // Check if operation succeeded.
|
Chris@16
|
192 if (bytes > 0)
|
Chris@16
|
193 return bytes;
|
Chris@16
|
194
|
Chris@16
|
195 // Check for EOF.
|
Chris@16
|
196 if (bytes == 0)
|
Chris@16
|
197 {
|
Chris@16
|
198 ec = boost::asio::error::eof;
|
Chris@16
|
199 return 0;
|
Chris@16
|
200 }
|
Chris@16
|
201
|
Chris@16
|
202 // Operation failed.
|
Chris@16
|
203 if ((state & user_set_non_blocking)
|
Chris@16
|
204 || (ec != boost::asio::error::would_block
|
Chris@16
|
205 && ec != boost::asio::error::try_again))
|
Chris@16
|
206 return 0;
|
Chris@16
|
207
|
Chris@16
|
208 // Wait for descriptor to become ready.
|
Chris@16
|
209 if (descriptor_ops::poll_read(d, 0, ec) < 0)
|
Chris@16
|
210 return 0;
|
Chris@16
|
211 }
|
Chris@16
|
212 }
|
Chris@16
|
213
|
Chris@16
|
214 bool non_blocking_read(int d, buf* bufs, std::size_t count,
|
Chris@16
|
215 boost::system::error_code& ec, std::size_t& bytes_transferred)
|
Chris@16
|
216 {
|
Chris@16
|
217 for (;;)
|
Chris@16
|
218 {
|
Chris@16
|
219 // Read some data.
|
Chris@16
|
220 errno = 0;
|
Chris@16
|
221 signed_size_type bytes = error_wrapper(::readv(
|
Chris@16
|
222 d, bufs, static_cast<int>(count)), ec);
|
Chris@16
|
223
|
Chris@16
|
224 // Check for end of stream.
|
Chris@16
|
225 if (bytes == 0)
|
Chris@16
|
226 {
|
Chris@16
|
227 ec = boost::asio::error::eof;
|
Chris@16
|
228 return true;
|
Chris@16
|
229 }
|
Chris@16
|
230
|
Chris@16
|
231 // Retry operation if interrupted by signal.
|
Chris@16
|
232 if (ec == boost::asio::error::interrupted)
|
Chris@16
|
233 continue;
|
Chris@16
|
234
|
Chris@16
|
235 // Check if we need to run the operation again.
|
Chris@16
|
236 if (ec == boost::asio::error::would_block
|
Chris@16
|
237 || ec == boost::asio::error::try_again)
|
Chris@16
|
238 return false;
|
Chris@16
|
239
|
Chris@16
|
240 // Operation is complete.
|
Chris@16
|
241 if (bytes > 0)
|
Chris@16
|
242 {
|
Chris@16
|
243 ec = boost::system::error_code();
|
Chris@16
|
244 bytes_transferred = bytes;
|
Chris@16
|
245 }
|
Chris@16
|
246 else
|
Chris@16
|
247 bytes_transferred = 0;
|
Chris@16
|
248
|
Chris@16
|
249 return true;
|
Chris@16
|
250 }
|
Chris@16
|
251 }
|
Chris@16
|
252
|
Chris@16
|
253 std::size_t sync_write(int d, state_type state, const buf* bufs,
|
Chris@16
|
254 std::size_t count, bool all_empty, boost::system::error_code& ec)
|
Chris@16
|
255 {
|
Chris@16
|
256 if (d == -1)
|
Chris@16
|
257 {
|
Chris@16
|
258 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
259 return 0;
|
Chris@16
|
260 }
|
Chris@16
|
261
|
Chris@16
|
262 // A request to write 0 bytes on a stream is a no-op.
|
Chris@16
|
263 if (all_empty)
|
Chris@16
|
264 {
|
Chris@16
|
265 ec = boost::system::error_code();
|
Chris@16
|
266 return 0;
|
Chris@16
|
267 }
|
Chris@16
|
268
|
Chris@16
|
269 // Write some data.
|
Chris@16
|
270 for (;;)
|
Chris@16
|
271 {
|
Chris@16
|
272 // Try to complete the operation without blocking.
|
Chris@16
|
273 errno = 0;
|
Chris@16
|
274 signed_size_type bytes = error_wrapper(::writev(
|
Chris@16
|
275 d, bufs, static_cast<int>(count)), ec);
|
Chris@16
|
276
|
Chris@16
|
277 // Check if operation succeeded.
|
Chris@16
|
278 if (bytes > 0)
|
Chris@16
|
279 return bytes;
|
Chris@16
|
280
|
Chris@16
|
281 // Operation failed.
|
Chris@16
|
282 if ((state & user_set_non_blocking)
|
Chris@16
|
283 || (ec != boost::asio::error::would_block
|
Chris@16
|
284 && ec != boost::asio::error::try_again))
|
Chris@16
|
285 return 0;
|
Chris@16
|
286
|
Chris@16
|
287 // Wait for descriptor to become ready.
|
Chris@16
|
288 if (descriptor_ops::poll_write(d, 0, ec) < 0)
|
Chris@16
|
289 return 0;
|
Chris@16
|
290 }
|
Chris@16
|
291 }
|
Chris@16
|
292
|
Chris@16
|
293 bool non_blocking_write(int d, const buf* bufs, std::size_t count,
|
Chris@16
|
294 boost::system::error_code& ec, std::size_t& bytes_transferred)
|
Chris@16
|
295 {
|
Chris@16
|
296 for (;;)
|
Chris@16
|
297 {
|
Chris@16
|
298 // Write some data.
|
Chris@16
|
299 errno = 0;
|
Chris@16
|
300 signed_size_type bytes = error_wrapper(::writev(
|
Chris@16
|
301 d, bufs, static_cast<int>(count)), ec);
|
Chris@16
|
302
|
Chris@16
|
303 // Retry operation if interrupted by signal.
|
Chris@16
|
304 if (ec == boost::asio::error::interrupted)
|
Chris@16
|
305 continue;
|
Chris@16
|
306
|
Chris@16
|
307 // Check if we need to run the operation again.
|
Chris@16
|
308 if (ec == boost::asio::error::would_block
|
Chris@16
|
309 || ec == boost::asio::error::try_again)
|
Chris@16
|
310 return false;
|
Chris@16
|
311
|
Chris@16
|
312 // Operation is complete.
|
Chris@16
|
313 if (bytes >= 0)
|
Chris@16
|
314 {
|
Chris@16
|
315 ec = boost::system::error_code();
|
Chris@16
|
316 bytes_transferred = bytes;
|
Chris@16
|
317 }
|
Chris@16
|
318 else
|
Chris@16
|
319 bytes_transferred = 0;
|
Chris@16
|
320
|
Chris@16
|
321 return true;
|
Chris@16
|
322 }
|
Chris@16
|
323 }
|
Chris@16
|
324
|
Chris@16
|
325 int ioctl(int d, state_type& state, long cmd,
|
Chris@16
|
326 ioctl_arg_type* arg, boost::system::error_code& ec)
|
Chris@16
|
327 {
|
Chris@16
|
328 if (d == -1)
|
Chris@16
|
329 {
|
Chris@16
|
330 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
331 return -1;
|
Chris@16
|
332 }
|
Chris@16
|
333
|
Chris@16
|
334 errno = 0;
|
Chris@16
|
335 int result = error_wrapper(::ioctl(d, cmd, arg), ec);
|
Chris@16
|
336
|
Chris@16
|
337 if (result >= 0)
|
Chris@16
|
338 {
|
Chris@16
|
339 ec = boost::system::error_code();
|
Chris@16
|
340
|
Chris@16
|
341 // When updating the non-blocking mode we always perform the ioctl syscall,
|
Chris@16
|
342 // even if the flags would otherwise indicate that the descriptor is
|
Chris@16
|
343 // already in the correct state. This ensures that the underlying
|
Chris@16
|
344 // descriptor is put into the state that has been requested by the user. If
|
Chris@16
|
345 // the ioctl syscall was successful then we need to update the flags to
|
Chris@16
|
346 // match.
|
Chris@16
|
347 if (cmd == static_cast<long>(FIONBIO))
|
Chris@16
|
348 {
|
Chris@16
|
349 if (*arg)
|
Chris@16
|
350 {
|
Chris@16
|
351 state |= user_set_non_blocking;
|
Chris@16
|
352 }
|
Chris@16
|
353 else
|
Chris@16
|
354 {
|
Chris@16
|
355 // Clearing the non-blocking mode always overrides any internally-set
|
Chris@16
|
356 // non-blocking flag. Any subsequent asynchronous operations will need
|
Chris@16
|
357 // to re-enable non-blocking I/O.
|
Chris@16
|
358 state &= ~(user_set_non_blocking | internal_non_blocking);
|
Chris@16
|
359 }
|
Chris@16
|
360 }
|
Chris@16
|
361 }
|
Chris@16
|
362
|
Chris@16
|
363 return result;
|
Chris@16
|
364 }
|
Chris@16
|
365
|
Chris@16
|
366 int fcntl(int d, int cmd, boost::system::error_code& ec)
|
Chris@16
|
367 {
|
Chris@16
|
368 if (d == -1)
|
Chris@16
|
369 {
|
Chris@16
|
370 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
371 return -1;
|
Chris@16
|
372 }
|
Chris@16
|
373
|
Chris@16
|
374 errno = 0;
|
Chris@16
|
375 int result = error_wrapper(::fcntl(d, cmd), ec);
|
Chris@16
|
376 if (result != -1)
|
Chris@16
|
377 ec = boost::system::error_code();
|
Chris@16
|
378 return result;
|
Chris@16
|
379 }
|
Chris@16
|
380
|
Chris@16
|
381 int fcntl(int d, int cmd, long arg, boost::system::error_code& ec)
|
Chris@16
|
382 {
|
Chris@16
|
383 if (d == -1)
|
Chris@16
|
384 {
|
Chris@16
|
385 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
386 return -1;
|
Chris@16
|
387 }
|
Chris@16
|
388
|
Chris@16
|
389 errno = 0;
|
Chris@16
|
390 int result = error_wrapper(::fcntl(d, cmd, arg), ec);
|
Chris@16
|
391 if (result != -1)
|
Chris@16
|
392 ec = boost::system::error_code();
|
Chris@16
|
393 return result;
|
Chris@16
|
394 }
|
Chris@16
|
395
|
Chris@16
|
396 int poll_read(int d, state_type state, boost::system::error_code& ec)
|
Chris@16
|
397 {
|
Chris@16
|
398 if (d == -1)
|
Chris@16
|
399 {
|
Chris@16
|
400 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
401 return -1;
|
Chris@16
|
402 }
|
Chris@16
|
403
|
Chris@16
|
404 pollfd fds;
|
Chris@16
|
405 fds.fd = d;
|
Chris@16
|
406 fds.events = POLLIN;
|
Chris@16
|
407 fds.revents = 0;
|
Chris@16
|
408 int timeout = (state & user_set_non_blocking) ? 0 : -1;
|
Chris@16
|
409 errno = 0;
|
Chris@16
|
410 int result = error_wrapper(::poll(&fds, 1, timeout), ec);
|
Chris@16
|
411 if (result == 0)
|
Chris@16
|
412 ec = (state & user_set_non_blocking)
|
Chris@16
|
413 ? boost::asio::error::would_block : boost::system::error_code();
|
Chris@16
|
414 else if (result > 0)
|
Chris@16
|
415 ec = boost::system::error_code();
|
Chris@16
|
416 return result;
|
Chris@16
|
417 }
|
Chris@16
|
418
|
Chris@16
|
419 int poll_write(int d, state_type state, boost::system::error_code& ec)
|
Chris@16
|
420 {
|
Chris@16
|
421 if (d == -1)
|
Chris@16
|
422 {
|
Chris@16
|
423 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
424 return -1;
|
Chris@16
|
425 }
|
Chris@16
|
426
|
Chris@16
|
427 pollfd fds;
|
Chris@16
|
428 fds.fd = d;
|
Chris@16
|
429 fds.events = POLLOUT;
|
Chris@16
|
430 fds.revents = 0;
|
Chris@16
|
431 int timeout = (state & user_set_non_blocking) ? 0 : -1;
|
Chris@16
|
432 errno = 0;
|
Chris@16
|
433 int result = error_wrapper(::poll(&fds, 1, timeout), ec);
|
Chris@16
|
434 if (result == 0)
|
Chris@16
|
435 ec = (state & user_set_non_blocking)
|
Chris@16
|
436 ? boost::asio::error::would_block : boost::system::error_code();
|
Chris@16
|
437 else if (result > 0)
|
Chris@16
|
438 ec = boost::system::error_code();
|
Chris@16
|
439 return result;
|
Chris@16
|
440 }
|
Chris@16
|
441
|
Chris@16
|
442 } // namespace descriptor_ops
|
Chris@16
|
443 } // namespace detail
|
Chris@16
|
444 } // namespace asio
|
Chris@16
|
445 } // namespace boost
|
Chris@16
|
446
|
Chris@16
|
447 #include <boost/asio/detail/pop_options.hpp>
|
Chris@16
|
448
|
Chris@16
|
449 #endif // !defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
450 // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
451 // && !defined(__CYGWIN__)
|
Chris@16
|
452
|
Chris@16
|
453 #endif // BOOST_ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
|