Example #1
0
 public void delayDisconnect(string reason)
 {
     if (kickTargetTimestamp != 0)
     {
         return;
     }
     sendChatMessage("^#f75d5d;" + reason);
     flushChatQueue();
     kickTargetTimestamp = Utils.getTimestamp() + 6;
     sendServerPacket(Packet.ClientDisconnect, new byte[1]);
     StarryboundServer.logInfo("[" + playerData.client + "] is being kicked for " + reason);
 }
Example #2
0
        public static ServerFile Read(string path)
        {
            if (!File.Exists(path))
            {
                return(new ServerFile());
            }

            using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                ServerFile file = Read(fs);
                StarryboundServer.logInfo("Starbound server config loaded successfully.");
                return(file);
            }
        }
Example #3
0
 private void doDisconnect(string logMessage)
 {
     if (this.state == ClientState.Disposing)
     {
         return;
     }
     this.state = ClientState.Disposing;
     StarryboundServer.logInfo("[" + playerData.client + "] " + logMessage);
     try
     {
         if (this.playerData.name != null)
         {
             Client target = StarryboundServer.getClient(this.playerData.name);
             if (target != null)
             {
                 Users.SaveUser(this.playerData);
                 StarryboundServer.removeClient(this);
                 if (this.kickTargetTimestamp == 0)
                 {
                     StarryboundServer.sendGlobalMessage(this.playerData.name + " has left the server.");
                 }
             }
         }
     }
     catch (Exception e)
     {
         StarryboundServer.logException("Failed to remove client from clients: " + e.ToString());
     }
     try
     {
         this.sendServerPacket(Packet.ClientDisconnect, new byte[1]);
     }
     catch (Exception) { }
     try
     {
         this.cSocket.Close();
         this.sSocket.Close();
     }
     catch (Exception) { }
     try
     {
         this.ClientForwarder.Abort();
         this.ServerForwarder.Abort();
     }
     catch (Exception) { }
 }
        public void runTcp()
        {
            try
            {
                IPAddress localAdd = IPAddress.Parse(StarryboundServer.config.proxyIP);
                tcpSocket = new TcpListener(localAdd, StarryboundServer.config.proxyPort);
                tcpSocket.Start();

                StarryboundServer.logInfo("Proxy server has been started on " + localAdd.ToString() + ":" + StarryboundServer.config.proxyPort);
                StarryboundServer.changeState(ServerState.ListenerReady, "ListenerThread::runTcp");

                try
                {
                    while (true)
                    {
                        TcpClient clientSocket = tcpSocket.AcceptTcpClient();
                        clientSocket.ReceiveTimeout = StarryboundServer.config.clientSocketTimeout * 1000;
                        clientSocket.SendTimeout    = StarryboundServer.config.internalSocketTimeout * 1000;
                        new Thread(new ThreadStart(new Client(clientSocket).run)).Start();
                    }
                }
                catch (ThreadAbortException)
                {
                    StarryboundServer.changeState(ServerState.Crashed, "ListenerThread::runTcp", "Thread has been aborted");
                }
                catch (Exception e)
                {
                    if ((int)StarryboundServer.serverState > 3)
                    {
                        return;
                    }
                    StarryboundServer.logException("ListenerThread Exception: " + e.ToString());
                    StarryboundServer.changeState(ServerState.Crashed, "ListenerThread::runTcp", e.ToString());
                }

                tcpSocket.Stop();
                StarryboundServer.logFatal("ListenerThread has failed - No new connections will be possible.");
            }
            catch (ThreadAbortException) { }
            catch (SocketException e)
            {
                StarryboundServer.logFatal("TcpListener has failed to start: " + e.Message);
                StarryboundServer.serverState = ServerState.Crashed;
            }
        }
        private void SourceRequest(byte[] data, EndPoint remote)
        {
            byte headerByte = data[4];

            byte[] dataArray;

            switch (headerByte)
            {
            case 0x54:
                dataArray = new byte[data.Length - 6];

                Buffer.BlockCopy(data, 5, dataArray, 0, dataArray.Length);

                string text   = Encoding.UTF8.GetString(dataArray);
                string needle = "Source Engine Query";

                if (text != needle)
                {
                    StarryboundServer.logError("RCON: Received invalid A2S_INFO request: " + text + " is invalid.");
                    return;
                }
                else
                {
                    StarryboundServer.logDebug("ListenerThread::SourceRequest", "RCON: Matched A2S_INFO request!");
                }

                try
                {
                    byte   header      = 0x49;
                    byte   protocol    = 0x02;
                    byte[] name        = encodeString(StarryboundServer.config.serverName);
                    byte[] map         = encodeString("Starbound");
                    byte[] folder      = encodeString("na");
                    byte[] game        = encodeString("Starbound");
                    byte[] appID       = BitConverter.GetBytes(Convert.ToUInt16(1337));
                    byte   players     = Convert.ToByte((uint)StarryboundServer.clientCount);
                    byte   maxplayers  = Convert.ToByte((uint)StarryboundServer.config.maxClients);
                    byte   bots        = Convert.ToByte((uint)0);
                    byte   servertype  = Convert.ToByte('d');
                    byte   environment = Convert.ToByte((StarryboundServer.IsMono ? 'l' : 'w'));
                    byte   visibility  = Convert.ToByte((uint)(StarryboundServer.config.proxyPass == "" ? 0 : 1));
                    byte   vac         = Convert.ToByte((uint)0);
                    byte[] version     = encodeString(StarryboundServer.starboundVersion.Name);

                    var s = new MemoryStream();
                    s.Write(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, 0, 4);
                    s.WriteByte(header);
                    s.WriteByte(protocol);
                    s.Write(name, 0, name.Length);
                    s.Write(map, 0, map.Length);
                    s.Write(folder, 0, folder.Length);
                    s.Write(game, 0, game.Length);
                    s.Write(appID, 0, appID.Length);
                    s.WriteByte(players);
                    s.WriteByte(maxplayers);
                    s.WriteByte(bots);
                    s.WriteByte(servertype);
                    s.WriteByte(environment);
                    s.WriteByte(visibility);
                    s.WriteByte(vac);
                    s.Write(version, 0, version.Length);

                    StarryboundServer.logInfo("RCON: Sending A2S_INFO Response packet to " + remote);
                    udpSocket.SendTo(s.ToArray(), remote);
                }
                catch (Exception e)
                {
                    StarryboundServer.logError("RCON: Unable to send data to stream! An error occurred.");
                    StarryboundServer.logError("RCON: " + e.ToString());
                }
                break;

            case 0x55:
                StarryboundServer.logDebug("ListenerThread::SourceRequest", "RCON: Received A2S_PLAYER request from " + remote);

                dataArray = new byte[4];
                Buffer.BlockCopy(data, 5, dataArray, 0, dataArray.Length);

                if (dataArray.SequenceEqual(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }))
                {
                    var buffer = new byte[4];
                    new Random().NextBytes(buffer);

                    if (challengeData.ContainsKey(remote))
                    {
                        challengeData.Remove(remote);
                    }
                    challengeData.Add(remote, buffer);

                    var s = new MemoryStream();
                    s.Write(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, 0, 4);
                    s.WriteByte(0x41);
                    s.Write(buffer, 0, 4);

                    StarryboundServer.logInfo("RCON: Sending A2S_PLAYER Challenge Response packet to " + remote);
                    udpSocket.SendTo(s.ToArray(), remote);
                }
                else
                {
                    if (!challengeData.ContainsKey(remote))
                    {
                        StarryboundServer.logError("RCON: Illegal A2S_PLAYER request received from " + remote + ". No challenge number has been issued to this address.");
                    }
                    else
                    {
                        var s = new MemoryStream();
                        s.Write(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, 0, 4);
                        s.WriteByte(0x44);

                        s.WriteByte(Convert.ToByte((uint)StarryboundServer.clientCount));

                        List <Client> clientList = StarryboundServer.getClients();

                        for (var i = 0; i < clientList.Count; i++)
                        {
                            Client client = clientList[i];
                            s.WriteByte(Convert.ToByte((uint)i));

                            byte[] name = encodeString(client.playerData.name);
                            s.Write(name, 0, name.Length);

                            byte[] score = new byte[4];
                            score = BitConverter.GetBytes((int)0);
                            s.Write(score, 0, score.Length);

                            float  seconds   = Utils.getTimestamp() - client.connectedTime;
                            byte[] connected = new byte[4];
                            connected = BitConverter.GetBytes(seconds);
                            s.Write(connected, 0, connected.Length);

                            //StarryboundServer.logDebug("ListenerThread::SourceA2SPlayer", "Client ID #" + i + ": " + Utils.ByteArrayToString(new byte[] { Convert.ToByte((uint)i) }) + Utils.ByteArrayToString(name) + Utils.ByteArrayToString(score) + Utils.ByteArrayToString(connected));
                        }

                        StarryboundServer.logInfo("RCON: Sending A2S_PLAYER Response packet for " + StarryboundServer.clientCount + " player(s) to " + remote);
                        //StarryboundServer.logDebug("ListenerThread::SourceA2SPlayer", "RCON: Dump packet: " + Utils.ByteArrayToString(s.ToArray()));
                        udpSocket.SendTo(s.ToArray(), remote);
                    }
                }
                break;

            default:
                StarryboundServer.logError("RCON: Received unknown or unsupported header byte - " + headerByte);
                break;
            }
        }
