Prettified error messages, first work on Util::Config server helpers.

This commit is contained in:
Thulinma 2014-01-22 23:47:59 +01:00
parent c6f63dfb95
commit 5c0f053006
25 changed files with 1254 additions and 327 deletions

View file

@ -13,7 +13,9 @@ endif
CPPFLAGS = -Wall -g -O2 -fPIC
override CPPFLAGS += -funsigned-char -DDEBUG="$(DEBUG)" -DPACKAGE_VERSION="\"$(PACKAGE_VERSION)\""
LDLIBS = -lcrypto -lrt
LDLIBS = -lcrypto
THREADLIB = -lpthread -lrt
LDLIBS = -lcrypto $(THREADLIB)
.DEFAULT_GOAL := all

3
README
View file

@ -6,6 +6,9 @@
| See COPYING file for full license |
|_________________________________________________|
NOTE: TinyThread++ is included also, but *not* copyright DDVTech BV.
License and author information for TinyThread++ can be found in the tinythread.h/cpp files.
The latest version of this code can always be found at:
https://github.com/DDVTECH/mistlib

View file

@ -2,8 +2,8 @@
/// Holds all code for the AMF namespace.
#include "amf.h"
#include "defines.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(){
@ -124,9 +124,9 @@ AMF::Object::Object(std::string indice, AMF::obj0type setType){ //object type in
numval = 0;
}
/// Prints the contents of this object to std::cerr.
/// Return the contents as a human-readable string.
/// If this object contains other objects, it will call itself recursively
/// and print all nested content in a nice human-readable format.
/// and print all nested content as well.
std::string AMF::Object::Print(std::string indent){
std::stringstream st;
st << indent;
@ -368,9 +368,6 @@ AMF::Object AMF::parseOne(const unsigned char *& data, unsigned int &len, unsign
unsigned int tmpi = 0;
unsigned char tmpdbl[8];
double *d; // hack to work around strict aliasing
#if DEBUG >= 10
fprintf(stderr, "Note: AMF type %hhx found. %i bytes left\n", data[i], len-i);
#endif
switch (data[i]){
case AMF::AMF0_NUMBER:
tmpdbl[7] = data[i + 1];
@ -496,9 +493,7 @@ AMF::Object AMF::parseOne(const unsigned char *& data, unsigned int &len, unsign
}
break;
}
#if DEBUG >= 2
fprintf(stderr, "Error: Unimplemented AMF type %hhx - returning.\n", data[i]);
#endif
DEBUG_MSG(DLVL_ERROR, "Error: Unimplemented AMF type %hhx - returning.", data[i]);
return AMF::Object("error", AMF::AMF0_DDV_CONTAINER);
} //parseOne
@ -668,99 +663,101 @@ AMF::Object3::Object3(std::string indice, AMF::obj3type setType){ //object type
intval = 0;
}
/// Prints the contents of this object to std::cerr.
/// Return the contents as a human-readable string.
/// If this object contains other objects, it will call itself recursively
/// and print all nested content in a nice human-readable format.
void AMF::Object3::Print(std::string indent){
std::cerr << indent;
/// and print all nested content as well.
std::string AMF::Object3::Print(std::string indent){
std::stringstream st;
st << indent;
// print my type
switch (myType){
case AMF::AMF3_UNDEFINED:
std::cerr << "Undefined";
st << "Undefined";
break;
case AMF::AMF3_NULL:
std::cerr << "Null";
st << "Null";
break;
case AMF::AMF3_FALSE:
std::cerr << "False";
st << "False";
break;
case AMF::AMF3_TRUE:
std::cerr << "True";
st << "True";
break;
case AMF::AMF3_INTEGER:
std::cerr << "Integer";
st << "Integer";
break;
case AMF::AMF3_DOUBLE:
std::cerr << "Double";
st << "Double";
break;
case AMF::AMF3_STRING:
std::cerr << "String";
st << "String";
break;
case AMF::AMF3_XMLDOC:
std::cerr << "XML Doc";
st << "XML Doc";
break;
case AMF::AMF3_DATE:
std::cerr << "Date";
st << "Date";
break;
case AMF::AMF3_ARRAY:
std::cerr << "Array";
st << "Array";
break;
case AMF::AMF3_OBJECT:
std::cerr << "Object";
st << "Object";
break;
case AMF::AMF3_XML:
std::cerr << "XML";
st << "XML";
break;
case AMF::AMF3_BYTES:
std::cerr << "ByteArray";
st << "ByteArray";
break;
case AMF::AMF3_DDV_CONTAINER:
std::cerr << "DDVTech Container";
st << "DDVTech Container";
break;
}
// print my string indice, if available
std::cerr << " " << myIndice << " ";
st << " " << myIndice << " ";
// print my numeric or string contents
switch (myType){
case AMF::AMF3_INTEGER:
std::cerr << intval;
st << intval;
break;
case AMF::AMF3_DOUBLE:
std::cerr << dblval;
st << 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;
st << "REF" << intval;
}else{
std::cerr << strval;
st << strval;
}
break;
case AMF::AMF3_DATE:
if (intval > 0){
std::cerr << "REF" << intval;
st << "REF" << intval;
}else{
std::cerr << dblval;
st << dblval;
}
break;
case AMF::AMF3_ARRAY:
case AMF::AMF3_OBJECT:
if (intval > 0){
std::cerr << "REF" << intval;
st << "REF" << intval;
}
break;
default:
break; //we don't care about the rest, and don't want a compiler warning...
}
std::cerr << std::endl;
st << 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 + " ");
st << it->Print(indent + " ");
}
}
return st.str();
} //print
/// Packs the AMF object to a std::string for transfer over the network.
@ -784,9 +781,6 @@ AMF::Object3 AMF::parseOne3(const unsigned char *& data, unsigned int &len, unsi
unsigned int arrsize = 0;
unsigned char tmpdbl[8];
double *d; // hack to work around strict aliasing
#if DEBUG >= 10
fprintf(stderr, "Note: AMF3 type %hhx found. %i bytes left\n", data[i], len-i);
#endif
switch (data[i]){
case AMF::AMF3_UNDEFINED:
case AMF::AMF3_NULL:
@ -1121,9 +1115,7 @@ AMF::Object3 AMF::parseOne3(const unsigned char *& data, unsigned int &len, unsi
}
break;
}
#if DEBUG >= 2
fprintf(stderr, "Error: Unimplemented AMF3 type %hhx - returning.\n", data[i]);
#endif
DEBUG_MSG(DLVL_ERROR, "Error: Unimplemented AMF3 type %hhx - returning.", data[i]);
return AMF::Object3("error", AMF::AMF3_DDV_CONTAINER);
} //parseOne

View file

