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
8
                                                     uint64_t num_slice) {
21
8
  if (peek_buffer_.length() != 0) {
22
1
    return readvFromPeekBuffer(max_length, slices, num_slice);
23
1
  }
24

            
25
7
  auto result = IoSocketHandleImpl::readv(max_length, slices, num_slice);
26
7
  reEnableEventBasedOnIOResult(result, Event::FileReadyType::Read);
27
7
  return result;
28
8
}
29

            
30
Api::IoCallUint64Result Win32SocketHandleImpl::read(Buffer::Instance& buffer,
31
6
                                                    absl::optional<uint64_t> max_length_opt) {
32
6
  if (peek_buffer_.length() != 0) {
33
    return readFromPeekBuffer(buffer, max_length_opt.value_or(UINT64_MAX));
34
  }
35

            
36
6
  auto result = IoSocketHandleImpl::read(buffer, max_length_opt);
37
6
  reEnableEventBasedOnIOResult(result, Event::FileReadyType::Read);
38
6
  return result;
39
6
}
40

            
41
Api::IoCallUint64Result Win32SocketHandleImpl::writev(const Buffer::RawSlice* slices,
42
7
                                                      uint64_t num_slice) {
43
7
  auto result = IoSocketHandleImpl::writev(slices, num_slice);
44
7
  reEnableEventBasedOnIOResult(result, Event::FileReadyType::Write);
45
7
  return result;
46
7
}
47

            
48
7
Api::IoCallUint64Result Win32SocketHandleImpl::write(Buffer::Instance& buffer) {
49
7
  Api::IoCallUint64Result result = IoSocketHandleImpl::write(buffer);
50
7
  reEnableEventBasedOnIOResult(result, Event::FileReadyType::Write);
51
7
  return result;
52
7
}
53

            
54
Api::IoCallUint64Result Win32SocketHandleImpl::sendmsg(const Buffer::RawSlice* slices,
55
                                                       uint64_t num_slice, int flags,
56
                                                       const Address::Ip* self_ip,
57
                                                       const Address::Instance& peer_address) {
58

            
59
  Api::IoCallUint64Result result =
60
      IoSocketHandleImpl::sendmsg(slices, num_slice, flags, self_ip, peer_address);
61
  reEnableEventBasedOnIOResult(result, Event::FileReadyType::Write);
62
  return result;
63
}
64

            
65
Api::IoCallUint64Result Win32SocketHandleImpl::recvmsg(
66
    Buffer::RawSlice* slices, const uint64_t num_slice, uint32_t self_port,
67
    const IoHandle::UdpSaveCmsgConfig& udp_save_cmsg_config, RecvMsgOutput& output) {
68
  Api::IoCallUint64Result result =
69
      IoSocketHandleImpl::recvmsg(slices, num_slice, self_port, udp_save_cmsg_config, output);
70
  reEnableEventBasedOnIOResult(result, Event::FileReadyType::Read);
71
  return result;
72
}
73

            
74
Api::IoCallUint64Result
75
Win32SocketHandleImpl::recvmmsg(RawSliceArrays& slices, uint32_t self_port,
76

            
77
                                const IoHandle::UdpSaveCmsgConfig& udp_save_cmsg_config,
78
                                RecvMsgOutput& output) {
79
  Api::IoCallUint64Result result =
80
      IoSocketHandleImpl::recvmmsg(slices, self_port, udp_save_cmsg_config, output);
81
  reEnableEventBasedOnIOResult(result, Event::FileReadyType::Read);
82
  return result;
83
}
84

            
85
8
Api::IoCallUint64Result Win32SocketHandleImpl::recv(void* buffer, size_t length, int flags) {
86
8
  if (flags & MSG_PEEK) {
87
7
    return emulatePeek(buffer, length);
88
7
  }
89

            
90
1
  if (peek_buffer_.length() == 0) {
91
1
    Api::IoCallUint64Result result = IoSocketHandleImpl::recv(buffer, length, flags);
92
1
    reEnableEventBasedOnIOResult(result, Event::FileReadyType::Read);
93
1
    return result;
94
1
  } else {
95
    return readFromPeekBuffer(buffer, length);
96
  }
97
1
}
98

            
99
7
Api::IoCallUint64Result Win32SocketHandleImpl::emulatePeek(void* buffer, size_t length) {
100
  // If there's not enough data in the peek buffer, try reading more.
101
7
  if (length > peek_buffer_.length()) {
102
    // The caller is responsible for calling with the larger size
103
    // in cases it needs to do so it can't rely on transparent event activation.
104
    // So in this case we should activate read again unless the read blocked.
105
6
    Api::IoCallUint64Result peek_result = drainToPeekBuffer(length);
106

            
107
    //  Some error happened.
108
6
    if (!peek_result.ok()) {
109
3
      if (peek_result.wouldBlock() && file_event_) {
110
2
        file_event_->registerEventIfEmulatedEdge(Event::FileReadyType::Read);
111
2
        if (peek_buffer_.length() == 0) {
112
1
          return peek_result;
113
1
        }
114
2
      } else {
115
1
        return peek_result;
116
1
      }
117
3
    }
118
6
  }
119

            
120
5
  return peekFromPeekBuffer(buffer, length);
121
7
}
122

            
123
void Win32SocketHandleImpl::reEnableEventBasedOnIOResult(const Api::IoCallUint64Result& result,
124
28
                                                         uint32_t event) {
125
28
  if (result.wouldBlock() && file_event_) {
126
1
    file_event_->registerEventIfEmulatedEdge(event);
127
1
  }
128
28
}
129

            
130
6
Api::IoCallUint64Result Win32SocketHandleImpl::drainToPeekBuffer(size_t length) {
131
6
  size_t total_bytes_read = 0;
132
11
  while (peek_buffer_.length() < length) {
133
8
    Buffer::Reservation reservation = peek_buffer_.reserveForRead();
134
8
    uint64_t bytes_to_read = std::min<uint64_t>(
135
8
        static_cast<uint64_t>(length - peek_buffer_.length()), reservation.length());
136
8
    Api::IoCallUint64Result result =
137
8
        IoSocketHandleImpl::readv(bytes_to_read, reservation.slices(), reservation.numSlices());
138
8
    uint64_t bytes_to_commit = result.ok() ? result.return_value_ : 0;
139
8
    reservation.commit(bytes_to_commit);
140
8
    total_bytes_read += bytes_to_commit;
141
8
    if (!result.ok() || bytes_to_commit == 0) {
142
3
      return result;
143
3
    }
144
8
  }
145
3
  return {total_bytes_read, Api::IoError::none()};
146
6
}
147

            
148
Api::IoCallUint64Result Win32SocketHandleImpl::readFromPeekBuffer(void* buffer, size_t length) {
149
  uint64_t copy_size = std::min(peek_buffer_.length(), static_cast<uint64_t>(length));
150
  peek_buffer_.copyOut(0, copy_size, buffer);
151
  peek_buffer_.drain(copy_size);
152
  return {copy_size, Api::IoError::none()};
153
}
154

            
155
Api::IoCallUint64Result Win32SocketHandleImpl::readvFromPeekBuffer(uint64_t max_length,
156
                                                                   Buffer::RawSlice* slices,
157
1
                                                                   uint64_t num_slice) {
158
1
  uint64_t bytes_read = peek_buffer_.copyOutToSlices(max_length, slices, num_slice);
159
1
  peek_buffer_.drain(bytes_read);
160
1
  return {bytes_read, Api::IoError::none()};
161
1
}
162

            
163
Api::IoCallUint64Result Win32SocketHandleImpl::readFromPeekBuffer(Buffer::Instance& buffer,
164
                                                                  size_t length) {
165
  auto length_to_move = std::min(peek_buffer_.length(), static_cast<uint64_t>(length));
166
  buffer.move(peek_buffer_, length_to_move);
167
  return {length_to_move, Api::IoError::none()};
168
}
169

            
170
5
Api::IoCallUint64Result Win32SocketHandleImpl::peekFromPeekBuffer(void* buffer, size_t length) {
171
5
  uint64_t copy_size = std::min(peek_buffer_.length(), static_cast<uint64_t>(length));
172
5
  peek_buffer_.copyOut(0, copy_size, buffer);
173
5
  return {copy_size, Api::IoError::none()};
174
5
}
175

            
176
void Win32SocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatcher,
177
                                                Event::FileReadyCb cb,
178
8
                                                Event::FileTriggerType trigger, uint32_t events) {
179
8
  IoSocketHandleImpl::initializeFileEvent(dispatcher, cb, trigger, events);
180
  // Activate the file event directly when we have the data in the peek_buffer_.
181
8
  if ((events & Event::FileReadyType::Read) && peek_buffer_.length() > 0) {
182
    activateFileEvents(Event::FileReadyType::Read);
183
  }
184
8
}
185

            
186
void Win32SocketHandleImpl::enableFileEvents(uint32_t events) {
187
  IoSocketHandleImpl::enableFileEvents(events);
188
  // Activate the file event directly when we have the data in the peek_buffer_.
189
  if ((events & Event::FileReadyType::Read) && peek_buffer_.length() > 0) {
190
    activateFileEvents(Event::FileReadyType::Read);
191
  }
192
}
193

            
194
} // namespace Network
195
} // namespace Envoy