Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / tools / quic / quic_socket_utils.cc
blobae557327b75a6a796f5962211b198362705204a6
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 <sys/socket.h>
10 #include <sys/uio.h>
11 #include <string>
13 #include "base/basictypes.h"
14 #include "base/logging.h"
15 #include "net/base/net_util.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 addr_data = reinterpret_cast<const uint8*>(&info->ipi6_addr);
36 len = sizeof(in6_addr);
37 } else if (cmsg->cmsg_type == IP_PKTINFO) {
38 in_pktinfo* info = reinterpret_cast<in_pktinfo*>CMSG_DATA(cmsg);
39 addr_data = reinterpret_cast<const uint8*>(&info->ipi_addr);
40 len = sizeof(in_addr);
41 } else {
42 continue;
44 return IPAddressNumber(addr_data, addr_data + len);
47 DCHECK(false) << "Unable to get address from msghdr";
48 return IPAddressNumber();
51 // static
52 bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr* hdr,
53 QuicPacketCount* dropped_packets) {
54 if (hdr->msg_controllen > 0) {
55 struct cmsghdr* cmsg;
56 for (cmsg = CMSG_FIRSTHDR(hdr);
57 cmsg != nullptr;
58 cmsg = CMSG_NXTHDR(hdr, cmsg)) {
59 if (cmsg->cmsg_type == SO_RXQ_OVFL) {
60 *dropped_packets = *(reinterpret_cast<int*>CMSG_DATA(cmsg));
61 return true;
65 return false;
68 // static
69 int QuicSocketUtils::SetGetAddressInfo(int fd, int address_family) {
70 int get_local_ip = 1;
71 int rc = setsockopt(fd, IPPROTO_IP, IP_PKTINFO,
72 &get_local_ip, sizeof(get_local_ip));
73 if (rc == 0 && address_family == AF_INET6) {
74 rc = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
75 &get_local_ip, sizeof(get_local_ip));
77 return rc;
80 // static
81 bool QuicSocketUtils::SetSendBufferSize(int fd, size_t size) {
82 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) != 0) {
83 LOG(ERROR) << "Failed to set socket send size";
84 return false;
86 return true;
89 // static
90 bool QuicSocketUtils::SetReceiveBufferSize(int fd, size_t size) {
91 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) != 0) {
92 LOG(ERROR) << "Failed to set socket recv size";
93 return false;
95 return true;
98 // static
99 int QuicSocketUtils::ReadPacket(int fd, char* buffer, size_t buf_len,
100 QuicPacketCount* dropped_packets,
101 IPAddressNumber* self_address,
102 IPEndPoint* peer_address) {
103 DCHECK(peer_address != nullptr);
104 const int kSpaceForOverflowAndIp =
105 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo));
106 char cbuf[kSpaceForOverflowAndIp];
107 memset(cbuf, 0, arraysize(cbuf));
109 iovec iov = {buffer, buf_len};
110 struct sockaddr_storage raw_address;
111 msghdr hdr;
113 hdr.msg_name = &raw_address;
114 hdr.msg_namelen = sizeof(sockaddr_storage);
115 hdr.msg_iov = &iov;
116 hdr.msg_iovlen = 1;
117 hdr.msg_flags = 0;
119 struct cmsghdr* cmsg = reinterpret_cast<struct cmsghdr*>(cbuf);
120 cmsg->cmsg_len = arraysize(cbuf);
121 hdr.msg_control = cmsg;
122 hdr.msg_controllen = arraysize(cbuf);
124 int bytes_read = recvmsg(fd, &hdr, 0);
126 // Return before setting dropped packets: if we get EAGAIN, it will
127 // be 0.
128 if (bytes_read < 0 && errno != 0) {
129 if (errno != EAGAIN) {
130 LOG(ERROR) << "Error reading " << strerror(errno);
132 return -1;
135 if (dropped_packets != nullptr) {
136 GetOverflowFromMsghdr(&hdr, dropped_packets);
138 if (self_address != nullptr) {
139 *self_address = QuicSocketUtils::GetAddressFromMsghdr(&hdr);
142 if (raw_address.ss_family == AF_INET) {
143 CHECK(peer_address->FromSockAddr(
144 reinterpret_cast<const sockaddr*>(&raw_address),
145 sizeof(struct sockaddr_in)));
146 } else if (raw_address.ss_family == AF_INET6) {
147 CHECK(peer_address->FromSockAddr(
148 reinterpret_cast<const sockaddr*>(&raw_address),
149 sizeof(struct sockaddr_in6)));
152 return bytes_read;
155 size_t QuicSocketUtils::SetIpInfoInCmsg(const IPAddressNumber& self_address,
156 cmsghdr* cmsg) {
157 if (GetAddressFamily(self_address) == ADDRESS_FAMILY_IPV4) {
158 cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
159 cmsg->cmsg_level = IPPROTO_IP;
160 cmsg->cmsg_type = IP_PKTINFO;
161 in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
162 memset(pktinfo, 0, sizeof(in_pktinfo));
163 pktinfo->ipi_ifindex = 0;
164 memcpy(&pktinfo->ipi_spec_dst, &self_address[0], self_address.size());
165 return sizeof(in_pktinfo);
166 } else {
167 cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
168 cmsg->cmsg_level = IPPROTO_IPV6;
169 cmsg->cmsg_type = IPV6_PKTINFO;
170 in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
171 memset(pktinfo, 0, sizeof(in6_pktinfo));
172 memcpy(&pktinfo->ipi6_addr, &self_address[0], self_address.size());
173 return sizeof(in6_pktinfo);
177 // static
178 WriteResult QuicSocketUtils::WritePacket(int fd,
179 const char* buffer,
180 size_t buf_len,
181 const IPAddressNumber& self_address,
182 const IPEndPoint& peer_address) {
183 sockaddr_storage raw_address;
184 socklen_t address_len = sizeof(raw_address);
185 CHECK(peer_address.ToSockAddr(
186 reinterpret_cast<struct sockaddr*>(&raw_address),
187 &address_len));
188 iovec iov = {const_cast<char*>(buffer), buf_len};
190 msghdr hdr;
191 hdr.msg_name = &raw_address;
192 hdr.msg_namelen = address_len;
193 hdr.msg_iov = &iov;
194 hdr.msg_iovlen = 1;
195 hdr.msg_flags = 0;
197 const int kSpaceForIpv4 = CMSG_SPACE(sizeof(in_pktinfo));
198 const int kSpaceForIpv6 = CMSG_SPACE(sizeof(in6_pktinfo));
199 // kSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info.
200 const int kSpaceForIp =
201 (kSpaceForIpv4 < kSpaceForIpv6) ? kSpaceForIpv6 : kSpaceForIpv4;
202 char cbuf[kSpaceForIp];
203 if (self_address.empty()) {
204 hdr.msg_control = 0;
205 hdr.msg_controllen = 0;
206 } else {
207 hdr.msg_control = cbuf;
208 hdr.msg_controllen = kSpaceForIp;
209 cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
210 SetIpInfoInCmsg(self_address, cmsg);
211 hdr.msg_controllen = cmsg->cmsg_len;
214 int rc = sendmsg(fd, &hdr, 0);
215 if (rc >= 0) {
216 return WriteResult(WRITE_STATUS_OK, rc);
218 return WriteResult((errno == EAGAIN || errno == EWOULDBLOCK) ?
219 WRITE_STATUS_BLOCKED : WRITE_STATUS_ERROR, errno);
222 } // namespace tools
223 } // namespace net