main.cpp
Go to the documentation of this file.
00001 
00046 #include <stdio.h>
00047 #include <stdlib.h>
00048 #include <unistd.h>
00049 #include <string.h>
00050 #include <signal.h>
00051 #include <poll.h>
00052 
00053 #include <vector>
00054 
00055 #include "port.h"
00056 
00057 using namespace std;
00058 
00059 // Global for term signal handler:
00060 vector<Port*> service_ports;
00061 vector<Port*> client_ports;
00062 vector<struct pollfd> pollfds;
00063 
00064 // Need to execute atexit() when a fatal signal is received
00065 void handle_term(int signum) {
00066     vector<Port*>::iterator iter;
00067     for(iter = service_ports.begin(); iter != service_ports.end(); ++iter) {
00068         delete *iter;
00069     }
00070     for(iter = client_ports.begin(); iter != client_ports.end(); ++iter) {
00071         delete *iter;
00072     }
00073    
00074     fflush(stderr);
00075     fflush(stdout);
00076 
00077     /* If we abort, we still need to do the above cleanup, but we should still
00078      * exit on an abort to signal that horrible things happened.
00079      * So, we restore default abort() behaviour and then re-raise the abort */
00080     if( signum == SIGABRT ) {
00081         signal(SIGABRT, SIG_DFL);
00082         abort();
00083     }
00084 
00085     printf("\nExiting virtual-serial\n");
00086     exit(0);
00087 }
00088 
00089 
00090 void print_help(const char* executable_name) {
00091     printf("Usage: \n"
00092            "1: %s [service] [client] [options]\n"
00093            "2: %s --service [ports] --client [ports] [options]\n"
00094            "\n"
00095            "1: Creates a pair of terminals and pipes them to each other\n"
00096            "[service] and [client] are port specification strings.\n"
00097            "\n"
00098            "2: Similar to 1, but it is possible to have multiple ports at either end\n"
00099            "of the connection.  [ports] is a list of port specification strings.\n"
00100            "\n"
00101            "Port specification: \n"
00102            "serial:devname,baudrate - Use a real serial port\n"
00103            "pty:path                - Create a pty, with symlink at given path\n"
00104            "path                    - Equivalent to pty:path\n"
00105            "\n"
00106            "With multiple ports, a char received on a given service port will be\n"
00107            "transmitted to all client ports, but not to other service ports. The\n"
00108            "converse holds for chars received on client ports.\n"
00109            "\n"
00110            "Options:\n"
00111            "--service [ports]   Specify additional service ports.  Each of [ports]\n"
00112            "                    is a port specification string.  If this option is\n"
00113            "                    specified multiple times, port lists will be added\n"
00114            "--client [ports]    Same as --service, but for client ports.\n"
00115            ,
00116            executable_name, executable_name);
00117 }
00118 
00119 
00120 void pass_data(vector<Port*>& from_ports, vector<Port*>& to_ports) {
00121     vector<Port*>::iterator from_iter, to_iter;
00122     for( from_iter = from_ports.begin(); from_iter < from_ports.end(); ++from_iter)
00123     {
00124         if ((*from_iter)->poll_revents() == POLLIN) {
00125             char buff[1024];
00126             int count = (*from_iter)->read(buff, sizeof(buff));
00127             for( to_iter = to_ports.begin();
00128                  to_iter < to_ports.end(); ++to_iter )
00129             {
00130                 (*to_iter)->write(buff, count);
00131             }
00132         }
00133     }
00134 }
00135 
00136 
00137 void update_blocking() 
00138 {
00139     poll(&pollfds[0], pollfds.size(), 1000);
00140     pass_data(service_ports, client_ports); 
00141     pass_data(client_ports, service_ports); 
00142 }
00143 
00144 
00145 int main(int argc, char *argv[]) {
00146     /* This program is often used as a daemon, with stdout piped to a log. Bash
00147      * seems to set pretty aggressive buffering on redirected stdout, which is
00148      * really annoying, since recent output ends up not being shown.  So, we
00149      * want to make sure stdout is using a relatively reasonable buffering 
00150      * policy (linebuffered, max 64 chars) */
00151     setvbuf(stdout, 0, _IOLBF, 64);
00152 
00153     if( argc < 3 ) {
00154         print_help(argv[0]);
00155         return 1;
00156     }
00157    
00158     /* Program parameters, to be parsed from options */
00159     vector<const char*> service_strs;
00160     vector<const char*> client_strs;
00161 
00162     // TODO: We've probably hit critical mass for optarg
00163     // (or making this a ROS node and using parameters...)
00164     int cur_arg = 1;
00165 
00166     /* If the first argument doesn't start with --, we assume that the first two
00167      * arguments are the service and client ports, respectively */
00168     if( strncmp(argv[1], "--", 2) ) {
00169         service_strs.push_back(argv[1]);
00170         client_strs.push_back(argv[2]);
00171         cur_arg = 3;
00172     }
00173 
00174     /* Now, handle any additional options */
00175     for(; cur_arg<argc; ++cur_arg) {
00176         if( !strcmp(argv[cur_arg], "--service") ) {
00177             /* Add all following args not starting with -- to the service list */
00178             while( (cur_arg+1 < argc) && strncmp(argv[cur_arg+1],"--",2) ) {
00179                 ++cur_arg;
00180                 if (argv[cur_arg][0] != '_') {
00181                     service_strs.push_back(argv[cur_arg]);
00182                 }
00183             }
00184         } else if( !strcmp(argv[cur_arg], "--client") ) {
00185             /* Add all following args not starting with -- to the client list */
00186             while( (cur_arg+1 < argc) && strncmp(argv[cur_arg+1],"--",2) ) {
00187                 ++cur_arg;
00188                 if (argv[cur_arg][0] != '_') {
00189                      client_strs.push_back(argv[cur_arg]);
00190                 }
00191             }
00192         } else {
00193             fprintf(stderr,"Unrecognized option: %s\n", argv[cur_arg]);
00194             exit(1);
00195         }
00196     }
00197 
00198     /* Check to make sure we have enough ports */
00199     if( service_strs.empty() ) {
00200         fprintf(stderr, "At least one service port must be specified!\n");
00201         exit(1);
00202     }
00203     if( client_strs.empty() ) {
00204         fprintf(stderr, "At least one client port must be specified!\n");
00205         exit(1);
00206     }
00207 
00208 
00209     /******* Begin actual initialization ********/
00210 
00211     // want to clean up and exit() on fatal signal:
00212     signal(SIGINT, handle_term);
00213     signal(SIGTERM, handle_term);
00214     signal(SIGABRT, handle_term);
00215 
00216     /* Open the ports, build pollfd array. */
00217     {
00218         pollfds.resize(service_strs.size() + client_strs.size());
00219         vector<struct pollfd>::iterator pollfd_iter = pollfds.begin();
00220         vector<const char*>::iterator str_iter;
00221 
00222         for(str_iter = service_strs.begin(); str_iter != service_strs.end(); ++str_iter, ++pollfd_iter) {
00223             service_ports.push_back(Port::create(*str_iter, &*pollfd_iter));
00224         }
00225         for(str_iter = client_strs.begin(); str_iter != client_strs.end(); ++str_iter, ++pollfd_iter) {
00226             client_ports.push_back(Port::create(*str_iter, &*pollfd_iter));
00227         }
00228     }
00229 
00230     while(1) {
00231         update_blocking();
00232     }
00233 }
00234 


kingfisher_bringup
Author(s): Mike Purvis, Ryan Gariepy
autogenerated on Sat Dec 28 2013 17:08:06