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/logging.h" 15 #include "net/quic/quic_protocol.h" 16 17 #ifndef SO_RXQ_OVFL 18 #define SO_RXQ_OVFL 40 19 #endif 20 21 namespace net { 22 namespace tools { 23 24 // static 25 IPAddressNumber QuicSocketUtils::GetAddressFromMsghdr(struct msghdr *hdr) { 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 = NULL; 31 int len = 0; 32 if (cmsg->cmsg_type == IPV6_PKTINFO) { 33 in6_pktinfo* info = reinterpret_cast<in6_pktinfo*>CMSG_DATA(cmsg); 34 in6_addr addr = info->ipi6_addr; 35 addr_data = reinterpret_cast<const uint8*>(&addr); 36 len = sizeof(addr); 37 } else if (cmsg->cmsg_type == IP_PKTINFO) { 38 in_pktinfo* info = reinterpret_cast<in_pktinfo*>CMSG_DATA(cmsg); 39 in_addr addr = info->ipi_addr; 40 addr_data = reinterpret_cast<const uint8*>(&addr); 41 len = sizeof(addr); 42 } else { 43 continue; 44 } 45 return IPAddressNumber(addr_data, addr_data + len); 46 } 47 } 48 DCHECK(false) << "Unable to get address from msghdr"; 49 return IPAddressNumber(); 50 } 51 52 // static 53 bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr *hdr, 54 int *dropped_packets) { 55 if (hdr->msg_controllen > 0) { 56 struct cmsghdr *cmsg; 57 for (cmsg = CMSG_FIRSTHDR(hdr); 58 cmsg != NULL; 59 cmsg = CMSG_NXTHDR(hdr, cmsg)) { 60 if (cmsg->cmsg_type == SO_RXQ_OVFL) { 61 *dropped_packets = *(reinterpret_cast<int*>CMSG_DATA(cmsg)); 62 return true; 63 } 64 } 65 } 66 return false; 67 } 68 69 // static 70 int QuicSocketUtils::SetGetAddressInfo(int fd, int address_family) { 71 int get_local_ip = 1; 72 if (address_family == AF_INET) { 73 return setsockopt(fd, IPPROTO_IP, IP_PKTINFO, 74 &get_local_ip, sizeof(get_local_ip)); 75 } else { 76 return setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 77 &get_local_ip, sizeof(get_local_ip)); 78 } 79 } 80 81 // static 82 int QuicSocketUtils::ReadPacket(int fd, char* buffer, size_t buf_len, 83 int* dropped_packets, 84 IPAddressNumber* self_address, 85 IPEndPoint* peer_address) { 86 CHECK(peer_address != NULL); 87 const int kSpaceForOverflowAndIp = 88 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo)); 89 char cbuf[kSpaceForOverflowAndIp]; 90 memset(cbuf, 0, arraysize(cbuf)); 91 92 iovec iov = {buffer, buf_len}; 93 struct sockaddr_storage raw_address; 94 msghdr hdr; 95 96 hdr.msg_name = &raw_address; 97 hdr.msg_namelen = sizeof(sockaddr_storage); 98 hdr.msg_iov = &iov; 99 hdr.msg_iovlen = 1; 100 hdr.msg_flags = 0; 101 102 struct cmsghdr *cmsg = (struct cmsghdr *) cbuf; 103 cmsg->cmsg_len = arraysize(cbuf); 104 hdr.msg_control = cmsg; 105 hdr.msg_controllen = arraysize(cbuf); 106 107 int bytes_read = recvmsg(fd, &hdr, 0); 108 109 // Return before setting dropped packets: if we get EAGAIN, it will 110 // be 0. 111 if (bytes_read < 0 && errno != 0) { 112 if (errno != EAGAIN) { 113 LOG(ERROR) << "Error reading " << strerror(errno); 114 } 115 return -1; 116 } 117 118 if (dropped_packets != NULL) { 119 GetOverflowFromMsghdr(&hdr, dropped_packets); 120 } 121 if (self_address != NULL) { 122 *self_address = QuicSocketUtils::GetAddressFromMsghdr(&hdr); 123 } 124 125 if (raw_address.ss_family == AF_INET) { 126 CHECK(peer_address->FromSockAddr( 127 reinterpret_cast<const sockaddr*>(&raw_address), 128 sizeof(struct sockaddr_in))); 129 } else if (raw_address.ss_family == AF_INET6) { 130 CHECK(peer_address->FromSockAddr( 131 reinterpret_cast<const sockaddr*>(&raw_address), 132 sizeof(struct sockaddr_in6))); 133 } 134 135 return bytes_read; 136 } 137 138 // static 139 WriteResult QuicSocketUtils::WritePacket(int fd, 140 const char* buffer, 141 size_t buf_len, 142 const IPAddressNumber& self_address, 143 const IPEndPoint& peer_address) { 144 sockaddr_storage raw_address; 145 socklen_t address_len = sizeof(raw_address); 146 CHECK(peer_address.ToSockAddr( 147 reinterpret_cast<struct sockaddr*>(&raw_address), 148 &address_len)); 149 iovec iov = {const_cast<char*>(buffer), buf_len}; 150 151 msghdr hdr; 152 hdr.msg_name = &raw_address; 153 hdr.msg_namelen = address_len; 154 hdr.msg_iov = &iov; 155 hdr.msg_iovlen = 1; 156 hdr.msg_flags = 0; 157 158 const int kSpaceForIpv4 = CMSG_SPACE(sizeof(in_pktinfo)); 159 const int kSpaceForIpv6 = CMSG_SPACE(sizeof(in6_pktinfo)); 160 // kSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info. 161 const int kSpaceForIp = 162 (kSpaceForIpv4 < kSpaceForIpv6) ? kSpaceForIpv6 : kSpaceForIpv4; 163 char cbuf[kSpaceForIp]; 164 if (self_address.empty()) { 165 hdr.msg_control = 0; 166 hdr.msg_controllen = 0; 167 } else if (GetAddressFamily(self_address) == ADDRESS_FAMILY_IPV4) { 168 hdr.msg_control = cbuf; 169 hdr.msg_controllen = kSpaceForIp; 170 cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr); 171 172 cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo)); 173 cmsg->cmsg_level = IPPROTO_IP; 174 cmsg->cmsg_type = IP_PKTINFO; 175 in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg)); 176 memset(pktinfo, 0, sizeof(in_pktinfo)); 177 pktinfo->ipi_ifindex = 0; 178 memcpy(&pktinfo->ipi_spec_dst, &self_address[0], self_address.size()); 179 hdr.msg_controllen = cmsg->cmsg_len; 180 } else { 181 hdr.msg_control = cbuf; 182 hdr.msg_controllen = kSpaceForIp; 183 cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr); 184 185 cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo)); 186 cmsg->cmsg_level = IPPROTO_IPV6; 187 cmsg->cmsg_type = IPV6_PKTINFO; 188 in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg)); 189 memset(pktinfo, 0, sizeof(in6_pktinfo)); 190 memcpy(&pktinfo->ipi6_addr, &self_address[0], self_address.size()); 191 hdr.msg_controllen = cmsg->cmsg_len; 192 } 193 194 int rc = sendmsg(fd, &hdr, 0); 195 if (rc >= 0) { 196 return WriteResult(WRITE_STATUS_OK, rc); 197 } 198 return WriteResult((errno == EAGAIN || errno == EWOULDBLOCK) ? 199 WRITE_STATUS_BLOCKED : WRITE_STATUS_ERROR, errno); 200 } 201 202 } // namespace tools 203 } // namespace net 204