Пример #1
0
        public static void HandleKerbalsRequest(ClientStructure client)
        {
            var kerbalFiles = FileHandler.GetFilesInPath(KerbalsPath);
            var kerbalsData = kerbalFiles.Select(k =>
            {
                var kerbalData = FileHandler.ReadFile(k);
                return(new KerbalInfo
                {
                    KerbalData = kerbalData,
                    NumBytes = kerbalData.Length,
                    KerbalName = Path.GetFileNameWithoutExtension(k)
                });
            });

            LunaLog.Debug($"Sending {client.PlayerName} {kerbalFiles.Length} kerbals...");

            var msgData = ServerContext.ServerMessageFactory.CreateNewMessageData <KerbalReplyMsgData>();

            msgData.Kerbals      = kerbalsData.ToArray();
            msgData.KerbalsCount = msgData.Kerbals.Length;

            MessageQueuer.SendToClient <KerbalSrvMsg>(client, msgData);
        }
Пример #2
0
        private static void HandleVesselCouple(ClientStructure client, VesselBaseMsgData message)
        {
            var msgData = (VesselCoupleMsgData)message;

            LunaLog.Debug($"Coupling message received! Dominant vessel: {msgData.VesselId}");
            MessageQueuer.RelayMessage <VesselSrvMsg>(client, msgData);

            if (VesselContext.RemovedVessels.Contains(msgData.CoupledVesselId))
            {
                return;
            }

            //Now remove the weak vessel but DO NOT add to the removed vessels as they might undock!!!
            LunaLog.Debug($"Removing weak coupled vessel {msgData.CoupledVesselId}");
            VesselStoreSystem.RemoveVessel(msgData.CoupledVesselId);

            //Tell all clients to remove the weak vessel
            var removeMsgData = ServerContext.ServerMessageFactory.CreateNewMessageData <VesselRemoveMsgData>();

            removeMsgData.VesselId = msgData.CoupledVesselId;

            MessageQueuer.SendToAllClients <VesselSrvMsg>(removeMsgData);
        }
Пример #3
0
        private static void HandleVesselRemove(ClientStructure client, VesselBaseMsgData message)
        {
            var data = (VesselRemoveMsgData)message;

            if (LockSystem.LockQuery.ControlLockExists(data.VesselId) && !LockSystem.LockQuery.ControlLockBelongsToPlayer(data.VesselId, client.PlayerName))
            {
                return;
            }

            if (VesselStoreSystem.VesselExists(data.VesselId))
            {
                LunaLog.Debug($"Removing vessel {data.VesselId} from {client.PlayerName}");
                VesselStoreSystem.RemoveVessel(data.VesselId);
            }

            if (data.AddToKillList)
            {
                VesselContext.RemovedVessels.Add(data.VesselId);
            }

            //Relay the message.
            MessageQueuer.RelayMessage <VesselSrvMsg>(client, data);
        }
Пример #4
0
        public override void HandleCommand(string commandArgs)
        {
            CommandSystemHelperMethods.SplitCommand(commandArgs, out var func, out var playerName);

            switch (func)
            {
            default:
                LunaLog.Debug("Undefined function. Usage: /whitelist [add|del] playername or /whitelist show");
                break;

            case "add":
                WhitelistAddCommand.Add(playerName);
                break;

            case "del":
                WhitelistRemoveCommand.Remove(playerName);
                break;

            case "show":
                WhitelistShowCommand.Retrieve();
                break;
            }
        }
Пример #5
0
        private static void HandleVesselProto(ClientStructure client, VesselBaseMsgData message)
        {
            var msgData = (VesselProtoMsgData)message;

            if (VesselContext.RemovedVessels.Contains(msgData.VesselId))
            {
                return;
            }

            if (msgData.NumBytes == 0)
            {
                LunaLog.Warning($"Received a vessel with 0 bytes ({msgData.VesselId}) from {client.PlayerName}.");
                return;
            }

            if (!VesselStoreSystem.VesselExists(msgData.VesselId))
            {
                LunaLog.Debug($"Saving vessel {msgData.VesselId} from {client.PlayerName}. Bytes: {msgData.NumBytes}");
            }

            VesselDataUpdater.RawConfigNodeInsertOrUpdate(msgData.VesselId, Encoding.UTF8.GetString(msgData.Data, 0, msgData.NumBytes));
            MessageQueuer.RelayMessage <VesselSrvMsg>(client, msgData);
        }
Пример #6
0
        public void HandleNewSubspace(ClientStructure client, WarpNewSubspaceMsgData message)
        {
            if (message.PlayerCreator != client.PlayerName)
            {
                return;
            }

            LunaLog.Debug($"{client.PlayerName} created a new subspace. Id {WarpContext.NextSubspaceId}");

            //Create Subspace
            WarpContext.Subspaces.TryAdd(WarpContext.NextSubspaceId, message.ServerTimeDifference);
            VesselRelaySystem.CreateNewSubspace(WarpContext.NextSubspaceId);

            //Tell all Clients about the new Subspace
            var msgData = ServerContext.ServerMessageFactory.CreateNewMessageData <WarpNewSubspaceMsgData>();

            msgData.ServerTimeDifference = message.ServerTimeDifference;
            msgData.PlayerCreator        = message.PlayerCreator;
            msgData.SubspaceKey          = WarpContext.NextSubspaceId;

            MessageQueuer.SendToAllClients <WarpSrvMsg>(msgData);
            WarpContext.NextSubspaceId++;
        }
Пример #7
0
        public override void HandleMessage(ClientStructure client, IMessageData messageData)
        {
            var message = messageData as KerbalBaseMsgData;

            switch (message?.KerbalMessageType)
            {
            case KerbalMessageType.REQUEST:
                var kerbalFiles = FileHandler.GetFilesInPath(Path.Combine(ServerContext.UniverseDirectory, "Kerbals"));
                var kerbalsData = kerbalFiles.Select(k => new KeyValuePair <string, byte[]>(Path.GetFileNameWithoutExtension(k),
                                                                                            FileHandler.ReadFile(k)));

                LunaLog.Debug($"Sending {client.PlayerName} {kerbalFiles.Length} kerbals...");

                var newMessageData = new KerbalReplyMsgData
                {
                    KerbalsData = kerbalsData.ToArray()
                };

                MessageQueuer.SendToClient <KerbalSrvMsg>(client, newMessageData);
                break;

            case KerbalMessageType.PROTO:
                var data = (KerbalProtoMsgData)message;

                LunaLog.Debug($"Saving kerbal {data.KerbalName} from {client.PlayerName}");

                var path = Path.Combine(ServerContext.UniverseDirectory, "Kerbals", data.KerbalName + ".txt");
                FileHandler.WriteToFile(path, data.KerbalData);

                MessageQueuer.RelayMessage <KerbalSrvMsg>(client, data);
                break;

            default:
                throw new NotImplementedException("Kerbal type not implemented");
            }
        }
Пример #8
0
        public void HandleChangeSubspace(ClientStructure client, WarpChangeSubspaceMsgData message)
        {
            if (message.PlayerName != client.PlayerName)
            {
                return;
            }

            var oldSubspace = client.Subspace;
            var newSubspace = message.Subspace;

            if (oldSubspace != newSubspace)
            {
                if (newSubspace < 0)
                {
                    LunaLog.Debug($"{client.PlayerName} is warping");
                }
                else if (WarpContext.Subspaces[newSubspace].Creator != client.PlayerName)
                {
                    LunaLog.Debug($"{client.PlayerName} synced with subspace '{message.Subspace}' created by {WarpContext.Subspaces[newSubspace].Creator}");
                }

                var msgData = ServerContext.ServerMessageFactory.CreateNewMessageData <WarpChangeSubspaceMsgData>();
                msgData.PlayerName = client.PlayerName;
                msgData.Subspace   = message.Subspace;

                MessageQueuer.RelayMessage <WarpSrvMsg>(client, msgData);

                if (newSubspace != -1)
                {
                    client.Subspace = newSubspace;

                    //Try to remove his old subspace
                    WarpSystem.RemoveSubspace(oldSubspace);
                }
            }
        }
Пример #9
0
        public static bool RemoveSubspace(int subspaceToRemove)
        {
            //Do not remove the subspace if there are clients there
            if (ServerContext.Clients.Any(c => c.Value.Subspace == subspaceToRemove))
            {
                return(false);
            }

            //If there's only 1 subspace do not remove it!
            if (WarpContext.Subspaces.Count == 1)
            {
                return(false);
            }

            //We are in the latest subspace and we NEVER remove it!
            if (subspaceToRemove == WarpContext.LatestSubspace.Id)
            {
                return(false);
            }

            LunaLog.Debug($"Removing abandoned subspace '{subspaceToRemove}'");
            WarpContext.Subspaces.TryRemove(subspaceToRemove, out _);
            return(true);
        }
