gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] gnash/libnet rtmp_server.cpp rtmp_server.h


From: Rob Savoye
Subject: [Gnash-commit] gnash/libnet rtmp_server.cpp rtmp_server.h
Date: Sat, 29 Mar 2008 18:48:33 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Rob Savoye <rsavoye>    08/03/29 18:48:33

Added files:
        libnet         : rtmp_server.cpp rtmp_server.h 

Log message:
        New files for RTMP server side functions.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/rtmp_server.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/rtmp_server.h?cvsroot=gnash&rev=1.1

Patches:
Index: rtmp_server.cpp
===================================================================
RCS file: rtmp_server.cpp
diff -N rtmp_server.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ rtmp_server.cpp     29 Mar 2008 18:48:32 -0000      1.1
@@ -0,0 +1,441 @@
+// 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>
+#include <string>
+#include <map>
+
+#if ! (defined(_WIN32) || defined(WIN32))
+#      include <netinet/in.h>
+#endif
+
+#include "log.h"
+#include "amf.h"
+#include "rtmp.h"
+#include "rtmp_server.h"
+#include "network.h"
+#include "element.h"
+#include "handler.h"
+
+using namespace amf;
+using namespace gnash;
+using namespace std;
+
+namespace gnash
+{
+
+extern map<int, Handler *> handlers;
+
+RTMPServer::RTMPServer() 
+{
+//    GNASH_REPORT_FUNCTION;
+//     _inbytes = 0;
+//     _outbytes = 0;
+    
+//    _body = new unsigned char(RTMP_BODY_SIZE+1);
+//    memset(_body, 0, RTMP_BODY_SIZE+1);
+}
+
+RTMPServer::~RTMPServer()
+{
+//    GNASH_REPORT_FUNCTION;
+    _variables.clear();
+//    delete _body;
+}
+
+// The handshake is a byte with the value of 0x3, followed by 1536
+// bytes of gibberish which we need to store for later.
+bool
+RTMPServer::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;
+}
+
+// The response is the gibberish sent back twice, preceeded by a byte
+// with the value of 0x3.
+bool
+RTMPServer::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;    
+}
+
+bool
+RTMPServer::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
+RTMPServer::packetSend(Buffer * /* buf */)
+{
+    GNASH_REPORT_FUNCTION;
+    return false;
+}
+
+bool
+RTMPServer::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;
+//         }
+//     }
+
+#if 1
+    Network::byte_t *end = buf->remove(0xc3);
+#else
+    Network::byte_t *end = buf->find(0xc3);
+    log_debug("END is %x", (void *)end);
+    *end = '*';
+#endif
+    ptr = parseHeader(ptr);
+//     ptr += headersize;
+
+# if 0    
+    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);
+       addVariable(el);
+       el->dump();
+    }
+    ptr += 1;
+    size_t actual_size = _total_size - AMF_HEADER_SIZE;
+    log_debug("Total size in header is %d, buffer size is: %d", _total_size, 
buf->size());
+//    buf->dump();
+    if (buf->size() < actual_size) {
+       log_debug("FIXME: MERGING");
+       buf = _handler->merge(buf);
+    }
+    while ((ptr - buf->begin()) < static_cast<int>(actual_size)) {
+       amf::Element *el = new amf::Element;
+       if (ptr) {
+           ptr = amf.extractVariable(el, ptr);
+           addVariable(el);
+       } else {
+           return true;
+       }
+       el->dump();             // FIXME: dump the AMF objects as they are read 
in
+    }
+    
+    RTMPproto::dump();
+#endif
+    switch(_type) {
+      case CHUNK_SIZE:
+      case BYTES_READ:
+      case PING:
+      case SERVER:
+      case CLIENT:
+      case VIDEO_DATA:
+      case NOTIFY:
+      case SHARED_OBJ:
+      case INVOKE:
+          break;
+      case AUDIO_DATA:
+          break;
+      default:
+          log_error (_("ERROR: Unidentified RTMP message content type 0x%x"), 
_type);
+          break;
+    };
+    
+    Element *url = getVariable("tcUrl");
+    Element *file = getVariable("swfUrl");
+    Element *app = getVariable("app");
+
+    if (file) {
+       log_debug("SWF file %s", file->getData());
+    }
+    if (url) {
+       log_debug("is Loading video %s", url->getData());
+    }
+    if (app) {
+       log_debug("is file name is %s", app->getData());
+    }
+    
+    return true;
+}
+
+// These process the incoming AMF object types from the data stream
+Network::byte_t *
+RTMPServer::decodeChunkSize(Network::byte_t *buf)
+{
+    GNASH_REPORT_FUNCTION;
+}
+
+Network::byte_t *
+RTMPServer::decodeBytesRead(Network::byte_t *buf)
+{
+    GNASH_REPORT_FUNCTION;
+}
+
+Network::byte_t *
+RTMPServer::decodePing(Network::byte_t *buf)
+{
+    GNASH_REPORT_FUNCTION;
+}
+
+Network::byte_t *
+RTMPServer::decodeServer(Network::byte_t *buf)
+{
+    GNASH_REPORT_FUNCTION;
+}
+
+Network::byte_t *
+RTMPServer::decodeClient(Network::byte_t *buf)
+{
+    GNASH_REPORT_FUNCTION;
+}
+
+Network::byte_t *
+RTMPServer::decodeAudioData(Network::byte_t *buf)
+{
+    GNASH_REPORT_FUNCTION;
+}
+
+Network::byte_t *
+RTMPServer::decodeVideoData(Network::byte_t *buf)
+{
+    GNASH_REPORT_FUNCTION;
+}
+
+Network::byte_t *
+RTMPServer::decodeNotify(Network::byte_t *buf)
+{
+    GNASH_REPORT_FUNCTION;
+}
+    
+Network::byte_t *
+RTMPServer::decodeSharedObj(Network::byte_t *buf)
+{
+    GNASH_REPORT_FUNCTION;
+}
+
+// Invoke a remote procedure call for an ActionScript class.
+Network::byte_t *
+RTMPServer::decodeInvoke(Network::byte_t *buf)
+{
+    GNASH_REPORT_FUNCTION;
+    
+}
+
+// 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);
+    RTMPServer 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 gnash namespace
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: rtmp_server.h
===================================================================
RCS file: rtmp_server.h
diff -N rtmp_server.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ rtmp_server.h       29 Mar 2008 18:48:32 -0000      1.1
@@ -0,0 +1,71 @@
+// 
+//   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_SERVER_H_
+#define _RTMP_SERVER_H_ 1
+
+#include <boost/cstdint.hpp>
+#include <string>
+#include <map>
+
+#include "rtmp.h"
+#include "amf.h"
+#include "element.h"
+#include "handler.h"
+#include "network.h"
+
+namespace gnash
+{
+  
+  class DSOEXPORT RTMPServer : public RTMPproto
+{
+public:
+    RTMPServer();
+    ~RTMPServer();
+    bool handShakeWait();
+    bool handShakeResponse();
+    bool serverFinish();
+    bool packetSend(Buffer *buf);
+    bool packetRead(Buffer *buf);
+
+    // These process the incoming RTMP message content types from the header
+    gnash::Network::byte_t *decodeChunkSize(gnash::Network::byte_t *buf);
+    gnash::Network::byte_t *decodeBytesRead(gnash::Network::byte_t *buf);
+    gnash::Network::byte_t *decodePing(gnash::Network::byte_t *buf);
+    gnash::Network::byte_t *decodeServer(gnash::Network::byte_t *buf);
+    gnash::Network::byte_t *decodeClient(gnash::Network::byte_t *buf);
+    gnash::Network::byte_t *decodeAudioData(gnash::Network::byte_t *buf);
+    gnash::Network::byte_t *decodeVideoData(gnash::Network::byte_t *buf);
+    gnash::Network::byte_t *decodeNotify(gnash::Network::byte_t *buf);
+    gnash::Network::byte_t *decodeSharedObj(gnash::Network::byte_t *buf);
+    gnash::Network::byte_t *decodeInvoke(gnash::Network::byte_t *buf);
+    void dump();
+  private:
+};
+
+// This is the thread for all incoming RTMP connections
+void rtmp_handler(Handler::thread_params_t *args);
+
+} // end of gnash namespace
+// end of _RTMP_SERVER_H_
+#endif
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:
+




reply via email to

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