Browse Source

Merge pull request #583 from PurpleI2P/openssl

recent changes
pull/613/head
orignal 8 years ago committed by GitHub
parent
commit
c06e739c9b
  1. 59
      BOB.cpp
  2. 2
      BOB.h
  3. 2
      DaemonLinux.cpp
  4. 1
      Reseed.cpp
  5. 19
      RouterContext.cpp
  6. 27
      SSU.cpp
  7. 3
      SSU.h
  8. 53
      SSUSession.cpp
  9. 2
      SSUSession.h

59
BOB.cpp

@ -70,7 +70,7 @@ namespace client
if (eol) if (eol)
{ {
*eol = 0; *eol = 0;
if (eol != receiver->buffer && eol[-1] == '\r') eol[-1] = 0; // workaround for Transmission, it sends '\r\n' terminated address
receiver->data = (uint8_t *)eol + 1; receiver->data = (uint8_t *)eol + 1;
receiver->dataLen = receiver->bufferOffset - (eol - receiver->buffer + 1); receiver->dataLen = receiver->bufferOffset - (eol - receiver->buffer + 1);
i2p::data::IdentHash ident; i2p::data::IdentHash ident;
@ -203,7 +203,7 @@ namespace client
BOBCommandSession::BOBCommandSession (BOBCommandChannel& owner): BOBCommandSession::BOBCommandSession (BOBCommandChannel& owner):
m_Owner (owner), m_Socket (m_Owner.GetService ()), m_Owner (owner), m_Socket (m_Owner.GetService ()),
m_ReceiveBufferOffset (0), m_IsOpen (true), m_IsQuiet (false), m_ReceiveBufferOffset (0), m_IsOpen (true), m_IsQuiet (false), m_IsActive (false),
m_InPort (0), m_OutPort (0), m_CurrentDestination (nullptr) m_InPort (0), m_OutPort (0), m_CurrentDestination (nullptr)
{ {
} }
@ -354,6 +354,11 @@ namespace client
void BOBCommandSession::StartCommandHandler (const char * operand, size_t len) void BOBCommandSession::StartCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: start ", m_Nickname); LogPrint (eLogDebug, "BOB: start ", m_Nickname);
if (m_IsActive)
{
SendReplyError ("tunnel is active");
return;
}
if (!m_CurrentDestination) if (!m_CurrentDestination)
{ {
m_CurrentDestination = new BOBDestination (i2p::client::context.CreateNewLocalDestination (m_Keys, true, &m_Options)); m_CurrentDestination = new BOBDestination (i2p::client::context.CreateNewLocalDestination (m_Keys, true, &m_Options));
@ -364,19 +369,27 @@ namespace client
if (m_OutPort && !m_Address.empty ()) if (m_OutPort && !m_Address.empty ())
m_CurrentDestination->CreateOutboundTunnel (m_Address, m_OutPort, m_IsQuiet); m_CurrentDestination->CreateOutboundTunnel (m_Address, m_OutPort, m_IsQuiet);
m_CurrentDestination->Start (); m_CurrentDestination->Start ();
SendReplyOK ("tunnel starting"); SendReplyOK ("Tunnel starting");
m_IsActive = true;
} }
void BOBCommandSession::StopCommandHandler (const char * operand, size_t len) void BOBCommandSession::StopCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: stop ", m_Nickname);
if (!m_IsActive)
{
SendReplyError ("tunnel is inactive");
return;
}
auto dest = m_Owner.FindDestination (m_Nickname); auto dest = m_Owner.FindDestination (m_Nickname);
if (dest) if (dest)
{ {
dest->StopTunnels (); dest->StopTunnels ();
SendReplyOK ("tunnel stopping"); SendReplyOK ("Tunnel stopping");
} }
else else
SendReplyError ("tunnel not found"); SendReplyError ("tunnel not found");
m_IsActive = false;
} }
void BOBCommandSession::SetNickCommandHandler (const char * operand, size_t len) void BOBCommandSession::SetNickCommandHandler (const char * operand, size_t len)
@ -384,7 +397,7 @@ namespace client
LogPrint (eLogDebug, "BOB: setnick ", operand); LogPrint (eLogDebug, "BOB: setnick ", operand);
m_Nickname = operand; m_Nickname = operand;
std::string msg ("Nickname set to "); std::string msg ("Nickname set to ");
msg += operand; msg += m_Nickname;
SendReplyOK (msg.c_str ()); SendReplyOK (msg.c_str ());
} }
@ -396,12 +409,15 @@ namespace client
{ {
m_Keys = m_CurrentDestination->GetKeys (); m_Keys = m_CurrentDestination->GetKeys ();
m_Nickname = operand; m_Nickname = operand;
}
if (m_Nickname == operand)
{
std::string msg ("Nickname set to "); std::string msg ("Nickname set to ");
msg += operand; msg += m_Nickname;
SendReplyOK (msg.c_str ()); SendReplyOK (msg.c_str ());
} }
else else
SendReplyError ("tunnel not found"); SendReplyError ("no nickname has been set");
} }
void BOBCommandSession::NewkeysCommandHandler (const char * operand, size_t len) void BOBCommandSession::NewkeysCommandHandler (const char * operand, size_t len)
@ -441,7 +457,10 @@ namespace client
{ {
LogPrint (eLogDebug, "BOB: outport ", operand); LogPrint (eLogDebug, "BOB: outport ", operand);
m_OutPort = boost::lexical_cast<int>(operand); m_OutPort = boost::lexical_cast<int>(operand);
if (m_OutPort >= 0)
SendReplyOK ("outbound port set"); SendReplyOK ("outbound port set");
else
SendReplyError ("port out of range");
} }
void BOBCommandSession::InhostCommandHandler (const char * operand, size_t len) void BOBCommandSession::InhostCommandHandler (const char * operand, size_t len)
@ -455,14 +474,27 @@ namespace client
{ {
LogPrint (eLogDebug, "BOB: inport ", operand); LogPrint (eLogDebug, "BOB: inport ", operand);
m_InPort = boost::lexical_cast<int>(operand); m_InPort = boost::lexical_cast<int>(operand);
if (m_InPort >= 0)
SendReplyOK ("inbound port set"); SendReplyOK ("inbound port set");
else
SendReplyError ("port out of range");
} }
void BOBCommandSession::QuietCommandHandler (const char * operand, size_t len) void BOBCommandSession::QuietCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: quiet"); LogPrint (eLogDebug, "BOB: quiet");
if (m_Nickname.length () > 0)
{
if (!m_IsActive)
{
m_IsQuiet = true; m_IsQuiet = true;
SendReplyOK ("quiet"); SendReplyOK ("Quiet set");
}
else
SendReplyError ("tunnel is active");
}
else
SendReplyError ("no nickname has been set");
} }
void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len) void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len)
@ -497,6 +529,7 @@ namespace client
{ {
LogPrint (eLogDebug, "BOB: clear"); LogPrint (eLogDebug, "BOB: clear");
m_Owner.DeleteDestination (m_Nickname); m_Owner.DeleteDestination (m_Nickname);
m_Nickname = "";
SendReplyOK ("cleared"); SendReplyOK ("cleared");
} }
@ -515,10 +548,14 @@ namespace client
const char * value = strchr (operand, '='); const char * value = strchr (operand, '=');
if (value) if (value)
{ {
std::string msg ("option ");
*(const_cast<char *>(value)) = 0; *(const_cast<char *>(value)) = 0;
m_Options[operand] = value + 1; m_Options[operand] = value + 1;
msg += operand;
*(const_cast<char *>(value)) = '='; *(const_cast<char *>(value)) = '=';
SendReplyOK ("option"); msg += " set to ";
msg += value;
SendReplyOK (msg.c_str ());
} }
else else
SendReplyError ("malformed"); SendReplyError ("malformed");
@ -527,10 +564,10 @@ namespace client
void BOBCommandSession::StatusCommandHandler (const char * operand, size_t len) void BOBCommandSession::StatusCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: status ", operand); LogPrint (eLogDebug, "BOB: status ", operand);
if (operand == m_Nickname) if (m_Nickname == operand)
{ {
std::stringstream s; std::stringstream s;
s << "DATA"; s << " NICKNAME:"; s << operand; s << "DATA"; s << " NICKNAME: "; s << m_Nickname;
if (m_CurrentDestination->GetLocalDestination ()->IsReady ()) if (m_CurrentDestination->GetLocalDestination ()->IsReady ())
s << " STARTING: false RUNNING: true STOPPING: false"; s << " STARTING: false RUNNING: true STOPPING: false";
else else

2
BOB.h

@ -188,7 +188,7 @@ namespace client
boost::asio::ip::tcp::socket m_Socket; boost::asio::ip::tcp::socket m_Socket;
char m_ReceiveBuffer[BOB_COMMAND_BUFFER_SIZE + 1], m_SendBuffer[BOB_COMMAND_BUFFER_SIZE + 1]; char m_ReceiveBuffer[BOB_COMMAND_BUFFER_SIZE + 1], m_SendBuffer[BOB_COMMAND_BUFFER_SIZE + 1];
size_t m_ReceiveBufferOffset; size_t m_ReceiveBufferOffset;
bool m_IsOpen, m_IsQuiet; bool m_IsOpen, m_IsQuiet, m_IsActive;
std::string m_Nickname, m_Address; std::string m_Nickname, m_Address;
int m_InPort, m_OutPort; int m_InPort, m_OutPort;
i2p::data::PrivateKeys m_Keys; i2p::data::PrivateKeys m_Keys;

2
DaemonLinux.cpp

@ -13,6 +13,7 @@
#include "FS.h" #include "FS.h"
#include "Log.h" #include "Log.h"
#include "RouterContext.h" #include "RouterContext.h"
#include "ClientContext.h"
void handle_signal(int sig) void handle_signal(int sig)
{ {
@ -21,6 +22,7 @@ void handle_signal(int sig)
case SIGHUP: case SIGHUP:
LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening log..."); LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening log...");
i2p::log::Logger().Reopen (); i2p::log::Logger().Reopen ();
i2p::client::context.ReloadConfig();
break; break;
case SIGINT: case SIGINT:
if (i2p::context.AcceptsTunnels () && !Daemon.gracefullShutdownInterval) if (i2p::context.AcceptsTunnels () && !Daemon.gracefullShutdownInterval)

1
Reseed.cpp

@ -15,6 +15,7 @@
#include "Identity.h" #include "Identity.h"
#include "NetDb.h" #include "NetDb.h"
#include "HTTP.h" #include "HTTP.h"
#include "util.h"
namespace i2p namespace i2p
{ {

19
RouterContext.cpp

@ -53,16 +53,27 @@ namespace i2p
bool ipv6; i2p::config::GetOption("ipv6", ipv6); bool ipv6; i2p::config::GetOption("ipv6", ipv6);
bool nat; i2p::config::GetOption("nat", nat); bool nat; i2p::config::GetOption("nat", nat);
std::string ifname; i2p::config::GetOption("ifname", ifname); std::string ifname; i2p::config::GetOption("ifname", ifname);
std::string host = ipv6 ? "::" : "127.0.0.1"; if (ipv4)
if (nat) { {
std::string host = "127.0.0.1";
if (!i2p::config::IsDefault("host")) if (!i2p::config::IsDefault("host"))
i2p::config::GetOption("host", host); i2p::config::GetOption("host", host);
} else if (!ifname.empty()) { else if (!nat && !ifname.empty())
/* bind to interface, we have no NAT so set external address too */ /* bind to interface, we have no NAT so set external address too */
host = i2p::util::net::GetInterfaceAddress(ifname, ipv6).to_string(); host = i2p::util::net::GetInterfaceAddress(ifname, false).to_string(); // v4
routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ());
routerInfo.AddNTCPAddress (host.c_str(), port);
} }
if (ipv6)
{
std::string host = "::";
if (!i2p::config::IsDefault("host") && !ipv4) // override if v6 only
i2p::config::GetOption("host", host);
else if (!ifname.empty())
host = i2p::util::net::GetInterfaceAddress(ifname, true).to_string(); // v6
routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ());
routerInfo.AddNTCPAddress (host.c_str(), port); routerInfo.AddNTCPAddress (host.c_str(), port);
}
routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | routerInfo.SetCaps (i2p::data::RouterInfo::eReachable |
i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC
routerInfo.SetProperty ("netId", std::to_string (I2PD_NET_ID)); routerInfo.SetProperty ("netId", std::to_string (I2PD_NET_ID));

27
SSU.cpp

@ -459,8 +459,31 @@ namespace transport
return GetRandomV4Session ( return GetRandomV4Session (
[excluded](std::shared_ptr<SSUSession> session)->bool [excluded](std::shared_ptr<SSUSession> session)->bool
{ {
return session->GetState () == eSessionStateEstablished && !session->IsV6 () && return session->GetState () == eSessionStateEstablished && session != excluded;
session != excluded; }
);
}
template<typename Filter>
std::shared_ptr<SSUSession> SSUServer::GetRandomV6Session (Filter filter) // v6 only
{
std::vector<std::shared_ptr<SSUSession> > filteredSessions;
for (auto s :m_SessionsV6)
if (filter (s.second)) filteredSessions.push_back (s.second);
if (filteredSessions.size () > 0)
{
auto ind = rand () % filteredSessions.size ();
return filteredSessions[ind];
}
return nullptr;
}
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded) // v6 only
{
return GetRandomV6Session (
[excluded](std::shared_ptr<SSUSession> session)->bool
{
return session->GetState () == eSessionStateEstablished && session != excluded;
} }
); );
} }

3
SSU.h

@ -48,6 +48,7 @@ namespace transport
std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const; std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const;
std::shared_ptr<SSUSession> FindSession (const boost::asio::ip::udp::endpoint& e) const; std::shared_ptr<SSUSession> FindSession (const boost::asio::ip::udp::endpoint& e) const;
std::shared_ptr<SSUSession> GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded); std::shared_ptr<SSUSession> GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded);
std::shared_ptr<SSUSession> GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded);
void DeleteSession (std::shared_ptr<SSUSession> session); void DeleteSession (std::shared_ptr<SSUSession> session);
void DeleteAllSessions (); void DeleteAllSessions ();
@ -79,6 +80,8 @@ namespace transport
void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false); void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
template<typename Filter> template<typename Filter>
std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter); std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter);
template<typename Filter>
std::shared_ptr<SSUSession> GetRandomV6Session (Filter filter);
std::set<SSUSession *> FindIntroducers (int maxNumIntroducers); std::set<SSUSession *> FindIntroducers (int maxNumIntroducers);
void ScheduleIntroducersUpdateTimer (); void ScheduleIntroducersUpdateTimer ();

