- initial import

This commit is contained in:
2018-06-05 11:05:37 +03:00
commit e1a4931375
4673 changed files with 1383093 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
project (helper_lib)
# Rely on C++ 11
set (CMAKE_CXX_STANDARD 11)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
set (HELPER_LIB_SOURCES
HL_AsyncCommand.cpp
HL_Calculator.cpp
HL_CsvReader.cpp
HL_Epoll.cpp
HL_HepSupport.cpp
HL_IuUP.cpp
HL_Log.cpp
HL_NetworkFrame.cpp
HL_NetworkSocket.cpp
HL_OsVersion.cpp
HL_Pointer.cpp
HL_Rtp.cpp
HL_Singletone.cpp
HL_SocketHeap.cpp
HL_String.cpp
HL_Sync.cpp
HL_Usb.cpp
HL_Uuid.cpp
HL_VariantMap.cpp
)
add_library(helper_lib ${HELPER_LIB_SOURCES})

View File

@@ -0,0 +1,16 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "HL_AsyncCommand.h"
AsyncCommand::AsyncCommand()
{
}
AsyncCommand::~AsyncCommand()
{
}

View File

@@ -0,0 +1,19 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HL_ASYNCCOMMAND_H
#define HL_ASYNCCOMMAND_H
class AsyncCommand
{
public:
AsyncCommand();
virtual ~AsyncCommand();
virtual void run(void* environment) = 0;
virtual bool finished() = 0;
};
#endif // HL_ASYNCCOMMAND_H

View File

@@ -0,0 +1,256 @@
#ifndef HL_BASE64_H
#define HL_BASE64_H
#include <string>
const char kBase64Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
class Base64 {
public:
static bool Encode(const std::string &in, std::string *out) {
int i = 0, j = 0;
size_t enc_len = 0;
unsigned char a3[3];
unsigned char a4[4];
out->resize(EncodedLength(in));
int input_len = in.size();
std::string::const_iterator input = in.begin();
while (input_len--) {
a3[i++] = *(input++);
if (i == 3) {
a3_to_a4(a4, a3);
for (i = 0; i < 4; i++) {
(*out)[enc_len++] = kBase64Alphabet[a4[i]];
}
i = 0;
}
}
if (i) {
for (j = i; j < 3; j++) {
a3[j] = '\0';
}
a3_to_a4(a4, a3);
for (j = 0; j < i + 1; j++) {
(*out)[enc_len++] = kBase64Alphabet[a4[j]];
}
while ((i++ < 3)) {
(*out)[enc_len++] = '=';
}
}
return (enc_len == out->size());
}
static bool Encode(const char *input, size_t input_length, char *out, size_t out_length) {
int i = 0, j = 0;
char *out_begin = out;
unsigned char a3[3];
unsigned char a4[4];
size_t encoded_length = EncodedLength(input_length);
if (out_length < encoded_length) return false;
while (input_length--) {
a3[i++] = *input++;
if (i == 3) {
a3_to_a4(a4, a3);
for (i = 0; i < 4; i++) {
*out++ = kBase64Alphabet[a4[i]];
}
i = 0;
}
}
if (i) {
for (j = i; j < 3; j++) {
a3[j] = '\0';
}
a3_to_a4(a4, a3);
for (j = 0; j < i + 1; j++) {
*out++ = kBase64Alphabet[a4[j]];
}
while ((i++ < 3)) {
*out++ = '=';
}
}
return (out == (out_begin + encoded_length));
}
static bool Decode(const std::string &in, std::string *out) {
int i = 0, j = 0;
size_t dec_len = 0;
unsigned char a3[3];
unsigned char a4[4];
int input_len = in.size();
std::string::const_iterator input = in.begin();
out->resize(DecodedLength(in));
while (input_len--) {
if (*input == '=') {
break;
}
a4[i++] = *(input++);
if (i == 4) {
for (i = 0; i <4; i++) {
a4[i] = b64_lookup(a4[i]);
}
a4_to_a3(a3,a4);
for (i = 0; i < 3; i++) {
(*out)[dec_len++] = a3[i];
}
i = 0;
}
}
if (i) {
for (j = i; j < 4; j++) {
a4[j] = '\0';
}
for (j = 0; j < 4; j++) {
a4[j] = b64_lookup(a4[j]);
}
a4_to_a3(a3,a4);
for (j = 0; j < i - 1; j++) {
(*out)[dec_len++] = a3[j];
}
}
return (dec_len == out->size());
}
static bool Decode(const char *input, size_t input_length, char *out, size_t out_length) {
int i = 0, j = 0;
char *out_begin = out;
unsigned char a3[3];
unsigned char a4[4];
size_t decoded_length = DecodedLength(input, input_length);
if (out_length < decoded_length) return false;
while (input_length--) {
if (*input == '=') {
break;
}
a4[i++] = *(input++);
if (i == 4) {
for (i = 0; i <4; i++) {
a4[i] = b64_lookup(a4[i]);
}
a4_to_a3(a3,a4);
for (i = 0; i < 3; i++) {
*out++ = a3[i];
}
i = 0;
}
}
if (i) {
for (j = i; j < 4; j++) {
a4[j] = '\0';
}
for (j = 0; j < 4; j++) {
a4[j] = b64_lookup(a4[j]);
}
a4_to_a3(a3,a4);
for (j = 0; j < i - 1; j++) {
*out++ = a3[j];
}
}
return (out == (out_begin + decoded_length));
}
static int DecodedLength(const char *in, size_t in_length) {
int numEq = 0;
const char *in_end = in + in_length;
while (*--in_end == '=') ++numEq;
return ((6 * in_length) / 8) - numEq;
}
static int DecodedLength(const std::string &in) {
int numEq = 0;
int n = in.size();
for (std::string::const_reverse_iterator it = in.rbegin(); *it == '='; ++it) {
++numEq;
}
return ((6 * n) / 8) - numEq;
}
inline static int EncodedLength(size_t length) {
return (length + 2 - ((length + 2) % 3)) / 3 * 4;
}
inline static int EncodedLength(const std::string &in) {
return EncodedLength(in.length());
}
inline static void StripPadding(std::string *in) {
while (!in->empty() && *(in->rbegin()) == '=') in->resize(in->size() - 1);
}
private:
static inline void a3_to_a4(unsigned char * a4, unsigned char * a3) {
a4[0] = (a3[0] & 0xfc) >> 2;
a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
a4[3] = (a3[2] & 0x3f);
}
static inline void a4_to_a3(unsigned char * a3, unsigned char * a4) {
a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4);
a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2);
a3[2] = ((a4[2] & 0x3) << 6) + a4[3];
}
static inline unsigned char b64_lookup(unsigned char c) {
if(c >='A' && c <='Z') return c - 'A';
if(c >='a' && c <='z') return c - 71;
if(c >='0' && c <='9') return c + 4;
if(c == '+') return 62;
if(c == '/') return 63;
return 255;
}
};
#endif // HL_BASE64_H

View File

@@ -0,0 +1,18 @@
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __HL_BYTEBUFFER_H
#define __HL_BYTEBUFFER_H
#include "ice/ICEByteBuffer.h"
typedef ice::ByteBuffer ByteBuffer;
typedef ice::PByteBuffer PByteBuffer;
typedef ice::BitReader BitReader;
typedef ice::BitWriter BitWriter;
typedef ice::BufferReader BufferReader;
typedef ice::BufferWriter BufferWriter;
#endif

View File

View File

