PipeProcess.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This library is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU Lesser General Public License as published by    *
00007 * the Free Software Foundation; either version 2.1 of the License, or (at     *
00008 * your option) any later version.                                             *
00009 *                                                                             *
00010 * This library is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
00013 * for more details.                                                           *
00014 *                                                                             *
00015 * You should have received a copy of the GNU Lesser General Public License    *
00016 * along with this library; if not, write to the Free Software Foundation,     *
00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
00018 *******************************************************************************
00019 *                              SOFA :: Framework                              *
00020 *                                                                             *
00021 * Authors: M. Adam, J. Allard, B. Andre, P-J. Bensoussan, S. Cotin, C. Duriez,*
00022 * H. Delingette, F. Falipou, F. Faure, S. Fonteneau, L. Heigeas, C. Mendoza,  *
00023 * M. Nesme, P. Neumann, J-P. de la Plata Alcade, F. Poyer and F. Roy          *
00024 *                                                                             *
00025 * Contact information: contact@sofa-framework.org                             *
00026 ******************************************************************************/
00027 #include "PipeProcess.h"
00028 
00029 #ifdef WIN32
00030 #include <windows.h>
00031 #include <process.h>
00032 #include <sys/types.h>
00033 #include <sys/stat.h>
00034 #include <fcntl.h>
00035 #include <stdio.h>
00036 typedef int ssize_t;
00037 typedef HANDLE fd_t;
00038 typedef SOCKET socket_t;
00039 #else
00040 #include <sys/types.h>
00041 #include <sys/stat.h>
00042 #include <fcntl.h>
00043 #include <sys/wait.h>
00044 #include <unistd.h>
00045 #include <sys/socket.h>
00046 #include <netinet/in.h>
00047 #include <netdb.h> 
00048 typedef int fd_t;
00049 typedef int socket_t;
00050 #endif
00051 
00052 #include <cstring>
00053 #include <iostream>
00054 #include <sstream>
00055 
00056 #define BUFSIZE (64*1024-1)
00057 #define STEPSIZE (1024)
00058 //#define STEPSIZE BUFSIZE
00059 
00060 namespace sofa
00061 {
00062 
00063 namespace helper
00064 {
00065 
00066 namespace system
00067 {
00068 
00069 PipeProcess::PipeProcess()
00070 {
00071 }
00072 
00073 PipeProcess::~PipeProcess()
00074 {
00075 }
00081 bool PipeProcess::executeProcess(const std::string &command,  const std::vector<std::string> &args, const std::string &filenameStdin, std::string & outString, std::string & errorString)
00082 {
00083     std::string fileIN = filenameStdin;
00084 
00085     //Remove this line below when Windows will be able to read file as stdin
00086     fileIN = "";
00087     
00088     fd_t fds[2][2];
00089     
00090     //char eol = '\n';
00091     char** cargs;
00092     std::string newCommand(command);
00093     
00094     cargs = new char* [args.size()+2];
00095     cargs[0] = (char*)command.c_str();
00096     for (unsigned int i=1 ; i< args.size() + 1 ; i++)
00097         cargs[i] = (char*)args[i-1].c_str();
00098     cargs[args.size() + 1] = NULL;
00099 
00100     fd_t fdin;
00101     fd_t fdout;
00102     fd_t fderr;
00103     
00104 #ifdef WIN32
00105     fdin = GetStdHandle(STD_INPUT_HANDLE);
00106     
00107     fdout = GetStdHandle(STD_OUTPUT_HANDLE);
00108     fderr = GetStdHandle(STD_ERROR_HANDLE);
00109     
00110     for (unsigned int i=0 ; i< args.size() ; i++)
00111         newCommand += " " + args[i];
00112     
00113 #else
00114     fdin = 0;
00115     fdout = 1;
00116     fderr = 2;
00117 #endif
00118 
00119     outString = "";
00120     errorString = "";
00121     std::stringstream outStream;
00122     std::stringstream errorStream;
00123 
00124 #ifdef WIN32
00125     SECURITY_ATTRIBUTES saAttr;
00126     // Set the bInheritHandle flag so pipe handles are inherited. 
00127     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
00128     saAttr.bInheritHandle = TRUE; 
00129     saAttr.lpSecurityDescriptor = NULL;
00130     if (!CreatePipe(&fds[0][0],&fds[0][1],&saAttr,0) || !CreatePipe(&fds[1][0],&fds[1][1],&saAttr,0))
00131 #else
00132     if (pipe(fds[0]) || pipe(fds[1]))
00133 #endif
00134     {
00135         std::cerr << "pipe failed."<<std::endl;
00136         return false;
00137     }
00138 #ifdef WIN32
00139     HANDLE hFile = 0;
00140     if (fileIN != "")
00141         hFile = CreateFileA( (fileIN.c_str()),
00142                         GENERIC_READ,
00143                         FILE_SHARE_READ,
00144                         NULL,
00145                         OPEN_EXISTING,
00146                         FILE_ATTRIBUTE_NORMAL,
00147                         NULL);
00148     
00149     if (hFile == INVALID_HANDLE_VALUE) {
00150         std::cerr<<"failed to open file for stdin\n";
00151     }
00152 
00153     // Ensure that the read handle to the child process's pipe for STDOUT is not inherited.
00154     SetHandleInformation( fds[0][0], HANDLE_FLAG_INHERIT, 0);
00155     SetHandleInformation( fds[1][0], HANDLE_FLAG_INHERIT, 0);
00156     SetHandleInformation( fdin, HANDLE_FLAG_INHERIT, 1);
00157     PROCESS_INFORMATION piProcInfo; 
00158     STARTUPINFOA siStartInfo;
00159     ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
00160     ZeroMemory( &siStartInfo, sizeof(STARTUPINFOA) );
00161     siStartInfo.cb = sizeof(STARTUPINFOA); 
00162     if (fileIN != "")
00163         siStartInfo.hStdInput = hFile;
00164     else siStartInfo.hStdInput = fdin;
00165 
00166     siStartInfo.hStdOutput = fds[0][1];
00167     siStartInfo.hStdError = fds[1][1];
00168     siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
00169     if (!CreateProcessA(NULL, 
00170       (char*)newCommand.c_str(),       // command line 
00171       NULL,          // process security attributes 
00172       NULL,          // primary thread security attributes 
00173       TRUE,          // handles are inherited 
00174       0,             // creation flags 
00175       NULL,          // use parent's environment 
00176       NULL,          // use parent's current directory 
00177       &siStartInfo,  // STARTUPINFO pointer 
00178       &piProcInfo))  // receives PROCESS_INFORMATION 
00179     {
00180         std::cerr << "CreateProcess failed : "<<GetLastError()<<std::endl;
00181     return 1;
00182     }
00183 
00184     { // parent process
00185     //char inbuf[BUFSIZE];
00186     char buf[2][BUFSIZE];
00187     int nfill[2];
00188     CloseHandle(fds[0][1]);
00189     CloseHandle(fds[1][1]);
00190     unsigned long exit = 0;
00191     for (int i=0;i<2;i++)
00192         nfill[i] = 0;
00193     for(int i=0;;i++)
00194     {
00195         GetExitCodeProcess(piProcInfo.hProcess,&exit);      //while the process is running
00196         if (exit != STILL_ACTIVE)
00197         break;
00198         
00199         bool busy = false;
00200         for (int i=0;i<2;i++)
00201         {
00202             DWORD n = BUFSIZE-nfill[i];
00203             if (n > STEPSIZE) n = STEPSIZE;
00204             DWORD bread = 0;
00205             DWORD avail = 0;
00206             PeekNamedPipe(fds[i][0],buf[i]+nfill[i],n,&bread,&avail,NULL);
00207             
00208             if (bread>0)
00209             {
00210                 busy = true;
00211                 ReadFile(fds[i][0], buf[i]+nfill[i], n, &n, NULL);
00212                 nfill[i] += n;
00213                 {
00214                     // write line
00215                     if (i==0)
00216                         outStream << std::string(buf[i],nfill[i]);
00217                     else
00218                         errorStream << std::string(buf[i],nfill[i]);
00219 
00220                     //std::cout << std::string(buf[i],nfill[i]) << std::endl;
00221                     nfill[i] = 0;
00222                 }
00223             }
00224         }
00225         if (!busy)
00226         Sleep(0);
00227     }
00228     CloseHandle(fds[0][0]);
00229     CloseHandle(fds[1][0]);
00230     int status=exit;
00231     CloseHandle(piProcInfo.hProcess);
00232     CloseHandle(piProcInfo.hThread);
00233     //waitpid(pid,&status,0);
00234 #else
00235     int filefd = 0;
00236     if (fileIN != "")
00237         filefd = open(fileIN.c_str(),O_RDONLY);
00238     
00239     pid_t   pid;
00240     pid = fork();
00241     if (pid < 0)
00242     {
00243         std::cerr << "fork failed."<<std::endl;
00244         return false;
00245     }
00246     else if (pid == 0)
00247     { // child process
00248         close(fds[0][0]);
00249         close(fds[1][0]);
00250         // Remove standard input
00251         if (fileIN != "")
00252             dup2(filefd, 0);
00253         else dup2(open("/dev/null",O_RDONLY),0);
00254         
00255         dup2(fds[0][1],1);
00256         dup2(fds[1][1],2);
00257         
00258         int retexec = execvp(command.c_str(), cargs);
00259         std::cerr << "PipeProcess : ERROR: execlp( "<< command.c_str() << " " ;
00260         for (unsigned int i=0; i<args.size() + 1 ; i++)
00261             std::cerr << cargs[i] << " ";
00262         std::cerr << ") returned "<<retexec<<std::endl;
00263         return false;
00264     }
00265     else
00266     { // parent process
00267 //      char inbuf[BUFSIZE];
00268         char buf[2][BUFSIZE];
00269         int nfill[2];
00270         close(fds[0][1]);
00271         close(fds[1][1]);
00272         fd_set rfds;
00273         int nfd = fdin+1;
00274         FD_ZERO(&rfds);
00275         FD_SET(fdin, &rfds);
00276         int nopen = 0;
00277         for (int i=0;i<2;i++)
00278         {
00279             //fcntl(fds[i][0],F_SETFL, fcntl(fds[i][0],F_GETFL)|O_NONBLOCK );
00280             FD_SET(fds[i][0], &rfds);
00281             if (fds[i][0] >= nfd) nfd = fds[i][0]+1;
00282             // add prefixes
00283             //buf[i][0] = '0'+i;
00284             //nfill[i] = 1;
00285             nfill[i] = 0;
00286             ++nopen;
00287         }
00288         fd_set ready;
00289         ready = rfds;
00290         while (nopen> 0 && select(nfd, &ready, NULL, NULL, NULL)> 0)
00291         {
00292             //read stdin
00293 //          if (FD_ISSET(fdin, &ready))
00294 //          {
00295 //              int n = read(fdin, inbuf, BUFSIZE);
00296 //              if (n>0)
00297 //              {
00298 //                  writeall(2,inbuf,n);
00299 //              }
00300 //              else if (n==0)
00301 //              {
00302 //                  FD_CLR(fdin, &rfds);
00303 //              }
00304 //          }
00305             for (int i=0;i<2;i++)
00306             {
00307                 if (FD_ISSET(fds[i][0], &ready))
00308                 {
00309                     int n = BUFSIZE-nfill[i];
00310                     if (n> STEPSIZE) n = STEPSIZE;
00311                     n = read(fds[i][0], buf[i]+nfill[i], n);
00312                     
00313                     if (n == 0)
00314                     {
00315                         if (nfill[i]> 1)
00316                         {
00317                             buf[i][nfill[i]] = '\n';
00318                             if (i==0) 
00319                                 outStream << std::string(buf[i],nfill[i]+1);
00320                             else
00321                                 errorStream << std::string(buf[i],nfill[i]+1);
00322                         }
00323                         --nopen;
00324                         FD_CLR(fds[i][0], &rfds);   
00325                     }
00326                     else
00327                     {
00328                         nfill[i] += n;
00329                     
00330                         // write line
00331                         if (i==0)
00332                             outStream << std::string(buf[i],nfill[i]);
00333                         else
00334                             errorStream << std::string(buf[i],nfill[i]);
00335 
00336                         //std::cout << std::string(buf[i],nfill[i]) << std::endl;
00337                         nfill[i] = 0;
00338                     }
00339                     
00340                 }
00341             }
00342             ready = rfds;
00343         }
00344         close(fds[0][0]);
00345         close(fds[1][0]);
00346         int status=0;
00347         waitpid(pid,&status,0);
00348 
00349         if (fdout != 1)
00350             close(fdout);
00351         close(filefd);
00352 #endif
00353         
00354         
00355         outString = outStream.str();
00356         errorString = errorStream.str();
00357         return (status == 0);
00358     }
00359 }
00360 
00361 }
00362 }
00363 }
00364 

Generated on Sun Nov 23 02:29:30 2008 for Sofa by  doxygen 1.5.7.1