Пример #10
0
        public static void HandleListFlagMessage(ClientStructure client, FlagListMsgData message)
        {
            //Send the list back
            var serverFlagFileNames = new List <string>();
            var serverFlagOwners    = new List <string>();
            var serverFlagShaSums   = new List <string>();
            var serverFlags         = FileHandler.GetFilesInPath(FlagPath, SearchOption.AllDirectories);

            foreach (var serverFlag in serverFlags)
            {
                var trimmedName   = Path.GetFileName(serverFlag);
                var flagOwnerPath = Path.GetDirectoryName(serverFlag);

                var flagOwner    = flagOwnerPath.Substring(Path.GetDirectoryName(flagOwnerPath).Length + 1);
                var isMatched    = false;
                var shaDifferent = false;
                for (var i = 0; i < message.FlagFileNames.Length; i++)
                {
                    if (message.FlagFileNames[i].ToLower() == trimmedName.ToLower())
                    {
                        isMatched    = true;
                        shaDifferent = Common.CalculateSha256Hash(serverFlag) != message.FlagShaSums[i];
                    }
                }
                if (!isMatched || shaDifferent)
                {
                    if (flagOwner == client.PlayerName)
                    {
                        LunaLog.Debug("Deleting flag " + trimmedName);
                        FileHandler.FileDelete(serverFlag);

                        MessageQueuer.RelayMessage <FlagSrvMsg>(client,
                                                                new FlagDeleteMsgData {
                            FlagName = trimmedName
                        });

                        if (FileHandler.GetFilesInPath(flagOwnerPath).Length == 0)
                        {
                            FileHandler.FolderDelete(flagOwnerPath);
                        }
                    }
                    else
                    {
                        LunaLog.Debug($"Sending flag {serverFlag} from {flagOwner} to {client.PlayerName}");

                        var newMessageData = new FlagDataMsgData
                        {
                            FlagName        = trimmedName,
                            OwnerPlayerName = flagOwner,
                            FlagData        = FileHandler.ReadFile(serverFlag)
                        };

                        MessageQueuer.SendToClient <FlagSrvMsg>(client, newMessageData);
                    }
                }
                //Don't tell the client we have a different copy of the flag so it is reuploaded
                if (FileHandler.FileExists(serverFlag))
                {
                    serverFlagFileNames.Add(trimmedName);
                    serverFlagOwners.Add(flagOwner);
                    serverFlagShaSums.Add(Common.CalculateSha256Hash(serverFlag));
                }
            }

            var listMessageData = new FlagListMsgData
            {
                FlagFileNames = serverFlagFileNames.ToArray(),
                FlagOwners    = serverFlagOwners.ToArray(),
                FlagShaSums   = serverFlagShaSums.ToArray()
            };

            MessageQueuer.SendToClient <FlagSrvMsg>(client, listMessageData);
        }
Пример #11
0
        public static async void StartReceiveingMessages()
        {
            try
            {
                while (ServerContext.ServerRunning)
                {
                    var msg = Server.ReadMessage();
                    if (msg != null)
                    {
                        var client = TryGetClient(msg);
                        switch (msg.MessageType)
                        {
                        case NetIncomingMessageType.ConnectionApproval:
                            if (ServerContext.UsePassword)
                            {
                                var password = msg.ReadString();
                                if (password != GeneralSettings.SettingsStore.Password)
                                {
                                    msg.SenderConnection.Deny("Invalid password");
                                    break;
                                }
                            }
                            msg.SenderConnection.Approve();
                            break;

                        case NetIncomingMessageType.Data:
                            ClientMessageReceiver.ReceiveCallback(client, msg);
                            break;

                        case NetIncomingMessageType.WarningMessage:
                            LunaLog.Warning(msg.ReadString());
                            break;

                        case NetIncomingMessageType.DebugMessage:
                            LunaLog.NetworkDebug(msg.ReadString());
                            break;

                        case NetIncomingMessageType.ConnectionLatencyUpdated:
                        case NetIncomingMessageType.VerboseDebugMessage:
                            LunaLog.NetworkVerboseDebug(msg.ReadString());
                            break;

                        case NetIncomingMessageType.Error:
                            LunaLog.Error(msg.ReadString());
                            break;

                        case NetIncomingMessageType.StatusChanged:
                            switch ((NetConnectionStatus)msg.ReadByte())
                            {
                            case NetConnectionStatus.Connected:
                                var endpoint = msg.SenderConnection.RemoteEndPoint;
                                LunaLog.Normal($"New client Connection from {endpoint.Address}:{endpoint.Port}");
                                ClientConnectionHandler.ConnectClient(msg.SenderConnection);
                                break;

                            case NetConnectionStatus.Disconnected:
                                var reason = msg.ReadString();
                                if (client != null)
                                {
                                    ClientConnectionHandler.DisconnectClient(client, reason);
                                }
                                break;
                            }
                            break;

                        default:
                            var details = msg.PeekString();
                            LunaLog.Debug($"Lidgren: {msg.MessageType.ToString().ToUpper()} -- {details}");
                            break;
                        }
                    }
                    else
                    {
                        await Task.Delay(IntervalSettings.SettingsStore.SendReceiveThreadTickMs);
                    }
                }
            }
            catch (Exception e)
            {
                LunaLog.Fatal($"ERROR in thread receive! Details: {e}");
            }
        }
