#include #include #include #include #include #include #include #include #include #include #include #include #include #include #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" #define BLOCK_SIZE 1 static int connect_server(char* domain) { int fd; int code; struct addrinfo *res; struct sockaddr_in ipv4; struct sockaddr_in6 ipv6; struct sockaddr *generic; size_t gensize; struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_protocol = 0 }; if ((code = getaddrinfo(domain, "https", &hints, &res))) { printf("connect_server: couldnt resolve: %s\n", gai_strerror(code)); return -1; } if (res->ai_family == AF_INET) { memcpy(&ipv4, res->ai_addr, sizeof(struct sockaddr_in)); generic = (struct sockaddr*) &ipv4; gensize = sizeof(struct sockaddr_in); } else if (res->ai_family == AF_INET6) { memcpy(&ipv6, res->ai_addr, sizeof(struct sockaddr_in6)); generic = (struct sockaddr*) &ipv6; gensize = sizeof(struct sockaddr_in6); } else { printf("connect_server: unsupported family\n"); freeaddrinfo(res); return -1; } if ((fd = socket(res->ai_family, SOCK_STREAM, 0)) == -1) { printf("connect_server: socket failure\n"); freeaddrinfo(res); return -1; } if (connect(fd, generic, gensize) == -1) { freeaddrinfo(res); return -1; } freeaddrinfo(res); return fd; } int main(int argc, char *argv[]) { libusb_context *ctx = NULL; struct fxlink_device *device = NULL; libusb_device *did = NULL; struct fxlink_device_list list; struct timeval zero_tv = { 0 }; char *url = NULL; int code; printf("Hello, Ma's Trix!\n"); if ((code = libusb_init(&ctx))) { elog_libusb(code, "cannot initialise libusb"); goto end; } libusb_set_option( ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO); fxlink_log_grab_libusb_logs(); fxlink_device_list_track(&list, ctx); while (1) { struct fxlink_message *msg; memset(&zero_tv, 0, sizeof(zero_tv)); libusb_handle_events_timeout(ctx, &zero_tv); fxlink_device_list_refresh(&list); if (device) { size_t i; bool found = false; for (i = 0; i < list.count; i++) { if (list.devices[i].dp == did) { found = true; break; } } if (!found) { printf("mastrix: device disconnected \n"); did = NULL; device = NULL; } } if (!device) { size_t i; for (i = 0; i < list.count; i++) { struct fxlink_device *dev = &list.devices[i]; char const *id = fxlink_device_id(dev); if (!fxlink_device_ready_to_connect(dev)) { continue; } if (!fxlink_device_has_fxlink_interface(dev)) { printf("mastrix: no fxlink interface(%s)\n", id); continue; } if (!fxlink_device_claim_fxlink(dev)) { printf("mastrix: cannot claim (%s)\n", id); continue; } device = dev; did = device->dp; fxlink_device_start_bulk_IN(device); break; } } if (!device) { usleep(100); /* Leave some time to the OS. */ continue; } libusb_handle_events_timeout(ctx, &zero_tv); msg = fxlink_device_finish_bulk_IN(device); if (!msg) { usleep(100); /* Leave some time to the OS. */ continue; } if (fxlink_message_is_apptype(msg, "matrix", "debug") || fxlink_message_is_apptype(msg, "fxlink", "text")) { char *buf = malloc(msg->size + 1); memset(buf, 0, msg->size + 1); memcpy(buf, msg->data, msg->size); printf("%s\n", buf); free(buf); } if (fxlink_message_is_apptype(msg, "matrix", "time")) { time_t now = time(NULL); struct tm *tm_struct = localtime(&now); uint8_t buf[3]; buf[0] = tm_struct->tm_hour; buf[1] = tm_struct->tm_min; buf[2] = tm_struct->tm_sec; fxlink_device_start_bulk_OUT( device, "matrix", "hour", buf, 3 * sizeof(uint8_t), false ); } if (fxlink_message_is_apptype(msg, "dbg", "crash")) { size_t items = msg->size / sizeof(uint32_t); ssize_t i; uint32_t *crash = msg->data; printf("Ma's Trix has crashed.\n"); printf("Stacktrace:\n"); printf("==========\n"); for (i = items - 1; i >= 0; i--) { uint32_t address = be32toh(crash[i]); printf("\t- <%08x> %s\n", address, i == items - 1? "[Crashed]" : ""); } printf("==========\n\n"); } if (fxlink_message_is_apptype(msg, "fxlink", "image")) { struct fxlink_message_image_raw *img; FILE *f; size_t y; uint8_t *colptr, *line; img = fxlink_message_image_decode(msg); colptr = malloc(img->width * img->height * 3); for (y = 0; y < img->height; y++) { line = img->data[y]; memcpy(colptr + y * (img->width * 3), line, img->width * 3); } printf( "Sending %dx%d raw screenshot " "(as RGB888)\n", img->width, img->height ); /* TODO: This does *not* work */ stbi_write_png( "screenshot.png", img->width, img->height, 3, colptr, img->width * 3 ); fxlink_message_image_raw_free(img); free(colptr); } if (fxlink_message_is_apptype(msg, "matrix", "url")) { char *buf = malloc(msg->size + 1); memset(buf, 0, msg->size + 1); memcpy(buf, msg->data, msg->size); if (url) { free(url); } url = buf; } if (fxlink_message_is_apptype(msg, "matrix", "http")) { /* TODO: Send over HTTPS */ const SSL_METHOD *method; SSL_CTX *ctx; SSL *ssl; char *buffer = NULL; size_t bufsize = 0; int fd = connect_server(url); if (fd == -1) { printf("mastrix: cannot create fd\n"); } method = TLS_client_method(); ctx = SSL_CTX_new(method); ssl = SSL_new(ctx); if (!SSL_set_fd(ssl, fd)) { printf("mastrix: SSL_set_fd failed\n"); goto cleanup; } if (SSL_connect(ssl) <= 0) { printf("mastrix: SSL_connect failed\n"); goto cleanup; } int bytes = SSL_write(ssl, msg->data, msg->size); while (1) { int read = 0, done = 0; char smolbuf[BLOCK_SIZE]; if ((read = SSL_read(ssl, smolbuf, BLOCK_SIZE)) < BLOCK_SIZE) { done = 1; } if (read > 0) { buffer = realloc(buffer, bufsize + read); memcpy(buffer + bufsize, smolbuf, read); bufsize += read; } if (done) { break; } } if (buffer) { printf("mastrix: sending %lu B to calculator\n", bufsize); fxlink_device_start_bulk_OUT( device, "matrix", "reply", buffer, bufsize, true ); } cleanup: SSL_free(ssl); SSL_CTX_free(ctx); close(fd); } if (msg) { fxlink_message_free(msg, true); fxlink_device_start_bulk_IN(device); } } end: return 0; }