We started redesigning GpuMemoryBuffer interface to handle multiple buffers [0].
[chromium-blink-merge.git] / net / tools / quic / quic_socket_utils.cc
blobcefcaae64d08d84b5c999187582dcbce98786576
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/quic/quic_protocol.h"
17 #ifndef SO_RXQ_OVFL
18 #define SO_RXQ_OVFL 40
19 #endif
21 namespace net {
22 namespace tools {
24 // static
25 IPAddressNumber QuicSocketUtils::GetAddressFromMsghdr(struct msghdr* hdr) {
26 if (hdr->msg_controllen > 0) {
27 for (cmsghdr* cmsg = CMSG_FIRSTHDR(hdr);
28 cmsg != nullptr;
29 cmsg = CMSG_NXTHDR(hdr, cmsg)) {
30 const uint8* addr_data = nullptr;
31 int len = 0;
32 if (cmsg->cmsg_type == IPV6_PKTINFO) {
33 in6_pktinfo* info = reinterpret_cast<in6_pktinfo*>CMSG_DATA(cmsg);
34 addr_data = reinterpret_cast<const uint8*>(&info->ipi6_addr);
35 len = sizeof(in6_addr);
36 } else if (cmsg->cmsg_type == IP_PKTINFO) {
37 in_pktinfo* info = reinterpret_cast<in_pktinfo*>CMSG_DATA(cmsg);
38 addr_data = reinterpret_cast<const uint8*>(&info->ipi_addr);
39 len = sizeof(in_addr);
40 } else {
41 continue;
43 return IPAddressNumber(addr_data, addr_data + len);
46 DCHECK(false) << "Unable to get address from msghdr";
47 return IPAddressNumber();
50 // static
51 bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr* hdr,
52 QuicPacketCount* dropped_packets) {
53 if (hdr->msg_controllen > 0) {
54 struct cmsghdr* cmsg;
55 for (cmsg = CMSG_FIRSTHDR(hdr);
56 cmsg != nullptr;
57 cmsg = CMSG_NXTHDR(hdr, cmsg)) {
58 if (cmsg->cmsg_type == SO_RXQ_OVFL) {
59 *dropped_packets = *(reinterpret_cast<int*>CMSG_DATA(cmsg));
60 return true;
64 return false;
67 // static
68 int QuicSocketUtils::SetGetAddressInfo(int fd, int address_family) {
69 int get_local_ip = 1;
70 int rc = setsockopt(fd, IPPROTO_IP, IP_PKTINFO,
71 &get_local_ip, sizeof(get_local_ip));
72 if (rc == 0 && address_family == AF_INET6) {
73 rc = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
74 &get_local_ip, sizeof(get_local_ip));
76 return rc;
79 // static
80 bool QuicSocketUtils::SetSendBufferSize(int fd, size_t size) {
81 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) != 0) {
82 LOG(ERROR) << "Failed to set socket send size";
83 return false;
85 return true;
88 // static
89 bool QuicSocketUtils::SetReceiveBufferSize(int fd, size_t size) {
90 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) != 0) {
91 LOG(ERROR) << "Failed to set socket recv size";
92 return false;
94 return true;
97 // static
98 int QuicSocketUtils::ReadPacket(int fd, char* buffer, size_t buf_len,
99 QuicPacketCount* dropped_packets,
100 IPAddressNumber* self_address,
101 IPEndPoint* peer_address) {
102 DCHECK(peer_address != nullptr);
103 const int kSpaceForOverflowAndIp =
104 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo));
105 char cbuf[kSpaceForOverflowAndIp];
106 memset(cbuf, 0, arraysize(cbuf));
108 iovec iov = {buffer, buf_len};
109 struct sockaddr_storage raw_address;
110 msghdr hdr;
112 hdr.msg_name = &raw_address;
113 hdr.msg_namelen = sizeof(sockaddr_storage);
114 hdr.msg_iov = &iov;
115 hdr.msg_iovlen = 1;
116 hdr.msg_flags = 0;
118 struct cmsghdr* cmsg = (struct cmsghdr*)cbuf;
119 cmsg->cmsg_len = arraysize(cbuf);
120 hdr.msg_control = cmsg;
121 hdr.msg_controllen = arraysize(cbuf);
123 int bytes_read = recvmsg(fd, &hdr, 0);
125 // Return before setting dropped packets: if we get EAGAIN, it will
126 // be 0.
127 if (bytes_read < 0 && errno != 0) {
128 if (errno != EAGAIN) {
129 LOG(ERROR) << "Error reading " << strerror(errno);
131 return -1;
134 if (dropped_packets != nullptr) {
135 GetOverflowFromMsghdr(&hdr, dropped_packets);
137 if (self_address != nullptr) {
138 *self_address = QuicSocketUtils::GetAddressFromMsghdr(&hdr);
141 if (raw_address.ss_family == AF_INET) {
142 CHECK(peer_address->FromSockAddr(
143 reinterpret_cast<const sockaddr*>(&raw_address),
144 sizeof(struct sockaddr_in)));
145 } else if (raw_address.ss_family == AF_INET6) {
146 CHECK(peer_address->FromSockAddr(
147 reinterpret_cast<const sockaddr*>(&raw_address),
148 sizeof(struct sockaddr_in6)));
151 return bytes_read;
154 size_t QuicSocketUtils::SetIpInfoInCmsg(const IPAddressNumber& self_address,
155 cmsghdr* cmsg) {
156 if (GetAddressFamily(self_address) == ADDRESS_FAMILY_IPV4) {
157 cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
158 cmsg->cmsg_level = IPPROTO_IP;
159 cmsg->cmsg_type = IP_PKTINFO;
160 in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
161 memset(pktinfo, 0, sizeof(in_pktinfo));
162 pktinfo->ipi_ifindex = 0;
163 memcpy(&pktinfo->ipi_spec_dst, &self_address[0], self_address.size());
164 return sizeof(in_pktinfo);
165 } else {
166 cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
167 cmsg->cmsg_level = IPPROTO_IPV6;
168 cmsg->cmsg_type = IPV6_PKTINFO;
169 in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
170 memset(pktinfo, 0, sizeof(in6_pktinfo));
171 memcpy(&pktinfo->ipi6_addr, &self_address[0], self_address.size());
172 return sizeof(in6_pktinfo);
176 // static
177 WriteResult QuicSocketUtils::WritePacket(int fd,
178 const char* buffer,
179 size_t buf_len,
180 const IPAddressNumber& self_address,
181 const IPEndPoint& peer_address) {
182 sockaddr_storage raw_address;
183 socklen_t address_len = sizeof(raw_address);
184 CHECK(peer_address.ToSockAddr(
185 reinterpret_cast<struct sockaddr*>(&raw_address),
186 &address_len));
187 iovec iov = {const_cast<char*>(buffer), buf_len};
189 msghdr hdr;
190 hdr.msg_name = &raw_address;
191 hdr.msg_namelen = address_len;
192 hdr.msg_iov = &iov;
193 hdr.msg_iovlen = 1;
194 hdr.msg_flags = 0;
196 const int kSpaceForIpv4 = CMSG_SPACE(sizeof(in_pktinfo));
197 const int kSpaceForIpv6 = CMSG_SPACE(sizeof(in6_pktinfo));
198 // kSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info.
199 const int kSpaceForIp =
200 (kSpaceForIpv4 < kSpaceForIpv6) ? kSpaceForIpv6 : kSpaceForIpv4;
201 char cbuf[kSpaceForIp];
202 if (self_address.empty()) {
203 hdr.msg_control = 0;
204 hdr.msg_controllen = 0;
205 } else {
206 hdr.msg_control = cbuf;
207 hdr.msg_controllen = kSpaceForIp;
208 cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
209 SetIpInfoInCmsg(self_address, cmsg);
210 hdr.msg_controllen = cmsg->cmsg_len;
213 int rc = sendmsg(fd, &hdr, 0);
214 if (rc >= 0) {
215 return WriteResult(WRITE_STATUS_OK, rc);
217 return WriteResult((errno == EAGAIN || errno == EWOULDBLOCK) ?
218 WRITE_STATUS_BLOCKED : WRITE_STATUS_ERROR, errno);
221 } // namespace tools
222 } // namespace net