I found a solution to detect the socket is disconnected by remote.
Using recv function with MSG_PEEK flag can test our socket fd is good or
bad.
When socket fd is bad, system will send SIGPIG signal and do something such
as terminating application, set external errno vaiable to EPIPE. I write
errno_sample.c to prove this concept (see attachments).

Do a few modification, let the XmlSocketServer.pl can disconnection the
client socket when receive the "<eof/>" message, we can test the
disconnection situation.

Test 1:
1.1 start server:
    perl XmlSocketServer.pl

1.2 compile errno_sample.c and run client
    gcc errno_sample.c -o client
    ./client

the output is:
[CONNECT] ret: 0, err: 0
[SELECT] ret: 0, err: 0
[RECV] ret: 3, err: 0
[SELECT] ret: 1, err: 0
[RECV] ret: 3, err: 0
[SELECT] ret: 1, err: 0
[RECV] ret: 6, err: 0
[SELECT] ret: 1, err: 0
[RECV] ret: 9, err: 0
sent close message
[SELECT] ret: 1, err: 0
[RECV] ret: 12, err: 0
sent close message
[SELECT] ret: 1, err: 32
[RECV] ret: 22, err: 32

client will send "<eof/> to server.
if server is close connection, client receive the errno EPIPE(32) and stop
itself.

=============================================================================================

use the same implement to add SocketConnection.lostConnection() method

=== modified file 'libcore/asobj/XMLSocket_as.cpp'
--- libcore/asobj/XMLSocket_as.cpp    2009-05-18 14:27:16 +0000
+++ libcore/asobj/XMLSocket_as.cpp    2009-05-26 19:38:25 +0000
@@ -38,6 +38,8 @@
 #include <boost/scoped_array.hpp>
 #include <boost/scoped_ptr.hpp>
 #include <string>
+#include <errno.h>
+#include <signal.h>

 #undef GNASH_XMLSOCKET_DEBUG

@@ -97,6 +99,15 @@
         _complete = true;
     }

+    bool lostConnection(){
+    char buf[10];
+    signal(SIGPIPE, SIG_IGN);
+    int r = recv(_socket.getFileFd(), buf, sizeof buf, MSG_PEEK);
+    log_debug(_("errno at lost connection, read: %d, err: %d"), r, errno);
+    signal(SIGPIPE, SIG_DFL);
+    return errno == EPIPE;
+    }
+
     size_t writeMessage(const std::string& str) {
         // We have to write the null terminator as well.
         return write(_socket.getFileFd(), str.c_str(), str.size() + 1);
@@ -293,6 +304,7 @@
     // Wait until something has happened with the connection
     if (!_connection.complete()) return;

+
     // If this XMLSocket hadn't finished a connection, check whether it
     // has now.
     if (!ready()) {
@@ -312,6 +324,13 @@
         _ready = true;
     }

+    if(_connection.lostConnection()){
+    log_debug(_("call onClose"));
+    callMethod(NSV::PROP_ON_CLOSE);
+    _vm.getRoot().removeAdvanceCallback(this);
+    return;
+    }
+
     // Now the connection is established we can receive data.
     checkForIncomingData();
 }

and test the lost connection situation


test 2.
2.1 make && make install
2.2 run gnash

but no EPIPE errno received. the debug log said the EAGAIN(11) errno instead

2634:1] 01:28:51 DEBUG: errno at lost connection, read: 0, err: 11
2634:1] 01:28:51 DEBUG: errno at lost connection, read: 0, err: 11
2634:1] 01:28:51 DEBUG: errno at lost connection, read: 0, err: 11

PS. test 2. we use the simple_server.c because of the modified
XmlSocketServer.pl made XMLSocket connection failed. However, I am not
familier with perl and have no idea to fix it.

Maybe I misunderstand something, please give me some information.
use IO::Socket;
use IO::Select;
use Time::HiRes;

$SIG{PIPE}='IGNORE';

$m=new IO::Socket::INET(Listen=>1,LocalPort=>8181);
$O=new IO::Select($m);


$/ = "\0";

while (@S = $O->can_read) {
    foreach (@S) {
        if ($_==$m) {
            $C=$m->accept;
            $O->add($C);
        }
        else {
            my $R=sysread($_, $i, 16000);
            
            # Log message received:
            print "XmlSocketServer: received \"$i\"\n";
            
            if ($R==0) {
                $T=syswrite($_, "\n", 16000);
                if ($T==undef) {
                    $O->remove($_);
		    $_->close;
                }
            } else {

                # Sleep a bit before sending a reply to mimic web traffic
                # (well, sort of).
                Time::HiRes::sleep(0.5);
		
                print "XmlSocketServer: sending \"$i\" \n";
              
                $i =~ s/\*NEWLINE\*/\n/g;
                $i =~ s/\*NULL\*/\0/g;

                foreach $C($O->handles) {
                    $T=syswrite($C, $i, 16000);
                }

		# Close client when receive the <eof/> 
		if ($i =~ /<eof[ ]*\/?>/ig ) {
                    $O->remove($_);
		    $_->close;
		}
            }
        }
    }
}

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include <errno.h>

int init_socket(int* fd, struct sockaddr_in* sa, const char* host, const int port){
    struct hostent *he;
    *fd = socket(PF_INET, SOCK_STREAM, 0);
    if(*fd < 0){
	perror("socket");
	return -1;
    }

    he = (struct hostent*)gethostbyname(host);
    if (he == NULL){
	herror(host);
	return -1;
    }

    bzero(sa, sizeof(struct sockaddr_in));
    sa->sin_family = AF_INET;
    sa->sin_port = htons (port);
    bcopy(he->h_addr_list[0], &sa->sin_addr, he->h_length);

    return 1;
}

int main(void){
    struct sockaddr_in sa;
    int fd, ret, count = 3;;
    const int bufSize = 1024;
    char buf[bufSize];
    const char host[] = "127.0.0.1";

    fd_set              fdset;
    struct timeval      tval;

    init_socket(&fd, &sa, host, 8080);
    if(fd < 0) {
	perror("socket");
	return 1;
    }

    ret = connect(fd, (struct sockaddr *)&sa, sizeof sa);
    printf("[CONNECT] ret: %d, err: %d\n", ret, errno);
    if( ret != 0 ){
	perror("connect fail");
	return 2;
    }

    for(;;){
	signal(SIGPIPE, SIG_IGN);
	write(fd, "ha\n", 3);

	if(count-- <0){
	    write(fd, "<eof>\n", sizeof "<eof>\n");
	    printf("sent close message\n");
	}

	FD_ZERO(&fdset);
	FD_SET(fd, &fdset);
	tval.tv_sec = 0;
	tval.tv_usec = 103;
	ret = select(fd + 1, &fdset, NULL, NULL, &tval);
	printf("[SELECT] ret: %d, err: %d\n", ret, errno);
	ret = recv(fd, buf, bufSize, MSG_PEEK);
	printf("[RECV] ret: %d, err: %d\n", ret, errno);
	sleep(1);
	signal(SIGPIPE, SIG_DFL);

	if (errno == EPIPE){
	    break;
	}

    }
    close(fd);
    return 0;
}

Attachment: DisConnectionSample.swf
Description: application/shockwave-flash

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define BACKLOG 4

