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; }
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