From: "Charles Coffing" <ccoffing@novell.com>
To: xen-devel@lists.sourceforge.net
Subject: [PATCH] serial-split.c
Date: Tue, 22 Feb 2005 16:24:49 -0700 [thread overview]
Message-ID: <s21b5cd8.053@sinclair.provo.novell.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 771 bytes --]
A while back (probably a few months, actually) I saw others struggling
to make sense of nsplitd. I had never managed to get nsplitd working
either, so I wrote a simple tool to split a serial port between two TCP
ports. Rather than letting it rot on my disk, here's the patch.
cd into tools/misc/serial-split and run "make" to build it.
Usage is as simple as running "serial-split" with no args. This will
(by default) split COM1 (running at 115200/8N1) between ports 12010 and
12011. Attach gdb with "target remote localhost:12011". Attach to the
console with (perhaps) "tools/misc/xencons localhost 12010".
Run "serial-split --help" for more help, or look at the comment at the
top of the file for a setup scenario.
Hope someone else finds this useful.
Charles
[-- Attachment #2: serial-split.patch --]
[-- Type: text/plain, Size: 13214 bytes --]
diff -ruN xen-2.0.bk.orig/tools/misc/serial-split/Makefile xen-2.0.bk/tools/misc/serial-split/Makefile
--- xen-2.0.bk.orig/tools/misc/serial-split/Makefile 1969-12-31 17:00:00.000000000 -0700
+++ xen-2.0.bk/tools/misc/serial-split/Makefile 2005-02-22 16:01:10.664346593 -0700
@@ -0,0 +1,18 @@
+CC = gcc
+CFLAGS = -Wall -O3
+CFILES = $(wildcard *.c)
+OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
+TARGET = serial-split
+
+all: $(TARGET)
+
+install: all
+
+clean:
+ rm *.o $(TARGET) *~
+
+$(TARGET): $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $^
+
+%.o: %.c Makefile
+ $(CC) $(CFLAGS) -c -o $@ $<
diff -ruN xen-2.0.bk.orig/tools/misc/serial-split/serial-split.c xen-2.0.bk/tools/misc/serial-split/serial-split.c
--- xen-2.0.bk.orig/tools/misc/serial-split/serial-split.c 1969-12-31 17:00:00.000000000 -0700
+++ xen-2.0.bk/tools/misc/serial-split/serial-split.c 2005-02-22 15:58:36.515562511 -0700
@@ -0,0 +1,422 @@
+/*
+ * serial-split.c
+ * pdb / console splitter
+ *
+ * Copyright 2005 Charles Coffing <ccoffing@novell.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * Typical setup:
+ *
+ * Development box Xen box
+ * ...-----+ +-----...
+ * +---------+ | |
+ * | gdb | | |
+ * | |\ high | |
+ * +---------+ \ | |
+ * \+-----------+ | serial | +------------------+
+ * | splitter |------------| Xen |
+ * /+-----------+ | | | - pdb (com1H)|
+ * +---------+ / | | | - printk (com1) |
+ * | console |/ low | | +------------------+
+ * | viewer | | |
+ * +---------+ | |
+ * ...-----+ +-----...
+ */
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+
+const unsigned int DefaultLowPort = 12010;
+const unsigned int DefaultBaud = 115200;
+const char DefaultSerialDevice[] = "/dev/ttyS0";
+
+#define DEBUG 0
+#define MAX(a,b) ((a)<(b)?(b):(a))
+
+
+static int cook_baud(int baud)
+{
+ int cooked_baud = 0;
+ switch (baud)
+ {
+ case 50: cooked_baud = B50; break;
+ case 75: cooked_baud = B75; break;
+ case 110: cooked_baud = B110; break;
+ case 134: cooked_baud = B134; break;
+ case 150: cooked_baud = B150; break;
+ case 200: cooked_baud = B200; break;
+ case 300: cooked_baud = B300; break;
+ case 600: cooked_baud = B600; break;
+ case 1200: cooked_baud = B1200; break;
+ case 1800: cooked_baud = B1800; break;
+ case 2400: cooked_baud = B2400; break;
+ case 4800: cooked_baud = B4800; break;
+ case 9600: cooked_baud = B9600; break;
+ case 19200: cooked_baud = B19200; break;
+ case 38400: cooked_baud = B38400; break;
+ case 57600: cooked_baud = B57600; break;
+ case 115200: cooked_baud = B115200; break;
+ }
+ return cooked_baud;
+}
+
+
+static int start_listener(unsigned short port)
+{
+ int fd;
+ struct sockaddr_in sin;
+ int on = 1;
+
+ if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ perror("socket");
+ goto out1;
+ }
+
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons (port);
+ sin.sin_addr.s_addr = INADDR_ANY;
+ if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
+ {
+ perror("bind");
+ goto out2;
+ }
+
+ if (listen(fd, 1) < 0)
+ {
+ perror("listen");
+ goto out2;
+ }
+
+ fprintf(stderr, "Listening on port %d\n", port);
+
+ return fd;
+
+out2:
+ close(fd);
+out1:
+ return -1;
+}
+
+
+static int accept_conn(int fd)
+{
+ int on = 1;
+ int new_fd;
+ struct sockaddr_in from;
+ socklen_t fromlen = sizeof(from);
+
+ new_fd = accept(fd, (struct sockaddr *)&from, &fromlen);
+ if (new_fd < 0)
+ perror("accept");
+ ioctl(new_fd, FIONBIO, &on);
+
+ fprintf(stderr, "Accepted connection on %d\n", new_fd);
+
+ return new_fd;
+}
+
+
+static void close_conn(int * fd)
+{
+ shutdown(*fd, 2);
+ close(*fd);
+ *fd = -1;
+}
+
+
+static int receive_data(int * fd, char * buf, ssize_t max_bytes, int * poll)
+{
+ ssize_t bytes;
+ if ((bytes = read(*fd, buf, max_bytes)) < 0)
+ {
+ perror("read");
+ *poll = 1;
+ return 0;
+ }
+ else if (bytes == 0)
+ {
+ close_conn(fd);
+ *poll = 0;
+ return 0;
+ }
+ else
+ {
+ if (bytes == max_bytes)
+ *poll = 1;
+ else
+ *poll = 0;
+#if DEBUG
+ {
+ ssize_t i;
+ fprintf(stderr, "Received %d bytes on %d:\n", bytes, *fd);
+ for (i = 0; i < bytes; ++ i)
+ {
+ if ((i & 0xf) == 0)
+ printf(" ");
+ printf("%02x", buf[i] & 0xff);
+ if (((i+1) & 0xf) == 0 || i + 1 == bytes)
+ printf("\n");
+ else
+ printf(" ");
+ }
+ }
+#endif
+ return bytes;
+ }
+}
+
+
+static void set_high_bit(char * buf, size_t bytes)
+{
+ size_t i;
+ for(i = 0; i < bytes; ++ i)
+ buf[i] |= 0x80;
+}
+
+
+static void clear_high_bit(char * buf, size_t bytes)
+{
+ size_t i;
+ for(i = 0; i < bytes; ++ i)
+ buf[i] &= 0x7f;
+}
+
+
+static int open_serial(char const * serial_dev, int baud)
+{
+ struct termios newsertio;
+ int serial_fd;
+ memset(&newsertio, 0, sizeof(newsertio));
+
+ if ((serial_fd = open(serial_dev, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0)
+ {
+ perror(serial_dev);
+ return -1;
+ }
+
+ newsertio.c_cflag = baud | CS8 | CLOCAL | CREAD;
+ newsertio.c_iflag = IGNBRK | IGNPAR; /* raw input */
+ newsertio.c_oflag = 0; /* raw output */
+ newsertio.c_lflag = 0; /* no echo, no signals */
+ newsertio.c_cc[VMIN] = 1;
+ newsertio.c_cc[VTIME] = 0;
+ tcflush(serial_fd, TCIFLUSH);
+ tcsetattr(serial_fd, TCSANOW, &newsertio);
+
+ fprintf(stderr, "Listening on %s\n", serial_dev);
+
+ return serial_fd;
+}
+
+
+static void main_loop(int serial_fd, int low_listener, int high_listener)
+{
+ fd_set rdfds;
+ int low_poll = 0, high_poll = 0, serial_poll = 0;
+ int low_fd = -1, high_fd = -1;
+
+ while(1)
+ {
+ char buf[1024];
+ ssize_t bytes;
+ int max;
+
+ FD_ZERO(&rdfds);
+ FD_SET(low_fd < 0 ? low_listener : low_fd, &rdfds);
+ FD_SET(high_fd < 0 ? high_listener : high_fd, &rdfds);
+ FD_SET(serial_fd, &rdfds);
+
+ max = MAX(low_fd, low_listener);
+ max = MAX(max, high_fd);
+ max = MAX(max, high_listener);
+ max = MAX(max, serial_fd);
+
+ if (select(max + 1, &rdfds, NULL, NULL, NULL) < 0)
+ {
+ perror("select");
+ continue;
+ }
+
+ if (FD_ISSET(low_listener, &rdfds))
+ {
+ assert(low_fd < 0);
+ low_fd = accept_conn(low_listener);
+ }
+
+ if (FD_ISSET(high_listener, &rdfds))
+ {
+ assert(high_fd < 0);
+ high_fd = accept_conn(high_listener);
+ }
+
+ if (low_poll || (low_fd >= 0 && FD_ISSET(low_fd, &rdfds)))
+ {
+ if ((bytes = receive_data(&low_fd, &buf[0], sizeof(buf),
+ &low_poll)) > 0)
+ {
+ clear_high_bit(&buf[0], bytes);
+ if (write(serial_fd, &buf[0], bytes) < 0)
+ perror("write");
+ }
+ }
+
+ if (high_poll || (high_fd >= 0 && FD_ISSET(high_fd, &rdfds)))
+ {
+ if ((bytes = receive_data(&high_fd, &buf[0], sizeof(buf),
+ &high_poll)) > 0)
+ {
+ set_high_bit(&buf[0], bytes);
+ if (write(serial_fd, &buf[0], bytes) < 0)
+ perror("write");
+ }
+ }
+
+ if (serial_poll || FD_ISSET(serial_fd, &rdfds))
+ {
+ if ((bytes = receive_data(&serial_fd, &buf[0], sizeof(buf),
+ &serial_poll)) > 0)
+ {
+ ssize_t i;
+ for (i = 0; i < bytes; ++ i)
+ {
+ if (buf[i] & 0x80)
+ {
+ if (high_fd >= 0)
+ {
+ buf[i] &= 0x7f;
+ if ((write(high_fd, &buf[i], 1)) < 0)
+ {
+ perror("write");
+ close_conn(&high_fd);
+ high_poll = 0;
+ }
+ }
+ }
+ else
+ {
+ if (low_fd >= 0)
+ {
+ if ((write(low_fd, &buf[i], 1)) < 0)
+ {
+ perror("write");
+ close_conn(&low_fd);
+ low_poll = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+static void usage()
+{
+ printf(
+"Description:\n"
+" Splits the serial port between two TCP ports. Bytes read from the\n"
+" serial port will be delivered to one of the two TCP ports (high or\n"
+" low) depending on whether the high bit is set. Bytes written to the\n"
+" TCP ports will be forwarded to the serial port; the high bit will be\n"
+" set or cleared to denote the source.\n"
+"Usage:\n"
+" serial-split [-d<serial-device>] [-b<baud>]\n"
+" [-l<low-port>] [-h<high-port>]\n"
+"Parameters:\n"
+" -d<serial-device> Defaults to %s.\n"
+" -b<baud> Baud rate of the serial port. Defaults to %d.\n"
+" Also assumes 8N1.\n"
+" -l<low-port> Low TCP port. Defaults to %d, or one less than\n"
+" the high port.\n"
+" -h<high-port> High TCP port. Defaults to %d, or one more than\n"
+" the low port.\n",
+DefaultSerialDevice, DefaultBaud, DefaultLowPort, DefaultLowPort + 1);
+
+ exit(1);
+}
+
+
+int main(int argc, char **argv)
+{
+ int cooked_baud = cook_baud(DefaultBaud);
+ char const * serial_dev = DefaultSerialDevice;
+ int low_port = -1, high_port = -1;
+ int serial_fd, low_listener, high_listener;
+
+ while ( --argc != 0 )
+ {
+ char *p = argv[argc];
+ if ( *(p++) != '-' )
+ usage();
+ switch (*(p++))
+ {
+ case 'b':
+ if ( (cooked_baud = cook_baud(atoi(p))) == 0 )
+ {
+ fprintf(stderr, "Bad baud rate\n");
+ exit(1);
+ }
+ break;
+ case 'd':
+ serial_dev = p;
+ break;
+ case 'l':
+ if ((low_port = atoi(p)) <= 0)
+ usage();
+ break;
+ case 'h':
+ if ((high_port = atoi(p)) <= 0)
+ usage();
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (low_port == -1 && high_port == -1)
+ low_port = DefaultLowPort;
+ if (low_port == -1)
+ low_port = high_port - 1;
+ if (high_port == -1)
+ high_port = low_port + 1;
+
+ if ((serial_fd = open_serial(serial_dev, cooked_baud)) < 0 ||
+ (low_listener = start_listener(low_port)) < 0 ||
+ (high_listener = start_listener(high_port)) < 0)
+ exit(1);
+
+ main_loop(serial_fd, low_listener, high_listener);
+
+ return 0;
+}
+
reply other threads:[~2005-02-22 23:24 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=s21b5cd8.053@sinclair.provo.novell.com \
--to=ccoffing@novell.com \
--cc=xen-devel@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.