IntermediateLayer

The IntermediateLayer is a pass-through for data in and out. This feature can be used to encrypt data, inject headers, and more.

Using the IntermediateLayer is simple as overriding two methods, one for when data is sent and one for when data is received.

Below is an example included with FishNet which demonstrates using a Caesar cipher to encrypt data.

You can find this example in the Demos folder, file name IntermediateLayerCipher.cs.

using FishNet.Managing.Transporting;
using System;

namespace FishNet.Example.IntermediateLayers
{
    /* Below is an example of creating a basic Caesar Cipher.
     * Bytes are modified by a set value of CIPHER_KEY, and then
     * the original src ArraySegment is returned.
     * 
     * It's very important to only iterate the bytes provided
     * as the segment. For example, if the ArraySegment contains
     * 1000 bytes but the Offset is 3 and Count is 5 then you should
     * only iterate bytes on index 3, 4, 5, 6, 7. The code below
     * shows one way of properly doing so.
     * 
     * If you are to change the byte array reference, size, or segment
     * count be sure to return a new ArraySegment with the new values.
     * For example, if your Offset was 0 and count was 10 but after
     * encrypting data the Offset was still 0 and count 15 you would
     * return new ArraySegment<byte>(theArray, 0, 15); */
    public class IntermediateLayerCipher : IntermediateLayer
    {
        private const byte CIPHER_KEY = 5;
        //Decipher incoming data.
        public override ArraySegment<byte> HandleIncoming(ArraySegment<byte> src, bool fromServer)
        {
            byte[] arr = src.Array;
            int length = src.Count;
            int offset = src.Offset;

            for (int i = src.Offset; i < (offset + length); i++)
            {
                short next = (short)(arr[i] - CIPHER_KEY);
                if (next < 0)
                    next += 256;
                arr[i] = (byte)next;
            }

            return src;
        }
        //Cipher outgoing data.
        public override ArraySegment<byte> HandleOutgoing(ArraySegment<byte> src, bool toServer)
        {
            byte[] arr = src.Array;
            int length = src.Count;
            int offset = src.Offset;

            for (int i = offset; i < (offset + length); i++)
            {
                short next = (short)(arr[i] + CIPHER_KEY);
                if (next > byte.MaxValue)
                    next -= 256;
                arr[i] = (byte)next;
            }

            return src;
        }

    }
}

In some cases you may need to inject headers into data sent, such as if you are validating each packet with an authorization key.

If such is the case it may be wise to reserve a number of bytes needed for your header. You can do this by calling SetMTUReserve() on your TransportManager. Here is an example of doing such.

public class MyIntermediateLayer : IntermediateLayer
{
    public override void InitializeOnce(TransportManager manager)
    {
        base.InitializeOnce(manager);
        const int bytesForMyHeader = 10;
        manager.SetMTUReserve(bytesForMyHeader);
    }
    //...rest omitted

Last updated