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
29namespace boost {
30namespace asio {
31namespace detail {
32namespace descriptor_ops {
33
34int 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
43int 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
81bool 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
122bool 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
167std::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
214bool 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
253std::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
293bool 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
325int 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
366int 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
381int 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
396int 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
419int 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

source code of boost/boost/asio/detail/impl/descriptor_ops.ipp