Global cleanups and standardization of code style.

This commit is contained in:
Thulinma 2012-12-11 11:03:33 +01:00
parent 51a9b4162c
commit 38ef8704f8
33 changed files with 4322 additions and 2824 deletions

View file

@ -4,68 +4,89 @@
#include "amf.h"
#include <sstream>
#include <cstdio> //needed for stderr only
/// Returns the std::string Indice for the current object, if available.
/// Returns an empty string if no indice exists.
std::string AMF::Object::Indice(){return myIndice;};
std::string AMF::Object::Indice(){
return myIndice;
}
/// Returns the AMF::obj0type AMF0 object type for this object.
AMF::obj0type AMF::Object::GetType(){return myType;};
AMF::obj0type AMF::Object::GetType(){
return myType;
}
/// Returns the numeric value of this object, if available.
/// If this object holds no numeric value, 0 is returned.
double AMF::Object::NumValue(){return numval;};
double AMF::Object::NumValue(){
return numval;
}
/// Returns the std::string value of this object, if available.
/// If this object holds no string value, an empty string is returned.
std::string AMF::Object::StrValue(){return strval;};
std::string AMF::Object::StrValue(){
return strval;
}
/// Returns the C-string value of this object, if available.
/// If this object holds no string value, an empty C-string is returned.
const char * AMF::Object::Str(){return strval.c_str();};
const char * AMF::Object::Str(){
return strval.c_str();
}
/// Returns a count of the amount of objects this object currently holds.
/// If this object is not a container type, this function will always return 0.
int AMF::Object::hasContent(){return contents.size();};
int AMF::Object::hasContent(){
return contents.size();
}
/// Adds an AMF::Object to this object. Works for all types, but only makes sense for container types.
void AMF::Object::addContent(AMF::Object c){contents.push_back(c);};
void AMF::Object::addContent(AMF::Object c){
contents.push_back(c);
}
/// Returns a pointer to the object held at indice i.
/// Returns AMF::AMF0_DDV_CONTAINER of indice "error" if no object is held at this indice.
/// \param i The indice of the object in this container.
AMF::Object* AMF::Object::getContentP(int i){return &contents.at(i);};
AMF::Object* AMF::Object::getContentP(int i){
return &contents.at(i);
}
/// Returns a copy of the object held at indice i.
/// Returns a AMF::AMF0_DDV_CONTAINER of indice "error" if no object is held at this indice.
/// \param i The indice of the object in this container.
AMF::Object AMF::Object::getContent(int i){return contents.at(i);};
AMF::Object AMF::Object::getContent(int i){
return contents.at(i);
}
/// Returns a pointer to the object held at indice s.
/// Returns NULL if no object is held at this indice.
/// \param s The indice of the object in this container.
AMF::Object* AMF::Object::getContentP(std::string s){
for (std::vector<AMF::Object>::iterator it = contents.begin(); it != contents.end(); it++){
if (it->Indice() == s){return &(*it);}
if (it->Indice() == s){
return &( *it);
}
}
return 0;
};
}
/// Returns a copy of the object held at indice s.
/// Returns a AMF::AMF0_DDV_CONTAINER of indice "error" if no object is held at this indice.
/// \param s The indice of the object in this container.
AMF::Object AMF::Object::getContent(std::string s){
for (std::vector<AMF::Object>::iterator it = contents.begin(); it != contents.end(); it++){
if (it->Indice() == s){return *it;}
if (it->Indice() == s){
return *it;
}
}
return AMF::Object("error", AMF0_DDV_CONTAINER);
};
}
/// Default constructor.
/// Simply fills the data with AMF::Object("error", AMF0_DDV_CONTAINER)
AMF::Object::Object(){
*this = AMF::Object("error", AMF0_DDV_CONTAINER);
};//default constructor
} //default constructor
/// Constructor for numeric objects.
/// The object type is by default AMF::AMF0_NUMBER, but this can be forced to a different value.
@ -77,7 +98,7 @@ AMF::Object::Object(std::string indice, double val, AMF::obj0type setType){//num
myType = setType;
strval = "";
numval = val;
};
}
/// Constructor for string objects.
/// The object type is by default AMF::AMF0_STRING, but this can be forced to a different value.
@ -90,7 +111,7 @@ AMF::Object::Object(std::string indice, std::string val, AMF::obj0type setType){
myType = setType;
strval = val;
numval = 0;
};
}
/// Constructor for container objects.
/// The object type is by default AMF::AMF0_OBJECT, but this can be forced to a different value.
@ -101,7 +122,7 @@ AMF::Object::Object(std::string indice, AMF::obj0type setType){//object type ini
myType = setType;
strval = "";
numval = 0;
};
}
/// Prints the contents of this object to std::cerr.
/// If this object contains other objects, it will call itself recursively
@ -111,41 +132,90 @@ std::string AMF::Object::Print(std::string indent){
st << indent;
// print my type
switch (myType){
case AMF::AMF0_NUMBER: st << "Number"; break;
case AMF::AMF0_BOOL: st << "Bool"; break;
case AMF::AMF0_NUMBER:
st << "Number";
break;
case AMF::AMF0_BOOL:
st << "Bool";
break;
case AMF::AMF0_STRING: //short string
case AMF::AMF0_LONGSTRING: st << "String"; break;
case AMF::AMF0_OBJECT: st << "Object"; break;
case AMF::AMF0_MOVIECLIP: st << "MovieClip"; break;
case AMF::AMF0_NULL: st << "Null"; break;
case AMF::AMF0_UNDEFINED: st << "Undefined"; break;
case AMF::AMF0_REFERENCE: st << "Reference"; break;
case AMF::AMF0_ECMA_ARRAY: st << "ECMA Array"; break;
case AMF::AMF0_OBJ_END: st << "Object end"; break;
case AMF::AMF0_STRICT_ARRAY: st << "Strict Array"; break;
case AMF::AMF0_DATE: st << "Date"; break;
case AMF::AMF0_UNSUPPORTED: st << "Unsupported"; break;
case AMF::AMF0_RECORDSET: st << "Recordset"; break;
case AMF::AMF0_XMLDOC: st << "XML Document"; break;
case AMF::AMF0_TYPED_OBJ: st << "Typed Object"; break;
case AMF::AMF0_UPGRADE: st << "Upgrade to AMF3"; break;
case AMF::AMF0_DDV_CONTAINER: st << "DDVTech Container"; break;
case AMF::AMF0_LONGSTRING:
st << "String";
break;
case AMF::AMF0_OBJECT:
st << "Object";
break;
case AMF::AMF0_MOVIECLIP:
st << "MovieClip";
break;
case AMF::AMF0_NULL:
st << "Null";
break;
case AMF::AMF0_UNDEFINED:
st << "Undefined";
break;
case AMF::AMF0_REFERENCE:
st << "Reference";
break;
case AMF::AMF0_ECMA_ARRAY:
st << "ECMA Array";
break;
case AMF::AMF0_OBJ_END:
st << "Object end";
break;
case AMF::AMF0_STRICT_ARRAY:
st << "Strict Array";
break;
case AMF::AMF0_DATE:
st << "Date";
break;
case AMF::AMF0_UNSUPPORTED:
st << "Unsupported";
break;
case AMF::AMF0_RECORDSET:
st << "Recordset";
break;
case AMF::AMF0_XMLDOC:
st << "XML Document";
break;
case AMF::AMF0_TYPED_OBJ:
st << "Typed Object";
break;
case AMF::AMF0_UPGRADE:
st << "Upgrade to AMF3";
break;
case AMF::AMF0_DDV_CONTAINER:
st << "DDVTech Container";
break;
}
// print my string indice, if available
st << " " << myIndice << " ";
// print my numeric or string contents
switch (myType){
case AMF::AMF0_NUMBER: case AMF::AMF0_BOOL: case AMF::AMF0_REFERENCE: case AMF::AMF0_DATE: st << numval; break;
case AMF::AMF0_STRING: case AMF::AMF0_LONGSTRING: case AMF::AMF0_XMLDOC: case AMF::AMF0_TYPED_OBJ: st << strval; break;
default: break;//we don't care about the rest, and don't want a compiler warning...
case AMF::AMF0_NUMBER:
case AMF::AMF0_BOOL:
case AMF::AMF0_REFERENCE:
case AMF::AMF0_DATE:
st << numval;
break;
case AMF::AMF0_STRING:
case AMF::AMF0_LONGSTRING:
case AMF::AMF0_XMLDOC:
case AMF::AMF0_TYPED_OBJ:
st << strval;
break;
default:
break; //we don't care about the rest, and don't want a compiler warning...
}
st << std::endl;
// if I hold other objects, print those too, recursively.
if (contents.size() > 0){
for (std::vector<AMF::Object>::iterator it = contents.begin(); it != contents.end(); it++){st << it->Print(indent+" ");}
for (std::vector<AMF::Object>::iterator it = contents.begin(); it != contents.end(); it++){
st << it->Print(indent + " ");
}
}
return st.str();
};//print
} //print
/// Packs the AMF object to a std::string for transfer over the network.
/// If the object is a container type, this function will call itself recursively and contain all contents.
@ -153,22 +223,34 @@ std::string AMF::Object::Print(std::string indent){
std::string AMF::Object::Pack(){
std::string r = "";
//check for string/longstring conversion
if ((myType == AMF::AMF0_STRING) && (strval.size() > 0xFFFF)){myType = AMF::AMF0_LONGSTRING;}
if ((myType == AMF::AMF0_STRING) && (strval.size() > 0xFFFF)){
myType = AMF::AMF0_LONGSTRING;
}
//skip output of DDV container types, they do not exist. Only output their contents.
if (myType != AMF::AMF0_DDV_CONTAINER){r += myType;}
if (myType != AMF::AMF0_DDV_CONTAINER){
r += myType;
}
//output the properly formatted AMF0 data stream for this object's contents.
switch (myType){
case AMF::AMF0_NUMBER:
r += *(((char*)&numval)+7); r += *(((char*)&numval)+6);
r += *(((char*)&numval)+5); r += *(((char*)&numval)+4);
r += *(((char*)&numval)+3); r += *(((char*)&numval)+2);
r += *(((char*)&numval)+1); r += *(((char*)&numval));
r += *(((char*) &numval) + 7);
r += *(((char*) &numval) + 6);
r += *(((char*) &numval) + 5);
r += *(((char*) &numval) + 4);
r += *(((char*) &numval) + 3);
r += *(((char*) &numval) + 2);
r += *(((char*) &numval) + 1);
r += *(((char*) &numval));
break;
case AMF::AMF0_DATE:
r += *(((char*)&numval)+7); r += *(((char*)&numval)+6);
r += *(((char*)&numval)+5); r += *(((char*)&numval)+4);
r += *(((char*)&numval)+3); r += *(((char*)&numval)+2);
r += *(((char*)&numval)+1); r += *(((char*)&numval));
r += *(((char*) &numval) + 7);
r += *(((char*) &numval) + 6);
r += *(((char*) &numval) + 5);
r += *(((char*) &numval) + 4);
r += *(((char*) &numval) + 3);
r += *(((char*) &numval) + 2);
r += *(((char*) &numval) + 1);
r += *(((char*) &numval));
r += (char)0; //timezone always 0
r += (char)0; //timezone always 0
break;
@ -188,11 +270,11 @@ std::string AMF::Object::Pack(){
r += strval.size() % 256;
r += strval;
break;
case AMF::AMF0_TYPED_OBJ:
case AMF::AMF0_TYPED_OBJ: //is an object, with the classname first
r += Indice().size() / 256;
r += Indice().size() % 256;
r += Indice();
//is an object, with the classname first
/* no break */
case AMF::AMF0_OBJECT:
if (contents.size() > 0){
for (std::vector<AMF::Object>::iterator it = contents.begin(); it != contents.end(); it++){
@ -202,7 +284,9 @@ std::string AMF::Object::Pack(){
r += it->Pack();
}
}
r += (char)0; r += (char)0; r += (char)9;
r += (char)0;
r += (char)0;
r += (char)9;
break;
case AMF::AMF0_MOVIECLIP:
case AMF::AMF0_OBJ_END:
@ -221,7 +305,10 @@ std::string AMF::Object::Pack(){
int arrlen = 0;
if (contents.size() > 0){
arrlen = contents.size();
r += arrlen / (256*256*256); r += arrlen / (256*256); r += arrlen / 256; r += arrlen % 256;
r += arrlen / (256 * 256 * 256);
r += arrlen / (256 * 256);
r += arrlen / 256;
r += arrlen % 256;
for (std::vector<AMF::Object>::iterator it = contents.begin(); it != contents.end(); it++){
r += it->Indice().size() / 256;
r += it->Indice().size() % 256;
@ -229,22 +316,35 @@ std::string AMF::Object::Pack(){
r += it->Pack();
}
}else{
r += (char)0; r += (char)0; r += (char)0; r += (char)0;
r += (char)0;
r += (char)0;
r += (char)0;
r += (char)0;
}
r += (char)0; r += (char)0; r += (char)9;
} break;
r += (char)0;
r += (char)0;
r += (char)9;
}
break;
case AMF::AMF0_STRICT_ARRAY: {
int arrlen = 0;
if (contents.size() > 0){
arrlen = contents.size();
r += arrlen / (256*256*256); r += arrlen / (256*256); r += arrlen / 256; r += arrlen % 256;
r += arrlen / (256 * 256 * 256);
r += arrlen / (256 * 256);
r += arrlen / 256;
r += arrlen % 256;
for (std::vector<AMF::Object>::iterator it = contents.begin(); it != contents.end(); it++){
r += it->Pack();
}
}else{
r += (char)0; r += (char)0; r += (char)0; r += (char)0;
r += (char)0;
r += (char)0;
r += (char)0;
r += (char)0;
}
} break;
}
break;
case AMF::AMF0_DDV_CONTAINER: //only send contents
if (contents.size() > 0){
for (std::vector<AMF::Object>::iterator it = contents.begin(); it != contents.end(); it++){
@ -254,7 +354,7 @@ std::string AMF::Object::Pack(){
break;
}
return r;
};//pack
} //pack
/// Parses a single AMF0 type - used recursively by the AMF::parse() functions.
/// This function updates i every call with the new position in the data.
@ -350,7 +450,8 @@ AMF::Object AMF::parseOne(const unsigned char *& data, unsigned int &len, unsign
}
i += 3; //skip 0x000009
return ret;
} break;
}
break;
case AMF::AMF0_TYPED_OBJ: {
++i;
tmpi = data[i] * 256 + data[i + 1]; //set tmpi to the UTF-8 length
@ -366,7 +467,8 @@ AMF::Object AMF::parseOne(const unsigned char *& data, unsigned int &len, unsign
}
i += 3; //skip 0x000009
return ret;
} break;
}
break;
case AMF::AMF0_ECMA_ARRAY: {
++i;
AMF::Object ret(name, AMF::AMF0_ECMA_ARRAY);
@ -380,7 +482,8 @@ AMF::Object AMF::parseOne(const unsigned char *& data, unsigned int &len, unsign
}
i += 3; //skip 0x000009
return ret;
} break;
}
break;
case AMF::AMF0_STRICT_ARRAY: {
AMF::Object ret(name, AMF::AMF0_STRICT_ARRAY);
tmpi = data[i + 1] * 256 * 256 * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 + data[i + 4]; //set tmpi to array length
@ -390,7 +493,8 @@ AMF::Object AMF::parseOne(const unsigned char *& data, unsigned int &len, unsign
--tmpi;
}
return ret;
} break;
}
break;
}
#if DEBUG >= 2
fprintf(stderr, "Error: Unimplemented AMF type %hhx - returning.\n", data[i]);
@ -406,7 +510,11 @@ AMF::Object AMF::parse(const unsigned char * data, unsigned int len){
unsigned int i = 0, j = 0;
while (i < len){
ret.addContent(AMF::parseOne(data, len, i, ""));
if (i > j){j = i;}else{return ret;}
if (i > j){
j = i;
}else{
return ret;
}
}
return ret;
} //parse
@ -420,69 +528,93 @@ AMF::Object AMF::parse(std::string data){
/// Returns the std::string Indice for the current object, if available.
/// Returns an empty string if no indice exists.
std::string AMF::Object3::Indice(){return myIndice;};
std::string AMF::Object3::Indice(){
return myIndice;
}
/// Returns the AMF::obj0type AMF0 object type for this object.
AMF::obj3type AMF::Object3::GetType(){return myType;};
AMF::obj3type AMF::Object3::GetType(){
return myType;
}
/// Returns the double value of this object, if available.
/// If this object holds no double value, 0 is returned.
double AMF::Object3::DblValue(){return dblval;};
double AMF::Object3::DblValue(){
return dblval;
}
/// Returns the integer value of this object, if available.
/// If this object holds no integer value, 0 is returned.
int AMF::Object3::IntValue(){return intval;};
int AMF::Object3::IntValue(){
return intval;
}
/// Returns the std::string value of this object, if available.
/// If this object holds no string value, an empty string is returned.
std::string AMF::Object3::StrValue(){return strval;};
std::string AMF::Object3::StrValue(){
return strval;
}
/// Returns the C-string value of this object, if available.
/// If this object holds no string value, an empty C-string is returned.
const char * AMF::Object3::Str(){return strval.c_str();};
const char * AMF::Object3::Str(){
return strval.c_str();
}
/// Returns a count of the amount of objects this object currently holds.
/// If this object is not a container type, this function will always return 0.
int AMF::Object3::hasContent(){return contents.size();};
int AMF::Object3::hasContent(){
return contents.size();
}
/// Adds an AMF::Object to this object. Works for all types, but only makes sense for container types.
void AMF::Object3::addContent(AMF::Object3 c){contents.push_back(c);};
void AMF::Object3::addContent(AMF::Object3 c){
contents.push_back(c);
}
/// Returns a pointer to the object held at indice i.
/// Returns AMF::AMF3_DDV_CONTAINER of indice "error" if no object is held at this indice.
/// \param i The indice of the object in this container.
AMF::Object3* AMF::Object3::getContentP(int i){return &contents.at(i);};
AMF::Object3* AMF::Object3::getContentP(int i){
return &contents.at(i);
}
/// Returns a copy of the object held at indice i.
/// Returns a AMF::AMF3_DDV_CONTAINER of indice "error" if no object is held at this indice.
/// \param i The indice of the object in this container.
AMF::Object3 AMF::Object3::getContent(int i){return contents.at(i);};
AMF::Object3 AMF::Object3::getContent(int i){
return contents.at(i);
}
/// Returns a pointer to the object held at indice s.
/// Returns NULL if no object is held at this indice.
/// \param s The indice of the object in this container.
AMF::Object3* AMF::Object3::getContentP(std::string s){
for (std::vector<AMF::Object3>::iterator it = contents.begin(); it != contents.end(); it++){
if (it->Indice() == s){return &(*it);}
if (it->Indice() == s){
return &( *it);
}
}
return 0;
};
}
/// Returns a copy of the object held at indice s.
/// Returns a AMF::AMF0_DDV_CONTAINER of indice "error" if no object is held at this indice.
/// \param s The indice of the object in this container.
AMF::Object3 AMF::Object3::getContent(std::string s){
for (std::vector<AMF::Object3>::iterator it = contents.begin(); it != contents.end(); it++){
if (it->Indice() == s){return *it;}
if (it->Indice() == s){
return *it;
}
}
return AMF::Object3("error", AMF3_DDV_CONTAINER);
};
}
/// Default constructor.
/// Simply fills the data with AMF::Object3("error", AMF3_DDV_CONTAINER)
AMF::Object3::Object3(){
*this = AMF::Object3("error", AMF3_DDV_CONTAINER);
};//default constructor
} //default constructor
/// Constructor for double objects.
/// The object type is by default AMF::AMF3_DOUBLE, but this can be forced to a different value.
@ -495,7 +627,7 @@ AMF::Object3::Object3(std::string indice, double val, AMF::obj3type setType){//n
strval = "";
dblval = val;
intval = 0;
};
}
/// Constructor for integer objects.
/// The object type is by default AMF::AMF3_INTEGER, but this can be forced to a different value.
@ -508,7 +640,7 @@ myType = setType;
strval = "";
dblval = val;
intval = 0;
};
}
/// Constructor for string objects.
/// The object type is by default AMF::AMF0_STRING, but this can be forced to a different value.
@ -522,7 +654,7 @@ AMF::Object3::Object3(std::string indice, std::string val, AMF::obj3type setType
strval = val;
dblval = 0;
intval = 0;
};
}
/// Constructor for container objects.
/// The object type is by default AMF::AMF0_OBJECT, but this can be forced to a different value.
@ -534,7 +666,7 @@ AMF::Object3::Object3(std::string indice, AMF::obj3type setType){//object type i
strval = "";
dblval = 0;
intval = 0;
};
}
/// Prints the contents of this object to std::cerr.
/// If this object contains other objects, it will call itself recursively
@ -543,28 +675,63 @@ void AMF::Object3::Print(std::string indent){
std::cerr << indent;
// print my type
switch (myType){
case AMF::AMF3_UNDEFINED: std::cerr << "Undefined"; break;
case AMF::AMF3_NULL: std::cerr << "Null"; break;
case AMF::AMF3_FALSE: std::cerr << "False"; break;
case AMF::AMF3_TRUE: std::cerr << "True"; break;
case AMF::AMF3_INTEGER: std::cerr << "Integer"; break;
case AMF::AMF3_DOUBLE: std::cerr << "Double"; break;
case AMF::AMF3_STRING: std::cerr << "String"; break;
case AMF::AMF3_XMLDOC: std::cerr << "XML Doc"; break;
case AMF::AMF3_DATE: std::cerr << "Date"; break;
case AMF::AMF3_ARRAY: std::cerr << "Array"; break;
case AMF::AMF3_OBJECT: std::cerr << "Object"; break;
case AMF::AMF3_XML: std::cerr << "XML"; break;
case AMF::AMF3_BYTES: std::cerr << "ByteArray"; break;
case AMF::AMF3_DDV_CONTAINER: std::cerr << "DDVTech Container"; break;
case AMF::AMF3_UNDEFINED:
std::cerr << "Undefined";
break;
case AMF::AMF3_NULL:
std::cerr << "Null";
break;
case AMF::AMF3_FALSE:
std::cerr << "False";
break;
case AMF::AMF3_TRUE:
std::cerr << "True";
break;
case AMF::AMF3_INTEGER:
std::cerr << "Integer";
break;
case AMF::AMF3_DOUBLE:
std::cerr << "Double";
break;
case AMF::AMF3_STRING:
std::cerr << "String";
break;
case AMF::AMF3_XMLDOC:
std::cerr << "XML Doc";
break;
case AMF::AMF3_DATE:
std::cerr << "Date";
break;
case AMF::AMF3_ARRAY:
std::cerr << "Array";
break;
case AMF::AMF3_OBJECT:
std::cerr << "Object";
break;
case AMF::AMF3_XML:
std::cerr << "XML";
break;
case AMF::AMF3_BYTES:
std::cerr << "ByteArray";
break;
case AMF::AMF3_DDV_CONTAINER:
std::cerr << "DDVTech Container";
break;
}
// print my string indice, if available
std::cerr << " " << myIndice << " ";
// print my numeric or string contents
switch (myType){
case AMF::AMF3_INTEGER: std::cerr << intval; break;
case AMF::AMF3_DOUBLE: std::cerr << dblval; break;
case AMF::AMF3_STRING: case AMF::AMF3_XMLDOC: case AMF::AMF3_XML: case AMF::AMF3_BYTES:
case AMF::AMF3_INTEGER:
std::cerr << intval;
break;
case AMF::AMF3_DOUBLE:
std::cerr << dblval;
break;
case AMF::AMF3_STRING:
case AMF::AMF3_XMLDOC:
case AMF::AMF3_XML:
case AMF::AMF3_BYTES:
if (intval > 0){
std::cerr << "REF" << intval;
}else{
@ -578,19 +745,23 @@ void AMF::Object3::Print(std::string indent){
std::cerr << dblval;
}
break;
case AMF::AMF3_ARRAY: case AMF::AMF3_OBJECT:
case AMF::AMF3_ARRAY:
case AMF::AMF3_OBJECT:
if (intval > 0){
std::cerr << "REF" << intval;
}
break;
default: break;//we don't care about the rest, and don't want a compiler warning...
default:
break; //we don't care about the rest, and don't want a compiler warning...
}
std::cerr << std::endl;
// if I hold other objects, print those too, recursively.
if (contents.size() > 0){
for (std::vector<AMF::Object3>::iterator it = contents.begin(); it != contents.end(); it++){it->Print(indent+" ");}
for (std::vector<AMF::Object3>::iterator it = contents.begin(); it != contents.end(); it++){
it->Print(indent + " ");
}
};//print
}
} //print
/// Packs the AMF object to a std::string for transfer over the network.
/// If the object is a container type, this function will call itself recursively and contain all contents.
@ -598,7 +769,7 @@ void AMF::Object3::Print(std::string indent){
std::string AMF::Object3::Pack(){
std::string r = "";
return r;
};//pack
} //pack
/// Parses a single AMF3 type - used recursively by the AMF::parse3() functions.
/// This function updates i every call with the new position in the data.
@ -879,7 +1050,8 @@ AMF::Object3 AMF::parseOne3(const unsigned char *& data, unsigned int &len, unsi
--arrsize;
}
return ret;
} break;
}
break;
case AMF::AMF3_OBJECT: {
if (data[i + 1] < 0x80){
tmpi = data[i + 1];
@ -946,7 +1118,8 @@ AMF::Object3 AMF::parseOne3(const unsigned char *& data, unsigned int &len, unsi
}while (tmpi > 0); //keep reading dynamic values until empty string
} //dynamic types
return ret;
} break;
}
break;
}
#if DEBUG >= 2
fprintf(stderr, "Error: Unimplemented AMF3 type %hhx - returning.\n", data[i]);
@ -962,7 +1135,11 @@ AMF::Object3 AMF::parse3(const unsigned char * data, unsigned int len){
unsigned int i = 0, j = 0;
while (i < len){
ret.addContent(AMF::parseOne3(data, len, i, ""));
if (i > j){j = i;}else{return ret;}
if (i > j){
j = i;
}else{
return ret;
}
}
return ret;
} //parse

