mirror of
https://github.com/tio/tio.git
synced 2026-05-01 14:57:59 +02:00
Add support for IPv4 and IPv6 network sockets
Add support for IPv4 and IPv6 network sockets via socket syntax "inet:<port>" and "inet6:<port>" respectively. For example, to listen and redirect serial device I/O to a host bound IPv4 socket simply do: $ tio /dev/ttyUSB0 --socket inet:4444 To connect do e.g.: $ nc 127.0.0.1 4444 Likewise, for IPv6 do: $ tio /dev/ttyUSB0 --socket inet6:4444 To connect do e.g.: $ nc ::1 4444 If port is 0 or no port is provided default port 3333 is used.
This commit is contained in:
parent
ba22191800
commit
17e96d70bc
2 changed files with 136 additions and 19 deletions
18
man/tio.1.in
18
man/tio.1.in
|
|
@ -140,13 +140,21 @@ sequences are not recognized), and any input from the serial port is multiplexed
|
||||||
|
|
||||||
Sockets remain open while the serial port is disconnected, and writes will block.
|
Sockets remain open while the serial port is disconnected, and writes will block.
|
||||||
|
|
||||||
Two socket types are supported using different prefixes in the socket field:
|
The following socket types are supported using different prefixes in the socket field:
|
||||||
|
|
||||||
unix:<filename> - Unix Domain Socket (file)
|
|
||||||
|
|
||||||
inet:<IP>:<port> - Internet Socket (network) (NOT YET SUPPORTED)
|
|
||||||
|
|
||||||
|
.RS
|
||||||
|
.TP 20n
|
||||||
|
.IP "\fBunix:<filename>"
|
||||||
|
Unix Domain Socket (file)
|
||||||
|
.IP "\fBinet:<port>"
|
||||||
|
Internet Socket (network)
|
||||||
|
.IP "\fBinet6:<port>"
|
||||||
|
Internet IPv6 Socket (network)
|
||||||
|
.P
|
||||||
|
If port is 0 or no port is provided default port 3333 is used.
|
||||||
|
.P
|
||||||
At present there is a hardcoded limit of 16 clients connected at one time.
|
At present there is a hardcoded limit of 16 clients connected at one time.
|
||||||
|
.RE
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-v ", " \-\-version
|
.BR \-v ", " \-\-version
|
||||||
|
|
|
||||||
137
src/socket.c
137
src/socket.c
|
|
@ -27,14 +27,19 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define MAX_SOCKET_CLIENTS 16
|
#define MAX_SOCKET_CLIENTS 16
|
||||||
|
#define SOCKET_PORT_DEFAULT 3333
|
||||||
|
|
||||||
static int sockfd;
|
static int sockfd;
|
||||||
static int clientfds[MAX_SOCKET_CLIENTS];
|
static int clientfds[MAX_SOCKET_CLIENTS];
|
||||||
|
static int socket_family = AF_UNSPEC;
|
||||||
|
static int port_number = SOCKET_PORT_DEFAULT;
|
||||||
|
|
||||||
static const char *socket_filename(void)
|
static const char *socket_filename(void)
|
||||||
{
|
{
|
||||||
|
|
@ -42,57 +47,161 @@ static const char *socket_filename(void)
|
||||||
return option.socket + 5;
|
return option.socket + 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int socket_inet_port(void)
|
||||||
|
{
|
||||||
|
/* skip 'inet:' */
|
||||||
|
int port_number = atoi(option.socket + 5);
|
||||||
|
if (port_number == 0)
|
||||||
|
{
|
||||||
|
port_number = SOCKET_PORT_DEFAULT;
|
||||||
|
}
|
||||||
|
return port_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int socket_inet6_port(void)
|
||||||
|
{
|
||||||
|
/* skip 'inet6:' */
|
||||||
|
int port_number = atoi(option.socket + 6);
|
||||||
|
if (port_number == 0)
|
||||||
|
{
|
||||||
|
port_number = SOCKET_PORT_DEFAULT;
|
||||||
|
}
|
||||||
|
return port_number;
|
||||||
|
}
|
||||||
|
|
||||||
static void socket_exit(void)
|
static void socket_exit(void)
|
||||||
{
|
{
|
||||||
unlink(socket_filename());
|
if (socket_family == AF_UNIX)
|
||||||
|
{
|
||||||
|
unlink(socket_filename());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void socket_configure(void)
|
void socket_configure(void)
|
||||||
{
|
{
|
||||||
|
struct sockaddr_un sockaddr_unix = {};
|
||||||
|
struct sockaddr_in sockaddr_inet = {};
|
||||||
|
struct sockaddr_in6 sockaddr_inet6 = {};
|
||||||
|
struct sockaddr *sockaddr_p;
|
||||||
|
socklen_t socklen;
|
||||||
|
|
||||||
if (!option.socket)
|
if (!option.socket)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp(option.socket, "unix:", 5) != 0)
|
/* Parse socket string */
|
||||||
|
|
||||||
|
if (strncmp(option.socket, "unix:", 5) == 0)
|
||||||
{
|
{
|
||||||
error_printf("%s: Invalid socket scheme, must be 'unix:'", option.socket);
|
socket_family = AF_UNIX;
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
|
if (strlen(socket_filename()) == 0)
|
||||||
|
{
|
||||||
|
error_printf("Missing socket filename");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(socket_filename()) > sizeof(sockaddr_unix.sun_path) - 1)
|
||||||
|
{
|
||||||
|
error_printf("Socket file path %s too long", option.socket);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sockaddr_un sockaddr = {};
|
if (strncmp(option.socket, "inet:", 5) == 0)
|
||||||
if (strlen(socket_filename()) > sizeof(sockaddr.sun_path) - 1)
|
|
||||||
{
|
{
|
||||||
error_printf("Socket file path %s too long", option.socket);
|
socket_family = AF_INET;
|
||||||
|
|
||||||
|
port_number = socket_inet_port();
|
||||||
|
|
||||||
|
if (port_number < 0)
|
||||||
|
{
|
||||||
|
error_printf("Invalid port number: %d", port_number);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(option.socket, "inet6:", 6) == 0)
|
||||||
|
{
|
||||||
|
socket_family = AF_INET6;
|
||||||
|
|
||||||
|
port_number = socket_inet6_port();
|
||||||
|
|
||||||
|
if (port_number < 0)
|
||||||
|
{
|
||||||
|
error_printf("Invalid port number: %d", port_number);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket_family == AF_UNSPEC)
|
||||||
|
{
|
||||||
|
error_printf("%s: Invalid socket scheme, must be prefixed with 'unix:', 'inet:', or 'inet6:'", option.socket);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
sockaddr.sun_family = AF_UNIX;
|
/* Configure socket */
|
||||||
strncpy(sockaddr.sun_path, socket_filename(), sizeof(sockaddr.sun_path) - 1);
|
|
||||||
|
|
||||||
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
if (socket_family == AF_UNIX)
|
||||||
|
{
|
||||||
|
sockaddr_unix.sun_family = AF_UNIX;
|
||||||
|
strncpy(sockaddr_unix.sun_path, socket_filename(), sizeof(sockaddr_unix.sun_path) - 1);
|
||||||
|
sockaddr_p = (struct sockaddr *) &sockaddr_unix;
|
||||||
|
socklen = sizeof(sockaddr_unix);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket_family == AF_INET)
|
||||||
|
{
|
||||||
|
sockaddr_inet.sin_family = AF_INET;
|
||||||
|
sockaddr_inet.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
sockaddr_inet.sin_port = htons(port_number);
|
||||||
|
sockaddr_p = (struct sockaddr *) &sockaddr_inet;
|
||||||
|
socklen = sizeof(sockaddr_inet);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket_family == AF_INET6)
|
||||||
|
{
|
||||||
|
sockaddr_inet6.sin6_family = AF_INET6;
|
||||||
|
inet_pton(AF_INET6, "::1", &sockaddr_inet6.sin6_addr);
|
||||||
|
sockaddr_inet6.sin6_port = htons(port_number);
|
||||||
|
sockaddr_p = (struct sockaddr *) &sockaddr_inet6;
|
||||||
|
socklen = sizeof(sockaddr_inet6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create socket */
|
||||||
|
sockfd = socket(socket_family, SOCK_STREAM, 0);
|
||||||
if (sockfd < 0)
|
if (sockfd < 0)
|
||||||
{
|
{
|
||||||
error_printf("Failed to create socket: %s", strerror(errno));
|
error_printf("Failed to create socket: %s", strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0)
|
/* Bind */
|
||||||
|
if (bind(sockfd, sockaddr_p, socklen) < 0)
|
||||||
{
|
{
|
||||||
error_printf("Failed to bind to socket %s: %s", socket_filename(), strerror(errno));
|
error_printf("Failed to bind to socket %s", strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Listen */
|
||||||
if (listen(sockfd, MAX_SOCKET_CLIENTS) < 0)
|
if (listen(sockfd, MAX_SOCKET_CLIENTS) < 0)
|
||||||
{
|
{
|
||||||
error_printf("Failed to listen on socket %s: %s", socket_filename(), strerror(errno));
|
error_printf("Failed to listen on socket %s", strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(clientfds, -1, sizeof(clientfds));
|
memset(clientfds, -1, sizeof(clientfds));
|
||||||
atexit(socket_exit);
|
atexit(socket_exit);
|
||||||
|
|
||||||
tio_printf("Listening on socket %s", socket_filename());
|
if (socket_family == AF_UNIX)
|
||||||
|
{
|
||||||
|
tio_printf("Listening on socket %s", socket_filename());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tio_printf("Listening on socket port %d", port_number);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void socket_write(char input_char)
|
void socket_write(char input_char)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue