Index: plugin/plugin.cpp
===================================================================
RCS file: /sources/gnash/gnash/plugin/plugin.cpp,v
retrieving revision 1.93
diff -U 2 -r1.93 plugin.cpp
--- plugin/plugin.cpp	21 Jan 2008 23:28:02 -0000	1.93
+++ plugin/plugin.cpp	30 Jan 2008 18:46:29 -0000
@@ -285,4 +285,6 @@
 	_height(0),
 	_streamfd(-1),
+	_ichan(0),
+	_ichanWatchId(0),
 	_childpid(0),
 	_filefd(-1)
@@ -309,4 +311,16 @@
 nsPluginInstance::~nsPluginInstance()
 {
+	cout << "plugin instance destruction" << endl;
+	if ( _ichan )
+	{
+		cout << "shutting down input chan " << _ichan << endl;
+		GError *error = NULL;
+		g_io_channel_shutdown (_ichan, TRUE, &error);
+		g_io_channel_unref (_ichan);
+	}
+	if ( _ichanWatchId )
+	{
+		g_source_remove(_ichanWatchId);
+	}
 }
 
@@ -356,4 +370,6 @@
 nsPluginInstance::shut()
 {
+	cout << "Shutting down" << endl;
+
 	if (_childpid > 0)
 	{
@@ -540,4 +556,60 @@
 }
 
+bool
+nsPluginInstance::handlePlayerRequestsWrapper(GIOChannel* iochan, GIOCondition cond, nsPluginInstance* plugin)
+{
+	return plugin->handlePlayerRequests(iochan, cond);
+}
+
+bool
+nsPluginInstance::handlePlayerRequests(GIOChannel* iochan, GIOCondition cond)
+{
+	assert(cond == G_IO_IN);
+	int inputfd = g_io_channel_unix_get_fd(iochan);
+
+	cout << "Checking player requests on fd " << inputfd << endl;
+	cout.flush();
+
+#define MAXLINE 256
+	char buf[MAXLINE];
+
+	int ret = read(inputfd, buf, MAXLINE-1);
+	if ( ret == -1 )
+	{
+		cout << " player request channel " << inputfd << " read error " << strerror(errno) << endl;
+		return false;
+	}
+	if ( ! ret )
+	{
+		cout << " no bytes read from player requests channel " << inputfd << endl;
+		return false; // correct ?
+	}
+	buf[ret] = '\0';
+
+	cout << " read " << ret << " bytes from fd " << inputfd << ": " << endl
+		<< buf << endl;
+
+	size_t linelen = ret;
+	if ( linelen < 4 )
+	{
+		cout << "Invalid player request (too short): " << buf << endl;
+		return true;
+	}
+
+	if ( strncmp(buf, "GET ", 4) )
+	{
+		cout << "Unknown player request: " << buf << endl;
+		return true;
+	}
+
+	char* url = buf+4;
+	char* target = "_top"; // todo: fix
+
+	cout << "Asked to get URL '" << url << "'" << endl;
+	NPN_GetURL(_instance, url, target);
+
+	return true;
+}
+
 void
 nsPluginInstance::startProc(Window win)
@@ -570,13 +642,19 @@
 
 	// 0 For reading, 1 for writing.
-	int pipefd[2];
+	int p2c_pipe[2];
+	int c2p_pipe[2];
 	
-	int ret = pipe(pipefd);
+	int ret = pipe(p2c_pipe);
 	if (ret == -1)
 	{
-		cout << "ERROR: pipe() failed: " << strerror(errno) << endl;
+		cout << "ERROR: parent to child pipe() failed: " << strerror(errno) << endl;
 	}
+	_streamfd = p2c_pipe[1];
 
-	_streamfd = pipefd[1];
+	ret = pipe(c2p_pipe);
+	if (ret == -1)
+	{
+		cout << "ERROR: child to parent pipe() failed: " << strerror(errno) << endl;
+	}
 
 	_childpid = fork();
@@ -593,12 +671,20 @@
 	{
 
-		// we want to write, so close read-fd0
-		ret = close (pipefd[0]);
-	
+		// we want to write to p2c pipe, so close read-fd0
+		ret = close (p2c_pipe[0]);
+		if (ret == -1)
+		{
+			cout << "ERROR: p2c_pipe[0] close() failed: " << strerror(errno)
+								<< endl;
+		}
+
+		// we want to read from c2p pipe, so close read-fd1
+		ret = close (c2p_pipe[1]);
 		if (ret == -1)
 		{
-			cout << "ERROR: close() failed: " << strerror(errno)
+			cout << "ERROR: c2p_pipe[1] close() failed: " << strerror(errno)
 								<< endl;
 		}
+	
 
 		cout << "Forked successfully, child process PID is " 
@@ -606,4 +692,8 @@
 								<< endl;
 
+		_ichan = g_io_channel_unix_new(c2p_pipe[0]);
+		g_io_channel_set_close_on_unref(_ichan, true);
+		_ichanWatchId = g_io_add_watch(_ichan, G_IO_IN, (GIOFunc)handlePlayerRequestsWrapper, this);
+
 		return;
 	}
@@ -611,6 +701,6 @@
 	// This is the child scope.
 
-	// We want to read, so close write-fd1
-	ret = close (pipefd[1]); 
+	// We want to read parent to child, so close write-fd1
+	ret = close (p2c_pipe[1]); 
 	if (ret == -1)
 	{
@@ -619,5 +709,5 @@
 
 	// close standard input and direct read-fd1 to standard input
-	ret = dup2 (pipefd[0], fileno(stdin));
+	ret = dup2 (p2c_pipe[0], fileno(stdin));
 	
 	if (ret == -1)
@@ -627,5 +717,5 @@
 
 	// Close all of the browser's file descriptors that we just 
-	// inherited (including pipefd[0] that we just dup'd to fd 0).
+	// inherited (including p2c_pipe[0] that we just dup'd to fd 0).
 	// Experiments show seventy or eighty file descriptors open in
 	// typical cases.  Rather than close all the thousands of possible file
@@ -637,4 +727,6 @@
 	for ( ; numfailed < 10; anfd++)
 	{
+		if ( anfd == c2p_pipe[1] ) continue; // don't close this
+		if ( anfd == c2p_pipe[0] ) continue; // don't close this either (correct?)
 		ret = close (anfd);
 		if (ret < 0) numfailed++;
@@ -646,5 +738,5 @@
 	}
 
-	cout << "Closed " << closed << "files." << endl;
+	cout << "Closed " << closed << " files." << endl;
 
 	/*
@@ -654,8 +746,9 @@
 	// Prepare width, height and window ID variables
 	const size_t buf_size = 30;
-	char xid[buf_size], width[buf_size], height[buf_size];
+	char xid[buf_size], width[buf_size], height[buf_size], hostfd[buf_size];
 	snprintf(xid, buf_size, "%ld", win);
 	snprintf(width, buf_size, "%d", _width);
 	snprintf(height, buf_size, "%d", _height);
+	snprintf(hostfd, buf_size, "%d", c2p_pipe[1]);
 
 	// Prepare Actionscript variables (e.g. Flashvars).
@@ -686,5 +779,5 @@
 	*/ 
 
-	const size_t maxargc = 16 + paramvalues.size() * 2;
+	const size_t maxargc = 18 + paramvalues.size() * 2;
 	const char **argv = new const char *[maxargc];
 
@@ -705,7 +798,12 @@
 	argv[argc++] = height;
 	
+	// Url of the root movie
 	argv[argc++] = "-u";
 	argv[argc++] = _swf_url.c_str();
 
+	// Host FD
+	argv[argc++] = "-F";
+	argv[argc++] = hostfd;
+
 	// Base URL is the page that the SWF is embedded in. It is 
 	// by Gnash for resolving relative URLs in the movie. If the
Index: plugin/plugin.h
===================================================================
RCS file: /sources/gnash/gnash/plugin/plugin.h,v
retrieving revision 1.35
diff -U 2 -r1.35 plugin.h
--- plugin/plugin.h	21 Jan 2008 23:28:02 -0000	1.35
+++ plugin/plugin.h	30 Jan 2008 18:46:29 -0000
@@ -94,4 +94,8 @@
 private:
 
+    static bool handlePlayerRequestsWrapper(GIOChannel* iochan, GIOCondition cond, nsPluginInstance* plugin);
+
+    bool handlePlayerRequests(GIOChannel* iochan, GIOCondition cond);
+
     // EMBED or OBJECT attributes / parameters
     // @@ this should likely replace the _options element below
@@ -106,4 +110,6 @@
     std::map<std::string, std::string> _options;
     int                                _streamfd;
+    GIOChannel*                        _ichan;
+    int                                _ichanWatchId;
     pid_t                              _childpid;
     int                                _filefd;
Index: server/vm/ASHandlers.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/vm/ASHandlers.cpp,v
retrieving revision 1.187
diff -U 2 -r1.187 ASHandlers.cpp
--- server/vm/ASHandlers.cpp	30 Jan 2008 14:51:48 -0000	1.187
+++ server/vm/ASHandlers.cpp	30 Jan 2008 18:46:30 -0000
@@ -2321,4 +2321,5 @@
 		// TODO: should mutex-protect this ?
 		// NOTE: we assuming the hostfd is set in blocking mode here..
+		log_debug("Attempt to write geturl requests fd %d", hostfd);
 		int ret = write(hostfd, cmd, len);
 		if ( ret == -1 )
@@ -2326,9 +2327,10 @@
 			log_error("Could not write to user-provided host requests fd %d: %s", hostfd, strerror(errno));
 		}
-		if ( ret < len )
+		if ( (size_t)ret < len )
 		{
-			log_error("Could only write %d bytes over %d required to user-provided host requests fd %d: %s",
+			log_error("Could only write %d bytes over "SIZET_FMT" required to user-provided host requests fd %d",
 				ret, len, hostfd);
 		}
+		log_debug("Wrote %d bytes of geturl requests (all needed)", ret);
 	}
 
