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