1 /*
2  Shmif- server library
3  Copyright (c) 2017-2018, Bjorn Stahl
4  All rights reserved.
5 
6   Redistribution and use in source and binary forms,
7  with or without modification, are permitted provided that the
8  following conditions are met:
9 
10  1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13  2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17  3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software without
19  specific prior written permission.
20 
21  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
26  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * This is used to be able to write headless servers for shmif, in order to
36  * easier facilitate testing, proxying and nesting of shmif connections.  It
37  * (re-) uses the same setup, platform and similar code from the normal arcan
38  * build, but with different event-routing and polling.
39  */
40 struct shmifsrv_client;
41 
42 /*
43  * Used for setup when we need to launch an external program with working/
44  * unique connection primitives from the start. If init_w and init_h are 0, the
45  * client needs to set its size on its own, or be told of it during the
46  * preroll- event stage.
47  */
48 struct shmifsrv_envp {
49 	char* path;
50 	char** argv;
51 	char** envv;
52 
53 	size_t init_w;
54 	size_t init_h;
55 
56 	int detach;
57 };
58 
59 enum shmifsrv_status {
60 	SHMIFSRV_OK = 1,
61 	SHMIFSRV_INVALID_ARGUMENT = -1,
62 	SHMIFSRV_OUT_OF_MEMORY = -2,
63 	SHMIFSRV_EXEC_FAILED = -3
64 };
65 
66 /*
67  * Depending on underlying OS, there are a number of recoverable shared memory
68  * related errors that can occur while reading/writing, but it is typically a
69  * sign of a malicious client. To work around this, we rely on setjmp/longjmp
70  * like behavior. This is wrapped with these functions, like so:
71  *
72  * if (!shmifsrv_enter(conn)){
73  *     something_bad_happened, anything between enter and leave
74  *     may be in a partial state, kill/clean.
75  *
76  *     return;
77  * }
78  *
79  * sensitive functions (marked [CRITICAL])
80  *     shmifsrv_queuestatus
81  *     shmifsrv_video
82  *     shmifsrv_audio
83  *
84  * shmifsrv_leave();
85  *
86  * only sensitive functions ([CRITICAL]) should be called within the
87  * _enter/_leave critical region. BEWARE that this function MAY temporarily
88  * modify the signal mask for some signals (e.g. SIGBUS).
89  */
90 bool shmifsrv_enter(struct shmifsrv_client*);
91 void shmifsrv_leave();
92 
93 /*
94  * Wrap a shmifsrv client into an interface that can be used with the normal
95  * arcan_shmif_... class of functions.
96  */
97 struct arcan_shmif_cont*
98 	shmifsrv_client_wrap(struct shmifsrv_client* srv);
99 
100 /*
101  * Allocate, prepare and transfer a new sub-segment to the frameserver
102  * referenced by [dst] (!NULL).
103  *
104  * [segid] specifies the type of the subsegment
105  *        (MUST match REQID if it is in response to a SEGREQ event)
106  *
107  * [hints] are default render hints for the segment and should be set to
108  *         what the client requested in a segment request, or left at 0.
109  *
110  * [idtok] is used as a reference in a client addressable namespace in
111  *         order to set spatial hints.
112  */
113 struct shmifsrv_client*
114 	shmifsrv_send_subsegment(struct shmifsrv_client* dst,
115 	int segid, int hints, size_t init_w, size_t init_h, int reqid, uint32_t idtok);
116 
117 /*
118  * Allocate and prepare a frameserver connection point accessible via the name
119  * [name](!NULL) an (optional) authentication key and the permission mask of
120  * the target socket. The function returns a valid server context or NULL with
121  * the reason for failure in statuscode.
122  *
123  * Design / legacy quirk:
124  * The listening socket is contained within shmifsrv_client and should be
125  * extracted using shmifsrv_client_handle. If a client connects (see
126  * shmifsrv_poll), this handle with mutate internally to that of the accepted
127  * connection and it is the responsibility of the caller to either close
128  * the descriptor or use it as the [fd] argument to this function in order
129  * to re-open the connection point.
130  *
131  * Example use:
132  * struct shmifsrv_client* cl =
133  *   shmifsrv_allocate_connpoint("demo", NULL, S_IRWXU, -1);
134  *
135  * if (!cl)
136  *  error("couldn't allocate resources");
137 
138  * int server_fd = shmifsrv_client_handler(cl);
139  * while(cl){
140  *    ... poll / wait in activity on server_fd ...
141  *    dispatch_client(cl); (have a thread/loop that runs shmifsrv_poll)
142  *    cl = shmifsrv_allocate_connpoint("demo", NULL, S_IRWXU, server_fd);
143  * }
144  *
145  */
146 struct shmifsrv_client* shmifsrv_allocate_connpoint(
147 	const char* name, const char* key, mode_t permission, int fd);
148 
149 /*
150  * Setup a connection-less frameserver, meaning that all primitives and
151  * allocation is passed through means that can be inherited via the client
152  * context itself, though it could also be used in the same process space.
153  *
154  * return NULL on failure, and, if provided, a shmifsrv_error status
155  * code.
156  */
157 struct shmifsrv_client* shmifsrv_spawn_client(
158 	struct shmifsrv_envp env, int* clsocket, int* statuscode, uint32_t idtok);
159 
160 /*
161  * Setup a preconnected frameserver, meaning that the initial socket
162  * pairing has been performed via some other mechanism, and it is only
163  * the memory/synch primitives that need to be prepared
164  */
165 struct shmifsrv_client* shmifsrv_inherit_connection(int sockin, int* sc);
166 
167 /*
168  * Retrieve an I/O multiplexable handle for mixing into poll() rather
169  * than throwing a _poll() call in there whenever there's time.
170  */
171 int shmifsrv_client_handle(struct shmifsrv_client*);
172 
173 /*
174  * This should be invoked at a monotonic tickrate, the common default
175  * used here is 25Hz (% 50, 75, 90 as nominal video framerates)
176  *
177  * Internally, it verifies that the shared resources are in a healthy
178  * state, forwards client- managed timers and so on.
179  */
180 bool shmifsrv_tick(struct shmifsrv_client*);
181 
182 /*
183  * Polling routine for pumping synchronization actions and determining
184  * updating status. Should be called periodically, as part of the normal
185  * processing loop, at least once every shmifsrv_monotonic_tick()/
186  */
187 enum shmifsrv_client_status {
188 	CLIENT_DEAD = -1,
189 	CLIENT_NOT_READY = 0,
190 	CLIENT_VBUFFER_READY = 1,
191 	CLIENT_ABUFFER_READY = 2
192 };
193 int shmifsrv_poll(struct shmifsrv_client*);
194 
195 /*
196  * Free the resources associated with a shmifsrv_client. If this client has
197  * been created through shmifsrv_allocate_connpoint and is still in a listening
198  * state, the underlying descriptor won't be closed in order for the connpoint
199  * to be reused.
200  *
201  * If [full] is set to false, the client will not be directly told that the
202  * connection is dead via the normal 'dead-man-switch' handle, only through
203  * the event-queue - forcing the client to try and use some recovery mechanism.
204  */
205 enum shmifsrv_action {
206 	SHMIFSRV_FREE_FULL   = 0,
207 	SHMIFSRV_FREE_NO_DMS = 1,
208 	SHMIFSRV_FREE_LOCAL  = 2
209 };
210 void shmifsrv_free(struct shmifsrv_client*, int mode);
211 
212 /*
213  * [CRITICAL]
214  * Add an event to the outgoing event-queue, will return false if the queue has
215  * been saturated (non-responsive client), true otherwise.
216  * arcan_shmif_descrevent() can be used to verify if there's supposed to be a
217  * descriptor coupled with the event.
218  *
219  * As a rule, only srv->client events carry descriptors (the exception is
220  * accelerated buffer passing) as the client isn't expected to be in a context
221  * where it can easily create descriptors to shareable resources (sandboxing)
222  * and as a means of closing paths where a client may attempt to starve the
223  * parent by filling descriptor tables. The descriptors passed can safely be
224  * closed afterwards.
225  */
226 bool shmifsrv_enqueue_event(
227 	struct shmifsrv_client*, struct arcan_event*, int fd);
228 
229 /*
230  * [CRITICAL]
231  * Attempt to dequeue up to [limit] events from the ingoing event queue. Will
232  * return the numbers of actual events dequeued. This will perform no additional
233  * tracking or management, only raw event access. For assistance with state
234  * tracking, feed the events through shmifsrv_process_event.
235  */
236 size_t shmifsrv_dequeue_events(
237 	struct shmifsrv_client*, struct arcan_event* newev, size_t limit);
238 
239 /*
240  * Retrieve the currently registered type for a client
241  */
242 enum ARCAN_SEGID shmifsrv_client_type(struct shmifsrv_client* cl);
243 
244 /*
245  * Set the mask of permitted subprotocols, this applies to coming negotiations
246  * as this is initiated by the client and provided permissions do not revoke.
247  */
248 void shmifsrv_client_protomask(struct shmifsrv_client* cl, unsigned mask);
249 
250 /*
251  * Handle some of the normal state-tracking events (e.g. CLOCKREQ,
252  * BUFFERSTREAM, FLUSHAUD). Returns true if the event was consumed and no
253  * further action is needed.
254  */
255 bool shmifsrv_process_event(
256 	struct shmifsrv_client*, struct arcan_event* ev);
257 
258 enum vbuffer_status {
259 	VBUFFER_OUTPUT = -1,
260 	VBUFFER_NODATA = 0,
261 	VBUFFER_OKDATA,
262 	VBUFFER_HANDLE
263 };
264 
265 struct shmifsrv_vbuffer {
266 	int state;
267 	union {
268 		shmif_pixel* buffer;
269 		uint8_t* buffer_bytes;
270 	};
271 
272 	struct {
273 		bool origo_ll : 1;
274 		bool ignore_alpha : 1;
275 		bool subregion : 1;
276 		bool srgb : 1;
277 		bool hwhandles : 1;
278 		bool tpack : 1;
279 		bool compressed : 1;
280 	} flags;
281 
282 /* if compressed is set (requires the compressed buffer subprotocol to be
283  * provided) the fourcc code will match that of the video format frame in
284  * the buffer */
285 	uint8_t fourcc[4];
286 
287 	union {
288 		struct {
289 			size_t w, h, pitch, stride;
290 		};
291 		size_t buffer_sz;
292 	};
293 
294 /* desired presentation time since connection epoch, hint */
295 	uint64_t vpts;
296 
297 /* only usedated with subregion : true */
298 	struct arcan_shmif_region region;
299 
300 /* only used with hwhandles : true */
301 	size_t formats[4];
302 	int planes[4];
303 };
304 
305 /*
306  * [CRITICAL]
307  * access the currently active video buffer slot in the client.
308  * the buffer is returned to the client. The contents of the buffer are
309  * a reference to shared memory, and should thus be explicitly copied out
310  * before leaving critical.
311  *
312  * The [state] field of the returned structure will match vbuffer_status:
313  * VBUFFER_OUTPUT - segment is configured for output, don't use this function.
314  * VBUFFER_NODATA - nothing available.
315  * VBUFFER_OKDATA - buffer is updated.
316  * VBUFFER_HANDLE - accelerated opaque handle, descriptor field set.
317  *
318  * Video buffers can operate in two different modes, accelerated (opaque)
319  * handle passing and accelerated. This server library does not currently
320  * provide support functions for working with opaque handles.
321  */
322 struct shmifsrv_vbuffer shmifsrv_video(struct shmifsrv_client*);
323 
324 /* [CRITICAL]
325  * Forward that the last known video buffer is no longer interesting and
326  * signal a release to the client
327  */
328 void shmifsrv_video_step(struct shmifsrv_client*);
329 
330 /* [CRITICAL]
331  * Flush all pending buffers to the provided drain function. In contrast to
332  * _video_step this function has an implicit step stage so all known buffers
333  * will be flushed and a waiting client will be woken up.
334  *
335  * Returns false is the indices are out of negotiated bounds or corrupt.
336  */
337 bool shmifsrv_audio(struct shmifsrv_client* cl,
338 	void (*on_buffer)(shmif_asample* buf,
339 		size_t n_samples, unsigned channels, unsigned rate, void* tag), void* tag);
340 
341 /*
342  * [THREAD_UNSAFE]
343  * This is a helper function that returns the number of monotonic ticks
344  * since the last time this function was called. It is thus a global state
345  * shared by many clients, along with the optional time to next tick. The
346  * typical pattern is:
347  *  [start]
348  *   shmifsrv_monotonic_rebase();
349  *
350  *  [loop]
351  *   num = shmifsrv_monotonic_tick(NULL);
352  *   while (num-- > 0)
353  *   	each_client(cl){ shmifsrv_tick( cl )
354  */
355 int shmifsrv_monotonic_tick(int* left);
356 
357 /*
358  * [THREAD_UNSAFE]
359  * Explicitly rebase the shared clock counter due to a large stall,
360  * pause, global suspend action and so on.
361  */
362 void shmifsrv_monotonic_rebase();
363