Пример #12
0
        public void StartReceiveingMessages()
        {
            try
            {
                while (ServerContext.ServerRunning)
                {
                    var msg = Server.ReadMessage();
                    if (msg != null)
                    {
                        var client = TryGetClient(msg);
                        switch (msg.MessageType)
                        {
                        case NetIncomingMessageType.ConnectionApproval:
                            msg.SenderConnection.Approve();
                            break;

                        case NetIncomingMessageType.Data:
                            ClientMessageReceiver.ReceiveCallback(client, msg);
                            break;

                        case NetIncomingMessageType.WarningMessage:
                            LunaLog.Error($"Lidgren WARNING: {msg.ReadString()}");
                            break;

                        case NetIncomingMessageType.DebugMessage:
                        case NetIncomingMessageType.VerboseDebugMessage:
                            LunaLog.Debug($"Lidgren DEBUG: {msg.MessageType}-- {msg.PeekString()}");
                            break;

                        case NetIncomingMessageType.StatusChanged:
                            switch ((NetConnectionStatus)msg.ReadByte())
                            {
                            case NetConnectionStatus.Connected:
                                var endpoint = msg.SenderConnection.RemoteEndPoint;
                                LunaLog.Normal($"New client Connection from {endpoint.Address}:{endpoint.Port}");
                                ClientConnectionHandler.ConnectClient(msg.SenderConnection);
                                break;

                            case NetConnectionStatus.Disconnected:
                                var reason = msg.ReadString();
                                if (client != null)
                                {
                                    ClientConnectionHandler.DisconnectClient(client, reason);
                                }
                                break;
                            }
                            break;

                        default:
                            var details = msg.PeekString();
                            LunaLog.Debug($"Lidgren: {msg.MessageType.ToString().ToUpper()} -- {details}");
                            break;
                        }
                    }
                    else
                    {
                        Thread.Sleep(GeneralSettings.SettingsStore.SendReceiveThreadTickMs);
                    }
                }
            }
            catch (Exception e)
            {
                LunaLog.Fatal($"ERROR in thread receive! Details: {e}");
            }
        }
