gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r11389: merge from branch.


From: Rob Savoye
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r11389: merge from branch.
Date: Tue, 25 Aug 2009 18:29:00 -0000
User-agent: Bazaar (1.16.1)

------------------------------------------------------------
revno: 11389 [merge]
committer: Rob Savoye <address@hidden>
branch nick: trunk
timestamp: Fri 2009-08-07 21:21:12 -0600
message:
  merge from branch.
modified:
  libbase/log.cpp
  libbase/log.h
  libcore/asobj/NetConnection_as.cpp
  libcore/asobj/flash/net/SharedObject_as.cpp
  libnet/diskstream.cpp
  libnet/network.cpp
  libnet/rtmp.h
  libnet/rtmp_client.cpp
  libnet/rtmp_client.h
  testsuite/network.all/SharedObject_as.hx
  utilities/processor.cpp
  utilities/rtmpget.cpp
=== modified file 'libbase/log.cpp'
--- a/libbase/log.cpp   2009-05-20 08:37:23 +0000
+++ b/libbase/log.cpp   2009-08-08 00:55:45 +0000
@@ -146,6 +146,12 @@
 }
 
 void
+processLog_network(const boost::format& fmt)
+{
+       dbglogfile.log(N_("NETWORK"), fmt.str());
+}
+
+void
 processLog_error(const boost::format& fmt)
 {
        dbglogfile.log(N_("ERROR"), fmt.str());

=== modified file 'libbase/log.h'
--- a/libbase/log.h     2009-06-07 21:14:22 +0000
+++ b/libbase/log.h     2009-08-08 00:55:45 +0000
@@ -136,10 +136,18 @@
         _actiondump = x;
     }
 
+    void setNetwork(int x) {
+        _network = x;
+    }
+
     int getActionDump() const {
         return _actiondump;
     }
     
+    int getNetwork() const {
+        return _network;
+    }
+    
     void setParserDump (int x) {
         _parserdump = x;
     }
@@ -204,6 +212,9 @@
     /// Whether to dump all SWF actions
     bool _actiondump;
 
+    /// Whether to dump all networking actions
+    bool _network;
+
     /// Whether to dump parser output
     bool _parserdump;
 
@@ -223,6 +234,7 @@
 
 };
 
+DSOEXPORT void processLog_network(const boost::format& fmt);
 DSOEXPORT void processLog_error(const boost::format& fmt);
 DSOEXPORT void processLog_unimpl(const boost::format& fmt);
 DSOEXPORT void processLog_trace(const boost::format& fmt);
@@ -251,7 +263,7 @@
 /// the code. Append the name to log_ to call the function, e.g. 
 /// log_error, log_unimpl.
 #define LOG_TYPES (error) (debug) (unimpl) (aserror) (swferror) \
-    (amferror) (security) (action) (parse) (trace) (abc)
+    (amferror) (security) (action) (parse) (trace) (abc) (network)
 
 /// This actually creates the template functions using the TOKENIZE
 /// functions above. The templates look like this:
@@ -342,6 +354,10 @@
 #define VERBOSE_MALFORMED_AMF 1
 #endif
 
+// Define to 0 this to remove Networking verbosity at compile-time
+#ifndef VERBOSE_NETWORKING
+#define VERBOSE_NETWORKING 1
+#endif
 
 #if VERBOSE_PARSE
 #define IF_VERBOSE_PARSE(x) do { if ( 
LogFile::getDefaultInstance().getParserDump() ) { x; } } while (0);
@@ -355,6 +371,12 @@
 #define IF_VERBOSE_ACTION(x)
 #endif
 
+#if VERBOSE_ACTION
+#define IF_VERBOSE_NETWORK(x) do { if ( 
LogFile::getDefaultInstance().getNetwork() ) { x; } } while (0);
+#else
+#define IF_VERBOSE_NETWORK(x)
+#endif
+
 #if VERBOSE_ASCODING_ERRORS
 // TODO: check if it's worth to check verbosity level too...
 #define IF_VERBOSE_ASCODING_ERRORS(x) { if ( 
gnash::RcInitFile::getDefaultInstance().showASCodingErrors() ) { x; } }

=== modified file 'libcore/asobj/NetConnection_as.cpp'
--- a/libcore/asobj/NetConnection_as.cpp        2009-08-04 17:39:22 +0000
+++ b/libcore/asobj/NetConnection_as.cpp        2009-08-08 03:21:12 +0000
@@ -846,24 +846,19 @@
 
     URL url(uri, getRunResources(*this).baseURL());
 
-    if ( url.protocol() == "rtmp" )
-    {
-        LOG_ONCE(log_unimpl("NetConnection.connect(%s): RTMP not "
-                    "yet supported", url) );
-        notifyStatus(CONNECT_FAILED);
-        return;
-    }
-
-    if ( url.protocol() != "http" )
-    {
+    if ((url.protocol() != "rtmp")
+       || (url.protocol() != "rtmpt")
+       || (url.protocol() != "rtmpts")
+       || (url.protocol() != "https")
+       || (url.protocol() == "http")) {
         IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror("NetConnection.connect(%s): invalid connection "
-            "protocol", url);
-        );
+                log_aserror("NetConnection.connect(%s): invalid connection "
+                            "protocol", url);
+                                  );
         notifyStatus(CONNECT_FAILED);
         return;
     }
