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 16 #ifndef SO_RXQ_OVFL 17 #define SO_RXQ_OVFL 40 18 #endif 19 20 namespace net { 21 namespace tools { 22 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); 36 } 37 ret.assign(addr_data, addr_data + len); 38 break; 39 } 40 } 41 return ret; 42 } 43 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; 55 } 56 } 57 } 58 return false; 59 } 60 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)); 70 } 71 } 72 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)); 83 84 iovec iov = {buffer, buf_len}; 85 struct sockaddr_storage raw_address; 86 msghdr hdr; 87 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; 93 94 struct cmsghdr *cmsg = (struct cmsghdr *) cbuf; 95 cmsg->cmsg_len = arraysize(cbuf); 96 hdr.msg_control = cmsg; 97 hdr.msg_controllen = arraysize(cbuf); 98 99 int bytes_read = recvmsg(fd, &hdr, 0); 100 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); 106 } 107 return -1; 108 } 109 110 if (dropped_packets != NULL) { 111 GetOverflowFromMsghdr(&hdr, dropped_packets); 112 } 113 if (self_address != NULL) { 114 *self_address = QuicSocketUtils::GetAddressFromMsghdr(&hdr); 115 } 116 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))); 125 } 126 127 return bytes_read; 128 } 129 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}; 141 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; 148 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); 162 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); 175 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; 183 } 184 185 int rc = sendmsg(fd, &hdr, 0); 186 *error = (rc >= 0) ? 0 : errno; 187 return rc; 188 } 189 190 } // namespace tools 191 } // namespace net 192