message.cpp
1 /** 2 * This file is part of Darling. 3 * 4 * Copyright (C) 2021 Darling developers 5 * 6 * Darling is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * Darling is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <darlingserver/message.hpp> 21 #include <unistd.h> 22 #include <cstdlib> 23 #include <stdexcept> 24 #include <new> 25 #include <mutex> 26 #include <system_error> 27 28 DarlingServer::Address::Address() { 29 _address.sun_family = AF_UNIX; 30 memset(_address.sun_path, 0, sizeof(_address.sun_path)); 31 _size = sizeof(_address); 32 }; 33 34 DarlingServer::Address::Address(const struct sockaddr_un& rawAddress, size_t addressLength) { 35 _address = rawAddress; 36 _size = addressLength; 37 }; 38 39 struct sockaddr_un& DarlingServer::Address::raw() { 40 return _address; 41 }; 42 43 const struct sockaddr_un& DarlingServer::Address::raw() const { 44 return _address; 45 }; 46 47 size_t DarlingServer::Address::rawSize() const { 48 return _size; 49 }; 50 51 void DarlingServer::Address::setRawSize(size_t newRawSize) { 52 _size = newRawSize; 53 }; 54 55 DarlingServer::Message::Message(size_t bufferSpace, size_t descriptorSpace, std::function<void()> sendNotificationCallback): 56 _sendNotificationCallback(sendNotificationCallback) 57 { 58 size_t controlLen = CMSG_SPACE(sizeof(struct ucred)) + (descriptorSpace > 0 ? CMSG_SPACE(sizeof(int) * descriptorSpace) : 0); 59 _controlHeader = static_cast<decltype(_controlHeader)>(malloc(controlLen)); 60 61 if (!_controlHeader) { 62 throw std::bad_alloc(); 63 } 64 65 _controlHeader->cmsg_len = CMSG_LEN(sizeof(struct ucred)); 66 _controlHeader->cmsg_level = SOL_SOCKET; 67 _controlHeader->cmsg_type = SCM_CREDENTIALS; 68 struct ucred ourCreds; 69 ourCreds.pid = getpid(); 70 ourCreds.uid = getuid(); 71 ourCreds.gid = getgid(); 72 // the cmsg man page says memcpy should be used with CMSG_DATA instead of direct pointer access 73 memcpy(CMSG_DATA(_controlHeader), &ourCreds, sizeof(ourCreds)); 74 75 if (descriptorSpace > 0) { 76 auto fdHeader = reinterpret_cast<decltype(_controlHeader)>(reinterpret_cast<char*>(_controlHeader) + CMSG_SPACE(sizeof(struct ucred))); 77 fdHeader->cmsg_len = CMSG_LEN(sizeof(int) * descriptorSpace); 78 fdHeader->cmsg_level = SOL_SOCKET; 79 fdHeader->cmsg_type = SCM_RIGHTS; 80 for (size_t i = 0; i < descriptorSpace; ++i) { 81 const int fd = -1; 82 memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &fd, sizeof(int)); 83 } 84 } 85 86 _buffer.resize(bufferSpace); 87 88 _header.msg_name = &_socketAddress.raw(); 89 _header.msg_namelen = _socketAddress.rawSize(); 90 _header.msg_iov = &_dataDescriptor; 91 _header.msg_iovlen = 1; 92 _header.msg_control = _controlHeader; 93 _header.msg_controllen = controlLen; 94 _header.msg_flags = 0; 95 96 _dataDescriptor.iov_base = _buffer.data(); 97 _dataDescriptor.iov_len = _buffer.size(); 98 }; 99 100 void DarlingServer::Message::_initWithOther(Message&& other) { 101 _sendNotificationCallback = std::move(other._sendNotificationCallback); 102 other._sendNotificationCallback = nullptr; 103 104 _buffer = std::move(other._buffer); 105 _socketAddress = std::move(other._socketAddress); 106 _controlHeader = std::move(other._controlHeader); 107 108 other._controlHeader = nullptr; 109 110 _header = std::move(other._header); 111 _header.msg_name = &_socketAddress.raw(); 112 _header.msg_iov = &_dataDescriptor; 113 114 _dataDescriptor.iov_base = _buffer.data(); 115 _dataDescriptor.iov_len = _buffer.size(); 116 }; 117 118 void DarlingServer::Message::_cleanupSelf() { 119 if (_controlHeader) { 120 auto fdHeader = _descriptorHeader(); 121 if (fdHeader) { 122 for (size_t i = 0; i < _descriptorSpace(); ++i) { 123 int fd = -1; 124 memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int)); 125 if (fd != -1) { 126 close(fd); 127 } 128 } 129 } 130 free(_controlHeader); 131 _controlHeader = nullptr; 132 } 133 }; 134 135 struct cmsghdr* DarlingServer::Message::_credentialsHeader() { 136 return const_cast<struct cmsghdr*>(const_cast<const Message*>(this)->_credentialsHeader()); 137 }; 138 139 const struct cmsghdr* DarlingServer::Message::_credentialsHeader() const { 140 const struct cmsghdr* hdr = CMSG_FIRSTHDR(&_header); 141 142 while (hdr) { 143 if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_CREDENTIALS) { 144 return hdr; 145 } 146 147 hdr = CMSG_NXTHDR(const_cast<struct msghdr*>(&_header), const_cast<struct cmsghdr*>(hdr)); 148 } 149 150 return nullptr; 151 }; 152 153 struct cmsghdr* DarlingServer::Message::_descriptorHeader() { 154 return const_cast<struct cmsghdr*>(const_cast<const Message*>(this)->_descriptorHeader()); 155 }; 156 157 const struct cmsghdr* DarlingServer::Message::_descriptorHeader() const { 158 const struct cmsghdr* hdr = CMSG_FIRSTHDR(&_header); 159 160 while (hdr) { 161 if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) { 162 return hdr; 163 } 164 165 hdr = CMSG_NXTHDR(const_cast<struct msghdr*>(&_header), const_cast<struct cmsghdr*>(hdr)); 166 } 167 168 return nullptr; 169 }; 170 171 size_t DarlingServer::Message::_descriptorSpace() const { 172 auto hdr = _descriptorHeader(); 173 174 if (!hdr) { 175 return 0; 176 } 177 178 return (hdr->cmsg_len - (reinterpret_cast<uintptr_t>(CMSG_DATA(hdr)) - reinterpret_cast<uintptr_t>(hdr))) / sizeof(int); 179 }; 180 181 DarlingServer::Message::~Message() { 182 _cleanupSelf(); 183 }; 184 185 DarlingServer::Message::Message(Message&& other) { 186 _initWithOther(std::move(other)); 187 }; 188 189 DarlingServer::Message& DarlingServer::Message::operator=(Message&& other) { 190 _cleanupSelf(); 191 _initWithOther(std::move(other)); 192 return *this; 193 }; 194 195 struct msghdr& DarlingServer::Message::rawHeader() { 196 return _header; 197 }; 198 199 const struct msghdr& DarlingServer::Message::rawHeader() const { 200 return _header; 201 }; 202 203 std::vector<uint8_t>& DarlingServer::Message::data() { 204 return _buffer; 205 }; 206 207 const std::vector<uint8_t>& DarlingServer::Message::data() const { 208 return _buffer; 209 }; 210 211 DarlingServer::Address DarlingServer::Message::address() const { 212 return _socketAddress; 213 }; 214 215 void DarlingServer::Message::setAddress(Address address) { 216 _socketAddress = address; 217 _header.msg_namelen = _socketAddress.rawSize(); 218 }; 219 220 std::vector<int> DarlingServer::Message::descriptors() const { 221 std::vector<int> descriptors; 222 auto fdHeader = _descriptorHeader(); 223 224 if (fdHeader) { 225 for (size_t i = 0; i < _descriptorSpace(); ++i) { 226 int fd = -1; 227 memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int)); 228 if (fd != -1) { 229 descriptors.push_back(fd); 230 } 231 } 232 } 233 234 return descriptors; 235 }; 236 237 void DarlingServer::Message::pushDescriptor(int descriptor) { 238 if (auto fdHeader = _descriptorHeader()) { 239 for (size_t i = 0; i < _descriptorSpace(); ++i) { 240 int fd = -1; 241 memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int)); 242 if (fd != -1) { 243 continue; 244 } 245 246 memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &descriptor, sizeof(int)); 247 return; 248 } 249 } 250 251 auto oldSpace = _descriptorSpace(); 252 _ensureDescriptorHeader(oldSpace + 1); 253 memcpy(CMSG_DATA(_descriptorHeader()) + (sizeof(int) * oldSpace), &descriptor, sizeof(int)); 254 }; 255 256 int DarlingServer::Message::extractDescriptor(int descriptor) { 257 if (auto fdHeader = _descriptorHeader()) { 258 for (size_t i = 0; i < _descriptorSpace(); ++i) { 259 int fd = -1; 260 memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int)); 261 if (fd != descriptor) { 262 continue; 263 } 264 265 fd = -1; 266 memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &fd, sizeof(int)); 267 return descriptor; 268 } 269 } 270 271 return -1; 272 }; 273 274 int DarlingServer::Message::extractDescriptorAtIndex(size_t index) { 275 if (auto fdHeader = _descriptorHeader()) { 276 for (size_t i = 0, presentIndex = 0; i < _descriptorSpace(); ++i) { 277 int fd = -1; 278 memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int)); 279 if (fd == -1) { 280 continue; 281 } 282 283 if (presentIndex++ != index) { 284 continue; 285 } 286 287 int tmp = -1; 288 memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &tmp, sizeof(int)); 289 return fd; 290 } 291 } 292 293 return -1; 294 }; 295 296 void DarlingServer::Message::replaceDescriptors(const std::vector<int>& newDescriptors) { 297 _ensureDescriptorHeader(newDescriptors.size()); 298 memcpy(CMSG_DATA(_descriptorHeader()), newDescriptors.data(), sizeof(int) * newDescriptors.size()); 299 }; 300 301 bool DarlingServer::Message::copyCredentialsOut(struct ucred& outputCredentials) const { 302 auto credHeader = _credentialsHeader(); 303 304 if (credHeader) { 305 memcpy(&outputCredentials, CMSG_DATA(credHeader), sizeof(outputCredentials)); 306 return true; 307 } else { 308 return false; 309 } 310 }; 311 312 void DarlingServer::Message::copyCredentialsIn(const struct ucred& inputCredentials) { 313 _ensureCredentialsHeader(); 314 memcpy(CMSG_DATA(_credentialsHeader()), &inputCredentials, sizeof(inputCredentials)); 315 }; 316 317 void DarlingServer::Message::_ensureCredentialsHeader() { 318 if (_credentialsHeader()) { 319 return; 320 } 321 322 auto fdHeader = _descriptorHeader(); 323 auto descSpace = _descriptorSpace(); 324 size_t controlLen = CMSG_SPACE(sizeof(struct ucred)) + (descSpace > 0 ? CMSG_SPACE(sizeof(int) * descSpace) : 0); 325 auto tmp = static_cast<decltype(_controlHeader)>(malloc(controlLen)); 326 auto old = _controlHeader; 327 struct cmsghdr* credHeader = nullptr; 328 329 if (!tmp) { 330 throw std::bad_alloc(); 331 } 332 333 _controlHeader = tmp; 334 _header.msg_control = _controlHeader; 335 336 credHeader = _controlHeader; 337 338 if (descSpace > 0) { 339 auto newFdHeader = reinterpret_cast<decltype(_controlHeader)>(reinterpret_cast<char*>(_controlHeader) + CMSG_SPACE(sizeof(struct ucred))); 340 memcpy(newFdHeader, fdHeader, CMSG_SPACE(sizeof(int) * descSpace)); 341 } 342 343 free(old); 344 345 _header.msg_controllen = controlLen; 346 347 credHeader->cmsg_len = CMSG_LEN(sizeof(struct ucred)); 348 credHeader->cmsg_level = SOL_SOCKET; 349 credHeader->cmsg_type = SCM_CREDENTIALS; 350 351 struct ucred creds; 352 creds.pid = getpid(); 353 creds.uid = getuid(); 354 creds.gid = getgid(); 355 memcpy(CMSG_DATA(credHeader), &creds, sizeof(struct ucred)); 356 }; 357 358 void DarlingServer::Message::_ensureDescriptorHeader(size_t newSpace) { 359 if (_descriptorSpace() == newSpace) { 360 return; 361 } 362 363 auto credHeader = _credentialsHeader(); 364 size_t oldSpace = _descriptorSpace(); 365 size_t controlLen = (credHeader ? CMSG_SPACE(sizeof(struct ucred)) : 0) + (newSpace == 0 ? 0 : CMSG_SPACE(sizeof(int) * newSpace)); 366 367 if (controlLen == 0) { 368 free(_controlHeader); 369 _controlHeader = nullptr; 370 _header.msg_control = nullptr; 371 _header.msg_controllen = 0; 372 return; 373 } 374 375 auto tmp = static_cast<decltype(_controlHeader)>(malloc(controlLen)); 376 auto old = _controlHeader; 377 struct cmsghdr* fdHeader = nullptr; 378 379 if (!tmp) { 380 throw std::bad_alloc(); 381 } 382 383 _controlHeader = tmp; 384 _header.msg_control = _controlHeader; 385 386 if (credHeader) { 387 memcpy(_controlHeader, credHeader, CMSG_SPACE(sizeof(struct ucred))); 388 fdHeader = reinterpret_cast<decltype(_controlHeader)>(reinterpret_cast<char*>(_controlHeader) + CMSG_SPACE(sizeof(struct ucred))); 389 } else { 390 fdHeader = _controlHeader; 391 } 392 393 free(old); 394 395 _header.msg_controllen = controlLen; 396 397 if (newSpace > 0) { 398 fdHeader->cmsg_len = CMSG_LEN(sizeof(int) * newSpace); 399 fdHeader->cmsg_level = SOL_SOCKET; 400 fdHeader->cmsg_type = SCM_RIGHTS; 401 402 for (size_t i = oldSpace; i < newSpace; ++i) { 403 int fd = -1; 404 memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &fd, sizeof(int)); 405 } 406 } 407 }; 408 409 pid_t DarlingServer::Message::pid() const { 410 struct ucred creds; 411 412 if (copyCredentialsOut(creds)) { 413 return creds.pid; 414 } else { 415 return -1; 416 } 417 }; 418 419 void DarlingServer::Message::setPID(pid_t pid) { 420 _ensureCredentialsHeader(); 421 struct ucred creds; 422 copyCredentialsOut(creds); 423 creds.pid = pid; 424 copyCredentialsIn(creds); 425 }; 426 427 uid_t DarlingServer::Message::uid() const { 428 struct ucred creds; 429 430 if (copyCredentialsOut(creds)) { 431 return creds.uid; 432 } else { 433 return -1; 434 } 435 }; 436 437 void DarlingServer::Message::setUID(uid_t uid) { 438 _ensureCredentialsHeader(); 439 struct ucred creds; 440 copyCredentialsOut(creds); 441 creds.uid = uid; 442 copyCredentialsIn(creds); 443 }; 444 445 gid_t DarlingServer::Message::gid() const { 446 struct ucred creds; 447 448 if (copyCredentialsOut(creds)) { 449 return creds.gid; 450 } else { 451 return -1; 452 } 453 }; 454 455 void DarlingServer::Message::setGID(gid_t gid) { 456 _ensureCredentialsHeader(); 457 struct ucred creds; 458 copyCredentialsOut(creds); 459 creds.gid = gid; 460 copyCredentialsIn(creds); 461 }; 462 463 std::function<void()> DarlingServer::Message::sendNotificationCallback() const { 464 return _sendNotificationCallback; 465 }; 466 467 void DarlingServer::Message::setSendNotificationCallback(std::function<void()> sendNotificationCallback) { 468 _sendNotificationCallback = sendNotificationCallback; 469 }; 470 471 // 472 // message queue 473 // 474 475 void DarlingServer::MessageQueue::push(Message&& message) { 476 std::unique_lock lock(_lock); 477 _messages.push_back(std::move(message)); 478 479 if (_messages.size() > 0) { 480 auto callback = _messageArrivalNotificationCallback; 481 lock.unlock(); 482 if (callback) { 483 callback(); 484 } 485 } 486 }; 487 488 std::optional<DarlingServer::Message> DarlingServer::MessageQueue::pop() { 489 std::scoped_lock lock(_lock); 490 if (_messages.size() > 0) { 491 Message message = std::move(_messages.front()); 492 _messages.pop_front(); 493 return message; 494 } else { 495 return std::nullopt; 496 } 497 }; 498 499 bool DarlingServer::MessageQueue::sendMany(int socket) { 500 bool canSendMore = true; 501 std::scoped_lock lock(_lock); 502 struct mmsghdr mmsgs[16]; 503 size_t len = 0; 504 int ret = 0; 505 506 while (ret >= 0) { 507 len = 0; 508 for (size_t i = 0; i < _messages.size() && i < sizeof(mmsgs) / sizeof(*mmsgs); ++i) { 509 mmsgs[i].msg_hdr = _messages[i].rawHeader(); 510 mmsgs[i].msg_len = 0; 511 512 // some systems report EINVAL when sending to an address filled with null bytes. 513 auto address = reinterpret_cast<sockaddr_un*>(mmsgs[i].msg_hdr.msg_name); 514 bool isAddressEmpty = true; 515 for (size_t j = 0; j < sizeof(address->sun_path); ++j) { 516 if (address->sun_path[j] != '\0') { 517 isAddressEmpty = false; 518 break; 519 } 520 } 521 if (isAddressEmpty) { 522 mmsgs[i].msg_hdr.msg_name = nullptr; 523 mmsgs[i].msg_hdr.msg_namelen = 0; 524 } 525 526 ++len; 527 } 528 529 if (len == 0) { 530 break; 531 } 532 533 ret = sendmmsg(socket, mmsgs, len, MSG_DONTWAIT); 534 535 if (ret < 0) { 536 if (errno == EAGAIN) { 537 canSendMore = false; 538 break; 539 } else if (errno == EINTR) { 540 ret = 0; 541 } else if (errno == EPIPE || errno == ECONNREFUSED) { 542 // this means that peer of the first message we tried to send has died. 543 // we'll just drop that message and try the others. 544 _messages.pop_front(); 545 ret = 0; 546 } else { 547 throw std::system_error(errno, std::generic_category(), "Failed to send messages through socket"); 548 } 549 } 550 551 for (size_t i = 0; i < ret; ++i) { 552 auto cb = _messages.front().sendNotificationCallback(); 553 _messages.pop_front(); 554 if (cb) { 555 cb(); 556 } 557 } 558 } 559 560 return canSendMore; 561 }; 562 563 bool DarlingServer::MessageQueue::receiveMany(int socket) { 564 bool canReadMore = true; 565 std::unique_lock lock(_lock); 566 struct mmsghdr mmsgs[16]; 567 int ret = 0; 568 569 while (ret >= 0) { 570 std::array<Message, sizeof(mmsgs) / sizeof(*mmsgs)> messages; 571 572 for (size_t i = 0; i < messages.size(); ++i) { 573 mmsgs[i].msg_hdr = messages[i].rawHeader(); 574 mmsgs[i].msg_len = 0; 575 } 576 577 ret = recvmmsg(socket, mmsgs, sizeof(mmsgs) / sizeof(*mmsgs), MSG_CMSG_CLOEXEC | MSG_DONTWAIT, nullptr); 578 579 if (ret < 0) { 580 if (errno == EAGAIN) { 581 canReadMore = false; 582 break; 583 } else if (errno == EINTR) { 584 ret = 0; 585 } else { 586 throw std::system_error(errno, std::generic_category(), "Failed to receive messages through socket"); 587 } 588 } 589 590 for (size_t i = 0; i < ret; ++i) { 591 messages[i].rawHeader() = mmsgs[i].msg_hdr; 592 messages[i].data().resize(mmsgs[i].msg_len); 593 messages[i].setAddress(Address(*(const struct sockaddr_un*)mmsgs[i].msg_hdr.msg_name, mmsgs[i].msg_hdr.msg_namelen)); 594 _messages.push_back(std::move(messages[i])); 595 } 596 } 597 598 if (_messages.size() > 0) { 599 auto callback = _messageArrivalNotificationCallback; 600 lock.unlock(); 601 if (callback) { 602 callback(); 603 } 604 } 605 606 return canReadMore; 607 }; 608 609 void DarlingServer::MessageQueue::setMessageArrivalNotificationCallback(std::function<void()> messageArrivalNotificationCallback) { 610 std::unique_lock lock(_lock); 611 _messageArrivalNotificationCallback = messageArrivalNotificationCallback; 612 }; 613 614 bool DarlingServer::MessageQueue::empty() const { 615 std::unique_lock lock(_lock); 616 return _messages.empty(); 617 };