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