fxlink: add --sockin and --sockout options to fxlink -i

This commit is contained in:
redoste 2024-09-14 03:11:02 +02:00
parent e201304423
commit c8afb9acb5
No known key found for this signature in database
3 changed files with 123 additions and 6 deletions

View file

@ -8,6 +8,7 @@
#pragma once #pragma once
#include <fxlink/filter.h> #include <fxlink/filter.h>
#include <libusb.h> #include <libusb.h>
#include <sys/un.h>
/* Global and command-line options. */ /* Global and command-line options. */
struct fxlink_options { struct fxlink_options {
@ -33,7 +34,9 @@ int main_send(struct fxlink_filter *filter, delay_t *delay, char **files,
/* Main function for -i */ /* Main function for -i */
int main_interactive(struct fxlink_filter *filter, delay_t *delay, 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 */ /* Main function for -t */
int main_tui_interactive(libusb_context *context); int main_tui_interactive(libusb_context *context);

View file

@ -13,6 +13,8 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h> #include <errno.h>
#include <locale.h> #include <locale.h>
@ -47,6 +49,10 @@ static const char *help_string =
" --fxlink-log[=FILE] -i: Append fxlink text messages to FILE. Without\n" " --fxlink-log[=FILE] -i: Append fxlink text messages to FILE. Without\n"
" argument, a unique name is generated.\n" " argument, a unique name is generated.\n"
" -r, --repeat -i: Reconnect if the calc disconnects (implies -w)\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" " --folder=FOLDER -s: Select destination folder for files\n"
"\n" "\n"
"Device filters:\n" "Device filters:\n"
@ -69,6 +75,8 @@ int main(int argc, char **argv)
struct fxlink_filter *filter = NULL; struct fxlink_filter *filter = NULL;
bool repeat = false; bool repeat = false;
char *outfolder = NULL; char *outfolder = NULL;
struct sockaddr_un sockin_addr = { AF_UNSPEC };
struct sockaddr_un sockout_addr = { AF_UNSPEC };
options.log_file = NULL; options.log_file = NULL;
options.verbose = false; options.verbose = false;
@ -79,7 +87,7 @@ int main(int argc, char **argv)
// Command-line argument parsing // 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[] = { const struct option longs[] = {
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "list", no_argument, NULL, 'l' }, { "list", no_argument, NULL, 'l' },
@ -93,6 +101,8 @@ int main(int argc, char **argv)
{ "repeat", no_argument, NULL, 'r' }, { "repeat", no_argument, NULL, 'r' },
{ "verbose", no_argument, NULL, 'v' }, { "verbose", no_argument, NULL, 'v' },
{ "folder", required_argument, NULL, OUT_FOLDER }, { "folder", required_argument, NULL, OUT_FOLDER },
{ "sockin", required_argument, NULL, SOCKIN },
{ "sockout", required_argument, NULL, SOCKOUT },
/* Deprecated options ignored for compatibility: */ /* Deprecated options ignored for compatibility: */
{ "quiet", no_argument, NULL, 'q' }, { "quiet", no_argument, NULL, 'q' },
{ "unmount", no_argument, NULL, 'u' }, { "unmount", no_argument, NULL, 'u' },
@ -171,6 +181,14 @@ int main(int argc, char **argv)
case OUT_FOLDER: case OUT_FOLDER:
outfolder = strdup(optarg); outfolder = strdup(optarg);
break; 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 '?': case '?':
error = 1; error = 1;
} }
@ -232,7 +250,9 @@ int main(int argc, char **argv)
} }
else if(mode == 'i') { else if(mode == 'i') {
do { 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); while(repeat);
} }

View file

@ -15,9 +15,15 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
static void handle_new_message(struct fxlink_device *fdev, 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 = "."; char const *path = ".";
@ -41,6 +47,11 @@ static void handle_new_message(struct fxlink_device *fdev,
if(fxlink_message_is_fxlink_text(msg)) { if(fxlink_message_is_fxlink_text(msg)) {
char const *str = msg->data; 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) if(options.verbose)
printf("------------------\n"); printf("------------------\n");
fwrite(str, 1, msg->size, stdout); fwrite(str, 1, msg->size, stdout);
@ -95,8 +106,77 @@ static void handle_new_message(struct fxlink_device *fdev,
free(filename); 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, 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 */ /* Wait for a device to be connected */
fxlink_filter_clean_libusb(filter); fxlink_filter_clean_libusb(filter);
@ -113,6 +193,14 @@ int main_interactive(struct fxlink_filter *filter, delay_t *delay,
return 1; 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"); hlog("interactive");
log_("connected to %s\n", fxlink_device_id(fdev)); 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) { while(1) {
fxlink_sdl2_handle_events(); fxlink_sdl2_handle_events();
handle_input_socket(fdev, socket_fd);
int transferred = -1; int transferred = -1;
int rc = libusb_bulk_transfer(fdev->dh, fdev->comm->ep_bulk_IN, buffer, int rc = libusb_bulk_transfer(fdev->dh, fdev->comm->ep_bulk_IN, buffer,
sizeof buffer, &transferred, 500 /* ms */); 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)) { if(tr && fxlink_transfer_complete(tr)) {
struct fxlink_message *msg = fxlink_transfer_finish_IN(tr); struct fxlink_message *msg = fxlink_transfer_finish_IN(tr);
if(msg) { if(msg) {
handle_new_message(fdev, msg); handle_new_message(fdev, msg, socket_fd, sockout_addr);
fxlink_message_free(msg, true); fxlink_message_free(msg, true);
} }
tr = NULL; tr = NULL;
@ -163,6 +253,10 @@ int main_interactive(struct fxlink_filter *filter, delay_t *delay,
fxlink_transfer_free(tr); fxlink_transfer_free(tr);
} }
if(socket_fd >= 0) {
close(socket_fd);
}
fxlink_device_cleanup(fdev); fxlink_device_cleanup(fdev);
free(fdev); free(fdev);
return 0; return 0;