8 #include "../mbedTLS++/SslConfig.h" 11 #include "event2/buffer.h" 21 super(a_LinkCallbacks),
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)),
25 m_ShouldShutdown(false)
34 super(a_LinkCallbacks),
35 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)),
64 ASSERT(a_LinkCallbacks !=
nullptr);
65 ASSERT(a_ConnectCallbacks !=
nullptr);
69 res->m_ConnectCallbacks = a_ConnectCallbacks;
71 res->m_Callbacks->OnLinkCreated(res);
75 class cHostnameCallback :
85 m_Link(std::move(a_Link)),
86 m_Port(a_ConnectPort),
91 void DoConnect(
const sockaddr * a_IP,
int size)
96 int ErrCode = bufferevent_socket_connect(m_Link->m_BufferEvent, a_IP, size);
99 m_IsConnecting =
true;
103 m_Link->GetCallbacks()->OnError(ErrCode, evutil_socket_error_to_string(ErrCode));
108 virtual bool OnNameResolvedV4(
const AString & a_Name,
const sockaddr_in * a_IP)
override 110 sockaddr_in Addr = *a_IP;
111 Addr.sin_port = htons(m_Port);
112 DoConnect(reinterpret_cast<const sockaddr *>(&Addr),
sizeof(Addr));
116 virtual bool OnNameResolvedV6(
const AString & a_Name,
const sockaddr_in6 * a_IP)
override 118 sockaddr_in6 Addr = *a_IP;
119 Addr.sin6_port = htons(m_Port);
120 DoConnect(reinterpret_cast<const sockaddr *>(&Addr),
sizeof(Addr));
124 virtual void OnError(
int a_ErrorCode,
const AString & a_ErrorMsg)
override 126 m_Link->GetCallbacks()->OnError(a_ErrorCode, a_ErrorMsg);
131 virtual void OnFinished()
override 135 virtual void OnNameResolved(
const AString & a_Name,
const AString & a_IP)
override 167 LOGD(
"%s: Cannot send data, the link is already shut down.", __FUNCTION__);
179 return SendRaw(a_Data, a_Length);
197 if (evbuffer_get_length(bufferevent_get_output(
m_BufferEvent)) == 0)
246 return "TLS is already active on this link";
248 if ((a_OwnCert ==
nullptr) != (a_OwnPrivKey ==
nullptr))
250 return "Either provide both the certificate and private key, or neither";
254 m_TlsContext = std::make_shared<cLinkTlsContext>(*this);
255 if (a_OwnCert !=
nullptr)
258 Config->SetOwnCert(std::move(a_OwnCert), std::move(a_OwnPrivKey));
286 return "TLS is already active on this link";
288 if ((a_OwnCert ==
nullptr) || (a_OwnPrivKey ==
nullptr))
290 return "Provide the server certificate and private key";
294 m_TlsContext = std::make_shared<cLinkTlsContext>(*this);
297 Config->SetOwnCert(a_OwnCert, a_OwnPrivKey);
303 m_TlsContext->StoreReceivedData(a_StartTLSData.data(), a_StartTLSData.size());
316 ASSERT(a_Self !=
nullptr);
325 while ((length = bufferevent_read(a_BufferEvent, data,
sizeof(data))) > 0)
327 if (tlsContext !=
nullptr)
329 ASSERT(tlsContext->IsLink(Self));
330 tlsContext->StoreReceivedData(data, length);
345 ASSERT(a_Self !=
nullptr);
347 ASSERT(Self->m_Callbacks !=
nullptr);
350 auto OutLen = evbuffer_get_length(bufferevent_get_output(Self->m_BufferEvent));
351 if ((OutLen == 0) && (Self->m_ShouldShutdown))
353 Self->DoActualShutdown();
363 ASSERT(a_Self !=
nullptr);
372 if (a_What & BEV_EVENT_ERROR)
375 int err = EVUTIL_SOCKET_ERROR();
376 if (Self->m_ConnectCallbacks !=
nullptr)
381 err = bufferevent_socket_get_dns_error(a_BufferEvent);
383 Self->m_ConnectCallbacks->OnError(err, evutil_socket_error_to_string(err));
387 Self->m_Callbacks->OnError(err, evutil_socket_error_to_string(err));
388 if (Self->m_Server ==
nullptr)
394 Self->m_Server->RemoveLink(Self.get());
397 Self->m_Self.reset();
402 if (a_What & BEV_EVENT_CONNECTED)
404 Self->UpdateLocalAddress();
405 Self->UpdateRemoteAddress();
406 if (Self->m_ConnectCallbacks !=
nullptr)
408 Self->m_ConnectCallbacks->OnConnected(*Self);
410 Self->m_ConnectCallbacks.reset();
416 if (a_What & BEV_EVENT_EOF)
419 auto tlsContext = Self->m_TlsContext;
420 if (tlsContext !=
nullptr)
422 tlsContext->FlushBuffers();
425 Self->m_Callbacks->OnRemoteClosed();
426 if (Self->m_Server !=
nullptr)
428 Self->m_Server->RemoveLink(Self.get());
434 Self->m_Self.reset();
439 LOGWARNING(
"cTCPLinkImpl: Unhandled LibEvent event %d (0x%x)", a_What, a_What);
440 ASSERT(!
"cTCPLinkImpl: Unhandled LibEvent event");
451 switch (a_Address->sa_family)
455 const sockaddr_in * sin =
reinterpret_cast<const sockaddr_in *
>(a_Address);
456 evutil_inet_ntop(AF_INET, &(sin->sin_addr), IP,
sizeof(IP));
457 a_Port = ntohs(sin->sin_port);
462 const sockaddr_in6 * sin =
reinterpret_cast<const sockaddr_in6 *
>(a_Address);
463 evutil_inet_ntop(AF_INET6, &(sin->sin6_addr), IP,
sizeof(IP));
464 a_Port = ntohs(sin->sin6_port);
470 LOGWARNING(
"%s: Unknown socket address family: %d", __FUNCTION__, a_Address->sa_family);
471 ASSERT(!
"Unknown socket address family");
485 socklen_t salen =
static_cast<socklen_t
>(
sizeof(sa));
486 getsockname(bufferevent_getfd(
m_BufferEvent), reinterpret_cast<sockaddr *>(&sa), &salen);
497 socklen_t salen =
static_cast<socklen_t
>(
sizeof(sa));
498 getpeername(bufferevent_getfd(
m_BufferEvent), reinterpret_cast<sockaddr *>(&sa), &salen);
522 return (bufferevent_write(
m_BufferEvent, a_Data, a_Length) == 0);
593 if (!HasHandshaken())
600 while ((NumBytes = ReadPlain(Buffer,
sizeof(Buffer))) > 0)
621 if (!HasHandshaken())
644 if (!HasHandshaken())
646 m_CleartextData.append(reinterpret_cast<const char *>(a_Data), a_Length);
652 WritePlain(a_Data, a_Length);
668 return MBEDTLS_ERR_SSL_WANT_READ;
675 return static_cast<int>(BytesToCopy);
685 return static_cast<int>(a_NumBytes);
704 return (Conn !=
nullptr);
void FlushBuffers(void)
Tries to read any cleartext data available through the SSL, reports it in the link.
virtual int SendEncrypted(const unsigned char *a_Buffer, size_t a_NumBytes) override
void RemoveLink(const cTCPLink *a_Link)
Removes the specified link from m_Connections.
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.
virtual AString StartTLSServer(cX509CertPtr a_OwnCert, cCryptoKeyPtr a_OwnPrivKey, const AString &a_StartTLSData) override
Starts a TLS handshake as a server connection.
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.
void TryFinishHandshaking(void)
Tries to finish handshaking the SSL.
cServerHandleImplPtr m_Server
The server handle that has created this link.
std::shared_ptr< cX509Cert > cX509CertPtr
bool m_ShouldShutdown
If true, Shutdown() has been called and is in queue.
void UpdateRemoteAddress(void)
Updates m_RemoteIP and m_RemotePort based on the metadata read from the socket.
Callbacks used when resolving names to IPs.
std::shared_ptr< cCryptoKey > cCryptoKeyPtr
cTCPLinkImplPtr m_Self
SharedPtr to self, used to keep this object alive as long as the callbacks are coming.
AString m_LocalIP
The IP address of the local endpoint.
cLinkTlsContextWPtr m_Self
Shared ownership of self, so that this object can keep itself alive for as long as it needs...
cLinkTlsContext(cTCPLinkImpl &a_Link)
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.
virtual AString StartTLSClient(cX509CertPtr a_OwnCert, cCryptoKeyPtr a_OwnPrivKey) override
Starts a TLS handshake as a client connection.
AString m_EncryptedData
Buffer for storing the incoming encrypted data until it is requested by the SSL decryptor.
std::shared_ptr< cLinkTlsContext > cLinkTlsContextPtr
static std::shared_ptr< cSslConfig > MakeDefaultConfig(bool a_IsClient)
Creates a new config with some sensible defaults on top of mbedTLS basic settings.
virtual void Close(void) override
Drops the connection without any more processing.
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. ...
static void ReadCallback(bufferevent *a_BufferEvent, void *a_Self)
Callback that LibEvent calls when there's data available from the remote peer.
virtual ~cTCPLinkImpl() override
Destroys the LibEvent handle representing the link.
static bool HostnameToIP(const AString &a_Hostname, cResolveNameCallbacksPtr a_Callbacks)
Queues a DNS query to resolve the specified hostname to IP address.
cCallbacksPtr m_Callbacks
Callbacks to be used for the various situations.
std::shared_ptr< cTCPLinkImpl > cTCPLinkImplPtr
void Send(const void *a_Data, size_t a_Length)
Sends the specified cleartext data over the SSL to the remote peer.
UInt16 m_LocalPort
The port of the local endpoint.
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 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...
void UpdateLocalAddress(void)
Updates m_LocalIP and m_LocalPort based on the metadata read from the socket.
bufferevent * m_BufferEvent
The LibEvent handle representing this connection.
void DoActualShutdown(void)
Calls shutdown on the link and disables LibEvent writing.
AString m_RemoteIP
The IP address of the remote endpoint.
void LOGWARNING(const char *a_Format, fmt::ArgList a_ArgList)
std::shared_ptr< cServerHandleImpl > cServerHandleImplPtr
static void WriteCallback(bufferevent *a_BufferEvent, void *a_Self)
Callback that LibEvent calls when the remote peer can receive more data.
void AddLink(cTCPLinkPtr a_Link)
Adds the specified link to m_Connections.
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.
std::shared_ptr< cCallbacks > cCallbacksPtr
std::weak_ptr< cLinkTlsContext > cLinkTlsContextWPtr
static cNetworkSingleton & Get(void)
Returns the singleton instance of this class.
cLinkTlsContextPtr m_TlsContext
The SSL context used for encryption, if this link uses SSL.
std::shared_ptr< cConnectCallbacks > cConnectCallbacksPtr
Interface that provides the methods available on a single TCP connection.
void Enable(cTCPLinkImplPtr a_Self)
Enables communication over the link.
virtual bool Send(const void *a_Data, size_t a_Length) override
Queues the specified data for sending to the remote peer.
bool SendRaw(const void *a_Data, size_t a_Length)
Sends the data directly to the socket (without the optional TLS).
void SetSelf(cLinkTlsContextWPtr a_Self)
Shares ownership of self, so that this object can keep itself alive for as long as it needs...
virtual int ReceiveEncrypted(unsigned char *a_Buffer, size_t a_NumBytes) override
void ResetSelf(void)
Removes the self ownership so that we can detect the SSL closure.
virtual void Shutdown(void) override
Closes the link gracefully.
AString m_CleartextData
Buffer for storing the outgoing cleartext data until the link has finished handshaking.
UInt16 m_RemotePort
The port of the remote endpoint.
cCallbacksPtr GetCallbacks(void) const
Returns the callbacks that are used.