53
SSUSession.cpp

@ -930,10 +930,10 @@ namespace transport
{ {
uint32_t nonce = bufbe32toh (buf); // 4 bytes uint32_t nonce = bufbe32toh (buf); // 4 bytes
uint8_t size = buf[4]; // 1 byte uint8_t size = buf[4]; // 1 byte
uint32_t address = (size == 4) ? buf32toh(buf + 5) : 0; // big endian, size bytes const uint8_t * address = buf + 5; // big endian, size bytes
uint16_t port = buf16toh(buf + size + 5); // big endian, 2 bytes uint16_t port = buf16toh(buf + size + 5); // big endian, 2 bytes
const uint8_t * introKey = buf + size + 7; const uint8_t * introKey = buf + size + 7;
if (port && !address) if (port && (size != 4) && (size != 16))
{ {
LogPrint (eLogWarning, "SSU: Address of ", size, " bytes not supported"); LogPrint (eLogWarning, "SSU: Address of ", size, " bytes not supported");
return; return;
@ -954,8 +954,7 @@ namespace transport
LogPrint (eLogDebug, "SSU: first peer test from Charlie. We are Alice"); LogPrint (eLogDebug, "SSU: first peer test from Charlie. We are Alice");
i2p::context.SetStatus (eRouterStatusOK); i2p::context.SetStatus (eRouterStatusOK);
m_Server.UpdatePeerTest (nonce, ePeerTestParticipantAlice2); m_Server.UpdatePeerTest (nonce, ePeerTestParticipantAlice2);
SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (), SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, true, false); // to Charlie
senderEndpoint.port (), introKey, true, false); // to Charlie
} }
break; break;
} }
@ -984,8 +983,7 @@ namespace transport
case ePeerTestParticipantCharlie: case ePeerTestParticipantCharlie:
{ {
LogPrint (eLogDebug, "SSU: peer test from Alice. We are Charlie"); LogPrint (eLogDebug, "SSU: peer test from Alice. We are Charlie");
SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (), SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey); // to Alice with her actual address
senderEndpoint.port (), introKey); // to Alice with her actual address
m_Server.RemovePeerTest (nonce); // nonce has been used m_Server.RemovePeerTest (nonce); // nonce has been used
break; break;
} }
@ -1000,17 +998,29 @@ namespace transport
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Charlie"); LogPrint (eLogDebug, "SSU: peer test from Bob. We are Charlie");
m_Server.NewPeerTest (nonce, ePeerTestParticipantCharlie); m_Server.NewPeerTest (nonce, ePeerTestParticipantCharlie);
Send (PAYLOAD_TYPE_PEER_TEST, buf, len); // back to Bob Send (PAYLOAD_TYPE_PEER_TEST, buf, len); // back to Bob
SendPeerTest (nonce, be32toh (address), be16toh (port), introKey); // to Alice with her address received from Bob boost::asio::ip::address addr; // Alice's address
if (size == 4) // v4
{
boost::asio::ip::address_v4::bytes_type bytes;
memcpy (bytes.data (), address, 4);
addr = boost::asio::ip::address_v4 (bytes);
}
else // v6
{
boost::asio::ip::address_v6::bytes_type bytes;
memcpy (bytes.data (), address, 6);
addr = boost::asio::ip::address_v6 (bytes);
}
SendPeerTest (nonce, addr, be16toh (port), introKey); // to Alice with her address received from Bob
} }
else else
{ {
LogPrint (eLogDebug, "SSU: peer test from Alice. We are Bob"); LogPrint (eLogDebug, "SSU: peer test from Alice. We are Bob");
auto session = m_Server.GetRandomEstablishedV4Session (shared_from_this ()); // Charlie, TODO: implement v6 support auto session = senderEndpoint.address ().is_v4 () ? m_Server.GetRandomEstablishedV4Session (shared_from_this ()) : m_Server.GetRandomEstablishedV6Session (shared_from_this ()); // Charlie
if (session) if (session)
{ {
m_Server.NewPeerTest (nonce, ePeerTestParticipantBob, shared_from_this ()); m_Server.NewPeerTest (nonce, ePeerTestParticipantBob, shared_from_this ());
session->SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (), session->SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, false); // to Charlie with Alice's actual address
senderEndpoint.port (), introKey, false); // to Charlie with Alice's actual address
} }
} }
} }
@ -1020,7 +1030,7 @@ namespace transport
} }
} }
void SSUSession::SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, void SSUSession::SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port,
const uint8_t * introKey, bool toAddress, bool sendAddress) const uint8_t * introKey, bool toAddress, bool sendAddress)
// toAddress is true for Alice<->Chalie communications only // toAddress is true for Alice<->Chalie communications only
// sendAddress is false if message comes from Alice // sendAddress is false if message comes from Alice
@ -1031,12 +1041,21 @@ namespace transport
htobe32buf (payload, nonce); htobe32buf (payload, nonce);
payload += 4; // nonce payload += 4; // nonce
// address and port // address and port
if (sendAddress && address) if (sendAddress)
{
if (address.is_v4 ())
{ {
*payload = 4; *payload = 4;
payload++; // size memcpy (payload + 1, address.to_v4 ().to_bytes ().data (), 4); // our IP V4
htobe32buf (payload, address); }
payload += 4; // address else if (address.is_v6 ())
{
*payload = 6;
memcpy (payload + 1, address.to_v6 ().to_bytes ().data (), 16); // our IP V6
}
else
*payload = 0;
payload += (payload[0] + 1);
} }
else else
{ {
@ -1064,7 +1083,7 @@ namespace transport
{ {
// encrypt message with specified intro key // encrypt message with specified intro key
FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80, introKey, iv, introKey); FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80, introKey, iv, introKey);
boost::asio::ip::udp::endpoint e (boost::asio::ip::address_v4 (address), port); boost::asio::ip::udp::endpoint e (address, port);
m_Server.Send (buf, 80, e); m_Server.Send (buf, 80, e);
} }
else else
@ -1090,7 +1109,7 @@ namespace transport
if (!nonce) nonce = 1; if (!nonce) nonce = 1;
m_IsPeerTest = false; m_IsPeerTest = false;
m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1); m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1);
SendPeerTest (nonce, 0, 0, address->key, false, false); // address and port always zero for Alice SendPeerTest (nonce, boost::asio::ip::address(), 0, address->key, false, false); // address and port always zero for Alice
} }
void SSUSession::SendKeepAlive () void SSUSession::SendKeepAlive ()

2
SSUSession.h

@ -118,7 +118,7 @@ namespace transport
void ScheduleConnectTimer (); void ScheduleConnectTimer ();
void HandleConnectTimer (const boost::system::error_code& ecode); void HandleConnectTimer (const boost::system::error_code& ecode);
void ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, const uint8_t * introKey, bool toAddress = true, bool sendAddress = true); void SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port, const uint8_t * introKey, bool toAddress = true, bool sendAddress = true);
void ProcessData (uint8_t * buf, size_t len); void ProcessData (uint8_t * buf, size_t len);
void SendSesionDestroyed (); void SendSesionDestroyed ();
void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key

Loading…
Cancel
Save