| /* |
| * |
| * Copyright (C) 2000 Paul Davis, pdavis@lpccomp.bc.ca |
| * |
| * 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., 675 Mass Ave, Cambridge, MA 02139, USA. |
| * |
| * |
| * This program acts as a bridge either between a socket(2) and a |
| * serial/parallel port or between a socket and a pseudo-tty. |
| */ |
| #include "../zlog_com.h" |
| |
| /** |
| * ºê¶¨Òå |
| */ |
| #define RECVBUF_MODEM_MAX_LEN 2048 |
| #define RECVBUF_SOCK_CLIENT_LEN 512 |
| |
| /** |
| * Íⲿ±äÁ¿ÒýÓà |
| */ |
| extern char* ptsname(int fd); |
| |
| /** |
| * Íⲿº¯ÊýÒýÓà |
| */ |
| extern int set_tty(int fd, char *settings); |
| |
| /** |
| * È«¾Ö±äÁ¿¶¨Òå |
| */ |
| struct sockaddr_in addr, remoteaddr; |
| int devfd; |
| int *remotefd; |
| char *machinename; |
| char *sttyparms; |
| char *sdevname; |
| char *linkname; |
| int sockfd = -1; |
| int port = 23000; |
| int debug = 0; |
| int isdaemon = 0; |
| int curConnects = 0; |
| int maxConnects = 1; |
| int writeonly; |
| |
| fd_set fdsread, fdsreaduse; |
| struct hostent *remotehost; |
| char devbuf[RECVBUF_MODEM_MAX_LEN]; |
| |
| /** |
| * ¾Ö²¿º¯ÊýÉùÃ÷ |
| */ |
| void zLogAgt_SigHandler(int sig); |
| int zLogAgt_connect_to(struct sockaddr_in *addr); |
| void usage(char *progname); |
| void link_slave(int fd); |
| |
| /** |
| * @brief ÐźŴ¦Àíº¯Êý |
| * @param[in] sigÐźÅÖµ |
| * @return VOID |
| * @note |
| * @see |
| */ |
| void zLogAgt_SigHandler(int sig) |
| { |
| int i; |
| |
| if (sockfd != -1) |
| close(sockfd); |
| |
| for (i=0; i<curConnects; i++) |
| close(remotefd[i]); |
| |
| if (devfd != -1) |
| close(devfd); |
| |
| if (linkname) |
| unlink(linkname); |
| |
| printf("Terminating on signal %d", sig); |
| exit(8); |
| } |
| |
| void link_slave(int fd) |
| { |
| char *slavename; |
| int status = grantpt(devfd); |
| if (status != -1) |
| status = unlockpt(devfd); |
| if (status != -1) { |
| slavename = ptsname(devfd); |
| if (slavename) { |
| // Safety first |
| unlink(linkname); |
| status = symlink(slavename, linkname); |
| } |
| else |
| status = -1; |
| } |
| if (status == -1) { |
| printf( "Cannot create link for pseudo-tty: %m"); |
| exit(9); |
| } |
| } |
| |
| /** |
| * @brief socketÍøÂçͨÐÅ´¦ÀíÁ÷³Ì |
| * @param[in] addr |
| * @return socket Ì×½Ó×Ö |
| * @note |
| * @see |
| */ |
| int zLogAgt_connect_to(struct sockaddr_in *addr) |
| { |
| int waitlogged = 0; |
| int stat; |
| int sockfd; |
| extern int errno; |
| |
| if (debug > 0) { |
| unsigned long ip = ntohl(addr->sin_addr.s_addr); |
| printf("Trying to connect to %d.%d.%d.%d", |
| (int)(ip>>24)&0xff, |
| (int)(ip>>16)&0xff, |
| (int)(ip>>8)&0xff, |
| (int)(ip>>0)&0xff); |
| } |
| |
| while (1) { |
| /* Open the socket for communications */ |
| sockfd = socket(AF_INET, SOCK_STREAM, 6); |
| |
| if (sockfd == -1) { |
| printf( "Can't open socket: %m"); |
| exit(10); |
| } |
| |
| /* Try to connect to the remote server, |
| if it fails, keep trying */ |
| |
| stat = connect(sockfd, (struct sockaddr*)addr, |
| sizeof(struct sockaddr_in)); |
| if (debug>1) |
| if (stat == -1) |
| printf( "Connect status %d, errno %d: %m\n", stat,errno); |
| else |
| printf( "Connect status %d\n", stat); |
| |
| if (stat == 0) |
| break; |
| /* Write a message to printf once */ |
| if (!waitlogged) { |
| printf( "Waiting for server on %s port %d: %m", machinename, port); |
| waitlogged = 1; |
| } |
| close(sockfd); |
| sleep(10); |
| } |
| if (waitlogged || debug > 0) |
| printf("Connected to server %s port %d", machinename, port); |
| |
| return sockfd; |
| } |
| |
| /** |
| * main º¯Êý¶¨Òå |
| */ |
| /** |
| * @brief net <-> serial ģʽÖ÷´¦Àíº¯Êý |
| * @param[in] usb É豸Îļþ¾ä±ú |
| * @return Á÷³Ì´¦Àí½á¹û |
| * @note |
| * @see |
| */ |
| int zLogAgt_NetSerial_Main(int fd_usb) |
| { |
| int result; |
| extern char *optarg; |
| extern int optind; |
| int maxfd = -1; |
| int devbytes; |
| int remoteaddrlen; |
| int waitlogged = 0; |
| register int i; |
| |
| PRINTF_DBG_INFO("Net and Serial Enter\n"); |
| |
| printf("sdevname=%s, port=%d, stty=%s\n",sdevname,port,sttyparms);//sdevname=/dev/ttyUSB0, port=23000, stty=921600 raw, optind=5 |
| |
| devfd = fd_usb; |
| |
| signal(SIGINT, zLogAgt_SigHandler); |
| signal(SIGHUP, zLogAgt_SigHandler); |
| signal(SIGTERM, zLogAgt_SigHandler); |
| |
| remotefd = (int *) malloc (maxConnects * sizeof(int)); |
| openlog("remserial", LOG_PID, LOG_USER); |
| |
| if (linkname) |
| link_slave(devfd); |
| |
| /* remserial -r server-name -p 23000 -s "9600 raw" /dev/ttyS0 */ |
| if (machinename) { |
| /* We are the client, |
| Find the IP address for the remote machine */ |
| remotehost = gethostbyname(machinename); |
| if (!remotehost) { |
| printf("Couldn't determine address of %s\n", machinename); |
| exit(3); |
| } |
| |
| /* Copy it into the addr structure */ |
| addr.sin_family = AF_INET; |
| memcpy(&(addr.sin_addr), remotehost->h_addr_list[0], |
| sizeof(struct in_addr)); |
| addr.sin_port = htons(port); |
| |
| remotefd[curConnects++] = zLogAgt_connect_to(&addr); |
| } |
| else { |
| /* We are the server */ |
| /* Open the initial socket for communications */ |
| sockfd = socket(AF_INET, SOCK_STREAM, 6); |
| if (sockfd == -1) { |
| printf("Can't open socket: %m\n"); |
| exit(4); |
| } |
| |
| addr.sin_family = AF_INET; |
| //addr.sin_addr.s_addr = 0; |
| addr.sin_port = htons(port); |
| addr.sin_addr.s_addr = htonl(INADDR_ANY); |
| |
| /* Set up to listen on the given port */ |
| if(bind(sockfd, (struct sockaddr*)(&addr), |
| sizeof(struct sockaddr_in)) < 0) { |
| printf("Couldn't bind port %d, aborting: %m",port); |
| exit(5); |
| } |
| if (debug > 1) |
| printf("Bound port\n"); |
| |
| /* Tell the system we want to listen on this socket */ |
| result = listen(sockfd, 4); |
| if (result == -1) { |
| printf( "Socket listen failed: %m"); |
| exit(6); |
| } |
| |
| if (debug > 1) |
| printf("Done listen\n"); |
| } |
| |
| if (isdaemon) { |
| setsid(); |
| close(0); |
| close(1); |
| close(2); |
| } |
| |
| /* Set up the files/sockets for the select() call */ |
| if (sockfd != -1) { |
| FD_SET(sockfd, &fdsread); |
| if (sockfd >= maxfd) |
| maxfd = sockfd + 1; |
| } |
| |
| for (i = 0; i < curConnects; i++) { |
| FD_SET(remotefd[i], &fdsread); |
| if (remotefd[i] >= maxfd) |
| maxfd = remotefd[i] + 1; |
| } |
| |
| if (!writeonly) { |
| FD_SET(devfd, &fdsread); |
| if (devfd >= maxfd) |
| maxfd = devfd + 1; |
| } |
| |
| while (1) { |
| /* Wait for data from the listening socket, the device |
| or the remote connection */ |
| fdsreaduse = fdsread; |
| if (select(maxfd, &fdsreaduse, NULL, NULL, NULL) == -1) |
| break; |
| |
| /* Activity on the controlling socket, only on server */ |
| if (!machinename && FD_ISSET(sockfd, &fdsreaduse)) { |
| int fd; |
| |
| /* Accept the remote systems attachment */ |
| remoteaddrlen = sizeof(struct sockaddr_in); |
| fd = accept(sockfd, (struct sockaddr*)(&remoteaddr), &remoteaddrlen); |
| |
| if (fd == -1) |
| printf("accept failed: \n"); |
| else if (curConnects < maxConnects) { |
| unsigned long ip; |
| remotefd[curConnects++] = fd; |
| /* Tell select to watch this new socket */ |
| FD_SET(fd, &fdsread); |
| if ( fd >= maxfd ) |
| maxfd = fd + 1; |
| ip = ntohl(remoteaddr.sin_addr.s_addr); |
| printf( "Connection from %d.%d.%d.%d\n", |
| (int)(ip>>24)&0xff, |
| (int)(ip>>16)&0xff, |
| (int)(ip>>8)&0xff, |
| (int)(ip>>0)&0xff); |
| } |
| else { |
| // Too many connections, just close it to reject |
| close(fd); |
| } |
| } |
| |
| /* Data to read from the device */ |
| if (FD_ISSET(devfd, &fdsreaduse)) { |
| devbytes = read(devfd, devbuf, RECVBUF_MODEM_MAX_LEN - 1); |
| |
| if (debug > 1) |
| printf("Device: %d bytes\n", devbytes); |
| if (devbytes <= 0) { |
| if (debug > 0) |
| printf("%s closed\n", sdevname); |
| close(devfd); |
| FD_CLR(devfd, &fdsread); |
| while (1) { |
| devfd = open(sdevname, O_RDWR); |
| if (devfd != -1) |
| break; |
| printf("Open of %s failed: %m\n", sdevname); |
| if (errno != EIO) |
| exit(7); |
| sleep(1); |
| } |
| if (debug > 0) |
| printf("%s re-opened", sdevname); |
| if (sttyparms) |
| set_tty(devfd, sttyparms); |
| if (linkname) |
| link_slave(devfd); |
| FD_SET(devfd, &fdsread); |
| if (devfd >= maxfd) |
| maxfd = devfd + 1; |
| } |
| else |
| for (i = 0; i < curConnects; i++) |
| write(remotefd[i], devbuf, devbytes); |
| } |
| |
| if (debug > 1) |
| printf("read Remotefd data start\n"); |
| /* Data to read from the remote system */ |
| for (i = 0; i < curConnects; i++) |
| if (FD_ISSET(remotefd[i], &fdsreaduse)) { |
| devbytes = read(remotefd[i], devbuf, RECVBUF_SOCK_CLIENT_LEN); |
| //if ( debug>1 && devbytes>0 ) |
| if (debug > 1) |
| printf("Remote: %d bytes", devbytes); |
| |
| if (devbytes == 0) { |
| register int j; |
| printf("Connection closed\n"); |
| close(remotefd[i]); |
| FD_CLR(remotefd[i], &fdsread); |
| curConnects--; |
| |
| for (j=i; j<curConnects; j++) |
| remotefd[j] = remotefd[j+1]; |
| |
| if (machinename) { |
| /* Wait for the server again */ |
| remotefd[curConnects++] = zLogAgt_connect_to(&addr); |
| FD_SET(remotefd[curConnects-1], &fdsread); |
| if (remotefd[curConnects-1] >= maxfd) |
| maxfd = remotefd[curConnects-1] + 1; |
| } |
| } |
| else if (devfd != -1) |
| /* Write the data to the device */ |
| write(devfd, devbuf, devbytes); |
| } |
| } |
| close(sockfd); |
| for (i=0; i<curConnects; i++) |
| close(remotefd[i]); |
| |
| return 0; |
| } |
| |