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