-
+    
     // This is for HTTP remoting
 
     if (!URLAccessManager::allow(url)) {

=== modified file 'libcore/asobj/flash/net/SharedObject_as.cpp'
--- a/libcore/asobj/flash/net/SharedObject_as.cpp       2009-08-04 17:39:22 
+0000
+++ b/libcore/asobj/flash/net/SharedObject_as.cpp       2009-08-08 03:21:12 
+0000
@@ -41,9 +41,11 @@
 #include "VM.h"
 #include "Property.h"
 #include "string_table.h"
+#include "rc.h" // for use of rcfile
 #include "URLAccessManager.h"
+#include "network.h"
+#include "rtmp_client.h"
 #include "URL.h"
-#include "rc.h" // for use of rcfile
 
 #include "NetConnection_as.h"
 #include <boost/scoped_array.hpp>
@@ -211,19 +213,15 @@
 private:
 
     SimpleBuffer& _buf;
-
     VM& _vm;
-
     string_table& _st;
-
     PropertiesOffsetTable& _offsetTable;
-
     bool _error;
 };
 
 } // anonymous namespace
 
-class SharedObject_as: public as_object
+class SharedObject_as: public as_object, public RTMPClient
 {
 public:
 
@@ -232,7 +230,8 @@
     SharedObject_as()
         : as_object(getSharedObjectInterface()),
           _data(0),
-          _persistance(0)
+          _persistance(0),
+         _connected(false)
     { 
     }
 
@@ -290,10 +289,13 @@
     /// Process the connect(uri) method.
     void connect(NetConnection_as *obj, const std::string& uri);
 
-    NetConnection_as *_netconn;
+    void setURI(const std::string &url) { _uri = url; }
+    std::string &getURI() { return _uri; }
+
+    bool isConnected() { return _connected; };
+    void isConnected(bool x) { _connected = x; };
 
 protected:
-
 #ifdef GNASH_USE_GC
     void markReachableResources() const;
 #endif
@@ -302,8 +304,9 @@
 
     as_object   *_data;
     bool        _persistance;
-
-    SOL _sol;
+    SOL                _sol;
+    bool       _connected;
+    std::string        _uri;
 };
 
 
@@ -871,13 +874,21 @@
     if (fn.nargs > 1) {
        const as_value& uri = fn.arg(1);
        const VM& vm = getVM(fn);
-       const std::string& uriStr = uri.to_string_versioned(vm.getSWFVersion());
+       const std::string& uriStr = uri.to_string_versioned(vm.getSWFVersion());
     }
     
     boost::intrusive_ptr<NetConnection_as> nc =
        boost::dynamic_pointer_cast<NetConnection_as>(                          
                     fn.arg(0).to_object(*getGlobal(fn)));
 
     // This is always set without validification.fooc->setURI(uriStr);
+    string str = nc->getURI();
+    obj->setPath(str);
+    URL uri = nc->getURI();
+    Network *net = new Network;
+
+    net->setProtocol(uri.protocol());
+    net->setHost(uri.hostname());
+    net->setPort(strtol(uri.port().c_str(), NULL, 0) & 0xffff);
 
     // Check first arg for validity 
     if (getSWFVersion(fn) > 6) {
@@ -888,7 +899,6 @@
             log_unimpl("SharedObject.connect(%s): args after the first are "
                     "not supported", ss.str());
         }
-//         nc->connect(uriStr);
         nc->connect();
     }
     
@@ -920,18 +930,21 @@
 as_value
 sharedobject_send(const fn_call& fn)
 {
+    GNASH_REPORT_FUNCTION;
+
     boost::intrusive_ptr<SharedObject_as> obj =
         ensureType<SharedObject_as>(fn.this_ptr);
-    UNUSED(obj);
 
-    LOG_ONCE(log_unimpl("SharedObject.send"));
+    if (obj->isConnected() == false) {
+       obj->connectToServer(obj->getURI());
+    }
+    
     return as_value();
 }
 
 as_value
 sharedobject_flush(const fn_call& fn)
