gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] gnash/libnet Makefile.am buffer.cpp buffer.h cq...


From: Rob Savoye
Subject: [Gnash-commit] gnash/libnet Makefile.am buffer.cpp buffer.h cq...
Date: Fri, 28 Mar 2008 03:30:24 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Rob Savoye <rsavoye>    08/03/28 03:30:23

Added files:
        libnet         : Makefile.am buffer.cpp buffer.h cque.cpp cque.h 
                         cqueue.cpp cqueue.h handler.cpp handler.h 
                         http.cpp http.h netstats.cpp netstats.h 
                         network.cpp network.h rtmp.cpp rtmp.h 
                         statistics.cpp statistics.h 

Log message:
                * libnet: New directory for networking and protocols.
                * 
libnet/buffer.{h,cpp},cque.{h,cpp},handler.{h,cpp},http.{h,cpp},
                
network.{h,cpp},rtmp.{h,cpp},netstats.{h,cpp},statistics.{h,cpp},
                cque.{h,cpp}: Moved from cygnal so they can be shared.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/Makefile.am?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/buffer.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/buffer.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/cque.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/cque.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/cqueue.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/cqueue.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/handler.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/handler.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/http.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/http.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/netstats.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/netstats.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/network.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/network.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/rtmp.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/rtmp.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/statistics.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/statistics.h?cvsroot=gnash&rev=1.1

Patches:
Index: Makefile.am
===================================================================
RCS file: Makefile.am
diff -N Makefile.am
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ Makefile.am 28 Mar 2008 03:30:21 -0000      1.1
@@ -0,0 +1,70 @@
+# 
+#   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 3 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   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
+#
+
+## Process this file with automake to generate Makefile.in
+
+AUTOMAKE_OPTIONS = dejagnu
+
+pkglib_LTLIBRARIES = libgnashnet.la
+
+AM_LDFLAGS = \
+       ../libbase/libgnashbase.la \
+       ../libamf/libgnashamf.la \
+       $(LIBLTDL) \
+       $(GLIB_LIBS) \
+       $(LIBXML_LIBS) \
+       $(CURL_LIBS) \
+       $(BOOST_LIBS) \
+       $(PTHREAD_LIBS)
+
+localedir = $(datadir)/locale
+
+INCLUDES = -I.. \
+        -I$(top_srcdir)        \
+        -I$(top_srcdir)/libamf \
+        -I$(top_srcdir)/libbase \
+        -I$(top_srcdir)/server \
+        -DLOCALEDIR=\"$(localedir)\" \
+        $(LIBXML_CFLAGS) \
+       $(DMALLOC_CFLAGS) \
+       $(CURL_CFLAGS) \
+       $(BOOST_CFLAGS) \
+       $(PTHREAD_CFLAGS)
+
+noinst_HEADERS = \
+       buffer.h \
+       cque.h \
+       handler.h \
+       http.h \
+       network.h \
+       rtmp.h \
+       statistics.h
+
+libgnashnet_la_SOURCES = \
+       buffer.cpp \
+       cque.cpp \
+       handler.cpp \
+       http.cpp \
+       network.cpp \
+       rtmp.cpp \
+       statistics.cpp
+
+# Rebuild with GCC 4.x Mudflap support
+mudflap:
+       @echo "Rebuilding with GCC Mudflap support"
+       $(MAKE) CXXFLAGS="$(CXXFLAGS) $(MUDFLAP_OPT)" LIBS="$(LIBS) 
$(MUDFLAP_LIB)"

