/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- encodeContextHeader
- encodeContextHeader
- encodeMsgHeader
- parseContextHeader
- parseContextHeader
- parseMessageHeader
- parseMessageHeader
- parseAMFPacket
- parseAMFPacket
- encodeAMFPacket
- encodeAMFPacket
- encodeMsgHeader
- dump
- dump
- dump
// amf.cpp: AMF (Action Message Format) rpc marshalling, for Gnash.
//
// Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
// 2011 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 "log.h"
#include "GnashException.h"
#include "buffer.h"
#include "amf.h"
#include "amf_msg.h"
#include "element.h"
#include "network.h"
#include "GnashSystemNetHeaders.h"
#include <boost/shared_ptr.hpp>
#include <string>
#include <boost/cstdint.hpp> // For C99 int types
using gnash::GnashException;
using gnash::log_error;
using std::cout;
using std::endl;
namespace cygnal
{
boost::shared_ptr<cygnal::Buffer>
AMF_msg::encodeContextHeader(boost::uint16_t version, boost::uint16_t headers,
boost::uint16_t messages)
{
// GNASH_REPORT_FUNCTION;
size_t size = sizeof(AMF_msg::context_header_t);
boost::shared_ptr<cygnal::Buffer> buf (new cygnal::Buffer(size));
// use a short as a temporary, as it turns out htons() returns a 32bit int
// instead when compiling with -O2. This forces appending bytes to get the
// right size.
boost::uint16_t swapped = htons(version);
*buf = swapped;
swapped = htons(headers);
*buf += swapped;
swapped = htons(messages);
*buf += swapped;
return buf;
}
boost::shared_ptr<cygnal::Buffer>
AMF_msg::encodeContextHeader(AMF_msg::context_header_t *head)
{
// GNASH_REPORT_FUNCTION;
return encodeContextHeader(head->version, head->headers, head->messages);
}
// example message header::
// 00 06 67 65 74 77 61 79 <- getway, message #1
// 00 04 2f 32 32 39 <- /229, operation name
// 00 00 00 0e <- byte length of message
boost::shared_ptr<cygnal::Buffer>
AMF_msg::encodeMsgHeader(AMF_msg::message_header_t *head)
{
// GNASH_REPORT_FUNCTION;
// The size of the buffer are the two strings, their lenght fields, and the integer.
// size_t size = head->target.size() + head->response.size() + sizeof(boost::uint32_t)
// + (sizeof(boost::uint16_t) * 2);
boost::shared_ptr<cygnal::Buffer> buf (new cygnal::Buffer(sizeof(AMF_msg::message_header_t)));
// Encode the target URI, which usually looks something like ."getway"
boost::uint16_t length = head->target.size();
*buf = length;
*buf += head->target;
// Encode the response URI, which usually looks something like "/229"
length = head->response.size();
*buf += length;
*buf += head->target;
// Encode the size of the encoded message
*buf += static_cast<boost::uint32_t>(head->size);
return buf;
}
// These methods parse the raw data of the AMF packet
boost::shared_ptr<AMF_msg::context_header_t>
AMF_msg::parseContextHeader(cygnal::Buffer &data)
{
// GNASH_REPORT_FUNCTION;
return parseContextHeader(data.reference(), data.size());
}
boost::shared_ptr<AMF_msg::context_header_t>
AMF_msg::parseContextHeader(boost::uint8_t *data, size_t /* size */)
{
// GNASH_REPORT_FUNCTION;
boost::shared_ptr<AMF_msg::context_header_t> msg (new AMF_msg::context_header_t);
boost::uint16_t tmpnum = *reinterpret_cast<boost::uint16_t *>(data);
msg->version = tmpnum;
tmpnum = *reinterpret_cast<boost::uint16_t *>(data + sizeof(boost::uint16_t));
msg->headers = ntohs(tmpnum);
tmpnum = *reinterpret_cast<boost::uint16_t *>(data + sizeof(boost::uint32_t));
msg->messages = ntohs(tmpnum);
return msg;
}
boost::shared_ptr<AMF_msg::message_header_t>
AMF_msg::parseMessageHeader(cygnal::Buffer &data)
{
// GNASH_REPORT_FUNCTION;
return parseMessageHeader(data.reference(), data.size());
}
boost::shared_ptr<AMF_msg::message_header_t>
AMF_msg::parseMessageHeader(boost::uint8_t *data, size_t size)
{
// GNASH_REPORT_FUNCTION;
AMF amf;
boost::uint8_t *tmpptr = data;
boost::shared_ptr<AMF_msg::message_header_t> msg (new AMF_msg::message_header_t);
// The target is a standard length->bytes field
boost::uint16_t length = ntohs((*(boost::uint16_t *)tmpptr) & 0xffff);
if (length == 0) {
boost::format msg("Length of string shouldn't be zero! amf_msg.cpp::%1%(): %2%");
msg % __FUNCTION__ % __LINE__;
throw GnashException(msg.str());
}
tmpptr += sizeof(boost::uint16_t);
std::string str1(reinterpret_cast<const char *>(tmpptr), length);
msg->target = str1;
if ((tmpptr - data) > static_cast<int>(size)) {
boost::format msg("Trying to read past the end of data! Wants %1% bytes, given %2% bytes");
msg % length % size;
throw GnashException(msg.str());
} else {
tmpptr += length;
}
// The response is a standard length->bytes field
length = ntohs((*(boost::uint16_t *)tmpptr) & 0xffff);
if (length == 0) {
boost::format msg("Length of string shouldn't be zero! amf_msg.cpp::%1%(): %2%");
msg % __FUNCTION__ % __LINE__;
throw GnashException(msg.str());
}
tmpptr += sizeof(boost::uint16_t);
std::string str2(reinterpret_cast<const char *>(tmpptr), length);
msg->response = str2;
tmpptr += length;
if ((tmpptr - data) > static_cast<int>(size)) {
boost::format msg("Trying to read past the end of data! Wants %1% bytes, given %2% bytes");
msg % length % size;
throw GnashException(msg.str());
}
// The length is a 4 word integer
msg->size = ntohl((*(boost::uint32_t *)tmpptr));
if (msg->target.empty()) {
log_error("AMF Message \'target\' field missing!");
}
if (msg->response.empty()) {
log_error("AMF Message \'reply\' field missing!");
}
if (msg->size == 0) {
log_error("AMF Message \'size\' field missing!");
} else {
msg->size = size;
}
// AMF_msg::dump(*msg);
return msg;
}
boost::shared_ptr<AMF_msg::context_header_t>
AMF_msg::parseAMFPacket(cygnal::Buffer &data)
{
// GNASH_REPORT_FUNCTION;
return parseAMFPacket(data.reference(), data.size());
}
boost::shared_ptr<AMF_msg::context_header_t>
AMF_msg::parseAMFPacket(boost::uint8_t *data, size_t size)
{
GNASH_REPORT_FUNCTION;
// _messages.push_back();
boost::uint8_t *ptr = data + sizeof(AMF_msg::context_header_t);
boost::shared_ptr<context_header_t> header = AMF_msg::parseContextHeader(data, size);
// log_debug("%s: %s", __PRETTY_FUNCTION__, hexify(data, size, true));
AMF amf;
/// Read all the messages from the AMF packet
try {
for (int i=0; i<header->messages; i++) {
boost::shared_ptr<AMF_msg::amf_message_t> msgpkt(new AMF_msg::amf_message_t);
boost::shared_ptr<AMF_msg::message_header_t> msghead = AMF_msg::parseMessageHeader(ptr, size);
if (msghead) {
ptr += msghead->target.size() + msghead->response.size()
+ (sizeof(boost::uint16_t) * 2)
+ (sizeof(boost::uint32_t));
boost::shared_ptr<cygnal::Element> el = amf.extractAMF(ptr, ptr+size);
msgpkt->header.target = msghead->target;
msgpkt->header.response = msghead->response;
msgpkt->header.size = msghead->size;
msgpkt->data = el;
ptr += amf.totalsize();
_messages.push_back(msgpkt);
}
}
} catch(std::exception& e) {
log_error("Error parsing the AMF packet: \n\t%s", e.what());
}
return header;
}
boost::shared_ptr<cygnal::Buffer>
AMF_msg::encodeAMFPacket(const std::string & /* target */,
const std::string & /*response */, size_t /* size */)
{
// GNASH_REPORT_FUNCTION;
return encodeAMFPacket();
}
boost::shared_ptr<cygnal::Buffer>
AMF_msg::encodeAMFPacket()
{
// GNASH_REPORT_FUNCTION;
boost::shared_ptr<cygnal::Buffer> buf(new cygnal::Buffer);
// Encode the packet header
boost::shared_ptr<cygnal::Buffer> buf1 = encodeContextHeader(0, 0, _messages.size());
*buf = buf1;
// Now encode all the messages
std::vector<boost::shared_ptr<AMF_msg::amf_message_t> >::iterator it;
for (it = _messages.begin(); it != _messages.end(); it++) {
boost::shared_ptr<AMF_msg::amf_message_t> msg = (*(it));
boost::shared_ptr<cygnal::Buffer> buf2 = encodeMsgHeader(msg->header.target,
msg->header.response,
msg->header.size);
// AMF_msg::dump(msg->header);
// msg->data->dump();
boost::shared_ptr<cygnal::Buffer> buf3 = msg->data->encode();
*buf += buf2;
*buf += buf3;
}
return buf;
}
boost::shared_ptr<cygnal::Buffer>
AMF_msg::encodeMsgHeader(const std::string &target,
const std::string &response, size_t size)
{
// GNASH_REPORT_FUNCTION;
size_t total = target.size() + sizeof(boost::uint16_t);
total += response.size() + sizeof(boost::uint16_t);
total += sizeof(boost::uint32_t);
boost::shared_ptr<cygnal::Buffer> buf (new cygnal::Buffer(total));
boost::uint16_t length = target.size();
swapBytes(&length, sizeof(boost::uint16_t));
*buf += length;
*buf += target;
length = response.size();
swapBytes(&length, sizeof(boost::uint16_t));
*buf += length;
*buf += response;
boost::uint32_t swapped = htonl(size);
*buf += swapped;
return buf;
}
void
AMF_msg::dump(AMF_msg::message_header_t &data)
{
// GNASH_REPORT_FUNCTION;
cout << "Target is: " << data.target << endl;
cout << "Response is: " << data.response << endl;
cout << "Data size is: " << data.size << endl;
}
void
AMF_msg::dump(AMF_msg::context_header_t &data)
{
// GNASH_REPORT_FUNCTION;
cout << "AMF Version: " << data.version << endl;
cout << "Number of headers: " << data.headers << endl;
cout << "Number of messages: " << data.messages << endl;
}
void
AMF_msg::dump()
{
// GNASH_REPORT_FUNCTION;
cout << "AMF Packet has " << _messages.size() << " messages." << endl;
std::vector<boost::shared_ptr<AMF_msg::amf_message_t> >::iterator it;
for (it = _messages.begin(); it != _messages.end(); it++) {
boost::shared_ptr<AMF_msg::amf_message_t> msg = (*(it));
AMF_msg::dump(msg->header);
msg->data->dump();
}
}
} // end of amf namespace
// local Variables:
// mode: C++
// indent-tabs-mode: t
// End: