message.hpp
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 #ifndef _DARLINGSERVER_MESSAGE_HPP_ 21 #define _DARLINGSERVER_MESSAGE_HPP_ 22 23 #include <sys/socket.h> 24 #include <sys/un.h> 25 #include <vector> 26 #include <cstdint> 27 #include <deque> 28 #include <mutex> 29 #include <optional> 30 #include <functional> 31 32 namespace DarlingServer { 33 class Address { 34 private: 35 struct sockaddr_un _address; 36 size_t _size; 37 38 public: 39 Address(); 40 Address(const struct sockaddr_un& rawAddress, size_t addressSize = sizeof(struct sockaddr_un)); 41 42 struct sockaddr_un& raw(); 43 const struct sockaddr_un& raw() const; 44 45 size_t rawSize() const; 46 void setRawSize(size_t newRawSize); 47 }; 48 49 /** 50 * A C++ wrapper for local (Unix) SOCK_DGRAM/SOCK_SEQPACKET socket messages, with support for file descriptors (SCM_RIGHTS) and credentials (SCM_CREDENTIALS). 51 */ 52 class Message { 53 private: 54 struct msghdr _header; 55 struct iovec _dataDescriptor; 56 std::vector<uint8_t> _buffer; 57 struct cmsghdr* _controlHeader = nullptr; 58 Address _socketAddress; 59 std::function<void()> _sendNotificationCallback = nullptr; 60 61 void _initWithOther(Message&&); 62 void _cleanupSelf(); 63 64 struct cmsghdr* _credentialsHeader(); 65 const struct cmsghdr* _credentialsHeader() const; 66 struct cmsghdr* _descriptorHeader(); 67 const struct cmsghdr* _descriptorHeader() const; 68 size_t _descriptorSpace() const; 69 70 void _ensureCredentialsHeader(); 71 void _ensureDescriptorHeader(size_t descriptorSpace); 72 73 public: 74 /** 75 * Default-initializes a Message. 76 * 77 * By default, the data buffer holds 256 bytes and the control data buffer has space for 4 descriptors. 78 * 79 * If this Message is being used to receive a message from a socket, you must preallocate 80 * the buffers for the recvmsg/recvmmsg call. The buffers are already preallocated to the 81 * sizes specified by in this constructor, however, if you wish to grow the data buffer, 82 * you can call pushData() with a null buffer pointer and a non-zero size. If you wish to 83 * grow the control data buffer, you can call pushDescriptor() with a descriptor value of `-1`. 84 */ 85 Message(size_t bufferSpace = 256, size_t descriptorSpace = 4, std::function<void()> sendNotificationCallback = nullptr); 86 ~Message(); 87 88 Message(Message&&); 89 Message& operator=(Message&&); 90 91 Message(const Message&) = delete; 92 Message& operator=(const Message&) = delete; 93 94 struct msghdr& rawHeader(); 95 const struct msghdr& rawHeader() const; 96 97 std::vector<uint8_t>& data(); 98 const std::vector<uint8_t>& data() const; 99 100 Address address() const; 101 void setAddress(Address address); 102 103 bool copyCredentialsOut(struct ucred& outputCredentials) const; 104 void copyCredentialsIn(const struct ucred& inputCredentials); 105 106 pid_t pid() const; 107 void setPID(pid_t pid); 108 109 uid_t uid() const; 110 void setUID(uid_t uid); 111 112 gid_t gid() const; 113 void setGID(gid_t gid); 114 115 std::function<void()> sendNotificationCallback() const; 116 void setSendNotificationCallback(std::function<void()> sendNotificationCallback); 117 118 /** 119 * Returns an array of all the descritors currently owned by this Message. 120 * 121 * Note that the descriptors are still owned by this Message during and after this call. 122 * Callers should NOT close the descriptors they receive in the returned vector. 123 * 124 * See extractDescriptor() for a method that will transfer ownership of a descriptor to the caller. 125 */ 126 std::vector<int> descriptors() const; 127 128 /** 129 * Acquires ownership of the given descriptor. 130 * 131 * Note that callers should NOT close the descriptor after a call to this method. 132 * This Message becomes the owner of the descriptor and will take care of closing it. 133 */ 134 void pushDescriptor(int descriptor); 135 136 /** 137 * Extracts a single descriptor from this Message, transferring ownership of it to the caller. 138 * 139 * @returns The descriptor that was extracted, or `-1` if it was not found. 140 */ 141 int extractDescriptor(int descriptor); 142 143 /** 144 * Like extractDescriptor(), but extracts it based on its index in the vector returned by descriptors(). 145 */ 146 int extractDescriptorAtIndex(size_t index); 147 148 /** 149 * Gives up ownership of the descriptors previously held by this Message and acquires ownership 150 * of the descriptors passed in the given vector. 151 * 152 * Note that this method does not return the old descriptors in any way, 153 * so if the caller wishes to know what they were, they must call descriptors() before calling this method. 154 */ 155 void replaceDescriptors(const std::vector<int>& newDescriptors); 156 }; 157 158 /** 159 * A thread-safe Message queue with methods for sending and receiving messages. 160 */ 161 class MessageQueue { 162 private: 163 std::deque<Message> _messages; 164 mutable std::mutex _lock; 165 std::function<void()> _messageArrivalNotificationCallback = nullptr; 166 167 public: 168 void setMessageArrivalNotificationCallback(std::function<void()> messageArrivalNotificationCallback); 169 170 void push(Message&& message); 171 std::optional<Message> pop(); 172 173 bool sendMany(int socket); 174 bool receiveMany(int socket); 175 176 bool empty() const; 177 }; 178 }; 179 180 #endif // _DARLINGSERVER_MESSAGE_HPP_