Jump to content

Unable to write to STDIN of C application using pipes created in PHP


skyprog

Recommended Posts

This is a server client web socket program, when client send "exe" command the server executes a C application.

The output of the c application is read from STDOUT by server and displayed on the client browser.

Now there is a C application that requires a user input(scanf), we saved the input in a txt file. We read the input

and write it to the stdin of the c program. The problem is that it seems that the C program is not accepting the input

that we are writting on the stdin. When i tried this code without any stream select it was working and displaying the sum of two numbers read from input file, but when i place it in stream select command its creating problem. My complete server code is  at the end.     

      a part of server code that is creating  child process on a client request

 

    if(strcmp($user_message, "exe") == 0 ) {
         echo "Executing a process\n";
          $cwd = '/var/www/html/test/websockets' ;
    
         $process = proc_open($exe_command, $descriptorspec, $pipes, $cwd);//creating child process
         sleep(1);
        
         if (is_resource($process))
         {
             echo "Process Created";
    
             $read_socks[] = $pipes[1];//add a descriptor
             $stdout = array($pipes[1]);//save stdout in a variable defined above
             $stdin  = array($pipes[0]);
    
             print_r ($stdout);
             print_r ($stdin);
          }
         }
         else
         {
           echo "Passing value to the C program".$user_message;
                                        
           //Read input.txt by line and store it in an array
           $input = array();
           $input = file('/var/www/html/test/websockets/input.txt');
    
         echo "INPUT";
         print_r($input);
         echo "\n";
    
         //Feed the input (hardcoded)
         $bytes = fwrite($stdin[0], "$input[0] $input[1]");
         echo "Bytes written:".$bytes;
                     sleep(1);
    
                 }
         }        
    }
add.c

    #include <stdio.h>

    int main(void)
    {
          int first, second;

          printf("Enter two integers > \n");
          scanf("%d", &first);
          scanf("%d", &second);
          printf("The two numbers are: %d  %d\n", first, second);
          printf("Output: %d\n", first+second);
    }
input.txt

 

    2

    4    

 

output

    

    Passing value to the C program3Array

    (

        [0] => Resource id #11

    )

 

    INPUTArray

    (

        [0] => 2

 

        [1] => 4

 

    )

 

    Bytes written:5

 

 

By doing ps I get

 

    root      1173  1164  0 12:08 pts/6    00:00:00 tclsh /usr/bin/unbuffer /var/www/html/test/websockets/./add

    root      1174  1173  0 12:08 pts/8    00:00:00 /var/www/html/test/websockets/./add

 

After bytes written the server is hanging there is no response from the C application i.e the addition result of 4+2.

Why there are two process of add i started 1 with proc open.

 

