/// <summary> /// Begin sending a new packet to the server. /// </summary> public BinaryWriter BeginSend(byte packetID) { mBuffer = Buffer.Create(); return(mBuffer.BeginPacket(packetID)); }
/// <summary> /// Send the specified packet. Marks the buffer as used. /// </summary> public void SendTcpPacket(Buffer buffer, bool instant = false) { #if !MODDING buffer.MarkAsUsed(); var reader = buffer.BeginReading(); if (buffer.size == 0) { #if UNITY_EDITOR Debug.LogError("Trying to send a zero packet! " + buffer.position + " " + buffer.isWriting + " " + id); #endif buffer.Recycle(); return; } #if DEBUG_PACKETS && !STANDALONE var packet = (Packet)buffer.PeekByte(4); if (packet != Packet.RequestPing && packet != Packet.ResponsePing) { UnityEngine.Debug.Log("Sending: " + packet + " to " + name + " (" + (buffer.size - 5).ToString("N0") + " bytes)"); } #endif if (custom != null) { if (!custom.SendPacket(buffer)) { buffer.Recycle(); Disconnect(); } else { buffer.Recycle(); } return; } if (mSocket != null && mSocket.Connected) { lock (mOut) { #if UNITY_WINRT mSocket.Send(buffer.buffer, buffer.size, SocketFlags.None); #else if (instant) { try { var before = mSocket.NoDelay; if (!before) { mSocket.NoDelay = true; } mSocket.Send(buffer.buffer, buffer.position, buffer.size, SocketFlags.None); if (!before) { mSocket.NoDelay = false; } buffer.Recycle(); return; } catch { } } if (mSending) { // Simply add this packet to the outgoing queue mOut.Enqueue(buffer); } else { // If it's the first packet, let's begin the send process mSending = true; try { mSocket.BeginSend(buffer.buffer, buffer.position, buffer.size, SocketFlags.None, OnSend, buffer); } catch (System.Exception ex) { mOut.Clear(); buffer.Recycle(); AddError(ex); CloseNotThreadSafe(false); mSending = false; } } #endif } return; } if (sendQueue != null) { if (buffer.position != 0) { // Offline mode sends packets individually and they should not be reused #if UNITY_EDITOR Debug.LogWarning("Packet's position is " + buffer.position + " instead of 0. Potentially sending the same packet more than once. Ignoring..."); #endif return; } // Skip the packet's size int size = reader.ReadInt32(); if (size == buffer.size) { lock (sendQueue) sendQueue.Enqueue(buffer); return; } // Multi-part packet -- split it up into separate ones lock (sendQueue) { for (;;) { var bytes = reader.ReadBytes(size); var temp = Buffer.Create(); var writer = temp.BeginWriting(); writer.Write(size); writer.Write(bytes); temp.BeginReading(4); sendQueue.Enqueue(temp); if (buffer.size > 0) { size = reader.ReadInt32(); } else { break; } } } } #endif buffer.Recycle(); }
/// <summary> /// Close the connection. /// </summary> void CloseNotThreadSafe(bool notify) { #if !MODDING #if STANDALONE || UNITY_EDITOR if (id != 0) { Tools.Log(name + " (" + address + "): Disconnected [" + id + "]"); } #endif Buffer.Recycle(mOut); stage = Stage.NotConnected; mSending = false; if (mSocket != null || custom != null) { if (mSocket != null) { try { if (mSocket.Connected) { mSocket.Shutdown(SocketShutdown.Both); } mSocket.Close(); } catch (System.Exception) { } mSocket = null; } if (custom != null) { custom.OnDisconnect(); } if (notify) { var buffer = Buffer.Create(); buffer.BeginPacket(Packet.Disconnect); buffer.EndTcpPacketWithOffset(4); lock (mIn) { Buffer.Recycle(mIn); mIn.Enqueue(buffer); } } else { lock (mIn) Buffer.Recycle(mIn); } } else if (notify && sendQueue != null) { sendQueue = null; Buffer buffer = Buffer.Create(); buffer.BeginPacket(Packet.Disconnect); buffer.EndTcpPacketWithOffset(4); lock (mIn) { Buffer.Recycle(mIn); mIn.Enqueue(buffer); } } if (mReceiveBuffer != null) { mReceiveBuffer.Recycle(); mReceiveBuffer = null; } if (onClose != null) { onClose(this); } id = 0; #endif }
/// <summary> /// Begin sending a new packet to the server. /// </summary> public BinaryWriter BeginSend(Packet type) { mBuffer = Buffer.Create(); return(mBuffer.BeginPacket(type)); }
/// <summary> /// Add an error packet to the incoming queue. /// </summary> public void AddError(string error) { AddError(Buffer.Create(), error); }
/// <summary> /// Add this packet to the incoming queue. /// </summary> public void AddPacket(Buffer buff) { lock (mIn) mIn.Enqueue(buff); lastReceivedTime = DateTime.UtcNow.Ticks / 10000; }
/// <summary> /// See if the received packet can be processed and split it up into different ones. /// </summary> bool ProcessBuffer(byte[] bytes, int offset, int byteCount) { if (offset + byteCount > bytes.Length) { LogError("ProcessBuffer(" + bytes.Length + " bytes, offset " + offset + ", count " + byteCount); return(false); } if (mReceiveBuffer == null) { // Create a new packet buffer mReceiveBuffer = Buffer.Create(); mReceiveBuffer.BeginWriting(false).Write(bytes, offset, byteCount); mExpected = 0; mOffset = 0; } else { // Append this data to the end of the last used buffer mReceiveBuffer.BeginWriting(true).Write(bytes, offset, byteCount); } for (mAvailable = mReceiveBuffer.size - mOffset; mAvailable > 4;) { // Figure out the expected size of the packet if (mExpected == 0) { mExpected = mReceiveBuffer.PeekInt(mOffset); // "GET " -- HTTP GET request sent by a web browser if (mExpected == 542393671) { if (httpGetSupport) { if (stage == Stage.Verifying || stage == Stage.WebBrowser) { stage = Stage.WebBrowser; string request = Encoding.ASCII.GetString(mReceiveBuffer.buffer, mOffset, mAvailable); mReceiveBuffer.BeginPacket(Packet.RequestHTTPGet).Write(request); mReceiveBuffer.EndPacket(); mReceiveBuffer.BeginReading(4); lock (mIn) { mIn.Enqueue(mReceiveBuffer); mReceiveBuffer = null; mExpected = 0; mOffset = 0; } } return(true); } mReceiveBuffer.Recycle(); mReceiveBuffer = null; mExpected = 0; mOffset = 0; Disconnect(); return(false); } else if (mExpected < 0 || mExpected > 16777216) { #if UNITY_EDITOR LogError("Malformed data packet: " + mOffset + ", " + mAvailable + " / " + mExpected); var temp = new byte[mReceiveBuffer.size]; for (int i = 0; i < byteCount; ++i) { temp[i] = mReceiveBuffer.buffer[i]; } var fn = "error_" + lastReceivedTime + ".full"; Tools.WriteFile(fn, temp); Debug.Log("Packet saved as " + fn); #else LogError("Malformed data packet: " + mOffset + ", " + mAvailable + " / " + mExpected); #endif mReceiveBuffer.Recycle(); mReceiveBuffer = null; mExpected = 0; mOffset = 0; Disconnect(); return(false); } } // The first 4 bytes of any packet always contain the number of bytes in that packet mAvailable -= 4; // If the entire packet is present if (mAvailable == mExpected) { // Reset the position to the beginning of the packet mReceiveBuffer.BeginReading(mOffset + 4); // This packet is now ready to be processed lock (mIn) { mIn.Enqueue(mReceiveBuffer); mReceiveBuffer = null; mExpected = 0; mOffset = 0; } break; } else if (mAvailable > mExpected) { // There is more than one packet. Extract this packet fully. int realSize = mExpected + 4; var temp = Buffer.Create(); // Extract the packet and move past its size component var bw = temp.BeginWriting(); bw.Write(mReceiveBuffer.buffer, mOffset, realSize); temp.BeginReading(4); // This packet is now ready to be processed lock (mIn) { mIn.Enqueue(temp); // Skip this packet mAvailable -= mExpected; mOffset += realSize; mExpected = 0; } } else { break; } } return(true); }
/// <summary> /// Load the channel's data from the specified file. /// </summary> public bool LoadFrom(BinaryReader reader) { int version = reader.ReadInt32(); if (version != Player.version) { return(false); } // Clear all RFCs, just in case for (int i = 0; i < rfcs.size; ++i) { RFC r = rfcs[i]; if (r.buffer != null) { r.buffer.Recycle(); } } rfcs.Clear(); created.Clear(); destroyed.Clear(); level = reader.ReadString(); data = reader.ReadString(); objectCounter = reader.ReadUInt32(); password = reader.ReadString(); persistent = reader.ReadBoolean(); playerLimit = reader.ReadUInt16(); int size = reader.ReadInt32(); for (int i = 0; i < size; ++i) { RFC rfc = new RFC(); rfc.uid = reader.ReadUInt32(); if (rfc.functionID == 0) { rfc.functionName = reader.ReadString(); } Buffer b = Buffer.Create(); b.BeginWriting(false).Write(reader.ReadBytes(reader.ReadInt32())); rfc.buffer = b; rfcs.Add(rfc); } size = reader.ReadInt32(); for (int i = 0; i < size; ++i) { CreatedObject co = new CreatedObject(); co.playerID = reader.ReadInt32(); co.objectID = reader.ReadUInt32(); co.objectIndex = reader.ReadUInt16(); co.type = 1; Buffer b = Buffer.Create(); b.BeginWriting(false).Write(reader.ReadBytes(reader.ReadInt32())); b.BeginReading(); co.buffer = b; created.Add(co); } size = reader.ReadInt32(); for (int i = 0; i < size; ++i) { destroyed.Add(reader.ReadUInt32()); } return(true); }
/// <summary> /// Process an incoming packet. /// </summary> bool ProcessPacket(Buffer buffer, IPEndPoint ip) { BinaryReader reader = buffer.BeginReading(); Packet request = (Packet)reader.ReadByte(); switch (request) { case Packet.RequestPing: { BeginSend(Packet.ResponsePing); EndSend(ip); break; } case Packet.RequestAddServer: { if (reader.ReadUInt16() != GameServer.gameID) { return(false); } ServerList.Entry ent = new ServerList.Entry(); ent.ReadFrom(reader); if (ent.externalAddress.Address.Equals(IPAddress.None) || ent.externalAddress.Address.Equals(IPAddress.IPv6None)) { ent.externalAddress = ip; } mList.Add(ent, mTime); #if STANDALONE Tools.Print(ip + " added a server (" + ent.internalAddress + ", " + ent.externalAddress + ")"); #endif return(true); } case Packet.RequestRemoveServer: { if (reader.ReadUInt16() != GameServer.gameID) { return(false); } IPEndPoint internalAddress, externalAddress; Tools.Serialize(reader, out internalAddress); Tools.Serialize(reader, out externalAddress); if (externalAddress.Address.Equals(IPAddress.None) || externalAddress.Address.Equals(IPAddress.IPv6None)) { externalAddress = ip; } RemoveServer(internalAddress, externalAddress); #if STANDALONE Tools.Print(ip + " removed a server (" + internalAddress + ", " + externalAddress + ")"); #endif return(true); } case Packet.RequestServerList: { if (reader.ReadUInt16() != GameServer.gameID) { return(false); } mList.WriteTo(BeginSend(Packet.ResponseServerList)); EndSend(ip); return(true); } } return(false); }