-{
-    
+{    
     GNASH_REPORT_FUNCTION;
 
     boost::intrusive_ptr<SharedObject_as> obj =

=== modified file 'libnet/diskstream.cpp'
--- a/libnet/diskstream.cpp     2009-05-04 22:20:08 +0000
+++ b/libnet/diskstream.cpp     2009-08-05 17:22:03 +0000
@@ -46,6 +46,12 @@
 #include "cache.h"
 #include "getclocktime.hpp"
 
+// This is Linux specific, but offers better I/O for sending
+// files out a network connection.
+#ifdef HAVE_SENDFILE
+# include <sys/sendfile.h>
+#endif
+
 #include <boost/thread/mutex.hpp>
 static boost::mutex io_mutex;
 

=== modified file 'libnet/network.cpp'
--- a/libnet/network.cpp        2009-07-18 23:10:13 +0000
+++ b/libnet/network.cpp        2009-08-08 02:48:35 +0000
@@ -833,7 +833,7 @@
 int
 Network::readNet(int fd, byte_t *buffer, int nbytes, int timeout)
 {
-//    GNASH_REPORT_FUNCTION;
+//     GNASH_REPORT_FUNCTION;
 
     fd_set              fdset;
     int                 ret = -1;
@@ -962,14 +962,14 @@
 int
 Network::writeNet(amf::Buffer *buffer)
 {
-//    GNASH_REPORT_FUNCTION;
+//     GNASH_REPORT_FUNCTION;
     return writeNet(buffer->reference(), buffer->allocated());
 };
 
 int
 Network::writeNet(int fd, amf::Buffer *buffer)
 {
-//    GNASH_REPORT_FUNCTION;
+//     GNASH_REPORT_FUNCTION;
     return writeNet(fd, buffer->reference(), buffer->allocated());
 };
 
@@ -977,7 +977,7 @@
 int
 Network::writeNet(amf::Buffer &buffer)
 {
-//    GNASH_REPORT_FUNCTION;
+//     GNASH_REPORT_FUNCTION;
     return writeNet(buffer.reference(), buffer.allocated());
 };
 
@@ -985,20 +985,21 @@
 int
 Network::writeNet(int fd, amf::Buffer &buffer)
 {
-//    GNASH_REPORT_FUNCTION;
+//     GNASH_REPORT_FUNCTION;
     return writeNet(fd, buffer.reference(), buffer.allocated());
 };
 
 int
 Network::writeNet(const std::string& data)
 {
-//    GNASH_REPORT_FUNCTION;
+//     GNASH_REPORT_FUNCTION;
     return writeNet(reinterpret_cast<const byte_t *>(data.c_str()), 
data.size());
 }
 
 int
 Network::writeNet(const byte_t *data, int nbytes)
 {
+//     GNASH_REPORT_FUNCTION;
     return writeNet(_sockfd, data, nbytes, _timeout);
 }
 
@@ -1017,12 +1018,15 @@
 int
 Network::writeNet(int fd, const byte_t *data, int nbytes)
 {
+//     GNASH_REPORT_FUNCTION;
     return writeNet(fd, data, nbytes, _timeout);
 }
 
 int
 Network::writeNet(int fd, const byte_t *buffer, int nbytes, int timeout)
 {
+//     GNASH_REPORT_FUNCTION;
+
     fd_set              fdset;
     int                 ret = -1;
 

=== modified file 'libnet/rtmp.h'
--- a/libnet/rtmp.h     2009-07-26 01:56:07 +0000
+++ b/libnet/rtmp.h     2009-08-08 02:47:08 +0000
@@ -36,8 +36,11 @@
 namespace gnash
 {
 
+const boost::uint8_t RTMP_VERSION = 0x3;
 const boost::uint8_t RTMP_HANDSHAKE = 0x3;
 const int  RTMP_HANDSHAKE_SIZE = 1536;
+const int  RTMP_RANDOM_SIZE = 1528;
+const int  RTMP_HANDSHAKE_HEADER_SIZE = 8;
 const int  MAX_AMF_INDEXES = 64;
 
 const int  RTMP_HEADSIZE_MASK = 0xc0;
@@ -48,6 +51,7 @@
 const int  PING_MSG_SIZE = 6;
 const int  RTMP_SYSTEM_CHANNEL = 2;
 
+
 // For terminating sequences, a byte with value 0x09 is used.
 const char TERMINATOR = 0x09;
 
@@ -82,17 +86,38 @@
     typedef std::map<const char*, amf::Element> AMFProperties;
     typedef std::deque<CQue *> queues_t;
     typedef enum {
-       RAW=0x0,
-       ADPCM=0x01,
-       MP3=0x02,
-       NELLYMOSER_8khz=0x05,
-       NEYYNOSER=0x6
+       RAW     = 0x0001,
+       ADPCM   = 0x0002,
+       MP3     = 0x0004,
+       INTEL   = 0x0005,
+       CELT    = 0x0008,               // unique to Gnash
+       NELLY8  = 0x0020,
+       NELLY   = 0x0040,
+       G711A   = 0x0080,
+       G711U   = 0x0100,
+       NELLY16 = 0x0200,
+       AAC     = 0x0400,
+       SPEEX   = 0x0800,
+       DEFAULT_AUDIO_SET = 0x0267,
+       ALLAUDIO = 0x0fff
     } audiocodecs_e;
     typedef enum {
-       H263=0x2,
-       SCREEN0x3,
-       VP6=0x4
+       UNUSED   = 0x0001,
+       JPEG     = 0x0002,
+       SORENSON = 0x4,
+       ADOBE    = 0x0008,
+       VP6      = 0x0010,
+       VP6ALPHA = 0x0020,
+       SCREEN2  = 0x0040,
+       H264     = 0x0080,
+       DEFAULT_VIDEO_SET = 0x007c,
+       ALLVIDEO = 0x00ff
     } videocodecs_e;
+    typedef enum {
+       SEEK = 0x1,
+       AMF0 = 0x0,
+       AMF3 = 0x3
+    } videofunction_e;
     // The second byte of the AMF file/stream is appears to be 0x00 if the
     // client is the Flash Player and 0x01 if the client is the FlashCom
     // server.
@@ -113,19 +138,19 @@
         INVOKE = 0x14,
        FLV_DATA = 0x16
     } content_types_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 {
+         CREATE = 0x1,         // Client sends event
+         DELETE = 0x2,         // Client sends event
+         REQUEST_CHANGE = 0x3, // Client sends event
+         CHANGE = 0x4,         // Server sends event
+         SUCCESS_CLIENT = 0x5, // Server sends event
+         SEND_MESSAGE = 0x6,   // Client sends event
+         STATUS = 0x7,         // Server sends evetn
+         CLEAR = 0x8,          // Server sends event
+         DELETE_SLOT = 0x9,    // Server sends event
+         REQUEST_DELETE_SLOT = 0xa,// Client sends event
+         SUCCESS_SERVER = 0xb  // Server sends event
+     } sharedobj_types_e;
     typedef enum {
        PING_CLEAR  = 0x0,      // clear the stream
        PING_PLAY   = 0x1,      // clear the playing buffer
@@ -190,6 +215,10 @@
        RTMPMsg::rtmp_source_e   src_dest;
        content_types_e type;
     } rtmp_head_t;
+    typedef struct {
+       boost::uint32_t uptime;
+       boost::uint8_t version[4];
+    } rtmp_handshake_head_t;
     typedef enum {
         HEADER_12 = 0x0,
         HEADER_8  = 0x40,
@@ -322,6 +351,7 @@
     CQue       _queues[MAX_AMF_INDEXES];
 //    queues_t    _channels;
     amf::Buffer        _buffer;
+    rtmp_handshake_head_t _handshake_header;
 };
 
 } // end of gnash namespace

=== modified file 'libnet/rtmp_client.cpp'
--- a/libnet/rtmp_client.cpp    2009-07-26 01:56:07 +0000
+++ b/libnet/rtmp_client.cpp    2009-08-08 02:50:32 +0000
@@ -21,6 +21,7 @@
 #include "gnashconfig.h"
 #endif
 
+#include <ctime>
 #include <iostream>
 #include <string>
 #include <map>
@@ -41,6 +42,7 @@
 #include "utility.h"
 #include "buffer.h"
 #include "GnashSleep.h"
+#include "URL.h"
 
 using namespace gnash;
 using namespace std;
@@ -80,11 +82,98 @@
 // Make the NetConnection object that is used to connect to the
 // server.
 boost::shared_ptr<Buffer> 
+RTMPClient::encodeConnect()
+{
+//     GNASH_REPORT_FUNCTION;
+    
+    return encodeConnect(_path.c_str());
+}
+
+boost::shared_ptr<Buffer> 
+RTMPClient::encodeConnect(const char *uri)
+{
+//     GNASH_REPORT_FUNCTION;
+    
+    return encodeConnect(uri, RTMPClient::DEFAULT_AUDIO_SET,
+                        RTMPClient::DEFAULT_VIDEO_SET,
+                        RTMPClient::SEEK);
+}
+
+boost::shared_ptr<Buffer> 
+RTMPClient::encodeConnect(const char *uri,
+                         double audioCodecs, double videoCodecs,
+                         double videoFunction)
+{
+    GNASH_REPORT_FUNCTION;
+    
+    URL url(uri);
+    string portstr;
+
+    short port = 0;
+    string protocol;           // the network protocol, rtmp or http
+    string query;              // any queries for the host
+    string app;                        // the application name
+    string path;               // the path to the file on the server
+    string tcUrl;              // the tcUrl field
+    string swfUrl;             // the swfUrl field
+    string filename;           // the filename to play
+    string pageUrl;            // the pageUrl field
+    string hostname;           // the hostname of the server
+
+
+    protocol = url.protocol();
+    hostname = url.hostname();
+    log_network("hostname: %s", hostname);
+    portstr = url.port();
+    query = url.querystring();
+
+    if (portstr.empty()) {
+        if ((protocol == "http") || (protocol == "rtmpt")) {
+            port = RTMPT_PORT;
+        }
+        if (protocol == "rtmp") {
+            port = RTMP_PORT;
+        }
+    } else {
+        port = strtol(portstr.c_str(), NULL, 0) & 0xffff;
+    }
+
+
+    path = url.path();
+
+    string::size_type end = path.rfind('/');
+    if (end != string::npos) {
+       filename = path.substr(end + 1);
+    }  
+    
+    tcUrl = uri;
+    app = filename;    
+    swfUrl = "mediaplayer.swf";
+    pageUrl = "http://gnashdev.org";;
+    
+    log_network("URL is %s", url);
+    log_network("Protocol is %s", protocol);
+    log_network("Host is %s", hostname);
+    log_network("Port is %s", port);
+    log_network("Path is %s", path);
+    log_network("Filename is %s", filename);
+    log_network("App is %s", app);
+    log_network("Query is %s", query);
+    log_network("tcUrl is %s", tcUrl);
+    log_network("swfUrl is %s", swfUrl);
+    log_network("pageUrl is %s", pageUrl);
+
+    return encodeConnect(app.c_str(), swfUrl.c_str(), tcUrl.c_str(),
+                        audioCodecs, videoCodecs, videoFunction,
+                        pageUrl.c_str());
+}
+
+boost::shared_ptr<Buffer> 
 RTMPClient::encodeConnect(const char *app, const char *swfUrl, const char 
*tcUrl,
                           double audioCodecs, double videoCodecs, double 
videoFunction,
                           const char *pageUrl)
 {
-//    GNASH_REPORT_FUNCTION;
+    GNASH_REPORT_FUNCTION;
     
     AMF amf_obj;
 
@@ -171,7 +260,75 @@
                   
     return buf;
 }
-
+    
+bool
+RTMPClient::connectToServer(const std::string &/* url */)
+{
+    GNASH_REPORT_FUNCTION;
+
+    // If we're currently not connected, build and send the
+    // initial handshake packet.
+    if (connected() == false) {
+       createClient();
+
+       // Build the NetConnection Packet, which seems to need
+       // to be on the end of the second block of handshake data.
+       // We build this here so we can get the total encoded
+       // size of the object.
+       boost::shared_ptr<amf::Buffer> ncbuf = encodeConnect();
+       boost::shared_ptr<amf::Buffer> head = encodeHeader(0x3,
+                           RTMP::HEADER_12, ncbuf->allocated(),
+                           RTMP::INVOKE, RTMPMsg::FROM_CLIENT);
+       
+
+       // Build the first handshake packet, and send it to the
+       // server.
+       boost::shared_ptr<amf::Buffer> handshake1 = handShakeRequest();
+       if (!handshake1) {
+           log_error("RTMP handshake request failed");
+           return false;
+       }
+       
+       boost::scoped_ptr<amf::Buffer> handshake2(new amf::Buffer
+                 ((RTMP_HANDSHAKE_SIZE * 2) + ncbuf->allocated()));
+
+       *handshake2 = handshake1;
+       *handshake2 += ncbuf;
+
+       // Finish the handshake process, which has to have the
+       // NetConnection::connect() as part of the buffer, or Red5
+       // refuses to answer.
+       setTimeout(20);
+#if 0
+       if (!clientFinish(*handshake2)) {
+#else
+       if (!clientFinish(*ncbuf)) {
+#endif
+           log_error("RTMP handshake completion failed!");
+//         return (false);
+       }
+       
+       // give the server time to process our NetConnection::connect() request 
+       boost::shared_ptr<amf::Buffer> response;
+       boost::shared_ptr<RTMP::rtmp_head_t> rthead;
+       boost::shared_ptr<RTMP::queues_t> que;
+       
+       RTMPClient::msgque_t msgque = recvResponse();
+       while (msgque.size()) {
+           boost::shared_ptr<RTMPMsg> msg = msgque.front();
+           msgque.pop_front();
+           if (msg->getStatus() ==  RTMPMsg::NC_CONNECT_SUCCESS) {
+               log_network("Sent NetConnection Connect message sucessfully");
+           }               
+           if (msg->getStatus() ==  RTMPMsg::NC_CONNECT_FAILED) {
+               log_error("Couldn't send NetConnection Connect message,");
+           }
+       }
+    }
+
+    return true;
+}
+    
 boost::shared_ptr<amf::Buffer>
 RTMPClient::encodeEchoRequest(const std::string &method, double id, 
amf::Element &el)
 {
@@ -360,112 +517,172 @@
 
 // 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
+boost::shared_ptr<amf::Buffer>
 RTMPClient::handShakeRequest()
 {
     GNASH_REPORT_FUNCTION;
+    boost::uint32_t zero = 0;
 
     // Make a buffer to hold the handshake data.
-    _handshake = new Buffer(RTMP_HANDSHAKE_SIZE+1);
-    if (!_handshake) {
-       return false;
+    boost::shared_ptr<amf::Buffer> handshake(new 
Buffer(RTMP_HANDSHAKE_SIZE+1));
+    if (!handshake) {
+       return handshake;
     }
 
-    // All RTMP connections start with a 0x3
-    *_handshake = RTMP_HANDSHAKE;
-
-    // Since we don't know what the format is, create a pattern we can
-    // recognize if we stumble across it later on.
-    for (int i=0; i<RTMP_HANDSHAKE_SIZE; i++) {
+    // All RTMP connections start with the RTMP version number
+    // which should always be 0x3.
+    *handshake = RTMP_VERSION;
+
+    // Get the uptime for the header
+    // yes, we loose precision here but it's only a 4 byte field
+    time_t t;
+    time(&t);
+    boost::uint32_t tt = t;
+    *handshake += tt;
+
+    // This next field in the header for the RTMP handshake should be zeros
+    *handshake += zero;
+
+    // The handshake contains random data after the initial header
+    for (int i=0; i<RTMP_RANDOM_SIZE; i++) {
        boost::uint8_t pad = i^256;
-        *_handshake += pad;
+        *handshake += pad;
     }
     
-    int ret = writeNet(_handshake);
-    if (ret) {
-       return true;
-    } else {
-       return false;
+    int ret = writeNet(*handshake);
+    if (ret <= 0) {
+       handshake.reset();
     }
+                                            
+    return handshake;
 }
 
 // The client finishes the handshake process by sending the second
 // data block we get from the server as the response
-bool
+
+boost::shared_ptr<amf::Buffer>
 RTMPClient::clientFinish()
 {
-    GNASH_REPORT_FUNCTION;
+//     GNASH_REPORT_FUNCTION;
+
     amf::Buffer data;
     return clientFinish(data);
 }
 
-bool
+boost::shared_ptr<amf::Buffer>
 RTMPClient::clientFinish(amf::Buffer &data)
 {
     GNASH_REPORT_FUNCTION;
     bool done = false;
     int ret = 0;
+    int retries = 5;
     int offset = 0;
-
     
-    // The total size of incoming bytes is twice the handshake size, plus the 
handshake
-    // header byte. Then we append the NetConnection::connect packet as well.
-    size_t maxsize = (RTMP_HANDSHAKE_SIZE*2)+1+data.size();
-    boost::shared_ptr<amf::Buffer> buf(new amf::Buffer(maxsize));
+    // Create the initial buffer to hold the response, and keep reading data
+    // until it is populated
+    // The handhake for this phase is twice the size of the initial handshake
+    // we sent previously, plus one byte for the RTMP version header.
+    int max_size = (RTMP_HANDSHAKE_SIZE*2) + 1;
+    boost::shared_ptr<amf::Buffer> handshake1(new amf::Buffer(
+                             max_size + data.allocated()));
     do {
-       ret = readNet(buf->reference() + offset, buf->size() - offset);
+       ret = readNet(handshake1->end(), max_size - offset);
        offset += ret;
-       buf->setSeekPointer(buf->reference() + offset);
-       if (offset == (RTMP_HANDSHAKE_SIZE*2)+1) {
+       handshake1->setSeekPointer(handshake1->reference() + offset);
+       if ((offset >= max_size) || (ret >= max_size)) {
+           handshake1->setSeekPointer(handshake1->reference() + max_size);
+//         log_network("Read entire packet of %d bytes", ret);
            done = true;
        }
        if (ret < 0) {
            log_error (_("Couldn't read data block in handshake!"));
+           handshake1.reset();
+           return handshake1;
+       }
+       // if retries equals zero, then we're done trying
+       if (retries == 0) {
            done = true;
+       } else {
+           --retries;
        }
-    } while (!done);    
+    } while (!done);
+
+    if (handshake1->allocated() == max_size) {
+       log_network (_("Read data block in handshake, got %d bytes."),
+                  handshake1->allocated());
+    } else {
+       log_error("Couldn't read data block in handshake, read %d bytes!",
+                 handshake1->allocated());
+    }    
+
+    _handshake_header.uptime = ntohl(*reinterpret_cast<boost::uint32_t *>
+                                    (handshake1->reference() + 1));
+
+    log_network("RTMP Handshake header: Uptime: %u", _handshake_header.uptime);
+
+#if 0
+    if (memcmp(handshake2->reference() + RTMP_HANDSHAKE_SIZE + 8,
+              _handshake->reference() + 8, RTMP_RANDOM_SIZE-8) == 0) {
+       log_network("Handshake matched");
+    } else {
+       log_network("Handshake didn't match");
+//     return false;
+    }
+#endif
+
+    // Make a new buffer big enough to hold the handshake, data, and header 
byte
+    boost::shared_ptr<amf::Buffer> handshake2(new amf::Buffer(
+                            RTMP_HANDSHAKE_SIZE + data.allocated()));
     
-    if (buf->allocated() > RTMP_HANDSHAKE_SIZE) {
-       log_debug (_("Read first data block in handshake"));
-    } else {
-       log_error (_("Couldn't read first data block in handshake"));
-    }
-    if (buf->allocated() > RTMP_HANDSHAKE_SIZE*2) {
-       log_debug (_("Read second data block in handshake"));
-    } else {
-       log_error (_("Couldn't read second data block in handshake"));
-       return false;
-    }
+    // Copy the timestamp from the message we just received.
+    handshake2->copy(handshake1->reference()+1, sizeof(boost::uint32_t));
 
 #if 1
-    if (memcmp(buf->reference() + RTMP_HANDSHAKE_SIZE + 1, 
_handshake->reference(), RTMP_HANDSHAKE_SIZE) == 0) {
-       log_debug("Handshake matched");
-    } else {
-       log_debug("Handshake didn't match");
-//     return false;
-    }
-    *buf += data;
+    // The next timestamp is the one we just received bumped up a tiny bit.
+    // I have no clue if this is correct, but fom hex dumps the previous
+    // timestamp should be the baseline, and this is just that time plus
+    // whatever it took to get the message. The 7 is a bit randomly chosen.
+    boost::uint32_t tt = htonl(_handshake_header.uptime + 7);
+#else
+    // Get the uptime for the header
+    // yes, we loose precision here but it's only a 4 byte field
+    time_t t;
+    time(&t);
+    boost::uint32_t tt = t;
 #endif
-    
-    // For some reason, Red5 won't connect unless the connect packet is
-    // part of the final handshake packet. Sending the identical data with
-    // two writeNet()s won't connect. Go figure...
-    _handshake->resize(RTMP_HANDSHAKE_SIZE + data.size());
-    // FIXME: unless the handshake is all zeros, Gnash won't connect to
-    // Red5 for some reason. Cygnal isn't so picky.
-    _handshake->clear();
-    _handshake->setSeekPointer(_handshake->reference() + RTMP_HANDSHAKE_SIZE);
+    *handshake2 += tt;
+
+    // Add the handshake data
+    boost::uint8_t *start = handshake1->reference() + RTMP_HANDSHAKE_SIZE
+       + 1 + 8;
+    handshake2->append(start, RTMP_RANDOM_SIZE);
     // Add the NetConnection::connect() packet
-    _handshake->append(data.reference(), data.allocated());
-    ret = writeNet(_handshake->reference(), _handshake->allocated());
+    *handshake2 += data;
+
+    // Write the second chunk to the server
+    log_network("About to write %d bytes, data is: %d bytes.",
+             handshake2->allocated(),
+             data.allocated());
+    log_network("Client response header for handshake 2: %s", 
hexify(handshake2->reference(), 12, false));
+    log_network("Data in response for handshake 2: %s", 
hexify(handshake1->reference() + RTMP_HANDSHAKE_SIZE + 1, 12, false));
+#if 0
+    ret = writeNet(handshake2->reference()+RTMP_HANDSHAKE_SIZE,
+                  RTMP_HANDSHAKE_SIZE + data.allocated() + 1);
+#else
+    ret = writeNet(*handshake2);
+#endif
     if ( ret <= 0 ) {
-       return false;
+       log_error("Couldn't write the second handshake packet!");
+       handshake1.reset();
+       return handshake1;
+    } else {
+       _connected = false;
     }
-    
+
     // Since the handshake completed sucessfully, we're connected.
-    _connected == true;
+    _connected = true;
 
-    return true;
+    return handshake1;
 }
 
 // Get and process an RTMP response. After reading all the data, then we have
@@ -483,13 +700,14 @@
     boost::shared_ptr<amf::Buffer> response = recvMsg();
     if (!response) {
        log_error("Got no response from the RTMP server");
+       return msgque;
     }
 
     // when doing remoting calls I don't see this problem with an empty packet 
from Red5,
     // but when I do streaming, it's always there, so we need to remove it.
     boost::uint8_t *pktstart = response->reference();
     if (*pktstart == 0xff) {
-       log_debug("Got empty packet in buffer.");
+       log_network("Got empty packet in buffer.");
        pktstart++;
     }
 
@@ -508,7 +726,7 @@
     // is indexed by the channel number, the second queue is all the messages 
that
     // have arrived for that channel.
     while (que->size()) {      // see if there are any messages at all
-       log_debug("%s: There are %d channel queues in the RTMP input queue, %d 
messages in front queue",
+       log_network("%s: There are %d channel queues in the RTMP input queue, 
%d messages in front queue",
                  __PRETTY_FUNCTION__, que->size(), que->front()->size());
        // Get the CQue for the first channel
        CQue *channel_q = que->front();
@@ -540,7 +758,7 @@
                  case RTMP::PING:
                  {
                      boost::shared_ptr<RTMP::rtmp_ping_t> ping = 
decodePing(ptr->reference() + rthead->head_size);
-                     log_debug("Got a Ping type %s", ping_str[ping->type]);
+                     log_network("Got a Ping type %s", ping_str[ping->type]);
                      break;
                  }
                  case RTMP::SERVER:

=== modified file 'libnet/rtmp_client.h'
--- a/libnet/rtmp_client.h      2009-07-26 01:56:07 +0000
+++ b/libnet/rtmp_client.h      2009-08-08 02:50:32 +0000
@@ -32,6 +32,7 @@
 #include "network.h"
 #include "buffer.h"
 #include "dsodefs.h"
+#include "URL.h"
 
 namespace gnash
 {
@@ -44,15 +45,24 @@
 
     bool handShakeWait();
 //    bool handShakeResponse();
-    bool clientFinish();
-    DSOEXPORT bool clientFinish(amf::Buffer &data);
-    DSOEXPORT bool handShakeRequest();
+    boost::shared_ptr<amf::Buffer> clientFinish();
+    DSOEXPORT  boost::shared_ptr<amf::Buffer> clientFinish(amf::Buffer &data);
+    DSOEXPORT boost::shared_ptr<amf::Buffer> handShakeRequest();
     
     // These are used for creating the primary objects
-    // Create the initial object sent to the server, which is 
NetConnection::connect()
-    DSOEXPORT boost::shared_ptr<amf::Buffer> encodeConnect(const char *app, 
const char *swfUrl, const char *tcUrl,
-                                   double audioCodecs, double videoCodecs, 
double videoFunction,
-                                   const char *pageUrl);
+    // Create the initial object sent to the server, which
+    // is NetConnection::connect()
+    DSOEXPORT boost::shared_ptr<amf::Buffer> encodeConnect();
+    DSOEXPORT boost::shared_ptr<amf::Buffer> encodeConnect(const char *uri);
+    DSOEXPORT boost::shared_ptr<amf::Buffer> encodeConnect(const char *uri, 
double audioCodecs, double videoCodecs,
+                  double videoFunction);
+    DSOEXPORT boost::shared_ptr<amf::Buffer> encodeConnect(const char *app,
+                  const char *swfUrl, const char *tcUrl,
+                   double audioCodecs, double videoCodecs, double 
videoFunction,
+                    const char *pageUrl);
+    
+    DSOEXPORT bool connectToServer(const std::string &url);
+
     // Create the second object sent to the server, which is 
NetStream():;NetStream()
     DSOEXPORT boost::shared_ptr<amf::Buffer> encodeStream(double id);
     boost::shared_ptr<amf::Buffer> encodeStreamOp(double id, rtmp_op_e op, 
bool flag);

=== modified file 'testsuite/network.all/SharedObject_as.hx'
--- a/testsuite/network.all/SharedObject_as.hx  2009-08-04 03:13:31 +0000
+++ b/testsuite/network.all/SharedObject_as.hx  2009-08-05 17:23:53 +0000
@@ -69,25 +69,30 @@
            DejaGnu.note("No RTMP port specified, defaulting to "+rtmpport);
        }
        
-       var nc:NetConnection = new NetConnection();
        // The Adobe flash player only supports remoting with RTMP
        rtmpuri = "rtmp://"+hostname+":"+rtmpport+"/fitcDemo";
-       
+
+       var nc:NetConnection = new NetConnection();
+//     addEventListeners();
+       nc.connect(rtmpuri);
+       DejaGnu.note("Connecting to "+rtmpuri);
+
 #if flash9
-        var x1:SharedObject = SharedObject.getRemote("sharedobjecttest", 
rtmpuri, true);
+        var x1:SharedObject = SharedObject.getRemote("rsoltest", nc.uri, true);
 #else
-       var x1:SharedObject = SharedObject.getRemote("sharedobjecttest", 
rtmpuri, true);
+       var x1:SharedObject = SharedObject.getRemote("rsoltest", nc.uri, true);
 #end         
+
         if (Std.is(x1, SharedObject)) {
             DejaGnu.pass("SharedObject class exists");
         } else {
             DejaGnu.fail("SharedObject class doesn't exist");
         }
-        DejaGnu.note("SharedObject type is "+Type.typeof(x1));
+//        DejaGnu.note("SharedObject type is "+Type.typeof(x1));
 
 //     var ns:NetStream = new NetStream(nc);
 #if flash9
-//     nc.addEventListener(NetStatusEvent.NET_STATUS, ncOnStatus);
+       nc.addEventListener(NetStatusEvent.NET_STATUS, ncOnStatus);
 #else
        nc.setID = function(id) {
            DejaGnu.note("Got a setID() from "+rtmpuri);
@@ -106,11 +111,12 @@
 //         DejaGnu.note(e.description);
 #end
        x1.connect(nc);
-
-//     Reflect.callMethod(x1, Reflect.field(x1, "connect"), []);
-       DejaGnu.note("Connecting to "+rtmpuri);
-
-       x1.send("sharedobjecttest", "Hello World");
+//     x1.addEventListener(SyncEvent.SYNC, syncHandler);
+
+       x1.data.whoami = "me";
+       x1.send("rsoltest", "Hello World");
+
+       DejaGnu.note("Sent SharedObject to "+rtmpuri);
 
 #if flash9
        x1.setDirty("data");

=== modified file 'utilities/processor.cpp'
--- a/utilities/processor.cpp   2009-07-13 09:04:26 +0000
+++ b/utilities/processor.cpp   2009-08-08 02:48:06 +0000
@@ -276,7 +276,7 @@
         dbglogfile.setVerbosity();
     }
 
-    while ((c = getopt (argc, argv, ":hwvapr:gf:d:")) != -1) {
+    while ((c = getopt (argc, argv, ":hwvapr:gf:d:n")) != -1) {
        switch (c) {
          case 'h':
              usage (argv[0]);
@@ -297,6 +297,9 @@
 #else
               log_error (_("The debugger has been disabled at configuration 
time"));
 #endif
+         case 'n':
+             dbglogfile.setNetwork(true); 
+             break;
          case 'a':
 #if VERBOSE_ACTION
              dbglogfile.setActionDump(true); 

=== modified file 'utilities/rtmpget.cpp'
--- a/utilities/rtmpget.cpp     2009-06-07 21:14:22 +0000
+++ b/utilities/rtmpget.cpp     2009-08-05 17:23:14 +0000
@@ -131,8 +131,8 @@
         { 'a', "app",           Arg_parser::yes  },
         { 'p', "path",          Arg_parser::yes  },
         { 'f', "filename",      Arg_parser::yes  },
-        { 't', "tcurl",     Arg_parser::yes  },
-        { 's', "swfurl",    Arg_parser::yes  },
+        { 't', "tcurl",         Arg_parser::yes  },
+        { 's', "swfurl",        Arg_parser::yes  },
         { 'u', "url",           Arg_parser::yes  },
         { 'n', "netdebug",      Arg_parser::no  }
         };
@@ -152,12 +152,14 @@
         dbglogfile.setVerbosity(rcfile.verbosityLevel());
     }    
 
+#if 0
     string app; // the application name
     string path; // the path to the file on the server
     string tcUrl; // the tcUrl field
     string swfUrl; // the swfUrl field
     string filename; // the filename to play
-
+#endif
+    
     // Handle command line arguments
     for( int i = 0; i < parser.arguments(); ++i ) {
         const int code = parser.code(i);
@@ -216,132 +218,23 @@
         return EXIT_FAILURE;
     }
 
-    RTMPClient client;    
-    short port = 0;
-    string protocol;        // the network protocol, rtmp or http
-    string query;       // any queries for the host
-    string pageUrl;     // the pageUrl field
-    string hostname;        // the hostname of the server
-    
-    URL url( infiles[0] );
-    string portstr;
-    
     // Trap ^C (SIGINT) so we can kill all the threads
     act.sa_handler = cntrlc_handler;
     sigaction (SIGINT, &act, NULL);
 
-    protocol = url.protocol();
-    hostname = url.hostname();
-    log_debug("hostname: %s", hostname);
-    portstr = url.port();
-    query = url.querystring();
-
-    if ( portstr.empty() )
-    {
-        if ((protocol == "http") || (protocol == "rtmpt")) {
-            port = RTMPT_PORT;
-        }
-        if (protocol == "rtmp") {
-            port = RTMP_PORT;
-        }
-    }
-    else
-    {
-        port = strtol(portstr.c_str(), NULL, 0) & 0xffff;
-    }
-
-
-    if ( path.empty() )
-    {
-        path = url.path();
-    }
-
-    if ( filename.empty() )
-    {
-        string::size_type end = path.rfind('/');
-        if (end != string::npos) {
-            filename = path.substr(end + 1);
-        }
-    }
-
-
-    if (tcUrl.empty()) {
-        tcUrl = protocol + "://" + hostname;
-        if (!portstr.empty()) {
-            tcUrl += ":" + portstr;
-        }
-        if (!query.empty()) {
-            tcUrl += "/" + query;
-        } else {
-            tcUrl += "/" + path;
-        }
-    }
-    
-    if (app.empty())
-    {
-
-        // Get the application name
-        // rtmp://localhost/application/resource
-        //                  ^^^^^^^^^^^ <-- appname is this
-        //
-        app = path;
-       if ( ! filename.empty() )
-       {
-               string::size_type end = app.rfind(filename);
-               if (end != string::npos) {
-                   app = app.substr(0, end);
-               }
-       }
-
-       // drop slashes
-        string::size_type end = app.find_first_not_of('/');
-       if (end != string::npos) {
-           app = app.substr(end);
-       }
-        end = app.find_last_not_of('/');
-       if (end != string::npos) {
-           app = app.substr(0, end+1);
-       }
-        
-        if (!query.empty()) {
-            app = path;
-            app += "?" + query;
-        }
-    }
-
-    if (swfUrl.empty()) {
-        swfUrl = "mediaplayer.swf";
-    }
-    if (pageUrl.empty()) {
-        pageUrl = "http://gnashdev.org";;
-    }
-    
-    log_debug("URL is %s", url);
-    log_debug("Protocol is %s", protocol);
-    log_debug("Host is %s", hostname);
-    log_debug("Port is %s", port);
-    log_debug("Path is %s", path);
-    log_debug("Filename is %s", filename);
-    log_debug("App is %s", app);
-    log_debug("Query is %s", query);
-    log_debug("tcUrl is %s", tcUrl);
-    log_debug("swfUrl is %s", swfUrl);
-    log_debug("pageUrl is %s", pageUrl);
-
+    RTMPClient client;
     client.toggleDebug(netdebug);
     if (client.createClient(hostname, port) == false) {
         log_error("Can't connect to RTMP server %s", hostname);
         exit(-1);
     }
     
-    if ( ! client.handShakeRequest() )
-    {
+    if (! client.handShakeRequest()) {
         log_error("RTMP handshake request failed");
         exit(EXIT_FAILURE);
     }
     
-    if ( ! client.clientFinish() )
-    {
+    if (! client.clientFinish()) {
         log_error("RTMP handshake completion failed");
         exit(EXIT_FAILURE);
     }
@@ -351,7 +244,13 @@
     // RTMP::rtmp_head_t *rthead = 0;
     // int ret = 0;
     log_debug("Sending NetConnection Connect message,");
-    BufferSharedPtr buf2 = client.encodeConnect(app.c_str(), swfUrl.c_str(), 
tcUrl.c_str(), 615, 124, 1, pageUrl.c_str());
+#if 0
+    BufferSharedPtr buf2 = client.encodeConnect(app.c_str(), swfUrl.c_str(), 
tcUrl.c_str(), RTMPClient::DEFAULT_AUDIO_SET,
+                     RTMPClient::DEFAULT_VIDEO_SET,
+                     RTMPClient::SEEK, pageUrl.c_str());
+#else
+    BufferSharedPtr buf2 = client.encodeConnect(infiles[0]);    
+#endif
 //    BufferSharedPtr buf2 = 
client.encodeConnect("video/2006/sekt/gate06/tablan_valentin", 
"mediaplayer.swf", 
"rtmp://velblod.videolectures.net/video/2006/sekt/gate06/tablan_valentin", 615, 
124, 1, "http://gnashdev.org";);
 //    BufferSharedPtr buf2 = client.encodeConnect("oflaDemo", 
"http://192.168.1.70/software/gnash/tests/ofla_demo.swf";, 
"rtmp://localhost/oflaDemo/stream", 615, 124, 1, 
"http://192.168.1.70/software/gnash/tests/index.html";);
     //buf2->resize(buf2->size() - 6); // FIXME: encodeConnect returns the 
wrong size for the buffer!


reply via email to

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