@ -108,7 +108,7 @@ namespace AMF {
Object3(std::string indice, double val, obj3type setType = AMF3_DOUBLE);
Object3(std::string indice, std::string val, obj3type setType = AMF3_STRING);
Object3(std::string indice, obj3type setType = AMF3_OBJECT);
void Print(std::string indent = "");
std::string Print(std::string indent = "");
std::string Pack();
protected:
std::string myIndice; ///< Holds this objects indice, if any.

View file

@ -1,7 +1,7 @@
#include"bitstream.h"
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include "bitstream.h"
#include "defines.h"
#include <stdlib.h>
#include <string.h>
namespace Utils{
bitstream::bitstream(){
@ -31,7 +31,6 @@ namespace Utils{
memcpy(data+dataSize, input, bytes);
dataSize += bytes;
}
//std::cout << std::hex << std::string(data, dataSize) << std::dec << std::endl;
}
void bitstream::append(std::string input){
@ -45,11 +44,11 @@ namespace Utils{
long long unsigned int bitstream::peek(size_t count){
if (count > 64){
std::cerr << "Utils::bitstream: Warning; Can not read "<< count <<" bits into a long long unsigned int!" << std::endl;
DEBUG_MSG(DLVL_WARN, "Can not read %d bits into a long long unsigned int!", (int)count);
//return 0;
}
if (count > size()){
std::cerr << "Utils::bitstream: not enough bits left in stream. Left: " << size() << " requested: " << count << std::endl;
DEBUG_MSG(DLVL_ERROR, "Not enough bits left in stream. Left: %d requested: %d", (int)size(), (int)count);
return 0;
}
long long unsigned int retval = 0;

View file

@ -2,6 +2,9 @@
/// Contains generic functions for managing configuration.
#include "config.h"
#include "defines.h"
#include "timing.h"
#include "tinythread.h"
#include <string.h>
#include <signal.h>
@ -22,7 +25,6 @@
#include <pwd.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <fstream>
#include <dirent.h> //for getMyExec
@ -295,6 +297,46 @@ bool Util::Config::getBool(std::string optname){
return getOption(optname).asBool();
}
struct callbackData{
Socket::Connection * sock;
void (*cb)(Socket::Connection &);
};
static void callThreadCallback(void * cDataArg){
DEBUG_MSG(DLVL_INSANE, "Thread for %p started", cDataArg);
callbackData * cData = (callbackData*)cDataArg;
cData->cb(*(cData->sock));
cData->sock->close();
delete cData->sock;
delete cData;
DEBUG_MSG(DLVL_INSANE, "Thread for %p ended", cDataArg);
}
int Util::Config::serveThreadedSocket(void (*callback)(Socket::Connection &)){
Socket::Server server_socket = Socket::Server(getInteger("listen_port"), getString("listen_interface"), false);
if (!server_socket.connected()){return 1;}
DEBUG_MSG(DLVL_DEVEL, "Activating threaded server: %s", getString("cmd").c_str());
activate();
while (is_active && server_socket.connected()){
Socket::Connection S = server_socket.accept();
if (S.connected()){ //check if the new connection is valid
callbackData * cData = new callbackData;
cData->sock = new Socket::Connection(S);
cData->cb = callback;
//spawn a new thread for this connection
tthread::thread T(callThreadCallback, (void*)cData);
//detach it, no need to keep track of it anymore
T.detach();
}else{
Util::sleep(10); //sleep 10ms
}
}//main loop
server_socket.close();
DEBUG_MSG(DLVL_DEVEL, "Threaded server exiting: %s", getString("cmd").c_str());
return 0;
}
/// Activated the stored config. This will:
/// - Drop permissions to the stored "username", if any.
/// - Daemonize the process if "daemonize" exists and is true.
@ -450,19 +492,13 @@ void Util::setUser(std::string username){
if (username != "root"){
struct passwd * user_info = getpwnam(username.c_str());
if ( !user_info){
#if DEBUG >= 1
fprintf(stderr, "Error: could not setuid %s: could not get PID\n", username.c_str());
#endif
DEBUG_MSG(DLVL_ERROR, "Error: could not setuid %s: could not get PID", username.c_str());
return;
}else{
if (setuid(user_info->pw_uid) != 0){
#if DEBUG >= 1
fprintf(stderr, "Error: could not setuid %s: not allowed\n", username.c_str());
#endif
DEBUG_MSG(DLVL_ERROR, "Error: could not setuid %s: not allowed", username.c_str());
}else{
#if DEBUG >= 3
fprintf(stderr, "Changed user to %s\n", username.c_str());
#endif
DEBUG_MSG(DLVL_DEVEL, "Change user to %s", username.c_str());
}
}
}
@ -473,12 +509,8 @@ void Util::setUser(std::string username){
/// Does not change directory to root.
/// Does redirect output to /dev/null
void Util::Daemonize(){
#if DEBUG >= 3
fprintf(stderr, "Going into background mode...\n");
#endif
DEBUG_MSG(DLVL_DEVEL, "Going into background mode...");
if (daemon(1, 0) < 0){
#if DEBUG >= 1
fprintf(stderr, "Failed to daemonize: %s\n", strerror(errno));
#endif
DEBUG_MSG(DLVL_ERROR, "Failed to daemonize: %s", strerror(errno));
}
}

View file

@ -33,6 +33,9 @@ namespace Util {
long long int getInteger(std::string optname);
bool getBool(std::string optname);
void activate();
int serveThreadedSocket(void (*callback)(Socket::Connection & S));
int serveForkedSocket(void (*callback)(Socket::Connection & S));
int servePlainSocket(void (*callback)(Socket::Connection & S));
void addBasicConnectorOptions(JSON::Value & capabilities);
void addConnectorOptions(int port, JSON::Value & capabilities);
};

View file

@ -1,4 +1,3 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
@ -69,7 +68,6 @@ namespace Converter {
char const * cmd[3] = {0, 0, 0};
std::string mistPath = Util::getMyPath() + "MistInfo";
cmd[0] = mistPath.c_str();
fprintf( stderr, "Querying %s\n", myPath.c_str());
JSON::Value result;
DIR * Dirp = opendir(myPath.c_str());
struct stat StatBuf;

18
lib/defines.h Normal file
View file

@ -0,0 +1,18 @@
// Defines to print debug messages.
#define DLVL_NONE 0 // All debugging disabled.
#define DLVL_FAIL 1 // Only messages about failed operations.
#define DLVL_ERROR 2 // Only messages about errors and failed operations.
#define DLVL_WARN 3 // Warnings, errors, and fail messages.
#define DLVL_DEVEL 4 // All of the above, plus status messages handy during development.
#define DLVL_MEDIUM 5 // Slightly more than just development-level messages.
#define DLVL_HIGH 6 // Verbose debugging messages.
#define DLVL_VERYHIGH 7 // Very verbose debugging messages.
#define DLVL_EXTREME 8 // Everything is reported in extreme detail.
#define DLVL_INSANE 9 // Everything is reported in insane detail.
#define DLVL_DONTEVEN 10 // All messages enabled, even pointless ones.
#if DEBUG > 0
#include <stdio.h>
#define DEBUG_MSG(lvl, msg, ...) if (DEBUG >= lvl){fprintf(stderr, "[%s:%d] " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__);}
#else
#define DEBUG_MSG(lvl, msg, ...) // Debugging disabled.
#endif

View file

@ -2,6 +2,7 @@
/// Holds all code for DDVTECH Stream Container parsing/generation.
#include "dtsc.h"
#include "defines.h"
#include <stdlib.h>
#include <string.h> //for memcmp
#include <arpa/inet.h> //for htonl/ntohl
@ -87,9 +88,9 @@ bool DTSC::Stream::parsePacket(std::string & buffer){
syncing = false;
return true;
}
#if DEBUG >= 2
#if DEBUG >= DLVL_WARN
if (!syncing){
std::cerr << "Error: Invalid DTMI data detected - re-syncing" << std::endl;
DEBUG_MSG(DLVL_WARN, "Invalid DTMI data detected - re-syncing");
syncing = true;
}
#endif
@ -155,9 +156,9 @@ bool DTSC::Stream::parsePacket(Socket::Buffer & buffer){
syncing = false;
return true;
}
#if DEBUG >= 2
#if DEBUG >= DLVL_WARN
if (!syncing){
std::cerr << "Error: Invalid DTMI data detected - syncing" << std::endl;
DEBUG_MSG(DLVL_WARN, "Invalid DTMI data detected - syncing");
syncing = true;
}
#endif
@ -206,9 +207,7 @@ void DTSC::Stream::waitForMeta(Socket::Connection & sourceSocket){
if (Util::getMS() - start >= 5000){
sourceSocket.close();
//and optionally print a debug message that this happened
#if DEBUG >= 4
fprintf(stderr, "Timed out while waiting for metadata\n");
#endif
DEBUG_MSG(DLVL_DEVEL, "Timing out while waiting for metadata");
}
}
@ -283,7 +282,7 @@ void DTSC::Stream::addPacket(JSON::Value & newPack){
}
/// Deletes a the first part of the buffer, updating the keyframes list and metadata as required.
/// Will print a warning to std::cerr if a track has less than 2 keyframes left because of this.
/// Will print a warning if a track has less than 2 keyframes left because of this.
void DTSC::Stream::cutOneBuffer(){
int trid = buffers.begin()->first.trackID;
long long unsigned int delTime = buffers.begin()->first.seekTime;
@ -517,7 +516,7 @@ DTSC::File::File(std::string filename, bool create){
if (create){
F = fopen(filename.c_str(), "w+b");
if(!F){
std::cerr << "Could not create file" << filename << ": " << strerror(errno) << std::endl;
DEBUG_MSG(DLVL_ERROR, "Could not create file %s: %s", filename.c_str(), strerror(errno));
return;
}
//write an empty header
@ -531,7 +530,7 @@ DTSC::File::File(std::string filename, bool create){
}
created = create;
if ( !F){
fprintf(stderr, "Could not open file %s\n", filename.c_str());
DEBUG_MSG(DLVL_ERROR, "Could not open file %s\n", filename.c_str());
return;
}
fseek(F, 0, SEEK_END);
@ -561,7 +560,7 @@ DTSC::readOnlyMeta & DTSC::File::getMeta(){
/// Forces a write if force is set to true.
bool DTSC::File::writeHeader(std::string & header, bool force){
if (headerSize != header.size() && !force){
fprintf(stderr, "Could not overwrite header - not equal size\n");
DEBUG_MSG(DLVL_ERROR, "Could not overwrite header - not equal size");
return false;
}
headerSize = header.size();
@ -601,30 +600,28 @@ long long int DTSC::File::addHeader(std::string & header){
}
/// Reads the header at the given file position.
/// If the packet could not be read for any reason, the reason is printed to stderr.
/// If the packet could not be read for any reason, the reason is printed.
/// Reading the header means the file position is moved to after the header.
void DTSC::File::readHeader(int pos){
fseek(F, pos, SEEK_SET);
if (fread(buffer, 4, 1, F) != 1){
if (feof(F)){
#if DEBUG >= 4
fprintf(stderr, "End of file reached (H%i)\n", pos);
#endif
DEBUG_MSG(DLVL_DEVEL, "End of file reached while reading header @ %d", pos);
}else{
fprintf(stderr, "Could not read header (H%i)\n", pos);
DEBUG_MSG(DLVL_ERROR, "Could not read header @ %d", pos);
}
strbuffer = "";
metadata = readOnlyMeta();
return;
}
if (memcmp(buffer, DTSC::Magic_Header, 4) != 0){
fprintf(stderr, "Invalid header - %.4s != %.4s (H%i)\n", buffer, DTSC::Magic_Header, pos);
DEBUG_MSG(DLVL_ERROR, "Invalid header - %.4s != %.4s @ %i", buffer, DTSC::Magic_Header, pos);
strbuffer = "";
metadata = readOnlyMeta();
return;
}
if (fread(buffer, 4, 1, F) != 1){
fprintf(stderr, "Could not read size (H%i)\n", pos);
DEBUG_MSG(DLVL_ERROR, "Could not read header size @ %i", pos);
strbuffer = "";
metadata = readOnlyMeta();
return;
@ -634,7 +631,7 @@ void DTSC::File::readHeader(int pos){
strbuffer.resize(packSize);
if (packSize){
if (fread((void*)strbuffer.c_str(), packSize, 1, F) != 1){
fprintf(stderr, "Could not read packet (H%i)\n", pos);
DEBUG_MSG(DLVL_ERROR, "Could not read header packet @ %i", pos);
strbuffer = "";
metadata = readOnlyMeta();
return;
@ -666,7 +663,7 @@ bool DTSC::File::reachedEOF(){
}
/// Reads the packet available at the current file position.
/// If the packet could not be read for any reason, the reason is printed to stderr.
/// If the packet could not be read for any reason, the reason is printed.
/// Reading the packet means the file position is increased to the next packet.
void DTSC::File::seekNext(){
if ( !currentPositions.size()){
@ -689,11 +686,9 @@ void DTSC::File::seekNext(){
lastreadpos = ftell(F);
if (fread(buffer, 4, 1, F) != 1){
if (feof(F)){
#if DEBUG >= 4
fprintf(stderr, "End of file reached.\n");
#endif
DEBUG_MSG(DLVL_DEVEL, "End of file reached while seeking @ %i", (int)lastreadpos);
}else{
fprintf(stderr, "Could not read header\n");
DEBUG_MSG(DLVL_ERROR, "Could not seek to next @ %i", (int)lastreadpos);
}
strbuffer = "";
jsonbuffer.null();
@ -712,13 +707,13 @@ void DTSC::File::seekNext(){
version = 2;
}
if (version == 0){
fprintf(stderr, "Invalid packet header @ %#x - %.4s != %.4s\n", (unsigned int)lastreadpos, buffer, DTSC::Magic_Packet2);
DEBUG_MSG(DLVL_ERROR, "Invalid packet header @ %#x - %.4s != %.4s @ %d", (unsigned int)lastreadpos, buffer, DTSC::Magic_Packet2, (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
return;
}
if (fread(buffer, 4, 1, F) != 1){
fprintf(stderr, "Could not read size\n");
DEBUG_MSG(DLVL_ERROR, "Could not read packet size @ %d", (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
return;
@ -727,7 +722,7 @@ void DTSC::File::seekNext(){
long packSize = ntohl(ubuffer[0]);
strbuffer.resize(packSize);
if (fread((void*)strbuffer.c_str(), packSize, 1, F) != 1){
fprintf(stderr, "Could not read packet\n");
DEBUG_MSG(DLVL_ERROR, "Could not read packet @ %d", (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
return;
@ -782,11 +777,9 @@ void DTSC::File::parseNext(){
lastreadpos = ftell(F);
if (fread(buffer, 4, 1, F) != 1){
if (feof(F)){
#if DEBUG >= 4
fprintf(stderr, "End of file reached.\n");
#endif
DEBUG_MSG(DLVL_DEVEL, "End of file reached @ %d", (int)lastreadpos);
}else{
fprintf(stderr, "Could not read header\n");
DEBUG_MSG(DLVL_ERROR, "Could not read header @ %d", (int)lastreadpos);
}
strbuffer = "";
jsonbuffer.null();
@ -798,7 +791,7 @@ void DTSC::File::parseNext(){
jsonbuffer = metadata.toJSON();
}else{
if (fread(buffer, 4, 1, F) != 1){
fprintf(stderr, "Could not read size\n");
DEBUG_MSG(DLVL_ERROR, "Could not read header size @ %d", (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
return;
@ -807,7 +800,7 @@ void DTSC::File::parseNext(){
long packSize = ntohl(ubuffer[0]);
strbuffer.resize(packSize);
if (fread((void*)strbuffer.c_str(), packSize, 1, F) != 1){
fprintf(stderr, "Could not read packet\n");
DEBUG_MSG(DLVL_ERROR, "Could not read header @ %d", (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
return;
@ -824,13 +817,13 @@ void DTSC::File::parseNext(){
version = 2;
}
if (version == 0){
fprintf(stderr, "Invalid packet header @ %#x - %.4s != %.4s\n", (unsigned int)lastreadpos, buffer, DTSC::Magic_Packet2);
DEBUG_MSG(DLVL_ERROR, "Invalid packet header @ %#x - %.4s != %.4s @ %d", (unsigned int)lastreadpos, buffer, DTSC::Magic_Packet2, (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
return;
}
if (fread(buffer, 4, 1, F) != 1){
fprintf(stderr, "Could not read size\n");
DEBUG_MSG(DLVL_ERROR, "Could not read packet size @ %d", (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
return;
@ -839,7 +832,7 @@ void DTSC::File::parseNext(){
long packSize = ntohl(ubuffer[0]);
strbuffer.resize(packSize);
if (fread((void*)strbuffer.c_str(), packSize, 1, F) != 1){
fprintf(stderr, "Could not read packet\n");
DEBUG_MSG(DLVL_ERROR, "Could not read packet @ %d", (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
return;

View file

@ -1,4 +1,5 @@
#include "dtsc.h"
#include "defines.h"
/// Retrieves a short in network order from the pointer p.
static short btohs(char * p){
@ -269,7 +270,7 @@ namespace DTSC {
void Track::update(JSON::Value & pack){
if (pack["time"].asInt() < lastms){
std::cerr << "Received packets for track " << trackID << " in wrong order (" << pack["time"].asInt() << " < " << lastms << ") - ignoring!" << std::endl;
DEBUG_MSG(DLVL_WARN, "Received packets for track %d in wrong order (%d < %d) - ignoring!", (int)trackID, (int)pack["time"].asInt(), (int)lastms);
return;
}
Part newPart;

View file

@ -1,4 +1,5 @@
#include "filesystem.h"
#include "defines.h"
Filesystem::Directory::Directory(std::string PathName, std::string BasePath){
MyBase = BasePath;
@ -26,9 +27,7 @@ void Filesystem::Directory::FillEntries(){
dirent * entry;
while ((entry = readdir(Dirp))){
if (stat((MyBase + MyPath + "/" + entry->d_name).c_str(), &StatBuf) == -1){
#if DEBUG >= 4
fprintf(stderr, "\tSkipping %s\n\t\tReason: %s\n", entry->d_name, strerror(errno));
#endif
DEBUG_MSG(DLVL_DEVEL, "Skipping %s, reason %s", entry->d_name, strerror(errno));
continue;
}
///Convert stat to string
@ -38,8 +37,9 @@ void Filesystem::Directory::FillEntries(){
}
void Filesystem::Directory::Print(){
/// \todo Remove? Libraries shouldn't print stuff.
if ( !ValidDir){
printf("%s is not a valid directory\n", (MyBase + MyPath).c_str());
DEBUG_MSG(DLVL_ERROR, "%s is not a valid directory", (MyBase + MyPath).c_str());
return;
}
printf("%s:\n", (MyBase + MyPath).c_str());
@ -74,9 +74,6 @@ std::string Filesystem::Directory::LIST(std::vector<std::string> ActiveStreams){
for (std::map<std::string, struct stat>::iterator it = Entries.begin(); it != Entries.end(); it++){
bool Active = (std::find(ActiveStreams.begin(), ActiveStreams.end(), ( *it).first) != ActiveStreams.end());
fprintf(stderr, "%s active?: %d\n", ( *it).first.c_str(), Active);
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';
@ -217,7 +214,6 @@ void Filesystem::Directory::STOR(std::string Path, std::string Data){
bool Filesystem::Directory::SimplifyPath(){
MyPath += "/";
fprintf(stderr, "MyPath: %s\n", MyPath.c_str());
std::vector<std::string> TempPath;
std::string TempString;
for (std::string::iterator it = MyPath.begin(); it != MyPath.end(); it++){
@ -258,7 +254,7 @@ bool Filesystem::Directory::DELE(std::string Path){
FileName = MyBase + MyPath + "/" + Path;
}
if (std::remove(FileName.c_str())){
fprintf(stderr, "Removing file %s unsuccesfull\n", FileName.c_str());
DEBUG_MSG(DLVL_ERROR, "Removing file %s failed", FileName.c_str());
return false;
}
return true;
@ -275,7 +271,7 @@ bool Filesystem::Directory::MKD(std::string Path){
FileName = MyBase + MyPath + "/" + Path;
}
if (mkdir(FileName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)){
fprintf(stderr, "Creating directory %s unsuccesfull\n", FileName.c_str());
DEBUG_MSG(DLVL_ERROR, "Creating directory %s failed", FileName.c_str());
return false;
}
MyVisible[FileName] = S_ALL;
@ -298,7 +294,7 @@ bool Filesystem::Directory::Rename(std::string From, std::string To){
FileTo = MyBase + MyPath + "/" + To;
}
if (std::rename(FileFrom.c_str(), FileTo.c_str())){
fprintf(stderr, "Renaming file %s to %s unsuccesfull\n", FileFrom.c_str(), FileTo.c_str());
DEBUG_MSG(DLVL_ERROR, "Renaming %s to %s failed", FileFrom.c_str(), FileTo.c_str());
return false;
}
return true;

View file

@ -23,7 +23,6 @@ FTP::User::User(Socket::Connection NewConnection, std::map<std::string, std::str
MyDir.SetVisibility("OnDemand", Filesystem::S_ACTIVE);
JSON::Value MyConfig = JSON::fromFile("/tmp/mist/streamlist");
fprintf(stderr, "Streamamount: %d\n", MyConfig["streams"].size());
for (JSON::ObjIter it = MyConfig["streams"].ObjBegin(); it != MyConfig["streams"].ObjEnd(); it++){
std::string ThisStream = ( *it).second["channel"]["URL"].toString();
ThisStream.erase(ThisStream.begin());
@ -32,7 +31,6 @@ FTP::User::User(Socket::Connection NewConnection, std::map<std::string, std::str
ThisStream.erase(0, ThisStream.find('/') + 1);
}
ActiveStreams.push_back(ThisStream);
fprintf(stderr, "\t%s\n", ThisStream.c_str());
}
}
@ -160,7 +158,6 @@ int FTP::User::ParseCommand(std::string Command){
break;
}
case CMD_LIST: {
std::cout << "Listening on :" << MyPassivePort << "\n";
Socket::Connection Connected = Passive.accept();
if (Connected.connected()){
Conn.Send("125 Data connection already open; transfer starting.\n");
@ -170,7 +167,6 @@ int FTP::User::ParseCommand(std::string Command){
while ( !Connected.connected()){
Connected = Passive.accept();
}
fprintf(stderr, "Sending LIST information\n");
std::string tmpstr = MyDir.LIST(ActiveStreams);
Connected.Send(tmpstr);
Connected.close();
@ -197,7 +193,6 @@ int FTP::User::ParseCommand(std::string Command){
return 530;
} //Not logged in.
MyPassivePort = (rand() % 9999);
std::cout << ":" << MyPassivePort << "\n";
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
return 229;
break;
@ -207,7 +202,6 @@ int FTP::User::ParseCommand(std::string Command){
return 530;
} //Not logged in.
MyPassivePort = (rand() % 9999) + 49152;
std::cout << ":" << MyPassivePort << "\n";
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
return 227;
break;
@ -222,7 +216,6 @@ int FTP::User::ParseCommand(std::string Command){
if ( !MyDir.HasPermission(Filesystem::P_RETR)){
return 550;
} //Access denied.
std::cout << "Listening on :" << MyPassivePort << "\n";
Socket::Connection Connected = Passive.accept();
if (Connected.connected()){
Conn.Send("125 Data connection already open; transfer starting.\n");
@ -232,7 +225,6 @@ int FTP::User::ParseCommand(std::string Command){
while ( !Connected.connected()){
Connected = Passive.accept();
}
fprintf(stderr, "Sending RETR information\n");
std::string tmpstr = MyDir.RETR(Command);
Connected.Send(tmpstr);
Connected.close();
@ -249,7 +241,6 @@ int FTP::User::ParseCommand(std::string Command){
if ( !MyDir.HasPermission(Filesystem::P_STOR)){
return 550;
} //Access denied.
std::cout << "Listening on :" << MyPassivePort << "\n";
Socket::Connection Connected = Passive.accept();
if (Connected.connected()){
Conn.Send("125 Data connection already open; transfer starting.\n");
@ -259,7 +250,6 @@ int FTP::User::ParseCommand(std::string Command){
while ( !Connected.connected()){
Connected = Passive.accept();
}
fprintf(stderr, "Reading STOR information\n");
std::string Buffer;
while (Connected.spool()){
}

View file

@ -1,6 +1,7 @@
/// \file json.cpp Holds all JSON-related code.
#include "json.h"
#include "defines.h"
#include <sstream>
#include <fstream>
#include <stdlib.h>
@ -642,11 +643,11 @@ unsigned int JSON::Value::packedSize() const{
}//packedSize
/// Pre-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.
/// Non-object-types will print an error.
/// The internal buffer is guaranteed to be up-to-date after this function is called.
void JSON::Value::netPrepare(){
if (myType != OBJECT){
fprintf(stderr, "Error: Only objects may be NetPacked!\n");
DEBUG_MSG(DLVL_ERROR, "Only objects may be netpacked!");
return;
}
std::string packed = toPacked();
@ -711,7 +712,7 @@ void JSON::Value::netPrepare(){
}
/// 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.
/// Non-object-types will print an error and return an empty string.
/// This function returns a reference to an internal buffer where the prepared data is kept.
/// The internal buffer is *not* made stale if any changes occur inside the object - subsequent calls to toPacked() will clear the buffer,
/// calls to netPrepare will guarantee it is up-to-date.
@ -719,7 +720,7 @@ std::string & JSON::Value::toNetPacked(){
static std::string emptystring;
//check if this is legal
if (myType != OBJECT){
fprintf(stderr, "Error: Only objects may be NetPacked!\n");
DEBUG_MSG(DLVL_ERROR, "Only objects may be netpacked!");
return emptystring;
}
//if sneaky storage doesn't contain correct data, re-calculate it
@ -1018,9 +1019,6 @@ JSON::Value JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigne
/// \param i Current parsing position in the raw data (defaults to 0).
/// \param ret Will be set to JSON::Value, parsed from the raw data.
void JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigned int &i, JSON::Value & ret){
#if DEBUG >= 10
fprintf(stderr, "Note: AMF type %hhx found. %i bytes left\n", data[i], len-i);
#endif
ret.null();
if (i >= len){
return;
@ -1087,9 +1085,7 @@ void JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigned int &
break;
}
}
#if DEBUG >= 2
fprintf(stderr, "Error: Unimplemented DTMI type %hhx, @ %i / %i - returning.\n", data[i], i, len);
#endif
DEBUG_MSG(DLVL_FAIL, "Unimplemented DTMI type %hhx, @ %i / %i - returning.\n", data[i], i, len);
i += 1;
return;
} //fromOneDTMI

View file

@ -3,6 +3,7 @@
#include <arpa/inet.h> //for htonl and friends
#include "mp4.h"
#include "json.h"
#include "defines.h"
#define Int64 uint64_t
@ -2286,7 +2287,7 @@ namespace MP4 {
void AVCC::setPayload(std::string newPayload){
if ( !reserve(0, payloadSize(), newPayload.size())){
std::cerr << "Cannot allocate enough memory for payload" << std::endl;
DEBUG_MSG(DLVL_ERROR, "Cannot allocate enough memory for payload");
return;
}
memcpy((char*)payload(), (char*)newPayload.c_str(), newPayload.size());

View file

@ -18,7 +18,6 @@ bool NAL_Unit::ReadData(std::string & InputData){
ShortAnnexB += (char)0x00;
ShortAnnexB += (char)0x00;
ShortAnnexB += (char)0x01;
// fprintf( stderr, "NAL_Unit::ReadData --- DataSize: %d\n", InputData.size() );
if (InputData.size() < 3){
return false;
}

View file

@ -1,4 +1,5 @@
#include "ogg.h"
#include "defines.h"
#include <string.h>
#include <stdlib.h>
#include <sstream>
@ -204,7 +205,7 @@ namespace OGG{
}
static void STerrMSG(){
std::cerr << "Segments too big, create a continue page" << std::endl;
DEBUG_MSG(DLVL_ERROR, "Segment too big, create a continue page");
}
/// \todo MAKE FIX HERE
@ -486,10 +487,10 @@ namespace OGG{
setGranulePosition(DTSCVec[0]["granule"].asInt());
for (unsigned int i = 1; i < DTSCVec.size(); i++){
if (DTSCVec[0]["granule"].asInt() != DTSCVec[i]["granule"].asInt()){
std::cerr << "Granule inconcistency!! " << DTSCVec[0]["granule"].asInt() << " != " << DTSCVec[i]["granule"].asInt() << std::endl;
DEBUG_MSG(DLVL_WARN, "Granule inconcistency!! %u != %u", (unsigned int)DTSCVec[0]["granule"].asInt(), (unsigned int)DTSCVec[i]["granule"].asInt());
}
if (DTSCVec[0]["trackid"].asInt() != DTSCVec[i]["trackid"].asInt()){
std::cerr << "Track ID inconcistency!! " << DTSCVec[0]["trackid"].asInt() << " != " <<DTSCVec[i]["trackid"].asInt() << std::endl;
DEBUG_MSG(DLVL_WARN, "Track ID inconcistency!! %u != %u", (unsigned int)DTSCVec[0]["trackid"].asInt(), (unsigned int)DTSCVec[i]["trackid"].asInt());
}
}
setBitstreamSerialNumber(serial);

View file

@ -2,6 +2,7 @@
/// Contains generic functions for managing processes.
#include "procs.h"
#include "defines.h"
#include <string.h>
#include <sys/types.h>
#include <signal.h>
@ -127,22 +128,19 @@ void Util::Procs::childsig_handler(int signum){
return;
}
#if DEBUG >= 5
#if DEBUG >= DLVL_DEVEL
std::string pname = plist[ret];
#endif
plist.erase(ret);
#if DEBUG >= 5
#if DEBUG >= DLVL_DEVEL
if (!isActive(pname)){
std::cerr << "Process " << pname << " fully terminated." << std::endl;
DEBUG_MSG(DLVL_DEVEL, "Process %s fully terminated", pname.c_str());
}
#endif
if (exitHandlers.count(ret) > 0){
TerminationNotifier tn = exitHandlers[ret];
exitHandlers.erase(ret);
#if DEBUG >= 5
std::cerr << "Calling termination handler for " << pname << std::endl;
#endif
tn(ret, exitcode);
}
}
@ -205,9 +203,7 @@ void Util::Procs::runCmd(std::string & cmd){
}
//execute the command
execvp(args[0], args);
#if DEBUG >= 1
std::cerr << "Error running \"" << cmd << "\": " << strerror(errno) << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Error running %s: %s", cmd.c_str(), strerror(errno));
_exit(42);
}
@ -225,14 +221,10 @@ pid_t Util::Procs::Start(std::string name, std::string cmd){
runCmd(cmd);
}else{
if (ret > 0){
#if DEBUG >= 5
std::cerr << "Process " << name << " started, PID " << ret << ": " << cmd << std::endl;
#endif
DEBUG_MSG(DLVL_DEVEL, "Process %s started, PID %d: %s", name.c_str(), ret, cmd.c_str());
plist.insert(std::pair<pid_t, std::string>(ret, name));
}else{
#if DEBUG >= 1
std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started: fork() failed", name.c_str());
return 0;
}
}
@ -251,9 +243,7 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
setHandler();
int pfildes[2];
if (pipe(pfildes) == -1){
#if DEBUG >= 1
std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. Pipe creation failed.", name.c_str());
return 0;
}
@ -270,9 +260,7 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
if (ret > 0){
plist.insert(std::pair<pid_t, std::string>(ret, name));
}else{
#if DEBUG >= 1
std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
close(pfildes[1]);
close(pfildes[0]);
return 0;
@ -289,14 +277,10 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
runCmd(cmd2);
}else{
if (ret2 > 0){
#if DEBUG >= 5
std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << "): " << cmd << " | " << cmd2 << std::endl;
#endif
DEBUG_MSG(DLVL_DEVEL, "Process %s started, PIDs (%d, %d): %s | %s", name.c_str(), ret, ret2, cmd.c_str(), cmd2.c_str());
plist.insert(std::pair<pid_t, std::string>(ret2, name));
}else{
#if DEBUG >= 1
std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
Stop(name);
close(pfildes[1]);
close(pfildes[0]);
@ -322,15 +306,11 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
int pfildes[2];
int pfildes2[2];
if (pipe(pfildes) == -1){
#if DEBUG >= 1
std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. Pipe creation failed.", name.c_str());
return 0;
}
if (pipe(pfildes2) == -1){
#if DEBUG >= 1
std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. Pipe creation failed.", name.c_str());
return 0;
}
@ -349,9 +329,7 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
if (ret > 0){
plist.insert(std::pair<pid_t, std::string>(ret, name));
}else{
#if DEBUG >= 1
std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
close(pfildes[1]);
close(pfildes[0]);
close(pfildes2[1]);
@ -372,14 +350,10 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
runCmd(cmd2);
}else{
if (ret2 > 0){
#if DEBUG >= 5
std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << "): " << cmd << " | " << cmd2 << std::endl;
#endif
DEBUG_MSG(DLVL_DEVEL, "Process %s started, PIDs (%d, %d): %s | %s", name.c_str(), ret, ret2, cmd.c_str(), cmd2.c_str());
plist.insert(std::pair<pid_t, std::string>(ret2, name));
}else{
#if DEBUG >= 1
std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
Stop(name);
close(pfildes[1]);
close(pfildes[0]);
@ -403,14 +377,10 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
runCmd(cmd3);
}else{
if (ret3 > 0){
#if DEBUG >= 5
std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << ", " << ret3 << "): " << cmd << " | " << cmd2 << " | " << cmd3 << std::endl;
#endif
DEBUG_MSG(DLVL_DEVEL, "Process %s started, PIDs (%d, %d, %d): %s | %s | %s", name.c_str(), ret, ret2, ret3, cmd.c_str(), cmd2.c_str(), cmd3.c_str());
plist.insert(std::pair<pid_t, std::string>(ret3, name));
}else{
#if DEBUG >= 1
std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
Stop(name);
close(pfildes[1]);
close(pfildes[0]);
@ -432,24 +402,18 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
/// \arg fdout Same as fdin, but for stderr.
pid_t Util::Procs::StartPiped(std::string name, char* const* argv, int * fdin, int * fdout, int * fderr){
if (isActive(name)){
#if DEBUG >= 1
std::cerr << name << " already active - skipping start" << std::endl;
#endif
DEBUG_MSG(DLVL_WARN, "Process %s already active - skipping start", name.c_str());
return getPid(name);
}
pid_t pid;
int pipein[2], pipeout[2], pipeerr[2];
setHandler();
if (fdin && *fdin == -1 && pipe(pipein) < 0){
#if DEBUG >= 1
std::cerr << "Pipe (in) creation failed for " << name << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Pipe in creation failed for process %s", name.c_str());
return 0;
}
if (fdout && *fdout == -1 && pipe(pipeout) < 0){
#if DEBUG >= 1
std::cerr << "Pipe (out) creation failed for " << name << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Pipe out creation failed for process %s", name.c_str());
if ( *fdin == -1){
close(pipein[0]);
close(pipein[1]);
@ -457,9 +421,7 @@ pid_t Util::Procs::StartPiped(std::string name, char* const* argv, int * fdin, i
return 0;
}
if (fderr && *fderr == -1 && pipe(pipeerr) < 0){
#if DEBUG >= 1
std::cerr << "Pipe (err) creation failed for " << name << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Pipe err creation failed for process %s", name.c_str());
if ( *fdin == -1){
close(pipein[0]);
close(pipein[1]);
@ -474,9 +436,7 @@ pid_t Util::Procs::StartPiped(std::string name, char* const* argv, int * fdin, i
if ( !fdin || !fdout || !fderr){
devnull = open("/dev/null", O_RDWR);
if (devnull == -1){
#if DEBUG >= 1
std::cerr << "Could not open /dev/null for " << name << ": " << strerror(errno) << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Could not open /dev/null for process %s: %s", name.c_str(), strerror(errno));
if ( *fdin == -1){
close(pipein[0]);
close(pipein[1]);
@ -528,14 +488,10 @@ pid_t Util::Procs::StartPiped(std::string name, char* const* argv, int * fdin, i
close(devnull);
}
execvp(argv[0], argv);
#if DEBUG >= 1
perror("execvp failed");
#endif
DEBUG_MSG(DLVL_ERROR, "execvp() failed for process %s", name.c_str());
exit(42);
}else if (pid == -1){
#if DEBUG >= 1
std::cerr << "Failed to fork for pipe: " << name << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "fork() for pipe failed for process %s", name.c_str());
if (fdin && *fdin == -1){
close(pipein[0]);
close(pipein[1]);
@ -553,14 +509,7 @@ pid_t Util::Procs::StartPiped(std::string name, char* const* argv, int * fdin, i
}
return 0;
}else{ //parent
#if DEBUG >= 5
std::cerr << "Piped process " << name << " started";
if (fdin ) std::cerr << " in=" << (*fdin == -1 ? pipein [1] : *fdin );
if (fdout) std::cerr << " out=" << (*fdout == -1 ? pipeout[0] : *fdout);
if (fderr) std::cerr << " err=" << (*fderr == -1 ? pipeerr[0] : *fderr);
if (devnull != -1) std::cerr << " null=" << devnull;
std::cerr << ", PID " << pid << ": " << argv[0] << std::endl;
#endif
DEBUG_MSG(DLVL_DEVEL, "Piped process %s started, PID %d: %s", name.c_str(), pid, argv[0]);
if (devnull != -1){
close(devnull);
}
@ -611,9 +560,7 @@ pid_t Util::Procs::StartPiped(std::string name, std::string cmd, int * fdin, int
pid_t Util::Procs::StartPiped2(std::string name, std::string cmd1, std::string cmd2, int * fdin, int * fdout, int * fderr1, int * fderr2){
int pfildes[2];
if (pipe(pfildes) == -1){
#if DEBUG >= 1
std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Pipe creation failed for process %s", name.c_str());
return 0;
}
pid_t res1 = StartPiped(name, cmd1, fdin, &pfildes[1], fderr1);

View file

@ -2,6 +2,7 @@
/// Holds all code for the RTMPStream namespace.
#include "rtmpchunks.h"
#include "defines.h"
#include "flv_tag.h"
#include "timing.h"
@ -261,9 +262,7 @@ bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme){
uint8_t *pTempHash = new uint8_t[512];
HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash);
bool result = (memcmp(pBuffer + clientDigestOffset, pTempHash, 32) == 0);
#if DEBUG >= 5
fprintf(stderr, "Client scheme validation %hhi %s\n", scheme, result?"success":"failed");
#endif
DEBUG_MSG(DLVL_MEDIUM, "Client scheme validation %hhi %s", scheme, result?"success":"failed");
delete[] pTempBuffer;
delete[] pTempHash;
return result;
@ -556,7 +555,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
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");
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x40 with no valid previous chunk!");
}
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
@ -574,7 +573,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
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");
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x80 with no valid previous chunk!");
}
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
@ -589,7 +588,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
break;
case 0xC0:
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n");
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0xC0 with no valid previous chunk!");
}
timestamp = prev.timestamp;
len = prev.len;
@ -704,7 +703,7 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
} //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");
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x40 with no valid previous chunk!");
}
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
@ -725,7 +724,7 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
} //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");
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x80 with no valid previous chunk!");
}
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
@ -740,7 +739,7 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
break;
case 0xC0:
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n");
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0xC0 with no valid previous chunk!");
}
timestamp = prev.timestamp;
len = prev.len;
@ -821,16 +820,12 @@ bool RTMPStream::doHandshake(){
} //"random" data
bool encrypted = (Version == 6);
#if DEBUG >= 8
fprintf(stderr, "Handshake version is %hhi\n", Version);
#endif
DEBUG_MSG(DLVL_HIGH, "Handshake version is %hhi", Version);
uint8_t _validationScheme = 5;
if (ValidateClientScheme(Client, 0)) _validationScheme = 0;
if (ValidateClientScheme(Client, 1)) _validationScheme = 1;
#if DEBUG >= 8
fprintf(stderr, "Handshake type is %hhi, encryption is %s\n", _validationScheme, encrypted?"on":"off");
#endif
DEBUG_MSG(DLVL_HIGH, "Handshake type is %hhi, encryption is %s", _validationScheme, encrypted?"on":"off");
//FIRST 1536 bytes from server response
//compute DH key position

View file

@ -4,6 +4,7 @@
#include "socket.h"
#include "timing.h"
#include "defines.h"
#include <sys/stat.h>
#include <poll.h>
#include <netdb.h>
@ -14,7 +15,6 @@
#endif
#define BUFFER_BLOCKSIZE 4096 //set buffer blocksize to 4KiB
#include <iostream>//temporary for debugging
std::string uint2string(unsigned int i){
std::stringstream st;
@ -70,7 +70,7 @@ void Socket::Buffer::append(const char * newdata, const unsigned int newdatasize
}
}
if (data.size() > 5000){
std::cerr << "Warning: After " << newdatasize << " new bytes, buffer has " << data.size() << " parts!" << std::endl;
DEBUG_MSG(DLVL_WARN, "Warning: After %d new bytes, buffer has %d parts!", newdatasize, (int)data.size());
}
}
@ -240,9 +240,7 @@ bool Socket::Connection::isBlocking(){
/// If the connection is already closed, nothing happens.
void Socket::Connection::close(){
if (connected()){
#if DEBUG >= 6
fprintf(stderr, "Socket closed.\n");
#endif
DEBUG_MSG(DLVL_HIGH, "Socket %d closed", sock);
if (sock != -1){
shutdown(sock, SHUT_RDWR);
errno = EINTR;
@ -285,9 +283,7 @@ Socket::Connection::Connection(std::string address, bool nonblock){
sock = socket(PF_UNIX, SOCK_STREAM, 0);
if (sock < 0){
remotehost = strerror(errno);
#if DEBUG >= 1
fprintf(stderr, "Could not create socket! Error: %s\n", remotehost.c_str());
#endif
DEBUG_MSG(DLVL_FAIL, "Could not create socket! Error: %s", remotehost.c_str());
return;
}
Error = false;
@ -307,9 +303,7 @@ Socket::Connection::Connection(std::string address, bool nonblock){
}
}else{
remotehost = strerror(errno);
#if DEBUG >= 1
fprintf(stderr, "Could not connect to %s! Error: %s\n", address.c_str(), remotehost.c_str());
#endif
DEBUG_MSG(DLVL_FAIL, "Could not connect to %s! Error: %s", address.c_str(), remotehost.c_str());
close();
}
} //Socket::Connection Unix Contructor
@ -340,9 +334,7 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){
hints.ai_next = NULL;
int s = getaddrinfo(host.c_str(), ss.str().c_str(), &hints, &result);
if (s != 0){
#if DEBUG >= 1
fprintf(stderr, "Could not connect to %s:%i! Error: %s\n", host.c_str(), port, gai_strerror(s));
#endif
DEBUG_MSG(DLVL_FAIL, "Could not connect to %s:%i! Error: %s", host.c_str(), port, gai_strerror(s));
close();
return;
}
@ -362,9 +354,7 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){
freeaddrinfo(result);
if (rp == 0){
#if DEBUG >= 1
fprintf(stderr, "Could not connect to %s! Error: %s\n", host.c_str(), remotehost.c_str());
#endif
DEBUG_MSG(DLVL_FAIL, "Could not connect to %s! Error: %s", host.c_str(), remotehost.c_str());
close();
}else{
if (nonblock){
@ -531,9 +521,7 @@ unsigned int Socket::Connection::iwrite(const void * buffer, int len){
if (errno != EPIPE){
Error = true;
remotehost = strerror(errno);
#if DEBUG >= 2
fprintf(stderr, "Could not iwrite data! Error: %s\n", remotehost.c_str());
#endif
DEBUG_MSG(DLVL_WARN, "Could not iwrite data! Error: %s\n", remotehost.c_str());
}
close();
return 0;
@ -571,9 +559,7 @@ int Socket::Connection::iread(void * buffer, int len){
if (errno != EPIPE){
Error = true;
remotehost = strerror(errno);
#if DEBUG >= 2
fprintf(stderr, "Could not iread data! Error: %s\n", remotehost.c_str());
#endif
DEBUG_MSG(DLVL_WARN, "Could not iread data! Error: %s\n", remotehost.c_str());
}
close();
return 0;
@ -661,7 +647,7 @@ Socket::Server::Server(){
/// \param nonblock (optional) Whether accept() calls will be nonblocking. Default is false (blocking).
Socket::Server::Server(int port, std::string hostname, bool nonblock){
if ( !IPv6bind(port, hostname, nonblock) && !IPv4bind(port, hostname, nonblock)){
fprintf(stderr, "Could not create socket %s:%i! Error: %s\n", hostname.c_str(), port, errors.c_str());
DEBUG_MSG(DLVL_FAIL, "Could not create socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str());
sock = -1;
}
} //Socket::Server TCP Constructor
@ -675,9 +661,7 @@ bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock){
sock = socket(AF_INET6, SOCK_STREAM, 0);
if (sock < 0){
errors = strerror(errno);
#if DEBUG >= 1
fprintf(stderr, "Could not create IPv6 socket %s:%i! Error: %s\n", hostname.c_str(), port, errors.c_str());
#endif
DEBUG_MSG(DLVL_ERROR, "Could not create IPv6 socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str());
return false;
}
int on = 1;
@ -699,23 +683,17 @@ bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock){
if (ret == 0){
ret = listen(sock, 100); //start listening, backlog of 100 allowed
if (ret == 0){
#if DEBUG >= 1
fprintf(stderr, "IPv6 socket success @ %s:%i\n", hostname.c_str(), port);
#endif
DEBUG_MSG(DLVL_DEVEL, "IPv6 socket success @ %s:%i\n", hostname.c_str(), port);
return true;
}else{
errors = strerror(errno);
#if DEBUG >= 1
fprintf(stderr, "IPv6 Listen failed! Error: %s\n", errors.c_str());
#endif
DEBUG_MSG(DLVL_ERROR, "IPv6 listen failed! Error: %s\n", errors.c_str());
close();
return false;
}
}else{
errors = strerror(errno);
#if DEBUG >= 1
fprintf(stderr, "IPv6 Binding %s:%i failed (%s)\n", hostname.c_str(), port, errors.c_str());
#endif
DEBUG_MSG(DLVL_ERROR, "IPv6 Binding %s:%i failed (%s)\n", hostname.c_str(), port, errors.c_str());
close();
return false;
}
@ -730,9 +708,7 @@ bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock){
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0){
errors = strerror(errno);
#if DEBUG >= 1
fprintf(stderr, "Could not create IPv4 socket %s:%i! Error: %s\n", hostname.c_str(), port, errors.c_str());
#endif
DEBUG_MSG(DLVL_ERROR, "Could not create IPv4 socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str());
return false;
}
int on = 1;
@ -754,23 +730,17 @@ bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock){
if (ret == 0){
ret = listen(sock, 100); //start listening, backlog of 100 allowed
if (ret == 0){
#if DEBUG >= 1
fprintf(stderr, "IPv4 socket success @ %s:%i\n", hostname.c_str(), port);
#endif
DEBUG_MSG(DLVL_DEVEL, "IPv4 socket success @ %s:%i\n", hostname.c_str(), port);
return true;
}else{
errors = strerror(errno);
#if DEBUG >= 1
fprintf(stderr, "IPv4 Listen failed! Error: %s\n", errors.c_str());
#endif
DEBUG_MSG(DLVL_ERROR, "IPv4 listen failed! Error: %s\n", errors.c_str());
close();
return false;
}
}else{
errors = strerror(errno);
#if DEBUG >= 1
fprintf(stderr, "IPv4 binding %s:%i failed (%s)\n", hostname.c_str(), port, errors.c_str());
#endif
DEBUG_MSG(DLVL_ERROR, "IPv4 Binding %s:%i failed (%s)\n", hostname.c_str(), port, errors.c_str());
close();
return false;
}
@ -787,9 +757,7 @@ Socket::Server::Server(std::string address, bool nonblock){
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0){
errors = strerror(errno);
#if DEBUG >= 1
fprintf(stderr, "Could not create socket! Error: %s\n", errors.c_str());
#endif
DEBUG_MSG(DLVL_ERROR, "Could not create unix socket %s! Error: %s", address.c_str(), errors.c_str());
return;
}
if (nonblock){
@ -807,17 +775,13 @@ Socket::Server::Server(std::string address, bool nonblock){
return;
}else{
errors = strerror(errno);
#if DEBUG >= 1
fprintf(stderr, "Listen failed! Error: %s\n", errors.c_str());
#endif
DEBUG_MSG(DLVL_ERROR, "Unix listen failed! Error: %s\n", errors.c_str());
close();
return;
}
}else{
errors = strerror(errno);
#if DEBUG >= 1
fprintf(stderr, "Binding failed! Error: %s\n", errors.c_str());
#endif
DEBUG_MSG(DLVL_ERROR, "Unix Binding %s failed (%s)\n", address.c_str(), errors.c_str());
close();
return;
}
@ -845,29 +809,20 @@ Socket::Connection Socket::Server::accept(bool nonblock){
Socket::Connection tmp(r);
if (r < 0){
if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EINTR)){
#if DEBUG >= 1
fprintf(stderr, "Error during accept - closing server socket.\n");
#endif
DEBUG_MSG(DLVL_FAIL, "Error during accept - closing server socket %d.", sock);
close();
}
}else{
if (addrinfo.sin6_family == AF_INET6){
tmp.remotehost = inet_ntop(AF_INET6, &(addrinfo.sin6_addr), addrconv, INET6_ADDRSTRLEN);
#if DEBUG >= 6
fprintf(stderr,"IPv6 addr: %s\n", tmp.remotehost.c_str());
#endif
DEBUG_MSG(DLVL_DEVEL, "IPv6 addr [%s]", tmp.remotehost.c_str());
}
if (addrinfo.sin6_family == AF_INET){
tmp.remotehost = inet_ntop(AF_INET, &(((sockaddr_in*) &addrinfo)->sin_addr), addrconv, INET6_ADDRSTRLEN);
#if DEBUG >= 6
fprintf(stderr,"IPv4 addr: %s\n", tmp.remotehost.c_str());
#endif
DEBUG_MSG(DLVL_DEVEL, "IPv4 addr [%s]", tmp.remotehost.c_str());
}
if (addrinfo.sin6_family == AF_UNIX){
#if DEBUG >= 6
tmp.remotehost = ((sockaddr_un*)&addrinfo)->sun_path;
fprintf(stderr,"Unix socket, no address\n");
#endif
DEBUG_MSG(DLVL_DEVEL, "Unix addr [?]");
tmp.remotehost = "UNIX_SOCKET";
}
}
@ -893,9 +848,7 @@ bool Socket::Server::isBlocking(){
/// If the connection is already closed, nothing happens.
void Socket::Server::close(){
if (connected()){
#if DEBUG >= 6
fprintf(stderr, "ServerSocket closed.\n");
#endif
DEBUG_MSG(DLVL_HIGH, "ServerSocket %d closed", sock);
shutdown(sock, SHUT_RDWR);
errno = EINTR;
while (::close(sock) != 0 && errno == EINTR){

View file

@ -1,10 +1,6 @@
/// \file stream.cpp
/// Utilities for handling streams.
#if DEBUG >= 4
#include <iostream>
#endif
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@ -14,6 +10,7 @@
#include "procs.h"
#include "config.h"
#include "socket.h"
#include "defines.h"
std::string Util::getTmpFolder(){
std::string dir;
@ -83,20 +80,12 @@ Socket::Connection Util::Stream::getStream(std::string streamname){
JSON::Value ServConf = JSON::fromFile(getTmpFolder() + "streamlist");
if (ServConf["streams"].isMember(streamname)){
if (ServConf["streams"][streamname]["source"].asString()[0] == '/'){
#if DEBUG >= 5
std::cerr << "Opening VoD stream from file " << ServConf["streams"][streamname]["source"].asString() << std::endl;
#endif
return getVod(ServConf["streams"][streamname]["source"].asString(), streamname);
}else{
#if DEBUG >= 5
std::cerr << "Opening live stream " << streamname << std::endl;
#endif
return Socket::Connection(getTmpFolder() + "stream_" + streamname);
}
}
#if DEBUG >= 5
std::cerr << "Could not open stream " << streamname << " - stream not found" << std::endl;
#endif
DEBUG_MSG(DLVL_ERROR, "Stream not found: %s", streamname.c_str());
return Socket::Connection();
}

303
lib/tinythread.cpp Normal file
View file

@ -0,0 +1,303 @@
/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*-
Copyright (c) 2010-2012 Marcus Geelnard
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include <exception>
#include "tinythread.h"
#if defined(_TTHREAD_POSIX_)
#include <unistd.h>
#include <map>
#elif defined(_TTHREAD_WIN32_)
#include <process.h>
#endif
namespace tthread {
//------------------------------------------------------------------------------
// condition_variable
//------------------------------------------------------------------------------
// NOTE 1: The Win32 implementation of the condition_variable class is based on
// the corresponding implementation in GLFW, which in turn is based on a
// description by Douglas C. Schmidt and Irfan Pyarali:
// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
//
// NOTE 2: Windows Vista actually has native support for condition variables
// (InitializeConditionVariable, WakeConditionVariable, etc), but we want to
// be portable with pre-Vista Windows versions, so TinyThread++ does not use
// Vista condition variables.
//------------------------------------------------------------------------------
#if defined(_TTHREAD_WIN32_)
#define _CONDITION_EVENT_ONE 0
#define _CONDITION_EVENT_ALL 1
#endif
#if defined(_TTHREAD_WIN32_)
condition_variable::condition_variable() : mWaitersCount(0)
{
mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL);
mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL);
InitializeCriticalSection(&mWaitersCountLock);
}
#endif
#if defined(_TTHREAD_WIN32_)
condition_variable::~condition_variable()
{
CloseHandle(mEvents[_CONDITION_EVENT_ONE]);
CloseHandle(mEvents[_CONDITION_EVENT_ALL]);
DeleteCriticalSection(&mWaitersCountLock);
}
#endif
#if defined(_TTHREAD_WIN32_)
void condition_variable::_wait()
{
// Wait for either event to become signaled due to notify_one() or
// notify_all() being called
int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE);
// Check if we are the last waiter
EnterCriticalSection(&mWaitersCountLock);
-- mWaitersCount;
bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) &&
(mWaitersCount == 0);
LeaveCriticalSection(&mWaitersCountLock);
// If we are the last waiter to be notified to stop waiting, reset the event
if(lastWaiter)
ResetEvent(mEvents[_CONDITION_EVENT_ALL]);
}
#endif
#if defined(_TTHREAD_WIN32_)
void condition_variable::notify_one()
{
// Are there any waiters?
EnterCriticalSection(&mWaitersCountLock);
bool haveWaiters = (mWaitersCount > 0);
LeaveCriticalSection(&mWaitersCountLock);
// If we have any waiting threads, send them a signal
if(haveWaiters)
SetEvent(mEvents[_CONDITION_EVENT_ONE]);
}
#endif
#if defined(_TTHREAD_WIN32_)
void condition_variable::notify_all()
{
// Are there any waiters?
EnterCriticalSection(&mWaitersCountLock);
bool haveWaiters = (mWaitersCount > 0);
LeaveCriticalSection(&mWaitersCountLock);
// If we have any waiting threads, send them a signal
if(haveWaiters)
SetEvent(mEvents[_CONDITION_EVENT_ALL]);
}
#endif
//------------------------------------------------------------------------------
// POSIX pthread_t to unique thread::id mapping logic.
// Note: Here we use a global thread safe std::map to convert instances of
// pthread_t to small thread identifier numbers (unique within one process).
// This method should be portable across different POSIX implementations.
//------------------------------------------------------------------------------
#if defined(_TTHREAD_POSIX_)
static thread::id _pthread_t_to_ID(const pthread_t &aHandle)
{
static mutex idMapLock;
static std::map<pthread_t, unsigned long int> idMap;
static unsigned long int idCount(1);
lock_guard<mutex> guard(idMapLock);
if(idMap.find(aHandle) == idMap.end())
idMap[aHandle] = idCount ++;
return thread::id(idMap[aHandle]);
}
#endif // _TTHREAD_POSIX_
//------------------------------------------------------------------------------
// thread
//------------------------------------------------------------------------------
/// Information to pass to the new thread (what to run).
struct _thread_start_info {
void (*mFunction)(void *); ///< Pointer to the function to be executed.
void * mArg; ///< Function argument for the thread function.
thread * mThread; ///< Pointer to the thread object.
};
// Thread wrapper function.
#if defined(_TTHREAD_WIN32_)
unsigned WINAPI thread::wrapper_function(void * aArg)
#elif defined(_TTHREAD_POSIX_)
void * thread::wrapper_function(void * aArg)
#endif
{
// Get thread startup information
_thread_start_info * ti = (_thread_start_info *) aArg;
try
{
// Call the actual client thread function
ti->mFunction(ti->mArg);
}
catch(...)
{
// Uncaught exceptions will terminate the application (default behavior
// according to C++11)
std::terminate();
}
// The thread is no longer executing
lock_guard<mutex> guard(ti->mThread->mDataMutex);
ti->mThread->mNotAThread = true;
// The thread is responsible for freeing the startup information
delete ti;
return 0;
}
thread::thread(void (*aFunction)(void *), void * aArg)
{
// Serialize access to this thread structure
lock_guard<mutex> guard(mDataMutex);
// Fill out the thread startup information (passed to the thread wrapper,
// which will eventually free it)
_thread_start_info * ti = new _thread_start_info;
ti->mFunction = aFunction;
ti->mArg = aArg;
ti->mThread = this;
// The thread is now alive
mNotAThread = false;
// Create the thread
#if defined(_TTHREAD_WIN32_)
mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID);
#elif defined(_TTHREAD_POSIX_)
if(pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0)
mHandle = 0;
#endif
// Did we fail to create the thread?
if(!mHandle)
{
mNotAThread = true;
delete ti;
}
}
thread::~thread()
{
if(joinable())
std::terminate();
}
void thread::join()
{
if(joinable())
{
#if defined(_TTHREAD_WIN32_)
WaitForSingleObject(mHandle, INFINITE);
CloseHandle(mHandle);
#elif defined(_TTHREAD_POSIX_)
pthread_join(mHandle, NULL);
#endif
}
}
bool thread::joinable() const
{
mDataMutex.lock();
bool result = !mNotAThread;
mDataMutex.unlock();
return result;
}
void thread::detach()
{
mDataMutex.lock();
if(!mNotAThread)
{
#if defined(_TTHREAD_WIN32_)
CloseHandle(mHandle);
#elif defined(_TTHREAD_POSIX_)
pthread_detach(mHandle);
#endif
mNotAThread = true;
}
mDataMutex.unlock();
}
thread::id thread::get_id() const
{
if(!joinable())
return id();
#if defined(_TTHREAD_WIN32_)
return id((unsigned long int) mWin32ThreadID);
#elif defined(_TTHREAD_POSIX_)
return _pthread_t_to_ID(mHandle);
#endif
}
unsigned thread::hardware_concurrency()
{
#if defined(_TTHREAD_WIN32_)
SYSTEM_INFO si;
GetSystemInfo(&si);
return (int) si.dwNumberOfProcessors;
#elif defined(_SC_NPROCESSORS_ONLN)
return (int) sysconf(_SC_NPROCESSORS_ONLN);
#elif defined(_SC_NPROC_ONLN)
return (int) sysconf(_SC_NPROC_ONLN);
#else
// The standard requires this function to return zero if the number of
// hardware cores could not be determined.
return 0;
#endif
}
//------------------------------------------------------------------------------
// this_thread
//------------------------------------------------------------------------------
thread::id this_thread::get_id()
{
#if defined(_TTHREAD_WIN32_)
return thread::id((unsigned long int) GetCurrentThreadId());
#elif defined(_TTHREAD_POSIX_)
return _pthread_t_to_ID(pthread_self());
#endif
}
}

714
lib/tinythread.h Normal file
View file

@ -0,0 +1,714 @@
/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*-
Copyright (c) 2010-2012 Marcus Geelnard
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#ifndef _TINYTHREAD_H_
#define _TINYTHREAD_H_
/// @file
/// @mainpage TinyThread++ API Reference
///
/// @section intro_sec Introduction
/// TinyThread++ is a minimal, portable implementation of basic threading
/// classes for C++.
///
/// They closely mimic the functionality and naming of the C++11 standard, and
/// should be easily replaceable with the corresponding std:: variants.
///
/// @section port_sec Portability
/// The Win32 variant uses the native Win32 API for implementing the thread
/// classes, while for other systems, the POSIX threads API (pthread) is used.
///
/// @section class_sec Classes
/// In order to mimic the threading API of the C++11 standard, subsets of
/// several classes are provided. The fundamental classes are:
/// @li tthread::thread
/// @li tthread::mutex
/// @li tthread::recursive_mutex
/// @li tthread::condition_variable
/// @li tthread::lock_guard
/// @li tthread::fast_mutex
///
/// @section misc_sec Miscellaneous
/// The following special keywords are available: #thread_local.
///
/// For more detailed information (including additional classes), browse the
/// different sections of this documentation. A good place to start is:
/// tinythread.h.
// Which platform are we on?
#if !defined(_TTHREAD_PLATFORM_DEFINED_)
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
#define _TTHREAD_WIN32_
#else
#define _TTHREAD_POSIX_
#endif
#define _TTHREAD_PLATFORM_DEFINED_
#endif
// Platform specific includes
#if defined(_TTHREAD_WIN32_)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#define __UNDEF_LEAN_AND_MEAN
#endif
#include <windows.h>
#ifdef __UNDEF_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#undef __UNDEF_LEAN_AND_MEAN
#endif
#else
#include <pthread.h>
#include <signal.h>
#include <sched.h>
#include <unistd.h>
#endif
// Generic includes
#include <ostream>
/// TinyThread++ version (major number).
#define TINYTHREAD_VERSION_MAJOR 1
/// TinyThread++ version (minor number).
#define TINYTHREAD_VERSION_MINOR 1
/// TinyThread++ version (full version).
#define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR)
// Do we have a fully featured C++11 compiler?
#if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L))
#define _TTHREAD_CPP11_
#endif
// ...at least partial C++11?
#if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__)
#define _TTHREAD_CPP11_PARTIAL_
#endif
// Macro for disabling assignments of objects.
#ifdef _TTHREAD_CPP11_PARTIAL_
#define _TTHREAD_DISABLE_ASSIGNMENT(name) \
name(const name&) = delete; \
name& operator=(const name&) = delete;
#else
#define _TTHREAD_DISABLE_ASSIGNMENT(name) \
name(const name&); \
name& operator=(const name&);
#endif
/// @def thread_local
/// Thread local storage keyword.
/// A variable that is declared with the @c thread_local keyword makes the
/// value of the variable local to each thread (known as thread-local storage,
/// or TLS). Example usage:
/// @code
/// // This variable is local to each thread.
/// thread_local int variable;
/// @endcode
/// @note The @c thread_local keyword is a macro that maps to the corresponding
/// compiler directive (e.g. @c __declspec(thread)). While the C++11 standard
/// allows for non-trivial types (e.g. classes with constructors and
/// destructors) to be declared with the @c thread_local keyword, most pre-C++11
/// compilers only allow for trivial types (e.g. @c int). So, to guarantee
/// portable code, only use trivial types for thread local storage.
/// @note This directive is currently not supported on Mac OS X (it will give
/// a compiler error), since compile-time TLS is not supported in the Mac OS X
/// executable format. Also, some older versions of MinGW (before GCC 4.x) do
/// not support this directive.
/// @hideinitializer
#if !defined(_TTHREAD_CPP11_) && !defined(thread_local)
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
#define thread_local __thread
#else
#define thread_local __declspec(thread)
#endif
#endif
/// Main name space for TinyThread++.
/// This namespace is more or less equivalent to the @c std namespace for the
/// C++11 thread classes. For instance, the tthread::mutex class corresponds to
/// the std::mutex class.
namespace tthread {
/// Mutex class.
/// This is a mutual exclusion object for synchronizing access to shared
/// memory areas for several threads. The mutex is non-recursive (i.e. a
/// program may deadlock if the thread that owns a mutex object calls lock()
/// on that object).
/// @see recursive_mutex
class mutex {
public:
/// Constructor.
mutex()
#if defined(_TTHREAD_WIN32_)
: mAlreadyLocked(false)
#endif
{
#if defined(_TTHREAD_WIN32_)
InitializeCriticalSection(&mHandle);
#else
pthread_mutex_init(&mHandle, NULL);
#endif
}
/// Destructor.
~mutex()
{
#if defined(_TTHREAD_WIN32_)
DeleteCriticalSection(&mHandle);
#else
pthread_mutex_destroy(&mHandle);
#endif
}
/// Lock the mutex.
/// The method will block the calling thread until a lock on the mutex can
/// be obtained. The mutex remains locked until @c unlock() is called.
/// @see lock_guard
inline void lock()
{
#if defined(_TTHREAD_WIN32_)
EnterCriticalSection(&mHandle);
while(mAlreadyLocked) Sleep(1000); // Simulate deadlock...
mAlreadyLocked = true;
#else
pthread_mutex_lock(&mHandle);
#endif
}
/// Try to lock the mutex.
/// The method will try to lock the mutex. If it fails, the function will
/// return immediately (non-blocking).
/// @return @c true if the lock was acquired, or @c false if the lock could
/// not be acquired.
inline bool try_lock()
{
#if defined(_TTHREAD_WIN32_)
bool ret = (TryEnterCriticalSection(&mHandle) ? true : false);
if(ret && mAlreadyLocked)
{
LeaveCriticalSection(&mHandle);
ret = false;
}
return ret;
#else
return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
#endif
}
/// Unlock the mutex.
/// If any threads are waiting for the lock on this mutex, one of them will
/// be unblocked.
inline void unlock()
{
#if defined(_TTHREAD_WIN32_)
mAlreadyLocked = false;
LeaveCriticalSection(&mHandle);
#else
pthread_mutex_unlock(&mHandle);
#endif
}
_TTHREAD_DISABLE_ASSIGNMENT(mutex)
private:
#if defined(_TTHREAD_WIN32_)
CRITICAL_SECTION mHandle;
bool mAlreadyLocked;
#else
pthread_mutex_t mHandle;
#endif
friend class condition_variable;
};
/// Recursive mutex class.
/// This is a mutual exclusion object for synchronizing access to shared
/// memory areas for several threads. The mutex is recursive (i.e. a thread
/// may lock the mutex several times, as long as it unlocks the mutex the same
/// number of times).
/// @see mutex
class recursive_mutex {
public:
/// Constructor.
recursive_mutex()
{
#if defined(_TTHREAD_WIN32_)
InitializeCriticalSection(&mHandle);
#else
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mHandle, &attr);
#endif
}
/// Destructor.
~recursive_mutex()
{
#if defined(_TTHREAD_WIN32_)
DeleteCriticalSection(&mHandle);
#else
pthread_mutex_destroy(&mHandle);
#endif
}
/// Lock the mutex.
/// The method will block the calling thread until a lock on the mutex can
/// be obtained. The mutex remains locked until @c unlock() is called.
/// @see lock_guard
inline void lock()
{
#if defined(_TTHREAD_WIN32_)
EnterCriticalSection(&mHandle);
#else
pthread_mutex_lock(&mHandle);
#endif
}
/// Try to lock the mutex.
/// The method will try to lock the mutex. If it fails, the function will
/// return immediately (non-blocking).
/// @return @c true if the lock was acquired, or @c false if the lock could
/// not be acquired.
inline bool try_lock()
{
#if defined(_TTHREAD_WIN32_)
return TryEnterCriticalSection(&mHandle) ? true : false;
#else
return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
#endif
}
/// Unlock the mutex.
/// If any threads are waiting for the lock on this mutex, one of them will
/// be unblocked.
inline void unlock()
{
#if defined(_TTHREAD_WIN32_)
LeaveCriticalSection(&mHandle);
#else
pthread_mutex_unlock(&mHandle);
#endif
}
_TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex)
private:
#if defined(_TTHREAD_WIN32_)
CRITICAL_SECTION mHandle;
#else
pthread_mutex_t mHandle;
#endif
friend class condition_variable;
};
/// Lock guard class.
/// The constructor locks the mutex, and the destructor unlocks the mutex, so
/// the mutex will automatically be unlocked when the lock guard goes out of
/// scope. Example usage:
/// @code
/// mutex m;
/// int counter;
///
/// void increment()
/// {
/// lock_guard<mutex> guard(m);
/// ++ counter;
/// }
/// @endcode
template <class T>
class lock_guard {
public:
typedef T mutex_type;
lock_guard() : mMutex(0) {}
/// The constructor locks the mutex.
explicit lock_guard(mutex_type &aMutex)
{
mMutex = &aMutex;
mMutex->lock();
}
/// The destructor unlocks the mutex.
~lock_guard()
{
if(mMutex)
mMutex->unlock();
}
private:
mutex_type * mMutex;
};
/// Condition variable class.
/// This is a signalling object for synchronizing the execution flow for
/// several threads. Example usage:
/// @code
/// // Shared data and associated mutex and condition variable objects
/// int count;
/// mutex m;
/// condition_variable cond;
///
/// // Wait for the counter to reach a certain number
/// void wait_counter(int targetCount)
/// {
/// lock_guard<mutex> guard(m);
/// while(count < targetCount)
/// cond.wait(m);
/// }
///
/// // Increment the counter, and notify waiting threads
/// void increment()
/// {
/// lock_guard<mutex> guard(m);
/// ++ count;
/// cond.notify_all();
/// }
/// @endcode
class condition_variable {
public:
/// Constructor.
#if defined(_TTHREAD_WIN32_)
condition_variable();
#else
condition_variable()
{
pthread_cond_init(&mHandle, NULL);
}
#endif
/// Destructor.
#if defined(_TTHREAD_WIN32_)
~condition_variable();
#else
~condition_variable()
{
pthread_cond_destroy(&mHandle);
}
#endif
/// Wait for the condition.
/// The function will block the calling thread until the condition variable
/// is woken by @c notify_one(), @c notify_all() or a spurious wake up.
/// @param[in] aMutex A mutex that will be unlocked when the wait operation
/// starts, an locked again as soon as the wait operation is finished.
template <class _mutexT>
inline void wait(_mutexT &aMutex)
{
#if defined(_TTHREAD_WIN32_)
// Increment number of waiters
EnterCriticalSection(&mWaitersCountLock);
++ mWaitersCount;
LeaveCriticalSection(&mWaitersCountLock);
// Release the mutex while waiting for the condition (will decrease
// the number of waiters when done)...
aMutex.unlock();
_wait();
aMutex.lock();
#else
pthread_cond_wait(&mHandle, &aMutex.mHandle);
#endif
}
/// Notify one thread that is waiting for the condition.
/// If at least one thread is blocked waiting for this condition variable,
/// one will be woken up.
/// @note Only threads that started waiting prior to this call will be
/// woken up.
#if defined(_TTHREAD_WIN32_)
void notify_one();
#else
inline void notify_one()
{
pthread_cond_signal(&mHandle);
}
#endif
/// Notify all threads that are waiting for the condition.
/// All threads that are blocked waiting for this condition variable will
/// be woken up.
/// @note Only threads that started waiting prior to this call will be
/// woken up.
#if defined(_TTHREAD_WIN32_)
void notify_all();
#else
inline void notify_all()
{
pthread_cond_broadcast(&mHandle);
}
#endif
_TTHREAD_DISABLE_ASSIGNMENT(condition_variable)
private:
#if defined(_TTHREAD_WIN32_)
void _wait();
HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs.
unsigned int mWaitersCount; ///< Count of the number of waiters.
CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount.
#else
pthread_cond_t mHandle;
#endif
};
/// Thread class.
class thread {
public:
#if defined(_TTHREAD_WIN32_)
typedef HANDLE native_handle_type;
#else
typedef pthread_t native_handle_type;
#endif
class id;
/// Default constructor.
/// Construct a @c thread object without an associated thread of execution
/// (i.e. non-joinable).
thread() : mHandle(0), mNotAThread(true)
#if defined(_TTHREAD_WIN32_)
, mWin32ThreadID(0)
#endif
{}
/// Thread starting constructor.
/// Construct a @c thread object with a new thread of execution.
/// @param[in] aFunction A function pointer to a function of type:
/// <tt>void fun(void * arg)</tt>
/// @param[in] aArg Argument to the thread function.
/// @note This constructor is not fully compatible with the standard C++
/// thread class. It is more similar to the pthread_create() (POSIX) and
/// CreateThread() (Windows) functions.
thread(void (*aFunction)(void *), void * aArg);
/// Destructor.
/// @note If the thread is joinable upon destruction, @c std::terminate()
/// will be called, which terminates the process. It is always wise to do
/// @c join() before deleting a thread object.
~thread();
/// Wait for the thread to finish (join execution flows).
/// After calling @c join(), the thread object is no longer associated with
/// a thread of execution (i.e. it is not joinable, and you may not join
/// with it nor detach from it).
void join();
/// Check if the thread is joinable.
/// A thread object is joinable if it has an associated thread of execution.
bool joinable() const;
/// Detach from the thread.
/// After calling @c detach(), the thread object is no longer assicated with
/// a thread of execution (i.e. it is not joinable). The thread continues
/// execution without the calling thread blocking, and when the thread
/// ends execution, any owned resources are released.
void detach();
/// Return the thread ID of a thread object.
id get_id() const;
/// Get the native handle for this thread.
/// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this
/// is a @c pthread_t.
inline native_handle_type native_handle()
{
return mHandle;
}
/// Determine the number of threads which can possibly execute concurrently.
/// This function is useful for determining the optimal number of threads to
/// use for a task.
/// @return The number of hardware thread contexts in the system.
/// @note If this value is not defined, the function returns zero (0).
static unsigned hardware_concurrency();
_TTHREAD_DISABLE_ASSIGNMENT(thread)
private:
native_handle_type mHandle; ///< Thread handle.
mutable mutex mDataMutex; ///< Serializer for access to the thread private data.
bool mNotAThread; ///< True if this object is not a thread of execution.
#if defined(_TTHREAD_WIN32_)
unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex).
#endif
// This is the internal thread wrapper function.
#if defined(_TTHREAD_WIN32_)
static unsigned WINAPI wrapper_function(void * aArg);
#else
static void * wrapper_function(void * aArg);
#endif
};
/// Thread ID.
/// The thread ID is a unique identifier for each thread.
/// @see thread::get_id()
class thread::id {
public:
/// Default constructor.
/// The default constructed ID is that of thread without a thread of
/// execution.
id() : mId(0) {};
id(unsigned long int aId) : mId(aId) {};
id(const id& aId) : mId(aId.mId) {};
inline id & operator=(const id &aId)
{
mId = aId.mId;
return *this;
}
inline friend bool operator==(const id &aId1, const id &aId2)
{
return (aId1.mId == aId2.mId);
}
inline friend bool operator!=(const id &aId1, const id &aId2)
{
return (aId1.mId != aId2.mId);
}
inline friend bool operator<=(const id &aId1, const id &aId2)
{
return (aId1.mId <= aId2.mId);
}
inline friend bool operator<(const id &aId1, const id &aId2)
{
return (aId1.mId < aId2.mId);
}
inline friend bool operator>=(const id &aId1, const id &aId2)
{
return (aId1.mId >= aId2.mId);
}
inline friend bool operator>(const id &aId1, const id &aId2)
{
return (aId1.mId > aId2.mId);
}
inline friend std::ostream& operator <<(std::ostream &os, const id &obj)
{
os << obj.mId;
return os;
}
private:
unsigned long int mId;
};
// Related to <ratio> - minimal to be able to support chrono.
typedef long long __intmax_t;
/// Minimal implementation of the @c ratio class. This class provides enough
/// functionality to implement some basic @c chrono classes.
template <__intmax_t N, __intmax_t D = 1> class ratio {
public:
static double _as_double() { return double(N) / double(D); }
};
/// Minimal implementation of the @c chrono namespace.
/// The @c chrono namespace provides types for specifying time intervals.
namespace chrono {
/// Duration template class. This class provides enough functionality to
/// implement @c this_thread::sleep_for().
template <class _Rep, class _Period = ratio<1> > class duration {
private:
_Rep rep_;
public:
typedef _Rep rep;
typedef _Period period;
/// Construct a duration object with the given duration.
template <class _Rep2>
explicit duration(const _Rep2& r) : rep_(r) {};
/// Return the value of the duration object.
rep count() const
{
return rep_;
}
};
// Standard duration types.
typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds.
typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds.
typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds.
typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds.
typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes.
typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours.
}
/// The namespace @c this_thread provides methods for dealing with the
/// calling thread.
namespace this_thread {
/// Return the thread ID of the calling thread.
thread::id get_id();
/// Yield execution to another thread.
/// Offers the operating system the opportunity to schedule another thread
/// that is ready to run on the current processor.
inline void yield()
{
#if defined(_TTHREAD_WIN32_)
Sleep(0);
#else
sched_yield();
#endif
}
/// Blocks the calling thread for a period of time.
/// @param[in] aTime Minimum time to put the thread to sleep.
/// Example usage:
/// @code
/// // Sleep for 100 milliseconds
/// this_thread::sleep_for(chrono::milliseconds(100));
/// @endcode
/// @note Supported duration types are: nanoseconds, microseconds,
/// milliseconds, seconds, minutes and hours.
template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period>& aTime)
{
#if defined(_TTHREAD_WIN32_)
Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5));
#else
usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5));
#endif
}
}
}
// Define/macro cleanup
#undef _TTHREAD_DISABLE_ASSIGNMENT
#endif // _TINYTHREAD_H_

View file

@ -3,6 +3,7 @@
#include <sstream>
#include "ts_packet.h"
#include "defines.h"
#ifndef FILLER_DATA
#define FILLER_DATA "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent commodo vulputate urna eu commodo. Cras tempor velit nec nulla placerat volutpat. Proin eleifend blandit quam sit amet suscipit. Pellentesque vitae tristique lorem. Maecenas facilisis consequat neque, vitae iaculis eros vulputate ut. Suspendisse ut arcu non eros vestibulum pulvinar id sed erat. Nam dictum tellus vel tellus rhoncus ut mollis tellus fermentum. Fusce volutpat consectetur ante, in mollis nisi euismod vulputate. Curabitur vitae facilisis ligula. Sed sed gravida dolor. Integer eu eros a dolor lobortis ullamcorper. Mauris interdum elit non neque interdum dictum. Suspendisse imperdiet eros sed sapien cursus pulvinar. Vestibulum ut dolor lectus, id commodo elit. Cras convallis varius leo eu porta. Duis luctus sapien nec dui adipiscing quis interdum nunc congue. Morbi pharetra aliquet mauris vitae tristique. Etiam feugiat sapien quis augue elementum id ultricies magna vulputate. Phasellus luctus, leo id egestas consequat, eros tortor commodo neque, vitae hendrerit nunc sem ut odio."
@ -236,7 +237,7 @@ void TS::Packet::DefaultPMT(){
/// \return A string representation of the packet.
const char* TS::Packet::ToString(){
if (strBuf.size() != 188){
std::cerr << "Error: Size invalid (" << strBuf.size() << ") Invalid data from this point on." << std::endl;
DEBUG_MSG(DLVL_ERROR, "Size invalid (%i) - invalid data from this point on", (int)strBuf.size());
}
return strBuf.c_str();
}

View file

@ -1,4 +1,5 @@
#include "vorbis.h"
#include "defines.h"
#include <stdlib.h>
#include <string.h>
#include <sstream>
@ -236,7 +237,7 @@ namespace vorbis{
long long unsigned int floorType = stream.get(16);
switch(floorType){
case 0:{
std::cerr << "WARNING: FloorType 0 in vorbis setup header not tested!" << std::endl;
DEBUG_MSG(DLVL_WARN, "FloorType 0 in vorbis setup header not tested!");
stream.skip(8);//order
stream.skip(16);//rate
stream.skip(16);//bark_map_size
@ -339,7 +340,7 @@ namespace vorbis{
}
char meh = stream.get(2);
if (meh != 0){
std::cerr << " Sanity Check ==0 : " << (int)meh << std::endl;
DEBUG_MSG(DLVL_ERROR, "Sanity check ==0 : %i", (int)meh);
exit(0);
}
if (mappingSubmaps > 1){