The Pedigree Project 0.1
UnixFilesystem.h
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#ifndef _UNIX_FILESYSTEM_H
21#define _UNIX_FILESYSTEM_H
22
23#include "pedigree/kernel/LockGuard.h"
24#include "pedigree/kernel/process/Semaphore.h"
25#include "pedigree/kernel/utilities/Buffer.h"
26#include "pedigree/kernel/utilities/List.h"
27#include "pedigree/kernel/utilities/RingBuffer.h"
28#include "pedigree/kernel/utilities/SharedPointer.h"
29#include "pedigree/kernel/utilities/Vector.h"
30
31#include "modules/system/vfs/Directory.h"
32#include "modules/system/vfs/File.h"
33#include "modules/system/vfs/Filesystem.h"
34#include <sys/socket.h>
35
36class Mutex;
37class FileDescriptor;
38class UnixSocket;
39
40#if defined(PEDIGREE_EXTERNAL_SOURCE)
42#else
44#endif
45
48 public:
49 enum : size_t { MaximumDescriptors = 253, MaximumInFlight = 16384 };
50
52
54 static bool create(size_t descriptorCount, SharedPointer<SocketRights>& rights);
55
56 void append(FileDescriptor* descriptor);
57 size_t count() const;
58 FileDescriptor* descriptor(size_t index) const;
59
60#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
61 static size_t inFlightForTest();
62#endif
63
64 private:
65 explicit SocketRights(size_t reservation);
66
67 SocketRights(const SocketRights&) = delete;
68 SocketRights& operator=(const SocketRights&) = delete;
69
70 Vector<FileDescriptor*> m_Descriptors;
71 size_t m_Reservation;
72
73 static Mutex m_InFlightLock;
74 static size_t m_InFlight;
75};
76
77#define MAX_UNIX_DGRAM_BACKLOG 65536
78#define MAX_UNIX_STREAM_QUEUE 65536
79#define MAX_UNIX_PACKET_BACKLOG 64
80
81#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
82using UnixStreamControlLockHook = void (*)();
83void setUnixStreamControlLockHookForTest(UnixStreamControlLockHook hook);
84#endif
85
93 friend class UnixSocket;
94
95 public:
96 explicit UnixSocketConnection(bool packets = false);
97
98 private:
100 class Stream {
101 public:
102 explicit Stream(bool packets);
103 ~Stream();
104
105 size_t write(const uint8_t* buffer, size_t count, bool block,
107 bool* interrupted = nullptr);
108 size_t writeVectors(const struct iovec* vectors, size_t vectorCount, bool block,
109 const SharedPointer<SocketRights>& rights, bool* interrupted = nullptr);
110 size_t read(uint8_t* buffer, size_t count, bool block,
111 SharedPointer<SocketRights>* rights = nullptr, bool* interrupted = nullptr);
112 size_t readVectors(struct iovec* vectors, size_t vectorCount, bool block,
113 SharedPointer<SocketRights>* rights, bool* interrupted = nullptr);
114
115 bool writePacket(const uint8_t* buffer, size_t count, bool block,
116 const SharedPointer<SocketRights>& rights, bool* interrupted);
117 bool readPacket(uint8_t* buffer, size_t count, bool block, SharedPointer<SocketRights>& rights,
118 uint64_t& bytesRead, uint64_t& packetLength, bool* interrupted);
119
120 Buffer<uint8_t, true>& records() {
121 return m_Records;
122 }
123
124 bool canWrite(bool block);
125 bool canRead(bool block);
126 uint64_t readableGeneration() const;
127 uint64_t writableGeneration() const;
128 void disableWrites();
129 void disableReads();
130 void monitor(Semaphore* waiter);
131 void monitor(Thread* thread, Event* event);
132 void cullMonitorTargets(Semaphore* waiter);
133 void cullMonitorTargets(Event* event);
134
135 Buffer<uint8_t, true>& buffer() {
136 return m_Bytes;
137 }
138
139 private:
141 public:
142 explicit ControlGuard(Stream& stream);
144
145 private:
146 Stream& m_Stream;
147 LockGuard<Mutex> m_Guard;
148 };
149
150 struct Control {
151 Control(uint64_t offset, const SharedPointer<SocketRights>& newRights)
152 : byteOffset(offset), rights(newRights) {}
153
154 uint64_t byteOffset;
156 };
157
158 void discardControls();
159 void discardControlsIfRequested();
160
161 struct Packet {
162 Packet() : bytes(nullptr), length(0), rights() {}
163 ~Packet() {
164 delete[] bytes;
165 }
166 uint8_t* bytes;
167 size_t length;
169 };
170
171 const bool m_Packets;
172 Buffer<uint8_t, true> m_Records;
173 List<Packet*> m_PendingPackets;
174 Buffer<uint8_t, true> m_Bytes;
176 UnixStreamSerializationGate m_ReceiveLock;
177 Mutex m_ControlLock;
178 Atomic<bool> m_DiscardControlsRequested;
179 List<Control*> m_Controls;
180 uint64_t m_BytesWritten;
181 uint64_t m_BytesRead;
182 };
183
184 Stream m_FirstStream;
185 Stream m_SecondStream;
186 bool m_Active;
187 bool m_Failed;
188 bool m_Closed[2];
189 bool m_ReadShutdown[2];
190 bool m_WriteShutdown[2];
191 struct ucred m_Creds[2];
192};
193
201 public:
202 SyncStatus sync() override {
203 return SyncStatus::Success;
204 }
205
207 virtual ~UnixFilesystem();
208
209 virtual bool initialise(Disk* pDisk) {
210 return false;
211 }
212
213 virtual File* getRoot() const {
214 return m_pRoot;
215 }
216
217 virtual const String& getVolumeLabel() const {
218 return m_VolumeLabel;
219 }
220
221 // Serialises pathname lookup, binding, unlink, and descriptor teardown for
222 // the in-memory socket namespace.
223 static Mutex& namespaceLock();
224
225 virtual void truncate(File* pFile) {}
226
227 virtual void fileAttributeChanged(File* pFile) {}
228
229 virtual void cacheDirectoryContents(File* pFile) {
230 if (pFile->isDirectory()) {
231 Directory* pDir = Directory::fromFile(pFile);
233 }
234 }
235
236 virtual void extend(File* pFile, size_t size) {}
237
238 protected:
239 virtual bool createFile(File* parent, const String& filename, uint32_t mask);
240 virtual bool createDirectory(File* parent, const String& filename, uint32_t mask);
241 virtual bool createSymlink(File* parent, const String& filename, const String& value) {
242 return false;
243 }
244 virtual bool removeNode(File* parent, const String& filename, File* file);
245 virtual bool renameNode(Directory*, const String&, File*, Directory*, const String&, File*) {
246 return true;
247 }
248
249 private:
250 File* m_pRoot;
251
252 static String m_VolumeLabel;
253 static Mutex m_NamespaceLock;
254
255 virtual bool isBytewise() const {
256 return true;
257 }
258};
259
263class UnixSocket : public File {
264 public:
265 enum SocketType { Streaming, Datagram, SequencedPacket };
266
267 enum SocketState {
268 Listening, // listening for connections
269 Connecting, // waiting for bind to be acked
270 Inactive, // unbound
271 Active, // bound, ready for data transfer
272 Closed // unbound but was once bound
273 };
274
275 UnixSocket(const String& name, Filesystem* pFs, File* pParent, UnixSocket* other = nullptr,
276 SocketType type = Datagram);
277 virtual ~UnixSocket();
278
279 virtual uint64_t readBytewise(uint64_t location, uint64_t size, uintptr_t buffer,
280 bool bCanBlock = true);
281 virtual uint64_t writeBytewise(uint64_t location, uint64_t size, uintptr_t buffer,
282 bool bCanBlock = true);
283
284 uint64_t recvfrom(uint64_t size, uintptr_t buffer, bool bCanBlock, String& from);
285
287 bool sendDatagram(uint64_t size, uintptr_t buffer, bool bCanBlock, uintptr_t source,
288 const SharedPointer<SocketRights>& rights, int* error = nullptr);
289
291 bool receiveDatagram(uint64_t size, uintptr_t buffer, bool bCanBlock, String& from,
292 SharedPointer<SocketRights>& rights, uint64_t& bytesRead,
293 uint64_t& datagramLength);
294
296 uint64_t sendStream(uint64_t size, uintptr_t buffer, bool bCanBlock,
297 const SharedPointer<SocketRights>& rights, bool* interrupted = nullptr);
298 uint64_t sendStream(const struct iovec* vectors, size_t vectorCount, bool bCanBlock,
299 const SharedPointer<SocketRights>& rights, bool* interrupted = nullptr);
300
302 uint64_t receiveStream(uint64_t size, uintptr_t buffer, bool bCanBlock,
303 SharedPointer<SocketRights>* rights, bool* interrupted = nullptr);
304 uint64_t receiveStream(struct iovec* vectors, size_t vectorCount, bool bCanBlock,
305 SharedPointer<SocketRights>* rights, bool* interrupted = nullptr);
306
308 bool sendPacket(uint64_t size, uintptr_t buffer, bool bCanBlock,
309 const SharedPointer<SocketRights>& rights, int* error = nullptr);
310 bool receivePacket(uint64_t size, uintptr_t buffer, bool bCanBlock,
311 SharedPointer<SocketRights>& rights, uint64_t& bytesRead,
312 uint64_t& packetLength, bool* interrupted = nullptr);
313
314 virtual int select(bool bWriting = false, int timeout = 0);
315
316 virtual bool isSocket() const {
317 return true;
318 }
319
320 virtual bool isSeekable() const {
321 return false;
322 }
323
324 // Bind this socket to another socket.
325 // The other socket should not already be bound.
326 bool bind(UnixSocket* other, bool block = false);
327
328 // Break the bound socket.
329 void unbind();
330
331 // Half-close one or both directions of a connected stream.
332 bool shutdown(int how);
333
334 // Whether writes can no longer reach the peer.
335 bool writeShutdown() const;
336
337 // Whether reads have reached a permanent EOF.
338 bool readShutdown() const;
339
340 // Acknowledges binding from another socket
341 void acknowledgeBind();
342
343 // Add a new socket for a client/server connection (for accept())
344 bool addSocket(UnixSocket* socket);
345
346 // Get the next socket in the listening queue (for non-datagram sockets).
347 UnixSocket* getSocket(bool block = false);
348
349 // Add a semaphore for the requested readiness directions.
350 void addWaiter(Semaphore* waiter, bool read, bool write);
351
352 // Remove a waiter semaphore.
353 void removeWaiter(Semaphore* waiter);
354
355 // Add an event to fire when the socket data changes.
356 void addWaiter(Thread* thread, Event* event);
357
358 // Remove a socket data change event.
359 void removeWaiter(Event* event);
360
361 // Get this socket's type
362 SocketType getType() const {
363 return m_Type;
364 }
365
366 // Get this socket's state
367 SocketState getState() const;
368
369 // Whether this endpoint completed a connection, including a peer that has
370 // since closed.
371 bool wasConnected() const;
372
375
376 // Mark a queued connection as failed and wake all poll/read/write waiters.
377 void failConnection();
378
379 // Mark this socket a listening socket
380 bool markListening();
381
382 // Get our credentials.
383 struct ucred getCredentials() const {
384 return m_Creds;
385 }
386
387 // Get the credentials of the other side.
388 struct ucred getPeerCredentials() const;
389
390 private:
391 typedef Buffer<uint8_t, true> UnixSocketStream;
392
393 void setCreds();
394 void notifyStream(UnixSocketConnection::Stream* stream);
395 SocketState getStateLocked() const;
396 UnixSocketConnection::Stream* incomingStream(
397 const SharedPointer<UnixSocketConnection>& connection) const;
398 UnixSocketConnection::Stream* outgoingStream(
399 const SharedPointer<UnixSocketConnection>& connection) const;
400
401 virtual bool isBytewise() const {
402 return true;
403 }
404
405 struct buf {
406 char* pBuffer;
407 uint64_t len;
408 char* remotePath; // Path of the socket that dumped data here, if any.
409 size_t remotePathLen;
411 };
412
413 static void destroyDatagram(struct buf* datagram);
414
415 SocketType m_Type;
416 SocketState m_State;
417
418 // For datagram sockets.
419
420 // Note: "servers" own the actual UNIX socket address, while clients get a
421 // virtual address to track their existence (or are bound to a specific
422 // name themselves).
424 DatagramBuffer m_Datagrams;
425
426 // For stream sockets.
427
428 // Listener readiness queue. Connected stream data lives in m_Connection.
429 UnixSocketStream m_Stream;
430
432 bool m_ConnectionSide;
433
434 // List of sockets pending accept() on this socket.
435 List<UnixSocket*> m_PendingSockets;
436
437 // Credentials associated at the time of bind()
438 struct ucred m_Creds;
439
440 // Serialises endpoint state and connection ownership. Buffer operations
441 // use their own locks and are never performed while this is held.
442 static Mutex m_ConnectionLock;
443};
444
448class UnixDirectory : public Directory {
449 public:
450 UnixDirectory(const String& name, Filesystem* pFs, File* pParent);
451 virtual ~UnixDirectory();
452
453 bool addEntry(const String& filename, File* pFile);
454 bool removeEntry(const String& filename, File* pFile);
455 bool removeFromParent(UnixDirectory* parent, const String& filename);
456
457 virtual void cacheDirectoryContents();
458
459 private:
460 Mutex m_Lock;
461};
462
463#endif
static Directory * fromFile(File *pF)
Definition Directory.h:151
virtual void cacheDirectoryContents()
Definition Directory.cc:332
Definition Disk.h:35
Definition Event.h:49
Definition File.h:75
virtual uint64_t read(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
Definition File.cc:239
virtual uint64_t write(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
Definition File.cc:342
virtual bool isDirectory()
Definition File.cc:804
Definition List.h:61
Definition Mutex.h:56
static bool create(size_t descriptorCount, SharedPointer< SocketRights > &rights)
virtual void cacheDirectoryContents()
virtual bool renameNode(Directory *, const String &, File *, Directory *, const String &, File *)
virtual bool createFile(File *parent, const String &filename, uint32_t mask)
SyncStatus sync() override
virtual const String & getVolumeLabel() const
virtual bool removeNode(File *parent, const String &filename, File *file)
virtual bool createDirectory(File *parent, const String &filename, uint32_t mask)
virtual File * getRoot() const
virtual bool initialise(Disk *pDisk)
virtual bool createSymlink(File *parent, const String &filename, const String &value)
uint64_t sendStream(uint64_t size, uintptr_t buffer, bool bCanBlock, const SharedPointer< SocketRights > &rights, bool *interrupted=nullptr)
virtual bool isBytewise() const
bool sendDatagram(uint64_t size, uintptr_t buffer, bool bCanBlock, uintptr_t source, const SharedPointer< SocketRights > &rights, int *error=nullptr)
virtual bool isSeekable() const
virtual uint64_t writeBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
virtual uint64_t readBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
virtual bool isSocket() const
uint64_t receiveStream(uint64_t size, uintptr_t buffer, bool bCanBlock, SharedPointer< SocketRights > *rights, bool *interrupted=nullptr)
virtual int select(bool bWriting=false, int timeout=0)
bool receiveDatagram(uint64_t size, uintptr_t buffer, bool bCanBlock, String &from, SharedPointer< SocketRights > &rights, uint64_t &bytesRead, uint64_t &datagramLength)
ReadinessGenerations readinessGenerations() override
bool sendPacket(uint64_t size, uintptr_t buffer, bool bCanBlock, const SharedPointer< SocketRights > &rights, int *error=nullptr)
A vector / dynamic array.
Definition Vector.h:33