@@ -35,6 +35,7 @@ file, You can obtain one at https://mozilla.org/MPL/2.0/.
35
35
#include <arpa/inet.h>
36
36
#include <sys/un.h>
37
37
#include <sys/ioctl.h>
38
+ #include <sys/epoll.h>
38
39
#include <unistd.h>
39
40
#include <errno.h>
40
41
#include <time.h>
@@ -58,10 +59,14 @@ file, You can obtain one at https://mozilla.org/MPL/2.0/.
58
59
59
60
// Define the function signature for the original open and ioctl syscalls
60
61
typedef int (* open_func_t )(const char * pathname , int flags , ...);
62
+ typedef int (* open64_func_t )(const char * pathname , int flags , ...);
61
63
typedef int (* ioctl_func_t )(int fd , unsigned long request , ...);
62
64
65
+ static int (* real_epoll_ctl )(int epfd , int op , int fd , struct epoll_event * event ) = NULL ;
66
+
63
67
// Function pointers to the original open and ioctl syscalls
64
68
static open_func_t real_open = NULL ;
69
+ static open64_func_t real_open64 = NULL ;
65
70
static ioctl_func_t real_ioctl = NULL ;
66
71
67
72
// type definition for correction struct
@@ -155,6 +160,41 @@ void init_real_open()
155
160
real_open = (open_func_t )dlsym (RTLD_NEXT , "open" );
156
161
}
157
162
163
+ void init_real_open64 ()
164
+ {
165
+ if (real_open64 != NULL )
166
+ return ;
167
+ real_open64 = (open64_func_t )dlsym (RTLD_NEXT , "open64" );
168
+ }
169
+
170
+ void init_real_epoll_ctl ()
171
+ {
172
+ if (real_epoll_ctl != NULL )
173
+ return ;
174
+ real_epoll_ctl = dlsym (RTLD_NEXT , "epoll_ctl" );
175
+ }
176
+
177
+ int make_nonblocking (int sockfd )
178
+ {
179
+ // Get the current file descriptor flags
180
+ int flags = fcntl (sockfd , F_GETFL , 0 );
181
+ if (flags == -1 )
182
+ {
183
+ interposer_log (LOG_ERROR , "Failed to get current flags on socket fd to make non-blocking" );
184
+ return -1 ;
185
+ }
186
+
187
+ // Set the non-blocking flag
188
+ flags |= O_NONBLOCK ;
189
+ if (fcntl (sockfd , F_SETFL , flags ) == -1 )
190
+ {
191
+ interposer_log (LOG_ERROR , "Failed to set flags on socket fd to make non-blocking" );
192
+ return -1 ;
193
+ }
194
+
195
+ return 0 ; // Success
196
+ }
197
+
158
198
int read_config (int fd , js_config_t * js_config )
159
199
{
160
200
ssize_t bytesRead ;
@@ -182,13 +222,83 @@ int read_config(int fd, js_config_t *js_config)
182
222
return 0 ;
183
223
}
184
224
225
+ int interposer_open_socket (js_interposer_t * interposer )
226
+ {
227
+ // Open the existing Unix socket
228
+ interposer -> sockfd = socket (AF_UNIX , SOCK_STREAM , 0 );
229
+ if (interposer -> sockfd == -1 )
230
+ {
231
+ interposer_log (LOG_ERROR , "Failed to create socket file descriptor when opening device: %s" , interposer -> open_dev_name );
232
+ return -1 ;
233
+ }
234
+
235
+ struct sockaddr_un addr ;
236
+ memset (& addr , 0 , sizeof (struct sockaddr_un ));
237
+ addr .sun_family = AF_UNIX ;
238
+ strncpy (addr .sun_path , interposer -> socket_path , sizeof (addr .sun_path ) - 1 );
239
+
240
+ // Wait for socket to connect.
241
+ int attempt = 0 ;
242
+ while (attempt ++ < SOCKET_CONNECT_TIMEOUT_MS )
243
+ {
244
+ if (connect (interposer -> sockfd , (struct sockaddr * )& addr , sizeof (struct sockaddr_un )) == -1 )
245
+ {
246
+ // sleep for 1ms
247
+ usleep (1000 );
248
+ continue ;
249
+ }
250
+ break ;
251
+ }
252
+ if (attempt >= SOCKET_CONNECT_TIMEOUT_MS )
253
+ {
254
+ interposer_log (LOG_ERROR , "Failed to connect to socket at %s" , interposer -> socket_path );
255
+ close (interposer -> sockfd );
256
+ return -1 ;
257
+ }
258
+
259
+ // Read the joystick config from the socket.
260
+ if (read_config (interposer -> sockfd , & (interposer -> js_config )) != 0 )
261
+ {
262
+ interposer_log (LOG_ERROR , "Failed to read config from socket: %s" , interposer -> socket_path );
263
+ close (interposer -> sockfd );
264
+ return -1 ;
265
+ }
266
+
267
+ return 0 ;
268
+ }
269
+
270
+ // Interpose epoll_ctl to make joystck socket fd non-blocking.
271
+ int epoll_ctl (int epfd , int op , int fd , struct epoll_event * event )
272
+ {
273
+ init_real_epoll_ctl ();
274
+
275
+ if (op == EPOLL_CTL_ADD )
276
+ {
277
+ // Find matching device in interposer list
278
+ for (size_t i = 0 ; i < NUM_JS_INTERPOSERS ; i ++ )
279
+ {
280
+ if (fd == interposers [i ].sockfd )
281
+ {
282
+ interposer_log (LOG_INFO , "Socket %s (%d) was added to epoll (%d), set non-blocking" , interposers [i ].socket_path , fd , epfd );
283
+ if (make_nonblocking (fd ) == -1 )
284
+ {
285
+ interposer_log (LOG_ERROR , "Failed to make socket non-blocking" );
286
+ }
287
+ break ;
288
+ }
289
+ }
290
+ }
291
+
292
+ return real_epoll_ctl (epfd , op , fd , event );
293
+ }
294
+
185
295
// Interposer function for open syscall
186
296
int open (const char * pathname , int flags , ...)
187
297
{
188
298
init_real_open ();
189
299
if (real_open == NULL )
190
300
{
191
- interposer_log ("Error getting original open function: %s" , dlerror ());
301
+ interposer_log (LOG_ERROR , "Error getting original open function: %s" , dlerror ());
192
302
return -1 ;
193
303
}
194
304
@@ -208,52 +318,55 @@ int open(const char *pathname, int flags, ...)
208
318
{
209
319
va_list args ;
210
320
va_start (args , flags );
211
- mode_t mode = va_arg (args , mode_t );
321
+ void * arg = va_arg (args , void * );
212
322
va_end (args );
213
- return real_open (pathname , flags , mode );
323
+ return real_open (pathname , flags , arg );
214
324
}
215
325
216
- interposer_log (LOG_INFO , "Intercepted open call for %s" , interposer -> open_dev_name );
326
+ if (interposer_open_socket (interposer ) == -1 )
327
+ return -1 ;
217
328
218
- // Open the existing Unix socket
219
- interposer -> sockfd = socket (AF_UNIX , SOCK_STREAM , 0 );
220
- if (interposer -> sockfd == -1 )
329
+ interposer_log (LOG_INFO , "Started interposer for 'open' call on %s with fd: %d" , interposer -> open_dev_name , interposer -> sockfd );
330
+
331
+ // Return the file descriptor of the unix socket.
332
+ return interposer -> sockfd ;
333
+ }
334
+
335
+ // Interposer function for open64
336
+ int open64 (const char * pathname , int flags , ...)
337
+ {
338
+ init_real_open64 ();
339
+ if (real_open64 == NULL )
221
340
{
222
- interposer_log (LOG_ERROR , "Failed to create socket file descriptor when opening devcie : %s" , interposer -> open_dev_name );
341
+ interposer_log (LOG_ERROR , "Error getting original open64 function : %s" , dlerror () );
223
342
return -1 ;
224
343
}
225
344
226
- struct sockaddr_un addr ;
227
- memset (& addr , 0 , sizeof (struct sockaddr_un ));
228
- addr .sun_family = AF_UNIX ;
229
- strncpy (addr .sun_path , interposer -> socket_path , sizeof (addr .sun_path ) - 1 );
230
-
231
- // Wait for socket to connect.
232
- int attempt = 0 ;
233
- while (attempt ++ < SOCKET_CONNECT_TIMEOUT_MS )
345
+ // Find matching device in interposer list
346
+ js_interposer_t * interposer = NULL ;
347
+ for (size_t i = 0 ; i < NUM_JS_INTERPOSERS ; i ++ )
234
348
{
235
- if (connect ( interposer -> sockfd , ( struct sockaddr * ) & addr , sizeof ( struct sockaddr_un )) == -1 )
349
+ if (strcmp ( pathname , interposers [ i ]. open_dev_name ) == 0 )
236
350
{
237
- // sleep for 1ms
238
- usleep (1000 );
239
- continue ;
351
+ interposer = & interposers [i ];
352
+ break ;
240
353
}
241
- break ;
242
354
}
243
- if (attempt >= SOCKET_CONNECT_TIMEOUT_MS )
355
+
356
+ // Call real open64
357
+ if (interposer == NULL )
244
358
{
245
- interposer_log (LOG_ERROR , "Failed to connect to socket at %s" , interposer -> socket_path );
246
- close (interposer -> sockfd );
247
- return -1 ;
359
+ va_list args ;
360
+ va_start (args , flags );
361
+ void * arg = va_arg (args , void * );
362
+ va_end (args );
363
+ return real_open64 (pathname , flags , arg );
248
364
}
249
365
250
- // Read the joystick config from the socket.
251
- if (read_config (interposer -> sockfd , & (interposer -> js_config )) != 0 )
252
- {
253
- interposer_log (LOG_ERROR , "Failed to read config from socket: %s" , interposer -> socket_path );
254
- close (interposer -> sockfd );
366
+ if (interposer_open_socket (interposer ) == -1 )
255
367
return -1 ;
256
- }
368
+
369
+ interposer_log (LOG_INFO , "Started interposer for 'open64' call on %s with fd: %d" , interposer -> open_dev_name , interposer -> sockfd );
257
370
258
371
// Return the file descriptor of the unix socket.
259
372
return interposer -> sockfd ;
@@ -305,78 +418,76 @@ int ioctl(int fd, unsigned long request, ...)
305
418
switch (request & 0xFF )
306
419
{
307
420
case 0x01 : /* JSIOCGVERSION get driver version */
308
- interposer_log (LOG_INFO , "Intercepted ioctl request %lu -> JSIOCGVERSION " , request );
421
+ interposer_log (LOG_INFO , "Intercepted ioctl JSIOCGVERSION(0x%08x) request for: %s " , request , interposer -> socket_path );
309
422
uint32_t * version = va_arg (args , uint32_t * );
310
423
* version = JS_VERSION ;
311
424
312
425
va_end (args );
313
426
return 0 ; // 0 indicates success
314
427
315
428
case 0x11 : /* JSIOCGAXES get number of axes */
316
- interposer_log (LOG_INFO , "Intercepted ioctl request %lu -> JSIOCGAXES " , request );
429
+ interposer_log (LOG_INFO , "Intercepted ioctl JSIOCGAXES(0x%08x) request for: %s " , request , interposer -> socket_path );
317
430
uint8_t * num_axes = va_arg (args , uint8_t * );
318
431
* num_axes = interposer -> js_config .num_axes ;
319
432
320
433
va_end (args );
321
434
return 0 ; // 0 indicates success
322
435
323
436
case 0x12 : /* JSIOCGBUTTONS get number of buttons */
324
- interposer_log (LOG_INFO , "Intercepted ioctl request %lu -> JSIOCGBUTTONS " , request );
437
+ interposer_log (LOG_INFO , "Intercepted ioctl JSIOCGBUTTONS(0x%08x) request for: %s " , request , interposer -> socket_path );
325
438
uint8_t * btn_count = va_arg (args , uint8_t * );
326
439
* btn_count = interposer -> js_config .num_btns ;
327
440
328
441
va_end (args );
329
442
return 0 ; // 0 indicates success
330
443
331
444
case 0x13 : /* JSIOCGNAME(len) get identifier string */
332
- interposer_log (LOG_INFO , "Intercepted ioctl request %lu -> JSIOCGNAME " , request );
445
+ interposer_log (LOG_INFO , "Intercepted ioctl JSIOCGNAME(0x%08x) request for: %s " , request , interposer -> socket_path );
333
446
char * name = va_arg (args , char * );
334
- size_t * len = va_arg (args , size_t * );
335
- strncpy (name , interposer -> js_config .name , strlen (interposer -> js_config .name ));
336
447
name [strlen (interposer -> js_config .name )] = '\0' ;
337
-
448
+ strncpy ( name , interposer -> js_config . name , strlen ( interposer -> js_config . name ));
338
449
va_end (args );
339
450
return 0 ; // 0 indicates success
340
451
341
452
case 0x21 : /* JSIOCSCORR set correction values */
342
- interposer_log (LOG_INFO , "Intercepted ioctl request %lu -> JSIOCSCORR " , request );
453
+ interposer_log (LOG_INFO , "Intercepted ioctl JSIOCSCORR(0x%08x) request for: %s " , request , interposer -> socket_path );
343
454
va_end (args );
344
455
return 0 ;
345
456
346
457
case 0x22 : /* JSIOCGCORR get correction values */
347
- interposer_log (LOG_INFO , "Intercepted ioctl request %lu -> JSIOCGCORR " , request );
458
+ interposer_log (LOG_INFO , "Intercepted ioctl JSIOCGCORR(0x%08x) request for: %s " , request , interposer -> socket_path );
348
459
js_corr_t * corr = va_arg (args , js_corr_t * );
349
460
memcpy (corr , & interposer -> corr , sizeof (interposer -> corr ));
350
461
351
462
va_end (args );
352
463
return 0 ; // 0 indicates success
353
464
354
465
case 0x31 : /* JSIOCSAXMAP set axis mapping */
355
- interposer_log (LOG_INFO , "Intercepted ioctl request %lu -> JSIOCSAXMAP " , request );
466
+ interposer_log (LOG_INFO , "Intercepted ioctl JSIOCSAXMAP(0x%08x) request for: %s " , request , interposer -> socket_path );
356
467
va_end (args );
357
468
return 0 ; // 0 indicates success
358
469
359
470
case 0x32 : /* JSIOCGAXMAP get axis mapping */
360
- interposer_log (LOG_INFO , "Intercepted ioctl request %lu -> JSIOCGAXMAP " , request );
471
+ interposer_log (LOG_INFO , "Intercepted ioctl JSIOCGAXMAP(0x%08x) request for: %s " , request , interposer -> socket_path );
361
472
uint8_t * axmap = va_arg (args , uint8_t * );
362
473
memcpy (axmap , interposer -> js_config .axes_map , interposer -> js_config .num_axes * sizeof (uint8_t ));
363
474
va_end (args );
364
475
return 0 ; // 0 indicates success
365
476
366
477
case 0x33 : /* JSIOCSBTNMAP set button mapping */
367
- interposer_log (LOG_INFO , "Intercepted ioctl request %lu -> JSIOCSBTNMAP " , request );
478
+ interposer_log (LOG_INFO , "Intercepted ioctl JSIOCSBTNMAP(0x%08x) request for: %s " , request , interposer -> socket_path );
368
479
va_end (args );
369
480
return 0 ; // 0 indicates success
370
481
371
482
case 0x34 : /* JSIOCGBTNMAP get button mapping */
372
- interposer_log (LOG_INFO , "Intercepted ioctl request %lu -> JSIOCGBTNMAP " , request );
483
+ interposer_log (LOG_INFO , "Intercepted ioctl JSIOCGBTNMAP(0x%08x) request for: %s " , request , interposer -> socket_path );
373
484
uint16_t * btn_map = va_arg (args , uint16_t * );
374
485
memcpy (btn_map , interposer -> js_config .btn_map , interposer -> js_config .num_btns * sizeof (uint16_t ));
375
486
va_end (args );
376
487
return 0 ; // 0 indicates success
377
488
378
489
default :
379
- interposer_log (LOG_WARN , "Unhandled Intercepted ioctl request %lu" , request );
490
+ interposer_log (LOG_WARN , "Unhandled Intercepted ioctl request %lu" , request , interposer -> socket_path );
380
491
void * arg = va_arg (args , void * );
381
492
va_end (args );
382
493
return real_ioctl (fd , request , arg );
0 commit comments