**complete server code**

 

         <?php
        execute_prog('unbuffer /var/www/html/test/websockets/./add');//unbuffer stdout
    function execute_prog($exe)
    {
            echo "[+execute_prog]";

            $host = 'localhost'; //host
            $port = '9000'; //port
            $null = NULL; //null var
                $read_socks;
                $new_client;


            $server = stream_socket_server("tcp://0.0.0.0:9000", $errno, $errorMessage);
            
            if ($server === false)
            {
                throw new UnexpectedValueException("Could not bind to socket: $errorMessage");
            }

            set_time_limit(1800);

            $exe_command = escapeshellcmd($exe);

            $descriptorspec = array(

                    0 => array("pipe", "r"),  // stdin -> for execution

                    1 => array("pipe", "w"),  // stdout -> for execution

                    2 => array("pipe", "w") // stderr

                );

        //     $process = proc_open($exe_command, $descriptorspec, $pipes);//creating child process
                                                           
    //         if (is_resource($process))
              {
                  $client_socks = array();
                          $read_socks = array($server);
                          $changed = array();
                          $stdout = NULL;
                          $stdin = NULL;

                while(1)
                {
                    //prepare readable sockets
                    $write  = NULL;
                    $err    = NULL;
                    $except = NULL;
                                $changed = $read_socks;//by refrence
    /*
                                echo "stdout:";
                                print_r ($stdout);
                    echo "\n";

                    echo "changed:";
                    print_r ($changed);
                    echo "\n";

                    echo "read sock:";
                    print_r ($read_socks);
                    echo "\n";
    */
                    if (false === ($num_changed_streams = stream_select($changed, $write, $except, 0)))
                    {
                        /* Error handling */
                                    echo "Errors\n";
                    }
                    else if ($num_changed_streams > 0)
                    {
                         /* At least on one of the streams something interesting happened */
                             echo "Data on ".$num_changed_streams." descriptor\n";

                                        if(in_array($stdout[0], $changed))
                         {
                             echo "Data on child process STDOUT\n";
                                                 
                                 $s = fgets($stdout[0]);

                             if( $s === false )
                                                 {
                                 // Hello program has finished.
                                 echo 'Finished', PHP_EOL;

                                 $s = NULL;
                                 //ob_flush();
                                 flush();

                                 // Close all descriptors and return...
                                                        // break;
                              }
                              else
                              {
                                 echo $s."</br>";

                                 //prepare data to be sent to client
                                 $response_text = mask(json_encode(array('type'=>'usermsg', 'name'=>$user_name, 'message'=>$s, 'color'=>$user_color)));
                                                      foreach ($read_socks as $sock)
                                                         {    
                                                           if(($sock != $server) && ($sock != $stdout))
                                                   fwrite($sock, $response_text, strlen($response_text));
                                                         }

                                 $s = NULL;
                                 //ob_flush();
                                 flush();
                             }

                         }
                                         else if(in_array($server, $changed))
                         {
                             //new client
                                           echo "New Connection\n";

                           $new_client = stream_socket_accept($server);

                           if ($new_client)
                           {
                              //print remote client information, ip and port number
                              echo 'Connection accepted from ' . stream_socket_get_name($new_client, true) . "n";
                                  $read_socks[] = $new_client;
                              echo "Now there are total ". count($read_socks) . " clients.n";
                           }

                                           $header = fread($new_client, 1024);//read data sent by the socket
                           perform_handshaking($header, $new_client, $host, $port); //perform websocket handshake

                           $ip = stream_socket_get_name($new_client, true);
                           $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' connected'))); //prepare json data
                                          fwrite($new_client,$response,strlen($response));

                           //delete the server socket from the read sockets
                           unset($changed[ array_search($server, $changed) ]);
                                
                                         }
                         else if($write)
                         {
                             echo "Data on child process STDIN\n";

                         }
                         else if($err)
                         {
                             echo "Data on child process STDERR\n";

                         }
                                         else
                         {
                                                 echo "Message from the client \n";
                             //message from existing client

                             foreach($changed as $sock)
                             {
                                 $data = fread($sock, 128);
                                                         //echo "Data read:".$data." From sock:".$sock."\n";

                                 if(!$data)
                                 {
                                     unset($client_socks[ array_search($sock, $client_socks) ]);
                                     @fclose($sock);
                                     echo "A client disconnected. Now there are total ". count($client_socks) . " clients.n";
                                     continue;
                                 }
                                                         else
                                 {
                                     $received_text = unmask($data); //unmask data
                                     $tst_msg = json_decode($received_text); //json decode
                                     $user_name = $tst_msg->name; //sender name
                                     $user_message = $tst_msg->message; //message text
                                     $user_color = $tst_msg->color; //color
                                                                 //echo "name:".$user_name." user mesg:".$user_message."\n";

                                      //prepare data to be sent to client
                                     $response_text = mask(json_encode(array('type'=>'usermsg', 'name'=>$user_name, 'message'=>$user_message, 'color'=>$user_color)));

                                     fwrite($sock, $response_text, strlen($response_text));
    //..................................................................................................................

                                                                 if(strcmp($user_message, "exe") == 0 )
                                                                 {
                                         echo "Executing a process\n";
                                          $cwd = '/var/www/html/test/websockets' ;

                                         $process = proc_open($exe_command, $descriptorspec, $pipes, $cwd);//creating child process
                                         sleep(1);
                                        
                                         if (is_resource($process))
                                         {
                                             echo "Process Created";

                                             $read_socks[] = $pipes[1];//add a descriptor
                                             $stdout = array($pipes[1]);//save stdout in a variable defined above
                                                                                 $stdin  = array($pipes[0]);

                                             print_r ($stdout);
                                                                                 print_r ($stdin);
                                          }
                                                                 }
                                                                 else
                                                                 {
                                                                     echo "Passing value to the C program".$user_message;
                                                                     print_r ($stdin);
                                         echo "\n";
                                                                     //$input = array($user_message);
                                        // fwrite($stdin[0],"$input[0]");//,strlen($user_message));   

                                         //Read input.txt by line and store it in an array
                                                                     $input = array();
                                         $input = file('/var/www/html/test/websockets/input.txt');
                                                                     echo "INPUT";
                                                                     print_r($input);
                                                                     echo "\n";

                                         //Feed the input (hardcoded)
                                         $bytes = fwrite($stdin[0], "$input[0] $input[1]");// $input[1]");
                                         echo "Bytes written:".$bytes;

                                                                 }
                                                         }        
                             }
                                         }

                        $num_changed_streams = 0;
                    }

                }

                        // close the listening socket
                        fclose($server);
                fclose($pipes[0]);
                fclose($pipes[1]);
                fclose($pipes[2]);
                echo "exitcode: ".proc_close($process)."\n";
            }    


        echo "[-execute_prog]";
    //    return $ret;
    }

     ?>
Any ideas how to solve this?

Thank you!

 

EDIT

 

The following code writes to the stdin of a C application but when i tried to integrate in the above client server its not working.

 

     <?php
     //descriptors to be handled by parent
     $descriptorspec = array(
            0 => array("pipe", "r"),
            1 => array("pipe", "w"),
            2 => array("file", "/var/www/html/websockets/error.txt", "a")
        );

        // define current working directory where files would be stored
        $cwd = '/var/www/html' ;

        $child_proc = escapeshellcmd("unbuffer /var/www/html/test/websockets/./add");
       // $process = proc_open('/var/www/html/websockets/add', $descriptorspec, $pipes);//creating child process
        $process = proc_open($child_proc, $descriptorspec, $pipes, $cwd);//creating child process
        sleep(1);

        if (is_resource($process))
        {

                //Read input.txt by line and store it in an array
                $input = file('/var/www/html/test/websockets/input.txt');

                //Feed the input (hardcoded)
                fwrite($pipes[0], "$input[0] $input[1]");

                fclose($pipes[0]);

                while ($s = fgets($pipes[1]))
                {
                    print $s."</br>";
                    flush();
                }

        ?>
Any guess why the code in the edit part is working where as when integrated in the client server application its output is not as expected. Edited by requinix
please use [code] tags when posting code
Link to comment
Share on other sites

Add a new line to the end of your input. The C program is probably waiting for a new line before processing the input, as that is the normal behavior.

$bytes = fwrite($stdin[0], "$input[0] $input[1]".PHP_EOL);
As for why the stand-alone code works without the new line, that is likely because you are closing the stream in that code which tells the child process there is no more input so it will process what it got.
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.