⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dataxfer.c

📁 This project provides a proxy that allows telnet/tcp connections to be made to serial ports on a mac
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  ser2net - A program for allowing telnet connection to serial ports *  Copyright (C) 2001  Corey Minyard <minyard@acm.org> * *  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. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *//* This code handles the actual transfer of data between the serial   ports and the TCP ports. */#include <termios.h>#include <sys/types.h>#include <sys/ioctl.h>#include <sys/time.h>#include <sys/socket.h>#include <sys/stat.h>#include <arpa/inet.h>#include <stdlib.h>#include <unistd.h>#include <stdio.h>#include <fcntl.h>#include <netinet/in.h>#include <errno.h>#include <syslog.h>#include <string.h>#include <signal.h>#include <ctype.h>#include "dataxfer.h"#include "selector.h"#include "devcfg.h"#include "utils.h"#include "telnet.h"extern selector_t *ser2net_sel;/** BASED ON sshd.c FROM openssh.com */#ifdef HAVE_TCPD_H#include <tcpd.h>static char *progname = "ser2net";#endif /* HAVE_TCPD_H */#ifdef USE_UUCP_LOCKINGstatic char *uucp_lck_dir = "/var/lock";#ifndef HAVE_TCPD_Hstatic char *progname = "ser2net";#endif#endif /* USE_UUCP_LOCKING *//* States for the tcp_to_dev_state and dev_to_tcp_state. */#define PORT_UNCONNECTED		0 /* The TCP port is not connected                                             to anything right now. */#define PORT_WAITING_INPUT		1 /* Waiting for input from the					     input side. */#define PORT_WAITING_OUTPUT_CLEAR	2 /* Waiting for output to clear					     so I can send data. */char *state_str[] = { "unconnected", "waiting input", "waiting output" };#define PORT_DISABLED		0 /* The port is not open. */#define PORT_RAW		1 /* Port will not do telnet negotiation. */#define PORT_RAWLP		2 /* Port will not do telnet negotiation and                                     termios setting, open for output only. */#define PORT_TELNET		3 /* Port will do telnet negotiation. */char *enabled_str[] = { "off", "raw", "rawlp", "telnet" };#define PORT_BUFSIZE	1024typedef struct port_info{    int            enabled;		/* If PORT_DISABLED, the port					   is disabled and the TCP					   accept port is not					   operational.  If PORT_RAW,					   the port is enabled and					   will not do any telnet					   negotiations.  If					   PORT_RAWLP, the port is enabled					   only for output without any					   termios setting - it allows					   to redirect /dev/lpX devices If					   PORT_TELNET, the port is					   enabled and it will do					   telnet negotiations. */    int            timeout;		/* The number of seconds to					   wait without any I/O before					   we shut the port down. */    int            timeout_left;	/* The amount of time left (in					   seconds) before the timeout					   goes off. */    sel_timer_t *timer;			/* Used to timeout when the no					   I/O has been seen for a					   certain period of time. */    /* Information about the TCP port. */    char               *portname;       /* The name given for the port. */    struct sockaddr_in tcpport;		/* The TCP port to listen on					   for connections to this					   terminal device. */    int            acceptfd;		/* The file descriptor used to					   accept connections on the					   TCP port. */    int            tcpfd;		/* When connected, the file                                           descriptor for the TCP                                           port used for I/O. */    struct sockaddr_in remote;		/* The socket address of who					   is connected to this port. */    unsigned int tcp_bytes_received;    /* Number of bytes read from the					   TCP port. */    unsigned int tcp_bytes_sent;        /* Number of bytes written to the					   TCP port. */    /* Information about the terminal device. */    char           *devname;		/* The full path to the device */    int            devfd;		/* The file descriptor for the                                           device, only valid if the                                           TCP port is open. */    struct termios termctl;		/* The termios information to					   set for the device. */    unsigned int dev_bytes_received;    /* Number of bytes read from the					   device. */    unsigned int dev_bytes_sent;        /* Number of bytes written to the					   device. */    /* Information use when transferring information from the TCP port       to the terminal device. */    int            tcp_to_dev_state;		/* State of transferring						   data from the TCP port                                                   to the device. */    unsigned char  tcp_to_dev_buf[PORT_BUFSIZE]; /* Buffer used for                                                    TCP to device                                                    transfers. */    int            tcp_to_dev_buf_start;	/* The first byte in						   the buffer that is						   ready to send. */    int            tcp_to_dev_buf_count;	/* The number of bytes                                                   in the buffer to                                                   send. */    struct controller_info *tcp_monitor; /* If non-null, send any input					    received from the TCP port					    to this controller port. */    /* Information use when transferring information from the terminal       device to the TCP port. */    int            dev_to_tcp_state;		/* State of transferring						   data from the device to                                                   the TCP port. */    char           dev_to_tcp_buf[PORT_BUFSIZE]; /* Buffer used for                                                    device to TCP                                                    transfers. */    int            dev_to_tcp_buf_start;	/* The first byte in						   the buffer that is						   ready to send. */    int            dev_to_tcp_buf_count;	/* The number of bytes                                                   in the buffer to                                                   send. */    struct controller_info *dev_monitor; /* If non-null, send any input					    received from the device					    to this controller port. */    struct port_info *next;		/* Used to keep a linked list					   of these. */    int config_num; /* Keep track of what configuration this was last		       updated under.  Setting to -1 means to delete		       the port when the current session is done. */    struct port_info *new_config; /* If the port is reconfigged while				     open, this will hold the new				     configuration that should be				     loaded when the current session				     is done. */    /* Banner to display at startup, or NULL if none. */    char *banner;    /* Data for the telnet processing */    telnet_data_t tn_data;    /* Allow RFC 2217 mode */    int allow_2217;    /* Is RFC 2217 mode enabled? */    int is_2217;    /* Holds whether break is on or not. */    int break_set;    /* Masks for RFC 2217 */    unsigned char linestate_mask;    unsigned char modemstate_mask;    unsigned char last_modemstate;} port_info_t;port_info_t *ports = NULL; /* Linked list of ports. */static void shutdown_port(port_info_t *port, char *reason);/* The init sequence we use. */static unsigned char telnet_init_seq[] = {    TN_IAC, TN_WILL, TN_OPT_SUPPRESS_GO_AHEAD,    TN_IAC, TN_WILL, TN_OPT_ECHO,    TN_IAC, TN_DONT, TN_OPT_ECHO,    TN_IAC, TN_DO,   TN_OPT_BINARY_TRANSMISSION,};/* Our telnet command table. */static void com_port_handler(void *cb_data, unsigned char *option, int len);static int com_port_will(void *cb_data);static struct telnet_cmd telnet_cmds[] = {    /*                        I will,  I do,  sent will, sent do */    { TN_OPT_SUPPRESS_GO_AHEAD,	   0,     1,          1,       0, },    { TN_OPT_ECHO,		   0,     1,          1,       1, },    { TN_OPT_BINARY_TRANSMISSION,  1,     1,          0,       1, },    { TN_OPT_COM_PORT,		   1,     0,          0,       0, 0, 0,      com_port_handler, com_port_will },    { 255 }};#ifdef USE_UUCP_LOCKINGstatic intuucp_fname_lock_size(char *devname){    char *ptr;    (ptr = strrchr(devname, '/'));    if (ptr == NULL) {	ptr = devname;    } else {	ptr = ptr + 1;    }    return 7 + strlen(uucp_lck_dir) + strlen(ptr);}static voiduucp_fname_lock(char *buf, char *devname){    char *ptr;    (ptr = strrchr(devname, '/'));    if (ptr == NULL) {	ptr = devname;    } else {	ptr = ptr + 1;    }    sprintf(buf, "%s/LCK..%s", uucp_lck_dir, ptr);}static voiduucp_rm_lock(char *devname){    char *lck_file;    if (!uucp_locking_enabled) return;    lck_file = malloc(uucp_fname_lock_size(devname));    if (lck_file == NULL) {	return;    }    uucp_fname_lock(lck_file, devname);    unlink(lck_file);    free(lck_file);}/* return 0=OK, -1=error, 1=locked by other proces */static intuucp_mk_lock(char *devname){    struct stat stt;    int pid=-1;    if (!uucp_locking_enabled) return 0;    if( stat(uucp_lck_dir, &stt) == 0 ) { /* is lock file directory present? */	char *lck_file, buf[64];	int fd;	lck_file = malloc(uucp_fname_lock_size(devname));	if (lck_file == NULL) {	    return -1;	}	uucp_fname_lock(lck_file, devname);	pid = 0;	if( (fd = open(lck_file, O_RDONLY)) >= 0 ) {	    int n;    	    n = read(fd, buf, sizeof(buf));	    close(fd);	    if( n == 4 ) 		/* Kermit-style lockfile. */		pid = *(int *)buf;	    else if( n > 0 ) {		/* Ascii lockfile. */		buf[n] = 0;		sscanf(buf, "%d", &pid);	    }	    if( pid > 0 && kill((pid_t)pid, 0) < 0 && errno == ESRCH ) {		/* death lockfile - remove it */		unlink(lck_file);		sleep(1);		pid = 0;	    } else		pid = 1;	}	if( pid == 0 ) {	    int mask;	    mask = umask(022);	    fd = open(lck_file, O_WRONLY | O_CREAT | O_EXCL, 0666);	    umask(mask);	    if( fd >= 0 ) {		snprintf( buf, sizeof(buf), "%10ld\t%s\n",					     (long)getpid(), progname );		write( fd, buf, strlen(buf) );		close(fd);	    } else {		pid = 1;	    }	}	free(lck_file);    }    return pid;}#endif /* USE_UUCP_LOCKING */static voidinit_port_data(port_info_t *port){    port->enabled = PORT_DISABLED;    port->portname = NULL;    memset(&(port->tcpport), 0, sizeof(port->tcpport));    port->acceptfd = -1;    port->tcpfd = -1;    port->timeout = 0;    port->next = NULL;    port->new_config = NULL;    port->tcp_monitor = NULL;        port->devname = NULL;    port->devfd = 0;    memset(&(port->remote), 0, sizeof(port->remote));    memset(&(port->termctl), 0, sizeof(port->termctl));    port->tcp_to_dev_state = PORT_UNCONNECTED;    port->tcp_to_dev_buf_start = 0;    port->tcp_to_dev_buf_count = 0;    port->tcp_bytes_received = 0;    port->tcp_bytes_sent = 0;    port->dev_to_tcp_state = PORT_UNCONNECTED;    port->dev_to_tcp_buf_start = 0;    port->dev_to_tcp_buf_count = 0;    port->dev_bytes_received = 0;    port->dev_bytes_sent = 0;    port->is_2217 = 0;    port->break_set = 0;}voiddelete_tcp_to_dev_char(port_info_t *port, int pos){    int j;    for (j=pos; j<port->tcp_to_dev_buf_count-1; j++) {	port->tcp_to_dev_buf[j] = port->tcp_to_dev_buf[j+1];    }    port->tcp_to_dev_buf_count--;}static voidreset_timer(port_info_t *port){    port->timeout_left = port->timeout;}/* Data is ready to read on the serial port. */static voidhandle_dev_fd_read(int fd, void *data){    port_info_t *port = (port_info_t *) data;    int write_count;    port->dev_to_tcp_buf_start = 0;    port->dev_to_tcp_buf_count = read(fd, port->dev_to_tcp_buf, PORT_BUFSIZE);    if (port->dev_to_tcp_buf_count < 0) {	/* Got an error on the read, shut down the port. */	syslog(LOG_ERR, "dev read error for port %s: %m", port->portname);	shutdown_port(port, "dev read error");	return;    } else if (port->dev_to_tcp_buf_count == 0) {	/* The port got closed somehow, shut it down. */	shutdown_port(port, "closed port");	return;    }    port->dev_bytes_received += port->dev_to_tcp_buf_count;    write_count = write(port->tcpfd,			port->dev_to_tcp_buf,			port->dev_to_tcp_buf_count);    if (port->dev_monitor != NULL) {	controller_write(port->dev_monitor,			 port->dev_to_tcp_buf,			 port->dev_to_tcp_buf_count);    }    if (write_count == -1) {	if (errno == EINTR) {	    /* EINTR means we were interrupted, just retry by returning. */	    return;	}	if (errno == EAGAIN) {	    /* This was due to O_NONBLOCK, we need to shut off the reader	       and start the writer monitor. */	    sel_set_fd_read_handler(ser2net_sel, port->devfd,				    SEL_FD_HANDLER_DISABLED);	    sel_set_fd_write_handler(ser2net_sel, port->tcpfd,				     SEL_FD_HANDLER_ENABLED);	    port->dev_to_tcp_state = PORT_WAITING_OUTPUT_CLEAR;	} else if (errno == EPIPE) {	    shutdown_port(port, "EPIPE");	} else {	    /* Some other bad error. */	    syslog(LOG_ERR, "The tcp write for port %s had error: %m",		   port->portname);	    shutdown_port(port, "tcp write error");	}    } else {	port->tcp_bytes_sent += write_count;	port->dev_to_tcp_buf_count -= write_count;	if (port->dev_to_tcp_buf_count != 0) {	    /* We didn't write all the data, shut off the reader and               start the write monitor. */	    port->dev_to_tcp_buf_start += write_count;	    sel_set_fd_read_handler(ser2net_sel, port->devfd,				    SEL_FD_HANDLER_DISABLED);	    sel_set_fd_write_handler(ser2net_sel, port->tcpfd,				     SEL_FD_HANDLER_ENABLED);	    port->dev_to_tcp_state = PORT_WAITING_OUTPUT_CLEAR;	}    }    reset_timer(port);}/* The serial port has room to write some data.  This is only activated   if a write fails to complete, it is deactivated as soon as writing   is available again. */static voidhandle_dev_fd_write(int fd, void *data){    port_info_t *port = (port_info_t *) data;    int write_count;    write_count = write(port->devfd,			&(port->tcp_to_dev_buf[port->tcp_to_dev_buf_start]),			port->tcp_to_dev_buf_count);    if (write_count == -1) {	if (errno == EINTR) {	    /* EINTR means we were interrupted, just retry by returning. */	    return;	}	if (errno == EAGAIN) {	    /* This again was due to O_NONBLOCK, just ignore it. */	} else {	    /* Some other bad error. */	    syslog(LOG_ERR, "The dev write for port %s had error: %m",		   port->portname);	    shutdown_port(port, "dev write error");	}    } else {	port->dev_bytes_sent += write_count;	port->tcp_to_dev_buf_count -= write_count;	if (port->tcp_to_dev_buf_count != 0) {	    /* We didn't write all the data, continue writing. */	    port->tcp_to_dev_buf_start += write_count;	} else {	    /* We are done writing, turn the reader back on. */	    sel_set_fd_read_handler(ser2net_sel, port->tcpfd,				    SEL_FD_HANDLER_ENABLED);	    sel_set_fd_write_handler(ser2net_sel, port->devfd,				     SEL_FD_HANDLER_DISABLED);	    port->tcp_to_dev_state = PORT_WAITING_INPUT;	}    }    reset_timer(port);}/* Handle an exception from the serial port. */static voidhandle_dev_fd_except(int fd, void *data){    port_info_t *port = (port_info_t *) data;    syslog(LOG_ERR, "Select exception on device for port %s",	   port->portname);    shutdown_port(port, "fd exception");}/* Data is ready to read on the TCP port. */static voidhandle_tcp_fd_read(int fd, void *data){    port_info_t *port = (port_info_t *) data;    int write_count;    port->tcp_to_dev_buf_start = 0;    port->tcp_to_dev_buf_count = read(fd, port->tcp_to_dev_buf, PORT_BUFSIZE);    if (port->tcp_to_dev_buf_count < 0) {	/* Got an error on the read, shut down the port. */	syslog(LOG_ERR, "read error for port %s: %m", port->portname);	shutdown_port(port, "tcp read error");	return;    } else if (port->tcp_to_dev_buf_count == 0) {	/* The other end closed the port, shut it down. */	shutdown_port(port, "tcp read close");	return;    }    port->tcp_bytes_received += port->tcp_to_dev_buf_count;    if (port->enabled == PORT_TELNET) {	port->tcp_to_dev_buf_count = process_telnet_data	    (port->tcp_to_dev_buf, port->tcp_to_dev_buf_count, &port->tn_data);	if (port->tn_data.error) {	    shutdown_port(port, "telnet output error");	    return;	}	if (port->tcp_to_dev_buf_count == 0) {	    /* We are out of characters; they were all processed.  We	       don't want to continue with 0, because that will mess	       up the other processing and it's not necessary. */	    return;	}    }    write_count = write(port->devfd,			port->tcp_to_dev_buf,			port->tcp_to_dev_buf_count);    if (port->tcp_monitor != NULL) {	controller_write(port->tcp_monitor,			 port->tcp_to_dev_buf,			 port->tcp_to_dev_buf_count);    }    if (write_count == -1) {	if (errno == EINTR) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -