log_legal refactored and locking recovery managed
[brisk.git] / web / briskin5 / Obj / briskin5.phh
1 <?php
2 define(BRISKIN5_PLAYERS_N, 3);
3 define(BRISKIN5_MAX_PLAYERS, BRISKIN5_PLAYERS_N);
4 // define(BRISKIN5_SHM_MIN, (50000 * BRISKIN5_MAX_PLAYERS));
5 define(BRISKIN5_SHM_MIN, 32768);
6 define(BRISKIN5_SHM_MAX, (BRISKIN5_SHM_MIN + 1048576));
7 define(BRISKIN5_SHM_DLT, 32768);
8
9 class Briskin5 {
10   var $user;
11   var $table;
12   var $table_idx;
13   var $table_token;
14
15   var $comm; // commands for many people
16   var $step; // current step of the comm array
17   var $garbage_timeout;
18
19   var $the_end;
20   
21   var $tok;
22   var $shm_sz;
23
24   function Briskin5 (&$room, $table_idx, $table_token) {
25     $this->user = array();
26     $this->table = array();
27
28     $this->the_end = FALSE;
29     $this->shm_sz = BRISKIN5_SHM_MIN;
30     if (($this->tok = @ftok(FTOK_PATH."/table".$table_idx, "B")) == -1) {
31       echo "FTOK FAILED";
32       exit;
33     }
34
35     $user  =& $room->user;
36     $table =& $room->table[$table_idx];
37
38     log_wr("Briskin5 constructor");
39
40     for ($i = 0 ; $i < $table->player_n ; $i++) {
41       $user[$table->player[$i]]->table_token = $table_token;
42       $this->user[$i] =& User::spawn(&$user[$table->player[$i]], 0, $i);
43     }
44     $this->table[0] =& Table::spawn(&$table);
45     $this->table_idx = $table_idx;
46     $this->table_token = $table_token;
47     $this->garbage_timeout = 0;
48     
49     log_wr("Briskin5 constructor end");
50   }
51
52
53   function &get_user($sess, &$idx)
54   {
55     GLOBAL $PHP_SELF, $G_false;
56
57     if (validate_sess($sess)) {
58       for ($i = 0 ; $i < BRISKIN5_MAX_PLAYERS ; $i++) {
59         if (strcmp($sess, $this->user[$i]->sess) == 0) {
60           // find it
61           $idx = $i;
62           $ret = &$this->user[$i];
63           return ($ret);
64         }
65       }
66       log_main(sprintf("get_user: Wrong sess from page [%s]",$PHP_SELF));
67       // for ($i = 0 ; $i < BRISKIN5_MAX_PLAYERS ; $i++) 
68       // log_main(sprintf("get_user: Wrong sess compared with [%s]",$this->user[$i]->sess));
69     }
70     else {
71       log_main(sprintf("get_user: Wrong strlen [%s]",$sess));
72     }
73
74     return ($G_false);
75   }
76
77
78   function garbage_manager($force)
79   {
80     
81     /* Garbage collector degli utenti in timeout */
82     $ismod = FALSE;
83     $curtime = time();
84     if ($force || $this->garbage_timeout < $curtime) {
85       
86       for ($i = 0 ; $i < BRISKIN5_MAX_PLAYERS ; $i++) {
87         $user_cur = &$this->user[$i];
88         if ($user_cur->sess == "" || 
89             ($user_cur->stat == 'table' && ($user_cur->subst == 'shutdowned' || $user_cur->subst == 'shutdowner')))
90           continue;
91         
92         if ($user_cur->lacc + EXPIRE_TIME_RD < $curtime) { // Auto logout dell'utente
93           log_rd2($user_cur->sess." bin5 AUTO LOGOUT.");
94
95           if ($user_cur->stat == 'table') {
96             log_auth($user_cur->sess," bin5 Autologout session.");
97
98             /* SI DELEGA AL garbage_manager principale LA RIMOZIONE DELL'UTENTE 
99
100             $tmp_sess = $user_cur->sess;
101             $user_cur->sess = "";
102             step_unproxy($tmp_sess);
103             $user_cur->name = "";
104             $user_cur->the_end = FALSE;
105             
106             */
107
108             $this->table_wakeup(&$user_cur);
109           }
110         }
111       }
112       log_rd2($user_cur->sess." GARBAGE UPDATED!");
113       
114       $this->garbage_timeout = $curtime + GARBAGE_TIMEOUT;
115       $ismod = TRUE;
116     }
117
118     return ($ismod);
119   }
120
121
122
123
124   //
125   //  static functions
126   //
127   function &load_data($table_idx, $table_token = "") 
128   {
129     GLOBAL $G_false, $sess;
130     $doexit = FALSE;
131     $shm = FALSE;
132
133     log_wr("TABLE_IDX ".FTOK_PATH."/table".$table_idx);
134     
135     do {
136       if (($tok = @ftok(FTOK_PATH."/table".$table_idx, "B")) == -1) {
137         log_main("ftok failed");
138         $doexit = TRUE;
139         break;
140       }
141
142       if (($shm_sz = sharedmem_sz($tok)) == -1) {
143         log_main("shmop_open failed");
144         break;
145       }
146         
147       if (($shm = shm_attach($tok, $shm_sz)) == FALSE)
148         break;
149
150       if (($bri = @shm_get_var($shm, $tok)) == FALSE) 
151         break;
152
153       if ($table_token != "" && $bri->table_token != $table_token) {
154         log_wr("bri->table_token: ".$bri->table_token."table_token: ".$table_token);
155         
156         break;
157       }
158       $bri->tok = $tok;
159
160       shm_detach($shm);
161         
162       $ret = &$bri;
163       return ($ret); 
164     } while (FALSE);
165
166     if ($shm != FALSE)
167       shm_detach($shm);
168
169     log_wr("briskin5 load_data failed");
170     if ($doexit)
171       exit();
172     
173     return ($G_false);
174   }
175   
176
177
178   function save_data(&$bri) 
179   {
180     GLOBAL $sess;
181     
182     $ret =   FALSE;
183     $shm =   FALSE;
184     
185     log_main("SAVE BRISKIN5 DATA");
186     
187     if (!isset($bri->tok))
188       return (FALSE);
189     
190     while ($bri->shm_sz < BRISKIN5_SHM_MAX) {
191       if (($shm = shm_attach($bri->tok, $bri->shm_sz)) == FALSE)
192         break;
193       
194       if (@shm_put_var($shm, $bri->tok, $bri) != FALSE) {
195         shm_detach($shm);
196         return (TRUE);
197       }
198       if (shm_remove($shm) === FALSE) {
199         log_only("REMOVE FALLITA");
200         break;
201       }
202       shm_detach($shm);
203       $bri->shm_sz += BRISKIN5_SHM_DLT;
204     } 
205
206     log_crit("save data failed!");
207
208     if ($shm)
209       shm_detach($shm);
210     
211     return ($ret);
212   }
213
214
215
216   function destroy_data($table_idx) 
217   {
218     GLOBAL $sess;
219
220     $ret =   FALSE;
221     $shm =   FALSE;
222     log_main("DESTROY BRISKIN5 DATA");
223     
224     do {
225       log_main("DESTROY2 BRISKIN5 DATA");
226
227       if (($tok = @ftok(FTOK_PATH."/table".$table_idx, "B")) == -1) 
228         break;
229
230       if (($shm = @shmop_open($tok, 'a', 0, 0)) == FALSE)
231         break;
232       
233       if (shmop_delete($shm) == 0) {
234         log_only("REMOVE FALLITA ");
235         break;
236       }
237    
238       $shm = FALSE;
239       log_main("DESTROY2 BRISKIN5 DATA SUCCESS");
240       
241       // log_main("QUI CI ARRIVA [".$bri->user[0]->name."]");
242       $ret = TRUE;
243     } while (0);
244     
245     if ($shm)
246       shm_detach($shm);
247     
248     return ($ret);
249   }
250
251   function lock_data($table_idx)
252   {
253     GLOBAL $sess; 
254     
255     log_wr("LOCK_DATA ".FTOK_PATH."/table".$table_idx);
256     //  echo "LOCK: ".FTOK_PATH."/main";
257     //  exit;
258     // WARNING monitor this step
259     if (($tok = @ftok(FTOK_PATH."/table".$table_idx, "B")) == -1) {
260       return (FALSE);
261     }
262     // WARNING monitor this step
263     if (($res = @sem_get($tok)) == FALSE) {
264       return (FALSE);
265     }
266     if (sem_acquire($res)) {   
267       log_lock("LOCK table ".$table_idx."[res: ".$res."]");
268       return ($res);
269     }
270     else {
271       log_lock("LOCK table ".$table_idx.":FAILED");
272       return (FALSE);
273     }
274   }
275   
276   function unlock_data($res)
277   {
278     GLOBAL $sess; 
279     
280     log_lock("UNLOCK table [res: ".$res."]");
281
282     return (sem_release($res));
283   }
284
285
286   function chatt_send(&$user, $mesg)
287   {
288     if ($user->stat == 'table') {
289       $table = &$this->table[$user->table];
290     }
291     
292     $user_mesg = substr($mesg,6);
293     
294     $curtime = time();
295     
296     $dt = date("H:i ", $curtime);
297     if (strncmp($user_mesg, "/nick ", 6) == 0) {
298       log_main($user->sess." chatt_send BEGIN");
299
300       if (($name_new = validate_name(substr($user_mesg, 6))) == FALSE) {
301           $user->comm[$user->step % COMM_N] = "gst.st = ".($user->step+1)."; ";
302           $user->comm[$user->step % COMM_N] .= sprintf('chatt_sub("%s", [2, "%s"],"Il nickname deve contenere almeno una lettera dell\'alfabeto o una cifra.");', $dt, NICKSERV);
303           $user->step_inc();
304
305           return;
306       }
307       $user_mesg = "COMMAND ".$user_mesg;
308       // Search dup name
309       // change
310       // update local graph
311       // update remote graphs
312       for ($i = 0 ; $i < BRISKIN5_MAX_PLAYERS ; $i++) {
313         $user_cur = &$this->user[$i];
314         //      if ($user_cur->sess == '' || $user_cur->stat != 'room')
315         if ($user_cur->sess == '')
316           continue;
317         if ($user_cur->name == $name_new) {
318           $user->comm[$user->step % COMM_N] = "gst.st = ".($user->step+1)."; ";
319           $user->comm[$user->step % COMM_N] .= sprintf('chatt_sub("%s", [2, "%s"],"Nickname <b>%s</b> gi&agrave; in uso.%d");', $dt, NICKSERV, xcape($name_new), $this->table[$user->table]->auth_only == TRUE);
320           $user->step_inc();
321           break;
322         }
323       }
324       if ($i == BRISKIN5_MAX_PLAYERS) {
325         if ($user->flags & USER_FLAG_AUTH && strcasecmp($user->name,$name_new) != 0) {
326           if ($this->table[$user->table]->auth_only == TRUE) {
327             $user->comm[$user->step % COMM_N] = "gst.st = ".($user->step+1)."; ";
328             $user->comm[$user->step % COMM_N] .= sprintf('chatt_sub("%s", [2, "%s"],"<b>Non puoi cambiare nick a un tavolo per soli autenticati.</b>");', $dt, NICKSERV);
329             $user->step_inc();
330             return;
331           }
332           else {
333             $user->flags &= ~USER_FLAG_AUTH; // Remove auth if name changed
334           }
335         }
336     
337         $user->name = $name_new;
338
339         log_main($user->sess." chatt_send start set");
340         
341
342         for ($i = 0 ; $i < BRISKIN5_MAX_PLAYERS ; $i++) {
343           log_main($user->sess." chatt_send set loop");
344           
345           $user_cur = &$this->user[$i];
346           if ($user_cur->sess == '')
347             continue;
348           if ($user_cur->stat == 'room') {
349             if ($user->stat == 'room' && $user->subst == 'standup') {
350               $this->standup_update(&$user);
351             }
352             else if ($user->stat == 'room' && $user->subst == 'sitdown' ||
353                      $user->stat == 'table') {
354               log_main($user->sess." chatt_send pre table update");
355
356               $this->table_update(&$user);
357
358               log_main($user->sess." chatt_send post table update");
359             }
360           }
361           else if ($user_cur->stat == 'table' && $user_cur->table == $user->table) {
362             $table = &$this->table[$user->table];
363             
364             $user_cur->comm[$user_cur->step % COMM_N] = "gst.st = ".($user_cur->step+1)."; ";
365             $user_cur->comm[$user_cur->step % COMM_N] .= sprintf('set_names([%d, "%s"], [%d, "%s"], [%d, "%s"], [%d, "%s"], [%d, "%s"]); ',
366                       $this->user[$table->player[($user_cur->table_pos) % BRISKIN5_PLAYERS_N]]->flags,
367                       xcape($this->user[$table->player[($user_cur->table_pos) % BRISKIN5_PLAYERS_N]]->name),
368
369                       $this->user[$table->player[($user_cur->table_pos+1) % BRISKIN5_PLAYERS_N]]->flags,
370                       xcape($this->user[$table->player[($user_cur->table_pos+1) % BRISKIN5_PLAYERS_N]]->name),
371
372                       $this->user[$table->player[($user_cur->table_pos+2) % BRISKIN5_PLAYERS_N]]->flags,
373                       xcape($this->user[$table->player[($user_cur->table_pos+2) % BRISKIN5_PLAYERS_N]]->name),
374
375                       (BRISKIN5_PLAYERS_N == 3 ? 0:  $this->user[$table->player[($user_cur->table_pos+3) % BRISKIN5_PLAYERS_N]]->flags),
376                       (BRISKIN5_PLAYERS_N == 3 ? "" :  xcape($this->user[$table->player[($user_cur->table_pos+3) % BRISKIN5_PLAYERS_N]]->name)),
377
378                       (BRISKIN5_PLAYERS_N == 3 ? 0:  $this->user[$table->player[($user_cur->table_pos+4) % BRISKIN5_PLAYERS_N]]->flags),
379                       (BRISKIN5_PLAYERS_N == 3 ? "" :  xcape($this->user[$table->player[($user_cur->table_pos+4) % BRISKIN5_PLAYERS_N]]->name)));
380             if ($user_cur == $user) {
381               $itin = ($user->flags & USER_FLAG_AUTH ? "<i>" : "");
382               $itou = ($user->flags & USER_FLAG_AUTH ? "</i>" : "");
383               $user_cur->comm[$user_cur->step % COMM_N] .= sprintf('$("myname").innerHTML = "<b>%s%s%s</b>";', 
384                                                                    $itin, xcape($user->name,ENT_COMPAT,"UTF-8"), $itou);
385             }
386             $user_cur->step_inc();
387           }
388         }
389       }
390     }
391     else {
392       for ($i = 0 ; $i < ($user->stat == 'room' ? BRISKIN5_MAX_PLAYERS : BRISKIN5_PLAYERS_N) ; $i++) {
393         if ($user->stat == 'room') {
394           $user_cur = &$this->user[$i];
395           if ($user_cur->sess == '' || $user_cur->stat != 'room')
396             continue;
397         }
398         else {
399           $user_cur = &$this->user[$table->player[$i]];
400         }
401         
402         $user_cur->comm[$user_cur->step % COMM_N] = "gst.st = ".($user_cur->step+1)."; ";
403         $user_cur->comm[$user_cur->step % COMM_N] .= sprintf('chatt_sub("%s", [%d, "%s"],"%s");',
404                                                              $dt, $user->flags, xcape($user->name), xcape($user_mesg));
405         $user_cur->step_inc();
406       }
407       log_legal($curtime, $user, ($user->stat == 'room' ? 'room' : 'table '.$user->table),$user_mesg);
408     }
409   }
410
411   function table_wakeup(&$user)
412   {
413     $table = &$this->table[0];
414
415     log_main("BRISKIN5_WAKEUP begin function table  stat: ".$user->stat."  subst: ".$user->subst);
416
417     $curtime = time();
418
419     log_main("BRISKIN5_WAKEUP from table [".$user->table."] nplayers_n: ".$this->table[$user->table]->player_n);
420     
421     for ($i = 0 ; $i < $table->player_n ; $i++) {
422       $user_cur = &$this->user[$i];
423       log_main("PREIMPOST INLOOP name: ".$user_cur->name);
424       
425       if ($user_cur == $user)
426         $user_cur->subst = "shutdowner";
427       else
428         $user_cur->subst = "shutdowned";
429       $user_cur->laccwr = $curtime;
430
431       $ret = "gst.st = ".($user_cur->step+1)."; ";
432       $ret .= 'gst.st_loc++; the_end=true; window.onbeforeunload = null; window.onunload = null; document.location.assign("../index.php");|';
433
434       log_wr($user_cur->sess." BRISKIN5_WAKEUP: ".$ret);
435       $user_cur->comm[$user_cur->step % COMM_N] = $ret;
436       $user_cur->step_inc();
437     }
438
439     $this->the_end = TRUE;
440   }
441   
442   /*
443    *  If all players are freezed the room garbage_manager clean up table and users.
444    */ 
445   function is_abandoned() 
446   {
447     $is_ab = TRUE;
448     $curtime = time();
449
450     $table = &$this->table[0];
451
452     for ($i = 0 ; $i < $table->player_n ; $i++) {
453       $user_cur = &$this->user[$i];
454
455       if ($user_cur->lacc + (EXPIRE_TIME_RD * 2) >= $curtime) { 
456         $is_ab = FALSE;
457         break;
458       }
459     }
460
461     return ($is_ab);
462   }
463 } // end class Briskin5
464
465 function locshm_exists($tok)
466 {
467   // return (TRUE);
468
469   if (($id = @shmop_open($tok,"a", 0, 0)) == FALSE) {
470     log_main($tok." SHM NOT exists");
471
472     return (FALSE);
473   }
474   else {
475     shmop_close($id);
476     log_main($tok." SHM exists");
477
478     return (TRUE);
479   }
480     
481 }
482
483
484 ?>