diff --git a/fxlink/fxlink.h b/fxlink/fxlink.h index 60afbed..d4c3cdc 100644 --- a/fxlink/fxlink.h +++ b/fxlink/fxlink.h @@ -8,6 +8,7 @@ #pragma once #include #include +#include /* Global and command-line options. */ struct fxlink_options { @@ -33,7 +34,9 @@ int main_send(struct fxlink_filter *filter, delay_t *delay, char **files, /* Main function for -i */ int main_interactive(struct fxlink_filter *filter, delay_t *delay, - libusb_context *context); + libusb_context *context, + const struct sockaddr_un *sockin_addr, + const struct sockaddr_un *sockout_addr); /* Main function for -t */ int main_tui_interactive(libusb_context *context); diff --git a/fxlink/main.c b/fxlink/main.c index 4a49f5d..1dc116c 100644 --- a/fxlink/main.c +++ b/fxlink/main.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -47,6 +49,10 @@ static const char *help_string = " --fxlink-log[=FILE] -i: Append fxlink text messages to FILE. Without\n" " argument, a unique name is generated.\n" " -r, --repeat -i: Reconnect if the calc disconnects (implies -w)\n" +" --sockin=SOCKET -i: Send messages read from the datagram Unix socket\n" +" SOCKET to the calculator as fxlink text messages.\n" +" --sockout=SOCKET -i: Send fxlink text messages read from the calculator\n" +" to the datagram Unix socket SOCKET.\n" " --folder=FOLDER -s: Select destination folder for files\n" "\n" "Device filters:\n" @@ -69,6 +75,8 @@ int main(int argc, char **argv) struct fxlink_filter *filter = NULL; bool repeat = false; char *outfolder = NULL; + struct sockaddr_un sockin_addr = { AF_UNSPEC }; + struct sockaddr_un sockout_addr = { AF_UNSPEC }; options.log_file = NULL; options.verbose = false; @@ -79,7 +87,7 @@ int main(int argc, char **argv) // Command-line argument parsing //--- - enum { LIBUSB_LOG=1, LOG_TO_FILE=2, OUT_FOLDER=3 }; + enum { LIBUSB_LOG=1, LOG_TO_FILE=2, OUT_FOLDER=3, SOCKIN=4, SOCKOUT=5 }; const struct option longs[] = { { "help", no_argument, NULL, 'h' }, { "list", no_argument, NULL, 'l' }, @@ -93,6 +101,8 @@ int main(int argc, char **argv) { "repeat", no_argument, NULL, 'r' }, { "verbose", no_argument, NULL, 'v' }, { "folder", required_argument, NULL, OUT_FOLDER }, + { "sockin", required_argument, NULL, SOCKIN }, + { "sockout", required_argument, NULL, SOCKOUT }, /* Deprecated options ignored for compatibility: */ { "quiet", no_argument, NULL, 'q' }, { "unmount", no_argument, NULL, 'u' }, @@ -171,6 +181,14 @@ int main(int argc, char **argv) case OUT_FOLDER: outfolder = strdup(optarg); break; + case SOCKIN: + sockin_addr.sun_family = AF_UNIX; + strncpy(sockin_addr.sun_path, optarg, sizeof(sockin_addr.sun_path) - 1); + break; + case SOCKOUT: + sockout_addr.sun_family = AF_UNIX; + strncpy(sockout_addr.sun_path, optarg, sizeof(sockout_addr.sun_path) - 1); + break; case '?': error = 1; } @@ -232,7 +250,9 @@ int main(int argc, char **argv) } else if(mode == 'i') { do { - rc = main_interactive(filter, &delay, context); + rc = main_interactive(filter, &delay, context, + sockin_addr.sun_family == AF_UNSPEC ? NULL : &sockin_addr, + sockout_addr.sun_family == AF_UNSPEC ? NULL : &sockout_addr); } while(repeat); } diff --git a/fxlink/modes/interactive.c b/fxlink/modes/interactive.c index 3c23c7b..e4726c3 100644 --- a/fxlink/modes/interactive.c +++ b/fxlink/modes/interactive.c @@ -15,9 +15,15 @@ #include #include #include +#include +#include +#include +#include static void handle_new_message(struct fxlink_device *fdev, - struct fxlink_message *msg) + struct fxlink_message *msg, + int socket_fd, + const struct sockaddr_un *sockout_addr) { char const *path = "."; @@ -41,6 +47,11 @@ static void handle_new_message(struct fxlink_device *fdev, if(fxlink_message_is_fxlink_text(msg)) { char const *str = msg->data; + if(socket_fd >= 0 && sockout_addr != NULL && + sendto(socket_fd, msg->data, msg->size, 0, sockout_addr, sizeof(*sockout_addr)) < 0) { + perror("sendto"); + } + if(options.verbose) printf("------------------\n"); fwrite(str, 1, msg->size, stdout); @@ -95,8 +106,77 @@ static void handle_new_message(struct fxlink_device *fdev, free(filename); } +static int setup_socket(const struct sockaddr_un *sockin_addr, + const struct sockaddr_un *sockout_addr) +{ + if(sockin_addr == NULL && sockout_addr == NULL) { + /* -1 is used to indicate that no fd were opened but it's not a fatal error */ + return -1; + } + + int socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if(socket_fd < 0) { + perror("socket"); + /* -2 is used to indicate an error */ + return -2; + } + + if(sockin_addr != NULL) { + unlink(sockin_addr->sun_path); + + if (bind(socket_fd, (struct sockaddr*)sockin_addr, sizeof(*sockin_addr)) < 0) { + perror("bind"); + close(socket_fd); + /* -2 is used to indicate an error */ + return -2; + } + } + + return socket_fd; +} + +static void handle_input_socket(struct fxlink_device *fdev, int socket_fd) +{ + if(socket_fd < 0) { + return; + } + + /* Don't start an OUT transfer if there's one in progress */ + if(fdev->comm->ftransfer_OUT) { + return; + } + + int dgram_len; + if(ioctl(socket_fd, FIONREAD, &dgram_len) < 0) { + perror("ioctl"); + return; + } + if(dgram_len <= 0) { + return; + } + + /* We need to use a static buffer as libfxlink will use it in it's main loop, + * outside of this stack frame + */ + static uint8_t* dgram_buf = NULL; + static ssize_t dgram_buf_len = 0; + if (dgram_buf_len < dgram_len) { + dgram_buf = realloc(dgram_buf, dgram_len); + dgram_buf_len = dgram_len; + } + + ssize_t recv_ret = recvfrom(socket_fd, dgram_buf, dgram_buf_len, 0, NULL, NULL); + if(recv_ret < 0) { + perror("recvfrom"); + } else if(recv_ret > 0) { + fxlink_device_start_bulk_OUT(fdev, "fxlink", "text", dgram_buf, recv_ret, false); + } +} + int main_interactive(struct fxlink_filter *filter, delay_t *delay, - libusb_context *ctx) + libusb_context *ctx, + const struct sockaddr_un *sockin_addr, + const struct sockaddr_un *sockout_addr) { /* Wait for a device to be connected */ fxlink_filter_clean_libusb(filter); @@ -113,6 +193,14 @@ int main_interactive(struct fxlink_filter *filter, delay_t *delay, return 1; } + /* socket used by sockin and sockout options */ + int socket_fd = setup_socket(sockin_addr, sockout_addr); + if(socket_fd <= -2) { + fxlink_device_cleanup(fdev); + free(fdev); + return 1; + } + hlog("interactive"); log_("connected to %s\n", fxlink_device_id(fdev)); @@ -124,6 +212,8 @@ int main_interactive(struct fxlink_filter *filter, delay_t *delay, while(1) { fxlink_sdl2_handle_events(); + handle_input_socket(fdev, socket_fd); + int transferred = -1; int rc = libusb_bulk_transfer(fdev->dh, fdev->comm->ep_bulk_IN, buffer, sizeof buffer, &transferred, 500 /* ms */); @@ -150,7 +240,7 @@ int main_interactive(struct fxlink_filter *filter, delay_t *delay, if(tr && fxlink_transfer_complete(tr)) { struct fxlink_message *msg = fxlink_transfer_finish_IN(tr); if(msg) { - handle_new_message(fdev, msg); + handle_new_message(fdev, msg, socket_fd, sockout_addr); fxlink_message_free(msg, true); } tr = NULL; @@ -163,6 +253,10 @@ int main_interactive(struct fxlink_filter *filter, delay_t *delay, fxlink_transfer_free(tr); } + if(socket_fd >= 0) { + close(socket_fd); + } + fxlink_device_cleanup(fdev); free(fdev); return 0;