gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] gnash ./ChangeLog testsuite/actionscript.all/Lo...


From: Rob Savoye
Subject: [Gnash-commit] gnash ./ChangeLog testsuite/actionscript.all/Lo...
Date: Sun, 05 Feb 2006 01:10:58 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Branch:         
Changes by:     Rob Savoye <address@hidden>     06/02/05 01:10:58

Modified files:
        .              : ChangeLog 
        testsuite/actionscript.all: LocalConnection.as 
        plugin         : Makefile.am 
        server         : LocalConnection.cpp LocalConnection.h 
                         NetConnection.cpp NetConnection.h network.cpp 
                         network.h 

Log message:
        * server/LocalConnection.h: Change API for connect(), and
        domain().
        * server/LocalConnection.cpp: Change API for connect(), and
        domain(). Initial implementations of domain(), connect(), and
        close().
        * server/network.cpp: Replace code with networking code from one
        of my other GPL'd projects, PowerGuru. That code is much more
        fully functional in a generic sense, and pretty solid too. Add
        more accessors to use for testing LocalConnection.
        * server/network.h: Add more accessors to use for testing
        LocalConnection.
        * testsuite/actionscript.all/LocalConnection.as: Test the newly
        implemented methods.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/ChangeLog.diff?tr1=1.89&tr2=1.90&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/testsuite/actionscript.all/LocalConnection.as.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/plugin/Makefile.am.diff?tr1=1.9&tr2=1.10&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/LocalConnection.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/LocalConnection.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/NetConnection.cpp.diff?tr1=1.3&tr2=1.4&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/NetConnection.h.diff?tr1=1.3&tr2=1.4&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/network.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/network.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text

Patches:
Index: gnash/ChangeLog
diff -u gnash/ChangeLog:1.89 gnash/ChangeLog:1.90
--- gnash/ChangeLog:1.89        Sat Feb  4 21:24:07 2006
+++ gnash/ChangeLog     Sun Feb  5 01:10:58 2006
@@ -1,5 +1,19 @@
 2006-02-04  Rob Savoye  <address@hidden>
 
+       * server/LocalConnection.h: Change API for connect(), and
+       domain().
+       * server/LocalConnection.cpp: Change API for connect(), and
+       domain(). Initial implementations of domain(), connect(), and
+       close().
+       * server/network.cpp: Replace code with networking code from one
+       of my other GPL'd projects, PowerGuru. That code is much more
+       fully functional in a generic sense, and pretty solid too. Add
+       more accessors to use for testing LocalConnection. 
+       * server/network.h: Add more accessors to use for testing
+       LocalConnection.
+       * testsuite/actionscript.all/LocalConnection.as: Test the newly
+       implemented methods.
+
        * server/network.{h,cpp}: New files to hold base networking class
        for use by other ActionScript objects. This base class contains
        the code for custom methods that implement accessors to the data
Index: gnash/plugin/Makefile.am
diff -u gnash/plugin/Makefile.am:1.9 gnash/plugin/Makefile.am:1.10
--- gnash/plugin/Makefile.am:1.9        Fri Feb  3 20:50:27 2006
+++ gnash/plugin/Makefile.am    Sun Feb  5 01:10:58 2006
@@ -85,10 +85,11 @@
 # directory for Firefox. For some reason if the same file is
 # installed in the users $(HOME)/.firefox.plugins, the plugin
 # won't load due to errors with an undefined MaiAtkObject.
-install-pluginLTLIBRARIES: $(plugin_LIBRARIES)
-       cp .libs/libgnashplugin.so $(plugindir)/libgnashplugin.so
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+       test -d "$(plugindir)"
+       cp .libs/libgnashplugin.so $(DESTDIR)$(plugindir)/libgnashplugin.so
 
-# install-pluginLTLIBRARIES: $(plugin_LIBRARIES)
+# install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
 #      if test -d $(HOME)/.firefox ; then \
 #         $(mkinstalldirs) $(HOME)/.firefox/plugins; \
 #         $(INSTALL) .libs/libgnash.so $(HOME)/.firefox/plugins/libgnash.so; \
@@ -97,5 +98,5 @@
 #         $(INSTALL) .libs/libgnash.so $(HOME)/.mozilla/plugins/libgnash.so; \
 #      fi
 
-uninstall-pluginLTLIBRARIES: $(plugin_LIBRARIES)
-       rm -f $(plugindir)/libgnashplugin.so
+uninstall-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+       rm -f $(DESTDIR)$(plugindir)/libgnashplugin.so
\ No newline at end of file
Index: gnash/server/LocalConnection.cpp
diff -u gnash/server/LocalConnection.cpp:1.1 
gnash/server/LocalConnection.cpp:1.2
--- gnash/server/LocalConnection.cpp:1.1        Wed Feb  1 23:52:44 2006
+++ gnash/server/LocalConnection.cpp    Sun Feb  5 01:10:58 2006
@@ -20,41 +20,114 @@
 #include "config.h"
 #endif
 