@@ -0,0 +1,625 @@
#ifndef __HL_CALCULATOR_H
#define __HL_CALCULATOR_H
#include <iostream>
#include <string>
#include "helper/HL_VariantMap.h"
#include "helper/HL_String.h"
#include "helper/HL_InternetAddress.h"
namespace Calc
{
class Parser;
namespace Ast
{
enum class Type
{
None,
And,
Or,
Equal,
NotEqual,
Less,
LessOrEqual,
Greater,
GreatorOrEqual,
Add,
Sub,
Mul,
Div,
Number,
String,
Var
};
class Item;
typedef Item* PItem;
class Item
{
friend class Calc::Parser;
public:
bool isVariable() const
{
return mType == Type::Var;
}
bool isFixed() const
{
return mType == Type::Number || mType == Type::String;
}
bool isOperation() const
{
return mType >= Type::And && mType <= Type::Div;
}
bool hasBrackets() const
{
return mHasBrackets;
}
int getOperatorLevel() const
{
switch (mType)
{
case Type::Or:
return -2;
case Type::And:
return -1;
case Type::Equal:
case Type::NotEqual:
return 0;
case Type::Less:
case Type::LessOrEqual:
case Type::Greater:
case Type::GreatorOrEqual:
return 1;
case Type::Add:
case Type::Sub:
return 2;
case Type::Mul:
case Type::Div:
return 3;
default:
return 4;
}
assert(0);
}
Type getType() const
{
return mType;
}
std::string getName() const
{
return mName;
}
Variant& value()
{
return mValue;
}
std::vector<PItem>& children()
{
return mChildren;
}
typedef std::map<std::string, std::string> NameMap;
std::ostream& print(std::ostream& oss, const NameMap& nm)
{
oss << " ( ";
if (isOperation())
mChildren.front()->print(oss, nm);
oss << " ";
switch (mType)
{
case Type::Number: oss << mValue.asStdString(); break;
case Type::String: oss << '"' << mValue.asStdString() << '"'; break;
case Type::Var: { NameMap::const_iterator iter = nm.find(mName); oss << ((iter != nm.end()) ? iter->second : mName);} break;
case Type::Add: oss << "+"; break;
case Type::Mul: oss << "*"; break;
case Type::Div: oss << "/"; break;
case Type::Sub: oss << "-"; break;
case Type::Equal: oss << "=="; break;
case Type::NotEqual: oss << "!="; break;
case Type::Less: oss << "<"; break;
case Type::LessOrEqual: oss << "<="; break;
case Type::Greater: oss << ">"; break;
case Type::GreatorOrEqual: oss << ">="; break;
case Type::Or: oss << "or"; break;
case Type::And: oss << "and"; break;
default:
throw std::runtime_error("operator expected");
}
oss << " ";
if (isOperation() && mChildren.size() == 2 && mChildren.back())
mChildren.back()->print(oss, nm);
oss << " ) ";
return oss;
}
typedef std::map<std::string, Variant> ValueMap;
Variant eval(const ValueMap& vm)
{
Variant result, left, right;
if (isOperation())
{
left = mChildren.front()->eval(vm);
right = mChildren.back()->eval(vm);
}
switch (mType)
{
case Type::Number:
case Type::String: result = mValue; break;
case Type::Var: { auto iter = vm.find(mName); if (iter != vm.end()) return iter->second; else throw std::runtime_error("Variable " + mName + " did not find."); }
break;
case Type::Add: result = left + right; break;
case Type::Mul: result = left * right; break;
case Type::Div: result = left / right; break;
case Type::Sub: result = left - right; break;
case Type::Equal: result = left == right; break;
case Type::NotEqual: result = left != right; break;
case Type::Less: result = left < right; break;
case Type::LessOrEqual: result = left <= right; break;
case Type::Greater: result = left > right; break;
case Type::GreatorOrEqual: result = left >= right; break;
case Type::Or: result = left.asBool() || right.asBool(); break;
case Type::And: result = left.asBool() && right.asBool(); break;
default:
assert(0);
}
return result;
}
~Item()
{
for (auto node: mChildren)
delete node;
mChildren.clear();
}
private:
Type mType = Type::None;
std::string mName;
Variant mValue;
std::vector<PItem> mChildren;
bool mHasBrackets = false;
};
}
static bool ishex(int c)
{
if (isdigit(c))
return true;
return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
class Parser
{
private:
enum class LexemType
{
None,
Hex,
Dec,
Float,
Str,
Oper,
Var,
OpenBracket,
CloseBracket
};
struct Lexem
{
LexemType mType = LexemType::None;
std::string mValue;
operator bool () const
{
return mType != LexemType::None;
}
std::string toString() const
{
return std::to_string((int)mType) + " : " + mValue;
}
};
Lexem mCurrentLexem;
Lexem processNewLexem(int c)
{
Lexem result;
if (c == '(')
mCurrentLexem.mType = LexemType::OpenBracket;
else
if (c == ')')
mCurrentLexem.mType = LexemType::CloseBracket;
else
if (isdigit(c))
mCurrentLexem.mType = LexemType::Dec;
else
if (isalpha(c))
mCurrentLexem.mType = LexemType::Var;
else
if (c == '+' || c == '-' || c == '/' || c == '*' || c == '=' || c == '<' || c == '>' || c == '&' || c == '|')
mCurrentLexem.mType = LexemType::Oper;
else
if (c == '"')
mCurrentLexem.mType = LexemType::Str;
else
return Lexem();
mCurrentLexem.mValue.push_back(c);
// Can we return result here already ?
if (mCurrentLexem.mType == LexemType::OpenBracket || mCurrentLexem.mType == LexemType::CloseBracket)
{
// Lexem finished
result = mCurrentLexem;
mCurrentLexem = Lexem();
return result;
}
if (mCurrentLexem.mType == LexemType::Oper)
{
if (mCurrentLexem.mValue == "+" ||
mCurrentLexem.mValue == "-" ||
mCurrentLexem.mValue == "*" ||
mCurrentLexem.mValue == "/" ||
mCurrentLexem.mValue == ">=" ||
mCurrentLexem.mValue == "<=" ||
mCurrentLexem.mValue == "==" ||
mCurrentLexem.mValue == "||" ||
mCurrentLexem.mValue == "&&")
{
// Lexem finished
result = mCurrentLexem;
mCurrentLexem = Lexem();
return result;
}
}
return Lexem();
}
void checkNumericLexem()
{
if (mCurrentLexem.mType != LexemType::Dec)
return;
// Check if there is ".:" characters
if (mCurrentLexem.mValue.find('.') != std::string::npos)
{
// Dot is here - is it float
bool isFloat = false;
StringHelper::toFloat(mCurrentLexem.mValue, 0.0f, &isFloat);
if (isFloat)
mCurrentLexem.mType = LexemType::Float;
else
{
// Maybe it is IP4/6 address ?
InternetAddress addr(mCurrentLexem.mValue, 8000);
if (!addr.isEmpty())
{
mCurrentLexem.mValue = "\"" + mCurrentLexem.mValue + "\"";
mCurrentLexem.mType = LexemType::Str;
}
}
}
}
Lexem getLexem(std::istream& input)
{
Lexem result;
// Iterate while characters avaialbe from input stream & lexem is not finished
bool putback = false;
int c = input.get();
while (!input.eof() && c && result.mType == LexemType::None)
{
switch (mCurrentLexem.mType)
{
case LexemType::None:
result = processNewLexem(c);
break;
case LexemType::Hex:
if (!ishex(c))
{
// Finish Hex lexem
result = mCurrentLexem;
putback = true;
}
else
mCurrentLexem.mValue.push_back(c);
break;
case LexemType::Dec:
if (c == 'x' && mCurrentLexem.mValue == "0")
mCurrentLexem.mType = LexemType::Hex;
else
if (isdigit(c) || c == '.')
{
mCurrentLexem.mValue.push_back(c);
}
else
{
checkNumericLexem();
result = mCurrentLexem;
putback = true;
}
break;
case LexemType::Oper:
// It must be one of two-characters operations
if (c == '<' || c == '>' || c == '=' || c == '&' || c == '|')
{
mCurrentLexem.mValue.push_back(c);
result = mCurrentLexem;
mCurrentLexem = Lexem();
}
else
{
result = mCurrentLexem;
putback = true;
}
break;
case LexemType::Var:
if (isdigit(c) || isalpha(c) || c == '.' || c == '_')
{
mCurrentLexem.mValue.push_back(c);
}
else
{
result = mCurrentLexem;
putback = true;
}
break;
case LexemType::Str:
mCurrentLexem.mValue.push_back(c);
if (c == '"')
{
result = mCurrentLexem;
// String lexem is finished
mCurrentLexem.mType = LexemType::None;
putback = false;
}
break;
default:
assert(0);
}
if (putback)
input.putback(c);
else
if (!result)
c = input.get();
}
checkNumericLexem();
// Recover partially processed lexem - maybe we finish processing at all but there is dec / float / string / variable
if (mCurrentLexem.mType != LexemType::None && result.mType == LexemType::None)
result = mCurrentLexem;
// Reset current lexem
mCurrentLexem = Lexem();
return result;
}
// Make AST node from lexem
Ast::PItem makeAst(const Lexem& l)
{
Ast::PItem result(new Ast::Item());
switch (l.mType)
{
case LexemType::Oper:
if (l.mValue == "-")
result->mType = Ast::Type::Sub;
else
if (l.mValue == "+")
result->mType = Ast::Type::Add;
else
if (l.mValue == "*")
result->mType = Ast::Type::Mul;
else
if (l.mValue == "/")
result->mType = Ast::Type::Div;
else
if (l.mValue == "<")
result->mType = Ast::Type::Less;
else
if (l.mValue == "<=")
result->mType = Ast::Type::LessOrEqual;
else
if (l.mValue == ">")
result->mType = Ast::Type::Greater;
else
if (l.mValue == ">=")
result->mType = Ast::Type::GreatorOrEqual;
else
if (l.mValue == "==")
result->mType = Ast::Type::Equal;
else
if (l.mValue == "!=")
result->mType = Ast::Type::NotEqual;
else
if (l.mValue == "&&")
result->mType = Ast::Type::And;
else
if (l.mValue == "||")
result->mType = Ast::Type::Or;
break;
case LexemType::Var:
result->mType = Ast::Type::Var;
result->mName = l.mValue;
break;
case LexemType::Dec:
result->mType = Ast::Type::Number;
result->mValue = atoi(l.mValue.c_str());
break;
case LexemType::Hex:
result->mType = Ast::Type::Number;
result->mValue = StringHelper::fromHex2Int(l.mValue);
break;
case LexemType::Float:
result->mType = Ast::Type::Number;
result->mValue = (float)atof(l.mValue.c_str());
break;
case LexemType::Str:
result->mType = Ast::Type::String;
result->mValue = l.mValue.substr(1, l.mValue.size() - 2);
break;
default:
throw std::runtime_error("Unexpected lexem.");
}
return result;
}
Lexem mLexem;
public:
Ast::PItem parseExpression(std::istream& input)
{
Ast::PItem operationNode(nullptr), leftNode(nullptr), rightNode(nullptr),
currentOperation(nullptr);
// While we have lexem
while (mLexem = getLexem(input))
{
std::cout << "Returned lexem: " << mLexem.toString() << std::endl;
if (!leftNode)
{
// It must be first operand!
switch (mLexem.mType)
{
case LexemType::OpenBracket:
leftNode = parseExpression(input);
leftNode->mHasBrackets = true;
break;
case LexemType::CloseBracket:
throw std::runtime_error("Expected +/-/constant/variable here.");
case LexemType::Dec:
case LexemType::Hex:
case LexemType::Str:
case LexemType::Var:
case LexemType::Float:
leftNode = makeAst(mLexem);
break;
default:
throw std::runtime_error("Open bracket or constant / number / string / variable expected.");
}
}
else
if (!operationNode)
{
// Well, there is left node already
// See operation here
switch (mLexem.mType)
{
case LexemType::Oper:
operationNode = makeAst(mLexem);
break;
case LexemType::None:
// Finish the tree building
break;
case LexemType::CloseBracket:
// Finish the tree building in this level
if (leftNode)
return leftNode;
break;
default:
throw std::runtime_error("Expected operation.");
}
// Parse rest of expression
rightNode = parseExpression(input);
// If right part of expression is operation - make left side child of right part - to allow calculation in right order
if (operationNode)
{
if (rightNode->isOperation() && rightNode->getOperatorLevel() <= operationNode->getOperatorLevel() && !rightNode->hasBrackets())
{
// Get left child of right expression - make it our right child
operationNode->children().push_back(leftNode);
operationNode->children().push_back(rightNode->children().front());
rightNode->children().front() = operationNode;
currentOperation = rightNode;
}
else
{
operationNode->children().push_back(leftNode);
operationNode->children().push_back(rightNode);
currentOperation = operationNode;
}
}
if (mLexem.mType == LexemType::CloseBracket)
break; // Exit from loop
}
}
return currentOperation ? currentOperation : leftNode;
}
public:
Ast::PItem parse(std::istream& input)
{
return nullptr;
}
void testLexemParser(const std::string& test)
{
std::istringstream iss(test);
for (Lexem l = getLexem(iss); l.mType != LexemType::None; l = getLexem(iss))
{
std::cout << "Lexem type: " << (int)l.mType << ", value: " << l.mValue << std::endl;
}
}
};
class Worker
{
public:
Variant eval(Ast::PItem ast);
};
}
#endif

View File

@@ -0,0 +1,26 @@
#include "HL_CsvReader.h"
#include "HL_String.h"
// --------- CsvFile ----------------
CsvReader::CsvReader(std::istream& stream)
:mInputStream(stream)
{}
CsvReader::~CsvReader()
{}
std::istream& CsvReader::stream() const
{
return mInputStream;
}
bool CsvReader::readLine(std::vector<std::string>& cells)
{
cells.clear();
std::string line;
if (!std::getline(mInputStream, line))
return false;
StringHelper::split(line, cells, ",;");
return true;
}

View File

@@ -0,0 +1,23 @@
#ifndef __HL_CSVREADER_H
#define __HL_CSVREADER_H
#include <string>
#include <istream>
#include <vector>
class CsvReader
{
public:
CsvReader(std::istream& stream);
~CsvReader();
void setStream(std::istream& input);
std::istream& stream() const;
bool readLine(std::vector<std::string>& cells);
protected:
std::istream& mInputStream;
};
#endif

View File

View File

View File

@@ -0,0 +1,85 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __EXCEPTION_H
#define __EXCEPTION_H
#include <exception>
#include <memory.h>
#include <stdio.h>
#include <string.h>
enum
{
ERR_MEDIA_SOCKET_FAILED = 1, // Failed to create media socket
ERR_CANNOT_FIND_SESSION = 2, // Cannot find session
ERR_NO_CREDENTIALS = 3, // No credentials to configure instance
ERR_BAD_VARIANT_TYPE = 4, // Bad variant type conversion
ERR_RINSTANCE = 5,
ERR_SRTP = 6, // libsrtp error
ERR_WEBRTC = 7, // webrtc error
ERR_NOMEM = 8, // no more memory
ERR_WMME_FAILED = 9, // WMME error
ERR_QPC = 10, // QueryPerformanceCounter failed
ERR_BAD_PARAM = 11, // Bad parameter
ERR_NET_FAILED = 12, // Call to OS network subsystem failed
ERR_NOT_IMPLEMENTED = 13, // Not implemented in this build
ERR_MIXER_OVERFLOW = 14, // No more available channels in audio mixer
ERR_WAVFILE_FAILED = 15, // Error with .wav file
ERR_DSOUND = 16, // DSound error
ERR_COREAUDIO = 17, // CoreAudio error
ERR_CREATEWINDOW = 18, // CreateWindow failed
ERR_REGISTERNOTIFICATION = 19, // RegisterDeviceNotification failed
ERR_PCAP = 20, // Smth bad with libpcap
ERR_CACHE_FAILED = 21, // Failed to open cache directory
ERR_FILENOTOPEN = 22, // Cannot open the file
ERR_OPENSLES = 23 // OpenSL ES failed. Subcode has actual error code.
};
class Exception: public std::exception
{
public:
Exception(int code, int subcode = 0)
:mCode(code), mSubcode(subcode)
{
sprintf(mMessage, "%d-%d", code, subcode);
}
Exception(int code, const char* message)
{
if (message)
strncpy(mMessage, message, (sizeof mMessage) - 1 );
}
Exception(const Exception& src)
:mCode(src.mCode), mSubcode(src.mSubcode)
{
memcpy(mMessage, src.mMessage, sizeof mMessage);
}
~Exception()
{ }
int code() const
{
return mCode;
}
int subcode() const
{
return mSubcode;
}
const char* what() const noexcept
{
return mMessage;
}
protected:
int mCode, mSubcode;
char mMessage[256];
};
#endif

View File

@@ -0,0 +1,220 @@
#include "HL_HepSupport.h"
using namespace HEP;
static const uint32_t HEPID1 = 0x011002;
static const uint32_t HEPID2 = 0x021002;
static const uint32_t HEPID3 = 0x48455033;
bool Packet::parseV3(const ByteBuffer& packet)
{
if (packet.size() < 30)
return false;
BufferReader r(packet);
char signature[4];
r.readBuffer(signature, 4);
if (signature[0] != 'H' || signature[1] != 'E' || signature[2] != 'P' || signature[3] != '3')
return false;
// Total length
int l = r.readUShort();
l -= 6;
InternetAddress sourceAddr4, destAddr4, sourceAddr6, destAddr6;
uint16_t sourcePort = 0, destPort = 0;
while (r.count() < packet.size())
{
mVendorId = (VendorId)r.readUShort();
ChunkType chunkType = (ChunkType)r.readUShort();
int chunkLength = r.readUShort();
switch (chunkType)
{
case ChunkType::IPProtocolFamily:
mIpProtocolFamily = r.readUChar();
break;
case ChunkType::IPProtocolID:
mIpProtocolId = r.readUChar();
break;
case ChunkType::IP4SourceAddress:
sourceAddr4 = r.readIp(AF_INET);
break;
case ChunkType::IP4DestinationAddress:
destAddr4 = r.readIp(AF_INET);
break;
case ChunkType::IP6SourceAddress:
sourceAddr6 = r.readIp(AF_INET);
break;
case ChunkType::IP6DestinationAddress:
destAddr6 = r.readIp(AF_INET6);
break;
case ChunkType::SourcePort:
sourcePort = r.readUShort();
break;
case ChunkType::DestinationPort:
destPort = r.readUShort();
break;
case ChunkType::Timestamp:
mTimestamp.tv_sec = r.readUInt();
break;
case ChunkType::TimestampMicro:
mTimestamp.tv_usec = r.readUInt() * 1000;
break;
case ChunkType::ProtocolType:
mProtocolType = (ProtocolId)r.readUChar();
break;
case ChunkType::CaptureAgentID:
mCaptureAgentId = r.readUInt();
break;
case ChunkType::KeepAliveTimer:
mKeepAliveTimer = r.readUShort();
break;
case ChunkType::AuthenticationKey:
mAuthenticateKey.resize(chunkLength - 6);
r.readBuffer(mAuthenticateKey.mutableData(), mAuthenticateKey.size());
break;
case ChunkType::PacketPayload:
r.readBuffer(mBody, chunkLength - 6);
break;
default:
r.readBuffer(nullptr, chunkLength - 6);
}
}
if (!sourceAddr4.isEmpty())
mSourceAddress = sourceAddr4;
else
if (!sourceAddr6.isEmpty())
mSourceAddress = sourceAddr6;
if (!mSourceAddress.isEmpty())
mSourceAddress.setPort(sourcePort);
if (!destAddr4.isEmpty())
mDestinationAddress = destAddr4;
else
if (!destAddr6.isEmpty())
mDestinationAddress = destAddr6;
if (!mDestinationAddress.isEmpty())
mDestinationAddress.setPort(destPort);
return true;
}
bool Packet::parseV2(const ByteBuffer &packet)
{
if (packet.size() < 31)
return false;
if (packet[0] != 0x02)
return false;
BufferReader r(packet);
r.readBuffer(nullptr, 4);
uint16_t sourcePort = r.readUShort();
uint16_t dstPort = r.readUShort();
mSourceAddress = r.readIp(AF_INET);
mSourceAddress.setPort(sourcePort);
mDestinationAddress = r.readIp(AF_INET);
mDestinationAddress.setPort(dstPort);
mTimestamp.tv_sec = r.readUInt();
mTimestamp.tv_usec = r.readUInt() * 1000;
mCaptureAgentId = r.readUShort();
r.readBuffer(nullptr, 2);
mBody.clear();
r.readBuffer(mBody, 65536 - 28);
return true;
}
#define WRITE_CHUNK_UCHAR(T, V) {w.writeUShort((uint16_t)mVendorId); w.writeUShort((uint16_t)T); w.writeUShort(1); w.writeUChar((uint8_t)V);}
#define WRITE_CHUNK_USHORT(T, V) {w.writeUShort((uint16_t)mVendorId); w.writeUShort((uint16_t)T); w.writeUShort(2); w.writeUShort((uint16_t)V);}
#define WRITE_CHUNK_UINT(T, V) {w.writeUShort((uint16_t)mVendorId); w.writeUShort((uint16_t)T); w.writeUShort(4); w.writeUInt((uint32_t)V);}
#define WRITE_CHUNK_IP4(T, V) {w.writeUShort((uint16_t)mVendorId); w.writeUShort((uint16_t)T); w.writeUShort(4); w.writeIp(V);}
#define WRITE_CHUNK_IP6(T, V) {w.writeUShort((uint16_t)mVendorId); w.writeUShort((uint16_t)T); w.writeUShort(8); w.writeIp(V);}
#define WRITE_CHUNK_BUFFER(T, V) {w.writeUShort((uint16_t)mVendorId); w.writeUShort((uint16_t)T); w.writeUShort(8); w.writeBuffer(V.data(), V.size());}
ByteBuffer Packet::buildV3()
{
ByteBuffer r; r.resize(mBody.size() + 512);
BufferWriter w(r);
// Signature
w.writeBuffer("HEP3", 4);
// Reserve place for total length
w.writeUShort(0);
WRITE_CHUNK_UCHAR(ChunkType::IPProtocolFamily, mIpProtocolFamily);
WRITE_CHUNK_UCHAR(ChunkType::IPProtocolID, mIpProtocolId);
// Source address
if (!mSourceAddress.isEmpty())
{
if (mSourceAddress.isV4())
WRITE_CHUNK_IP4(ChunkType::IP4SourceAddress, mSourceAddress)
else
if (mSourceAddress.isV6())
WRITE_CHUNK_IP6(ChunkType::IP6SourceAddress, mSourceAddress);
WRITE_CHUNK_USHORT(ChunkType::SourcePort, mSourceAddress.port());
}
// Destination address
if (!mDestinationAddress.isEmpty())
{
if (mDestinationAddress.isV4())
WRITE_CHUNK_IP4(ChunkType::IP4DestinationAddress, mDestinationAddress)
else
if (mDestinationAddress.isV6())
WRITE_CHUNK_IP6(ChunkType::IP6DestinationAddress, mDestinationAddress);
WRITE_CHUNK_USHORT(ChunkType::DestinationPort, mDestinationAddress.port());
}
// Timestamp
WRITE_CHUNK_UINT(ChunkType::Timestamp, mTimestamp.tv_sec);
// TimestampMicro
WRITE_CHUNK_UINT(ChunkType::TimestampMicro, mTimestamp.tv_usec / 1000);
// Protocol type
WRITE_CHUNK_UINT(ChunkType::ProtocolType, mProtocolType);
// Capture agent ID
WRITE_CHUNK_UINT(ChunkType::CaptureAgentID, mCaptureAgentId);
// Keep alive timer value
WRITE_CHUNK_USHORT(ChunkType::KeepAliveTimer, mKeepAliveTimer);
// Authentication key
WRITE_CHUNK_BUFFER(ChunkType::AuthenticationKey, mAuthenticateKey);
// Payload
WRITE_CHUNK_BUFFER(ChunkType::PacketPayload, mBody);
r.resize(w.offset());
w.rewind(); w.skip(4); w.writeUShort((uint16_t)r.size());
return r;
}

View File

@@ -0,0 +1,84 @@
#ifndef __HELPER_HEP_SUPPORT_H
#define __HELPER_HEP_SUPPORT_H
#include "HL_ByteBuffer.h"
#include "HL_InternetAddress.h"
namespace HEP
{
enum class ChunkType
{
None = 0,
IPProtocolFamily,
IPProtocolID,
IP4SourceAddress,
IP4DestinationAddress,
IP6SourceAddress,
IP6DestinationAddress,
SourcePort,
DestinationPort,
Timestamp,
TimestampMicro,
ProtocolType, // Maps to Protocol Types below
CaptureAgentID,
KeepAliveTimer,
AuthenticationKey,
PacketPayload,
CompressedPayload,
InternalC
};
enum class VendorId
{
None,
FreeSwitch,
Kamailio,
OpenSIPS,
Asterisk,
Homer,
SipXecs
};
enum class ProtocolId
{
Reserved = 0,
SIP,
XMPP,
SDP,
RTP,
RTCP,
MGCP,
MEGACO,
M2UA,
M3UA,
IAX,
H322,
H321
};
struct Packet
{
bool parseV3(const ByteBuffer& packet);
bool parseV2(const ByteBuffer& packet);
ByteBuffer buildV3();
uint8_t
mIpProtocolFamily,
mIpProtocolId;
InternetAddress
mSourceAddress,
mDestinationAddress;
timeval mTimestamp;
ProtocolId mProtocolType;
uint16_t mCaptureAgentId;
uint16_t mKeepAliveTimer;
ByteBuffer mAuthenticateKey;
ByteBuffer mBody;
VendorId mVendorId;
};
}
#endif

View File

@@ -0,0 +1,12 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __HL_INTERNETADDRESS_H
#define __HL_INTERNETADDRESS_H
#include "ice/ICEAddress.h"
typedef ice::NetworkAddress InternetAddress;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
#ifndef HL_IUUP_H
#define HL_IUUP_H
#include <memory>
class IuUP
{
public:
enum class PduType
{
DataWithCrc = 0,
DataNoCrc = 1,
ControlProc = 14
};
struct Frame
{
PduType mPduType;
uint8_t mFrameNumber;
uint8_t mFqc;
uint8_t mRfci;
uint8_t mHeaderCrc;
bool mHeaderCrcOk;
uint16_t mPayloadCrc;
bool mPayloadCrcOk;
const uint8_t* mPayload;
uint16_t mPayloadSize;
};
/* Default value is false */
static bool TwoBytePseudoheader;
static bool parse(const uint8_t* packet, int size, Frame& result);
static bool parse2(const uint8_t* packet, int size, Frame& result);
};
#endif // HL_IUUP_H

View File

@@ -0,0 +1,5 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

View File

@@ -0,0 +1,20 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __LOG_H
#define __LOG_H
#include "ice/ICELog.h"
using ice::GLogger;
using ice::LogLock;
using ice::LL_MEDIA;
using ice::LL_DEBUG;
using ice::LL_INFO;
using ice::LL_CRITICAL;
using ice::LL_NONE;
#endif

View File

@@ -0,0 +1,141 @@
#include "HL_NetworkFrame.h"
#include "HL_InternetAddress.h"
#define ETHERTYPE_MPLS_UC (0x8847)
#define ETHERTYPE_MPLS_MC (0x8848)
#define MPLS_STACK_MASK (0x00000100)
#define MPLS_STACK_SHIFT (8)
NetworkFrame::PacketData NetworkFrame::GetUdpPayloadForEthernet(NetworkFrame::PacketData& packet, InternetAddress& source, InternetAddress& destination)
{
PacketData result(packet);
const EthernetHeader* ethernet = reinterpret_cast<const EthernetHeader*>(packet.mData);
// Skip ethernet header
packet.mData += sizeof(EthernetHeader);
packet.mLength -= sizeof(EthernetHeader);
// See if there is Vlan header
uint16_t proto = 0;
if (ethernet->mEtherType == 129)
{
const VlanHeader* vlan = reinterpret_cast<const VlanHeader*>(packet.mData);
packet.mData += sizeof(VlanHeader);
packet.mLength -= sizeof(VlanHeader);
proto = ntohs(vlan->mData);
}
// Skip MPLS headers
if (proto == ETHERTYPE_MPLS_UC || proto == ETHERTYPE_MPLS_MC)
{
// Parse MPLS here until marker "bottom of mpls stack"
for(bool bottomOfStack = false; !bottomOfStack;
bottomOfStack = ((ntohl(*(uint32_t*)(packet.mData - 4)) & MPLS_STACK_MASK) >> MPLS_STACK_SHIFT) != 0)
{
packet.mData += 4;
packet.mLength -=4;
}
}
const Ip4Header* ip4 = reinterpret_cast<const Ip4Header*>(packet.mData);
if (ip4->mProtocol != IPPROTO_UDP)
return PacketData();
switch (ip4->version())
{
case 4:
return GetUdpPayloadForIp4(packet, source, destination);
case 6:
return GetUdpPayloadForIp6(packet, source, destination);
default:
return PacketData();
}
}
NetworkFrame::PacketData NetworkFrame::GetUdpPayloadForSLL(NetworkFrame::PacketData& packet, InternetAddress& source, InternetAddress& destination)
{
PacketData result(packet);
if (packet.mLength < 16)
return PacketData();
const LinuxSllHeader* sll = reinterpret_cast<const LinuxSllHeader*>(packet.mData);
packet.mData += sizeof(LinuxSllHeader);
packet.mLength -= sizeof(LinuxSllHeader);
switch (ntohs(sll->mProtocolType))
{
case 0x0800:
return GetUdpPayloadForIp4(packet, source, destination);
case 0x86DD:
return GetUdpPayloadForIp6(packet, source, destination);
default:
return PacketData();
}
}
NetworkFrame::PacketData NetworkFrame::GetUdpPayloadForIp4(NetworkFrame::PacketData& packet, InternetAddress& source, InternetAddress& destination)
{
PacketData result(packet);
const Ip4Header* ip4 = reinterpret_cast<const Ip4Header*>(packet.mData);
if (ip4->mProtocol != IPPROTO_UDP)
return PacketData(nullptr, 0);
result.mData += ip4->headerLength();
result.mLength -= ip4->headerLength();
const UdpHeader* udp = reinterpret_cast<const UdpHeader*>(result.mData);
result.mData += sizeof(UdpHeader);
result.mLength -= sizeof(UdpHeader);
// Check if UDP payload length is smaller than full packet length. It can be VLAN trailer data - we need to skip it
size_t length = ntohs(udp->mDatagramLength);
if (length - sizeof(UdpHeader) < (size_t)result.mLength)
result.mLength = length - sizeof(UdpHeader);
source.setIp(ip4->mSource);
source.setPort(ntohs(udp->mSourcePort));
destination.setIp(ip4->mDestination);
destination.setPort(ntohs(udp->mDestinationPort));
return result;
}
NetworkFrame::PacketData NetworkFrame::GetUdpPayloadForIp6(NetworkFrame::PacketData& packet, InternetAddress& source, InternetAddress& destination)
{
PacketData result(packet);
const Ip4Header* ip4 = reinterpret_cast<const Ip4Header*>(packet.mData);
if (ip4->mProtocol != IPPROTO_UDP)
return PacketData(nullptr, 0);
result.mData += ip4->headerLength();
result.mLength -= ip4->headerLength();
const UdpHeader* udp = reinterpret_cast<const UdpHeader*>(packet.mData);
result.mData += sizeof(UdpHeader);
result.mLength -= sizeof(UdpHeader);
/*
if (result.mLength != ntohs(udp->mDatagramLength))
return PacketData(nullptr, 0);
*/
source.setIp(ip4->mSource);
source.setPort(ntohs(udp->mSourcePort));
destination.setIp(ip4->mDestination);
destination.setPort(ntohs(udp->mDestinationPort));
return result;
}

View File

@@ -0,0 +1,114 @@
#ifndef _HL_NETWORK_FRAME_H
#define _HL_NETWORK_FRAME_H
#include <stdint.h>
#include "HL_InternetAddress.h"
class NetworkFrame
{
public:
struct PacketData
{
const uint8_t* mData;
int mLength;
PacketData(const uint8_t* data, int length)
:mData(data), mLength(length)
{}
PacketData()
:mData(nullptr), mLength(0)
{}
};
static PacketData GetUdpPayloadForEthernet(PacketData& packet, InternetAddress& source, InternetAddress& destination);
static PacketData GetUdpPayloadForIp4(PacketData& packet, InternetAddress& source, InternetAddress& destination);
static PacketData GetUdpPayloadForIp6(PacketData& packet, InternetAddress& source, InternetAddress& destination);
static PacketData GetUdpPayloadForSLL(PacketData& packet, InternetAddress& source, InternetAddress& destination);
struct EthernetHeader
{
/* Ethernet addresses are 6 bytes */
static const int AddressLength = 6;
uint8_t mEtherDHost[AddressLength]; /* Destination host address */
uint8_t mEtherSHost[AddressLength]; /* Source host address */
uint16_t mEtherType; /* IP? ARP? RARP? etc */
};
struct __attribute__((packed)) LinuxSllHeader
{
uint16_t mPacketType;
uint16_t mARPHRD;
uint16_t mAddressLength;
uint64_t mAddress;
uint16_t mProtocolType;
};
struct VlanHeader
{
uint16_t mMagicId;
uint16_t mData;
};
struct Ip4Header
{
uint8_t mVhl; /* version << 4 | header length >> 2 */
uint8_t mTos; /* type of service */
uint16_t mLen; /* total length */
uint16_t mId; /* identification */
uint16_t mOffset; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
uint8_t mTtl; /* time to live */
uint8_t mProtocol; /* protocol */
uint16_t mChecksum; /* checksum */
in_addr mSource,
mDestination; /* source and dest address */
int headerLength() const
{
return (mVhl & 0x0f) * 4;
}
int version() const
{
return mVhl >> 4;
}
};
struct UdpHeader
{
uint16_t mSourcePort; /* source port */
uint16_t mDestinationPort;
uint16_t mDatagramLength; /* datagram length */
uint16_t mDatagramChecksum; /* datagram checksum */
};
struct TcpHeader
{
uint16_t mSourcePort; /* source port */
uint16_t mDestinationPort; /* destination port */
uint32_t mSeqNo; /* sequence number */
uint32_t mAckNo; /* acknowledgement number */
uint32_t mDataOffset; /* data offset, rsvd */
#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
uint8_t mFlags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
uint16_t mWindow; /* window */
uint16_t mChecksum; /* checksum */
uint16_t mUrgentPointer; /* urgent pointer */
};
};
#endif

View File

@@ -0,0 +1,180 @@
/* Copyright(C) 2007-2017 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if defined(TARGET_LINUX) || defined(TARGET_ANDROID)
# include <asm/ioctls.h>
#endif
#include "../config.h"
#include "HL_NetworkSocket.h"
#if defined(TARGET_OSX) || defined(TARGET_LINUX)
# include <fcntl.h>
#endif
#include <unistd.h>
#include <assert.h>
DatagramSocket::DatagramSocket()
:mFamily(AF_INET), mHandle(INVALID_SOCKET), mLocalPort(0)
{
}
DatagramSocket::~DatagramSocket()
{
closeSocket();
}
void DatagramSocket::open(int family)
{
if (mHandle != INVALID_SOCKET || mFamily != family)
closeSocket();
assert(family == AF_INET || family == AF_INET6);
mFamily = family;
mHandle = ::socket(mFamily, SOCK_DGRAM, IPPROTO_UDP);
if (mHandle != INVALID_SOCKET)
{
sockaddr_in addr4; sockaddr_in6 addr6;
memset(&addr4, 0, sizeof(addr4)); memset(&addr6, 0, sizeof(addr6));
socklen_t l = mFamily == AF_INET ? sizeof(addr4) : sizeof(addr6);
int retcode = getsockname(mHandle, (mFamily == AF_INET ? (sockaddr*)&addr4 : (sockaddr*)&addr6), &l);
if (!retcode)
{
mLocalPort = ntohs(mFamily == AF_INET ? addr4.sin_port : addr6.sin6_port);
}
}
}
int DatagramSocket::localport()
{
return mLocalPort;
}
void DatagramSocket::sendDatagram(InternetAddress &dest, const void *packetData, unsigned int packetSize)
{
if (mHandle == INVALID_SOCKET)
return;
int sent = ::sendto(mHandle, (const char*)packetData, packetSize, 0, dest.genericsockaddr(), dest.sockaddrLen());
}
unsigned DatagramSocket::recvDatagram(InternetAddress &src, void *packetBuffer, unsigned packetCapacity)
{
if (mHandle == INVALID_SOCKET)
return 0;
sockaddr_in sourceaddr;
#ifdef WIN32
int addrlen = sizeof(sourceaddr);
#else
socklen_t addrlen = sizeof(sourceaddr);
#endif
int received = ::recvfrom(mHandle, (char*)packetBuffer, packetCapacity, 0, (sockaddr*)&sourceaddr, &addrlen);
if (received > 0)
{
src = InternetAddress((sockaddr&)sourceaddr, addrlen);
return received;
}
else
return 0;
}
void DatagramSocket::closeSocket()
{
if (mHandle != INVALID_SOCKET)
{
#ifdef WIN32
::closesocket(mHandle);
#else
close(mHandle);
#endif
mHandle = INVALID_SOCKET;
}
}
bool DatagramSocket::isValid() const
{
return mHandle != INVALID_SOCKET;
}
int DatagramSocket::family() const
{
return mFamily;
}
bool DatagramSocket::setBlocking(bool blocking)
{
#if defined(TARGET_WIN)
unsigned long mode = blocking ? 0 : 1;
return (ioctlsocket(mHandle, FIONBIO, &mode) == 0) ? true : false;
#endif
#if defined(TARGET_OSX) || defined(TARGET_LINUX)
int flags = fcntl(mHandle, F_GETFL, 0);
if (flags < 0)
return false;
flags = blocking ? (flags&~O_NONBLOCK) : (flags|O_NONBLOCK);
return (fcntl(mHandle, F_SETFL, flags) == 0) ? true : false;
#endif
#if defined(TARGET_ANDROID)
unsigned long mode = blocking ? 0 : 1;
return (ioctl(mHandle, FIONBIO, &mode) == 0) ? true : false;
#endif
return false;
}
SOCKET DatagramSocket::socket() const
{
return mHandle;
}
DatagramAgreggator::DatagramAgreggator()
{
FD_ZERO(&mReadSet);
mMaxHandle = 0;
}
DatagramAgreggator::~DatagramAgreggator()
{
}
void DatagramAgreggator::addSocket(PDatagramSocket socket)
{
if (socket->mHandle == INVALID_SOCKET)
return;
FD_SET(socket->mHandle, &mReadSet);
if (socket->mHandle > mMaxHandle)
mMaxHandle = socket->mHandle;
mSocketVector.push_back(socket);
}
unsigned DatagramAgreggator::count()
{
return mSocketVector.size();
}
bool DatagramAgreggator::hasDataAtIndex(unsigned index)
{
PDatagramSocket socket = mSocketVector[index];
return (FD_ISSET(socket->mHandle, &mReadSet) != 0);
}
PDatagramSocket DatagramAgreggator::socketAt(unsigned index)
{
return mSocketVector[index];
}
bool DatagramAgreggator::waitForData(unsigned milliseconds)
{
timeval tv;
tv.tv_sec = milliseconds / 1000;
tv.tv_usec = (milliseconds % 1000) * 1000;
int rescode = ::select(mMaxHandle, &mReadSet, NULL, NULL, &tv);
return rescode > 0;
}

View File

@@ -0,0 +1,66 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __NETWORK_SOCKET_H
#define __NETWORK_SOCKET_H
#include "HL_InternetAddress.h"
#include <vector>
#include <memory>
class NetworkSocket
{
public:
virtual int localport() = 0;
};
class DatagramSocket
{
friend class SocketHeap;
friend class DatagramAgreggator;
public:
DatagramSocket();
virtual ~DatagramSocket();
virtual int localport();
virtual void sendDatagram(InternetAddress& dest, const void* packetData, unsigned packetSize);
virtual unsigned recvDatagram(InternetAddress& src, void* packetBuffer, unsigned packetCapacity);
virtual void closeSocket();
virtual bool isValid() const;
virtual int family() const;
virtual bool setBlocking(bool blocking);
virtual SOCKET socket() const;
virtual void open(int family);
protected:
int mFamily;
SOCKET mHandle;
int mLocalPort;
};
typedef std::shared_ptr<DatagramSocket> PDatagramSocket;
class DatagramAgreggator
{
public:
DatagramAgreggator();
~DatagramAgreggator();
void addSocket(PDatagramSocket socket);
unsigned count();
bool hasDataAtIndex(unsigned index);
PDatagramSocket socketAt(unsigned index);
bool waitForData(unsigned milliseconds);
protected:
typedef std::vector<PDatagramSocket> SocketList;
SocketList mSocketVector;
fd_set mReadSet;
SOCKET mMaxHandle;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,125 @@
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "HL_OsVersion.h"
#ifdef TARGET_WIN
#include <windows.h>
#if defined(USE_MINIDUMP)
# include <DbgHelp.h>
#endif
int winVersion()
{
DWORD dwVersion = 0;
DWORD dwMajorVersion = 0;
DWORD dwMinorVersion = 0;
DWORD dwBuild = 0;
dwVersion = GetVersion();
// Get the Windows version.
dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
// Get the build number.
if (dwVersion < 0x80000000)
dwBuild = (DWORD)(HIWORD(dwVersion));
if (dwMajorVersion == 5)
return Win_Xp;
if (dwMinorVersion == 1)
return Win_Seven;
else
return Win_Vista;
}
// ----------------- CrashMiniDump -----------------
#if defined(USE_MINIDUMP)
static LONG WINAPI MyExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo)
{
// Open the file
HANDLE hFile = CreateFile( L"MiniDump.dmp", GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) )
{
// Create the minidump
MINIDUMP_EXCEPTION_INFORMATION mdei;
mdei.ThreadId = GetCurrentThreadId();
mdei.ExceptionPointers = ExceptionInfo;
mdei.ClientPointers = FALSE;
MINIDUMP_TYPE mdt = MiniDumpWithFullMemory;
BOOL rv = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
hFile, mdt, (ExceptionInfo != 0) ? &mdei : 0, 0, 0 );
// Close the file
CloseHandle( hFile );
}
else
{
}
return EXCEPTION_CONTINUE_SEARCH;
}
static LPTOP_LEVEL_EXCEPTION_FILTER OldExceptionHandler = nullptr;
void CrashMiniDump::registerHandler()
{
OldExceptionHandler = ::SetUnhandledExceptionFilter(&MyExceptionHandler);
}
void CrashMiniDump::unregisterHandler()
{
::SetUnhandledExceptionFilter(nullptr);
}
#endif
#endif
#ifdef TARGET_IOS
int iosVersion()
{
return 4; // Stick with this for now
}
#endif
#if defined(TARGET_LINUX) || defined(TARGET_OSX)
#include <stdio.h>
#include <sys/select.h>
#include <termios.h>
#include <sys/ioctl.h>
int _kbhit()
{
static const int STDIN = 0;
static bool initialized = false;
if (! initialized) {
// Use termios to turn off line buffering
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
#endif

View File

@@ -0,0 +1,51 @@
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __OS_VERSION_H
#define __OS_VERSION_H
#ifdef TARGET_WIN
enum
{
Win_Xp = 0,
Win_Vista = 1,
Win_Seven = 2,
Win_Eight = 3,
Win_Ten = 4
};
extern int winVersion();
class CrashMiniDump
{
public:
static void registerHandler();
static void unregisterHandler();
};
extern void writeMiniDump();
#endif
#ifdef TARGET_IOS
int iosVersion();
#endif
#if defined(TARGET_LINUX) || defined(TARGET_OSX)
#include <stdio.h>
#include <sys/select.h>
#include <termios.h>
#if defined(TARGET_LINUX)
# include <stropts.h>
#endif
extern int _kbhit();
#endif
#endif

View File

@@ -0,0 +1,55 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "HL_Pointer.h"
UsageCounter::UsageCounter()
{}
UsageCounter::~UsageCounter()
{}
int UsageCounter::obtain(int usageId)
{
Lock l(mGuard);
UsageMap::iterator usageIter = mUsage.find(usageId);
if (usageIter != mUsage.end())
usageIter->second = usageIter->second + 1;
else
mUsage[usageId] = 1;
return usageCount();
}
int UsageCounter::release(int usageId)
{
Lock l(mGuard);
UsageMap::iterator usageIter = mUsage.find(usageId);
if (usageIter == mUsage.end())
return usageCount();
usageIter->second = usageIter->second - 1;
if (!usageIter->second)
mUsage.erase(usageIter);
return usageCount();
}
int UsageCounter::usageCount()
{
Lock l(mGuard);
UsageMap::const_iterator usageIter;
int result = 0;
for (usageIter = mUsage.begin(); usageIter != mUsage.end(); usageIter++)
result += usageIter->second;
return result;
}
void UsageCounter::clear()
{
Lock l(mGuard);
mUsage.clear();
}

View File

@@ -0,0 +1,34 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __SMART_POINTER_H
#define __SMART_POINTER_H
#ifdef USE_NATIVE_SMARTPTR
# include <memory>
# define SharedPtr std::shared_ptr
#else
#include "../../libs/resiprocate/rutil/SharedPtr.hxx"
using resip::SharedPtr;
#endif
#include "HL_Sync.h"
#include <map>
class UsageCounter
{
public:
UsageCounter();
~UsageCounter();
int obtain(int usageId);
int release(int usageId);
int usageCount();
void clear();
protected:
typedef std::map<int, int> UsageMap;
UsageMap mUsage;
Mutex mGuard;
};
#endif

View File

@@ -0,0 +1,222 @@
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "HL_Rtp.h"
#include "HL_Exception.h"
#include "HL_String.h"
#include "rtprawpacket.h"
#include "rtpipv4address.h"
#include <alloc.h>
#include <sstream>
#include <tuple>
struct RtpHeader
{
unsigned char cc:4; /* CSRC count */
unsigned char x:1; /* header extension flag */
unsigned char p:1; /* padding flag */
unsigned char version:2; /* protocol version */
unsigned char pt:7; /* payload type */
unsigned char m:1; /* marker bit */
unsigned short seq; /* sequence number */
unsigned int ts; /* timestamp */
unsigned int ssrc; /* synchronization source */
};
struct RtcpHeader
{
unsigned char rc:5; /* reception report count */
unsigned char p:1; /* padding flag */
unsigned char version:2; /* protocol version */
unsigned char pt:8; /* payload type */
uint16_t len; /* length */
uint32_t ssrc; /* synchronization source */
};
bool RtpHelper::isRtp(const void* buffer, int length)
{
if (length < 12)
return false;
unsigned char _type = reinterpret_cast<const RtpHeader*>(buffer)->pt;
bool rtp = ( (_type & 0x7F) >= 96 && (_type & 0x7F) < 127) || ((_type & 0x7F) < 35);
return rtp;
}
bool RtpHelper::isRtpOrRtcp(const void* buffer, int length)
{
if (length < 12)
return false;
unsigned char b = ((const unsigned char*)buffer)[0];
return (b & 0xC0 ) == 128;
}
bool RtpHelper::isRtcp(const void* buffer, int length)
{
return (isRtpOrRtcp(buffer, length) && !isRtp(buffer, length));
}
unsigned RtpHelper::findSsrc(const void* buffer, int length)
{
if (isRtp(buffer, length))
return reinterpret_cast<const RtpHeader*>(buffer)->ssrc;
else
return reinterpret_cast<const RtcpHeader*>(buffer)->ssrc;
}
int RtpHelper::findPtype(const void* buffer, int length)
{
if (isRtp(buffer, length))
return reinterpret_cast<const RtpHeader*>(buffer)->pt;
else
return -1;
}
int RtpHelper::findPayloadLength(const void* buffer, int length)
{
if (isRtp(buffer, length))
{
return length - 12;
}
else
return -1;
}
RtpDump::RtpDump(const char *filename)
:mFilename(filename)
{}
RtpDump::~RtpDump()
{
flush();
for (PacketList::iterator packetIter=mPacketList.begin(); packetIter!=mPacketList.end(); ++packetIter)
{
//free(packetIter->mData);
delete packetIter->mPacket;
}
}
void RtpDump::load()
{
FILE* f = fopen(mFilename.c_str(), "rb");
if (!f)
throw Exception(ERR_WAVFILE_FAILED);
while (!feof(f))
{
RtpData data;
fread(&data.mLength, sizeof data.mLength, 1, f);
data.mData = new char[data.mLength];
fread(data.mData, 1, data.mLength, f);
jrtplib::RTPIPv4Address addr(jrtplib::RTPAddress::IPv4Address);
jrtplib::RTPTime t(0);
jrtplib::RTPRawPacket* raw = new jrtplib::RTPRawPacket((unsigned char*)data.mData, data.mLength, &addr, t, true);
data.mPacket = new jrtplib::RTPPacket(*raw);
mPacketList.push_back(data);
}
}
int RtpDump::count() const
{
return mPacketList.size();
}
jrtplib::RTPPacket& RtpDump::packetAt(int index)
{
return *mPacketList[index].mPacket;
}
void RtpDump::add(const void* buffer, int len)
{
RtpData data;
data.mData = malloc(len);
memcpy(data.mData, buffer, len);
data.mLength = len;
jrtplib::RTPIPv4Address addr(jrtplib::RTPAddress::IPv4Address);
jrtplib::RTPTime t(0);
jrtplib::RTPRawPacket* raw = new jrtplib::RTPRawPacket((unsigned char*)const_cast<void*>(data.mData), data.mLength, &addr, t, true);
data.mPacket = new jrtplib::RTPPacket(*raw);
//delete raw;
mPacketList.push_back(data);
}
void RtpDump::flush()
{
FILE* f = fopen(mFilename.c_str(), "wb");
if (!f)
throw Exception(ERR_WAVFILE_FAILED);
PacketList::iterator packetIter = mPacketList.begin();
for (;packetIter != mPacketList.end(); ++packetIter)
{
RtpData& data = *packetIter;
// Disabled for debugging only
//fwrite(&data.mLength, sizeof data.mLength, 1, f);
fwrite(data.mData, data.mLength, 1, f);
}
fclose(f);
}
// -------------- MediaStreamId --------------------
bool MediaStreamId::operator < (const MediaStreamId& right) const
{
if (mSsrcIsId)
return std::tie(mSSRC, mSource, mDestination) < std::tie(right.mSSRC, right.mSource, right.mDestination);
else
return std::tie(mSource, mDestination) < std::tie(right.mSource, right.mDestination);
}
bool MediaStreamId::operator == (const MediaStreamId& right) const
{
if (mSsrcIsId)
return std::tie(mSSRC, mSource, mDestination) == std::tie(right.mSSRC, right.mSource, right.mDestination);
else
return std::tie(mSource, mDestination) == std::tie(right.mSource, right.mDestination);
}
std::string MediaStreamId::toString() const
{
std::ostringstream oss;
oss << "src: " << mSource.toStdString() <<
" dst: " << mDestination.toStdString() <<
" ssrc: " << StringHelper::toHex(mSSRC);
return oss.str();
}
void writeToJson(const MediaStreamId& id, std::ostringstream& oss)
{
oss << " \"src\": \"" << id.mSource.toStdString() << "\"," << std::endl
<< " \"dst\": \"" << id.mDestination.toStdString() << "\"," << std::endl
<< " \"ssrc\": \"" << StringHelper::toHex(id.mSSRC) << "\"," << std::endl
<< " \"link_id\": \"" << id.mLinkId.toString() << "\"" << std::endl;
}
std::string MediaStreamId::getDetectDescription() const
{
std::ostringstream oss;
oss << "{\"event\": \"stream_detected\"," << std::endl;
writeToJson(*this, oss);
oss << "}";
return oss.str();
}
std::string MediaStreamId::getFinishDescription() const
{
std::ostringstream oss;
oss << "{" << std::endl
<< " \"event\": \"stream_finished\", " << std::endl;
writeToJson(*this, oss);
oss << "}";
return oss.str();
}

