/******************************************************************************* * Copyright (c) 2021 Nerian Vision GmbH * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. *******************************************************************************/ #ifndef VISIONTRANSFER_DATACHANNEL_CONTROL_H #define VISIONTRANSFER_DATACHANNEL_CONTROL_H #include #include #include #include #include #include namespace visiontransfer { namespace internal { /** * \brief Commands understood on DataChannelService channel 0 (control) */ class DataChannelControlCommands { public: enum Command { CTLReserved, CTLRequestAdvertisement, CTLProvideAdvertisement, CTLRequestSubscriptions, CTLProvideSubscriptions, CTLRequestUnsubscriptions, CTLProvideUnsubscriptions }; }; /** * \brief Internal helpers for packing and unpacking channel 0 service messages */ class DataChannelControlUtil { public: static DataChannelControlCommands::Command getCommand(unsigned char* data, int datalen) { if (datalen < 2) throw std::runtime_error("Buffer too small"); return (DataChannelControlCommands::Command) ntohs(*((uint16_t*) data)); } // Advertisements (available services) static int packAdvertisementMessage(unsigned char* data, int datalen, DataChannelControlCommands::Command cmd, const std::map >& channels) { int origDataLen = datalen; if (datalen < 3) throw std::runtime_error("Buffer too small"); *((uint16_t*)data) = htons(cmd); uint8_t num = (uint8_t) std::min(255, (int) channels.size()); // pack 255 items max data[2] = num; // payload data += 3; datalen -= 3; int i = 0; for (auto kv: channels) { i++; if (i>num) break; if (datalen < 3) throw std::runtime_error("Buffer too small"); auto p = kv.second; const std::string& infoString = p->getInfoString(); uint8_t strSize = (uint8_t) std::min(255, (int) infoString.size()); int elemLen = 1 + 1 + 1 + strSize; if (datalen < elemLen) throw std::runtime_error("Buffer too small"); data[0] = p->getChannelID(); data[1] = p->getChannelType(); data[2] = strSize; std::memcpy(data + 3, infoString.c_str(), strSize); data += elemLen; datalen -= elemLen; } return (origDataLen - datalen); } static std::vector unpackAdvertisementMessage(unsigned char* data, int datalen) { std::vector result; if (datalen < 3) throw std::runtime_error("Buffer too small"); uint8_t num = data[2]; data += 3; datalen -= 3; for (int i=0; i& subscriptions) { if (datalen < 4) throw std::runtime_error("Buffer too small"); *((uint16_t*)data) = htons(cmd); uint8_t num = (uint8_t) std::min(255, (int) subscriptions.size()); data[2] = num; // pack 255 items max data += 3; datalen -= 3; if (datalen < (1*num)) throw std::runtime_error("Buffer too small"); for (int i=0; i unpackSubscriptionMessage(unsigned char* data, int datalen) { std::vector result; if (datalen < 3) throw std::runtime_error("Buffer too small"); uint8_t num = data[2]; data += 3; datalen -= 3; if (datalen < (1*num)) throw std::runtime_error("Buffer too small"); for (int i=0; i(data[0])); data += 1; datalen -= 1; } return result; } }; }} // namespaces #endif