HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NET_BoostAsioExt.h
Go to the documentation of this file.
1 /*
2  * POPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: NET_BoostAsioExt.h
7  *
8  * COMMENTS:
9  * Place for all boost.asio extensions (i.e. sendfile).
10  */
11 
12 #ifndef __NET_BOOSTASIOEXT_H__
13 #define __NET_BOOSTASIOEXT_H__
14 
15 #include "NET_API.h"
16 
17 #include <UT/UT_IpAddress.h>
18 
19 #include <vector>
20 #include <limits>
21 
22 // -----------------------------------------------------------------------------
23 // Extensions to Boost.Asio
24 // -----------------------------------------------------------------------------
25 
26 inline UT_IpAddress
28 {
29  if (from.is_v4())
30  {
31  return UT_IpAddress(UT_IpAddressV4(from.to_v4().to_uint()));
32  }
33  return UT_IpAddress(UT_IpAddressV6(from.to_v6().to_bytes()));
34 }
35 
36 #if !defined(WIN32)
37 /// Sendfile system call async support
38 #define NET_SUPPORT_SENDFILE
39 
40 #if defined(LINUX)
41 #include <sys/sendfile.h>
42 #elif defined(MBSD)
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <sys/uio.h>
46 #endif
47 
49 {
50  // NB: Implementation from:
51  // https://www.boost.org/doc/libs/1_75_0/doc/html/boost_asio/reference/basic_stream_socket/native_non_blocking/overload1.html
52 
54  NET_TCPSocket& socket,
55  int fd,
56  off_t offset,
57  std::size_t size)
58  : mySocket(socket), myFD(fd), myOffset(offset), mySize(size), myBytesTransferred(0)
59  {
60  }
61 
62  template <typename Self>
63  void operator()(
64  Self& self,
65  hboost::system::error_code ec = hboost::system::error_code(),
66  std::size_t bytes_transfered = 0)
67  {
68  // Make sure the underlying socket is non-blocking for this to work.
69  if (!ec)
70  {
71  if (!mySocket.native_non_blocking())
72  mySocket.native_non_blocking(true, ec);
73  }
74 
75  if (!ec)
76  {
77  for (;;)
78  {
79  errno = 0;
80 #if defined(LINUX)
81  int n = ::sendfile(
82  mySocket.native_handle(), myFD, &myOffset, mySize);
83 #elif defined(MBSD)
84  // On OSX the sendfile call differs from Linux version so we
85  // try to replicate its behaviour after the fact.
86  // - returns 0 on success or -1 on error. Instead if it was a
87  // success adjust n to reflect how much was written.
88  // - the offset does not get adjusted like it does for Linux.
89  // Instead the offset gets adjusted based on the amount
90  // read after the fact.
91  //
92  off_t size = static_cast<off_t>(mySize);
93  int n = ::sendfile(
94  myFD, mySocket.native_handle(), myOffset, &size, nullptr /*hdtr*/, 0 /*flags*/);
95  if (n >= 0)
96  {
97  myOffset += size;
98  n = size;
99  }
100 #endif
101  ec = hboost::system::error_code(
102  n < 0 ? errno : 0,
103  hboost::asio::error::get_system_category());
104  // Adjust our parameters based on what was just read.
105  myBytesTransferred += ec ? 0 : n;
106  mySize -= ec ? 0 : n;
107 
108  // If interrupted by a signal then try again right away
109  if (ec == hboost::asio::error::interrupted)
110  continue;
111 
112  // Check if we need to run the operation again.
113  if (ec == hboost::asio::error::would_block
114  || ec == hboost::asio::error::try_again)
115  {
116  // Wait for the socket to become ready again.
117  mySocket.async_wait(
118  NET_TCPSocket::wait_write, std::move(self));
119  return;
120  }
121 
122  if (ec || n == 0 || mySize <= 0)
123  {
124  // An error occurred, or we have reach the end of what we
125  // wanted to send. Either way we are finished here and the
126  // completion handler can be called.
127  break;
128  }
129  }
130  }
131 
132  self.complete(ec, myBytesTransferred);
133  }
134 
136  int myFD;
137  off_t myOffset;
138  std::size_t mySize;
139  std::size_t myBytesTransferred;
140 };
141 
142 /// Async composed function to use the system sendfile call. The completion
143 /// token is only called if the operation is completely finished or an error
144 /// of some kind has occurred.
145 template <typename CompletionToken>
146 auto
148  NET_TCPSocket& socket,
149  int fd,
150  off_t offset,
151  std::size_t size,
152  CompletionToken&& token) ->
153  typename hboost::asio::async_result<
155  void(hboost::system::error_code, std::size_t)>::return_type
156 {
157  return hboost::asio::async_compose<
158  CompletionToken, void(hboost::system::error_code, std::size_t)>(
159  NET_SendfileOp{socket, fd, offset, size}, token, socket);
160 }
161 #endif // !defined(WIN32)
162 
163 #endif // __NET_BOOSTASIOLINUXEXT_H__
164 
NET_SendfileOp(NET_TCPSocket &socket, int fd, off_t offset, std::size_t size)
void
Definition: png.h:1083
This represents a Ipv4 address.
Definition: UT_IpAddress.h:34
auto NETasyncSendfile(NET_TCPSocket &socket, int fd, off_t offset, std::size_t size, CompletionToken &&token) -> typename hboost::asio::async_result< typename std::decay< CompletionToken >::type, void(hboost::system::error_code, std::size_t)>::return_type
GLsizeiptr size
Definition: glcorearb.h:664
This represents either an Ipv4 address or an Ipv6 address.
Definition: UT_IpAddress.h:230
UT_IpAddress NETconvertIPAddressType(hboost::asio::ip::address &from)
GLuint GLuint64EXT address
Definition: glew.h:14913
GLdouble n
Definition: glcorearb.h:2008
std::size_t myBytesTransferred
This represents a Ipv6 address.
Definition: UT_IpAddress.h:137
NET_TCPSocket & mySocket
hboost::asio::ip::tcp::socket NET_TCPSocket
Definition: NET_BoostAsio.h:44
std::size_t mySize
GLintptr offset
Definition: glcorearb.h:665
type
Definition: core.h:1059
void operator()(Self &self, hboost::system::error_code ec=hboost::system::error_code(), std::size_t bytes_transfered=0)