+#include <errno.h>
+
 #include "log.h"
 #include "LocalConnection.h"
+#include "network.h"
 
 namespace gnash {
 
+// \class LocalConnection
+/// \brief Open a connection between two SWF movies so they can send
+/// each otherFlash  Objects to be executed.
+///
 LocalConnection::LocalConnection() {
 }
 
 LocalConnection::~LocalConnection() {
 }
 
-
+/// \brief Closes (disconnects) the LocalConnection object.
 void
 LocalConnection::close()
 {
-    log_msg("%s:unimplemented \n", __FUNCTION__);
+    closeNet();
 }
 
-void
-LocalConnection::connect()
+/// \brief Prepares the LocalConnection object to receive commands from a
+/// LocalConnection.send() command.
+/// 
+/// The name is a symbolic name like "lc_name", that is used by the
+/// send() command to signify which local connection to send the
+/// object to.
+bool
+LocalConnection::connect(const char *name)
 {
-    log_msg("%s:unimplemented \n", __FUNCTION__);
-}
+    short lastport;
+    const char *lcname;
 
-void
-LocalConnection::domain()
+    std::map<const char *, short>::const_iterator it;
+    for (it = _allocated.begin(); it != _allocated.end(); it++) {
+        lcname = it->first;
+        lastport  = it->second;
+        if (strcmp(name, lcname) == 0) {
+            log_msg("ERROR: %s already allocated!\n", name);
+            return false;
+        }
+    }
+
+    // Allocate the tcp/ip port adfter the last allocated one.
+    if (lastport != 0) {
+        _allocated[name] = lastport+1;
+    }
+
+    // Create the socket
+    if (createServer(lastport+1)) {
+        log_msg("New server started for \"%s\" connections.\n", name);
+    } else {
+        log_msg("ERROR: Couldn't create a new server for \"%s\"!\n");
+        return false;
+    }
+
+    if (newConnection(false)) {
+        log_msg("New connection started for \"%s\" connections.\n", name);
+//        writeNet(heloCreate(_version));
+        return true;
+    } else {
+        if (errno == EAGAIN) {
+            log_msg("No clients tried to connect within the allocated time 
limit\n");
+            return false;
+        }
+        else {
+            log_msg("ERROR: Couldn't create a new connection!\n");
+        }
+            
+        return false;
+    }
+
+    _name = name;
+}
+
+/// \brief Returns a string representing the superdomain of the
+/// location of the current SWF file.
+///
+/// The domain is either the "localhost", or the hostname from the
+/// network connection. This behaviour changed for SWF v7. Prior to v7
+/// only the domain was returned, ie dropping off node names like
+/// "www". As of v7, the behaviour is to return the full host
+/// name. Gnash defaults to the v7 behaviour.
+/// \note If this becomes a problem, we'll have to implemented the
+/// older behaviour based on the version of the flash movie being
+/// played.
+std::string
+LocalConnection::domain(void)
 {
-    log_msg("%s:unimplemented \n", __FUNCTION__);
+    if (_host.size() == 0) {
+        return "localhost";
+    } else {
+        return _host;
+    }
 }
 
+/// \brief Invokes a method on a specified LocalConnection object.
 void
 LocalConnection::send()
 {
     log_msg("%s:unimplemented \n", __FUNCTION__);
 }
+
+/// \brief Instantiate a new LocalConnection object within a flash movie
 void
 localconnection_new(const fn_call& fn)
 {
@@ -64,20 +137,54 @@
     localconnection_obj->set_member("connect", &localconnection_connect);
     localconnection_obj->set_member("domain", &localconnection_domain);
     localconnection_obj->set_member("send", &localconnection_send);
+#ifdef ENABLE_TESTING
+    localconnection_obj->set_member("connected",  &network_connected);
+    localconnection_obj->set_member("getfilefd",  &network_getfilefd);
+    localconnection_obj->set_member("getlistenfd",  &network_getlistenfd);
+#endif
 
     fn.result->set_as_object_interface(localconnection_obj);
 }
 
-void localconnection_close(const fn_call& fn) {
-    log_msg("%s:unimplemented \n", __FUNCTION__);
+/// \brief The callback for LocalConnection::close()
+void localconnection_close(const fn_call& fn)
+{
+//    log_msg("%s: %d args\n", __PRETTY_FUNCTION__, fn.nargs);
+    
+    localconnection_as_object *ptr = (localconnection_as_object*)fn.this_ptr;
+    assert(ptr);
+    
+    ptr->obj.close();
 }
-void localconnection_connect(const fn_call& fn) {
-    log_msg("%s:unimplemented \n", __FUNCTION__);
+
+/// \brief The callback for LocalConnection::connect()
+void localconnection_connect(const fn_call& fn)
+{
+//    log_msg("%s: %d args\n", __PRETTY_FUNCTION__, fn.nargs);
+    localconnection_as_object *ptr = (localconnection_as_object*)fn.this_ptr;
+    
+    assert(ptr);
+    if (fn.nargs != 0) {
+        
ptr->obj.connect(fn.env->bottom(fn.first_arg_bottom_index).to_string());
+    } else {
+        log_msg("ERROR: No connection name specified to 
LocalConnection.connect()!\n");
+        ptr->obj.connect("localhost"); // FIXME: This should probably
+                                       // fail instead
+    }
 }
-void localconnection_domain(const fn_call& fn) {
-    log_msg("%s:unimplemented \n", __FUNCTION__);
+
+/// \brief The callback for LocalConnection::domain()
+void localconnection_domain(const fn_call& fn)
+{
+//    log_msg("%s:\n", __PRETTY_FUNCTION__);
+    localconnection_as_object *ptr = (localconnection_as_object*)fn.this_ptr;
+    assert(ptr);
+    fn.result->set_tu_string(ptr->obj.domain().c_str());
 }
-void localconnection_send(const fn_call& fn) {
+
+// \brief The callback for LocalConnection::send()
+void localconnection_send(const fn_call& fn)
+{
     log_msg("%s:unimplemented \n", __FUNCTION__);
 }
 
Index: gnash/server/LocalConnection.h
diff -u gnash/server/LocalConnection.h:1.1 gnash/server/LocalConnection.h:1.2
--- gnash/server/LocalConnection.h:1.1  Wed Feb  1 23:52:44 2006
+++ gnash/server/LocalConnection.h      Sun Feb  5 01:10:58 2006
@@ -23,23 +23,30 @@
 #include "config.h"
 #endif
 
+#include <string>
+#include <map>
+
 #include "impl.h"
 #include "log.h"
+#include "network.h"
 
 namespace gnash {
   
-class LocalConnection {
+class LocalConnection : public Network {
 public:
     LocalConnection();
     ~LocalConnection();
-   void close();
-   void connect();
-   void domain();
-   void send();
+    void close(void);
+    bool connect(const char *name);
+    std::string domain(void);
+    void send();
+// FIXME: these should be callbacks
+//     bool        _allowDomain;
+//     bool        _allowInsecureDomain;
+//     bool        _onStatus;
 private:
-    bool _allowDomain;
-    bool _allowInsecureDomain;
-    bool _onStatus;
+    std::string _name;
+    std::map<const char *, short> _allocated;
 };
 
 struct localconnection_as_object : public as_object
Index: gnash/server/NetConnection.cpp
diff -u gnash/server/NetConnection.cpp:1.3 gnash/server/NetConnection.cpp:1.4
--- gnash/server/NetConnection.cpp:1.3  Sat Feb  4 21:24:07 2006
+++ gnash/server/NetConnection.cpp      Sun Feb  5 01:10:58 2006
@@ -55,7 +55,6 @@
 NetConnection::~NetConnection() {
 }
 
-/// \fn void NetConnection::connect(const char *arg)
 /// \brief Open a connection to stream FLV files.
 /// \param the URL
 /// \return nothing
@@ -103,7 +102,6 @@
     log_msg("%s:unimplemented \n", __FUNCTION__);
 }
 
-/// \fn void netconnection_new(const fn_call& fn)
 /// \brief callback to instantiate a new NetConnection object.
 /// \param fn the parameters from the Flash movie
 /// \return nothing from the function call.
Index: gnash/server/NetConnection.h
diff -u gnash/server/NetConnection.h:1.3 gnash/server/NetConnection.h:1.4
--- gnash/server/NetConnection.h:1.3    Sat Feb  4 21:24:07 2006
+++ gnash/server/NetConnection.h        Sun Feb  5 01:10:58 2006
@@ -31,10 +31,6 @@
 
 namespace gnash {
 
-// Define the ports for the RTMP protocols
-const int RTMP = 1935;
-const int RTMPT = 80;
-
 class NetConnection : public Network {
 public:
     NetConnection();
Index: gnash/server/network.cpp
diff -u gnash/server/network.cpp:1.1 gnash/server/network.cpp:1.2
--- gnash/server/network.cpp:1.1        Sat Feb  4 21:24:07 2006
+++ gnash/server/network.cpp    Sun Feb  5 01:10:58 2006
@@ -1,4 +1,4 @@
-// 
+//
 //   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
 //
 // This program is free software; you can redistribute it and/or modify
@@ -54,169 +54,456 @@
 
 namespace gnash {
 
-const int SOCKET_DATA   = 1;  
-const int INBUF         = 10000;
+static const int SOCKET_DATA    = 1;  
+static const int INBUF          = 10000;
+static const char *DEFAULTPROTO = "tcp";
+static const short DEFAULTPORT  = RTMP;
+static const int DEFAULTTIMEOUT = 5;
+static const int BLOCKING_TIMEOUT= -1;
+
+#ifndef INADDR_NONE
+#define INADDR_NONE  0xffffffff
+#endif
   
-Network::Network() : _sockfd(0), _port(0), _connected(false)
+Network::Network() : _ipaddr(INADDR_ANY), _sockfd(0), _listenfd(0), _port(0), 
_connected(false), _debug(false)
 {
-  //log_msg("%s: \n", __FUNCTION__);
+    //log_msg("%s: \n", __PRETTY_FUNCTION__);
 }
 
 Network::~Network() 
 {
-  //log_msg("%s: \n", __FUNCTION__);
+    //log_msg("%s: \n", __PRETTY_FUNCTION__);
 }
 
+// Description: Create a tcp/ip network server. This creates a server
+//              that listens for incoming socket connections. This
+//              support IP aliasing on the host, and will sequntially
+//              look for IP address to bind this port to.
 bool
-Network::clientConnect(const char *host, short port)
+Network::createServer(void)
 {
-  struct sockaddr_in  sock_in;
-  fd_set              fdset;
-  struct timeval      tval;
-  int                 ret;
-  int                 retries;
-  char                thishostname[MAXHOSTNAMELEN];
-  struct protoent     *proto;
+    log_msg("%s: \n", __PRETTY_FUNCTION__);
+    return createServer(DEFAULTPORT);
+}
 
-  if (port < 1024) {
-    log_error("Can't connect to priviledged port #%hd!\n", port);
-    _connected = false;
-    return false;
-  }
+bool
+Network::createServer(short port)
+{
+    log_msg("%s: \n", __PRETTY_FUNCTION__);
+    struct protoent *ppe;
+    struct sockaddr_in sock_in;
+    int             on, type;
+    int             retries = 0;
+    const struct hostent  *host;
+    struct in_addr  *thisaddr, newaddr;
+    in_addr_t       nodeaddr, netaddr;
+  
+    host = gethostbyname("localhost");
+    thisaddr = reinterpret_cast<struct in_addr *>(host->h_addr_list[0]);
+    _ipaddr = thisaddr->s_addr;
+    memset(&sock_in, 0, sizeof(sock_in));
 
-  log_msg("%s: to host %s at port %d\n", __FUNCTION__, host, port);
+#if 0
+    // Accept incoming connections only on our IP number
+    sock_in.sin_addr.s_addr = thisaddr->s_addr;
+#else
+    // Accept incoming connections on any IP number
+    sock_in.sin_addr.s_addr = INADDR_ANY;
+#endif
+    
+    _ipaddr = sock_in.sin_addr.s_addr;
+    sock_in.sin_family = AF_INET;
+    sock_in.sin_port = htons(port);
   
-  memset(&sock_in, 0, sizeof(struct sockaddr_in));
-  memset(&thishostname, 0, MAXHOSTNAMELEN);
-  if (strlen(host) == 0) {
-    if (gethostname(thishostname, MAXHOSTNAMELEN) == 0) {
-      log_msg("The hostname for this machine is %s.\n", thishostname);
+    if ((ppe = getprotobyname(DEFAULTPROTO)) == 0) {
+        // error, wasn't able to get a protocol entry
+        log_msg("WARNING: unable to get protocol entry for %s\n",
+                DEFAULTPROTO);
+        return false;
+    }
+    
+    // set protocol type
+    if (DEFAULTPROTO == "udp") {
+        type = SOCK_DGRAM;
     } else {
-      log_msg("Couldn't get the hostname for this machine!\n");
-      return false;
-    }   
-  }
-  const struct hostent *hent = ::gethostbyname(host);
-  if (hent > 0) {
-    ::memcpy(&sock_in.sin_addr, hent->h_addr, hent->h_length);
-  }
-  sock_in.sin_family = AF_INET;
-  sock_in.sin_port = ntohs(static_cast<short>(port));
+        type = SOCK_STREAM;
+    }
+    
+    // Get a file descriptor for this socket connection
+    _listenfd = socket(PF_INET, type, ppe->p_proto);
+    
+    // error, wasn't able to create a socket
+    if (_listenfd < 0) {
+        log_msg("unable to create socket: %s\n", strerror(errno));
+        return true;
+    }
+    
+    on = 1;
+    if (setsockopt(_listenfd, SOL_SOCKET, SO_REUSEADDR,
+                   (char *)&on, sizeof(on)) < 0) {
+        log_msg("setsockopt SO_REUSEADDR failed!\n");
+        return false;
+    }
+    
+    retries = 0;
+    
+    nodeaddr = inet_lnaof(*thisaddr);
+    while (retries < 5) {
+        if (bind(_listenfd, reinterpret_cast<struct sockaddr *>(&sock_in),
+                 sizeof(sock_in)) == -1) {
+            log_msg("WARNING: unable to bind to %s port! %s\n",
+                    inet_ntoa(sock_in.sin_addr), strerror(errno));
+            retries++;
+        }
 
 #if 0
-    char ascip[32];
-    inet_ntop(AF_INET, &sock_in.sin_addr.s_addr, ascip, INET_ADDRSTRLEN);
-      log_msg("The IP address for this client socket is %s\n", ascip);
+        char                ascip[32];
+        inet_ntop(AF_INET, &_ipaddr, ascip, INET_ADDRSTRLEN);
+        log_msg("Host Name is %s, IP is %s", host->h_name, ascip);
 #endif
+    
+        log_msg("Server bound to service on port: %hd, %s using fd #%d\n",
+                ntohs(sock_in.sin_port), inet_ntoa(sock_in.sin_addr),
+                _listenfd);
+        
+        if (type == SOCK_STREAM && listen(_listenfd, 5) < 0) {
+            log_msg("ERROR: unable to listen on port: %d: %s ",
+                port, strerror(errno));
+            return false;
+        }
 
-  proto = ::getprotobyname("TCP");
+        _port = port;
+    
+#if 0
+        log_msg("Listening for net traffic on fd #%d\n", _sockfd);
+#endif
+    
+        return true;
+    }
+    return false;
+}
 
-  _sockfd = ::socket(PF_INET, SOCK_STREAM, proto->p_proto);
-  if (_sockfd < 0)
-    {
-      log_error("unable to create socket : %s\n", strerror(errno));
-      _sockfd = -1;
-      return false;
-    }
-
-  retries = 2;
-  while (retries-- > 0) {
-    // We use select to wait for the read file descriptor to be
-    // active, which means there is a client waiting to connect.
-    FD_ZERO(&fdset);
-    FD_SET(_sockfd, &fdset);
-    
-    // Reset the timeout value, since select modifies it on return. To
-    // block, set the timeout to zero.
-    tval.tv_sec = 5;
-    tval.tv_usec = 0;
-    
-    ret = ::select(_sockfd+1, &fdset, NULL, NULL, &tval);
-
-    // If interupted by a system call, try again
-    if (ret == -1 && errno == EINTR)
-      {
-        log_msg("The connect() socket for fd #%d was interupted by a system 
call!\n",
-                _sockfd);
-        continue;
-      }
-    
-    if (ret == -1)
-      {
-        log_msg("The connect() socket for fd #%d never was available for 
writing!\n",
-                _sockfd);
-#ifdef HAVE_WINSOCK
-        ::shutdown(_sockfd, SHUT_BOTH);
-#else
-        ::shutdown(_sockfd, SHUT_RDWR);
+// Description: Accept a new network connection for the port we have
+//              created a server for.
+// The default is to block.
+bool
+Network::newConnection(void)
+{
+    log_msg("%s: \n", __PRETTY_FUNCTION__);
+
+    return newConnection(true);
+}
+
+bool
+Network::newConnection(bool block)
+{
+    log_msg("%s: \n", __PRETTY_FUNCTION__);
+    struct sockaddr    fsin;
+    socklen_t          alen;
+    int                        ret;
+    struct timeval        tval;
+    fd_set                fdset;
+    int                   retries = 3;
+  
+    alen = sizeof(struct sockaddr_in);
+  
+#ifdef NET_DEBUG
+    log_msg("Trying to accept net traffic on fd #%d\n", _sockfd);
 #endif
-        _sockfd = -1;      
+  
+    if (_listenfd <= 2) {
         return false;
-      }
-    if (ret == 0) {
-      log_error("The connect() socket for fd #%d timed out waiting to 
write!\n",
-                _sockfd);
-      continue;
     }
+  
+    while (retries--) {
+        // We use select to wait for the read file descriptor to be
+        // active, which means there is a client waiting to connect.
+        FD_ZERO(&fdset);
+        // also return on any input from stdin
+//         if (_console) {
+//             FD_SET(fileno(stdin), &fdset);
+//         }
+        FD_SET(_listenfd, &fdset);
+    
+        // Reset the timeout value, since select modifies it on return. To
+        // block, set the timeout to zero.
+        tval.tv_sec = 1;
+        tval.tv_usec = 0;
+    
+        if (block) {
+            ret = select(_listenfd+1, &fdset, NULL, NULL, NULL);
+        } else {
+            ret = select(_listenfd+1, &fdset, NULL, NULL, &tval);
+        }
+    
+        if (FD_ISSET(0, &fdset)) {
+            log_msg("There is data at the console for stdin!");
+            return true;
+        }
+
+        // If interupted by a system call, try again
+        if (ret == -1 && errno == EINTR) {
+            log_msg("The accept() socket for fd #%d was interupted by a system 
call!\n", _listenfd);
+        }
+    
+        if (ret == -1) {
+            log_msg("ERROR: The accept() socket for fd #%d never was available 
for writing!",
+                    _listenfd);
+            return false;
+        }
+    
+        if (ret == 0) {
+            if (_debug) {
+                log_msg("ERROR: The accept() socket for fd #%d timed out 
waiting to write!\n",
+                        _listenfd);
+            }
+        }
+    }
+  
+    fcntl(_listenfd, F_SETFL, O_NONBLOCK); // Don't let accept() block
+    _sockfd = accept(_listenfd, &fsin, &alen);
+  
+    if (_sockfd < 0) {
+        log_msg("unable to accept : %s\n", strerror(errno));
+        return false;
+    }
+  
+    log_msg("Accepting tcp/ip connection on fd #%d\n", _sockfd);
 
-    if (ret > 0) {
-      ret = ::connect(_sockfd, reinterpret_cast<struct sockaddr *>(&sock_in), 
sizeof(sock_in));
-      if (ret == 0) {
-        log_msg("\tport %d at IP %s for fd #%d\n", port,
-                ::inet_ntoa(sock_in.sin_addr), _sockfd);
-        _connected = true;
-        return true;
-      }
-      if (ret == -1) {
-        log_msg("The connect() socket for fd #%d never was available for 
writing!\n",
-                _sockfd);
-        _sockfd = -1;      
+    return true;
+}
+
+// Create a client connection to a tcp/ip based service
+bool
+Network::createClient(void)
+{
+    return createClient("localhost", RTMP);
+}
+bool
+Network::createClient(short port)
+{
+}
+bool
+Network::createClient(const char *hostname)
+{
+    return createClient(hostname, RTMP);        
+}
+    
+bool
+Network::createClient(const char *hostname, short port)
+{
+    struct sockaddr_in  sock_in;
+    fd_set              fdset;
+    struct timeval      tval;
+    int                 ret;
+    int                 retries;
+    char                thishostname[MAXHOSTNAMELEN];
+    struct protoent     *proto;
+
+    if (port < 1024) {
+        log_error("Can't connect to priviledged port #%hd!\n", port);
+        _connected = false;
         return false;
-      }
     }
-  }
-  //  ::close(_sockfd);
-  //  return false;
 
-  printf("\tConnected at port %d on IP %s for fd #%d\n", port,
-          ::inet_ntoa(sock_in.sin_addr), _sockfd);
+    log_msg("%s: to host %s at port %d\n", __FUNCTION__, hostname, port);
+  
+    memset(&sock_in, 0, sizeof(struct sockaddr_in));
+    memset(&thishostname, 0, MAXHOSTNAMELEN);
+    if (strlen(hostname) == 0) {
+        if (gethostname(thishostname, MAXHOSTNAMELEN) == 0) {
+            log_msg("The hostname for this machine is %s.\n", thishostname);
+        } else {
+            log_msg("Couldn't get the hostname for this machine!\n");
+            return false;
+        }   
+    }
+    const struct hostent *hent = ::gethostbyname(hostname);
+    if (hent > 0) {
+        ::memcpy(&sock_in.sin_addr, hent->h_addr, hent->h_length);
+    }
+    sock_in.sin_family = AF_INET;
+    sock_in.sin_port = ntohs(static_cast<short>(port));
+
+#if 0
+    char ascip[32];
+    inet_ntop(AF_INET, &sock_in.sin_addr.s_addr, ascip, INET_ADDRSTRLEN);
+    log_msg("The IP address for this client socket is %s\n", ascip);
+#endif
+
+    proto = ::getprotobyname("TCP");
+
+    _sockfd = ::socket(PF_INET, SOCK_STREAM, proto->p_proto);
+    if (_sockfd < 0)
+        {
+            log_error("unable to create socket : %s\n", strerror(errno));
+            _sockfd = -1;
+            return false;
+        }
+
+    retries = 2;
+    while (retries-- > 0) {
+        // We use select to wait for the read file descriptor to be
+        // active, which means there is a client waiting to connect.
+        FD_ZERO(&fdset);
+        FD_SET(_sockfd, &fdset);
+    
+        // Reset the timeout value, since select modifies it on return. To
+        // block, set the timeout to zero.
+        tval.tv_sec = 5;
+        tval.tv_usec = 0;
+    
+        ret = ::select(_sockfd+1, &fdset, NULL, NULL, &tval);
+
+        // If interupted by a system call, try again
+        if (ret == -1 && errno == EINTR)
+            {
+                log_msg("The connect() socket for fd #%d was interupted by a 
system call!\n",
+                        _sockfd);
+                continue;
+            }
+    
+        if (ret == -1)
+            {
+                log_msg("The connect() socket for fd #%d never was available 
for writing!\n",
+                        _sockfd);
+#ifdef HAVE_WINSOCK
+                ::shutdown(_sockfd, SHUT_BOTH);
+#else
+                ::shutdown(_sockfd, SHUT_RDWR);
+#endif
+                _sockfd = -1;      
+                return false;
+            }
+        if (ret == 0) {
+            log_error("The connect() socket for fd #%d timed out waiting to 
write!\n",
+                      _sockfd);
+            continue;
+        }
+
+        if (ret > 0) {
+            ret = ::connect(_sockfd, reinterpret_cast<struct sockaddr 
*>(&sock_in), sizeof(sock_in));
+            if (ret == 0) {
+                log_msg("\tport %d at IP %s for fd #%d\n", port,
+                        ::inet_ntoa(sock_in.sin_addr), _sockfd);
+                _connected = true;
+                return true;
+            }
+            if (ret == -1) {
+                log_msg("The connect() socket for fd #%d never was available 
for writing!\n",
+                        _sockfd);
+                _sockfd = -1;      
+                return false;
+            }
+        }
+    }
+    //  ::close(_sockfd);
+    //  return false;
+
+    printf("\tConnected at port %d on IP %s for fd #%d\n", port,
+           ::inet_ntoa(sock_in.sin_addr), _sockfd);
   
 #ifndef HAVE_WINSOCK
-  fcntl(_sockfd, F_SETFL, O_NONBLOCK);
+    fcntl(_sockfd, F_SETFL, O_NONBLOCK);
 #endif
 
-  _connected = true;
-  return true;
+    _connected = true;
+    return true;
 }
 
-void
-Network::close()
-{
-  log_msg("%s: \n", __FUNCTION__);
-  // Since the return code from close() doesn't get used by Shockwave,
-  // we don't care either.
-  if (_sockfd > 0) {
-    ::close(_sockfd);
-  }
+bool
+Network::closeNet()
+{  
+//    log_msg("%s: \n", __PRETTY_FUNCTION__);
+    if (_sockfd > 0) {
+        closeNet(_sockfd);
+        _sockfd = 0;
+        _connected = false;        
+    }
+  
+    return false;
 }
 
 bool
-Network::send(const char *data)
+Network::closeNet(int sockfd)
+{
+    int retries = 0;
+    
+    // If we can't close the socket, other processes must be
+    // locked on it, so we wait a second, and try again. After a
+    // few tries, we give up, cause there must be something
+    // wrong.
+
+    if (sockfd <= 0) {
+        return true;
+    }
+  
+    while (retries < 3) {
+        if (sockfd) {
+            // Shutdown the socket connection
+#if 0
+            if (shutdown(sockfd, SHUT_RDWR) < 0) {
+                if (errno != ENOTCONN) {
+                    cerr << "WARNING: Unable to shutdown socket for fd #\n"
+                         << sockfd << strerror(errno) << endl;
+                } else {
+                    cerr << "The socket using fd #" << sockfd
+                         << " has been shut down successfully." << endl;
+                    return true;
+                }
+            }
+#endif 
+            if (close(sockfd) < 0) {
+                log_msg("WARNING: Unable to close the socket for fd%d\n%s\n",
+                        sockfd, strerror(errno));
+                sleep(1);
+                retries++;
+            } else {
+                log_msg("Closed the socket on fd #%d\n", sockfd);
+                return true;
+            }
+        }
+    } 
+    return false;
+}
+// Description: Close an open socket connection.
+bool
+Network::closeConnection(void)
 {
-  log_msg("%s: \n", __FUNCTION__);
-  int length = strlen(data);
+    log_msg("%s: \n", __FUNCTION__);
+
+    closeConnection(_sockfd);
+    _listenfd = 0;
+    _connected = false;
   
-  int ret = write(_sockfd, data, length);
+    return false;
+}
 
-  log_msg("%s: sent %d bytes, data was %s\n",
-          __FUNCTION__, ret, data);
-  if (ret == length) {
-    return true;
-  } else {
+bool
+Network::closeConnection(int fd)
+{
+    log_msg("%s: \n", __FUNCTION__);
+    if (fd > 0) {
+        closeConnection(fd);
+    }
+  
     return false;
-  }
 }
 
+void
+Network::toggleDebug(bool val)
+{
+    // Turn on our own debugging
+    _debug = val;
+
+    // Turn on debugging for the utility methods
+    toggleDebug(true);
+}
+
+#ifdef ENABLE_TESTING
+// These are the callbacks used to define custom methods for our AS
+// classes. This way we can examine the private dats after calling a
+// method to see if it worked correctly.
 void network_geturl(const fn_call& fn)
 {
     network_as_object *ptr = (network_as_object*)fn.this_ptr;
@@ -252,4 +539,24 @@
     fn.result->set_tu_string(ptr->obj.getPath().c_str());
 }
 
-} // end of gnaash namespace
+void network_connected(const fn_call& fn)
+{
+    network_as_object *ptr = (network_as_object*)fn.this_ptr;
+    assert(ptr);
+    fn.result->set_bool(ptr->obj.connected());
+}
+void network_getfilefd(const fn_call& fn)
+{
+    network_as_object *ptr = (network_as_object*)fn.this_ptr;
+    assert(ptr);
+    fn.result->set_int(ptr->obj.getFileFd());
+}
+void network_getlistenfd(const fn_call& fn)
+{
+    network_as_object *ptr = (network_as_object*)fn.this_ptr;
+    assert(ptr);
+    fn.result->set_int(ptr->obj.getListenFd());
+}
+#endif
+
+} // end of gnash namespace
Index: gnash/server/network.h
diff -u gnash/server/network.h:1.1 gnash/server/network.h:1.2
--- gnash/server/network.h:1.1  Sat Feb  4 21:24:07 2006
+++ gnash/server/network.h      Sun Feb  5 01:10:58 2006
@@ -10,7 +10,6 @@
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU General Public License for more details.
-
 // You should have received a copy of the GNU General Public License
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
@@ -24,6 +23,8 @@
 #endif
 
 #include <string>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include "xml.h"
 #include "impl.h"
@@ -31,19 +32,59 @@
 
 namespace gnash {
 
+// Define the ports for the RTMP protocols
+const int RTMP = 1935;
+const int RTMPT = 80;
+
 class Network {
 public:
     Network();
     ~Network();
     
-    bool clientConnect(const char *host, short port);
-    bool serverConnect(short port);
-    void close();
+    // Create a new server. After creating it, then you have to wait
+    // for an incoming connection.
+    bool createServer(void);
+    bool createServer(short port);
+    
+    // Accept a client connection for the current server.
+    bool newConnection(void);
+    bool newConnection(bool block);
+    
+    // Create a client connection to a tcp/ip server
+    bool createClient(void);
+    bool createClient(short port);
+    bool createClient(const char *hostname);
+    bool createClient(const char *hostname, short port);
+
+    // Read from the socket
+    int readNet(char *buffer, int nbytes);
+    int readNet(char *buffer, int nbytes, int timeout);
+    int readNet(int fd, char *buffer, int nbytes);
+    int readNet(int fd, char *buffer, int nbytes, int timeout);
+    
+    // Write to the socket  
+    int writeNet(std::string buffer);
+    int writeNet(char const *buffer);
+    int writeNet(char const *buffer, int nbytes);
+    int writeNet(int fd, char const *buffer);
+    int writeNet(int fd, char const *buffer, int nbytes);
+    int writeNet(int fd, char const *buffer, int nbytes, int timeout);
+    
+    // Close the connection
+    bool closeNet();
+    bool closeNet(int fd);
+    bool closeConnection();
+    bool closeConnection(int fd);
+
+    // Change the debug flag
+    void toggleDebug(bool val);
+    
     bool send(const char *str);
 #ifdef ENABLE_TESTING 
     // Accessors for testing
     bool connected()            { return _connected; };
-    int getFileno()             { return static_cast<int>(_sockfd); };
+    int getFileFd()             { return _sockfd; };
+    int getListenFd()           { return _listenfd; };
     short getPort()             { return _port; };
     std::string getURL()        { return _url; }
     std::string getProtocol()   { return _protocol; }
@@ -52,7 +93,9 @@
     std::string getPath()       { return _path; }    
 #endif
 protected:
-    short       _sockfd;
+    in_addr_t   _ipaddr;
+    int         _sockfd;
+    int         _listenfd;
     short       _port;
     std::string _portstr;
     std::string _url;
@@ -60,6 +103,7 @@
     std::string _host;
     std::string _path;
     bool        _connected;
+    bool        _debug;
 };
 
 struct network_as_object : public as_object
@@ -73,6 +117,10 @@
 void network_gethost(const fn_call& fn);
 void network_getport(const fn_call& fn);
 void network_getpath(const fn_call& fn);
+void network_connected(const fn_call& fn);
+
+void network_getfilefd(const fn_call& fn);
+void network_getlistenfd(const fn_call& fn);
 #endif
 } // end of gnash namespace
 
Index: gnash/testsuite/actionscript.all/LocalConnection.as
diff -u gnash/testsuite/actionscript.all/LocalConnection.as:1.1 
gnash/testsuite/actionscript.all/LocalConnection.as:1.2
--- gnash/testsuite/actionscript.all/LocalConnection.as:1.1     Thu Feb  2 
00:03:02 2006
+++ gnash/testsuite/actionscript.all/LocalConnection.as Sun Feb  5 01:10:58 2006
@@ -54,3 +54,33 @@
 } else {
        trace("FAILED: LocalConnection::send() doesn't exist");
 }
+
+// Get the domain. By default this should be "localhost" because we
+// haven't made any connections yet,
+var domain = tmp.domain();
+if (domain  == "localhost") {
+       trace("PASSED: LocalConnection::domain() returned localhost");
+} else {
+       trace("FAILED: LocalConnection::domain() returned localhost");
+}
+
+
+// If the listen() times out waiting for a connection, it'll set the
+// main socket file descriptor to an error condition, although the
+// initial file descriptor returned by bind is still fine, since we
+// could always (in a normal application) check later for incoming
+// connections.
+tmp.connect("lc_test");
+if ((tmp.getfilefd() == -1) && (tmp.getlistenfd() > 2)) {
+       trace("PASSED: LocalConnection::connect()");
+} else {
+       trace("FAILED: LocalConnection::connect()");
+}
+
+// Close the connection, and then check the state
+tmp.close();
+if (tmp.connected() == false) {
+       trace("PASSED: LocalConnection::close()");
+} else {
+       trace("FAILED: LocalConnection::close()");
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]