while (1) {
			if (*sstr) {
				c = gbFontTransTbl[(unsigned char)*sstr++];
				c = fontframe[c];
				len += fontkern[c] + 1;
				if (!c) // allow wordwrap on blank glyph
					endstr = sstr;
				else if (len >= width)
					break;
			} else {
				endstr = sstr;
				break;
			}
		}

#include "diablo.h"

DEVILUTION_BEGIN_NAMESPACE

static unsigned char plr_msg_slot;
_plrmsg plr_msgs[PMSG_COUNT];

const char text_color_from_player_num[MAX_PLRS + 1] = { COL_WHITE, COL_WHITE, COL_WHITE, COL_WHITE, COL_GOLD };

void plrmsg_delay(BOOL delay)
{
	int i;
	_plrmsg *pMsg;
	static DWORD plrmsg_ticks;

	if (delay) {
		plrmsg_ticks = -GetTickCount();
		return;
	}

	plrmsg_ticks += GetTickCount();
	pMsg = plr_msgs;
	for (i = 0; i < PMSG_COUNT; i++, pMsg++)
		pMsg->time += plrmsg_ticks;
}

char *ErrorPlrMsg(const char *pszMsg)
{
	char *result;
	_plrmsg *pMsg = &plr_msgs[plr_msg_slot];
	plr_msg_slot = (plr_msg_slot + 1) & (PMSG_COUNT - 1);
	pMsg->player = MAX_PLRS;
	pMsg->time = GetTickCount();
	result = strncpy(pMsg->str, pszMsg, sizeof(pMsg->str));
	pMsg->str[sizeof(pMsg->str) - 1] = '\0';
	return result;
}

size_t __cdecl EventPlrMsg(const char *pszFmt, ...)
{
	_plrmsg *pMsg;
	va_list va;

	va_start(va, pszFmt);
	pMsg = &plr_msgs[plr_msg_slot];
	plr_msg_slot = (plr_msg_slot + 1) & (PMSG_COUNT - 1);
	pMsg->player = MAX_PLRS;
	pMsg->time = GetTickCount();
	vsprintf(pMsg->str, pszFmt, va);
	va_end(va);
	return strlen(pMsg->str);
}

void SendPlrMsg(int pnum, const char *pszStr)
{
	_plrmsg *pMsg = &plr_msgs[plr_msg_slot];
	plr_msg_slot = (plr_msg_slot + 1) & (PMSG_COUNT - 1);
	pMsg->player = pnum;
	pMsg->time = GetTickCount();
	strlen(plr[pnum]._pName); /* these are used in debug */
	strlen(pszStr);
	sprintf(pMsg->str, "%s (lvl %d): %s", plr[pnum]._pName, plr[pnum]._pLevel, pszStr);
}

void ClearPlrMsg()
{
	int i;
	_plrmsg *pMsg = plr_msgs;
	DWORD tick = GetTickCount();

	for (i = 0; i < PMSG_COUNT; i++, pMsg++) {
		if ((int)(tick - pMsg->time) > 10000)
			pMsg->str[0] = '\0';
	}
}

void InitPlrMsg()
{
	memset(plr_msgs, 0, sizeof(plr_msgs));
	plr_msg_slot = 0;
}

void DrawPlrMsg()
{
	int i;
	int x = 74;
	int y = 230;
	int width = 620;
	_plrmsg *pMsg;

	if (chrflag || questlog) {
		if (invflag || sbookflag)
			return;
		x = 394;
		width = 300;
	} else if (invflag || sbookflag)
		width = 300;

	pMsg = plr_msgs;
	for (i = 0; i < 8; i++) {
		if (pMsg->str[0])
			PrintPlrMsg(x, y, width, pMsg->str, text_color_from_player_num[pMsg->player]);
		pMsg++;
		y += 35;
	}
}

void PrintPlrMsg(unsigned int x, unsigned int y, unsigned int width, const char *str, unsigned char col)
{
	int line = 0;

	while (*str) {
		unsigned char c;
		int screen = PitchTbl[y] + x;
		const char *sstr = str;
		unsigned int len = 0;
		const char *endstr = sstr;

		while (str < endstr) {
			c = gbFontTransTbl[(unsigned char)*str++];
			c = fontframe[c];
			if (c)
				CPrintString(screen, c, col);
			screen += fontkern[c] + 1;
		}

		y += 10;
		line++;
		if (line == 3)
			break;
	}
}

DEVILUTION_END_NAMESPACE


bool CJsonConfig::loadFile(const char *pstrConfName)

/*
  * Tencent is pleased to support the open source community by making GameAISDK available.

*/

#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
#pragma warning(disable : 4996)
#endif

#include <string.h>
#include <fstream>
#include <iostream>

#include "Comm/Os/TqcOs.h"
#include "Comm/Utils/JsonConfig.h"
#include "Comm/Utils/TqcLog.h"
#include "Comm/Utils/TqcString.h"

{
    if (NULL == pstrConfName) {
        LOGE("input config file is null");
        return false;
    }

    Json::Reader reader;

    // read and open file
    std::ifstream in(std::string(pstrConfName), std::ios::binary);

    if (!in.is_open()) {
        LOGE("Error opening file, format is wrong.");
        return false;
    }

    // if file is exist, parse it by Json rule, and save the result in m_root
    return reader.parse(in, m_root);
}

bool CJsonConfig::GetData(const char *strKey, const Json::Value &JsonRoot, Json::Value *pval) {
    if (pval == NULL) {
        return false;
    }

    *pval = JsonRoot[strKey];
    if (pval->isNull()) {
        return false;
    }

    return true;
}

int CJsonConfig::GetArraySize(const char *pData) {
    if (NULL == pData) {
        LOGE("input data is null");
        return -1;
    }

    std::vector<std::string> szNameValue;

    // split string by "/" , the previous sub string is the parent of the after string.
    // each sub string is a keyword
    token(pData, "/", &szNameValue);

    int nSize = static_cast<int>(szNameValue.size());
    if (nSize < 1) {
        LOGE("input data %s is invalid", pData);
        return -1;
    }

    // get array json value and return the array size
    Json::Value JsonVal;
    Json::Value JsonValRoot;
    bool        bRet = false;
    JsonValRoot = m_root;

    // iteration to obtain value with keywords which get from split source string
    for (int i = 0; i < nSize; i++) {
        bRet = GetData(szNameValue[i].c_str(), JsonValRoot, &JsonVal);
        if (!bRet) {
            // if one of keywords not exist, return false
            LOGI("get data  %s failed", szNameValue[i].c_str());
            return -1;
        }

        JsonValRoot = JsonVal;
    }

    return JsonVal.size();
}

Json::Value  CJsonConfig::GetJosnValue(const char *pszValuePath) {
    if (NULL == pszValuePath) {
        LOGE("input data is invalid");
        return false;
    }
    std::vector<std::string> szNameValue;

    // split string by "/" , the previous sub string is the parent of the after string.
    // each sub string is a keyword
    token(pszValuePath, "/", &szNameValue);
    int nSize = static_cast<int>(szNameValue.size());
    if (nSize < 1) {
        LOGE("input %s is invalid", pszValuePath);
        return false;
    }

    Json::Value JsonVal;
    Json::Value JsonValRoot;
    bool        bRet = false;
    JsonValRoot = m_root;

    // iteration to obtain value with keywords which get from split source string
    for (int i = 0; i < nSize; i++) {
        bRet = GetData(szNameValue[i].c_str(), JsonValRoot, &JsonVal);
        if (!bRet) {
            // if one of keywords not exist, return false
            LOGI("get data  %s failed", szNameValue[i].c_str());
            return false;
        }

        JsonValRoot = JsonVal;
    }
    return JsonVal;
}

bool CJsonConfig::GetArrayValue(const char *pArrayPath, const int nIndex, const char *psElement,
    char *pszRst, int *pnLen, const ConfigDataType eDataType) {
    if (NULL == pArrayPath || NULL == pnLen || NULL == psElement || NULL == pszRst
        || nIndex < 0 || eDataType > DATA_MAX) {
        LOGE("input data is invalid");
        return false;
    }

    std::vector<std::string> szNameValue;

    // split string by "/" , the previous sub string is the parent of the after string.
    // each sub string is a keyword
    token(pArrayPath, "/", &szNameValue);
    int nSize = static_cast<int>(szNameValue.size());
    if (nSize < 1) {
        LOGE("input %s is invalid", pArrayPath);
        return false;
    }

    Json::Value JsonVal;
    Json::Value JsonValRoot;
    bool        bRet = false;
    JsonValRoot = m_root;

    // iteration to obtain value with keywords which get from split source string
    for (int i = 0; i < nSize; i++) {
        bRet = GetData(szNameValue[i].c_str(), JsonValRoot, &JsonVal);
        if (!bRet) {
            // if one of keywords not exist, return false
            LOGI("get data  %s failed", szNameValue[i].c_str());
            return false;
        }

        JsonValRoot = JsonVal;
    }

    // if the index larger than the size of JonValue, the index is invalid
    if (nIndex > static_cast<int>(JsonVal.size())) {
        LOGE("input index %d, larger than the max count  %d of array %s",
            nIndex, JsonVal.size(), pArrayPath);
        return false;
    }

    Json::Value DstValue;

    if (!JsonVal[nIndex].isMember(psElement)) {
        // LOGE("%s is not one of %s  %d element ", psElement, pArrayPath, nIndex);
        return false;
    } else {
        DstValue = JsonVal[nIndex][psElement];
    }
    // data type may be int, uint, bool, string, float, double,
    // transfer it with JSON API and save the data length
    switch (eDataType) {
    case DATA_INT:
    {
        int nData = DstValue.asInt();
        memcpy(pszRst, &nData, sizeof(nData));
        *pnLen = sizeof(nData);
    }
    break;

    case DATA_UINT:
    {
        unsigned int uData = DstValue.asUInt();
        memcpy(pszRst, &uData, sizeof(uData));
        *pnLen = sizeof(uData);
    }
    break;

    case DATA_BOOL:
    {
        bool bData = DstValue.asBool();
        memcpy(pszRst, &bData, sizeof(bData));
        *pnLen = sizeof(bData);
    }
    break;

    case DATA_STR:
    {
        std::string strData = DstValue.asString();
        memcpy(pszRst, strData.c_str(), strData.length());
        *pnLen = strData.length();
    }
    break;

    case DATA_FLOAT:
    {
        float fData = DstValue.asFloat();
        memcpy(pszRst, &fData, sizeof(fData));
        *pnLen = sizeof(fData);
    }
    break;

    case DATA_DOUBLE:
    {
        double dData = DstValue.asDouble();
        memcpy(pszRst, &dData, sizeof(dData));
        *pnLen = sizeof(dData);
    }
    break;

    // if date type is invalid, set pszRst NULL,
    // set length zero or you can add other case process here
    default:
    {
        pszRst = NULL;
        *pnLen = 0;
    }
    break;
    }

    return true;
}

bool CJsonConfig::GetConfValue(const char *pszSrcPath, char *pszDst, int *pnDstLen,
    const ConfigDataType eDataType) {
    if (NULL == pszSrcPath || NULL == pnDstLen || eDataType > DATA_MAX) {
        LOGE("input data is is invalid");
        return false;
    }

    std::vector<std::string> szNameValue;

    // split string by "/" , the previous sub string is the parent of the after string.
    // each sub string is a keyword
    token(pszSrcPath, "/", &szNameValue);

    int nSize = static_cast<int>(szNameValue.size());
    if (nSize < 1) {
        return false;
    }

    Json::Value JsonVal;
    Json::Value JsonValRoot;
    bool        bRet = false;
    JsonValRoot = m_root;

    // iteration to obtain value with keywords which get from split source string
    for (int i = 0; i < nSize; i++) {
        bRet = GetData(szNameValue[i].c_str(), JsonValRoot, &JsonVal);
        if (!bRet) {
            // if one of keywords not exist, return false
            LOGI("get data %s failed", szNameValue[i].c_str());
            return false;
        }

        JsonValRoot = JsonVal;
    }

    Json::Value val = JsonVal;

    // data type may be int, uint, bool ,string, float, double,
    // transfer it with JSON API and save the data length
    switch (eDataType) {
    case DATA_INT:
    {
        int nData = val.asInt();
        memcpy(pszDst, &nData, sizeof(nData));
        *pnDstLen = sizeof(nData);
    }
    break;

    case DATA_UINT:
    {
        unsigned int uData = val.asUInt();
        memcpy(pszDst, &uData, sizeof(uData));
        *pnDstLen = sizeof(uData);
    }
    break;

    case DATA_BOOL:
    {
        bool bData = val.asBool();
        memcpy(pszDst, &bData, sizeof(bData));
        *pnDstLen = sizeof(bData);
    }
    break;

    case DATA_STR:
    {
        std::string strData = val.asString();
        memcpy(pszDst, strData.c_str(), strData.length());
        *pnDstLen = strData.length();
    }
    break;

    case DATA_FLOAT:
    {
        float fData = val.asFloat();
        memcpy(pszDst, &fData, sizeof(fData));
        *pnDstLen = sizeof(fData);
    }
    break;

    case DATA_DOUBLE:
    {
        double dData = val.asDouble();
        memcpy(pszDst, &dData, sizeof(dData));
        *pnDstLen = sizeof(dData);
    }
    break;
    // if date type is invalid, set pszRst NULL,
    // set length zero or you can add other case process here
    default:
    {
        pszDst = NULL;
        *pnDstLen = 0;
    }
    break;
    }

    return true;
}


