Logout button in popup window works but user gets no feedback
-
But it does… try this...
in the LAN enable the captive portal. Make sure that the anti-lockout rule is in place which should allow connectivity to the box even if the captive portal is enabled.
Ssh to the box and spawn a shell... You should be able to get in because the web anti-lock rule allows you in. Fire up the a web browser and try to go to a website... You should see the captive protal login. Login... now logout...
you will notice that your ssh session will die... it will just hang there. The socket is not closed properly to the shell does not see that there has been a disconnect. IP packets to the box are dropped...
you have to do a ~. to disconnect and then you can ssh back to the box.
I believe the same thing is happening to the client browser. If you execute a logout page (not using the popup) which does a POST to index.php you will notice that the browser will just site there waiting... If you run firebug you will see that the HTML logout mesg does make it to the browser but since the socket is never closes and IP packets are just being dropped by the box the browser just goes into a "wait"... This happens in all browsers that I have tested.
Mozilla is nice because it will display the HTML text as it arrives so even though it goes into a wait state the "Disconnecting..." mesg gets displayed. Safari and other webkit friends do not display the text although I have confirmed that they have received it.
I am about to do more testing on this.. My approach is to move the disconnect code to a shell script and then execute it with mwexe_bg and then continue with an exit in index.php. The shell script will sleep for 1 second and then execute the php code to do the disconnect...
I will let you know how that test turns out. If my theory is correct the logout button should start to work properly since the HTML disconnect text is sent to the browser and the socket is closed before ipfw is called to close things off.
--luis
-
and guess what… my theory was correct and the following works beautifully and fixes the logout issue on ** ALL ** browsers including the popup logout window.
Here is what I did... i created the following file in /usr/local/captiveportal/captiveportal-disconnect.php
#!/usr/local/bin/php -f
require_once("functions.inc");
global $g, $config;$sessionid = $argv[1];
$logoutReason = $argv[2];
$term_cause = $argv[3];if ( $argc != 4 || $sessionid == "" || logoutReason == "" || $term_cause == "" )
exit;$cplock = lock('captiveportal');
/* read database */
$cpdb = captiveportal_read_db();$radiusservers = captiveportal_get_radius_servers();
/* find entry */
for ($i = 0; $i < count($cpdb); $i++) {
if ($cpdb[$i][5] == $sessionid) {
captiveportal_disconnect($cpdb[$i],$radiusservers, $term_cause);
captiveportal_logportalauth($cpdb[$i][4],$cpdb[$i][3],$cpdb[$i][2],$logoutReason);
unset($cpdb[$i]);
break;
}
}/* write database */
captiveportal_write_db($cpdb);unlock($cplock);
?>
then I modified disconnect_client in index.php as follows
function disconnect_client($sessionid, $logoutReason = "LOGOUT", $term_cause = 1) {
mwexec_bg("/usr/local/captiveportal/captiveportal-disconnect.php $sessionid $logoutReason $term_cause");
}the time it takes to the shell to spawn php and execute the logout is more than enough time for the HTML Disconnect mesg to make it back to the browser and for httpd to close the socket.
One more thing… its probably better to move the call to disconnect_client in index.php to after the echo of the HTML Disconnect mesg. This way the mesg gets sent to the browser before the disconnect is started. Since mwexec is the very last thing that gets executed before index.php exits there is very little chance that the captive portal disconnect will happen before socket to the client is closed.
Here is the code.
if ($_POST['logout_id']) {
echo << <eod<br><title>Disconnecting…</title>You have been disconnected.
EOD;
disconnect_client($_POST['logout_id']);
exit;The logout is now ** VERY ** clean.
Take care.
–luis</eod<br>
-
I put the client disconnect after the html is sent.
It might need some php buffer flushing too but should be ok for now.Thank you for tracing.
-
I see that all you did was move the call to disconnect_client() to after the html code. In our experimentation here that does nothing for solving the LOGOUT button issue that is discussed in the post. As stated in my postings the HTML is making it to the web browser. So… that is not the issue. Running the console in Chrome, for example, shows that the LOGOUT HTML code made it to the browser. The problem is that the browser does not render the code until after the socket is closed by the server. The socket is never closed because ipfw shuts down the connection and from then on all IP packets are dropped. The connection is left hanging and the browser just spins away waiting for a response from the server. The only way we have found to solve the problem is have the calls to ipfw happen in another process which executes after index.php exits and the sever closes the socket.
So... your code change is pretty much a NOP.
Let me know if you need further info.
Take care.
--luis
-
Try adding
ob_flush();
Just before the disconnect, maybe even
ob_flush(); sleep(1);
To see if that makes a difference.
-
I will try it but i doubt it will make any difference. As stated previously I am seeing the HTML code in the browser. When you do this with mozilla the "Disconnected…." mesg actually is displayed. But in all browsers the page just sits there with the rotating wait i am busy signal waiting for the server to close the socket.
ob_flush() just flushes the output buffers. It does not close the socket. So... it doesn't help given that all of the HMTL code with the "Disconnect..." message has already made it the browser. As stated numerous times the problem with web browsers based in webkit is that these browsers will not render the HTML code until the socket is closed. The socket is Never closed properly because the calls to ipfw are done synchronously before the index.php exits. Once the ipfw calls are made the socket becomes unresponsive and all traffic between the client and pfsense are dropped. The as far as the browser is concerned the socket is open and it continues to wait for data which never arrives. Hence the busy wait signal in ** ALL *** the browsers tested to date.
The only solution found so far is to execute the ipfw commands asynchronously after index.php has exited. As stated previously in this thread that works perfectly...
--luis
-
Can you try putting a closing php://output
Either with fclose() or stream_close(). -
I assume you mean as in
fclose(STDOUT);
that might work. I will give that a shot and report back to you.
–luis
-
Hi have tried…
EOD;
fclose("php://stdin");
fclose("php://stdout");
fclose("php://stderr");
disconnect_client($_POST['logout_id']);and
EOD;
fclose("STDIN");
fclose("STDOUT");
fclose("STDERR");
disconnect_client($_POST['logout_id']);And neither work…
so far the only that works for me is the solution listed earlier in the post where the pfctl statements are done in another process.
--luis
-
how about in the case we discover logout action before calling exit just do
register_shutdown_function(disconnect_client, $_POST['logout_id']);
That should do as well.
-
I will give it a try… the 64,000 question is... does php execute the function before or after it closes the descriptors. If it executes the function before closing the descriptors then it will not work...
--luis
-
This does not work…
if ($_POST['logout_id']) {
echo << <eod<br><title>Disconnecting…</title>You have been disconnected.
EOD;
register_shutdown_function(disconnect_client,$_POST['logout_id']);
exit;
–-As stated before the only thing that I have been able to make work is this...
--- index.php 2011-02-06 16:24:13.000000000 +0000
+++ index.php.new 2011-02-06 16:16:27.000000000 +0000
@@ -412,29 +412,7 @@
*/
function disconnect_client($sessionid, $logoutReason = "LOGOUT", $term_cause = 1) {- global $g, $config;
- $cplock = lock('captiveportal');
- /* read database */
- $cpdb = captiveportal_read_db();
- $radiusservers = captiveportal_get_radius_servers();
- /* find entry */
- for ($i = 0; $i < count($cpdb); $i++) {
- if ($cpdb[$i][5] == $sessionid) {
- captiveportal_disconnect($cpdb[$i],$radiusservers, $term_cause);
- captiveportal_logportalauth($cpdb[$i][4],$cpdb[$i][3],$cpdb[$i][2],$logoutReason);
- unset($cpdb[$i]);
- break;
- }
- }
- /* write database */
- captiveportal_write_db($cpdb);
- unlock($cplock);
- mwexec_bg("/usr/local/captiveportal/captiveportal-disconnect.php $sessionid $logoutReason $term_cause");
}
Where /usr/local/www/captiveportal/captiveportal-disconnect.php contains the following
–-
#!/usr/local/bin/php -f
require_once("functions.inc");
global $g, $config;$sessionid = $argv[1];
$logoutReason = $argv[2];
$term_cause = $argv[3];if ( $argc != 4 || $sessionid == "" || logoutReason == "" || $term_cause == "" )
exit;echo "$sessionid $logoutReason $term_cause";
$cplock = lock('captiveportal');
/* read database */
$cpdb = captiveportal_read_db();$radiusservers = captiveportal_get_radius_servers();
/* find entry */
for ($i = 0; $i < count($cpdb); $i++) {
if ($cpdb[$i][5] == $sessionid) {
captiveportal_disconnect($cpdb[$i],$radiusservers, $term_cause);
captiveportal_logportalauth($cpdb[$i][4],$cpdb[$i][3],$cpdb[$i][2],$logoutReason);
unset($cpdb[$i]);
break;
}
}/* write database */
captiveportal_write_db($cpdb);unlock($cplock);
?>
–-</eod<br>