tio / tio

A serial device I/O tool
https://tio.github.io
Other
1.94k stars 155 forks source link

Support connecting to UNIX/TCP sockets #175

Open heroin-moose opened 1 year ago

heroin-moose commented 1 year ago

Connecting to UNIX sockets comes in be handy with QEMU, for example. Like when you have a bunch of VMs and want to connect to a serial console:

$ tio ~/VM/vm1.console

Quick POC shows that everything works, I'm able to read/write to a serial console with a simple diff:

diff --git a/src/tty.c b/src/tty.c
index 8c7bfa7..65c0289 100644
--- a/src/tty.c
+++ b/src/tty.c
@@ -1085,10 +1085,19 @@ int tty_connect(void)
     struct timeval tv;
     struct timeval *tv_p = &tv;
     bool ignore_stdin = false;
+    struct sockaddr_un addr;

-    /* Open tty device */
-    fd = open(option.tty_device, O_RDWR | O_NOCTTY | O_NONBLOCK);
-    if (fd < 0)
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    strncpy(addr.sun_path, option.tty_device, sizeof(addr.sun_path) - 1);
+
+    fd = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (fd == -1) {
+   tio_error_printf("Cannot allocate socket (%s)", strerror(errno));
+   exit(EXIT_FAILURE);
+    }
+
+    if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
     {
         tio_error_printf_silent("Could not open tty device (%s)", strerror(errno));
         goto error_open;
@@ -1098,7 +1107,9 @@ int tty_connect(void)
     if (!isatty(fd))
     {
         tio_error_printf("Not a tty device");
+#if 0
         exit(EXIT_FAILURE);;
+#endif
     }

     /* Lock device file */
@@ -1139,7 +1150,9 @@ int tty_connect(void)
     if (tcgetattr(fd, &tio_old) < 0)
     {
         tio_error_printf_silent("Could not get port settings (%s)", strerror(errno));
+#if 0
         goto error_tcgetattr;
+#endif
     }

 #ifdef HAVE_IOSSIOSPEED
@@ -1169,7 +1182,9 @@ int tty_connect(void)
     if (status == -1)
     {
         tio_error_printf_silent("Could not apply port settings (%s)", strerror(errno));
+#if 0
         goto error_tcsetattr;
+#endif
     }

     /* Set arbitrary baudrate (only works on supported platforms) */
@@ -1178,7 +1193,9 @@ int tty_connect(void)
         if (setspeed(fd, option.baudrate) != 0)
         {
             tio_error_printf_silent("Could not set baudrate speed (%s)", strerror(errno));
+#if 0
             goto error_setspeed;
+#endif
         }
     }

@@ -1394,9 +1411,11 @@ int tty_connect(void)

     return TIO_SUCCESS;

+#if 0
 error_setspeed:
 error_tcsetattr:
 error_tcgetattr:
+#endif
 error_read:
     tty_disconnect();
 error_open:

However it's necessary not call all TTY-related or else everything goes boom. I suspect that it's best to factor out two functions , one for each method. Anyway, if you are okay with the idea, I'll make a proper merge request.

lundmar commented 1 year ago

I'm a bit undecided on the feature of letting tio be able to connect to sockets. I mean, if you want to connect to a UNIX socket you could easily do so with nc -U <socket>. Of course, that will give you a raw connection and you won't have any of tio's features available (line time stamping, hex mode, local echo, mappings, auto connect, etc.).

That being said, tio already supports redirecting serial I/O to a socket using e.g. tio --socket unix:test-socket-0. Likewise tio could be used to connect to the same socket via a similar syntax tio unix:test-socket-0, tio inet:192.168.0.42:3333, etc. This way tio can be used end to end for sharing serial ports.

On the other hand, there is the principle of letting one tool do one thing well, namely connecting to serial ports.

heroin-moose commented 1 year ago

Sadly nc -U <socket> can't handle complex TTY features, can't handle escapes, echoes back passwords and so on. It is possible to run minicom -D unix#test.sock or socat with right flags, but I was thinking about replacing minicom with tio so this feature kinda felt natural. But of course I understand that this is not the primary focus of tio.

lundmar commented 1 year ago

After some more consideration I think it makes sense to support connecting to a socket as that will make tio be able to both serve a serial port via a socket and connect to it - it will be an end to end solution. In short we will be able to do the following:

Host serial port on socket: tio --socket unix:/tmp/tio-socket-0 /dev/ttyUSB0

Connect to same socket: tio unix:/tmp/tio-socket-0

However, getting there is a bit more involved. I'm making a TODO list here, mostly for my own reference.

Besides a bit of refactoring the following changes spring to mind:

pernu commented 1 year ago

It would be really great to have unix socket support. nc -U ... is barely functional and minicom is a bit dated and limited. Key use case is of course QEMU.

Habbie commented 1 year ago

Wonderful! Given your list of changes, can you update the issue title to also mention TCP? I came here to request that only to see you already considered it part of this request :)

Zorbatron commented 9 months ago

I'm not sure if this should be a separate issue, but if TCP support is planned, could RFC 2217 be a feature alongside TCP? TLDR on RFC2217: it's an extension to telnet that allows a client to specify COM port parameters to a server. Example being the client wanting to change the baud rate on a console server in real time. And I don't know of a real world use, but maybe UDP too, instead of just TCP.

lundmar commented 9 months ago

@Zorbatron That is possible but first things first. It can be added if there is a demand for it.

vifino commented 4 months ago

RFC 2217 would definitely be the way to go for TCP connections, would allow connecting to ser2net, proprietary TCP serial gateways, etc.. I would certainly love it!