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 #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