public override void Process(ClientConnection conn, byte[] readBuffer, int length, int num) { var data = Encoding.ASCII.GetString (readBuffer, num, length - 1); var lines = data.Split ('\n'); foreach (var line in lines) { if (line == "tdcm1") { //player.HasClientMod = true; ProgramLog.Log ("{0} is a TDCM protocol version 1 client.", conn.RemoteAddress); } else if (line == "tdsmcomp1") { conn.CompressionVersion = 1; ProgramLog.Log ("{0} supports TDSM compression version 1.", conn.RemoteAddress); } } var ctx = new HookContext { Connection = conn, }; var args = new HookArgs.DisconnectReceived { Content = data, Lines = lines, }; HookPoints.DisconnectReceived.Invoke (ref ctx, ref args); ctx.CheckForKick (); }
public override void Process(ClientConnection conn, byte[] readBuffer, int length, int num) { if (conn.State == SlotState.ACCEPTED) { SlotManager.Schedule (conn, conn.DesiredQueue); return; } int whoAmI = conn.SlotIndex; if (NetPlay.slots[whoAmI].state == SlotState.ASSIGNING_SLOT) { NetPlay.slots[whoAmI].state = SlotState.SENDING_WORLD; } var ctx = new HookContext() { Connection = conn, Player = conn.Player }; var args = new HookArgs.WorldRequestMessage() { SpawnX = Main.spawnTileX, SpawnY = Main.spawnTileY }; HookPoints.WorldRequestMessage.Invoke(ref ctx, ref args); //NetMessage.SendData(7, whoAmI); var msg = NetMessage.PrepareThreadInstance(); msg.WorldData(args.SpawnX, args.SpawnY); msg.Send(whoAmI); }
public override void Process(ClientConnection conn, byte[] readBuffer, int length, int pos) { var slot = conn.SlotIndex; if (slot >= 0) Process (slot, readBuffer, length, pos); else ProgramLog.Error.Log ("Attempt to process packet {0} before slot assignment.", GetPacket()); }
public override void Process(ClientConnection conn, byte[] readBuffer, int length, int num) { if (conn.State == SlotState.ACCEPTED) { SlotManager.Schedule (conn, conn.DesiredQueue); return; } int whoAmI = conn.SlotIndex; if (NetPlay.slots[whoAmI].state == SlotState.ASSIGNING_SLOT) { NetPlay.slots[whoAmI].state = SlotState.SENDING_WORLD; } NetMessage.SendData(7, whoAmI); }
public override void Process(ClientConnection conn, byte[] readBuffer, int length, int num) { QNPC_Types qType = (QNPC_Types)readBuffer[num++]; int QuestID = readBuffer[num++]; if (QuestID == 255) QuestID = -1; if (qType != QNPC_Types.GHOST && qType != QNPC_Types.ALCHEMIST && qType != QNPC_Types.DARK_MAGE && qType != QNPC_Types.PALADIN && qType != QNPC_Types.TINKERER) { conn.Kick("Sent unknown Quest NPC Name ID."); return; } if (!Main.players[conn.SlotIndex].HasClientMod) { conn.Kick("Sent Quest NPC Name Packet without permissions."); return; } if (!Server.AllowTDCMRPG) { conn.Kick("Invalid Client Message, Acting as TDCM"); return; } if(QuestID > (int)QuestType.QUESTS_END || QuestID < (int)QuestType.NO_QUEST) { conn.Kick("Uknown Quest ID."); return; } //Set the players Quest NPC Name & Current Quest Id Main.players[conn.SlotIndex].QuestNPCName = QuestNPCType.GetQuestNPCName(qType); Main.players[conn.SlotIndex].CurrentQuest = QuestID; }
static bool AcceptClient(Socket client) { client.NoDelay = true; string addr; try { var rep = client.RemoteEndPoint; if (rep != null) { addr = rep.ToString(); } else { ProgramLog.Debug.Log("Accepted socket disconnected"); return(false); } } catch (Exception e) { ProgramLog.Debug.Log("Accepted socket exception ({0})", HandleSocketException(e)); return(false); } try { ProgramLog.Users.Log("{0} is connecting...", addr); var conn = new Networking.ClientConnection(client, -1); //ignore the warning } catch (SocketException) { client.SafeClose(); ProgramLog.Users.Log("{0} disconnected.", addr); } return(true); }
internal static string WaitingMessage(ClientConnection conn) { int i = 0; for (int q = 3; q > conn.Queue; q--) { i += queues[q].Count; } i += Math.Min (queues[conn.Queue].Count, Math.Max (0, conn.IndexInQueue - queues[conn.Queue].TotalDequeued)); if (i <= 0) i = 1; string suffix = "th"; switch (i % 10) { case 1: suffix = "st"; break; case 2: suffix = "nd"; break; case 3: suffix = "rd"; break; } switch (i % 100) { case 11: case 12: case 13: suffix = "th"; break; } return String.Format (waitingMessage, i, suffix); }
static bool AssignSlot(ClientConnection conn, int id) { if (! conn.AssignSlot (id)) return false; conn.State = SlotState.ASSIGNING_SLOT; conn.ResetTimeout (); var slot = NetPlay.slots[id]; slot.remoteAddress = conn.RemoteAddress; slot.conn = conn; conn.Player.whoAmi = id; Main.players[id] = conn.Player; var age = conn.Age; if (age > TimeSpan.FromMilliseconds (500)) ProgramLog.Debug.Log ("Slot {1} assigned to {0} after {2}.", slot.remoteAddress, id, age); else ProgramLog.Debug.Log ("Slot {1} assigned to {0}.", slot.remoteAddress, id); return true; }
// TODO: optimize public static void RemoveFromQueues(ClientConnection conn) { lock (syncRoot) { for (int q = 3; q >= 0; q--) { queues[q].Remove (conn); } } }
public static int Schedule(ClientConnection conn, int priority) { int id; lock (syncRoot) { if (priority > 2 || priority < 0) { // bypass queue id = AssignSlotOrQueue (conn, 3); } else id = AssignSlotOrQueue (conn, priority); } // we send here, so as to prevent a deadlock between our lock // and the connection's sendqueue lock if (id == -1) { var msg = NetMessage.PrepareThreadInstance (); msg.SendTileLoading (1, WaitingMessage (conn)); conn.Send (msg.Output); } else if (id >= 0) { var msg = NetMessage.PrepareThreadInstance (); msg.ConnectionResponse (id); conn.Send (msg.Output); } return id; }
public void Send(ClientConnection conn) { conn.CopyAndSend (Segment); }
public static bool HandoverSlot(ClientConnection src, ClientConnection dst) { int id = src.SlotIndex; if (id < 0 || id > MAX_SLOTS) return false; lock (syncRoot) { handovers[id] = dst; // in case the connection dies during the operation if (src.SlotIndex != id) { handovers[id] = null; return false; } } return true; }
public void Reset() { tileSection = new bool[Main.maxTilesX / 200, Main.maxTilesY / 150]; if (tileSection.GetLength(0) >= Main.maxSectionsX && tileSection.GetLength(1) >= Main.maxSectionsY) { for (int i = 0; i < Main.maxSectionsX; i++) for (int j = 0; j < Main.maxSectionsY; j++) tileSection[i, j] = false; } else { tileSection = new bool [Main.maxSectionsX, Main.maxSectionsY]; } var oldPlayer = Main.players[this.whoAmI]; if (oldPlayer != null && state != SlotState.VACANT) { NetMessage.OnPlayerLeft (oldPlayer, this, announced); } announced = false; this.remoteAddress = "<unknown>"; if (this.whoAmI < 255) { Main.players[this.whoAmI] = new Player(); } this.timeOut = 0; // TODO: move to connection this.statusCount = 0; this.statusMax = 0; this.statusText2 = ""; this.statusText = ""; this.name = "Anonymous"; this.conn = null; this.SpamClear(); NetMessage.buffer[this.whoAmI].Reset(); conn = null; //socket.SafeClose (); }
public static void Dispatch(ClientConnection conn, byte[] readBuffer, int start, int length) { try { int num = start + 1; byte pkt = readBuffer[start]; if (conn.State == SlotState.SERVER_AUTH && pkt != 38) { conn.Kick ("Incorrect password."); return; } if ((conn.State & SlotState.DISCONNECTING) == 0) { var handler = messageArray[pkt]; var state = conn.State; if (handler != null) { //ProgramLog.Debug.Log ("{2}, packet {0}, len {1}", (Packet)readBuffer[start], length, conn.State); if ((state & handler.IgnoredStates) != 0) { //ProgramLog.Debug.Log ("ignoring"); } else if ((state & handler.ValidStates) != 0) { handler.Process (conn, readBuffer, length, num); } else { ProgramLog.Debug.Log ("{0}: sent message {1} in state {2}.", conn.RemoteAddress, (pkt > 0 && pkt <= 51) ? (object)(Packet)pkt : pkt, conn.State); conn.Kick ("Invalid operation in this state."); } } else { var ctx = new HookContext() { }; var args = new HookArgs.UnkownReceivedPacket() { Conn = conn, Length = length, Start = start, ReadBuffer = readBuffer }; //ProgramLog.Debug.Log("Received unknown packet {0}", pkt); HookPoints.UnkownReceivedPacket.Invoke(ref ctx, ref args); if (ctx.Result != HookResult.IGNORE && state != SlotState.PLAYING) // this is what stock would do conn.Kick(String.Format("Message not understood ({0}).", pkt)); } } } catch (Exception e) { string pkt = "invalid packet"; if (readBuffer.Length > start) pkt = String.Format ("packet {0}", (Packet)readBuffer[start]); ProgramLog.Log (e, String.Format ("Exception handling {0} of length {1} from {2}", pkt, length, conn.RemoteAddress)); conn.Kick ("Server malfunction, please reconnect."); } }
public override void Process(ClientConnection conn, byte[] readBuffer, int length, int num) { string chat; if(!ParseString(readBuffer, num + 4, length - 5, out chat)) { conn.Kick("Invalid characters in chat message."); return; } if (conn.State < SlotState.PLAYING) { if (chat != "/playing") { ProgramLog.Debug.Log ("{0}: sent message PLAYER_CHAT in state {1}.", conn.RemoteAddress, conn.State); conn.Kick ("Invalid operation at this state."); } else { ProgramLog.Debug.Log ("Replying to early online player query."); var msg = NetMessage.PrepareThreadInstance (); msg.PlayerChat (255, string.Concat ("Current players: ", String.Join (", ", from p in Main.players where p.Active select p.Name), "."), 255, 240, 20); conn.Send (msg.Output); } return; } int whoAmI = conn.SlotIndex; var player = Main.players[whoAmI]; if (chat.Length == 0) //TODO: check for undetectable spam return; if (chat.Substring(0, 1).Equals("/")) { if (Main.players[whoAmI].Op) ProgramLog.Admin.Log (player.Name + " sent command: " + chat); else ProgramLog.Users.Log (player.Name + " sent command: " + chat); Program.commandParser.ParsePlayerCommand (player, chat); return; } Color color = ChatColor.White; if (player.Op) { color = ChatColor.DeepSkyBlue; } else if (player.Difficulty == 1) { color = ChatColor.Khaki; } else if (player.Difficulty == 2) { color = ChatColor.Tomato; } else if (player.team > 0 && player.team < Main.teamColor.Length) { color = Main.teamColor[player.team]; } var ctx = new HookContext { Connection = player.Connection, Sender = player, Player = player, }; var args = new HookArgs.PlayerChat { Message = chat, Color = color, }; HookPoints.PlayerChat.Invoke (ref ctx, ref args); if (ctx.CheckForKick() || ctx.Result == HookResult.IGNORE) return; NetMessage.SendData (Packet.PLAYER_CHAT, -1, -1, chat, whoAmI, args.Color.R, args.Color.G, args.Color.B); ProgramLog.Chat.Log ("<" + player.Name + "> " + chat, SendingLogger.PLAYER); }
public void Remove(ClientConnection c) { var len = array.Length; for (int i = 0; i < count; i++) { int k = (head + i) % len; if (array[k] == c) { realCount -= 1; array[k] = null; } } while (array[head] == null && count > 0) { head = (head + 1) % array.Length; count -= 1; TotalDequeued += 1; } while (count > 0 && array[(head + count - 1) % array.Length] == null) { count -= 1; TotalDequeued += 1; } }
static string GetName(ClientConnection conn, byte[] readBuffer, int num, int len) { string name; try { name = Encoding.ASCII.GetString (readBuffer, num, len).Trim(); } catch (ArgumentException) { conn.Kick ("Invalid name: contains non-ASCII characters."); return null; } if (name.Length > 20) { conn.Kick ("Invalid name: longer than 20 characters."); return null; } if (name == "") { conn.Kick ("Invalid name: whitespace or empty."); return null; } foreach (char c in name) { if (c < 32 || c > 126) { conn.Kick ("Invalid name: contains non-printable characters."); return null; } } if (name.Contains (" " + " ")) { conn.Kick ("Invalid name: contains double spaces."); return null; } return name; }
public void Reset() { if (tileSection != null && tileSection.GetLength(0) >= Main.maxSectionsX && tileSection.GetLength(1) >= Main.maxSectionsY) { Array.Clear (tileSection, 0, tileSection.GetLength(0) * tileSection.GetLength(1)); } else { tileSection = new bool [Main.maxSectionsX, Main.maxSectionsY]; } var oldPlayer = Main.players[this.whoAmI]; if (oldPlayer != null && state != SlotState.VACANT) { NetMessage.OnPlayerLeft (oldPlayer, this, announced); } announced = false; this.remoteAddress = "<unknown>"; if (this.whoAmI < 255) { Main.players[this.whoAmI] = new Player(); } this.statusCount = 0; this.statusMax = 0; this.statusText2 = ""; this.statusText = ""; this.name = "Anonymous"; this.conn = null; this.SpamClear(); conn = null; }
public override void Process(ClientConnection conn, byte[] readBuffer, int length, int num) { // ServerSlot slot = Netplay.slots[whoAmI]; // PlayerLoginEvent loginEvent = new PlayerLoginEvent(); // loginEvent.Slot = slot; // loginEvent.Sender = Main.players[whoAmI]; // Server.PluginManager.processHook(Plugin.Hooks.PLAYER_PRELOGIN, loginEvent); // if ((loginEvent.Cancelled || loginEvent.Action == PlayerLoginAction.REJECT) && (slot.state & SlotState.DISCONNECTING) == 0) // { // slot.Kick ("Disconnected by server."); // return; // } string clientName = conn.RemoteAddress.Split(':')[0]; // // if (Server.BanList.containsException(clientName)) // { // slot.Kick ("You are banned from this Server."); // return; // } if (Program.properties.UseWhiteList && !Server.WhiteList.containsException(clientName)) { conn.Kick ("You are not on the WhiteList."); return; } string version = Networking.StringCache.FindOrMake (new ArraySegment<byte> (readBuffer, num, length - 1)); var ctx = new HookContext { Connection = conn, }; var args = new HookArgs.ConnectionRequestReceived { Version = version, }; HookPoints.ConnectionRequestReceived.Invoke (ref ctx, ref args); if (ctx.CheckForKick ()) return; if (ctx.Result == HookResult.DEFAULT && !(version == "Terraria" + Statics.CURRENT_TERRARIA_RELEASE)) { if (version.Length > 30) version = version.Substring (0, 30); ProgramLog.Debug.Log ("Client version string: {0}", version); conn.Kick (string.Concat ("This server requires Terraria ", Statics.VERSION_NUMBER)); return; } var msg = NetMessage.PrepareThreadInstance (); if (ctx.Result == HookResult.ASK_PASS || (NetPlay.password != null && NetPlay.password != "")) { conn.State = SlotState.SERVER_AUTH; msg.PasswordRequest (); conn.Send (msg.Output); return; } conn.State = SlotState.ACCEPTED; msg.ConnectionResponse (253 /* arbitrary fake value, true slot assigned later */); conn.Send (msg.Output); }
static int AssignSlotOrQueue(ClientConnection conn, int queue) { int id = -1; conn.Queue = queue; if (queue == 3) { if (privFreeSlots.Count > 0) { // use other slots for highest priority connections first id = privFreeSlots.Pop (); privSlotsInUse += 1; } else if (freeSlots.Count > 0) id = freeSlots.Pop (); } else if (freeSlots.Count > 0 && freeSlots.Count > (privSlotsInUse - overlimitSlots)) id = freeSlots.Pop (); if (id == -1) { conn.State = SlotState.QUEUED; conn.ResetTimeout (); queues[queue].Enqueue (conn); ProgramLog.Debug.Log ("Connection {0} queued with priority {1}.", conn.RemoteAddress, queue); return -1; } if (AssignSlot (conn, id)) return id; PushSlot (id); return -2; }
static bool AcceptClient(Socket client) { client.NoDelay = true; string addr; try { var rep = client.RemoteEndPoint; if (rep != null) addr = rep.ToString(); else { ProgramLog.Debug.Log ("Accepted socket disconnected"); return false; } } catch (Exception e) { ProgramLog.Debug.Log ("Accepted socket exception ({0})", HandleSocketException (e)); return false; } try { ProgramLog.Users.Log ("{0} is connecting...", addr); var conn = new Networking.ClientConnection (client, -1); //ignore the warning } catch (SocketException) { client.SafeClose (); ProgramLog.Users.Log ("{0} disconnected.", addr); } return true; }
public void Enqueue(ClientConnection c) { if (count == array.Length) Grow (); int tail = (head + count) % array.Length; array[tail] = c; count += 1; realCount += 1; TotalEnqueued += 1; c.IndexInQueue = TotalEnqueued; }
public override void Process(ClientConnection conn, byte[] readBuffer, int length, int num) { int start = num - 1; if (conn.State == SlotState.ASSIGNING_SLOT) { // TODO: verify that data didn't change. int who = conn.SlotIndex; NetMessage.SendData (4, -1, who, conn.Player.Name, who); return; } if (conn.Player != null) { conn.Kick ("Player data sent twice."); return; } var player = new Player (); conn.Player = player; player.Connection = conn; player.IPAddress = conn.RemoteAddress; player.whoAmi = conn.SlotIndex; var data = new HookArgs.PlayerDataReceived (); data.Parse (readBuffer, num + 1, length); if (data.Hair >= MAX_HAIR_ID) { data.Hair = 0; } var ctx = new HookContext { Connection = conn, Player = player, Sender = player, }; HookPoints.PlayerDataReceived.Invoke (ref ctx, ref data); if (ctx.CheckForKick ()) return; if (! data.NameChecked) { string error; if (! data.CheckName (out error)) { conn.Kick (error); return; } } if (! data.BansChecked) { string address = conn.RemoteAddress.Split(':')[0]; if (Server.BanList.containsException (address) || Server.BanList.containsException (data.Name)) { ProgramLog.Admin.Log ("Prevented user {0} from accessing the server.", data.Name); conn.Kick ("You are banned from this server."); return; } } data.Apply (player); if (ctx.Result == HookResult.ASK_PASS) { conn.State = SlotState.PLAYER_AUTH; var msg = NetMessage.PrepareThreadInstance (); msg.PasswordRequest (); conn.Send (msg.Output); return; } else // HookResult.DEFAULT { // don't allow replacing connections for guests, but do for registered users if (conn.State < SlotState.PLAYING) { var lname = player.Name.ToLower(); foreach (var otherPlayer in Main.players) { var otherSlot = NetPlay.slots[otherPlayer.whoAmi]; if (otherPlayer.Name != null && lname == otherPlayer.Name.ToLower() && otherSlot.state >= SlotState.CONNECTED) { conn.Kick ("A \"" + otherPlayer.Name + "\" is already on this server."); return; } } } //conn.Queue = (int)loginEvent.Priority; // actual queueing done on world request message // and now decide whether to queue the connection //SlotManager.Schedule (conn, (int)loginEvent.Priority); //NetMessage.SendData (4, -1, -1, player.Name, whoAmI); } }
void Grow() { int len = array.Length; var a = new ClientConnection [len * 3 / 2 + 16]; for (int i = 0; i < count; i++) { int k = (head + i) % len; a[i] = array[k]; } head = 0; array = a; }
public abstract void Process(ClientConnection conn, byte[] readBuffer, int length, int pos);
public override void Process(ClientConnection conn, byte[] readBuffer, int length, int num) { int start = num - 1; string password = Encoding.ASCII.GetString(readBuffer, num, length - num + start); if (conn.State == SlotState.SERVER_AUTH) { var ctx = new HookContext { Connection = conn, }; var args = new HookArgs.ServerPassReceived { Password = password, }; HookPoints.ServerPassReceived.Invoke (ref ctx, ref args); if (ctx.CheckForKick ()) return; if (ctx.Result == HookResult.ASK_PASS) { var msg = NetMessage.PrepareThreadInstance (); msg.PasswordRequest (); conn.Send (msg.Output); } else if (ctx.Result == HookResult.CONTINUE || password == NetPlay.password) { conn.State = SlotState.ACCEPTED; var msg = NetMessage.PrepareThreadInstance (); msg.ConnectionResponse (253 /* dummy value, real slot assigned later */); conn.Send (msg.Output); return; } conn.Kick ("Incorrect server password."); } else if (conn.State == SlotState.PLAYER_AUTH) { var name = conn.Player.Name ?? ""; var ctx = new HookContext { Connection = conn, Player = conn.Player, Sender = conn.Player, }; var args = new HookArgs.PlayerPassReceived { Password = password, }; HookPoints.PlayerPassReceived.Invoke (ref ctx, ref args); if (ctx.CheckForKick ()) return; if (ctx.Result == HookResult.ASK_PASS) { var msg = NetMessage.PrepareThreadInstance (); msg.PasswordRequest (); conn.Send (msg.Output); } else // HookResult.DEFAULT { var lower = name.ToLower(); bool reserved = false; //conn.Queue = (int)loginEvent.Priority; foreach (var otherPlayer in Main.players) { //var otherSlot = Netplay.slots[otherPlayer.whoAmi]; var otherConn = otherPlayer.Connection; if (otherPlayer.Name != null && lower == otherPlayer.Name.ToLower() && otherConn != null && otherConn.State >= SlotState.CONNECTED) { if (! reserved) { reserved = SlotManager.HandoverSlot (otherConn, conn); } otherConn.Kick ("Replaced by new connection."); } } //conn.State = SlotState.SENDING_WORLD; if (! reserved) // reserved slots get assigned immediately during the kick { SlotManager.Schedule (conn, conn.DesiredQueue); } //NetMessage.SendData (4, -1, whoAmI, name, whoAmI); // broadcast player data now // replay packets from side buffer //conn.conn.ProcessSideBuffer (); //var buf = NetMessage.buffer[whoAmI]; //NetMessage.CheckBytes (whoAmI, buf.sideBuffer, ref buf.sideBufferBytes, ref buf.sideBufferMsgLen); //buf.ResetSideBuffer (); //NetMessage.SendData (7, whoAmI); // continue with world data } } }
public static void FreeSlot(int id) { ClientConnection assignedTo = null; var slot = NetPlay.slots[id]; slot.Reset(); lock (syncRoot) { if (handovers[id] != null) { assignedTo = handovers[id]; handovers[id] = null; if (!AssignSlot(assignedTo, id)) { assignedTo = null; ProgramLog.Debug.Log("Slot {0} handover failed.", id); } else { ProgramLog.Debug.Log("Slot {0} handover successful.", id); } } if (assignedTo == null) { assignedTo = FindForSlot(id); } if (assignedTo == null) { PushSlot(id); ProgramLog.Debug.Log("Freed slot {0}", id); // this is for when a privileged slot is freed, but no privileged clients are waiting // so we check if we have an unprivileged slot to use if (isPrivileged[id] && (freeSlots.Count > 0 && freeSlots.Count > (privSlotsInUse - overlimitSlots))) { id = freeSlots.Pop(); assignedTo = FindForSlot(id); if (assignedTo == null) { freeSlots.Push(id); return; } } else { return; } } } var msg = NetMessage.PrepareThreadInstance(); msg.ConnectionResponse(id); assignedTo.Send(msg.Output); }