1 /*
2  * Copyright 2015-2016, Björn Ståhl
3  * License: 3-Clause BSD, see COPYING file in arcan source repository.
4  * Reference: http://arcan-fe.com
5  */
6 
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <stdbool.h>
10 #include <stdlib.h>
11 #include <sys/mman.h>
12 
13 #define FRAMESERVER_PRIVATE
14 #define LUA_PRIVATE
15 #define A3D_PRIVATE
16 
17 #include "arcan_shmif.h"
18 #include "arcan_math.h"
19 #include "arcan_audio.h"
20 #include "arcan_general.h"
21 #include "arcan_event.h"
22 
23 #include PLATFORM_HEADER
24 #include "arcan_video.h"
25 #include "arcan_frameserver.h"
26 #include "arcan_lua.h"
27 #include "arcan_3dbase.h"
28 #include "arcan_ffunc_lut.h"
29 #include "arcan_vr.h"
30 
31 #ifdef ARCAN_LWA
32 extern enum arcan_ffunc_rv arcan_lwa_ffunc FFUNC_HEAD;
33 #endif
34 
35 /*
36  * will be allocated / initialized once
37  */
38 static arcan_vfunc_cb* f_lut;
39 extern int system_page_size;
40 
41 static enum arcan_ffunc_rv fatal_ffunc FFUNC_HEAD
42 {
43 /* avoid the possible infinite recursion in delete(broken ffunc)->
44  * fatal->delete->... */
45 	static bool in_fatal;
46 	if (in_fatal)
47 		return FRV_NOFRAME;
48 
49 	abort();
50 	in_fatal = true;
51 	arcan_fatal("ffunc_lut(), invalid index used in ffunc CB - \n"
52 		"\tinvestigate malicious activity or data corruption\n");
53 
54 	return FRV_NOFRAME;
55 }
56 
57 static enum arcan_ffunc_rv null_ffunc FFUNC_HEAD
58 {
59 	return FRV_NOFRAME;
60 }
61 
arcan_ffunc_initlut()62 void arcan_ffunc_initlut()
63 {
64 /* recovery scripts might force this to be called multiple times */
65 	if (f_lut){
66 		munmap(f_lut, system_page_size);
67 		f_lut= NULL;
68 	}
69 
70 	f_lut = mmap(NULL, system_page_size,
71 		PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
72 
73 	if (!f_lut)
74 		arcan_fatal("ffunc_lut() investigate memory issues");
75 
76 	for (size_t i = 0; i < system_page_size / sizeof(arcan_vfunc_cb*); i++)
77 		f_lut[i] = fatal_ffunc;
78 
79 	f_lut[FFUNC_NULL] = null_ffunc;
80 
81 	f_lut[FFUNC_AVFEED] = arcan_frameserver_avfeedframe;
82 	f_lut[FFUNC_FEEDCOPY] = arcan_frameserver_feedcopy;
83 	f_lut[FFUNC_NULLFRAME] = arcan_frameserver_emptyframe;
84 	f_lut[FFUNC_VFRAME] = arcan_frameserver_vdirect;
85 	f_lut[FFUNC_NULLFEED] = arcan_frameserver_nullfeed;
86 	f_lut[FFUNC_LUA_PROC] = arcan_lua_proctarget;
87 	f_lut[FFUNC_3DOBJ] = arcan_ffunc_3dobj;
88 	f_lut[FFUNC_SOCKVER] = arcan_frameserver_verifyffunc;
89 	f_lut[FFUNC_SOCKPOLL] = arcan_frameserver_pollffunc;
90 	f_lut[FFUNC_VR] = arcan_vr_ffunc;
91 
92 #ifdef ARCAN_LWA
93 	f_lut[FFUNC_LWA] = arcan_lwa_ffunc;
94 #else
95 	f_lut[FFUNC_LWA] = fatal_ffunc;
96 #endif
97 
98 	mprotect(f_lut, system_page_size, PROT_READ);
99 }
100 
arcan_ffunc_register(arcan_vfunc_cb cb)101 int arcan_ffunc_register(arcan_vfunc_cb cb)
102 {
103 	int found = -1;
104 
105 /* sweep the adressable range, look for one entry that is not 0 or
106  * LWA and that references the fatal ffunc */
107 	for (size_t i = 1; i < 256; i++){
108 		if (f_lut[i] == fatal_ffunc && i != FFUNC_LWA){
109 			found = i;
110 			break;
111 		}
112 	}
113 
114 /* out of space */
115 	if (found == -1)
116 		return -1;
117 
118 /* protect against multiple register calls on the same function */
119 	for (size_t i = 0; i < 256; i++){
120 		if (f_lut[i] == cb)
121 			return i;
122 	}
123 
124 /* register (need to unprotect) */
125 	mprotect(f_lut, system_page_size, PROT_READ | PROT_WRITE);
126 	f_lut[found] = cb;
127 	mprotect(f_lut, system_page_size, PROT_READ);
128 
129 	return found;
130 }
131 
arcan_ffunc_lookup(ffunc_ind ind)132 arcan_vfunc_cb arcan_ffunc_lookup(ffunc_ind ind)
133 {
134 	return f_lut[ind];
135 }
136