Line data Source code
1 : #include "source/common/network/win32_socket_handle_impl.h"
2 :
3 : #include "envoy/buffer/buffer.h"
4 :
5 : #include "source/common/api/os_sys_calls_impl.h"
6 : #include "source/common/common/utility.h"
7 : #include "source/common/event/file_event_impl.h"
8 : #include "source/common/network/address_impl.h"
9 :
10 : #include "absl/container/fixed_array.h"
11 : #include "absl/types/optional.h"
12 :
13 : using Envoy::Api::SysCallIntResult;
14 : using Envoy::Api::SysCallSizeResult;
15 :
16 : namespace Envoy {
17 : namespace Network {
18 :
19 : Api::IoCallUint64Result Win32SocketHandleImpl::readv(uint64_t max_length, Buffer::RawSlice* slices,
20 0 : uint64_t num_slice) {
21 0 : if (peek_buffer_.length() != 0) {
22 0 : return readvFromPeekBuffer(max_length, slices, num_slice);
23 0 : }
24 :
25 0 : auto result = IoSocketHandleImpl::readv(max_length, slices, num_slice);
26 0 : reEnableEventBasedOnIOResult(result, Event::FileReadyType::Read);
27 0 : return result;
28 0 : }
29 :
30 : Api::IoCallUint64Result Win32SocketHandleImpl::read(Buffer::Instance& buffer,
31 0 : absl::optional<uint64_t> max_length_opt) {
32 0 : if (peek_buffer_.length() != 0) {
33 0 : return readFromPeekBuffer(buffer, max_length_opt.value_or(UINT64_MAX));
34 0 : }
35 :
36 0 : auto result = IoSocketHandleImpl::read(buffer, max_length_opt);
37 0 : reEnableEventBasedOnIOResult(result, Event::FileReadyType::Read);
38 0 : return result;
39 0 : }
40 :
41 : Api::IoCallUint64Result Win32SocketHandleImpl::writev(const Buffer::RawSlice* slices,
42 0 : uint64_t num_slice) {
43 0 : auto result = IoSocketHandleImpl::writev(slices, num_slice);
44 0 : reEnableEventBasedOnIOResult(result, Event::FileReadyType::Write);
45 0 : return result;
46 0 : }
47 :
48 0 : Api::IoCallUint64Result Win32SocketHandleImpl::write(Buffer::Instance& buffer) {
49 0 : Api::IoCallUint64Result result = IoSocketHandleImpl::write(buffer);
50 0 : reEnableEventBasedOnIOResult(result, Event::FileReadyType::Write);
51 0 : return result;
52 0 : }
53 :
54 : Api::IoCallUint64Result Win32SocketHandleImpl::sendmsg(const Buffer::RawSlice* slices,
55 : uint64_t num_slice, int flags,
56 : const Address::Ip* self_ip,
57 0 : const Address::Instance& peer_address) {
58 :
59 0 : Api::IoCallUint64Result result =
60 0 : IoSocketHandleImpl::sendmsg(slices, num_slice, flags, self_ip, peer_address);
61 0 : reEnableEventBasedOnIOResult(result, Event::FileReadyType::Write);
62 0 : return result;
63 0 : }
64 :
65 : Api::IoCallUint64Result Win32SocketHandleImpl::recvmsg(Buffer::RawSlice* slices,
66 : const uint64_t num_slice, uint32_t self_port,
67 0 : RecvMsgOutput& output) {
68 0 : Api::IoCallUint64Result result =
69 0 : IoSocketHandleImpl::recvmsg(slices, num_slice, self_port, output);
70 0 : reEnableEventBasedOnIOResult(result, Event::FileReadyType::Read);
71 0 : return result;
72 0 : }
73 :
74 : Api::IoCallUint64Result Win32SocketHandleImpl::recvmmsg(RawSliceArrays& slices, uint32_t self_port,
75 0 : RecvMsgOutput& output) {
76 0 : Api::IoCallUint64Result result = IoSocketHandleImpl::recvmmsg(slices, self_port, output);
77 0 : reEnableEventBasedOnIOResult(result, Event::FileReadyType::Read);
78 0 : return result;
79 0 : }
80 :
81 0 : Api::IoCallUint64Result Win32SocketHandleImpl::recv(void* buffer, size_t length, int flags) {
82 0 : if (flags & MSG_PEEK) {
83 0 : return emulatePeek(buffer, length);
84 0 : }
85 :
86 0 : if (peek_buffer_.length() == 0) {
87 0 : Api::IoCallUint64Result result = IoSocketHandleImpl::recv(buffer, length, flags);
88 0 : reEnableEventBasedOnIOResult(result, Event::FileReadyType::Read);
89 0 : return result;
90 0 : } else {
91 0 : return readFromPeekBuffer(buffer, length);
92 0 : }
93 0 : }
94 :
95 0 : Api::IoCallUint64Result Win32SocketHandleImpl::emulatePeek(void* buffer, size_t length) {
96 : // If there's not enough data in the peek buffer, try reading more.
97 0 : if (length > peek_buffer_.length()) {
98 : // The caller is responsible for calling with the larger size
99 : // in cases it needs to do so it can't rely on transparent event activation.
100 : // So in this case we should activate read again unless the read blocked.
101 0 : Api::IoCallUint64Result peek_result = drainToPeekBuffer(length);
102 :
103 : // Some error happened.
104 0 : if (!peek_result.ok()) {
105 0 : if (peek_result.wouldBlock() && file_event_) {
106 0 : file_event_->registerEventIfEmulatedEdge(Event::FileReadyType::Read);
107 0 : if (peek_buffer_.length() == 0) {
108 0 : return peek_result;
109 0 : }
110 0 : } else {
111 0 : return peek_result;
112 0 : }
113 0 : }
114 0 : }
115 :
116 0 : return peekFromPeekBuffer(buffer, length);
117 0 : }
118 :
119 : void Win32SocketHandleImpl::reEnableEventBasedOnIOResult(const Api::IoCallUint64Result& result,
120 0 : uint32_t event) {
121 0 : if (result.wouldBlock() && file_event_) {
122 0 : file_event_->registerEventIfEmulatedEdge(event);
123 0 : }
124 0 : }
125 :
126 0 : Api::IoCallUint64Result Win32SocketHandleImpl::drainToPeekBuffer(size_t length) {
127 0 : size_t total_bytes_read = 0;
128 0 : while (peek_buffer_.length() < length) {
129 0 : Buffer::Reservation reservation = peek_buffer_.reserveForRead();
130 0 : uint64_t bytes_to_read = std::min<uint64_t>(
131 0 : static_cast<uint64_t>(length - peek_buffer_.length()), reservation.length());
132 0 : Api::IoCallUint64Result result =
133 0 : IoSocketHandleImpl::readv(bytes_to_read, reservation.slices(), reservation.numSlices());
134 0 : uint64_t bytes_to_commit = result.ok() ? result.return_value_ : 0;
135 0 : reservation.commit(bytes_to_commit);
136 0 : total_bytes_read += bytes_to_commit;
137 0 : if (!result.ok() || bytes_to_commit == 0) {
138 0 : return result;
139 0 : }
140 0 : }
141 0 : return {total_bytes_read, Api::IoError::none()};
142 0 : }
143 :
144 0 : Api::IoCallUint64Result Win32SocketHandleImpl::readFromPeekBuffer(void* buffer, size_t length) {
145 0 : uint64_t copy_size = std::min(peek_buffer_.length(), static_cast<uint64_t>(length));
146 0 : peek_buffer_.copyOut(0, copy_size, buffer);
147 0 : peek_buffer_.drain(copy_size);
148 0 : return {copy_size, Api::IoError::none()};
149 0 : }
150 :
151 : Api::IoCallUint64Result Win32SocketHandleImpl::readvFromPeekBuffer(uint64_t max_length,
152 : Buffer::RawSlice* slices,
153 0 : uint64_t num_slice) {
154 0 : uint64_t bytes_read = peek_buffer_.copyOutToSlices(max_length, slices, num_slice);
155 0 : peek_buffer_.drain(bytes_read);
156 0 : return {bytes_read, Api::IoError::none()};
157 0 : }
158 :
159 : Api::IoCallUint64Result Win32SocketHandleImpl::readFromPeekBuffer(Buffer::Instance& buffer,
160 0 : size_t length) {
161 0 : auto length_to_move = std::min(peek_buffer_.length(), static_cast<uint64_t>(length));
162 0 : buffer.move(peek_buffer_, length_to_move);
163 0 : return {length_to_move, Api::IoError::none()};
164 0 : }
165 :
166 0 : Api::IoCallUint64Result Win32SocketHandleImpl::peekFromPeekBuffer(void* buffer, size_t length) {
167 0 : uint64_t copy_size = std::min(peek_buffer_.length(), static_cast<uint64_t>(length));
168 0 : peek_buffer_.copyOut(0, copy_size, buffer);
169 0 : return {copy_size, Api::IoError::none()};
170 0 : }
171 :
172 : void Win32SocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatcher,
173 : Event::FileReadyCb cb,
174 0 : Event::FileTriggerType trigger, uint32_t events) {
175 0 : IoSocketHandleImpl::initializeFileEvent(dispatcher, cb, trigger, events);
176 : // Activate the file event directly when we have the data in the peek_buffer_.
177 0 : if ((events & Event::FileReadyType::Read) && peek_buffer_.length() > 0) {
178 0 : activateFileEvents(Event::FileReadyType::Read);
179 0 : }
180 0 : }
181 :
182 0 : void Win32SocketHandleImpl::enableFileEvents(uint32_t events) {
183 0 : IoSocketHandleImpl::enableFileEvents(events);
184 : // Activate the file event directly when we have the data in the peek_buffer_.
185 0 : if ((events & Event::FileReadyType::Read) && peek_buffer_.length() > 0) {
186 0 : activateFileEvents(Event::FileReadyType::Read);
187 0 : }
188 0 : }
189 :
190 : } // namespace Network
191 : } // namespace Envoy
|