From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Charles Coffing" Subject: [PATCH] serial-split.c Date: Tue, 22 Feb 2005 16:24:49 -0700 Message-ID: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=__PartDFFC8B51.0__=" Sender: xen-devel-admin@lists.sourceforge.net Errors-To: xen-devel-admin@lists.sourceforge.net List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , List-Archive: To: xen-devel@lists.sourceforge.net List-Id: xen-devel@lists.xenproject.org This is a MIME message. If you are reading this text, you may want to consider changing to a mail reader or gateway that understands how to properly handle MIME multipart messages. --=__PartDFFC8B51.0__= Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Content-Disposition: inline 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 --=__PartDFFC8B51.0__= Content-Type: text/plain; name="serial-split.patch" Content-Disposition: attachment; filename="serial-split.patch" Content-Transfer-Encoding: quoted-printable diff -ruN xen-2.0.bk.orig/tools/misc/serial-split/Makefile xen-2.0.bk/too= ls/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.66434= 6593 -0700 @@ -0,0 +1,18 @@ +CC =3D gcc +CFLAGS =3D -Wall -O3 +CFILES =3D $(wildcard *.c) +OBJS =3D $(patsubst %.c,%.o,$(wildcard *.c)) +TARGET =3D 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const unsigned int DefaultLowPort =3D 12010; +const unsigned int DefaultBaud =3D 115200; +const char DefaultSerialDevice[] =3D "/dev/ttyS0"; + +#define DEBUG 0 +#define MAX(a,b) ((a)<(b)?(b):(a)) + + +static int cook_baud(int baud) +{ + int cooked_baud =3D 0; + switch (baud) + { + case 50: cooked_baud =3D B50; break; + case 75: cooked_baud =3D B75; break; + case 110: cooked_baud =3D B110; break; + case 134: cooked_baud =3D B134; break; + case 150: cooked_baud =3D B150; break; + case 200: cooked_baud =3D B200; break; + case 300: cooked_baud =3D B300; break; + case 600: cooked_baud =3D B600; break; + case 1200: cooked_baud =3D B1200; break; + case 1800: cooked_baud =3D B1800; break; + case 2400: cooked_baud =3D B2400; break; + case 4800: cooked_baud =3D B4800; break; + case 9600: cooked_baud =3D B9600; break; + case 19200: cooked_baud =3D B19200; break; + case 38400: cooked_baud =3D B38400; break; + case 57600: cooked_baud =3D B57600; break; + case 115200: cooked_baud =3D B115200; break; + } + return cooked_baud; +} + + +static int start_listener(unsigned short port) +{ + int fd; + struct sockaddr_in sin; + int on =3D 1; + + if ((fd =3D 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 =3D AF_INET; + sin.sin_port =3D htons (port); + sin.sin_addr.s_addr =3D 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 =3D 1; + int new_fd; + struct sockaddr_in from; + socklen_t fromlen =3D sizeof(from); + + new_fd =3D 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 =3D -1; +} + + +static int receive_data(int * fd, char * buf, ssize_t max_bytes, int * p= oll) +{ + ssize_t bytes; + if ((bytes =3D read(*fd, buf, max_bytes)) < 0) + { + perror("read"); + *poll =3D 1; + return 0; + } + else if (bytes =3D=3D 0) + { + close_conn(fd); + *poll =3D 0; + return 0; + } + else + { + if (bytes =3D=3D max_bytes) + *poll =3D 1; + else + *poll =3D 0; +#if DEBUG + { + ssize_t i; + fprintf(stderr, "Received %d bytes on %d:\n", bytes, *fd); + for (i =3D 0; i < bytes; ++ i) + { + if ((i & 0xf) =3D=3D 0) + printf(" "); + printf("%02x", buf[i] & 0xff); + if (((i+1) & 0xf) =3D=3D 0 || i + 1 =3D=3D bytes) + printf("\n"); + else + printf(" "); + } + } +#endif + return bytes; + } +} + + +static void set_high_bit(char * buf, size_t bytes) +{ + size_t i; + for(i =3D 0; i < bytes; ++ i) + buf[i] |=3D 0x80; +} + + +static void clear_high_bit(char * buf, size_t bytes) +{ + size_t i; + for(i =3D 0; i < bytes; ++ i) + buf[i] &=3D 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 =3D open(serial_dev, O_RDWR | O_NOCTTY | O_NONBLOCK))= < 0) + { + perror(serial_dev);=20 + return -1; + } +=20 + newsertio.c_cflag =3D baud | CS8 | CLOCAL | CREAD; + newsertio.c_iflag =3D IGNBRK | IGNPAR; /* raw input */ + newsertio.c_oflag =3D 0; /* raw output */ + newsertio.c_lflag =3D 0; /* no echo, no signals */ + newsertio.c_cc[VMIN] =3D 1; + newsertio.c_cc[VTIME] =3D 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 =3D 0, high_poll =3D 0, serial_poll =3D 0; + int low_fd =3D -1, high_fd =3D -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 =3D MAX(low_fd, low_listener); + max =3D MAX(max, high_fd); + max =3D MAX(max, high_listener); + max =3D 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 =3D accept_conn(low_listener); + } + + if (FD_ISSET(high_listener, &rdfds)) + { + assert(high_fd < 0); + high_fd =3D accept_conn(high_listener); + } + + if (low_poll || (low_fd >=3D 0 && FD_ISSET(low_fd, &rdfds))) + { + if ((bytes =3D 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 >=3D 0 && FD_ISSET(high_fd, &rdfds))) + { + if ((bytes =3D 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 =3D receive_data(&serial_fd, &buf[0], sizeof(buf)= , + &serial_poll)) > 0) + { + ssize_t i; + for (i =3D 0; i < bytes; ++ i) + { + if (buf[i] & 0x80) + { + if (high_fd >=3D 0) + { + buf[i] &=3D 0x7f; + if ((write(high_fd, &buf[i], 1)) < 0) + { + perror("write"); + close_conn(&high_fd); + high_poll =3D 0; + } + } + } + else + { + if (low_fd >=3D 0) + { + if ((write(low_fd, &buf[i], 1)) < 0) + { + perror("write"); + close_conn(&low_fd); + low_poll =3D 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 t= o the\n" +" TCP ports will be forwarded to the serial port; the high bit wi= ll be\n" +" set or cleared to denote the source.\n" +"Usage:\n" +" serial-split [-d] [-b]\n" +" [-l] [-h]\n" +"Parameters:\n" +" -d Defaults to %s.\n" +" -b Baud rate of the serial port. Defaults to %= d.\n" +" Also assumes 8N1.\n" +" -l Low TCP port. Defaults to %d, or one less t= han\n" +" the high port.\n" +" -h High TCP port. Defaults to %d, or one more = than\n" +" the low port.\n", +DefaultSerialDevice, DefaultBaud, DefaultLowPort, DefaultLowPort + 1); + =20 + exit(1); +} + + +int main(int argc, char **argv) +{ + int cooked_baud =3D cook_baud(DefaultBaud); + char const * serial_dev =3D DefaultSerialDevice; + int low_port =3D -1, high_port =3D -1; + int serial_fd, low_listener, high_listener; +=20 + while ( --argc !=3D 0 ) + { + char *p =3D argv[argc]; + if ( *(p++) !=3D '-' ) + usage(); + switch (*(p++)) + { + case 'b': + if ( (cooked_baud =3D cook_baud(atoi(p))) =3D=3D 0 ) + { + fprintf(stderr, "Bad baud rate\n"); + exit(1); + } + break; + case 'd': + serial_dev =3D p; + break; + case 'l': + if ((low_port =3D atoi(p)) <=3D 0) + usage(); + break; + case 'h': + if ((high_port =3D atoi(p)) <=3D 0) + usage(); + break; + default: + usage(); + } + } + + if (low_port =3D=3D -1 && high_port =3D=3D -1) + low_port =3D DefaultLowPort; + if (low_port =3D=3D -1) + low_port =3D high_port - 1; + if (high_port =3D=3D -1) + high_port =3D low_port + 1; + + if ((serial_fd =3D open_serial(serial_dev, cooked_baud)) < 0 || + (low_listener =3D start_listener(low_port)) < 0 || + (high_listener =3D start_listener(high_port)) < 0) + exit(1); + + main_loop(serial_fd, low_listener, high_listener); + + return 0; +} + --=__PartDFFC8B51.0__=-- ------------------------------------------------------- SF email is sponsored by - The IT Product Guide Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now. http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click