/// <summary> /// Send unencrypted packet to server /// </summary> public bool SendRaw(Packet pkt) { m_sendLock.WaitOne(); byte[] toSend; OnSendRawData(pkt, out toSend); DataChunk wrap = new DataChunk(toSend.Length) {Data = toSend}; try { m_sock.BeginSend(wrap.Data, 0, wrap.Data.Length, SocketFlags.None, _sendCB, wrap); } catch (SocketException) { return false; } return true; }
/// <summary> /// Processes the data chunk that was received from the server - MUST BE OVERRIDDEN WITH PROCESSING LOGIC /// </summary> protected abstract void OnReceiveData(DataChunk wrappedData);
/// <summary> /// Starts an asyncronous receive operation on the underlying socket /// </summary> protected void StartDataReceive(DataChunk buffer) { m_sock.BeginReceive(buffer.Data, 0, buffer.Data.Length, SocketFlags.None, _recvCB, buffer); }
//--------------------------------------- // Send a packet to the server //--------------------------------------- public bool SendPacket(Packet pkt) { if (!m_sendLock.WaitOne(Constants.ResponseTimeout)) //do one send at a time return false; byte[] toSend; OnSendData(pkt, out toSend); DataChunk wrap = new DataChunk(toSend.Length) {Data = toSend}; try { m_sock.BeginSend(wrap.Data, 0, wrap.Data.Length, SocketFlags.None, _sendCB, wrap); } catch (SocketException) { //connection aborted by hardware errors produce a socketexception. return false; } return true; }
/// <summary> /// Provides for implementation-specific logic to be called on a successful socket connect() operation /// </summary> protected virtual void OnConnect() { DataChunk wrap = new DataChunk(); m_sock.BeginReceive(wrap.Data, 0, wrap.Data.Length, SocketFlags.None, _recvCB, wrap); }
protected override void OnReceiveData(DataChunk state) { EODataChunk wrap = (EODataChunk)state; if (wrap.Data.Length == 0) wrap.State = EODataChunk.DataReceiveState.NoData; try { switch (wrap.State) { case EODataChunk.DataReceiveState.ReadLen1: { wrap.RawLength[0] = wrap.Data[0]; wrap.State = EODataChunk.DataReceiveState.ReadLen2; wrap.Data = new byte[EODataChunk.BUFFER_SIZE]; StartDataReceive(wrap); break; } case EODataChunk.DataReceiveState.ReadLen2: { wrap.RawLength[1] = wrap.Data[0]; wrap.State = EODataChunk.DataReceiveState.ReadData; wrap.Data = new byte[Packet.DecodeNumber(wrap.RawLength)]; StartDataReceive(wrap); break; } case EODataChunk.DataReceiveState.ReadData: { byte[] data = new byte[wrap.Data.Length]; Array.Copy(wrap.Data, data, data.Length); m_packetProcessor.Decode(ref data); //This block handles receipt of file data that is transferred to the client. //It should make file transfer nuances pretty transparent to the client. //The header for files stored in a Packet type is always as follows: FAMILY_INIT, ACTION_INIT, (InitReply) //A 3-byte offset is found throughout the code that handles creating these files. if (data[0] == 255 && data[1] == 255) //INIT_INIT packet! check to see if expecting a file or player list { Packet pkt = new Packet(data); byte reply = pkt.GetChar(); if (ExpectingFile || reply == (byte)InitReply.INIT_MAP_MUTATION) //handle the map mutation: should work with the byte/char weirdness { int dataGrabbed = 0; //find first zero byte int pktOffset = 0; for (; pktOffset < data.Length; ++pktOffset) if (data[pktOffset] == 0) break; //continue receiving until we have grabbed enough data to fill the allocated packet buffer do { byte[] fileBuffer = new byte[pkt.Length - pktOffset]; int nextGrabbed = ReceiveRaw(ref fileBuffer); Array.Copy(fileBuffer, 0, data, dataGrabbed + 3, data.Length - (dataGrabbed + pktOffset)); dataGrabbed += nextGrabbed; } while (dataGrabbed < pkt.Length - pktOffset); if (pktOffset > 3) data = data.SubArray(0, pkt.Length - (pktOffset - 3)); //rewrite the InitReply with the correct value (retrieved with GetChar, server sends with GetByte for other reply types) data[2] = reply; } else if (ExpectingPlayerList) { //online list sends a char... rewrite it with a byte so it is parsed correctly. data[2] = reply; } } ThreadPool.QueueUserWorkItem(_handlePacket, new Packet(data)); EODataChunk newWrap = new EODataChunk(); StartDataReceive(newWrap); break; } default: { Console.WriteLine("ERROR: Invalid data wrapper state in _recvCB (should be ReadLen1, ReadLen2, or ReadData). Closing connection."); Disconnect(); break; } } } catch (SocketException se) { //in the process of disconnecting Console.WriteLine("There was a SocketException with SocketErrorCode {0} in _recvCB", se.SocketErrorCode); } }