[Top][All Lists]
[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()");
+}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] gnash ./ChangeLog testsuite/actionscript.all/Lo...,
Rob Savoye <=