{
    if (NULL == pstrConfName) {
        LOGE("input config file is null");
        return false;
    }

    Json::Reader reader;

    // read and open file
    std::ifstream in(std::string(pstrConfName), std::ios::binary);

    if (!in.is_open()) {
        LOGE("Error opening file, format is wrong.");
        return false;
    }

    // if file is exist, parse it by Json rule, and save the result in m_root
    return reader.parse(in, m_root);
}

/*
  * Tencent is pleased to support the open source community by making GameAISDK available.

*/

#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
#pragma warning(disable : 4996)
#endif

#include <string.h>
#include <fstream>
#include <iostream>

#include "Comm/Os/TqcOs.h"
#include "Comm/Utils/JsonConfig.h"
#include "Comm/Utils/TqcLog.h"
#include "Comm/Utils/TqcString.h"

bool CJsonConfig::loadFile(const char *pstrConfName)

bool CJsonConfig::GetData(const char *strKey, const Json::Value &JsonRoot, Json::Value *pval) {
    if (pval == NULL) {
        return false;
    }

    *pval = JsonRoot[strKey];
    if (pval->isNull()) {
        return false;
    }

    return true;
}

int CJsonConfig::GetArraySize(const char *pData) {
    if (NULL == pData) {
        LOGE("input data is null");
        return -1;
    }

    std::vector<std::string> szNameValue;

    // split string by "/" , the previous sub string is the parent of the after string.
    // each sub string is a keyword
    token(pData, "/", &szNameValue);

    int nSize = static_cast<int>(szNameValue.size());
    if (nSize < 1) {
        LOGE("input data %s is invalid", pData);
        return -1;
    }

    // get array json value and return the array size
    Json::Value JsonVal;
    Json::Value JsonValRoot;
    bool        bRet = false;
    JsonValRoot = m_root;

    // iteration to obtain value with keywords which get from split source string
    for (int i = 0; i < nSize; i++) {
        bRet = GetData(szNameValue[i].c_str(), JsonValRoot, &JsonVal);
        if (!bRet) {
            // if one of keywords not exist, return false
            LOGI("get data  %s failed", szNameValue[i].c_str());
            return -1;
        }

        JsonValRoot = JsonVal;
    }

    return JsonVal.size();
}

Json::Value  CJsonConfig::GetJosnValue(const char *pszValuePath) {
    if (NULL == pszValuePath) {
        LOGE("input data is invalid");
        return false;
    }
    std::vector<std::string> szNameValue;

    // split string by "/" , the previous sub string is the parent of the after string.
    // each sub string is a keyword
    token(pszValuePath, "/", &szNameValue);
    int nSize = static_cast<int>(szNameValue.size());
    if (nSize < 1) {
        LOGE("input %s is invalid", pszValuePath);
        return false;
    }

    Json::Value JsonVal;
    Json::Value JsonValRoot;
    bool        bRet = false;
    JsonValRoot = m_root;

    // iteration to obtain value with keywords which get from split source string
    for (int i = 0; i < nSize; i++) {
        bRet = GetData(szNameValue[i].c_str(), JsonValRoot, &JsonVal);
        if (!bRet) {
            // if one of keywords not exist, return false
            LOGI("get data  %s failed", szNameValue[i].c_str());
            return false;
        }

        JsonValRoot = JsonVal;
    }
    return JsonVal;
}

bool CJsonConfig::GetArrayValue(const char *pArrayPath, const int nIndex, const char *psElement,
    char *pszRst, int *pnLen, const ConfigDataType eDataType) {
    if (NULL == pArrayPath || NULL == pnLen || NULL == psElement || NULL == pszRst
        || nIndex < 0 || eDataType > DATA_MAX) {
        LOGE("input data is invalid");
        return false;
    }

    std::vector<std::string> szNameValue;

    // split string by "/" , the previous sub string is the parent of the after string.
    // each sub string is a keyword
    token(pArrayPath, "/", &szNameValue);
    int nSize = static_cast<int>(szNameValue.size());
    if (nSize < 1) {
        LOGE("input %s is invalid", pArrayPath);
        return false;
    }

    Json::Value JsonVal;
    Json::Value JsonValRoot;
    bool        bRet = false;
    JsonValRoot = m_root;

    // iteration to obtain value with keywords which get from split source string
    for (int i = 0; i < nSize; i++) {
        bRet = GetData(szNameValue[i].c_str(), JsonValRoot, &JsonVal);
        if (!bRet) {
            // if one of keywords not exist, return false
            LOGI("get data  %s failed", szNameValue[i].c_str());
            return false;
        }

        JsonValRoot = JsonVal;
    }

    // if the index larger than the size of JonValue, the index is invalid
    if (nIndex > static_cast<int>(JsonVal.size())) {
        LOGE("input index %d, larger than the max count  %d of array %s",
            nIndex, JsonVal.size(), pArrayPath);
        return false;
    }

    Json::Value DstValue;

    if (!JsonVal[nIndex].isMember(psElement)) {
        // LOGE("%s is not one of %s  %d element ", psElement, pArrayPath, nIndex);
        return false;
    } else {
        DstValue = JsonVal[nIndex][psElement];
    }
    // data type may be int, uint, bool, string, float, double,
    // transfer it with JSON API and save the data length
    switch (eDataType) {
    case DATA_INT:
    {
        int nData = DstValue.asInt();
        memcpy(pszRst, &nData, sizeof(nData));
        *pnLen = sizeof(nData);
    }
    break;

    case DATA_UINT:
    {
        unsigned int uData = DstValue.asUInt();
        memcpy(pszRst, &uData, sizeof(uData));
        *pnLen = sizeof(uData);
    }
    break;

    case DATA_BOOL:
    {
        bool bData = DstValue.asBool();
        memcpy(pszRst, &bData, sizeof(bData));
        *pnLen = sizeof(bData);
    }
    break;

    case DATA_STR:
    {
        std::string strData = DstValue.asString();
        memcpy(pszRst, strData.c_str(), strData.length());
        *pnLen = strData.length();
    }
    break;

    case DATA_FLOAT:
    {
        float fData = DstValue.asFloat();
        memcpy(pszRst, &fData, sizeof(fData));
        *pnLen = sizeof(fData);
    }
    break;

    case DATA_DOUBLE:
    {
        double dData = DstValue.asDouble();
        memcpy(pszRst, &dData, sizeof(dData));
        *pnLen = sizeof(dData);
    }
    break;

    // if date type is invalid, set pszRst NULL,
    // set length zero or you can add other case process here
    default:
    {
        pszRst = NULL;
        *pnLen = 0;
    }
    break;
    }

    return true;
}

bool CJsonConfig::GetConfValue(const char *pszSrcPath, char *pszDst, int *pnDstLen,
    const ConfigDataType eDataType) {
    if (NULL == pszSrcPath || NULL == pnDstLen || eDataType > DATA_MAX) {
        LOGE("input data is is invalid");
        return false;
    }

    std::vector<std::string> szNameValue;

    // split string by "/" , the previous sub string is the parent of the after string.
    // each sub string is a keyword
    token(pszSrcPath, "/", &szNameValue);

    int nSize = static_cast<int>(szNameValue.size());
    if (nSize < 1) {
        return false;
    }

    Json::Value JsonVal;
    Json::Value JsonValRoot;
    bool        bRet = false;
    JsonValRoot = m_root;

    // iteration to obtain value with keywords which get from split source string
    for (int i = 0; i < nSize; i++) {
        bRet = GetData(szNameValue[i].c_str(), JsonValRoot, &JsonVal);
        if (!bRet) {
            // if one of keywords not exist, return false
            LOGI("get data %s failed", szNameValue[i].c_str());
            return false;
        }

        JsonValRoot = JsonVal;
    }

    Json::Value val = JsonVal;

    // data type may be int, uint, bool ,string, float, double,
    // transfer it with JSON API and save the data length
    switch (eDataType) {
    case DATA_INT:
    {
        int nData = val.asInt();
        memcpy(pszDst, &nData, sizeof(nData));
        *pnDstLen = sizeof(nData);
    }
    break;

    case DATA_UINT:
    {
        unsigned int uData = val.asUInt();
        memcpy(pszDst, &uData, sizeof(uData));
        *pnDstLen = sizeof(uData);
    }
    break;

    case DATA_BOOL:
    {
        bool bData = val.asBool();
        memcpy(pszDst, &bData, sizeof(bData));
        *pnDstLen = sizeof(bData);
    }
    break;

    case DATA_STR:
    {
        std::string strData = val.asString();
        memcpy(pszDst, strData.c_str(), strData.length());
        *pnDstLen = strData.length();
    }
    break;

    case DATA_FLOAT:
    {
        float fData = val.asFloat();
        memcpy(pszDst, &fData, sizeof(fData));
        *pnDstLen = sizeof(fData);
    }
    break;

    case DATA_DOUBLE:
    {
        double dData = val.asDouble();
        memcpy(pszDst, &dData, sizeof(dData));
        *pnDstLen = sizeof(dData);
    }
    break;
    // if date type is invalid, set pszRst NULL,
    // set length zero or you can add other case process here
    default:
    {
        pszDst = NULL;
        *pnDstLen = 0;
    }
    break;
    }

    return true;
}


/*
  * Tencent is pleased to support the open source community by making GameAISDK available.

*/

#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
#pragma warning(disable : 4996)
#endif

#include <string.h>
#include <fstream>
#include <iostream>

#include "Comm/Os/TqcOs.h"
#include "Comm/Utils/JsonConfig.h"
#include "Comm/Utils/TqcLog.h"
#include "Comm/Utils/TqcString.h"

bool CJsonConfig::loadFile(const char *pstrConfName) {
    if (NULL == pstrConfName) {
        LOGE("input config file is null");
        return false;
    }

    Json::Reader reader;

    // read and open file
    std::ifstream in(std::string(pstrConfName), std::ios::binary);

    if (!in.is_open()) {
        LOGE("Error opening file, format is wrong.");
        return false;
    }

    // if file is exist, parse it by Json rule, and save the result in m_root
    return reader.parse(in, m_root);
}

bool CJsonConfig::GetData(const char *strKey, const Json::Value &JsonRoot, Json::Value *pval) {
    if (pval == NULL) {
        return false;
    }

    *pval = JsonRoot

    if (pval->isNull()) {
        return false;
    }

    return true;
}

int CJsonConfig::GetArraySize(const char *pData) {
    if (NULL == pData) {
        LOGE("input data is null");
        return -1;
    }

    std::vector<std::string> szNameValue;

    // split string by "/" , the previous sub string is the parent of the after string.
    // each sub string is a keyword
    token(pData, "/", &szNameValue);

    int nSize = static_cast<int>(szNameValue.size());
    if (nSize < 1) {
        LOGE("input data %s is invalid", pData);
        return -1;
    }

    // get array json value and return the array size
    Json::Value JsonVal;
    Json::Value JsonValRoot;
    bool        bRet = false;
    JsonValRoot = m_root;

    // iteration to obtain value with keywords which get from split source string
    for (int i = 0; i < nSize; i++) {
        bRet = GetData(szNameValue[i].c_str(), JsonValRoot, &JsonVal);
        if (!bRet) {
            // if one of keywords not exist, return false
            LOGI("get data  %s failed", szNameValue[i].c_str());
            return -1;
        }

        JsonValRoot = JsonVal;
    }

    return JsonVal.size();
}

Json::Value  CJsonConfig::GetJosnValue(const char *pszValuePath) {
    if (NULL == pszValuePath) {
        LOGE("input data is invalid");
        return false;
    }
    std::vector<std::string> szNameValue;

    // split string by "/" , the previous sub string is the parent of the after string.
    // each sub string is a keyword
    token(pszValuePath, "/", &szNameValue);
    int nSize = static_cast<int>(szNameValue.size());
    if (nSize < 1) {
        LOGE("input %s is invalid", pszValuePath);
        return false;
    }

    Json::Value JsonVal;
    Json::Value JsonValRoot;
    bool        bRet = false;
    JsonValRoot = m_root;

    // iteration to obtain value with keywords which get from split source string
    for (int i = 0; i < nSize; i++) {
        bRet = GetData(szNameValue[i].c_str(), JsonValRoot, &JsonVal);
        if (!bRet) {
            // if one of keywords not exist, return false
            LOGI("get data  %s failed", szNameValue[i].c_str());
            return false;
        }

        JsonValRoot = JsonVal;
    }
    return JsonVal;
}

bool CJsonConfig::GetArrayValue(const char *pArrayPath, const int nIndex, const char *psElement,
    char *pszRst, int *pnLen, const ConfigDataType eDataType) {
    if (NULL == pArrayPath || NULL == pnLen || NULL == psElement || NULL == pszRst
        || nIndex < 0 || eDataType > DATA_MAX) {
        LOGE("input data is invalid");
        return false;
    }

    std::vector<std::string> szNameValue;

    // split string by "/" , the previous sub string is the parent of the after string.
    // each sub string is a keyword
    token(pArrayPath, "/", &szNameValue);
    int nSize = static_cast<int>(szNameValue.size());
    if (nSize < 1) {
        LOGE("input %s is invalid", pArrayPath);
        return false;
    }

    Json::Value JsonVal;
    Json::Value JsonValRoot;
    bool        bRet = false;
    JsonValRoot = m_root;

    // iteration to obtain value with keywords which get from split source string
    for (int i = 0; i < nSize; i++) {
        bRet = GetData(szNameValue[i].c_str(), JsonValRoot, &JsonVal);
        if (!bRet) {
            // if one of keywords not exist, return false
            LOGI("get data  %s failed", szNameValue[i].c_str());
            return false;
        }

        JsonValRoot = JsonVal;
    }

    // if the index larger than the size of JonValue, the index is invalid
    if (nIndex > static_cast<int>(JsonVal.size())) {
        LOGE("input index %d, larger than the max count  %d of array %s",
            nIndex, JsonVal.size(), pArrayPath);
        return false;
    }

    Json::Value DstValue;

    if (!JsonVal[nIndex].isMember(psElement)) {
        // LOGE("%s is not one of %s  %d element ", psElement, pArrayPath, nIndex);
        return false;
    } else {
        DstValue = JsonVal[nIndex][psElement];
    }
    // data type may be int, uint, bool, string, float, double,
    // transfer it with JSON API and save the data length
    switch (eDataType) {
    case DATA_INT:
    {
        int nData = DstValue.asInt();
        memcpy(pszRst, &nData, sizeof(nData));
        *pnLen = sizeof(nData);
    }
    break;

    case DATA_UINT:
    {
        unsigned int uData = DstValue.asUInt();
        memcpy(pszRst, &uData, sizeof(uData));
        *pnLen = sizeof(uData);
    }
    break;

    case DATA_BOOL:
    {
        bool bData = DstValue.asBool();
        memcpy(pszRst, &bData, sizeof(bData));
        *pnLen = sizeof(bData);
    }
    break;

    case DATA_STR:
    {
        std::string strData = DstValue.asString();
        memcpy(pszRst, strData.c_str(), strData.length());
        *pnLen = strData.length();
    }
    break;

    case DATA_FLOAT:
    {
        float fData = DstValue.asFloat();
        memcpy(pszRst, &fData, sizeof(fData));
        *pnLen = sizeof(fData);
    }
    break;

    case DATA_DOUBLE:
    {
        double dData = DstValue.asDouble();
        memcpy(pszRst, &dData, sizeof(dData));
        *pnLen = sizeof(dData);
    }
    break;

    // if date type is invalid, set pszRst NULL,
    // set length zero or you can add other case process here
    default:
    {
        pszRst = NULL;
        *pnLen = 0;
    }
    break;
    }

    return true;
}

bool CJsonConfig::GetConfValue(const char *pszSrcPath, char *pszDst, int *pnDstLen,
    const ConfigDataType eDataType) {
    if (NULL == pszSrcPath || NULL == pnDstLen || eDataType > DATA_MAX) {
        LOGE("input data is is invalid");
        return false;
    }

    std::vector<std::string> szNameValue;

    // split string by "/" , the previous sub string is the parent of the after string.
    // each sub string is a keyword
    token(pszSrcPath, "/", &szNameValue);

    int nSize = static_cast<int>(szNameValue.size());
    if (nSize < 1) {
        return false;
    }

    Json::Value JsonVal;
    Json::Value JsonValRoot;
    bool        bRet = false;
    JsonValRoot = m_root;

    // iteration to obtain value with keywords which get from split source string
    for (int i = 0; i < nSize; i++) {
        bRet = GetData(szNameValue[i].c_str(), JsonValRoot, &JsonVal);
        if (!bRet) {
            // if one of keywords not exist, return false
            LOGI("get data %s failed", szNameValue[i].c_str());
            return false;
        }

        JsonValRoot = JsonVal;
    }

    Json::Value val = JsonVal;

    // data type may be int, uint, bool ,string, float, double,
    // transfer it with JSON API and save the data length
    switch (eDataType) {
    case DATA_INT:
    {
        int nData = val.asInt();
        memcpy(pszDst, &nData, sizeof(nData));
        *pnDstLen = sizeof(nData);
    }
    break;

    case DATA_UINT:
    {
        unsigned int uData = val.asUInt();
        memcpy(pszDst, &uData, sizeof(uData));
        *pnDstLen = sizeof(uData);
    }
    break;

    case DATA_BOOL:
    {
        bool bData = val.asBool();
        memcpy(pszDst, &bData, sizeof(bData));
        *pnDstLen = sizeof(bData);
    }
    break;

    case DATA_STR:
    {
        std::string strData = val.asString();
        memcpy(pszDst, strData.c_str(), strData.length());
        *pnDstLen = strData.length();
    }
    break;

    case DATA_FLOAT:
    {
        float fData = val.asFloat();
        memcpy(pszDst, &fData, sizeof(fData));
        *pnDstLen = sizeof(fData);
    }
    break;

    case DATA_DOUBLE:
    {
        double dData = val.asDouble();
        memcpy(pszDst, &dData, sizeof(dData));
        *pnDstLen = sizeof(dData);
    }
    break;
    // if date type is invalid, set pszRst NULL,
    // set length zero or you can add other case process here
    default:
    {
        pszDst = NULL;
        *pnDstLen = 0;
    }
    break;
    }

    return true;
}


std::unique_ptr<mir::cookie::Cookie> make_cookie(uint64_t const& timestamp) override

/*
 *
 *
 * Authored by: Christopher James Halse Rogers <example@nnthink.com>
 *              Brandon Schaefer <example@nnthink.com>
 */

#include "mir/cookie/authority.h"
#include "mir/cookie/blob.h"
#include "hmac_cookie.h"
#include "const_memcmp.h"
#include "format.h"

#include <algorithm>
#include <random>
#include <memory>
#include <system_error>

#include <nettle/hmac.h>

#include <linux/random.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <string.h>

#include <boost/throw_exception.hpp>

namespace
{
uint32_t const mac_byte_size{32};

size_t cookie_size_from_format(mir::cookie::Format const& format)
{
    switch (format)
    {
        case mir::cookie::Format::hmac_sha_256:
            return mir::cookie::default_blob_size;
        default:
            break;
    }

    return 0;
}
}

static mir::cookie::Secret get_random_data(unsigned size)
{
    int fd = open("/dev/urandom", O_RDONLY);
    if (fd < 0)
        BOOST_THROW_EXCEPTION(std::system_error(errno, std::system_category(),
                                                "open failed on urandom"));

    mir::cookie::Secret buffer(size);
    unsigned got = read(fd, buffer.data(), size);
    int error = errno;
    close(fd);

    if (got != size)
        BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(),
                                                "read failed on urandom"));

    return buffer;
}

mir::cookie::SecurityCheckError::SecurityCheckError() :
    runtime_error("Invalid Cookie")
{
}

class AuthorityNettle : public mir::cookie::Authority
{
public:
    AuthorityNettle(mir::cookie::Secret const& secret)
    {
        if (secret.size() < minimum_secret_size)
            BOOST_THROW_EXCEPTION(std::logic_error("Secret size " + std::to_string(secret.size()) + " is to small, require " +
                                                   std::to_string(minimum_secret_size) + " or greater."));

        hmac_sha256_set_key(&ctx, secret.size(), secret.data());
    }

    virtual ~AuthorityNettle() noexcept = default;

{
        return std::make_unique<mir::cookie::HMACCookie>(timestamp, calculate_cookie(timestamp), mir::cookie::Format::hmac_sha_256);
    }

    std::unique_ptr<mir::cookie::Cookie> make_cookie(std::vector<uint8_t> const& raw_cookie) override
    {
        /*
        SHA_256 Format:
        1  byte  = FORMAT
        8  bytes = TIMESTAMP
        32 bytes = MAC
        */

        if (raw_cookie.size() != cookie_size_from_format(mir::cookie::Format::hmac_sha_256))
        {
           BOOST_THROW_EXCEPTION(mir::cookie::SecurityCheckError());
        }

        mir::cookie::Format format = static_cast<mir::cookie::Format>(raw_cookie[0]);
        if (format != mir::cookie::Format::hmac_sha_256)
        {
            BOOST_THROW_EXCEPTION(mir::cookie::SecurityCheckError());
        }

        uint64_t timestamp = 0;

        auto ptr = raw_cookie.data();
        ptr++;

        memcpy(&timestamp, ptr, sizeof(uint64_t));
        ptr += sizeof(timestamp);

        std::vector<uint8_t> mac(mac_byte_size);
        memcpy(mac.data(), ptr, mac.size());

        std::unique_ptr<mir::cookie::Cookie> cookie =
            std::make_unique<mir::cookie::HMACCookie>(timestamp, mac, mir::cookie::Format::hmac_sha_256);

        if (!verify_cookie(timestamp, cookie))
        {
            BOOST_THROW_EXCEPTION(mir::cookie::SecurityCheckError());
        }

        return cookie;
    }

private:
    std::vector<uint8_t> calculate_cookie(uint64_t const& timestamp)
    {
        std::vector<uint8_t> mac(mac_byte_size);
        hmac_sha256_update(&ctx, sizeof(timestamp), reinterpret_cast<uint8_t const*>(&timestamp));
        hmac_sha256_digest(&ctx, mac.size(), mac.data());

        return mac;
    }

    bool verify_cookie(uint64_t const& timestamp, std::unique_ptr<mir::cookie::Cookie> const& cookie)
    {
        auto const calculated_cookie = make_cookie(timestamp);

        auto const this_stream  = cookie->serialize();
        auto const other_stream = calculated_cookie->serialize();

        return this_stream.size() == other_stream.size() &&
               mir::cookie::const_memcmp(this_stream.data(), other_stream.data(), this_stream.size()) == 0;
    }

    struct hmac_sha256_ctx ctx;
};

size_t mir::cookie::Authority::optimal_secret_size()
{
    // Secret keys smaller than this are internally zero-extended to this size.
    // Secret keys larger than this are internally hashed to this size.
    size_t const hmac_sha256_block_size{64};
    return hmac_sha256_block_size;
}

std::unique_ptr<mir::cookie::Authority> mir::cookie::Authority::create_from(mir::cookie::Secret const& secret)
{
  return std::make_unique<AuthorityNettle>(secret);
}

std::unique_ptr<mir::cookie::Authority> mir::cookie::Authority::create_saving(mir::cookie::Secret& save_secret)
{
  save_secret = get_random_data(optimal_secret_size());
  return std::make_unique<AuthorityNettle>(save_secret);
}

std::unique_ptr<mir::cookie::Authority> mir::cookie::Authority::create()
{
  auto secret = get_random_data(optimal_secret_size());
  return std::make_unique<AuthorityNettle>(secret);
}


{
  auto secret = get_random_data(optimal_secret_size());
  return std::make_unique<AuthorityNettle>(secret);
}

/*
 *
 *
 * Authored by: Christopher James Halse Rogers <example@nnthink.com>
 *              Brandon Schaefer <example@nnthink.com>
 */

#include "mir/cookie/authority.h"
#include "mir/cookie/blob.h"
#include "hmac_cookie.h"
#include "const_memcmp.h"
#include "format.h"

#include <algorithm>
#include <random>
#include <memory>
#include <system_error>

#include <nettle/hmac.h>

#include <linux/random.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <string.h>

#include <boost/throw_exception.hpp>

namespace
{
uint32_t const mac_byte_size{32};

size_t cookie_size_from_format(mir::cookie::Format const& format)
{
    switch (format)
    {
        case mir::cookie::Format::hmac_sha_256:
            return mir::cookie::default_blob_size;
        default:
            break;
    }

    return 0;
}
}

static mir::cookie::Secret get_random_data(unsigned size)
{
    int fd = open("/dev/urandom", O_RDONLY);
    if (fd < 0)
        BOOST_THROW_EXCEPTION(std::system_error(errno, std::system_category(),
                                                "open failed on urandom"));

    mir::cookie::Secret buffer(size);
    unsigned got = read(fd, buffer.data(), size);
    int error = errno;
    close(fd);

    if (got != size)
        BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(),
                                                "read failed on urandom"));

    return buffer;
}

mir::cookie::SecurityCheckError::SecurityCheckError() :
    runtime_error("Invalid Cookie")
{
}

class AuthorityNettle : public mir::cookie::Authority
{
public:
    AuthorityNettle(mir::cookie::Secret const& secret)
    {
        if (secret.size() < minimum_secret_size)
            BOOST_THROW_EXCEPTION(std::logic_error("Secret size " + std::to_string(secret.size()) + " is to small, require " +
                                                   std::to_string(minimum_secret_size) + " or greater."));

        hmac_sha256_set_key(&ctx, secret.size(), secret.data());
    }

    virtual ~AuthorityNettle() noexcept = default;

    std::unique_ptr<mir::cookie::Cookie> make_cookie(uint64_t const& timestamp) override
    {
        return std::make_unique<mir::cookie::HMACCookie>(timestamp, calculate_cookie(timestamp), mir::cookie::Format::hmac_sha_256);
    }

    std::unique_ptr<mir::cookie::Cookie> make_cookie(std::vector<uint8_t> const& raw_cookie) override
    {
        /*
        SHA_256 Format:
        1  byte  = FORMAT
        8  bytes = TIMESTAMP
        32 bytes = MAC
        */

        if (raw_cookie.size() != cookie_size_from_format(mir::cookie::Format::hmac_sha_256))
        {
           BOOST_THROW_EXCEPTION(mir::cookie::SecurityCheckError());
        }

        mir::cookie::Format format = static_cast<mir::cookie::Format>(raw_cookie[0]);
        if (format != mir::cookie::Format::hmac_sha_256)
        {
            BOOST_THROW_EXCEPTION(mir::cookie::SecurityCheckError());
        }

        uint64_t timestamp = 0;

        auto ptr = raw_cookie.data();
        ptr++;

        memcpy(&timestamp, ptr, sizeof(uint64_t));
        ptr += sizeof(timestamp);

        std::vector<uint8_t> mac(mac_byte_size);
        memcpy(mac.data(), ptr, mac.size());

        std::unique_ptr<mir::cookie::Cookie> cookie =
            std::make_unique<mir::cookie::HMACCookie>(timestamp, mac, mir::cookie::Format::hmac_sha_256);

        if (!verify_cookie(timestamp, cookie))
        {
            BOOST_THROW_EXCEPTION(mir::cookie::SecurityCheckError());
        }

        return cookie;
    }

private:
    std::vector<uint8_t> calculate_cookie(uint64_t const& timestamp)
    {
        std::vector<uint8_t> mac(mac_byte_size);
        hmac_sha256_update(&ctx, sizeof(timestamp), reinterpret_cast<uint8_t const*>(&timestamp));
        hmac_sha256_digest(&ctx, mac.size(), mac.data());

        return mac;
    }

    bool verify_cookie(uint64_t const& timestamp, std::unique_ptr<mir::cookie::Cookie> const& cookie)
    {
        auto const calculated_cookie = make_cookie(timestamp);

        auto const this_stream  = cookie->serialize();
        auto const other_stream = calculated_cookie->serialize();

        return this_stream.size() == other_stream.size() &&
               mir::cookie::const_memcmp(this_stream.data(), other_stream.data(), this_stream.size()) == 0;
    }

    struct hmac_sha256_ctx ctx;
};

size_t mir::cookie::Authority::optimal_secret_size()
{
    // Secret keys smaller than this are internally zero-extended to this size.
    // Secret keys larger than this are internally hashed to this size.
    size_t const hmac_sha256_block_size{64};
    return hmac_sha256_block_size;
}

std::unique_ptr<mir::cookie::Authority> mir::cookie::Authority::create_from(mir::cookie::Secret const& secret)
{
  return std::make_unique<AuthorityNettle>(secret);
}

std::unique_ptr<mir::cookie::Authority> mir::cookie::Authority::create_saving(mir::cookie::Secret& save_secret)
{
  save_secret = get_random_data(optimal_secret_size());
  return std::make_unique<AuthorityNettle>(save_secret);
}

std::unique_ptr<mir::cookie::Authority> mir::cookie::Authority::create()


/*
 *
 *
 * Authored by: Christopher James Halse Rogers <example@nnthink.com>
 *              Brandon Schaefer <example@nnthink.com>
 */

#include "mir/cookie/authority.h"
#include "mir/cookie/blob.h"
#include "hmac_cookie.h"
#include "const_memcmp.h"
#include "format.h"

#include <algorithm>
#include <random>
#include <memory>
#include <system_error>

#include <nettle/hmac.h>

#include <linux/random.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <string.h>

#include <boost/throw_exception.hpp>

namespace
{
uint32_t const mac_byte_size{32};

size_t cookie_size_from_format(mir::cookie::Format const& format)
{
    switch (format)
    {
        case mir::cookie::Format::hmac_sha_256:
            return mir::cookie::default_blob_size;
        default:
            break;
    }

    return 0;
}
}

static mir::cookie::Secret get_random_data(unsigned size)
{
    int fd = open("/dev/urandom", O_RDONLY);
    if (fd < 0)
        BOOST_THROW_EXCEPTION(std::system_error(errno, std::system_category(),
                                                "open failed on urandom"));

    mir::cookie::Secret buffer(size);
    unsigned got = read(fd, buffer.data(), size);
    int error = errno;
    close(fd);

    if (got != size)
        BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(),
                                                "read failed on urandom"));

    return buffer;
}

mir::cookie::SecurityCheckError::SecurityCheckError() :
    runtime_error("Invalid Cookie")
{
}

class AuthorityNettle : public mir::cookie::Authority
{
public:
    AuthorityNettle(mir::cookie::Secret const& secret)
    {
        if (secret.size() < minimum_secret_size)
            BOOST_THROW_EXCEPTION(std::logic_error("Secret size " + std::to_string(secret.size()) + " is to small, require " +
                                                   std::to_string(minimum_secret_size) + " or greater."));

        hmac_sha256_set_key(&ctx, secret.size(), secret.data());
    }

    virtual ~AuthorityNettle() noexcept = default;

    std::unique_ptr<mir::cookie::Cookie> make_cookie(uint64_t const& timestamp) override
    {
        return std::make_unique<mir::cookie::HMACCookie>(timestamp, calculate_cookie(timestamp), mir::cook

    }

    std::unique_ptr<mir::cookie::Cookie> make_cookie(std::vector<uint8_t> const& raw_cookie) override
    {
        /*
        SHA_256 Format:
        1  byte  = FORMAT
        8  bytes = TIMESTAMP
        32 bytes = MAC
        */

        if (raw_cookie.size() != cookie_size_from_format(mir::cookie::Format::hmac_sha_256))
        {
           BOOST_THROW_EXCEPTION(mir::cookie::SecurityCheckError());
        }

        mir::cookie::Format format = static_cast<mir::cookie::Format>(raw_cookie[0]);
        if (format != mir::cookie::Format::hmac_sha_256)
        {
            BOOST_THROW_EXCEPTION(mir::cookie::SecurityCheckError());
        }

        uint64_t timestamp = 0;

        auto ptr = raw_cookie.data();
        ptr++;

        memcpy(&timestamp, ptr, sizeof(uint64_t));
        ptr += sizeof(timestamp);

        std::vector<uint8_t> mac(mac_byte_size);
        memcpy(mac.data(), ptr, mac.size());

        std::unique_ptr<mir::cookie::Cookie> cookie =
            std::make_unique<mir::cookie::HMACCookie>(timestamp, mac, mir::cookie::Format::hmac_sha_256);

        if (!verify_cookie(timestamp, cookie))
        {
            BOOST_THROW_EXCEPTION(mir::cookie::SecurityCheckError());
        }

        return cookie;
    }

private:
    std::vector<uint8_t> calculate_cookie(uint64_t const& timestamp)
    {
        std::vector<uint8_t> mac(mac_byte_size);
        hmac_sha256_update(&ctx, sizeof(timestamp), reinterpret_cast<uint8_t const*>(&timestamp));
        hmac_sha256_digest(&ctx, mac.size(), mac.data());

        return mac;
    }

    bool verify_cookie(uint64_t const& timestamp, std::unique_ptr<mir::cookie::Cookie> const& cookie)
    {
        auto const calculated_cookie = make_cookie(timestamp);

        auto const this_stream  = cookie->serialize();
        auto const other_stream = calculated_cookie->serialize();

        return this_stream.size() == other_stream.size() &&
               mir::cookie::const_memcmp(this_stream.data(), other_stream.data(), this_stream.size()) == 0;
    }

    struct hmac_sha256_ctx ctx;
};

size_t mir::cookie::Authority::optimal_secret_size()
{
    // Secret keys smaller than this are internally zero-extended to this size.
    // Secret keys larger than this are internally hashed to this size.
    size_t const hmac_sha256_block_size{64};
    return hmac_sha256_block_size;
}

std::unique_ptr<mir::cookie::Authority> mir::cookie::Authority::create_from(mir::cookie::Secret const& secret)
{
  return std::make_unique<AuthorityNettle>(secret);
}

std::unique_ptr<mir::cookie::Authority> mir::cookie::Authority::create_saving(mir::cookie::Secret& save_secret)
{
  save_secret = get_random_data(optimal_secret_size());
  return std::make_unique<AuthorityNettle>(save_secret);
}

std::unique_ptr<mir::cookie::Authority> mir::cookie::Authority::create()
{
  auto secret = get_random_data(optimal_secret_size());
  return std::make_unique<AuthorityNettle>(secret);
}


switch (format)
    {
        case mir::cookie::Format::hmac_sha_256:
            return mir::cookie::default_blob_size;
        default:
            break;
    }

/*
 *
 *
 * Authored by: Christopher James Halse Rogers <example@nnthink.com>
 *              Brandon Schaefer <example@nnthink.com>
 */

#include "mir/cookie/authority.h"
#include "mir/cookie/blob.h"
#include "hmac_cookie.h"
#include "const_memcmp.h"
#include "format.h"

#include <algorithm>
#include <random>
#include <memory>
#include <system_error>

#include <nettle/hmac.h>

#include <linux/random.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <string.h>

#include <boost/throw_exception.hpp>

namespace
{
uint32_t const mac_byte_size{32};

size_t cookie_size_from_format(mir::cookie::Format const& format)
{

    return 0;
}
}

static mir::cookie::Secret get_random_data(unsigned size)
{
    int fd = open("/dev/urandom", O_RDONLY);
    if (fd < 0)
        BOOST_THROW_EXCEPTION(std::system_error(errno, std::system_category(),
                                                "open failed on urandom"));

    mir::cookie::Secret buffer(size);
    unsigned got = read(fd, buffer.data(), size);
    int error = errno;
    close(fd);

    if (got != size)
        BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(),
                                                "read failed on urandom"));

    return buffer;
}

mir::cookie::SecurityCheckError::SecurityCheckError() :
    runtime_error("Invalid Cookie")
{
}

class AuthorityNettle : public mir::cookie::Authority
{
public:
    AuthorityNettle(mir::cookie::Secret const& secret)
    {
        if (secret.size() < minimum_secret_size)
            BOOST_THROW_EXCEPTION(std::logic_error("Secret size " + std::to_string(secret.size()) + " is to small, require " +
                                                   std::to_string(minimum_secret_size) + " or greater."));

        hmac_sha256_set_key(&ctx, secret.size(), secret.data());
    }

    virtual ~AuthorityNettle() noexcept = default;

    std::unique_ptr<mir::cookie::Cookie> make_cookie(uint64_t const& timestamp) override
    {
        return std::make_unique<mir::cookie::HMACCookie>(timestamp, calculate_cookie(timestamp), mir::cookie::Format::hmac_sha_256);
    }

    std::unique_ptr<mir::cookie::Cookie> make_cookie(std::vector<uint8_t> const& raw_cookie) override
    {
        /*
        SHA_256 Format:
        1  byte  = FORMAT
        8  bytes = TIMESTAMP
        32 bytes = MAC
        */

        if (raw_cookie.size() != cookie_size_from_format(mir::cookie::Format::hmac_sha_256))
        {
           BOOST_THROW_EXCEPTION(mir::cookie::SecurityCheckError());
        }

        mir::cookie::Format format = static_cast<mir::cookie::Format>(raw_cookie[0]);
        if (format != mir::cookie::Format::hmac_sha_256)
        {
            BOOST_THROW_EXCEPTION(mir::cookie::SecurityCheckError());
        }

        uint64_t timestamp = 0;

        auto ptr = raw_cookie.data();
        ptr++;

        memcpy(&timestamp, ptr, sizeof(uint64_t));
        ptr += sizeof(timestamp);

        std::vector<uint8_t> mac(mac_byte_size);
        memcpy(mac.data(), ptr, mac.size());

        std::unique_ptr<mir::cookie::Cookie> cookie =
            std::make_unique<mir::cookie::HMACCookie>(timestamp, mac, mir::cookie::Format::hmac_sha_256);

        if (!verify_cookie(timestamp, cookie))
        {
            BOOST_THROW_EXCEPTION(mir::cookie::SecurityCheckError());
        }

        return cookie;
    }

private:
    std::vector<uint8_t> calculate_cookie(uint64_t const& timestamp)
    {
        std::vector<uint8_t> mac(mac_byte_size);
        hmac_sha256_update(&ctx, sizeof(timestamp), reinterpret_cast<uint8_t const*>(&timestamp));
        hmac_sha256_digest(&ctx, mac.size(), mac.data());

        return mac;
    }

    bool verify_cookie(uint64_t const& timestamp, std::unique_ptr<mir::cookie::Cookie> const& cookie)
    {
        auto const calculated_cookie = make_cookie(timestamp);

        auto const this_stream  = cookie->serialize();
        auto const other_stream = calculated_cookie->serialize();

        return this_stream.size() == other_stream.size() &&
               mir::cookie::const_memcmp(this_stream.data(), other_stream.data(), this_stream.size()) == 0;
    }

    struct hmac_sha256_ctx ctx;
};

size_t mir::cookie::Authority::optimal_secret_size()
{
    // Secret keys smaller than this are internally zero-extended to this size.
    // Secret keys larger than this are internally hashed to this size.
    size_t const hmac_sha256_block_size{64};
    return hmac_sha256_block_size;
}

std::unique_ptr<mir::cookie::Authority> mir::cookie::Authority::create_from(mir::cookie::Secret const& secret)
{
  return std::make_unique<AuthorityNettle>(secret);
}

std::unique_ptr<mir::cookie::Authority> mir::cookie::Authority::create_saving(mir::cookie::Secret& save_secret)
{
  save_secret = get_random_data(optimal_secret_size());
  return std::make_unique<AuthorityNettle>(save_secret);
}

std::unique_ptr<mir::cookie::Authority> mir::cookie::Authority::create()
{
  auto secret = get_random_data(optimal_secret_size());
  return std::make_unique<AuthorityNettle>(secret);
}


/*
 *
 * ========================= eCAL LICENSE =================================
*/

/**
 * @brief  eCAL registration gateway class
**/

#include <ecal/ecal.h>

#include "ecal_def.h"
#include <ecal/ecal_core.h>

#include "ecal_config_hlp.h"
#include "ecal_reggate.h"
#include "ecal_servgate.h"
#include "pubsub/ecal_pubgate.h"
#include "pubsub/ecal_subgate.h"

#include <iterator>

namespace eCAL
{
  // CUdpRegistrationReceiver
  bool CUdpRegistrationReceiver::HasSample(const std::string& sample_name_)
  {
    if (!g_reggate()) return(false);
    return(g_reggate()->HasSample(sample_name_));
  }

  size_t CUdpRegistrationReceiver::ApplySample(const eCAL::pb::Sample& ecal_sample_, eCAL::pb::eTLayerType /*layer_*/)
  {
    if (!g_reggate()) return 0;
    return g_reggate()->ApplySample(ecal_sample_);
  }

  // CRegGate
  std::atomic<bool> CRegGate::m_created;

  CRegGate::CRegGate() :
              m_network(NET_ENABLED),
              m_loopback(false),
              m_callback_pub(nullptr),
              m_callback_sub(nullptr),
              m_callback_service(nullptr),
              m_callback_process(nullptr)
  {
  };

{
    Destroy();
  }

  void CRegGate::Create()
  {
    if(m_created) return;

    // network mode
    m_network = eCALPAR(NET, ENABLED);

    // start registration receive thread
    SReceiverAttr attr;
    bool local_only = !eCALPAR(NET, ENABLED);
    // for local only communication we switch to local broadcasting to bypass vpn's or firewalls
    if (local_only)
    {
      attr.ipaddr    = "127.255.255.255";
      attr.broadcast = true;
    }
    else
    {
      attr.ipaddr    = eCALPAR(NET, UDP_MULTICAST_GROUP);
      attr.broadcast = false;
    }
    attr.port     = eCALPAR(NET, UDP_MULTICAST_PORT) + NET_UDP_MULTICAST_PORT_REG_OFF;
    attr.loopback = true;
    attr.rcvbuf   = eCALPAR(NET, UDP_MULTICAST_RCVBUF);

    m_reg_rcv.Create(attr);
    m_reg_rcv_thread.Start(0, std::bind(&CUdpRegistrationReceiver::Receive, &m_reg_rcv_process, &m_reg_rcv));

    m_created = true;
  }

  void CRegGate::Destroy()
  {
    if(!m_created) return;

    // stop registration receive thread
    m_reg_rcv_thread.Stop();

    // reset callbacks
    m_callback_pub     = nullptr;
    m_callback_sub     = nullptr;
    m_callback_service = nullptr;
    m_callback_process = nullptr;

    // finished
    m_created          = false;
  }

  void CRegGate::EnableLoopback(bool state_)
  {
    m_loopback = state_;
  }

