aboutsummaryrefslogtreecommitdiffstats
path: root/include/NT.h
blob: a24d9d405704392b7a01ffaf0957a6b6c7c4dfcf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#pragma once
#include <cstdint>
#include <set>
#include <vector>
#include <string>

#if defined(_WIN32) && defined(NT_CONSOLE_APP)
#define NT_API
#elif defined(_WIN32) && defined(NT_EXPORTS)
#define NT_API __declspec(dllexport)
#elif defined(_WIN32)
#define NT_API __declspec(dllimport)
#else
#define NT_API
#endif

enum OBJECT_TYPE {
    MULTIGROUP,
    RELATION,
    TUPLE,
    ATTRIBUTE,
    TRANSACTION
};

enum METHOD {
    OPEN,
    CLOSE,
    PARSE, // To plug a secondary namespace
    SECURITY
};

enum AUTH_CLAIM {
    READ,
    WRITE
};

enum AUTH_METHOD {
    CERTIFICATE,
    PLAIN_TEXT
};

namespace nt
{
	class NT_API ObjectManager
	{
	public:
		class IObject {
		public:
			virtual ~IObject() = default;
		};
        class Multigroup : IObject {};
        class Relation : IObject {};
        class Tuple : IObject {};
        class Transaction : IObject {};
        struct object_type {
            OBJECT_TYPE label;
            // If the object is not durable. E.g.: TRANSACTION
            bool disposable;
            std::set<METHOD> methods;
        };
        struct registry_head {
            uint32_t reference_count;
            uint32_t handle_count;
            struct object_type* type;
            std::vector<std::string> path;
            //security_descriptor to be added later, maybe also a set of labels
        };
        struct registry {
            struct registry_head* head;
            IObject object;
            // TODO: Treat as a list for now, but ideally it's a tree
            struct registry* next;
        };
        struct registry** entries;
        // Looks into this registry and attempts to retrieve the entry
		struct registry* Find(const std::vector<std::string> object_path) { return nullptr; }
	};

    class NT_API PermissionsManager
    {
    public:
        // For validating connections at login
		std::set<AUTH_CLAIM> Firewall(AUTH_METHOD method) { return {}; }
		// For validating permission to an object
		const bool Access(const ObjectManager::registry* object, const void* connection_context) {
			// Checks the security descriptor on the head of the object we find in the ObjectManager::registry
			// Then additionally check other metadata yet to be defined in the connection_context,
			// like user group, policy, etc.
			// Yet to decide if this should be summoned at every attempt to get ahold of an object,
			// that might produce significant overhead. How can we solve this?
			return object != nullptr && connection_context != nullptr;
		}
	};

    class NT_API NamespaceReferenceManager
    {
    };
    
    class NT_API CursorManager
    {
    };
    
    class NT_API IdentityManager
    {
    public:
        // Looks into the methods of the object type and asserts if it can be opened
		const bool CanOpen(ObjectManager::registry* object) { return object != nullptr; }
		const bool CanClose(ObjectManager::registry* object) { return object != nullptr; }
	};

    class NT_API LifecycleManager
    {
    public:
        // If object is not being monitored already, monitors the lifecycle by updating the handle count.
        // Maybe also look at the reference count and kill some categories of disposable objects no longer referenced by other objects, like transactions.
        // Think of other use cases later.
		void Monitor(ObjectManager::registry* object) {}
        // Serializes contention for the change of a mutable reference.
        // This can be used in, for example, the HEAD of a branch to serialize the access.
        // If the object does not causes contention, like a relation (since they are immutable, just like multigroups, all snapshots)
        // then just approve, as they do not cause any contention. Transactions also do not cause any, 
        // the only things that do are mutable reference states in shared sessions,
        // for example: the HEAD of a branch, namespace collisions (creating two branches with the same name, or two multigroups with the same name from the same state, etc),
        // multi-branch atomic commits (which I wish to not have as it damages isolation), 
        // garbage collection of old state (as in, we want to delete an old-enough history to save up space), etc.
		const bool Contention(ObjectManager::registry* object){ return object != nullptr; }
        // The inverse of `Monitor`, stops monitoring.
        // Maybe garbage collect here also if the counters goes to zero.
		void Unmonitor(ObjectManager::registry* object) {}
    };

    class NT_API HandlerManager
    {
    public:
        // This is supposed to represent an authorized access to a certain object in the registry
        // This increases the handle count in the object manager
        // We should consider adding on the object manager a vector of all the handles that refer to an object
		struct handle {
			ObjectManager::registry* object = nullptr;
			void* connection_context = nullptr;
		};
		void DeallocateHandle(struct handle* handle) {}
		struct handle Open(std::vector<std::string> object_path, void* connection_context) {
			ObjectManager objects;
			PermissionsManager permissions;
			IdentityManager identities;
			LifecycleManager lifecycles;
			ObjectManager::registry* retrieved_object = objects.Find((const std::vector<std::string>)object_path);
			if (permissions.Access(retrieved_object, (const void*)connection_context)
				&& identities.CanOpen(retrieved_object)
				&& lifecycles.Contention(retrieved_object)) {
				// Starts monitoring this guy
				lifecycles.Monitor(retrieved_object);
				return { retrieved_object, connection_context }; // Return a successful handle
            }
            else {
                // Return something more algebraic instead of null or an int
                return {};
            };
        }
		bool Close(struct handle *handle) {
			if (handle == nullptr) {
				return false;
			}
			PermissionsManager permissions;
			IdentityManager identities;
			LifecycleManager lifecycles;
			// Somehow grab the object pointer and connection (maybe drop it...) from the handle
			ObjectManager::registry* object = handle->object;
			void* connection_context = handle->connection_context;
			// Checking for permissions here may be relevant.
			// What if we have a handle but no permission? Spooky
			if (permissions.Access(object, connection_context)
				&& identities.CanClose(object)
                // TODO: I think that in this case we do not need to worry about contention.
                // But be careful to evaluate this scenario later.
                //&& LifecycleManager::Contention(retrieved_object)
				) {
				// Stops monitoring this guy
				lifecycles.Unmonitor(object);
                DeallocateHandle(handle);
                return true; // Return a successful handle
            }
            else {
                // Return something more algebraic instead of null or an int.
                // It's kinda bad to not even report what went wrong.
                return false;
            };
        }
    };

    class NT_API WAM
    {
    };

    class NT_API NT
    {
    public:
        bool IsRunning() const;
        void SimulateEntryCall() {};
    };
}