@fails-components/webtransport 0.1.5 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +42 -111
- package/build.js +4 -4
- package/dist/lib/dom.d.ts +6 -0
- package/dist/lib/dom.d.ts.map +1 -1
- package/dist/lib/event-loop.d.ts +8 -3
- package/dist/lib/event-loop.d.ts.map +1 -1
- package/dist/lib/server.d.ts +3 -2
- package/dist/lib/server.d.ts.map +1 -1
- package/dist/lib/session.d.ts +78 -18
- package/dist/lib/session.d.ts.map +1 -1
- package/dist/lib/stream.d.ts +13 -5
- package/dist/lib/stream.d.ts.map +1 -1
- package/dist/lib/transport.d.ts.map +1 -1
- package/dist/lib/types.d.ts +11 -2
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/webtransport.d.ts +22 -0
- package/dist/lib/webtransport.d.ts.map +1 -1
- package/dist/test/bidirectional-streams.spec.d.ts.map +1 -1
- package/dist/test/datagrams.spec.d.ts.map +1 -1
- package/dist/test/fixtures/p-timeout.d.ts +8 -0
- package/dist/test/fixtures/p-timeout.d.ts.map +1 -0
- package/dist/test/fixtures/read-stream.d.ts.map +1 -1
- package/dist/test/unidirectional-streams.spec.d.ts.map +1 -1
- package/lib/dom.ts +7 -2
- package/lib/event-loop.js +13 -7
- package/lib/server.js +1 -1
- package/lib/session.js +71 -21
- package/lib/stream.js +137 -12
- package/lib/transport.js +3 -1
- package/lib/types.ts +13 -2
- package/lib/webtransport.js +31 -0
- package/package.json +5 -4
- package/platform/base/strings/utf_ostream_operators.h +5 -0
- package/platform/quiche/quic/core/io/socket_win.inc +3 -0
- package/platform/quiche_platform_impl/quiche_command_line_flags_impl.h +7 -0
- package/platform/quiche_platform_impl/quiche_export_impl.h +3 -9
- package/platform/quiche_platform_impl/quiche_server_stats_impl.h +1 -22
- package/platform/quiche_platform_impl/quiche_stream_buffer_allocator_impl.h +1 -4
- package/platform/quiche_platform_impl/quiche_time_utils_impl.h +1 -13
- package/platform/quiche_platform_impl/quiche_udp_socket_platform_impl.h +9 -0
- package/readme.md +3 -1
- package/src/http3client.cc +13 -29
- package/src/http3client.h +2 -6
- package/src/http3clientsession.cc +51 -40
- package/src/http3clientsession.h +44 -31
- package/src/http3clientstream.cc +17 -0
- package/src/http3clientstream.h +10 -0
- package/src/http3eventloop.cc +81 -61
- package/src/http3eventloop.h +10 -7
- package/src/http3server.cc +1 -1
- package/src/http3serversession.cc +1 -136
- package/src/http3serversession.h +7 -77
- package/src/http3serverstream.cc +0 -49
- package/src/http3serverstream.h +0 -5
- package/src/http3wtsessionvisitor.cc +1 -1
- package/src/http3wtsessionvisitor.h +24 -37
- package/src/http3wtstreamvisitor.cc +35 -8
- package/src/http3wtstreamvisitor.h +81 -3
- package/test/bidirectional-streams.spec.js +16 -7
- package/test/datagrams.spec.js +31 -20
- package/test/fixtures/p-timeout.js +33 -0
- package/test/fixtures/read-stream.js +4 -1
- package/test/unidirectional-streams.spec.js +24 -15
- package/platform/net/quiche/common/platform/impl/quiche_flags_impl.h +0 -12
- package/platform/poll.h +0 -2
- package/platform/quiche/quic/core/io/quic_poll_event_loop.h +0 -8
- package/platform/quiche_platform_impl/quic_testvalue_impl.h +0 -19
- package/platform/quiche_platform_impl/quic_udp_socket_winsock.cc +0 -732
- package/platform/quiche_platform_impl/quiche_time_utils_impl.cc +0 -43
- package/platform/quiche_platform_impl/socket_winsock.cc +0 -535
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// from envoy so LICENSE.envoy applies
|
|
2
|
-
// NOLINT(namespace-envoy)
|
|
3
|
-
|
|
4
|
-
// This file is part of the QUICHE platform implementation, and is not to be
|
|
5
|
-
// consumed or referenced directly by other Envoy code. It serves purely as a
|
|
6
|
-
// porting layer for QUICHE.
|
|
7
|
-
|
|
8
|
-
#include "quiche_platform_impl/quiche_time_utils_impl.h"
|
|
9
|
-
|
|
10
|
-
namespace quiche {
|
|
11
|
-
|
|
12
|
-
namespace {
|
|
13
|
-
absl::optional<int64_t> quicheUtcDateTimeToUnixSecondsInner(int year, int month, int day, int hour,
|
|
14
|
-
int minute, int second) {
|
|
15
|
-
const absl::CivilSecond civil_time(year, month, day, hour, minute, second);
|
|
16
|
-
if (second != 60 && (civil_time.year() != year || civil_time.month() != month ||
|
|
17
|
-
civil_time.day() != day || civil_time.hour() != hour ||
|
|
18
|
-
civil_time.minute() != minute || civil_time.second() != second)) {
|
|
19
|
-
return absl::nullopt;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const absl::Time time = absl::FromCivil(civil_time, absl::UTCTimeZone());
|
|
23
|
-
return absl::ToUnixSeconds(time);
|
|
24
|
-
}
|
|
25
|
-
} // namespace
|
|
26
|
-
|
|
27
|
-
// NOLINTNEXTLINE(readability-identifier-naming)
|
|
28
|
-
absl::optional<int64_t> QuicheUtcDateTimeToUnixSecondsImpl(int year, int month, int day, int hour,
|
|
29
|
-
int minute, int second) {
|
|
30
|
-
// Handle leap seconds without letting any other irregularities happen.
|
|
31
|
-
if (second == 60) {
|
|
32
|
-
auto previous_second =
|
|
33
|
-
quicheUtcDateTimeToUnixSecondsInner(year, month, day, hour, minute, second - 1);
|
|
34
|
-
if (!previous_second.has_value()) {
|
|
35
|
-
return absl::nullopt;
|
|
36
|
-
}
|
|
37
|
-
return *previous_second + 1;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return quicheUtcDateTimeToUnixSecondsInner(year, month, day, hour, minute, second);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
} // namespace quiche
|
|
@@ -1,535 +0,0 @@
|
|
|
1
|
-
// Port to Windows Marten Richter
|
|
2
|
-
// Copyright 2022 The Chromium Authors. All rights reserved.
|
|
3
|
-
// Use of this source code is governed by a BSD-style license that can be
|
|
4
|
-
// found in the LICENSE file.
|
|
5
|
-
#include <winsock2.h>
|
|
6
|
-
#include <ws2tcpip.h>
|
|
7
|
-
#include <mswsock.h>
|
|
8
|
-
|
|
9
|
-
#include <climits>
|
|
10
|
-
|
|
11
|
-
#include "absl/base/attributes.h"
|
|
12
|
-
#include "absl/container/flat_hash_set.h"
|
|
13
|
-
#include "absl/status/status.h"
|
|
14
|
-
#include "absl/status/statusor.h"
|
|
15
|
-
#include "absl/strings/string_view.h"
|
|
16
|
-
#include "quiche/quic/core/io/socket.h"
|
|
17
|
-
#include "quiche/quic/platform/api/quic_ip_address_family.h"
|
|
18
|
-
#include "quiche/common/platform/api/quiche_logging.h"
|
|
19
|
-
|
|
20
|
-
namespace quic::socket_api {
|
|
21
|
-
|
|
22
|
-
namespace {
|
|
23
|
-
|
|
24
|
-
int ToPlatformSocketType(SocketProtocol protocol) {
|
|
25
|
-
switch (protocol) {
|
|
26
|
-
case SocketProtocol::kUdp:
|
|
27
|
-
return SOCK_DGRAM;
|
|
28
|
-
case SocketProtocol::kTcp:
|
|
29
|
-
return SOCK_STREAM;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
QUICHE_NOTREACHED();
|
|
33
|
-
return -1;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
int ToPlatformProtocol(SocketProtocol protocol) {
|
|
37
|
-
switch (protocol) {
|
|
38
|
-
case SocketProtocol::kUdp:
|
|
39
|
-
return IPPROTO_UDP;
|
|
40
|
-
case SocketProtocol::kTcp:
|
|
41
|
-
return IPPROTO_TCP;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
QUICHE_NOTREACHED();
|
|
45
|
-
return -1;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Wrapper of absl::ErrnoToStatus that ensures the `unavailable_error_numbers`
|
|
49
|
-
// and only those numbers result in `absl::StatusCode::kUnavailable`, converting
|
|
50
|
-
// any other would-be-unavailable Statuses to `absl::StatusCode::kNotFound`.
|
|
51
|
-
absl::Status ToStatus(int error_number, absl::string_view method_name,
|
|
52
|
-
absl::flat_hash_set<int> unavailable_error_numbers = {
|
|
53
|
-
EAGAIN, EWOULDBLOCK}) {
|
|
54
|
-
QUICHE_DCHECK_NE(error_number, 0);
|
|
55
|
-
QUICHE_DCHECK_NE(error_number, EINTR);
|
|
56
|
-
|
|
57
|
-
absl::Status status = absl::ErrnoToStatus(error_number, method_name);
|
|
58
|
-
QUICHE_DCHECK(!status.ok());
|
|
59
|
-
|
|
60
|
-
if (!absl::IsUnavailable(status) &&
|
|
61
|
-
unavailable_error_numbers.contains(error_number)) {
|
|
62
|
-
status = absl::UnavailableError(status.message());
|
|
63
|
-
} else if (absl::IsUnavailable(status) &&
|
|
64
|
-
!unavailable_error_numbers.contains(error_number)) {
|
|
65
|
-
status = absl::NotFoundError(status.message());
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return status;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/*
|
|
72
|
-
absl::Status SetSocketFlags(SocketFd fd, int to_add, int to_remove) {
|
|
73
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
74
|
-
QUICHE_DCHECK(to_add || to_remove);
|
|
75
|
-
QUICHE_DCHECK(!(to_add & to_remove));
|
|
76
|
-
|
|
77
|
-
int flags;
|
|
78
|
-
do {
|
|
79
|
-
flags = ::fcntl(fd, F_GETFL);
|
|
80
|
-
} while (flags < 0 && errno == EINTR);
|
|
81
|
-
if (flags < 0) {
|
|
82
|
-
absl::Status status = ToStatus(errno, "::fcntl()");
|
|
83
|
-
QUICHE_LOG_FIRST_N(ERROR, 100)
|
|
84
|
-
<< "Could not get flags for socket " << fd << " with error: " << status;
|
|
85
|
-
return status;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
QUICHE_DCHECK(!(flags & to_add) || (flags & to_remove));
|
|
89
|
-
|
|
90
|
-
int fcntl_result;
|
|
91
|
-
do {
|
|
92
|
-
fcntl_result = ::fcntl(fd, F_SETFL, (flags | to_add) & ~to_remove);
|
|
93
|
-
} while (fcntl_result < 0 && errno == EINTR);
|
|
94
|
-
if (fcntl_result < 0) {
|
|
95
|
-
absl::Status status = ToStatus(errno, "::fcntl()");
|
|
96
|
-
QUICHE_LOG_FIRST_N(ERROR, 100)
|
|
97
|
-
<< "Could not set flags for socket " << fd << " with error: " << status;
|
|
98
|
-
return status;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return absl::OkStatus();
|
|
102
|
-
}
|
|
103
|
-
*/
|
|
104
|
-
|
|
105
|
-
absl::Status SetSocketMode(SocketFd fd, unsigned long mode) {
|
|
106
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
107
|
-
|
|
108
|
-
int flags;
|
|
109
|
-
int ret = 0;
|
|
110
|
-
do {
|
|
111
|
-
ret = ioctlsocket(fd, FIONBIO, &mode);
|
|
112
|
-
} while (ret == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
|
|
113
|
-
if (ret == SOCKET_ERROR) {
|
|
114
|
-
absl::Status status = ToStatus(WSAGetLastError(), "WSAIoctl");
|
|
115
|
-
QUICHE_LOG_FIRST_N(ERROR, 100)
|
|
116
|
-
<< "Could not set mode for socket " << fd << " with error: " << status;
|
|
117
|
-
return status;
|
|
118
|
-
}
|
|
119
|
-
return absl::OkStatus();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
absl::StatusOr<QuicSocketAddress> ValidateAndConvertAddress(
|
|
123
|
-
const sockaddr_storage& addr, socklen_t addr_len) {
|
|
124
|
-
if (addr.ss_family != AF_INET && addr.ss_family != AF_INET6) {
|
|
125
|
-
QUICHE_DVLOG(1) << "Socket did not have recognized address family: "
|
|
126
|
-
<< addr.ss_family;
|
|
127
|
-
return absl::UnimplementedError("Unrecognized address family.");
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if ((addr.ss_family == AF_INET && addr_len != sizeof(sockaddr_in)) ||
|
|
131
|
-
(addr.ss_family == AF_INET6 && addr_len != sizeof(sockaddr_in6))) {
|
|
132
|
-
QUICHE_DVLOG(1) << "Socket did not have expected address size ("
|
|
133
|
-
<< (addr.ss_family == AF_INET ? sizeof(sockaddr_in)
|
|
134
|
-
: sizeof(sockaddr_in6))
|
|
135
|
-
<< "), had: " << addr_len;
|
|
136
|
-
return absl::UnimplementedError("Unhandled address size.");
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return QuicSocketAddress(addr);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
absl::StatusOr<SocketFd> CreateSocketWithFlags(IpAddressFamily address_family,
|
|
143
|
-
SocketProtocol protocol,
|
|
144
|
-
int flags) {
|
|
145
|
-
int address_family_int = ToPlatformAddressFamily(address_family);
|
|
146
|
-
|
|
147
|
-
int type_int = ToPlatformSocketType(protocol);
|
|
148
|
-
type_int |= flags;
|
|
149
|
-
|
|
150
|
-
int protocol_int = ToPlatformProtocol(protocol);
|
|
151
|
-
|
|
152
|
-
SocketFd fd;
|
|
153
|
-
do {
|
|
154
|
-
fd = ::socket(address_family_int, type_int, protocol_int);
|
|
155
|
-
} while (fd < 0 && errno == EINTR);
|
|
156
|
-
|
|
157
|
-
if (fd >= 0) {
|
|
158
|
-
return fd;
|
|
159
|
-
} else {
|
|
160
|
-
absl::Status status = ToStatus(errno, "::socket()");
|
|
161
|
-
QUICHE_LOG_FIRST_N(ERROR, 100)
|
|
162
|
-
<< "Failed to create socket with error: " << status;
|
|
163
|
-
return status;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
absl::StatusOr<AcceptResult> AcceptInternal(SocketFd fd) {
|
|
168
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
169
|
-
|
|
170
|
-
sockaddr_storage peer_addr;
|
|
171
|
-
socklen_t peer_addr_len = sizeof(peer_addr);
|
|
172
|
-
SocketFd connection_socket;
|
|
173
|
-
do {
|
|
174
|
-
connection_socket = ::accept(
|
|
175
|
-
fd, reinterpret_cast<struct sockaddr*>(&peer_addr), &peer_addr_len);
|
|
176
|
-
} while (connection_socket < 0 && errno == EINTR);
|
|
177
|
-
|
|
178
|
-
if (connection_socket < 0) {
|
|
179
|
-
absl::Status status = ToStatus(errno, "::accept()");
|
|
180
|
-
QUICHE_DVLOG(1) << "Failed to accept connection from socket " << fd
|
|
181
|
-
<< " with error: " << status;
|
|
182
|
-
return status;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
absl::StatusOr<QuicSocketAddress> peer_address =
|
|
186
|
-
ValidateAndConvertAddress(peer_addr, peer_addr_len);
|
|
187
|
-
|
|
188
|
-
if (peer_address.ok()) {
|
|
189
|
-
return AcceptResult{connection_socket, peer_address.value()};
|
|
190
|
-
} else {
|
|
191
|
-
return peer_address.status();
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
#if defined(__linux__) && defined(SOCK_NONBLOCK)
|
|
196
|
-
absl::StatusOr<AcceptResult> AcceptWithFlags(SocketFd fd, int flags) {
|
|
197
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
198
|
-
|
|
199
|
-
sockaddr_storage peer_addr;
|
|
200
|
-
socklen_t peer_addr_len = sizeof(peer_addr);
|
|
201
|
-
SocketFd connection_socket;
|
|
202
|
-
do {
|
|
203
|
-
connection_socket =
|
|
204
|
-
::accept4(fd, reinterpret_cast<struct sockaddr*>(&peer_addr),
|
|
205
|
-
&peer_addr_len, flags);
|
|
206
|
-
} while (connection_socket < 0 && errno == EINTR);
|
|
207
|
-
|
|
208
|
-
if (connection_socket < 0) {
|
|
209
|
-
absl::Status status = ToStatus(errno, "::accept4()");
|
|
210
|
-
QUICHE_DVLOG(1) << "Failed to accept connection from socket " << fd
|
|
211
|
-
<< " with error: " << status;
|
|
212
|
-
return status;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
absl::StatusOr<QuicSocketAddress> peer_address =
|
|
216
|
-
ValidateAndConvertAddress(peer_addr, peer_addr_len);
|
|
217
|
-
|
|
218
|
-
if (peer_address.ok()) {
|
|
219
|
-
return AcceptResult{connection_socket, peer_address.value()};
|
|
220
|
-
} else {
|
|
221
|
-
return peer_address.status();
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
#endif // defined(__linux__) && defined(SOCK_NONBLOCK)
|
|
225
|
-
|
|
226
|
-
socklen_t GetAddrlen(IpAddressFamily family) {
|
|
227
|
-
switch (family) {
|
|
228
|
-
case IpAddressFamily::IP_V4:
|
|
229
|
-
return sizeof(sockaddr_in);
|
|
230
|
-
case IpAddressFamily::IP_V6:
|
|
231
|
-
return sizeof(sockaddr_in6);
|
|
232
|
-
default:
|
|
233
|
-
QUICHE_NOTREACHED();
|
|
234
|
-
return 0;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
absl::Status SetSockOptInt(SocketFd fd, int option, int value) {
|
|
239
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
240
|
-
|
|
241
|
-
int result;
|
|
242
|
-
do {
|
|
243
|
-
result = ::setsockopt(fd, SOL_SOCKET, option,reinterpret_cast<const char *>(&value), sizeof(value));
|
|
244
|
-
} while (result < 0 && errno == EINTR);
|
|
245
|
-
|
|
246
|
-
if (result >= 0) {
|
|
247
|
-
return absl::OkStatus();
|
|
248
|
-
} else {
|
|
249
|
-
absl::Status status = ToStatus(errno, "::setsockopt()");
|
|
250
|
-
QUICHE_DVLOG(1) << "Failed to set socket " << fd << " option " << option
|
|
251
|
-
<< " to " << value << " with error: " << status;
|
|
252
|
-
return status;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
} // namespace
|
|
257
|
-
|
|
258
|
-
absl::StatusOr<SocketFd> CreateSocket(IpAddressFamily address_family,
|
|
259
|
-
SocketProtocol protocol, bool blocking) {
|
|
260
|
-
int flags = 0;
|
|
261
|
-
#if defined(__linux__) && defined(SOCK_NONBLOCK)
|
|
262
|
-
if (!blocking) {
|
|
263
|
-
flags = SOCK_NONBLOCK;
|
|
264
|
-
}
|
|
265
|
-
#endif
|
|
266
|
-
|
|
267
|
-
absl::StatusOr<SocketFd> socket =
|
|
268
|
-
CreateSocketWithFlags(address_family, protocol, flags);
|
|
269
|
-
if (!socket.ok() || blocking) {
|
|
270
|
-
return socket;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
#if !defined(__linux__) || !defined(SOCK_NONBLOCK)
|
|
274
|
-
// If non-blocking could not be set directly on socket creation, need to do
|
|
275
|
-
// it now.
|
|
276
|
-
absl::Status set_non_blocking_result =
|
|
277
|
-
SetSocketBlocking(socket.value(), /*blocking=*/false);
|
|
278
|
-
if (!set_non_blocking_result.ok()) {
|
|
279
|
-
QUICHE_LOG_FIRST_N(ERROR, 100) << "Failed to set socket " << socket.value()
|
|
280
|
-
<< " as non-blocking on creation.";
|
|
281
|
-
if (!Close(socket.value()).ok()) {
|
|
282
|
-
QUICHE_LOG_FIRST_N(ERROR, 100)
|
|
283
|
-
<< "Failed to close socket " << socket.value()
|
|
284
|
-
<< " after set-non-blocking error on creation.";
|
|
285
|
-
}
|
|
286
|
-
return set_non_blocking_result;
|
|
287
|
-
}
|
|
288
|
-
#endif
|
|
289
|
-
|
|
290
|
-
return socket;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
absl::Status SetSocketBlocking(SocketFd fd, bool blocking) {
|
|
294
|
-
if (blocking) {
|
|
295
|
-
return SetSocketMode(fd, 0);
|
|
296
|
-
} else {
|
|
297
|
-
return SetSocketMode(fd, 1);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
absl::Status SetReceiveBufferSize(SocketFd fd, QuicByteCount size) {
|
|
302
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
303
|
-
QUICHE_DCHECK_LE(size, QuicByteCount{INT_MAX});
|
|
304
|
-
|
|
305
|
-
return SetSockOptInt(fd, SO_RCVBUF, static_cast<int>(size));
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
absl::Status SetSendBufferSize(SocketFd fd, QuicByteCount size) {
|
|
309
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
310
|
-
QUICHE_DCHECK_LE(size, QuicByteCount{INT_MAX});
|
|
311
|
-
|
|
312
|
-
return SetSockOptInt(fd, SO_SNDBUF, static_cast<int>(size));
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
absl::Status Connect(SocketFd fd, const QuicSocketAddress& peer_address) {
|
|
316
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
317
|
-
QUICHE_DCHECK(peer_address.IsInitialized());
|
|
318
|
-
|
|
319
|
-
sockaddr_storage addr = peer_address.generic_address();
|
|
320
|
-
socklen_t addrlen = GetAddrlen(peer_address.host().address_family());
|
|
321
|
-
|
|
322
|
-
int connect_result;
|
|
323
|
-
do {
|
|
324
|
-
connect_result = ::connect(fd, reinterpret_cast<sockaddr*>(&addr), addrlen);
|
|
325
|
-
} while (connect_result < 0 && errno == EINTR);
|
|
326
|
-
|
|
327
|
-
if (connect_result >= 0) {
|
|
328
|
-
return absl::OkStatus();
|
|
329
|
-
} else {
|
|
330
|
-
// For ::connect(), only `EINPROGRESS` indicates unavailable.
|
|
331
|
-
absl::Status status =
|
|
332
|
-
ToStatus(errno, "::connect()", /*unavailable_error_numbers=*/
|
|
333
|
-
{EINPROGRESS});
|
|
334
|
-
QUICHE_DVLOG(1) << "Failed to connect socket " << fd
|
|
335
|
-
<< " to address: " << peer_address.ToString()
|
|
336
|
-
<< " with error: " << status;
|
|
337
|
-
return status;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
absl::Status GetSocketError(SocketFd fd) {
|
|
342
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
343
|
-
|
|
344
|
-
int socket_error = 0;
|
|
345
|
-
socklen_t len = sizeof(socket_error);
|
|
346
|
-
int sockopt_result;
|
|
347
|
-
do {
|
|
348
|
-
sockopt_result =
|
|
349
|
-
::getsockopt(fd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char *> (&socket_error), &len);
|
|
350
|
-
} while (sockopt_result < 0 && errno == EINTR);
|
|
351
|
-
|
|
352
|
-
if (sockopt_result >= 0) {
|
|
353
|
-
if (socket_error == 0) {
|
|
354
|
-
return absl::OkStatus();
|
|
355
|
-
} else {
|
|
356
|
-
return ToStatus(socket_error, "SO_ERROR");
|
|
357
|
-
}
|
|
358
|
-
} else {
|
|
359
|
-
absl::Status status = ToStatus(errno, "::getsockopt()");
|
|
360
|
-
QUICHE_LOG_FIRST_N(ERROR, 100)
|
|
361
|
-
<< "Failed to get socket error information from socket " << fd
|
|
362
|
-
<< " with error: " << status;
|
|
363
|
-
return status;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
absl::Status Bind(SocketFd fd, const QuicSocketAddress& address) {
|
|
368
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
369
|
-
QUICHE_DCHECK(address.IsInitialized());
|
|
370
|
-
|
|
371
|
-
sockaddr_storage addr = address.generic_address();
|
|
372
|
-
socklen_t addr_len = GetAddrlen(address.host().address_family());
|
|
373
|
-
|
|
374
|
-
int result;
|
|
375
|
-
do {
|
|
376
|
-
result = ::bind(fd, reinterpret_cast<sockaddr*>(&addr), addr_len);
|
|
377
|
-
} while (result < 0 && errno == EINTR);
|
|
378
|
-
|
|
379
|
-
if (result >= 0) {
|
|
380
|
-
return absl::OkStatus();
|
|
381
|
-
} else {
|
|
382
|
-
absl::Status status = ToStatus(errno, "::bind()");
|
|
383
|
-
QUICHE_DVLOG(1) << "Failed to bind socket " << fd
|
|
384
|
-
<< " to address: " << address.ToString()
|
|
385
|
-
<< " with error: " << status;
|
|
386
|
-
return status;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
absl::StatusOr<QuicSocketAddress> GetSocketAddress(SocketFd fd) {
|
|
391
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
392
|
-
|
|
393
|
-
sockaddr_storage addr;
|
|
394
|
-
socklen_t addr_len = sizeof(addr);
|
|
395
|
-
|
|
396
|
-
int result;
|
|
397
|
-
do {
|
|
398
|
-
result = ::getsockname(fd, reinterpret_cast<sockaddr*>(&addr), &addr_len);
|
|
399
|
-
} while (result < 0 && errno == EINTR);
|
|
400
|
-
|
|
401
|
-
if (result >= 0) {
|
|
402
|
-
return ValidateAndConvertAddress(addr, addr_len);
|
|
403
|
-
} else {
|
|
404
|
-
absl::Status status = ToStatus(errno, "::getsockname()");
|
|
405
|
-
QUICHE_DVLOG(1) << "Failed to get socket " << fd
|
|
406
|
-
<< " name with error: " << status;
|
|
407
|
-
return status;
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
absl::Status Listen(SocketFd fd, int backlog) {
|
|
412
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
413
|
-
QUICHE_DCHECK_GT(backlog, 0);
|
|
414
|
-
|
|
415
|
-
int result;
|
|
416
|
-
do {
|
|
417
|
-
result = ::listen(fd, backlog);
|
|
418
|
-
} while (result < 0 && errno == EINTR);
|
|
419
|
-
|
|
420
|
-
if (result >= 0) {
|
|
421
|
-
return absl::OkStatus();
|
|
422
|
-
} else {
|
|
423
|
-
absl::Status status = ToStatus(errno, "::listen()");
|
|
424
|
-
QUICHE_DVLOG(1) << "Failed to mark socket: " << fd
|
|
425
|
-
<< " to listen with error :" << status;
|
|
426
|
-
return status;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
absl::StatusOr<AcceptResult> Accept(SocketFd fd, bool blocking) {
|
|
431
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
432
|
-
|
|
433
|
-
#if defined(__linux__) && defined(SOCK_NONBLOCK)
|
|
434
|
-
if (!blocking) {
|
|
435
|
-
return AcceptWithFlags(fd, SOCK_NONBLOCK);
|
|
436
|
-
}
|
|
437
|
-
#endif
|
|
438
|
-
|
|
439
|
-
absl::StatusOr<AcceptResult> accept_result = AcceptInternal(fd);
|
|
440
|
-
if (!accept_result.ok() || blocking) {
|
|
441
|
-
return accept_result;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
#if !defined(__linux__) || !defined(SOCK_NONBLOCK)
|
|
445
|
-
// If non-blocking could not be set directly on socket acceptance, need to
|
|
446
|
-
// do it now.
|
|
447
|
-
absl::Status set_non_blocking_result =
|
|
448
|
-
SetSocketBlocking(accept_result.value().fd, /*blocking=*/false);
|
|
449
|
-
if (!set_non_blocking_result.ok()) {
|
|
450
|
-
QUICHE_LOG_FIRST_N(ERROR, 100)
|
|
451
|
-
<< "Failed to set socket " << fd << " as non-blocking on acceptance.";
|
|
452
|
-
if (!Close(accept_result.value().fd).ok()) {
|
|
453
|
-
QUICHE_LOG_FIRST_N(ERROR, 100)
|
|
454
|
-
<< "Failed to close socket " << accept_result.value().fd
|
|
455
|
-
<< " after error setting non-blocking on acceptance.";
|
|
456
|
-
}
|
|
457
|
-
return set_non_blocking_result;
|
|
458
|
-
}
|
|
459
|
-
#endif
|
|
460
|
-
|
|
461
|
-
return accept_result;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
absl::StatusOr<absl::Span<char>> Receive(SocketFd fd, absl::Span<char> buffer,
|
|
465
|
-
bool peek) {
|
|
466
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
467
|
-
QUICHE_DCHECK(!buffer.empty());
|
|
468
|
-
|
|
469
|
-
SSIZE_T num_read;
|
|
470
|
-
do {
|
|
471
|
-
num_read =
|
|
472
|
-
::recv(fd, buffer.data(), buffer.size(), /*flags=*/peek ? MSG_PEEK : 0);
|
|
473
|
-
} while (num_read < 0 && errno == EINTR);
|
|
474
|
-
|
|
475
|
-
if (num_read > 0 && static_cast<size_t>(num_read) > buffer.size()) {
|
|
476
|
-
QUICHE_LOG_FIRST_N(WARNING, 100)
|
|
477
|
-
<< "Received more bytes (" << num_read << ") from socket " << fd
|
|
478
|
-
<< " than buffer size (" << buffer.size() << ").";
|
|
479
|
-
return absl::OutOfRangeError(
|
|
480
|
-
"::recv(): Received more bytes than buffer size.");
|
|
481
|
-
} else if (num_read >= 0) {
|
|
482
|
-
return buffer.subspan(0, num_read);
|
|
483
|
-
} else {
|
|
484
|
-
absl::Status status = ToStatus(errno, "::recv()");
|
|
485
|
-
QUICHE_DVLOG(1) << "Failed to receive from socket: " << fd
|
|
486
|
-
<< " with error: " << status;
|
|
487
|
-
return status;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
absl::StatusOr<absl::string_view> Send(SocketFd fd, absl::string_view buffer) {
|
|
492
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
493
|
-
QUICHE_DCHECK(!buffer.empty());
|
|
494
|
-
|
|
495
|
-
SSIZE_T num_sent;
|
|
496
|
-
do {
|
|
497
|
-
num_sent = ::send(fd, buffer.data(), buffer.size(), /*flags=*/0);
|
|
498
|
-
} while (num_sent < 0 && errno == EINTR);
|
|
499
|
-
|
|
500
|
-
if (num_sent > 0 && static_cast<size_t>(num_sent) > buffer.size()) {
|
|
501
|
-
QUICHE_LOG_FIRST_N(WARNING, 100)
|
|
502
|
-
<< "Sent more bytes (" << num_sent << ") to socket " << fd
|
|
503
|
-
<< " than buffer size (" << buffer.size() << ").";
|
|
504
|
-
return absl::OutOfRangeError("::send(): Sent more bytes than buffer size.");
|
|
505
|
-
} else if (num_sent >= 0) {
|
|
506
|
-
return buffer.substr(num_sent);
|
|
507
|
-
} else {
|
|
508
|
-
absl::Status status = ToStatus(errno, "::send()");
|
|
509
|
-
QUICHE_DVLOG(1) << "Failed to send to socket: " << fd
|
|
510
|
-
<< " with error: " << status;
|
|
511
|
-
return status;
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
absl::Status Close(SocketFd fd) {
|
|
516
|
-
QUICHE_DCHECK_GE(fd, 0);
|
|
517
|
-
|
|
518
|
-
int close_result = ::closesocket(fd);
|
|
519
|
-
|
|
520
|
-
if (close_result >= 0) {
|
|
521
|
-
return absl::OkStatus();
|
|
522
|
-
} else if (errno == EINTR) {
|
|
523
|
-
// Ignore EINTR on close because the socket is left in an undefined state
|
|
524
|
-
// and can't be acted on again.
|
|
525
|
-
QUICHE_DVLOG(1) << "Socket " << fd << " close unspecified due to EINTR.";
|
|
526
|
-
return absl::OkStatus();
|
|
527
|
-
} else {
|
|
528
|
-
absl::Status status = ToStatus(errno, "::close()");
|
|
529
|
-
QUICHE_DVLOG(1) << "Failed to close socket: " << fd
|
|
530
|
-
<< " with error: " << status;
|
|
531
|
-
return status;
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
} // namespace quic::socket_api
|