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. 4 5 #include "net/tools/quic/quic_socket_utils.h" 6 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> 13 14 #include "base/basictypes.h" 15 #include "base/logging.h" 16 #include "net/quic/quic_protocol.h" 17 18 #ifndef SO_RXQ_OVFL 19 #define SO_RXQ_OVFL 40 20 #endif 21 22 namespace net { 23 namespace tools { 24 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; 45 } 46 return IPAddressNumber(addr_data, addr_data + len); 47 } 48 } 49 DCHECK(false) << "Unable to get address from msghdr"; 50 return IPAddressNumber(); 51 } 52 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; 64 } 65 } 66 } 67 return false; 68 } 69 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)); 78 } 79 return rc; 80 } 81 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; 87 } 88 return true; 89 } 90 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; 96 } 97 return true; 98 } 99 100 // static 101 int QuicSocketUtils::ReadPacket(int fd, char* buffer, size_t buf_len, 102 uint32* dropped_packets, 103 IPAddressNumber* self_address, 104 IPEndPoint* peer_address) { 105 CHECK(peer_address != NULL); 106 const int kSpaceForOverflowAndIp = 107 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo)); 108 char cbuf[kSpaceForOverflowAndIp]; 109 memset(cbuf, 0, arraysize(cbuf)); 110 111 iovec iov = {buffer, buf_len}; 112 struct sockaddr_storage raw_address; 113 msghdr hdr; 114 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; 120 121 struct cmsghdr *cmsg = (struct cmsghdr *) cbuf; 122 cmsg->cmsg_len = arraysize(cbuf); 123 hdr.msg_control = cmsg; 124 hdr.msg_controllen = arraysize(cbuf); 125 126 int bytes_read = recvmsg(fd, &hdr, 0); 127 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); 133 } 134 return -1; 135 } 136 137 if (dropped_packets != NULL) { 138 GetOverflowFromMsghdr(&hdr, dropped_packets); 139 } 140 if (self_address != NULL) { 141 *self_address = QuicSocketUtils::GetAddressFromMsghdr(&hdr); 142 } 143 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))); 152 } 153 154 return bytes_read; 155 } 156 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); 176 } 177 } 178 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}; 191 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; 198 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; 214 } 215 216 int rc = sendmsg(fd, &hdr, 0); 217 if (rc >= 0) { 218 return WriteResult(WRITE_STATUS_OK, rc); 219 } 220 return WriteResult((errno == EAGAIN || errno == EWOULDBLOCK) ? 221 WRITE_STATUS_BLOCKED : WRITE_STATUS_ERROR, errno); 222 } 223 224 } // namespace tools 225 } // namespace net 226