Пример #13
0
        public static void Main()
        {
            try
            {
                ServerContext.StartTime = DateTime.UtcNow.Ticks;

                //Start the server clock
                ServerContext.ServerClock.Start();

                //Set the last player activity time to server start
                ServerContext.LastPlayerActivity = ServerContext.ServerClock.ElapsedMilliseconds;

                //Register the ctrl+c event
                Console.CancelKeyPress      += CatchExit;
                ServerContext.ServerStarting = true;

                LunaLog.Debug("Loading settings...");
                if (GeneralSettings.SettingsStore.GameDifficulty == GameDifficulty.Custom)
                {
                    GameplaySettings.Reset();
                    GameplaySettings.Load();
                }

                //Set day for log change
                ServerContext.Day = DateTime.Now.Day;

                //Load plugins
                LmpPluginHandler.LoadPlugins();

                Console.Title = $"LMPServer v{VersionInfo.VersionNumber}";

                while (ServerContext.ServerStarting || ServerContext.ServerRestarting)
                {
                    if (ServerContext.ServerRestarting)
                    {
                        LunaLog.Debug("Reloading settings...");
                        GeneralSettings.Reset();
                        GeneralSettings.Load();
                        if (GeneralSettings.SettingsStore.GameDifficulty == GameDifficulty.Custom)
                        {
                            LunaLog.Debug("Reloading gameplay settings...");
                            GameplaySettings.Reset();
                            GameplaySettings.Load();
                        }
                    }

                    ServerContext.ServerRestarting = false;
                    LunaLog.Normal($"Starting Luna Server v{VersionInfo.FullVersionNumber}");

                    if (GeneralSettings.SettingsStore.GameDifficulty == GameDifficulty.Custom)
                    {
                        //Generate the config file by accessing the object.
                        LunaLog.Debug("Loading gameplay settings...");
                        GameplaySettings.Load();
                    }

                    //Load universe
                    LunaLog.Normal("Loading universe... ");
                    Universe.CheckUniverse();

                    LunaLog.Normal($"Starting {GeneralSettings.SettingsStore.WarpMode} server on Port {GeneralSettings.SettingsStore.Port}... ");

                    ServerContext.ServerRunning = true;

                    var commandThread = Task.Run(() => new CommandHandler().ThreadMain());
                    var clientThread  = Task.Run(() => new ClientMainThread().ThreadMain());

                    ServerContext.LidgrenServer.SetupLidgrenServer();
                    Task.Run(() => ServerContext.LidgrenServer.StartReceiveingMessages());
                    Task.Run(() => ServerContext.LidgrenServer.RegisterWithMasterServer());

                    var vesselRelayThread = Task.Run(() => VesselRelaySystem.RelayOldVesselMessages());

                    var vesselRelayFarThread    = Task.Run(() => VesselUpdateRelaySystem.RelayToFarPlayers());
                    var vesselRelayMediumThread = Task.Run(() => VesselUpdateRelaySystem.RelayToMediumDistancePlayers());
                    var vesselRelayCloseThread  = Task.Run(() => VesselUpdateRelaySystem.RelayToClosePlayers());

                    while (ServerContext.ServerStarting)
                    {
                        Thread.Sleep(500);
                    }

                    LunaLog.Normal("Ready!");
                    LmpPluginHandler.FireOnServerStart();
                    while (ServerContext.ServerRunning)
                    {
                        //Run the log expire function every 10 minutes
                        if (ServerContext.ServerClock.ElapsedMilliseconds - _lastLogExpiredCheck > 600000)
                        {
                            _lastLogExpiredCheck = ServerContext.ServerClock.ElapsedMilliseconds;
                            LogExpire.ExpireLogs();
                        }

                        // Check if the day has changed, every minute
                        if (ServerContext.ServerClock.ElapsedMilliseconds - _lastDayCheck > 60000)
                        {
                            _lastDayCheck = ServerContext.ServerClock.ElapsedMilliseconds;
                            if (ServerContext.Day != DateTime.Now.Day)
                            {
                                LunaLog.LogFilename = Path.Combine(LunaLog.LogFolder, $"lmpserver {DateTime.Now:yyyy-MM-dd HH-mm-ss}.log");
                                LunaLog.WriteToLog($"Continued from logfile {DateTime.Now:yyyy-MM-dd HH-mm-ss}.log");
                                ServerContext.Day = DateTime.Now.Day;
                            }
                        }

                        Thread.Sleep(500);
                    }

                    LmpPluginHandler.FireOnServerStop();
                    commandThread.Wait();
                    clientThread.Wait();
                    vesselRelayThread.Wait();

                    vesselRelayFarThread.Wait();
                    vesselRelayMediumThread.Wait();
                    vesselRelayCloseThread.Wait();
                }
                LunaLog.Normal("Goodbye and thanks for all the fish!");
                Environment.Exit(0);
            }
            catch (Exception e)
            {
                LunaLog.Fatal($"Error in main server thread, Exception: {e}");
                throw;
            }
        }
Пример #14
0
 public void HandleJoinMessage(ClientStructure client, ChatJoinMsgData message)
 {
     AddChannelToPlayer(message.From, message.Channel);
     LunaLog.Debug($"{message.From} joined channel: {message.Channel}");
     MessageQueuer.RelayMessage <ChatSrvMsg>(client, message);
 }
Пример #15
0
 public void HandleLeaveMessage(ClientStructure client, ChatLeaveMsgData message)
 {
     RemoveChannelFromPlayer(message.From, message.Channel);
     LunaLog.Debug($"{message.From} left channel: {message.Channel}");
     MessageQueuer.RelayMessage <ChatSrvMsg>(client, message);
 }