Index: buffer.cpp
===================================================================
RCS file: buffer.cpp
diff -N buffer.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ buffer.cpp  28 Mar 2008 03:30:21 -0000      1.1
@@ -0,0 +1,212 @@
+// 
+//   Copyright (C) 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#include <boost/cstdint.hpp>
+#include "buffer.h"
+#include "log.h"
+#include "network.h"
+
+using namespace std;
+using namespace gnash;
+
+namespace cygnal
+{
+
+void *
+Buffer::init(size_t nbytes)
+{
+//    GNASH_REPORT_FUNCTION;
+    if (_ptr == 0) {
+        _ptr = new Network::byte_t[nbytes];
+        _nbytes = nbytes;
+        // this could be a performance hit, but for debugging we leave it in 
so we get
+        // easier to ready hex dumps in GDB,
+        empty();
+    }
+
+#ifdef USE_STATS_BUFFERS
+    clock_gettime (CLOCK_REALTIME, &_stamp);
+#endif
+    return _ptr;
+}
+
+Buffer::Buffer() 
+{
+//    GNASH_REPORT_FUNCTION;
+    _ptr = 0;
+    _nbytes = gnash::NETBUFSIZE;
+    init(gnash::NETBUFSIZE);
+}
+    
+// Create with a size other than the default
+Buffer::Buffer(size_t nbytes)
+{
+//    GNASH_REPORT_FUNCTION;
+    _ptr = 0;
+    _nbytes = nbytes;
+    init(nbytes);
+}
+
+// Delete the allocate memory
+Buffer::~Buffer()
+{
+//    GNASH_REPORT_FUNCTION;
+    if (_ptr) {
+#ifdef USE_STATS_BUFFERS
+       struct timespec now;
+       clock_gettime (CLOCK_REALTIME, &now);
+       log_debug("Buffer %x (%d) stayed in queue for %f seconds",
+                 (void *)_ptr, _nbytes,
+                 (float)((now.tv_sec - _stamp.tv_sec) + ((now.tv_nsec - 
_stamp.tv_nsec)/1e9)));
+#endif
+        delete[] _ptr;
+        _ptr = 0;
+        _nbytes = 0;
+    }
+}
+
+Network::byte_t *
+Buffer::find(Network::byte_t b)
+{
+//    GNASH_REPORT_FUNCTION;
+    for (size_t i=0; i< _nbytes; i++) {
+       if ( *(_ptr + i) == b) {
+           return _ptr + i;
+       }
+    }
+    return 0;
+}
+
+// Put data into the buffer
+void
+Buffer::copy(Network::byte_t *data, size_t nbytes)
+{    
+//    GNASH_REPORT_FUNCTION;
+    std::copy(data, data + nbytes, _ptr);
+}
+
+void
+Buffer::copy(string &str)
+{    
+//    GNASH_REPORT_FUNCTION;
+    std::copy(str.begin(), str.end(), _ptr);
+}
+
+// make ourselves be able to be copied.
+Buffer &
+Buffer::operator=(Buffer *buf)
+{
+//    GNASH_REPORT_FUNCTION;
+    if (buf->size() != _nbytes) {
+         resize(buf->size());
+    }
+    
+    std::copy(buf->reference(), buf->reference() + _nbytes, _ptr);
+
+    return *this;
+}
+
+Buffer &
+Buffer::operator=(Buffer &buf)
+{
+//    GNASH_REPORT_FUNCTION;
+    if (buf.size() != _nbytes) {
+         resize(buf.size());
+    }
+    
+    std::copy(buf.reference(), buf.reference() + _nbytes, _ptr);
+
+    return *this;
+}
+
+// Check to see if two Buffer objects are identical
+bool
+Buffer::operator==(Buffer *buf)
+{ 
+//    GNASH_REPORT_FUNCTION;
+   if (buf->size() == _nbytes) {
+        if (memcmp(buf->reference(), _ptr, _nbytes) == 0)  {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool
+Buffer::operator==(Buffer &buf)
+{
+//    GNASH_REPORT_FUNCTION;
+    if (buf.size() == _nbytes){
+        if (memcmp(buf.reference(), _ptr, _nbytes) == 0)  {
+            return true;
+        }
+    }
+    return false;
+}
+
+// Just reset to having no data, but still having storage
+void
+Buffer::empty()
+{
+//    GNASH_REPORT_FUNCTION;
+    if (_ptr) {
+        memset(_ptr, 0, _nbytes);
+    }
+}
+
+// Resize the buffer that holds the data
+void *
+Buffer::resize(size_t nbytes)
+{
+//    GNASH_REPORT_FUNCTION;
+    // Allocate a new memory block
+    Network::byte_t *tmp = new Network::byte_t[nbytes];
+    // And copy ourselves into it
+    if (nbytes > _nbytes) {
+        std::copy(_ptr, _ptr + _nbytes, tmp);
+    }
+    
+    if (nbytes < _nbytes) {
+        std::copy(_ptr, _ptr + nbytes, tmp);
+    }
+
+    _nbytes = nbytes;
+
+    // Delete the old block, it's unused now
+    delete[] _ptr;
+
+    // Make the memeory block use the new space
+    _ptr = tmp;
+
+    return tmp;
+}
+
+void
+Buffer::dump()
+{
+    cerr << "Buffer is " << _nbytes << " bytes at " << (void *)_ptr << endl;
+    cerr << gnash::hexify((unsigned char *)_ptr, _nbytes, true) << endl;
+}
+
+} // end of cygnal namespace
+
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: buffer.h
===================================================================
RCS file: buffer.h
diff -N buffer.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ buffer.h    28 Mar 2008 03:30:21 -0000      1.1
@@ -0,0 +1,87 @@
+// 
+//   Copyright (C) 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#ifndef __BUFFER_H__
+#define __BUFFER_H__ 1
+
+#include <boost/cstdint.hpp>
+#include <string>
+#include <time.h>
+
+#include "network.h"
+
+// _definst_ is the default instance name
+namespace cygnal
+{
+
+class Buffer 
+{
+public:
+    Buffer();
+    // Create with a size other than the default
+    Buffer(size_t nbytes);
+    
+    // Delete the allocate memory
+    ~Buffer();
+    void empty();
+
+    // Resize the buffer that holds the data
+    void *resize(size_t nbytes);
+
+    // Put data into the buffer
+    void copy(gnash::Network::byte_t *data, size_t nbytes);
+    void copy(gnash::Network::byte_t *data) { copy(data, _nbytes); };
+    void copy(std::string &str);
+    
+    // Accessors
+    gnash::Network::byte_t *find(gnash::Network::byte_t b);
+    gnash::Network::byte_t *begin() { return _ptr ; };
+    gnash::Network::byte_t *end() { return _ptr + _nbytes; };
+    gnash::Network::byte_t *reference() { return _ptr; }
+    size_t size() { return _nbytes; }
+    void setSize(size_t nbytes) { _nbytes = nbytes; };
+    
+    // make ourselves be able to be copied.
+    Buffer &operator=(Buffer *buf);
+    Buffer &operator=(Buffer &buf);
+
+    // Test against other buffers
+    bool operator==(Buffer *buf);
+    bool operator==(Buffer &buf);
+    gnash::Network::byte_t operator[](int x) { return *(_ptr + x); };
+    
+    // debug stuff, not need for running Cygnal
+    void dump();
+private:
+    void *init(size_t nbytes);
+    gnash::Network::byte_t *_ptr;
+    int         _nbytes;
+#ifdef USE_STATS_BUFFERS
+    struct timespec _stamp;    // used for timing how long data stays in the 
queue.
+#endif
+};
+
+
+} // end of cygnal namespace
+
+#endif // end of __BUFFER_H__
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: cque.cpp
===================================================================
RCS file: cque.cpp
diff -N cque.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ cque.cpp    28 Mar 2008 03:30:21 -0000      1.1
@@ -0,0 +1,263 @@
+// 
+//   Copyright (C) 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include <string>
+#include <vector>
+#include <deque>
+#include <time.h>
+
+#include "log.h"
+#include "gmemory.h"
+#include "buffer.h"
+#include "cque.h"
+
+using namespace gnash;
+using namespace std;
+using namespace boost;
+
+
+namespace cygnal
+{
+
+CQue::CQue()
+{
+//    GNASH_REPORT_FUNCTION;
+    _stats.totalbytes = 0;
+    _stats.totalin = 0;
+    _stats.totalout = 0;
+    clock_gettime (CLOCK_REALTIME, &_stats.start);
+    _name = "default";
+}
+
+CQue::~CQue()
+{
+//    GNASH_REPORT_FUNCTION;
+//    clear();
+#if 0
+    deque<Buffer *>::iterator it;
+    boost::mutex::scoped_lock lock(_mutex);
+    for (it = _que.begin(); it != _que.end(); it++) {
+       Buffer *ptr = *(it);
+       delete ptr;
+    }
+#endif
+}
+
+// Wait for a condition variable to trigger
+void
+CQue::wait()
+{
+//    GNASH_REPORT_FUNCTION;
+    boost::mutex::scoped_lock lk(_cond_mutex);
+    _cond.wait(lk);
+//    log_debug("wait mutex released for \"%s\"", _name);
+}
+
+// Notify a condition variable to trigger
+void
+CQue::notify()
+{
+//    GNASH_REPORT_FUNCTION;
+    _cond.notify_one();
+//    log_debug("wait mutex triggered for \"%s\"", _name);
+}
+
+size_t
+CQue::size()
+{
+//    GNASH_REPORT_FUNCTION;
+    boost::mutex::scoped_lock lock(_mutex);
+    return _que.size();
+}
+
+bool
+CQue::push(Buffer *data)
+{
+//    GNASH_REPORT_FUNCTION;
+    boost::mutex::scoped_lock lock(_mutex);
+    _que.push_back(data);
+#ifdef USE_STATS_QUEUE
+    _stats.totalbytes += data->size();
+    _stats.totalin++;
+#endif
+    return true;
+}
+
+// Push data
+bool
+CQue::push(gnash::Network::byte_t *data, int nbytes)
+{
+//    GNASH_REPORT_FUNCTION;
+    Buffer *buf = new Buffer;
+    std::copy(data, data + nbytes, buf->reference());
+    return push(buf);
+}
+
+
+// Pop the first date element off the FIFO
+Buffer *
+CQue::pop()
+{
+//    GNASH_REPORT_FUNCTION;
+    Buffer *buf = 0;
+    boost::mutex::scoped_lock lock(_mutex);
+    if (_que.size()) {
+        buf = _que.front();
+        _que.pop_front();
+#ifdef USE_STATS_QUEUE
+       _stats.totalout++;
+#endif
+    }
+    return buf;
+}
+
+// Peek at the first data element without removing it
+Buffer *
+CQue::peek()
+{
+//    GNASH_REPORT_FUNCTION;
+    boost::mutex::scoped_lock lock(_mutex);
+    if (_que.size()) {
+        return _que.front();
+    }
+    return 0;  
+}
+
+// Return the size of the queues
+void
+CQue::clear()
+{
+//    GNASH_REPORT_FUNCTION;
+    boost::mutex::scoped_lock lock(_mutex);
+    _que.clear();
+}
+
+// Remove a range of elements
+void
+CQue::remove(Buffer *begin, Buffer *end)
+{
+    GNASH_REPORT_FUNCTION;
+    deque<Buffer *>::iterator it;
+    deque<Buffer *>::iterator start;
+    deque<Buffer *>::iterator stop;
+    boost::mutex::scoped_lock lock(_mutex);
+    Buffer *ptr;
+    for (it = _que.begin(); it != _que.end(); it++) {
+       ptr = *(it);
+       if (ptr->reference() == begin->reference()) {
+           start = it;
+       }
+       if (ptr->reference() == end->reference()) {
+           stop = it;
+           break;
+       }
+    }
+    _que.erase(start, stop);
+}
+
+// Remove an element
+void
+CQue::remove(Buffer *element)
+{
+    GNASH_REPORT_FUNCTION;
+    deque<Buffer *>::iterator it;
+    boost::mutex::scoped_lock lock(_mutex);
+    for (it = _que.begin(); it != _que.end(); it++) {
+       Buffer *ptr = *(it);
+       if (ptr->reference() == element->reference()) {
+           _que.erase(it);
+       }
+    }
+}
+
+// Merge sucessive buffers into one single larger buffer. This is for some
+// protocols, than have very long headers.
+Buffer *
+CQue::merge(Buffer *begin)
+{
+    GNASH_REPORT_FUNCTION;
+    int totalsize = 0;
+    deque<Buffer *>::iterator it;
+    vector<deque<Buffer *>::iterator> elements;
+    vector<deque<Buffer *>::iterator>::iterator eit;
+    boost::mutex::scoped_lock lock(_mutex);
+    for (it = _que.begin(); it != _que.end(); it++) {
+       Buffer *ptr = *(it);
+       if (totalsize > 0) {
+           totalsize += ptr->size();
+           elements.push_back(it);
+           if (ptr->size() < gnash::NETBUFSIZE) {
+               Buffer *newbuf = new Buffer(totalsize);
+               Network::byte_t *tmp = newbuf->reference();
+               Buffer *buf;
+//             _que.insert(elements.begin(), newbuf);
+               for (eit = elements.begin(); eit != elements.end(); eit++) {
+                   deque<Buffer *>::iterator ita = *(eit);
+                   buf = *(ita);
+                   std::copy(buf->reference(), buf->reference() + buf->size(), 
tmp);
+                   tmp += buf->size();
+                   _que.erase(ita);
+               }
+               _que.push_back(newbuf);
+               return newbuf;
+           }
+           continue;
+       }
+       if (ptr->reference() == begin->reference()) {
+           totalsize = ptr->size();
+           elements.push_back(it);
+       }
+    }
+    return 0;
+}
+
+// Dump internal data.
+void
+CQue::dump()
+{
+//    GNASH_REPORT_FUNCTION;
+    deque<Buffer *>::iterator it;
+    boost::mutex::scoped_lock lock(_mutex);
+    cerr << endl << "CQue \"" << _name << "\" has "<< _que.size() << " 
buffers." << endl;
+    for (it = _que.begin(); it != _que.end(); it++) {
+       Buffer *ptr = *(it);
+        ptr->dump();
+    }
+#ifdef USE_STATS_QUEUE
+    struct timespec now;
+    clock_gettime (CLOCK_REALTIME, &now);
+    cerr << "Que lifespan is " <<
+       (float)((now.tv_sec - _stats.start.tv_sec) + ((now.tv_nsec - 
_stats.start.tv_nsec)/1e9)) << " seconds" << endl;
+    cerr << "Total number of bytes is " << _stats.totalbytes << " bytes" << 
endl;
+    cerr << "Total number of packets pushed to queue is: " << _stats.totalin 
<< endl;
+    cerr << "Total number of packets popped from queue is: " << 
_stats.totalout << endl;
+#endif
+}
+
+} // end of cygnal namespace
+
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:
+

Index: cque.h
===================================================================
RCS file: cque.h
diff -N cque.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ cque.h      28 Mar 2008 03:30:21 -0000      1.1
@@ -0,0 +1,100 @@
+// 
+//   Copyright (C) 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#ifndef __CQUE_H__
+#define __CQUE_H__ 1
+
+#include <boost/cstdint.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+#include <deque>
+#include <time.h>
+
+#include "buffer.h"
+#include "network.h"
+
+// _definst_ is the default instance name
+namespace cygnal
+{
+
+class CQue {
+public:
+#ifdef USE_STATS_QUEUE
+    typedef struct {
+       struct timespec start;
+       int             totalbytes;
+       int             totalin;
+       int             totalout;
+    } que_stats_t;
+#endif
+    CQue();
+    CQue(const std::string &str) { _name = str; };
+    ~CQue();
+    // Push data onto the que
+    bool push(gnash::Network::byte_t *data, int nbytes);
+    bool push(Buffer *data);
+    // Pop the first date element off the que
+    Buffer *pop();
+    // Peek at the first date element witjhout removing it from the que
+    Buffer *peek();
+    // Get the number of elements in the que
+    size_t size();
+    // Wait for a condition variable to trigger
+    void wait();
+    // Notify a condition variable to trigger
+    void notify();
+    // Empty the que of all data. 
+    void clear();
+    // Remove a range of elements
+    void remove(Buffer *begin, Buffer *end);
+//     // Remove an element
+//    void remove(Buffer *it);
+    void remove(Buffer *it);
+    // Merge sucessive buffers into one single larger buffer. This is for some
+    // protocols, than have very long headers.
+    Buffer *merge(Buffer *begin);
+    
+    // Dump the data to the terminal
+    void dump();
+    que_stats_t *stats() { return &_stats; };
+    void setName(const std::string &str) { _name = str; }
+private:
+    // an optional name for the queue, only used for debugging messages to 
make them unique
+    std::string _name;
+    // The queue itself
+    std::deque<Buffer *> _que;
+    // A condition variable used to signal the other thread when the que has 
data
+    boost::condition   _cond;
+    // This is the mutex used by the condition variable. It needs to be 
separate from the
+    // one used to lock access to the que.
+    boost::mutex       _cond_mutex;
+    // This is the mutex that control access to the que.
+    boost::mutex       _mutex;
+#ifdef USE_STATS_QUEUE
+    que_stats_t                _stats;
+#endif
+};
+    
+} // end of cygnal namespace
+
+#endif // end of __CQUE_H__
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: cqueue.cpp
===================================================================
RCS file: cqueue.cpp
diff -N cqueue.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ cqueue.cpp  28 Mar 2008 03:30:22 -0000      1.1
@@ -0,0 +1,116 @@
+// http.cpp:  HyperText Transport Protocol handler for Cygnal, for Gnash.
+// 
+//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include <boost/thread/mutex.hpp>
+#include <boost/date_time/gregorian/gregorian.hpp>
+//#include <boost/date_time/local_time/local_time.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+//#include <boost/date_time/time_zone_base.hpp>
+#include <string>
+#include <vector>
+#include "log.h"
+#include "cqueue.h"
+
+using namespace gnash;
+using namespace std;
+using namespace boost;
+
+namespace cygnal
+{
+
+CQueue::CQueue()
+{
+//    GNASH_REPORT_FUNCTION;
+}
+
+CQueue::~CQueue()
+{
+//    GNASH_REPORT_FUNCTION;
+}
+
+#if 0
+void
+memcpy(boost::uint8_t *data, size_t size,
+                 vector<uint8_t> *ptr)
+{
+//    GNASH_REPORT_FUNCTION;
+    ptr->reserve(size);
+    std::copy(data, data + size, ptr->begin());
+}
+    
+void
+memcpy(std::vector<uint8_t> *ptr,
+                 uint8_t *data, size_t size)
+{
+//    GNASH_REPORT_FUNCTION;
+    data = new uint8_t[size + 1];
+    std::copy(ptr->begin(), ptr->end(), data);
+}
+#endif
+
+// Push bytes on the FIFO
+bool
+CQueue::push(uint8_t *data, int nbytes)
+{
+//    GNASH_REPORT_FUNCTION;
+    vector<boost::uint8_t> *ptr = new vector<boost::uint8_t>;
+    ptr->reserve(nbytes);
+    std::copy(data, data + nbytes, ptr->begin());
+    _queue.push_back(ptr);
+}
+
+bool
+CQueue::push(vector<uint8_t> *data)
+{
+//    GNASH_REPORT_FUNCTION;
+    _queue.push_back(data);
+}
+
+// Pop the first date element off the FIFO
+vector<uint8_t> *
+CQueue::pop()
+{
+//    GNASH_REPORT_FUNCTION;
+}
+
+// Peek at the first data element without removing it
+vector <uint8_t> *
+CQueue::peek()
+{
+//    GNASH_REPORT_FUNCTION;
+}
+
+// Dump internal data.
+void
+CQueue::dump()
+{
+//    GNASH_REPORT_FUNCTION;
+}
+
+} // end of cygnal namespace
+
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: cqueue.h
===================================================================
RCS file: cqueue.h
diff -N cqueue.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ cqueue.h    28 Mar 2008 03:30:22 -0000      1.1
@@ -0,0 +1,72 @@
+// http.cpp:  HyperText Transport Protocol handler for Cygnal, for Gnash.
+// 
+//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#ifndef __CQUEUE_H__
+#define __CQUEUE_H__ 1
+
+
+#include <boost/cstdint.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/date_time/gregorian/gregorian.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <string>
+#include <iostream>
+#include <vector>
+#include "log.h"
+
+namespace cygnal
+{
+
+class CQueue 
+{
+public:
+    CQueue();
+    ~CQueue();
+
+    // Push bytes on the FIFO
+    bool push(boost::uint8_t *data, int nbytes);
+    bool push(std::vector<boost::uint8_t> *data);
+    // Pop the first date element off the FIFO
+    std::vector<uint8_t> *pop();
+    // Peek at the first data element without removing it
+    std::vector<uint8_t> *peek();
+//     void memcpy(boost::uint8_t *data, size_t size,
+//                  std::vector<boost::uint8_t> *ptr);
+//     void memcpy(std::vector<boost::uint8_t> *ptr,
+//                  boost::uint8_t *data, size_t size);
+    size_t size() { return _queue.size(); };
+    // Dump internal data.
+    void dump();
+private:
+    std::vector<std::vector<boost::uint8_t> *> _queue;
+};
+
+
+} // end of cygnal namespace
+
+#endif // end of __CQUEUE_H__
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: handler.cpp
===================================================================
RCS file: handler.cpp
diff -N handler.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ handler.cpp 28 Mar 2008 03:30:22 -0000      1.1
@@ -0,0 +1,294 @@
+// 
+//   Copyright (C) 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <string>
+#include <deque>
+#include <list>
+#include <map>
+
+#include "log.h"
+#include "network.h"
+#include "buffer.h"
+
+#include "rtmp.h"
+#include "http.h"
+
+using namespace gnash;
+using namespace std;
+using namespace boost;
+
+namespace cygnal
+{
+
+extern map<int, Handler *> handlers;
+
+Handler::Handler()
+    : _die(false), _netfd(0)
+{
+//    GNASH_REPORT_FUNCTION;
+}
+
+Handler::~Handler()
+{
+//    GNASH_REPORT_FUNCTION;
+    closeConnection();
+    _die = true;
+    notifyout();
+    notifyin();
+}
+
+bool
+Handler::push(Buffer *data, fifo_e direction)
+{
+//    GNASH_REPORT_FUNCTION;
+    if (direction == Handler::OUTGOING) {
+       _outgoing.push(data);
+       return true;
+    }
+    if (direction == Handler::INCOMING) {
+       _incoming.push(data);
+       return true;
+    }
+    
+    return false;
+}
+
+// Push bytes on the outgoing FIFO
+bool
+Handler::push(gnash::Network::byte_t *data, int nbytes, fifo_e direction)
+{
+//    GNASH_REPORT_FUNCTION;
+    Buffer *ptr = new Buffer;
+    ptr->copy(data, nbytes);
+    return push(ptr, direction);
+}
+
+// Pop the first date element off the FIFO
+Buffer *
+Handler::pop(fifo_e direction)
+{
+//    GNASH_REPORT_FUNCTION;
+    Buffer *buf;
+    
+    if (direction == Handler::OUTGOING) {
+       if (_outgoing.size()) {
+           buf = _outgoing.pop();
+           return buf; 
+       }
+    }
+    if (direction == Handler::INCOMING) {
+       if (_incoming.size()) {
+           buf = _incoming.pop();
+           return buf; 
+       }
+    }
+
+    return buf;
+}
+
+// Peek at the first data element without removing it
+Buffer *
+Handler::peek(fifo_e direction)
+{
+//    GNASH_REPORT_FUNCTION;
+    if (direction == Handler::OUTGOING) {
+       if (_outgoing.size()) {
+           return _outgoing.peek();
+       }
+    }
+    if (direction == Handler::INCOMING) {
+       if (_incoming.size()) {
+           return _incoming.peek();
+       }
+    }    
+    return 0;
+}
+
+// Return the size of the queues
+size_t
+Handler::size(fifo_e direction)
+{
+//    GNASH_REPORT_FUNCTION;
+    if (direction == Handler::OUTGOING) {
+       return _outgoing.size();
+    }
+    if (direction == Handler::INCOMING) {
+       return _incoming.size();
+    }
+    
+    return 0;                  // we should never actually get to here
+}
+
+// Return the size of the queues
+void
+Handler::clear(fifo_e direction)
+{
+//    GNASH_REPORT_FUNCTION;
+    if (direction == Handler::OUTGOING) {
+       _outgoing.clear();
+    }
+    if (direction == Handler::INCOMING) {
+       _incoming.clear();
+    }    
+}
+
+// Dump internal data.
+void
+Handler::dump()
+{
+//    GNASH_REPORT_FUNCTION;
+    _incoming.dump();
+    _outgoing.dump();    
+}
+
+// start the two thread handlers for the queues
+bool
+Handler::start(thread_params_t *args)
+{
+    GNASH_REPORT_FUNCTION;
+//    Handler *hand = reinterpret_cast<Handler *>(args->handle);
+    
+    _incoming.setName("Incoming");
+    _outgoing.setName("Outgoing");
+    
+    log_debug(_("Starting Handlers for port %d, tid %ld"),
+             args->port, pthread_self());
+
+    if (args->port == 4080) {                  // FIXME: hack alert!
+       boost::thread handler(boost::bind(&httphandler, args));
+    }
+    if (args->port == RTMP) {
+       boost::thread handler(boost::bind(&rtmp_handler, args));
+    }
+    
+    boost::thread outport(boost::bind(&netout_handler, args));
+    boost::thread inport(boost::bind(&netin_handler, args));
+// We don't want to wait for the threads to complete, we
+// want to return to the main program so it can spawn another
+// thread for the next incoming connection.    
+//     inport.join();    
+//     outport.join();
+//     handler.join();
+//     if (_die) {
+//     log_debug("Handler done...");
+//     }
+    return true;
+}
+    
+extern "C" {
+void
+netin_handler(Handler::thread_params_t *args)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    Handler *hand = reinterpret_cast<Handler *>(args->handle);
+
+    log_debug("Starting to wait for data in net for fd #%d", args->netfd);
+    
+    do {
+       Buffer *buf = new Buffer;
+       size_t ret = hand->readNet(args->netfd, buf->reference(), buf->size(), 
1);
+       // the read timed out as there was no data, but the socket is still 
open.
+       if (ret == 0) {
+           continue;
+       }
+       // ret is "no position" when the socket is closed from the other end of 
the connection,
+       // so we're done.
+       if (ret == string::npos) {
+           break;
+       }
+       // We got data. Resize the buffer if necessary.
+       if (ret > 0) {
+           if (ret != buf->size()) {
+               buf->resize(ret);
+           }
+           hand->push(buf);
+           hand->notify();
+       } else {
+           log_debug("no more data for fd #%d, exiting...", args->netfd);
+           hand->die();
+           break;
+       }
+    } while (!hand->timetodie());
+    // We're done. Notify the other threads the socket is closed, and tell 
them to die.
+    log_debug("Net In handler done for fd #%d...", args->netfd);
+    hand->notify();
+    hand->closeNet(args->netfd);
+//    hand->dump();
+}
+
+void
+netout_handler(Handler::thread_params_t *args)
+{
+//    GNASH_REPORT_FUNCTION;
+    int ret;
+    Handler *hand = reinterpret_cast<Handler *>(args->handle);
+
+    log_debug("Starting to wait for data in que for fd #%d", args->netfd);
+    
+    do {
+       // Don't look for any more packets in the que cause we're done
+       if (hand->timetodie()) {
+           break;
+       }
+       hand->waitout();
+       while (hand->outsize()) {
+           Buffer *buf = hand->popout();
+//         log_debug("FIXME: got data in Outgoing que");
+//         buf->dump();
+//         ret = hand->writeNet(buf->reference(), buf->size(), 15);
+//         if (buf->size() != gnash::NETBUFSIZE) {
+//                     log_debug("Got smaller packet, size %d", buf->size());  
        
+//         }
+           ret = hand->writeNet(args->netfd, buf);
+           delete buf;
+       }
+    } while (ret > 0);
+    hand->die();
+    log_debug("Net Out handler done for fd #%d...", args->netfd);
+    hand->notifyin();
+    hand->closeNet(args->netfd);
+#if 0
+    map<int, Handler *>::iterator hit = handlers.find(args->netfd);
+    if ((*hit).second) {
+       log_debug("Removing handle %x for fd #%d: ",
+                 (void *)hand), args->netfd;
+       handlers.erase(args->netfd);
+    }
+    delete hand;
+#endif
+}
+    
+} // end of extern C
+
+} // end of cygnal namespace
+
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:
+

Index: handler.h
===================================================================
RCS file: handler.h
diff -N handler.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ handler.h   28 Mar 2008 03:30:22 -0000      1.1
@@ -0,0 +1,163 @@
+// 
+//   Copyright (C) 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#ifndef __HANDLER_H__
+#define __HANDLER_H__ 1
+
+#include <boost/cstdint.hpp>
+//#include <boost/thread/condition.hpp>
+#include <string>
+#include <deque>
+
+#include "log.h"
+#include "network.h"
+#include "buffer.h"
+#include "cque.h"
+#include "network.h"
+
+// _definst_ is the default instance name
+namespace cygnal
+{
+
+
+class Handler : public gnash::Network
+{
+public:
+    Handler();
+    ~Handler();
+
+    typedef enum {
+       UNKNOWN,
+       STATUS,
+       POLL,
+       HELP,
+       INTERVAL,
+       QUIT,
+    } admin_cmd_e;
+    // This is used to pass parameters to a thread using boost::bind
+    typedef struct {
+       int netfd;
+       int port;
+       void *handle;
+       std::string filespec;
+    } thread_params_t ;
+    
+    // Specify which queue should be used
+    typedef enum { INCOMING, OUTGOING } fifo_e;
+    
+    // Push bytes on the incoming FIFO, which is the default
+    bool push(Buffer *data)
+       { return _incoming.push(data); };
+    bool push(Buffer *data, fifo_e direction);
+    bool push(gnash::Network::byte_t *data, int nbytes, fifo_e direction);
+    bool push(gnash::Network::byte_t *data, int nbytes)
+       { return _incoming.push(data, nbytes); };
+    bool pushin(gnash::Network::byte_t *data, int nbytes)
+       { return _incoming.push(data, nbytes); };
+    bool pushin(Buffer *data)
+       { return _incoming.push(data); };
+    
+    // Push bytes on the incoming FIFO, which must be specified
+    bool pushout(gnash::Network::byte_t *data, int nbytes)
+       { return _outgoing.push(data, nbytes); };
+    bool pushout(Buffer *data)
+       { return _outgoing.push(data); };
+    
+    // Pop the first date element off the incoming FIFO
+    Buffer *pop() { return _incoming.pop(); };
+    Buffer *pop(fifo_e direction);
+    Buffer *popin()
+       { return _incoming.pop(); };
+    // Pop the first date element off the outgoing FIFO
+    Buffer *popout()
+       { return _outgoing.pop(); };
+    
+    // Peek at the first data element without removing it
+    Buffer *peek() { return _incoming.peek(); };
+    Buffer *peek(fifo_e direction);
+    Buffer *peekin()
+       { return _incoming.peek(); };
+    // Pop the first date element off the outgoing FIFO
+    Buffer *peekout()
+       { return _outgoing.peek(); };    
+
+    // Removes all the buffers from the queues
+    void clear() { _incoming.clear(); };
+    void clear(fifo_e direction);
+    void clearin() { _incoming.clear(); };
+    void clearout() { _outgoing.clear(); };
+    void clearall() { _outgoing.clear(); _incoming.clear(); };
+    
+    // Return the size of the queues, default to the incoming queue
+    size_t size(fifo_e direction);
+    size_t size() { return _incoming.size(); };
+    size_t insize() { return _incoming.size(); };
+    size_t outsize() { return _outgoing.size(); };
+
+    // Notify the other thread a message is in the que
+    void notify() { _incoming.notify(); };
+    void notifyin() { _incoming.notify(); };
+    void notifyout() { _outgoing.notify(); };
+
+    // Wait for a message from the other thread
+    void wait() { _incoming.wait(); };
+    void waitin() { _incoming.wait(); };
+    void waitout() { _outgoing.wait(); };
+
+    // start the two thread handlers for the queues
+    bool start(thread_params_t *args);
+
+    // Take a buffer and write it to the network
+    int writeNet(int fd, Buffer *buf)
+       { return Network::writeNet(fd, buf->reference(), buf->size()); };
+    
+    int writeNet(Buffer *buf)
+       { return Network::writeNet(buf->reference(), buf->size()); };
+    
+    // Dump internal data.
+    void dump();
+#ifdef USE_STATS_QUEUE
+    CQue::que_stats_t *statsin()  { return _incoming.stats(); };
+    CQue::que_stats_t *statsout() { return _outgoing.stats(); };
+#endif
+    void die() { _die = true; _outgoing.notify(); };
+    bool timetodie() { return _die; };
+    
+private:
+    bool _die;
+    int _netfd;
+    CQue _incoming;
+    CQue _outgoing;
+};
+
+// This is the thread for all incoming network connections, which
+// has to be in C.
+extern "C" {
+    void netin_handler(Handler::thread_params_t *args);
+    void netout_handler(Handler::thread_params_t *args);
+    void start_handler(Handler::thread_params_t *args);
+}
+
+} // end of cygnal namespace
+
+#endif // end of __HANDLER_H__
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: http.cpp
===================================================================
RCS file: http.cpp
diff -N http.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ http.cpp    28 Mar 2008 03:30:22 -0000      1.1
@@ -0,0 +1,1337 @@
+// http.cpp:  HyperText Transport Protocol handler for Cygnal, for Gnash.
+// 
+//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include <boost/thread/mutex.hpp>
+#include <boost/date_time/gregorian/gregorian.hpp>
+//#include <boost/date_time/local_time/local_time.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+//#include <boost/date_time/time_zone_base.hpp>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string>
+#include <iostream>
+#include <cstring>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <algorithm>
+
+#include "http.h"
+#include "log.h"
+#include "network.h"
+#include "handler.h"
+
+using namespace gnash;
+using namespace std;
+
+static boost::mutex stl_mutex;
+
+namespace cygnal
+{
+
+extern map<int, Handler *> handlers;
+
+// FIXME, this seems too small to me.  --gnu
+static const int readsize = 1024;
+
+HTTP::HTTP() 
+    : _filesize(0),
+      _port(80),
+      _keepalive(true),
+      _handler(0),
+      _clientid(0),
+      _index(0)
+{
+//    GNASH_REPORT_FUNCTION;
+//    struct status_codes *status = new struct status_codes;
+    
+//    _status_codes(CONTINUE, status);
+}
+
+HTTP::HTTP(Handler *hand) 
+    : _filesize(0), _port(80), _keepalive(false)
+{
+//    GNASH_REPORT_FUNCTION;
+    _handler = hand;
+}
+
+HTTP::~HTTP()
+{
+//    GNASH_REPORT_FUNCTION;
+}
+
+bool
+HTTP::clearHeader()
+{
+    _header.str("");
+    _body.str("");
+    _charset.clear();
+    _connections.clear();
+    _language.clear();
+    _encoding.clear();
+    _te.clear();
+    _accept.clear();
+    _filesize = 0;
+    _clientid = 0;
+    _index = 0;
+    return true;
+}
+
+HTTP &
+HTTP::operator = (HTTP& /*obj*/)
+{
+    GNASH_REPORT_FUNCTION;
+//    this = obj;
+    // TODO: FIXME !
+    return *this; 
+}
+
+bool
+HTTP::waitForGetRequest(Network& /*net*/)
+{
+    GNASH_REPORT_FUNCTION;
+    return false;              // FIXME: this should be finished
+}
+
+bool
+HTTP::waitForGetRequest()
+{
+    GNASH_REPORT_FUNCTION;
+
+//     Network::byte_t buffer[readsize+1];
+//     const char *ptr = reinterpret_cast<const char *>(buffer);
+//     memset(buffer, 0, readsize+1);
+    
+//    _handler->wait();
+    Buffer *buf = _handler->pop();
+
+    if (buf == 0) {
+       log_debug("Que empty, net connection dropped for fd #%d", 
_handler->getFileFd());
+       return false;
+    }
+    
+    clearHeader();
+    extractCommand(buf);    
+    extractAccept(buf);
+    extractMethod(buf);
+    extractReferer(buf);
+    extractHost(buf);
+    extractAgent(buf);
+    extractLanguage(buf);
+    extractCharset(buf);
+    extractConnection(buf);
+    extractKeepAlive(buf);
+    extractEncoding(buf);
+    extractTE(buf);
+//    dump();
+
+    delete buf;                        // we're done with the buffer
+    
+    _filespec = _url;
+    if (!_url.empty()) {
+       return true;
+    }
+    return false;
+}
+
+bool
+HTTP::formatHeader(http_status_e type)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    formatHeader(_filesize, type);
+    return true;
+}
+
+
+bool
+HTTP::formatHeader(int filesize, http_status_e type)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    _header << "HTTP/1.1 200 OK" << "\r\n";
+    formatDate();
+    formatServer();
+//     if (type == NONE) {
+//     formatConnection("close"); // this is the default for HTTP 1.1
+//     }
+//     _header << "Accept-Ranges: bytes" << "\r\n";
+    formatLastModified();
+    formatEtag("24103b9-1c54-ec8632c0"); // FIXME: borrowed from tcpdump
+    formatAcceptRanges("bytes");
+    formatContentLength(filesize);
+    formatKeepAlive("timeout=15, max=100");
+    formatConnection("Keep-Alive");
+    formatContentType();
+    // All HTTP messages are followed by a blank line.
+    terminateHeader();
+    return true;
+}
+
+bool
+HTTP::formatErrorResponse(http_status_e code)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    // First build the message body, so we know how to set Content-Length
+    _body << "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">" << "\r\n";
+    _body << "<html><head>" << "\r\n";
+    _body << "<title>" << code << " Not Found</title>" << "\r\n";
+    _body << "</head><body>" << "\r\n";
+    _body << "<h1>Not Found</h1>" << "\r\n";
+    _body << "<p>The requested URL " << _filespec << " was not found on this 
server.</p>" << "\r\n";
+    _body << "<hr>" << "\r\n";
+    _body << "<address>Cygnal (GNU/Linux) Server at localhost Port " << _port 
<< " </address>" << "\r\n";
+    _body << "</body></html>" << "\r\n";
+    _body << "\r\n";
+
+    // First build the header
+    _header << "HTTP/1.1 " << code << " Not Found" << "\r\n";
+    formatDate();
+    formatServer();
+    _filesize = _body.str().size();
+    formatContentLength(_filesize);
+    formatConnection("close");
+    formatContentType(HTTP::HTML);
+    return true;
+}
+
+bool
+HTTP::formatDate()
+{
+//    GNASH_REPORT_FUNCTION;
+    boost::posix_time::ptime now = 
boost::posix_time::second_clock::local_time();
+    
+//    cout <<  now.time_of_day() << "\r\n";
+    
+    boost::gregorian::date d(now.date());
+//     boost::gregorian::date d(boost::gregorian::day_clock::local_day());
+//     cout << boost::posix_time::to_simple_string(now) << "\r\n";
+//     cout << d.day_of_week() << "\r\n";
+//     cout << d.day() << "\r\n";
+//     cout << d.year() << "\r\n";
+//     cout << d.month() << "\r\n";
+    
+//    boost::date_time::time_zone_ptr zone(new posix_time_zone("MST"));
+//    boost::date_time::time_zone_base b(now "MST");
+//    cout << zone.dst_zone_abbrev() << "\r\n";
+
+    _header << "Date: " << d.day_of_week();
+    _header << ", " << d.day();
+    _header << " "  << d.month();
+    _header << " "  << d.year();
+    _header << " "  << now.time_of_day();
+    _header << " GMT" << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatServer()
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "Server: Cygnal (GNU/Linux)" << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatServer(const string &data)
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "Server: " << data << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatMethod(const string &data)
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "Method: " << data << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatReferer(const string &refer)
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "Referer: " << refer << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatConnection(const string &options)
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "Connection: " << options << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatKeepAlive(const string &options)
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "Keep-Alive: " << options << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatContentType()
+{
+    return formatContentType(_filetype);
+}
+
+bool
+HTTP::formatContentType(filetype_e filetype)
+{
+//    GNASH_REPORT_FUNCTION;
+    
+    switch (filetype) {
+      case HTML:
+         _header << "Content-Type: text/html" << "\r\n";
+//       _header << "Content-Type: text/html; charset=UTF-8" << "\r\n";
+         break;
+      case SWF:
+         _header << "Content-Type: application/x-shockwave-flash" << "\r\n";
+//       _header << "Content-Type: application/futuresplash" << "\r\n";
+         break;
+      case VIDEO:
+         _header << "Content-Type: video/flv" << "\r\n";
+         break;
+      case MP3:
+         _header << "Content-Type: audio/mpeg" << "\r\n";
+         break;
+      case FCS:
+         _header << "Content-Type: application/x-fcs" << "\r\n";
+         break;
+      default:
+         _header << "Content-Type: text/html" << "\r\n";
+//       _header << "Content-Type: text/html; charset=UTF-8" << "\r\n";
+    }
+    return true;
+}
+
+bool
+HTTP::formatContentLength()
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "Content-Length: " << _filesize << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatContentLength(int filesize)
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "Content-Length: " << filesize << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatHost(const string &host)
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "Host: " << host << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatAgent(const string &agent)
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "User-Agent: " << agent << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatAcceptRanges(const string &range)
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "Accept-Ranges: " << range << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatEtag(const string &tag)
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "Etag: " << tag << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatLastModified(const string &date)
+{
+    _header << "Last-Modified: " << date << "\r\n";
+}
+
+bool
+HTTP::formatLastModified()
+{
+//    GNASH_REPORT_FUNCTION;
+    boost::posix_time::ptime now = 
boost::posix_time::second_clock::local_time();
+    stringstream date;
+    
+    boost::gregorian::date d(now.date());
+    
+    date << d.day_of_week();
+    date << ", " << d.day();
+    date << " "  << d.month();
+    date << " "  << d.year();
+    date << " "  << now.time_of_day();
+    date << " GMT";
+
+    return formatLastModified(date.str());
+}
+
+bool
+HTTP::formatLanguage(const string &lang)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    // For some browsers this appears to also be Content-Language
+    _header << "Accept-Language: " << lang << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatCharset(const string &set)
+{
+//    GNASH_REPORT_FUNCTION;
+    // For some browsers this appears to also be Content-Charset
+    _header << "Accept-Charset: " << set << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatEncoding(const string &code)
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "Accept-Encoding: " << code << "\r\n";
+    return true;
+}
+
+bool
+HTTP::formatTE(const string &te)
+{
+//    GNASH_REPORT_FUNCTION;
+    _header << "TE: " << te << "\r\n";
+    return true;
+}
+
+bool
+HTTP::sendGetReply(http_status_e code)
+{
+    GNASH_REPORT_FUNCTION;
+    
+    formatHeader(_filesize, code);
+//    int ret = Network::writeNet(_header.str());
+    Buffer *buf = new Buffer;
+//    Network::byte_t *ptr = (Network::byte_t *)_body.str().c_str();
+//     buf->copy(ptr, _body.str().size());
+//    _handler->dump();
+    if (_header.str().size()) {
+       buf->resize(_header.str().size());
+       string str = _header.str();
+       buf->copy(str);
+       _handler->pushout(buf);
+       _handler->notifyout();
+        log_debug (_("Sent GET Reply"));
+       return true; // Default to true
+    } else {
+       clearHeader();
+       log_debug (_("Couldn't send GET Reply, no header data"));
+    }
+    
+    return false;
+}
+
+bool
+HTTP::sendPostReply(rtmpt_cmd_e code)
+{
+    GNASH_REPORT_FUNCTION;
+
+    _header << "HTTP/1.1 200 OK" << "\r\n";
+    formatDate();
+    formatServer();
+    formatContentType(HTTP::FCS);
+    // All HTTP messages are followed by a blank line.
+    terminateHeader();
+    return true;
+
+#if 0
+    formatHeader(_filesize, code);
+    Buffer *buf = new Buffer;
+    if (_header.str().size()) {
+       buf->resize(_header.str().size());
+       string str = _header.str();
+       buf->copy(str);
+       _handler->pushout(buf);
+       _handler->notifyout();
+        log_debug (_("Sent GET Reply"));
+       return true; // Default to true
+    } else {
+       clearHeader();
+       log_debug (_("Couldn't send POST Reply, no header data"));
+    }
+#endif
+    return false;
+}
+
+bool
+HTTP::formatRequest(const string &url, http_method_e req)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    _header.str("");
+
+    _header << req << " " << url << "HTTP/1.1" << "\r\n";
+    _header << "User-Agent: Opera/9.01 (X11; Linux i686; U; en)" << "\r\n";
+    _header << "Accept: text/html, application/xml;q=0.9, 
application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, 
*/*;q=0.1" << "\r\n";
+
+    _header << "Accept-Language: en" << "\r\n";
+    _header << "Accept-Charset: iso-8859-1, utf-8, utf-16, *;q=0.1" << "\r\n";
+    
+    _header << "Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0" << 
"\r\n";
+    _header << "Referer: " << url << "\r\n";
+
+    _header << "Connection: Keep-Alive, TE" << "\r\n";
+    _header << "TE: deflate, gzip, chunked, identity, trailers" << "\r\n";
+    return true;
+}
+// bool
+// HTTP::sendGetReply(Network &net)
+// {
+//     GNASH_REPORT_FUNCTION;    
+// }
+
+// This is what a GET request looks like.
+// GET 
/software/gnash/tests/flvplayer2.swf?file=http://localhost:4080/software/gnash/tests/lulutest.flv
 HTTP/1.1
+// User-Agent: Opera/9.01 (X11; Linux i686; U; en)
+// Host: localhost:4080
+// Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, 
image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
+// Accept-Language: en
+// Accept-Charset: iso-8859-1, utf-8, utf-16, *;q=0.1
+// Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0
+// Referer: http://localhost/software/gnash/tests/
+// Connection: Keep-Alive, TE
+// TE: deflate, gzip, chunked, identity, trailers
+int
+HTTP::extractAccept(Network::byte_t *data) {
+//    GNASH_REPORT_FUNCTION;
+    
+    string body = reinterpret_cast<const char *>(data);
+    string::size_type start, end, length, pos;
+    string pattern = "Accept: ";
+    
+    start = body.find(pattern, 0);
+    if (start == string::npos) {
+        return -1;
+    }
+    end =  body.find("\r\n", start);
+    if (end == string::npos) {
+       end = body.find("\n", start);
+//         return "error";
+    }
+
+    length = end-start-pattern.size();
+    start = start+pattern.size();
+    pos = start;
+    while (pos <= end) {
+       pos = (body.find(",", start) + 2);
+       if (pos <= start) {
+           return _encoding.size();
+       }
+       if ((pos == string::npos) || (pos > end)) {
+           length = end - start;
+       } else {
+           length = pos - start - 2;
+       }
+       string substr = body.substr(start, length);
+//     printf("FIXME: \"%s\"\n", substr.c_str());
+       _accept.push_back(substr);
+       start = pos;
+    }
+
+    return _accept.size();
+}
+
+/// These methods extract data from an RTMPT message. RTMP is an
+/// extension to HTTP that adds commands to manipulate the
+/// connection's persistance.
+//
+/// The URL to be opened has the following form:
+/// http://server/<comand>/[<client>/]<index>
+/// <command>
+///    denotes the RTMPT request type, "OPEN", "SEND", "IDLE", "CLOSE")
+/// <client>
+///    specifies the id of the client that performs the requests
+///    (only sent for established sessions)
+/// <index>
+///    is a consecutive number that seems to be used to detect missing packages
+HTTP::rtmpt_cmd_e
+HTTP::extractRTMPT(gnash::Network::byte_t *data)
+{
+    GNASH_REPORT_FUNCTION;
+
+    string body = reinterpret_cast<const char *>(data);
+    string tmp, cid, indx;
+    HTTP::rtmpt_cmd_e cmd;
+
+    // force the case to make comparisons easier
+    std::transform(body.begin(), body.end(), body.begin(), 
+               (int(*)(int)) toupper);
+    string::size_type start, end;
+
+    // Extract the command first
+    start = body.find("OPEN", 0);
+    if (start != string::npos) {
+        cmd = HTTP::OPEN;
+    }
+    start = body.find("SEND", 0);
+    if (start != string::npos) {
+        cmd = HTTP::SEND;
+    }
+    start = body.find("IDLE", 0);
+    if (start != string::npos) {
+        cmd = HTTP::IDLE;
+    }
+    start = body.find("CLOSE", 0);
+    if (start != string::npos) {
+        cmd = HTTP::CLOSE;
+    }
+
+    // Extract the optional client id
+    start = body.find("/", start+1);
+    if (start != string::npos) {
+       end = body.find("/", start+1);
+       if (end != string::npos) {
+           indx = body.substr(end, body.size());
+           cid = body.substr(start, (end-start));
+       } else {
+           cid = body.substr(start, body.size());
+       }
+    }
+
+    _index = strtol(indx.c_str(), NULL, 0);
+    _clientid = strtol(cid.c_str(), NULL, 0);
+    end =  body.find("\r\n", start);
+//     if (end != string::npos) {
+//         cmd = HTTP::CLOSE;
+//     }
+
+    return cmd;
+}
+
+HTTP::http_method_e
+HTTP::extractCommand(gnash::Network::byte_t *data)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    string body = reinterpret_cast<const char *>(data);
+    HTTP::http_method_e cmd;
+
+    // force the case to make comparisons easier
+//     std::transform(body.begin(), body.end(), body.begin(), 
+//                (int(*)(int)) toupper);
+    string::size_type start, end;
+
+    // Extract the command
+    start = body.find("GET", 0);
+    if (start != string::npos) {
+        cmd = HTTP::GET;
+    }
+    start = body.find("POST", 0);
+    if (start != string::npos) {
+        cmd = HTTP::POST;
+    }
+    start = body.find("HEAD", 0);
+    if (start != string::npos) {
+        cmd = HTTP::HEAD;
+    }
+    start = body.find("CONNECT", 0);
+    if (start != string::npos) {
+        cmd = HTTP::CONNECT;
+    }
+    start = body.find("TRACE", 0);
+    if (start != string::npos) {
+        cmd = HTTP::TRACE;
+    }
+    start = body.find("OPTIONS", 0);
+    if (start != string::npos) {
+        cmd = HTTP::OPTIONS;
+    }
+    start = body.find("PUT", 0);
+    if (start != string::npos) {
+        cmd = HTTP::PUT;
+    }
+    start = body.find("DELETE", 0);
+    if (start != string::npos) {
+        cmd = HTTP::DELETE;
+    }
+
+    _command = cmd;
+    return cmd;
+}
+
+string &
+HTTP::extractAcceptRanges(Network::byte_t *data) {
+//    GNASH_REPORT_FUNCTION;
+    
+    string body = reinterpret_cast<const char *>(data);
+    string::size_type start, end, length, pos;
+    string pattern = "Accept-Ranges: ";
+    start = body.find(pattern, 0);
+    if (start == string::npos) {
+        _acceptranges = "error";
+        return _acceptranges;
+    }
+    end =  body.find("\r\n", start);
+    if (end == string::npos) {
+        _acceptranges = "error";
+        return _acceptranges;
+    }
+    
+    _acceptranges = body.substr(start+pattern.size(), end-start-1);
+    return _acceptranges;    
+}
+
+string &
+HTTP::extractMethod(Network::byte_t *data) {
+//    GNASH_REPORT_FUNCTION;
+    
+    boost::mutex::scoped_lock lock(stl_mutex);
+    string body = reinterpret_cast<const char *>(data);
+    string::size_type start, end;
+    int length;
+
+    length = body.size();
+    start = body.find(" ", 0);
+    if (start == string::npos) {
+        _method = "error";
+        return _method;
+    }
+    _method = body.substr(0, start);
+    end = body.find(" ", start+1);
+    if (end == string::npos) {
+        _method = "error";
+        return _method;
+    }
+    _url = body.substr(start+1, end-start-1);
+    _version = body.substr(end+1, length);
+
+    end = _url.find("?", 0);
+//    _filespec = _url.substr(start+1, end);
+    return _method;
+}
+
+string &
+HTTP::extractReferer(Network::byte_t *data) {
+//    GNASH_REPORT_FUNCTION;
+    
+    string body = reinterpret_cast<const char *>(data);
+    string::size_type start, end;
+    string pattern = "Referer: ";
+    
+    start = body.find(pattern, 0);
+    if (start == string::npos) {
+       _referer = "error";
+       return _referer;
+    }
+    end =  body.find("\r\n", start);
+    if (end == string::npos) {
+       _referer = "error";
+        return _referer;
+    }
+    
+    _referer = body.substr(start+pattern.size(), end-start-1);
+    return _referer;
+}
+
+int
+HTTP::extractConnection(Network::byte_t *data) {
+//    GNASH_REPORT_FUNCTION;
+    
+    string body = reinterpret_cast<const char *>(data);
+    string::size_type start, end, length, pos;
+    string pattern = "Connection: ";
+    
+    start = body.find(pattern, 0);
+    if (start == string::npos) {
+        return -1;
+    }
+    end =  body.find("\r\n", start);
+    if (end == string::npos) {
+       end = body.find("\n", start);
+//         return "error";
+    }
+
+    length = end-start-pattern.size();
+    start = start+pattern.size();
+    string _connection = body.substr(start, length);
+    pos = start;
+    while (pos <= end) {
+       pos = (body.find(",", start) + 2);
+       if (pos <= start) {
+           return _encoding.size();
+       }
+       if ((pos == string::npos) || (pos > end)) {
+           length = end - start;
+       } else {
+           length = pos - start - 2;
+       }
+       string substr = body.substr(start, length);
+//     printf("FIXME: \"%s\"\n", substr.c_str());
+       _connections.push_back(substr);
+       // Opera uses upper case first letters, Firefox doesn't.
+       if ((substr == "Keep-Alive") || (substr == "keep-alive")) {
+           _keepalive = true;
+       }
+       start = pos;
+    }
+
+    return _connections.size();
+}
+
+int
+HTTP::extractKeepAlive(Network::byte_t *data) {
+//    GNASH_REPORT_FUNCTION;
+    
+    string body = reinterpret_cast<const char *>(data);
+    string::size_type start, end, length, pos;
+    string pattern = "Keep-Alive: ";
+    
+    start = body.find(pattern, 0);
+    if (start == string::npos) {
+        return -1;
+    }
+    end =  body.find("\r\n", start);
+    if (end == string::npos) {
+       end = body.find("\n", start);
+//         return "error";
+    }
+
+    length = end-start-pattern.size();
+    start = start+pattern.size();
+    string _connection = body.substr(start, length);
+    pos = start;
+    while (pos <= end) {
+       pos = (body.find(",", start) + 2);
+       if (pos <= start) {
+           return _encoding.size();
+       }
+       if ((pos == string::npos) || (pos > end)) {
+           length = end - start;
+       } else {
+           length = pos - start - 2;
+       }
+       string substr = body.substr(start, length);
+//     printf("FIXME: \"%s\"\n", substr.c_str());
+       _kalive.push_back(substr);
+       _keepalive = true;      // if we get this header setting, we want to 
keep alive
+       start = pos;
+    }
+
+    return _connections.size();
+}
+
+string &
+HTTP::extractHost(Network::byte_t *data) {
+//    GNASH_REPORT_FUNCTION;
+    
+    string body = reinterpret_cast<const char *>(data);
+    string::size_type start, end;
+    string pattern = "Host: ";
+    
+    start = body.find(pattern, 0);
+    if (start == string::npos) {
+        _host = "error"; 
+        return _host;
+   }
+    end =  body.find("\r\n", start);
+    if (end == string::npos) {
+        _host = "error"; 
+        return _host;
+    }
+    
+    _host = body.substr(start+pattern.size(), end-start-1);
+    return _host;
+}
+
+string &
+HTTP::extractAgent(Network::byte_t *data) {
+//    GNASH_REPORT_FUNCTION;
+    
+    string body = reinterpret_cast<const char *>(data);
+    string::size_type start, end;
+    string pattern = "User-Agent: ";
+    _agent = "error";
+    
+    start = body.find(pattern, 0);
+    if (start == string::npos) {
+        return _agent;
+    }
+    end =  body.find("\r\n", start);
+    if (end == string::npos) {
+        return _agent;
+    }
+    
+    _agent = body.substr(start+pattern.size(), end-start-1);
+    return _agent;
+}
+
+int
+HTTP::extractLanguage(Network::byte_t *data) {
+//    GNASH_REPORT_FUNCTION;
+    
+    string body = reinterpret_cast<const char *>(data);
+    string::size_type start, end, length, pos, terminate;
+    // match both Accept-Language and Content-Language
+    string pattern = "-Language: ";
+    
+    start = body.find(pattern, 0);
+    if (start == string::npos) {
+        return -1;
+    }
+    end =  body.find("\r\n", start);
+    if (end == string::npos) {
+       end = body.find("\n", start);
+//        return "error";
+    }
+    length = end-start-pattern.size();
+    start = start+pattern.size();
+    pos = start;
+    terminate = (body.find(";", start));
+    if (terminate == string::npos) {
+       terminate = end;
+    }
+    
+    while (pos <= end) {
+       pos = (body.find(",", start));
+       if (pos <= start) {
+           return _encoding.size();
+       }
+       if ((pos == string::npos) || (pos >= terminate)) {
+           length = terminate - start;
+       } else {
+           length = pos - start;
+       }
+       string substr = body.substr(start, length);
+//     printf("FIXME: \"%s\"\n", substr.c_str());
+       _language.push_back(substr);
+       start = pos + 1;
+    }
+    
+//    _language = body.substr(start+pattern.size(), end-start-1);
+    return _language.size();
+}
+
+int
+HTTP::extractCharset(Network::byte_t *data) {
+//    GNASH_REPORT_FUNCTION;
+    
+    string body = reinterpret_cast<const char *>(data);
+    string::size_type start, end, length, pos, terminate;
+// match both Accept-Charset and Content-Charset
+    string pattern = "-Charset: ";
+    
+    start = body.find(pattern, 0);
+    if (start == string::npos) {
+        return -1;
+    }
+    end =  body.find("\r\n", start);
+    if (end == string::npos) {
+       end = body.find("\n", start);
+//        return "error";
+    }
+    
+    length = end-start-pattern.size();
+    start = start+pattern.size();
+    string _connection = body.substr(start, length);
+    pos = start;
+    terminate = (body.find(";", start));
+    if (terminate == string::npos) {
+       terminate = end;
+    }
+    while (pos <= end) {
+       pos = (body.find(",", start) + 2);
+       if (pos <= start) {
+           return _encoding.size();
+       }
+       if ((pos == string::npos) || (pos >= terminate)) {
+           length = terminate - start;
+       } else {
+           length = pos - start - 2;
+       }
+       string substr = body.substr(start, length);
+//     printf("FIXME: \"%s\"\n", substr.c_str());
+       _charset.push_back(substr);
+       start = pos;
+    }
+//    _charset = body.substr(start+pattern.size(), end-start-1);
+    return _charset.size();
+}
+
+int
+HTTP::extractEncoding(Network::byte_t *data) {
+//    GNASH_REPORT_FUNCTION;
+    
+    string body = reinterpret_cast<const char *>(data);
+    string::size_type start, end, length, pos, terminate;
+    // match both Accept-Encoding and Content-Encoding
+    string pattern = "-Encoding: ";
+    
+    start = body.find(pattern, 0);
+    if (start == string::npos) {
+        return -1;
+    }
+    end =  body.find("\r\n", start);
+    if (end == string::npos) {
+       end = body.find("\n", start);
+//        return "error";
+    }
+    
+   length = end-start-pattern.size();
+    start = start+pattern.size();
+    string _connection = body.substr(start, length);
+    pos = start;
+    // Drop anything after a ';' character
+    terminate = (body.find(";", start));
+    if (terminate == string::npos) {
+       terminate = end;
+    }
+    while (pos <= end) {
+       pos = (body.find(",", start) + 2);
+       if (pos <= start) {
+           return _encoding.size();
+       }
+       if ((pos == string::npos) || (pos >= terminate)) {
+           length = terminate - start;
+       } else {
+           length = pos - start - 2;
+       }
+       string substr = body.substr(start, length);
+//     printf("FIXME: \"%s\"\n", substr.c_str());
+       _encoding.push_back(substr);
+       start = pos;
+    }
+
+//    _encoding = body.substr(start+pattern.size(), end-start-1);
+    return _encoding.size();
+}
+
+int
+HTTP::extractTE(Network::byte_t *data) {
+//    GNASH_REPORT_FUNCTION;
+    
+    string body = reinterpret_cast<const char *>(data);
+    string::size_type start, end, length, pos;
+    string pattern = "TE: ";
+    
+    start = body.find(pattern, 0);
+    if (start == string::npos) {
+        return -1;
+    }
+    end = body.find("\r\n", start);
+    if (end == string::npos) {
+       end = body.find("\n", start);
+//        return "error";
+    }
+    
+    length = end-start-pattern.size();
+    start = start+pattern.size();
+    pos = start;
+    while (pos <= end) {
+       pos = (body.find(",", start));
+       if (pos <= start) {
+           return _encoding.size();
+       }
+       if ((pos == string::npos) || (pos >= end)) {
+           length = end - start;
+       } else {
+           length = pos - start;
+       }
+       string substr = body.substr(start, length);
+//     printf("FIXME: \"%s\"\n", substr.c_str());
+       _te.push_back(substr);
+       start = pos + 2;
+    }
+    return _te.size();
+}
+
+// Get the file type, so we know how to set the
+// Content-type in the header.
+HTTP::filetype_e
+HTTP::getFileStats(std::string &filespec)
+{
+//    GNASH_REPORT_FUNCTION;    
+    bool try_again = true;
+    string actual_filespec = filespec;
+    struct stat st;
+
+    while (try_again) {
+       try_again = false;
+//     cerr << "Trying to open " << actual_filespec << "\r\n";
+       if (stat(actual_filespec.c_str(), &st) == 0) {
+           // If it's a directory, then we emulate what apache
+           // does, which is to load the index.html file in that
+           // directry if it exists.
+           if (S_ISDIR(st.st_mode)) {
+               log_debug("%s is a directory\n", actual_filespec.c_str());
+               if (actual_filespec[actual_filespec.size()-1] != '/') {
+                   actual_filespec += '/';
+               }
+               actual_filespec += "index.html";
+               try_again = true;
+               continue;
+           } else {            // not a directory
+               log_debug("%s is not a directory\n", actual_filespec.c_str());
+               _filespec = actual_filespec;
+               string::size_type pos;
+               pos = filespec.rfind(".");
+               if (pos != string::npos) {
+                   string suffix = filespec.substr(pos, filespec.size());
+                   if (suffix == "html") {
+                       _filetype = HTML;
+                       log_debug("HTML content found");
+                   }
+                   if (suffix == "swf") {
+                       _filetype = SWF;
+                       log_debug("SWF content found");
+                   }
+                   if (suffix == "flv") {
+                       _filetype = VIDEO;
+                       log_debug("FLV content found");
+                   }
+                   if (suffix == "mp3") {
+                       _filetype = AUDIO;
+                       log_debug("MP3 content found");
+                   }
+               }
+           }
+       } else {
+           _filetype = HTTP::ERROR;
+       } // end of stat()
+    } // end of try_waiting
+
+    _filesize = st.st_size;
+    return _filetype;
+}
+
+void
+HTTP::dump() {
+//    GNASH_REPORT_FUNCTION;
+    
+    boost::mutex::scoped_lock lock(stl_mutex);
+    vector<string>::iterator it;
+    
+    log_debug (_("==== The HTTP header breaks down as follows: ===="));
+    log_debug (_("Filespec: %s"), _filespec.c_str());
+    log_debug (_("URL: %s"), _url.c_str());
+    log_debug (_("Version: %s"), _version.c_str());
+    for (it = _accept.begin(); it != _accept.end(); it++) {
+        log_debug("Accept param: \"%s\"", (*(it)).c_str());
+    }
+    log_debug (_("Method: %s"), _method.c_str());
+    log_debug (_("Referer: %s"), _referer.c_str());
+    log_debug (_("Connections:"));
+    for (it = _connections.begin(); it != _connections.end(); it++) {
+        log_debug("Connection param is: \"%s\"", (*(it)).c_str());
+    }
+    log_debug (_("Host: %s"), _host.c_str());
+    log_debug (_("User Agent: %s"), _agent.c_str());
+    for (it = _language.begin(); it != _language.end(); it++) {
+        log_debug("Language param: \"%s\"", (*(it)).c_str());
+    }
+    for (it = _charset.begin(); it != _charset.end(); it++) {
+        log_debug("Charset param: \"%s\"", (*(it)).c_str());
+    }
+    for (it = _encoding.begin(); it != _encoding.end(); it++) {
+        log_debug("Encodings param: \"%s\"", (*(it)).c_str());
+    }
+    for (it = _te.begin(); it != _te.end(); it++) {
+        log_debug("TE param: \"%s\"", (*(it)).c_str());
+    }
+
+    // Dump the RTMPT fields
+    log_debug("RTMPT optional index is: ", _index);
+    log_debug("RTMPT optional client ID is: ", _clientid);
+    log_debug (_("==== ==== ===="));
+}
+
+extern "C" {
+void
+httphandler(Handler::thread_params_t *args)
+{
+    GNASH_REPORT_FUNCTION;
+    int retries = 10;
+//    struct thread_params thread_data;
+    string url, filespec, parameters;
+    string::size_type pos;
+    Handler *hand = reinterpret_cast<Handler *>(args->handle);
+    HTTP www;
+    www.setHandler(hand);
+
+    log_debug(_("Starting HTTP Handler for fd #%d, tid %ld"),
+             args->netfd, pthread_self());
+    
+    string docroot = args->filespec;
+    
+    while (!hand->timetodie()) {       
+       log_debug(_("Waiting for HTTP GET request on fd #%d..."), args->netfd);
+       hand->wait();
+       // This thread is the last to wake up when the browser
+       // closes the network connection. When browsers do this
+       // varies, elinks and lynx are very forgiving to a more
+       // flexible HTTP protocol, which Firefox/Mozilla & Opera
+       // are much pickier, and will hang or fail to load if
+       // you aren't careful.
+       if (hand->timetodie()) {
+           log_debug("Not waiting no more, no more for more HTTP data for fd 
#%d...", args->netfd);
+           map<int, Handler *>::iterator hit = handlers.find(args->netfd);
+           if ((*hit).second) {
+               log_debug("Removing handle %x for HTTP on fd #%d", (void 
*)hand), args->netfd;
+               handlers.erase(args->netfd);
+               delete (*hit).second;
+           }
+           return;
+       }
+#ifdef USE_STATISTICS
+       struct timespec start;
+       clock_gettime (CLOCK_REALTIME, &start);
+#endif
+       
+//     conndata->statistics->setFileType(NetStats::RTMPT);
+//     conndata->statistics->startClock();
+//     args->netfd = www.getFileFd();
+       if (!www.waitForGetRequest()) {
+           hand->clearout();   // remove all data from the outgoing que
+           hand->die();        // tell all the threads for this connection to 
die
+           hand->notifyin();
+           log_debug("Net HTTP done for fd #%d...", args->netfd);
+//         hand->closeNet(args->netfd);
+           return;
+       }
+       url = docroot;
+       url += www.getURL();
+       pos = url.find("?");
+       filespec = url.substr(0, pos);
+       parameters = url.substr(pos + 1, url.size());
+       // Get the file size for the HTTP header
+       
+       if (www.getFileStats(filespec) == HTTP::ERROR) {
+           www.formatErrorResponse(HTTP::NOT_FOUND);
+       }
+       www.sendGetReply(HTTP::LIFE_IS_GOOD);
+//     strcpy(thread_data.filespec, filespec.c_str());
+//     thread_data.statistics = conndata->statistics;
+       
+       // Keep track of the network statistics
+//     conndata->statistics->stopClock();
+//     log_debug (_("Bytes read: %d"), www.getBytesIn());
+//     log_debug (_("Bytes written: %d"), www.getBytesOut());
+//     st.setBytes(www.getBytesIn() + www.getBytesOut());
+//     conndata->statistics->addStats();
+       
+       if (filespec[filespec.size()-1] == '/') {
+           filespec += "/index.html";
+       }
+       if (url != docroot) {
+           log_debug (_("File to load is: %s"), filespec.c_str());
+           log_debug (_("Parameters are: %s"), parameters.c_str());
+           struct stat st;
+           int filefd, ret;
+#ifdef USE_STATISTICS
+           struct timespec start;
+           clock_gettime (CLOCK_REALTIME, &start);
+#endif
+           if (stat(filespec.c_str(), &st) == 0) {
+               filefd = ::open(filespec.c_str(), O_RDONLY);
+               log_debug (_("File \"%s\" is %lld bytes in size, disk fd #%d"), 
filespec,
+                          st.st_size, filefd);
+               do {
+                   Buffer *buf = new Buffer;
+                   ret = read(filefd, buf->reference(), buf->size());
+                   if (ret == 0) { // the file is done
+                       delete buf;
+                       break;
+                   }
+                   if (ret != buf->size()) {
+                       buf->resize(ret);
+//                     log_debug("Got last data block from disk file, size 
%d", buf->size());
+                   }
+//                 log_debug("Read %d bytes from %s.", ret, filespec);
+#if 1
+                   hand->pushout(buf);
+                   hand->notifyout();
+#else
+                   // Don't bother with the outgoing que
+                   if (ret > 0) {
+                       ret = hand->writeNet(buf);
+                   }
+                   delete buf;
+#endif
+               } while(ret > 0);
+               log_debug("Done transferring %s to net fd #%d",
+                         filespec, args->netfd);
+               ::close(filefd); // close the disk file
+               // See if this is a persistant connection
+//             if (!www.keepAlive()) {
+//                 log_debug("Keep-Alive is off", www.keepAlive());
+// //              hand->closeConnection();
+//             }
+#ifdef USE_STATISTICS
+               struct timespec end;
+               clock_gettime (CLOCK_REALTIME, &end);
+               log_debug("Read %d bytes from \"%s\" in %f seconds",
+                         st.st_size, filespec,
+                         (float)((end.tv_sec - start.tv_sec) + ((end.tv_nsec - 
start.tv_nsec)/1e9)));
+#endif
+           }
+
+//         memset(args->filespec, 0, 256);
+//         memcpy(->filespec, filespec.c_str(), filespec.size());
+//         boost::thread sendthr(boost::bind(&stream_thread, args));
+//         sendthr.join();
+       }
+#ifdef USE_STATISTICS
+       struct timespec end;
+       clock_gettime (CLOCK_REALTIME, &end);
+       log_debug("Processing time for GET request was %f seconds",
+                 (float)((end.tv_sec - start.tv_sec) + ((end.tv_nsec - 
start.tv_nsec)/1e9)));
+#endif
+//     conndata->statistics->dump();
+//    }
+    } // end of while retries
+    
+    log_debug("httphandler all done now finally...");
+    
+} // end of httphandler
+    
+} // end of extern C
+
+} // end of cygnal namespace
+
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: http.h
===================================================================
RCS file: http.h
diff -N http.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ http.h      28 Mar 2008 03:30:22 -0000      1.1
@@ -0,0 +1,304 @@
+// 
+//   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#ifndef _HTTP_H_
+#define _HTTP_H_
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include <string>
+#include <map>
+#include <vector>
+
+#include "rtmp.h"
+#include "handler.h"
+#include "network.h"
+
+namespace cygnal
+{
+    
+class HTTP
+{
+public:
+// as defined by the W3: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+    typedef enum {
+        // 1xx: Informational - Request received, continuing process
+        CONTINUE = 100,
+        SWITCHPROTOCOLS = 101,
+        // 2xx: Success - The action was successfully received,
+        // understood, and accepted
+        OK = 200,
+        CREATED = 201,
+        ACCEPTED = 202,
+        NON_AUTHORITATIVE = 203,
+        NO_CONTENT = 204,
+        RESET_CONTENT = 205,
+        PARTIAL_CONTENT = 206,
+        // 3xx: Redirection - Further action must be taken in order to
+        // complete the request
+        MULTIPLE_CHOICES = 300,
+        MOVED_PERMANENTLY = 301,
+        FOUND = 302,
+        SEE_OTHER = 303,
+        NOT_MODIFIED = 304,
+        USE_PROXY = 305,
+        TEMPORARY_REDIRECT = 307,
+        // 4xx: Client Error - The request contains bad syntax or
+        // cannot be fulfilled
+        BAD_REQUEST = 400,
+        UNAUTHORIZED = 401,
+        PAYMENT_REQUIRED = 402,
+        FORBIDDEN = 403,
+        NOT_FOUND = 404,
+        METHOD_NOT_ALLOWED = 405,
+        NOT_ACCEPTABLE = 406,
+        PROXY_AUTHENTICATION_REQUIRED = 407,
+        REQUEST_TIMEOUT = 408,
+        CONFLICT = 409,
+        GONE = 410,
+        LENGTH_REQUIRED = 411,
+        PRECONDITION_FAILED = 412,
+        REQUEST_ENTITY_TOO_LARGE = 413,
+        REQUEST_URI_TOO_LARGE = 414,
+        UNSUPPORTED_MEDIA_TYPE = 415,
+        REQUESTED_RANGE_NOT_SATISFIABLE = 416,
+        EXPECTATION_FAILED = 417,
+        // 5xx: Server Error - The server failed to fulfill an apparently 
valid request
+        INTERNAL_SERVER_ERROR = 500,
+        NOT_IMPLEMENTED = 501,
+        BAD_GATEWAY = 502,
+        SERVICE_UNAVAILABLE = 503,
+        GATEWAY_TIMEOUT = 504,
+        HTTP_VERSION_NOT_SUPPORTED = 505,
+       // Gnash/Cygnal extensions for internal use
+       LIFE_IS_GOOD = 1234,
+       CLOSEPIPE = 1235
+    } http_status_e;
+    typedef enum {
+        OPTIONS,
+        GET,
+        HEAD,
+        POST,
+        PUT,
+        DELETE,
+        TRACE,
+        CONNECT
+    } http_method_e;
+    typedef enum {
+       OPEN,
+       SEND,
+       IDLE,
+       CLOSE
+    } rtmpt_cmd_e;
+    struct status_codes {
+        const char *code;
+        const char *msg;
+    };
+    typedef enum {
+       ERROR = -1,
+       NONE = 0,
+       HTML,
+       SWF,
+       VIDEO,
+       AUDIO,
+       MP3,
+       FCS,
+       OSCP
+    } filetype_e;
+    HTTP();
+    HTTP(Handler *hand);
+    ~HTTP();
+    bool waitForGetRequest();
+    bool waitForGetRequest(gnash::Network &net);
+    
+    // Handle the GET request response
+    bool sendGetReply(http_status_e code);
+    bool sendPostReply(rtmpt_cmd_e code);
+//    bool sendGetReply(Network &net);
+
+    // Make copies of ourself
+    HTTP &operator = (HTTP &obj);
+
+    // These methods extract data from an RTMPT message. RTMP is an
+    // extension to HTTP that adds commands to manipulate the
+    // connection's persistance.
+    rtmpt_cmd_e extractRTMPT(gnash::Network::byte_t *data);
+    rtmpt_cmd_e extractRTMPT(Buffer *data)
+       { return extractRTMPT(data->reference()); };
+
+    // These methods extract the fields in the HTTP header.
+    // These all return the number of items found, or 0
+    http_method_e extractCommand(gnash::Network::byte_t *data);
+    http_method_e extractCommand(Buffer *data)
+       { return extractCommand(data->reference()); };
+    int extractAccept(gnash::Network::byte_t *data);
+    int extractAccept(Buffer *data)
+       { return extractAccept(data->reference()); };
+    std::string &extractAcceptRanges(gnash::Network::byte_t *data);
+    std::string &extractAcceptRanges(Buffer *data)
+       { return extractAcceptRanges(data->reference()); };
+    int extractLanguage(gnash::Network::byte_t *data);
+    int extractLanguage(Buffer *data)
+       { return extractLanguage(data->reference()); };
+    int extractCharset(gnash::Network::byte_t *data);
+    int extractCharset(Buffer *data)
+       { return extractCharset(data->reference()); };
+    int extractEncoding(gnash::Network::byte_t *data);
+    int extractEncoding(Buffer *data)
+       { return extractEncoding(data->reference()); };
+    int extractTE(gnash::Network::byte_t *data);
+    int extractTE(Buffer *data)
+       { return extractTE(data->reference()); };
+    int extractConnection(gnash::Network::byte_t *data);
+    int extractConnection(Buffer *data)
+       { return extractConnection(data->reference()); };
+    int extractKeepAlive(gnash::Network::byte_t *data);
+    int extractKeepAlive(Buffer *data)
+       { return extractConnection(data->reference()); };
+
+    // These return the string that was found for this field.
+    std::string &extractMethod(gnash::Network::byte_t *data);
+    std::string &extractMethod(Buffer *data)
+       { return extractMethod(data->reference()); };
+    std::string &extractReferer(gnash::Network::byte_t *data);
+    std::string &extractReferer(Buffer *data)
+       { return extractReferer(data->reference()); };
+    std::string &extractHost(gnash::Network::byte_t *data);
+    std::string &extractHost(Buffer *data)
+       { return extractHost(data->reference()); };
+    std::string &extractAgent(gnash::Network::byte_t *data);
+    std::string &extractAgent(Buffer *data)
+       { return extractAgent(data->reference()); };
+
+    // These methods add data to the fields in the HTTP header.
+    // These return true if OK, false if error.
+    bool clearHeader();
+    bool formatHeader(int filesize, http_status_e type);
+    bool formatHeader(http_status_e type);
+    bool formatRequest(const std::string &url, http_method_e req);
+    bool formatMethod(const std::string &data);
+    bool formatDate();
+    bool formatServer();
+    bool formatServer(const std::string &data);
+    bool formatReferer(const std::string &data);
+    bool formatConnection(const std::string &data);
+    bool formatKeepAlive(const std::string &data);
+    bool formatContentLength();
+    bool formatContentLength(int filesize);
+    bool formatContentType();
+    bool formatContentType(filetype_e type);
+    bool formatHost(const std::string &data);
+    bool formatAgent(const std::string &data);
+    bool formatAcceptRanges(const std::string &data);
+    bool formatLastModified();
+    bool formatLastModified(const std::string &data);
+    bool formatEtag(const std::string &data);
+    bool formatLanguage(const std::string &data);
+    bool formatCharset(const std::string &data);
+    bool formatEncoding(const std::string &data);
+    bool formatTE(const std::string &data);
+
+    bool formatErrorResponse(http_status_e err);
+    
+    // All HTTP messages are terminated with a blank line
+    void terminateHeader() { _header << "\r\n"; };
+    
+    // Return the header that's been built up.
+    std::string getHeader() { return _header.str(); };
+
+    // Return the body that's been built up.
+    std::string getBody() { return _body.str(); };
+
+    // Get the file type, so we know how to set the
+    // Content-type in the header.
+//    filetype_e getFileType(std::string &filespec);
+    filetype_e getFileStats(std::string &filespec);
+    void dump();
+
+    // These accessors are used mostly just for debugging.
+    bool keepAlive() { return _keepalive; }
+    int getFileSize() { return _filesize; }
+    std::string &getFilespec() { return _filespec; }
+    std::string &getURL() { return _url; }
+    std::map<int, struct status_codes *> getStatusCodes()
+       { return _status_codes; }
+    std::string getVersion() { return _version; }
+    std::string getMethod() { return _method; }
+    std::string getReferer() { return _referer; }
+    std::vector<std::string> getLanguage() { return _language;  }
+    std::vector<std::string> getConnection() { return _connections; }
+    std::vector<std::string> getKeepAlive() { return _kalive; }
+    std::vector<std::string> getTE() { return _te; }
+    std::vector<std::string> getCharset() { return _charset; }
+    std::vector<std::string> getEncoding() { return _encoding; }
+
+    int         getHostPort(){ return _port; }
+    std::string getHost() { return _host; }
+    std::string getUserAgent() { return _agent; }
+
+    void setHandler(Handler *hand) { _handler = hand; };
+private:
+    std::stringstream _header;
+    std::stringstream _body;
+    std::string _command;
+    filetype_e  _filetype;
+    std::string _filespec;
+    int         _filesize;
+    std::string _url;
+    std::map<int, struct status_codes *> _status_codes;
+    std::string _version;
+    std::string _method;
+    std::string _referer;
+    std::string _host;
+    int         _port;
+    std::string _agent;
+    std::string _acceptranges;
+    std::vector<std::string> _connections;
+    std::vector<std::string> _language;
+    std::vector<std::string> _charset;
+    std::vector<std::string> _encoding;
+    std::vector<std::string> _te;
+    std::vector<std::string> _accept;
+    std::vector<std::string> _kalive;
+    // Connection parameters we care about
+    bool       _keepalive;
+    Handler     *_handler;
+    // These two field hold the data from an RTMPT message
+    int                _clientid;
+    int                _index;
+//    bool     _te;
+};  
+
+// This is the thread for all incoming HTTP connections
+extern "C" {
+    void httphandler(Handler::thread_params_t *args);
+}
+
+
+} // end of cygnal namespace
+
+// end of _HTTP_H_
+#endif
+
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: netstats.cpp
===================================================================
RCS file: netstats.cpp
diff -N netstats.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ netstats.cpp        28 Mar 2008 03:30:23 -0000      1.1
@@ -0,0 +1,75 @@
+// 
+//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include <boost/date_time/date.hpp>
+#include "netstats.h"
+#include "log.h"
+
+using namespace gnash;
+using namespace boost::posix_time;
+
+namespace cygnal {
+
+NetStats::NetStats()
+{
+//    GNASH_REPORT_FUNCTION;
+}
+
+NetStats::~NetStats()
+{
+//    GNASH_REPORT_FUNCTION;    
+}
+
+boost::posix_time::ptime
+NetStats::startClock()
+{
+//    GNASH_REPORT_FUNCTION;
+
+    _starttime = boost::posix_time::microsec_clock::local_time();
+    return _stoptime;
+}
+
+boost::posix_time::ptime
+NetStats::stopClock()
+{
+//    GNASH_REPORT_FUNCTION;
+    
+    _stoptime = boost::posix_time::microsec_clock::local_time();
+    return _stoptime;
+}
+
+NetStats &
+NetStats::operator = (NetStats &stats) {
+    _starttime = stats.getStartTime();
+    _stoptime = stats.getStopTime();
+    _bytes = stats.getBytes();
+    _type = stats.getFileType();
+    return *this;
+}
+
+} // end of cygnal namespace
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: netstats.h
===================================================================
RCS file: netstats.h
diff -N netstats.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ netstats.h  28 Mar 2008 03:30:23 -0000      1.1
@@ -0,0 +1,125 @@
+// 
+//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#ifndef __NETSTATS_H__
+#define __NETSTATS_H__
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+//include all types plus i/o
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <string>
+
+// This is what the ActionScript 'Client' class returns:
+//
+// bytes_in            Total number of bytes received.
+// bytes_out           Total number of bytes sent.
+// msg_in              Total number of RTMP messages received.
+// msg_out             Total number of RTMP messages sent.
+// msg_dropped         Total number of dropped RTMP messages.
+// ping_rtt            Length of time the client takes to respond to a ping 
message.
+// audio_queue_msgs    Current number of audio messages in the queue waiting 
to be delivered to the client.
+// video_queue_msgs    Current number of video messages in the queue waiting 
to be delivered to the client.
+// so_queue_msgs       Current number of shared object messages in the queue 
waiting to be delivered to the client.
+// data_queue_msgs     Current number of data messages in the queue waiting to 
be delivered to the client.
+// dropped_audio_msgs  Number of audio messages that were dropped.
+// dropped_video_msgs  Number of video messages that were dropped.
+// audio_queue_bytes   Total size of all audio messages (in bytes) in the 
queue waiting to be delivered to the client.
+// video_queue_bytes   Total size of all video messages (in bytes) in the 
queue waiting to be delivered to the client.
+// so_queue_bytes      Total size of all shared object messages (in bytes) in 
the queue waiting to be delivered to the client.
+// data_queue_bytes    Total size of all data messages (in bytes) in the queue 
waiting to be delivered to the client.
+// dropped_audio_bytes Total size of all audio messages (in bytes) that were 
dropped.
+// dropped_video_bytes Total size of all video messages (in bytes) that were 
dropped.
+// bw_out              Current upstream (client to server) bandwidth for this 
client.
+// bw_in               Current downstream (server to client) bandwidth for 
this client.
+// client_id           A unique ID issued by the server for this client.
+//
+// samples are taken every 3 seconds, or the interval supplied in 
Client::setInterval()
+
+namespace cygnal 
+{
+
+class NetStats {
+public:
+    NetStats();
+    ~NetStats();
+    typedef enum {
+        NO_CODEC,
+        OGG,
+        THEORA,
+       DIRAC,
+       SNOW,
+        MP3,
+        MPEG4,
+       H264,
+       H263,
+        FLV,
+        VP6,
+        VP7
+    } codec_e;
+    typedef enum {
+        NO_FILETYPE,
+        HTTP,
+        RTMP,
+        RTMPT,
+        RTMPTS,
+        SWF,
+        SWF6,
+        SWF7,
+        SWF8,
+        SWF9,
+        AUDIO,
+        VIDEO
+    } filetypes_e;
+    // start the clock counting down
+    boost::posix_time::ptime startClock();
+    // stop the clock from counting down
+    boost::posix_time::ptime stopClock();
+    
+    // Accessors to set to the private data
+    void setStartTime(boost::posix_time::ptime x) { _starttime = x; };
+    void setStopTime(boost::posix_time::ptime x) { _stoptime = x; };
+    void setBytes(int x) { _bytes = x; };
+    void setFileType(filetypes_e x) { _type = x; };
+    // Accumulate the byts transferred
+    int addBytes(int x) { _bytes += x; return _bytes; };
+    
+    // Accessors to get to the private data
+    int getBytes() { return _bytes; };
+    filetypes_e getFileType() { return _type; };
+    boost::posix_time::ptime getStartTime() { return _starttime; };
+    boost::posix_time::ptime getStopTime() { return _stoptime; };
+    boost::posix_time::time_duration getTimeSpan() { return _stoptime - 
_starttime; };
+    NetStats &operator = (NetStats &stats);
+private:
+    boost::posix_time::ptime _starttime;
+    boost::posix_time::ptime _stoptime;
+    int                      _bytes;
+    filetypes_e              _type;
+};
+ 
+} // end of cygnal namespace
+
+#endif // __NETSTATS_H__
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: network.cpp
===================================================================
RCS file: network.cpp
diff -N network.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ network.cpp 28 Mar 2008 03:30:23 -0000      1.1
@@ -0,0 +1,911 @@
+//
+//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include "utility.h"
+#include "log.h"
+#include "network.h"
+
+#include <sys/types.h>
+#include <cstring>
+#include <cstdio>
+#include <cerrno>
+#include <fcntl.h>
+#if defined(HAVE_WINSOCK_H) && !defined(__OS2__)
+# include <winsock2.h>
+# include <windows.h>
+# include <sys/stat.h>
+# include <io.h>
+# include <ws2tcpip.h>
+#else
+# include <sys/time.h>
+# include <unistd.h>
+# include <sys/select.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <sys/socket.h>
+# include <sys/un.h>
+# include <netdb.h>
+# include <sys/param.h>
+# include <sys/select.h>
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+using namespace std;
+
+namespace gnash {
+
+static const char *DEFAULTPROTO = "tcp";
+static const short DEFAULTPORT  = RTMP;
+
+#ifndef INADDR_NONE
+#define INADDR_NONE  0xffffffff
+#endif
+
+Network::Network()
+       :
+       _ipaddr(INADDR_ANY),
+       _sockfd(0),
+       _listenfd(0),
+       _port(0),
+       _connected(false),
+       _debug(false),
+       _timeout(0)
+{
+//    GNASH_REPORT_FUNCTION;
+#if defined(HAVE_WINSOCK_H) && !defined(__OS2__)
+    WORD wVersionRequested;
+    WSADATA wsaData;
+    wVersionRequested = MAKEWORD(1, 1);                // Windows Sockets 1.1
+    if (WSAStartup( wVersionRequested, &wsaData ) != 0) {
+        log_error(_("Could not find a usable WinSock DLL"));
+        exit(1);
+    }
+#endif
+
+}
+
+Network::~Network()
+{
+//    GNASH_REPORT_FUNCTION;
+#if defined(HAVE_WINSOCK_H) && !defined(__OS2__)
+    WSACleanup();
+#else
+    closeNet();
+#endif
+}
+
+// Description: Create a tcp/ip network server. This creates a server
+//              that listens for incoming socket connections. This
+//              supports IP aliasing on the host, and will sequntially
+//              look for IP address to bind this port to.
+int
+Network::createServer(void)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    return createServer(DEFAULTPORT);
+}
+
+// FIXME: Should also support IPv6 (AF_INET6)
+int
+Network::createServer(short port)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    struct protoent *ppe;
+    struct sockaddr_in sock_in;
+    int             on, type;
+    int             retries = 0;
+    in_addr_t       nodeaddr;
+
+#if 0
+    if (port < 1024) {
+       log_error(_("Can't connect to privileged port #%d"), port);
+       return -1;
+    }
+#endif
+    
+    if (_listenfd >= 2) {
+       log_debug("already connected to port %hd", port);
+       return _listenfd;
+    }
+    
+    const struct hostent *host = gethostbyname("localhost");
+    struct in_addr *thisaddr = reinterpret_cast<struct in_addr 
*>(host->h_addr_list[0]);
+    _ipaddr = thisaddr->s_addr;
+    memset(&sock_in, 0, sizeof(sock_in));
+
+#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);
+
+    if ((ppe = getprotobyname(DEFAULTPROTO)) == 0) {
+        log_error(_("unable to get protocol entry for %s"),
+                DEFAULTPROTO);
+        return -1;
+    }
+
+    // set protocol type
+    if ( strcmp(DEFAULTPROTO, "udp") == 0) {
+        type = SOCK_DGRAM;
+    } else {
+        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_error(_("unable to create socket: %s"), strerror(errno));
+        return -1;
+    }
+
+    on = 1;
+    if (setsockopt(_listenfd, SOL_SOCKET, SO_REUSEADDR,
+                   (char *)&on, sizeof(on)) < 0) {
+        log_error(_("setsockopt SO_REUSEADDR failed"));
+        return -1;
+    }
+
+    retries = 0;
+
+    nodeaddr = inet_lnaof(*thisaddr);
+    while (retries < 5) {
+        if (bind(_listenfd, reinterpret_cast<struct sockaddr *>(&sock_in),
+                 sizeof(sock_in)) == -1) {
+            log_error(_("unable to bind to port %hd: %s"),
+                    port, strerror(errno));
+//                    inet_ntoa(sock_in.sin_addr), strerror(errno));
+            retries++;
+        }
+
+       if (_debug) {
+//             char  ascip[INET_ADDRSTRLEN];
+//             inet_ntop(sock_in.sin_family, &_ipaddr, ascip, INET_ADDRSTRLEN);
+               char *ascip = ::inet_ntoa(sock_in.sin_addr);
+               log_debug(_("Server bound to service on %s, port %hd, using fd 
#%d"),
+                   ascip, ntohs(sock_in.sin_port),
+                   _listenfd);
+       }
+
+        if (type == SOCK_STREAM && listen(_listenfd, 5) < 0) {
+            log_error(_("unable to listen on port: %hd: %s "),
+                port, strerror(errno));
+            return -1;
+        }
+
+       // We have a socket created
+        _port = port;
+        return _listenfd;
+    }
+    return -1;
+}
+
+// Description: Accept a new network connection for the port we have
+//              created a server for.
+// The default is to block.
+int
+Network::newConnection(void)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    return newConnection(true, _listenfd);
+}
+
+int
+Network::newConnection(int fd)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    return newConnection(true, fd);
+}
+
+int
+Network::newConnection(bool block)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    return newConnection(block, _listenfd);
+}
+
+int
+Network::newConnection(bool block, int fd)
+{
+    GNASH_REPORT_FUNCTION;
+
+    struct sockaddr    newfsin;
+    socklen_t          alen;
+    int                        ret;
+    struct timeval        tval;
+    fd_set                fdset;
+    int                   retries = 3;
+
+    alen = sizeof(struct sockaddr_in);
+
+    if (fd <= 2) {
+        return -1;
+    }
+    if (_debug) {
+       log_debug(_("Trying to accept net traffic on fd #%d for port %d"), fd, 
_port);
+    }
+
+    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(fd, &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(fd+1, &fdset, NULL, NULL, NULL);
+        } else {
+            ret = select(fd+1, &fdset, NULL, NULL, &tval);
+        }
+
+        if (FD_ISSET(0, &fdset)) {
+           if (_debug) {
+               log_debug(_("There is data at the console for stdin"));
+           }
+            return 1;
+        }
+
+        // If interupted by a system call, try again
+        if (ret == -1 && errno == EINTR) {
+            log_debug(_("The accept() socket for fd #%d was interupted by a 
system call"), fd);
+        }
+
+        if (ret == -1) {
+            log_debug(_("The accept() socket for fd #%d never was available 
for writing"), fd);
+            return -1;
+        }
+
+        if (ret == 0) {
+            if (_debug) {
+                log_debug(_("The accept() socket for fd #%d timed out waiting 
to write"), fd);
+            }
+        }
+    }
+
+#ifndef HAVE_WINSOCK_H
+    fcntl(_listenfd, F_SETFL, O_NONBLOCK); // Don't let accept() block
+#endif
+    _sockfd = accept(fd, &newfsin, &alen);
+
+    if (_sockfd < 0) {
+        log_error(_("unable to accept: %s"), strerror(errno));
+        return -1;
+    }
+
+    if (_debug) {
+       log_debug(_("Accepting tcp/ip connection on fd #%d for port %d"), 
_sockfd, _port);
+    }
+
+    return _sockfd;
+}
+
+#ifdef _WIN32
+/* from sys/socket.h */
+typedef unsigned short      sa_family_t;
+
+/* from sys/un.h */
+#define UNIX_PATH_MAX   108
+
+struct sockaddr_un {
+    sa_family_t sun_family; /* AF_UNIX */
+    char sun_path[UNIX_PATH_MAX];   /* pathname */
+};
+
+#endif /* _WIN32 */
+
+// Connect to a named pipe
+bool
+Network::connectSocket(const string &sockname)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    struct sockaddr_un  addr;
+    fd_set              fdset;
+    struct timeval      tval;
+    int                 ret;
+    int                 retries;
+
+    addr.sun_family = AF_UNIX;
+    // socket names must be 108 bytes or less as specifiec in sys/un.h.
+    strncpy(addr.sun_path, sockname.c_str(), 100);
+
+    _sockfd = ::socket(AF_UNIX, SOCK_STREAM, 0);
+    if (_sockfd < 0)
+        {
+            log_error(_("unable to create socket: %s"), 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_debug(_("The connect() socket for fd %d was interupted by 
a system call"),
+                        _sockfd);
+                continue;
+            }
+
+        if (ret == -1)
+            {
+                log_debug(_("The connect() socket for fd %d never was 
available for writing"),
+                        _sockfd);
+#ifdef HAVE_WINSOCK_H
+                ::shutdown(_sockfd, 0); // FIXME: was 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"),
+                      _sockfd);
+            continue;
+        }
+
+        if (ret > 0) {
+            ret = ::connect(_sockfd, reinterpret_cast<struct sockaddr 
*>(&addr), sizeof(addr));
+            if (ret == 0) {
+                log_debug(_("\tsocket name %s for fd %d"), sockname, _sockfd);
+                _connected = true;
+                assert(_sockfd > 0);
+                return true;
+            }
+            if (ret == -1) {
+                log_error(_("The connect() socket for fd %d never was 
available for writing"),
+                        _sockfd);
+                _sockfd = -1;
+                assert(!_connected);
+                return false;
+            }
+        }
+    }
+    
+
+#ifndef HAVE_WINSOCK_H
+    fcntl(_sockfd, F_SETFL, O_NONBLOCK);
+#endif
+
+    _connected = true;
+    assert(_sockfd > 0);
+    return true;    
+}
+
+// Create a client connection to a tcp/ip based service
+bool
+Network::createClient(void)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    return createClient("localhost", RTMP);
+}
+bool
+Network::createClient(short /* port */)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    return false;
+}
+
+bool
+Network::createClient(const string &hostname)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    return createClient(hostname, RTMP);
+}
+
+bool
+Network::createClient(const string &hostname, short port)
+{
+    GNASH_REPORT_FUNCTION;
+
+    struct sockaddr_in  sock_in;
+    fd_set              fdset;
+    struct timeval      tval;
+    int                 ret;
+    int                 retries;
+    char                thishostname[MAXHOSTNAMELEN];
+    struct protoent     *proto;
+
+    assert( ! connected() );
+
+    if (port < 1024) {
+        log_error(_("Can't connect to privileged port %hd"), port);
+        _connected = false;
+        return false;
+    }
+
+    log_debug(_("%s: to host %s at port %d"), __FUNCTION__, hostname, port);
+
+    memset(&sock_in, 0, sizeof(struct sockaddr_in));
+    memset(&thishostname, 0, MAXHOSTNAMELEN);
+    if (hostname.size() == 0) {
+        if (gethostname(thishostname, MAXHOSTNAMELEN) == 0) {
+            log_debug(_("The hostname for this machine is %s"), thishostname);
+        } else {
+            log_debug(_("Couldn't get the hostname for this machine"));
+            return false;
+        }
+    }
+    const struct hostent *hent = ::gethostbyname(hostname.c_str());
+    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[INET_ADDRSTRLEN];
+    inet_ntop(sock_in.sin_family, &sock_in.sin_addr.s_addr, ascip, 
INET_ADDRSTRLEN);
+    log_debug(_("The IP address for this client socket is %s"), ascip);
+#endif
+
+    proto = ::getprotobyname("TCP");
+
+    _sockfd = ::socket(PF_INET, SOCK_STREAM, proto->p_proto);
+    if (_sockfd < 0)
+        {
+            log_error(_("unable to create socket: %s"), 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_debug(_("The connect() socket for fd %d was interupted by 
a system call"),
+                        _sockfd);
+                continue;
+            }
+
+        if (ret == -1)
+            {
+                log_debug(_("The connect() socket for fd %d never was 
available for writing"),
+                        _sockfd);
+#ifdef HAVE_WINSOCK_H
+                ::shutdown(_sockfd, 0); // FIXME: was 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"),
+                      _sockfd);
+            continue;
+        }
+
+        if (ret > 0) {
+            ret = ::connect(_sockfd, reinterpret_cast<struct sockaddr 
*>(&sock_in), sizeof(sock_in));
+            if (ret == 0) {
+               char *ascip = ::inet_ntoa(sock_in.sin_addr);
+//             char ascip[INET_ADDRSTRLEN];
+//             inet_ntop(sock_in.sin_family, &sock_in.sin_addr.s_addr, ascip, 
INET_ADDRSTRLEN);
+                log_debug(_("\tport %d at IP %s for fd %d"), port,
+                        ascip, _sockfd);
+                _connected = true;
+                assert(_sockfd > 0);
+                return true;
+            }
+            if (ret == -1) {
+                log_error(_("The connect() socket for fd %d never was 
available for writing"),
+                        _sockfd);
+                _sockfd = -1;
+                assert(!_connected);
+                return false;
+            }
+        }
+    }
+    //  ::close(_sockfd);
+    //  return false;
+
+    printf("\tConnected at port %d on IP %s for fd #%d", port,
+           ::inet_ntoa(sock_in.sin_addr), _sockfd);
+
+#ifndef HAVE_WINSOCK_H
+    fcntl(_sockfd, F_SETFL, O_NONBLOCK);
+#endif
+
+    _connected = true;
+    assert(_sockfd > 0);
+    return true;
+}
+
+bool
+Network::closeNet()
+{
+    GNASH_REPORT_FUNCTION;
+
+    if ((_sockfd > 0) && (_connected)) {
+        closeNet(_sockfd);
+        _sockfd = 0;
+        _connected = false;
+    }
+
+    return false;
+}
+
+bool
+Network::closeNet(int sockfd)
+{
+    GNASH_REPORT_FUNCTION;
+
+    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 #"
+                         << sockfd << strerror(errno) << endl;
+                } else {
+                    cerr << "The socket using fd #" << sockfd
+                         << " has been shut down successfully." << endl;
+                    return true;
+                }
+            }
+#endif
+            if (::close(sockfd) < 0) {
+               // If we have a bad file descriptor, it's because
+               // this got closed already, usually by another
+               // thread being paranoid.
+               if (errno != EBADF) {
+                   log_error(_("Unable to close the socket for fd #%d: %s"),
+                             sockfd, strerror(errno));
+               }
+#ifndef HAVE_WINSOCK_H
+                sleep(1);
+#endif
+                retries++;
+            } else {
+               log_debug(_("Closed the socket on fd #%d for port %d"), sockfd, 
_port);
+                return true;
+            }
+        }
+    }
+    return false;
+}
+// Description: Close an open socket connection.
+bool
+Network::closeConnection(void)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    closeConnection(_sockfd);
+    _sockfd = 0;
+    closeConnection(_listenfd);
+    _listenfd = 0;
+    _connected = false;
+
+    return false;
+}
+
+bool
+Network::closeConnection(int fd)
+{
+    GNASH_REPORT_FUNCTION;
+
+    if (fd > 0) {
+        ::close(fd);
+       log_debug("%s: Closed fd #%d", __FUNCTION__, fd);
+//        closeNet(fd);
+    }
+
+    return false;
+}
+
+// Read from the connection
+int
+Network::readNet(byte_t *buffer, int nbytes)
+{
+    return readNet(_sockfd, buffer, nbytes, _timeout);
+}
+
+int
+Network::readNet(byte_t *buffer, int nbytes, int timeout)
+{
+    return readNet(_sockfd, buffer, nbytes, timeout);
+}
+
+int
+Network::readNet(int fd, byte_t *buffer, int nbytes)
+{
+    return readNet(fd, buffer, nbytes, _timeout);
+}
+
+int
+Network::readNet(int fd, byte_t *buffer, int nbytes, int timeout)
+{
+    fd_set              fdset;
+    int                 ret = -1;
+    struct timeval      tval;
+
+#ifdef NET_TIMING
+    if (_timing_debug)
+    {
+        gettimeofday(&tp, NULL);
+        read_start_time = static_cast<double>(tp.tv_sec)
+            + static_cast<double>(tp.tv_usec*1e-6);
+    }
+#endif
+    if (fd > 2) {
+        FD_ZERO(&fdset);
+        FD_SET(fd, &fdset);
+
+        if (timeout == 0) {
+           ret = select(fd+1, &fdset, NULL, NULL, NULL);
+       } else {        
+           tval.tv_sec = timeout;
+           tval.tv_usec = 0;
+           ret = select(fd+1, &fdset, NULL, NULL, &tval);
+       }
+
+        // If interupted by a system call, try again
+        if (ret == -1 && errno == EINTR) {
+            log_error (_("The socket for fd %d was interupted by a system 
call"), fd);
+        }
+
+        if (ret == -1) {
+            log_error (_("The socket for fd %d was never available for 
reading"), fd);
+            return -1;
+        }
+
+        if (ret == 0) {
+           if (_debug) {
+               log_debug (_("The socket for fd %d timed out waiting to read"), 
fd);
+           }
+            return 0;
+        }
+
+        ret = read(fd, buffer, nbytes);
+       // If we read zero bytes, the network is closed, as we returned from 
the select()
+       if (ret == 0) {
+           return -1;
+       }
+       
+       if (_debug) {
+           log_debug (_("read %d bytes from fd %d from port %d"), ret, fd, 
_port);
+       }
+#if 0
+       if (ret) {
+           log_debug (_("%s: Read packet data from fd %d (%d bytes): \n%s"),
+                      __FUNCTION__, fd, ret, hexify(buffer, ret, true));
+       }
+#endif    
+    }
+
+    return ret;
+
+}
+
+// Write to the connection
+int
+Network::writeNet(const std::string& buffer)
+{
+    return writeNet(reinterpret_cast<const byte_t *>(buffer.c_str()), 
buffer.size());
+}
+
+int
+Network::writeNet(const byte_t *buffer, int nbytes)
+{
+    return writeNet(_sockfd, buffer, nbytes, _timeout);
+}
+
+// int
+// Network::writeNet(const byte_t *buffer, int nbytes)
+// {
+//     return writeNet(_sockfd, buffer, nbytes, _timeout);
+// }
+
+// int
+// Network::writeNet(int fd, const byte_t *buffer)
+// {
+//     return writeNet(fd, buffer, strlen(buffer), _timeout);
+// }
+
+int
+Network::writeNet(int fd, const byte_t *buffer, int nbytes)
+{
+    return writeNet(fd, buffer, nbytes, _timeout);
+}
+
+int
+Network::writeNet(int fd, const byte_t *buffer, int nbytes, int timeout)
+{
+    fd_set              fdset;
+    int                 ret = -1;
+    struct timeval      tval;
+
+    // We need a writable, and not const point for byte arithmetic.
+    byte_t *bufptr = const_cast<byte_t *>(buffer);
+
+#ifdef NET_TIMING
+    // If we are debugging the tcp/ip timings, get the initial time.
+    if (_timing_debug)
+    {
+        gettimeofday(&starttime, 0);
+    }
+#endif
+    if (fd > 2) {
+        FD_ZERO(&fdset);
+        FD_SET(fd, &fdset);
+
+        // Reset the timeout value, since select modifies it on return
+        if (timeout <= 0) {
+            timeout = 5;
+        }
+        tval.tv_sec = timeout;
+        tval.tv_usec = 0;
+        ret = select(fd+1, NULL, &fdset, NULL, &tval);
+
+        // If interupted by a system call, try again
+        if (ret == -1 && errno == EINTR) {
+            log_error (_("The socket for fd %d was interupted by a system 
call"), fd);
+        }
+
+        if (ret == -1) {
+            log_error (_("The socket for fd %d was never available for 
writing"), fd);
+        }
+
+        if (ret == 0) {
+            log_debug (_("The socket for fd %d timed out waiting to write"), 
fd);
+           return 0;
+        }
+
+        ret = write(fd, bufptr, nbytes);
+
+        if (ret == 0) {
+            log_error (_("Wrote zero out of %d bytes to fd %d: %s"), 
+               nbytes, fd, strerror(errno));
+            return ret;
+        }
+        if (ret < 0) {
+            log_error (_("Couldn't write %d bytes to fd %d: %s"), 
+               nbytes, fd, strerror(errno));
+            return ret;
+        }
+        if (ret > 0) {
+            bufptr += ret;
+            if (ret != nbytes) {
+               if (_debug) {
+                   log_debug (_("wrote %d bytes to fd %d, expected %d"),
+                              ret, fd, nbytes);
+               }
+            } else {
+               if (_debug) {
+                   log_debug (_("wrote %d bytes to fd %d for port %d"),
+                              ret, fd, _port);
+               }
+//                return ret;
+            }
+        }
+#if 0
+       if (ret) {
+           log_debug (_("%s: Wrote packet data to fd %d: \n%s"),
+                      __FUNCTION__, fd, hexify(buffer, ret, true));
+       }
+#endif    
+    }
+
+#ifdef NET_TIMING
+    if (_timing_debug)
+    {
+        gettimeofday(&endtime, 0);
+
+        if ((endtime.tv_sec - starttime.tv_sec) &&
+            endtime.tv_usec - starttime.tv_usec)
+        {
+            log_debug (_("took %d usec to write (%d bytes)"),
+               endtime.tv_usec - starttime.tv_usec, bytes_written);
+        }
+    }
+#endif
+
+
+    return ret;
+}
+
+void
+Network::toggleDebug(bool val)
+{
+    // Turn on our own debugging
+    _debug = val;
+
+    // Turn on debugging for the utility methods
+               // recursive on all control paths,
+               // function will cause runtime stack overflow
+
+               // toggleDebug(true);
+}
+
+
+} // end of gnash namespace
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: network.h
===================================================================
RCS file: network.h
diff -N network.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ network.h   28 Mar 2008 03:30:23 -0000      1.1
@@ -0,0 +1,160 @@
+// 
+//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+
+#ifndef __NETWORK_H__
+#define __NETWORK_H__
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#if !defined(HAVE_WINSOCK_H) || defined(__OS2__)
+# include <netinet/in.h>
+# include <arpa/inet.h>
+#else
+# include <winsock2.h>
+# include <windows.h>
+# include <fcntl.h>
+# include <sys/stat.h>
+# include <io.h>
+#endif
+
+#include "dsodefs.h" //For DSOEXPORT.
+#include <boost/cstdint.hpp>
+#include <cassert>
+#include <string>
+
+namespace gnash {
+
+// Define the ports for the RTMP protocols
+const short ADMIN = 1111;
+const short RTMP = 1935;
+const short RTMPT = 80;
+const short RTMPTS = 443;
+
+#ifdef __OS2__
+ typedef int    socklen_t;
+ #define SHUT_RDWR 0x2
+#endif
+
+#if defined(HAVE_WINSOCK_H) && !defined(__OS2__)
+  typedef long   in_addr_t;
+#  define inet_lnaof(x) inet_addr(inet_ntoa(x))
+  typedef int    socklen_t;
+#endif
+
+// Adjust for the constant size
+const size_t NETBUFSIZE = 2048;        // 1500 appears to be the default size 
as used by FMS
+
+class Network {
+public:
+    typedef boost::uint8_t byte_t;
+
+    DSOEXPORT Network();
+    DSOEXPORT ~Network();
+    
+    // Create a new server. After creating it, then you have to wait
+    // for an incoming connection.
+    int createServer(void);
+    DSOEXPORT int createServer(short port);
+    
+    // Accept a client connection for the current server.
+    int newConnection(void);
+    int newConnection(int fd);
+    int newConnection(bool block, int fd);
+    DSOEXPORT int newConnection(bool block);
+
+    // Connect to a named pipe
+    bool connectSocket(const std::string &sock);
+
+    // Create a client connection to a tcp/ip server
+    bool createClient(void);
+    bool createClient(short port);
+    bool createClient(const std::string &hostname);
+    DSOEXPORT bool createClient(const std::string &hostname, short port);
+
+    // Read from the connection
+    int readNet(byte_t *buffer, int nbytes);
+    DSOEXPORT int readNet(byte_t *buffer, int nbytes, int timeout);
+    int readNet(int fd, byte_t *buffer, int nbytes);
+    int readNet(int fd, byte_t *buffer, int nbytes, int timeout);
+    
+    // Write to the connection
+    int writeNet(const std::string &buffer);
+    DSOEXPORT int writeNet(const byte_t *buffer, int nbytes);
+//    int writeNet(int fd, const byte_t *buffer);
+    int writeNet(int fd, const byte_t *buffer, int nbytes);
+    int writeNet(int fd, const byte_t *buffer, int nbytes, int timeout);
+    
+    // Close the connection
+    DSOEXPORT bool closeNet();
+    bool closeNet(int fd);
+    DSOEXPORT bool closeConnection();
+    bool closeConnection(int fd);
+
+    // Change the debug flag
+    void toggleDebug(bool val);
+    
+    bool send(const char *str);
+
+    // Accessors for testing
+    bool connected()           
+    {
+        assert ( ( _connected && _sockfd > 0 ) || ( ! _connected && _sockfd <= 
0 ) );
+        return _connected;
+    };
+
+    void setPort(short x) { _port = x; };
+    short getPort() const { return _port; };
+    void setFileFd(int x) { _sockfd = x; };
+    int getFileFd() const { return _sockfd; };
+    int getListenFd() const { return _listenfd; };
+    void setListenFd(int x) { _listenfd = x; };
+    const std::string& getURL() const { return _url; }
+    const std::string& getProtocol() const  { return _protocol; }
+    const std::string& getHost() const { return _host; }
+    const std::string& getPortStr() const { return _portstr; }
+    const std::string& getPath() const { return _path; }
+    int getTimeout() const { return _timeout; }
+
+    // Network is not copiable !
+    //Network &operator = (Network &net) {}
+
+ protected:
+    in_addr_t   _ipaddr;
+    int         _sockfd;       // the file descriptor used for reading and 
writing
+    int         _listenfd;     // the file descriptor used to listen for new 
connections
+    short       _port;
+    std::string _portstr;
+    std::string _url;
+    std::string _protocol;
+    std::string _host;
+    std::string _path;
+    bool        _connected;
+    bool        _debug;
+    int         _timeout;
+};
+
+} // end of gnash namespace
+
+// __NETWORK_H__
+#endif
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: rtmp.cpp
===================================================================
RCS file: rtmp.cpp
diff -N rtmp.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ rtmp.cpp    28 Mar 2008 03:30:23 -0000      1.1
@@ -0,0 +1,520 @@
+// rtmp.cpp:  Adobe/Macromedia Real Time Message Protocol handler, for Gnash.
+// 
+//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include <iostream>
+
+#if ! (defined(_WIN32) || defined(WIN32))
+#      include <netinet/in.h>
+#endif
+
+#include "log.h"
+#include "amf.h"
+#include "rtmp.h"
+#include "network.h"
+#include "handler.h"
+
+using namespace amf;
+using namespace gnash;
+using namespace std;
+
+namespace cygnal
+{
+
+extern map<int, Handler *> handlers;
+
+// These are the textual responses
+const char *response_str[] = {
+    "/onStatus",
+    "/onResult",
+    "/onDebugEvents"
+};
+
+int
+RTMPproto::headerSize(Network::byte_t header)
+{
+//    GNASH_REPORT_FUNCTION;
+    
+    int headersize = -1;
+    
+    switch (header & AMF_HEADSIZE_MASK) {
+      case HEADER_12:
+          headersize = 12;
+          break;
+      case HEADER_8:
+          headersize = 8;
+          break;
+      case HEADER_4:
+          headersize = 4;
+          break;
+      case HEADER_1:
+          headersize = 11;
+          break;
+      default:
+          log_error(_("AMF Header size bits (0x%X) out of range"),
+                       header & AMF_HEADSIZE_MASK);
+          headersize = 1;
+          break;
+    };
+
+    return headersize;
+}
+
+RTMPproto::RTMPproto() 
+    : _handshake(0), _handler(0)
+{
+//    GNASH_REPORT_FUNCTION;
+//     _inbytes = 0;
+//     _outbytes = 0;
+    
+//    _body = new unsigned char(RTMP_BODY_SIZE+1);
+//    memset(_body, 0, RTMP_BODY_SIZE+1);
+}
+
+RTMPproto::~RTMPproto()
+{
+//    GNASH_REPORT_FUNCTION;
+    _variables.clear();
+//    delete _body;
+}
+
+void
+RTMPproto::addVariable(char *name, char *value)
+{
+    _variables[name] = value;
+}
+
+std::string
+RTMPproto::getVariable(char *name)
+{
+    return _variables[name];
+}
+
+// The handshake is a byte with the value of 0x3, followed by 1536
+// bytes of gibberish which we need to store for later.
+bool
+RTMPproto::handShakeWait()
+{
+    GNASH_REPORT_FUNCTION;
+
+//     char buffer[RTMP_BODY_SIZE+16];
+//     memset(buffer, 0, RTMP_BODY_SIZE+16);
+    Buffer *buf = _handler->pop();
+
+    if (buf == 0) {
+       log_debug("Que empty, net connection dropped for fd #%d", 
_handler->getFileFd());
+       return false;
+    }    
+//     if (readNet(buffer, 1) == 1) {
+    log_debug (_("Read initial Handshake Request"));
+//     } else {
+//         log_error (_("Couldn't read initial Handshake Request"));
+//         return false;
+//     }
+//    _inbytes += 1;
+
+    if (*(buf->reference()) == 0x3) {
+        log_debug (_("Handshake is correct"));
+    } else {
+        log_error (_("Handshake isn't correct"));
+        return false;
+    }
+
+//     if (buf->size() >= RTMP_BODY_SIZE) {
+//     secret = _handler->merge(buf->reference());
+//     }
+
+    if (buf->size() >= RTMP_BODY_SIZE) {
+       _handshake = new Buffer(RTMP_BODY_SIZE);
+       _handshake->copy(buf->reference() + 1, RTMP_BODY_SIZE);
+       log_debug (_("Handshake Data matched"));
+       delete buf;                     // we're done with the buffer
+       return true;
+    } else {
+       delete buf;                     // we're done with the buffer
+       log_error (_("Handshake Data didn't match"));
+       return false;
+    }
+    
+    return true;
+}
+
+// A request for a handshake is initiated by sending a byte with a
+// value of 0x3, followed by a message body of unknown format.
+bool
+RTMPproto::handShakeRequest()
+{
+    GNASH_REPORT_FUNCTION;
+
+#if 0
+    char buffer[RTMP_BODY_SIZE+1];
+    char c = 0x3;
+    int  i, ret;
+    
+    ret = writeNet(&c, 1);
+    _outbytes += 1;
+    // something went wrong, chances are the other end of the network
+    // connection is down, or never initialized.
+    if (ret <= 0) {
+        return false;
+    }
+
+    // Since we don't know what the format is, create a pattern we can
+    // recognize if we stumble across it later on.
+    for (i=0; i<RTMP_BODY_SIZE; i++) {
+        buffer[i] = i^256;
+    }
+    
+    _outbytes += RTMP_BODY_SIZE;
+    ret = writeNet(buffer, RTMP_BODY_SIZE);
+#endif
+    
+    return true;
+}
+
+// The response is the gibberish sent back twice, preceeded by a byte
+// with the value of 0x3.
+bool
+RTMPproto::handShakeResponse()
+{
+    GNASH_REPORT_FUNCTION;
+
+    Buffer *buf = new Buffer((RTMP_BODY_SIZE * 2) + 1);
+    Network::byte_t *ptr = buf->reference();
+    *ptr = 0x3;
+
+    std::copy(_handshake->begin(), _handshake->end(), (ptr + 1));
+    std::copy(_handshake->begin(), _handshake->end(), ptr + _handshake->size() 
+ 1);
+    _handler->pushout(buf);
+    _handler->notifyout();
+
+    log_debug("Sent RTMP Handshake response");
+
+    return true;    
+}
+
+// The client finished the handshake process by sending the second
+// data block we get from the server as the response
+bool
+RTMPproto::clientFinish()
+{
+    GNASH_REPORT_FUNCTION;
+
+#if 0
+    char buffer[RTMP_BODY_SIZE+1];
+    memset(buffer, 0, RTMP_BODY_SIZE+1);
+
+    if (readNet(buffer, RTMP_BODY_SIZE) == RTMP_BODY_SIZE) {        
+        log_debug (_("Read first data block in handshake"));
+    } else {
+        log_error (_("Couldn't read first data block in handshake"));
+        return false;
+    }
+    _inbytes += RTMP_BODY_SIZE;
+    if (readNet(buffer, RTMP_BODY_SIZE) == RTMP_BODY_SIZE) {        
+        log_debug (_("Read second data block in handshake"));
+//         _body = new char(RTMP_BODY_SIZE+1);
+//         memcpy(_body, buffer, RTMP_BODY_SIZE);
+    } else {
+        log_error (_("Couldn't read second data block in handshake"));
+        return false;
+    }
+    _inbytes += RTMP_BODY_SIZE;
+
+    writeNet(buffer, RTMP_BODY_SIZE);
+    _outbytes += RTMP_BODY_SIZE;
+#endif
+    
+    return true;
+}
+
+bool
+RTMPproto::serverFinish()
+{
+    GNASH_REPORT_FUNCTION;
+
+    Buffer *buf = _handler->pop();
+    Buffer *obj = buf;
+    
+    if (buf == 0) {
+       log_debug("Que empty, net connection dropped for fd #%d", 
_handler->getFileFd());
+       return false;
+    }
+    
+    // The first data packet is often buried in with the end of the handshake.
+    // So after the handshake block, we strip that part off, and just pass on
+    // the remainder for processing.
+    if (buf->size() > RTMP_BODY_SIZE) {
+       int size = buf->size() - RTMP_BODY_SIZE;  
+       obj = new Buffer[size];
+       obj->copy(buf->begin()+RTMP_BODY_SIZE, size);
+    } else {
+       _handler->wait();
+       obj = _handler->pop();
+    }
+    
+    int diff = std::memcmp(buf->begin(), _handshake->begin(), RTMP_BODY_SIZE);
+    delete buf;                        // we're done with the buffer
+    if (diff == 0) {
+       log_debug (_("Handshake Finish Data matched"));
+    } else {
+       log_error (_("Handshake Finish Data didn't match by %d bytes"), diff);
+//        return false;
+    }
+    
+    packetRead(obj);
+    
+    return true;
+}
+
+bool
+RTMPproto::packetRequest()
+{
+    GNASH_REPORT_FUNCTION;
+    return false;
+}
+
+bool
+RTMPproto::packetSend(Buffer *buf)
+{
+    GNASH_REPORT_FUNCTION;
+    return false;
+}
+
+bool
+RTMPproto::packetRead(Buffer *buf)
+{
+    GNASH_REPORT_FUNCTION;
+
+    int ret;
+    int packetsize = 0;
+    unsigned int amf_index, headersize;
+    Network::byte_t *ptr = buf->reference();
+    AMF amf;
+    
+//    
address@hidden@\000\000\000\000\000\000\003\000\003app\002\000#software/gnash/tests/1153948634.flv\000\bflashVer\002\000\fLNX
 
6,0,82,0\000\006swfUrl\002\000\035file:///file|address@hidden://localhost/software/gnash/tests/1153948634
+    amf_index = *buf->reference() & AMF_INDEX_MASK;
+    headersize = headerSize(*buf->reference());
+    log_debug (_("The Header size is: %d"), headersize);
+    log_debug (_("The AMF index is: 0x%x"), amf_index);
+
+//     if (headersize > 1) {
+//     packetsize = parseHeader(ptr);
+//         if (packetsize) {
+//             log_debug (_("Read first RTMP packet header of size %d"), 
packetsize);
+//         } else {
+//             log_error (_("Couldn't read first RTMP packet header"));
+//             return false;
+//         }
+//     }
+
+    Network::byte_t *end = buf->find(0xc3);
+    log_debug("END is 0x%x", (void *)end);
+    *end = '*';
+    packetsize = parseHeader(ptr);
+    ptr += headersize;
+
+    Element el;
+    ptr = amf.extractElement(&el, ptr);
+    el.dump();
+    ptr = amf.extractElement(&el, ptr) + 1;
+    el.dump();
+    log_debug (_("Reading AMF packets till we're done..."));
+//    buf->dump();
+    while (ptr < end) {
+       amf::Element *el = new amf::Element;
+       ptr = amf.extractVariable(el, ptr);
+       el->dump();
+//     if (ptr != 0) {
+//         ptr += 1;    
+// //      addObj(el);
+//     } else {
+//         break;
+//         }
+    }
+    ptr += 1;
+    while (ptr < buf->end()) {
+       amf::Element *el = new amf::Element;
+       ptr = amf.extractVariable(el, ptr);
+       el->dump();
+    }
+    
+    return true;
+}
+
+int
+RTMPproto::parseHeader(Network::byte_t *in)
+{
+//    GNASH_REPORT_FUNCTION;
+
+    Network::byte_t *tmpptr = in;
+    
+    _amf_index = *tmpptr & AMF_INDEX_MASK;
+    log_debug (_("The AMF channel index is %d"), _amf_index);
+    
+    _header_size = headerSize(*tmpptr++);
+    log_debug (_("The header size is %d"), _header_size);
+
+    if (_header_size >= 4) {
+        _mystery_word = *tmpptr++;
+        _mystery_word = (_mystery_word << 12) + *tmpptr++;
+        _mystery_word = (_mystery_word << 8) + *tmpptr++;
+        log_debug(_("The mystery word is: %d"), _mystery_word);
+    }
+
+    if (_header_size >= 8) {
+        _total_size = *tmpptr++;
+        _total_size = (_total_size << 12) + *tmpptr++;
+        _total_size = (_total_size << 8) + *tmpptr++;
+        _total_size = _total_size & 0xffffff;
+//        _amf_data = new uint8_t(_total_size+1);
+//        _seekptr = _amf_data;
+//        memset(_amf_data, 0, _total_size+1);
+        log_debug(_("The body size is: %d"), _total_size);
+    }
+
+    if (_header_size >= 8) {
+        _type = *(AMF::content_types_e *)tmpptr;
+        tmpptr++;
+        log_debug(_("The type is: 0x%x"), _type);
+    }
+
+    switch(_type) {
+      case AMF::CHUNK_SIZE:
+      case AMF::BYTES_READ:
+      case AMF::PING:
+      case AMF::SERVER:
+      case AMF::CLIENT:
+      case AMF::VIDEO_DATA:
+      case AMF::NOTIFY:
+      case AMF::SHARED_OBJ:
+      case AMF::INVOKE:
+          _packet_size = AMF_VIDEO_PACKET_SIZE;
+          break;
+      case AMF::AUDIO_DATA:
+          _packet_size = AMF_AUDIO_PACKET_SIZE;
+          break;
+      default:
+          log_error (_("ERROR: Unidentified AMF header data type 0x%x"), 
_type);
+          break;
+    };
+    
+    if (_header_size == 12) {
+//        hexify((Network::byte_t *)hexint, (Network::byte_t *)tmpptr, 3, 
false);
+        _src_dest = *(reinterpret_cast<rtmp_source_e *>(tmpptr));
+        tmpptr += sizeof(unsigned int);
+//        log_debug(_("The source/destination is: %d, or 0x%s"), _src_dest, 
hexint);
+    }
+
+    return _packet_size;
+}
+
+// This is the thread for all incoming RTMP connections
+void
+rtmp_handler(Handler::thread_params_t *args)
+{
+    GNASH_REPORT_FUNCTION;
+    Handler *hand = reinterpret_cast<Handler *>(args->handle);
+    RTMPproto rtmp;
+
+    rtmp.setHandler(hand);
+    string docroot = args->filespec;
+
+    log_debug(_("Starting RTMP Handler for fd #%d, tid %ld"),
+             args->netfd, pthread_self());
+    
+    while (!hand->timetodie()) {       
+       log_debug(_("Waiting for RTMP request on fd #%d..."), args->netfd);
+       hand->wait();
+       // This thread is the last to wake up when the browser
+       // closes the network connection. When browsers do this
+       // varies, elinks and lynx are very forgiving to a more
+       // flexible HTTP protocol, which Firefox/Mozilla & Opera
+       // are much pickier, and will hang or fail to load if
+       // you aren't careful.
+       if (hand->timetodie()) {
+           log_debug("Not waiting no more, no more for RTMP data for fd 
#%d...", args->netfd);
+           map<int, Handler *>::iterator hit = handlers.find(args->netfd);
+           if ((*hit).second) {
+               log_debug("Removing handle %x for RTMP on fd #%d", (void 
*)hand), args->netfd;
+               handlers.erase(args->netfd);
+           }
+
+           return;
+       }
+#ifdef USE_STATISTICS
+       struct timespec start;
+       clock_gettime (CLOCK_REALTIME, &start);
+#endif
+       if (!rtmp.handShakeWait()) {
+           hand->clearout();   // remove all data from the outgoing que
+           hand->die();        // tell all the threads for this connection to 
die
+           hand->notifyin();
+           log_debug("Net RTMP done for fd #%d...", args->netfd);
+//         hand->closeNet(args->netfd);
+           return;
+       }
+       string url, filespec;
+       url = docroot;
+       
+       rtmp.handShakeResponse();
+
+       hand->wait();
+       // This thread is the last to wake up when the browser
+       // closes the network connection. When browsers do this
+       // varies, elinks and lynx are very forgiving to a more
+       // flexible HTTP protocol, which Firefox/Mozilla & Opera
+       // are much pickier, and will hang or fail to load if
+       // you aren't careful.
+       if (hand->timetodie()) {
+           log_debug("Not waiting no more, no more for RTMP data for fd 
#%d...", args->netfd);
+           map<int, Handler *>::iterator hit = handlers.find(args->netfd);
+           if ((*hit).second) {
+               log_debug("Removing handle %x for RTMP on fd #%d", (void 
*)hand), args->netfd;
+               handlers.erase(args->netfd);
+           }
+
+           return;
+       }
+       rtmp.serverFinish();
+    
+    // Keep track of the network statistics
+//    Statistics st;
+//    st.setFileType(NetStats::RTMP);
+//     st.stopClock();
+//     log_debug (_("Bytes read: %d"), proto.getBytesIn());
+//     log_debug (_("Bytes written: %d"), proto.getBytesOut());
+//     st.setBytes(proto.getBytesIn() + proto.getBytesOut());
+//     st.addStats();
+//     proto.resetBytesIn();
+//     proto.resetBytesOut();  
+
+//     st.dump(); 
+    }
+}
+    
+} // end of cygnal namespace
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: rtmp.h
===================================================================
RCS file: rtmp.h
diff -N rtmp.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ rtmp.h      28 Mar 2008 03:30:23 -0000      1.1
@@ -0,0 +1,165 @@
+// 
+//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+
+#ifndef _RTMP_H_
+#define _RTMP_H_
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include "tu_config.h"
+
+#include <boost/cstdint.hpp>
+#include <vector>
+
+#include "amf.h"
+#include "handler.h"
+#include "network.h"
+
+namespace cygnal
+{
+
+#define RTMP_HANDSHAKE 0x3
+#define RTMP_BODY_SIZE 1536
+#define MAX_AMF_INDEXES 64
+
+class DSOEXPORT RTMPproto
+{
+public:
+    typedef enum {
+       CLIENT,                     // Flash player
+       SERVER                      // Flash com server
+    } rtmp_source_e;
+    typedef enum {
+        CONNECT = 0x1,
+        DISCONNECT = 0x2,
+        SET_ATTRIBUTE = 0x3,
+        UPDATE_DATA = 0x4,
+        UPDATE_ATTRIBUTE = 0x5,
+        SEND_MESSAGE = 0x6,
+        STATUS = 0x7,
+        CLEAR_DATA = 0x8,
+        DELETE_DATA = 0x9,
+        DELETE_ATTRIBUTE = 0xa,
+        INITIAL_DATA = 0xb
+    } sharedobj_types_e;
+    typedef enum {
+        RTMP_STATE_HANDSHAKE_SEND,
+        RTMP_STATE_HANDSHAKE_RECV,
+        RTMP_STATE_HANDSHAKE_ACK,
+        RTMP_STATE_CONNECT,
+        RTMP_STATE_NETCONNECT,
+        RTMP_STATE_NETSTREAM,
+        RTMP_STATE_HEADER,
+        RTMP_STATE_DONE
+    } rtmp_state_t;
+    typedef enum {
+        RTMP_ERR_UNDEF=0,
+        RTMP_ERR_NOTFOUND,
+        RTMP_ERR_PERM,
+        RTMP_ERR_DISKFULL,
+        RTMP_ERR_ILLEGAL,
+        RTMP_ERR_UNKNOWNID,
+        RTMP_ERR_EXISTS,
+        RTMP_ERR_NOSUCHUSER,
+        RTMP_ERR_TIMEOUT,
+        RTMP_ERR_NORESPONSE
+    } rtmp_error_t;
+
+// Each header consists of the following:
+//
+// * UTF string (including length bytes) - name
+// * Boolean - specifies if understanding the header is `required'
+// * Long - Length in bytes of header
+// * Variable - Actual data (including a type code)
+    typedef struct {
+        amf::amfutf8_t name;
+       boost::uint8_t required;
+       boost::uint32_t length;
+        void *data;
+    } rtmp_head_t;    
+    typedef enum {
+        HEADER_12 = 0x0,
+        HEADER_8  = 0x40,
+        HEADER_4  = 0x80,
+        HEADER_1  = 0xc0
+    } rtmp_headersize_e;    
+    
+// Each body consists of the following:
+//
+// * UTF String - Target
+// * UTF String - Response
+// * Long - Body length in bytes
+// * Variable - Actual data (including a type code)
+    typedef struct {
+        amf::amfutf8_t target;
+        amf::amfutf8_t response;
+       boost::uint32_t length;
+        void *data;
+    } rtmp_body_t;
+    
+    RTMPproto();
+    ~RTMPproto();
+    bool handShakeWait();
+    bool handShakeRequest();
+    bool handShakeResponse();
+    bool clientFinish();
+    bool serverFinish();
+    bool packetRequest();
+    bool packetSend(Buffer *buf);
+    bool packetRead(Buffer *buf);
+
+    void addVariable(char *name, char *value);
+    std::string getVariable(char *name);
+    void setHandler(Handler *hand) { _handler = hand; };
+    int headerSize(gnash::Network::byte_t header);
+    int parseHeader(gnash::Network::byte_t *header);
+
+    int getHeaderSize()         { return _header_size; }; 
+    int getTotalSize()          { return _total_size; }; 
+    int getPacketSize()         { return _packet_size; };
+    int getMysteryWord()        { return _mystery_word; };
+    rtmp_source_e getRouting()  { return _src_dest; };
+    int getAMFIndex()           { return _amf_index; };
+  private:
+    std::map<char *, std::string> _variables;
+//     unsigned char               _body[RTMP_BODY_SIZE+1];
+//     std::vector<amf::AMF *>     _amfs;
+    Buffer             *_handshake;
+    Handler            *_handler;
+    int                 _amf_index;
+    int                 _header_size;
+    int                 _total_size;
+    int                 _packet_size;
+    rtmp_source_e       _src_dest;
+    amf::AMF::content_types_e     _type;
+    int                 _mystery_word;
+};
+
+// This is the thread for all incoming RTMP connections
+void rtmp_handler(Handler::thread_params_t *args);
+
+} // end of cygnal namespace
+// end of _RTMP_H_
+#endif
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:
+

Index: statistics.cpp
===================================================================
RCS file: statistics.cpp
diff -N statistics.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ statistics.cpp      28 Mar 2008 03:30:23 -0000      1.1
@@ -0,0 +1,137 @@
+// statistics.cpp:  Network performance stats for Cygnal, for Gnash.
+// 
+//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include <boost/thread/mutex.hpp>
+#include <string>
+#include <list>
+#include <iostream>
+
+#include "log.h"
+#include "netstats.h"
+#include "statistics.h"
+
+using namespace gnash;
+using namespace std;
+
+static boost::mutex io_mutex;
+
+// The string versions of the codec, used for debugging. If you add
+// another enum type to codec_e, you have to add the string
+// representation here or you'll get the wrong output.
+const char *codec_names[] = {
+    "NO_CODEC",
+    "Ogg",
+    "Theora",
+    "Dirac",
+    "Snow",
+    "MP3",
+    "MPEG4",
+    "H264",
+    "H263",
+    "FLV",
+    "VP6",
+    "VP7"
+};
+
+// The string versions of the file type, used for debugging. If you add
+// another enum type to filetypes_e, you have to add the string
+// representation here or you'll get the wrong output.
+const char *filetype_names[] = {
+        "NO_FILETYPE",
+       "HTTP",
+        "RTMP",
+        "RTMPT",
+        "RTMPTS",
+        "SWF",
+        "SWF5",
+        "SWF6",
+        "SWF7",
+        "SWF8",
+        "SWF9",
+        "AUDIO",
+        "VIDEO"
+};
+
+namespace cygnal 
+{
+
+Statistics::Statistics() {
+}
+
+Statistics::~Statistics() {
+    dump();
+}
+
+float
+Statistics::getFPS() {
+       return 0.0; // TODO: FIXME !
+}
+
+int
+Statistics::getBitRate() {
+
+    return (getStartTime() - getStopTime()).seconds() / getBytes();
+}
+
+int
+Statistics::addStats() {
+    NetStats *st = new NetStats;
+
+    st->setStartTime(getStartTime());
+    st->setStopTime(getStopTime());
+    st->setBytes(getBytes());
+    st->setFileType(getFileType());
+    
+    boost::mutex::scoped_lock lock(io_mutex);
+    _netstats.push_back(st);
+    
+    return _netstats.size();
+}
+
+void
+Statistics::dump() {   
+    boost::mutex::scoped_lock lock(io_mutex);
+    list<NetStats *>::iterator it;
+
+    for (it = _netstats.begin(); it != _netstats.end(); it++) {
+        NetStats *stats = (*it);
+        if (stats->getFileType() <= VIDEO) {
+            log_debug (_("Stream type is: %s"), 
filetype_names[stats->getFileType()]);
+        }
+//         if (((stats->getFileType() == VIDEO) || (stats->getFileType() == 
AUDIO)) &&
+//             stats->getCodec() <= VP7) {
+//             log_debug (_("Stream codec is: %s"), 
codec_names[stats->getCodec()]);
+//         }
+        log_debug (_("%d bytes were transfered in %s seconds"),
+                stats->getBytes(),
+                 to_simple_string(stats->getTimeSpan()).c_str());
+    }
+}
+
+} // end of cygnal namespace
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: statistics.h
===================================================================
RCS file: statistics.h
diff -N statistics.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ statistics.h        28 Mar 2008 03:30:23 -0000      1.1
@@ -0,0 +1,95 @@
+// 
+//   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// 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
+//
+
+#ifndef __STATISTICS_H__
+#define __STATISTICS_H__
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include <sys/time.h>
+#include <network.h>
+#include <list>
+
+#include "netstats.h"
+
+namespace cygnal 
+{
+
+class Statistics : public NetStats {
+public:
+    Statistics();
+    ~Statistics();
+    typedef enum {
+        NO_BROWSER,
+        MOZILLA,
+        FIREFOX,
+        OPERA,
+        KONQUEROR,
+        GALEON,
+        EPIPHANY,
+        SAFARI,
+        IE
+    } browser_e;
+    typedef enum {
+        NO_OSTYPE,
+        LINUX,
+        BSDS,
+        DARWIN,
+        WIN32,
+        SOLARIS
+    } ostype_e;
+
+    // Add a sample
+    int addStats();
+    
+    // these make calculations on the collected network data.
+    float getFPS();
+    int getBitRate();
+    
+    // Accessors
+    void setIPaddr(in_addr_t x) { _ipaddr = x; };
+    void setBrowser(browser_e x) { _browser = x; } ;
+    void setOS(ostype_e x) { _os = x; } ;
+    in_addr_t getIPaddr() { return _ipaddr; };
+    browser_e getBrowser() { return _browser; };
+    ostype_e getOS() { return _os; };
+    
+//    void setFilespec(std::string &x) { _filespec = x; } ;
+//    std::string &getFilespec() { return _filespec; };
+    // Dump the collected network statistics in a human readable form.
+    void dump();
+    void clear();
+private:
+    in_addr_t           _ipaddr;
+    browser_e           _browser;
+    ostype_e            _os;
+    std::list<NetStats *> _netstats;
+    boost::uint32_t     _msg_count;
+    std::vector<std::string> _filespec;
+};
+ 
+} // end of cygnal namespace
+
+#endif // __STATISTICS_H__
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:




reply via email to

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