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_