Home | History | Annotate | Download | only in quic
      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