コード例 #1
0
ファイル: NetConnection_as.cpp プロジェクト: adamh/gnash-fork
    void push_amf(const SimpleBuffer &amf) 
    {
        //GNASH_REPORT_FUNCTION;

        _postdata.append(amf.data(), amf.size());
        queued_count++;
    }
コード例 #2
0
ファイル: RTMP.cpp プロジェクト: aopui/gnash
void
RTMP::call(const SimpleBuffer& amf)
{
    RTMPPacket p(amf.size());
    setupInvokePacket(p);
    
    // Copy the data.
    p.buffer->append(amf.data(), amf.size());
    sendPacket(p);
}
コード例 #3
0
ファイル: SharedObject_as.cpp プロジェクト: adamh/gnash-fork
    /// Return the size of the data plus header.
    size_t size() const {
        if (!_data) return 0;
        SimpleBuffer buf;

        // The header comprises 2 bytes and a length field of 4 bytes.
        if (encodeData(_name, *_data, buf)) {
            return buf.size() + 6;
        }
        return 0;
    }
コード例 #4
0
ファイル: sound_handler.cpp プロジェクト: BrandRegard/gnash
/// Ensure that each buffer has appropriate padding for the decoder.
//
/// Note: all callers passing a SimpleBuffer should already do this,
/// so this is a paranoid check.
void
ensurePadding(SimpleBuffer& data, media::MediaHandler* m)
{
    const size_t padding = m ? m->getInputPaddingSize() : 0;
    if (data.capacity() - data.size() < padding) {
        log_error(_("Sound data creator didn't appropriately pad "
                    "buffer. We'll do so now, but will cost memory copies."));
        data.reserve(data.size() + padding);
    }
}
コード例 #5
0
vespalib::string render(const StateExplorer &state, const Url &url) {
    Slime top;
    state.get_state(slime::SlimeInserter(top), true);
    if (top.get().type().getId() == slime::NIX::ID) {
        top.setObject();
    }
    inject_children(state, url, top.get());
    SimpleBuffer buf;
    slime::JsonFormat::encode(top, buf, true);
    return buf.get().make_string();
}
コード例 #6
0
ファイル: rtmpget.cpp プロジェクト: aopui/gnash
void
sendCreateStream(rtmp::RTMP& r, FakeNC& nc)
{
    const size_t cn = nc.callNumber();

    SimpleBuffer buf;
    amf::write(buf, "createStream");
    amf::write(buf, static_cast<double>(cn));
    buf.appendByte(amf::NULL_AMF0);
    nc.queueCall(cn, "createStream");
    r.call(buf);
}
コード例 #7
0
ファイル: RTMP.cpp プロジェクト: aopui/gnash
void
RTMP::play(const SimpleBuffer& buf, int streamID)
{
    RTMPPacket packet(buf.size());
  
    packet.header.channel = CHANNEL_VIDEO;
    packet.header.packetType = PACKET_TYPE_INVOKE;
  
    packet.header._streamID = streamID;
  
    packet.buffer->append(buf.data(), buf.size());
    sendPacket(packet);
}
コード例 #8
0
ファイル: rtmpget.cpp プロジェクト: aopui/gnash
void
replyBWCheck(rtmp::RTMP& r, FakeNC& /*nc*/, double txn)
{
    // Infofield1?
    SimpleBuffer buf;
    amf::write(buf, "_result");
    amf::write(buf, txn);
    buf.appendByte(amf::NULL_AMF0);
    amf::write(buf, 0.0);
    
    r.call(buf);

}
コード例 #9
0
ファイル: rtmpget.cpp プロジェクト: aopui/gnash
void
sendCheckBW(rtmp::RTMP& r, FakeNC& nc)
{
    SimpleBuffer buf;
    
    const size_t cn = nc.callNumber();

    amf::write(buf, "_checkbw");
    amf::write(buf, static_cast<double>(cn));
    buf.appendByte(amf::NULL_AMF0);

    nc.queueCall(cn, "_checkbw");
    r.call(buf);
}
コード例 #10
0
ファイル: rtmpget.cpp プロジェクト: aopui/gnash
void
sendFCSubscribe(rtmp::RTMP& r, FakeNC& nc, const std::string& subscribepath)
{
    const size_t cn = nc.callNumber();

    SimpleBuffer buf;
    amf::write(buf, "FCSubscribe");

    // What is this?
    amf::write(buf, static_cast<double>(cn));
    buf.appendByte(amf::NULL_AMF0);
    amf::write(buf, subscribepath);

    nc.queueCall(cn, "FCSubscribe");
    r.call(buf);
}
コード例 #11
0
ファイル: rtmpget.cpp プロジェクト: aopui/gnash
// Which channel to send on? Always video?
//ASnative(2101, 202)(this, "play", null, name, start * 1000, len * 1000, reset);
// This call is not queued (it's a play call, and doesn't have a callback).
void
sendPlayPacket(rtmp::RTMP& r, FakeNC& nc)
{

    const int streamid = nc.streamID();
    const double seektime = nc.seekTime() * 1000.0;
    const double length = nc.length() * 1000.0;

    log_debug("Sending play packet. Stream id: %s, playpath %s", streamid,
            nc.playpath());

    SimpleBuffer buf;

    amf::write(buf, "play");

    // What is this? The play stream? Call number?
    amf::write(buf, 0.0);
    buf.appendByte(amf::NULL_AMF0);

    log_debug( "seekTime=%.2f, dLength=%d, sending play: %s",
        seektime, length, nc.playpath());
    amf::write(buf, nc.playpath());

    // Optional parameters start and len.
    //
    // start: -2, -1, 0, positive number
    //  -2: looks for a live stream, then a recorded stream, if not found
    //  any open a live stream
    //  -1: plays a live stream
    // >=0: plays a recorded streams from 'start' milliseconds
    amf::write(buf, seektime);

    // len: -1, 0, positive number
    //  -1: plays live or recorded stream to the end (default)
    //   0: plays a frame 'start' ms away from the beginning
    //  >0: plays a live or recoded stream for 'len' milliseconds
    //enc += EncodeNumber(enc, -1.0); // len
    amf::write(buf, length);
    
    r.play(buf, streamid);
}
コード例 #12
0
ファイル: rtmpget.cpp プロジェクト: aopui/gnash
void
sendPausePacket(rtmp::RTMP& r, FakeNC& nc, bool flag, double time)
{
    const int streamid = nc.streamID();

    SimpleBuffer buf;

    amf::write(buf, "pause");

    // What is this? The play stream? Call number?
    amf::write(buf, 0.0);
    buf.appendByte(amf::NULL_AMF0);

    log_debug( "Pause: flag=%s, time=%d", flag, time);
    amf::write(buf, flag);

    // "this.time", i.e. NetStream.time.
    amf::write(buf, time * 1000.0);

    r.play(buf, streamid);
}
コード例 #13
0
ファイル: rtmpget.cpp プロジェクト: aopui/gnash
/// These functions create an RTMP call buffer and send it. They mimic
/// NetConnection.call() methods and replies to server calls.
//
/// If a call is initiated by us, we send our own call number.
/// If we are replying to a server call, we send the server's call number back.
void
sendConnectPacket(rtmp::RTMP& r, FakeNC& nc, const std::string& app,
        const std::string& ver, const std::string& swfurl,
        const std::string& tcurl, const std::string& pageurl)
{
    log_debug("Sending connect packet.");
    
    log_debug("app      : %s", app);
    log_debug("flashVer : %s", ver);
    log_debug("tcURL    : %s", tcurl);
    log_debug("swfURL   : %s", swfurl);
    log_debug("pageURL  : %s", pageurl);

    SimpleBuffer buf;

    amf::write(buf, "connect");
    const size_t cn = nc.callNumber();
    
    /// Call number?
    amf::write(buf, static_cast<double>(cn));

    buf.appendByte(amf::OBJECT_AMF0);
    if (!app.empty()) amf::writeProperty(buf, "app", app);
    if (!ver.empty()) amf::writeProperty(buf, "flashVer", ver);
    if (!swfurl.empty()) amf::writeProperty(buf, "swfUrl", swfurl);
    if (!tcurl.empty()) amf::writeProperty(buf, "tcUrl", tcurl);
    amf::writeProperty(buf, "fpad", false);
    amf::writeProperty(buf, "capabilities", 15.0);
    amf::writeProperty(buf, "audioCodecs", 3191.0);
    amf::writeProperty(buf, "videoCodecs", 252.0);
    amf::writeProperty(buf, "videoFunction", 1.0);
    if (!pageurl.empty()) amf::writeProperty(buf, "pageUrl", pageurl);
    buf.appendByte(0);
    buf.appendByte(0);
    buf.appendByte(amf::OBJECT_END_AMF0);

    nc.queueCall(cn, "connect");
    r.call(buf);

}
コード例 #14
0
ファイル: NetConnection_as.cpp プロジェクト: adamh/gnash-fork
bool
HTTPRemotingHandler::advance()
{

#ifdef GNASH_DEBUG_REMOTING
    log_debug("advancing HTTPRemotingHandler");
#endif
    if (_connection) {

#ifdef GNASH_DEBUG_REMOTING
        log_debug("have connection");
#endif

        // Fill last chunk before reading in the next
        size_t toRead = reply.capacity() - reply.size();
        if (! toRead) toRead = NCCALLREPLYCHUNK;

#ifdef GNASH_DEBUG_REMOTING
        log_debug("Attempt to read %d bytes", toRead);
#endif

        // See if we need to allocate more bytes for the next
        // read chunk
        if (reply.capacity() < reply.size() + toRead) {
            // if _connection->size() >= 0, reserve for it, so
            // if HTTP Content-Length response header is correct
            // we'll be allocating only once for all.
            const size_t newCapacity = reply.size() + toRead;

#ifdef GNASH_DEBUG_REMOTING
            log_debug("NetConnection.call: reply buffer capacity (%d) "
                      "is too small to accept next %d bytes of chunk "
                      "(current size is %d). Reserving %d bytes.",
                reply.capacity(), toRead, reply.size(), newCapacity);
#endif

            reply.reserve(newCapacity);

#ifdef GNASH_DEBUG_REMOTING
            log_debug(" after reserve, new capacity is %d", reply.capacity());
#endif
        }

        const int read =
            _connection->readNonBlocking(reply.data() + reply.size(), toRead);

        if (read > 0) {
#ifdef GNASH_DEBUG_REMOTING
            log_debug("read '%1%' bytes: %2%", read, 
                    hexify(reply.data() + reply.size(), read, false));
#endif
            reply.resize(reply.size() + read);
        }

        // There is no way to tell if we have a whole amf reply without
        // parsing everything
        //
        // The reply format has a header field which specifies the
        // number of bytes in the reply, but potlatch sends 0xffffffff
        // and works fine in the proprietary player
        //
        // For now we just wait until we have the full reply.
        //
        // FIXME make this parse on other conditions, including: 1) when
        // the buffer is full, 2) when we have a "length in bytes" value
        // thas is satisfied

        if (_connection->bad()) {
            log_debug("connection is in error condition, calling "
                    "NetConnection.onStatus");
            reply.resize(0);
            reply_start = 0;
            // reset connection before calling the callback
            _connection.reset();

            // This is just a guess, but is better than sending
            // 'undefined'
            _nc.notifyStatus(NetConnection_as::CALL_FAILED);
        }
        else if (_connection->eof()) {

            if (reply.size() > 8) {


#ifdef GNASH_DEBUG_REMOTING
                log_debug("hit eof");
#endif
                boost::uint16_t li;
                const boost::uint8_t *b = reply.data() + reply_start;
                const boost::uint8_t *end = reply.data() + reply.size();
                
                amf::Reader rd(b, end, getGlobal(_nc.owner()));

                // parse header
                b += 2; // skip version indicator and client id

                // NOTE: this looks much like parsing of an OBJECT_AMF0
                boost::int16_t si = readNetworkShort(b);
                b += 2; // number of headers
                uint8_t headers_ok = 1;
                if (si != 0) {

#ifdef GNASH_DEBUG_REMOTING
                    log_debug("NetConnection::call(): amf headers "
                            "section parsing");
#endif
                    as_value tmp;
                    for (size_t i = si; i > 0; --i) {
                        if(b + 2 > end) {
                            headers_ok = 0;
                            break;
                        }
                        si = readNetworkShort(b); b += 2; // name length
                        if(b + si > end) {
                            headers_ok = 0;
                            break;
                        }
                        std::string headerName((char*)b, si); // end-b);
#ifdef GNASH_DEBUG_REMOTING
                        log_debug("Header name %s", headerName);
#endif
                        b += si;
                        if ( b + 5 > end ) {
                            headers_ok = 0;
                            break;
                        }
                        b += 5; // skip past bool and length long
                        if(!rd(tmp)) {
                            headers_ok = 0;
                            break;
                        }
#ifdef GNASH_DEBUG_REMOTING
                        log_debug("Header value %s", tmp);
#endif

                        { // method call for each header
                          // FIXME: it seems to me that the call should happen
                            VM& vm = getVM(_nc.owner());
                            string_table& st = vm.getStringTable();
                            string_table::key key = st.find(headerName);
#ifdef GNASH_DEBUG_REMOTING
                            log_debug("Calling NetConnection.%s(%s)",
                                    headerName, tmp);
#endif
                            callMethod(&_nc.owner(), key, tmp);
                        }
                    }
                }

                if(headers_ok == 1) {

                    si = readNetworkShort(b); b += 2; // number of replies

                    // TODO consider counting number of replies we
                    // actually parse and doing something if it
                    // doesn't match this value (does it matter?
                    if(si > 0) {
                        // parse replies until we get a parse error or we reach the end of the buffer
                        while(b < end) {
                            if(b + 2 > end) break;
                            si = readNetworkShort(b); b += 2; // reply length
                            if(si < 4) { // shorted valid response is '/1/a'
                                log_error("NetConnection::call(): reply message name too short");
                                break;
                            }
                            if(b + si > end) break;

                            // Reply message is: '/id/methodName'

                            int ns = 1; // next slash position
                            while (ns<si-1 && *(b+ns) != '/') ++ns;
                            if ( ns >= si-1 ) {
                                std::string msg(
                                        reinterpret_cast<const char*>(b), si);
                                log_error("NetConnection::call(): invalid "
                                        "reply message name (%s)", msg);
                                break;
                            }

                            std::string id(reinterpret_cast<const char*>(b),
                                    ns);

                            std::string methodName(
                                    reinterpret_cast<const char*>(b+ns+1),
                                    si-ns-1);

                            b += si;

                            // parse past unused string in header
                            if(b + 2 > end) break;
                            si = readNetworkShort(b); b += 2; // reply length
                            if(b + si > end) break;
                            b += si;

                            // this field is supposed to hold the
                            // total number of bytes in the rest of
                            // this particular reply value, but
                            // openstreetmap.org (which works great
                            // in the adobe player) sends
                            // 0xffffffff. So we just ignore it
                            if(b + 4 > end) break;
                            li = readNetworkLong(b); b += 4; // reply length

#ifdef GNASH_DEBUG_REMOTING
                            log_debug("about to parse amf value");
#endif
                            // this updates b to point to the next unparsed byte
                            as_value replyval;
                            if (!rd(replyval)) {
                                log_error("parse amf failed");
                                // this will happen if we get
                                // bogus data, or if the data runs
                                // off the end of the buffer
                                // provided, or if we get data we
                                // don't know how to parse
                                break;
                            }
#ifdef GNASH_DEBUG_REMOTING
                            log_debug("parsed amf");
#endif

                            // update variable to show how much we've parsed
                            reply_start = b - reply.data();

                            // if actionscript specified a callback object,
                            // call it
                            as_object* callback = pop_callback(id);
                            if (callback) {

                                string_table::key methodKey;
                                if ( methodName == "onResult" ) {
                                    methodKey = NSV::PROP_ON_RESULT;
                                }
                                else if (methodName == "onStatus") {
                                    methodKey = NSV::PROP_ON_STATUS;
                                }
                                else {
                                    // NOTE: the pp is known to actually
                                    // invoke the custom method, but with 7
                                    // undefined arguments (?)
                                    log_error("Unsupported HTTP Remoting "
                                            "response callback: '%s' "
                                            "(size %d)", methodName,
                                            methodName.size());
                                    continue;
                                }

#ifdef GNASH_DEBUG_REMOTING
                                log_debug("calling onResult callback");
#endif
                                // FIXME check if above line can fail and we
                                // have to react
                                callMethod(callback, methodKey, replyval);
#ifdef GNASH_DEBUG_REMOTING
                                log_debug("callback called");
#endif
                            } else {
                                log_error("Unknown HTTP Remoting response identifier '%s'", id);
                            }
                        }
                    }
                }
            }
            else
            {
                log_error("Response from remoting service < 8 bytes");
            }

#ifdef GNASH_DEBUG_REMOTING
            log_debug("deleting connection");
#endif
            _connection.reset();
            reply.resize(0);
            reply_start = 0;
        }
    }

    if(!_connection && queued_count > 0) {
//#ifdef GNASH_DEBUG_REMOTING
        log_debug("creating connection");
//#endif
        // set the "number of bodies" header

        (reinterpret_cast<boost::uint16_t*>(_postdata.data() + 4))[0] = htons(queued_count);
        std::string postdata_str(reinterpret_cast<char*>(_postdata.data()), _postdata.size());
#ifdef GNASH_DEBUG_REMOTING
        log_debug("NetConnection.call(): encoded args from %1% calls: %2%", queued_count, hexify(postdata.data(), postdata.size(), false));
#endif
        queued_count = 0;

        // TODO: it might be useful for a Remoting Handler to have a 
        // StreamProvider member
        const StreamProvider& sp =
            getRunResources(_nc.owner()).streamProvider();

        _connection.reset(sp.getStream(_url, postdata_str, _headers).release());

        _postdata.resize(6);
#ifdef GNASH_DEBUG_REMOTING
        log_debug("connection created");
#endif
    }

    if (_connection == 0) {
        // nothing more to do
        return false;
    }

    return true;
}
コード例 #15
0
ファイル: SharedObject_as.cpp プロジェクト: adamh/gnash-fork
/// Returns false if the data cannot be written to file.
//
/// If there is no data, the file is removed and the function returns true.
bool
SharedObject_as::flush(int space) const
{

    /// This is called on on destruction of the SharedObject, or (allegedly)
    /// on a call to SharedObject.data, so _data is not guaranteed to exist.
    //
    /// The function should never be called from SharedObject.flush() when
    /// _data is 0.
    if (!_data) return false;

    if (space > 0) {
        log_unimpl("SharedObject.flush() called with a minimum disk space "
                "argument (%d), which is currently ignored", space);
    }

    const std::string& filespec = getFilespec();

    if (!mkdirRecursive(filespec)) {
        log_error("Couldn't create dir for flushing SharedObject %s", filespec);
        return false;
    }

#ifdef USE_SOL_READONLY
    log_debug(_("SharedObject %s not flushed (compiled as read-only mode)"),
            filespec);
    return false;
#endif

    if (rcfile.getSOLReadOnly()) {
        log_security("Attempting to write object %s when it's SOL "
                "Read Only is set! Refusing...", filespec);
        return false;
    }
    
    // Open file
    std::ofstream ofs(filespec.c_str(), std::ios::binary);
    if (!ofs) {
        log_error("SharedObject::flush(): Failed opening file '%s' in "
                "binary mode", filespec.c_str());
        return false;
    }

    // Encode data part.
    SimpleBuffer buf;
    if (!encodeData(_name, *_data, buf)) {
        std::remove(filespec.c_str());
        return true;
    }

    // Encode header part.
    SimpleBuffer header;
    encodeHeader(buf.size(), header);
    
    // Write header
    ofs.write(reinterpret_cast<const char*>(header.data()), header.size());
    if (!ofs) {
        log_error("Error writing SOL header");
        return false;
    }

    // Write AMF data
    ofs.write(reinterpret_cast<const char*>(buf.data()), buf.size());
    if (!ofs) {
        log_error("Error writing %d bytes to output file %s",
                buf.size(), filespec.c_str());
        return false;
    }
    ofs.close();

    log_security("SharedObject '%s' written to filesystem.", filespec);
    return true;
}