Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / net / tools / quic / quic_socket_utils.cc
blob4d7d36007601b7d8576b2e5287cdc8634bd38e34
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/logging.h"
16 #ifndef SO_RXQ_OVFL
17 #define SO_RXQ_OVFL 40
18 #endif
20 namespace net {
21 namespace tools {
23 // static
24 IPAddressNumber QuicSocketUtils::GetAddressFromMsghdr(struct msghdr *hdr) {
25 IPAddressNumber ret;
26 if (hdr->msg_controllen > 0) {
27 for (cmsghdr* cmsg = CMSG_FIRSTHDR(hdr);
28 cmsg != NULL;
29 cmsg = CMSG_NXTHDR(hdr, cmsg)) {
30 const uint8* addr_data = reinterpret_cast<const uint8*>CMSG_DATA(cmsg);
31 int len = 0;
32 if (cmsg->cmsg_type == IPV6_PKTINFO) {
33 len = sizeof(in6_pktinfo);
34 } else if (cmsg->cmsg_type == IP_PKTINFO) {
35 len = sizeof(in_pktinfo);
37 ret.assign(addr_data, addr_data + len);
38 break;
41 return ret;
44 // static
45 bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr *hdr,
46 int *dropped_packets) {
47 if (hdr->msg_controllen > 0) {
48 struct cmsghdr *cmsg;
49 for (cmsg = CMSG_FIRSTHDR(hdr);
50 cmsg != NULL;
51 cmsg = CMSG_NXTHDR(hdr, cmsg)) {
52 if (cmsg->cmsg_type == SO_RXQ_OVFL) {
53 *dropped_packets = *(reinterpret_cast<int*>CMSG_DATA(cmsg));
54 return true;
58 return false;
61 // static
62 int QuicSocketUtils::SetGetAddressInfo(int fd, int address_family) {
63 int get_local_ip = 1;
64 if (address_family == AF_INET) {
65 return setsockopt(fd, IPPROTO_IP, IP_PKTINFO,
66 &get_local_ip, sizeof(get_local_ip));
67 } else {
68 return setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
69 &get_local_ip, sizeof(get_local_ip));
73 // static
74 int QuicSocketUtils::ReadPacket(int fd, char* buffer, size_t buf_len,
75 int* dropped_packets,
76 IPAddressNumber* self_address,
77 IPEndPoint* peer_address) {
78 CHECK(peer_address != NULL);
79 const int kSpaceForOverflowAndIp =
80 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo));
81 char cbuf[kSpaceForOverflowAndIp];
82 memset(cbuf, 0, arraysize(cbuf));
84 iovec iov = {buffer, buf_len};
85 struct sockaddr_storage raw_address;
86 msghdr hdr;
88 hdr.msg_name = &raw_address;
89 hdr.msg_namelen = sizeof(sockaddr_storage);
90 hdr.msg_iov = &iov;
91 hdr.msg_iovlen = 1;
92 hdr.msg_flags = 0;
94 struct cmsghdr *cmsg = (struct cmsghdr *) cbuf;
95 cmsg->cmsg_len = arraysize(cbuf);
96 hdr.msg_control = cmsg;
97 hdr.msg_controllen = arraysize(cbuf);
99 int bytes_read = recvmsg(fd, &hdr, 0);
101 // Return before setting dropped packets: if we get EAGAIN, it will
102 // be 0.
103 if (bytes_read < 0 && errno != 0) {
104 if (errno != EAGAIN) {
105 LOG(ERROR) << "Error reading " << strerror(errno);
107 return -1;
110 if (dropped_packets != NULL) {
111 GetOverflowFromMsghdr(&hdr, dropped_packets);
113 if (self_address != NULL) {
114 *self_address = QuicSocketUtils::GetAddressFromMsghdr(&hdr);
117 if (raw_address.ss_family == AF_INET) {
118 CHECK(peer_address->FromSockAddr(
119 reinterpret_cast<const sockaddr*>(&raw_address),
120 sizeof(struct sockaddr_in)));
121 } else if (raw_address.ss_family == AF_INET6) {
122 CHECK(peer_address->FromSockAddr(
123 reinterpret_cast<const sockaddr*>(&raw_address),
124 sizeof(struct sockaddr_in6)));
127 return bytes_read;
130 // static
131 int QuicSocketUtils::WritePacket(int fd, const char* buffer, size_t buf_len,
132 const IPAddressNumber& self_address,
133 const IPEndPoint& peer_address,
134 int* error) {
135 sockaddr_storage raw_address;
136 socklen_t address_len = sizeof(raw_address);
137 CHECK(peer_address.ToSockAddr(
138 reinterpret_cast<struct sockaddr*>(&raw_address),
139 &address_len));
140 iovec iov = {const_cast<char*>(buffer), buf_len};
142 msghdr hdr;
143 hdr.msg_name = &raw_address;
144 hdr.msg_namelen = address_len;
145 hdr.msg_iov = &iov;
146 hdr.msg_iovlen = 1;
147 hdr.msg_flags = 0;
149 const int kSpaceForIpv4 = CMSG_SPACE(sizeof(in_pktinfo));
150 const int kSpaceForIpv6 = CMSG_SPACE(sizeof(in6_pktinfo));
151 // kSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info.
152 const int kSpaceForIp =
153 (kSpaceForIpv4 < kSpaceForIpv6) ? kSpaceForIpv6 : kSpaceForIpv4;
154 char cbuf[kSpaceForIp];
155 if (self_address.empty()) {
156 hdr.msg_control = 0;
157 hdr.msg_controllen = 0;
158 } else if (GetAddressFamily(self_address) == ADDRESS_FAMILY_IPV4) {
159 hdr.msg_control = cbuf;
160 hdr.msg_controllen = kSpaceForIp;
161 cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
163 cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
164 cmsg->cmsg_level = IPPROTO_IP;
165 cmsg->cmsg_type = IP_PKTINFO;
166 in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
167 memset(pktinfo, 0, sizeof(in_pktinfo));
168 pktinfo->ipi_ifindex = 0;
169 memcpy(&pktinfo->ipi_spec_dst, &self_address[0], self_address.size());
170 hdr.msg_controllen = cmsg->cmsg_len;
171 } else {
172 hdr.msg_control = cbuf;
173 hdr.msg_controllen = kSpaceForIp;
174 cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
176 cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
177 cmsg->cmsg_level = IPPROTO_IPV6;
178 cmsg->cmsg_type = IPV6_PKTINFO;
179 in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
180 memset(pktinfo, 0, sizeof(in6_pktinfo));
181 memcpy(&pktinfo->ipi6_addr, &self_address[0], self_address.size());
182 hdr.msg_controllen = cmsg->cmsg_len;
185 int rc = sendmsg(fd, &hdr, 0);
186 *error = (rc >= 0) ? 0 : errno;
187 return rc;
190 } // namespace tools
191 } // namespace net