// DESC: This script reads messages coming from the serial port and forwards them via TCP to a all remote host (and vice versa). // Copyright (C) 2014 NetModule AG // usage: usage: serial-tcp-broadcast.are .... " // Version: 2.0 // /* Options to configure by user*/ /* Serial Baud Rate 9600, 19200, 38400, 57600, 115200 */ SER_SPEED=115200; /* number of data bits (5, 6, 7, 8) */ SER_DATABIT=8; /* number of stop bits (1, 2) */ SER_STOPBIT=1; /* parity (0=no parity, 1=odd parity, 2=even parity) */ SER_PARITY=0; /* flow control (0=none, 1=xon/xoff, 2=hardware) */ SER_FLOW=0; /* name of the Serial Interface (Only changed if your device has more then one serial Interface (NB3710) */ DEV = "SERIAL1"; /* TCP Options */ /* If the script try to connect to a tcp slave, how many retries should it make */ RETRY = 3; /* The pause in seconds between the retries*/ RETRY_INTERVAL = 3; /* How many seconds should the script wait to run a new set of retries after the client got lost, or the retries were not sucessfull */ RECOVER_INTERVAL = 120; //################################################################ //################################################################ //################################################################ /* Only changed things below this line if you know what you are doing */ //################################################################ //################################################################ //################################################################ POLL_TIMEOUT = 10; /* seconds */ REMOTE_PORT =2000; /* port of the remote serial slaves 2000 is default on NB Products */ template slave { hostname = ""; fd = -1; state = "down"; downSince = 0; void slave(string remotehost) { nb_syslog("creating slave %s",remotehost); if ( strlen(remotehost) > 0 ) { this.hostname=remotehost; } else { nb_syslog("No Hostname defined slave could not be created"); } } int jiffy() { sys = sysinfo(); u = struct_get(sys, "uptime"); if (is_void(u) || u < 1) { return 0; } else { return u; } } int connect() { nb_syslog("Connecting to %s", this.hostname); /* open TCP socket */ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,1); setsockopt(sock, SOL_TCP, TCP_KEEPIDLE,1); setsockopt(sock, SOL_TCP, TCP_KEEPINTVL,5); setsockopt(sock, SOL_TCP, TCP_KEEPCNT,5); if (sock < 0) { nb_syslog("ERROR: unable to open socket"); } for ( i = 0; i < RETRY; i++) { if (connect(sock, this.hostname, REMOTE_PORT) < 0){ nb_syslog("Could not connect to %s (port %d)", this.hostname, REMOTE_PORT); nb_syslog("Retry connect, trial #%i, waiting %s sec", i, RETRY_INTERVAL); sleep(RETRY_INTERVAL); } else { nb_syslog("TCP connection is opened - remote server %s:%d", this.hostname, REMOTE_PORT); this.fd=sock; this.state="up"; return 0; } } nb_syslog("Max retries reached, giving up TCP connection to %s",this.hostname); this.downSince=this.jiffy(); this.state="down"; close(this.fd); return -1; } int disconnect() { close(this.fd); this.fd=-1; this.state="down"; this.downSince=this.jiffy(); nb_syslog("Host %s disconnected", this.hostname); return 0; } } // of template slave void usage() { nb_syslog("usage: serial-tcp-broadcast.are .... "); exit(1); } int start_serial() { /* check serial port config */ status = nb_config_get("serial.0.status"); if (status != "2") { nb_syslog("Serial port is not enabled for us"); exit(1); } /* set attributes */ rc = nb_serial_setattr(DEV, SER_SPEED, SER_DATABIT, SER_STOPBIT, SER_PARITY, SER_FLOW); if (rc != 0) { nb_syslog("ERROR: unable to set serial attributes (rc %d)", rc); exit(1); } /* open serial port */ fd = nb_serial_open(DEV); if (fd < 0) { nb_syslog("Unable to open serial device (%s)", DEV); exit(1); } return fd; } int stop_serial() { close(fd); return 0; } // ################################################### // ################################################### // ########Begining of Program######################## // ################################################### // ################################################### // ################################################### /* check arguments */ if (strlen(argv[1]) == 0) { nb_syslog("ERROR: no remote host specified"); usage(); } /* create slave host list and set */ nb_syslog("creating slaves"); for (i=1; i < argc; i++) { slaves[i-1] = new slave(argv[i]); } // connect to slave //for ( i=0; i < length(slaves); i++) { for ( i=0; i < length(slaves); i++) { nb_syslog("connect to slave %i",i); rc = slaves[i].connect(); if (rc < 0) { nb_syslog("could not create socket %s", slaves[i].hostname); } } nb_syslog("starting serial"); serial_fd = start_serial(); // Creating tcp fd array for select() fds=mkarray(); tcp_fds=mkarray(); j=0; for ( i=0; i < length(slaves); i++) { if (slaves[i].state == "up") { tcp_fds[j]=slaves[i].fd; j++; } } fds=array_merge(serial_fd, tcp_fds); while (1) { buffer = ""; rc = select(fds, POLL_TIMEOUT); if (rc == -1) { nb_syslog("ERROR: select failed"); } else if (rc == serial_fd) { /* received something from serial device */ data = read(serial_fd, 4096); if (data) { serialbuffer = strcat(serialbuffer, data); nb_syslog("data on serial port: %s",serialBuffer); } } else if (rc != 0 && array_search(tcp_fds, rc) != NULL) { /* received something from TCP */ data = recv(rc); len=strlen(data); if ( len > 0) { /* write to serial device */ write(serial_fd, data, len); } else if(len == 0) { //nb_syslog("tcp connection is gone lets set the slave correctly"); for ( i=0; i < length(slaves); i++) { if (rc == slaves[i].fd) { /* lets put the socket on disable */ slaves[i].disconnect(); } } } } /* check serial buffer and send message */ len = strlen(serialbuffer); // we have data for the slaves lets sent it msg = serialbuffer; msglen = len; serialbuffer = ""; /* send TCP packet to every socket */ if (len > 0) { for ( i=0; i < length(slaves); i++) { if (slaves[i].state == "up" ) { sent = send(slaves[i].fd, msg); if (sent == -1) { nb_syslog("failed sending to host: %s fd: %i",slaves[i].hostname,slaves[i].fd); /* lets put the socket on disable */ slaves[i].disconnect(); } } } } /* check if we have a error on the soocket */ for ( i=0; i < length(slaves); i++) { if (slaves[i].state == "up" ) { sockop=getsockopt(slaves[i].fd, SOL_SOCKET, 4); if (sockop != 0) { nb_syslog("Error No %i on slave %s, Set Slave offline and try reconnect again", sockop, slaves[i].hostname); slaves[i].disconnect(); } } } // reconnect to lost slaves for ( i=0; i < length(slaves); i++) { if (slaves[i].state == "down" ) { if ( (slaves[i].downSince + RECOVER_INTERVAL) < slaves[i].jiffy() ) { slaves[i].connect(); } } } // recreate online fds fds=mkarray(); tcp_fds=mkarray(); j=0; for ( i=0; i < length(slaves); i++) { if (slaves[i].state == "up") { tcp_fds[j]=slaves[i].fd; j++; } } fds=array_merge(serial_fd, tcp_fds); } exit(0);