View File

@@ -0,0 +1,85 @@
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __HL_RTP_H
#define __HL_RTP_H
#include "jrtplib/src/rtppacket.h"
#include "HL_Uuid.h"
#include "HL_InternetAddress.h"
#include <vector>
#include <string>
// Class to carry rtp/rtcp socket pair
template<class T>
struct RtpPair
{
T mRtp;
T mRtcp;
RtpPair()
{}
RtpPair(const T& rtp, const T& rtcp)
:mRtp(rtp), mRtcp(rtcp)
{}
bool multiplexed() { return mRtp == mRtcp; }
};
class RtpHelper
{
public:
static bool isRtp(const void* buffer, int length);
static int findPtype(const void* buffer, int length);
static bool isRtpOrRtcp(const void* buffer, int length);
static bool isRtcp(const void* buffer, int length);
static unsigned findSsrc(const void* buffer, int length);
static int findPayloadLength(const void* buffer, int length);
};
class RtpDump
{
protected:
struct RtpData
{
jrtplib::RTPPacket* mPacket;
void* mData;
unsigned mLength;
};
typedef std::vector<RtpData> PacketList;
PacketList mPacketList;
std::string mFilename;
public:
RtpDump(const char* filename);
~RtpDump();
void load();
int count() const;
jrtplib::RTPPacket& packetAt(int index);
void add(const void* data, int len);
void flush();
};
struct MediaStreamId
{
InternetAddress mSource;
InternetAddress mDestination;
uint32_t mSSRC = 0;
bool mSsrcIsId = true;
Uuid mLinkId;
bool operator < (const MediaStreamId& s2) const;
bool operator == (const MediaStreamId& right) const;
std::string toString() const;
std::string getDetectDescription() const;
std::string getFinishDescription() const;
};
#endif

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,38 @@
#ifndef __HL_SINGLETONE_H
#define __HL_SINGLETONE_H
#include <atomic>
#include <mutex>
template <class T>
class SafeSingleton
{
protected:
static std::atomic<T*> SharedInstance;
static std::mutex mMutex;
public:
static T& instance()
{
T* tmp = SharedInstance.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);
if (tmp == nullptr)
{
std::lock_guard<std::mutex> lock(mMutex);
tmp = SharedInstance.load(std::memory_order_relaxed);
if (tmp == nullptr)
{
tmp = new T();
std::atomic_thread_fence(std::memory_order_release);
SharedInstance.store(tmp, std::memory_order_relaxed);
}
}
return *tmp;
}
};
template <class T>
std::atomic<T*> SafeSingleton<T>::SharedInstance;
template <class T>
std::mutex SafeSingleton<T>::mMutex;
#endif

