Prettified error messages, first work on Util::Config server helpers.
This commit is contained in:
parent
c6f63dfb95
commit
5c0f053006
25 changed files with 1254 additions and 327 deletions
4
Makefile
4
Makefile
|
@ -13,7 +13,9 @@ endif
|
||||||
CPPFLAGS = -Wall -g -O2 -fPIC
|
CPPFLAGS = -Wall -g -O2 -fPIC
|
||||||
override CPPFLAGS += -funsigned-char -DDEBUG="$(DEBUG)" -DPACKAGE_VERSION="\"$(PACKAGE_VERSION)\""
|
override CPPFLAGS += -funsigned-char -DDEBUG="$(DEBUG)" -DPACKAGE_VERSION="\"$(PACKAGE_VERSION)\""
|
||||||
|
|
||||||
LDLIBS = -lcrypto -lrt
|
LDLIBS = -lcrypto
|
||||||
|
THREADLIB = -lpthread -lrt
|
||||||
|
LDLIBS = -lcrypto $(THREADLIB)
|
||||||
|
|
||||||
|
|
||||||
.DEFAULT_GOAL := all
|
.DEFAULT_GOAL := all
|
||||||
|
|
3
README
3
README
|
@ -6,6 +6,9 @@
|
||||||
| See COPYING file for full license |
|
| 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:
|
The latest version of this code can always be found at:
|
||||||
https://github.com/DDVTECH/mistlib
|
https://github.com/DDVTECH/mistlib
|
||||||
|
|
78
lib/amf.cpp
78
lib/amf.cpp
|
@ -2,8 +2,8 @@
|
||||||
/// Holds all code for the AMF namespace.
|
/// Holds all code for the AMF namespace.
|
||||||
|
|
||||||
#include "amf.h"
|
#include "amf.h"
|
||||||
|
#include "defines.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cstdio> //needed for stderr only
|
|
||||||
/// Returns the std::string Indice for the current object, if available.
|
/// Returns the std::string Indice for the current object, if available.
|
||||||
/// Returns an empty string if no indice exists.
|
/// Returns an empty string if no indice exists.
|
||||||
std::string AMF::Object::Indice(){
|
std::string AMF::Object::Indice(){
|
||||||
|
@ -124,9 +124,9 @@ AMF::Object::Object(std::string indice, AMF::obj0type setType){ //object type in
|
||||||
numval = 0;
|
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
|
/// 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::string AMF::Object::Print(std::string indent){
|
||||||
std::stringstream st;
|
std::stringstream st;
|
||||||
st << indent;
|
st << indent;
|
||||||
|
@ -368,9 +368,6 @@ AMF::Object AMF::parseOne(const unsigned char *& data, unsigned int &len, unsign
|
||||||
unsigned int tmpi = 0;
|
unsigned int tmpi = 0;
|
||||||
unsigned char tmpdbl[8];
|
unsigned char tmpdbl[8];
|
||||||
double *d; // hack to work around strict aliasing
|
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]){
|
switch (data[i]){
|
||||||
case AMF::AMF0_NUMBER:
|
case AMF::AMF0_NUMBER:
|
||||||
tmpdbl[7] = data[i + 1];
|
tmpdbl[7] = data[i + 1];
|
||||||
|
@ -496,9 +493,7 @@ AMF::Object AMF::parseOne(const unsigned char *& data, unsigned int &len, unsign
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#if DEBUG >= 2
|
DEBUG_MSG(DLVL_ERROR, "Error: Unimplemented AMF type %hhx - returning.", data[i]);
|
||||||
fprintf(stderr, "Error: Unimplemented AMF type %hhx - returning.\n", data[i]);
|
|
||||||
#endif
|
|
||||||
return AMF::Object("error", AMF::AMF0_DDV_CONTAINER);
|
return AMF::Object("error", AMF::AMF0_DDV_CONTAINER);
|
||||||
} //parseOne
|
} //parseOne
|
||||||
|
|
||||||
|
@ -668,99 +663,101 @@ AMF::Object3::Object3(std::string indice, AMF::obj3type setType){ //object type
|
||||||
intval = 0;
|
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
|
/// 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.
|
||||||
void AMF::Object3::Print(std::string indent){
|
std::string AMF::Object3::Print(std::string indent){
|
||||||
std::cerr << indent;
|
std::stringstream st;
|
||||||
|
st << indent;
|
||||||
// print my type
|
// print my type
|
||||||
switch (myType){
|
switch (myType){
|
||||||
case AMF::AMF3_UNDEFINED:
|
case AMF::AMF3_UNDEFINED:
|
||||||
std::cerr << "Undefined";
|
st << "Undefined";
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_NULL:
|
case AMF::AMF3_NULL:
|
||||||
std::cerr << "Null";
|
st << "Null";
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_FALSE:
|
case AMF::AMF3_FALSE:
|
||||||
std::cerr << "False";
|
st << "False";
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_TRUE:
|
case AMF::AMF3_TRUE:
|
||||||
std::cerr << "True";
|
st << "True";
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_INTEGER:
|
case AMF::AMF3_INTEGER:
|
||||||
std::cerr << "Integer";
|
st << "Integer";
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_DOUBLE:
|
case AMF::AMF3_DOUBLE:
|
||||||
std::cerr << "Double";
|
st << "Double";
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_STRING:
|
case AMF::AMF3_STRING:
|
||||||
std::cerr << "String";
|
st << "String";
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_XMLDOC:
|
case AMF::AMF3_XMLDOC:
|
||||||
std::cerr << "XML Doc";
|
st << "XML Doc";
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_DATE:
|
case AMF::AMF3_DATE:
|
||||||
std::cerr << "Date";
|
st << "Date";
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_ARRAY:
|
case AMF::AMF3_ARRAY:
|
||||||
std::cerr << "Array";
|
st << "Array";
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_OBJECT:
|
case AMF::AMF3_OBJECT:
|
||||||
std::cerr << "Object";
|
st << "Object";
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_XML:
|
case AMF::AMF3_XML:
|
||||||
std::cerr << "XML";
|
st << "XML";
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_BYTES:
|
case AMF::AMF3_BYTES:
|
||||||
std::cerr << "ByteArray";
|
st << "ByteArray";
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_DDV_CONTAINER:
|
case AMF::AMF3_DDV_CONTAINER:
|
||||||
std::cerr << "DDVTech Container";
|
st << "DDVTech Container";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// print my string indice, if available
|
// print my string indice, if available
|
||||||
std::cerr << " " << myIndice << " ";
|
st << " " << myIndice << " ";
|
||||||
// print my numeric or string contents
|
// print my numeric or string contents
|
||||||
switch (myType){
|
switch (myType){
|
||||||
case AMF::AMF3_INTEGER:
|
case AMF::AMF3_INTEGER:
|
||||||
std::cerr << intval;
|
st << intval;
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_DOUBLE:
|
case AMF::AMF3_DOUBLE:
|
||||||
std::cerr << dblval;
|
st << dblval;
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_STRING:
|
case AMF::AMF3_STRING:
|
||||||
case AMF::AMF3_XMLDOC:
|
case AMF::AMF3_XMLDOC:
|
||||||
case AMF::AMF3_XML:
|
case AMF::AMF3_XML:
|
||||||
case AMF::AMF3_BYTES:
|
case AMF::AMF3_BYTES:
|
||||||
if (intval > 0){
|
if (intval > 0){
|
||||||
std::cerr << "REF" << intval;
|
st << "REF" << intval;
|
||||||
}else{
|
}else{
|
||||||
std::cerr << strval;
|
st << strval;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_DATE:
|
case AMF::AMF3_DATE:
|
||||||
if (intval > 0){
|
if (intval > 0){
|
||||||
std::cerr << "REF" << intval;
|
st << "REF" << intval;
|
||||||
}else{
|
}else{
|
||||||
std::cerr << dblval;
|
st << dblval;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AMF::AMF3_ARRAY:
|
case AMF::AMF3_ARRAY:
|
||||||
case AMF::AMF3_OBJECT:
|
case AMF::AMF3_OBJECT:
|
||||||
if (intval > 0){
|
if (intval > 0){
|
||||||
std::cerr << "REF" << intval;
|
st << "REF" << intval;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break; //we don't care about the rest, and don't want a compiler warning...
|
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 I hold other objects, print those too, recursively.
|
||||||
if (contents.size() > 0){
|
if (contents.size() > 0){
|
||||||
for (std::vector<AMF::Object3>::iterator it = contents.begin(); it != contents.end(); it++){
|
for (std::vector<AMF::Object3>::iterator it = contents.begin(); it != contents.end(); it++){
|
||||||
it->Print(indent + " ");
|
st << it->Print(indent + " ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return st.str();
|
||||||
} //print
|
} //print
|
||||||
|
|
||||||
/// Packs the AMF object to a std::string for transfer over the network.
|
/// 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 int arrsize = 0;
|
||||||
unsigned char tmpdbl[8];
|
unsigned char tmpdbl[8];
|
||||||
double *d; // hack to work around strict aliasing
|
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]){
|
switch (data[i]){
|
||||||
case AMF::AMF3_UNDEFINED:
|
case AMF::AMF3_UNDEFINED:
|
||||||
case AMF::AMF3_NULL:
|
case AMF::AMF3_NULL:
|
||||||
|
@ -1121,9 +1115,7 @@ AMF::Object3 AMF::parseOne3(const unsigned char *& data, unsigned int &len, unsi
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#if DEBUG >= 2
|
DEBUG_MSG(DLVL_ERROR, "Error: Unimplemented AMF3 type %hhx - returning.", data[i]);
|
||||||
fprintf(stderr, "Error: Unimplemented AMF3 type %hhx - returning.\n", data[i]);
|
|
||||||
#endif
|
|
||||||
return AMF::Object3("error", AMF::AMF3_DDV_CONTAINER);
|
return AMF::Object3("error", AMF::AMF3_DDV_CONTAINER);
|
||||||
} //parseOne
|
} //parseOne
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ namespace AMF {
|
||||||
Object3(std::string indice, double val, obj3type setType = AMF3_DOUBLE);
|
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, std::string val, obj3type setType = AMF3_STRING);
|
||||||
Object3(std::string indice, obj3type setType = AMF3_OBJECT);
|
Object3(std::string indice, obj3type setType = AMF3_OBJECT);
|
||||||
void Print(std::string indent = "");
|
std::string Print(std::string indent = "");
|
||||||
std::string Pack();
|
std::string Pack();
|
||||||
protected:
|
protected:
|
||||||
std::string myIndice; ///< Holds this objects indice, if any.
|
std::string myIndice; ///< Holds this objects indice, if any.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include"bitstream.h"
|
#include "bitstream.h"
|
||||||
#include<stdlib.h>
|
#include "defines.h"
|
||||||
#include<string.h>
|
#include <stdlib.h>
|
||||||
#include<iostream>
|
#include <string.h>
|
||||||
|
|
||||||
namespace Utils{
|
namespace Utils{
|
||||||
bitstream::bitstream(){
|
bitstream::bitstream(){
|
||||||
|
@ -31,7 +31,6 @@ namespace Utils{
|
||||||
memcpy(data+dataSize, input, bytes);
|
memcpy(data+dataSize, input, bytes);
|
||||||
dataSize += bytes;
|
dataSize += bytes;
|
||||||
}
|
}
|
||||||
//std::cout << std::hex << std::string(data, dataSize) << std::dec << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bitstream::append(std::string input){
|
void bitstream::append(std::string input){
|
||||||
|
@ -45,11 +44,11 @@ namespace Utils{
|
||||||
|
|
||||||
long long unsigned int bitstream::peek(size_t count){
|
long long unsigned int bitstream::peek(size_t count){
|
||||||
if (count > 64){
|
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;
|
//return 0;
|
||||||
}
|
}
|
||||||
if (count > size()){
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
long long unsigned int retval = 0;
|
long long unsigned int retval = 0;
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
/// Contains generic functions for managing configuration.
|
/// Contains generic functions for managing configuration.
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "defines.h"
|
||||||
|
#include "timing.h"
|
||||||
|
#include "tinythread.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
@ -22,7 +25,6 @@
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <dirent.h> //for getMyExec
|
#include <dirent.h> //for getMyExec
|
||||||
|
|
||||||
|
@ -295,6 +297,46 @@ bool Util::Config::getBool(std::string optname){
|
||||||
return getOption(optname).asBool();
|
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:
|
/// Activated the stored config. This will:
|
||||||
/// - Drop permissions to the stored "username", if any.
|
/// - Drop permissions to the stored "username", if any.
|
||||||
/// - Daemonize the process if "daemonize" exists and is true.
|
/// - Daemonize the process if "daemonize" exists and is true.
|
||||||
|
@ -450,19 +492,13 @@ void Util::setUser(std::string username){
|
||||||
if (username != "root"){
|
if (username != "root"){
|
||||||
struct passwd * user_info = getpwnam(username.c_str());
|
struct passwd * user_info = getpwnam(username.c_str());
|
||||||
if ( !user_info){
|
if ( !user_info){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Error: could not setuid %s: could not get PID", username.c_str());
|
||||||
fprintf(stderr, "Error: could not setuid %s: could not get PID\n", username.c_str());
|
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}else{
|
}else{
|
||||||
if (setuid(user_info->pw_uid) != 0){
|
if (setuid(user_info->pw_uid) != 0){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Error: could not setuid %s: not allowed", username.c_str());
|
||||||
fprintf(stderr, "Error: could not setuid %s: not allowed\n", username.c_str());
|
|
||||||
#endif
|
|
||||||
}else{
|
}else{
|
||||||
#if DEBUG >= 3
|
DEBUG_MSG(DLVL_DEVEL, "Change user to %s", username.c_str());
|
||||||
fprintf(stderr, "Changed user to %s\n", username.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -473,12 +509,8 @@ void Util::setUser(std::string username){
|
||||||
/// Does not change directory to root.
|
/// Does not change directory to root.
|
||||||
/// Does redirect output to /dev/null
|
/// Does redirect output to /dev/null
|
||||||
void Util::Daemonize(){
|
void Util::Daemonize(){
|
||||||
#if DEBUG >= 3
|
DEBUG_MSG(DLVL_DEVEL, "Going into background mode...");
|
||||||
fprintf(stderr, "Going into background mode...\n");
|
|
||||||
#endif
|
|
||||||
if (daemon(1, 0) < 0){
|
if (daemon(1, 0) < 0){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Failed to daemonize: %s", strerror(errno));
|
||||||
fprintf(stderr, "Failed to daemonize: %s\n", strerror(errno));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,9 @@ namespace Util {
|
||||||
long long int getInteger(std::string optname);
|
long long int getInteger(std::string optname);
|
||||||
bool getBool(std::string optname);
|
bool getBool(std::string optname);
|
||||||
void activate();
|
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 addBasicConnectorOptions(JSON::Value & capabilities);
|
||||||
void addConnectorOptions(int port, JSON::Value & capabilities);
|
void addConnectorOptions(int port, JSON::Value & capabilities);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -69,7 +68,6 @@ namespace Converter {
|
||||||
char const * cmd[3] = {0, 0, 0};
|
char const * cmd[3] = {0, 0, 0};
|
||||||
std::string mistPath = Util::getMyPath() + "MistInfo";
|
std::string mistPath = Util::getMyPath() + "MistInfo";
|
||||||
cmd[0] = mistPath.c_str();
|
cmd[0] = mistPath.c_str();
|
||||||
fprintf( stderr, "Querying %s\n", myPath.c_str());
|
|
||||||
JSON::Value result;
|
JSON::Value result;
|
||||||
DIR * Dirp = opendir(myPath.c_str());
|
DIR * Dirp = opendir(myPath.c_str());
|
||||||
struct stat StatBuf;
|
struct stat StatBuf;
|
||||||
|
|
18
lib/defines.h
Normal file
18
lib/defines.h
Normal 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
|
65
lib/dtsc.cpp
65
lib/dtsc.cpp
|
@ -2,6 +2,7 @@
|
||||||
/// Holds all code for DDVTECH Stream Container parsing/generation.
|
/// Holds all code for DDVTECH Stream Container parsing/generation.
|
||||||
|
|
||||||
#include "dtsc.h"
|
#include "dtsc.h"
|
||||||
|
#include "defines.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h> //for memcmp
|
#include <string.h> //for memcmp
|
||||||
#include <arpa/inet.h> //for htonl/ntohl
|
#include <arpa/inet.h> //for htonl/ntohl
|
||||||
|
@ -87,9 +88,9 @@ bool DTSC::Stream::parsePacket(std::string & buffer){
|
||||||
syncing = false;
|
syncing = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#if DEBUG >= 2
|
#if DEBUG >= DLVL_WARN
|
||||||
if (!syncing){
|
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;
|
syncing = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -155,9 +156,9 @@ bool DTSC::Stream::parsePacket(Socket::Buffer & buffer){
|
||||||
syncing = false;
|
syncing = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#if DEBUG >= 2
|
#if DEBUG >= DLVL_WARN
|
||||||
if (!syncing){
|
if (!syncing){
|
||||||
std::cerr << "Error: Invalid DTMI data detected - syncing" << std::endl;
|
DEBUG_MSG(DLVL_WARN, "Invalid DTMI data detected - syncing");
|
||||||
syncing = true;
|
syncing = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -206,9 +207,7 @@ void DTSC::Stream::waitForMeta(Socket::Connection & sourceSocket){
|
||||||
if (Util::getMS() - start >= 5000){
|
if (Util::getMS() - start >= 5000){
|
||||||
sourceSocket.close();
|
sourceSocket.close();
|
||||||
//and optionally print a debug message that this happened
|
//and optionally print a debug message that this happened
|
||||||
#if DEBUG >= 4
|
DEBUG_MSG(DLVL_DEVEL, "Timing out while waiting for metadata");
|
||||||
fprintf(stderr, "Timed out while waiting for metadata\n");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
/// 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(){
|
void DTSC::Stream::cutOneBuffer(){
|
||||||
int trid = buffers.begin()->first.trackID;
|
int trid = buffers.begin()->first.trackID;
|
||||||
long long unsigned int delTime = buffers.begin()->first.seekTime;
|
long long unsigned int delTime = buffers.begin()->first.seekTime;
|
||||||
|
@ -517,7 +516,7 @@ DTSC::File::File(std::string filename, bool create){
|
||||||
if (create){
|
if (create){
|
||||||
F = fopen(filename.c_str(), "w+b");
|
F = fopen(filename.c_str(), "w+b");
|
||||||
if(!F){
|
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;
|
return;
|
||||||
}
|
}
|
||||||
//write an empty header
|
//write an empty header
|
||||||
|
@ -531,7 +530,7 @@ DTSC::File::File(std::string filename, bool create){
|
||||||
}
|
}
|
||||||
created = create;
|
created = create;
|
||||||
if ( !F){
|
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;
|
return;
|
||||||
}
|
}
|
||||||
fseek(F, 0, SEEK_END);
|
fseek(F, 0, SEEK_END);
|
||||||
|
@ -561,7 +560,7 @@ DTSC::readOnlyMeta & DTSC::File::getMeta(){
|
||||||
/// Forces a write if force is set to true.
|
/// Forces a write if force is set to true.
|
||||||
bool DTSC::File::writeHeader(std::string & header, bool force){
|
bool DTSC::File::writeHeader(std::string & header, bool force){
|
||||||
if (headerSize != header.size() && !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;
|
return false;
|
||||||
}
|
}
|
||||||
headerSize = header.size();
|
headerSize = header.size();
|
||||||
|
@ -601,30 +600,28 @@ long long int DTSC::File::addHeader(std::string & header){
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads the header at the given file position.
|
/// 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.
|
/// Reading the header means the file position is moved to after the header.
|
||||||
void DTSC::File::readHeader(int pos){
|
void DTSC::File::readHeader(int pos){
|
||||||
fseek(F, pos, SEEK_SET);
|
fseek(F, pos, SEEK_SET);
|
||||||
if (fread(buffer, 4, 1, F) != 1){
|
if (fread(buffer, 4, 1, F) != 1){
|
||||||
if (feof(F)){
|
if (feof(F)){
|
||||||
#if DEBUG >= 4
|
DEBUG_MSG(DLVL_DEVEL, "End of file reached while reading header @ %d", pos);
|
||||||
fprintf(stderr, "End of file reached (H%i)\n", pos);
|
|
||||||
#endif
|
|
||||||
}else{
|
}else{
|
||||||
fprintf(stderr, "Could not read header (H%i)\n", pos);
|
DEBUG_MSG(DLVL_ERROR, "Could not read header @ %d", pos);
|
||||||
}
|
}
|
||||||
strbuffer = "";
|
strbuffer = "";
|
||||||
metadata = readOnlyMeta();
|
metadata = readOnlyMeta();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (memcmp(buffer, DTSC::Magic_Header, 4) != 0){
|
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 = "";
|
strbuffer = "";
|
||||||
metadata = readOnlyMeta();
|
metadata = readOnlyMeta();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fread(buffer, 4, 1, F) != 1){
|
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 = "";
|
strbuffer = "";
|
||||||
metadata = readOnlyMeta();
|
metadata = readOnlyMeta();
|
||||||
return;
|
return;
|
||||||
|
@ -634,7 +631,7 @@ void DTSC::File::readHeader(int pos){
|
||||||
strbuffer.resize(packSize);
|
strbuffer.resize(packSize);
|
||||||
if (packSize){
|
if (packSize){
|
||||||
if (fread((void*)strbuffer.c_str(), packSize, 1, F) != 1){
|
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 = "";
|
strbuffer = "";
|
||||||
metadata = readOnlyMeta();
|
metadata = readOnlyMeta();
|
||||||
return;
|
return;
|
||||||
|
@ -666,7 +663,7 @@ bool DTSC::File::reachedEOF(){
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads the packet available at the current file position.
|
/// 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.
|
/// Reading the packet means the file position is increased to the next packet.
|
||||||
void DTSC::File::seekNext(){
|
void DTSC::File::seekNext(){
|
||||||
if ( !currentPositions.size()){
|
if ( !currentPositions.size()){
|
||||||
|
@ -689,11 +686,9 @@ void DTSC::File::seekNext(){
|
||||||
lastreadpos = ftell(F);
|
lastreadpos = ftell(F);
|
||||||
if (fread(buffer, 4, 1, F) != 1){
|
if (fread(buffer, 4, 1, F) != 1){
|
||||||
if (feof(F)){
|
if (feof(F)){
|
||||||
#if DEBUG >= 4
|
DEBUG_MSG(DLVL_DEVEL, "End of file reached while seeking @ %i", (int)lastreadpos);
|
||||||
fprintf(stderr, "End of file reached.\n");
|
|
||||||
#endif
|
|
||||||
}else{
|
}else{
|
||||||
fprintf(stderr, "Could not read header\n");
|
DEBUG_MSG(DLVL_ERROR, "Could not seek to next @ %i", (int)lastreadpos);
|
||||||
}
|
}
|
||||||
strbuffer = "";
|
strbuffer = "";
|
||||||
jsonbuffer.null();
|
jsonbuffer.null();
|
||||||
|
@ -712,13 +707,13 @@ void DTSC::File::seekNext(){
|
||||||
version = 2;
|
version = 2;
|
||||||
}
|
}
|
||||||
if (version == 0){
|
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 = "";
|
strbuffer = "";
|
||||||
jsonbuffer.null();
|
jsonbuffer.null();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fread(buffer, 4, 1, F) != 1){
|
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 = "";
|
strbuffer = "";
|
||||||
jsonbuffer.null();
|
jsonbuffer.null();
|
||||||
return;
|
return;
|
||||||
|
@ -727,7 +722,7 @@ void DTSC::File::seekNext(){
|
||||||
long packSize = ntohl(ubuffer[0]);
|
long packSize = ntohl(ubuffer[0]);
|
||||||
strbuffer.resize(packSize);
|
strbuffer.resize(packSize);
|
||||||
if (fread((void*)strbuffer.c_str(), packSize, 1, F) != 1){
|
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 = "";
|
strbuffer = "";
|
||||||
jsonbuffer.null();
|
jsonbuffer.null();
|
||||||
return;
|
return;
|
||||||
|
@ -782,11 +777,9 @@ void DTSC::File::parseNext(){
|
||||||
lastreadpos = ftell(F);
|
lastreadpos = ftell(F);
|
||||||
if (fread(buffer, 4, 1, F) != 1){
|
if (fread(buffer, 4, 1, F) != 1){
|
||||||
if (feof(F)){
|
if (feof(F)){
|
||||||
#if DEBUG >= 4
|
DEBUG_MSG(DLVL_DEVEL, "End of file reached @ %d", (int)lastreadpos);
|
||||||
fprintf(stderr, "End of file reached.\n");
|
|
||||||
#endif
|
|
||||||
}else{
|
}else{
|
||||||
fprintf(stderr, "Could not read header\n");
|
DEBUG_MSG(DLVL_ERROR, "Could not read header @ %d", (int)lastreadpos);
|
||||||
}
|
}
|
||||||
strbuffer = "";
|
strbuffer = "";
|
||||||
jsonbuffer.null();
|
jsonbuffer.null();
|
||||||
|
@ -798,7 +791,7 @@ void DTSC::File::parseNext(){
|
||||||
jsonbuffer = metadata.toJSON();
|
jsonbuffer = metadata.toJSON();
|
||||||
}else{
|
}else{
|
||||||
if (fread(buffer, 4, 1, F) != 1){
|
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 = "";
|
strbuffer = "";
|
||||||
jsonbuffer.null();
|
jsonbuffer.null();
|
||||||
return;
|
return;
|
||||||
|
@ -807,7 +800,7 @@ void DTSC::File::parseNext(){
|
||||||
long packSize = ntohl(ubuffer[0]);
|
long packSize = ntohl(ubuffer[0]);
|
||||||
strbuffer.resize(packSize);
|
strbuffer.resize(packSize);
|
||||||
if (fread((void*)strbuffer.c_str(), packSize, 1, F) != 1){
|
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 = "";
|
strbuffer = "";
|
||||||
jsonbuffer.null();
|
jsonbuffer.null();
|
||||||
return;
|
return;
|
||||||
|
@ -824,13 +817,13 @@ void DTSC::File::parseNext(){
|
||||||
version = 2;
|
version = 2;
|
||||||
}
|
}
|
||||||
if (version == 0){
|
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 = "";
|
strbuffer = "";
|
||||||
jsonbuffer.null();
|
jsonbuffer.null();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fread(buffer, 4, 1, F) != 1){
|
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 = "";
|
strbuffer = "";
|
||||||
jsonbuffer.null();
|
jsonbuffer.null();
|
||||||
return;
|
return;
|
||||||
|
@ -839,7 +832,7 @@ void DTSC::File::parseNext(){
|
||||||
long packSize = ntohl(ubuffer[0]);
|
long packSize = ntohl(ubuffer[0]);
|
||||||
strbuffer.resize(packSize);
|
strbuffer.resize(packSize);
|
||||||
if (fread((void*)strbuffer.c_str(), packSize, 1, F) != 1){
|
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 = "";
|
strbuffer = "";
|
||||||
jsonbuffer.null();
|
jsonbuffer.null();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "dtsc.h"
|
#include "dtsc.h"
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
/// Retrieves a short in network order from the pointer p.
|
/// Retrieves a short in network order from the pointer p.
|
||||||
static short btohs(char * p){
|
static short btohs(char * p){
|
||||||
|
@ -269,7 +270,7 @@ namespace DTSC {
|
||||||
|
|
||||||
void Track::update(JSON::Value & pack){
|
void Track::update(JSON::Value & pack){
|
||||||
if (pack["time"].asInt() < lastms){
|
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;
|
return;
|
||||||
}
|
}
|
||||||
Part newPart;
|
Part newPart;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
Filesystem::Directory::Directory(std::string PathName, std::string BasePath){
|
Filesystem::Directory::Directory(std::string PathName, std::string BasePath){
|
||||||
MyBase = BasePath;
|
MyBase = BasePath;
|
||||||
|
@ -26,9 +27,7 @@ void Filesystem::Directory::FillEntries(){
|
||||||
dirent * entry;
|
dirent * entry;
|
||||||
while ((entry = readdir(Dirp))){
|
while ((entry = readdir(Dirp))){
|
||||||
if (stat((MyBase + MyPath + "/" + entry->d_name).c_str(), &StatBuf) == -1){
|
if (stat((MyBase + MyPath + "/" + entry->d_name).c_str(), &StatBuf) == -1){
|
||||||
#if DEBUG >= 4
|
DEBUG_MSG(DLVL_DEVEL, "Skipping %s, reason %s", entry->d_name, strerror(errno));
|
||||||
fprintf(stderr, "\tSkipping %s\n\t\tReason: %s\n", entry->d_name, strerror(errno));
|
|
||||||
#endif
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
///Convert stat to string
|
///Convert stat to string
|
||||||
|
@ -38,8 +37,9 @@ void Filesystem::Directory::FillEntries(){
|
||||||
}
|
}
|
||||||
|
|
||||||
void Filesystem::Directory::Print(){
|
void Filesystem::Directory::Print(){
|
||||||
|
/// \todo Remove? Libraries shouldn't print stuff.
|
||||||
if ( !ValidDir){
|
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;
|
return;
|
||||||
}
|
}
|
||||||
printf("%s:\n", (MyBase + MyPath).c_str());
|
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++){
|
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());
|
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 ((Active && (MyVisible[MyPath] & S_ACTIVE)) || (( !Active) && (MyVisible[MyPath] & S_INACTIVE)) || ((( *it).second.st_mode / 010000) == 4)){
|
||||||
if ((( *it).second.st_mode / 010000) == 4){
|
if ((( *it).second.st_mode / 010000) == 4){
|
||||||
Converter << 'd';
|
Converter << 'd';
|
||||||
|
@ -217,7 +214,6 @@ void Filesystem::Directory::STOR(std::string Path, std::string Data){
|
||||||
|
|
||||||
bool Filesystem::Directory::SimplifyPath(){
|
bool Filesystem::Directory::SimplifyPath(){
|
||||||
MyPath += "/";
|
MyPath += "/";
|
||||||
fprintf(stderr, "MyPath: %s\n", MyPath.c_str());
|
|
||||||
std::vector<std::string> TempPath;
|
std::vector<std::string> TempPath;
|
||||||
std::string TempString;
|
std::string TempString;
|
||||||
for (std::string::iterator it = MyPath.begin(); it != MyPath.end(); it++){
|
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;
|
FileName = MyBase + MyPath + "/" + Path;
|
||||||
}
|
}
|
||||||
if (std::remove(FileName.c_str())){
|
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 false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -275,7 +271,7 @@ bool Filesystem::Directory::MKD(std::string Path){
|
||||||
FileName = MyBase + MyPath + "/" + Path;
|
FileName = MyBase + MyPath + "/" + Path;
|
||||||
}
|
}
|
||||||
if (mkdir(FileName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)){
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
MyVisible[FileName] = S_ALL;
|
MyVisible[FileName] = S_ALL;
|
||||||
|
@ -298,7 +294,7 @@ bool Filesystem::Directory::Rename(std::string From, std::string To){
|
||||||
FileTo = MyBase + MyPath + "/" + To;
|
FileTo = MyBase + MyPath + "/" + To;
|
||||||
}
|
}
|
||||||
if (std::rename(FileFrom.c_str(), FileTo.c_str())){
|
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 false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
10
lib/ftp.cpp
10
lib/ftp.cpp
|
@ -23,7 +23,6 @@ FTP::User::User(Socket::Connection NewConnection, std::map<std::string, std::str
|
||||||
MyDir.SetVisibility("OnDemand", Filesystem::S_ACTIVE);
|
MyDir.SetVisibility("OnDemand", Filesystem::S_ACTIVE);
|
||||||
|
|
||||||
JSON::Value MyConfig = JSON::fromFile("/tmp/mist/streamlist");
|
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++){
|
for (JSON::ObjIter it = MyConfig["streams"].ObjBegin(); it != MyConfig["streams"].ObjEnd(); it++){
|
||||||
std::string ThisStream = ( *it).second["channel"]["URL"].toString();
|
std::string ThisStream = ( *it).second["channel"]["URL"].toString();
|
||||||
ThisStream.erase(ThisStream.begin());
|
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);
|
ThisStream.erase(0, ThisStream.find('/') + 1);
|
||||||
}
|
}
|
||||||
ActiveStreams.push_back(ThisStream);
|
ActiveStreams.push_back(ThisStream);
|
||||||
fprintf(stderr, "\t%s\n", ThisStream.c_str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +158,6 @@ int FTP::User::ParseCommand(std::string Command){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_LIST: {
|
case CMD_LIST: {
|
||||||
std::cout << "Listening on :" << MyPassivePort << "\n";
|
|
||||||
Socket::Connection Connected = Passive.accept();
|
Socket::Connection Connected = Passive.accept();
|
||||||
if (Connected.connected()){
|
if (Connected.connected()){
|
||||||
Conn.Send("125 Data connection already open; transfer starting.\n");
|
Conn.Send("125 Data connection already open; transfer starting.\n");
|
||||||
|
@ -170,7 +167,6 @@ int FTP::User::ParseCommand(std::string Command){
|
||||||
while ( !Connected.connected()){
|
while ( !Connected.connected()){
|
||||||
Connected = Passive.accept();
|
Connected = Passive.accept();
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Sending LIST information\n");
|
|
||||||
std::string tmpstr = MyDir.LIST(ActiveStreams);
|
std::string tmpstr = MyDir.LIST(ActiveStreams);
|
||||||
Connected.Send(tmpstr);
|
Connected.Send(tmpstr);
|
||||||
Connected.close();
|
Connected.close();
|
||||||
|
@ -197,7 +193,6 @@ int FTP::User::ParseCommand(std::string Command){
|
||||||
return 530;
|
return 530;
|
||||||
} //Not logged in.
|
} //Not logged in.
|
||||||
MyPassivePort = (rand() % 9999);
|
MyPassivePort = (rand() % 9999);
|
||||||
std::cout << ":" << MyPassivePort << "\n";
|
|
||||||
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
|
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
|
||||||
return 229;
|
return 229;
|
||||||
break;
|
break;
|
||||||
|
@ -207,7 +202,6 @@ int FTP::User::ParseCommand(std::string Command){
|
||||||
return 530;
|
return 530;
|
||||||
} //Not logged in.
|
} //Not logged in.
|
||||||
MyPassivePort = (rand() % 9999) + 49152;
|
MyPassivePort = (rand() % 9999) + 49152;
|
||||||
std::cout << ":" << MyPassivePort << "\n";
|
|
||||||
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
|
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
|
||||||
return 227;
|
return 227;
|
||||||
break;
|
break;
|
||||||
|
@ -222,7 +216,6 @@ int FTP::User::ParseCommand(std::string Command){
|
||||||
if ( !MyDir.HasPermission(Filesystem::P_RETR)){
|
if ( !MyDir.HasPermission(Filesystem::P_RETR)){
|
||||||
return 550;
|
return 550;
|
||||||
} //Access denied.
|
} //Access denied.
|
||||||
std::cout << "Listening on :" << MyPassivePort << "\n";
|
|
||||||
Socket::Connection Connected = Passive.accept();
|
Socket::Connection Connected = Passive.accept();
|
||||||
if (Connected.connected()){
|
if (Connected.connected()){
|
||||||
Conn.Send("125 Data connection already open; transfer starting.\n");
|
Conn.Send("125 Data connection already open; transfer starting.\n");
|
||||||
|
@ -232,7 +225,6 @@ int FTP::User::ParseCommand(std::string Command){
|
||||||
while ( !Connected.connected()){
|
while ( !Connected.connected()){
|
||||||
Connected = Passive.accept();
|
Connected = Passive.accept();
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Sending RETR information\n");
|
|
||||||
std::string tmpstr = MyDir.RETR(Command);
|
std::string tmpstr = MyDir.RETR(Command);
|
||||||
Connected.Send(tmpstr);
|
Connected.Send(tmpstr);
|
||||||
Connected.close();
|
Connected.close();
|
||||||
|
@ -249,7 +241,6 @@ int FTP::User::ParseCommand(std::string Command){
|
||||||
if ( !MyDir.HasPermission(Filesystem::P_STOR)){
|
if ( !MyDir.HasPermission(Filesystem::P_STOR)){
|
||||||
return 550;
|
return 550;
|
||||||
} //Access denied.
|
} //Access denied.
|
||||||
std::cout << "Listening on :" << MyPassivePort << "\n";
|
|
||||||
Socket::Connection Connected = Passive.accept();
|
Socket::Connection Connected = Passive.accept();
|
||||||
if (Connected.connected()){
|
if (Connected.connected()){
|
||||||
Conn.Send("125 Data connection already open; transfer starting.\n");
|
Conn.Send("125 Data connection already open; transfer starting.\n");
|
||||||
|
@ -259,7 +250,6 @@ int FTP::User::ParseCommand(std::string Command){
|
||||||
while ( !Connected.connected()){
|
while ( !Connected.connected()){
|
||||||
Connected = Passive.accept();
|
Connected = Passive.accept();
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Reading STOR information\n");
|
|
||||||
std::string Buffer;
|
std::string Buffer;
|
||||||
while (Connected.spool()){
|
while (Connected.spool()){
|
||||||
}
|
}
|
||||||
|
|
16
lib/json.cpp
16
lib/json.cpp
|
@ -1,6 +1,7 @@
|
||||||
/// \file json.cpp Holds all JSON-related code.
|
/// \file json.cpp Holds all JSON-related code.
|
||||||
|
|
||||||
#include "json.h"
|
#include "json.h"
|
||||||
|
#include "defines.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -642,11 +643,11 @@ unsigned int JSON::Value::packedSize() const{
|
||||||
}//packedSize
|
}//packedSize
|
||||||
|
|
||||||
/// Pre-packs any object-type JSON::Value to a std::string for transfer over the network, including proper DTMI header.
|
/// 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.
|
/// The internal buffer is guaranteed to be up-to-date after this function is called.
|
||||||
void JSON::Value::netPrepare(){
|
void JSON::Value::netPrepare(){
|
||||||
if (myType != OBJECT){
|
if (myType != OBJECT){
|
||||||
fprintf(stderr, "Error: Only objects may be NetPacked!\n");
|
DEBUG_MSG(DLVL_ERROR, "Only objects may be netpacked!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string packed = toPacked();
|
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.
|
/// 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.
|
/// 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,
|
/// 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.
|
/// calls to netPrepare will guarantee it is up-to-date.
|
||||||
|
@ -719,7 +720,7 @@ std::string & JSON::Value::toNetPacked(){
|
||||||
static std::string emptystring;
|
static std::string emptystring;
|
||||||
//check if this is legal
|
//check if this is legal
|
||||||
if (myType != OBJECT){
|
if (myType != OBJECT){
|
||||||
fprintf(stderr, "Error: Only objects may be NetPacked!\n");
|
DEBUG_MSG(DLVL_ERROR, "Only objects may be netpacked!");
|
||||||
return emptystring;
|
return emptystring;
|
||||||
}
|
}
|
||||||
//if sneaky storage doesn't contain correct data, re-calculate it
|
//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 i Current parsing position in the raw data (defaults to 0).
|
||||||
/// \param ret Will be set to JSON::Value, parsed from the raw data.
|
/// \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){
|
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();
|
ret.null();
|
||||||
if (i >= len){
|
if (i >= len){
|
||||||
return;
|
return;
|
||||||
|
@ -1087,9 +1085,7 @@ void JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigned int &
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if DEBUG >= 2
|
DEBUG_MSG(DLVL_FAIL, "Unimplemented DTMI type %hhx, @ %i / %i - returning.\n", data[i], i, len);
|
||||||
fprintf(stderr, "Error: Unimplemented DTMI type %hhx, @ %i / %i - returning.\n", data[i], i, len);
|
|
||||||
#endif
|
|
||||||
i += 1;
|
i += 1;
|
||||||
return;
|
return;
|
||||||
} //fromOneDTMI
|
} //fromOneDTMI
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <arpa/inet.h> //for htonl and friends
|
#include <arpa/inet.h> //for htonl and friends
|
||||||
#include "mp4.h"
|
#include "mp4.h"
|
||||||
#include "json.h"
|
#include "json.h"
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
#define Int64 uint64_t
|
#define Int64 uint64_t
|
||||||
|
|
||||||
|
@ -2286,7 +2287,7 @@ namespace MP4 {
|
||||||
|
|
||||||
void AVCC::setPayload(std::string newPayload){
|
void AVCC::setPayload(std::string newPayload){
|
||||||
if ( !reserve(0, payloadSize(), newPayload.size())){
|
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;
|
return;
|
||||||
}
|
}
|
||||||
memcpy((char*)payload(), (char*)newPayload.c_str(), newPayload.size());
|
memcpy((char*)payload(), (char*)newPayload.c_str(), newPayload.size());
|
||||||
|
|
|
@ -18,7 +18,6 @@ bool NAL_Unit::ReadData(std::string & InputData){
|
||||||
ShortAnnexB += (char)0x00;
|
ShortAnnexB += (char)0x00;
|
||||||
ShortAnnexB += (char)0x00;
|
ShortAnnexB += (char)0x00;
|
||||||
ShortAnnexB += (char)0x01;
|
ShortAnnexB += (char)0x01;
|
||||||
// fprintf( stderr, "NAL_Unit::ReadData --- DataSize: %d\n", InputData.size() );
|
|
||||||
if (InputData.size() < 3){
|
if (InputData.size() < 3){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "ogg.h"
|
#include "ogg.h"
|
||||||
|
#include "defines.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -204,7 +205,7 @@ namespace OGG{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void STerrMSG(){
|
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
|
/// \todo MAKE FIX HERE
|
||||||
|
@ -486,10 +487,10 @@ namespace OGG{
|
||||||
setGranulePosition(DTSCVec[0]["granule"].asInt());
|
setGranulePosition(DTSCVec[0]["granule"].asInt());
|
||||||
for (unsigned int i = 1; i < DTSCVec.size(); i++){
|
for (unsigned int i = 1; i < DTSCVec.size(); i++){
|
||||||
if (DTSCVec[0]["granule"].asInt() != DTSCVec[i]["granule"].asInt()){
|
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()){
|
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);
|
setBitstreamSerialNumber(serial);
|
||||||
|
|
107
lib/procs.cpp
107
lib/procs.cpp
|
@ -2,6 +2,7 @@
|
||||||
/// Contains generic functions for managing processes.
|
/// Contains generic functions for managing processes.
|
||||||
|
|
||||||
#include "procs.h"
|
#include "procs.h"
|
||||||
|
#include "defines.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
@ -127,22 +128,19 @@ void Util::Procs::childsig_handler(int signum){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG >= 5
|
#if DEBUG >= DLVL_DEVEL
|
||||||
std::string pname = plist[ret];
|
std::string pname = plist[ret];
|
||||||
#endif
|
#endif
|
||||||
plist.erase(ret);
|
plist.erase(ret);
|
||||||
#if DEBUG >= 5
|
#if DEBUG >= DLVL_DEVEL
|
||||||
if (!isActive(pname)){
|
if (!isActive(pname)){
|
||||||
std::cerr << "Process " << pname << " fully terminated." << std::endl;
|
DEBUG_MSG(DLVL_DEVEL, "Process %s fully terminated", pname.c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (exitHandlers.count(ret) > 0){
|
if (exitHandlers.count(ret) > 0){
|
||||||
TerminationNotifier tn = exitHandlers[ret];
|
TerminationNotifier tn = exitHandlers[ret];
|
||||||
exitHandlers.erase(ret);
|
exitHandlers.erase(ret);
|
||||||
#if DEBUG >= 5
|
|
||||||
std::cerr << "Calling termination handler for " << pname << std::endl;
|
|
||||||
#endif
|
|
||||||
tn(ret, exitcode);
|
tn(ret, exitcode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,9 +203,7 @@ void Util::Procs::runCmd(std::string & cmd){
|
||||||
}
|
}
|
||||||
//execute the command
|
//execute the command
|
||||||
execvp(args[0], args);
|
execvp(args[0], args);
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Error running %s: %s", cmd.c_str(), strerror(errno));
|
||||||
std::cerr << "Error running \"" << cmd << "\": " << strerror(errno) << std::endl;
|
|
||||||
#endif
|
|
||||||
_exit(42);
|
_exit(42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,14 +221,10 @@ pid_t Util::Procs::Start(std::string name, std::string cmd){
|
||||||
runCmd(cmd);
|
runCmd(cmd);
|
||||||
}else{
|
}else{
|
||||||
if (ret > 0){
|
if (ret > 0){
|
||||||
#if DEBUG >= 5
|
DEBUG_MSG(DLVL_DEVEL, "Process %s started, PID %d: %s", name.c_str(), ret, cmd.c_str());
|
||||||
std::cerr << "Process " << name << " started, PID " << ret << ": " << cmd << std::endl;
|
|
||||||
#endif
|
|
||||||
plist.insert(std::pair<pid_t, std::string>(ret, name));
|
plist.insert(std::pair<pid_t, std::string>(ret, name));
|
||||||
}else{
|
}else{
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started: fork() failed", name.c_str());
|
||||||
std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,9 +243,7 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
|
||||||
setHandler();
|
setHandler();
|
||||||
int pfildes[2];
|
int pfildes[2];
|
||||||
if (pipe(pfildes) == -1){
|
if (pipe(pfildes) == -1){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. Pipe creation failed.", name.c_str());
|
||||||
std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl;
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,9 +260,7 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
|
||||||
if (ret > 0){
|
if (ret > 0){
|
||||||
plist.insert(std::pair<pid_t, std::string>(ret, name));
|
plist.insert(std::pair<pid_t, std::string>(ret, name));
|
||||||
}else{
|
}else{
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
||||||
std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
|
|
||||||
#endif
|
|
||||||
close(pfildes[1]);
|
close(pfildes[1]);
|
||||||
close(pfildes[0]);
|
close(pfildes[0]);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -289,14 +277,10 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
|
||||||
runCmd(cmd2);
|
runCmd(cmd2);
|
||||||
}else{
|
}else{
|
||||||
if (ret2 > 0){
|
if (ret2 > 0){
|
||||||
#if DEBUG >= 5
|
DEBUG_MSG(DLVL_DEVEL, "Process %s started, PIDs (%d, %d): %s | %s", name.c_str(), ret, ret2, cmd.c_str(), cmd2.c_str());
|
||||||
std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << "): " << cmd << " | " << cmd2 << std::endl;
|
|
||||||
#endif
|
|
||||||
plist.insert(std::pair<pid_t, std::string>(ret2, name));
|
plist.insert(std::pair<pid_t, std::string>(ret2, name));
|
||||||
}else{
|
}else{
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
||||||
std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
|
|
||||||
#endif
|
|
||||||
Stop(name);
|
Stop(name);
|
||||||
close(pfildes[1]);
|
close(pfildes[1]);
|
||||||
close(pfildes[0]);
|
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 pfildes[2];
|
||||||
int pfildes2[2];
|
int pfildes2[2];
|
||||||
if (pipe(pfildes) == -1){
|
if (pipe(pfildes) == -1){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. Pipe creation failed.", name.c_str());
|
||||||
std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl;
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (pipe(pfildes2) == -1){
|
if (pipe(pfildes2) == -1){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. Pipe creation failed.", name.c_str());
|
||||||
std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl;
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,9 +329,7 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
|
||||||
if (ret > 0){
|
if (ret > 0){
|
||||||
plist.insert(std::pair<pid_t, std::string>(ret, name));
|
plist.insert(std::pair<pid_t, std::string>(ret, name));
|
||||||
}else{
|
}else{
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
||||||
std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
|
|
||||||
#endif
|
|
||||||
close(pfildes[1]);
|
close(pfildes[1]);
|
||||||
close(pfildes[0]);
|
close(pfildes[0]);
|
||||||
close(pfildes2[1]);
|
close(pfildes2[1]);
|
||||||
|
@ -372,14 +350,10 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
|
||||||
runCmd(cmd2);
|
runCmd(cmd2);
|
||||||
}else{
|
}else{
|
||||||
if (ret2 > 0){
|
if (ret2 > 0){
|
||||||
#if DEBUG >= 5
|
DEBUG_MSG(DLVL_DEVEL, "Process %s started, PIDs (%d, %d): %s | %s", name.c_str(), ret, ret2, cmd.c_str(), cmd2.c_str());
|
||||||
std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << "): " << cmd << " | " << cmd2 << std::endl;
|
|
||||||
#endif
|
|
||||||
plist.insert(std::pair<pid_t, std::string>(ret2, name));
|
plist.insert(std::pair<pid_t, std::string>(ret2, name));
|
||||||
}else{
|
}else{
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
||||||
std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
|
|
||||||
#endif
|
|
||||||
Stop(name);
|
Stop(name);
|
||||||
close(pfildes[1]);
|
close(pfildes[1]);
|
||||||
close(pfildes[0]);
|
close(pfildes[0]);
|
||||||
|
@ -403,14 +377,10 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
|
||||||
runCmd(cmd3);
|
runCmd(cmd3);
|
||||||
}else{
|
}else{
|
||||||
if (ret3 > 0){
|
if (ret3 > 0){
|
||||||
#if DEBUG >= 5
|
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());
|
||||||
std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << ", " << ret3 << "): " << cmd << " | " << cmd2 << " | " << cmd3 << std::endl;
|
|
||||||
#endif
|
|
||||||
plist.insert(std::pair<pid_t, std::string>(ret3, name));
|
plist.insert(std::pair<pid_t, std::string>(ret3, name));
|
||||||
}else{
|
}else{
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
||||||
std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
|
|
||||||
#endif
|
|
||||||
Stop(name);
|
Stop(name);
|
||||||
close(pfildes[1]);
|
close(pfildes[1]);
|
||||||
close(pfildes[0]);
|
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.
|
/// \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){
|
pid_t Util::Procs::StartPiped(std::string name, char* const* argv, int * fdin, int * fdout, int * fderr){
|
||||||
if (isActive(name)){
|
if (isActive(name)){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_WARN, "Process %s already active - skipping start", name.c_str());
|
||||||
std::cerr << name << " already active - skipping start" << std::endl;
|
|
||||||
#endif
|
|
||||||
return getPid(name);
|
return getPid(name);
|
||||||
}
|
}
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int pipein[2], pipeout[2], pipeerr[2];
|
int pipein[2], pipeout[2], pipeerr[2];
|
||||||
setHandler();
|
setHandler();
|
||||||
if (fdin && *fdin == -1 && pipe(pipein) < 0){
|
if (fdin && *fdin == -1 && pipe(pipein) < 0){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Pipe in creation failed for process %s", name.c_str());
|
||||||
std::cerr << "Pipe (in) creation failed for " << name << std::endl;
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (fdout && *fdout == -1 && pipe(pipeout) < 0){
|
if (fdout && *fdout == -1 && pipe(pipeout) < 0){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Pipe out creation failed for process %s", name.c_str());
|
||||||
std::cerr << "Pipe (out) creation failed for " << name << std::endl;
|
|
||||||
#endif
|
|
||||||
if ( *fdin == -1){
|
if ( *fdin == -1){
|
||||||
close(pipein[0]);
|
close(pipein[0]);
|
||||||
close(pipein[1]);
|
close(pipein[1]);
|
||||||
|
@ -457,9 +421,7 @@ pid_t Util::Procs::StartPiped(std::string name, char* const* argv, int * fdin, i
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (fderr && *fderr == -1 && pipe(pipeerr) < 0){
|
if (fderr && *fderr == -1 && pipe(pipeerr) < 0){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Pipe err creation failed for process %s", name.c_str());
|
||||||
std::cerr << "Pipe (err) creation failed for " << name << std::endl;
|
|
||||||
#endif
|
|
||||||
if ( *fdin == -1){
|
if ( *fdin == -1){
|
||||||
close(pipein[0]);
|
close(pipein[0]);
|
||||||
close(pipein[1]);
|
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){
|
if ( !fdin || !fdout || !fderr){
|
||||||
devnull = open("/dev/null", O_RDWR);
|
devnull = open("/dev/null", O_RDWR);
|
||||||
if (devnull == -1){
|
if (devnull == -1){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Could not open /dev/null for process %s: %s", name.c_str(), strerror(errno));
|
||||||
std::cerr << "Could not open /dev/null for " << name << ": " << strerror(errno) << std::endl;
|
|
||||||
#endif
|
|
||||||
if ( *fdin == -1){
|
if ( *fdin == -1){
|
||||||
close(pipein[0]);
|
close(pipein[0]);
|
||||||
close(pipein[1]);
|
close(pipein[1]);
|
||||||
|
@ -528,14 +488,10 @@ pid_t Util::Procs::StartPiped(std::string name, char* const* argv, int * fdin, i
|
||||||
close(devnull);
|
close(devnull);
|
||||||
}
|
}
|
||||||
execvp(argv[0], argv);
|
execvp(argv[0], argv);
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "execvp() failed for process %s", name.c_str());
|
||||||
perror("execvp failed");
|
|
||||||
#endif
|
|
||||||
exit(42);
|
exit(42);
|
||||||
}else if (pid == -1){
|
}else if (pid == -1){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "fork() for pipe failed for process %s", name.c_str());
|
||||||
std::cerr << "Failed to fork for pipe: " << name << std::endl;
|
|
||||||
#endif
|
|
||||||
if (fdin && *fdin == -1){
|
if (fdin && *fdin == -1){
|
||||||
close(pipein[0]);
|
close(pipein[0]);
|
||||||
close(pipein[1]);
|
close(pipein[1]);
|
||||||
|
@ -553,14 +509,7 @@ pid_t Util::Procs::StartPiped(std::string name, char* const* argv, int * fdin, i
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}else{ //parent
|
}else{ //parent
|
||||||
#if DEBUG >= 5
|
DEBUG_MSG(DLVL_DEVEL, "Piped process %s started, PID %d: %s", name.c_str(), pid, argv[0]);
|
||||||
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
|
|
||||||
if (devnull != -1){
|
if (devnull != -1){
|
||||||
close(devnull);
|
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){
|
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];
|
int pfildes[2];
|
||||||
if (pipe(pfildes) == -1){
|
if (pipe(pfildes) == -1){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Pipe creation failed for process %s", name.c_str());
|
||||||
std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl;
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pid_t res1 = StartPiped(name, cmd1, fdin, &pfildes[1], fderr1);
|
pid_t res1 = StartPiped(name, cmd1, fdin, &pfildes[1], fderr1);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
/// Holds all code for the RTMPStream namespace.
|
/// Holds all code for the RTMPStream namespace.
|
||||||
|
|
||||||
#include "rtmpchunks.h"
|
#include "rtmpchunks.h"
|
||||||
|
#include "defines.h"
|
||||||
#include "flv_tag.h"
|
#include "flv_tag.h"
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
|
|
||||||
|
@ -261,9 +262,7 @@ bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme){
|
||||||
uint8_t *pTempHash = new uint8_t[512];
|
uint8_t *pTempHash = new uint8_t[512];
|
||||||
HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash);
|
HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash);
|
||||||
bool result = (memcmp(pBuffer + clientDigestOffset, pTempHash, 32) == 0);
|
bool result = (memcmp(pBuffer + clientDigestOffset, pTempHash, 32) == 0);
|
||||||
#if DEBUG >= 5
|
DEBUG_MSG(DLVL_MEDIUM, "Client scheme validation %hhi %s", scheme, result?"success":"failed");
|
||||||
fprintf(stderr, "Client scheme validation %hhi %s\n", scheme, result?"success":"failed");
|
|
||||||
#endif
|
|
||||||
delete[] pTempBuffer;
|
delete[] pTempBuffer;
|
||||||
delete[] pTempHash;
|
delete[] pTempHash;
|
||||||
return result;
|
return result;
|
||||||
|
@ -556,7 +555,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
||||||
case 0x40:
|
case 0x40:
|
||||||
if (indata.size() < i + 7) return false; //can't read whole header
|
if (indata.size() < i + 7) return false; //can't read whole header
|
||||||
if (prev.msg_type_id == 0){
|
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 * 256;
|
||||||
timestamp += indata[i++ ] * 256;
|
timestamp += indata[i++ ] * 256;
|
||||||
|
@ -574,7 +573,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
||||||
case 0x80:
|
case 0x80:
|
||||||
if (indata.size() < i + 3) return false; //can't read whole header
|
if (indata.size() < i + 3) return false; //can't read whole header
|
||||||
if (prev.msg_type_id == 0){
|
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 * 256;
|
||||||
timestamp += indata[i++ ] * 256;
|
timestamp += indata[i++ ] * 256;
|
||||||
|
@ -589,7 +588,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
||||||
break;
|
break;
|
||||||
case 0xC0:
|
case 0xC0:
|
||||||
if (prev.msg_type_id == 0){
|
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;
|
timestamp = prev.timestamp;
|
||||||
len = prev.len;
|
len = prev.len;
|
||||||
|
@ -704,7 +703,7 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
||||||
} //can't read whole header
|
} //can't read whole header
|
||||||
indata = buffer.copy(i + 7);
|
indata = buffer.copy(i + 7);
|
||||||
if (prev.msg_type_id == 0){
|
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 * 256;
|
||||||
timestamp += indata[i++ ] * 256;
|
timestamp += indata[i++ ] * 256;
|
||||||
|
@ -725,7 +724,7 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
||||||
} //can't read whole header
|
} //can't read whole header
|
||||||
indata = buffer.copy(i + 3);
|
indata = buffer.copy(i + 3);
|
||||||
if (prev.msg_type_id == 0){
|
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 * 256;
|
||||||
timestamp += indata[i++ ] * 256;
|
timestamp += indata[i++ ] * 256;
|
||||||
|
@ -740,7 +739,7 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
||||||
break;
|
break;
|
||||||
case 0xC0:
|
case 0xC0:
|
||||||
if (prev.msg_type_id == 0){
|
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;
|
timestamp = prev.timestamp;
|
||||||
len = prev.len;
|
len = prev.len;
|
||||||
|
@ -821,16 +820,12 @@ bool RTMPStream::doHandshake(){
|
||||||
} //"random" data
|
} //"random" data
|
||||||
|
|
||||||
bool encrypted = (Version == 6);
|
bool encrypted = (Version == 6);
|
||||||
#if DEBUG >= 8
|
DEBUG_MSG(DLVL_HIGH, "Handshake version is %hhi", Version);
|
||||||
fprintf(stderr, "Handshake version is %hhi\n", Version);
|
|
||||||
#endif
|
|
||||||
uint8_t _validationScheme = 5;
|
uint8_t _validationScheme = 5;
|
||||||
if (ValidateClientScheme(Client, 0)) _validationScheme = 0;
|
if (ValidateClientScheme(Client, 0)) _validationScheme = 0;
|
||||||
if (ValidateClientScheme(Client, 1)) _validationScheme = 1;
|
if (ValidateClientScheme(Client, 1)) _validationScheme = 1;
|
||||||
|
|
||||||
#if DEBUG >= 8
|
DEBUG_MSG(DLVL_HIGH, "Handshake type is %hhi, encryption is %s", _validationScheme, encrypted?"on":"off");
|
||||||
fprintf(stderr, "Handshake type is %hhi, encryption is %s\n", _validationScheme, encrypted?"on":"off");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//FIRST 1536 bytes from server response
|
//FIRST 1536 bytes from server response
|
||||||
//compute DH key position
|
//compute DH key position
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
|
#include "defines.h"
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
@ -14,7 +15,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BUFFER_BLOCKSIZE 4096 //set buffer blocksize to 4KiB
|
#define BUFFER_BLOCKSIZE 4096 //set buffer blocksize to 4KiB
|
||||||
#include <iostream>//temporary for debugging
|
|
||||||
|
|
||||||
std::string uint2string(unsigned int i){
|
std::string uint2string(unsigned int i){
|
||||||
std::stringstream st;
|
std::stringstream st;
|
||||||
|
@ -70,7 +70,7 @@ void Socket::Buffer::append(const char * newdata, const unsigned int newdatasize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data.size() > 5000){
|
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.
|
/// If the connection is already closed, nothing happens.
|
||||||
void Socket::Connection::close(){
|
void Socket::Connection::close(){
|
||||||
if (connected()){
|
if (connected()){
|
||||||
#if DEBUG >= 6
|
DEBUG_MSG(DLVL_HIGH, "Socket %d closed", sock);
|
||||||
fprintf(stderr, "Socket closed.\n");
|
|
||||||
#endif
|
|
||||||
if (sock != -1){
|
if (sock != -1){
|
||||||
shutdown(sock, SHUT_RDWR);
|
shutdown(sock, SHUT_RDWR);
|
||||||
errno = EINTR;
|
errno = EINTR;
|
||||||
|
@ -285,9 +283,7 @@ Socket::Connection::Connection(std::string address, bool nonblock){
|
||||||
sock = socket(PF_UNIX, SOCK_STREAM, 0);
|
sock = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||||
if (sock < 0){
|
if (sock < 0){
|
||||||
remotehost = strerror(errno);
|
remotehost = strerror(errno);
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_FAIL, "Could not create socket! Error: %s", remotehost.c_str());
|
||||||
fprintf(stderr, "Could not create socket! Error: %s\n", remotehost.c_str());
|
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Error = false;
|
Error = false;
|
||||||
|
@ -307,9 +303,7 @@ Socket::Connection::Connection(std::string address, bool nonblock){
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
remotehost = strerror(errno);
|
remotehost = strerror(errno);
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_FAIL, "Could not connect to %s! Error: %s", address.c_str(), remotehost.c_str());
|
||||||
fprintf(stderr, "Could not connect to %s! Error: %s\n", address.c_str(), remotehost.c_str());
|
|
||||||
#endif
|
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
} //Socket::Connection Unix Contructor
|
} //Socket::Connection Unix Contructor
|
||||||
|
@ -340,9 +334,7 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){
|
||||||
hints.ai_next = NULL;
|
hints.ai_next = NULL;
|
||||||
int s = getaddrinfo(host.c_str(), ss.str().c_str(), &hints, &result);
|
int s = getaddrinfo(host.c_str(), ss.str().c_str(), &hints, &result);
|
||||||
if (s != 0){
|
if (s != 0){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_FAIL, "Could not connect to %s:%i! Error: %s", host.c_str(), port, gai_strerror(s));
|
||||||
fprintf(stderr, "Could not connect to %s:%i! Error: %s\n", host.c_str(), port, gai_strerror(s));
|
|
||||||
#endif
|
|
||||||
close();
|
close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -362,9 +354,7 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){
|
||||||
freeaddrinfo(result);
|
freeaddrinfo(result);
|
||||||
|
|
||||||
if (rp == 0){
|
if (rp == 0){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_FAIL, "Could not connect to %s! Error: %s", host.c_str(), remotehost.c_str());
|
||||||
fprintf(stderr, "Could not connect to %s! Error: %s\n", host.c_str(), remotehost.c_str());
|
|
||||||
#endif
|
|
||||||
close();
|
close();
|
||||||
}else{
|
}else{
|
||||||
if (nonblock){
|
if (nonblock){
|
||||||
|
@ -531,9 +521,7 @@ unsigned int Socket::Connection::iwrite(const void * buffer, int len){
|
||||||
if (errno != EPIPE){
|
if (errno != EPIPE){
|
||||||
Error = true;
|
Error = true;
|
||||||
remotehost = strerror(errno);
|
remotehost = strerror(errno);
|
||||||
#if DEBUG >= 2
|
DEBUG_MSG(DLVL_WARN, "Could not iwrite data! Error: %s\n", remotehost.c_str());
|
||||||
fprintf(stderr, "Could not iwrite data! Error: %s\n", remotehost.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -571,9 +559,7 @@ int Socket::Connection::iread(void * buffer, int len){
|
||||||
if (errno != EPIPE){
|
if (errno != EPIPE){
|
||||||
Error = true;
|
Error = true;
|
||||||
remotehost = strerror(errno);
|
remotehost = strerror(errno);
|
||||||
#if DEBUG >= 2
|
DEBUG_MSG(DLVL_WARN, "Could not iread data! Error: %s\n", remotehost.c_str());
|
||||||
fprintf(stderr, "Could not iread data! Error: %s\n", remotehost.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -661,7 +647,7 @@ Socket::Server::Server(){
|
||||||
/// \param nonblock (optional) Whether accept() calls will be nonblocking. Default is false (blocking).
|
/// \param nonblock (optional) Whether accept() calls will be nonblocking. Default is false (blocking).
|
||||||
Socket::Server::Server(int port, std::string hostname, bool nonblock){
|
Socket::Server::Server(int port, std::string hostname, bool nonblock){
|
||||||
if ( !IPv6bind(port, hostname, nonblock) && !IPv4bind(port, hostname, 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;
|
sock = -1;
|
||||||
}
|
}
|
||||||
} //Socket::Server TCP Constructor
|
} //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);
|
sock = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
if (sock < 0){
|
if (sock < 0){
|
||||||
errors = strerror(errno);
|
errors = strerror(errno);
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Could not create IPv6 socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str());
|
||||||
fprintf(stderr, "Could not create IPv6 socket %s:%i! Error: %s\n", hostname.c_str(), port, errors.c_str());
|
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int on = 1;
|
int on = 1;
|
||||||
|
@ -699,23 +683,17 @@ bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock){
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
ret = listen(sock, 100); //start listening, backlog of 100 allowed
|
ret = listen(sock, 100); //start listening, backlog of 100 allowed
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_DEVEL, "IPv6 socket success @ %s:%i\n", hostname.c_str(), port);
|
||||||
fprintf(stderr, "IPv6 socket success @ %s:%i\n", hostname.c_str(), port);
|
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}else{
|
}else{
|
||||||
errors = strerror(errno);
|
errors = strerror(errno);
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "IPv6 listen failed! Error: %s\n", errors.c_str());
|
||||||
fprintf(stderr, "IPv6 Listen failed! Error: %s\n", errors.c_str());
|
|
||||||
#endif
|
|
||||||
close();
|
close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
errors = strerror(errno);
|
errors = strerror(errno);
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "IPv6 Binding %s:%i failed (%s)\n", hostname.c_str(), port, errors.c_str());
|
||||||
fprintf(stderr, "IPv6 Binding %s:%i failed (%s)\n", hostname.c_str(), port, errors.c_str());
|
|
||||||
#endif
|
|
||||||
close();
|
close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -730,9 +708,7 @@ bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock){
|
||||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (sock < 0){
|
if (sock < 0){
|
||||||
errors = strerror(errno);
|
errors = strerror(errno);
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Could not create IPv4 socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str());
|
||||||
fprintf(stderr, "Could not create IPv4 socket %s:%i! Error: %s\n", hostname.c_str(), port, errors.c_str());
|
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int on = 1;
|
int on = 1;
|
||||||
|
@ -754,23 +730,17 @@ bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock){
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
ret = listen(sock, 100); //start listening, backlog of 100 allowed
|
ret = listen(sock, 100); //start listening, backlog of 100 allowed
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_DEVEL, "IPv4 socket success @ %s:%i\n", hostname.c_str(), port);
|
||||||
fprintf(stderr, "IPv4 socket success @ %s:%i\n", hostname.c_str(), port);
|
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}else{
|
}else{
|
||||||
errors = strerror(errno);
|
errors = strerror(errno);
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "IPv4 listen failed! Error: %s\n", errors.c_str());
|
||||||
fprintf(stderr, "IPv4 Listen failed! Error: %s\n", errors.c_str());
|
|
||||||
#endif
|
|
||||||
close();
|
close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
errors = strerror(errno);
|
errors = strerror(errno);
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "IPv4 Binding %s:%i failed (%s)\n", hostname.c_str(), port, errors.c_str());
|
||||||
fprintf(stderr, "IPv4 binding %s:%i failed (%s)\n", hostname.c_str(), port, errors.c_str());
|
|
||||||
#endif
|
|
||||||
close();
|
close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -787,9 +757,7 @@ Socket::Server::Server(std::string address, bool nonblock){
|
||||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (sock < 0){
|
if (sock < 0){
|
||||||
errors = strerror(errno);
|
errors = strerror(errno);
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Could not create unix socket %s! Error: %s", address.c_str(), errors.c_str());
|
||||||
fprintf(stderr, "Could not create socket! Error: %s\n", errors.c_str());
|
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (nonblock){
|
if (nonblock){
|
||||||
|
@ -807,17 +775,13 @@ Socket::Server::Server(std::string address, bool nonblock){
|
||||||
return;
|
return;
|
||||||
}else{
|
}else{
|
||||||
errors = strerror(errno);
|
errors = strerror(errno);
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Unix listen failed! Error: %s\n", errors.c_str());
|
||||||
fprintf(stderr, "Listen failed! Error: %s\n", errors.c_str());
|
|
||||||
#endif
|
|
||||||
close();
|
close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
errors = strerror(errno);
|
errors = strerror(errno);
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_ERROR, "Unix Binding %s failed (%s)\n", address.c_str(), errors.c_str());
|
||||||
fprintf(stderr, "Binding failed! Error: %s\n", errors.c_str());
|
|
||||||
#endif
|
|
||||||
close();
|
close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -845,29 +809,20 @@ Socket::Connection Socket::Server::accept(bool nonblock){
|
||||||
Socket::Connection tmp(r);
|
Socket::Connection tmp(r);
|
||||||
if (r < 0){
|
if (r < 0){
|
||||||
if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EINTR)){
|
if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EINTR)){
|
||||||
#if DEBUG >= 1
|
DEBUG_MSG(DLVL_FAIL, "Error during accept - closing server socket %d.", sock);
|
||||||
fprintf(stderr, "Error during accept - closing server socket.\n");
|
|
||||||
#endif
|
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if (addrinfo.sin6_family == AF_INET6){
|
if (addrinfo.sin6_family == AF_INET6){
|
||||||
tmp.remotehost = inet_ntop(AF_INET6, &(addrinfo.sin6_addr), addrconv, INET6_ADDRSTRLEN);
|
tmp.remotehost = inet_ntop(AF_INET6, &(addrinfo.sin6_addr), addrconv, INET6_ADDRSTRLEN);
|
||||||
#if DEBUG >= 6
|
DEBUG_MSG(DLVL_DEVEL, "IPv6 addr [%s]", tmp.remotehost.c_str());
|
||||||
fprintf(stderr,"IPv6 addr: %s\n", tmp.remotehost.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (addrinfo.sin6_family == AF_INET){
|
if (addrinfo.sin6_family == AF_INET){
|
||||||
tmp.remotehost = inet_ntop(AF_INET, &(((sockaddr_in*) &addrinfo)->sin_addr), addrconv, INET6_ADDRSTRLEN);
|
tmp.remotehost = inet_ntop(AF_INET, &(((sockaddr_in*) &addrinfo)->sin_addr), addrconv, INET6_ADDRSTRLEN);
|
||||||
#if DEBUG >= 6
|
DEBUG_MSG(DLVL_DEVEL, "IPv4 addr [%s]", tmp.remotehost.c_str());
|
||||||
fprintf(stderr,"IPv4 addr: %s\n", tmp.remotehost.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (addrinfo.sin6_family == AF_UNIX){
|
if (addrinfo.sin6_family == AF_UNIX){
|
||||||
#if DEBUG >= 6
|
DEBUG_MSG(DLVL_DEVEL, "Unix addr [?]");
|
||||||
tmp.remotehost = ((sockaddr_un*)&addrinfo)->sun_path;
|
|
||||||
fprintf(stderr,"Unix socket, no address\n");
|
|
||||||
#endif
|
|
||||||
tmp.remotehost = "UNIX_SOCKET";
|
tmp.remotehost = "UNIX_SOCKET";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -893,9 +848,7 @@ bool Socket::Server::isBlocking(){
|
||||||
/// If the connection is already closed, nothing happens.
|
/// If the connection is already closed, nothing happens.
|
||||||
void Socket::Server::close(){
|
void Socket::Server::close(){
|
||||||
if (connected()){
|
if (connected()){
|
||||||
#if DEBUG >= 6
|
DEBUG_MSG(DLVL_HIGH, "ServerSocket %d closed", sock);
|
||||||
fprintf(stderr, "ServerSocket closed.\n");
|
|
||||||
#endif
|
|
||||||
shutdown(sock, SHUT_RDWR);
|
shutdown(sock, SHUT_RDWR);
|
||||||
errno = EINTR;
|
errno = EINTR;
|
||||||
while (::close(sock) != 0 && errno == EINTR){
|
while (::close(sock) != 0 && errno == EINTR){
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
/// \file stream.cpp
|
/// \file stream.cpp
|
||||||
/// Utilities for handling streams.
|
/// Utilities for handling streams.
|
||||||
|
|
||||||
#if DEBUG >= 4
|
|
||||||
#include <iostream>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -14,6 +10,7 @@
|
||||||
#include "procs.h"
|
#include "procs.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
std::string Util::getTmpFolder(){
|
std::string Util::getTmpFolder(){
|
||||||
std::string dir;
|
std::string dir;
|
||||||
|
@ -83,20 +80,12 @@ Socket::Connection Util::Stream::getStream(std::string streamname){
|
||||||
JSON::Value ServConf = JSON::fromFile(getTmpFolder() + "streamlist");
|
JSON::Value ServConf = JSON::fromFile(getTmpFolder() + "streamlist");
|
||||||
if (ServConf["streams"].isMember(streamname)){
|
if (ServConf["streams"].isMember(streamname)){
|
||||||
if (ServConf["streams"][streamname]["source"].asString()[0] == '/'){
|
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);
|
return getVod(ServConf["streams"][streamname]["source"].asString(), streamname);
|
||||||
}else{
|
}else{
|
||||||
#if DEBUG >= 5
|
|
||||||
std::cerr << "Opening live stream " << streamname << std::endl;
|
|
||||||
#endif
|
|
||||||
return Socket::Connection(getTmpFolder() + "stream_" + streamname);
|
return Socket::Connection(getTmpFolder() + "stream_" + streamname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if DEBUG >= 5
|
DEBUG_MSG(DLVL_ERROR, "Stream not found: %s", streamname.c_str());
|
||||||
std::cerr << "Could not open stream " << streamname << " - stream not found" << std::endl;
|
|
||||||
#endif
|
|
||||||
return Socket::Connection();
|
return Socket::Connection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
303
lib/tinythread.cpp
Normal file
303
lib/tinythread.cpp
Normal 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
714
lib/tinythread.h
Normal 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_
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "ts_packet.h"
|
#include "ts_packet.h"
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
#ifndef FILLER_DATA
|
#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."
|
#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.
|
/// \return A string representation of the packet.
|
||||||
const char* TS::Packet::ToString(){
|
const char* TS::Packet::ToString(){
|
||||||
if (strBuf.size() != 188){
|
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();
|
return strBuf.c_str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "vorbis.h"
|
#include "vorbis.h"
|
||||||
|
#include "defines.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -236,7 +237,7 @@ namespace vorbis{
|
||||||
long long unsigned int floorType = stream.get(16);
|
long long unsigned int floorType = stream.get(16);
|
||||||
switch(floorType){
|
switch(floorType){
|
||||||
case 0:{
|
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(8);//order
|
||||||
stream.skip(16);//rate
|
stream.skip(16);//rate
|
||||||
stream.skip(16);//bark_map_size
|
stream.skip(16);//bark_map_size
|
||||||
|
@ -339,7 +340,7 @@ namespace vorbis{
|
||||||
}
|
}
|
||||||
char meh = stream.get(2);
|
char meh = stream.get(2);
|
||||||
if (meh != 0){
|
if (meh != 0){
|
||||||
std::cerr << " Sanity Check ==0 : " << (int)meh << std::endl;
|
DEBUG_MSG(DLVL_ERROR, "Sanity check ==0 : %i", (int)meh);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
if (mappingSubmaps > 1){
|
if (mappingSubmaps > 1){
|
||||||
|
|
Loading…
Add table
Reference in a new issue