int main() {
    register int s, c;
    int count;
    int b;
    struct sockaddr_in sa;
    char buffer[]="<xml></xml>";
    short end[]={0x00};

    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket");
        return 1;
    }

    bzero(&sa, sizeof sa);

    sa.sin_family = AF_INET;
    sa.sin_port   = htons(8080);

    if (INADDR_ANY)
        sa.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(s, (struct sockaddr *)&sa, sizeof sa) < 0) {
        perror("bind");
        return 2;
    }

    listen(s, BACKLOG);

    for (;;) {
        b = sizeof sa;
        c = accept(s, (struct sockaddr *)&sa, &b);
	if( c < 0){
            perror("error");
	}

	for(count=0;count<5;count++){
		printf("send data %s\n", buffer);
		send(c, buffer, sizeof(buffer), 0);
		send(c, end, sizeof(end), 0);
		printf("delay 1 seconds\n");
		sleep(1);
	}
	break;
    }
}
=== modified file 'libcore/asobj/XMLSocket_as.cpp'
--- libcore/asobj/XMLSocket_as.cpp	2009-05-18 14:27:16 +0000
+++ libcore/asobj/XMLSocket_as.cpp	2009-05-26 19:38:25 +0000
@@ -38,6 +38,8 @@
 #include <boost/scoped_array.hpp>
 #include <boost/scoped_ptr.hpp>
 #include <string>
+#include <errno.h>
+#include <signal.h>
 
 #undef GNASH_XMLSOCKET_DEBUG
 
@@ -97,6 +99,15 @@
         _complete = true;
     }
 
+    bool lostConnection(){
+	char buf[10];
+	signal(SIGPIPE, SIG_IGN);
+	int r = recv(_socket.getFileFd(), buf, sizeof buf, MSG_PEEK);
+	log_debug(_("errno at lost connection, read: %d, err: %d"), r, errno);
+	signal(SIGPIPE, SIG_DFL);
+	return errno == EPIPE;
+    }
+
     size_t writeMessage(const std::string& str) {
         // We have to write the null terminator as well.
         return write(_socket.getFileFd(), str.c_str(), str.size() + 1);
@@ -293,6 +304,7 @@
     // Wait until something has happened with the connection
     if (!_connection.complete()) return;
     
+
     // If this XMLSocket hadn't finished a connection, check whether it
     // has now.
     if (!ready()) {
@@ -312,6 +324,13 @@
         _ready = true;
     }
 
+    if(_connection.lostConnection()){
+	log_debug(_("call onClose"));
+	callMethod(NSV::PROP_ON_CLOSE);
+	_vm.getRoot().removeAdvanceCallback(this);
+	return;
+    }
+
     // Now the connection is established we can receive data.
     checkForIncomingData();
 }

=== modified file 'testsuite/XmlSocketServer.pl'
--- testsuite/XmlSocketServer.pl	2008-08-20 16:15:55 +0000
+++ testsuite/XmlSocketServer.pl	2009-05-27 03:24:05 +0000
@@ -4,7 +4,7 @@
 
 $SIG{PIPE}='IGNORE';
 
-$m=new IO::Socket::INET(Listen=>1,LocalPort=>2229);
+$m=new IO::Socket::INET(Listen=>1,LocalPort=>8181);
 $O=new IO::Select($m);
 
 
@@ -26,13 +26,14 @@
                 $T=syswrite($_, "\n", 16000);
                 if ($T==undef) {
                     $O->remove($_);
+		    $_->close;
                 }
-            }
-            else {
-            
+            } else {
+
                 # Sleep a bit before sending a reply to mimic web traffic
                 # (well, sort of).
                 Time::HiRes::sleep(0.5);
+		
                 print "XmlSocketServer: sending \"$i\" \n";
               
                 $i =~ s/\*NEWLINE\*/\n/g;
@@ -41,6 +42,12 @@
                 foreach $C($O->handles) {
                     $T=syswrite($C, $i, 16000);
                 }
+
+		# Close client when receive the <eof/> 
+		if ($i =~ /<eof[ ]*\/?>/ig ) {
+                    $O->remove($_);
+		    $_->close;
+		}
             }
         }
     }

_______________________________________________
Gnash-dev mailing list
Gnash-dev@gnu.org
http://lists.gnu.org/mailman/listinfo/gnash-dev

Reply via email to