00001 #include "ExecutableCommPort.h"
00002 #include <sys/types.h>
00003 #include <sys/socket.h>
00004 #include <sys/wait.h>
00005 #include <unistd.h>
00006
00007 using namespace std;
00008
00009 const std::string ExecutableCommPort::autoRegisterExecutableCommPort = CommPort::getRegistry().registerType<ExecutableCommPort>("ExecutableCommPort");
00010
00011 ExecutableCommPort::~ExecutableCommPort() {
00012 if(opened>0) {
00013 cerr << "Connection still open in ExecutableCommPort destructor" << endl;
00014 command.removePrimitiveListener(this);
00015 shell.removePrimitiveListener(this);
00016 }
00017 if(!isChildRunning())
00018 return;
00019 cerr << "ExecutableCommPort destructing, but child is still running... waiting 3 seconds" << endl;
00020 if(waitChild(3000,500))
00021 return;
00022 cerr << "ExecutableCommPort child is STILL running... sending interrupt signal" << endl;
00023 if(kill(child,SIGINT)==-1) {
00024 perror("ExecutableCommPort unable to kill child");
00025 return;
00026 }
00027 if(waitChild(2000,500))
00028 return;
00029 cerr << "ExecutableCommPort child is STILL running... sending kill signal and moving on..." << endl;
00030 if(kill(child,SIGKILL)==-1) {
00031 perror("ExecutableCommPort unable to kill child");
00032 return;
00033 }
00034 }
00035
00036 bool ExecutableCommPort::open() {
00037 if(opened++>0)
00038 return true;
00039 command.addPrimitiveListener(this);
00040 shell.addPrimitiveListener(this);
00041
00042 int s2c[2];
00043 int c2s[2];
00044 if(pipe(s2c)==-1) {
00045 perror("ERROR: ExecutableCommPort could not open simulator to child pipe");
00046 return false;
00047 }
00048 if(pipe(c2s)==-1) {
00049 perror("ERROR: ExecutableCommPort could not open child to simulator pipe");
00050 ::close(s2c[0]);
00051 ::close(s2c[1]);
00052 return false;
00053 }
00054
00055 child = fork();
00056 if(child==-1) {
00057 perror("ERROR: ExecutableCommPort could not fork to launch executable");
00058 ::close(s2c[0]);
00059 ::close(s2c[1]);
00060 ::close(c2s[0]);
00061 ::close(c2s[1]);
00062 return false;
00063 }
00064
00065 if(child==0) {
00066
00067 ::close(s2c[WRITEPIPE]);
00068 ::close(c2s[READPIPE]);
00069
00070 ::close(STDIN_FILENO);
00071 if(::dup2(s2c[READPIPE],STDIN_FILENO)==-1)
00072 perror("ERROR: ExecutableCommPort could not dup2 the child's input to stdin");
00073 ::close(s2c[READPIPE]);
00074
00075 ::close(STDOUT_FILENO);
00076 if(::dup2(c2s[WRITEPIPE],STDOUT_FILENO)==-1)
00077 perror("ERROR: ExecutableCommPort could not dup2 the child's output to stdout");
00078 ::close(c2s[WRITEPIPE]);
00079
00080
00081 execlp(shell.c_str(), shell.c_str(), "-c", command.c_str(), NULL);
00082
00083
00084 perror("ERROR: ExecutableCommPort could not launch the executable!");
00085 ::close(STDIN_FILENO);
00086 ::close(STDOUT_FILENO);
00087 _exit(EXIT_FAILURE);
00088
00089 } else {
00090
00091 ::close(s2c[READPIPE]);
00092 ::close(c2s[WRITEPIPE]);
00093 rbuf.adoptFD(c2s[READPIPE]);
00094 wbuf.adoptFD(s2c[WRITEPIPE]);
00095 }
00096 return true;
00097 }
00098
00099 bool ExecutableCommPort::close() {
00100 if(opened==0)
00101 std::cerr << "Warning: ExecutableCommPort close() without open()" << std::endl;
00102 if(--opened>0)
00103 return false;
00104 command.removePrimitiveListener(this);
00105 shell.removePrimitiveListener(this);
00106 rbuf.close();
00107 wbuf.close();
00108 return true;
00109 }
00110
00111 void ExecutableCommPort::plistValueChanged(const plist::PrimitiveBase& pl) {
00112 if(&pl==&command || &pl==&shell) {
00113 if(opened>0) {
00114 unsigned int tmp=opened;
00115 opened=1;
00116 close();
00117 open();
00118 opened=tmp;
00119 }
00120 } else {
00121 std::cerr << "Unhandled value change in " << getClassName() << ": " << pl.get() << std::endl;
00122 }
00123 }
00124
00125 bool ExecutableCommPort::waitChild(unsigned int t, unsigned int p) {
00126 if(!isChildRunning())
00127 return true;
00128 for(unsigned int x=0; x<t; x+=p) {
00129 usleep(p*1000);
00130 if(!isChildRunning())
00131 return true;
00132 }
00133 return false;
00134 }
00135
00136 bool ExecutableCommPort::isChildRunning() const {
00137 if(child==0)
00138 return false;
00139 int status=0;
00140 int ret=waitpid(child,&status,WNOHANG);
00141 if(ret==-1) {
00142 perror("ExecutableCommPort unable to check child status, waitpid");
00143 return false;
00144 }
00145 if(ret==0)
00146 return false;
00147 if(WIFEXITED(status) || WIFSIGNALED(status))
00148 return false;
00149 return true;
00150 }
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161