libvisiontransfer  10.6.0
datachannel-control.h
1 /*******************************************************************************
2  * Copyright (c) 2023 Allied Vision Technologies GmbH
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *******************************************************************************/
14 
15 #ifndef VISIONTRANSFER_DATACHANNEL_CONTROL_H
16 #define VISIONTRANSFER_DATACHANNEL_CONTROL_H
17 
18 #include <cstring>
19 #include <memory>
20 #include <map>
21 #include <set>
22 #include <vector>
23 
24 #include <visiontransfer/datachannelservicebase.h>
25 
26 namespace visiontransfer {
27 namespace internal {
28 
32 class DataChannelControlCommands {
33 public:
34  enum Command {
35  CTLReserved,
36  CTLRequestAdvertisement,
37  CTLProvideAdvertisement,
38  CTLRequestSubscriptions,
39  CTLProvideSubscriptions,
40  CTLRequestUnsubscriptions,
41  CTLProvideUnsubscriptions
42  };
43 };
44 
48 class DataChannelControlUtil {
49 public:
50  static DataChannelControlCommands::Command getCommand(unsigned char* data, int datalen) {
51  if (datalen < 2) throw std::runtime_error("Buffer too small");
52  return (DataChannelControlCommands::Command) ntohs(*((uint16_t*) data));
53  }
54  // Advertisements (available services)
55  static int packAdvertisementMessage(unsigned char* data, int datalen, DataChannelControlCommands::Command cmd, const std::map<DataChannel::ID, std::shared_ptr<DataChannel> >& channels) {
56  int origDataLen = datalen;
57  if (datalen < 3) throw std::runtime_error("Buffer too small");
58  *((uint16_t*)data) = htons(cmd);
59  uint8_t num = (uint8_t) std::min(255, (int) channels.size()); // pack 255 items max
60  data[2] = num;
61  // payload
62  data += 3; datalen -= 3;
63  int i = 0;
64  for (auto kv: channels) {
65  i++; if (i>num) break;
66  if (datalen < 3) throw std::runtime_error("Buffer too small");
67  auto p = kv.second;
68  const std::string& infoString = p->getInfoString();
69  uint8_t strSize = (uint8_t) std::min(255, (int) infoString.size());
70  int elemLen = 1 + 1 + 1 + strSize;
71  if (datalen < elemLen) throw std::runtime_error("Buffer too small");
72  data[0] = p->getChannelID();
73  data[1] = p->getChannelType();
74  data[2] = strSize;
75  std::memcpy(data + 3, infoString.c_str(), strSize);
76  data += elemLen; datalen -= elemLen;
77  }
78  return (origDataLen - datalen);
79  }
80  static std::vector<DataChannelInfo> unpackAdvertisementMessage(unsigned char* data, int datalen) {
81  std::vector<DataChannelInfo> result;
82  if (datalen < 3) throw std::runtime_error("Buffer too small");
83  uint8_t num = data[2];
84  data += 3; datalen -= 3;
85  for (int i=0; i<num; ++i) {
86  if (datalen < 3) throw std::runtime_error("Buffer too small");
87  uint8_t id = data[0];
88  uint8_t type = data[1];
89  uint8_t strSize = data[2];
90  int elemLen = 1 + 1 + 1 + strSize;
91  if (datalen < elemLen) throw std::runtime_error("Buffer too small");
92  result.emplace_back(DataChannelInfo((DataChannel::ID) id, (DataChannel::Type) type, std::string(data[3], strSize)));
93  data += elemLen; datalen -= elemLen;
94  }
95  return result;
96  }
97 
98  // Subscriptions (connected services)
99  static int packSubscriptionMessage(unsigned char* data, int datalen, DataChannelControlCommands::Command cmd, const std::vector<DataChannel::ID>& subscriptions) {
100  if (datalen < 4) throw std::runtime_error("Buffer too small");
101  *((uint16_t*)data) = htons(cmd);
102  uint8_t num = (uint8_t) std::min(255, (int) subscriptions.size());
103  data[2] = num; // pack 255 items max
104  data += 3; datalen -= 3;
105  if (datalen < (1*num)) throw std::runtime_error("Buffer too small");
106  for (int i=0; i<num; ++i) {
107  auto p = subscriptions[i];
108  data[0] = p;
109  data += 1; datalen -= 1;
110  }
111  return (2+1+1*num);
112  }
113  static std::vector<DataChannel::ID> unpackSubscriptionMessage(unsigned char* data, int datalen) {
114  std::vector<DataChannel::ID> result;
115  if (datalen < 3) throw std::runtime_error("Buffer too small");
116  uint8_t num = data[2];
117  data += 3; datalen -= 3;
118  if (datalen < (1*num)) throw std::runtime_error("Buffer too small");
119  for (int i=0; i<num; ++i) {
120  result.emplace_back(static_cast<DataChannel::ID>(data[0]));
121  data += 1; datalen -= 1;
122  }
123  return result;
124  }
125 };
126 
127 }} // namespaces
128 
129 #endif
130 
Allied Vision