Skip to content

3.SSLClient ‐ Server

ReferenceType edited this page Jul 15, 2024 · 2 revisions

Ssl Client / Server

  • Utilizes standard TLS authentication and encryption.
  • Implements a core SSL model for efficient byte data transmission.
  • Optimized for high-traffic scenarios with small messages, where messages are concatenated and sent in batches under load.
  • Capable of handling large file transfers; however, it is recommended to chunk the file rather than sending it in a single operation.
  • Employs memory pooling to significantly reduce GC pressure. Optimized for environments with a high frequency of connection and disconnection events.

Initialization

Ssl requires certificates to work with. In this case you can either load an existing certificate or generate self signed certificate.
Note that certificate generation is not supported on Unity

 var scert = new X509Certificate2("server.pfx", "greenpass");
 var cert = new X509Certificate2("client.pfx", "greenpass");

//using NetworkLibrary.Components.Crypto.Certificate;
 var scert = CertificateGenerator.GenerateSelfSignedCertificate();
 var cert = CertificateGenerator.GenerateSelfSignedCertificate();

To initialise server and you can simply:

 SslServer server = new SslServer(20008,scert);
 server.OnClientAccepted += HandleAccept;
 server.OnClientDisconnected += HandleDisconnect;
 server.OnBytesReceived += ServerBytesReceived;
 server.StartServer();
  SslClient client = new SslClient(cert);
  client.OnDisconnected += HandleDC;
  client.OnBytesReceived += ClientBytesReceived;
  client.Connect("127.0.0.1", 20008);

You can also use empty constructor or pass a null certificate. System will generate self signed certificate.

  SslServer server = new SslServer(20008);
  SslClient client = new SslClient();

Certificate validation is handled with a validation callback which shall return true if the validation is successful. Note that, self signed ceritifactes will generate ssl policy errors.

server.RemoteCertificateValidationCallback += (_, _, _, _) => { return true; };

The Default callback is as follows:

 private bool DefaultValidationCallback(object sender, 
                                        X509Certificate certificate, 
                                        X509Chain chain, 
                                        SslPolicyErrors sslPolicyErrors)
 {
     if (sslPolicyErrors == SslPolicyErrors.None)
         return true;
     return false;
 }

To send data with client:

 byte[] data = new byte[10000];
 client.SendAsync(data);
 client.SendAsync(data, offset:200, count:50);

To send data with server:

 Guid ClientId;
 server.SendAsync(ClientId, data);
 server.SendAsync(ClientId, data, offset:200, count:50);

Where client id comes from on accepted callback.

Send Behavior

Sends never block the caller(until max buffered memory limit is reached). If send operation detects the underlying socket is busy with previous send, it will queue/buffer the messages. Once the send operation is complete socket will check the state of message buffer. if buffer is not empty it will loop for another send. Note that this operation sends entire buffer in bulk, not a single message. This provides great efficiency on small high traffic messages.

Receive behaviour

Receive is an async callback from socket. To keep message consistency, Receive wont be looped until your OnBytesReceived callback returns.
Remember that the buffer you receive on your callback is sockets buffer region, It will be owerwritten on next receive.
If you want to store this bytes, you must do a copy or it will be overwritten on next receive.

Configuration

if you want to limit your max memory you can change:

server.MaxIndexedMemoryPerClient;
client.MaxIndexedMemory;

which will block the traffic once the threashold is reached, until bufferred bytes are cleared.

Important

There is an important configuration you should take into account Which you must set before starting the server:

client.GatherConfig = ScatterGatherConfig.UseQueue;
server.GatherConfig = ScatterGatherConfig.UseBuffer;

Determines whether to use queue or buffer for message gathering mechanism.

UseQueue requires your byte[] sources to be not modified after send. Queue copies the data during the send operation from the array reference.
Hence, your data may be copied asynchronously in separate thread.

UseBuffer will copy your data into a buffer on caller thread immediately. During socket send, a buffer swap will be performed(WriteBuffer and SendBuffer).
This means you can modify or reuse your data safely.

Queue implementation is more efficient and maybe suitable static resources or for short lived disposable data i.e.(Encoding.UTF8.GetBytes(string)).
Buffer provides data safety where your send byte[] or segment can be reused for manipulation, i.e. Streams.

Full example

All examples cam be found on Examples.

 //var scert = new X509Certificate2("server.pfx", "greenpass");
 //var cert = new X509Certificate2("client.pfx", "greenpass");
 var scert = CertificateGenerator.GenerateSelfSignedCertificate();
 var cert = CertificateGenerator.GenerateSelfSignedCertificate();

 SslServer server = new SslServer(20008,scert);
 server.OnBytesReceived += ServerBytesReceived;
 server.RemoteCertificateValidationCallback += (_, _, _, _) => { return true; };
 server.StartServer();

 SslClient client = new SslClient(cert);
 client.OnBytesReceived += ClientBytesReceived;
 client.RemoteCertificateValidationCallback += (_, _, _, _) => { return true; };
 client.Connect("127.0.0.1", 20008);
 client.SendAsync(Encoding.UTF8.GetBytes("Hello I'm a client!"));

 void ServerBytesReceived(Guid clientId, byte[] bytes, int offset, int count)
 {
     Console.WriteLine(Encoding.UTF8.GetString(bytes, offset, count));
     server.SendBytesToClient(clientId, Encoding.UTF8.GetBytes("Hello I'm the server"));
 }

 void ClientBytesReceived(byte[] bytes, int offset, int count)
 {
     Console.WriteLine(Encoding.UTF8.GetString(bytes, offset, count));
 }