lokinet/llarp/utp/session.hpp

295 lines
7.0 KiB
C++
Raw Normal View History

2019-03-29 14:23:19 +00:00
#ifndef LLARP_UTP_SESSION_HPP
#define LLARP_UTP_SESSION_HPP
2019-03-29 14:03:07 +00:00
#include <crypto/crypto.hpp>
#include <link/session.hpp>
2019-07-30 23:42:13 +00:00
#include <utility>
2019-03-29 14:23:19 +00:00
#include <utp/inbound_message.hpp>
2019-04-01 21:26:31 +00:00
#include <deque>
2019-03-29 14:03:07 +00:00
#include <utp.h>
namespace llarp
{
namespace utp
{
struct LinkLayer;
2019-04-02 09:03:53 +00:00
struct Session : public ILinkSession
{
/// remote router's rc
RouterContact remoteRC;
/// underlying socket
utp_socket* sock;
/// link layer parent
2019-04-02 09:03:53 +00:00
ILinkLayer* parent;
/// did we get a LIM from the remote yet?
bool gotLIM;
/// remote router's transport pubkey
PubKey remoteTransportPubKey;
/// remote router's transport ip
Addr remoteAddr;
/// rx session key
SharedSecret rxKey;
/// tx session key
SharedSecret txKey;
/// timestamp last active
2019-07-18 13:31:28 +00:00
llarp_time_t lastActive = 0;
2019-03-29 15:26:44 +00:00
/// timestamp last send success
2019-07-18 13:31:28 +00:00
llarp_time_t lastSend = 0;
2019-03-07 22:53:36 +00:00
/// session timeout (60s)
const static llarp_time_t sessionTimeout = DefaultLinkSessionLifetime;
2019-07-26 16:19:31 +00:00
struct OutboundMessage
{
OutboundMessage(uint32_t id, CompletionHandler func)
2019-07-30 23:42:13 +00:00
: msgid{id}, completed{std::move(func)}
2019-07-26 16:19:31 +00:00
{
}
const uint32_t msgid;
std::deque< utp_iovec > vecs;
std::deque< FragmentBuffer > fragments;
CompletionHandler completed;
void
Dropped()
{
if(completed)
{
completed(DeliveryStatus::eDeliveryDropped);
completed = nullptr;
}
}
void
Delivered()
{
if(completed)
{
completed(DeliveryStatus::eDeliverySuccess);
completed = nullptr;
}
}
bool
operator<(const OutboundMessage& other) const
{
return msgid < other.msgid;
}
};
/// current rx fragment buffer
FragmentBuffer recvBuf;
/// current offset in current rx fragment buffer
size_t recvBufOffset;
/// rx fragment message body
AlignedBuffer< FragmentBodySize > rxFragBody;
/// the next message id for tx
uint32_t m_NextTXMsgID;
/// the next message id for rx
uint32_t m_NextRXMsgID;
using SendQueue_t = std::deque< OutboundMessage >;
2019-07-26 16:19:31 +00:00
/// messages we are currently sending
SendQueue_t sendq;
/// messages we are recving right now
std::unordered_map< uint32_t, InboundMessage > m_RecvMsgs;
/// are we stalled or nah?
bool stalled = false;
uint64_t m_RXRate = 0;
uint64_t m_TXRate = 0;
2019-08-10 10:51:02 +00:00
llarp_time_t m_LastTick = 0;
/// mark session as alive
void
Alive();
2019-02-18 23:58:12 +00:00
util::StatusObject
ExtractStatus() const override;
2019-07-30 23:42:13 +00:00
~Session() override = 0;
2019-04-02 09:03:53 +00:00
/// base
explicit Session(LinkLayer* p);
enum State
{
eInitial, // initial state
eConnecting, // we are connecting
eLinkEstablished, // when utp connection is established
eCryptoHandshake, // crypto handshake initiated
eSessionReady, // session is ready
eClose // utp connection is closed
};
/// session state, call EnterState(State) to set
State state;
/// hook for utp for when we have established a connection
void
2019-04-02 09:03:53 +00:00
OnLinkEstablished(ILinkLayer* p) override;
/// switch states
void
EnterState(State st);
/// handle LIM after handshake
bool
GotSessionRenegotiate(const LinkIntroMessage* msg);
/// re negotiate session with our new local RC
bool
2019-04-02 09:03:53 +00:00
RenegotiateSession() override;
bool
ShouldPing() const override;
/// pump tx queue
void
PumpWrite(size_t numMessages);
2019-01-04 12:43:41 +00:00
void
2019-04-02 09:03:53 +00:00
Pump() override;
bool
SendKeepAlive() override;
bool
2019-05-07 13:04:43 +00:00
IsEstablished() const override
2019-04-02 09:03:53 +00:00
{
2019-05-07 13:04:43 +00:00
return state == eSessionReady;
2019-04-02 09:03:53 +00:00
}
bool
TimedOut(llarp_time_t now) const override;
2019-01-04 12:43:41 +00:00
/// verify a fragment buffer and the decrypt it
/// buf is assumed to be FragmentBufferSize bytes long
bool
VerifyThenDecrypt(const byte_t* buf);
/// encrypt a fragment then hash the ciphertext
bool
EncryptThenHash(const byte_t* ptr, uint32_t msgid, uint16_t sz,
uint16_t remain);
/// queue a fully formed message
bool
2019-07-26 16:19:31 +00:00
SendMessageBuffer(const llarp_buffer_t& buf,
ILinkSession::CompletionHandler) override;
/// prune expired inbound messages
void
PruneInboundMessages(llarp_time_t now);
/// do low level connect
void
Connect();
/// handle outbound connection made
void
OutboundLinkEstablished(LinkLayer* p);
// send first message
void
OutboundHandshake();
// do key exchange for handshake
template < bool (Crypto::*dh_func)(SharedSecret&, const PubKey&,
const SecretKey&, const TunnelNonce&) >
bool
DoKeyExchange(SharedSecret& K, const KeyExchangeNonce& n,
const PubKey& other, const SecretKey& secret);
bool
DoClientKeyExchange(SharedSecret& K, const KeyExchangeNonce& n,
const PubKey& other, const SecretKey& secret)
{
return DoKeyExchange< &Crypto::transport_dh_client >(K, n, other,
secret);
}
bool
DoServerKeyExchange(SharedSecret& K, const KeyExchangeNonce& n,
const PubKey& other, const SecretKey& secret)
{
return DoKeyExchange< &Crypto::transport_dh_server >(K, n, other,
secret);
}
/// does K = HS(K + A)
bool
MutateKey(SharedSecret& K, const AlignedBuffer< 24 >& A);
void
2019-04-02 09:03:53 +00:00
Tick(llarp_time_t now) override;
/// close session
void
2019-04-02 09:03:53 +00:00
Close() override;
/// low level read
bool
Recv(const byte_t* buf, size_t sz);
/// get remote identity pubkey
2019-04-02 09:03:53 +00:00
PubKey
GetPubKey() const override;
/// get remote address
Addr
2019-04-02 09:03:53 +00:00
GetRemoteEndpoint() const override;
RouterContact
GetRemoteRC() const override
{
return remoteRC;
}
/// get parent link
ILinkLayer*
2019-04-02 09:03:53 +00:00
GetLinkLayer() const override;
void
MarkEstablished();
2019-04-02 09:03:53 +00:00
size_t
SendQueueBacklog() const override
{
return sendq.size();
}
};
struct InboundSession final : public Session
{
InboundSession(LinkLayer* p, utp_socket* s, const Addr& addr);
bool
InboundLIM(const LinkIntroMessage* msg);
void
Start() override
{
}
};
struct OutboundSession final : public Session
{
OutboundSession(LinkLayer* p, utp_socket* s, const RouterContact& rc,
const AddressInfo& addr);
bool
OutboundLIM(const LinkIntroMessage* msg);
void
Start() override;
};
} // namespace utp
} // namespace llarp
#endif