SecureSocket - Documentation
You can create a TCP socket with the function Create TCP socket
. You must save the socket to a variable to be sure it is not garbage collected:
Before connecting to the server, you should bind the events you plan to use to be sure to not miss one. The available events are the following:
Event Name | Signature | Description |
---|---|---|
OnMessage |
void Func(const TArray<uint8>& Data) |
Called when the server sent us data. |
OnConnected |
void Func() |
Called when the TCP socket is connected to the server. |
OnConnectionError |
void Func() |
Called when the TCP failed to connect to the server. |
OnClosed |
void Func() |
Called when the connection is closed. |
OnUpgradeSuccess |
void Func() |
Called when the connection has been upgraded to SSL/TLS. |
OnUpgradeFailed |
void Func(const FString& Error) |
Called when the connection failed to upgrade to SSL/TLS. |
ℹ️ | Some nodes automatically bind the events they use to an execution pin. |
---|
To easily connect to the server, you can use an helper node that automatically binds the OnConnected
and OnConnectionFailed
events for you:
The same node exists to connect to a server with SSL/TLS:
The Connected
execution pin is called when the connection and the upgrade is over and the socket is ready to communicate trough an SSL/TLS connection.
You can upgrade an unencrypted connection to SSL/TLS at any time with the Upgrade TCP connection to SSL/TLS
node:
You can send binary or string messages easily through your TCP socket:
ℹ️ | When you send a string message, the As ANSI option allows you to choose how the string is converted to binary. If As ANSI is set to true , each character will use 8 bits. If it is set to false each character will use 16 bits. |
---|
You can close the TCP connection at any time with the Close Connection
node:
ℹ️ | When the TCP socket is destroyed, the connection is automatically cleanly closed. |
---|
As for TCP, there is a node to create an UDP socket:
You can send data through your UDP socket with the Send
or Send Binary
nodes. You can use DTLS by setting Use Dtls
to true:
To receive messages, you have to bind the OnMessage
event and add a listening port:
DTLS is used like UDP. When you send a message with Use Dtls
set to true, a DTLS handshake is established with the server and stored in the socket for the specific IP/Port combination. Messages exchanged with this host will then be encrypted and decrypted. You can handle the lifetime of these DTLS sessions with the nodes:
ℹ️ | Setting the auto close delay to a negative number (< 0) disable the delay and the DTLS connection will never be destroyed unless the socket is destroyed or Forget DTLS Connection is called. |
---|
To be able to use Secure Socket in C++, you have to add it to your project's build configuration.
Edit <your_project>/Source/<your_project>/<your_project>.Build.cs
and add:
PrivateDependencyModuleNames.AddRange(new string[] { "SecureSocket" });
For the includes to work with your IDE, you have to regenerate the project's files by right-clicking on <your_project>.uproject and selecting Regenerate <IDE> project files . |
---|
Secure socket has 3 files to include:
#include "TcpSocket.h" // For TCP sockets
#include "UdpSocket.h" // For UDP sockets
#include "SecureSocketLibrary.h" // For MD5, SHA, AES and conversion
UTcpSocket* const TcpSocket = UTcpSocket::CreateTcpSocket();
To handle status change or messages, you must bind UFUNCTION()
functions to the following events:
Event Name | Signature | Description |
---|---|---|
OnMessage |
void Func(const TArray<uint8>& Data) |
Called when the server sent us data. |
OnConnected |
void Func() |
Called when the TCP socket is connected to the server. |
OnConnectionError |
void Func() |
Called when the TCP failed to connect to the server. |
OnClosed |
void Func() |
Called when the connection is closed. |
OnUpgradeSuccess |
void Func() |
Called when the connection has been upgraded to SSL/TLS. |
OnUpgradeFailed |
void Func(const FString& Error) |
Called when the connection failed to upgrade to SSL/TLS. |
As these events are Dynamic Multicast Delegates
, you have to bind them with AddDynamic()
:
TcpSocket->OnMessage .AddDynamic(this, &UMyClass::OnMessageTCP);
TcpSocket->OnConnected .AddDynamic(this, &UMyClass::OnConnectedTCP);
TcpSocket->OnClosed .AddDynamic(this, &UMyClass::OnClosedTCP);
TcpSocket->OnConnectionError.AddDynamic(this, &UMyClass::OnConnectionError);
TcpSocket->OnUpgradeSuccess .AddDynamic(this, &UMyClass::OnConnectionUpgradedTCP);
TcpSocket->OnUpgradeFailed .AddDynamic(this, &UMyClass::OnConnectionUpgradFailedTCP);
To connect, simply call the Connect()
function:
TcpSocket->Connect(TEXT("my.server.com"), 500);
Once your socket is connected, you can upgrade the connection to an encrypted connection with UpgradeToSsl
:
if (TcpSocket->UpgradeToSsl())
{
// We successfully started the handshake procedure.
// Be careful that the connection is still not encrypted here,
// OnUpgradeSuccess will be called when the handshake succeeded
// and you can start sending encrypted data.
}
else
{
// An internal error occurred and the handshake wasn't able to start.
// Additional information is available in the output log.
}
You can downgrade the connection to unencrypted at any time with DowngradeFromSsl()
:
if (TcpSocket->DowngradeFromSsl())
{
// Connection is not encrypted anymore.
}
else
{
// The connection wasn't encrypted.
}
To send data, you have to call the Send()
function. It is overloaded to accept either a const FString&
or a const TArray<uint8>&
:
// You can get it programmatically.
const FString StringData = TEXT("Hello there!");
const TArray<uint8> BinaryData = { 0, 1, 2, 3, 4, 5 };
TcpSocket->Send(StringData, /* bIsAnsi */ true);
TcpSocket->Send(BinaryData);
To cleanly close the connection, call the CloseConnection()
function:
TcpSocket->CloseConnection();
UUdpocket* const UdpSocket = UUdpSocket::CreateUdpSocket();
To send data, you have to call the Send()
function. It is overloaded to accept either a const FString&
or a const TArray<uint8>&
:
const FString ServerAddress = TEXT("my.server.com");
const int32 ServerPort = 501;
const FString StringData = USocketLibrary::MD5_HashString(TEXT("MyPassword"));
const TArray<uint8> BinaryData = { 0, 1, 2, 3, 4, 5}
UdpSocket->Send(ServerAddress, ServerPort, StringData, false /* bIsANSI */, false /* bUseDTLS */);
UdpSocket->Send(ServerAddress, ServerPort, BinaryData, /* bUseDTLS */ false);
To receive messages, you have to listen on a port with SetListeningPort()
and bind a function to the OnMessage
event:
UCLASS()
class MYGAME_API UMyClass : public UObject
{
GENERATED_BODY()
public:
// Called when we receive a message
void OnMessage(const FString& Host, const int32 Port, const TArray<uint8>& Data)
{
const FString StringData = USocketLibrary::ToString_Binary(Data, EStringEncoding::ANSICHAR);
UE_LOG(LogTemp, Log, TEXT("New message from %s:%d: %s."), *Host, Port, *StringData);
}
// Setup UDP receive example
void SetupSocket()
{
UdpSocket->OnMessage.AddDynamic(this, &UMyClass::OnMessage);
UdpSocket->SetListeningPort(502);
}
private:
// Our socket previously created
UPROPERTY()
UUdpSocket* UdpSocket;
};
DTLS is used like UDP. When you send a message with bUseDtls
set to true, a DTLS handshake is established with the server and stored in the socket for the specific IP/Port combination. Messages exchanged with this host will then be encrypted and decrypted. You can handle the lifetime of these DTLS sessions with bool UUdpSocket::ForgetDtlsConnection(const FString & Host, const int32 Port)
and void UUdpSocket::SetDtlsConnectionAutoCloseDelay(const float Delay)
.
ℹ️ | Setting the auto close delay to a negative number (< 0) disable the delay and the DTLS connection will never be destroyed unless the socket is destroyed or ForgetDtlsConnection() is called. |
---|
If you need help, have a feature request, experience troubles or detected a bug, please contact us at [email protected].