- initial import
This commit is contained in:
29
src/engine/helper/CMakeLists.txt
Normal file
29
src/engine/helper/CMakeLists.txt
Normal 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})
|
||||
16
src/engine/helper/HL_AsyncCommand.cpp
Normal file
16
src/engine/helper/HL_AsyncCommand.cpp
Normal 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()
|
||||
{
|
||||
|
||||
}
|
||||
19
src/engine/helper/HL_AsyncCommand.h
Normal file
19
src/engine/helper/HL_AsyncCommand.h
Normal 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
|
||||
256
src/engine/helper/HL_Base64.h
Normal file
256
src/engine/helper/HL_Base64.h
Normal 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
|
||||
18
src/engine/helper/HL_ByteBuffer.h
Normal file
18
src/engine/helper/HL_ByteBuffer.h
Normal 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
|
||||
0
src/engine/helper/HL_Calculator.cpp
Normal file
0
src/engine/helper/HL_Calculator.cpp
Normal file
625
src/engine/helper/HL_Calculator.h
Normal file
625
src/engine/helper/HL_Calculator.h
Normal 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
|
||||
26
src/engine/helper/HL_CsvReader.cpp
Normal file
26
src/engine/helper/HL_CsvReader.cpp
Normal 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;
|
||||
}
|
||||
23
src/engine/helper/HL_CsvReader.h
Normal file
23
src/engine/helper/HL_CsvReader.h
Normal 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
|
||||
0
src/engine/helper/HL_Epoll.cpp
Normal file
0
src/engine/helper/HL_Epoll.cpp
Normal file
0
src/engine/helper/HL_Epoll.h
Normal file
0
src/engine/helper/HL_Epoll.h
Normal file
85
src/engine/helper/HL_Exception.h
Normal file
85
src/engine/helper/HL_Exception.h
Normal 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
|
||||
220
src/engine/helper/HL_HepSupport.cpp
Normal file
220
src/engine/helper/HL_HepSupport.cpp
Normal 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;
|
||||
}
|
||||
84
src/engine/helper/HL_HepSupport.h
Normal file
84
src/engine/helper/HL_HepSupport.h
Normal 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
|
||||
12
src/engine/helper/HL_InternetAddress.h
Normal file
12
src/engine/helper/HL_InternetAddress.h
Normal 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
|
||||
1220
src/engine/helper/HL_IuUP.cpp
Normal file
1220
src/engine/helper/HL_IuUP.cpp
Normal file
File diff suppressed because it is too large
Load Diff
39
src/engine/helper/HL_IuUP.h
Normal file
39
src/engine/helper/HL_IuUP.h
Normal 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
|
||||
|
||||
5
src/engine/helper/HL_Log.cpp
Normal file
5
src/engine/helper/HL_Log.cpp
Normal 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/. */
|
||||
|
||||
20
src/engine/helper/HL_Log.h
Normal file
20
src/engine/helper/HL_Log.h
Normal 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
|
||||
141
src/engine/helper/HL_NetworkFrame.cpp
Normal file
141
src/engine/helper/HL_NetworkFrame.cpp
Normal 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;
|
||||
}
|
||||
114
src/engine/helper/HL_NetworkFrame.h
Normal file
114
src/engine/helper/HL_NetworkFrame.h
Normal 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
|
||||
180
src/engine/helper/HL_NetworkSocket.cpp
Normal file
180
src/engine/helper/HL_NetworkSocket.cpp
Normal 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;
|
||||
}
|
||||
66
src/engine/helper/HL_NetworkSocket.h
Normal file
66
src/engine/helper/HL_NetworkSocket.h
Normal 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
|
||||
1043
src/engine/helper/HL_Optional.hpp
Normal file
1043
src/engine/helper/HL_Optional.hpp
Normal file
File diff suppressed because it is too large
Load Diff
125
src/engine/helper/HL_OsVersion.cpp
Normal file
125
src/engine/helper/HL_OsVersion.cpp
Normal 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
|
||||
51
src/engine/helper/HL_OsVersion.h
Normal file
51
src/engine/helper/HL_OsVersion.h
Normal 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
|
||||
55
src/engine/helper/HL_Pointer.cpp
Normal file
55
src/engine/helper/HL_Pointer.cpp
Normal 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();
|
||||
}
|
||||
34
src/engine/helper/HL_Pointer.h
Normal file
34
src/engine/helper/HL_Pointer.h
Normal 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
|
||||
222
src/engine/helper/HL_Rtp.cpp
Normal file
222
src/engine/helper/HL_Rtp.cpp
Normal 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();
|
||||
}
|
||||
|
||||
85
src/engine/helper/HL_Rtp.h
Normal file
85
src/engine/helper/HL_Rtp.h
Normal 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
|
||||
1
src/engine/helper/HL_Singletone.cpp
Normal file
1
src/engine/helper/HL_Singletone.cpp
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
38
src/engine/helper/HL_Singletone.h
Normal file
38
src/engine/helper/HL_Singletone.h
Normal 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
|
||||
290
src/engine/helper/HL_SocketHeap.cpp
Normal file
290
src/engine/helper/HL_SocketHeap.cpp
Normal 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;
|
||||
}
|
||||
114
src/engine/helper/HL_SocketHeap.h
Normal file
114
src/engine/helper/HL_SocketHeap.h
Normal 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
|
||||
24
src/engine/helper/HL_StreamState.h
Normal file
24
src/engine/helper/HL_StreamState.h
Normal 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
|
||||
439
src/engine/helper/HL_String.cpp
Normal file
439
src/engine/helper/HL_String.cpp
Normal 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, <);
|
||||
#else
|
||||
lt = *localtime(&t);
|
||||
#endif
|
||||
strftime(buffer, sizeof(buffer)-1, "%Y-%m-%d %H:%M:%S", <);
|
||||
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;
|
||||
}
|
||||
73
src/engine/helper/HL_String.h
Normal file
73
src/engine/helper/HL_String.h
Normal 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
|
||||
86
src/engine/helper/HL_Sync.cpp
Normal file
86
src/engine/helper/HL_Sync.cpp
Normal 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;
|
||||
}
|
||||
80
src/engine/helper/HL_Sync.h
Normal file
80
src/engine/helper/HL_Sync.h
Normal 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
|
||||
98
src/engine/helper/HL_ThreadPool.h
Normal file
98
src/engine/helper/HL_ThreadPool.h
Normal 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
|
||||
29
src/engine/helper/HL_Types.h
Normal file
29
src/engine/helper/HL_Types.h
Normal 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
|
||||
109
src/engine/helper/HL_Usb.cpp
Normal file
109
src/engine/helper/HL_Usb.cpp
Normal 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
|
||||
47
src/engine/helper/HL_Usb.h
Normal file
47
src/engine/helper/HL_Usb.h
Normal 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
|
||||
67
src/engine/helper/HL_Uuid.cpp
Normal file
67
src/engine/helper/HL_Uuid.cpp
Normal 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
|
||||
}
|
||||
35
src/engine/helper/HL_Uuid.h
Normal file
35
src/engine/helper/HL_Uuid.h
Normal 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
|
||||
373
src/engine/helper/HL_VariantMap.cpp
Normal file
373
src/engine/helper/HL_VariantMap.cpp
Normal 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];
|
||||
}
|
||||
99
src/engine/helper/HL_VariantMap.h
Normal file
99
src/engine/helper/HL_VariantMap.h
Normal 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
|
||||
Reference in New Issue
Block a user