1//
2// detail/impl/descriptor_ops.ipp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2021 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  int result = ::open(path, flags);
37  get_last_error(ec, result < 0);
38  return result;
39}
40
41int close(int d, state_type& state, boost::system::error_code& ec)
42{
43  int result = 0;
44  if (d != -1)
45  {
46    result = ::close(d);
47    get_last_error(ec, result < 0);
48
49    if (result != 0
50        && (ec == boost::asio::error::would_block
51          || ec == boost::asio::error::try_again))
52    {
53      // According to UNIX Network Programming Vol. 1, it is possible for
54      // close() to fail with EWOULDBLOCK under certain circumstances. What
55      // isn't clear is the state of the descriptor after this error. The one
56      // current OS where this behaviour is seen, Windows, says that the socket
57      // remains open. Therefore we'll put the descriptor back into blocking
58      // mode and have another attempt at closing it.
59#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
60      int flags = ::fcntl(d, F_GETFL, 0);
61      if (flags >= 0)
62        ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK);
63#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
64      ioctl_arg_type arg = 0;
65      ::ioctl(d, FIONBIO, &arg);
66#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
67      state &= ~non_blocking;
68
69      result = ::close(d);
70      get_last_error(ec, result < 0);
71    }
72  }
73
74  return result;
75}
76
77bool set_user_non_blocking(int d, state_type& state,
78    bool value, boost::system::error_code& ec)
79{
80  if (d == -1)
81  {
82    ec = boost::asio::error::bad_descriptor;
83    return false;
84  }
85
86#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
87  int result = ::fcntl(d, F_GETFL, 0);
88  get_last_error(ec, result < 0);
89  if (result >= 0)
90  {
91    int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
92    result = ::fcntl(d, F_SETFL, flag);
93    get_last_error(ec, result < 0);
94  }
95#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
96  ioctl_arg_type arg = (value ? 1 : 0);
97  int result = ::ioctl(d, FIONBIO, &arg);
98  get_last_error(ec, result < 0);
99#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
100
101  if (result >= 0)
102  {
103    if (value)
104      state |= user_set_non_blocking;
105    else
106    {
107      // Clearing the user-set non-blocking mode always overrides any
108      // internally-set non-blocking flag. Any subsequent asynchronous
109      // operations will need to re-enable non-blocking I/O.
110      state &= ~(user_set_non_blocking | internal_non_blocking);
111    }
112    return true;
113  }
114
115  return false;
116}
117
118bool set_internal_non_blocking(int d, state_type& state,
119    bool value, boost::system::error_code& ec)
120{
121  if (d == -1)
122  {
123    ec = boost::asio::error::bad_descriptor;
124    return false;
125  }
126
127  if (!value && (state & user_set_non_blocking))
128  {
129    // It does not make sense to clear the internal non-blocking flag if the
130    // user still wants non-blocking behaviour. Return an error and let the
131    // caller figure out whether to update the user-set non-blocking flag.
132    ec = boost::asio::error::invalid_argument;
133    return false;
134  }
135
136#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
137  int result = ::fcntl(d, F_GETFL, 0);
138  get_last_error(ec, result < 0);
139  if (result >= 0)
140  {
141    int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
142    result = ::fcntl(d, F_SETFL, flag);
143    get_last_error(ec, result < 0);
144  }
145#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
146  ioctl_arg_type arg = (value ? 1 : 0);
147  int result = ::ioctl(d, FIONBIO, &arg);
148  get_last_error(ec, result < 0);
149#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
150
151  if (result >= 0)
152  {
153    if (value)
154      state |= internal_non_blocking;
155    else
156      state &= ~internal_non_blocking;
157    return true;
158  }
159
160  return false;
161}
162
163std::size_t sync_read(int d, state_type state, buf* bufs,
164    std::size_t count, bool all_empty, boost::system::error_code& ec)
165{
166  if (d == -1)
167  {
168    ec = boost::asio::error::bad_descriptor;
169    return 0;
170  }
171
172  // A request to read 0 bytes on a stream is a no-op.
173  if (all_empty)
174  {
175    ec.assign(0, ec.category());
176    return 0;
177  }
178
179  // Read some data.
180  for (;;)
181  {
182    // Try to complete the operation without blocking.
183    signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count));
184    get_last_error(ec, bytes < 0);
185
186    // Check if operation succeeded.
187    if (bytes > 0)
188      return bytes;
189
190    // Check for EOF.
191    if (bytes == 0)
192    {
193      ec = boost::asio::error::eof;
194      return 0;
195    }
196
197    // Operation failed.
198    if ((state & user_set_non_blocking)
199        || (ec != boost::asio::error::would_block
200          && ec != boost::asio::error::try_again))
201      return 0;
202
203    // Wait for descriptor to become ready.
204    if (descriptor_ops::poll_read(d, 0, ec) < 0)
205      return 0;
206  }
207}
208
209std::size_t sync_read1(int d, state_type state, void* data,
210    std::size_t size, boost::system::error_code& ec)
211{
212  if (d == -1)
213  {
214    ec = boost::asio::error::bad_descriptor;
215    return 0;
216  }
217
218  // A request to read 0 bytes on a stream is a no-op.
219  if (size == 0)
220  {
221    ec.assign(0, ec.category());
222    return 0;
223  }
224
225  // Read some data.
226  for (;;)
227  {
228    // Try to complete the operation without blocking.
229    signed_size_type bytes = ::read(d, data, size);
230    get_last_error(ec, bytes < 0);
231
232    // Check if operation succeeded.
233    if (bytes > 0)
234      return bytes;
235
236    // Check for EOF.
237    if (bytes == 0)
238    {
239      ec = boost::asio::error::eof;
240      return 0;
241    }
242
243    // Operation failed.
244    if ((state & user_set_non_blocking)
245        || (ec != boost::asio::error::would_block
246          && ec != boost::asio::error::try_again))
247      return 0;
248
249    // Wait for descriptor to become ready.
250    if (descriptor_ops::poll_read(d, 0, ec) < 0)
251      return 0;
252  }
253}
254
255bool non_blocking_read(int d, buf* bufs, std::size_t count,
256    boost::system::error_code& ec, std::size_t& bytes_transferred)
257{
258  for (;;)
259  {
260    // Read some data.
261    signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count));
262    get_last_error(ec, bytes < 0);
263
264    // Check for end of stream.
265    if (bytes == 0)
266    {
267      ec = boost::asio::error::eof;
268      return true;
269    }
270
271    // Check if operation succeeded.
272    if (bytes > 0)
273    {
274      bytes_transferred = bytes;
275      return true;
276    }
277
278    // Retry operation if interrupted by signal.
279    if (ec == boost::asio::error::interrupted)
280      continue;
281
282    // Check if we need to run the operation again.
283    if (ec == boost::asio::error::would_block
284        || ec == boost::asio::error::try_again)
285      return false;
286
287    // Operation failed.
288    bytes_transferred = 0;
289    return true;
290  }
291}
292
293bool non_blocking_read1(int d, void* data, std::size_t size,
294    boost::system::error_code& ec, std::size_t& bytes_transferred)
295{
296  for (;;)
297  {
298    // Read some data.
299    signed_size_type bytes = ::read(d, data, size);
300    get_last_error(ec, bytes < 0);
301
302    // Check for end of stream.
303    if (bytes == 0)
304    {
305      ec = boost::asio::error::eof;
306      return true;
307    }
308
309    // Check if operation succeeded.
310    if (bytes > 0)
311    {
312      bytes_transferred = bytes;
313      return true;
314    }
315
316    // Retry operation if interrupted by signal.
317    if (ec == boost::asio::error::interrupted)
318      continue;
319
320    // Check if we need to run the operation again.
321    if (ec == boost::asio::error::would_block
322        || ec == boost::asio::error::try_again)
323      return false;
324
325    // Operation failed.
326    bytes_transferred = 0;
327    return true;
328  }
329}
330
331std::size_t sync_write(int d, state_type state, const buf* bufs,
332    std::size_t count, bool all_empty, boost::system::error_code& ec)
333{
334  if (d == -1)
335  {
336    ec = boost::asio::error::bad_descriptor;
337    return 0;
338  }
339
340  // A request to write 0 bytes on a stream is a no-op.
341  if (all_empty)
342  {
343    ec.assign(0, ec.category());
344    return 0;
345  }
346
347  // Write some data.
348  for (;;)
349  {
350    // Try to complete the operation without blocking.
351    signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count));
352    get_last_error(ec, bytes < 0);
353
354    // Check if operation succeeded.
355    if (bytes > 0)
356      return bytes;
357
358    // Operation failed.
359    if ((state & user_set_non_blocking)
360        || (ec != boost::asio::error::would_block
361          && ec != boost::asio::error::try_again))
362      return 0;
363
364    // Wait for descriptor to become ready.
365    if (descriptor_ops::poll_write(d, 0, ec) < 0)
366      return 0;
367  }
368}
369
370std::size_t sync_write1(int d, state_type state, const void* data,
371    std::size_t size, boost::system::error_code& ec)
372{
373  if (d == -1)
374  {
375    ec = boost::asio::error::bad_descriptor;
376    return 0;
377  }
378
379  // A request to write 0 bytes on a stream is a no-op.
380  if (size == 0)
381  {
382    ec.assign(0, ec.category());
383    return 0;
384  }
385
386  // Write some data.
387  for (;;)
388  {
389    // Try to complete the operation without blocking.
390    signed_size_type bytes = ::write(d, data, size);
391    get_last_error(ec, bytes < 0);
392
393    // Check if operation succeeded.
394    if (bytes > 0)
395      return bytes;
396
397    // Operation failed.
398    if ((state & user_set_non_blocking)
399        || (ec != boost::asio::error::would_block
400          && ec != boost::asio::error::try_again))
401      return 0;
402
403    // Wait for descriptor to become ready.
404    if (descriptor_ops::poll_write(d, 0, ec) < 0)
405      return 0;
406  }
407}
408
409bool non_blocking_write(int d, const buf* bufs, std::size_t count,
410    boost::system::error_code& ec, std::size_t& bytes_transferred)
411{
412  for (;;)
413  {
414    // Write some data.
415    signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count));
416    get_last_error(ec, bytes < 0);
417
418    // Check if operation succeeded.
419    if (bytes >= 0)
420    {
421      bytes_transferred = bytes;
422      return true;
423    }
424
425    // Retry operation if interrupted by signal.
426    if (ec == boost::asio::error::interrupted)
427      continue;
428
429    // Check if we need to run the operation again.
430    if (ec == boost::asio::error::would_block
431        || ec == boost::asio::error::try_again)
432      return false;
433
434    // Operation failed.
435    bytes_transferred = 0;
436    return true;
437  }
438}
439
440bool non_blocking_write1(int d, const void* data, std::size_t size,
441    boost::system::error_code& ec, std::size_t& bytes_transferred)
442{
443  for (;;)
444  {
445    // Write some data.
446    signed_size_type bytes = ::write(d, data, size);
447    get_last_error(ec, bytes < 0);
448
449    // Check if operation succeeded.
450    if (bytes >= 0)
451    {
452      bytes_transferred = bytes;
453      return true;
454    }
455
456    // Retry operation if interrupted by signal.
457    if (ec == boost::asio::error::interrupted)
458      continue;
459
460    // Check if we need to run the operation again.
461    if (ec == boost::asio::error::would_block
462        || ec == boost::asio::error::try_again)
463      return false;
464
465    // Operation failed.
466    bytes_transferred = 0;
467    return true;
468  }
469}
470
471int ioctl(int d, state_type& state, long cmd,
472    ioctl_arg_type* arg, boost::system::error_code& ec)
473{
474  if (d == -1)
475  {
476    ec = boost::asio::error::bad_descriptor;
477    return -1;
478  }
479
480  int result = ::ioctl(d, cmd, arg);
481  get_last_error(ec, result < 0);
482
483  if (result >= 0)
484  {
485    // When updating the non-blocking mode we always perform the ioctl syscall,
486    // even if the flags would otherwise indicate that the descriptor is
487    // already in the correct state. This ensures that the underlying
488    // descriptor is put into the state that has been requested by the user. If
489    // the ioctl syscall was successful then we need to update the flags to
490    // match.
491    if (cmd == static_cast<long>(FIONBIO))
492    {
493      if (*arg)
494      {
495        state |= user_set_non_blocking;
496      }
497      else
498      {
499        // Clearing the non-blocking mode always overrides any internally-set
500        // non-blocking flag. Any subsequent asynchronous operations will need
501        // to re-enable non-blocking I/O.
502        state &= ~(user_set_non_blocking | internal_non_blocking);
503      }
504    }
505  }
506
507  return result;
508}
509
510int fcntl(int d, int cmd, boost::system::error_code& ec)
511{
512  if (d == -1)
513  {
514    ec = boost::asio::error::bad_descriptor;
515    return -1;
516  }
517
518  int result = ::fcntl(d, cmd);
519  get_last_error(ec, result < 0);
520  return result;
521}
522
523int fcntl(int d, int cmd, long arg, boost::system::error_code& ec)
524{
525  if (d == -1)
526  {
527    ec = boost::asio::error::bad_descriptor;
528    return -1;
529  }
530
531  int result = ::fcntl(d, cmd, arg);
532  get_last_error(ec, result < 0);
533  return result;
534}
535
536int poll_read(int d, state_type state, boost::system::error_code& ec)
537{
538  if (d == -1)
539  {
540    ec = boost::asio::error::bad_descriptor;
541    return -1;
542  }
543
544  pollfd fds;
545  fds.fd = d;
546  fds.events = POLLIN;
547  fds.revents = 0;
548  int timeout = (state & user_set_non_blocking) ? 0 : -1;
549  int result = ::poll(&fds, 1, timeout);
550  get_last_error(ec, result < 0);
551  if (result == 0)
552    if (state & user_set_non_blocking)
553      ec = boost::asio::error::would_block;
554  return result;
555}
556
557int poll_write(int d, state_type state, boost::system::error_code& ec)
558{
559  if (d == -1)
560  {
561    ec = boost::asio::error::bad_descriptor;
562    return -1;
563  }
564
565  pollfd fds;
566  fds.fd = d;
567  fds.events = POLLOUT;
568  fds.revents = 0;
569  int timeout = (state & user_set_non_blocking) ? 0 : -1;
570  int result = ::poll(&fds, 1, timeout);
571  get_last_error(ec, result < 0);
572  if (result == 0)
573    if (state & user_set_non_blocking)
574      ec = boost::asio::error::would_block;
575  return result;
576}
577
578int poll_error(int d, state_type state, boost::system::error_code& ec)
579{
580  if (d == -1)
581  {
582    ec = boost::asio::error::bad_descriptor;
583    return -1;
584  }
585
586  pollfd fds;
587  fds.fd = d;
588  fds.events = POLLPRI | POLLERR | POLLHUP;
589  fds.revents = 0;
590  int timeout = (state & user_set_non_blocking) ? 0 : -1;
591  int result = ::poll(&fds, 1, timeout);
592  get_last_error(ec, result < 0);
593  if (result == 0)
594    if (state & user_set_non_blocking)
595      ec = boost::asio::error::would_block;
596  return result;
597}
598
599} // namespace descriptor_ops
600} // namespace detail
601} // namespace asio
602} // namespace boost
603
604#include <boost/asio/detail/pop_options.hpp>
605
606#endif // !defined(BOOST_ASIO_WINDOWS)
607       //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
608       //   && !defined(__CYGWIN__)
609
610#endif // BOOST_ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
611