Cuberite
A lightweight, fast and extensible game server for Minecraft
TCPLinkImpl.cpp
Go to the documentation of this file.
1 
2 // TCPLinkImpl.cpp
3 
4 // Implements the cTCPLinkImpl class implementing the TCP link functionality
5 
6 #include "Globals.h"
7 #include "TCPLinkImpl.h"
8 #include "../mbedTLS++/SslConfig.h"
9 #include "NetworkSingleton.h"
10 #include "ServerHandleImpl.h"
11 #include "event2/buffer.h"
12 
13 
14 
15 
16 
18 // cTCPLinkImpl:
19 
20 cTCPLinkImpl::cTCPLinkImpl(const std::string & a_Host, cTCPLink::cCallbacksPtr a_LinkCallbacks):
21  Super(std::move(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)),
23  m_LocalPort(0),
24  m_RemoteHost(a_Host),
25  m_RemotePort(0),
26  m_ShouldShutdown(false)
27 {
28 }
29 
30 
31 
32 
33 
35  evutil_socket_t a_Socket,
36  cTCPLink::cCallbacksPtr a_LinkCallbacks,
37  cServerHandleImplPtr a_Server,
38  const sockaddr * a_Address,
39  socklen_t a_AddrLen
40 ):
41  Super(std::move(a_LinkCallbacks)),
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)),
44  m_LocalPort(0),
45  m_RemotePort(0),
46  m_ShouldShutdown(false)
47 {
48  // Update the endpoint addresses:
50  UpdateAddress(a_Address, a_AddrLen, m_RemoteIP, m_RemotePort);
51 }
52 
53 
54 
55 
56 
58 {
59  // If the TLS context still exists, free it:
60  m_TlsContext.reset();
61 
62  bufferevent_free(m_BufferEvent);
63 }
64 
65 
66 
67 
68 
70 {
71  ASSERT(a_LinkCallbacks != nullptr);
72  ASSERT(a_ConnectCallbacks != nullptr);
73 
74  // Create a new link:
75  cTCPLinkImplPtr res{new cTCPLinkImpl(a_Host, std::move(a_LinkCallbacks))}; // Cannot use std::make_shared here, constructor is not accessible
76  res->m_ConnectCallbacks = std::move(a_ConnectCallbacks);
78  res->m_Callbacks->OnLinkCreated(res);
79  res->Enable(res);
80 
81  // Callback to connect after performing lookup:
82  class cHostnameCallback :
84  {
85  cTCPLinkImplPtr m_Link;
86  UInt16 m_Port;
87  bool m_IsConnecting;
88 
89  public:
90 
91  cHostnameCallback(cTCPLinkImplPtr a_Link, UInt16 a_ConnectPort):
92  m_Link(std::move(a_Link)),
93  m_Port(a_ConnectPort),
94  m_IsConnecting(false)
95  {
96  }
97 
98  void DoConnect(const sockaddr * a_IP, int size)
99  {
100  // Make sure connect is only completed once
101  if (!m_IsConnecting)
102  {
103  int ErrCode = bufferevent_socket_connect(m_Link->m_BufferEvent, a_IP, size);
104  if (ErrCode == 0)
105  {
106  m_IsConnecting = true;
107  }
108  else
109  {
110  m_Link->GetCallbacks()->OnError(ErrCode, evutil_socket_error_to_string(ErrCode));
111  }
112  }
113  }
114 
115  virtual bool OnNameResolvedV4(const AString & a_Name, const sockaddr_in * a_IP) override
116  {
117  sockaddr_in Addr = *a_IP;
118  Addr.sin_port = htons(m_Port);
119  DoConnect(reinterpret_cast<const sockaddr *>(&Addr), sizeof(Addr));
120  return false; // Don't care about recieving ip as string
121  }
122 
123  virtual bool OnNameResolvedV6(const AString & a_Name, const sockaddr_in6 * a_IP) override
124  {
125  sockaddr_in6 Addr = *a_IP;
126  Addr.sin6_port = htons(m_Port);
127  DoConnect(reinterpret_cast<const sockaddr *>(&Addr), sizeof(Addr));
128  return false; // Don't care about recieving ip as string
129  }
130 
131  virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override
132  {
133  m_Link->GetCallbacks()->OnError(a_ErrorCode, a_ErrorMsg);
134  cNetworkSingleton::Get().RemoveLink(m_Link.get());
135  }
136 
137  // Don't need to do anything for these
138  virtual void OnFinished() override
139  {
140  }
141 
142  virtual void OnNameResolved(const AString & a_Name, const AString & a_IP) override
143  {
144  }
145  };
146 
147  // Schedule the host query
148  cNetwork::HostnameToIP(a_Host, std::make_shared<cHostnameCallback>(res, a_Port));
149  return res;
150 }
151 
152 
153 
154 
155 
157 {
158  // Take hold of a shared copy of self, to keep as long as the callbacks are coming:
159  m_Self = std::move(a_Self);
160 
161  // Set the LibEvent callbacks and enable processing:
162  bufferevent_setcb(m_BufferEvent, ReadCallback, WriteCallback, EventCallback, this);
163  bufferevent_enable(m_BufferEvent, EV_READ | EV_WRITE);
164 }
165 
166 
167 
168 
169 
170 bool cTCPLinkImpl::Send(const void * a_Data, size_t a_Length)
171 {
172  if (m_ShouldShutdown)
173  {
174  LOGD("%s: Cannot send data, the link is already shut down.", __FUNCTION__);
175  return false;
176  }
177 
178  // If running in TLS mode, push the data into the TLS context instead:
179  if (m_TlsContext != nullptr)
180  {
181  m_TlsContext->Send(a_Data, a_Length);
182  return true;
183  }
184 
185  // Send the data:
186  return SendRaw(a_Data, a_Length);
187 }
188 
189 
190 
191 
192 
194 {
195  // If running in TLS mode, notify the TLS layer:
196  if (m_TlsContext != nullptr)
197  {
198  m_TlsContext->NotifyClose();
199  m_TlsContext->ResetSelf();
200  m_TlsContext.reset();
201  }
202 
203  // If there's no outgoing data, shutdown the socket directly:
204  if (evbuffer_get_length(bufferevent_get_output(m_BufferEvent)) == 0)
205  {
207  return;
208  }
209 
210  // There's still outgoing data in the LibEvent buffer, schedule a shutdown when it's written to OS's TCP stack:
211  m_ShouldShutdown = true;
212 }
213 
214 
215 
216 
217 
219 {
220  // If running in TLS mode, notify the TLS layer:
221  if (m_TlsContext != nullptr)
222  {
223  m_TlsContext->NotifyClose();
224  m_TlsContext->ResetSelf();
225  m_TlsContext.reset();
226  }
227 
228  // Disable all events on the socket, but keep it alive:
229  bufferevent_disable(m_BufferEvent, EV_READ | EV_WRITE);
230  if (m_Server == nullptr)
231  {
233  }
234  else
235  {
236  m_Server->RemoveLink(this);
237  }
238  m_Self.reset();
239 }
240 
241 
242 
243 
244 
246  cX509CertPtr a_OwnCert,
247  cCryptoKeyPtr a_OwnPrivKey,
248  cX509CertPtr a_TrustedRootCAs
249 )
250 {
251  // Check preconditions:
252  if (m_TlsContext != nullptr)
253  {
254  return "TLS is already active on this link";
255  }
256  if ((a_OwnCert == nullptr) != (a_OwnPrivKey == nullptr))
257  {
258  return "Either provide both the certificate and private key, or neither";
259  }
260 
261  // Create the TLS context:
262  m_TlsContext = std::make_shared<cLinkTlsContext>(*this);
263  if ((a_OwnCert == nullptr) && (a_TrustedRootCAs == nullptr))
264  {
265  // Use the (shared) default TLS config
266  m_TlsContext->Initialize(true);
267  }
268  else
269  {
270  // Need a specialized config for the own certificate / trusted root CAs:
271  auto Config = cSslConfig::MakeDefaultConfig(true);
272  if (a_OwnCert != nullptr)
273  {
274  Config->SetOwnCert(std::move(a_OwnCert), std::move(a_OwnPrivKey));
275  }
276  if (a_TrustedRootCAs != nullptr)
277  {
278  Config->SetAuthMode(eSslAuthMode::Required);
279  Config->SetCACerts(std::move(a_TrustedRootCAs));
280  }
281  m_TlsContext->Initialize(Config);
282  }
283 
284  // Enable SNI / peer name verification:
285  if (!m_RemoteHost.empty())
286  {
287  m_TlsContext->SetExpectedPeerName(m_RemoteHost);
288  }
289 
291 
292  // Start the handshake:
293  m_TlsContext->Handshake();
294  return {};
295 }
296 
297 
298 
299 
300 
302  cX509CertPtr a_OwnCert,
303  cCryptoKeyPtr a_OwnPrivKey,
304  const AString & a_StartTLSData
305 )
306 {
307  // Check preconditions:
308  if (m_TlsContext != nullptr)
309  {
310  return "TLS is already active on this link";
311  }
312  if ((a_OwnCert == nullptr) || (a_OwnPrivKey == nullptr))
313  {
314  return "Provide the server certificate and private key";
315  }
316 
317  // Create the TLS context:
318  m_TlsContext = std::make_shared<cLinkTlsContext>(*this);
319  {
320  auto Config = cSslConfig::MakeDefaultConfig(false);
321  Config->SetOwnCert(a_OwnCert, a_OwnPrivKey);
322  m_TlsContext->Initialize(std::move(Config));
323  }
325 
326  // Push the initial data:
327  m_TlsContext->StoreReceivedData(a_StartTLSData.data(), a_StartTLSData.size());
328 
329  // Start the handshake:
330  m_TlsContext->Handshake();
331  return {};
332 }
333 
334 
335 
336 
337 
338 void cTCPLinkImpl::ReadCallback(bufferevent * a_BufferEvent, void * a_Self)
339 {
340  ASSERT(a_Self != nullptr);
341  cTCPLinkImpl * Self = static_cast<cTCPLinkImpl *>(a_Self);
342  ASSERT(Self->m_BufferEvent == a_BufferEvent);
343  ASSERT(Self->m_Callbacks != nullptr);
344 
345  // Read all the incoming data, in 1024-byte chunks:
346  char data[1024];
347  size_t length;
348  auto tlsContext = Self->m_TlsContext;
349  while ((length = bufferevent_read(a_BufferEvent, data, sizeof(data))) > 0)
350  {
351  if (tlsContext != nullptr)
352  {
353  ASSERT(tlsContext->IsLink(Self));
354  tlsContext->StoreReceivedData(data, length);
355  }
356  else
357  {
358  Self->ReceivedCleartextData(data, length);
359  }
360  }
361 }
362 
363 
364 
365 
366 
367 void cTCPLinkImpl::WriteCallback(bufferevent * a_BufferEvent, void * a_Self)
368 {
369  ASSERT(a_Self != nullptr);
370  auto Self = static_cast<cTCPLinkImpl *>(a_Self);
371  ASSERT(Self->m_Callbacks != nullptr);
372 
373  // If there's no more data to write and the link has been scheduled for shutdown, do the shutdown:
374  auto OutLen = evbuffer_get_length(bufferevent_get_output(Self->m_BufferEvent));
375  if ((OutLen == 0) && (Self->m_ShouldShutdown))
376  {
377  Self->DoActualShutdown();
378  }
379 }
380 
381 
382 
383 
384 
385 void cTCPLinkImpl::EventCallback(bufferevent * a_BufferEvent, short a_What, void * a_Self)
386 {
387  ASSERT(a_Self != nullptr);
388  cTCPLinkImplPtr Self = static_cast<cTCPLinkImpl *>(a_Self)->m_Self;
389  if (Self == nullptr)
390  {
391  // The link has already been freed
392  return;
393  }
394 
395  // If an error is reported, call the error callback:
396  if (a_What & BEV_EVENT_ERROR)
397  {
398  // Choose the proper callback to call based on whether we were waiting for connection or not:
399  int err = EVUTIL_SOCKET_ERROR();
400  if (Self->m_ConnectCallbacks != nullptr)
401  {
402  if (err == 0)
403  {
404  // This could be a DNS failure
405  err = bufferevent_socket_get_dns_error(a_BufferEvent);
406  }
407  Self->m_ConnectCallbacks->OnError(err, evutil_socket_error_to_string(err));
408  }
409  else
410  {
411  Self->m_Callbacks->OnError(err, evutil_socket_error_to_string(err));
412  if (Self->m_Server == nullptr)
413  {
414  cNetworkSingleton::Get().RemoveLink(Self.get());
415  }
416  else
417  {
418  Self->m_Server->RemoveLink(Self.get());
419  }
420  }
421  Self->m_Self.reset();
422  return;
423  }
424 
425  // Pending connection succeeded, call the connection callback:
426  if (a_What & BEV_EVENT_CONNECTED)
427  {
428  Self->UpdateLocalAddress();
429  Self->UpdateRemoteAddress();
430  if (Self->m_ConnectCallbacks != nullptr)
431  {
432  Self->m_ConnectCallbacks->OnConnected(*Self);
433  // Reset the connect callbacks so that later errors get reported through the link callbacks:
434  Self->m_ConnectCallbacks.reset();
435  return;
436  }
437  }
438 
439  // If the connection has been closed, call the link callback and remove the connection:
440  if (a_What & BEV_EVENT_EOF)
441  {
442  // If running in TLS mode and there's data left in the TLS contect, report it:
443  auto tlsContext = Self->m_TlsContext;
444  if (tlsContext != nullptr)
445  {
446  tlsContext->FlushBuffers();
447  }
448 
449  Self->m_Callbacks->OnRemoteClosed();
450  if (Self->m_Server != nullptr)
451  {
452  Self->m_Server->RemoveLink(Self.get());
453  }
454  else
455  {
456  cNetworkSingleton::Get().RemoveLink(Self.get());
457  }
458  Self->m_Self.reset();
459  return;
460  }
461 
462  // Unknown event, report it:
463  LOGWARNING("cTCPLinkImpl: Unhandled LibEvent event %d (0x%x)", a_What, a_What);
464  ASSERT(!"cTCPLinkImpl: Unhandled LibEvent event");
465 }
466 
467 
468 
469 
470 
471 void cTCPLinkImpl::UpdateAddress(const sockaddr * a_Address, socklen_t a_AddrLen, AString & a_IP, UInt16 & a_Port)
472 {
473  // Based on the family specified in the address, use the correct datastructure to convert to IP string:
474  char IP[128];
475  switch (a_Address->sa_family)
476  {
477  case AF_INET: // IPv4:
478  {
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);
482  break;
483  }
484  case AF_INET6: // IPv6
485  {
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);
489  break;
490  }
491 
492  default:
493  {
494  LOGWARNING("%s: Unknown socket address family: %d", __FUNCTION__, a_Address->sa_family);
495  ASSERT(!"Unknown socket address family");
496  break;
497  }
498  }
499  a_IP.assign(IP);
500 }
501 
502 
503 
504 
505 
507 {
508  sockaddr_storage sa;
509  socklen_t salen = static_cast<socklen_t>(sizeof(sa));
510  getsockname(bufferevent_getfd(m_BufferEvent), reinterpret_cast<sockaddr *>(&sa), &salen);
511  UpdateAddress(reinterpret_cast<const sockaddr *>(&sa), salen, m_LocalIP, m_LocalPort);
512 }
513 
514 
515 
516 
517 
519 {
520  sockaddr_storage sa;
521  socklen_t salen = static_cast<socklen_t>(sizeof(sa));
522  getpeername(bufferevent_getfd(m_BufferEvent), reinterpret_cast<sockaddr *>(&sa), &salen);
523  UpdateAddress(reinterpret_cast<const sockaddr *>(&sa), salen, m_RemoteIP, m_RemotePort);
524 }
525 
526 
527 
528 
529 
531 {
532  #ifdef _WIN32
533  shutdown(bufferevent_getfd(m_BufferEvent), SD_SEND);
534  #else
535  shutdown(bufferevent_getfd(m_BufferEvent), SHUT_WR);
536  #endif
537  bufferevent_disable(m_BufferEvent, EV_WRITE);
538 }
539 
540 
541 
542 
543 
544 bool cTCPLinkImpl::SendRaw(const void * a_Data, size_t a_Length)
545 {
546  return (bufferevent_write(m_BufferEvent, a_Data, a_Length) == 0);
547 }
548 
549 
550 
551 
552 
553 void cTCPLinkImpl::ReceivedCleartextData(const char * a_Data, size_t a_Length)
554 {
555  ASSERT(m_Callbacks != nullptr);
556  m_Callbacks->OnReceivedData(a_Data, a_Length);
557 }
558 
559 
560 
561 
562 
564 // cTCPLinkImpl::cLinkTlsContext:
565 
567  m_Link(a_Link)
568 {
569 }
570 
571 
572 
573 
574 
576 {
577  m_Self = std::move(a_Self);
578 }
579 
580 
581 
582 
583 
585 {
586  m_Self.reset();
587 }
588 
589 
590 
591 
592 
593 void cTCPLinkImpl::cLinkTlsContext::StoreReceivedData(const char * a_Data, size_t a_NumBytes)
594 {
595  // Hold self alive for the duration of this function
597 
598  m_EncryptedData.append(a_Data, a_NumBytes);
599 
600  // Try to finish a pending handshake:
601  TryFinishHandshaking();
602 
603  // Flush any cleartext data that can be "received":
604  FlushBuffers();
605 }
606 
607 
608 
609 
610 
612 {
613  // Hold self alive for the duration of this function
615 
616  // If the handshake didn't complete yet, bail out:
617  if (!HasHandshaken())
618  {
619  return;
620  }
621 
622  char Buffer[1024];
623  int NumBytes;
624  while ((NumBytes = ReadPlain(Buffer, sizeof(Buffer))) > 0)
625  {
626  m_Link.ReceivedCleartextData(Buffer, static_cast<size_t>(NumBytes));
627  if (m_Self.expired())
628  {
629  // The callback closed the SSL context, bail out
630  return;
631  }
632  }
633 }
634 
635 
636 
637 
638 
640 {
641  // Hold self alive for the duration of this function
643 
644  // If the handshake hasn't finished yet, retry:
645  if (!HasHandshaken())
646  {
647  Handshake();
648  // If the handshake succeeded, write all the queued plaintext data:
649  if (HasHandshaken())
650  {
651  m_Link.GetCallbacks()->OnTlsHandshakeCompleted();
652  WritePlain(m_CleartextData.data(), m_CleartextData.size());
653  m_CleartextData.clear();
654  }
655  }
656 }
657 
658 
659 
660 
661 
662 void cTCPLinkImpl::cLinkTlsContext::Send(const void * a_Data, size_t a_Length)
663 {
664  // Hold self alive for the duration of this function
666 
667  // If the handshake hasn't completed yet, queue the data:
668  if (!HasHandshaken())
669  {
670  m_CleartextData.append(reinterpret_cast<const char *>(a_Data), a_Length);
671  TryFinishHandshaking();
672  return;
673  }
674 
675  // The connection is all set up, write the cleartext data into the SSL context:
676  WritePlain(a_Data, a_Length);
677  FlushBuffers();
678 }
679 
680 
681 
682 
683 
684 int cTCPLinkImpl::cLinkTlsContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
685 {
686  // Hold self alive for the duration of this function
688 
689  // If there's nothing queued in the buffer, report empty buffer:
690  if (m_EncryptedData.empty())
691  {
692  return MBEDTLS_ERR_SSL_WANT_READ;
693  }
694 
695  // Copy as much data as possible to the provided buffer:
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);
700 }
701 
702 
703 
704 
705 
706 int cTCPLinkImpl::cLinkTlsContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes)
707 {
708  m_Link.SendRaw(a_Buffer, a_NumBytes);
709  return static_cast<int>(a_NumBytes);
710 }
711 
712 
713 
714 
715 
717 // cNetwork API:
718 
720  const AString & a_Host,
721  UInt16 a_Port,
722  cNetwork::cConnectCallbacksPtr a_ConnectCallbacks,
723  cTCPLink::cCallbacksPtr a_LinkCallbacks
724 )
725 {
726  // Add a connection request to the queue:
727  cTCPLinkImplPtr Conn = cTCPLinkImpl::Connect(a_Host, a_Port, std::move(a_LinkCallbacks), std::move(a_ConnectCallbacks));
728  return (Conn != nullptr);
729 }
730 
731 
732 
733 
734 
#define ASSERT(x)
Definition: Globals.h:276
unsigned short UInt16
Definition: Globals.h:158
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
#define LOGD
Definition: LoggerSimple.h:83
std::shared_ptr< cCryptoKey > cCryptoKeyPtr
Definition: CryptoKey.h:72
std::shared_ptr< cX509Cert > cX509CertPtr
Definition: SslConfig.h:13
std::shared_ptr< cTCPLinkImpl > cTCPLinkImplPtr
std::shared_ptr< cServerHandleImpl > cServerHandleImplPtr
std::string AString
Definition: StringUtils.h:11
Definition: FastNBT.h:132
static std::shared_ptr< cSslConfig > MakeDefaultConfig(bool a_IsClient)
Creates a new config with some sensible defaults on top of mbedTLS basic settings.
Definition: SslConfig.cpp:226
Interface that provides the methods available on a single TCP connection.
Definition: Network.h:42
cCallbacksPtr m_Callbacks
Callbacks to be used for the various situations.
Definition: Network.h:139
std::shared_ptr< cCallbacks > cCallbacksPtr
Definition: Network.h:71
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
Definition: Network.h:249
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.
Definition: Network.h:278
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.
Definition: TCPLinkImpl.h:178
virtual ~cTCPLinkImpl() override
Destroys the LibEvent handle representing the link.
Definition: TCPLinkImpl.cpp:57
cLinkTlsContextPtr m_TlsContext
The SSL context used for encryption, if this link uses SSL.
Definition: TCPLinkImpl.h:182
bufferevent * m_BufferEvent
The LibEvent handle representing this connection.
Definition: TCPLinkImpl.h:149
AString m_LocalIP
The IP address of the local endpoint.
Definition: TCPLinkImpl.h:156
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.
Definition: TCPLinkImpl.h:159
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.
Definition: TCPLinkImpl.cpp:69
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.
Definition: TCPLinkImpl.cpp:34
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.
Definition: TCPLinkImpl.h:169
std::shared_ptr< cLinkTlsContext > cLinkTlsContextPtr
Definition: TCPLinkImpl.h:90
AString m_RemoteHost
The original host parameter which was used for creating the link, either hostname or IP address.
Definition: TCPLinkImpl.h:163
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.
Definition: TCPLinkImpl.h:153
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
Definition: TCPLinkImpl.h:92
AString m_RemoteIP
The IP address of the remote endpoint.
Definition: TCPLinkImpl.h:166
cTCPLinkImplPtr m_Self
SharedPtr to self, used to keep this object alive as long as the callbacks are coming.
Definition: TCPLinkImpl.h:173
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.