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
80#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
81using UnixStreamControlLockHook = void (*)();
82void setUnixStreamControlLockHookForTest(UnixStreamControlLockHook hook);
83#endif
84
92 friend class UnixSocket;
93
94 public:
96
97 private:
99 class Stream {
100 public:
101 Stream();
102 ~Stream();
103
104 size_t write(const uint8_t* buffer, size_t count, bool block,
106 bool* interrupted = nullptr);
107 size_t writeVectors(const struct iovec* vectors, size_t vectorCount, bool block,
108 const SharedPointer<SocketRights>& rights, bool* interrupted = nullptr);
109 size_t read(uint8_t* buffer, size_t count, bool block,
110 SharedPointer<SocketRights>* rights = nullptr, bool* interrupted = nullptr);
111 size_t readVectors(struct iovec* vectors, size_t vectorCount, bool block,
112 SharedPointer<SocketRights>* rights, bool* interrupted = nullptr);
113
114 bool canWrite(bool block);
115 bool canRead(bool block);
116 uint64_t readableGeneration() const;
117 uint64_t writableGeneration() const;
118 void disableWrites();
119 void disableReads();
120 void monitor(Semaphore* waiter);
121 void monitor(Thread* thread, Event* event);
122 void cullMonitorTargets(Semaphore* waiter);
123 void cullMonitorTargets(Event* event);
124
125 Buffer<uint8_t, true>& buffer() {
126 return m_Bytes;
127 }
128
129 private:
131 public:
132 explicit ControlGuard(Stream& stream);
134
135 private:
136 Stream& m_Stream;
137 LockGuard<Mutex> m_Guard;
138 };
139
140 struct Control {
141 Control(uint64_t offset, const SharedPointer<SocketRights>& newRights)
142 : byteOffset(offset), rights(newRights) {}
143
144 uint64_t byteOffset;
146 };
147
148 void discardControls();
149 void discardControlsIfRequested();
150
151 Buffer<uint8_t, true> m_Bytes;
153 UnixStreamSerializationGate m_ReceiveLock;
154 Mutex m_ControlLock;
155 Atomic<bool> m_DiscardControlsRequested;
156 List<Control*> m_Controls;
157 uint64_t m_BytesWritten;
158 uint64_t m_BytesRead;
159 };
160
161 Stream m_FirstStream;
162 Stream m_SecondStream;
163 bool m_Active;
164 bool m_Failed;
165 bool m_Closed[2];
166 bool m_ReadShutdown[2];
167 bool m_WriteShutdown[2];
168 struct ucred m_Creds[2];
169};
170
178 public:
179 SyncStatus sync() override {
180 return SyncStatus::Success;
181 }
182
184 virtual ~UnixFilesystem();
185
186 virtual bool initialise(Disk* pDisk) {
187 return false;
188 }
189
190 virtual File* getRoot() const {
191 return m_pRoot;
192 }
193
194 virtual const String& getVolumeLabel() const {
195 return m_VolumeLabel;
196 }
197
198 // Serialises pathname lookup, binding, unlink, and descriptor teardown for
199 // the in-memory socket namespace.
200 static Mutex& namespaceLock();
201
202 virtual void truncate(File* pFile) {}
203
204 virtual void fileAttributeChanged(File* pFile) {}
205
206 virtual void cacheDirectoryContents(File* pFile) {
207 if (pFile->isDirectory()) {
208 Directory* pDir = Directory::fromFile(pFile);
210 }
211 }
212
213 virtual void extend(File* pFile, size_t size) {}
214
215 protected:
216 virtual bool createFile(File* parent, const String& filename, uint32_t mask);
217 virtual bool createDirectory(File* parent, const String& filename, uint32_t mask);
218 virtual bool createSymlink(File* parent, const String& filename, const String& value) {
219 return false;
220 }
221 virtual bool removeNode(File* parent, const String& filename, File* file);
222 virtual bool renameNode(Directory*, const String&, File*, Directory*, const String&, File*) {
223 return true;
224 }
225
226 private:
227 File* m_pRoot;
228
229 static String m_VolumeLabel;
230 static Mutex m_NamespaceLock;
231
232 virtual bool isBytewise() const {
233 return true;
234 }
235};
236
240class UnixSocket : public File {
241 public:
242 enum SocketType { Streaming, Datagram };
243
244 enum SocketState {
245 Listening, // listening for connections
246 Connecting, // waiting for bind to be acked
247 Inactive, // unbound
248 Active, // bound, ready for data transfer
249 Closed // unbound but was once bound
250 };
251
252 UnixSocket(const String& name, Filesystem* pFs, File* pParent, UnixSocket* other = nullptr,
253 SocketType type = Datagram);
254 virtual ~UnixSocket();
255
256 virtual uint64_t readBytewise(uint64_t location, uint64_t size, uintptr_t buffer,
257 bool bCanBlock = true);
258 virtual uint64_t writeBytewise(uint64_t location, uint64_t size, uintptr_t buffer,
259 bool bCanBlock = true);
260
261 uint64_t recvfrom(uint64_t size, uintptr_t buffer, bool bCanBlock, String& from);
262
264 bool sendDatagram(uint64_t size, uintptr_t buffer, bool bCanBlock, uintptr_t source,
265 const SharedPointer<SocketRights>& rights, int* error = nullptr);
266
268 bool receiveDatagram(uint64_t size, uintptr_t buffer, bool bCanBlock, String& from,
269 SharedPointer<SocketRights>& rights, uint64_t& bytesRead,
270 uint64_t& datagramLength);
271
273 uint64_t sendStream(uint64_t size, uintptr_t buffer, bool bCanBlock,
274 const SharedPointer<SocketRights>& rights, bool* interrupted = nullptr);
275 uint64_t sendStream(const struct iovec* vectors, size_t vectorCount, bool bCanBlock,
276 const SharedPointer<SocketRights>& rights, bool* interrupted = nullptr);
277
279 uint64_t receiveStream(uint64_t size, uintptr_t buffer, bool bCanBlock,
280 SharedPointer<SocketRights>* rights, bool* interrupted = nullptr);
281 uint64_t receiveStream(struct iovec* vectors, size_t vectorCount, bool bCanBlock,
282 SharedPointer<SocketRights>* rights, bool* interrupted = nullptr);
283
284 virtual int select(bool bWriting = false, int timeout = 0);
285
286 virtual bool isSocket() const {
287 return true;
288 }
289
290 virtual bool isSeekable() const {
291 return false;
292 }
293
294 // Bind this socket to another socket.
295 // The other socket should not already be bound.
296 bool bind(UnixSocket* other, bool block = false);
297
298 // Break the bound socket.
299 void unbind();
300
301 // Half-close one or both directions of a connected stream.
302 bool shutdown(int how);
303
304 // Whether writes can no longer reach the peer.
305 bool writeShutdown() const;
306
307 // Whether reads have reached a permanent EOF.
308 bool readShutdown() const;
309
310 // Acknowledges binding from another socket
311 void acknowledgeBind();
312
313 // Add a new socket for a client/server connection (for accept())
314 bool addSocket(UnixSocket* socket);
315
316 // Get the next socket in the listening queue (for non-datagram sockets).
317 UnixSocket* getSocket(bool block = false);
318
319 // Add a semaphore for the requested readiness directions.
320 void addWaiter(Semaphore* waiter, bool read, bool write);
321
322 // Remove a waiter semaphore.
323 void removeWaiter(Semaphore* waiter);
324
325 // Add an event to fire when the socket data changes.
326 void addWaiter(Thread* thread, Event* event);
327
328 // Remove a socket data change event.
329 void removeWaiter(Event* event);
330
331 // Get this socket's type
332 SocketType getType() const {
333 return m_Type;
334 }
335
336 // Get this socket's state
337 SocketState getState() const;
338
339 // Whether this endpoint completed a connection, including a peer that has
340 // since closed.
341 bool wasConnected() const;
342
345
346 // Mark a queued connection as failed and wake all poll/read/write waiters.
347 void failConnection();
348
349 // Mark this socket a listening socket
350 bool markListening();
351
352 // Get our credentials.
353 struct ucred getCredentials() const {
354 return m_Creds;
355 }
356
357 // Get the credentials of the other side.
358 struct ucred getPeerCredentials() const;
359
360 private:
361 typedef Buffer<uint8_t, true> UnixSocketStream;
362
363 void setCreds();
364 SocketState getStateLocked() const;
365 UnixSocketConnection::Stream* incomingStream(
366 const SharedPointer<UnixSocketConnection>& connection) const;
367 UnixSocketConnection::Stream* outgoingStream(
368 const SharedPointer<UnixSocketConnection>& connection) const;
369
370 virtual bool isBytewise() const {
371 return true;
372 }
373
374 struct buf {
375 char* pBuffer;
376 uint64_t len;
377 char* remotePath; // Path of the socket that dumped data here, if any.
378 size_t remotePathLen;
380 };
381
382 static void destroyDatagram(struct buf* datagram);
383
384 SocketType m_Type;
385 SocketState m_State;
386
387 // For datagram sockets.
388
389 // Note: "servers" own the actual UNIX socket address, while clients get a
390 // virtual address to track their existence (or are bound to a specific
391 // name themselves).
393 DatagramBuffer m_Datagrams;
394
395 // For stream sockets.
396
397 // Listener readiness queue. Connected stream data lives in m_Connection.
398 UnixSocketStream m_Stream;
399
401 bool m_ConnectionSide;
402
403 // List of sockets pending accept() on this socket.
404 List<UnixSocket*> m_PendingSockets;
405
406 // Credentials associated at the time of bind()
407 struct ucred m_Creds;
408
409 // Serialises endpoint state and connection ownership. Buffer operations
410 // use their own locks and are never performed while this is held.
411 static Mutex m_ConnectionLock;
412};
413
417class UnixDirectory : public Directory {
418 public:
419 UnixDirectory(const String& name, Filesystem* pFs, File* pParent);
420 virtual ~UnixDirectory();
421
422 bool addEntry(const String& filename, File* pFile);
423 bool removeEntry(const String& filename, File* pFile);
424 bool removeFromParent(UnixDirectory* parent, const String& filename);
425
426 virtual void cacheDirectoryContents();
427
428 private:
429 Mutex m_Lock;
430};
431
432#endif
static Directory * fromFile(File *pF)
Definition Directory.h:148
virtual void cacheDirectoryContents()
Definition Directory.cc:322
Definition Disk.h:35
Definition Event.h:49
Definition File.h:74
virtual uint64_t read(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
Definition File.cc:230
virtual uint64_t write(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
Definition File.cc:315
virtual bool isDirectory()
Definition File.cc:721
Definition List.h:61
Definition Mutex.h:56
Utility class to provide a ring buffer.
Definition RingBuffer.h:62
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
A vector / dynamic array.
Definition Vector.h:33