never gonna give you up

This commit is contained in:
viandoxdev 2022-08-30 15:37:34 +02:00
parent 092a33325d
commit afe99fc054
No known key found for this signature in database
GPG Key ID: AF1410C5BC10AA25
9 changed files with 381 additions and 218 deletions

208
hid.c
View File

@ -1,19 +1,18 @@
#include<stdlib.h> #include <dirent.h>
#include<dirent.h> #include <fcntl.h>
#include<string.h> #include <linux/input.h>
#include<stdio.h> #include <linux/joystick.h>
#include<sys/ioctl.h> #include <linux/uinput.h>
#include<linux/input.h> #include <stdbool.h>
#include<fcntl.h> #include <stdio.h>
#include<linux/uinput.h> #include <stdlib.h>
#include<linux/input.h> #include <string.h>
#include<linux/joystick.h> #include <sys/ioctl.h>
#include<stdbool.h> #include <time.h>
#include<time.h>
#include "hid.h" #include "hid.h"
#include "vec.h"
#include "main.h" #include "main.h"
#include "vec.h"
// List of uniq of the currently known devices // List of uniq of the currently known devices
static Vec devices; static Vec devices;
@ -28,34 +27,80 @@ static pthread_cond_t devices_queue_cond = PTHREAD_COND_INITIALIZER;
// Mutex for devices // Mutex for devices
static pthread_mutex_t devices_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t devices_mutex = PTHREAD_MUTEX_INITIALIZER;
static char * DEFAULT_NAME = "Unnamed Device"; static char *DEFAULT_NAME = "Unnamed Device";
// uniqs are just hexadecimal numbers with colons in between each byte // uniqs are just hexadecimal numbers with colons in between each byte
uniq_t parse_uniq(char uniq[17]) { uniq_t parse_uniq(char uniq[17]) {
uniq_t res = 0; uniq_t res = 0;
for(int i = 0; i < 17; i++) { for (int i = 0; i < 17; i++) {
char c = uniq[i]; char c = uniq[i];
int digit; int digit;
if(c >= '0' && c <= '9') digit = c - '0'; if (c >= '0' && c <= '9')
else if(c >= 'a' && c <= 'f') digit = c - 'a' + 10; digit = c - '0';
else if(c >= 'A' && c <= 'F') digit = c - 'A' + 10; else if (c >= 'a' && c <= 'f')
else continue; digit = c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
digit = c - 'A' + 10;
else
continue;
res <<= 4; res <<= 4;
res += digit; res += digit;
} }
return res; return res;
} }
bool filter_event(int fd, char * event) { static inline bool bit_set(uint8_t *bits, int i) { return bits[i / 8] & (1 << (i % 8)); }
void setup_device(PhysicalDevice *dev) {
dev->device_info.code = DeviceInfo;
dev->device_info.abs_count = 0;
dev->device_info.rel_count = 0;
dev->device_info.key_count = 0;
uint8_t bits[EV_MAX] = {};
uint8_t feat_bits[KEY_MAX] = {};
ioctl(dev->event, EVIOCGBIT(0, EV_MAX), bits);
for (int i = 0; i < EV_MAX; i++) {
if (bit_set(bits, i)) {
ioctl(dev->event, EVIOCGBIT(i, KEY_MAX), feat_bits);
for (int j = 0; j < KEY_MAX; j++) {
if (bit_set(feat_bits, j)) {
if (i == EV_ABS) {
struct input_absinfo abs;
ioctl(dev->event, EVIOCGABS(j), &abs);
uint8_t index = dev->device_info.abs_count++;
dev->device_info.abs_id[index] = j;
dev->device_info.abs_min[index] = abs.minimum;
dev->device_info.abs_max[index] = abs.maximum;
dev->device_info.abs_fuzz[index] = abs.fuzz;
dev->device_info.abs_flat[index] = abs.flat;
dev->device_info.abs_res[index] = abs.resolution;
dev->mapping.abs_indices[j] = index;
} else if (i == EV_REL) {
uint8_t index = dev->device_info.rel_count++;
dev->device_info.rel_id[index] = j;
dev->mapping.rel_indices[j] = index;
} else if (i == EV_KEY) {
uint8_t index = dev->device_info.key_count++;
dev->device_info.key_id[index] = j;
dev->mapping.key_indices[j] = index;
}
}
}
}
}
}
bool filter_event(int fd, char *event) {
char device_path[64]; char device_path[64];
snprintf(device_path, 64, "/sys/class/input/%s/device", event); snprintf(device_path, 64, "/sys/class/input/%s/device", event);
DIR * device_dir = opendir(device_path); DIR *device_dir = opendir(device_path);
struct dirent * device_dirent; struct dirent *device_dirent;
bool found = false; bool found = false;
while((device_dirent = readdir(device_dir)) != NULL) { while ((device_dirent = readdir(device_dir)) != NULL) {
if(device_dirent->d_type == DT_DIR && strncmp(device_dirent->d_name, "js", 2) == 0) { if (device_dirent->d_type == DT_DIR && strncmp(device_dirent->d_name, "js", 2) == 0) {
found = true; found = true;
break; break;
} }
@ -63,7 +108,7 @@ bool filter_event(int fd, char * event) {
closedir(device_dir); closedir(device_dir);
if(!found) { if (!found) {
return false; return false;
} }
@ -73,35 +118,35 @@ bool filter_event(int fd, char * event) {
} }
void poll_devices_init() { void poll_devices_init() {
devices = vec_of(uniq_t); devices = vec_of(uniq_t);
new_devices = vec_of(PhysicalDevice); new_devices = vec_of(PhysicalDevice);
devices_queue = vec_of(PhysicalDevice); devices_queue = vec_of(PhysicalDevice);
} }
PhysicalDevice get_device() { PhysicalDevice get_device() {
pthread_mutex_lock(&devices_queue_mutex); pthread_mutex_lock(&devices_queue_mutex);
if(devices_queue.len > 0){ if (devices_queue.len > 0) {
PhysicalDevice r; PhysicalDevice r;
vec_pop(&devices_queue, &r); vec_pop(&devices_queue, &r);
pthread_mutex_unlock(&devices_queue_mutex); pthread_mutex_unlock(&devices_queue_mutex);
return r; return r;
} }
while(devices_queue.len == 0) { while (devices_queue.len == 0) {
pthread_cond_wait(&devices_queue_cond, &devices_queue_mutex); pthread_cond_wait(&devices_queue_cond, &devices_queue_mutex);
} }
PhysicalDevice res; PhysicalDevice res;
vec_pop(&devices_queue, &res); vec_pop(&devices_queue, &res);
if(devices_queue.len > 0) { if (devices_queue.len > 0) {
pthread_cond_signal(&devices_queue_cond); pthread_cond_signal(&devices_queue_cond);
} }
pthread_mutex_unlock(&devices_queue_mutex); pthread_mutex_unlock(&devices_queue_mutex);
return res; return res;
} }
void return_device(PhysicalDevice * dev) { void return_device(PhysicalDevice *dev) {
if(dev->name != NULL && dev->name != DEFAULT_NAME) { if (dev->name != NULL && dev->name != DEFAULT_NAME) {
printf("HID: Returning device '%s' (%012lx)\n", dev->name, dev->uniq); printf("HID: Returning device '%s' (%012lx)\n", dev->name, dev->uniq);
free(dev->name); free(dev->name);
} else { } else {
@ -110,9 +155,9 @@ void return_device(PhysicalDevice * dev) {
close(dev->event); close(dev->event);
close(dev->hidraw); close(dev->hidraw);
pthread_mutex_lock(&devices_mutex); pthread_mutex_lock(&devices_mutex);
for(int i = 0; i < devices.len; i++) { for (int i = 0; i < devices.len; i++) {
uniq_t * uniq = vec_get(&devices, i); uniq_t *uniq = vec_get(&devices, i);
if(*uniq == dev->uniq) { if (*uniq == dev->uniq) {
vec_remove(&devices, i, NULL); vec_remove(&devices, i, NULL);
break; break;
} }
@ -123,67 +168,61 @@ void return_device(PhysicalDevice * dev) {
void poll_devices() { void poll_devices() {
vec_clear(&new_devices); vec_clear(&new_devices);
DIR * input_dir = opendir("/sys/class/input"); DIR *input_dir = opendir("/sys/class/input");
struct dirent * input; struct dirent *input;
while((input = readdir(input_dir)) != NULL) { while ((input = readdir(input_dir)) != NULL) {
// Ignore if the entry isn't a linkg or doesn't start with event // Ignore if the entry isn't a linkg or doesn't start with event
if(input->d_type != DT_LNK || strncmp(input->d_name, "event", 5) != 0) { if (input->d_type != DT_LNK || strncmp(input->d_name, "event", 5) != 0) {
continue; continue;
} }
PhysicalDevice dev = {}; PhysicalDevice dev;
char event_path[64]; char event_path[64];
snprintf(event_path, 64, "/dev/input/%s", input->d_name); snprintf(event_path, 64, "/dev/input/%s", input->d_name);
dev.event = open(event_path, O_RDONLY); dev.event = open(event_path, O_RDONLY);
if(dev.event < 0) { if (dev.event < 0) {
continue; continue;
} }
char name_buf[256] = {}; char name_buf[256] = {};
char * name; char *name;
if(ioctl(dev.event, EVIOCGNAME(256), name_buf) >= 0) if (ioctl(dev.event, EVIOCGNAME(256), name_buf) >= 0)
name = name_buf; name = name_buf;
else else
name = DEFAULT_NAME; name = DEFAULT_NAME;
if(!filter_event(dev.event, input->d_name)) goto skip; if (!filter_event(dev.event, input->d_name))
goto skip;
uniq_t uniq; uniq_t uniq;
{ {
char uniq_str[17] = {}; char uniq_str[17] = {};
char uniq_path[256]; ioctl(dev.event, EVIOCGUNIQ(17), uniq_str);
snprintf(uniq_path, 256, "/sys/class/input/%s/device/uniq", input->d_name);
int uniq_fd = open(uniq_path, O_RDONLY);
if(uniq_fd < 0) goto skip;
read(uniq_fd, uniq_str, 17);
uniq = parse_uniq(uniq_str); uniq = parse_uniq(uniq_str);
close(uniq_fd);
// If we couldn't parse the uniq (this assumes uniq can't be zero, which is probably alright) // If we couldn't parse the uniq (this assumes uniq can't be zero, which is probably alright)
if(uniq == 0) goto skip; if (uniq == 0)
goto skip;
} }
bool found = false; bool found = false;
pthread_mutex_lock(&devices_mutex); pthread_mutex_lock(&devices_mutex);
for(int i = 0; i < devices.len; i++) { for (int i = 0; i < devices.len; i++) {
uniq_t * dev_uniq = vec_get(&devices, i); uniq_t *dev_uniq = vec_get(&devices, i);
if(*dev_uniq == uniq) { if (*dev_uniq == uniq) {
found = true; found = true;
break; break;
} }
} }
pthread_mutex_unlock(&devices_mutex); pthread_mutex_unlock(&devices_mutex);
if(found) goto skip; if (found)
goto skip;
dev.uniq = uniq; dev.uniq = uniq;
@ -193,13 +232,14 @@ void poll_devices() {
char hidraw_path[256]; char hidraw_path[256];
snprintf(hidraw_path, 256, "/sys/class/input/%s/device/device/hidraw", input->d_name); snprintf(hidraw_path, 256, "/sys/class/input/%s/device/device/hidraw", input->d_name);
DIR * hidraw_dir = opendir(hidraw_path); DIR *hidraw_dir = opendir(hidraw_path);
struct dirent * hidraw = NULL; struct dirent *hidraw = NULL;
while((hidraw = readdir(hidraw_dir)) != NULL) { while ((hidraw = readdir(hidraw_dir)) != NULL) {
if(strncmp(hidraw->d_name, "hidraw", 6) == 0) break; if (strncmp(hidraw->d_name, "hidraw", 6) == 0)
break;
} }
if(hidraw == NULL) { if (hidraw == NULL) {
printf("Couldn't get hidraw of %s", input->d_name); printf("Couldn't get hidraw of %s", input->d_name);
continue; continue;
} }
@ -210,14 +250,17 @@ void poll_devices() {
} }
dev.hidraw = open(hidraw_path, O_WRONLY); dev.hidraw = open(hidraw_path, O_WRONLY);
if(dev.hidraw < 0) goto skip; if (dev.hidraw < 0)
goto skip;
dev.name = malloc(256); dev.name = malloc(256);
if(dev.name == NULL) if (dev.name == NULL)
dev.name = DEFAULT_NAME; dev.name = DEFAULT_NAME;
else else
strcpy(dev.name, name); strcpy(dev.name, name);
setup_device(&dev);
pthread_mutex_lock(&devices_mutex); pthread_mutex_lock(&devices_mutex);
vec_push(&devices, &uniq); vec_push(&devices, &uniq);
pthread_mutex_unlock(&devices_mutex); pthread_mutex_unlock(&devices_mutex);
@ -227,13 +270,13 @@ void poll_devices() {
continue; continue;
// close open file descriptor and continue // close open file descriptor and continue
skip: skip:
close(dev.event); close(dev.event);
continue; continue;
}; };
closedir(input_dir); closedir(input_dir);
if(new_devices.len > 0) { if (new_devices.len > 0) {
pthread_mutex_lock(&devices_queue_mutex); pthread_mutex_lock(&devices_queue_mutex);
vec_extend(&devices_queue, new_devices.data, new_devices.len); vec_extend(&devices_queue, new_devices.data, new_devices.len);
// Signal that there are new devices // Signal that there are new devices
@ -242,13 +285,32 @@ skip:
} }
} }
void * hid_thread() { void apply_controller_state(PhysicalDevice *dev, MessageControllerState *state) {
uint8_t buf[32] = {0x05, 0xff, 0x00, 0x00};
buf[4] = state->small_rumble;
buf[5] = state->big_rumble;
buf[6] = state->led[0];
buf[7] = state->led[1];
buf[8] = state->led[2];
buf[9] = state->flash_on;
buf[10] = state->flash_off;
write(dev->hidraw, buf, 32);
if(state->flash_on == 0 && state->flash_off == 0) {
fsync(dev->hidraw);
// Send a second time because it doesn't work otherwise
write(dev->hidraw, buf, 32);
};
}
void *hid_thread() {
printf("HID: start\n"); printf("HID: start\n");
poll_devices_init(); poll_devices_init();
while(1) { while (1) {
poll_devices(); poll_devices();
struct timespec ts; struct timespec ts;
ts.tv_sec = 1; ts.tv_sec = 1;
ts.tv_nsec = 0; ts.tv_nsec = 0;
nanosleep(&ts, NULL); nanosleep(&ts, NULL);
} }

27
hid.h
View File

@ -1,21 +1,32 @@
// vi: set ft=c // vi: set ft=c
#ifndef HID_H #ifndef HID_H
#define HID_H #define HID_H
#include<stdint.h> #include "net.h"
#include<pthread.h>
#include "vec.h" #include "vec.h"
#include <linux/input.h>
#include <pthread.h>
#include <stdint.h>
typedef uint64_t uniq_t; typedef uint64_t uniq_t;
typedef struct { typedef struct {
int event; uint8_t abs_indices[ABS_CNT];
int hidraw; uint8_t rel_indices[REL_CNT];
uniq_t uniq; uint8_t key_indices[KEY_CNT];
char * name; } DeviceMap;
typedef struct {
int event;
int hidraw;
uniq_t uniq;
char *name;
DeviceMap mapping;
MessageDeviceInfo device_info;
} PhysicalDevice; } PhysicalDevice;
void * hid_thread(); void *hid_thread();
void return_device(PhysicalDevice * dev); void return_device(PhysicalDevice *dev);
PhysicalDevice get_device(); PhysicalDevice get_device();
void apply_controller_state(PhysicalDevice *dev, MessageControllerState *state);
#endif #endif

14
main.c
View File

@ -12,6 +12,7 @@
#include "main.h" #include "main.h"
#include "hid.h" #include "hid.h"
#include "server.h" #include "server.h"
#include "util.h"
const char* USAGE[] = { const char* USAGE[] = {
"jsfw client [address] [port]\n", "jsfw client [address] [port]\n",
@ -19,14 +20,6 @@ const char* USAGE[] = {
}; };
const size_t EVENT_SIZE = sizeof(struct js_event); const size_t EVENT_SIZE = sizeof(struct js_event);
void panicf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
exit(1);
}
uint16_t parse_port(const char * str) { uint16_t parse_port(const char * str) {
long long n = atoll(str); long long n = atoll(str);
if(n <= 0 || n > UINT16_MAX) if(n <= 0 || n > UINT16_MAX)
@ -37,9 +30,8 @@ uint16_t parse_port(const char * str) {
void server(uint16_t port) { void server(uint16_t port) {
printf("Server (port: %u).\n", port); printf("Server (port: %u).\n", port);
pthread_t _; pthread_t thread;
pthread_create(&_, NULL, hid_thread, NULL); pthread_create(&thread, NULL, hid_thread, NULL);
server_run(port); server_run(port);
} }

5
main.h
View File

@ -1,10 +1,5 @@
// vi: set ft=c // vi: set ft=c
#ifndef MAIN_H #ifndef MAIN_H
#define MAIN_H #define MAIN_H
#include<stdint.h>
#include<pthread.h>
#include "vec.h"
void panicf(const char * fmt, ...);
#endif #endif

196
net.c
View File

@ -9,79 +9,145 @@ Message msg_device_info() {
return s; return s;
} }
int msg_deserialize(const uint8_t * buf, size_t len, Message * dst) { int msg_deserialize(const uint8_t *buf, size_t len, Message *dst) {
// Decrement len so that it becomes the len of the data without the code. // Decrement len so that it becomes the len of the data without the code.
if(len-- < 1) return -1; if (len-- < 1)
return -1;
// This ensures that only a byte is read instead of a full enum value // This ensures that only a byte is read instead of a full enum value
uint8_t code_byte = buf[0]; uint8_t code_byte = buf[0];
MessageCode code = (MessageCode) code_byte; MessageCode code = (MessageCode)code_byte;
switch(code) { switch (code) {
case Heartbeat: case DeviceInfo:
if(MSS_HEARTBEAT > len) return -1; if (len < 3)
dst->code = code;
dst->heartbeat.alive = buf[1];
return 0;
case DeviceInfo:
if(MSS_DEVICE_INFO > len) return -1;
dst->code = code;
return 0;
case DeviceReport:
if(len < MSS_DEVICE_REPORT) return -1;
dst->code = code;
return 0;
case DeviceDestroy:
if(len < MSS_DEVICE_DESTROY) return -1;
dst->code = code;
return 0;
case ControllerState:
if(len < MSS_CONTROLLER_STATE) return -1;
dst->code = code;
dst->controller_state.led[0] = buf[1];
dst->controller_state.led[1] = buf[2];
dst->controller_state.led[2] = buf[3];
dst->controller_state.small_rumble = buf[4];
dst->controller_state.big_rumble = buf[5];
dst->controller_state.flash_on = buf[6];
dst->controller_state.flash_off = buf[7];
return 0;
default:
return -1; return -1;
uint8_t abs = buf[1];
uint8_t rel = buf[2];
uint8_t key = buf[3];
buf += 4;
if (MSS_DEVICE_INFO(abs, rel, key) > len)
return -1;
dst->code = code;
dst->device_info.abs_count = abs;
dst->device_info.rel_count = rel;
dst->device_info.key_count = key;
// SOA in c but serialized as AOS
for (int i = 0; i < abs; i++) {
uint32_t *buf32 = (uint32_t *)(buf + 1);
dst->device_info.abs_id[i] = buf[0];
dst->device_info.abs_min[i] = buf32[0];
dst->device_info.abs_max[i] = buf32[1];
dst->device_info.abs_fuzz[i] = buf32[2];
dst->device_info.abs_flat[i] = buf32[3];
dst->device_info.abs_res[i] = buf32[4];
buf += 21;
}
for (int i = 0; i < rel; i++)
dst->device_info.rel_id[i] = *(buf++);
for (int i = 0; i < key; i++)
dst->device_info.key_id[i] = *(buf++);
return 0;
case DeviceReport:
if (len < MSS_DEVICE_REPORT)
return -1;
dst->code = code;
return 0;
case DeviceDestroy:
if (len < MSS_DEVICE_DESTROY)
return -1;
dst->code = code;
return 0;
case ControllerState:
if (len < MSS_CONTROLLER_STATE)
return -1;
dst->code = code;
dst->controller_state.led[0] = buf[1];
dst->controller_state.led[1] = buf[2];
dst->controller_state.led[2] = buf[3];
dst->controller_state.small_rumble = buf[4];
dst->controller_state.big_rumble = buf[5];
dst->controller_state.flash_on = buf[6];
dst->controller_state.flash_off = buf[7];
return 0;
default:
return -1;
} }
} }
// The indices have to match with msg_deserialize // The indices have to match with msg_deserialize
int msg_serialize(uint8_t * buf, size_t len, Message msg) { int msg_serialize(uint8_t *buf, size_t len, Message *msg) {
switch(msg.code) { // If len is 0 we can't serialize any message
case Heartbeat: if (len-- == 0)
if(MSS_HEARTBEAT >= len) return -1; return -1;
buf[0] = (uint8_t) msg.code;
buf[1] = msg.heartbeat.alive; switch (msg->code) {
return 0; case DeviceInfo:; // semicolon needed here
case DeviceInfo: uint8_t abs = msg->device_info.abs_count;
if(MSS_DEVICE_INFO >= len) return -1; uint8_t rel = msg->device_info.rel_count;
buf[0] = (uint8_t) msg.code; uint8_t key = msg->device_info.key_count;
return 0; if (len < MSS_DEVICE_INFO(abs, rel, len))
case DeviceReport:
if(MSS_DEVICE_REPORT >= len) return -1;
buf[0] = (uint8_t) msg.code;
return 0;
case DeviceDestroy:
if(MSS_DEVICE_DESTROY >= len) return -1;
buf[0] = (uint8_t) msg.code;
return 0;
case ControllerState:
if(MSS_CONTROLLER_STATE >= len) return -1;
buf[0] = (uint8_t) msg.code;
buf[1] = msg.controller_state.led[0];
buf[2] = msg.controller_state.led[1];
buf[3] = msg.controller_state.led[2];
buf[4] = msg.controller_state.small_rumble;
buf[5] = msg.controller_state.big_rumble;
buf[6] = msg.controller_state.flash_on;
buf[7] = msg.controller_state.flash_off;
return 0;
default:
return -1; return -1;
buf[0] = (uint8_t)msg->code;
buf[1] = abs;
buf[2] = rel;
buf[3] = key;
buf += 4;
for (int i = 0; i < abs; i++) {
uint32_t *buf32 = (uint32_t *)(buf + 1);
buf[0] = msg->device_info.abs_id[i];
buf32[0] = msg->device_info.abs_min[i];
buf32[1] = msg->device_info.abs_max[i];
buf32[2] = msg->device_info.abs_fuzz[i];
buf32[3] = msg->device_info.abs_flat[i];
buf32[4] = msg->device_info.abs_res[i];
buf += 21;
}
for (int i = 0; i < rel; i++)
*(buf++) = msg->device_info.rel_id[i];
for (int i = 0; i < key; i++)
*(buf++) = msg->device_info.key_id[i];
return MSS_DEVICE_INFO(abs, rel, key) + 1;
case DeviceReport:
if (len < MSS_DEVICE_REPORT)
return -1;
buf[0] = (uint8_t)msg->code;
return MSS_DEVICE_REPORT + 1;
case DeviceDestroy:
if (len < MSS_DEVICE_DESTROY)
return -1;
buf[0] = (uint8_t)msg->code;
return MSS_DEVICE_DESTROY + 1;
case ControllerState:
if (len < MSS_CONTROLLER_STATE)
return -1;
buf[0] = (uint8_t)msg->code;
buf[1] = msg->controller_state.led[0];
buf[2] = msg->controller_state.led[1];
buf[3] = msg->controller_state.led[2];
buf[4] = msg->controller_state.small_rumble;
buf[5] = msg->controller_state.big_rumble;
buf[6] = msg->controller_state.flash_on;
buf[7] = msg->controller_state.flash_off;
return MSS_CONTROLLER_STATE + 1;
default:
return -1;
} }
} }

57
net.h
View File

@ -1,30 +1,39 @@
// vi: set ft=c // vi: set ft=c
#ifndef NET_H #ifndef NET_H
#define NET_H #define NET_H
#include<stdint.h> #include <linux/input.h>
#include<stdlib.h> #include <stdint.h>
#include <stdlib.h>
typedef enum { typedef enum {
Heartbeat = 0, DeviceInfo = 1,
DeviceInfo = 1, DeviceReport = 2,
DeviceReport = 2, DeviceDestroy = 3,
DeviceDestroy = 3,
ControllerState = 4, ControllerState = 4,
} MessageCode; } MessageCode;
typedef struct { typedef struct {
MessageCode code; MessageCode code;
uint8_t alive;
} MessageHeartbeat; uint8_t abs_count;
#define MSS_HEARTBEAT 1 uint8_t rel_count;
uint8_t key_count;
uint8_t abs_id[ABS_CNT];
uint32_t abs_min[ABS_CNT];
uint32_t abs_max[ABS_CNT];
uint32_t abs_fuzz[ABS_CNT];
uint32_t abs_flat[ABS_CNT];
uint32_t abs_res[ABS_CNT];
uint8_t rel_id[REL_CNT];
uint8_t key_id[KEY_CNT];
} MessageDeviceInfo;
#define MSS_DEVICE_INFO(abs, rel, key) (3 + abs * 21 + rel * 1 + key * 1)
// MSS -> Message Serialized Size: // MSS -> Message Serialized Size:
// Size of the data of the message when serialized (no alignment / padding) // Size of the data of the message when serialized (no alignment / padding)
typedef struct {
MessageCode code;
} MessageDeviceInfo;
#define MSS_DEVICE_INFO 0
typedef struct { typedef struct {
MessageCode code; MessageCode code;
} MessageDeviceReport; } MessageDeviceReport;
@ -35,8 +44,9 @@ typedef struct {
} MessageDeviceDestroy; } MessageDeviceDestroy;
#define MSS_DEVICE_DESTROY 0 #define MSS_DEVICE_DESTROY 0
typedef struct { typedef struct {
MessageCode code; MessageCode code;
uint8_t led[3]; uint8_t led[3];
uint8_t small_rumble; uint8_t small_rumble;
uint8_t big_rumble; uint8_t big_rumble;
@ -46,15 +56,18 @@ typedef struct {
#define MSS_CONTROLLER_STATE 7 #define MSS_CONTROLLER_STATE 7
typedef union { typedef union {
MessageCode code; MessageCode code;
MessageHeartbeat heartbeat; MessageDeviceInfo device_info;
MessageDeviceInfo device_info; MessageDeviceReport device_report;
MessageDeviceReport device_report; MessageDeviceDestroy device_destroy;
MessageDeviceDestroy device_destroy;
MessageControllerState controller_state; MessageControllerState controller_state;
} Message; } Message;
int msg_deserialize(const uint8_t * buf, size_t len, Message * dst); // Read a message from a buffer with a length, message goes into dst, returns -1 if a messsage couldn't be
int msg_serialize(uint8_t * buf, size_t len, Message msg); // read
int msg_deserialize(const uint8_t *buf, size_t len, Message *dst);
// Write a message to a buffer with a length, return -1 if the message couldn't be written (buffer not big
// enough). Returns the length of the serialized message if succeeded.
int msg_serialize(uint8_t *buf, size_t len, Message *msg);
#endif #endif

View File

@ -1,14 +1,19 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <fcntl.h>
#include <linux/input.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <pthread.h> #include <pthread.h>
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/socket.h> #include <sys/socket.h>
#include "hid.h" #include "hid.h"
#include "main.h"
#include "net.h" #include "net.h"
#include "util.h"
#include "vec.h" #include "vec.h"
struct Connection { struct Connection {
@ -19,12 +24,13 @@ struct Connection {
void *server_handle_conn(void *args_) { void *server_handle_conn(void *args_) {
struct Connection *args = args_; struct Connection *args = args_;
printf("THREAD(%u): start\n", args->id); printf("CONN(%u): start\n", args->id);
int enable = 1; int enable = true;
int idle_time = 10; int idle_time = 10;
int keep_count = 5; int keep_count = 5;
int keep_interval = 5; int keep_interval = 2;
if (setsockopt(args->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)) != 0) if (setsockopt(args->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)) != 0)
printf("ERR(server_handle_conn): Enabling socket keepalives on client\n"); printf("ERR(server_handle_conn): Enabling socket keepalives on client\n");
if (setsockopt(args->socket, SOL_TCP, TCP_KEEPIDLE, &idle_time, sizeof(idle_time)) != 0) if (setsockopt(args->socket, SOL_TCP, TCP_KEEPIDLE, &idle_time, sizeof(idle_time)) != 0)
@ -34,26 +40,50 @@ void *server_handle_conn(void *args_) {
if (setsockopt(args->socket, SOL_TCP, TCP_KEEPINTVL, &keep_interval, sizeof(keep_interval)) != 0) if (setsockopt(args->socket, SOL_TCP, TCP_KEEPINTVL, &keep_interval, sizeof(keep_interval)) != 0)
printf("ERR(server_handle_conn): Setting idle retry interval\n"); printf("ERR(server_handle_conn): Setting idle retry interval\n");
uint8_t buf[2048];
PhysicalDevice dev = get_device(); PhysicalDevice dev = get_device();
printf("THREAD(%u): got device '%s'\n", args->id, dev.name); printf("CONN(%u): got device '%s'\n", args->id, dev.name);
int len = msg_serialize(buf, 2048, (Message *)&dev.device_info);
write(args->socket, buf, len);
struct pollfd pfd[2] = {};
pfd[0].fd = args->socket;
pfd[0].events = POLLIN;
pfd[1].fd = dev.event;
pfd[1].events = POLLIN;
uint8_t buf[1024];
while (1) { while (1) {
int len = recv(args->socket, buf, 1024, MSG_WAITALL); int rc = poll(pfd, 1, -1);
if (rc < 0) // error (connection closed)
if (len <= 0)
goto conn_end; goto conn_end;
Message msg; if (pfd[0].revents & POLLIN) {
if (msg_deserialize(buf, len, &msg) == 0) { int len = recv(args->socket, buf, 2048, 0);
if (len <= 0)
goto conn_end;
Message msg;
if (msg_deserialize(buf, len, &msg) == 0) {
if(msg.code == ControllerState) {
apply_controller_state(&dev, (MessageControllerState*)&msg);
} else {
printf("CONN(%d): Illegal message\n", args->id);
}
} else {
printf("CONN(%d): Couldn't parse message.\n", args->id);
}
}
if (pfd[1].revents & POLLIN) {
} else {
printf("Couldn't parse message.\n");
} }
} }
printf("THREAD(%u): connection closed\n", args->id);
conn_end: conn_end:
shutdown(args->socket, SHUT_RDWR);
printf("CONN(%u): connection closed\n", args->id);
return_device(&dev); return_device(&dev);
free(args); free(args);
return NULL; return NULL;

26
util.c
View File

@ -1,22 +1,18 @@
#include<limits.h>
#include<stdarg.h>
#include<stdio.h>
#include<stdlib.h>
#include "util.h" #include "util.h"
#include <limits.h>
#ifndef __has_builtin #ifndef __has_builtin
#define __has_builtin(_) 0 #define __has_builtin(_) 0
#endif #endif
unsigned long log2lu(unsigned long n) { void panicf(const char *fmt, ...) {
#if __has_builtin(__builtin_clz) va_list args;
return sizeof(unsigned long) * CHAR_BIT - __builtin_clz(n) - 1; va_start(args, fmt);
#else vprintf(fmt, args);
unsigned long res = 0; va_end(args);
while(n >>= 1) ++res; exit(1);
return res;
#endif
}
uint32_t rotl(uint32_t n, unsigned int c) {
const unsigned int mask = (CHAR_BIT*sizeof(n) - 1);
c &= mask;
return (n<<c) | (n>>( (-c)&mask ));
} }

4
util.h
View File

@ -1,9 +1,7 @@
// vi: set ft=c // vi: set ft=c
#ifndef UTIL_H #ifndef UTIL_H
#define UTIL_H #define UTIL_H
#include <stdint.h>
unsigned long log2lu(unsigned long); void panicf(const char *fmt, ...);
uint32_t rotl (uint32_t n, unsigned int c);
#endif #endif