add cmd unix socket with 'userauth' command implemented, incomplete usermgmt page...
[brisk.git] / web / Obj / sac-a-push.phh
index 502670d..b184fb4 100644 (file)
@@ -25,6 +25,9 @@
 define('SITE_PREFIX', '/brisk/');
 define('SITE_PREFIX_LEN', 7);
 
+define('DIRECT_ST_READ',  1);
+define('DIRECT_ST_WRITE', 2);
+
 declare(ticks = 1);
 
 function global_dump()
@@ -221,6 +224,14 @@ function headers_render($header, $len)
     }
     else if (isset($header['HTTP-Response'])) {
         $s = sprintf("HTTP/1.1 %s\r\n", $header['HTTP-Response']);
+        foreach($header as $key => $value) {
+            if (strtolower($key) == "http-response")
+                continue;
+            $s .= sprintf("%s: %s\r\n", $key, $value);
+        }
+        if ($len >= 0) {
+            $s .= sprintf("Content-Length: %ld\r\n", $len);
+        }
     }
     else {
         $s = "HTTP/1.1 200 OK\r\n";
@@ -392,12 +403,15 @@ class Sac_a_push {
     
     var $file_socket;
     var $unix_socket;
+    var $direct_socket;   // socket where read direct commands
     var $socks;
     var $s2u;             // user associated with input socket
     var $s2p;             // pending page associated with input socket
     var $pending_pages;
+    var $is_daemon;
 
-    var $list;
+    var $list_web;
+    var $list_cmd;
     var $in;
 
     var $debug;
@@ -438,18 +452,24 @@ class Sac_a_push {
         }
     }
 
-    static function create(&$app, $sockname, $debug, $blocking_mode)
+    static function create(&$app, $sockname, $debug, $blocking_mode, $argv)
     {        
         $thiz = new Sac_a_push();
         
         $thiz->app = $app;
         $thiz->file_socket = $sockname;
         $thiz->unix_socket = "unix://$sockname";
+        $thiz->direct_socket = "unix://${sockname}2";
         $thiz->debug = $debug;
         $thiz->socks = array();
         $thiz->s2u  = array();
         $thiz->s2p  = array();
         $thiz->pending_pages = array();
+        $thiz->is_daemon = FALSE;
+
+        if (array_search("-d", $argv) !== FALSE || array_search("--daemon", $argv) !== FALSE) {
+            $thiz->is_daemon = TRUE;
+        }
 
         // create a couple of sockets for control management
         if (($sockpair = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM,
@@ -476,13 +496,20 @@ class Sac_a_push {
         if (file_exists($thiz->file_socket)) {
             unlink($thiz->file_socket);
         }
+        if (file_exists($thiz->file_socket."2")) {
+            unlink($thiz->file_socket."2");
+        }
     
         $old_umask = umask(0);
-        if (($thiz->list = stream_socket_server($thiz->unix_socket, $err, $errs)) === FALSE) {
+        if (($thiz->list_web = stream_socket_server($thiz->unix_socket, $err, $errs)) === FALSE) {
+            return (FALSE);
+        }
+        if (($thiz->list_cmd = stream_socket_server($thiz->direct_socket, $err, $errs)) === FALSE) {
             return (FALSE);
         }
         umask($old_umask);
-        stream_set_blocking($thiz->list, $thiz->blocking_mode); # Set the stream to non-blocking
+        stream_set_blocking($thiz->list_web, $thiz->blocking_mode); # Set the stream to non-blocking
+        stream_set_blocking($thiz->list_cmd, $thiz->blocking_mode); # Set the stream to non-blocking
 
         if (($thiz->in = fopen("php://stdin", "r")) === FALSE) {
             return(FALSE);
@@ -603,6 +630,7 @@ class Sac_a_push {
         GLOBAL $G_splash_w, $G_topbanner, $G_with_donors, $G_with_poll;
         GLOBAL $G_with_sidebanner, $G_with_sidebanner2, $G_with_splash;
         GLOBAL $G_with_topbanner;
+        GLOBAL $G_tos_vers, $G_tos_fname, $G_tos_dtsoft, $G_tos_dthard, $G_tos_idx, $G_doc_path;
 
         if ($this->main_loop) {
             return (FALSE);
@@ -611,6 +639,7 @@ class Sac_a_push {
         $this->main_loop = TRUE;
         
         while ($this->main_loop) {
+            $this->app->sess_cur_set(FALSE);
             $this->curtime = time();
             fprintf(STDERR, "IN LOOP: Current opened: %d  pending_pages: %d\n", count($this->socks), count($this->pending_pages));
             
@@ -619,9 +648,16 @@ class Sac_a_push {
             /* if ($shutdown)  */
             /*     $read   = array_merge(array("$in" => $in), $socks); */
             /* else */
-            $read   = array_merge(array(intval($this->list) => $this->list, intval($this->in) => $this->in,
-                                        intval(static::$cnt_slave) => static::$cnt_slave),
-                                  $this->socks);
+            $pre_read = array_merge(array(intval($this->list_web) => $this->list_web,
+                                          intval($this->list_cmd) => $this->list_cmd,
+                                          intval(static::$cnt_slave) => static::$cnt_slave),
+                                    $this->socks);
+            if ($this->is_daemon == FALSE) {
+                $read = array_merge($pre_read, array(intval($this->in) => $this->in));
+            }
+            else {
+                $read = $pre_read;
+            }
             
             if ($this->debug > 1) {
                 printf("PRE_SELECT\n");
@@ -648,9 +684,9 @@ class Sac_a_push {
                     if (!is_resource($sock)) {
                         continue;
                     }
-                    if ($sock === $this->list) {
+                    if ($sock === $this->list_web) {
                         printf("NUOVA CONNEX\n");
-                        if (($new_unix = stream_socket_accept($this->list)) == FALSE) {
+                        if (($new_unix = stream_socket_accept($this->list_web)) == FALSE) {
                             printf("SOCKET_ACCEPT FAILED\n");
                             continue;
                         }
@@ -695,18 +731,31 @@ class Sac_a_push {
                             printf("WARNING: ancillary_getstream failed\n");
                         }
                     }
-                    else {
+                    else if ($sock === $this->list_cmd) {
+                        printf("NUOVA DIRECT CONNEX\n");
+                        if (($new_unix = stream_socket_accept($this->list_cmd)) == FALSE) {
+                            printf("SOCKET_ACCEPT FAILED\n");
+                            continue;
+                        }
+                        stream_set_blocking($new_unix, $this->blocking_mode);
+                        $this->direct_mgmt($new_unix);
+                    } // not socket_list nor socket_list_cmd
+                    else {  // already opened socket
                         $buf = fread($sock, 4096);
                         // if socket is closed
-                        if ($buf == FALSE || mb_strlen($buf, "ASCII") == 0) {
+                        if ($buf == FALSE || feof($sock)) {
                             // close socket case
                             if ($buf == FALSE) {
-                                printf("ERROR READING\n");
+                                printf("INFO: read return false\n");
                             }
-                            if ($sock === $this->list) {
+                            if ($sock === $this->list_web) {
                                 printf("Arrivati %d bytes da list\n", mb_strlen($buf, "ASCII"));
                                 return(21);
                             }
+                            else if ($sock === $this->list_cmd) {
+                                printf("Arrivati %d bytes da list_cmd\n", mb_strlen($buf, "ASCII"));
+                                return(23);
+                            }
                             else if ($sock === $this->in || $sock === static::$cnt_slave) {
                                 printf("Arrivati %d bytes da stdin\n", mb_strlen($buf, "ASCII"));
                                 return(22);
@@ -716,6 +765,10 @@ class Sac_a_push {
                                 if (isset($this->s2u[$id])) {
                                     // $user_a[$s2u[$id]]->disable();
                                     if ($this->s2u[$id]->rd_socket_get() != NULL) {
+                                        // try to send close frame (for websocket)
+                                        $clo = $this->s2u[$id]->stream_close();
+                                        $clo_l = mb_strlen($clo, "ASCII");
+                                        @fwrite($sock, $clo, $clo_l);
                                         $this->s2u[$id]->rd_socket_set(NULL);
                                     }
                                     unset($this->s2u[$id]);
@@ -728,14 +781,17 @@ class Sac_a_push {
                                 printf("post unset\n");
                                 print_r($this->socks);
                             }
-                        }
-                        else {
+                        }  // if ($buf == FALSE || mb_strlen($buf, "ASCII") == 0) {
+                        else { // data on the socket
                             if ($this->debug > 1) {
                                 print_r($read);
                             }
-                            if ($sock === $this->list) {
+                            if ($sock === $this->list_web) {
                                 printf("Arrivati %d bytes da list\n", mb_strlen($buf, "ASCII"));
                             }
+                            else if ($sock === $this->list_cmd) {
+                                printf("Arrivati %d bytes da list_cmd\n", mb_strlen($buf, "ASCII"));
+                            }
                             else if ($sock === $this->in || $sock === static::$cnt_slave) {
                                 printf("Arrivati %d bytes da stdin\n", mb_strlen($buf, "ASCII"));
                                 $line = trim($buf);
@@ -744,7 +800,7 @@ class Sac_a_push {
 
                                     global_dump();
                                 }
-                                else if ($line == "shutdown") {
+                                else if ($line == "shutdown" || $line == "sd") {
                                     if ($this->app->dump_data()) {
                                         return(0);
                                     }
@@ -753,7 +809,7 @@ class Sac_a_push {
                                     }
                                 }
                             }
-                            else {
+                            else {  // data arrived from not special socket
                                 $key = array_search("$sock", $this->socks);
                                 fprintf(STDERR, "Arrivati %d bytes dalla socket n. %d\n", mb_strlen($buf, "ASCII"), $key);
                                 if (isset($this->s2p[$id])) {
@@ -790,7 +846,6 @@ class Sac_a_push {
                         if (!strncmp($path, SITE_PREFIX, SITE_PREFIX_LEN)) {
                             $rret = $this->app->request_mgr($this, $header, $header_out, $new_socket, substr($path, SITE_PREFIX_LEN), $addr, $get, $post, $cookie);
                         }
-                        fprintf(STDERR, "\n\n DI QUI PASSA [%s]\n\n", $rret);
                         if ($rret == FALSE) {
                             // FIXME: manage 404 !!!
                             printf("TODO: fix unknown page\n");
@@ -849,7 +904,7 @@ class Sac_a_push {
                         // echo "SPIA: [".substr($response, 0, 60)."...]\n";
                         // echo "SPIA: [".$response."]\n";
                         $response_l = mb_strlen($response, "ASCII");
-                        $wret = @fwrite($sock, $response);
+                        $wret = @fwrite($sock, $response, $response_l);
                         if ($wret < $response_l) {
                             printf("TROUBLE WITH FWRITE: %d\n", $wret);
                             $user->rd_cache_set(mb_substr($response, $wret, $response_l - $wret, "ASCII"));
@@ -868,14 +923,99 @@ class Sac_a_push {
                         }
                         unset($this->socks[$id]);
                         unset($this->s2u[$id]);
+                        $clo = $user->stream_close();
+                        $clo_l = mb_strlen($clo, "ASCII");
+                        @fwrite($sock, $clo, $clo_l);
                         fclose($sock);
                         printf("CLOSE ON LOOP\n");
                     }
-                }
+                }  // if (isset($this->s2u[$id]...
             }  // foreach ($this->socks...
             printf("\n");
         }  // while (...
     }  // function run(...
-}
 
+    function direct_command($cmdstr)
+    {
+        GLOBAL $G_alarm_passwd;
+
+        $cmd = cmd_deserialize($cmdstr);
+
+        if (!isset($cmd['cmd'])) {
+            return cmd_return(500, 'no cmd found');
+        }
+        // "cmd" => "userauth", "sess" => 'xxxxxxxxxxx', 'private' => 'it_must_be_correct',
+        //           'the_end' => 'true' );
+        // cmd=userauth&sess=52d796ac08c47&private=yourpasswd192.168.122.152d796ac08c47&the_end=true
+        if ($cmd['cmd'] == 'userauth') {
+            if (!isset($cmd['sess']) || !isset($cmd['private'])) {
+                return cmd_return(401, 'malformed cmd');
+            }
+            $idx = -1;
+            if (($user = $this->app->get_user($cmd['sess'], &$idx)) == FALSE)
+                return cmd_return(402, 'user not found');
+
+            if (($user->flags & USER_FLAG_TY_ADMIN) == 0x00)
+                return cmd_return(403, 'permission denied');
+
+            if (md5($G_alarm_passwd.$user->ip.$user->sess) != $cmd['private'])
+                return cmd_return(404, 'authentication failed ['.$cmd['private'].']['.$G_alarm_passwd.$user->ip.$user->sess.']');
+
+            return cmd_return(200, 'success');
+        }
+
+        return cmd_return(501, 'no cmd found');
+    }
+
+    function direct_mgmt($socket)
+    {
+        printf("DIRECT: begin\n");
+        $st = DIRECT_ST_READ;
+        $cmd_all = "";
+        $endtime = $this->curtime + 3;
+
+        while(time() <= $endtime) {
+            printf("DIRECT: init loop %d\n", $st);
+            if ($st == DIRECT_ST_READ) {
+                $buf = fread($socket, 4096);
+                if ($buf == FALSE && feof($socket)) {
+                    break;
+                }
+                else if ($buf != FALSE && strlen($buf) > 0) {
+                    $cmd_all .= $buf;
+
+                    if (substr(trim($cmd_all), -13) == "&the_end=true") {
+                        $output_arr = $this->direct_command($cmd_all);
+                        $output = cmd_serialize($output_arr);
+                        $output_cur = 0;
+                        $output_len = mb_strlen($output, "ASCII");
+                        $st = DIRECT_ST_WRITE;
+                        continue;
+                    }
+                }
+            }
+            else if ($st == DIRECT_ST_WRITE)  {
+                $ret = fwrite($socket, $output, $output_len);
+                if ($ret === FALSE) {
+                    if (feof($socket)) {
+                        break;
+                    }
+                }
+                else if ($ret > 0 && $ret < $output_len) {
+                    $output = substr($output, -($output_len - $ret));
+                    $output_len -= $ret;
+                    continue;
+                }
+                else if ($ret == $output_len) {
+                    fclose($socket);
+                    return TRUE;
+                }
+            }
+            usleep(10000);
+        }
+
+        fclose($socket);
+        return FALSE;
+    }
+} // class Sac_a_push
 ?>