client mostly done
This commit is contained in:
parent
5bdf9f4c58
commit
063c69303b
|
@ -1,6 +1,8 @@
|
||||||
|
# vi:ft=yaml
|
||||||
BasedOnStyle: LLVM
|
BasedOnStyle: LLVM
|
||||||
IndentWidth: 4
|
IndentWidth: 4
|
||||||
AlignConsecutiveDeclarations: true
|
AlignConsecutiveDeclarations: true
|
||||||
AlignConsecutiveAssignments: true
|
AlignConsecutiveAssignments: true
|
||||||
PointerAlignment: Right
|
PointerAlignment: Right
|
||||||
ColumnLimit: 110
|
ColumnLimit: 110
|
||||||
|
IncludeBlocks: Regroup
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -1,6 +1,6 @@
|
||||||
Q=@
|
Q=@
|
||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-g -Wall -Wno-format-truncation -pthread
|
CFLAGS=-g -Wall -Wno-format-truncation -pthread -DJSFW_DEV
|
||||||
LDFLAGS=
|
LDFLAGS=
|
||||||
BUILD_DIR=./objects
|
BUILD_DIR=./objects
|
||||||
BIN=jsfw
|
BIN=jsfw
|
||||||
|
|
319
client.c
319
client.c
|
@ -1,4 +1,319 @@
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
void client_run(char *address, uint16_t port) {}
|
#include "net.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/uinput.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int fd;
|
||||||
|
MessageDeviceInfo info;
|
||||||
|
} VirtualDevice;
|
||||||
|
|
||||||
|
#ifdef JSFW_DEV
|
||||||
|
// Path for dev environment (no root)
|
||||||
|
const char *FIFO_PATH = "/tmp/jsfw_fifo";
|
||||||
|
#else
|
||||||
|
const char *FIFO_PATH = "/run/jsfw_fifo";
|
||||||
|
#endif
|
||||||
|
const int CONN_RETRY_DELAY = 5;
|
||||||
|
// Constant for the virtual device
|
||||||
|
const uint16_t VIRT_VENDOR = 0x6969;
|
||||||
|
const uint16_t VIRT_PRODUCT = 0x0420;
|
||||||
|
const uint16_t VIRT_VERSION = 1;
|
||||||
|
const char *VIRT_NAME = "JSFW Virtual Device";
|
||||||
|
|
||||||
|
static int fifo_attempt = 0;
|
||||||
|
|
||||||
|
static struct sockaddr_in server_addr = {};
|
||||||
|
static char server_addrp[64] = {};
|
||||||
|
static uint16_t server_port = -1;
|
||||||
|
|
||||||
|
static struct pollfd poll_fds[2];
|
||||||
|
static struct pollfd *fifo_poll = &poll_fds[0];
|
||||||
|
static struct pollfd *socket_poll = &poll_fds[1];
|
||||||
|
static int fifo = -1;
|
||||||
|
static int sock = -1;
|
||||||
|
// static to avoid having this on the stack because a message is about 2kb in memory
|
||||||
|
static Message message;
|
||||||
|
static VirtualDevice device = {};
|
||||||
|
|
||||||
|
static inline bool device_exists() { return device.fd > 0; }
|
||||||
|
|
||||||
|
void device_destroy() {
|
||||||
|
if (!device_exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ioctl(device.fd, UI_DEV_DESTROY);
|
||||||
|
close(device.fd);
|
||||||
|
device.fd = -1;
|
||||||
|
printf("CLIENT: Destroyed device\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_init(MessageDeviceInfo *dev) {
|
||||||
|
device_destroy();
|
||||||
|
|
||||||
|
int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("CLIENT: Error while opening /dev/uinput, ");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abs
|
||||||
|
if (dev->abs_count > 0) {
|
||||||
|
ioctl(fd, UI_SET_EVBIT, EV_ABS);
|
||||||
|
for (int i = 0; i < dev->abs_count; i++) {
|
||||||
|
struct uinput_abs_setup setup;
|
||||||
|
setup.code = dev->abs_id[i];
|
||||||
|
setup.absinfo.minimum = dev->abs_min[i];
|
||||||
|
setup.absinfo.maximum = dev->abs_max[i];
|
||||||
|
setup.absinfo.fuzz = dev->abs_fuzz[i];
|
||||||
|
setup.absinfo.flat = dev->abs_flat[i];
|
||||||
|
setup.absinfo.resolution = dev->abs_res[i];
|
||||||
|
setup.absinfo.value = 0;
|
||||||
|
ioctl(fd, UI_ABS_SETUP, &setup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rel
|
||||||
|
if (dev->rel_count > 0) {
|
||||||
|
ioctl(fd, UI_SET_EVBIT, EV_REL);
|
||||||
|
for (int i = 0; i < dev->rel_count; i++) {
|
||||||
|
ioctl(fd, UI_SET_RELBIT, dev->rel_id[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key
|
||||||
|
if (dev->key_count > 0) {
|
||||||
|
ioctl(fd, UI_SET_EVBIT, EV_KEY);
|
||||||
|
for (int i = 0; i < dev->key_count; i++) {
|
||||||
|
ioctl(fd, UI_SET_KEYBIT, dev->key_id[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct uinput_setup setup = {};
|
||||||
|
|
||||||
|
setup.id.bustype = BUS_VIRTUAL;
|
||||||
|
setup.id.vendor = VIRT_VENDOR;
|
||||||
|
setup.id.product = VIRT_PRODUCT;
|
||||||
|
setup.id.version = VIRT_VERSION;
|
||||||
|
strncpy(setup.name, VIRT_NAME, UINPUT_MAX_NAME_SIZE);
|
||||||
|
|
||||||
|
ioctl(fd, UI_DEV_SETUP, &setup);
|
||||||
|
ioctl(fd, UI_DEV_CREATE);
|
||||||
|
|
||||||
|
device.fd = fd;
|
||||||
|
memcpy(&device.info, dev, sizeof(MessageDeviceInfo));
|
||||||
|
printf("CLIENT: Created device (abs: %d, rel: %d, key: %d)\n", dev->abs_count, dev->rel_count,
|
||||||
|
dev->key_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
int device_emit(uint16_t type, uint16_t id, uint32_t value) {
|
||||||
|
struct input_event event = {};
|
||||||
|
|
||||||
|
event.type = type;
|
||||||
|
event.code = id;
|
||||||
|
event.value = value;
|
||||||
|
|
||||||
|
return write(device.fd, &event, sizeof(event)) != sizeof(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_handle_report(MessageDeviceReport *report) {
|
||||||
|
if (!device_exists()) {
|
||||||
|
printf("CLIENT: Got report but device info\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (report->abs_count != device.info.abs_count || report->rel_count != device.info.rel_count ||
|
||||||
|
report->key_count != device.info.key_count) {
|
||||||
|
printf("CLIENT: Report doesn't match with device info\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < report->abs_count; i++) {
|
||||||
|
if (device_emit(EV_ABS, device.info.abs_id[i], report->abs[i]) != 0)
|
||||||
|
printf("CLIENT: Error writing abs event to uinput\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < report->rel_count; i++) {
|
||||||
|
if (device_emit(EV_REL, device.info.rel_id[i], report->rel[i]) != 0)
|
||||||
|
printf("CLIENT: Error writing rel event to uinput\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < report->key_count; i++) {
|
||||||
|
if (device_emit(EV_KEY, device.info.key_id[i], (uint32_t)(!report->key[i]) - 1 ) != 0)
|
||||||
|
printf("CLIENT: Error writing key event to uinput\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
device_emit(EV_SYN, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_fifo();
|
||||||
|
|
||||||
|
void open_fifo() {
|
||||||
|
close(fifo);
|
||||||
|
fifo = open(FIFO_PATH, O_RDONLY | O_NONBLOCK);
|
||||||
|
if (fifo < 0 && fifo_attempt == 0) {
|
||||||
|
fifo_attempt++;
|
||||||
|
unlink(FIFO_PATH);
|
||||||
|
setup_fifo();
|
||||||
|
} else if (fifo < 0) {
|
||||||
|
panicf("CLIENT: Couldn't open fifo, aborting\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_fifo() {
|
||||||
|
mode_t prev = umask(0);
|
||||||
|
mkfifo(FIFO_PATH, 0666);
|
||||||
|
umask(prev);
|
||||||
|
|
||||||
|
open_fifo();
|
||||||
|
|
||||||
|
fifo_poll->fd = fifo;
|
||||||
|
fifo_poll->events = POLLIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void connect_server() {
|
||||||
|
while (1) {
|
||||||
|
if (sock > 0) {
|
||||||
|
device_destroy();
|
||||||
|
shutdown(sock, SHUT_RDWR);
|
||||||
|
close(sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sock < 0)
|
||||||
|
panicf("Couldn't create socket\n");
|
||||||
|
|
||||||
|
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {
|
||||||
|
printf("CLIENT: Couldn't connect to %s:%d, retrying in %ds\n", server_addrp, server_port,
|
||||||
|
CONN_RETRY_DELAY);
|
||||||
|
struct timespec ts = {};
|
||||||
|
ts.tv_sec = CONN_RETRY_DELAY;
|
||||||
|
nanosleep(&ts, NULL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Set non blocking
|
||||||
|
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
|
||||||
|
socket_poll->fd = sock;
|
||||||
|
printf("CLIENT: Connected !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_server(char *address, uint16_t port) {
|
||||||
|
// setup address
|
||||||
|
server_addr.sin_family = AF_INET;
|
||||||
|
if (inet_pton(AF_INET, address, &server_addr.sin_addr) == 0)
|
||||||
|
printf("CLIENT: failed to parse address '%s', defaulting to 0.0.0.0 (localhost)\n", address);
|
||||||
|
inet_ntop(AF_INET, &server_addr.sin_addr, server_addrp, 64);
|
||||||
|
server_port = port;
|
||||||
|
server_addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
socket_poll->events = POLLIN;
|
||||||
|
|
||||||
|
connect_server();
|
||||||
|
}
|
||||||
|
|
||||||
|
void early_checks() {
|
||||||
|
int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("CLIENT: Can't open /dev/uinput, aborting now: ");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void client_run(char *address, uint16_t port) {
|
||||||
|
// Device doesn't exist yet
|
||||||
|
device.fd = -1;
|
||||||
|
|
||||||
|
early_checks();
|
||||||
|
setup_fifo();
|
||||||
|
setup_server(address, port);
|
||||||
|
|
||||||
|
uint8_t buf[2049];
|
||||||
|
while (1) {
|
||||||
|
int rc = poll(poll_fds, 2, -1);
|
||||||
|
if (rc < 0) {
|
||||||
|
perror("CLIENT: Error on poll, ");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fifo_poll->revents & POLLHUP || fifo_poll->revents & POLLERR) {
|
||||||
|
// Reopen fifo
|
||||||
|
open_fifo();
|
||||||
|
} else if (fifo_poll->revents & POLLIN) {
|
||||||
|
int len = read(fifo, buf, 2048);
|
||||||
|
if (len <= 0) {
|
||||||
|
// This shouldn't ever happen as the poll already checks for the kind of error that would
|
||||||
|
// cause len to be <= 0
|
||||||
|
printf("CLIENT: supposedly unreachable code reached\n");
|
||||||
|
open_fifo();
|
||||||
|
} else {
|
||||||
|
// We've got data from the fifo
|
||||||
|
// TODO: parse and handle that
|
||||||
|
buf[len] = '\0';
|
||||||
|
printf("CLIENT: Got fifo message:\n%s\n", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A broken or closed socket produces a POLLIN event, so we check for error on the recv
|
||||||
|
if (socket_poll->revents & POLLIN) {
|
||||||
|
int len = recv(sock, buf, 2048, 0);
|
||||||
|
if (len <= 0) {
|
||||||
|
printf("CLIENT: Lost connection to server, reconnecting\n");
|
||||||
|
shutdown(sock, SHUT_RDWR);
|
||||||
|
connect_server();
|
||||||
|
// we can continue here because there's nothing after, unlike above for fifo (this reduces
|
||||||
|
// indentation)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We've got data from the server
|
||||||
|
if (msg_deserialize(buf, len, &message) != 0) {
|
||||||
|
printf("CLIENT: Couldn't parse message (code: %d, len: %d)\n", buf[0], len);
|
||||||
|
int l = len > 100 ? 100 : len;
|
||||||
|
for(int i = 0; i < l; i++) {
|
||||||
|
printf("%02x", buf[i]);
|
||||||
|
}
|
||||||
|
if(len > 100) {
|
||||||
|
printf(" ... %d more bytes", len - 100);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.code == DeviceInfo) {
|
||||||
|
|
||||||
|
if (device_exists())
|
||||||
|
printf("CLIENT: Got more than one device info\n");
|
||||||
|
device_init((MessageDeviceInfo *)&message);
|
||||||
|
|
||||||
|
} else if (message.code == DeviceReport) {
|
||||||
|
|
||||||
|
device_handle_report((MessageDeviceReport *)&message);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
printf("CLIENT: Illegal message\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
2
client.h
2
client.h
|
@ -1,4 +1,4 @@
|
||||||
// vi: set ft=c
|
// vi:ft=c
|
||||||
#ifndef CLIENT_H
|
#ifndef CLIENT_H
|
||||||
#define CLIENT_H
|
#define CLIENT_H
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
23
hid.c
23
hid.c
|
@ -1,3 +1,7 @@
|
||||||
|
#include "hid.h"
|
||||||
|
|
||||||
|
#include "vec.h"
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
@ -10,9 +14,6 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "hid.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;
|
||||||
// List of the new devices of a poll, static to keep the allocation alive
|
// List of the new devices of a poll, static to keep the allocation alive
|
||||||
|
@ -59,7 +60,7 @@ void setup_device(PhysicalDevice *dev) {
|
||||||
for (int i = 0; i < ABS_CNT; i++)
|
for (int i = 0; i < ABS_CNT; i++)
|
||||||
dev->mapping.abs_indices[i] = -1;
|
dev->mapping.abs_indices[i] = -1;
|
||||||
for (int i = 0; i < REL_CNT; i++)
|
for (int i = 0; i < REL_CNT; i++)
|
||||||
dev->mapping.key_indices[i] = -1;
|
dev->mapping.rel_indices[i] = -1;
|
||||||
for (int i = 0; i < KEY_CNT; i++)
|
for (int i = 0; i < KEY_CNT; i++)
|
||||||
dev->mapping.key_indices[i] = -1;
|
dev->mapping.key_indices[i] = -1;
|
||||||
|
|
||||||
|
@ -74,7 +75,7 @@ void setup_device(PhysicalDevice *dev) {
|
||||||
if (i == EV_ABS) {
|
if (i == EV_ABS) {
|
||||||
struct input_absinfo abs;
|
struct input_absinfo abs;
|
||||||
ioctl(dev->event, EVIOCGABS(j), &abs);
|
ioctl(dev->event, EVIOCGABS(j), &abs);
|
||||||
uint8_t index = dev->device_info.abs_count++;
|
uint16_t index = dev->device_info.abs_count++;
|
||||||
dev->device_info.abs_id[index] = j;
|
dev->device_info.abs_id[index] = j;
|
||||||
dev->device_info.abs_min[index] = abs.minimum;
|
dev->device_info.abs_min[index] = abs.minimum;
|
||||||
dev->device_info.abs_max[index] = abs.maximum;
|
dev->device_info.abs_max[index] = abs.maximum;
|
||||||
|
@ -83,11 +84,11 @@ void setup_device(PhysicalDevice *dev) {
|
||||||
dev->device_info.abs_res[index] = abs.resolution;
|
dev->device_info.abs_res[index] = abs.resolution;
|
||||||
dev->mapping.abs_indices[j] = index;
|
dev->mapping.abs_indices[j] = index;
|
||||||
} else if (i == EV_REL) {
|
} else if (i == EV_REL) {
|
||||||
uint8_t index = dev->device_info.rel_count++;
|
uint16_t index = dev->device_info.rel_count++;
|
||||||
dev->device_info.rel_id[index] = j;
|
dev->device_info.rel_id[index] = j;
|
||||||
dev->mapping.rel_indices[j] = index;
|
dev->mapping.rel_indices[j] = index;
|
||||||
} else if (i == EV_KEY) {
|
} else if (i == EV_KEY) {
|
||||||
uint8_t index = dev->device_info.key_count++;
|
uint16_t index = dev->device_info.key_count++;
|
||||||
dev->device_info.key_id[index] = j;
|
dev->device_info.key_id[index] = j;
|
||||||
dev->mapping.key_indices[j] = index;
|
dev->mapping.key_indices[j] = index;
|
||||||
}
|
}
|
||||||
|
@ -153,10 +154,10 @@ PhysicalDevice get_device() {
|
||||||
|
|
||||||
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 {
|
||||||
printf("HID: Returning device %012lx\n", dev->uniq);
|
printf("HID: Returning device %012lx\n", dev->uniq);
|
||||||
}
|
}
|
||||||
close(dev->event);
|
close(dev->event);
|
||||||
close(dev->hidraw);
|
close(dev->hidraw);
|
||||||
|
@ -272,7 +273,7 @@ void poll_devices() {
|
||||||
pthread_mutex_unlock(&devices_mutex);
|
pthread_mutex_unlock(&devices_mutex);
|
||||||
vec_push(&new_devices, &dev);
|
vec_push(&new_devices, &dev);
|
||||||
|
|
||||||
printf("HID: New device, %s (%s: %012lx)\n", name, input->d_name, dev.uniq);
|
printf("HID: New device, %s (%s: %012lx)\n", name, input->d_name, dev.uniq);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// close open file descriptor and continue
|
// close open file descriptor and continue
|
||||||
|
@ -311,7 +312,7 @@ void apply_controller_state(PhysicalDevice *dev, MessageControllerState *state)
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hid_thread() {
|
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();
|
||||||
|
|
8
hid.h
8
hid.h
|
@ -1,4 +1,4 @@
|
||||||
// vi: set ft=c
|
// vi:ft=c
|
||||||
#ifndef HID_H
|
#ifndef HID_H
|
||||||
#define HID_H
|
#define HID_H
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
@ -8,9 +8,9 @@
|
||||||
typedef uint64_t uniq_t;
|
typedef uint64_t uniq_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t abs_indices[ABS_CNT];
|
uint16_t abs_indices[ABS_CNT];
|
||||||
uint8_t rel_indices[REL_CNT];
|
uint16_t rel_indices[REL_CNT];
|
||||||
uint8_t key_indices[KEY_CNT];
|
uint16_t key_indices[KEY_CNT];
|
||||||
} DeviceMap;
|
} DeviceMap;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
13
main.c
13
main.c
|
@ -1,15 +1,16 @@
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
#include "hid.h"
|
||||||
|
#include "server.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "client.h"
|
|
||||||
#include "hid.h"
|
|
||||||
#include "main.h"
|
|
||||||
#include "server.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
const char *USAGE[] = {
|
const char *USAGE[] = {
|
||||||
"jsfw client [address] [port]\n",
|
"jsfw client [address] [port]\n",
|
||||||
"jsfw server [port]\n",
|
"jsfw server [port]\n",
|
||||||
|
|
2
main.h
2
main.h
|
@ -1,4 +1,4 @@
|
||||||
// vi: set ft=c
|
// vi:ft=c
|
||||||
#ifndef MAIN_H
|
#ifndef MAIN_H
|
||||||
#define MAIN_H
|
#define MAIN_H
|
||||||
|
|
||||||
|
|
98
net.c
98
net.c
|
@ -1,4 +1,5 @@
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
Message msg_device_info() {
|
Message msg_device_info() {
|
||||||
|
@ -18,16 +19,17 @@ int msg_deserialize(const uint8_t *buf, size_t len, Message *dst) {
|
||||||
uint8_t code_byte = buf[0];
|
uint8_t code_byte = buf[0];
|
||||||
MessageCode code = (MessageCode)code_byte;
|
MessageCode code = (MessageCode)code_byte;
|
||||||
|
|
||||||
uint8_t abs, rel, key;
|
uint16_t abs, rel, key, *buf16;
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case DeviceInfo:
|
case DeviceInfo:
|
||||||
if (len < 3)
|
if (len < 6)
|
||||||
return -1;
|
return -1;
|
||||||
abs = buf[1];
|
buf16 = (uint16_t *)(buf + 1);
|
||||||
rel = buf[2];
|
abs = buf16[0];
|
||||||
key = buf[3];
|
rel = buf16[1];
|
||||||
buf += 4;
|
key = buf16[2];
|
||||||
|
buf += 7;
|
||||||
if (MSS_DEVICE_INFO(abs, rel, key) > len)
|
if (MSS_DEVICE_INFO(abs, rel, key) > len)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -38,33 +40,38 @@ int msg_deserialize(const uint8_t *buf, size_t len, Message *dst) {
|
||||||
|
|
||||||
// SOA in c but serialized as AOS
|
// SOA in c but serialized as AOS
|
||||||
for (int i = 0; i < abs; i++) {
|
for (int i = 0; i < abs; i++) {
|
||||||
uint32_t *buf32 = (uint32_t *)(buf + 1);
|
uint32_t *buf32 = (uint32_t *)(buf + 2);
|
||||||
|
|
||||||
dst->device_info.abs_id[i] = buf[0];
|
dst->device_info.abs_id[i] = *(uint16_t *)buf;
|
||||||
dst->device_info.abs_min[i] = buf32[0];
|
dst->device_info.abs_min[i] = buf32[0];
|
||||||
dst->device_info.abs_max[i] = buf32[1];
|
dst->device_info.abs_max[i] = buf32[1];
|
||||||
dst->device_info.abs_fuzz[i] = buf32[2];
|
dst->device_info.abs_fuzz[i] = buf32[2];
|
||||||
dst->device_info.abs_flat[i] = buf32[3];
|
dst->device_info.abs_flat[i] = buf32[3];
|
||||||
dst->device_info.abs_res[i] = buf32[4];
|
dst->device_info.abs_res[i] = buf32[4];
|
||||||
|
|
||||||
buf += 21;
|
buf += 22;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < rel; i++)
|
for (int i = 0; i < rel; i++) {
|
||||||
dst->device_info.rel_id[i] = *(buf++);
|
dst->device_info.rel_id[i] = *(uint16_t *)buf;
|
||||||
|
buf += 2;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < key; i++)
|
for (int i = 0; i < key; i++) {
|
||||||
dst->device_info.key_id[i] = *(buf++);
|
dst->device_info.key_id[i] = *(uint16_t *)buf;
|
||||||
|
buf += 2;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
case DeviceReport:
|
case DeviceReport:
|
||||||
if (len < 3)
|
if (len < 6)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
abs = buf[1];
|
buf16 = (uint16_t *)(buf + 1);
|
||||||
rel = buf[2];
|
abs = buf16[0];
|
||||||
key = buf[3];
|
rel = buf16[1];
|
||||||
buf += 4;
|
key = buf16[2];
|
||||||
|
buf += 7;
|
||||||
if (len < MSS_DEVICE_REPORT(abs, rel, key))
|
if (len < MSS_DEVICE_REPORT(abs, rel, key))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -86,11 +93,6 @@ int msg_deserialize(const uint8_t *buf, size_t len, Message *dst) {
|
||||||
for (int i = 0; i < key; i++)
|
for (int i = 0; i < key; i++)
|
||||||
dst->device_report.key[i] = *(buf++);
|
dst->device_report.key[i] = *(buf++);
|
||||||
|
|
||||||
return 0;
|
|
||||||
case DeviceDestroy:
|
|
||||||
if (len < MSS_DEVICE_DESTROY)
|
|
||||||
return -1;
|
|
||||||
dst->code = code;
|
|
||||||
return 0;
|
return 0;
|
||||||
case ControllerState:
|
case ControllerState:
|
||||||
if (len < MSS_CONTROLLER_STATE)
|
if (len < MSS_CONTROLLER_STATE)
|
||||||
|
@ -115,7 +117,7 @@ int msg_serialize(uint8_t *buf, size_t len, Message *msg) {
|
||||||
if (len-- == 0)
|
if (len-- == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
uint8_t abs, rel, key;
|
uint16_t abs, rel, key, *buf16;
|
||||||
|
|
||||||
switch (msg->code) {
|
switch (msg->code) {
|
||||||
case DeviceInfo:
|
case DeviceInfo:
|
||||||
|
@ -125,30 +127,36 @@ int msg_serialize(uint8_t *buf, size_t len, Message *msg) {
|
||||||
if (len < MSS_DEVICE_INFO(abs, rel, key))
|
if (len < MSS_DEVICE_INFO(abs, rel, key))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
buf[0] = (uint8_t)msg->code;
|
buf[0] = (uint8_t)msg->code;
|
||||||
buf[1] = abs;
|
buf16 = (uint16_t *)(buf + 1);
|
||||||
buf[2] = rel;
|
buf16[0] = abs;
|
||||||
buf[3] = key;
|
buf16[1] = rel;
|
||||||
buf += 4;
|
buf16[2] = key;
|
||||||
|
buf += 7;
|
||||||
|
|
||||||
for (int i = 0; i < abs; i++) {
|
for (int i = 0; i < abs; i++) {
|
||||||
uint32_t *buf32 = (uint32_t *)(buf + 1);
|
uint32_t *buf32 = (uint32_t *)(buf + 2);
|
||||||
|
|
||||||
|
*(uint16_t *)buf = msg->device_info.abs_id[i];
|
||||||
|
|
||||||
buf[0] = msg->device_info.abs_id[i];
|
|
||||||
buf32[0] = msg->device_info.abs_min[i];
|
buf32[0] = msg->device_info.abs_min[i];
|
||||||
buf32[1] = msg->device_info.abs_max[i];
|
buf32[1] = msg->device_info.abs_max[i];
|
||||||
buf32[2] = msg->device_info.abs_fuzz[i];
|
buf32[2] = msg->device_info.abs_fuzz[i];
|
||||||
buf32[3] = msg->device_info.abs_flat[i];
|
buf32[3] = msg->device_info.abs_flat[i];
|
||||||
buf32[4] = msg->device_info.abs_res[i];
|
buf32[4] = msg->device_info.abs_res[i];
|
||||||
|
|
||||||
buf += 21;
|
buf += 22;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < rel; i++)
|
for (int i = 0; i < rel; i++) {
|
||||||
*(buf++) = msg->device_info.rel_id[i];
|
*(uint16_t *)buf = msg->device_info.rel_id[i];
|
||||||
|
buf += 2;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < key; i++)
|
for (int i = 0; i < key; i++) {
|
||||||
*(buf++) = msg->device_info.key_id[i];
|
*(uint16_t *)buf = msg->device_info.key_id[i];
|
||||||
|
buf += 2;
|
||||||
|
}
|
||||||
|
|
||||||
return MSS_DEVICE_INFO(abs, rel, key) + 1;
|
return MSS_DEVICE_INFO(abs, rel, key) + 1;
|
||||||
case DeviceReport:
|
case DeviceReport:
|
||||||
|
@ -157,11 +165,13 @@ int msg_serialize(uint8_t *buf, size_t len, Message *msg) {
|
||||||
key = msg->device_report.key_count;
|
key = msg->device_report.key_count;
|
||||||
if (len < MSS_DEVICE_REPORT(abs, rel, key))
|
if (len < MSS_DEVICE_REPORT(abs, rel, key))
|
||||||
return -1;
|
return -1;
|
||||||
buf[0] = (uint8_t)msg->code;
|
|
||||||
buf[1] = abs;
|
buf[0] = (uint8_t)msg->code;
|
||||||
buf[2] = rel;
|
buf16 = (uint16_t *)(buf + 1);
|
||||||
buf[3] = key;
|
buf16[0] = abs;
|
||||||
buf += 4;
|
buf16[1] = rel;
|
||||||
|
buf16[2] = key;
|
||||||
|
buf += 7;
|
||||||
|
|
||||||
for (int i = 0; i < abs; i++) {
|
for (int i = 0; i < abs; i++) {
|
||||||
*(uint32_t *)buf = msg->device_report.abs[i];
|
*(uint32_t *)buf = msg->device_report.abs[i];
|
||||||
|
@ -177,12 +187,6 @@ int msg_serialize(uint8_t *buf, size_t len, Message *msg) {
|
||||||
*(buf++) = msg->device_report.key[i];
|
*(buf++) = msg->device_report.key[i];
|
||||||
|
|
||||||
return MSS_DEVICE_REPORT(abs, rel, key) + 1;
|
return MSS_DEVICE_REPORT(abs, rel, key) + 1;
|
||||||
case DeviceDestroy:
|
|
||||||
if (len < MSS_DEVICE_DESTROY)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
buf[0] = (uint8_t)msg->code;
|
|
||||||
return MSS_DEVICE_DESTROY + 1;
|
|
||||||
case ControllerState:
|
case ControllerState:
|
||||||
if (len < MSS_CONTROLLER_STATE)
|
if (len < MSS_CONTROLLER_STATE)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
31
net.h
31
net.h
|
@ -1,4 +1,4 @@
|
||||||
// vi: set ft=c
|
// vi:ft=c
|
||||||
#ifndef NET_H
|
#ifndef NET_H
|
||||||
#define NET_H
|
#define NET_H
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
@ -12,46 +12,40 @@ typedef enum {
|
||||||
ControllerState = 4,
|
ControllerState = 4,
|
||||||
} MessageCode;
|
} MessageCode;
|
||||||
|
|
||||||
// TODO: replace counts by uint16_t
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MessageCode code;
|
MessageCode code;
|
||||||
|
|
||||||
uint8_t abs_count;
|
uint16_t abs_count;
|
||||||
uint8_t rel_count;
|
uint16_t rel_count;
|
||||||
uint8_t key_count;
|
uint16_t key_count;
|
||||||
|
|
||||||
uint8_t abs_id[ABS_CNT];
|
uint16_t abs_id[ABS_CNT];
|
||||||
uint32_t abs_min[ABS_CNT];
|
uint32_t abs_min[ABS_CNT];
|
||||||
uint32_t abs_max[ABS_CNT];
|
uint32_t abs_max[ABS_CNT];
|
||||||
uint32_t abs_fuzz[ABS_CNT];
|
uint32_t abs_fuzz[ABS_CNT];
|
||||||
uint32_t abs_flat[ABS_CNT];
|
uint32_t abs_flat[ABS_CNT];
|
||||||
uint32_t abs_res[ABS_CNT];
|
uint32_t abs_res[ABS_CNT];
|
||||||
|
|
||||||
uint8_t rel_id[REL_CNT];
|
uint16_t rel_id[REL_CNT];
|
||||||
|
|
||||||
uint8_t key_id[KEY_CNT];
|
uint16_t key_id[KEY_CNT];
|
||||||
} MessageDeviceInfo;
|
} MessageDeviceInfo;
|
||||||
#define MSS_DEVICE_INFO(abs, rel, key) (3 + abs * 21 + rel * 1 + key * 1)
|
#define MSS_DEVICE_INFO(abs, rel, key) (6 + abs * 22 + rel * 2 + key * 2)
|
||||||
// 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 {
|
typedef struct {
|
||||||
MessageCode code;
|
MessageCode code;
|
||||||
|
|
||||||
uint8_t abs_count;
|
uint16_t abs_count;
|
||||||
uint8_t rel_count;
|
uint16_t rel_count;
|
||||||
uint8_t key_count;
|
uint16_t key_count;
|
||||||
|
|
||||||
uint32_t abs[ABS_CNT];
|
uint32_t abs[ABS_CNT];
|
||||||
uint32_t rel[REL_CNT];
|
uint32_t rel[REL_CNT];
|
||||||
uint8_t key[KEY_CNT];
|
uint8_t key[KEY_CNT];
|
||||||
} MessageDeviceReport;
|
} MessageDeviceReport;
|
||||||
#define MSS_DEVICE_REPORT(abs, rel, key) (3 + abs * 4 + rel * 4 + key * 1)
|
#define MSS_DEVICE_REPORT(abs, rel, key) (6 + abs * 4 + rel * 4 + key * 1)
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
MessageCode code;
|
|
||||||
} MessageDeviceDestroy;
|
|
||||||
#define MSS_DEVICE_DESTROY 0
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MessageCode code;
|
MessageCode code;
|
||||||
|
@ -68,7 +62,6 @@ typedef union {
|
||||||
MessageCode code;
|
MessageCode code;
|
||||||
MessageDeviceInfo device_info;
|
MessageDeviceInfo device_info;
|
||||||
MessageDeviceReport device_report;
|
MessageDeviceReport device_report;
|
||||||
MessageDeviceDestroy device_destroy;
|
|
||||||
MessageControllerState controller_state;
|
MessageControllerState controller_state;
|
||||||
} Message;
|
} Message;
|
||||||
|
|
||||||
|
|
48
server.c
48
server.c
|
@ -1,3 +1,7 @@
|
||||||
|
#include "hid.h"
|
||||||
|
#include "net.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
|
@ -11,10 +15,6 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "hid.h"
|
|
||||||
#include "net.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
struct Connection {
|
struct Connection {
|
||||||
int socket;
|
int socket;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
@ -62,15 +62,28 @@ void *server_handle_conn(void *args_) {
|
||||||
report.rel_count = dev.device_info.rel_count;
|
report.rel_count = dev.device_info.rel_count;
|
||||||
report.key_count = dev.device_info.key_count;
|
report.key_count = dev.device_info.key_count;
|
||||||
|
|
||||||
|
char *closing_message = "";
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int rc = poll(pfds, 2, -1);
|
int rc = poll(pfds, 2, -1);
|
||||||
if (rc < 0) // error (connection closed)
|
if (rc < 0) { // error (connection closed)
|
||||||
|
closing_message = "Poll error";
|
||||||
goto conn_end;
|
goto conn_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown connection if we lost the peer
|
||||||
|
if (socket_poll->revents & POLLHUP || socket_poll->revents & POLLERR) {
|
||||||
|
closing_message = "Lost peer";
|
||||||
|
goto conn_end;
|
||||||
|
}
|
||||||
|
|
||||||
if (socket_poll->revents & POLLIN) {
|
if (socket_poll->revents & POLLIN) {
|
||||||
int len = recv(args->socket, buf, 2048, 0);
|
int len = recv(args->socket, buf, 2048, 0);
|
||||||
if (len <= 0)
|
|
||||||
|
if (len <= 0) {
|
||||||
|
closing_message = "Lost peer";
|
||||||
goto conn_end;
|
goto conn_end;
|
||||||
|
}
|
||||||
|
|
||||||
Message msg;
|
Message msg;
|
||||||
if (msg_deserialize(buf, len, &msg) == 0) {
|
if (msg_deserialize(buf, len, &msg) == 0) {
|
||||||
|
@ -85,11 +98,23 @@ void *server_handle_conn(void *args_) {
|
||||||
printf("CONN(%d): Couldn't parse message.\n", args->id);
|
printf("CONN(%d): Couldn't parse message.\n", args->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shutdown connection if we lost the device
|
||||||
|
if (event_poll->revents & POLLHUP || event_poll->revents & POLLERR) {
|
||||||
|
closing_message = "Lost device";
|
||||||
|
goto conn_end;
|
||||||
|
}
|
||||||
|
|
||||||
if (event_poll->revents & POLLIN) {
|
if (event_poll->revents & POLLIN) {
|
||||||
struct input_event event;
|
struct input_event event;
|
||||||
int len = read(dev.event, &event, sizeof(struct input_event));
|
|
||||||
if (len <= 0)
|
int len = read(dev.event, &event, sizeof(struct input_event));
|
||||||
|
|
||||||
|
if (len <= 0) {
|
||||||
|
closing_message = "Lost device";
|
||||||
goto conn_end;
|
goto conn_end;
|
||||||
|
}
|
||||||
|
|
||||||
if (len < sizeof(struct input_event)) {
|
if (len < sizeof(struct input_event)) {
|
||||||
printf("CONN(%d): error reading event\n", args->id);
|
printf("CONN(%d): error reading event\n", args->id);
|
||||||
continue;
|
continue;
|
||||||
|
@ -129,7 +154,6 @@ void *server_handle_conn(void *args_) {
|
||||||
printf("CONN(%d): Invalid key\n", args->id);
|
printf("CONN(%d): Invalid key\n", args->id);
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
report.key[index] = !!event.value;
|
report.key[index] = !!event.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,14 +161,14 @@ void *server_handle_conn(void *args_) {
|
||||||
|
|
||||||
conn_end:
|
conn_end:
|
||||||
shutdown(args->socket, SHUT_RDWR);
|
shutdown(args->socket, SHUT_RDWR);
|
||||||
printf("CONN(%u): connection closed\n", args->id);
|
printf("CONN(%u): connection closed (%s)\n", args->id, closing_message);
|
||||||
return_device(&dev);
|
return_device(&dev);
|
||||||
free(args);
|
free(args);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void server_run(uint16_t port) {
|
void server_run(uint16_t port) {
|
||||||
printf("SERVER: start\n");
|
printf("SERVER: start\n");
|
||||||
|
|
||||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (sock < 0)
|
if (sock < 0)
|
||||||
|
@ -170,7 +194,7 @@ void server_run(uint16_t port) {
|
||||||
conn.socket = accept(sock, &con_addr, &con_len);
|
conn.socket = accept(sock, &con_addr, &con_len);
|
||||||
|
|
||||||
if (conn.socket >= 0) {
|
if (conn.socket >= 0) {
|
||||||
printf("SERVER: got connection\n");
|
printf("SERVER: got connection\n");
|
||||||
|
|
||||||
conn.id = ids++;
|
conn.id = ids++;
|
||||||
|
|
||||||
|
|
2
server.h
2
server.h
|
@ -1,4 +1,4 @@
|
||||||
// vi: set ft=c
|
// vi:ft=c
|
||||||
#ifndef SERVER_H
|
#ifndef SERVER_H
|
||||||
#define SERVER_H
|
#define SERVER_H
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
4
util.c
4
util.c
|
@ -1,9 +1,9 @@
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#ifndef __has_builtin
|
#ifndef __has_builtin
|
||||||
#define __has_builtin(_) 0
|
#define __has_builtin(_) 0
|
||||||
#endif
|
#endif
|
||||||
|
|
2
util.h
2
util.h
|
@ -1,4 +1,4 @@
|
||||||
// vi: set ft=c
|
// vi:ft=c
|
||||||
#ifndef UTIL_H
|
#ifndef UTIL_H
|
||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
|
|
1
vec.c
1
vec.c
|
@ -1,4 +1,5 @@
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
Loading…
Reference in New Issue