Example #6
0
        public void run()
        {
            try
            {
                this.cIn  = new BinaryReader(this.cSocket.GetStream());
                this.cOut = new BinaryWriter(this.cSocket.GetStream());

                IPEndPoint ipep = (IPEndPoint)this.cSocket.Client.RemoteEndPoint;
                IPAddress  ipa  = ipep.Address;

                this.playerData.ip = ipep.Address.ToString();

                StarryboundServer.logInfo("[" + playerData.client + "] Accepting new connection.");

                if ((int)StarryboundServer.serverState < 3)
                {
                    MemoryStream packet      = new MemoryStream();
                    BinaryWriter packetWrite = new BinaryWriter(packet);
                    packetWrite.WriteBE(StarryboundServer.ProtocolVersion);
                    this.sendClientPacket(Packet.ProtocolVersion, packet.ToArray());

                    rejectPreConnected("Connection Failed: The server is not ready yet.");
                    return;
                }
                else if ((int)StarryboundServer.serverState > 3)
                {
                    MemoryStream packet      = new MemoryStream();
                    BinaryWriter packetWrite = new BinaryWriter(packet);
                    packetWrite.WriteBE(StarryboundServer.ProtocolVersion);
                    this.sendClientPacket(Packet.ProtocolVersion, packet.ToArray());

                    rejectPreConnected("Connection Failed: The server is shutting down.");
                    return;
                }
                else if (StarryboundServer.restartTime != 0)
                {
                    MemoryStream packet      = new MemoryStream();
                    BinaryWriter packetWrite = new BinaryWriter(packet);
                    packetWrite.WriteBE(StarryboundServer.ProtocolVersion);
                    this.sendClientPacket(Packet.ProtocolVersion, packet.ToArray());

                    rejectPreConnected("Connection Failed: The server is restarting.");
                    return;
                }

                sSocket = new TcpClient();
                sSocket.ReceiveTimeout = StarryboundServer.config.internalSocketTimeout * 1000;
                sSocket.SendTimeout    = StarryboundServer.config.internalSocketTimeout * 1000;
                IAsyncResult result  = sSocket.BeginConnect((StarryboundServer.config.proxyIP.Equals("0.0.0.0") ? IPAddress.Loopback : IPAddress.Parse(StarryboundServer.config.proxyIP)), StarryboundServer.config.serverPort, null, null);
                bool         success = result.AsyncWaitHandle.WaitOne(3000, true);
                if (!success || !sSocket.Connected)
                {
                    StarryboundServer.failedConnections++;
                    if (StarryboundServer.failedConnections >= StarryboundServer.config.maxFailedConnections)
                    {
                        StarryboundServer.logFatal(StarryboundServer.failedConnections + " clients failed to connect in a row. Restarting...");
                        StarryboundServer.serverState = ServerState.Crashed;
                    }
                    MemoryStream packet      = new MemoryStream();
                    BinaryWriter packetWrite = new BinaryWriter(packet);
                    packetWrite.WriteBE(StarryboundServer.ProtocolVersion);
                    this.sendClientPacket(Packet.ProtocolVersion, packet.ToArray());
                    rejectPreConnected("Connection Failed: Unable to connect to the parent server.");
                    return;
                }

                this.sIn  = new BinaryReader(this.sSocket.GetStream());
                this.sOut = new BinaryWriter(this.sSocket.GetStream());

                this.connectedTime = Utils.getTimestamp();

                // Forwarding for data from SERVER (sIn) to CLIENT (cOut)
                this.ServerForwarder = new Thread(new ThreadStart(new ForwardThread(this, this.sIn, this.cOut, Direction.Server).run));
                ServerForwarder.Start();

                // Forwarding for data from CLIENT (cIn) to SERVER (sOut)
                this.ClientForwarder = new Thread(new ThreadStart(new ForwardThread(this, this.cIn, this.sOut, Direction.Client).run));
                ClientForwarder.Start();

                StarryboundServer.failedConnections = 0;
            }
            catch (Exception e)
            {
                StarryboundServer.logException("ClientThread Exception: " + e.ToString());
                StarryboundServer.failedConnections++;
                MemoryStream packet      = new MemoryStream();
                BinaryWriter packetWrite = new BinaryWriter(packet);
                packetWrite.WriteBE(StarryboundServer.ProtocolVersion);
                this.sendClientPacket(Packet.ProtocolVersion, packet.ToArray());
                rejectPreConnected("Connection Failed: A internal server error occurred (1)");
            }
        }
        void parseOutput(string consoleLine)
        {
            try
            {
                foreach (string line in filterConsole)
                {
                    if (consoleLine.Contains(line))
                    {
                        return;
                    }
                }

                if (consoleLine.StartsWith("Error: ") || consoleLine.StartsWith("AssetException:"))
                {
                    this.parseError = true;
                }
                else if ((consoleLine.StartsWith("Warn:") || consoleLine.StartsWith("Info:") || consoleLine.StartsWith("Debug:")) && this.parseError)
                {
                    logStarboundError(" ");
                    this.parseError = false;
                }
                else if (String.IsNullOrWhiteSpace(consoleLine) && this.parseError)
                {
                    logStarboundError(" ");
                    this.parseError = false;
                    return;
                }

                if (consoleLine.StartsWith("Warn: Perf: "))
                {
                    string[] perf     = consoleLine.Remove(0, 12).Split(' ');
                    string   function = perf[0];
                    float    millis   = Convert.ToSingle(perf[2]);
                    if (millis > 5000)
                    {
                        StarryboundServer.logWarn("Parent Server [" + function + "] lagged for " + (millis / 1000) + " seconds");
                    }
                    return;
                }
                else if (consoleLine.Contains("Info: Server version"))
                {
                    string[] versionString   = consoleLine.Split('\'');
                    string   versionName     = versionString[1];
                    int      protocolVersion = int.Parse(versionString[3]);
                    StarryboundServer.starboundVersion.Protocol = protocolVersion;
                    StarryboundServer.starboundVersion.Name     = versionName;
                    if (protocolVersion != StarryboundServer.ProtocolVersion)
                    {
                        StarryboundServer.logFatal("Detected protcol version [" + protocolVersion + "] != [" + StarryboundServer.ProtocolVersion + "] to expected protocol version!");
                        Thread.Sleep(5000);
                        Environment.Exit(4);
                    }
                    StarryboundServer.logInfo("Parent Server Version: [" + versionName + "] Protocol: [" + protocolVersion + "]");
                    return;
                }
                else if (consoleLine.Contains("TcpServer will close, listener thread caught exception"))
                {
                    StarryboundServer.logFatal("Parent Server TcpServer listener thread caught exception, Forcing a restart.");
                    StarryboundServer.changeState(ServerState.Crashed, "ServerThread::parseOutput", "Starbound Tcp listener has crashed");
                }
                else if (consoleLine.Contains("TcpServer listening on: "))
                {
                    StarryboundServer.changeState(ServerState.StarboundReady, "ServerThread::parseOutput");
                    ServerConfig.RemovePrivateConfig();
                }
                else if (consoleLine.StartsWith("Info: Kicking client "))
                {
                    string[] kick = consoleLine.Remove(0, 21).Split(' ');
                    string   user = kick[0];
                    string   id   = kick[1];
                    string   ip   = kick[2];
                    StarryboundServer.logWarn("Parent Server disconnected " + user + " " + ip + " for inactivity.");
                    return;
                }

                if (!this.parseError)
                {
                    Console.WriteLine("[STAR] " + consoleLine);
                }
                else
                {
                    logStarboundError(consoleLine);
                }
            }
            catch (Exception) { }
        }