blob: b6c58cdb1d36664ef2185250f26e59d709267186 [file] [log] [blame]
wubcfddec82020-01-13 07:45:27 -08001// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/third_party/quiche/src/quic/core/quic_udp_socket.h"
6#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
7#include "net/third_party/quiche/src/quic/platform/api/quic_udp_socket_platform_api.h"
8
9#include <arpa/inet.h>
10#include <fcntl.h>
11#include <netinet/in.h>
12#include <sys/select.h>
13#include <sys/socket.h>
14#include <sys/types.h>
15
16#if defined(__APPLE__) && !defined(__APPLE_USE_RFC_3542)
17#error "__APPLE_USE_RFC_3542 needs to be defined."
18#endif
19
20#if defined(__linux__)
21#include <alloca.h>
22// For SO_TIMESTAMPING.
23#include <linux/net_tstamp.h>
24#endif
25
26#if defined(__linux__) && !defined(__ANDROID__)
27#define QUIC_UDP_SOCKET_SUPPORT_TTL 1
28#endif
29
30namespace quic {
31namespace {
wuba27a3c92020-01-28 08:43:21 -080032
33#if defined(__linux__) && (!defined(__ANDROID_API__) || __ANDROID_API__ >= 21)
34#define QUIC_UDP_SOCKET_SUPPORT_LINUX_TIMESTAMPING 1
35// This is the structure that SO_TIMESTAMPING fills into the cmsg header.
36// It is well-defined, but does not have a definition in a public header.
37// See https://www.kernel.org/doc/Documentation/networking/timestamping.txt
38// for more information.
39struct LinuxSoTimestamping {
40 // The converted system time of the timestamp.
41 struct timespec systime;
42 // Deprecated; serves only as padding.
43 struct timespec hwtimetrans;
44 // The raw hardware timestamp.
45 struct timespec hwtimeraw;
46};
47const size_t kCmsgSpaceForRecvTimestamp =
48 CMSG_SPACE(sizeof(LinuxSoTimestamping));
49#else
50const size_t kCmsgSpaceForRecvTimestamp = 0;
51#endif
52
53const size_t kMinCmsgSpaceForRead =
54 CMSG_SPACE(sizeof(uint32_t)) // Dropped packet count
55 + CMSG_SPACE(sizeof(in_pktinfo)) // V4 Self IP
56 + CMSG_SPACE(sizeof(in6_pktinfo)) // V6 Self IP
57 + kCmsgSpaceForRecvTimestamp + CMSG_SPACE(sizeof(int)) // TTL
58 + kCmsgSpaceForGooglePacketHeader;
59
wubcfddec82020-01-13 07:45:27 -080060QuicUdpSocketFd CreateNonblockingSocket(int address_family) {
61#if defined(__linux__) && defined(SOCK_NONBLOCK)
62
63 // Create a nonblocking socket directly.
64 int fd = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
65 if (fd < 0) {
66 QUIC_LOG_FIRST_N(ERROR, 100)
67 << "socket() failed with address_family=" << address_family << ": "
68 << strerror(errno);
69 return kQuicInvalidSocketFd;
70 }
71
72 return fd;
73
74#else
75
76 // Create a socket and use fcntl to set it to nonblocking.
77 // This implementation is used when building for iOS, OSX and old versions of
78 // Linux (< 2.6.27) and old versions of Android (< API 21).
79 int fd = socket(address_family, SOCK_DGRAM, IPPROTO_UDP);
80 if (fd < 0) {
81 QUIC_LOG_FIRST_N(ERROR, 100)
82 << "socket() failed with address_family=" << address_family << ": "
83 << strerror(errno);
84 return kQuicInvalidSocketFd;
85 }
86 int current_flags = fcntl(fd, F_GETFL, 0);
87 if (current_flags == -1) {
88 QUIC_LOG_FIRST_N(ERROR, 100)
89 << "failed to get current socket flags: " << strerror(errno);
90 close(fd);
91 return kQuicInvalidSocketFd;
92 }
93
94 int rc = fcntl(fd, F_SETFL, current_flags | O_NONBLOCK);
95 if (rc == -1) {
96 QUIC_LOG_FIRST_N(ERROR, 100)
97 << "failed to set socket to non-blocking: " << strerror(errno);
98 close(fd);
99 return kQuicInvalidSocketFd;
100 }
101
102 return fd;
103
104#endif
105} // End CreateNonblockingSocket
106
107void SetV4SelfIpInControlMessage(const QuicIpAddress& self_address,
108 cmsghdr* cmsg) {
109 DCHECK(self_address.IsIPv4());
110 in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
111 memset(pktinfo, 0, sizeof(in_pktinfo));
112 pktinfo->ipi_ifindex = 0;
113 std::string address_string = self_address.ToPackedString();
114 memcpy(&pktinfo->ipi_spec_dst, address_string.c_str(),
115 address_string.length());
116}
117
118void SetV6SelfIpInControlMessage(const QuicIpAddress& self_address,
119 cmsghdr* cmsg) {
120 DCHECK(self_address.IsIPv6());
121 in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
122 memset(pktinfo, 0, sizeof(in6_pktinfo));
123 std::string address_string = self_address.ToPackedString();
124 memcpy(&pktinfo->ipi6_addr, address_string.c_str(), address_string.length());
125}
126
127void PopulatePacketInfoFromControlMessage(struct cmsghdr* cmsg,
128 QuicUdpPacketInfo* packet_info,
129 BitMask64 packet_info_interested) {
130#if defined(__linux__) && defined(SO_RXQ_OVFL)
131 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_RXQ_OVFL) {
132 if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::DROPPED_PACKETS)) {
133 packet_info->SetDroppedPackets(
134 *(reinterpret_cast<uint32_t*> CMSG_DATA(cmsg)));
135 }
136 return;
137 }
138#endif
139
wuba27a3c92020-01-28 08:43:21 -0800140#if defined(QUIC_UDP_SOCKET_SUPPORT_LINUX_TIMESTAMPING)
wubcfddec82020-01-13 07:45:27 -0800141 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMPING) {
wubcfddec82020-01-13 07:45:27 -0800142 if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::RECV_TIMESTAMP)) {
wuba27a3c92020-01-28 08:43:21 -0800143 LinuxSoTimestamping* linux_ts =
144 reinterpret_cast<LinuxSoTimestamping*>(CMSG_DATA(cmsg));
wubcfddec82020-01-13 07:45:27 -0800145 timespec* ts = &linux_ts->systime;
146 int64_t usec = (static_cast<int64_t>(ts->tv_sec) * 1000 * 1000) +
147 (static_cast<int64_t>(ts->tv_nsec) / 1000);
148 packet_info->SetReceiveTimestamp(
149 QuicWallTime::FromUNIXMicroseconds(usec));
150 }
151 return;
152 }
153#endif
154
155 if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
156 if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::V6_SELF_IP)) {
157 const in6_pktinfo* info = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
158 const char* addr_data = reinterpret_cast<const char*>(&info->ipi6_addr);
159 int addr_len = sizeof(in6_addr);
160 QuicIpAddress self_v6_ip;
161 if (self_v6_ip.FromPackedString(addr_data, addr_len)) {
162 packet_info->SetSelfV6Ip(self_v6_ip);
163 } else {
164 QUIC_BUG << "QuicIpAddress::FromPackedString failed";
165 }
166 }
167 return;
168 }
169
170 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
171 if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::V4_SELF_IP)) {
172 const in_pktinfo* info = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
173 const char* addr_data = reinterpret_cast<const char*>(&info->ipi_addr);
174 int addr_len = sizeof(in_addr);
175 QuicIpAddress self_v4_ip;
176 if (self_v4_ip.FromPackedString(addr_data, addr_len)) {
177 packet_info->SetSelfV4Ip(self_v4_ip);
178 } else {
179 QUIC_BUG << "QuicIpAddress::FromPackedString failed";
180 }
181 }
182 return;
183 }
184
185 if ((cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) ||
186 (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT)) {
187 if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::TTL)) {
188 packet_info->SetTtl(*(reinterpret_cast<int*>(CMSG_DATA(cmsg))));
189 }
190 return;
191 }
192
193 if (packet_info_interested.IsSet(
194 QuicUdpPacketInfoBit::GOOGLE_PACKET_HEADER)) {
195 BufferSpan google_packet_headers;
196 if (GetGooglePacketHeadersFromControlMessage(
197 cmsg, &google_packet_headers.buffer,
198 &google_packet_headers.buffer_len)) {
199 packet_info->SetGooglePacketHeaders(google_packet_headers);
200 }
201 }
202}
203
204bool NextCmsg(msghdr* hdr,
205 char* control_buffer,
206 size_t control_buffer_len,
207 int cmsg_level,
208 int cmsg_type,
209 size_t data_size,
210 cmsghdr** cmsg /*in, out*/) {
211 // msg_controllen needs to be increased first, otherwise CMSG_NXTHDR will
212 // return nullptr.
213 hdr->msg_controllen += CMSG_SPACE(data_size);
214 if (hdr->msg_controllen > control_buffer_len) {
215 return false;
216 }
217
218 if ((*cmsg) == nullptr) {
219 DCHECK_EQ(nullptr, hdr->msg_control);
220 memset(control_buffer, 0, control_buffer_len);
221 hdr->msg_control = control_buffer;
222 (*cmsg) = CMSG_FIRSTHDR(hdr);
223 } else {
224 DCHECK_NE(nullptr, hdr->msg_control);
225 (*cmsg) = CMSG_NXTHDR(hdr, (*cmsg));
226 }
227
228 if (nullptr == (*cmsg)) {
229 return false;
230 }
231
232 (*cmsg)->cmsg_len = CMSG_LEN(data_size);
233 (*cmsg)->cmsg_level = cmsg_level;
234 (*cmsg)->cmsg_type = cmsg_type;
235
236 return true;
237}
238} // namespace
239
240QuicUdpSocketFd QuicUdpSocketApi::Create(int address_family,
241 int receive_buffer_size,
242 int send_buffer_size) {
wuba27a3c92020-01-28 08:43:21 -0800243 // DCHECK here so the program exits early(before reading packets) in debug
244 // mode. This should have been a static_assert, however it can't be done on
245 // ios/osx because CMSG_SPACE isn't a constant expression there.
246 DCHECK_GE(kDefaultUdpPacketControlBufferSize, kMinCmsgSpaceForRead);
wubcfddec82020-01-13 07:45:27 -0800247 QuicUdpSocketFd fd = CreateNonblockingSocket(address_family);
248
249 if (fd == kQuicInvalidSocketFd) {
250 return kQuicInvalidSocketFd;
251 }
252
253 if (!SetupSocket(fd, address_family, receive_buffer_size, send_buffer_size)) {
254 Destroy(fd);
255 return kQuicInvalidSocketFd;
256 }
257
258 return fd;
259}
260
261bool QuicUdpSocketApi::SetupSocket(QuicUdpSocketFd fd,
262 int address_family,
263 int receive_buffer_size,
264 int send_buffer_size) {
265 // Receive buffer size.
266 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &receive_buffer_size,
267 sizeof(receive_buffer_size)) != 0) {
268 QUIC_LOG_FIRST_N(ERROR, 100) << "Failed to set socket recv size";
269 return false;
270 }
271
272 // Send buffer size.
273 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &send_buffer_size,
274 sizeof(send_buffer_size)) != 0) {
275 QUIC_LOG_FIRST_N(ERROR, 100) << "Failed to set socket send size";
276 return false;
277 }
278
279 if (!EnableReceiveSelfIpAddressForV4(fd)) {
280 QUIC_LOG_FIRST_N(ERROR, 100) << "Failed to enable receiving of self v4 ip";
281 return false;
282 }
283
284 if (address_family == AF_INET6 && !EnableReceiveSelfIpAddressForV6(fd)) {
285 QUIC_LOG_FIRST_N(ERROR, 100) << "Failed to enable receiving of self v6 ip";
286 return false;
287 }
288
289 return true;
290}
291
292void QuicUdpSocketApi::Destroy(QuicUdpSocketFd fd) {
293 if (fd != kQuicInvalidSocketFd) {
294 close(fd);
295 }
296}
297
298bool QuicUdpSocketApi::Bind(QuicUdpSocketFd fd, QuicSocketAddress address) {
299 sockaddr_storage addr = address.generic_address();
300 int addr_len =
301 address.host().IsIPv4() ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
302 return 0 == bind(fd, reinterpret_cast<sockaddr*>(&addr), addr_len);
303}
304
305bool QuicUdpSocketApi::EnableDroppedPacketCount(QuicUdpSocketFd fd) {
306#if defined(__linux__) && defined(SO_RXQ_OVFL)
307 int get_overflow = 1;
308 return 0 == setsockopt(fd, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow,
309 sizeof(get_overflow));
310#else
311 (void)fd;
312 return false;
313#endif
314}
315
316bool QuicUdpSocketApi::EnableReceiveSelfIpAddressForV4(QuicUdpSocketFd fd) {
317 int get_self_ip = 1;
318 return 0 == setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_self_ip,
319 sizeof(get_self_ip));
320}
321
322bool QuicUdpSocketApi::EnableReceiveSelfIpAddressForV6(QuicUdpSocketFd fd) {
323 int get_self_ip = 1;
324 return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_self_ip,
325 sizeof(get_self_ip));
326}
327
328bool QuicUdpSocketApi::EnableReceiveTimestamp(QuicUdpSocketFd fd) {
329#if defined(__linux__) && (!defined(__ANDROID_API__) || __ANDROID_API__ >= 21)
330 int timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE;
331 return 0 == setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &timestamping,
332 sizeof(timestamping));
333#else
334 (void)fd;
335 return false;
336#endif
337}
338
339bool QuicUdpSocketApi::EnableReceiveTtlForV4(QuicUdpSocketFd fd) {
340#if defined(QUIC_UDP_SOCKET_SUPPORT_TTL)
341 int get_ttl = 1;
342 return 0 == setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &get_ttl, sizeof(get_ttl));
343#else
344 (void)fd;
345 return false;
346#endif
347}
348
349bool QuicUdpSocketApi::EnableReceiveTtlForV6(QuicUdpSocketFd fd) {
350#if defined(QUIC_UDP_SOCKET_SUPPORT_TTL)
351 int get_ttl = 1;
352 return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &get_ttl,
353 sizeof(get_ttl));
354#else
355 (void)fd;
356 return false;
357#endif
358}
359
360bool QuicUdpSocketApi::WaitUntilReadable(QuicUdpSocketFd fd,
361 QuicTime::Delta timeout) {
362 fd_set read_fds;
363 FD_ZERO(&read_fds);
364 FD_SET(fd, &read_fds);
365
366 timeval select_timeout;
367 select_timeout.tv_sec = timeout.ToSeconds();
368 select_timeout.tv_usec = timeout.ToMicroseconds() % 1000000;
369
370 return 1 == select(1 + fd, &read_fds, nullptr, nullptr, &select_timeout);
371}
372
373void QuicUdpSocketApi::ReadPacket(QuicUdpSocketFd fd,
374 BitMask64 packet_info_interested,
375 ReadPacketResult* result) {
376 result->ok = false;
377 BufferSpan& packet_buffer = result->packet_buffer;
378 BufferSpan& control_buffer = result->control_buffer;
379 QuicUdpPacketInfo* packet_info = &result->packet_info;
380
wuba27a3c92020-01-28 08:43:21 -0800381 DCHECK_GE(control_buffer.buffer_len, kMinCmsgSpaceForRead);
382
wubcfddec82020-01-13 07:45:27 -0800383 struct iovec iov = {packet_buffer.buffer, packet_buffer.buffer_len};
384 struct sockaddr_storage raw_peer_address;
385
386 if (control_buffer.buffer_len > 0) {
387 reinterpret_cast<struct cmsghdr*>(control_buffer.buffer)->cmsg_len =
388 control_buffer.buffer_len;
389 }
390
391 msghdr hdr;
392 hdr.msg_name = &raw_peer_address;
393 hdr.msg_namelen = sizeof(raw_peer_address);
394 hdr.msg_iov = &iov;
395 hdr.msg_iovlen = 1;
396 hdr.msg_flags = 0;
397 hdr.msg_control = control_buffer.buffer;
398 hdr.msg_controllen = control_buffer.buffer_len;
399
wub40d77962020-01-22 09:28:14 -0800400#if defined(__linux__)
wubcfddec82020-01-13 07:45:27 -0800401 // If MSG_TRUNC is set on Linux, recvmsg will return the real packet size even
402 // if |packet_buffer| is too small to receive it.
403 int flags = MSG_TRUNC;
404#else
405 int flags = 0;
406#endif
407
408 int bytes_read = recvmsg(fd, &hdr, flags);
409 if (bytes_read < 0) {
410 const int error_num = errno;
411 if (error_num != EAGAIN) {
412 QUIC_LOG_FIRST_N(ERROR, 100)
413 << "Error reading packet: " << strerror(error_num);
414 }
415 return;
416 }
417
418 if (QUIC_PREDICT_FALSE(hdr.msg_flags & MSG_CTRUNC)) {
419 QUIC_BUG << "Control buffer too small. size:" << control_buffer.buffer_len;
420 return;
421 }
422
wub40d77962020-01-22 09:28:14 -0800423 if (QUIC_PREDICT_FALSE(hdr.msg_flags & MSG_TRUNC) ||
424 // Normally "bytes_read > packet_buffer.buffer_len" implies the MSG_TRUNC
425 // bit is set, but it is not the case if tested with config=android_arm64.
426 static_cast<size_t>(bytes_read) > packet_buffer.buffer_len) {
wubcfddec82020-01-13 07:45:27 -0800427 QUIC_LOG_FIRST_N(WARNING, 100)
428 << "Received truncated QUIC packet: buffer size:"
429 << packet_buffer.buffer_len << " packet size:" << bytes_read;
430 return;
431 }
432
433 packet_buffer.buffer_len = bytes_read;
434 if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::PEER_ADDRESS)) {
435 packet_info->SetPeerAddress(QuicSocketAddress(raw_peer_address));
436 }
437
438 if (hdr.msg_controllen > 0) {
439 for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr); cmsg != nullptr;
440 cmsg = CMSG_NXTHDR(&hdr, cmsg)) {
441 BitMask64 prior_bitmask = packet_info->bitmask();
442 PopulatePacketInfoFromControlMessage(cmsg, packet_info,
443 packet_info_interested);
444 if (packet_info->bitmask() == prior_bitmask) {
445 QUIC_DLOG(INFO) << "Ignored cmsg_level:" << cmsg->cmsg_level
446 << ", cmsg_type:" << cmsg->cmsg_type;
447 }
448 }
449 }
450
451 result->ok = true;
452}
453
454size_t QuicUdpSocketApi::ReadMultiplePackets(QuicUdpSocketFd fd,
455 BitMask64 packet_info_interested,
456 ReadPacketResults* results) {
457#if defined(__linux__) && !defined(__ANDROID__)
458 // Use recvmmsg.
459 size_t hdrs_size = sizeof(mmsghdr) * results->size();
460 mmsghdr* hdrs = static_cast<mmsghdr*>(alloca(hdrs_size));
461 memset(hdrs, 0, hdrs_size);
462
463 struct TempPerPacketData {
464 iovec iov;
465 sockaddr_storage raw_peer_address;
466 };
467 TempPerPacketData* packet_data_array = static_cast<TempPerPacketData*>(
468 alloca(sizeof(TempPerPacketData) * results->size()));
469
470 for (size_t i = 0; i < results->size(); ++i) {
471 (*results)[i].ok = false;
472
473 msghdr* hdr = &hdrs[i].msg_hdr;
474 TempPerPacketData* packet_data = &packet_data_array[i];
475 packet_data->iov.iov_base = (*results)[i].packet_buffer.buffer;
476 packet_data->iov.iov_len = (*results)[i].packet_buffer.buffer_len;
477
478 hdr->msg_name = &packet_data->raw_peer_address;
479 hdr->msg_namelen = sizeof(sockaddr_storage);
480 hdr->msg_iov = &packet_data->iov;
481 hdr->msg_iovlen = 1;
482 hdr->msg_flags = 0;
483 hdr->msg_control = (*results)[i].control_buffer.buffer;
484 hdr->msg_controllen = (*results)[i].control_buffer.buffer_len;
wuba27a3c92020-01-28 08:43:21 -0800485
486 DCHECK_GE(hdr->msg_controllen, kMinCmsgSpaceForRead);
wubcfddec82020-01-13 07:45:27 -0800487 }
488 // If MSG_TRUNC is set on Linux, recvmmsg will return the real packet size in
489 // |hdrs[i].msg_len| even if packet buffer is too small to receive it.
490 int packets_read = recvmmsg(fd, hdrs, results->size(), MSG_TRUNC, nullptr);
491 if (packets_read <= 0) {
492 const int error_num = errno;
493 if (error_num != EAGAIN) {
494 QUIC_LOG_FIRST_N(ERROR, 100)
495 << "Error reading packets: " << strerror(error_num);
496 }
497 return 0;
498 }
499
wubcfddec82020-01-13 07:45:27 -0800500 for (int i = 0; i < packets_read; ++i) {
501 if (hdrs[i].msg_len == 0) {
502 continue;
503 }
504
505 msghdr& hdr = hdrs[i].msg_hdr;
506 if (QUIC_PREDICT_FALSE(hdr.msg_flags & MSG_CTRUNC)) {
507 QUIC_BUG << "Control buffer too small. size:"
508 << (*results)[i].control_buffer.buffer_len
509 << ", need:" << hdr.msg_controllen;
510 continue;
511 }
512
513 if (QUIC_PREDICT_FALSE(hdr.msg_flags & MSG_TRUNC)) {
514 QUIC_LOG_FIRST_N(WARNING, 100)
515 << "Received truncated QUIC packet: buffer size:"
516 << (*results)[i].packet_buffer.buffer_len
517 << " packet size:" << hdrs[i].msg_len;
518 continue;
519 }
520
wubcfddec82020-01-13 07:45:27 -0800521 (*results)[i].ok = true;
522 (*results)[i].packet_buffer.buffer_len = hdrs[i].msg_len;
523
524 QuicUdpPacketInfo* packet_info = &(*results)[i].packet_info;
525 if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::PEER_ADDRESS)) {
526 packet_info->SetPeerAddress(
527 QuicSocketAddress(packet_data_array[i].raw_peer_address));
528 }
529
530 if (hdr.msg_controllen > 0) {
531 for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr); cmsg != nullptr;
532 cmsg = CMSG_NXTHDR(&hdr, cmsg)) {
533 PopulatePacketInfoFromControlMessage(cmsg, packet_info,
534 packet_info_interested);
535 }
536 }
537 }
wub77cd0a32020-01-21 12:53:24 -0800538 return packets_read;
wubcfddec82020-01-13 07:45:27 -0800539#else
540 size_t num_packets = 0;
541 for (ReadPacketResult& result : *results) {
542 result.ok = false;
543 }
544 for (ReadPacketResult& result : *results) {
wub77cd0a32020-01-21 12:53:24 -0800545 errno = 0;
wubcfddec82020-01-13 07:45:27 -0800546 ReadPacket(fd, packet_info_interested, &result);
wub77cd0a32020-01-21 12:53:24 -0800547 if (!result.ok && errno == EAGAIN) {
wubcfddec82020-01-13 07:45:27 -0800548 break;
549 }
550 ++num_packets;
551 }
552 return num_packets;
553#endif
554}
555
556WriteResult QuicUdpSocketApi::WritePacket(
557 QuicUdpSocketFd fd,
558 const char* packet_buffer,
559 size_t packet_buffer_len,
560 const QuicUdpPacketInfo& packet_info) {
561 if (!packet_info.HasValue(QuicUdpPacketInfoBit::PEER_ADDRESS)) {
562 return WriteResult(WRITE_STATUS_ERROR, EINVAL);
563 }
564
565 char control_buffer[512];
566 sockaddr_storage raw_peer_address =
567 packet_info.peer_address().generic_address();
568 iovec iov = {const_cast<char*>(packet_buffer), packet_buffer_len};
569
570 msghdr hdr;
571 hdr.msg_name = &raw_peer_address;
572 hdr.msg_namelen = packet_info.peer_address().host().IsIPv4()
573 ? sizeof(sockaddr_in)
574 : sizeof(sockaddr_in6);
575 hdr.msg_iov = &iov;
576 hdr.msg_iovlen = 1;
577 hdr.msg_flags = 0;
578 hdr.msg_control = nullptr;
579 hdr.msg_controllen = 0;
580
581 cmsghdr* cmsg = nullptr;
582
583 // Set self IP.
584 if (packet_info.HasValue(QuicUdpPacketInfoBit::V4_SELF_IP) &&
585 packet_info.self_v4_ip().IsInitialized()) {
586 if (!NextCmsg(&hdr, control_buffer, sizeof(control_buffer), IPPROTO_IP,
587 IP_PKTINFO, sizeof(in_pktinfo), &cmsg)) {
588 QUIC_LOG_FIRST_N(ERROR, 100)
589 << "Not enough buffer to set self v4 ip address.";
590 return WriteResult(WRITE_STATUS_ERROR, EINVAL);
591 }
592 SetV4SelfIpInControlMessage(packet_info.self_v4_ip(), cmsg);
593 } else if (packet_info.HasValue(QuicUdpPacketInfoBit::V6_SELF_IP) &&
594 packet_info.self_v6_ip().IsInitialized()) {
595 if (!NextCmsg(&hdr, control_buffer, sizeof(control_buffer), IPPROTO_IPV6,
596 IPV6_PKTINFO, sizeof(in6_pktinfo), &cmsg)) {
597 QUIC_LOG_FIRST_N(ERROR, 100)
598 << "Not enough buffer to set self v6 ip address.";
599 return WriteResult(WRITE_STATUS_ERROR, EINVAL);
600 }
601 SetV6SelfIpInControlMessage(packet_info.self_v6_ip(), cmsg);
602 }
603
604#if defined(QUIC_UDP_SOCKET_SUPPORT_TTL)
605 // Set ttl.
606 if (packet_info.HasValue(QuicUdpPacketInfoBit::TTL)) {
607 int cmsg_level =
608 packet_info.peer_address().host().IsIPv4() ? IPPROTO_IP : IPPROTO_IPV6;
609 int cmsg_type =
610 packet_info.peer_address().host().IsIPv4() ? IP_TTL : IPV6_HOPLIMIT;
611 if (!NextCmsg(&hdr, control_buffer, sizeof(control_buffer), cmsg_level,
612 cmsg_type, sizeof(int), &cmsg)) {
613 QUIC_LOG_FIRST_N(ERROR, 100) << "Not enough buffer to set ttl.";
614 return WriteResult(WRITE_STATUS_ERROR, EINVAL);
615 }
616 *reinterpret_cast<int*>(CMSG_DATA(cmsg)) = packet_info.ttl();
617 }
618#endif
619
620 int rc;
621 do {
622 rc = sendmsg(fd, &hdr, 0);
623 } while (rc < 0 && errno == EINTR);
624 if (rc >= 0) {
625 return WriteResult(WRITE_STATUS_OK, rc);
626 }
627 return WriteResult((errno == EAGAIN || errno == EWOULDBLOCK)
628 ? WRITE_STATUS_BLOCKED
629 : WRITE_STATUS_ERROR,
630 errno);
631}
632
633} // namespace quic