View File

@@ -0,0 +1,290 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "../config.h"
#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#endif
#include <set>
#include <assert.h>
#include "HL_SocketHeap.h"
#include "HL_Log.h"
#include "HL_Sync.h"
#include "HL_Exception.h"
#define LOG_SUBSYSTEM "[SocketHeap]"
#ifndef WIN32
#define WSAGetLastError(X) errno
#define closesocket(X) close(X)
#define WSAEADDRINUSE EADDRINUSE
#endif
// ----------------------------- SocketHeap -------------------------
SocketHeap::SocketHeap(unsigned short start, unsigned short finish)
{
mStart = start;
mFinish = finish;
}
SocketHeap::~SocketHeap()
{
stop();
}
void SocketHeap::start()
{
#if defined(USE_RESIP_INTEGRATION)
if (!mId)
run();
#else
#endif
}
void SocketHeap::stop()
{
#if defined(USE_RESIP_INTEGRATION)
if (mId)
{
shutdown();
// Wait for worker thread
join();
}
#endif
}
void SocketHeap::setRange(unsigned short start, unsigned short finish)
{
assert(mStart <= mFinish);
Lock l(mGuard);
mStart = start;
mFinish = finish;
}
void SocketHeap::range(unsigned short &start, unsigned short &finish)
{
Lock l(mGuard);
start = mStart;
finish = mFinish;
}
RtpPair<PDatagramSocket> SocketHeap::allocSocketPair(int family, SocketSink *sink, Multiplex m)
{
PDatagramSocket rtp, rtcp;
for (int attempt=0; (!rtp || !rtcp) && attempt < (mFinish - mStart)/2; attempt++)
{
// Allocate RTP
try
{
rtp = allocSocket(family, sink);
if (m == DoMultiplexing)
rtcp = rtp;
else
rtcp = allocSocket(family, sink, rtp->localport() + 1);
}
catch(...)
{}
}
if (!rtp || !rtcp)
{
if (rtp)
freeSocket(rtp);
if (rtcp)
freeSocket(rtcp);
throw Exception(ERR_NET_FAILED);
}
ICELogInfo(<< "Allocated socket pair " << (family == AF_INET ? "AF_INET" : "AF_INET6") << " "
<< rtp->socket() << ":" << rtcp->socket()
<< " at ports " << rtp->localport() << ":"<< rtcp->localport());
return RtpPair<PDatagramSocket>(rtp, rtcp);
}
void SocketHeap::freeSocketPair(const RtpPair<PDatagramSocket> &p)
{
freeSocket(p.mRtp);
freeSocket(p.mRtcp);
}
PDatagramSocket SocketHeap::allocSocket(int family, SocketSink* sink, int port)
{
Lock l(mGuard);
SOCKET sock = ::socket(family, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET)
{
// Return null socket
PDatagramSocket result(new DatagramSocket());
result->mLocalPort = port;
result->mFamily = family;
return result;
}
// Obtain port number
sockaddr_in addr;
sockaddr_in6 addr6;
int result;
int testport;
do
{
testport = port ? port : rand() % ((mFinish - mStart) / 2) * 2 + mStart;
switch (family)
{
case AF_INET:
memset(&addr, 0, sizeof addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(testport);
result = ::bind(sock, (const sockaddr*)&addr, sizeof addr);
if (result)
result = WSAGetLastError();
break;
case AF_INET6:
memset(&addr6, 0, sizeof addr6);
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(testport);
result = ::bind(sock, (const sockaddr*)&addr6, sizeof addr6);
if (result)
result = WSAGetLastError();
break;
}
} while (result == WSAEADDRINUSE);
if (result)
{
closesocket(sock);
throw Exception(ERR_NET_FAILED, WSAGetLastError());
}
PDatagramSocket resultObject(new DatagramSocket());
resultObject->mLocalPort = testport;
resultObject->mHandle = sock;
if (!resultObject->setBlocking(false))
{
resultObject->closeSocket();
throw Exception(ERR_NET_FAILED, WSAGetLastError());
}
// Put socket object to the map
mSocketMap[sock].mSink = sink;
mSocketMap[sock].mSocket = resultObject;
return resultObject;
}
void SocketHeap::freeSocket(PDatagramSocket socket)
{
if (!socket)
return;
Lock l(mDeleteGuard);
mDeleteVector.push_back(socket);
}
void SocketHeap::processDeleted()
{
Lock l(mDeleteGuard);
SocketVector::iterator socketIter = mDeleteVector.begin();
while (socketIter != mDeleteVector.end())
{
// Find socket to delete in main socket map
SocketMap::iterator itemIter = mSocketMap.find((*socketIter)->mHandle);
if (itemIter != mSocketMap.end())
{
// If found - delete socket object from map
mSocketMap.erase(itemIter);
}
socketIter++;
}
mDeleteVector.clear();
}
void SocketHeap::thread()
{
/*#ifdef __linux__
// TODO: make epoll implementation for massive polling
#else*/
while (!isShutdown())
{
// Define socket agreggator
DatagramAgreggator agreggator;
// Make a protected copy of sockets
{
Lock l(mGuard);
// Remove deleted sockets from map and close them
{
processDeleted();
}
// Update socket set
for (SocketMap::iterator socketIter = mSocketMap.begin(); socketIter != mSocketMap.end(); ++socketIter)
{
// Add handle to set
agreggator.addSocket(socketIter->second.mSocket);
}
}
// If set is not empty
if (agreggator.count() > 0)
{
if (agreggator.waitForData(10))
{
ICELogMedia(<< "There is data on UDP sockets");
Lock l(mGuard);
// Remove deleted sockets to avoid call non-existant sinks
processDeleted();
for (unsigned i=0; i<agreggator.count(); i++)
{
if (agreggator.hasDataAtIndex(i))
{
//ICELogInfo(<<"Got incoming UDP packet at index " << (const int)i);
PDatagramSocket sock = agreggator.socketAt(i);
// Find corresponding data sink
SocketMap::iterator socketItemIter = mSocketMap.find(sock->mHandle);
if (socketItemIter != mSocketMap.end())
{
InternetAddress src;
unsigned received = sock->recvDatagram(src, mTempPacket, sizeof mTempPacket);
if ( received > 0 && received <= MAX_VALID_UDPPACKET_SIZE)
socketItemIter->second.mSink->onReceivedData(sock, src, mTempPacket, received);
}
// There is a call to ProcessDeleted() as OnReceivedData() could delete sockets
processDeleted();
}
} //of for
}
}
else
SyncHelper::delay(1000); // Delay for 1 millisecond
}
mId = 0;
//#endif
}
static SocketHeap GRTPSocketHeap(20002, 25100);
SocketHeap& SocketHeap::instance()
{
return GRTPSocketHeap;
}

View File

@@ -0,0 +1,114 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __SOCKET_HEAP_H
#define __SOCKET_HEAP_H
#include "../config.h"
#include <map>
#include <vector>
#include <algorithm>
#ifdef USE_RESIP_INTEGRATION
# include "resiprocate/rutil/ThreadIf.hxx"
#else
# include <thread>
#endif
#include "HL_NetworkSocket.h"
#include "HL_Sync.h"
#include "HL_Rtp.h"
// Class is used to process incoming datagrams
class SocketSink
{
public:
virtual void onReceivedData(PDatagramSocket socket, InternetAddress& src, const void* receivedPtr, unsigned receivedSize) = 0;
};
// Class allocates new UDP sockets and tracks incoming packets on them. It runs in separate thread
#ifdef USE_RESIP_INTEGRATION
class SocketHeap: public resip::ThreadIf
#else
class SocketHeap: public std::thread
#endif
{
public:
enum Multiplex
{
DoMultiplexing,
DontMultiplexing
};
SocketHeap(unsigned short start, unsigned short finish);
~SocketHeap();
static SocketHeap& instance();
void start();
void stop();
// Specifies ne\ port number range. The sockets will be allocated in range [start..finish]
void setRange(unsigned short start, unsigned short finish);
// Returns used port number range
void range(unsigned short& start, unsigned short& finish);
// Attempts to allocate and return socket + allocated port number. REQUIRES pointer to data sink - it will be used to process incoming datagrams
PDatagramSocket allocSocket(int family, SocketSink* sink, int port = 0);
RtpPair<PDatagramSocket> allocSocketPair(int family, SocketSink* sink, Multiplex m);
// Stops receiving data for specified socket and frees socket itself.
void freeSocket(PDatagramSocket socket);
void freeSocketPair(const RtpPair<PDatagramSocket>& p);
// Sends data to specified address on specified socket.
void sendData(DatagramSocket& socket, InternetAddress& dest, const void* dataPtr, int dataSize);
protected:
struct SocketItem
{
// Local port number for socket
PDatagramSocket mSocket;
// Data sink pointer
SocketSink* mSink;
SocketItem()
:mSink(NULL)
{ }
SocketItem(unsigned short portnumber, SocketSink* sink)
:mSink(sink)
{
mSocket->mLocalPort = portnumber;
}
~SocketItem()
{ }
};
typedef std::map<SOCKET, SocketItem> SocketMap;
typedef std::vector<unsigned short> PortVector;
typedef std::vector<PDatagramSocket> SocketVector;
Mutex mGuard;
SocketMap mSocketMap;
PortVector mPortVector;
unsigned short mStart,
mFinish;
SocketVector mDeleteVector;
Mutex mDeleteGuard;
char mTempPacket[MAX_UDPPACKET_SIZE];
virtual void thread();
// Processes mDeleteVector -> updates mSocketMap, removes socket items and closes sockets specified in mDeleteVector
void processDeleted();
};
#endif

View File

@@ -0,0 +1,24 @@
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __HL_STREAM_STATE
#define __HL_STREAM_STATE
// How to use stream state flags.
enum class StreamState
{
Sending = 1, // Transmitting RTP. Set this flag to allow outgoing media stream.
Receiving = 2, // Receiving RTP. Set this flag to allow receiving media stream.
Playing = 4, // Play to audio. Unmutes the audio from specified stream.
Grabbing = 8, // Capture audio. Unmutes the audio to specified stream.
Srtp = 16, // Use SRTP. Make attempt
SipSend = 32, // Declare send capability in SDP
SipRecv = 64 // Declare recv capability in SDP
};
#endif

View File

@@ -0,0 +1,439 @@
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "HL_String.h"
#include <sstream>
#include <iomanip>
#include <memory.h>
#include <algorithm>
#ifdef TARGET_WIN
# include <WinSock2.h>
# include <Windows.h>
# include <cctype>
#endif
std::string StringHelper::extractFilename(const std::string& path)
{
// Look for separator from end of string
for (int i = path.size() - 1; i >= 0; i--)
{
if (path[i] == '/' || path[i] == '\\')
return path.substr(i+1);
}
return "";
}
std::string StringHelper::makeUtf8(const std::tstring &arg)
{
#if defined(TARGET_WIN)
size_t required = WideCharToMultiByte(CP_UTF8, 0, arg.c_str(), -1, NULL, 0, NULL, NULL);
char *result = (char*)_alloca(required + 1);
WideCharToMultiByte(CP_UTF8, 0, arg.c_str(), -1, result, required+1, NULL, NULL);
return result;
#else
return arg;
#endif
}
std::tstring StringHelper::makeTstring(const std::string& arg)
{
#if defined(TARGET_WIN)
size_t count = MultiByteToWideChar(CP_UTF8, 0, arg.c_str(), -1, NULL, 0);
wchar_t* result = (wchar_t*)_alloca(count * 2);
MultiByteToWideChar(CP_UTF8, 0, arg.c_str(), -1, result, count);
return result;
#else
return arg;
#endif
}
int StringHelper::toInt(const char *s, int defaultValue, bool* isOk)
{
int result;
if (sscanf(s, "%d", &result) != 1)
{
if (isOk)
*isOk = false;
result = defaultValue;
}
else
if (isOk)
*isOk = true;
return result;
}
uint64_t StringHelper::toUint64(const char* s, uint64_t def, bool *isOk)
{
uint64_t result = def;
#if defined(TARGET_WIN)
if (sscanf(s, "%d", &result) != 1)
#else
if (sscanf(s, "%llu", &result) != 1)
#endif
{
if (isOk)
*isOk = false;
result = def;
}
else
if (isOk)
*isOk = true;
return result;
}
std::string StringHelper::toHex(unsigned int value)
{
char buffer[32];
sprintf(buffer, "%x", value);
return buffer;
}
std::string StringHelper::toHex(const void *ptr)
{
std::ostringstream oss;
oss << std::hex << ptr;
return oss.str();
}
//must be lowercase for MD5
static const char hexmap[] = "0123456789abcdef";
std::string StringHelper::toHex(const uint8_t* input, size_t inputLength)
{
std::string result; result.resize(inputLength * 2);
const char* p = (const char*)input;
char* r = &result[0];
for (size_t i=0; i < inputLength; ++i)
{
unsigned char temp = *p++;
int hi = (temp & 0xf0)>>4;
int low = (temp & 0xf);
*r++ = hexmap[hi];
*r++ = hexmap[low];
}
*r = 0;
return result;
}
std::string StringHelper::prefixLines(const std::string &source, const std::string &prefix)
{
// Read source line by line
std::istringstream iss(source);
std::ostringstream oss;
std::string line;
while (std::getline(iss,line))
{
oss << prefix << line << std::endl;
}
return oss.str();
}
std::string StringHelper::doubleToString(double value, int precision)
{
std::stringstream ss;
ss << std::fixed << std::setprecision(precision) << value;
return ss.str();
}
const char* StringHelper::findSubstring(const char* buffer, const char* substring, size_t bufferLength)
{
#if defined(TARGET_WIN)
return (const char*)strstr(buffer, substring);
#else
return (const char*)memmem(buffer, bufferLength, substring, strlen(substring));
#endif
}
void StringHelper::split(const std::string& src, std::vector<std::string>& dst, const std::string& delims)
{
dst.clear();
std::string::size_type p = 0;
while (p < src.size())
{
std::string::size_type f = src.find_first_of(delims, p);
if (f == std::string::npos)
{
std::string t = src.substr(p);
if (!t.empty())
dst.push_back(t);
p = src.size();
}
else
{
std::string t = src.substr(p, f-p);
if (!t.empty())
dst.push_back(t);
p = f + 1;
}
}
}
std::pair<std::string, int> StringHelper::parseHost(const std::string& host, int defaultPort)
{
std::pair<std::string, int> result;
std::size_t p = host.find(':');
if (p != std::string::npos)
{
result.first = host.substr(0, p);
result.second = StringHelper::toInt(host.c_str() + p + 1, defaultPort);
}
else
{
result.first = host;
result.second = defaultPort;
}
return result;
}
std::pair<std::string, std::string> StringHelper::parseAssignment(const std::string& s, bool trimQuotes)
{
std::pair<std::string, std::string> result;
std::string::size_type p = s.find('=');
if (p != std::string::npos)
{
result.first = StringHelper::trim(s.substr(0, p));
result.second = StringHelper::trim(s.substr(p+1));
if (trimQuotes && result.second.size() >= 2)
{
if (result.second[0] == '"' && result.second[result.second.size()-1] == '"' ||
result.second[0] == '\'' && result.second[result.second.size()-1] == '\'')
result.second = result.second.substr(1, result.second.size() - 2);
}
}
else
result.first = StringHelper::trim(s);
return result;
}
std::string StringHelper::intToString(int value)
{
char buffer[32];
sprintf(buffer, "%d", value);
return buffer;
}
float StringHelper::toFloat(const std::string &s, float v, bool* isOk)
{
float result = 0.0;
int code = sscanf(s.c_str(), "%f", &result);
if (code == 1)
{
if (isOk)
*isOk = true;
}
else
{
result = v;
if (isOk)
*isOk = false;
}
return result;
}
std::string StringHelper::trim(const std::string &s)
{
auto wsfront = std::find_if_not(s.begin(), s.end(), [](int c) { return std::isspace(c); });
auto wsback = std::find_if_not(s.rbegin(), s.rend(), [](int c) { return std::isspace(c); }).base();
return (wsback <= wsfront ? std::string() : std::string(wsfront,wsback));
}
std::string StringHelper::timeToString(time_t t)
{
char buffer[96];
struct tm lt;
#if defined(TARGET_LINUX) || defined(TARGET_OSX) || defined(TARGET_ANDROID)
localtime_r(&t, &lt);
#else
lt = *localtime(&t);
#endif
strftime(buffer, sizeof(buffer)-1, "%Y-%m-%d %H:%M:%S", &lt);
return buffer;
}
std::string StringHelper::millisecondsToString(uint64_t t)
{
return timeToString(t/1000);
}
int StringHelper::fromHex2Int(const std::string &s)
{
int result = 0;
sscanf(s.c_str(), "%x", &result);
return result;
}
static int hex2code(char s)
{
if (s >= '0' && s <= '9')
return s - '0';
if (s >= 'a' && s <= 'f')
return s - 'a' + 10;
if (s >= 'A' && s <= 'F')
return s - 'A' + 10;
return 0;
}
static int hex2code(const char* s)
{
return hex2code(s[0]) << 4 + hex2code(s[1]);
}
std::string StringHelper::fromHex2String(const std::string& s)
{
std::string result; result.resize(s.size() / 2);
const char* t = s.c_str();
for (size_t i = 0; i < result.size(); i++)
result[i] = hex2code(t[i*2]);
return result;
}
std::string StringHelper::replace(const std::string& s, char f, char r)
{
std::string result(s);
for (std::string::size_type i = 0; i < result.size(); i++)
if (result[i] == 'f')
result[i] = r;
return result;
}
std::string StringHelper::replace(const std::string& s, const std::string& tmpl, const std::string& n)
{
std::string result(s);
std::string::size_type p;
while ( (p = result.find(tmpl)) != std::string::npos)
{
result.replace(p, tmpl.size(), n);
}
return result;
}
std::string StringHelper::decodeUri(const std::string& s)
{
std::string ret;
ret.reserve(s.size());
char ch;
int i, ii;
for (i=0; i<(int)s.length(); i++)
{
if (s[i] == 37)
{
sscanf(s.substr(i+1,2).c_str(), "%x", &ii);
ch = static_cast<char>(ii);
ret += ch;
i += 2;
}
else
ret += s[i];
}
return ret;
}
#define XML_HEADER "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
// --------------------- XcapHelper -----------------
std::string XcapHelper::buildBuddyList(std::string listName, std::vector<std::string> buddies)
{
std::ostringstream result;
result << XML_HEADER <<
"<resource-lists xmlns=\"urn:ietf:params:xml:ns:resource-lists\">" <<
"<list name=\"" << listName.c_str() << "\">";
// to test CT only!
//result << "<entry uri=\"" << "sip:dbogovych1@10.11.1.25" << "\"/>";
//result << "<entry uri=\"" << "sip:dbogovych2@10.11.1.25" << "\"/>";
for (unsigned i = 0; i<buddies.size(); i++)
{
result << "<entry uri=\"" << normalizeSipUri(buddies[i]).c_str() << "\"/>";
}
result << "</list></resource-lists>";
return result.str();
}
std::string XcapHelper::buildRules(std::vector<std::string> buddies)
{
std::ostringstream result;
result << XML_HEADER <<
"<ruleset xmlns=\"urn:ietf:params:xml:ns:common-policy\">" <<
"<rule id=\"presence_allow\">" <<
"<conditions>";
for (unsigned i = 0; i<buddies.size(); i++)
{
result << "<identity><one id=\"" <<
normalizeSipUri(buddies[i]).c_str() << "\"/></identity>";
}
result << "</conditions>" <<
"<actions>" <<
"<sub-handling xmlns=\"urn:ietf:params:xml:ns:pres-rules\">" <<
"allow" <<
"</sub-handling>" <<
"</actions>" <<
"<transformations>" <<
"<provide-devices xmlns=\"urn:ietf:params:xml:ns:pres-rules\">" <<
"<all-devices/>" <<
"</provide-devices>" <<
"<provide-persons xmlns=\"urn:ietf:params:xml:ns:pres-rules\">" <<
"<all-persons/>" <<
"</provide-persons>" <<
"<provide-services xmlns=\"urn:ietf:params:xml:ns:pres-rules\">" <<
"<all-services/>" <<
"</provide-services>" <<
"</transformations>" <<
"</rule>" <<
"</ruleset>";
return result.str();
}
std::string XcapHelper::buildServices(std::string serviceUri, std::string listRef)
{
std::ostringstream result;
result << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl <<
"<rls-services xmlns=\"urn:ietf:params:xml:ns:rls-services\"" << std::endl <<
"xmlns:rl=\"urn:ietf:params:xml:ns:resource-lists\"" << std::endl <<
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" << std::endl <<
"<service uri=\"" << normalizeSipUri(serviceUri).c_str() << "\">" << std::endl <<
"<resource-list>" << listRef.c_str() << "</resource-list>" << std::endl <<
"<packages>" << std::endl <<
"<package>presence</package>" << std::endl <<
"</packages>" << std::endl <<
"</service>" << std::endl <<
"</rls-services>";
return result.str();
}
std::string XcapHelper::normalizeSipUri(std::string uri)
{
if (uri.length())
{
if (uri[0] == '<')
uri.erase(0,1);
if (uri.length())
{
if (uri[uri.length()-1] == '>')
uri.erase(uri.length()-1, 1);
}
}
return uri;
}

View File

@@ -0,0 +1,73 @@
/* Copyright(C) 2007-2018 VoIPobjects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __HELPER_STRING_H
#define __HELPER_STRING_H
#include <vector>
#include <string>
#include <sstream>
#include "HL_Types.h"
#ifdef TARGET_OSX
#define stricmp strcasecmp
#endif
class StringHelper
{
public:
static std::string extractFilename(const std::string& path);
static std::string makeUtf8(const std::tstring& arg);
static std::tstring makeTstring(const std::string& arg);
static int toInt(const char* s, int defaultValue, bool* isOk = nullptr);
static uint64_t toUint64(const char* s, uint64_t def, bool *isOk = nullptr);
static std::string toHex(unsigned int value);
static std::string toHex(const void* ptr);
static std::string toHex(const uint8_t* input, size_t inputLength);
static std::string intToString(int value);
static std::string prefixLines(const std::string& source, const std::string& prefix);
static std::string doubleToString(double value, int precision);
static const char* findSubstring(const char* buffer, const char* substring, size_t bufferLength);
static void split(const std::string& src, std::vector<std::string>& dst, const std::string& delims);
template <typename T>
static std::string join(const std::vector<T>& v, const std::string& delimiter)
{
std::ostringstream s;
for (const auto& i : v)
{
if (&i != &v[0])
s << delimiter;
s << i;
}
return s.str();
}
static std::pair<std::string, int> parseHost(const std::string& host, int defaultPort);
static std::pair<std::string, std::string> parseAssignment(const std::string& s, bool trimQuotes = true);
static float toFloat(const std::string& s, float defaultValue = 0.0, bool* isOk = nullptr);
static std::string trim(const std::string& s);
static std::string timeToString(time_t t);
static std::string millisecondsToString(uint64_t t);
static int fromHex2Int(const std::string& s);
static std::string fromHex2String(const std::string& s);
static std::string replace(const std::string& s, char f, char r);
static std::string replace(const std::string& s, const std::string& tmpl, const std::string& n);
static std::string decodeUri(const std::string& s);
};
class XcapHelper
{
public:
static std::string buildBuddyList(std::string listName, std::vector<std::string> buddies);
static std::string buildRules(std::vector<std::string> buddies);
static std::string buildServices(std::string serviceUri, std::string listRef);
static std::string normalizeSipUri(std::string uri);
};
#endif

View File

@@ -0,0 +1,86 @@
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "HL_Sync.h"
#include <assert.h>
#include <atomic>
#ifdef TARGET_OSX
# include <libkern/OSAtomic.h>
#endif
#ifdef TARGET_WIN
# include <Windows.h>
#endif
void SyncHelper::delay(unsigned int microseconds)
{
#ifdef TARGET_WIN
::Sleep(microseconds/1000);
#endif
#if defined(TARGET_OSX) || defined(TARGET_LINUX)
timespec requested, remaining;
requested.tv_sec = microseconds / 1000000;
requested.tv_nsec = (microseconds % 1000000) * 1000;
remaining.tv_nsec = 0;
remaining.tv_sec = 0;
nanosleep(&requested, &remaining);
#endif
}
long SyncHelper::increment(long *value)
{
assert(value);
#ifdef TARGET_WIN
return ::InterlockedIncrement((LONG*)value);
#elif TARGET_OSX
return OSAtomicIncrement32((int32_t*)value);
#elif TARGET_LINUX
return -1;
#endif
}
// ------------------- ThreadHelper -------------------
void ThreadHelper::setName(const std::string &name)
{
#if defined(TARGET_LINUX)
pthread_setname_np(pthread_self(), name.c_str());
#endif
}
// ------------------- TimeHelper ---------------
using namespace std::chrono;
static uint64_t TimestampStartPoint = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
static time_t TimestampBase = time(nullptr);
uint64_t TimeHelper::getTimestamp()
{
time_point<steady_clock> t = steady_clock::now();
uint64_t ms = duration_cast< milliseconds >(t.time_since_epoch()).count();
return ms - TimestampStartPoint + TimestampBase * 1000;
}
uint64_t TimeHelper::getUptime()
{
time_point<steady_clock> t = steady_clock::now();
uint64_t ms = duration_cast< milliseconds >(t.time_since_epoch()).count();
return ms - TimestampStartPoint;
}
uint32_t TimeHelper::getDelta(uint32_t later, uint32_t earlier)
{
if (later > earlier)
return later - earlier;
if (later < earlier && later < 0x7FFFFFFF && earlier >= 0x7FFFFFFF)
return 0xFFFFFFFF - earlier + later;
return 0;
}

View File

@@ -0,0 +1,80 @@
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __HL_SYNC_H
#define __HL_SYNC_H
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <thread>
typedef std::recursive_mutex Mutex;
typedef std::unique_lock<std::recursive_mutex> Lock;
class SyncHelper
{
public:
static void delay(unsigned microseconds);
static long increment(long* value);
};
class Semaphore
{
private:
unsigned int m_uiCount;
std::mutex m_mutex;
std::condition_variable m_condition;
public:
inline Semaphore(unsigned int uiCount)
: m_uiCount(uiCount) { }
inline void Wait()
{
std::unique_lock< std::mutex > lock(m_mutex);
m_condition.wait(lock,[&]()->bool{ return m_uiCount>0; });
--m_uiCount;
}
template< typename R,typename P >
bool Wait(const std::chrono::duration<R,P>& crRelTime)
{
std::unique_lock< std::mutex > lock(m_mutex);
if (!m_condition.wait_for(lock,crRelTime,[&]()->bool{ return m_uiCount>0; }))
return false;
--m_uiCount;
return true;
}
inline void Signal()
{
std::unique_lock< std::mutex > lock(m_mutex);
++m_uiCount;
m_condition.notify_one();
}
};
class ThreadHelper
{
public:
static void setName(const std::string& name);
};
class TimeHelper
{
public:
// Returns current timestamp in milliseconds
static uint64_t getTimestamp();
// Returns uptime (of calling process) in milliseconds
static uint64_t getUptime();
// Finds time delta between 'later' and 'earlier' time points.
// Handles cases when clock is wrapped.
static uint32_t getDelta(uint32_t later, uint32_t earlier);
};
#endif

View File

@@ -0,0 +1,98 @@
#ifndef __HL_THREAD_POOL_H
#define __HL_THREAD_POOL_H
#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>
class ThreadPool {
public:
ThreadPool(size_t);
template<class F, class... Args>
auto enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>;
~ThreadPool();
private:
// need to keep track of threads so we can join them
std::vector< std::thread > workers;
// the task queue
std::queue< std::function<void()> > tasks;
// synchronization
std::mutex queue_mutex;
std::condition_variable condition;
bool stop;
};
// the constructor just launches some amount of workers
inline ThreadPool::ThreadPool(size_t threads)
: stop(false)
{
for(size_t i = 0;i<threads;++i)
workers.emplace_back(
[this]
{
for(;;)
{
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->condition.wait(lock,
[this]{ return this->stop || !this->tasks.empty(); });
if(this->stop && this->tasks.empty())
return;
task = std::move(this->tasks.front());
this->tasks.pop();
}
task();
}
}
);
}
// add new work item to the pool
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
using return_type = typename std::result_of<F(Args...)>::type;
auto task = std::make_shared< std::packaged_task<return_type()> >(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(queue_mutex);
// don't allow enqueueing after stopping the pool
if(stop)
throw std::runtime_error("enqueue on stopped ThreadPool");
tasks.emplace([task](){ (*task)(); });
}
condition.notify_one();
return res;
}
// the destructor joins all threads
inline ThreadPool::~ThreadPool()
{
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
}
condition.notify_all();
for(std::thread &worker: workers)
worker.join();
}
#endif

View File

@@ -0,0 +1,29 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __HL_TYPES_H
#define __HL_TYPES_H
#ifdef WIN32
# define tstring wstring
# define to_tstring to_wstring
#else
# define tstring string
# define to_tstring to_string
#endif
#ifdef WIN32
#define ALLOCA(X) _alloca(X)
#else
#define ALLOCA(X) alloca(X)
#endif
enum SdpDirection
{
Sdp_Answer,
Sdp_Offer
};
#endif

View File

@@ -0,0 +1,109 @@
#include "HL_Usb.h"
#include "HL_Exception.h"
#ifdef TARGET_WIN
#include <devguid.h>
#define ADR_WINDOW_CLASS_NAME L"HIDDEN_USB_CHANGE_DELEGATE_WINDOWCLASS_%u"
#define ADR_WINDOW_NAME L"HIDDEN_USB_CHANGE_DELEGATE_WINDOW_%u"
UsbChangeListener::UsbChangeListener()
:mNotifyHandle(NULL), mHiddenWindow(NULL), mDelegate(NULL)
{
wsprintf(mWindowClassName, ADR_WINDOW_CLASS_NAME, (unsigned int)rand());
}
UsbChangeListener::~UsbChangeListener()
{
stop();
}
void UsbChangeListener::setDelegate(Delegate* d)
{
mDelegate = d;
}
UsbChangeListener::Delegate* UsbChangeListener::getDelegate() const
{
return mDelegate;
}
void UsbChangeListener::start()
{
// Exposing Window to Mixer
WNDCLASSEX wcx;
memset( &wcx, 0, sizeof(WNDCLASSEX) );
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpszClassName = mWindowClassName;
wcx.lpfnWndProc = (WNDPROC)ADRWindowProc;
::RegisterClassEx(&wcx);
wchar_t windowname[128];
wsprintf(windowname, ADR_WINDOW_NAME, rand());
mHiddenWindow = CreateWindow( mWindowClassName,
windowname,
WS_POPUP | WS_DISABLED,
0, 0, 0, 0,
NULL, NULL, NULL, NULL );
if (!mHiddenWindow)
throw Exception(ERR_CREATEWINDOW, GetLastError());
if (!SetWindowLongPtr(mHiddenWindow, GWLP_USERDATA, (LONG_PTR)this))
throw Exception(ERR_CREATEWINDOW, GetLastError());
// Adjust notification filter
memset(&mNotificationFilter, 0, sizeof(mNotificationFilter));
mNotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
mNotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
// Register notification
if (!RegisterDeviceNotification(mHiddenWindow, &mNotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES))
throw Exception(ERR_REGISTERNOTIFICATION, GetLastError());
}
LRESULT CALLBACK UsbChangeListener::ADRWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
if ( uMsg == WM_DEVICECHANGE )
{
if (wParam == DBT_DEVICEARRIVAL || wParam == DBT_DEVICEREMOVECOMPLETE)
{
LONG_PTR l = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (l)
{
UsbChangeListener* obj = reinterpret_cast<UsbChangeListener*>(l);
switch (wParam)
{
case DBT_DEVICEARRIVAL:
obj->getDelegate()->onDeviceInsert(NULL);
break;
case DBT_DEVICEREMOVECOMPLETE:
obj->getDelegate()->onDeviceRemove(NULL);
break;
}
}
}
}
return ::DefWindowProc( hwnd, uMsg, wParam, lParam);
}
void UsbChangeListener::stop()
{
// Unregister
if (mNotifyHandle != NULL)
{
::UnregisterDeviceNotification(mNotifyHandle);
mNotifyHandle = NULL;
}
//Destroy the window
if (mHiddenWindow != NULL)
{
::DestroyWindow(mHiddenWindow);
mHiddenWindow = NULL;
::UnregisterClass(mWindowClassName, NULL);
}
}
#endif

View File

@@ -0,0 +1,47 @@
#ifndef __HELPER_USB_H
#define __HELPER_USB_H
#ifdef TARGET_WIN
#include <winsock2.h>
#include <windows.h>
#include <Dbt.h>
class UsbChangeListener
{
public:
class Delegate
{
public:
virtual void onDeviceInsert(const wchar_t* name) = 0;
virtual void onDeviceRemove(const wchar_t* name) = 0;
};
UsbChangeListener();
~UsbChangeListener();
void setDelegate(Delegate* d);
Delegate* getDelegate() const;
void start();
void stop();
protected:
HDEVNOTIFY mNotifyHandle; /// Handle to track notifications about USB insert/removal.
HWND mHiddenWindow; /// Hidden window to receive notifications
DEV_BROADCAST_DEVICEINTERFACE mNotificationFilter; /// Notifications filter
wchar_t mWindowClassName[256]; /// Hidden window class
Delegate* mDelegate; /// Event handler pointer
/// Hidden window procedure.
/// @param hwnd Window handle
/// @param uMsg Message ID
/// @param wParam First param
/// @param lParam Second param
static LRESULT CALLBACK ADRWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
};
#endif
#endif

View File

@@ -0,0 +1,67 @@
#include "HL_Uuid.h"
#include <memory.h>
Uuid::Uuid()
{
#if defined(TARGET_WIN) || defined(TARGET_LINUX) || defined(TARGET_OSX)
memset(mUuid, 0, sizeof mUuid);
#endif
}
Uuid Uuid::generateOne()
{
Uuid result;
#if defined(TARGET_LINUX) || defined(TARGET_OSX)
uuid_generate(result.mUuid);
#endif
#if defined(TARGET_WIN)
UuidCreate(&result.mUuid);
#endif
return result;
}
Uuid Uuid::parse(const std::string &s)
{
Uuid result;
#if defined(TARGET_LINUX) || defined(TARGET_OSX)
uuid_parse(s.c_str(), result.mUuid);
#endif
#if defined(TARGET_WIN)
UuidFromStringA((RPC_CSTR)s.c_str(), &result.mUuid);
#endif
return result;
}
std::string Uuid::toString() const
{
char buf[64];
#if defined(TARGET_LINUX) || defined(TARGET_OSX)
uuid_unparse_lower(mUuid, buf);
#endif
#if defined(TARGET_WIN)
RPC_CSTR s = nullptr;
UuidToStringA(&mUuid, &s);
if (s)
{
strcpy(buf, (const char*)s);
RpcStringFreeA(&s);
s = nullptr;
}
#endif
return buf;
}
bool Uuid::operator < (const Uuid& right) const
{
#if defined(TARGET_LINUX) || defined(TARGET_OSX)
return memcmp(mUuid, right.mUuid, sizeof(mUuid)) < 0;
#endif
#if defined(TARGET_WIN)
return memcmp(&mUuid, &right.mUuid, sizeof(mUuid)) < 0;
#endif
}

View File

@@ -0,0 +1,35 @@
#ifndef __HL_UUID_H
#define __HL_UUID_H
#include <string>
#if defined(TARGET_LINUX) || defined(TARGET_OSX)
# include <uuid/uuid.h>
#endif
#if defined(TARGET_WIN)
# include <rpc.h>
#endif
class Uuid
{
public:
Uuid();
static Uuid generateOne();
static Uuid parse(const std::string& s);
std::string toString() const;
bool operator < (const Uuid& right) const;
protected:
#if defined(TARGET_LINUX) || defined(TARGET_OSX)
uuid_t mUuid;
#endif
#if defined(TARGET_WIN)
UUID mUuid;
#endif
#if defined(TARGET_ANDROID)
// Stub only
#endif
};
#endif

View File

@@ -0,0 +1,373 @@
/* Copyright(C) 2007-2017 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "HL_VariantMap.h"
#include "HL_Exception.h"
#include <assert.h>
#if defined(TARGET_ANDROID)
# define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>
#include <stdint.h>
Variant::Variant()
{
mType = VTYPE_INT;
mInt = 0;
mInt64 = 0;
mBool = 0;
mFloat = 0;
mPointer = NULL;
}
Variant::~Variant()
{
}
Variant::Variant(bool value)
:mType(VTYPE_BOOL), mBool(value)
{}
Variant::Variant(int value)
:mType(VTYPE_INT), mInt(value)
{}
Variant::Variant(int64_t value)
:mType(VTYPE_INT64), mInt64(value)
{}
Variant::Variant(float value)
:mType(VTYPE_FLOAT), mFloat(value)
{}
Variant::Variant(double value)
:mType(VTYPE_FLOAT), mFloat((float)value)
{}
Variant::Variant(const std::string& value)
:mType(VTYPE_STRING), mString(value)
{}
Variant& Variant::operator = (bool value)
{
mType = VTYPE_BOOL;
mBool = value;
return *this;
}
Variant& Variant::operator = (int value)
{
mType = VTYPE_INT;
mInt = value;
return *this;
}
Variant& Variant::operator = (int64_t value)
{
mType = VTYPE_INT64;
mInt64 = value;
return *this;
}
Variant& Variant::operator = (float value)
{
mType = VTYPE_FLOAT;
mFloat = value;
return *this;
}
Variant& Variant::operator = (const std::string& value)
{
mType = VTYPE_STRING;
mString = value;
return *this;
}
Variant& Variant::operator = (const char* value)
{
mType = VTYPE_STRING;
mString = value;
return *this;
}
Variant& Variant::operator = (void* value)
{
mType = VTYPE_POINTER;
mPointer = value;
return *this;
}
Variant& Variant::operator = (PVariantMap map)
{
mType = VTYPE_VMAP;
mVMap = map;
return *this;
}
Variant Variant::operator + (const Variant& rhs)
{
switch (type())
{
case VTYPE_BOOL:
case VTYPE_INT: return asInt() + rhs.asInt();
case VTYPE_INT64: return asInt64() + rhs.asInt64();
case VTYPE_FLOAT: return asFloat() + rhs.asFloat();
case VTYPE_STRING: return asStdString() + rhs.asStdString();
default:
return false;
}
}
Variant Variant::operator - (const Variant& rhs)
{
switch (type())
{
case VTYPE_BOOL:
case VTYPE_STRING:
case VTYPE_INT: return asInt() - rhs.asInt();
case VTYPE_INT64: return asInt64() - rhs.asInt64();
case VTYPE_FLOAT: return asFloat() - rhs.asFloat();
default:
return false;
}
}
Variant Variant::operator * (const Variant& rhs)
{
switch (type())
{
case VTYPE_BOOL:
case VTYPE_STRING:
case VTYPE_INT: return asInt() * rhs.asInt();
case VTYPE_INT64: return asInt64() * rhs.asInt64();
case VTYPE_FLOAT: return asFloat() * rhs.asFloat();
default:
return false;
}
}
Variant Variant::operator / (const Variant& rhs)
{
switch (type())
{
case VTYPE_BOOL:
case VTYPE_STRING:
case VTYPE_INT: return asInt() / rhs.asInt();
case VTYPE_INT64: return asInt64() / rhs.asInt64();
case VTYPE_FLOAT: return asFloat() / rhs.asFloat();
default:
return false;
}
}
bool Variant::operator < (const Variant& rhs) const
{
switch (type())
{
case VTYPE_STRING: return asStdString() < rhs.asStdString();
case VTYPE_BOOL:
case VTYPE_INT: return asInt() < rhs.asInt();
case VTYPE_INT64: return asInt64() < rhs.asInt64();
case VTYPE_FLOAT: return asFloat() < rhs.asFloat();
default:
return false;
}
}
bool Variant::operator > (const Variant& rhs) const
{
return !(*this == rhs) && !(*this < rhs);
}
bool Variant::operator == (const Variant& rhs) const
{
switch (type())
{
case VTYPE_STRING: return asStdString() == rhs.asStdString();
case VTYPE_BOOL: return asBool() == rhs.asBool();
case VTYPE_INT: return asInt() == rhs.asInt();
case VTYPE_INT64: return asInt64() == rhs.asInt64();
case VTYPE_FLOAT: return asFloat() == rhs.asFloat();
case VTYPE_POINTER: return asPointer() == rhs.asPointer();
case VTYPE_VMAP: assert(0); break;
default:
return false;
}
}
bool Variant::operator != (const Variant& rhs) const
{
return !(*this == rhs);
}
bool Variant::operator <= (const Variant& rhs) const
{
return (*this < rhs) || (*this == rhs);
}
bool Variant::operator >= (const Variant& rhs) const
{
return (*this > rhs) || (*this == rhs);
}
int Variant::asInt() const
{
if (mType != VTYPE_INT)
throw Exception(ERR_BAD_VARIANT_TYPE);
return mInt;
}
int64_t Variant::asInt64() const
{
if (mType != VTYPE_INT64)
throw Exception(ERR_BAD_VARIANT_TYPE);
return mInt;
}
bool Variant::asBool() const
{
switch (mType)
{
case VTYPE_INT:
return mInt != 0;
case VTYPE_INT64:
return mInt64 != 0;
case VTYPE_BOOL:
return mBool;
case VTYPE_FLOAT:
return mFloat != 0;
case VTYPE_STRING:
return mString.length() != 0;
default:
throw Exception(ERR_BAD_VARIANT_TYPE);
}
}
float Variant::asFloat() const
{
switch (mType)
{
case VTYPE_INT:
return (float)mInt;
case VTYPE_INT64:
return (float)mInt64;
case VTYPE_FLOAT:
return mFloat;
default:
throw Exception(ERR_BAD_VARIANT_TYPE);
}
}
std::string Variant::asStdString() const
{
char buffer[32];
switch (mType)
{
case VTYPE_STRING:
return mString;
case VTYPE_INT:
sprintf(buffer, "%d", mInt);
return buffer;
case VTYPE_INT64:
sprintf(buffer, "%" PRId64, mInt64);
return buffer;
case VTYPE_BOOL:
return mBool ? "true" : "false";
case VTYPE_FLOAT:
sprintf(buffer, "%f", mFloat);
return buffer;
default:
throw Exception(ERR_BAD_VARIANT_TYPE);
}
}
void* Variant::asPointer() const
{
switch (mType)
{
case VTYPE_POINTER:
return mPointer;
default:
throw Exception(ERR_BAD_VARIANT_TYPE);
}
}
PVariantMap Variant::asVMap()
{
switch (mType)
{
case VTYPE_VMAP:
return mVMap;
default:
throw Exception(ERR_BAD_VARIANT_TYPE);
}
}
VariantType Variant::type() const
{
return mType;
}
VariantMap::VariantMap()
{
}
VariantMap::~VariantMap()
{
}
bool VariantMap::empty() const
{
return mData.empty();
}
void VariantMap::clear()
{
mData.clear();
}
bool VariantMap::exists(int itemId) const
{
return mData.find(itemId) != mData.end();
}
Variant& VariantMap::operator [](int itemId)
{
return mData[itemId];
}
Variant& VariantMap::at(int itemId)
{
return mData[itemId];
}

View File

@@ -0,0 +1,99 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __VARIANT_MAP_H
#define __VARIANT_MAP_H
#include <string>
#include <map>
#include "HL_Pointer.h"
enum VariantType
{
VTYPE_BOOL,
VTYPE_INT,
VTYPE_INT64,
VTYPE_FLOAT,
VTYPE_STRING,
VTYPE_POINTER,
VTYPE_VMAP
};
class VariantMap;
typedef std::shared_ptr<VariantMap> PVariantMap;
class Variant
{
public:
Variant();
~Variant();
Variant(bool value);
Variant(int value);
Variant(int64_t value);
Variant(float value);
Variant(double value);
Variant(const std::string& value);
Variant& operator = (bool value);
Variant& operator = (int value);
Variant& operator = (int64_t value);
Variant& operator = (float value);
Variant& operator = (const std::string& value);
Variant& operator = (const char* value);
Variant& operator = (void* value);
Variant& operator = (PVariantMap vmap);
Variant operator + (const Variant& rhs);
Variant operator - (const Variant& rhs);
Variant operator * (const Variant& rhs);
Variant operator / (const Variant& rhs);
bool operator < (const Variant& rhs) const;
bool operator > (const Variant& rhs) const;
bool operator == (const Variant& rhs) const;
bool operator != (const Variant& rhs) const;
bool operator <= (const Variant& rhs) const;
bool operator >= (const Variant& rhs) const;
int asInt() const;
int64_t asInt64() const;
bool asBool() const;
float asFloat() const ;
std::string asStdString() const;
//const char* asString();
void* asPointer() const;
PVariantMap asVMap();
VariantType type() const;
protected:
VariantType mType;
bool mBool;
int mInt;
int64_t mInt64;
float mFloat;
std::string mString;
void* mPointer;
PVariantMap mVMap;
};
class VariantMap
{
public:
VariantMap();
~VariantMap();
bool empty() const;
void clear();
bool exists(int itemId) const;
Variant& operator[](int itemId);
Variant& at(int itemId);
protected:
std::map<int, Variant> mData;
};
#endif