8 #include "../mbedTLS++/SslConfig.h"
11 #include "event2/buffer.h"
22 m_BufferEvent(bufferevent_socket_new(
cNetworkSingleton::Get().GetEventBase(), -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS | BEV_OPT_UNLOCK_CALLBACKS)),
26 m_ShouldShutdown(false)
35 evutil_socket_t a_Socket,
38 const sockaddr * a_Address,
42 m_BufferEvent(bufferevent_socket_new(
cNetworkSingleton::Get().GetEventBase(), a_Socket, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS | BEV_OPT_UNLOCK_CALLBACKS)),
43 m_Server(
std::move(a_Server)),
46 m_ShouldShutdown(false)
71 ASSERT(a_LinkCallbacks !=
nullptr);
72 ASSERT(a_ConnectCallbacks !=
nullptr);
76 res->m_ConnectCallbacks = std::move(a_ConnectCallbacks);
78 res->m_Callbacks->OnLinkCreated(res);
82 class cHostnameCallback :
92 m_Link(std::move(a_Link)),
93 m_Port(a_ConnectPort),
98 void DoConnect(
const sockaddr * a_IP,
int size)
103 int ErrCode = bufferevent_socket_connect(m_Link->m_BufferEvent, a_IP, size);
106 m_IsConnecting =
true;
110 m_Link->GetCallbacks()->OnError(ErrCode, evutil_socket_error_to_string(ErrCode));
115 virtual bool OnNameResolvedV4(
const AString & a_Name,
const sockaddr_in * a_IP)
override
117 sockaddr_in Addr = *a_IP;
118 Addr.sin_port = htons(m_Port);
119 DoConnect(
reinterpret_cast<const sockaddr *
>(&Addr),
sizeof(Addr));
123 virtual bool OnNameResolvedV6(
const AString & a_Name,
const sockaddr_in6 * a_IP)
override
125 sockaddr_in6 Addr = *a_IP;
126 Addr.sin6_port = htons(m_Port);
127 DoConnect(
reinterpret_cast<const sockaddr *
>(&Addr),
sizeof(Addr));
131 virtual void OnError(
int a_ErrorCode,
const AString & a_ErrorMsg)
override
133 m_Link->GetCallbacks()->OnError(a_ErrorCode, a_ErrorMsg);
138 virtual void OnFinished()
override
142 virtual void OnNameResolved(
const AString & a_Name,
const AString & a_IP)
override
159 m_Self = std::move(a_Self);
174 LOGD(
"%s: Cannot send data, the link is already shut down.", __FUNCTION__);
186 return SendRaw(a_Data, a_Length);
204 if (evbuffer_get_length(bufferevent_get_output(
m_BufferEvent)) == 0)
254 return "TLS is already active on this link";
256 if ((a_OwnCert ==
nullptr) != (a_OwnPrivKey ==
nullptr))
258 return "Either provide both the certificate and private key, or neither";
262 m_TlsContext = std::make_shared<cLinkTlsContext>(*
this);
263 if ((a_OwnCert ==
nullptr) && (a_TrustedRootCAs ==
nullptr))
272 if (a_OwnCert !=
nullptr)
274 Config->SetOwnCert(std::move(a_OwnCert), std::move(a_OwnPrivKey));
276 if (a_TrustedRootCAs !=
nullptr)
279 Config->SetCACerts(std::move(a_TrustedRootCAs));
310 return "TLS is already active on this link";
312 if ((a_OwnCert ==
nullptr) || (a_OwnPrivKey ==
nullptr))
314 return "Provide the server certificate and private key";
318 m_TlsContext = std::make_shared<cLinkTlsContext>(*
this);
321 Config->SetOwnCert(a_OwnCert, a_OwnPrivKey);
327 m_TlsContext->StoreReceivedData(a_StartTLSData.data(), a_StartTLSData.size());
340 ASSERT(a_Self !=
nullptr);
349 while ((length = bufferevent_read(a_BufferEvent, data,
sizeof(data))) > 0)
351 if (tlsContext !=
nullptr)
353 ASSERT(tlsContext->IsLink(Self));
354 tlsContext->StoreReceivedData(data, length);
369 ASSERT(a_Self !=
nullptr);
371 ASSERT(Self->m_Callbacks !=
nullptr);
374 auto OutLen = evbuffer_get_length(bufferevent_get_output(Self->m_BufferEvent));
375 if ((OutLen == 0) && (Self->m_ShouldShutdown))
377 Self->DoActualShutdown();
387 ASSERT(a_Self !=
nullptr);
396 if (a_What & BEV_EVENT_ERROR)
399 int err = EVUTIL_SOCKET_ERROR();
400 if (Self->m_ConnectCallbacks !=
nullptr)
405 err = bufferevent_socket_get_dns_error(a_BufferEvent);
407 Self->m_ConnectCallbacks->OnError(err, evutil_socket_error_to_string(err));
411 Self->m_Callbacks->OnError(err, evutil_socket_error_to_string(err));
412 if (Self->m_Server ==
nullptr)
418 Self->m_Server->RemoveLink(Self.get());
421 Self->m_Self.reset();
426 if (a_What & BEV_EVENT_CONNECTED)
428 Self->UpdateLocalAddress();
429 Self->UpdateRemoteAddress();
430 if (Self->m_ConnectCallbacks !=
nullptr)
432 Self->m_ConnectCallbacks->OnConnected(*Self);
434 Self->m_ConnectCallbacks.reset();
440 if (a_What & BEV_EVENT_EOF)
443 auto tlsContext = Self->m_TlsContext;
444 if (tlsContext !=
nullptr)
446 tlsContext->FlushBuffers();
449 Self->m_Callbacks->OnRemoteClosed();
450 if (Self->m_Server !=
nullptr)
452 Self->m_Server->RemoveLink(Self.get());
458 Self->m_Self.reset();
463 LOGWARNING(
"cTCPLinkImpl: Unhandled LibEvent event %d (0x%x)", a_What, a_What);
464 ASSERT(!
"cTCPLinkImpl: Unhandled LibEvent event");
475 switch (a_Address->sa_family)
479 const sockaddr_in * sin =
reinterpret_cast<const sockaddr_in *
>(a_Address);
480 evutil_inet_ntop(AF_INET, &(sin->sin_addr), IP,
sizeof(IP));
481 a_Port = ntohs(sin->sin_port);
486 const sockaddr_in6 * sin =
reinterpret_cast<const sockaddr_in6 *
>(a_Address);
487 evutil_inet_ntop(AF_INET6, &(sin->sin6_addr), IP,
sizeof(IP));
488 a_Port = ntohs(sin->sin6_port);
494 LOGWARNING(
"%s: Unknown socket address family: %d", __FUNCTION__, a_Address->sa_family);
495 ASSERT(!
"Unknown socket address family");
509 socklen_t salen =
static_cast<socklen_t
>(
sizeof(sa));
510 getsockname(bufferevent_getfd(
m_BufferEvent),
reinterpret_cast<sockaddr *
>(&sa), &salen);
521 socklen_t salen =
static_cast<socklen_t
>(
sizeof(sa));
522 getpeername(bufferevent_getfd(
m_BufferEvent),
reinterpret_cast<sockaddr *
>(&sa), &salen);
546 return (bufferevent_write(
m_BufferEvent, a_Data, a_Length) == 0);
577 m_Self = std::move(a_Self);
598 m_EncryptedData.append(a_Data, a_NumBytes);
601 TryFinishHandshaking();
617 if (!HasHandshaken())
624 while ((NumBytes = ReadPlain(Buffer,
sizeof(Buffer))) > 0)
626 m_Link.ReceivedCleartextData(Buffer,
static_cast<size_t>(NumBytes));
645 if (!HasHandshaken())
651 m_Link.GetCallbacks()->OnTlsHandshakeCompleted();
652 WritePlain(m_CleartextData.data(), m_CleartextData.size());
653 m_CleartextData.clear();
668 if (!HasHandshaken())
670 m_CleartextData.append(
reinterpret_cast<const char *
>(a_Data), a_Length);
671 TryFinishHandshaking();
676 WritePlain(a_Data, a_Length);
690 if (m_EncryptedData.empty())
692 return MBEDTLS_ERR_SSL_WANT_READ;
696 size_t BytesToCopy = std::min(a_NumBytes, m_EncryptedData.size());
697 memcpy(a_Buffer, m_EncryptedData.data(), BytesToCopy);
698 m_EncryptedData.erase(0, BytesToCopy);
699 return static_cast<int>(BytesToCopy);
708 m_Link.SendRaw(a_Buffer, a_NumBytes);
709 return static_cast<int>(a_NumBytes);
728 return (Conn !=
nullptr);
void LOGWARNING(std::string_view a_Format, const Args &... args)
std::shared_ptr< cCryptoKey > cCryptoKeyPtr
std::shared_ptr< cX509Cert > cX509CertPtr
std::shared_ptr< cTCPLinkImpl > cTCPLinkImplPtr
std::shared_ptr< cServerHandleImpl > cServerHandleImplPtr
static std::shared_ptr< cSslConfig > MakeDefaultConfig(bool a_IsClient)
Creates a new config with some sensible defaults on top of mbedTLS basic settings.
Interface that provides the methods available on a single TCP connection.
cCallbacksPtr m_Callbacks
Callbacks to be used for the various situations.
std::shared_ptr< cCallbacks > cCallbacksPtr
static bool Connect(const AString &a_Host, UInt16 a_Port, cConnectCallbacksPtr a_ConnectCallbacks, cTCPLink::cCallbacksPtr a_LinkCallbacks)
Queues a TCP connection to be made to the specified host.
std::shared_ptr< cConnectCallbacks > cConnectCallbacksPtr
static bool HostnameToIP(const AString &a_Hostname, cResolveNameCallbacksPtr a_Callbacks)
Queues a DNS query to resolve the specified hostname to IP address.
Callbacks used when resolving names to IPs.
static cNetworkSingleton & Get(void)
Returns the singleton instance of this class.
void AddLink(const cTCPLinkPtr &a_Link)
Adds the specified link to m_Connections.
void RemoveLink(const cTCPLink *a_Link)
Removes the specified link from m_Connections.
void ReceivedCleartextData(const char *a_Data, size_t a_Length)
Called by the TLS when it has decoded a piece of incoming cleartext data from the socket.
static void WriteCallback(bufferevent *a_BufferEvent, void *a_Self)
Callback that LibEvent calls when the remote peer can receive more data.
bool m_ShouldShutdown
If true, Shutdown() has been called and is in queue.
virtual ~cTCPLinkImpl() override
Destroys the LibEvent handle representing the link.
cLinkTlsContextPtr m_TlsContext
The SSL context used for encryption, if this link uses SSL.
bufferevent * m_BufferEvent
The LibEvent handle representing this connection.
AString m_LocalIP
The IP address of the local endpoint.
static void EventCallback(bufferevent *a_BufferEvent, short a_What, void *a_Self)
Callback that LibEvent calls when there's a non-data-related event on the socket.
void UpdateLocalAddress(void)
Updates m_LocalIP and m_LocalPort based on the metadata read from the socket.
UInt16 m_LocalPort
The port of the local endpoint.
static cTCPLinkImplPtr Connect(const AString &a_Host, UInt16 a_Port, cTCPLink::cCallbacksPtr a_LinkCallbacks, cNetwork::cConnectCallbacksPtr a_ConnectCallbacks)
Queues a connection request to the specified host.
virtual bool Send(const void *a_Data, size_t a_Length) override
Queues the specified data for sending to the remote peer.
static void ReadCallback(bufferevent *a_BufferEvent, void *a_Self)
Callback that LibEvent calls when there's data available from the remote peer.
bool SendRaw(const void *a_Data, size_t a_Length)
Sends the data directly to the socket (without the optional TLS).
cTCPLinkImpl(evutil_socket_t a_Socket, cCallbacksPtr a_LinkCallbacks, cServerHandleImplPtr a_Server, const sockaddr *a_Address, socklen_t a_AddrLen)
Creates a new link based on the given socket.
void UpdateRemoteAddress(void)
Updates m_RemoteIP and m_RemotePort based on the metadata read from the socket.
virtual void Shutdown(void) override
Closes the link gracefully.
virtual void Close(void) override
Drops the connection without any more processing.
void Enable(cTCPLinkImplPtr a_Self)
Enables communication over the link.
UInt16 m_RemotePort
The port of the remote endpoint.
std::shared_ptr< cLinkTlsContext > cLinkTlsContextPtr
AString m_RemoteHost
The original host parameter which was used for creating the link, either hostname or IP address.
static void UpdateAddress(const sockaddr *a_Address, socklen_t a_AddrLen, AString &a_IP, UInt16 &a_Port)
Sets a_IP and a_Port to values read from a_Address, based on the correct address family.
cServerHandleImplPtr m_Server
The server handle that has created this link.
virtual AString StartTLSServer(cX509CertPtr a_OwnCert, cCryptoKeyPtr a_OwnPrivKey, const AString &a_StartTLSData) override
Starts a TLS handshake as a server connection.
virtual AString StartTLSClient(cX509CertPtr a_OwnCert, cCryptoKeyPtr a_OwnPrivKey, cX509CertPtr a_TrustedRootCAs) override
Starts a TLS handshake as a client connection.
std::weak_ptr< cLinkTlsContext > cLinkTlsContextWPtr
AString m_RemoteIP
The IP address of the remote endpoint.
cTCPLinkImplPtr m_Self
SharedPtr to self, used to keep this object alive as long as the callbacks are coming.
void DoActualShutdown(void)
Calls shutdown on the link and disables LibEvent writing.
cLinkTlsContext(cTCPLinkImpl &a_Link)
void SetSelf(cLinkTlsContextWPtr a_Self)
Shares ownership of self, so that this object can keep itself alive for as long as it needs.
void FlushBuffers(void)
Tries to read any cleartext data available through the SSL, reports it in the link.
void StoreReceivedData(const char *a_Data, size_t a_NumBytes)
Stores the specified block of data into the buffer of the data to be decrypted (incoming from remote)...
void Send(const void *a_Data, size_t a_Length)
Sends the specified cleartext data over the SSL to the remote peer.
virtual int ReceiveEncrypted(unsigned char *a_Buffer, size_t a_NumBytes) override
virtual int SendEncrypted(const unsigned char *a_Buffer, size_t a_NumBytes) override
void TryFinishHandshaking(void)
Tries to finish handshaking the SSL.
void ResetSelf(void)
Removes the self ownership so that we can detect the SSL closure.