Initialize UserMetricsRecorder on Windows Ash and Ozone
[chromium-blink-merge.git] / net / tools / quic / quic_socket_utils.cc
blob0eb11858cbe36425eca78b844dd4af70f8902064
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.
5 #include "net/tools/quic/quic_socket_utils.h"
7 #include <errno.h>
8 #include <netinet/in.h>
9 #include <string.h>
10 #include <sys/socket.h>
11 #include <sys/uio.h>
12 #include <string>
14 #include "base/basictypes.h"
15 #include "base/logging.h"
16 #include "net/quic/quic_protocol.h"
18 #ifndef SO_RXQ_OVFL
19 #define SO_RXQ_OVFL 40
20 #endif
22 namespace net {
23 namespace tools {
25 // static
26 IPAddressNumber QuicSocketUtils::GetAddressFromMsghdr(struct msghdr* hdr) {
27 if (hdr->msg_controllen > 0) {
28 for (cmsghdr* cmsg = CMSG_FIRSTHDR(hdr);
29 cmsg != nullptr;
30 cmsg = CMSG_NXTHDR(hdr, cmsg)) {
31 const uint8* addr_data = nullptr;
32 int len = 0;
33 if (cmsg->cmsg_type == IPV6_PKTINFO) {
34 in6_pktinfo* info = reinterpret_cast<in6_pktinfo*>CMSG_DATA(cmsg);
35 in6_addr addr = info->ipi6_addr;
36 addr_data = reinterpret_cast<const uint8*>(&addr);
37 len = sizeof(addr);
38 } else if (cmsg->cmsg_type == IP_PKTINFO) {
39 in_pktinfo* info = reinterpret_cast<in_pktinfo*>CMSG_DATA(cmsg);
40 in_addr addr = info->ipi_addr;
41 addr_data = reinterpret_cast<const uint8*>(&addr);
42 len = sizeof(addr);
43 } else {
44 continue;
46 return IPAddressNumber(addr_data, addr_data + len);
49 DCHECK(false) << "Unable to get address from msghdr";
50 return IPAddressNumber();
53 // static
54 bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr* hdr,
55 QuicPacketCount* dropped_packets) {
56 if (hdr->msg_controllen > 0) {
57 struct cmsghdr* cmsg;
58 for (cmsg = CMSG_FIRSTHDR(hdr);
59 cmsg != nullptr;
60 cmsg = CMSG_NXTHDR(hdr, cmsg)) {
61 if (cmsg->cmsg_type == SO_RXQ_OVFL) {
62 *dropped_packets = *(reinterpret_cast<int*>CMSG_DATA(cmsg));
63 return true;
67 return false;
70 // static
71 int QuicSocketUtils::SetGetAddressInfo(int fd, int address_family) {
72 int get_local_ip = 1;
73 int rc = setsockopt(fd, IPPROTO_IP, IP_PKTINFO,
74 &get_local_ip, sizeof(get_local_ip));
75 if (rc == 0 && address_family == AF_INET6) {
76 rc = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
77 &get_local_ip, sizeof(get_local_ip));
79 return rc;
82 // static
83 bool QuicSocketUtils::SetSendBufferSize(int fd, size_t size) {
84 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) != 0) {
85 LOG(ERROR) << "Failed to set socket send size";
86 return false;
88 return true;
91 // static
92 bool QuicSocketUtils::SetReceiveBufferSize(int fd, size_t size) {
93 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) != 0) {
94 LOG(ERROR) << "Failed to set socket recv size";
95 return false;
97 return true;
100 // static
101 int QuicSocketUtils::ReadPacket(int fd, char* buffer, size_t buf_len,
102 QuicPacketCount* dropped_packets,
103 IPAddressNumber* self_address,
104 IPEndPoint* peer_address) {
105 DCHECK(peer_address != nullptr);
106 const int kSpaceForOverflowAndIp =
107 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo));
108 char cbuf[kSpaceForOverflowAndIp];
109 memset(cbuf, 0, arraysize(cbuf));
111 iovec iov = {buffer, buf_len};
112 struct sockaddr_storage raw_address;
113 msghdr hdr;
115 hdr.msg_name = &raw_address;
116 hdr.msg_namelen = sizeof(sockaddr_storage);
117 hdr.msg_iov = &iov;
118 hdr.msg_iovlen = 1;
119 hdr.msg_flags = 0;
121 struct cmsghdr* cmsg = (struct cmsghdr*)cbuf;
122 cmsg->cmsg_len = arraysize(cbuf);
123 hdr.msg_control = cmsg;
124 hdr.msg_controllen = arraysize(cbuf);
126 int bytes_read = recvmsg(fd, &hdr, 0);
128 // Return before setting dropped packets: if we get EAGAIN, it will
129 // be 0.
130 if (bytes_read < 0 && errno != 0) {
131 if (errno != EAGAIN) {
132 LOG(ERROR) << "Error reading " << strerror(errno);
134 return -1;
137 if (dropped_packets != nullptr) {
138 GetOverflowFromMsghdr(&hdr, dropped_packets);
140 if (self_address != nullptr) {
141 *self_address = QuicSocketUtils::GetAddressFromMsghdr(&hdr);
144 if (raw_address.ss_family == AF_INET) {
145 CHECK(peer_address->FromSockAddr(
146 reinterpret_cast<const sockaddr*>(&raw_address),
147 sizeof(struct sockaddr_in)));
148 } else if (raw_address.ss_family == AF_INET6) {
149 CHECK(peer_address->FromSockAddr(
150 reinterpret_cast<const sockaddr*>(&raw_address),
151 sizeof(struct sockaddr_in6)));
154 return bytes_read;
157 size_t QuicSocketUtils::SetIpInfoInCmsg(const IPAddressNumber& self_address,
158 cmsghdr* cmsg) {
159 if (GetAddressFamily(self_address) == ADDRESS_FAMILY_IPV4) {
160 cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
161 cmsg->cmsg_level = IPPROTO_IP;
162 cmsg->cmsg_type = IP_PKTINFO;
163 in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
164 memset(pktinfo, 0, sizeof(in_pktinfo));
165 pktinfo->ipi_ifindex = 0;
166 memcpy(&pktinfo->ipi_spec_dst, &self_address[0], self_address.size());
167 return sizeof(in_pktinfo);
168 } else {
169 cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
170 cmsg->cmsg_level = IPPROTO_IPV6;
171 cmsg->cmsg_type = IPV6_PKTINFO;
172 in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
173 memset(pktinfo, 0, sizeof(in6_pktinfo));
174 memcpy(&pktinfo->ipi6_addr, &self_address[0], self_address.size());
175 return sizeof(in6_pktinfo);
179 // static
180 WriteResult QuicSocketUtils::WritePacket(int fd,
181 const char* buffer,
182 size_t buf_len,
183 const IPAddressNumber& self_address,
184 const IPEndPoint& peer_address) {
185 sockaddr_storage raw_address;
186 socklen_t address_len = sizeof(raw_address);
187 CHECK(peer_address.ToSockAddr(
188 reinterpret_cast<struct sockaddr*>(&raw_address),
189 &address_len));
190 iovec iov = {const_cast<char*>(buffer), buf_len};
192 msghdr hdr;
193 hdr.msg_name = &raw_address;
194 hdr.msg_namelen = address_len;
195 hdr.msg_iov = &iov;
196 hdr.msg_iovlen = 1;
197 hdr.msg_flags = 0;
199 const int kSpaceForIpv4 = CMSG_SPACE(sizeof(in_pktinfo));
200 const int kSpaceForIpv6 = CMSG_SPACE(sizeof(in6_pktinfo));
201 // kSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info.
202 const int kSpaceForIp =
203 (kSpaceForIpv4 < kSpaceForIpv6) ? kSpaceForIpv6 : kSpaceForIpv4;
204 char cbuf[kSpaceForIp];
205 if (self_address.empty()) {
206 hdr.msg_control = 0;
207 hdr.msg_controllen = 0;
208 } else {
209 hdr.msg_control = cbuf;
210 hdr.msg_controllen = kSpaceForIp;
211 cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
212 SetIpInfoInCmsg(self_address, cmsg);
213 hdr.msg_controllen = cmsg->cmsg_len;
216 int rc = sendmsg(fd, &hdr, 0);
217 if (rc >= 0) {
218 return WriteResult(WRITE_STATUS_OK, rc);
220 return WriteResult((errno == EAGAIN || errno == EWOULDBLOCK) ?
221 WRITE_STATUS_BLOCKED : WRITE_STATUS_ERROR, errno);
224 } // namespace tools
225 } // namespace net