  size_t CRegGate::ApplySample(const eCAL::pb::Sample& ecal_sample_)
  {
    if(!m_created) return 0;

    std::string reg_sample;
    if ( m_callback_pub
      || m_callback_sub
      || m_callback_service
      || m_callback_process
      )
    {
      reg_sample = ecal_sample_.SerializeAsString();
    }

    switch(ecal_sample_.cmd_type())
    {
    case eCAL::pb::bct_none:
    case eCAL::pb::bct_set_sample:
    case eCAL::pb::bct_reg_process:
      if (m_loopback || (ecal_sample_.process().pid() != Process::GetProcessID()))
      {
        if (g_pubgate()) g_pubgate()->ApplyProcessRegistration(ecal_sample_);
      }
      if (m_callback_process) m_callback_process(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      break;
    case eCAL::pb::bct_reg_service:
      if (m_callback_service) m_callback_service(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      if (g_servgate()) g_servgate()->ApplyServiceRegistration(ecal_sample_);
      break;
    case eCAL::pb::bct_reg_subscriber:
      {
        // process local subscriber registrations
        if(IsLocalHost(ecal_sample_))
        {
          // do not register subscriber of the same process
          // only if loop back flag is set true
          if(m_loopback || (ecal_sample_.topic().pid() != Process::GetProcessID()))
          {
            if (g_pubgate()) g_pubgate()->ApplyLocSubRegistration(ecal_sample_);
          }
        }
        // process external subscriber registrations
        else
        {
          if(m_network)
          {
            if (g_pubgate()) g_pubgate()->ApplyExtSubRegistration(ecal_sample_);
          }
        }
        if (m_callback_sub) m_callback_sub(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      }
      break;
    case eCAL::pb::bct_reg_publisher:
      {
        // we only process publisher registrations from that hosts
        // to get memory file names from local publishers
        if(IsLocalHost(ecal_sample_))
        {
          // do not register publisher of the same process
          // only if loop back flag is set true
          if(m_loopback || (ecal_sample_.topic().pid() != Process::GetProcessID()))
          {
            if (g_subgate()) g_subgate()->ApplyLocPubRegistration(ecal_sample_);
          }
        }
        else
        {
          if(m_network)
          {
            if (g_subgate()) g_subgate()->ApplyExtPubRegistration(ecal_sample_);
          }
        }
        if (m_callback_pub) m_callback_pub(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      }
      break;
    default:
      {
        eCAL::Logging::Log(log_level_warning, "CRegGate::ApplySample : unknown sample type");
      }
      break;
    }

    return 0;
  }

  bool CRegGate::AddRegistrationCallback(enum eCAL_Registration_Event event_, RegistrationCallbackT callback_)
  {
    if (!m_created) return false;
    switch (event_)
    {
    case reg_event_publisher:
      m_callback_pub = callback_;
      return true;
    case reg_event_subscriber:
      m_callback_sub = callback_;
      return true;
    case reg_event_service:
      m_callback_service = callback_;
      return true;
    case reg_event_process:
      m_callback_process = callback_;
      return true;
    default:
      return false;
    }
  }

  bool CRegGate::RemRegistrationCallback(enum eCAL_Registration_Event event_)
  {
    if (!m_created) return false;
    switch (event_)
    {
    case reg_event_publisher:
      m_callback_pub = nullptr;
      return true;
    case reg_event_subscriber:
      m_callback_sub = nullptr;
      return true;
    case reg_event_service:
      m_callback_service = nullptr;
      return true;
    case reg_event_process:
      m_callback_process = nullptr;
      return true;
    default:
      return false;
    }
  }

  bool CRegGate::IsLocalHost(const eCAL::pb::Sample& ecal_sample_)
  {
    std::string host_name = ecal_sample_.topic().hname();
    int         host_id   = ecal_sample_.topic().hid();
    if (host_name.empty()) return false;
    if (host_id != 0)
    {
      if (host_id != Process::GetHostID()) return false;
    }
    if (host_name != Process::GetHostName()) return false;
    return true;
  }
};


/*
 *
 * ========================= eCAL LICENSE =================================
*/

/**
 * @brief  eCAL registration gateway class
**/

#include <ecal/ecal.h>

#include "ecal_def.h"
#include <ecal/ecal_core.h>

#include "ecal_config_hlp.h"
#include "ecal_reggate.h"
#include "ecal_servgate.h"
#include "pubsub/ecal_pubgate.h"
#include "pubsub/ecal_subgate.h"

#include <iterator>

namespace eCAL
{
  // CUdpRegistrationReceiver
  bool CUdpRegistrationReceiver::HasSample(const std::string& sample_name_)
  {
    if (!g_reggate()) return(false);
    return(g_reggate()->HasSample(sample_name_));
  }

  size_t CUdpRegistrationReceiver::ApplySample(const eCAL::pb::Sample& ecal_sample_, eCAL::pb::eTLayerType /*layer_*/)
  {
    if (!g_reggate()) return 0;
    return g_reggate()->ApplySample(ecal_sample_);
  }

  // CRegGate
  std::atomic<bool> CRegGate::m_created;

  CRegGate::CRegGate() :
              m_network(NET_ENABLED),
              m_loopback(false),
              m_callback_pub(nullptr),
              m_callback_sub(nullptr),
              m_callback_service(nullptr),
              m_callback_process(nullptr)
  {
  };

  CRegGate::~CRegGate()
  {
    Destroy();
  }

  void CRegGate::Create()
  {
    if(m_created) return;

    // network mode
    m_network = eCALPAR(NET, ENABLED);

    // start registration receive thread
    SReceiverAttr attr;
    bool local_only = !eCALPAR(NET, ENABLED);
    // for local only communication we switch to local broadcasting to bypass vpn's or firewalls
    if (local_only)
    {
      attr.ipaddr    = "127.255.255.255";
      attr.broadcast = true;
    }
    else
    {
      attr.ipaddr    = eCALPAR(NET, UDP_MULTICAST_GROUP);
      attr.broadcast = false;
    }
    attr.port     = eCALPAR(NET, UDP_MULTICAST_PORT) + NET_UDP_MULTICAST_PORT_REG_OFF;
    attr.loopback = true;
    attr.rcvbuf   = eCALPAR(NET, UDP_MULTICAST_RCVBUF);

    m_reg_rcv.Create(attr);
    m_reg_rcv_thread.Start(0, std::bind(&CUdpRegistrationReceiver::Receive, &m_reg_rcv_process, &m_reg_rcv));

    m_created = true;
  }

  void CRegGate::Destroy()
  {
    if(!m_created) return;

    // stop registration receive thread
    m_reg_rcv_thread.Stop();

    // reset callbacks
    m_callback_pub     = nullptr;
    m_callback_sub     = nullptr;
    m_callback_service = nullptr;
    m_callback_process = nullptr;

    // finished
    m_created          = false;
  }

  void CRegGate::EnableLoopback(bool state_)

  size_t CRegGate::ApplySample(const eCAL::pb::Sample& ecal_sample_)
  {
    if(!m_created) return 0;

    std::string reg_sample;
    if ( m_callback_pub
      || m_callback_sub
      || m_callback_service
      || m_callback_process
      )
    {
      reg_sample = ecal_sample_.SerializeAsString();
    }

    switch(ecal_sample_.cmd_type())
    {
    case eCAL::pb::bct_none:
    case eCAL::pb::bct_set_sample:
    case eCAL::pb::bct_reg_process:
      if (m_loopback || (ecal_sample_.process().pid() != Process::GetProcessID()))
      {
        if (g_pubgate()) g_pubgate()->ApplyProcessRegistration(ecal_sample_);
      }
      if (m_callback_process) m_callback_process(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      break;
    case eCAL::pb::bct_reg_service:
      if (m_callback_service) m_callback_service(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      if (g_servgate()) g_servgate()->ApplyServiceRegistration(ecal_sample_);
      break;
    case eCAL::pb::bct_reg_subscriber:
      {
        // process local subscriber registrations
        if(IsLocalHost(ecal_sample_))
        {
          // do not register subscriber of the same process
          // only if loop back flag is set true
          if(m_loopback || (ecal_sample_.topic().pid() != Process::GetProcessID()))
          {
            if (g_pubgate()) g_pubgate()->ApplyLocSubRegistration(ecal_sample_);
          }
        }
        // process external subscriber registrations
        else
        {
          if(m_network)
          {
            if (g_pubgate()) g_pubgate()->ApplyExtSubRegistration(ecal_sample_);
          }
        }
        if (m_callback_sub) m_callback_sub(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      }
      break;
    case eCAL::pb::bct_reg_publisher:
      {
        // we only process publisher registrations from that hosts
        // to get memory file names from local publishers
        if(IsLocalHost(ecal_sample_))
        {
          // do not register publisher of the same process
          // only if loop back flag is set true
          if(m_loopback || (ecal_sample_.topic().pid() != Process::GetProcessID()))
          {
            if (g_subgate()) g_subgate()->ApplyLocPubRegistration(ecal_sample_);
          }
        }
        else
        {
          if(m_network)
          {
            if (g_subgate()) g_subgate()->ApplyExtPubRegistration(ecal_sample_);
          }
        }
        if (m_callback_pub) m_callback_pub(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      }
      break;
    default:
      {
        eCAL::Logging::Log(log_level_warning, "CRegGate::ApplySample : unknown sample type");
      }
      break;
    }

    return 0;
  }

  bool CRegGate::AddRegistrationCallback(enum eCAL_Registration_Event event_, RegistrationCallbackT callback_)
  {
    if (!m_created) return false;
    switch (event_)
    {
    case reg_event_publisher:
      m_callback_pub = callback_;
      return true;
    case reg_event_subscriber:
      m_callback_sub = callback_;
      return true;
    case reg_event_service:
      m_callback_service = callback_;
      return true;
    case reg_event_process:
      m_callback_process = callback_;
      return true;
    default:
      return false;
    }
  }

  bool CRegGate::RemRegistrationCallback(enum eCAL_Registration_Event event_)
  {
    if (!m_created) return false;
    switch (event_)
    {
    case reg_event_publisher:
      m_callback_pub = nullptr;
      return true;
    case reg_event_subscriber:
      m_callback_sub = nullptr;
      return true;
    case reg_event_service:
      m_callback_service = nullptr;
      return true;
    case reg_event_process:
      m_callback_process = nullptr;
      return true;
    default:
      return false;
    }
  }

  bool CRegGate::IsLocalHost(const eCAL::pb::Sample& ecal_sample_)
  {
    std::string host_name = ecal_sample_.topic().hname();
    int         host_id   = ecal_sample_.topic().hid();
    if (host_name.empty()) return false;
    if (host_id != 0)
    {
      if (host_id != Process::GetHostID()) return false;
    }
    if (host_name != Process::GetHostName()) return false;
    return true;
  }
};


/*
 *
 * ========================= eCAL LICENSE =================================
*/

/**
 * @brief  eCAL registration gateway class
**/

#include <ecal/ecal.h>

#include "ecal_def.h"
#include <ecal/ecal_core.h>

#include "ecal_config_hlp.h"
#include "ecal_reggate.h"
#include "ecal_servgate.h"
#include "pubsub/ecal_pubgate.h"
#include "pubsub/ecal_subgate.h"

#include <iterator>

namespace eCAL
{
  // CUdpRegistrationReceiver
  bool CUdpRegistrationReceiver::HasSample(const std::string& sample_name_)
  {
    if (!g_reggate()) return(false);
    return(g_reggate()->HasSample(sample_name_));
  }

  size_t CUdpRegistrationReceiver::ApplySample(const eCAL::pb::Sample& ecal_sample_, eCAL::pb::eTLayerType /*layer_*/)
  {
    if (!g_reggate()) return 0;
    return g_reggate()->ApplySample(ecal_sample_);
  }

  // CRegGate
  std::atomic<bool> CRegGate::m_created;

  CRegGate::CRegGate() :
              m_network(NET_ENABLED),
              m_loopback(false),
              m_callback_pub(nullptr),
              m_callback_sub(nullptr),
              m_callback_service(nullptr),
              m_callback_process(nullptr)
  {
  };

  CRegGate::~CRegGate()
  {
    Destroy();
  }

  void CRegGate::Create()
  {

    // network mode
    m_network = eCALPAR(NET, ENABLED);

    // start registration receive thread
    SReceiverAttr attr;
    bool local_only = !eCALPAR(NET, ENABLED);
    // for local only communication we switch to local broadcasting to bypass vpn's or firewalls
    if (local_only)
    {
      attr.ipaddr    = "127.255.255.255";
      attr.broadcast = true;
    }
    else
    {
      attr.ipaddr    = eCALPAR(NET, UDP_MULTICAST_GROUP);
      attr.broadcast = false;
    }
    attr.port     = eCALPAR(NET, UDP_MULTICAST_PORT) + NET_UDP_MULTICAST_PORT_REG_OFF;
    attr.loopback = true;
    attr.rcvbuf   = eCALPAR(NET, UDP_MULTICAST_RCVBUF);

    m_reg_rcv.Create(attr);
    m_reg_rcv_thread.Start(0, std::bind(&CUdpRegistrationReceiver::Receive, &m_reg_rcv_process, &m_reg_rcv));

    m_created = true;
  }

  void CRegGate::Destroy()
  {
    if(!m_created) return;

    // stop registration receive thread
    m_reg_rcv_thread.Stop();

    // reset callbacks
    m_callback_pub     = nullptr;
    m_callback_sub     = nullptr;
    m_callback_service = nullptr;
    m_callback_process = nullptr;

    // finished
    m_created          = false;
  }

  void CRegGate::EnableLoopback(bool state_)
  {
    m_loopback = state_;
  }

  size_t CRegGate::ApplySample(const eCAL::pb::Sample& ecal_sample_)
  {
    if(!m_created) return 0;

    std::string reg_sample;
    if ( m_callback_pub
      || m_callback_sub
      || m_callback_service
      || m_callback_process
      )
    {
      reg_sample = ecal_sample_.SerializeAsString();
    }

    switch(ecal_sample_.cmd_type())
    {
    case eCAL::pb::bct_none:
    case eCAL::pb::bct_set_sample:
    case eCAL::pb::bct_reg_process:
      if (m_loopback || (ecal_sample_.process().pid() != Process::GetProcessID()))
      {
        if (g_pubgate()) g_pubgate()->ApplyProcessRegistration(ecal_sample_);
      }
      if (m_callback_process) m_callback_process(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      break;
    case eCAL::pb::bct_reg_service:
      if (m_callback_service) m_callback_service(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      if (g_servgate()) g_servgate()->ApplyServiceRegistration(ecal_sample_);
      break;
    case eCAL::pb::bct_reg_subscriber:
      {
        // process local subscriber registrations
        if(IsLocalHost(ecal_sample_))
        {
          // do not register subscriber of the same process
          // only if loop back flag is set true
          if(m_loopback || (ecal_sample_.topic().pid() != Process::GetProcessID()))
          {
            if (g_pubgate()) g_pubgate()->ApplyLocSubRegistration(ecal_sample_);
          }
        }
        // process external subscriber registrations
        else
        {
          if(m_network)
          {
            if (g_pubgate()) g_pubgate()->ApplyExtSubRegistration(ecal_sample_);
          }
        }
        if (m_callback_sub) m_callback_sub(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      }
      break;
    case eCAL::pb::bct_reg_publisher:
      {
        // we only process publisher registrations from that hosts
        // to get memory file names from local publishers
        if(IsLocalHost(ecal_sample_))
        {
          // do not register publisher of the same process
          // only if loop back flag is set true
          if(m_loopback || (ecal_sample_.topic().pid() != Process::GetProcessID()))
          {
            if (g_subgate()) g_subgate()->ApplyLocPubRegistration(ecal_sample_);
          }
        }
        else
        {
          if(m_network)
          {
            if (g_subgate()) g_subgate()->ApplyExtPubRegistration(ecal_sample_);
          }
        }
        if (m_callback_pub) m_callback_pub(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      }
      break;
    default:
      {
        eCAL::Logging::Log(log_level_warning, "CRegGate::ApplySample : unknown sample type");
      }
      break;
    }

    return 0;
  }

  bool CRegGate::AddRegistrationCallback(enum eCAL_Registration_Event event_, RegistrationCallbackT callback_)
  {
    if (!m_created) return false;
    switch (event_)
    {
    case reg_event_publisher:
      m_callback_pub = callback_;
      return true;
    case reg_event_subscriber:
      m_callback_sub = callback_;
      return true;
    case reg_event_service:
      m_callback_service = callback_;
      return true;
    case reg_event_process:
      m_callback_process = callback_;
      return true;
    default:
      return false;
    }
  }

  bool CRegGate::RemRegistrationCallback(enum eCAL_Registration_Event event_)
  {
    if (!m_created) return false;
    switch (event_)
    {
    case reg_event_publisher:
      m_callback_pub = nullptr;
      return true;
    case reg_event_subscriber:
      m_callback_sub = nullptr;
      return true;
    case reg_event_service:
      m_callback_service = nullptr;
      return true;
    case reg_event_process:
      m_callback_process = nullptr;
      return true;
    default:
      return false;
    }
  }

  bool CRegGate::IsLocalHost(const eCAL::pb::Sample& ecal_sample_)
  {
    std::string host_name = ecal_sample_.topic().hname();
    int         host_id   = ecal_sample_.topic().hid();
    if (host_name.empty()) return false;
    if (host_id != 0)
    {
      if (host_id != Process::GetHostID()) return false;
    }
    if (host_name != Process::GetHostName()) return false;
    return true;
  }
};


bool CUdpRegistrationReceiver::HasSample(const std::string& sample_name_)
  {
    if (!g_reggate()) return(false);
    return(g_reggate()->HasSample(sample_name_));
  }

/*
 *
 * ========================= eCAL LICENSE =================================
*/

/**
 * @brief  eCAL registration gateway class
**/

#include <ecal/ecal.h>

#include "ecal_def.h"
#include <ecal/ecal_core.h>

#include "ecal_config_hlp.h"
#include "ecal_reggate.h"
#include "ecal_servgate.h"
#include "pubsub/ecal_pubgate.h"
#include "pubsub/ecal_subgate.h"

#include <iterator>

namespace eCAL
{
  // CUdpRegistrationReceiver

  size_t CUdpRegistrationReceiver::ApplySample(const eCAL::pb::Sample& ecal_sample_, eCAL::pb::eTLayerType /*layer_*/)
  {
    if (!g_reggate()) return 0;
    return g_reggate()->ApplySample(ecal_sample_);
  }

  // CRegGate
  std::atomic<bool> CRegGate::m_created;

  CRegGate::CRegGate() :
              m_network(NET_ENABLED),
              m_loopback(false),
              m_callback_pub(nullptr),
              m_callback_sub(nullptr),
              m_callback_service(nullptr),
              m_callback_process(nullptr)
  {
  };

  CRegGate::~CRegGate()
  {
    Destroy();
  }

  void CRegGate::Create()
  {
    if(m_created) return;

    // network mode
    m_network = eCALPAR(NET, ENABLED);

    // start registration receive thread
    SReceiverAttr attr;
    bool local_only = !eCALPAR(NET, ENABLED);
    // for local only communication we switch to local broadcasting to bypass vpn's or firewalls
    if (local_only)
    {
      attr.ipaddr    = "127.255.255.255";
      attr.broadcast = true;
    }
    else
    {
      attr.ipaddr    = eCALPAR(NET, UDP_MULTICAST_GROUP);
      attr.broadcast = false;
    }
    attr.port     = eCALPAR(NET, UDP_MULTICAST_PORT) + NET_UDP_MULTICAST_PORT_REG_OFF;
    attr.loopback = true;
    attr.rcvbuf   = eCALPAR(NET, UDP_MULTICAST_RCVBUF);

    m_reg_rcv.Create(attr);
    m_reg_rcv_thread.Start(0, std::bind(&CUdpRegistrationReceiver::Receive, &m_reg_rcv_process, &m_reg_rcv));

    m_created = true;
  }

  void CRegGate::Destroy()
  {
    if(!m_created) return;

    // stop registration receive thread
    m_reg_rcv_thread.Stop();

    // reset callbacks
    m_callback_pub     = nullptr;
    m_callback_sub     = nullptr;
    m_callback_service = nullptr;
    m_callback_process = nullptr;

    // finished
    m_created          = false;
  }

  void CRegGate::EnableLoopback(bool state_)
  {
    m_loopback = state_;
  }

  size_t CRegGate::ApplySample(const eCAL::pb::Sample& ecal_sample_)
  {
    if(!m_created) return 0;

    std::string reg_sample;
    if ( m_callback_pub
      || m_callback_sub
      || m_callback_service
      || m_callback_process
      )
    {
      reg_sample = ecal_sample_.SerializeAsString();
    }

    switch(ecal_sample_.cmd_type())
    {
    case eCAL::pb::bct_none:
    case eCAL::pb::bct_set_sample:
    case eCAL::pb::bct_reg_process:
      if (m_loopback || (ecal_sample_.process().pid() != Process::GetProcessID()))
      {
        if (g_pubgate()) g_pubgate()->ApplyProcessRegistration(ecal_sample_);
      }
      if (m_callback_process) m_callback_process(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      break;
    case eCAL::pb::bct_reg_service:
      if (m_callback_service) m_callback_service(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      if (g_servgate()) g_servgate()->ApplyServiceRegistration(ecal_sample_);
      break;
    case eCAL::pb::bct_reg_subscriber:
      {
        // process local subscriber registrations
        if(IsLocalHost(ecal_sample_))
        {
          // do not register subscriber of the same process
          // only if loop back flag is set true
          if(m_loopback || (ecal_sample_.topic().pid() != Process::GetProcessID()))
          {
            if (g_pubgate()) g_pubgate()->ApplyLocSubRegistration(ecal_sample_);
          }
        }
        // process external subscriber registrations
        else
        {
          if(m_network)
          {
            if (g_pubgate()) g_pubgate()->ApplyExtSubRegistration(ecal_sample_);
          }
        }
        if (m_callback_sub) m_callback_sub(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      }
      break;
    case eCAL::pb::bct_reg_publisher:
      {
        // we only process publisher registrations from that hosts
        // to get memory file names from local publishers
        if(IsLocalHost(ecal_sample_))
        {
          // do not register publisher of the same process
          // only if loop back flag is set true
          if(m_loopback || (ecal_sample_.topic().pid() != Process::GetProcessID()))
          {
            if (g_subgate()) g_subgate()->ApplyLocPubRegistration(ecal_sample_);
          }
        }
        else
        {
          if(m_network)
          {
            if (g_subgate()) g_subgate()->ApplyExtPubRegistration(ecal_sample_);
          }
        }
        if (m_callback_pub) m_callback_pub(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      }
      break;
    default:
      {
        eCAL::Logging::Log(log_level_warning, "CRegGate::ApplySample : unknown sample type");
      }
      break;
    }

    return 0;
  }

  bool CRegGate::AddRegistrationCallback(enum eCAL_Registration_Event event_, RegistrationCallbackT callback_)
  {
    if (!m_created) return false;
    switch (event_)
    {
    case reg_event_publisher:
      m_callback_pub = callback_;
      return true;
    case reg_event_subscriber:
      m_callback_sub = callback_;
      return true;
    case reg_event_service:
      m_callback_service = callback_;
      return true;
    case reg_event_process:
      m_callback_process = callback_;
      return true;
    default:
      return false;
    }
  }

  bool CRegGate::RemRegistrationCallback(enum eCAL_Registration_Event event_)
  {
    if (!m_created) return false;
    switch (event_)
    {
    case reg_event_publisher:
      m_callback_pub = nullptr;
      return true;
    case reg_event_subscriber:
      m_callback_sub = nullptr;
      return true;
    case reg_event_service:
      m_callback_service = nullptr;
      return true;
    case reg_event_process:
      m_callback_process = nullptr;
      return true;
    default:
      return false;
    }
  }

  bool CRegGate::IsLocalHost(const eCAL::pb::Sample& ecal_sample_)
  {
    std::string host_name = ecal_sample_.topic().hname();
    int         host_id   = ecal_sample_.topic().hid();
    if (host_name.empty()) return false;
    if (host_id != 0)
    {
      if (host_id != Process::GetHostID()) return false;
    }
    if (host_name != Process::GetHostName()) return false;
    return true;
  }
};


switch (event_)
    {
    case reg_event_publisher:
      m_callback_pub = callback_;
      return true;
    case reg_event_subscriber:
      m_callback_sub = callback_;
      return true;
    case reg_event_service:
      m_callback_service = callback_;
      return true;
    case reg_event_process:
      m_callback_process = callback_;
      return true;
    default:
      return false;
    }

/*
 *
 * ========================= eCAL LICENSE =================================
*/

/**
 * @brief  eCAL registration gateway class
**/

#include <ecal/ecal.h>

#include "ecal_def.h"
#include <ecal/ecal_core.h>

#include "ecal_config_hlp.h"
#include "ecal_reggate.h"
#include "ecal_servgate.h"
#include "pubsub/ecal_pubgate.h"
#include "pubsub/ecal_subgate.h"

#include <iterator>

namespace eCAL
{
  // CUdpRegistrationReceiver
  bool CUdpRegistrationReceiver::HasSample(const std::string& sample_name_)
  {
    if (!g_reggate()) return(false);
    return(g_reggate()->HasSample(sample_name_));
  }

  size_t CUdpRegistrationReceiver::ApplySample(const eCAL::pb::Sample& ecal_sample_, eCAL::pb::eTLayerType /*layer_*/)
  {
    if (!g_reggate()) return 0;
    return g_reggate()->ApplySample(ecal_sample_);
  }

  // CRegGate
  std::atomic<bool> CRegGate::m_created;

  CRegGate::CRegGate() :
              m_network(NET_ENABLED),
              m_loopback(false),
              m_callback_pub(nullptr),
              m_callback_sub(nullptr),
              m_callback_service(nullptr),
              m_callback_process(nullptr)
  {
  };

  CRegGate::~CRegGate()
  {
    Destroy();
  }

  void CRegGate::Create()
  {
    if(m_created) return;

    // network mode
    m_network = eCALPAR(NET, ENABLED);

    // start registration receive thread
    SReceiverAttr attr;
    bool local_only = !eCALPAR(NET, ENABLED);
    // for local only communication we switch to local broadcasting to bypass vpn's or firewalls
    if (local_only)
    {
      attr.ipaddr    = "127.255.255.255";
      attr.broadcast = true;
    }
    else
    {
      attr.ipaddr    = eCALPAR(NET, UDP_MULTICAST_GROUP);
      attr.broadcast = false;
    }
    attr.port     = eCALPAR(NET, UDP_MULTICAST_PORT) + NET_UDP_MULTICAST_PORT_REG_OFF;
    attr.loopback = true;
    attr.rcvbuf   = eCALPAR(NET, UDP_MULTICAST_RCVBUF);

    m_reg_rcv.Create(attr);
    m_reg_rcv_thread.Start(0, std::bind(&CUdpRegistrationReceiver::Receive, &m_reg_rcv_process, &m_reg_rcv));

    m_created = true;
  }

  void CRegGate::Destroy()
  {
    if(!m_created) return;

    // stop registration receive thread
    m_reg_rcv_thread.Stop();

    // reset callbacks
    m_callback_pub     = nullptr;
    m_callback_sub     = nullptr;
    m_callback_service = nullptr;
    m_callback_process = nullptr;

    // finished
    m_created          = false;
  }

  void CRegGate::EnableLoopback(bool state_)
  {
    m_loopback = state_;
  }

  size_t CRegGate::ApplySample(const eCAL::pb::Sample& ecal_sample_)
  {
    if(!m_created) return 0;

    std::string reg_sample;
    if ( m_callback_pub
      || m_callback_sub
      || m_callback_service
      || m_callback_process
      )
    {
      reg_sample = ecal_sample_.SerializeAsString();
    }

    switch(ecal_sample_.cmd_type())
    {
    case eCAL::pb::bct_none:
    case eCAL::pb::bct_set_sample:
    case eCAL::pb::bct_reg_process:
      if (m_loopback || (ecal_sample_.process().pid() != Process::GetProcessID()))
      {
        if (g_pubgate()) g_pubgate()->ApplyProcessRegistration(ecal_sample_);
      }
      if (m_callback_process) m_callback_process(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      break;
    case eCAL::pb::bct_reg_service:
      if (m_callback_service) m_callback_service(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      if (g_servgate()) g_servgate()->ApplyServiceRegistration(ecal_sample_);
      break;
    case eCAL::pb::bct_reg_subscriber:
      {
        // process local subscriber registrations
        if(IsLocalHost(ecal_sample_))
        {
          // do not register subscriber of the same process
          // only if loop back flag is set true
          if(m_loopback || (ecal_sample_.topic().pid() != Process::GetProcessID()))
          {
            if (g_pubgate()) g_pubgate()->ApplyLocSubRegistration(ecal_sample_);
          }
        }
        // process external subscriber registrations
        else
        {
          if(m_network)
          {
            if (g_pubgate()) g_pubgate()->ApplyExtSubRegistration(ecal_sample_);
          }
        }
        if (m_callback_sub) m_callback_sub(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      }
      break;
    case eCAL::pb::bct_reg_publisher:
      {
        // we only process publisher registrations from that hosts
        // to get memory file names from local publishers
        if(IsLocalHost(ecal_sample_))
        {
          // do not register publisher of the same process
          // only if loop back flag is set true
          if(m_loopback || (ecal_sample_.topic().pid() != Process::GetProcessID()))
          {
            if (g_subgate()) g_subgate()->ApplyLocPubRegistration(ecal_sample_);
          }
        }
        else
        {
          if(m_network)
          {
            if (g_subgate()) g_subgate()->ApplyExtPubRegistration(ecal_sample_);
          }
        }
        if (m_callback_pub) m_callback_pub(reg_sample.c_str(), static_cast<int>(reg_sample.size()));
      }
      break;
    default:
      {
        eCAL::Logging::Log(log_level_warning, "CRegGate::ApplySample : unknown sample type");
      }
      break;
    }

    return 0;
  }

  bool CRegGate::AddRegistrationCallback(enum eCAL_Registration_Event event_, RegistrationCallbackT callback_)
  {
    if (!m_created) return false;

  }

  bool CRegGate::RemRegistrationCallback(enum eCAL_Registration_Event event_)
  {
    if (!m_created) return false;
    switch (event_)
    {
    case reg_event_publisher:
      m_callback_pub = nullptr;
      return true;
    case reg_event_subscriber:
      m_callback_sub = nullptr;
      return true;
    case reg_event_service:
      m_callback_service = nullptr;
      return true;
    case reg_event_process:
      m_callback_process = nullptr;
      return true;
    default:
      return false;
    }
  }

  bool CRegGate::IsLocalHost(const eCAL::pb::Sample& ecal_sample_)
  {
    std::string host_name = ecal_sample_.topic().hname();
    int         host_id   = ecal_sample_.topic().hid();
    if (host_name.empty()) return false;
    if (host_id != 0)
    {
      if (host_id != Process::GetHostID()) return false;
    }
    if (host_name != Process::GetHostName()) return false;
    return true;
  }
};


/*
 *
 * ========================= eCAL LICENSE =================================
*/

/**
 * @brief  eCAL server gateway class
**/

#include <ecal/ecal.h>

#include "ecal_def.h"
#include "ecal_servgate.h"
#include "ecal_config_hlp.h"

#include <iterator>
#include <atomic>

namespace eCAL
{
  // CServGate
  std::atomic<bool> CServGate::m_created;
  CServGate::CServGate() = default;

  CServGate::~CServGate()
  {
    Destroy();
  }

  void CServGate::Create()
  {
    if(m_created) return;
    m_created = true;
  }

  void CServGate::Destroy()
  {
    if(!m_created) return;
    m_created = false;
  }

  bool CServGate::Register(const std::string& service_name_, CServiceServerImpl* service_)
  {
    if(!m_created) return(false);

    // register internal service implementation
    std::lock_guard<std::mutex> lock(m_internal_service_sync);
    m_internal_service_map.emplace(std::pair<std::string, CServiceServerImpl*>(service_name_, service_));

    return(true);
  }

  bool CServGate::Unregister(const std::string& service_name_, CServiceServerImpl* service_)
  {
    if(!m_created) return(false);
    bool ret_state = false;

    std::lock_guard<std::mutex> lock(m_internal_service_sync);
    auto res = m_internal_service_map.equal_range(service_name_);
    for(ServiceNameServiceImplMapT::iterator iter = res.first; iter != res.second; ++iter)
    {
      if(iter->second == service_)
      {
        m_internal_service_map.erase(iter);
        break;
      }
    }

    return(ret_state);
  }

  std::vector<CServGate::SService> CServGate::GetServiceInfo(const std::string& service_name_)
  {
    auto now = RegClockT::now();

    std::vector<CServGate::SService> ret_vec;
    std::lock_guard<std::mutex> lock(m_service_register_sync);

    // Cleanup old services
    auto service_reg_it = m_service_register_map.begin();
    while (service_reg_it != m_service_register_map.end())
    {
      if (now - service_reg_it->second.second > std::chrono::milliseconds(eCALPAR(CMN, REGISTRATION_TO)))
      {
#ifndef NDEBUG
        // log it
        Logging::Log(log_level_debug1, "CServGate::GetServiceInfo - Removing service due to timeout");
#endif // !NDEBUG
        m_service_register_map.erase(service_reg_it++);
      }
      else
      {
        service_reg_it++;
      }
    }

    // Look for requested services
    for (auto& service : m_service_register_map)
    {
      if (service.second.first.sname == service_name_)
      {
        ret_vec.push_back(service.second.first);
      }
    }
    return(ret_vec);
  }

  void CServGate::ApplyServiceRegistration(const eCAL::pb::Sample & ecal_sample_)
  {
    auto registration_time = RegClockT::now();

    SService service;
    auto ecal_sample_service = ecal_sample_.service();
    service.hname    = ecal_sample_service.hname();
    service.pname    = ecal_sample_service.pname();
    service.uname    = ecal_sample_service.uname();
    service.pid      = static_cast<int>(ecal_sample_service.pid());
    service.sname    = ecal_sample_service.sname();
    service.tcp_port = static_cast<unsigned short>(ecal_sample_service.tcp_port());

    // register service
    std::lock_guard<std::mutex> lock(m_service_register_sync);
    std::string key = service.sname + ":" + std::to_string(service.tcp_port) + "@" + std::to_string(service.pid) + "@" + service.hname;

    auto existing_service_it = m_service_register_map.find(key);
    if (existing_service_it == m_service_register_map.end())
    {
      // Create new entry
#ifndef NDEBUG
      // log it
      Logging::Log(log_level_debug1, "CServGate::GetServiceInfo - Received new service registration");
#endif // !NDEBUG

      m_service_register_map.emplace(key, std::make_pair(service, registration_time));
    }
    else
    {
      // Update existing entry
      existing_service_it->second.second = registration_time;
    }
  }

{
    if (!m_created) return;

    // refresh service registrations
    std::lock_guard<std::mutex> lock(m_internal_service_sync);
    for (auto iter : m_internal_service_map)
    {
      iter.second->RefreshRegistration();
    }
  }
};


{
    if(!m_created) return(false);
    bool ret_state = false;

    std::lock_guard<std::mutex> lock(m_internal_service_sync);
    auto res = m_internal_service_map.equal_range(service_name_);
    for(ServiceNameServiceImplMapT::iterator iter = res.first; iter != res.second; ++iter)
    {
      if(iter->second == service_)
      {
        m_internal_service_map.erase(iter);
        break;
      }
    }

    return(ret_state);
  }

/*
 *
 * ========================= eCAL LICENSE =================================
*/

/**
 * @brief  eCAL server gateway class
**/

#include <ecal/ecal.h>

#include "ecal_def.h"
#include "ecal_servgate.h"
#include "ecal_config_hlp.h"

#include <iterator>
#include <atomic>

namespace eCAL
{
  // CServGate
  std::atomic<bool> CServGate::m_created;
  CServGate::CServGate() = default;

  CServGate::~CServGate()
  {
    Destroy();
  }

  void CServGate::Create()
  {
    if(m_created) return;
    m_created = true;
  }

  void CServGate::Destroy()
  {
    if(!m_created) return;
    m_created = false;
  }

  bool CServGate::Register(const std::string& service_name_, CServiceServerImpl* service_)
  {
    if(!m_created) return(false);

    // register internal service implementation
    std::lock_guard<std::mutex> lock(m_internal_service_sync);
    m_internal_service_map.emplace(std::pair<std::string, CServiceServerImpl*>(service_name_, service_));

    return(true);
  }

  bool CServGate::Unregister(const std::string& service_name_, CServiceServerImpl* service_)

  std::vector<CServGate::SService> CServGate::GetServiceInfo(const std::string& service_name_)
  {
    auto now = RegClockT::now();

    std::vector<CServGate::SService> ret_vec;
    std::lock_guard<std::mutex> lock(m_service_register_sync);

    // Cleanup old services
    auto service_reg_it = m_service_register_map.begin();
    while (service_reg_it != m_service_register_map.end())
    {
      if (now - service_reg_it->second.second > std::chrono::milliseconds(eCALPAR(CMN, REGISTRATION_TO)))
      {
#ifndef NDEBUG
        // log it
        Logging::Log(log_level_debug1, "CServGate::GetServiceInfo - Removing service due to timeout");
#endif // !NDEBUG
        m_service_register_map.erase(service_reg_it++);
      }
      else
      {
        service_reg_it++;
      }
    }

    // Look for requested services
    for (auto& service : m_service_register_map)
    {
      if (service.second.first.sname == service_name_)
      {
        ret_vec.push_back(service.second.first);
      }
    }
    return(ret_vec);
  }

  void CServGate::ApplyServiceRegistration(const eCAL::pb::Sample & ecal_sample_)
  {
    auto registration_time = RegClockT::now();

    SService service;
    auto ecal_sample_service = ecal_sample_.service();
    service.hname    = ecal_sample_service.hname();
    service.pname    = ecal_sample_service.pname();
    service.uname    = ecal_sample_service.uname();
    service.pid      = static_cast<int>(ecal_sample_service.pid());
    service.sname    = ecal_sample_service.sname();
    service.tcp_port = static_cast<unsigned short>(ecal_sample_service.tcp_port());

    // register service
    std::lock_guard<std::mutex> lock(m_service_register_sync);
    std::string key = service.sname + ":" + std::to_string(service.tcp_port) + "@" + std::to_string(service.pid) + "@" + service.hname;

    auto existing_service_it = m_service_register_map.find(key);
    if (existing_service_it == m_service_register_map.end())
    {
      // Create new entry
#ifndef NDEBUG
      // log it
      Logging::Log(log_level_debug1, "CServGate::GetServiceInfo - Received new service registration");
#endif // !NDEBUG

      m_service_register_map.emplace(key, std::make_pair(service, registration_time));
    }
    else
    {
      // Update existing entry
      existing_service_it->second.second = registration_time;
    }
  }

  void CServGate::RefreshRegistrations()
  {
    if (!m_created) return;

    // refresh service registrations
    std::lock_guard<std::mutex> lock(m_internal_service_sync);
    for (auto iter : m_internal_service_map)
    {
      iter.second->RefreshRegistration();
    }
  }
};


/*
 *
 * ========================= eCAL LICENSE =================================
*/

/**
 * @brief  eCAL server gateway class
**/

#include <ecal/ecal.h>

#include "ecal_def.h"
#include "ecal_servgate.h"
#include "ecal_config_hlp.h"

#include <iterator>
#include <atomic>

namespace eCAL
{
  // CServGate
  std::atomic<bool> CServGate::m_created;
  CServGate::CServGate() = default;

  CServGate::~CServGate()
  {
    Destroy();
  }

  void CServGate::Create()
  {
    if(m_created) return;
    m_created = true;
  }

  void CServGate::Destroy()
  {
    if(!m_created) return;
    m_created = false;
  }

  bool CServGate::Register(const std::string& service_name_, CServiceServerImpl* service_)
  {
    if(!m_created) return(false);

    // register internal service implementation
    std::lock_guard<std::mutex> lock(m_internal_service_sync);
    m_internal_service_map.emplace(std::pair<std::string, CServiceServerImpl*>(service_name_, service_));

    return(true);
  }

  bool CServGate::Unregister(const std::string& service_name_, CServiceServerImpl* service_)
  {
    if(!m_created) return(false);
    bool ret_state = false;

    std::lock_guard<std::mutex> lock(m_internal_service_sync);
    auto res = m_internal_service_map.equal_range(service_name_);
    for(ServiceNameServiceImplMapT::iterator iter = res.first; iter != res.second; ++iter)
    {
      if(iter->second == service_)
      {
        m_internal_service_map.erase(iter);
        break;
      }
    }

    return(ret_state);
  }

  std::vector<CServGate::SService> CServGate::GetServiceInfo(const std::string& service_name_)
  {
    auto now = RegClockT::now();

    std::vector<CServGate::SService> ret_vec;
    std::lock_guard<std::mutex> lock(m_service_register_sync);

    // Cleanup old services
    auto service_reg_it = m_service_register_map.begin();
    while (service_reg_it != m_service_register_map.end())
    {
      if (now - service_reg_it->second.second > std::chrono::milliseconds(eCALPAR(CMN, REGISTRATION_TO)))
      {
#ifndef NDEBUG
        // log it
        Logging::Log(log_level_debug1, "CServGate::GetServiceInfo - Removing service due to timeout");
#endif // !NDEBUG
        m_service_register_map.erase(service_reg_it++);
      }
      else
      {
        service_reg_it++;
      }
    }

    // Look for requested services
    for (auto& service : m_service_register_map)
    {
      if (service.second.first.sname == service_name_)
      {
        ret_vec.push_back(service.second.first);
      }
    }
    return(ret_vec);
  }

  void CServGate::ApplyServiceRegistration(const eCAL::pb::Sample & ecal_sample_)
  {
    auto registration_time = RegClockT::now();

    SService service;
    auto ecal_sample_service = ecal_sample_.service();
    service.hname    = ecal_sample_service

    service.pname    = ecal_sample_service.pname();
    service.uname    = ecal_sample_service.uname();
    service.pid      = static_cast<int>(ecal_sample_service.pid());
    service.sname    = ecal_sample_service.sname();
    service.tcp_port = static_cast<unsigned short>(ecal_sample_service.tcp_port());

    // register service
    std::lock_guard<std::mutex> lock(m_service_register_sync);
    std::string key = service.sname + ":" + std::to_string(service.tcp_port) + "@" + std::to_string(service.pid) + "@" + service.hname;

    auto existing_service_it = m_service_register_map.find(key);
    if (existing_service_it == m_service_register_map.end())
    {
      // Create new entry
#ifndef NDEBUG
      // log it
      Logging::Log(log_level_debug1, "CServGate::GetServiceInfo - Received new service registration");
#endif // !NDEBUG

      m_service_register_map.emplace(key, std::make_pair(service, registration_time));
    }
    else
    {
      // Update existing entry
      existing_service_it->second.second = registration_time;
    }
  }

  void CServGate::RefreshRegistrations()
  {
    if (!m_created) return;

    // refresh service registrations
    std::lock_guard<std::mutex> lock(m_internal_service_sync);
    for (auto iter : m_internal_service_map)
    {
      iter.second->RefreshRegistration();
    }
  }
};