View file

@ -4,7 +4,6 @@
#pragma once
#include <vector>
#include <iostream>
//#include <string.h>
#include <string>
/// Holds all AMF parsing and creation related functions and classes.
@ -78,7 +77,8 @@ namespace AMF{
std::string strval; ///< Holds this objects string value, if any.
double numval; ///< Holds this objects numeric value, if any.
std::vector<Object> contents; ///< Holds this objects contents, if any (for container types).
};//AMFType
};
//AMFType
/// Parses a C-string to a valid AMF::Object.
Object parse(const unsigned char * data, unsigned int len);
@ -117,7 +117,8 @@ namespace AMF{
double dblval; ///< Holds this objects double value, if any.
int intval; ///< Holds this objects int value, if any.
std::vector<Object3> contents; ///< Holds this objects contents, if any (for container types).
};//AMFType
};
//AMFType
/// Parses a C-string to a valid AMF::Object3.
Object3 parse3(const unsigned char * data, unsigned int len);
@ -126,4 +127,4 @@ namespace AMF{
/// Parses a single AMF3 type - used recursively by the AMF::parse3() functions.
Object3 parseOne3(const unsigned char *& data, unsigned int &len, unsigned int &i, std::string name);
};//AMF namespace
} //AMF namespace

View file

@ -8,33 +8,19 @@
namespace Secure {
static unsigned char __gbv2keypub_der[] = {
0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe5, 0xd7, 0x9c,
0x7d, 0x73, 0xc6, 0xe6, 0xfb, 0x35, 0x7e, 0xd7, 0x57, 0x99, 0x07, 0xdb,
0x99, 0x70, 0xc9, 0xd0, 0x3e, 0x53, 0x57, 0x3c, 0x1e, 0x55, 0xda, 0x0f,
0x69, 0xbf, 0x26, 0x79, 0xc7, 0xb6, 0xdd, 0x8e, 0x83, 0x32, 0x65, 0x74,
0x0d, 0x74, 0x48, 0x42, 0x49, 0x22, 0x52, 0x58, 0x56, 0xc3, 0xe4, 0x49,
0x5d, 0xac, 0x6a, 0x94, 0xb1, 0x64, 0x14, 0xbf, 0x4d, 0xd5, 0xd7, 0x3a,
0xca, 0x5c, 0x1e, 0x6f, 0x42, 0x30, 0xac, 0x29, 0xaa, 0xa0, 0x85, 0xd2,
0x16, 0xa2, 0x8e, 0x89, 0x12, 0xc4, 0x92, 0x06, 0xea, 0xed, 0x48, 0xf6,
0xdb, 0xed, 0x4f, 0x62, 0x6c, 0xfa, 0xcf, 0xc2, 0xb9, 0x8d, 0x04, 0xb2,
0xba, 0x63, 0xc9, 0xcc, 0xee, 0x23, 0x64, 0x46, 0x14, 0x12, 0xc8, 0x38,
0x67, 0x69, 0x6b, 0xaf, 0xd1, 0x7c, 0xb1, 0xb5, 0x79, 0xe4, 0x4e, 0x3a,
0xa7, 0xe8, 0x28, 0x89, 0x25, 0xc0, 0xd0, 0xd8, 0xc7, 0xd2, 0x26, 0xaa,
0xf5, 0xbf, 0x36, 0x55, 0x01, 0x89, 0x58, 0x1f, 0x1e, 0xf5, 0xa5, 0x42,
0x8f, 0x60, 0x2e, 0xc2, 0xd8, 0x21, 0x0b, 0x6c, 0x8d, 0xbb, 0x72, 0xf2,
0x19, 0x30, 0xe3, 0x4c, 0x3e, 0x80, 0xe7, 0xf2, 0xe3, 0x89, 0x4f, 0xd4,
0xee, 0x96, 0x3e, 0x4a, 0x9b, 0xe5, 0x16, 0x01, 0xf1, 0x98, 0xc9, 0x0b,
0xd6, 0xdf, 0x8a, 0x64, 0x47, 0xc4, 0x44, 0xcc, 0x92, 0x69, 0x28, 0xee,
0x7d, 0xac, 0xdc, 0x30, 0x56, 0x3a, 0xe7, 0xbc, 0xba, 0x45, 0x16, 0x2c,
0x4c, 0x46, 0x6b, 0x2b, 0x20, 0xfb, 0x3d, 0x20, 0x35, 0xbb, 0x48, 0x49,
0x13, 0x65, 0xc9, 0x9a, 0x38, 0x10, 0x84, 0x1a, 0x8c, 0xc9, 0xd7, 0xde,
0x07, 0x10, 0x5a, 0xfb, 0xb4, 0x95, 0xae, 0x18, 0xf2, 0xe3, 0x15, 0xe8,
0xad, 0x7e, 0xe5, 0x3c, 0xa8, 0x47, 0x85, 0xd6, 0x1f, 0x54, 0xb5, 0xa3,
0x79, 0x02, 0x03, 0x01, 0x00, 0x01
}; ///< The GBv2 public key file.
static unsigned char __gbv2keypub_der[] = {0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe5, 0xd7, 0x9c, 0x7d, 0x73, 0xc6, 0xe6, 0xfb,
0x35, 0x7e, 0xd7, 0x57, 0x99, 0x07, 0xdb, 0x99, 0x70, 0xc9, 0xd0, 0x3e, 0x53, 0x57, 0x3c, 0x1e, 0x55, 0xda, 0x0f, 0x69, 0xbf, 0x26, 0x79, 0xc7,
0xb6, 0xdd, 0x8e, 0x83, 0x32, 0x65, 0x74, 0x0d, 0x74, 0x48, 0x42, 0x49, 0x22, 0x52, 0x58, 0x56, 0xc3, 0xe4, 0x49, 0x5d, 0xac, 0x6a, 0x94, 0xb1,
0x64, 0x14, 0xbf, 0x4d, 0xd5, 0xd7, 0x3a, 0xca, 0x5c, 0x1e, 0x6f, 0x42, 0x30, 0xac, 0x29, 0xaa, 0xa0, 0x85, 0xd2, 0x16, 0xa2, 0x8e, 0x89, 0x12,
0xc4, 0x92, 0x06, 0xea, 0xed, 0x48, 0xf6, 0xdb, 0xed, 0x4f, 0x62, 0x6c, 0xfa, 0xcf, 0xc2, 0xb9, 0x8d, 0x04, 0xb2, 0xba, 0x63, 0xc9, 0xcc, 0xee,
0x23, 0x64, 0x46, 0x14, 0x12, 0xc8, 0x38, 0x67, 0x69, 0x6b, 0xaf, 0xd1, 0x7c, 0xb1, 0xb5, 0x79, 0xe4, 0x4e, 0x3a, 0xa7, 0xe8, 0x28, 0x89, 0x25,
0xc0, 0xd0, 0xd8, 0xc7, 0xd2, 0x26, 0xaa, 0xf5, 0xbf, 0x36, 0x55, 0x01, 0x89, 0x58, 0x1f, 0x1e, 0xf5, 0xa5, 0x42, 0x8f, 0x60, 0x2e, 0xc2, 0xd8,
0x21, 0x0b, 0x6c, 0x8d, 0xbb, 0x72, 0xf2, 0x19, 0x30, 0xe3, 0x4c, 0x3e, 0x80, 0xe7, 0xf2, 0xe3, 0x89, 0x4f, 0xd4, 0xee, 0x96, 0x3e, 0x4a, 0x9b,
0xe5, 0x16, 0x01, 0xf1, 0x98, 0xc9, 0x0b, 0xd6, 0xdf, 0x8a, 0x64, 0x47, 0xc4, 0x44, 0xcc, 0x92, 0x69, 0x28, 0xee, 0x7d, 0xac, 0xdc, 0x30, 0x56,
0x3a, 0xe7, 0xbc, 0xba, 0x45, 0x16, 0x2c, 0x4c, 0x46, 0x6b, 0x2b, 0x20, 0xfb, 0x3d, 0x20, 0x35, 0xbb, 0x48, 0x49, 0x13, 0x65, 0xc9, 0x9a, 0x38,
0x10, 0x84, 0x1a, 0x8c, 0xc9, 0xd7, 0xde, 0x07, 0x10, 0x5a, 0xfb, 0xb4, 0x95, 0xae, 0x18, 0xf2, 0xe3, 0x15, 0xe8, 0xad, 0x7e, 0xe5, 0x3c, 0xa8,
0x47, 0x85, 0xd6, 0x1f, 0x54, 0xb5, 0xa3, 0x79, 0x02, 0x03, 0x01, 0x00, 0x01}; ///< The GBv2 public key file.
static unsigned int __gbv2keypub_der_len = 294; ///< Length of GBv2 public key data
/// Attempts to load the GBv2 public key.

View file

@ -17,16 +17,28 @@ std::string Base64::encode(std::string const input) {
char quad[4], triple[3];
unsigned int i, x, n = 3;
for (x = 0; x < in_len; x = x + 3){
if ((in_len - x) / 3 == 0){n = (in_len - x) % 3;}
for (i=0; i < 3; i++){triple[i] = '0';}
for (i=0; i < n; i++){triple[i] = input[x + i];}
if ((in_len - x) / 3 == 0){
n = (in_len - x) % 3;
}
for (i = 0; i < 3; i++){
triple[i] = '0';
}
for (i = 0; i < n; i++){
triple[i] = input[x + i];
}
quad[0] = chars[(triple[0] & 0xFC) >> 2]; // FC = 11111100
quad[1] = chars[((triple[0] & 0x03) << 4) | ((triple[1] & 0xF0) >> 4)]; // 03 = 11
quad[2] = chars[((triple[1] & 0x0F) << 2) | ((triple[2] & 0xC0) >> 6)]; // 0F = 1111, C0=11110
quad[3] = chars[triple[2] & 0x3F]; // 3F = 111111
if (n < 3){quad[3] = '=';}
if (n < 2){quad[2] = '=';}
for(i=0; i < 4; i++){ret += quad[i];}
if (n < 3){
quad[3] = '=';
}
if (n < 2){
quad[2] = '=';
}
for (i = 0; i < 4; i++){
ret += quad[i];
}
}
return ret;
} //base64_encode
@ -42,23 +54,33 @@ std::string Base64::decode(std::string const& encoded_string) {
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])){
char_array_4[i++] = encoded_string[in_]; in_++;
char_array_4[i++ ] = encoded_string[in_];
in_++;
if (i == 4){
for (i = 0; i <4; i++){char_array_4[i] = chars.find(char_array_4[i]);}
for (i = 0; i < 4; i++){
char_array_4[i] = chars.find(char_array_4[i]);
}
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++){ret += char_array_3[i];}
for (i = 0; (i < 3); i++){
ret += char_array_3[i];
}
i = 0;
}
}
if (i){
for (j = i; j <4; j++){char_array_4[j] = 0;}
for (j = 0; j <4; j++){char_array_4[j] = chars.find(char_array_4[j]);}
for (j = i; j < 4; j++){
char_array_4[j] = 0;
}
for (j = 0; j < 4; j++){
char_array_4[j] = chars.find(char_array_4[j]);
}
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
for (j = 0; (j < i - 1); j++)
ret += char_array_3[j];
}
return ret;
}

View file

