roughtime.googlesource.com/roughtime.git@v0.0.0-20201210012726-dd529367052d/udp_processor.cc (about)

     1  /* Copyright 2016 The Roughtime Authors.
     2   *
     3   * Licensed under the Apache License, Version 2.0 (the "License");
     4   * you may not use this file except in compliance with the License.
     5   * You may obtain a copy of the License at
     6   *
     7   *   http://www.apache.org/licenses/LICENSE-2.0
     8   *
     9   * Unless required by applicable law or agreed to in writing, software
    10   * distributed under the License is distributed on an "AS IS" BASIS,
    11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12   * See the License for the specific language governing permissions and
    13   * limitations under the License. */
    14  
    15  #include "udp_processor.h"
    16  
    17  #include <fcntl.h>
    18  #include <unistd.h>
    19  
    20  
    21  #include "logging.h"
    22  #include "open_source_fillins.h"
    23  
    24  namespace roughtime {
    25  
    26  UdpProcessor::UdpProcessor() {
    27    // These never change.  We can set them up just once and reuse them forever.
    28    memset(recv_mmsghdrs_, 0, sizeof(recv_mmsghdrs_));
    29    for (size_t i = 0; i < kBatchSize; i++) {
    30      recv_iov_[i].iov_base = recv_buf_[i];
    31      recv_iov_[i].iov_len = sizeof(recv_buf_[i]);
    32      recv_mmsghdrs_[i].msg_hdr.msg_name = &sockaddrs_[i];
    33      recv_mmsghdrs_[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage);
    34      recv_mmsghdrs_[i].msg_hdr.msg_iov = &recv_iov_[i];
    35      recv_mmsghdrs_[i].msg_hdr.msg_iovlen = 1;
    36    }
    37  
    38    memset(send_mmsghdrs_, 0, sizeof(send_mmsghdrs_));
    39    for (size_t i = 0; i < kBatchSize; i++) {
    40      send_iov_[i].iov_base = send_buf_[i];
    41      send_mmsghdrs_[i].msg_hdr.msg_iov = &send_iov_[i];
    42      send_mmsghdrs_[i].msg_hdr.msg_iovlen = 1;
    43      // iov_len varies per batch, as does msg_name.
    44    }
    45  }
    46  
    47  UdpProcessor::~UdpProcessor() {}
    48  
    49  bool UdpProcessor::AddBrokenReplyGenerator(
    50      std::unique_ptr<BrokenReplyGenerator> broken_reply_generator) {
    51    const uint16_t new_sum =
    52        broken_reply_generator_sum_ + broken_reply_generator->probability_1024();
    53    if (new_sum > 1024) {
    54      return false;
    55    }
    56  
    57    broken_reply_generator_sum_ = new_sum;
    58    broken_reply_generators_.push_back(std::move(broken_reply_generator));
    59  
    60    return true;
    61  }
    62  
    63  // static
    64  bool UdpProcessor::MakeSocket(int port, int *out_sock, uint16_t *out_port) {
    65    *out_sock = -1;
    66    *out_port = 0;
    67  
    68    const int fd = socket(AF_INET6, SOCK_DGRAM, 0);
    69    if (fd == -1) {
    70      ROUGHTIME_PLOG(ERROR) << "socket";
    71      return false;
    72    }
    73  
    74    struct sockaddr_in6 sin6;
    75    memset(&sin6, 0, sizeof(sin6));
    76    sin6.sin6_family = AF_INET6;
    77    sin6.sin6_addr = in6addr_any;
    78    sin6.sin6_port = htons(port);
    79    if (bind(fd, reinterpret_cast<sockaddr *>(&sin6), sizeof(sin6))) {
    80      ROUGHTIME_PLOG(ERROR) << "bind";
    81      close(fd);
    82      return false;
    83    }
    84  
    85    socklen_t sin6_len = sizeof(sin6);
    86    if (getsockname(fd, reinterpret_cast<sockaddr *>(&sin6), &sin6_len)) {
    87      ////ROUGHTIME_PLOG(ERROR) << "getsockname";
    88      close(fd);
    89      return false;
    90    }
    91  
    92    *out_sock = fd;
    93    *out_port = ntohs(sin6.sin6_port);
    94    return true;
    95  }
    96  
    97  void UdpProcessor::PrepareResponse(struct msghdr *out_send_header,
    98                                     const struct msghdr &recv_header) {
    99    out_send_header->msg_name = recv_header.msg_name;
   100    out_send_header->msg_namelen = recv_header.msg_namelen;
   101  }
   102  
   103  void UdpProcessor::Reset() {
   104    // Clear out the addresses from last time.  (Without this |recvmmsg| thinks
   105    // we are trying to receive from these addresses.)
   106    memset(sockaddrs_, 0, sizeof(sockaddrs_));
   107    for (size_t i = 0; i < kBatchSize; i++) {
   108      recv_mmsghdrs_[i].msg_hdr.msg_flags = 0;
   109      recv_mmsghdrs_[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage);
   110    }
   111  }
   112  
   113  #if defined(__MACH__)
   114  static const unsigned MSG_WAITFORONE = 0;
   115  #endif
   116  
   117  #if defined(__MACH__) || defined(__Fuchsia__)
   118  static int recvmmsg(int fd, struct mmsghdr *msgvec, unsigned vlen,
   119                      unsigned flags, struct timespec *timeout) {
   120    ssize_t r = recvmsg(fd, &msgvec->msg_hdr, 0);
   121    if (r < 0) {
   122      return r;
   123    }
   124  
   125    msgvec->msg_len = r;
   126    return 1;
   127  }
   128  
   129  int sendmmsg(int fd, struct mmsghdr *msgvec, unsigned vlen, unsigned flags) {
   130    ROUGHTIME_CHECK_EQ((unsigned) 1, vlen);
   131    ssize_t r = sendmsg(fd, &msgvec->msg_hdr, 0);
   132    if (r < 0) {
   133      return r;
   134    }
   135  
   136    msgvec->msg_len = r;
   137    return 1;
   138  }
   139  #endif
   140  
   141  bool UdpProcessor::HandleOne(const struct msghdr *from, const uint8_t *packet,
   142                               size_t len, Server *server) {
   143    return server->AddRequest(packet, len);
   144  }
   145  
   146  bool UdpProcessor::ProcessBatch(int fd, Server *server, Stats *out_stats) {
   147    server->Reset();
   148    memset(out_stats, 0, sizeof(Stats));
   149    Reset();
   150  
   151    int r;
   152    do {
   153      r = recvmmsg(fd, recv_mmsghdrs_, kBatchSize, MSG_WAITFORONE,
   154                   nullptr /* timeout */);
   155    } while (r == -1 && errno == EINTR);
   156  
   157    if (r < 0) {
   158      ROUGHTIME_PLOG(ERROR) << "recvmmsg";
   159      return false;
   160    } else if (r == 0) {
   161      return true;
   162    }
   163  
   164    out_stats->packets_in = r;
   165  
   166    size_t index = 0;
   167    for (size_t i = 0; i < static_cast<size_t>(r); i++) {
   168      const msghdr *recv_header = &recv_mmsghdrs_[i].msg_hdr;
   169      out_stats->bytes_in += recv_mmsghdrs_[i].msg_len;
   170      if ((recv_header->msg_flags & (MSG_CTRUNC | MSG_TRUNC)) != 0) {
   171        out_stats->requests_truncated++;
   172        continue;
   173      }
   174      if (!HandleOne(recv_header, recv_buf_[i], recv_mmsghdrs_[i].msg_len,
   175                     server)) {
   176        out_stats->requests_invalid++;
   177        continue;
   178      }
   179  
   180      // Fill in the destination address for this response.  The data and its
   181      // length will be set below.
   182      msghdr *send_header = &send_mmsghdrs_[index].msg_hdr;
   183      PrepareResponse(send_header, *recv_header);
   184      index++;
   185    }
   186  
   187    if (index == 0) {
   188      return true;
   189    }
   190  
   191    server->Sign();
   192  
   193    out_stats->packets_out = index;
   194    for (size_t i = 0; i < index; i++) {
   195      size_t reply_len;
   196      if (!server->MakeResponse(send_buf_[i], &reply_len, i)) {
   197        ROUGHTIME_LOG(ERROR) << "failed to assemble responses";
   198        return false;
   199      }
   200      requests_processed_++;
   201  
   202      uint8_t broken_output_buf[kMaxResponseSize];
   203      if (MaybeBreakResponse(broken_output_buf, &reply_len,
   204                             sizeof(broken_output_buf), send_buf_[i], reply_len,
   205                             recv_buf_[i], recv_mmsghdrs_[i].msg_len)) {
   206        ROUGHTIME_DCHECK_LE(reply_len, sizeof(broken_output_buf));
   207        memcpy(send_buf_[i], broken_output_buf, reply_len);
   208      }
   209  
   210      out_stats->bytes_out += reply_len;
   211      send_iov_[i].iov_len = reply_len;
   212    }
   213  
   214    int messages_sent;
   215    do {
   216      messages_sent = sendmmsg(fd, send_mmsghdrs_, index, 0);
   217    } while (messages_sent == -1 && errno == EINTR);
   218  
   219    if (messages_sent == -1) {
   220      ROUGHTIME_PLOG(ERROR) << "sendmmsg";
   221      return false;
   222    }
   223    ROUGHTIME_LOG_IF_EVERY_N_SEC(ERROR, (static_cast<size_t>(messages_sent) < index),
   224                              30)
   225        << "only " << messages_sent << " of " << index << " messages were sent";
   226  
   227    return true;
   228  }
   229  
   230  bool UdpProcessor::MaybeBreakResponse(uint8_t *out, size_t *out_len,
   231                                        size_t max_out_len,
   232                                        const uint8_t *normal_response,
   233                                        size_t normal_response_len,
   234                                        const uint8_t *request,
   235                                        size_t request_len) {
   236    const uint16_t rand = requests_processed_ & 1023;
   237    if (rand >= broken_reply_generator_sum_) {
   238      return false;
   239    }
   240  
   241    uint16_t sum = 0;
   242    BrokenReplyGenerator *selected = nullptr;
   243    for (const auto &i : broken_reply_generators_) {
   244      sum += i->probability_1024();
   245      if (rand < sum) {
   246        selected = i.get();
   247        break;
   248      }
   249    }
   250  
   251    return selected->Process(out, out_len, max_out_len, normal_response,
   252                             normal_response_len, request, request_len);
   253  }
   254  
   255  }  // namespace roughtime