Пример #16
0
        public static void LoadPlugins()
        {
            var pluginDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");

            if (!FileHandler.FolderExists(pluginDirectory))
            {
                FileHandler.FolderCreate(pluginDirectory);
            }
            LunaLog.Debug("Loading plugins...");

            //Load all the assemblies just in case they depend on each other during instantation
            var loadedAssemblies = new List <Assembly>();
            var pluginFiles      = FileHandler.GetFilesInPath(pluginDirectory, SearchOption.AllDirectories);

            foreach (var pluginFile in pluginFiles.Where(pluginFile => Path.GetExtension(pluginFile)?.ToLower() == ".dll"))
            {
                try
                {
                    //UnsafeLoadFrom will not throw an exception if the dll is marked as unsafe,
                    //such as downloaded from internet in Windows
                    //See http://stackoverflow.com/a/15238782
                    var loadedAssembly = Assembly.UnsafeLoadFrom(pluginFile);
                    loadedAssemblies.Add(loadedAssembly);
                    LunaLog.Debug($"Loaded {pluginFile}");
                }
                catch (NotSupportedException)
                {
                    //This should only occur if using Assembly.LoadFrom() above instead of Assembly.UnsafeLoadFrom()
                    LunaLog.Debug($"Can't load dll, perhaps it is blocked: {pluginFile}");
                }
                catch
                {
                    LunaLog.Debug($"Error loading {pluginFile}");
                }
            }

            //Iterate through the assemblies looking for classes that have the ILmpPlugin interface
            foreach (var loadedAssembly in loadedAssemblies)
            {
                foreach (var loadedType in loadedAssembly.GetExportedTypes().Where(t => t.GetInterfaces().Any(i => i == typeof(ILmpPlugin))))
                {
                    LunaLog.Debug($"Loading plugin: {loadedType.FullName}");
                    try
                    {
                        var pluginInstance = ActivatePluginType(loadedType);
                        if (pluginInstance != null)
                        {
                            LunaLog.Debug($"Loaded plugin: {loadedType.FullName}");
                            lock (ListLock)
                            {
                                LoadedPlugins.Add(pluginInstance);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        LunaLog.Error($"Error loading plugin {loadedType.FullName}({loadedType.Assembly.FullName}) Exception: {ex}");
                    }
                }
                LunaLog.Debug("Done!");
            }
        }
Пример #17
0
        private static void HandleMessage(IMasterServerMessageBase message, NetIncomingMessage netMsg, NetPeer peer)
        {
            if (BannedIpsRetriever.IsBanned(netMsg.SenderEndPoint))
            {
                LunaLog.Debug($"Ignoring BANNED ip: {netMsg.SenderEndPoint}");
                return;
            }

            try
            {
                switch ((message?.Data as MsBaseMsgData)?.MasterServerMessageSubType)
                {
                case MasterServerMessageSubType.RegisterServer:
                    RegisterServer(message, netMsg);
                    break;

                case MasterServerMessageSubType.RequestServers:
                    LunaLog.Normal($"LIST REQUEST from: {netMsg.SenderEndPoint}");
                    SendServerLists(netMsg, peer);
                    break;

                case MasterServerMessageSubType.Introduction:
                    var msgData = (MsIntroductionMsgData)message.Data;
                    if (ServerDictionary.TryGetValue(msgData.Id, out var server))
                    {
                        _ = Task.Run(() =>
                        {
                            if (!server.InternalEndpoint6.Address.Equals(IPAddress.IPv6Loopback) &&
                                !server.InternalEndpoint6.Address.Equals(IPAddress.IPv6Loopback))
                            {
                                // Both client and server are listening on IPv6, try an IPv6 firewall punchthrough
                                // This also triggers a first punchthrough on IPv4 with the public addresses
                                LunaLog.Normal(
                                    $"INTRODUCTION request from: {msgData.InternalEndpoint6} to server: {server.InternalEndpoint6}");
                                peer.Introduce(server.InternalEndpoint6, server.ExternalEndpoint,
                                               msgData.InternalEndpoint6, // client internal
                                               netMsg.SenderEndPoint,     // client external
                                               msgData.Token);            // request token

                                // Give the first introduction attempt some time
                                Thread.Sleep(50);
                            }

                            LunaLog.Normal(
                                $"INTRODUCTION request from: {netMsg.SenderEndPoint} to server: {server.ExternalEndpoint}");
                            peer.Introduce(server.InternalEndpoint, server.ExternalEndpoint,
                                           msgData.InternalEndpoint, // client internal
                                           netMsg.SenderEndPoint,    // client external
                                           msgData.Token);           // request token
                        });
                    }
                    else
                    {
                        LunaLog.Warning($"Client {netMsg.SenderEndPoint} requested introduction to non listed host!");
                    }
                    break;
                }
            }
            catch (Exception e)
            {
                LunaLog.Error($"Error handling message. Details: {e}");
            }
        }