update TODO list
[brisk.git] / web / spush / brisk-spush.php
1 #!/usr/bin/php
2 <?php
3 /*
4  *  brisk - spush/brisk-spush.php
5  *
6  *  Copyright (C) 2012 Matteo Nastasi
7  *                          mailto: nastasi@alternativeoutput.it 
8  *                                  matteo.nastasi@milug.org
9  *                          web: http://www.alternativeoutput.it
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details. You should have received a
20  * copy of the GNU General Public License along with this program; if
21  * not, write to the Free Software Foundation, Inc, 59 Temple Place -
22  * Suite 330, Boston, MA 02111-1307, USA.
23  *
24  * TODO
25  *   index_wr.php::chat
26  *   index_wr.php::reload
27  *   index_wr.php::exit
28  *
29  *   setcookie (for tables only)
30  *   keepalive
31  *   chunked 
32  *   BUG - after restart index_rd.php receive from prev clients a lot of req
33  *   DONE/FROZEN - problema con getpeer (HOSTADDR)
34  *
35  *   DONE - index_rd.php porting
36  *   DONE - generic var management from internet
37  *   DONE - index.php auth part
38  */
39
40 $G_base = "../";
41
42 require_once("./sac-a-push.phh");
43 require_once("./brisk-spush.phh");
44 require_once($G_base."Obj/brisk.phh");
45 require_once($G_base."Obj/auth.phh");
46 // require_once("../Obj/proxyscan.phh");
47 require_once($G_base."index.php");
48 require_once($G_base."index_wr.php");
49 require_once($G_base."index_rd_ifra.php");
50 require_once($G_base."briskin5/Obj/briskin5.phh");
51
52 define('SITE_PREFIX', '/brisk/');
53
54 class SPUser {
55     var $id;
56     var $sess;
57     var $cnt;
58     var $sock;
59     
60     function SPUser($id)
61     {
62         $this->id = $id;
63         $this->cnt = -1;
64         $this->sock = NULL;
65     }
66
67     function enable($sock, $sess)
68     {
69         $this->sess = $sess;
70         $this->cnt = 0;
71         $this->sock = $sock;
72
73         return ($this->id);
74     }
75
76     function disable()
77     {
78         $this->cnt = -1;
79         $this->sock = NULL;
80     }
81
82     function is_enable()
83     {
84         return ($this->cnt < 0 ? FALSE : TRUE);
85     }
86
87     function sock_get()
88     {
89         return $this->sock;
90     }
91
92     function sock_set($sock)
93     {
94         $this->sock = $sock;
95     }
96
97     function id_get()
98     {
99         return $this->id;
100     }
101     
102     function sess_get()
103     {
104         return $this->sess;
105     }
106
107     function cnt_get()
108     {
109         return $this->cnt;
110     }
111
112     function cnt_inc()
113     {
114         return $this->cnt++;
115     }
116 }
117
118 function user_get_free($user_arr)
119 {
120     foreach ($user_arr as $i => $user) {
121         if (!$user->is_enable()) {
122             return ($user);
123         }
124     }
125     return FALSE;
126 }
127
128 function user_get_sess($user_arr, $sess)
129 {
130     foreach ($user_arr as $i => $user) {
131         printf("SESS: [%s]  cur: [%s]\n", $user->sess_get(), $sess);
132         if ($user->sess_get() == $sess) {
133             return ($user);
134         }
135     }
136     return FALSE;
137 }
138
139 function headers_render($header)
140 {
141     
142     $s = "";
143     $s .= "HTTP/1.1 200 OK\r\n";
144     if (!isset($header['Date']))
145         $s .= sprintf("Date: %s\r\n", date(DATE_RFC822));
146     if (!isset($header['Connection']))
147         $s .= "Connection: close\r\n";
148     if (!isset($header['Content-Type']))
149         $s .= "Content-Type: text/html\r\n";
150     foreach($header as $key => $value) {
151         $s .= sprintf("%s: %s\r\n", $key, $value);
152     }
153     $s .= "Mop: was/here\r\n";
154     $s .= "\r\n";
155
156     return ($s);
157 }
158
159
160 /*
161  *  Caching system using ob php system to cache old style pages
162  *  to a var and than send it with more calm
163  */
164 $G_headers = "";
165
166 function shutta()
167 {
168   log_rd2("SHUTTA [".connection_status()."] !");
169 }
170
171 register_shutdown_function('shutta');
172
173 /*
174  *  MAIN
175  */
176 $shutdown = FALSE;
177
178 function main()
179 {
180     GLOBAL $G_headers;
181     GLOBAL $shutdown;
182     $main_loop = TRUE;
183
184     /*
185      *  INIT
186      */
187
188     $FILE_SOCKET = "/tmp/brisk.sock";
189     $UNIX_SOCKET = "unix://$FILE_SOCKET";
190     $debug = 0;
191     $fixed_fd = 2;
192     $socks = array();
193
194     $blocking_mode = 0; // 0 for non-blocking
195
196     if (($room = Room::create()) == FALSE) {
197         log_crit("load_data failed");
198         return FALSE;
199     }
200
201     $s2u  = array();
202
203     $rndstr = "";
204     for ($i = 0 ; $i < 4096 ; $i++) {
205         $rndstr .= chr(mt_rand(65, 90));
206     }
207
208     if (file_exists($FILE_SOCKET)) {
209         unlink($FILE_SOCKET);
210     }
211     
212     $old_umask = umask(0);
213     if (($list = stream_socket_server($UNIX_SOCKET, $err, $errs)) === FALSE) {
214         exit(11);
215     }
216     umask($old_umask);
217
218     if (($in = fopen("php://stdin", "r")) === FALSE) {
219         exit(11);
220     }
221
222     stream_set_blocking($list, $blocking_mode); # Set the stream to non-blocking
223
224     while ($main_loop) {
225         echo "IN LOOP\n";
226         /* Prepare the read array */
227         if ($shutdown) 
228             $read   = array_merge(array("$in" => $in), $socks);
229         else
230             $read   = array_merge(array("$list" => $list, "$in" => $in), $socks);
231
232         if ($debug > 1) {
233             printf("PRE_SELECT\n");
234             print_r($read);
235         }
236         $write  = NULL;
237         $except = NULL;
238         $num_changed_sockets = stream_select($read, $write, $except, 1); // 0, 250000);
239         
240         if ($num_changed_sockets === FALSE) {
241             printf("No data in 5 secs");
242         } 
243         else if ($num_changed_sockets > 0) {
244             printf("num sock %d num_of_socket: %d\n", $num_changed_sockets, count($read));
245             if ($debug > 1) {
246                 print_r($read);
247             }
248             /* At least at one of the sockets something interesting happened */
249             foreach ($read as $i => $sock) {
250                 if ($sock === $list) {
251                     printf("NUOVA CONNEX\n");
252                     $new_unix = stream_socket_accept($list);
253                     $stream_info = "";
254                     $method      = "";
255                     $get         = array();
256                     $post        = array();
257                     $cookie      = array();
258                     if (($new_socket = ancillary_getstream($new_unix, $stream_info)) !== FALSE) {
259                         printf("RECEIVED HEADER:\n%s", $stream_info);
260                         $path = spu_process_info($stream_info, $method, $header, $get, $post, $cookie);
261                         printf("PATH: [%s]\n", $path);
262                         printf("M: %s\nHEADER:\n", $method);
263                         print_r($header);
264                         printf("GET:\n");
265                         print_r($get);
266                         printf("POST:\n");
267                         print_r($post);
268                         printf("COOKIE:\n");
269                         print_r($cookie);
270
271                         $addr = stream_socket_get_name($new_socket, TRUE);
272
273                         switch ($path) {
274                         case SITE_PREFIX:
275                         case SITE_PREFIX."index.php":
276                             $header_out = array();
277                             ob_start();
278                             index_main($room, $header_out, $addr, $get, $post, $cookie);
279                             $content = ob_get_contents();
280                             ob_end_clean();
281                             // printf("OUT: [%s]\n", $G_content);
282                             fwrite($new_socket, headers_render($header_out).$content);
283                             fclose($new_socket);
284                             break;
285                         case SITE_PREFIX."index_wr.php":
286                             $header_out = array();
287                             $addr = "";
288                             // $ret = socket_getpeername($new_socket, $addr);
289                             printf("RET: %s\n", $addr);
290                             // exit(123);
291                             ob_start();
292                             index_wr_main($room, $addr, $get, $post, $cookie);
293                             $content = ob_get_contents();
294                             ob_end_clean();
295                             
296                             // printf("OUT: [%s]\n", $G_content);
297                             fwrite($new_socket, headers_render($header_out).$content);
298                             fclose($new_socket);
299                             break;
300                         case SITE_PREFIX."index_rd_ifra.php":
301                             do {
302                                 if (!isset($cookie['sess'])) {
303                                     fclose($new_socket);
304                                     break;
305                                 }
306                                 if (($user = $room->get_user($cookie['sess'], $idx)) == FALSE) {
307                                     fclose($new_socket);
308                                     break;
309                                 }
310                                 if (($prev = $user->rd_socket_get()) != NULL) {
311                                     unset($s2u[intval($user->rd_socket_get())]);
312                                     unset($socks[intval($user->rd_socket_get())]);
313                                     fclose($user->rd_socket_get());
314                                     $user->rd_socket_set(NULL);
315                                 }
316
317                                 $header_out = array();
318                                 $body = "";
319                                 index_rd_ifra_init($room, $user, $header_out, $body, $get, $post, $cookie);
320                                 stream_set_blocking($new_socket, $blocking_mode); // Set the stream to non-blocking
321                                 fwrite($new_socket, headers_render($header_out).$body);
322                                 fflush($new_socket);
323
324                                 $s2u[intval($new_socket)] = $idx;
325                                 $socks[intval($new_socket)] = $new_socket;                                
326                                 $user->rd_socket_set($new_socket);
327                             } while (FALSE);
328
329                             break;
330                         }
331                             
332
333
334
335                         if (0 == 1) {
336                             /* TODO: here stuff to decide if it is old or new user */
337                             if (($user_cur = user_get_sess($user_a, $get['sess'])) != FALSE) {
338                                 /* close the previous socket */
339                                 unset($s2u[intval($user_cur->sock_get())]);
340                                 unset($socks[intval($user_cur->sock_get())]);
341                                 fclose($user_cur->sock_get());
342                                 /* assign the new socket */
343                                 $user_cur->sock_set($new_socket);
344                                 $id = $user_cur->id_get();
345                                 $s2u[intval($new_socket)] = $id;
346                                 $socks[intval($new_socket)] = $new_socket;
347                                 fwrite($new_socket, $rndstr);
348                                 fflush($new_socket);
349                             }
350                             else if (($user_cur = user_get_free($user_a)) != FALSE) {
351                                 stream_set_blocking($new_socket, $blocking_mode); // Set the stream to non-blocking
352                                 $socks[intval($new_socket)] = $new_socket;
353
354                                 $id = $user_cur->id_get();
355                                 $user_a[$id]->enable($new_socket, $get['sess']);
356                                 printf("s2u: ci passo %d\n", intval($new_socket));
357                                 $s2u[intval($new_socket)] = $id;
358
359                                 fwrite($new_socket, $rndstr);
360                                 fflush($new_socket);
361                             }
362                             else {
363                                 printf("Too many opened users\n");
364                                 fclose($new_socket);
365                             }
366                         }
367                     }
368                     else {
369                         printf("WARNING: ancillary_getstream failed\n");
370                     }
371                 }
372                 else {
373                     if (($buf = fread($sock, 512)) === FALSE) {
374                         printf("error read\n");
375                         exit(123);
376                     }
377                     else if (strlen($buf) === 0) {
378                         if ($sock === $list) {
379                             printf("Arrivati %d bytes da list\n", strlen($buf));
380                         }
381                         else if ($sock === $in) {
382                             printf("Arrivati %d bytes da stdin\n", strlen($buf));
383                         }
384                         else {
385                             // $user_a[$s2u[intval($sock)]]->disable();
386                             if ($room->user[$s2u[intval($sock)]]->rd_socket_get() != NULL) {
387                                 $room->user[$s2u[intval($sock)]]->rd_socket_set(NULL);
388                             }
389                             unset($socks[intval($sock)]);
390                             unset($s2u[intval($sock)]);
391                             fclose($sock);
392                         }
393                         if ($debug > 1) {
394                             printf("post unset\n");
395                             print_r($socks);
396                         }
397                     }
398                     else {
399                         if ($debug > 1) {
400                             print_r($read);
401                         }
402                         if ($sock === $list) {
403                             printf("Arrivati %d bytes da list\n", strlen($buf));
404                         }
405                         else if ($sock === $in) {
406                             printf("Arrivati %d bytes da stdin\n", strlen($buf));
407                         }
408                         else {
409                             $key = array_search("$sock", $socks);
410                             printf("Arrivati %d bytes dalla socket n. %d\n", strlen($buf), $key);
411                         }
412                     }
413                 }
414             }
415         }
416
417
418
419
420         foreach ($socks as $k => $sock) {
421             if (isset($s2u[intval($sock)])) {
422                 $body = "";
423                 
424
425                 $body = "";
426                 $user = $room->user[$s2u[intval($sock)]];
427                 index_rd_ifra_main($room, $user, $body);
428                 if ($body == "" && $user->rd_tout_is_expired($curtime)) {
429                     $body = index_rd_ifra_keepalive($user);
430                 }
431
432                 if ($body != "") {
433                     echo "SPIA: [".substr($body, 0, 60)."...]\n";
434                     fwrite($sock, $body);
435                     fflush($sock);
436                     $user->rd_tout_reset($curtime);
437                 }
438
439                 // close socket after a while to prevent client memory consumption
440                 if ($user->rd_endtime_is_expired($curtime)) {
441                     // $user_a[$s2u[intval($sock)]]->disable();
442                     if ($room->user[$s2u[intval($sock)]]->rd_socket_get() != NULL) {
443                         $room->user[$s2u[intval($sock)]]->rd_socket_set(NULL);
444                     }
445                     unset($socks[intval($sock)]);
446                     unset($s2u[intval($sock)]);
447                     fclose($sock);
448                 }
449             }
450         }
451     }
452     
453     exit(0);
454 }
455
456 main();
457 ?>