Connect PPAPI IPC channels for non-SFI mode.
[chromium-blink-merge.git] / net / tools / quic / quic_socket_utils.cc
blob1ab3bdf0fe3e2c00c3c3212958a5f28086fd6f5c
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 != NULL;
30 cmsg = CMSG_NXTHDR(hdr, cmsg)) {
31 const uint8* addr_data = NULL;
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 uint32 *dropped_packets) {
56 if (hdr->msg_controllen > 0) {
57 struct cmsghdr *cmsg;
58 for (cmsg = CMSG_FIRSTHDR(hdr);
59 cmsg != NULL;
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 if (address_family == AF_INET) {
74 return setsockopt(fd, IPPROTO_IP, IP_PKTINFO,
75 &get_local_ip, sizeof(get_local_ip));
76 } else {
77 return setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
78 &get_local_ip, sizeof(get_local_ip));
82 // static
83 int QuicSocketUtils::ReadPacket(int fd, char* buffer, size_t buf_len,
84 uint32* dropped_packets,
85 IPAddressNumber* self_address,
86 IPEndPoint* peer_address) {
87 CHECK(peer_address != NULL);
88 const int kSpaceForOverflowAndIp =
89 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo));
90 char cbuf[kSpaceForOverflowAndIp];
91 memset(cbuf, 0, arraysize(cbuf));
93 iovec iov = {buffer, buf_len};
94 struct sockaddr_storage raw_address;
95 msghdr hdr;
97 hdr.msg_name = &raw_address;
98 hdr.msg_namelen = sizeof(sockaddr_storage);
99 hdr.msg_iov = &iov;
100 hdr.msg_iovlen = 1;
101 hdr.msg_flags = 0;
103 struct cmsghdr *cmsg = (struct cmsghdr *) cbuf;
104 cmsg->cmsg_len = arraysize(cbuf);
105 hdr.msg_control = cmsg;
106 hdr.msg_controllen = arraysize(cbuf);
108 int bytes_read = recvmsg(fd, &hdr, 0);
110 // Return before setting dropped packets: if we get EAGAIN, it will
111 // be 0.
112 if (bytes_read < 0 && errno != 0) {
113 if (errno != EAGAIN) {
114 LOG(ERROR) << "Error reading " << strerror(errno);
116 return -1;
119 if (dropped_packets != NULL) {
120 GetOverflowFromMsghdr(&hdr, dropped_packets);
122 if (self_address != NULL) {
123 *self_address = QuicSocketUtils::GetAddressFromMsghdr(&hdr);
126 if (raw_address.ss_family == AF_INET) {
127 CHECK(peer_address->FromSockAddr(
128 reinterpret_cast<const sockaddr*>(&raw_address),
129 sizeof(struct sockaddr_in)));
130 } else if (raw_address.ss_family == AF_INET6) {
131 CHECK(peer_address->FromSockAddr(
132 reinterpret_cast<const sockaddr*>(&raw_address),
133 sizeof(struct sockaddr_in6)));
136 return bytes_read;
139 // static
140 WriteResult QuicSocketUtils::WritePacket(int fd,
141 const char* buffer,
142 size_t buf_len,
143 const IPAddressNumber& self_address,
144 const IPEndPoint& peer_address) {
145 sockaddr_storage raw_address;
146 socklen_t address_len = sizeof(raw_address);
147 CHECK(peer_address.ToSockAddr(
148 reinterpret_cast<struct sockaddr*>(&raw_address),
149 &address_len));
150 iovec iov = {const_cast<char*>(buffer), buf_len};
152 msghdr hdr;
153 hdr.msg_name = &raw_address;
154 hdr.msg_namelen = address_len;
155 hdr.msg_iov = &iov;
156 hdr.msg_iovlen = 1;
157 hdr.msg_flags = 0;
159 const int kSpaceForIpv4 = CMSG_SPACE(sizeof(in_pktinfo));
160 const int kSpaceForIpv6 = CMSG_SPACE(sizeof(in6_pktinfo));
161 // kSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info.
162 const int kSpaceForIp =
163 (kSpaceForIpv4 < kSpaceForIpv6) ? kSpaceForIpv6 : kSpaceForIpv4;
164 char cbuf[kSpaceForIp];
165 if (self_address.empty()) {
166 hdr.msg_control = 0;
167 hdr.msg_controllen = 0;
168 } else if (GetAddressFamily(self_address) == ADDRESS_FAMILY_IPV4) {
169 hdr.msg_control = cbuf;
170 hdr.msg_controllen = kSpaceForIp;
171 cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
173 cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
174 cmsg->cmsg_level = IPPROTO_IP;
175 cmsg->cmsg_type = IP_PKTINFO;
176 in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
177 memset(pktinfo, 0, sizeof(in_pktinfo));
178 pktinfo->ipi_ifindex = 0;
179 memcpy(&pktinfo->ipi_spec_dst, &self_address[0], self_address.size());
180 hdr.msg_controllen = cmsg->cmsg_len;
181 } else {
182 hdr.msg_control = cbuf;
183 hdr.msg_controllen = kSpaceForIp;
184 cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
186 cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
187 cmsg->cmsg_level = IPPROTO_IPV6;
188 cmsg->cmsg_type = IPV6_PKTINFO;
189 in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
190 memset(pktinfo, 0, sizeof(in6_pktinfo));
191 memcpy(&pktinfo->ipi6_addr, &self_address[0], self_address.size());
192 hdr.msg_controllen = cmsg->cmsg_len;
195 int rc = sendmsg(fd, &hdr, 0);
196 if (rc >= 0) {
197 return WriteResult(WRITE_STATUS_OK, rc);
199 return WriteResult((errno == EAGAIN || errno == EWOULDBLOCK) ?
200 WRITE_STATUS_BLOCKED : WRITE_STATUS_ERROR, errno);
203 } // namespace tools
204 } // namespace net