@ -62,8 +62,12 @@ void Util::Config::addOption(std::string optname, JSON::Value option){
}
long_count = 0;
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++){
if (it->second.isMember("long")){long_count++;}
if (it->second.isMember("long_off")){long_count++;}
if (it->second.isMember("long")){
long_count++;
}
if (it->second.isMember("long_off")){
long_count++;
}
}
}
@ -73,16 +77,30 @@ void Util::Config::printHelp(std::ostream & output){
std::map<long long int, std::string> args;
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++){
unsigned int current = 0;
if (it->second.isMember("long")){current += it->second["long"].asString().size() + 4;}
if (it->second.isMember("short")){current += it->second["short"].asString().size() + 3;}
if (current > longest){longest = current;}
if (it->second.isMember("long")){
current += it->second["long"].asString().size() + 4;
}
if (it->second.isMember("short")){
current += it->second["short"].asString().size() + 3;
}
if (current > longest){
longest = current;
}
current = 0;
if (it->second.isMember("long_off")){current += it->second["long_off"].asString().size() + 4;}
if (it->second.isMember("short_off")){current += it->second["short_off"].asString().size() + 3;}
if (current > longest){longest = current;}
if (it->second.isMember("long_off")){
current += it->second["long_off"].asString().size() + 4;
}
if (it->second.isMember("short_off")){
current += it->second["short_off"].asString().size() + 3;
}
if (current > longest){
longest = current;
}
if (it->second.isMember("arg_num")){
current = it->first.size() + 3;
if (current > longest){longest = current;}
if (current > longest){
longest = current;
}
args[it->second["arg_num"].asInt()] = it->first;
}
}
@ -108,7 +126,9 @@ void Util::Config::printHelp(std::ostream & output){
f = "-" + it->second["short"].asString();
}
}
while (f.size() < longest){f.append(" ");}
while (f.size() < longest){
f.append(" ");
}
if (it->second.isMember("arg")){
output << f << "(" << it->second["arg"].asString() << ") " << it->second["help"].asString() << std::endl;
}else{
@ -126,7 +146,9 @@ void Util::Config::printHelp(std::ostream & output){
f = "-" + it->second["short_off"].asString();
}
}
while (f.size() < longest){f.append(" ");}
while (f.size() < longest){
f.append(" ");
}
if (it->second.isMember("arg")){
output << f << "(" << it->second["arg"].asString() << ") " << it->second["help"].asString() << std::endl;
}else{
@ -135,13 +157,14 @@ void Util::Config::printHelp(std::ostream & output){
}
if (it->second.isMember("arg_num")){
f = it->first;
while (f.size() < longest){f.append(" ");}
while (f.size() < longest){
f.append(" ");
}
output << f << "(" << it->second["arg"].asString() << ") " << it->second["help"].asString() << std::endl;
}
}
}
/// Parses commandline arguments.
/// Calls exit if an unknown option is encountered, printing a help message.
void Util::Config::parseArgs(int argc, char ** argv){
@ -153,22 +176,30 @@ void Util::Config::parseArgs(int argc, char ** argv){
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++){
if (it->second.isMember("short")){
shortopts += it->second["short"].asString();
if (it->second.isMember("arg")){shortopts += ":";}
if (it->second.isMember("arg")){
shortopts += ":";
}
}
if (it->second.isMember("short_off")){
shortopts += it->second["short_off"].asString();
if (it->second.isMember("arg")){shortopts += ":";}
if (it->second.isMember("arg")){
shortopts += ":";
}
}
if (it->second.isMember("long")){
longOpts[long_i].name = it->second["long"].asString().c_str();
longOpts[long_i].val = it->second["short"].asString()[0];
if (it->second.isMember("arg")){longOpts[long_i].has_arg = 1;}
if (it->second.isMember("arg")){
longOpts[long_i].has_arg = 1;
}
long_i++;
}
if (it->second.isMember("long_off")){
longOpts[long_i].name = it->second["long_off"].asString().c_str();
longOpts[long_i].val = it->second["short_off"].asString()[0];
if (it->second.isMember("arg")){longOpts[long_i].has_arg = 1;}
if (it->second.isMember("arg")){
longOpts[long_i].has_arg = 1;
}
long_i++;
}
if (it->second.isMember("arg_num") && !(it->second.isMember("value") && it->second["value"].size())){
@ -306,21 +337,33 @@ void Util::Config::addConnectorOptions(int port){
JSON::Value stored_port = JSON::fromString("{\"long\":\"port\", \"short\":\"p\", \"arg\":\"integer\", \"help\":\"TCP port to listen on.\"}");
stored_port["value"].append((long long int)port);
addOption("listen_port", stored_port);
addOption("listen_interface", JSON::fromString("{\"long\":\"interface\", \"value\":[\"0.0.0.0\"], \"short\":\"i\", \"arg\":\"string\", \"help\":\"Interface address to listen on, or 0.0.0.0 for all available interfaces.\"}"));
addOption("username", JSON::fromString("{\"long\":\"username\", \"value\":[\"root\"], \"short\":\"u\", \"arg\":\"string\", \"help\":\"Username to drop privileges to, or root to not drop provileges.\"}"));
addOption("daemonize", JSON::fromString("{\"long\":\"daemon\", \"short\":\"d\", \"value\":[1], \"long_off\":\"nodaemon\", \"short_off\":\"n\", \"help\":\"Whether or not to daemonize the process after starting.\"}"));
addOption("listen_interface",
JSON::fromString(
"{\"long\":\"interface\", \"value\":[\"0.0.0.0\"], \"short\":\"i\", \"arg\":\"string\", \"help\":\"Interface address to listen on, or 0.0.0.0 for all available interfaces.\"}"));
addOption("username",
JSON::fromString(
"{\"long\":\"username\", \"value\":[\"root\"], \"short\":\"u\", \"arg\":\"string\", \"help\":\"Username to drop privileges to, or root to not drop provileges.\"}"));
addOption("daemonize",
JSON::fromString(
"{\"long\":\"daemon\", \"short\":\"d\", \"value\":[1], \"long_off\":\"nodaemon\", \"short_off\":\"n\", \"help\":\"Whether or not to daemonize the process after starting.\"}"));
} //addConnectorOptions
/// Gets directory the current executable is stored in.
std::string Util::getMyPath(){
char mypath[500];
int ret = readlink("/proc/self/exe", mypath, 500);
if (ret != -1){mypath[ret] = 0;}else{mypath[0] = 0;}
if (ret != -1){
mypath[ret] = 0;
}else{
mypath[0] = 0;
}
std::string tPath = mypath;
size_t slash = tPath.rfind('/');
if (slash == std::string::npos){
slash = tPath.rfind('\\');
if (slash == std::string::npos){return "";}
if (slash == std::string::npos){
return "";
}
}
tPath.resize(slash + 1);
return tPath;

View file

@ -2,6 +2,11 @@
/// Contains generic function headers for managing configuration.
#pragma once
#ifndef PACKAGE_VERSION
#define PACKAGE_VERSION "unknown"
#endif
#include <string>
#include "json.h"
@ -40,4 +45,5 @@ namespace Util{
/// Will turn the current process into a daemon.
void Daemonize();
};
}
;

View file

View file

@ -1,25 +0,0 @@
/// \file crypto.h
/// Holds all headers needed for RTMP cryptography functions.
#pragma once
#include <stdint.h>
#include <string>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/rc4.h>
#include <openssl/ssl.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/hmac.h>
void InitRC4Encryption(uint8_t *secretKey, uint8_t *pubKeyIn, uint8_t *pubKeyOut, RC4_KEY *rc4keyIn, RC4_KEY *rc4keyOut);
void HMACsha256(const void *pData, uint32_t dataLength, const void *pKey, uint32_t keyLength, void *pResult);
extern uint8_t genuineFMSKey[];
bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme);

View file

@ -5,12 +5,12 @@
#include <stdlib.h>
#include <string.h> //for memcmp
#include <arpa/inet.h> //for htonl/ntohl
char DTSC::Magic_Header[] = "DTSC";
char DTSC::Magic_Packet[] = "DTPD";
/// Initializes a DTSC::Stream with only one packet buffer.
DTSC::Stream::Stream(){
datapointertype = DTSC::INVALID;
datapointer = 0;
buffercount = 1;
}
@ -18,8 +18,11 @@ DTSC::Stream::Stream(){
/// Initializes a DTSC::Stream with a minimum of rbuffers packet buffers.
/// The actual buffer count may not at all times be the requested amount.
DTSC::Stream::Stream(unsigned int rbuffers){
datapointertype = DTSC::INVALID;
datapointer = 0;
if (rbuffers < 1){rbuffers = 1;}
if (rbuffers < 1){
rbuffers = 1;
}
buffercount = rbuffers;
}
@ -39,7 +42,9 @@ bool DTSC::Stream::parsePacket(std::string & buffer){
if (buffer.length() > 8){
if (memcmp(buffer.c_str(), DTSC::Magic_Header, 4) == 0){
len = ntohl(((uint32_t *)buffer.c_str())[1]);
if (buffer.length() < len+8){return false;}
if (buffer.length() < len + 8){
return false;
}
unsigned int i = 0;
metadata = JSON::fromDTMI((unsigned char*)buffer.c_str() + 8, len, i);
buffer.erase(0, len + 8);
@ -47,7 +52,9 @@ bool DTSC::Stream::parsePacket(std::string & buffer){
}
if (memcmp(buffer.c_str(), DTSC::Magic_Packet, 4) == 0){
len = ntohl(((uint32_t *)buffer.c_str())[1]);
if (buffer.length() < len+8){return false;}
if (buffer.length() < len + 8){
return false;
}
buffers.push_front(JSON::Value());
unsigned int i = 0;
buffers.front() = JSON::fromDTMI((unsigned char*)buffer.c_str() + 8, len, i);
@ -59,13 +66,23 @@ bool DTSC::Stream::parsePacket(std::string & buffer){
}
if (buffers.front().isMember("datatype")){
std::string tmp = buffers.front()["datatype"].asString();
if (tmp == "video"){datapointertype = VIDEO;}
if (tmp == "audio"){datapointertype = AUDIO;}
if (tmp == "meta"){datapointertype = META;}
if (tmp == "pause_marker"){datapointertype = PAUSEMARK;}
if (tmp == "video"){
datapointertype = VIDEO;
}
if (tmp == "audio"){
datapointertype = AUDIO;
}
if (tmp == "meta"){
datapointertype = META;
}
if (tmp == "pause_marker"){
datapointertype = PAUSEMARK;
}
}
buffer.erase(0, len + 8);
while (buffers.size() > buffercount){buffers.pop_back();}
while (buffers.size() > buffercount){
buffers.pop_back();
}
advanceRings();
syncing = false;
return true;
@ -97,7 +114,9 @@ bool DTSC::Stream::parsePacket(Socket::Buffer & buffer){
std::string header_bytes = buffer.copy(8);
if (memcmp(header_bytes.c_str(), DTSC::Magic_Header, 4) == 0){
len = ntohl(((uint32_t *)header_bytes.c_str())[1]);
if (!buffer.available(len+8)){return false;}
if ( !buffer.available(len + 8)){
return false;
}
unsigned int i = 0;
std::string wholepacket = buffer.remove(len + 8);
metadata = JSON::fromDTMI((unsigned char*)wholepacket.c_str() + 8, len, i);
@ -105,7 +124,9 @@ bool DTSC::Stream::parsePacket(Socket::Buffer & buffer){
}
if (memcmp(header_bytes.c_str(), DTSC::Magic_Packet, 4) == 0){
len = ntohl(((uint32_t *)header_bytes.c_str())[1]);
if (!buffer.available(len+8)){return false;}
if ( !buffer.available(len + 8)){
return false;
}
buffers.push_front(JSON::Value());
unsigned int i = 0;
std::string wholepacket = buffer.remove(len + 8);
@ -118,12 +139,22 @@ bool DTSC::Stream::parsePacket(Socket::Buffer & buffer){
}
if (buffers.front().isMember("datatype")){
std::string tmp = buffers.front()["datatype"].asString();
if (tmp == "video"){datapointertype = VIDEO;}
if (tmp == "audio"){datapointertype = AUDIO;}
if (tmp == "meta"){datapointertype = META;}
if (tmp == "pause_marker"){datapointertype = PAUSEMARK;}
if (tmp == "video"){
datapointertype = VIDEO;
}
if (tmp == "audio"){
datapointertype = AUDIO;
}
if (tmp == "meta"){
datapointertype = META;
}
if (tmp == "pause_marker"){
datapointertype = PAUSEMARK;
}
}
while (buffers.size() > buffercount){
buffers.pop_back();
}
while (buffers.size() > buffercount){buffers.pop_back();}
advanceRings();
syncing = false;
return true;
@ -186,18 +217,29 @@ void DTSC::Stream::advanceRings(){
std::set<DTSC::Ring *>::iterator sit;
for (sit = rings.begin(); sit != rings.end(); sit++){
( *sit)->b++;
if ((*sit)->waiting){(*sit)->waiting = false; (*sit)->b = 0;}
if ((*sit)->starved || ((*sit)->b >= buffers.size())){(*sit)->starved = true; (*sit)->b = 0;}
if (( *sit)->waiting){
( *sit)->waiting = false;
( *sit)->b = 0;
}
if (( *sit)->starved || (( *sit)->b >= buffers.size())){
( *sit)->starved = true;
( *sit)->b = 0;
}
}
for (dit = keyframes.begin(); dit != keyframes.end(); dit++){
dit->b++;
if (dit->b >= buffers.size()){keyframes.erase(dit); break;}
if (dit->b >= buffers.size()){
keyframes.erase(dit);
break;
}
}
if ((lastType() == VIDEO) && (buffers.front().isMember("keyframe"))){
keyframes.push_front(DTSC::Ring(0));
}
//increase buffer size if no keyframes available
if ((buffercount > 1) && (keyframes.size() < 1)){buffercount++;}
if ((buffercount > 1) && (keyframes.size() < 1)){
buffercount++;
}
}
/// Constructs a new Ring, at the given buffer position.
@ -235,7 +277,9 @@ void DTSC::Stream::dropRing(DTSC::Ring * ptr){
/// Drops all Ring classes that have been given out.
DTSC::Stream::~Stream(){
std::set<DTSC::Ring *>::iterator sit;
for (sit = rings.begin(); sit != rings.end(); sit++){delete (*sit);}
for (sit = rings.begin(); sit != rings.end(); sit++){
delete ( *sit);
}
}
/// Open a filename for DTSC reading/writing.
@ -300,11 +344,17 @@ long long int DTSC::File::addHeader(std::string & header){
long long int writePos = ftell(F);
int hSize = htonl(header.size());
int ret = fwrite(DTSC::Magic_Header, 4, 1, F); //write header
if (ret != 1){return 0;}
if (ret != 1){
return 0;
}
ret = fwrite((void*)( &hSize), 4, 1, F); //write size
if (ret != 1){return 0;}
if (ret != 1){
return 0;
}
ret = fwrite(header.c_str(), header.size(), 1, F); //write contents
if (ret != 1){return 0;}
if (ret != 1){
return 0;
}
return writePos; //return position written at
}
@ -423,13 +473,19 @@ void DTSC::File::seekNext(){
}
/// Returns the byte positon of the start of the last packet that was read.
long long int DTSC::File::getLastReadPos(){return lastreadpos;}
long long int DTSC::File::getLastReadPos(){
return lastreadpos;
}
/// Returns the internal buffer of the last read packet in raw binary format.
std::string & DTSC::File::getPacket(){return strbuffer;}
std::string & DTSC::File::getPacket(){
return strbuffer;
}
/// Returns the internal buffer of the last read packet in JSON format.
JSON::Value & DTSC::File::getJSON(){return jsonbuffer;}
JSON::Value & DTSC::File::getJSON(){
return jsonbuffer;
}
/// Attempts to seek to the given frame number within the file.
/// Returns true if successful, false otherwise.
@ -444,7 +500,10 @@ bool DTSC::File::seek_frame(int frameno){
}
}else{
for (int i = frameno; i >= 1; --i){
if (frames.count(i) > 0){currframe = i; break;}
if (frames.count(i) > 0){
currframe = i;
break;
}
}
if (fseek(F, frames[currframe], SEEK_SET) == 0){
#if DEBUG >= 4
@ -452,7 +511,9 @@ bool DTSC::File::seek_frame(int frameno){
#endif
while (currframe < frameno){
seekNext();
if (jsonbuffer.isNull()){return false;}
if (jsonbuffer.isNull()){
return false;
}
}
seek_frame(frameno);
return true;
@ -468,8 +529,13 @@ bool DTSC::File::seek_time(int ms){
currtime = 0;
currframe = 1;
for (it = msframes.begin(); it != msframes.end(); ++it){
if (it->second > ms){break;}
if (it->second > currtime){currtime = it->second; currframe = it->first;}
if (it->second > ms){
break;
}
if (it->second > currtime){
currtime = it->second;
currframe = it->first;
}
}
if (fseek(F, frames[currframe], SEEK_SET) == 0){
#if DEBUG >= 4
@ -477,7 +543,9 @@ bool DTSC::File::seek_time(int ms){
#endif
while (currtime < ms){
seekNext();
if (jsonbuffer.isNull()){return false;}
if (jsonbuffer.isNull()){
return false;
}
}
if (currtime > ms){
return seek_frame(currframe - 1);

View file

@ -12,8 +12,6 @@
#include "json.h"
#include "socket.h"
/// Holds all DDVTECH Stream Container classes and parsers.
///length (int, length in seconds, if available)
///video:
@ -91,8 +89,8 @@ namespace DTSC{
FILE * F;
unsigned long headerSize;
char buffer[4];
};//FileWriter
};
//FileWriter
/// A part from the DTSC::Stream ringbuffer.
/// Holds information about a buffer that will stay consistent
@ -134,4 +132,4 @@ namespace DTSC{
datatype datapointertype;
unsigned int buffercount;
};
};
}

View file

@ -1,15 +1,19 @@
#include "filesystem.h"
Filesystem::Directory::Directory(std::string PathName, std::string BasePath){
MyBase = BasePath;
if( PathName[0] == '/' ) { PathName.erase(0,1); }
if( BasePath[BasePath.size()-1] != '/' ) { BasePath += "/"; }
if (PathName[0] == '/'){
PathName.erase(0, 1);
}
if (BasePath[BasePath.size() - 1] != '/'){
BasePath += "/";
}
MyPath = PathName;
FillEntries();
}
Filesystem::Directory::~Directory( ) { }
Filesystem::Directory::~Directory(){
}
void Filesystem::Directory::FillEntries(){
fprintf(stderr, "Filling Entries of %s:\n", (MyBase + MyPath).c_str());
@ -21,7 +25,7 @@ void Filesystem::Directory::FillEntries( ) {
ValidDir = false;
}else{
dirent * entry;
while( entry = readdir( Dirp ) ) {
while ((entry = readdir(Dirp))){
if (stat((MyBase + MyPath + "/" + entry->d_name).c_str(), &StatBuf) == -1){
fprintf(stderr, "\tSkipping %s\n\t\tReason: %s\n", entry->d_name, strerror(errno));
continue;
@ -64,7 +68,9 @@ std::string Filesystem::Directory::LIST( std::vector<std::string> ActiveStreams
char datestring[256]; //For time localisation
std::string MyLoc = MyBase + MyPath;
if( MyLoc[MyLoc.size()-1] != '/' ) { MyLoc += "/"; }
if (MyLoc[MyLoc.size() - 1] != '/'){
MyLoc += "/";
}
for (std::map<std::string, struct stat>::iterator it = Entries.begin(); it != Entries.end(); it++){
@ -73,19 +79,59 @@ std::string Filesystem::Directory::LIST( std::vector<std::string> ActiveStreams
fprintf(stderr, "\tMyPath: %s\n\tVisible: %d\n", MyPath.c_str(), MyVisible[MyPath]);
fprintf(stderr, "\t\tBitmask S_ACTIVE: %d\n\t\tBitmask S_INACTIVE: %d\n", MyVisible[MyPath] & S_ACTIVE, MyVisible[MyPath] & S_INACTIVE);
if ((Active && (MyVisible[MyPath] & S_ACTIVE)) || (( !Active) && (MyVisible[MyPath] & S_INACTIVE)) || ((( *it).second.st_mode / 010000) == 4)){
if( ((*it).second.st_mode / 010000) == 4 ) { Converter << 'd'; } else { Converter << '-'; }
if ((( *it).second.st_mode / 010000) == 4){
Converter << 'd';
}else{
Converter << '-';
}
MyPermissions = ((( *it).second.st_mode % 010000) / 0100);
if( MyPermissions & 4 ) { Converter << 'r'; } else { Converter << '-'; }
if( MyPermissions & 2 ) { Converter << 'w'; } else { Converter << '-'; }
if( MyPermissions & 1 ) { Converter << 'x'; } else { Converter << '-'; }
if (MyPermissions & 4){
Converter << 'r';
}else{
Converter << '-';
}
if (MyPermissions & 2){
Converter << 'w';
}else{
Converter << '-';
}
if (MyPermissions & 1){
Converter << 'x';
}else{
Converter << '-';
}
MyPermissions = ((( *it).second.st_mode % 0100) / 010);
if( MyPermissions & 4 ) { Converter << 'r'; } else { Converter << '-'; }
if( MyPermissions & 2 ) { Converter << 'w'; } else { Converter << '-'; }
if( MyPermissions & 1 ) { Converter << 'x'; } else { Converter << '-'; }
if (MyPermissions & 4){
Converter << 'r';
}else{
Converter << '-';
}
if (MyPermissions & 2){
Converter << 'w';
}else{
Converter << '-';
}
if (MyPermissions & 1){
Converter << 'x';
}else{
Converter << '-';
}
MyPermissions = (( *it).second.st_mode % 010);
if( MyPermissions & 4 ) { Converter << 'r'; } else { Converter << '-'; }
if( MyPermissions & 2 ) { Converter << 'w'; } else { Converter << '-'; }
if( MyPermissions & 1 ) { Converter << 'x'; } else { Converter << '-'; }
if (MyPermissions & 4){
Converter << 'r';
}else{
Converter << '-';
}
if (MyPermissions & 2){
Converter << 'w';
}else{
Converter << '-';
}
if (MyPermissions & 1){
Converter << 'x';
}else{
Converter << '-';
}
Converter << ' ';
Converter << ( *it).second.st_nlink;
Converter << ' ';
@ -147,7 +193,9 @@ std::string Filesystem::Directory::RETR( std::string Path ) {
}
std::ifstream File;
File.open(FileName.c_str());
while( File.good() ) { Result += File.get(); }
while (File.good()){
Result += File.get();
}
File.close();
return Result;
}
@ -191,7 +239,9 @@ bool Filesystem::Directory::SimplifyPath( ) {
MyPath = "";
for (std::vector<std::string>::iterator it = TempPath.begin(); it != TempPath.end(); it++){
MyPath += ( *it);
if( it != ( TempPath.end() - 1 ) ) { MyPath += "/"; }
if (it != (TempPath.end() - 1)){
MyPath += "/";
}
}
if (MyVisible.find(MyPath) == MyVisible.end()){
MyVisible[MyPath] = S_ALL;

View file

@ -32,10 +32,7 @@ namespace Filesystem {
};
enum DIR_Show{
S_NONE = 0x00,
S_ACTIVE = 0x01,
S_INACTIVE = 0x02,
S_ALL = 0x03,
S_NONE = 0x00, S_ACTIVE = 0x01, S_INACTIVE = 0x02, S_ALL = 0x03,
};
class Directory{
@ -65,5 +62,6 @@ namespace Filesystem {
std::map<std::string, struct stat> Entries;
std::map<std::string, char> MyPermissions;
std::map<std::string, char> MyVisible;
};//Directory Class
};//Filesystem namespace
};
//Directory Class
}//Filesystem namespace

View file

@ -1,9 +1,9 @@
/// \file flv_tag.cpp
/// Holds all code for the FLV namespace.
#include "flv_tag.h"
#include "amf.h"
#include "rtmpchunks.h"
#include "flv_tag.h"
#include <stdio.h> //for Tag::FileLoader
#include <unistd.h> //for Tag::FileLoader
#include <fcntl.h> //for Tag::FileLoader
@ -57,17 +57,31 @@ bool FLV::Tag::needsInitData(){
switch (data[0]){
case 0x09:
switch (data[11] & 0x0F){
case 2: return true; break;//H263 requires init data
case 7: return true; break;//AVC requires init data
default: return false; break;//other formats do not
case 2:
return true;
break; //H263 requires init data
case 7:
return true;
break; //AVC requires init data
default:
return false;
break; //other formats do not
}
break;
case 0x08:
switch (data[11] & 0xF0){
case 0x20: return false; break;//MP3 does not...? Unsure.
case 0xA0: return true; break;//AAC requires init data
case 0xE0: return false; break;//MP38kHz does not...?
default: return false; break;//other formats do not
case 0x20:
return false;
break; //MP3 does not...? Unsure.
case 0xA0:
return true;
break; //AAC requires init data
case 0xE0:
return false;
break; //MP38kHz does not...?
default:
return false;
break; //other formats do not
}
break;
}
@ -79,11 +93,15 @@ bool FLV::Tag::isInitData(){
switch (data[0]){
case 0x09:
switch (data[11] & 0xF0){
case 0x50: return true; break;
case 0x50:
return true;
break;
}
if ((data[11] & 0x0F) == 7){
switch (data[12]){
case 0: return true; break;
case 0:
return true;
break;
}
}
break;
@ -106,62 +124,140 @@ std::string FLV::Tag::tagType(){
switch (data[0]){
case 0x09:
switch (data[11] & 0x0F){
case 1: R << "JPEG"; break;
case 2: R << "H263"; break;
case 3: R << "ScreenVideo1"; break;
case 4: R << "VP6"; break;
case 5: R << "VP6Alpha"; break;
case 6: R << "ScreenVideo2"; break;
case 7: R << "H264"; break;
default: R << "unknown"; break;
case 1:
R << "JPEG";
break;
case 2:
R << "H263";
break;
case 3:
R << "ScreenVideo1";
break;
case 4:
R << "VP6";
break;
case 5:
R << "VP6Alpha";
break;
case 6:
R << "ScreenVideo2";
break;
case 7:
R << "H264";
break;
default:
R << "unknown";
break;
}
R << " video ";
switch (data[11] & 0xF0){
case 0x10: R << "keyframe"; break;
case 0x20: R << "iframe"; break;
case 0x30: R << "disposableiframe"; break;
case 0x40: R << "generatedkeyframe"; break;
case 0x50: R << "videoinfo"; break;
case 0x10:
R << "keyframe";
break;
case 0x20:
R << "iframe";
break;
case 0x30:
R << "disposableiframe";
break;
case 0x40:
R << "generatedkeyframe";
break;
case 0x50:
R << "videoinfo";
break;
}
if ((data[11] & 0x0F) == 7){
switch (data[12]){
case 0: R << " header"; break;
case 1: R << " NALU"; break;
case 2: R << " endofsequence"; break;
case 0:
R << " header";
break;
case 1:
R << " NALU";
break;
case 2:
R << " endofsequence";
break;
}
}
break;
case 0x08:
switch (data[11] & 0xF0){
case 0x00: R << "linear PCM PE"; break;
case 0x10: R << "ADPCM"; break;
case 0x20: R << "MP3"; break;
case 0x30: R << "linear PCM LE"; break;
case 0x40: R << "Nelly16kHz"; break;
case 0x50: R << "Nelly8kHz"; break;
case 0x60: R << "Nelly"; break;
case 0x70: R << "G711A-law"; break;
case 0x80: R << "G711mu-law"; break;
case 0x90: R << "reserved"; break;
case 0xA0: R << "AAC"; break;
case 0xB0: R << "Speex"; break;
case 0xE0: R << "MP38kHz"; break;
case 0xF0: R << "DeviceSpecific"; break;
default: R << "unknown"; break;
case 0x00:
R << "linear PCM PE";
break;
case 0x10:
R << "ADPCM";
break;
case 0x20:
R << "MP3";
break;
case 0x30:
R << "linear PCM LE";
break;
case 0x40:
R << "Nelly16kHz";
break;
case 0x50:
R << "Nelly8kHz";
break;
case 0x60:
R << "Nelly";
break;
case 0x70:
R << "G711A-law";
break;
case 0x80:
R << "G711mu-law";
break;
case 0x90:
R << "reserved";
break;
case 0xA0:
R << "AAC";
break;
case 0xB0:
R << "Speex";
break;
case 0xE0:
R << "MP38kHz";
break;
case 0xF0:
R << "DeviceSpecific";
break;
default:
R << "unknown";
break;
}
switch (data[11] & 0x0C){
case 0x0: R << " 5.5kHz"; break;
case 0x4: R << " 11kHz"; break;
case 0x8: R << " 22kHz"; break;
case 0xC: R << " 44kHz"; break;
case 0x0:
R << " 5.5kHz";
break;
case 0x4:
R << " 11kHz";
break;
case 0x8:
R << " 22kHz";
break;
case 0xC:
R << " 44kHz";
break;
}
switch (data[11] & 0x02){
case 0: R << " 8bit"; break;
case 2: R << " 16bit"; break;
case 0:
R << " 8bit";
break;
case 2:
R << " 16bit";
break;
}
switch (data[11] & 0x01){
case 0: R << " mono"; break;
case 1: R << " stereo"; break;
case 0:
R << " mono";
break;
case 1:
R << " stereo";
break;
}
R << " audio";
if ((data[12] == 0) && ((data[11] & 0xF0) == 0xA0)){
@ -198,7 +294,12 @@ void FLV::Tag::tagTime(unsigned int T){
/// The buffer length is initialized to 0, and later automatically
/// increased if neccesary.
FLV::Tag::Tag(){
len = 0; buf = 0; data = 0; isKeyframe = false; done = true; sofar = 0;
len = 0;
buf = 0;
data = 0;
isKeyframe = false;
done = true;
sofar = 0;
} //empty constructor
/// Copy constructor, copies the contents of an existing tag.
@ -219,13 +320,17 @@ FLV::Tag::Tag(const Tag& O){
isKeyframe = O.isKeyframe;
} //copy constructor
/// Copy constructor from a RTMP chunk.
/// Copies the contents of a RTMP chunk into a valid FLV tag.
/// Exactly the same as making a chunk by through the default (empty) constructor
/// and then calling FLV::Tag::ChunkLoader with the chunk as argument.
FLV::Tag::Tag(const RTMPStream::Chunk& O){
len = 0; buf = 0; data = 0; isKeyframe = false; done = true; sofar = 0;
len = 0;
buf = 0;
data = 0;
isKeyframe = false;
done = true;
sofar = 0;
ChunkLoader(O);
}
@ -258,13 +363,17 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){
case DTSC::VIDEO:
len = S.lastData().length() + 16;
if (S.metadata.isMember("video") && S.metadata["video"].isMember("codec")){
if (S.metadata["video"]["codec"].asString() == "H264"){len += 4;}
if (S.metadata["video"]["codec"].asString() == "H264"){
len += 4;
}
}
break;
case DTSC::AUDIO:
len = S.lastData().length() + 16;
if (S.metadata.isMember("audio") && S.metadata["audio"].isMember("codec")){
if (S.metadata["audio"]["codec"].asString() == "AAC"){len += 1;}
if (S.metadata["audio"]["codec"].asString() == "AAC"){
len += 1;
}
}
break;
case DTSC::META:
@ -289,18 +398,32 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){
memcpy(data + 12, S.lastData().c_str(), S.lastData().length());
}else{
memcpy(data + 16, S.lastData().c_str(), S.lastData().length());
if (S.getPacket().isMember("nalu")){data[12] = 1;}else{data[12] = 2;}
if (S.getPacket().isMember("nalu")){
data[12] = 1;
}else{
data[12] = 2;
}
int offset = S.getPacket()["offset"].asInt();
data[13] = (offset >> 16) & 0xFF;
data[14] = (offset >> 8) & 0XFF;
data[15] = offset & 0xFF;
}
data[11] = 0;
if (S.metadata["video"]["codec"].asString() == "H264"){data[11] += 7;}
if (S.metadata["video"]["codec"].asString() == "H263"){data[11] += 2;}
if (S.getPacket().isMember("keyframe")){data[11] += 0x10;}
if (S.getPacket().isMember("interframe")){data[11] += 0x20;}
if (S.getPacket().isMember("disposableframe")){data[11] += 0x30;}
if (S.metadata["video"]["codec"].asString() == "H264"){
data[11] += 7;
}
if (S.metadata["video"]["codec"].asString() == "H263"){
data[11] += 2;
}
if (S.getPacket().isMember("keyframe")){
data[11] += 0x10;
}
if (S.getPacket().isMember("interframe")){
data[11] += 0x20;
}
if (S.getPacket().isMember("disposableframe")){
data[11] += 0x30;
}
break;
case DTSC::AUDIO: {
if ((unsigned int)len == S.lastData().length() + 16){
@ -310,8 +433,12 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){
data[12] = 1; //raw AAC data, not sequence header
}
data[11] = 0;
if (S.metadata["audio"]["codec"].asString() == "AAC"){data[11] += 0xA0;}
if (S.metadata["audio"]["codec"].asString() == "MP3"){data[11] += 0x20;}
if (S.metadata["audio"]["codec"].asString() == "AAC"){
data[11] += 0xA0;
}
if (S.metadata["audio"]["codec"].asString() == "MP3"){
data[11] += 0x20;
}
unsigned int datarate = S.metadata["audio"]["rate"].asInt();
if (datarate >= 44100){
data[11] += 0x0C;
@ -320,22 +447,34 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){
}else if (datarate >= 11025){
data[11] += 0x04;
}
if (S.metadata["audio"]["size"].asInt() == 16){data[11] += 0x02;}
if (S.metadata["audio"]["channels"].asInt() > 1){data[11] += 0x01;}
if (S.metadata["audio"]["size"].asInt() == 16){
data[11] += 0x02;
}
if (S.metadata["audio"]["channels"].asInt() > 1){
data[11] += 0x01;
}
break;
}
case DTSC::META:
memcpy(data + 11, S.lastData().c_str(), S.lastData().length());
break;
default: break;
default:
break;
}
}
setLen();
switch (S.lastType()){
case DTSC::VIDEO: data[0] = 0x09; break;
case DTSC::AUDIO: data[0] = 0x08; break;
case DTSC::META: data[0] = 0x12; break;
default: break;
case DTSC::VIDEO:
data[0] = 0x09;
break;
case DTSC::AUDIO:
data[0] = 0x08;
break;
case DTSC::META:
data[0] = 0x12;
break;
default:
break;
}
data[1] = ((len - 15) >> 16) & 0xFF;
data[2] = ((len - 15) >> 8) & 0xFF;
@ -425,8 +564,12 @@ bool FLV::Tag::DTSCAudioInit(DTSC::Stream & S){
memcpy(data + 13, S.metadata["audio"]["init"].asString().c_str(), len - 17);
data[12] = 0; //AAC sequence header
data[11] = 0;
if (S.metadata["audio"]["codec"].asString() == "AAC"){data[11] += 0xA0;}
if (S.metadata["audio"]["codec"].asString() == "MP3"){data[11] += 0x20;}
if (S.metadata["audio"]["codec"].asString() == "AAC"){
data[11] += 0xA0;
}
if (S.metadata["audio"]["codec"].asString() == "MP3"){
data[11] += 0x20;
}
unsigned int datarate = S.metadata["audio"]["rate"].asInt();
if (datarate >= 44100){
data[11] += 0x0C;
@ -435,8 +578,12 @@ bool FLV::Tag::DTSCAudioInit(DTSC::Stream & S){
}else if (datarate >= 11025){
data[11] += 0x04;
}
if (S.metadata["audio"]["size"].asInt() == 16){data[11] += 0x02;}
if (S.metadata["audio"]["channels"].asInt() > 1){data[11] += 0x01;}
if (S.metadata["audio"]["size"].asInt() == 16){
data[11] += 0x02;
}
if (S.metadata["audio"]["channels"].asInt() > 1){
data[11] += 0x01;
}
}
setLen();
data[0] = 0x08;
@ -536,7 +683,8 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S){
int i = 0;
if (S.metadata.isMember("audio")){
trinfo.addContent(AMF::Object("", AMF::AMF0_OBJECT));
trinfo.getContentP(i)->addContent(AMF::Object("length", ((double)S.metadata["length"].asInt()) * ((double)S.metadata["audio"]["rate"].asInt()), AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent(
AMF::Object("length", ((double)S.metadata["length"].asInt()) * ((double)S.metadata["audio"]["rate"].asInt()), AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent(AMF::Object("timescale", S.metadata["audio"]["rate"].asInt(), AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent(AMF::Object("sampledescription", AMF::AMF0_STRICT_ARRAY));
if (S.metadata["audio"]["codec"].asString() == "AAC"){
@ -549,7 +697,8 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S){
}
if (S.metadata.isMember("video")){
trinfo.addContent(AMF::Object("", AMF::AMF0_OBJECT));
trinfo.getContentP(i)->addContent(AMF::Object("length", ((double)S.metadata["length"].asInt()) * ((double)S.metadata["video"]["fkps"].asInt() / 1000.0), AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent(
AMF::Object("length", ((double)S.metadata["length"].asInt()) * ((double)S.metadata["video"]["fkps"].asInt() / 1000.0), AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent(AMF::Object("timescale", ((double)S.metadata["video"]["fkps"].asInt() / 1000.0), AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent(AMF::Object("sampledescription", AMF::AMF0_STRICT_ARRAY));
if (S.metadata["video"]["codec"].asString() == "H264"){
@ -616,7 +765,6 @@ bool FLV::Tag::ChunkLoader(const RTMPStream::Chunk& O){
return true;
}
/// Helper function for FLV::MemLoader.
/// This function will try to read count bytes from data buffer D into buffer.
/// This function should be called repeatedly until true.
@ -629,17 +777,24 @@ bool FLV::Tag::ChunkLoader(const RTMPStream::Chunk& O){
/// \param P The current position in the data buffer. Will be updated to reflect new position.
/// \return True if count bytes are read succesfully, false otherwise.
bool FLV::Tag::MemReadUntil(char * buffer, unsigned int count, unsigned int & sofar, char * D, unsigned int S, unsigned int & P){
if (sofar >= count){return true;}
if (sofar >= count){
return true;
}
int r = 0;
if (P+(count-sofar) > S){r = S-P;}else{r = count-sofar;}
if (P + (count - sofar) > S){
r = S - P;
}else{
r = count - sofar;
}
memcpy(buffer + sofar, D + P, r);
P += r;
sofar += r;
if (sofar >= count){return true;}
if (sofar >= count){
return true;
}
return false;
} //Tag::MemReadUntil
/// Try to load a tag from a data buffer in memory.
/// This is a stateful function - if fed incorrect data, it will most likely never return true again!
/// While this function returns false, the Tag might not contain valid data.
@ -648,7 +803,10 @@ bool FLV::Tag::MemReadUntil(char * buffer, unsigned int count, unsigned int & so
/// \param P The current position in the data buffer. Will be updated to reflect new position.
/// \return True if a whole tag is succesfully read, false otherwise.
bool FLV::Tag::MemLoader(char * D, unsigned int S, unsigned int & P){
if (buf < 15){data = (char*)realloc(data, 15); buf = 15;}
if (buf < 15){
data = (char*)realloc(data, 15);
buf = 15;
}
if (done){
//read a header
if (MemReadUntil(data, 11, sofar, D, S, P)){
@ -658,14 +816,21 @@ bool FLV::Tag::MemLoader(char * D, unsigned int S, unsigned int & P){
if (FLV::check_header(data)){
sofar = 0;
memcpy(FLV::Header, data, 13);
}else{FLV::Parse_Error = true; Error_Str = "Invalid header received."; return false;}
}else{
FLV::Parse_Error = true;
Error_Str = "Invalid header received.";
return false;
}
}
}else{
//if a tag header, calculate length and read tag body
len = data[3] + 15;
len += (data[2] << 8);
len += (data[1] << 16);
if (buf < len){data = (char*)realloc(data, len); buf = len;}
if (buf < len){
data = (char*)realloc(data, len);
buf = len;
}
if (data[0] > 0x12){
data[0] += 32;
FLV::Parse_Error = true;
@ -681,7 +846,11 @@ bool FLV::Tag::MemLoader(char * D, unsigned int S, unsigned int & P){
//read tag body
if (MemReadUntil(data, len, sofar, D, S, P)){
//calculate keyframeness, next time read header again, return true
if ((data[0] == 0x09) && (((data[11] & 0xf0) >> 4) == 1)){isKeyframe = true;}else{isKeyframe = false;}
if ((data[0] == 0x09) && (((data[11] & 0xf0) >> 4) == 1)){
isKeyframe = true;
}else{
isKeyframe = false;
}
done = true;
sofar = 0;
return true;
@ -690,7 +859,6 @@ bool FLV::Tag::MemLoader(char * D, unsigned int S, unsigned int & P){
return false;
} //Tag::MemLoader
/// Helper function for FLV::FileLoader.
/// This function will try to read count bytes from file f into buffer.
/// This function should be called repeatedly until true.
@ -700,12 +868,20 @@ bool FLV::Tag::MemLoader(char * D, unsigned int S, unsigned int & P){
/// \param f File to read from.
/// \return True if count bytes are read succesfully, false otherwise.
bool FLV::Tag::FileReadUntil(char * buffer, unsigned int count, unsigned int & sofar, FILE * f){
if (sofar >= count){return true;}
if (sofar >= count){
return true;
}
int r = 0;
r = fread(buffer + sofar, 1, count - sofar, f);
if (r < 0){FLV::Parse_Error = true; Error_Str = "File reading error."; return false;}
if (r < 0){
FLV::Parse_Error = true;
Error_Str = "File reading error.";
return false;
}
sofar += r;
if (sofar >= count){return true;}
if (sofar >= count){
return true;
}
return false;
}
@ -718,7 +894,10 @@ bool FLV::Tag::FileLoader(FILE * f){
int preflags = fcntl(fileno(f), F_GETFL, 0);
int postflags = preflags | O_NONBLOCK;
fcntl(fileno(f), F_SETFL, postflags);
if (buf < 15){data = (char*)realloc(data, 15); buf = 15;}
if (buf < 15){
data = (char*)realloc(data, 15);
buf = 15;
}
if (done){
//read a header
@ -729,14 +908,21 @@ bool FLV::Tag::FileLoader(FILE * f){
if (FLV::check_header(data)){
sofar = 0;
memcpy(FLV::Header, data, 13);
}else{FLV::Parse_Error = true; Error_Str = "Invalid header received."; return false;}
}else{
FLV::Parse_Error = true;
Error_Str = "Invalid header received.";
return false;
}
}
}else{
//if a tag header, calculate length and read tag body
len = data[3] + 15;
len += (data[2] << 8);
len += (data[1] << 16);
if (buf < len){data = (char*)realloc(data, len); buf = len;}
if (buf < len){
data = (char*)realloc(data, len);
buf = len;
}
if (data[0] > 0x12){
data[0] += 32;
FLV::Parse_Error = true;
@ -752,7 +938,11 @@ bool FLV::Tag::FileLoader(FILE * f){
//read tag body
if (FileReadUntil(data, len, sofar, f)){
//calculate keyframeness, next time read header again, return true
if ((data[0] == 0x09) && (((data[11] & 0xf0) >> 4) == 1)){isKeyframe = true;}else{isKeyframe = false;}
if ((data[0] == 0x09) && (((data[11] & 0xf0) >> 4) == 1)){
isKeyframe = true;
}else{
isKeyframe = false;
}
done = true;
sofar = 0;
fcntl(fileno(f), F_SETFL, preflags);
@ -772,17 +962,31 @@ JSON::Value FLV::Tag::toJSON(JSON::Value & metadata){
AMF::Object * tmp = meta_in.getContentP(1);
if (tmp->getContentP("videocodecid")){
switch ((unsigned int)tmp->getContentP("videocodecid")->NumValue()){
case 2: metadata["video"]["codec"] = "H263"; break;
case 4: metadata["video"]["codec"] = "VP6"; break;
case 7: metadata["video"]["codec"] = "H264"; break;
default: metadata["video"]["codec"] = "?"; break;
case 2:
metadata["video"]["codec"] = "H263";
break;
case 4:
metadata["video"]["codec"] = "VP6";
break;
case 7:
metadata["video"]["codec"] = "H264";
break;
default:
metadata["video"]["codec"] = "?";
break;
}
}
if (tmp->getContentP("audiocodecid")){
switch ((unsigned int)tmp->getContentP("audiocodecid")->NumValue()){
case 2: metadata["audio"]["codec"] = "MP3"; break;
case 10: metadata["audio"]["codec"] = "AAC"; break;
default: metadata["audio"]["codec"] = "?"; break;
case 2:
metadata["audio"]["codec"] = "MP3";
break;
case 10:
metadata["audio"]["codec"] = "AAC";
break;
default:
metadata["audio"]["codec"] = "?";
break;
}
}
if (tmp->getContentP("width")){
@ -814,14 +1018,28 @@ JSON::Value FLV::Tag::toJSON(JSON::Value & metadata){
}
}
}
if (!metadata.isMember("length")){metadata["length"] = 0;}
if ( !metadata.isMember("length")){
metadata["length"] = 0;
}
if (metadata.isMember("video")){
if (!metadata["video"].isMember("width")){metadata["video"]["width"] = 0;}
if (!metadata["video"].isMember("height")){metadata["video"]["height"] = 0;}
if (!metadata["video"].isMember("fpks")){metadata["video"]["fpks"] = 0;}
if (!metadata["video"].isMember("bps")){metadata["video"]["bps"] = 0;}
if (!metadata["video"].isMember("keyms")){metadata["video"]["keyms"] = 0;}
if (!metadata["video"].isMember("keyvar")){metadata["video"]["keyvar"] = 0;}
if ( !metadata["video"].isMember("width")){
metadata["video"]["width"] = 0;
}
if ( !metadata["video"].isMember("height")){
metadata["video"]["height"] = 0;
}
if ( !metadata["video"].isMember("fpks")){
metadata["video"]["fpks"] = 0;
}
if ( !metadata["video"].isMember("bps")){
metadata["video"]["bps"] = 0;
}
if ( !metadata["video"].isMember("keyms")){
metadata["video"]["keyms"] = 0;
}
if ( !metadata["video"].isMember("keyvar")){
metadata["video"]["keyvar"] = 0;
}
}
return pack_out; //empty
}
@ -839,35 +1057,59 @@ JSON::Value FLV::Tag::toJSON(JSON::Value & metadata){
pack_out["time"] = tagTime();
if ( !metadata["audio"].isMember("codec") || metadata["audio"]["size"].asString() == ""){
switch (audiodata & 0xF0){
case 0x20: metadata["audio"]["codec"] = "MP3"; break;
case 0xA0: metadata["audio"]["codec"] = "AAC"; break;
case 0x20:
metadata["audio"]["codec"] = "MP3";
break;
case 0xA0:
metadata["audio"]["codec"] = "AAC";
break;
}
}
if ( !metadata["audio"].isMember("rate") || metadata["audio"]["rate"].asInt() < 1){
switch (audiodata & 0x0C){
case 0x0: metadata["audio"]["rate"] = 5512; break;
case 0x4: metadata["audio"]["rate"] = 11025; break;
case 0x8: metadata["audio"]["rate"] = 22050; break;
case 0xC: metadata["audio"]["rate"] = 44100; break;
case 0x0:
metadata["audio"]["rate"] = 5512;
break;
case 0x4:
metadata["audio"]["rate"] = 11025;
break;
case 0x8:
metadata["audio"]["rate"] = 22050;
break;
case 0xC:
metadata["audio"]["rate"] = 44100;
break;
}
}
if ( !metadata["audio"].isMember("size") || metadata["audio"]["size"].asInt() < 1){
switch (audiodata & 0x02){
case 0x0: metadata["audio"]["size"] = 8; break;
case 0x2: metadata["audio"]["size"] = 16; break;
case 0x0:
metadata["audio"]["size"] = 8;
break;
case 0x2:
metadata["audio"]["size"] = 16;
break;
}
}
if ( !metadata["audio"].isMember("channels") || metadata["audio"]["channels"].asInt() < 1){
switch (audiodata & 0x01){
case 0x0: metadata["audio"]["channels"] = 1; break;
case 0x1: metadata["audio"]["channels"] = 2; break;
case 0x0:
metadata["audio"]["channels"] = 1;
break;
case 0x1:
metadata["audio"]["channels"] = 2;
break;
}
}
if ((audiodata & 0xF0) == 0xA0){
if (len < 18){return JSON::Value();}
if (len < 18){
return JSON::Value();
}
pack_out["data"] = std::string((char*)data + 13, (size_t)len - 17);
}else{
if (len < 17){return JSON::Value();}
if (len < 17){
return JSON::Value();
}
pack_out["data"] = std::string((char*)data + 12, (size_t)len - 16);
}
return pack_out;
@ -876,42 +1118,70 @@ JSON::Value FLV::Tag::toJSON(JSON::Value & metadata){
char videodata = data[11];
if (needsInitData() && isInitData()){
if ((videodata & 0x0F) == 7){
if (len < 21){return JSON::Value();}
if (len < 21){
return JSON::Value();
}
metadata["video"]["init"] = std::string((char*)data + 16, (size_t)len - 20);
}else{
if (len < 17){return JSON::Value();}
if (len < 17){
return JSON::Value();
}
metadata["video"]["init"] = std::string((char*)data + 12, (size_t)len - 16);
}
return pack_out; //skip rest of parsing, get next tag.
}
if ( !metadata["video"].isMember("codec") || metadata["video"]["codec"].asString() == ""){
switch (videodata & 0x0F){
case 2: metadata["video"]["codec"] = "H263"; break;
case 4: metadata["video"]["codec"] = "VP6"; break;
case 7: metadata["video"]["codec"] = "H264"; break;
case 2:
metadata["video"]["codec"] = "H263";
break;
case 4:
metadata["video"]["codec"] = "VP6";
break;
case 7:
metadata["video"]["codec"] = "H264";
break;
}
}
pack_out["datatype"] = "video";
switch (videodata & 0xF0){
case 0x10: pack_out["keyframe"] = 1; break;
case 0x20: pack_out["interframe"] = 1; break;
case 0x30: pack_out["disposableframe"] = 1; break;
case 0x40: pack_out["keyframe"] = 1; break;
case 0x50: return JSON::Value(); break;//the video info byte we just throw away - useless to us...
case 0x10:
pack_out["keyframe"] = 1;
break;
case 0x20:
pack_out["interframe"] = 1;
break;
case 0x30:
pack_out["disposableframe"] = 1;
break;
case 0x40:
pack_out["keyframe"] = 1;
break;
case 0x50:
return JSON::Value();
break; //the video info byte we just throw away - useless to us...
}
pack_out["time"] = tagTime();
if ((videodata & 0x0F) == 7){
switch (data[12]){
case 1: pack_out["nalu"] = 1; break;
case 2: pack_out["nalu_end"] = 1; break;
case 1:
pack_out["nalu"] = 1;
break;
case 2:
pack_out["nalu_end"] = 1;
break;
}
int offset = (data[13] << 16) + (data[14] << 8) + data[15];
offset = (offset << 8) >> 8;
pack_out["offset"] = offset;
if (len < 21){return JSON::Value();}
if (len < 21){
return JSON::Value();
}
pack_out["data"] = std::string((char*)data + 16, (size_t)len - 20);
}else{
if (len < 17){return JSON::Value();}
if (len < 17){
return JSON::Value();
}
pack_out["data"] = std::string((char*)data + 12, (size_t)len - 16);
}
return pack_out;

View file

@ -7,10 +7,11 @@
#include "json.h"
#include <string>
//forward declaration of RTMPStream::Chunk to avoid circular dependencies.
namespace RTMPStream {
class Chunk;
};
}
/// This namespace holds all FLV-parsing related functionality.
namespace FLV {
@ -59,6 +60,7 @@ namespace FLV {
void Meta_Put(JSON::Value & meta, std::string cat, std::string elem, std::string val);
void Meta_Put(JSON::Value & meta, std::string cat, std::string elem, uint64_t val);
bool Meta_Has(JSON::Value & meta, std::string cat, std::string elem);
};//Tag
};
//Tag
};//FLV namespace
}//FLV namespace

View file

@ -2,6 +2,7 @@
FTP::User::User(Socket::Connection NewConnection, std::map<std::string, std::string> Credentials){
Conn = NewConnection;
MyPassivePort = 0;
USER = "";
PASS = "";
MODE = MODE_STREAM;
@ -35,32 +36,98 @@ FTP::User::User( Socket::Connection NewConnection, std::map<std::string,std::str
}
}
FTP::User::~User( ) { }
FTP::User::~User(){
}
int FTP::User::ParseCommand(std::string Command){
Commands ThisCmd = CMD_NOCMD;
if( Command.substr(0,4) == "NOOP" ) { ThisCmd = CMD_NOOP; Command.erase(0,5); }
if( Command.substr(0,4) == "USER" ) { ThisCmd = CMD_USER; Command.erase(0,5); }
if( Command.substr(0,4) == "PASS" ) { ThisCmd = CMD_PASS; Command.erase(0,5); }
if( Command.substr(0,4) == "QUIT" ) { ThisCmd = CMD_QUIT; Command.erase(0,5); }
if( Command.substr(0,4) == "PORT" ) { ThisCmd = CMD_PORT; Command.erase(0,5); }
if( Command.substr(0,4) == "RETR" ) { ThisCmd = CMD_RETR; Command.erase(0,5); }
if( Command.substr(0,4) == "STOR" ) { ThisCmd = CMD_STOR; Command.erase(0,5); }
if( Command.substr(0,4) == "TYPE" ) { ThisCmd = CMD_TYPE; Command.erase(0,5); }
if( Command.substr(0,4) == "MODE" ) { ThisCmd = CMD_MODE; Command.erase(0,5); }
if( Command.substr(0,4) == "STRU" ) { ThisCmd = CMD_STRU; Command.erase(0,5); }
if( Command.substr(0,4) == "EPSV" ) { ThisCmd = CMD_EPSV; Command.erase(0,5); }
if( Command.substr(0,4) == "PASV" ) { ThisCmd = CMD_PASV; Command.erase(0,5); }
if( Command.substr(0,4) == "LIST" ) { ThisCmd = CMD_LIST; Command.erase(0,5); }
if( Command.substr(0,4) == "CDUP" ) { ThisCmd = CMD_CDUP; Command.erase(0,5); }
if( Command.substr(0,4) == "DELE" ) { ThisCmd = CMD_DELE; Command.erase(0,5); }
if( Command.substr(0,4) == "RNFR" ) { ThisCmd = CMD_RNFR; Command.erase(0,5); }
if( Command.substr(0,4) == "RNTO" ) { ThisCmd = CMD_RNTO; Command.erase(0,5); }
if( Command.substr(0,3) == "PWD" ) { ThisCmd = CMD_PWD; Command.erase(0,4); }
if( Command.substr(0,3) == "CWD" ) { ThisCmd = CMD_CWD; Command.erase(0,4); }
if( Command.substr(0,3) == "RMD" ) { ThisCmd = CMD_RMD; Command.erase(0,4); }
if( Command.substr(0,3) == "MKD" ) { ThisCmd = CMD_MKD; Command.erase(0,4); }
if( ThisCmd != CMD_RNTO ) { RNFR = ""; }
if (Command.substr(0, 4) == "NOOP"){
ThisCmd = CMD_NOOP;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "USER"){
ThisCmd = CMD_USER;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "PASS"){
ThisCmd = CMD_PASS;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "QUIT"){
ThisCmd = CMD_QUIT;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "PORT"){
ThisCmd = CMD_PORT;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "RETR"){
ThisCmd = CMD_RETR;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "STOR"){
ThisCmd = CMD_STOR;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "TYPE"){
ThisCmd = CMD_TYPE;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "MODE"){
ThisCmd = CMD_MODE;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "STRU"){
ThisCmd = CMD_STRU;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "EPSV"){
ThisCmd = CMD_EPSV;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "PASV"){
ThisCmd = CMD_PASV;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "LIST"){
ThisCmd = CMD_LIST;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "CDUP"){
ThisCmd = CMD_CDUP;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "DELE"){
ThisCmd = CMD_DELE;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "RNFR"){
ThisCmd = CMD_RNFR;
Command.erase(0, 5);
}
if (Command.substr(0, 4) == "RNTO"){
ThisCmd = CMD_RNTO;
Command.erase(0, 5);
}
if (Command.substr(0, 3) == "PWD"){
ThisCmd = CMD_PWD;
Command.erase(0, 4);
}
if (Command.substr(0, 3) == "CWD"){
ThisCmd = CMD_CWD;
Command.erase(0, 4);
}
if (Command.substr(0, 3) == "RMD"){
ThisCmd = CMD_RMD;
Command.erase(0, 4);
}
if (Command.substr(0, 3) == "MKD"){
ThisCmd = CMD_MKD;
Command.erase(0, 4);
}
if (ThisCmd != CMD_RNTO){
RNFR = "";
}
switch (ThisCmd){
case CMD_NOOP: {
return 200; //Command okay.
@ -69,14 +136,20 @@ int FTP::User::ParseCommand( std::string Command ) {
case CMD_USER: {
USER = "";
PASS = "";
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if (Command == ""){
return 501;
} //Syntax error in parameters or arguments.
USER = Command;
return 331; //User name okay, need password.
break;
}
case CMD_PASS: {
if( USER == "" ) { return 503; }//Bad sequence of commands
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if (USER == ""){
return 503;
} //Bad sequence of commands
if (Command == ""){
return 501;
} //Syntax error in parameters or arguments.
PASS = Command;
if ( !LoggedIn()){
USER = "";
@ -109,14 +182,20 @@ int FTP::User::ParseCommand( std::string Command ) {
break;
}
case CMD_PORT: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if ( !LoggedIn()){
return 530;
} //Not logged in.
if (Command == ""){
return 501;
} //Syntax error in parameters or arguments.
PORT = atoi(Command.c_str());
return 200; //Command okay.
break;
}
case CMD_EPSV: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if ( !LoggedIn()){
return 530;
} //Not logged in.
MyPassivePort = (rand() % 9999);
std::cout << ":" << MyPassivePort << "\n";
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
@ -124,7 +203,9 @@ int FTP::User::ParseCommand( std::string Command ) {
break;
}
case CMD_PASV: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if ( !LoggedIn()){
return 530;
} //Not logged in.
MyPassivePort = (rand() % 9999) + 49152;
std::cout << ":" << MyPassivePort << "\n";
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
@ -132,9 +213,15 @@ int FTP::User::ParseCommand( std::string Command ) {
break;
}
case CMD_RETR: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( !MyDir.HasPermission( Filesystem::P_RETR ) ) { return 550; }//Access denied.
if ( !LoggedIn()){
return 530;
} //Not logged in.
if (Command == ""){
return 501;
} //Syntax error in parameters or arguments.
if ( !MyDir.HasPermission(Filesystem::P_RETR)){
return 550;
} //Access denied.
std::cout << "Listening on :" << MyPassivePort << "\n";
Socket::Connection Connected = Passive.accept();
if (Connected.connected()){
@ -153,9 +240,15 @@ int FTP::User::ParseCommand( std::string Command ) {
break;
}
case CMD_STOR: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( !MyDir.HasPermission( Filesystem::P_STOR ) ) { return 550; }//Access denied.
if ( !LoggedIn()){
return 530;
} //Not logged in.
if (Command == ""){
return 501;
} //Syntax error in parameters or arguments.
if ( !MyDir.HasPermission(Filesystem::P_STOR)){
return 550;
} //Access denied.
std::cout << "Listening on :" << MyPassivePort << "\n";
Socket::Connection Connected = Passive.accept();
if (Connected.connected()){
@ -168,7 +261,8 @@ int FTP::User::ParseCommand( std::string Command ) {
}
fprintf(stderr, "Reading STOR information\n");
std::string Buffer;
while( Connected.spool() ) { }
while (Connected.spool()){
}
/// \todo Comment me back in. ^_^
//Buffer = Connected.Received();
MyDir.STOR(Command, Buffer);
@ -176,22 +270,36 @@ int FTP::User::ParseCommand( std::string Command ) {
break;
}
case CMD_TYPE: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( Command.size() != 1 && Command.size() != 3 ) { return 501; }//Syntax error in parameters or arguments.
if ( !LoggedIn()){
return 530;
} //Not logged in.
if (Command == ""){
return 501;
} //Syntax error in parameters or arguments.
if (Command.size() != 1 && Command.size() != 3){
return 501;
} //Syntax error in parameters or arguments.
switch (Command[0]){
case 'A': {
if (Command.size() > 1){
if( Command[1] != ' ' ) { return 501; }//Syntax error in parameters or arguments.
if( Command[2] != 'N' ) { return 504; }//Command not implemented for that parameter.
if (Command[1] != ' '){
return 501;
} //Syntax error in parameters or arguments.
if (Command[2] != 'N'){
return 504;
} //Command not implemented for that parameter.
}
TYPE = TYPE_ASCII_NONPRINT;
break;
}
case 'I': {
if (Command.size() > 1){
if( Command[1] != ' ' ) { return 501; }//Syntax error in parameters or arguments.
if( Command[2] != 'N' ) { return 504; }//Command not implemented for that parameter.
if (Command[1] != ' '){
return 501;
} //Syntax error in parameters or arguments.
if (Command[2] != 'N'){
return 504;
} //Command not implemented for that parameter.
}
TYPE = TYPE_IMAGE_NONPRINT;
break;
@ -205,18 +313,32 @@ int FTP::User::ParseCommand( std::string Command ) {
break;
}
case CMD_MODE: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( Command.size() != 1 ) { return 501; }//Syntax error in parameters or arguments.
if( Command[0] != 'S' ) { return 504; }//Command not implemented for that parameter.
if ( !LoggedIn()){
return 530;
} //Not logged in.
if (Command == ""){
return 501;
} //Syntax error in parameters or arguments.
if (Command.size() != 1){
return 501;
} //Syntax error in parameters or arguments.
if (Command[0] != 'S'){
return 504;
} //Command not implemented for that parameter.
MODE = MODE_STREAM;
return 200; //Command okay.
break;
}
case CMD_STRU: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( Command.size() != 1 ) { return 501; }//Syntax error in parameters or arguments.
if ( !LoggedIn()){
return 530;
} //Not logged in.
if (Command == ""){
return 501;
} //Syntax error in parameters or arguments.
if (Command.size() != 1){
return 501;
} //Syntax error in parameters or arguments.
switch (Command[0]){
case 'F': {
STRU = STRU_FILE;
@ -235,13 +357,19 @@ int FTP::User::ParseCommand( std::string Command ) {
break;
}
case CMD_PWD: {
if( !LoggedIn( ) ) { return 550; }//Not logged in.
if( Command != "" ) { return 501; }//Syntax error in parameters or arguments.
if ( !LoggedIn()){
return 550;
} //Not logged in.
if (Command != ""){
return 501;
} //Syntax error in parameters or arguments.
return 2570; //257 -- 0 to indicate PWD over MKD
break;
}
case CMD_CWD: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if ( !LoggedIn()){
return 530;
} //Not logged in.
Filesystem::Directory TmpDir = MyDir;
if (TmpDir.CWD(Command)){
if (TmpDir.IsDir()){
@ -253,8 +381,12 @@ int FTP::User::ParseCommand( std::string Command ) {
break;
}
case CMD_CDUP: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command != "" ) { return 501; }//Syntax error in parameters or arguments.
if ( !LoggedIn()){
return 530;
} //Not logged in.
if (Command != ""){
return 501;
} //Syntax error in parameters or arguments.
Filesystem::Directory TmpDir = MyDir;
if (TmpDir.CDUP()){
if (TmpDir.IsDir()){
@ -266,39 +398,73 @@ int FTP::User::ParseCommand( std::string Command ) {
break;
}
case CMD_DELE: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( !MyDir.DELE( Command ) ) { return 550; }
if ( !LoggedIn()){
return 530;
} //Not logged in.
if (Command == ""){
return 501;
} //Syntax error in parameters or arguments.
if ( !MyDir.DELE(Command)){
return 550;
}
return 250;
break;
}
case CMD_RMD: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( !MyDir.HasPermission( Filesystem::P_RMD ) ) { return 550; }
if( !MyDir.DELE( Command ) ) { return 550; }
if ( !LoggedIn()){
return 530;
} //Not logged in.
if (Command == ""){
return 501;
} //Syntax error in parameters or arguments.
if ( !MyDir.HasPermission(Filesystem::P_RMD)){
return 550;
}
if ( !MyDir.DELE(Command)){
return 550;
}
return 250;
break;
}
case CMD_MKD: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( !MyDir.HasPermission( Filesystem::P_MKD ) ) { return 550; }
if( !MyDir.MKD( Command ) ) { return 550; }
if ( !LoggedIn()){
return 530;
} //Not logged in.
if (Command == ""){
return 501;
} //Syntax error in parameters or arguments.
if ( !MyDir.HasPermission(Filesystem::P_MKD)){
return 550;
}
if ( !MyDir.MKD(Command)){
return 550;
}
return 2571;
break;
}
case CMD_RNFR: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if ( !LoggedIn()){
return 530;
} //Not logged in.
if (Command == ""){
return 501;
} //Syntax error in parameters or arguments.
RNFR = Command;
return 350; //Awaiting further information
}
case CMD_RNTO: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( RNFR == "" ) { return 503; } //Bad sequence of commands
if( !MyDir.Rename( RNFR, Command ) ) { return 550; }
if ( !LoggedIn()){
return 530;
} //Not logged in.
if (Command == ""){
return 501;
} //Syntax error in parameters or arguments.
if (RNFR == ""){
return 503;
} //Bad sequence of commands
if ( !MyDir.Rename(RNFR, Command)){
return 550;
}
return 250;
}
default: {
@ -309,7 +475,9 @@ int FTP::User::ParseCommand( std::string Command ) {
}
bool FTP::User::LoggedIn(){
if( USER == "" || PASS == "" ) { return false; }
if (USER == "" || PASS == ""){
return false;
}
if ( !AllCredentials.size()){
return true;
}

View file

@ -16,17 +16,18 @@ namespace FTP {
enum Mode{
MODE_STREAM,
};//FTP::Mode enumeration
};
//FTP::Mode enumeration
enum Structure{
STRU_FILE,
STRU_RECORD,
};//FTP::Structure enumeration
STRU_FILE, STRU_RECORD,
};
//FTP::Structure enumeration
enum Type{
TYPE_ASCII_NONPRINT,
TYPE_IMAGE_NONPRINT,
};//FTP::Type enumeration
TYPE_ASCII_NONPRINT, TYPE_IMAGE_NONPRINT,
};
//FTP::Type enumeration
enum Commands{
CMD_NOCMD,
@ -51,7 +52,8 @@ namespace FTP {
CMD_MKD,
CMD_RNFR,
CMD_RNTO,
};//FTP::Commands enumeration
};
//FTP::Commands enumeration
class User{
public:
@ -74,6 +76,7 @@ namespace FTP {
Filesystem::Directory MyDir;
std::string RNFR;
std::vector<std::string> ActiveStreams;
};//FTP::User class
};
//FTP::User class
};//FTP Namespace
}//FTP Namespace

View file

@ -5,7 +5,9 @@
/// This constructor creates an empty HTTP::Parser, ready for use for either reading or writing.
/// All this constructor does is call HTTP::Parser::Clean().
HTTP::Parser::Parser(){Clean();}
HTTP::Parser::Parser(){
Clean();
}
/// Completely re-initializes the HTTP::Parser, leaving it ready for either reading or writing usage.
void HTTP::Parser::Clean(){
@ -27,7 +29,9 @@ void HTTP::Parser::Clean(){
std::string & HTTP::Parser::BuildRequest(){
/// \todo Include GET/POST variable parsing?
std::map<std::string, std::string>::iterator it;
if (protocol.size() < 5 || protocol.substr(0, 4) != "HTTP"){protocol = "HTTP/1.0";}
if (protocol.size() < 5 || protocol.substr(0, 4) != "HTTP"){
protocol = "HTTP/1.0";
}
builder = method + " " + url + " " + protocol + "\r\n";
for (it = headers.begin(); it != headers.end(); it++){
if (( *it).first != "" && ( *it).second != ""){
@ -47,7 +51,9 @@ std::string & HTTP::Parser::BuildRequest(){
std::string & HTTP::Parser::BuildResponse(std::string code, std::string message){
/// \todo Include GET/POST variable parsing?
std::map<std::string, std::string>::iterator it;
if (protocol.size() < 5 || protocol.substr(0, 4) != "HTTP"){protocol = "HTTP/1.0";}
if (protocol.size() < 5 || protocol.substr(0, 4) != "HTTP"){
protocol = "HTTP/1.0";
}
builder = protocol + " " + code + " " + message + "\r\n";
for (it = headers.begin(); it != headers.end(); it++){
if (( *it).first != "" && ( *it).second != ""){
@ -67,7 +73,11 @@ std::string & HTTP::Parser::BuildResponse(std::string code, std::string message)
void HTTP::Parser::Trim(std::string & s){
size_t startpos = s.find_first_not_of(" \t");
size_t endpos = s.find_last_not_of(" \t");
if ((std::string::npos == startpos) || (std::string::npos == endpos)){s = "";}else{s = s.substr(startpos, endpos-startpos+1);}
if ((std::string::npos == startpos) || (std::string::npos == endpos)){
s = "";
}else{
s = s.substr(startpos, endpos - startpos + 1);
}
}
/// Function that sets the body of a response or request, along with the correct Content-Length header.
@ -96,9 +106,13 @@ std::string HTTP::Parser::getUrl(){
}
/// Returns header i, if set.
std::string HTTP::Parser::GetHeader(std::string i){return headers[i];}
std::string HTTP::Parser::GetHeader(std::string i){
return headers[i];
}
/// Returns POST variable i, if set.
std::string HTTP::Parser::GetVar(std::string i){return vars[i];}
std::string HTTP::Parser::GetVar(std::string i){
return vars[i];
}
/// Sets header i to string value v.
void HTTP::Parser::SetHeader(std::string i, std::string v){
@ -153,28 +167,38 @@ bool HTTP::Parser::parse(std::string & HTTPbuffer){
}else{
HTTPbuffer.erase(0, f + 1);
}
while (tmpA.find('\r') != std::string::npos){tmpA.erase(tmpA.find('\r'));}
while (tmpA.find('\r') != std::string::npos){
tmpA.erase(tmpA.find('\r'));
}
if ( !seenReq){
seenReq = true;
f = tmpA.find(' ');
if (f != std::string::npos){
method = tmpA.substr(0, f); tmpA.erase(0, f+1);
method = tmpA.substr(0, f);
tmpA.erase(0, f + 1);
f = tmpA.find(' ');
if (f != std::string::npos){
url = tmpA.substr(0, f); tmpA.erase(0, f+1);
url = tmpA.substr(0, f);
tmpA.erase(0, f + 1);
protocol = tmpA;
if (url.find('?') != std::string::npos){
parseVars(url.substr(url.find('?') + 1)); //parse GET variables
}
}else{seenReq = false;}
}else{seenReq = false;}
}else{
seenReq = false;
}
}else{
seenReq = false;
}
}else{
if (tmpA.size() == 0){
seenHeaders = true;
body.clear();
if (GetHeader("Content-Length") != ""){
length = atoi(GetHeader("Content-Length").c_str());
if (body.capacity() < length){body.reserve(length);}
if (body.capacity() < length){
body.reserve(length);
}
}
}else{
f = tmpA.find(':');
@ -267,7 +291,11 @@ std::string HTTP::Parser::urlunescape(const std::string & in){
}
out += tmp;
}else{
if (in[i] == '+'){out += ' ';}else{out += in[i];}
if (in[i] == '+'){
out += ' ';
}else{
out += in[i];
}
}
}
return out;
@ -284,7 +312,8 @@ std::string HTTP::Parser::urlencode(const std::string &c){
std::string escaped = "";
int max = c.length();
for (int i = 0; i < max; i++){
if (('0'<=c[i] && c[i]<='9') || ('a'<=c[i] && c[i]<='z') || ('A'<=c[i] && c[i]<='Z') || (c[i]=='~' || c[i]=='!' || c[i]=='*' || c[i]=='(' || c[i]==')' || c[i]=='\'')){
if (('0' <= c[i] && c[i] <= '9') || ('a' <= c[i] && c[i] <= 'z') || ('A' <= c[i] && c[i] <= 'Z')
|| (c[i] == '~' || c[i] == '!' || c[i] == '*' || c[i] == '(' || c[i] == ')' || c[i] == '\'')){
escaped.append( &c[i], 1);
}else{
escaped.append("%");

View file

@ -45,5 +45,7 @@ namespace HTTP{
void Trim(std::string & s);
static int unhex(char c);
static std::string hex(char dec);
};//HTTP::Parser class
};//HTTP namespace
};
//HTTP::Parser class
}//HTTP namespace

View file

@ -7,7 +7,6 @@
#include <stdint.h> //for uint64_t
#include <string.h> //for memcpy
#include <arpa/inet.h> //for htonl
int JSON::Value::c2hex(int c){
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
@ -15,7 +14,6 @@ int JSON::Value::c2hex(int c){
return 0;
}
std::string JSON::Value::read_string(int separator, std::istream & fromstream){
std::string out;
bool escaped = false;
@ -27,17 +25,28 @@ std::string JSON::Value::read_string(int separator, std::istream & fromstream){
}
if (escaped){
switch (c){
case 'b': out += '\b'; break;
case 'f': out += '\f'; break;
case 'n': out += '\n'; break;
case 'r': out += '\r'; break;
case 't': out += '\t'; break;
case 'b':
out += '\b';
break;
case 'f':
out += '\f';
break;
case 'n':
out += '\n';
break;
case 'r':
out += '\r';
break;
case 't':
out += '\t';
break;
case 'u': {
int d1 = fromstream.get();
int d2 = fromstream.get();
int d3 = fromstream.get();
int d4 = fromstream.get();
c = c2hex(d4) + (c2hex(d3) << 4) + (c2hex(d2) << 8) + (c2hex(d1) << 16);
break;
}
default:
out += (char)c;
@ -58,14 +67,30 @@ std::string JSON::Value::string_escape(std::string val){
std::string out = "\"";
for (unsigned int i = 0; i < val.size(); ++i){
switch (val[i]){
case '"': out += "\\\""; break;
case '\\': out += "\\\\"; break;
case '\n': out += "\\n"; break;
case '\b': out += "\\b"; break;
case '\f': out += "\\f"; break;
case '\r': out += "\\r"; break;
case '\t': out += "\\t"; break;
default: out += val[i];
case '"':
out += "\\\"";
break;
case '\\':
out += "\\\\";
break;
case '\n':
out += "\\n";
break;
case '\b':
out += "\\b";
break;
case '\f':
out += "\\f";
break;
case '\r':
out += "\\r";
break;
case '\t':
out += "\\t";
break;
default:
out += val[i];
break;
}
}
out += "\"";
@ -76,9 +101,15 @@ std::string JSON::Value::string_escape(std::string val){
void JSON::Value::skipToEnd(std::istream & fromstream){
while (fromstream.good()){
char peek = fromstream.peek();
if (peek == ','){return;}
if (peek == ']'){return;}
if (peek == '}'){return;}
if (peek == ','){
return;
}
if (peek == ']'){
return;
}
if (peek == '}'){
return;
}
peek = fromstream.get();
}
}
@ -146,11 +177,15 @@ JSON::Value::Value(std::istream & fromstream){
}
break;
case '}':
if (reading_object){c = fromstream.get();}
if (reading_object){
c = fromstream.get();
}
return;
break;
case ']':
if (reading_array){c = fromstream.get();}
if (reading_array){
c = fromstream.get();
}
return;
break;
case 't':
@ -185,12 +220,14 @@ JSON::Value::Value(std::istream & fromstream){
JSON::Value::Value(const std::string & val){
myType = STRING;
strVal = val;
intVal = 0;
}
/// Sets this JSON::Value to the given string.
JSON::Value::Value(const char * val){
myType = STRING;
strVal = val;
intVal = 0;
}
/// Sets this JSON::Value to the given integer.
@ -202,14 +239,24 @@ JSON::Value::Value(long long int val){
/// Compares a JSON::Value to another for equality.
bool JSON::Value::operator==(const JSON::Value & rhs) const{
if (myType != rhs.myType) return false;
if (myType == INTEGER || myType == BOOL){return intVal == rhs.intVal;}
if (myType == STRING){return strVal == rhs.strVal;}
if (myType == EMPTY){return true;}
if (myType == INTEGER || myType == BOOL){
return intVal == rhs.intVal;
}
if (myType == STRING){
return strVal == rhs.strVal;
}
if (myType == EMPTY){
return true;
}
if (myType == OBJECT){
if (objVal.size() != rhs.objVal.size()) return false;
for (std::map<std::string, Value>::const_iterator it = objVal.begin(); it != objVal.end(); ++it){
if (!rhs.isMember(it->first)){return false;}
if (it->second != rhs.objVal.find(it->first)->second){return false;}
if ( !rhs.isMember(it->first)){
return false;
}
if (it->second != rhs.objVal.find(it->first)->second){
return false;
}
}
return true;
}
@ -217,7 +264,9 @@ bool JSON::Value::operator==(const JSON::Value & rhs) const{
if (arrVal.size() != rhs.arrVal.size()) return false;
int i = 0;
for (std::deque<Value>::const_iterator it = arrVal.begin(); it != arrVal.end(); ++it){
if (*it != rhs.arrVal[i]){return false;}
if ( *it != rhs.arrVal[i]){
return false;
}
i++;
}
return true;
@ -280,7 +329,6 @@ JSON::Value::operator long long int(){
return 0;
}
/// Automatic conversion to std::string.
/// Returns the raw string value if available, otherwise calls toString().
JSON::Value::operator std::string(){
@ -298,12 +346,24 @@ JSON::Value::operator std::string(){
/// Automatic conversion to bool.
/// Returns true if there is anything meaningful stored into this value.
JSON::Value::operator bool(){
if (myType == STRING){return strVal != "";}
if (myType == INTEGER){return intVal != 0;}
if (myType == BOOL){return intVal != 0;}
if (myType == OBJECT){return size() > 0;}
if (myType == ARRAY){return size() > 0;}
if (myType == EMPTY){return false;}
if (myType == STRING){
return strVal != "";
}
if (myType == INTEGER){
return intVal != 0;
}
if (myType == BOOL){
return intVal != 0;
}
if (myType == OBJECT){
return size() > 0;
}
if (myType == ARRAY){
return size() > 0;
}
if (myType == EMPTY){
return false;
}
return false; //unimplemented? should never happen...
}
@ -320,7 +380,6 @@ const bool JSON::Value::asBool(){
return (bool) *this;
}
/// Retrieves or sets the JSON::Value at this position in the object.
/// Converts destructively to object if not already an object.
JSON::Value & JSON::Value::operator[](const std::string i){
@ -362,10 +421,14 @@ std::string JSON::Value::toPacked(){
if (isInt() || isNull() || isBool()){
r += 0x01;
uint64_t numval = intVal;
r += *(((char*)&numval)+7); r += *(((char*)&numval)+6);
r += *(((char*)&numval)+5); r += *(((char*)&numval)+4);
r += *(((char*)&numval)+3); r += *(((char*)&numval)+2);
r += *(((char*)&numval)+1); r += *(((char*)&numval));
r += *(((char*) &numval) + 7);
r += *(((char*) &numval) + 6);
r += *(((char*) &numval) + 5);
r += *(((char*) &numval) + 4);
r += *(((char*) &numval) + 3);
r += *(((char*) &numval) + 2);
r += *(((char*) &numval) + 1);
r += *(((char*) &numval));
}
if (isString()){
r += 0x02;
@ -385,7 +448,9 @@ std::string JSON::Value::toPacked(){
r += it->second.toPacked();
}
}
r += (char)0x0; r += (char)0x0; r += (char)0xEE;
r += (char)0x0;
r += (char)0x0;
r += (char)0xEE;
strVal.clear();
}
if (isArray()){
@ -393,11 +458,14 @@ std::string JSON::Value::toPacked(){
for (JSON::ArrIter it = arrVal.begin(); it != arrVal.end(); it++){
r += it->toPacked();
}
r += (char)0x0; r += (char)0x0; r += (char)0xEE;
r += (char)0x0;
r += (char)0x0;
r += (char)0xEE;
}
return r;
};//toPacked
}
;
//toPacked
/// Packs any object-type JSON::Value to a std::string for transfer over the network, including proper DTMI header.
/// Non-object-types will print an error to stderr and return an empty string.
@ -429,7 +497,6 @@ std::string & JSON::Value::toNetPacked(){
return strVal;
}
/// Converts this JSON::Value to valid JSON notation and returns it.
/// Makes absolutely no attempts to pretty-print anything. :-)
std::string JSON::Value::toString(){
@ -449,7 +516,9 @@ std::string JSON::Value::toString(){
if (arrVal.size() > 0){
for (ArrIter it = ArrBegin(); it != ArrEnd(); it++){
tmp += it->toString();
if (it + 1 != ArrEnd()){tmp += ",";}
if (it + 1 != ArrEnd()){
tmp += ",";
}
}
}
tmp += "]";
@ -464,7 +533,9 @@ std::string JSON::Value::toString(){
for (ObjIter it2 = ObjBegin(); it2 != ObjEnd(); it2++){
tmp2 += "\"" + it2->first + "\":";
tmp2 += it2->second.toString();
if (it2 != it3){tmp2 += ",";}
if (it2 != it3){
tmp2 += ",";
}
}
}
tmp2 += "}";
@ -502,7 +573,9 @@ std::string JSON::Value::toPrettyString(int indentation){
std::string tmp = "[\n";
for (ArrIter it = ArrBegin(); it != ArrEnd(); it++){
tmp += std::string(indentation + 2, ' ') + it->toPrettyString(indentation + 2);
if (it + 1 != ArrEnd()){tmp += ",\n";}
if (it + 1 != ArrEnd()){
tmp += ",\n";
}
}
tmp += "\n" + std::string(indentation, ' ') + "]";
return tmp;
@ -519,7 +592,9 @@ std::string JSON::Value::toPrettyString(int indentation){
for (ObjIter it2 = ObjBegin(); it2 != ObjEnd(); it2++){
tmp2 += std::string(indentation + 2, ' ') + "\"" + it2->first + "\":";
tmp2 += it2->second.toPrettyString(indentation + 2);
if (it2 != it3){tmp2 += ",\n";}
if (it2 != it3){
tmp2 += ",\n";
}
}
tmp2 += "\n" + std::string(indentation, ' ') + "}";
return tmp2;
@ -563,11 +638,15 @@ void JSON::Value::prepend(const JSON::Value & rhs){
/// given size.
void JSON::Value::shrink(unsigned int size){
if (myType == ARRAY){
while (arrVal.size() > size){arrVal.pop_front();}
while (arrVal.size() > size){
arrVal.pop_front();
}
return;
}
if (myType == OBJECT){
while (objVal.size() > size){objVal.erase(objVal.begin());}
while (objVal.size() > size){
objVal.erase(objVal.begin());
}
return;
}
}
@ -688,13 +767,15 @@ JSON::Value JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigne
i += 9; //skip 8(an uint64_t)+1 forwards
uint64_t * d = (uint64_t*)tmpdbl;
return JSON::Value((long long int) *d);
} break;
}
break;
case 0x02: { //string
unsigned int tmpi = data[i + 1] * 256 * 256 * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 + data[i + 4]; //set tmpi to UTF-8-long length
std::string tmpstr = std::string((const char *)data + i + 5, (size_t)tmpi); //set the string data
i += tmpi + 5; //skip length+size+1 forwards
return JSON::Value(tmpstr);
} break;
}
break;
case 0xFF: //also object
case 0xE0: { //object
++i;
@ -707,7 +788,8 @@ JSON::Value JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigne
}
i += 3; //skip 0x0000EE
return ret;
} break;
}
break;
case 0x0A: { //array
JSON::Value ret;
++i;
@ -716,7 +798,8 @@ JSON::Value JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigne
}
i += 3; //skip 0x0000EE
return ret;
} break;
}
break;
}
#if DEBUG >= 2
fprintf(stderr, "Error: Unimplemented DTMI type %hhx - returning.\n", data[i]);

View file

@ -7,15 +7,20 @@
#include <istream>
//empty definition of DTSC::Stream so it can be a friend.
namespace DTSC{class Stream;}
namespace DTSC {
class Stream;
}
/// JSON-related classes and functions
namespace JSON {
/// Lists all types of JSON::Value.
enum ValueType{ EMPTY, BOOL, INTEGER, STRING, ARRAY, OBJECT };
enum ValueType{
EMPTY, BOOL, INTEGER, STRING, ARRAY, OBJECT
};
class Value;//forward declaration for below typedef
class Value;
//forward declaration for below typedef
typedef std::map<std::string, Value>::iterator ObjIter;
typedef std::deque<Value>::iterator ArrIter;
@ -92,4 +97,4 @@ namespace JSON{
Value fromString(std::string json);
Value fromFile(std::string filename);
};
}

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@ namespace MP4{
Box(char * datapointer = 0, bool manage = true);
~Box();
std::string getType();
bool isType( char* boxType );
bool isType(const char* boxType);
bool read(std::string & newData);
long long int boxedSize();
long long int payloadSize();
@ -52,14 +52,16 @@ namespace MP4{
int data_size; ///< Currently reserved size
bool managed; ///< If false, will not attempt to resize/free the data pointer.
int payloadOffset; ///<The offset of the payload with regards to the data
};//Box Class
};
//Box Class
struct afrt_runtable{
long firstFragment;
long long int firstTimestamp;
long duration;
long discontinuity;
};//fragmentRun
};
//fragmentRun
/// AFRT Box class
class AFRT: public Box{
@ -78,7 +80,8 @@ namespace MP4{
void setFragmentRun(afrt_runtable newRun, long no);
afrt_runtable getFragmentRun(long no);
std::string toPrettyString(int indent = 0);
};//AFRT Box
};
//AFRT Box
struct asrt_runtable{
long firstSegment;
@ -100,7 +103,8 @@ namespace MP4{
void setSegmentRun(long firstSegment, long fragmentsPerSegment, long no);
asrt_runtable getSegmentRun(long no);
std::string toPrettyString(int indent = 0);
};//ASRT Box
};
//ASRT Box
/// ABST Box class
class ABST: public Box{
@ -143,7 +147,8 @@ namespace MP4{
void setFragmentRunTable(AFRT & table, long no);
AFRT & getFragmentRunTable(long no);
std::string toPrettyString(long indent = 0);
};//ABST Box
};
//ABST Box
class MFHD: public Box{
public:
@ -151,7 +156,8 @@ namespace MP4{
void setSequenceNumber(long newSequenceNumber);
long getSequenceNumber();
std::string toPrettyString(int indent = 0);
};//MFHD Box
};
//MFHD Box
class MOOF: public Box{
public:
@ -160,7 +166,8 @@ namespace MP4{
void setContent(Box & newContent, long no);
Box & getContent(long no);
std::string toPrettyString(int indent = 0);
};//MOOF Box
};
//MOOF Box
class TRAF: public Box{
public:
@ -169,7 +176,8 @@ namespace MP4{
void setContent(Box & newContent, long no);
Box & getContent(long no);
std::string toPrettyString(int indent = 0);
};//TRAF Box
};
//TRAF Box
struct trunSampleInformation{
long sampleDuration;
@ -309,4 +317,5 @@ namespace MP4{
void setValue(long newValue, size_t index);
long getValue(size_t index);
};
};
}

View file

@ -25,7 +25,9 @@ bool Util::Procs::handler_set = false;
/// Used internally to capture child signals and update plist.
void Util::Procs::childsig_handler(int signum){
if (signum != SIGCHLD){return;}
if (signum != SIGCHLD){
return;
}
int status;
pid_t ret = waitpid( -1, &status, WNOHANG);
if (ret == 0){ //ignore, would block otherwise
@ -41,7 +43,9 @@ void Util::Procs::childsig_handler(int signum){
exitcode = WEXITSTATUS(status);
}else if (WIFSIGNALED(status)){
exitcode = -WTERMSIG(status);
}else{/* not possible */return;}
}else{/* not possible */
return;
}
#if DEBUG >= 1
std::string pname = plist[ret];
@ -84,7 +88,9 @@ void Util::Procs::runCmd(std::string & cmd){
++i;
args[i] = tmp2;
}
if (i == 20){args[20] = 0;}
if (i == 20){
args[20] = 0;
}
//execute the command
execvp(args[0], args);
#if DEBUG >= 1
@ -98,7 +104,9 @@ void Util::Procs::runCmd(std::string & cmd){
/// \arg name Name for this process - only used internally.
/// \arg cmd Commandline for this process.
pid_t Util::Procs::Start(std::string name, std::string cmd){
if (isActive(name)){return getPid(name);}
if (isActive(name)){
return getPid(name);
}
if ( !handler_set){
struct sigaction new_action;
new_action.sa_handler = Util::Procs::childsig_handler;
@ -132,7 +140,9 @@ pid_t Util::Procs::Start(std::string name, std::string cmd){
/// \arg cmd Commandline for sub (sending) process.
/// \arg cmd2 Commandline for main (receiving) process.
pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
if (isActive(name)){return getPid(name);}
if (isActive(name)){
return getPid(name);
}
if ( !handler_set){
struct sigaction new_action;
new_action.sa_handler = Util::Procs::childsig_handler;
@ -207,7 +217,9 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
/// \arg cmd2 Commandline for sub (middle) process.
/// \arg cmd3 Commandline for main (receiving) process.
pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, std::string cmd3){
if (isActive(name)){return getPid(name);}
if (isActive(name)){
return getPid(name);
}
if ( !handler_set){
struct sigaction new_action;
new_action.sa_handler = Util::Procs::childsig_handler;
@ -329,7 +341,9 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
/// \arg fdout Same as fdin, but for stdout.
/// \arg fdout Same as fdin, but for stderr.
pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int * fdout, int * fderr){
if (isActive(name)){return getPid(name);}
if (isActive(name)){
return getPid(name);
}
pid_t pid;
int pipein[2], pipeout[2], pipeerr[2];
if ( !handler_set){
@ -350,15 +364,24 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int *
#if DEBUG >= 1
std::cerr << "Pipe (out) creation failed for " << name << std::endl;
#endif
if (*fdin == -1){close(pipein[0]);close(pipein[1]);}
if ( *fdin == -1){
close(pipein[0]);
close(pipein[1]);
}
return 0;
}
if (fderr && *fderr == -1 && pipe(pipeerr) < 0){
#if DEBUG >= 1
std::cerr << "Pipe (err) creation failed for " << name << std::endl;
#endif
if (*fdin == -1){close(pipein [0]);close(pipein [1]);}
if (*fdout == -1){close(pipeout[0]);close(pipeout[1]);}
if ( *fdin == -1){
close(pipein[0]);
close(pipein[1]);
}
if ( *fdout == -1){
close(pipeout[0]);
close(pipeout[1]);
}
return 0;
}
int devnull = -1;
@ -368,9 +391,18 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int *
#if DEBUG >= 1
std::cerr << "Could not open /dev/null for " << name << ": " << strerror(errno) << std::endl;
#endif
if (*fdin == -1){close(pipein [0]);close(pipein [1]);}
if (*fdout == -1){close(pipeout[0]);close(pipeout[1]);}
if (*fderr == -1){close(pipeerr[0]);close(pipeerr[1]);}
if ( *fdin == -1){
close(pipein[0]);
close(pipein[1]);
}
if ( *fdout == -1){
close(pipeout[0]);
close(pipeout[1]);
}
if ( *fderr == -1){
close(pipeerr[0]);
close(pipeerr[1]);
}
return 0;
}
}
@ -406,7 +438,9 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int *
dup2( *fderr, STDERR_FILENO);
close( *fderr);
}
if (devnull != -1){close(devnull);}
if (devnull != -1){
close(devnull);
}
execvp(argv[0], argv);
#if DEBUG >= 1
perror("execvp failed");
@ -416,10 +450,21 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int *
#if DEBUG >= 1
std::cerr << "Failed to fork for pipe: " << name << std::endl;
#endif
if (fdin && *fdin == -1){close(pipein [0]);close(pipein [1]);}
if (fdout && *fdout == -1){close(pipeout[0]);close(pipeout[1]);}
if (fderr && *fderr == -1){close(pipeerr[0]);close(pipeerr[1]);}
if (devnull != -1){close(devnull);}
if (fdin && *fdin == -1){
close(pipein[0]);
close(pipein[1]);
}
if (fdout && *fdout == -1){
close(pipeout[0]);
close(pipeout[1]);
}
if (fderr && *fderr == -1){
close(pipeerr[0]);
close(pipeerr[1]);
}
if (devnull != -1){
close(devnull);
}
return 0;
}else{ //parent
#if DEBUG >= 1
@ -430,7 +475,9 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int *
if (devnull != -1) std::cerr << " null=" << devnull;
std::cerr << ", PID " << pid << ": " << argv[0] << std::endl;
#endif
if (devnull != -1){close(devnull);}
if (devnull != -1){
close(devnull);
}
if (fdin && *fdin == -1){
close(pipein[0]); // close unused end end
*fdin = pipein[1];
@ -448,7 +495,6 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int *
return pid;
}
/// Stops the named process, if running.
/// \arg name (Internal) name of process to stop
void Util::Procs::Stop(std::string name){
@ -456,7 +502,9 @@ void Util::Procs::Stop(std::string name){
while (isActive(name)){
Stop(getPid(name));
max--;
if (max <= 0){return;}
if (max <= 0){
return;
}
}
}
@ -485,7 +533,9 @@ int Util::Procs::Count(){
bool Util::Procs::isActive(std::string name){
std::map<pid_t, std::string>::iterator it;
for (it = plist.begin(); it != plist.end(); it++){
if ((*it).second == name){return true;}
if (( *it).second == name){
return true;
}
}
return false;
}
@ -500,7 +550,9 @@ bool Util::Procs::isActive(pid_t name){
pid_t Util::Procs::getPid(std::string name){
std::map<pid_t, std::string>::iterator it;
for (it = plist.begin(); it != plist.end(); it++){
if ((*it).second == name){return (*it).first;}
if (( *it).second == name){
return ( *it).first;
}
}
return 0;
}

View file

@ -35,4 +35,4 @@ namespace Util{
static bool SetTerminationNotifier(pid_t pid, TerminationNotifier notifier);
};
};
}

View file

@ -39,19 +39,17 @@ std::map<unsigned int, RTMPStream::Chunk> RTMPStream::Chunk::lastrecv;
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
uint8_t genuineFMSKey[] = {
0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20,
0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, // Genuine Adobe Flash Media Server 001
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57,
0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae
}; // 68
uint8_t genuineFMSKey[] = {0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20,
0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65, 0x72,
0x76, // Genuine Adobe Flash Media Server 001
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec,
0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 68
uint8_t genuineFPKey[] = {
0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20,
0x50, 0x6c, 0x61, 0x79, // Genuine Adobe Flash Player 001
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57,
0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae
}; // 62
uint8_t genuineFPKey[] = {0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20,
0x50, 0x6c, 0x61,
0x79, // Genuine Adobe Flash Player 001
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec,
0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 62
inline uint32_t GetDigestOffset(uint8_t *pBuffer, uint8_t scheme){
if (scheme == 0){
@ -104,66 +102,119 @@ DHWrapper::~DHWrapper() {
bool DHWrapper::Initialize(){
Cleanup();
_pDH = DH_new();
if (!_pDH){Cleanup(); return false;}
if ( !_pDH){
Cleanup();
return false;
}
_pDH->p = BN_new();
if (!_pDH->p){Cleanup(); return false;}
if ( !_pDH->p){
Cleanup();
return false;
}
_pDH->g = BN_new();
if (!_pDH->g){Cleanup(); return false;}
if (BN_hex2bn(&_pDH->p, P1024) == 0){Cleanup(); return false;}
if (BN_set_word(_pDH->g, 2) != 1){Cleanup(); return false;}
if ( !_pDH->g){
Cleanup();
return false;
}
if (BN_hex2bn( &_pDH->p, P1024) == 0){
Cleanup();
return false;
}
if (BN_set_word(_pDH->g, 2) != 1){
Cleanup();
return false;
}
_pDH->length = _bitsCount;
if (DH_generate_key(_pDH) != 1){Cleanup(); return false;}
if (DH_generate_key(_pDH) != 1){
Cleanup();
return false;
}
return true;
}
bool DHWrapper::CopyPublicKey(uint8_t *pDst, int32_t dstLength){
if (!_pDH){return false;}
if ( !_pDH){
return false;
}
return CopyKey(_pDH->pub_key, pDst, dstLength);
}
bool DHWrapper::CopyPrivateKey(uint8_t *pDst, int32_t dstLength){
if (!_pDH){return false;}
if ( !_pDH){
return false;
}
return CopyKey(_pDH->priv_key, pDst, dstLength);
}
bool DHWrapper::CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length){
if (!_pDH){return false;}
if (_sharedKeyLength != 0 || _pSharedKey){return false;}
if ( !_pDH){
return false;
}
if (_sharedKeyLength != 0 || _pSharedKey){
return false;
}
_sharedKeyLength = DH_size(_pDH);
if (_sharedKeyLength <= 0 || _sharedKeyLength > 1024){return false;}
if (_sharedKeyLength <= 0 || _sharedKeyLength > 1024){
return false;
}
_pSharedKey = new uint8_t[_sharedKeyLength];
_peerPublickey = BN_bin2bn(pPeerPublicKey, length, 0);
if (!_peerPublickey){return false;}
if ( !_peerPublickey){
return false;
}
if (DH_compute_key(_pSharedKey, _peerPublickey, _pDH) != _sharedKeyLength){return false;}
if (DH_compute_key(_pSharedKey, _peerPublickey, _pDH) != _sharedKeyLength){
return false;
}
return true;
}
bool DHWrapper::CopySharedKey(uint8_t *pDst, int32_t dstLength){
if (!_pDH){return false;}
if (dstLength != _sharedKeyLength){return false;}
if ( !_pDH){
return false;
}
if (dstLength != _sharedKeyLength){
return false;
}
memcpy(pDst, _pSharedKey, _sharedKeyLength);
return true;
}
void DHWrapper::Cleanup(){
if (_pDH){
if (_pDH->p){BN_free(_pDH->p); _pDH->p = 0;}
if (_pDH->g){BN_free(_pDH->g); _pDH->g = 0;}
DH_free(_pDH); _pDH = 0;
if (_pDH->p){
BN_free(_pDH->p);
_pDH->p = 0;
}
if (_pDH->g){
BN_free(_pDH->g);
_pDH->g = 0;
}
DH_free(_pDH);
_pDH = 0;
}
if (_pSharedKey){
delete[] _pSharedKey;
_pSharedKey = 0;
}
if (_pSharedKey){delete[] _pSharedKey; _pSharedKey = 0;}
_sharedKeyLength = 0;
if (_peerPublickey){BN_free(_peerPublickey); _peerPublickey = 0;}
if (_peerPublickey){
BN_free(_peerPublickey);
_peerPublickey = 0;
}
}
bool DHWrapper::CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength){
int32_t keySize = BN_num_bytes(pNum);
if ((keySize <= 0) || (dstLength <= 0) || (keySize > dstLength)){return false;}
if (BN_bn2bin(pNum, pDst) != keySize){return false;}
if ((keySize <= 0) || (dstLength <= 0) || (keySize > dstLength)){
return false;
}
if (BN_bn2bin(pNum, pDst) != keySize){
return false;
}
return true;
}
@ -237,7 +288,9 @@ std::string & RTMPStream::Chunk::Pack(){
}
}
//override - we always sent type 0x00 if the timestamp has decreased since last chunk in this channel
if (timestamp < prev.timestamp){chtype = 0x00;}
if (timestamp < prev.timestamp){
chtype = 0x00;
}
}
if (cs_id <= 63){
output += (unsigned char)(chtype | cs_id);
@ -259,7 +312,10 @@ std::string & RTMPStream::Chunk::Pack(){
}else{
tmpi = timestamp - prev.timestamp;
}
if (tmpi >= 0x00ffffff){ntime = tmpi; tmpi = 0x00ffffff;}
if (tmpi >= 0x00ffffff){
ntime = tmpi;
tmpi = 0x00ffffff;
}
output += (unsigned char)((tmpi >> 16) & 0xff);
output += (unsigned char)((tmpi >> 8) & 0xff);
output += (unsigned char)(tmpi & 0xff);
@ -290,7 +346,9 @@ std::string & RTMPStream::Chunk::Pack(){
len_left = 0;
while (len_left < len){
tmpi = len - len_left;
if (tmpi > RTMPStream::chunk_snd_max){tmpi = RTMPStream::chunk_snd_max;}
if (tmpi > RTMPStream::chunk_snd_max){
tmpi = RTMPStream::chunk_snd_max;
}
output.append(data, len_left, tmpi);
len_left += tmpi;
if (len_left < len){
@ -313,8 +371,9 @@ std::string & RTMPStream::Chunk::Pack(){
return output;
} //SendChunk
/// Default contructor, creates an empty chunk with all values initialized to zero.
/// Default constructor, creates an empty chunk with all values initialized to zero.
RTMPStream::Chunk::Chunk(){
headertype = 0;
cs_id = 0;
timestamp = 0;
len = 0;
@ -438,7 +497,6 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigne
return ch.Pack();
} //SendUSR
/// Parses the argument string into the current chunk.
/// Tries to read a whole chunk, removing data from the input string as it reads.
/// If only part of a chunk is read, it will remove the part and call itself again.
@ -491,11 +549,15 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
break;
case 0x40:
if (indata.size() < i + 7) return false; //can't read whole header
if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0x40 with no valid previous chunk!\n");}
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0x40 with no valid previous chunk!\n");
}
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
if (timestamp != 0x00ffffff){timestamp += prev.timestamp;}
if (timestamp != 0x00ffffff){
timestamp += prev.timestamp;
}
len = indata[i++ ] * 256 * 256;
len += indata[i++ ] * 256;
len += indata[i++ ];
@ -505,18 +567,24 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
break;
case 0x80:
if (indata.size() < i + 3) return false; //can't read whole header
if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0x80 with no valid previous chunk!\n");}
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0x80 with no valid previous chunk!\n");
}
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
if (timestamp != 0x00ffffff){timestamp += prev.timestamp;}
if (timestamp != 0x00ffffff){
timestamp += prev.timestamp;
}
len = prev.len;
len_left = prev.len_left;
msg_type_id = prev.msg_type_id;
msg_stream_id = prev.msg_stream_id;
break;
case 0xC0:
if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n");}
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n");
}
timestamp = prev.timestamp;
len = prev.len;
len_left = prev.len_left;
@ -581,7 +649,9 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
gettimeofday( &RTMPStream::lastrec, 0);
unsigned int i = 0;
if (!buffer.available(3)){return false;}//we want at least 3 bytes
if ( !buffer.available(3)){
return false;
} //we want at least 3 bytes
std::string indata = buffer.copy(3);
unsigned char chunktype = indata[i++ ];
@ -605,7 +675,9 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
headertype = chunktype & 0xC0;
switch (headertype){
case 0x00:
if (!buffer.available(i+11)){return false;} //can't read whole header
if ( !buffer.available(i + 11)){
return false;
} //can't read whole header
indata = buffer.copy(i + 11);
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
@ -621,13 +693,19 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
msg_stream_id += indata[i++ ] * 256 * 256 * 256;
break;
case 0x40:
if (!buffer.available(i+7)){return false;} //can't read whole header
if ( !buffer.available(i + 7)){
return false;
} //can't read whole header
indata = buffer.copy(i + 7);
if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0x40 with no valid previous chunk!\n");}
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0x40 with no valid previous chunk!\n");
}
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
if (timestamp != 0x00ffffff){timestamp += prev.timestamp;}
if (timestamp != 0x00ffffff){
timestamp += prev.timestamp;
}
len = indata[i++ ] * 256 * 256;
len += indata[i++ ] * 256;
len += indata[i++ ];
@ -636,20 +714,28 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
msg_stream_id = prev.msg_stream_id;
break;
case 0x80:
if (!buffer.available(i+3)){return false;} //can't read whole header
if ( !buffer.available(i + 3)){
return false;
} //can't read whole header
indata = buffer.copy(i + 3);
if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0x80 with no valid previous chunk!\n");}
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0x80 with no valid previous chunk!\n");
}
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
if (timestamp != 0x00ffffff){timestamp += prev.timestamp;}
if (timestamp != 0x00ffffff){
timestamp += prev.timestamp;
}
len = prev.len;
len_left = prev.len_left;
msg_type_id = prev.msg_type_id;
msg_stream_id = prev.msg_stream_id;
break;
case 0xC0:
if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n");}
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n");
}
timestamp = prev.timestamp;
len = prev.len;
len_left = prev.len_left;
@ -670,7 +756,9 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
}
//read extended timestamp, if neccesary
if (timestamp == 0x00ffffff){
if (!buffer.available(i+4)){return false;} //can't read timestamp
if ( !buffer.available(i + 4)){
return false;
} //can't read timestamp
indata = buffer.copy(i + 4);
timestamp = indata[i++ ] * 256 * 256 * 256;
timestamp += indata[i++ ] * 256 * 256;
@ -680,7 +768,9 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
//read data if length > 0, and allocate it
if (real_len > 0){
if (!buffer.available(i+real_len)){return false;}//can't read all data (yet)
if ( !buffer.available(i + real_len)){
return false;
} //can't read all data (yet)
buffer.remove(i); //remove the header
if (prev.len_left > 0){
data = prev.data + buffer.remove(real_len); //append the data and remove from buffer
@ -720,7 +810,9 @@ bool RTMPStream::doHandshake(){
//Build S1 Packet
*((uint32_t*)Server) = 0; //time zero
*(((uint32_t*)(Server + 4))) = htonl(0x01020304); //version 1 2 3 4
for (int i = 8; i < 3072; ++i){Server[i] = versionstring[i%16];}//"random" data
for (int i = 8; i < 3072; ++i){
Server[i] = versionstring[i % 16];
} //"random" data
bool encrypted = (Version == 6);
#if DEBUG >= 4

View file

@ -13,7 +13,7 @@
//forward declaration of FLV::Tag to avoid circular dependencies.
namespace FLV {
class Tag;
};
}
/// Contains all functions and classes needed for RTMP connections.
namespace RTMPStream {
@ -50,7 +50,8 @@ namespace RTMPStream{
private:
static std::map<unsigned int, Chunk> lastsend;
static std::map<unsigned int, Chunk> lastrecv;
};//RTMPStream::Chunk
};
//RTMPStream::Chunk
std::string & SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data);
std::string & SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts);
@ -66,4 +67,4 @@ namespace RTMPStream{
extern std::string handshake_out;
/// Does the handshake. Expects handshake_in to be filled, and fills handshake_out.
bool doHandshake();
};//RTMPStream namespace
} //RTMPStream namespace

View file

@ -16,7 +16,6 @@
#define BUFFER_BLOCKSIZE 4096 //set buffer blocksize to 4KiB
#include <iostream>//temporary for debugging
std::string uint2string(unsigned int i){
std::stringstream st;
st << i;
@ -27,7 +26,9 @@ std::string uint2string(unsigned int i){
/// The back is popped as long as it is empty, first - this way this function is
/// guaranteed to return 0 if the buffer is empty.
unsigned int Socket::Buffer::size(){
while (data.size() > 0 && data.back().empty()){data.pop_back();}
while (data.size() > 0 && data.back().empty()){
data.pop_back();
}
return data.size();
}
@ -45,7 +46,9 @@ void Socket::Buffer::append(const char * newdata, const unsigned int newdatasize
j = i;
while (j < newdatasize && j - i <= BUFFER_BLOCKSIZE){
j++;
if (newdata[j-1] == '\n'){break;}
if (newdata[j - 1] == '\n'){
break;
}
}
if (i != j){
data.push_front(std::string(newdata + i, (size_t)(j - i)));
@ -64,7 +67,9 @@ bool Socket::Buffer::available(unsigned int count){
unsigned int i = 0;
for (std::deque<std::string>::iterator it = data.begin(); it != data.end(); ++it){
i += ( *it).size();
if (i >= count){return true;}
if (i >= count){
return true;
}
}
return false;
}
@ -72,7 +77,9 @@ bool Socket::Buffer::available(unsigned int count){
/// Removes count bytes from the buffer, returning them by value.
/// Returns an empty string if not all count bytes are available.
std::string Socket::Buffer::remove(unsigned int count){
if (!available(count)){return "";}
if ( !available(count)){
return "";
}
unsigned int i = 0;
std::string ret;
ret.reserve(count);
@ -93,7 +100,9 @@ std::string Socket::Buffer::remove(unsigned int count){
/// Copies count bytes from the buffer, returning them by value.
/// Returns an empty string if not all count bytes are available.
std::string Socket::Buffer::copy(unsigned int count){
if (!available(count)){return "";}
if ( !available(count)){
return "";
}
unsigned int i = 0;
std::string ret;
for (std::deque<std::string>::reverse_iterator it = data.rbegin(); it != data.rend(); ++it){
@ -118,7 +127,6 @@ std::string & Socket::Buffer::get(){
}
}
/// Create a new base socket. This is a basic constructor for converting any valid socket to a Socket::Connection.
/// \param sockNo Integer representing the socket to convert.
Socket::Connection::Connection(int sockNo){
@ -172,9 +180,15 @@ void setFDBlocking(int FD, bool blocking){
/// Set this socket to be blocking (true) or nonblocking (false).
void Socket::Connection::setBlocking(bool blocking){
if (sock >=0){setFDBlocking(sock, blocking);}
if (pipes[0] >=0){setFDBlocking(pipes[0], blocking);}
if (pipes[1] >=0){setFDBlocking(pipes[1], blocking);}
if (sock >= 0){
setFDBlocking(sock, blocking);
}
if (pipes[0] >= 0){
setFDBlocking(pipes[0], blocking);
}
if (pipes[1] >= 0){
setFDBlocking(pipes[1], blocking);
}
}
/// Close connection. The internal socket is closed and then set to -1.
@ -187,29 +201,36 @@ void Socket::Connection::close(){
if (sock != -1){
shutdown(sock, SHUT_RDWR);
errno = EINTR;
while (::close(sock) != 0 && errno == EINTR){}
while (::close(sock) != 0 && errno == EINTR){
}
sock = -1;
}
if (pipes[0] != -1){
errno = EINTR;
while (::close(pipes[0]) != 0 && errno == EINTR){}
while (::close(pipes[0]) != 0 && errno == EINTR){
}
pipes[0] = -1;
}
if (pipes[1] != -1){
errno = EINTR;
while (::close(pipes[1]) != 0 && errno == EINTR){}
while (::close(pipes[1]) != 0 && errno == EINTR){
}
pipes[1] = -1;
}
}
} //Socket::Connection::close
/// Returns internal socket number.
int Socket::Connection::getSocket(){return sock;}
int Socket::Connection::getSocket(){
return sock;
}
/// Returns a string describing the last error that occured.
/// Simply calls strerror(errno) - not very reliable!
/// \todo Improve getError at some point to be more reliable and only report socket errors.
std::string Socket::Connection::getError(){return strerror(errno);}
std::string Socket::Connection::getError(){
return strerror(errno);
}
/// Create a new Unix Socket. This socket will (try to) connect to the given address right away.
/// \param address String containing the location of the Unix socket to connect to.
@ -282,8 +303,12 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){
for (rp = result; rp != NULL; rp = rp->ai_next){
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sock < 0){continue;}
if (connect(sock, rp->ai_addr, rp->ai_addrlen) == 0){break;}
if (sock < 0){
continue;
}
if (connect(sock, rp->ai_addr, rp->ai_addrlen) == 0){
break;
}
::close(sock);
}
freeaddrinfo(result);
@ -357,7 +382,6 @@ bool Socket::Connection::flush(){
}
}
/// Returns a reference to the download buffer.
Socket::Buffer & Socket::Connection::Received(){
return downbuffer;
@ -390,7 +414,9 @@ void Socket::Connection::SendNow(const char * data, size_t len){
/// This means this function is blocking if the socket is, but nonblocking otherwise.
void Socket::Connection::Send(const char * data, size_t len){
while (upbuffer.size() > 0){
if (!iwrite(upbuffer.get())){break;}
if ( !iwrite(upbuffer.get())){
break;
}
}
if (upbuffer.size() > 0){
upbuffer.append(data, len);
@ -442,7 +468,9 @@ void Socket::Connection::Send(std::string & data){
/// \param len Amount of bytes to write.
/// \returns The amount of bytes actually written.
int Socket::Connection::iwrite(const void * buffer, int len){
if (!connected() || len < 1){return 0;}
if ( !connected() || len < 1){
return 0;
}
int r;
if (sock >= 0){
r = send(sock, buffer, len, 0);
@ -479,7 +507,9 @@ int Socket::Connection::iwrite(const void * buffer, int len){
/// \param len Amount of bytes to read.
/// \returns The amount of bytes actually read.
int Socket::Connection::iread(void * buffer, int len){
if (!connected() || len < 1){return 0;}
if ( !connected() || len < 1){
return 0;
}
int r;
if (sock >= 0){
r = recv(sock, buffer, len, 0);
@ -518,7 +548,9 @@ int Socket::Connection::iread(void * buffer, int len){
bool Socket::Connection::iread(Buffer & buffer){
char cbuffer[BUFFER_BLOCKSIZE];
int num = iread(cbuffer, BUFFER_BLOCKSIZE);
if (num < 1){return false;}
if (num < 1){
return false;
}
buffer.append(cbuffer, num);
return true;
} //iread
@ -529,9 +561,13 @@ bool Socket::Connection::iread(Buffer & buffer){
/// \param buffer std::string to remove data from.
/// \return True if more data was sent, false otherwise.
bool Socket::Connection::iwrite(std::string & buffer){
if (buffer.size() < 1){return false;}
if (buffer.size() < 1){
return false;
}
int tmp = iwrite((void*)buffer.c_str(), buffer.size());
if (tmp < 1){return false;}
if (tmp < 1){
return false;
}
buffer = buffer.substr(tmp);
return true;
} //iwrite
@ -736,7 +772,9 @@ Socket::Server::Server(std::string address, bool nonblock){
/// \param nonblock (optional) Whether the newly connected socket should be nonblocking. Default is false (blocking).
/// \returns A Socket::Connection, which may or may not be connected, depending on settings and circumstances.
Socket::Connection Socket::Server::accept(bool nonblock){
if (sock < 0){return Socket::Connection(-1);}
if (sock < 0){
return Socket::Connection( -1);
}
struct sockaddr_in6 addrinfo;
socklen_t len = sizeof(addrinfo);
static char addrconv[INET6_ADDRSTRLEN];
@ -789,7 +827,8 @@ void Socket::Server::close(){
#endif
shutdown(sock, SHUT_RDWR);
errno = EINTR;
while (::close(sock) != 0 && errno == EINTR){}
while (::close(sock) != 0 && errno == EINTR){
}
sock = -1;
}
} //Socket::Server::close
@ -804,4 +843,6 @@ bool Socket::Server::connected() const{
} //Socket::Server::connected
/// Returns internal socket number.
int Socket::Server::getSocket(){return sock;}
int Socket::Server::getSocket(){
return sock;
}

View file

@ -17,7 +17,9 @@
#include <deque>
//for being friendly with Socket::Connection down below
namespace Buffer{class user;};
namespace Buffer {
class user;
}
///Holds Socket tools.
namespace Socket {
@ -34,7 +36,8 @@ namespace Socket{
bool available(unsigned int count);
std::string remove(unsigned int count);
std::string copy(unsigned int count);
};//Buffer
};
//Buffer
/// This class is for easy communicating through sockets, either TCP or Unix.
class Connection{
@ -107,4 +110,4 @@ namespace Socket{
int getSocket(); ///< Returns internal socket number.
};
};
}

View file

@ -19,7 +19,10 @@
void Util::Stream::sanitizeName(std::string & streamname){
//strip anything that isn't numbers, digits or underscores
for (std::string::iterator i = streamname.end() - 1; i >= streamname.begin(); --i){
if (*i == '?'){streamname.erase(i, streamname.end()); break;}
if ( *i == '?'){
streamname.erase(i, streamname.end());
break;
}
if ( !isalpha( *i) && !isdigit( *i) && *i != '_'){
streamname.erase(i);
}else{

View file

@ -4,11 +4,14 @@
#include "timing.h"
#include <sys/time.h>//for gettimeofday
#include <time.h>//for time and nanosleep
/// Sleeps for the indicated amount of milliseconds or longer.
void Util::sleep(int ms){
if (ms < 0){return;}
if (ms > 10000){return;}
if (ms < 0){
return;
}
if (ms > 10000){
return;
}
struct timespec T;
T.tv_sec = ms / 1000;
T.tv_nsec = 1000000 * (ms % 1000);

View file

@ -7,4 +7,4 @@ namespace Util{
void sleep(int ms); ///< Sleeps for the indicated amount of milliseconds or longer.
long long int getMS(); ///< Gets the current time in milliseconds.
long long int epoch(); ///< Gets the amount of seconds since 01/01/1970.
};
}