Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(111)

Side by Side Diff: net/tools/quic/quic_socket_utils.cc

Issue 2548213002: Move quic_socket_utils to platform/impl/ (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/tools/quic/quic_socket_utils.h"
6
7 #include <errno.h>
8 #include <linux/net_tstamp.h>
9 #include <netinet/in.h>
10 #include <string.h>
11 #include <sys/socket.h>
12 #include <sys/uio.h>
13 #include <string>
14
15 #include "base/logging.h"
16 #include "net/quic/core/quic_bug_tracker.h"
17 #include "net/quic/core/quic_flags.h"
18 #include "net/quic/core/quic_packets.h"
19 #include "net/quic/platform/api/quic_socket_address.h"
20
21 #ifndef SO_RXQ_OVFL
22 #define SO_RXQ_OVFL 40
23 #endif
24
25 using std::string;
26
27 namespace net {
28
29 // static
30 void QuicSocketUtils::GetAddressAndTimestampFromMsghdr(
31 struct msghdr* hdr,
32 QuicIpAddress* address,
33 QuicWallTime* walltimestamp) {
34 if (hdr->msg_controllen > 0) {
35 for (cmsghdr* cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr;
36 cmsg = CMSG_NXTHDR(hdr, cmsg)) {
37 char* addr_data = nullptr;
38 int len = 0;
39 if (cmsg->cmsg_type == IPV6_PKTINFO) {
40 in6_pktinfo* info = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
41 addr_data = reinterpret_cast<char*>(&info->ipi6_addr);
42 len = sizeof(in6_addr);
43 address->FromPackedString(addr_data, len);
44 } else if (cmsg->cmsg_type == IP_PKTINFO) {
45 in_pktinfo* info = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
46 addr_data = reinterpret_cast<char*>(&info->ipi_addr);
47 len = sizeof(in_addr);
48 address->FromPackedString(addr_data, len);
49 } else if (cmsg->cmsg_level == SOL_SOCKET &&
50 cmsg->cmsg_type == SO_TIMESTAMPING) {
51 LinuxTimestamping* lts =
52 reinterpret_cast<LinuxTimestamping*>(CMSG_DATA(cmsg));
53 timespec* ts = &lts->systime;
54 int64_t usec = (static_cast<int64_t>(ts->tv_sec) * 1000 * 1000) +
55 (static_cast<int64_t>(ts->tv_nsec) / 1000);
56 *walltimestamp = QuicWallTime::FromUNIXMicroseconds(usec);
57 }
58 }
59 }
60 }
61
62 // static
63 bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr* hdr,
64 QuicPacketCount* dropped_packets) {
65 if (hdr->msg_controllen > 0) {
66 struct cmsghdr* cmsg;
67 for (cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr;
68 cmsg = CMSG_NXTHDR(hdr, cmsg)) {
69 if (cmsg->cmsg_type == SO_RXQ_OVFL) {
70 *dropped_packets = *(reinterpret_cast<uint32_t*> CMSG_DATA(cmsg));
71 return true;
72 }
73 }
74 }
75 return false;
76 }
77
78 // static
79 bool QuicSocketUtils::GetTtlFromMsghdr(struct msghdr* hdr, int* ttl) {
80 if (hdr->msg_controllen > 0) {
81 struct cmsghdr* cmsg;
82 for (cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr;
83 cmsg = CMSG_NXTHDR(hdr, cmsg)) {
84 if ((cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) ||
85 (cmsg->cmsg_level == IPPROTO_IPV6 &&
86 cmsg->cmsg_type == IPV6_HOPLIMIT)) {
87 *ttl = *(reinterpret_cast<int*>(CMSG_DATA(cmsg)));
88 return true;
89 }
90 }
91 }
92 return false;
93 }
94
95 // static
96 int QuicSocketUtils::SetGetAddressInfo(int fd, int address_family) {
97 int get_local_ip = 1;
98 int rc = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip,
99 sizeof(get_local_ip));
100 if (rc == 0 && address_family == AF_INET6) {
101 rc = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_local_ip,
102 sizeof(get_local_ip));
103 }
104 return rc;
105 }
106
107 // static
108 int QuicSocketUtils::SetGetSoftwareReceiveTimestamp(int fd) {
109 int timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE;
110 return setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &timestamping,
111 sizeof(timestamping));
112 }
113
114 // static
115 bool QuicSocketUtils::SetSendBufferSize(int fd, size_t size) {
116 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) != 0) {
117 LOG(ERROR) << "Failed to set socket send size";
118 return false;
119 }
120 return true;
121 }
122
123 // static
124 bool QuicSocketUtils::SetReceiveBufferSize(int fd, size_t size) {
125 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) != 0) {
126 LOG(ERROR) << "Failed to set socket recv size";
127 return false;
128 }
129 return true;
130 }
131
132 // static
133 int QuicSocketUtils::ReadPacket(int fd,
134 char* buffer,
135 size_t buf_len,
136 QuicPacketCount* dropped_packets,
137 QuicIpAddress* self_address,
138 QuicWallTime* walltimestamp,
139 QuicSocketAddress* peer_address) {
140 DCHECK(peer_address != nullptr);
141 char cbuf[kSpaceForCmsg];
142 memset(cbuf, 0, arraysize(cbuf));
143
144 iovec iov = {buffer, buf_len};
145 struct sockaddr_storage raw_address;
146 msghdr hdr;
147
148 hdr.msg_name = &raw_address;
149 hdr.msg_namelen = sizeof(sockaddr_storage);
150 hdr.msg_iov = &iov;
151 hdr.msg_iovlen = 1;
152 hdr.msg_flags = 0;
153
154 struct cmsghdr* cmsg = reinterpret_cast<struct cmsghdr*>(cbuf);
155 cmsg->cmsg_len = arraysize(cbuf);
156 hdr.msg_control = cmsg;
157 hdr.msg_controllen = arraysize(cbuf);
158
159 int bytes_read = recvmsg(fd, &hdr, 0);
160
161 // Return before setting dropped packets: if we get EAGAIN, it will
162 // be 0.
163 if (bytes_read < 0 && errno != 0) {
164 if (errno != EAGAIN) {
165 LOG(ERROR) << "Error reading " << strerror(errno);
166 }
167 return -1;
168 }
169
170 if (hdr.msg_controllen >= arraysize(cbuf)) {
171 QUIC_BUG << "Incorrectly set control length: " << hdr.msg_controllen
172 << ", expected " << arraysize(cbuf);
173 return -1;
174 }
175
176 if (dropped_packets != nullptr) {
177 GetOverflowFromMsghdr(&hdr, dropped_packets);
178 }
179
180 QuicIpAddress stack_address;
181 if (self_address == nullptr) {
182 self_address = &stack_address;
183 }
184
185 QuicWallTime stack_walltimestamp = QuicWallTime::FromUNIXMicroseconds(0);
186 if (walltimestamp == nullptr) {
187 walltimestamp = &stack_walltimestamp;
188 }
189
190 GetAddressAndTimestampFromMsghdr(&hdr, self_address, walltimestamp);
191
192 *peer_address = QuicSocketAddress(raw_address);
193 return bytes_read;
194 }
195
196 size_t QuicSocketUtils::SetIpInfoInCmsg(const QuicIpAddress& self_address,
197 cmsghdr* cmsg) {
198 string address_string;
199 if (self_address.IsIPv4()) {
200 cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
201 cmsg->cmsg_level = IPPROTO_IP;
202 cmsg->cmsg_type = IP_PKTINFO;
203 in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
204 memset(pktinfo, 0, sizeof(in_pktinfo));
205 pktinfo->ipi_ifindex = 0;
206 address_string = self_address.ToPackedString();
207 memcpy(&pktinfo->ipi_spec_dst, address_string.c_str(),
208 address_string.length());
209 return sizeof(in_pktinfo);
210 } else if (self_address.IsIPv6()) {
211 cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
212 cmsg->cmsg_level = IPPROTO_IPV6;
213 cmsg->cmsg_type = IPV6_PKTINFO;
214 in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
215 memset(pktinfo, 0, sizeof(in6_pktinfo));
216 address_string = self_address.ToPackedString();
217 memcpy(&pktinfo->ipi6_addr, address_string.c_str(),
218 address_string.length());
219 return sizeof(in6_pktinfo);
220 } else {
221 NOTREACHED() << "Unrecognized IPAddress";
222 return 0;
223 }
224 }
225
226 // static
227 WriteResult QuicSocketUtils::WritePacket(
228 int fd,
229 const char* buffer,
230 size_t buf_len,
231 const QuicIpAddress& self_address,
232 const QuicSocketAddress& peer_address) {
233 sockaddr_storage raw_address = peer_address.generic_address();
234 iovec iov = {const_cast<char*>(buffer), buf_len};
235
236 msghdr hdr;
237 hdr.msg_name = &raw_address;
238 hdr.msg_namelen = raw_address.ss_family == AF_INET ? sizeof(sockaddr_in)
239 : sizeof(sockaddr_in6);
240 hdr.msg_iov = &iov;
241 hdr.msg_iovlen = 1;
242 hdr.msg_flags = 0;
243
244 const int kSpaceForIpv4 = CMSG_SPACE(sizeof(in_pktinfo));
245 const int kSpaceForIpv6 = CMSG_SPACE(sizeof(in6_pktinfo));
246 // kSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info.
247 const int kSpaceForIp =
248 (kSpaceForIpv4 < kSpaceForIpv6) ? kSpaceForIpv6 : kSpaceForIpv4;
249 char cbuf[kSpaceForIp];
250 if (!self_address.IsInitialized()) {
251 hdr.msg_control = 0;
252 hdr.msg_controllen = 0;
253 } else {
254 hdr.msg_control = cbuf;
255 hdr.msg_controllen = kSpaceForIp;
256 cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
257 SetIpInfoInCmsg(self_address, cmsg);
258 hdr.msg_controllen = cmsg->cmsg_len;
259 }
260
261 int rc;
262 do {
263 rc = sendmsg(fd, &hdr, 0);
264 } while (rc < 0 && errno == EINTR);
265 if (rc >= 0) {
266 return WriteResult(WRITE_STATUS_OK, rc);
267 }
268 return WriteResult((errno == EAGAIN || errno == EWOULDBLOCK)
269 ? WRITE_STATUS_BLOCKED
270 : WRITE_STATUS_ERROR,
271 errno);
272 }
273
274 // static
275 int QuicSocketUtils::CreateUDPSocket(const QuicSocketAddress& address,
276 bool* overflow_supported) {
277 int address_family = address.host().AddressFamilyToInt();
278 int fd = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
279 if (fd < 0) {
280 LOG(ERROR) << "socket() failed: " << strerror(errno);
281 return -1;
282 }
283
284 int get_overflow = 1;
285 int rc = setsockopt(fd, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow,
286 sizeof(get_overflow));
287 if (rc < 0) {
288 DLOG(WARNING) << "Socket overflow detection not supported";
289 } else {
290 *overflow_supported = true;
291 }
292
293 if (!SetReceiveBufferSize(fd, kDefaultSocketReceiveBuffer)) {
294 return -1;
295 }
296
297 if (!SetSendBufferSize(fd, kDefaultSocketReceiveBuffer)) {
298 return -1;
299 }
300
301 rc = SetGetAddressInfo(fd, address_family);
302 if (rc < 0) {
303 LOG(ERROR) << "IP detection not supported" << strerror(errno);
304 return -1;
305 }
306
307 rc = SetGetSoftwareReceiveTimestamp(fd);
308 if (rc < 0) {
309 LOG(WARNING) << "SO_TIMESTAMPING not supported; using fallback: "
310 << strerror(errno);
311 }
312
313 return fd;
314 }
315
316 } // namespace net
OLDNEW
« no previous file with comments | « net/tools/quic/quic_socket_utils.h ('k') | net/tools/quic/test_tools/packet_dropping_test_writer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698