/// <summary> /// Blocking receive TCP call. /// </summary> /// <returns></returns> public bool ProcessReceive() { try { //OwningConnection.MyTCPSocket.Blocking = true; SocketDebug(5); if (OwningConnection.MyTCPSocket.Connected && OwningConnection.MyTCPSocket.Poll(0, SelectMode.SelectRead)) { SocketDebug(6); m_TCPBytesReceived = OwningConnection.MyTCPSocket.Receive(m_TCPBuffer, 0, m_TCPBuffer.Length, SocketFlags.None, out m_LastTCPReceiveStatus); SocketDebug(7); Log.LogMsg("Received " + m_TCPBytesReceived.ToString() + " on socket " + OwningConnection.MyTCPSocket.Handle.ToString() + " with socket error reading " + m_LastTCPReceiveStatus.ToString()); OnReceiveResolved(false, m_TCPBuffer, m_TCPBytesReceived, m_LastTCPReceiveStatus, m_TCPSockState); } else if (!OwningConnection.IsAlive) { SocketDebug(8); Log.LogMsg("DuplexBlockingTransit can't ProcessReceive because OwningConnection is not connected."); Log.LogMsg("Can't receive on socket " + OwningConnection.MyTCPSocket.Handle.ToString() + " with socket error reading " + m_LastTCPReceiveStatus.ToString()); OwningConnection.KillConnection("Couldn't receive. Connection has been closed."); SocketDebug(9); } } catch (Exception e) { string error = "";// OwningConnection.MyTCPSocket.GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.Error).ToString(); Log.LogMsg("Error receiving data on DuplexBlockingTransit. (" + error + ")" + e.Message + ", Stack=\r\n" + e.StackTrace); OwningConnection.KillConnection("Connection lost! Network receive error: " + e.Message); } return(true); }
private void SendBytes(bool isUDP, byte[] data) { try { if (!OwningConnection.IsConnected) { return; } if (isUDP) { SocketDebug(777); OwningConnection.MyUDPSocket.SendTo(data, OwningConnection.UDPSendTarget); } else { SocketDebug(3); OwningConnection.MyTCPSocket.Blocking = true; OwningConnection.MyTCPSocket.Send(data); SocketDebug(4); } OwningConnection.SentBytes(data); OwningConnection.PacketSent(); } catch (Exception e) { Log.LogMsg("Error SendBytes. " + e.Message); OwningConnection.KillConnection("Send error. " + e.Message); } }
private void IO_Completed(object sender, SocketAsyncEventArgs e) { try { // determine which type of operation just completed and call the associated handler switch (e.LastOperation) { case SocketAsyncOperation.Receive: OnReceiveResolved(e); break; case SocketAsyncOperation.Send: #if !SILVERLIGHT case SocketAsyncOperation.SendTo: #endif //Log.LogMsg("Send EVENT completed for @" + ((SockState)e.UserToken).ID.ToString() + "@"); OnSendResolved(e, e.UserToken as SockState); break; default: //This exception will occur if you code the Completed event of some //operation to come to this method, by mistake. throw new ArgumentException("The last operation completed on the socket was not a receive or send"); } } catch (Exception ex) { Log.LogMsg("Error in IO_Completed. " + ex.Message); OwningConnection.KillConnection("Error I/O. " + ex.Message); } }
/// <summary> /// Gets called when a receive operation resolves. If we were listening for data and the connection /// closed, that also counts as a receive operation resolving. /// </summary> /// <param name="args"></param> private void OnReceiveResolved(bool isUDP, byte[] buffer, int bytesReceived, SocketError status, SockState sockState) { SocketDebug(19); //// Log.LogMsg("==>++++ Async RECEIVE Op Completed - #" + ((SockState)args.UserToken).ID.ToString() + "#"); try { if (!OwningConnection.IsAlive && bytesReceived > 0) { SocketDebug(20); return; } SocketDebug(21); // If there was a socket error, close the connection. This is NOT a normal // situation, if you get an error here. if (status != SocketError.Success) { SocketDebug(22); Log.LogMsg("Receive status = " + status.ToString()); if (!OwningConnection.ShuttingDown) { //// Log.LogMsg("Testy 111"); OwningConnection.KillConnection("Connection lost! Network receive error: " + status); } //Jump out of the ProcessReceive method. SocketDebug(23); return; } SocketDebug(24); m_TCPSockState.AsyncEventArgs.RemoteEndPoint = OwningConnection.MyTCPSocket.RemoteEndPoint; // If no data was received, close the connection. This is a NORMAL // situation that shows when the client has finished sending data. if (bytesReceived == 0) { SocketDebug(25); if (!OwningConnection.ShuttingDown) { //// Log.LogMsg("Testy 114"); OwningConnection.KillConnection("Connection closed by remote host."); } return; } SocketDebug(26); OwningConnection.ReceivedBytes(bytesReceived); // restart listening process SocketDebug(27); OwningConnection.AssembleInboundPacket(buffer, bytesReceived, sockState); SocketDebug(28); } catch (Exception ex) { Log.LogMsg("Error ProcessReceive. " + ex.Message); OwningConnection.KillConnection("Error receive. " + ex.Message); } }
protected Queue <NetQItem> m_SendQueue = new Queue <NetQItem>(); // packet send queue /// <summary> /// Sends arbitrary bytes of data across the wire. Note that if the remote endpoint can't decipher the data /// as a known packet, the connection will be dropped by that endpoint immediately. /// </summary> /// <param name="data">bytes to send</param> public virtual int Send(byte[] data, PacketFlags flags) { SocketDebug(32); //Log.LogMsg("@__@ Monitor Enter"); if (!OwningConnection.IsAlive) { Log.LogMsg("DuplexBlockingTransit - cant send data because owning connection isn't alive. MyTcpSocket == Null -> " + (OwningConnection.MyTCPSocket == null)); Log.LogMsg("Can't send on socket " + OwningConnection.MyTCPSocket.Handle.ToString() + " with socket error reading " + m_LastTCPReceiveStatus.ToString()); OwningConnection.KillConnection("Couldn't send. Connection has been closed."); return(-1); } SocketDebug(33); // Log.LogMsg("==>Sending " + data.Length.ToString() + " bytes."); try { bool isUDP = (flags & PacketFlags.UDP) != 0; if (isUDP) { SocketDebug(34); if (!OwningConnection.CanSendUDP) { Log.LogMsg("!!! Tried sending UDP packet when the connection wasn't yet ready to send UDP. Dropping packet."); return(0); } SocketDebug(35); // Don't allow fragmenting UDP packets if (data.Length > 1024) { Log.LogMsg("Message exceeded UDP size of 1024 bytes. Sending via TCP instead."); flags &= ~PacketFlags.UDP; } } SocketDebug(36); NetQItem qi = new NetQItem(); qi.Flags = flags; qi.Data = data; qi.IsUDP = isUDP; m_SendQueue.Enqueue(qi); Log.LogMsg("Send queue now has " + m_SendQueue.Count.ToString() + " items in it."); SocketDebug(37); return(1); } catch (Exception sendExc) { Log.LogMsg("DuplexBlockingTransit - Failed to send data. " + sendExc.Message); return(-1);; } return(1); }
/// <summary> /// Gets called when a receive operation resolves. If we were listening for data and the connection /// closed, that also counts as a receive operation resolving. /// </summary> /// <param name="args"></param> private void OnReceiveResolved(SocketAsyncEventArgs args) { // Log.LogMsg("Testy 21"); // Log.LogMsg("==>++++ Async RECEIVE Op Completed - #" + ((SockState)args.UserToken).ID.ToString() + "#"); try { if (!OwningConnection.IsAlive && args.BytesTransferred > 0) { // Log.LogMsg("Testy 22"); return; } SockState state = args.UserToken as SockState; // If there was a socket error, close the connection. This is NOT a normal // situation, if you get an error here. if (args.SocketError != SocketError.Success) { // Log.LogMsg("Testy 222"); OwningConnection.KillConnection("Connection lost! Network receive error: " + args.SocketError); //Jump out of the ProcessReceive method. return; } // If no data was received, close the connection. This is a NORMAL // situation that shows when the client has finished sending data. if (args.BytesTransferred == 0) { // Log.LogMsg("Testy 223"); OwningConnection.KillConnection("Connection closed by remote host."); return; } //// Log.LogMsg("Testy 224"); OwningConnection.ReceivedBytes(args.BytesTransferred); // restart listening process //// Log.LogMsg("Testy 225"); OwningConnection.AssembleInboundPacket(args, state); //// Log.LogMsg("Testy 226"); ListenForDataOnSocket(); } catch (Exception ex) { //// Log.LogMsg("Testy 23"); Log.LogMsg("Error ProcessReceive. " + ex.Message); OwningConnection.KillConnection("Error receive. " + ex.Message); } }
/// <summary> /// Serializes and sends a packet across the wire /// </summary> /// <param name="msg">The packet to send</param> public virtual int Send(Packet msg) { try { if (msg.NeedsDeliveryAck) { m_NumAcksWaitingFor++; } byte[] raw = OwningConnection.SerializePacket(msg); //Log.LogMsg("Sending -> " + msg.GetType().ToString() + " (" + raw.Length.ToString() + " bytes)"); //Log.LogMsg(" That message is " + raw.Length.ToString() + " bytes long"); return(Send(raw, msg.Flags)); } catch (Exception sendExc) { OwningConnection.KillConnection(sendExc.Message); return(-1);; } }
private void SendBytes(bool isUDP, byte[] data) { try { SocketDebug(10); if (!OwningConnection.IsConnected) { SocketDebug(11); Log.LogMsg("DuplexBlockingTransit can't send bytes. OwningConnection is not connected."); return; } if (isUDP) { SocketDebug(12); OwningConnection.MyUDPSocket.SendTo(data, OwningConnection.UDPSendTarget); // Log.LogMsg("Testy UDP SEND COMPLETE. Is owning connection still alive? " + OwningConnection.IsAlive); } else { //OwningConnection.MyTCPSocket.Blocking = true; SocketDebug(15); OwningConnection.MyTCPSocket.Send(data); SocketDebug(16); } SocketDebug(17); OwningConnection.SentBytes(data); OwningConnection.PacketSent(); SocketDebug(18); } catch (Exception e) { Log.LogMsg("Error SendBytes. " + e.Message); OwningConnection.KillConnection("Send error. " + e.Message); } }
/// <summary> /// Serializes and sends a packet across the wire /// </summary> /// <param name="msg">The packet to send</param> public virtual int Send(Packet msg) { try { SocketDebug(29); if (msg.NeedsDeliveryAck) { m_NumAcksWaitingFor++; } SocketDebug(30); byte[] raw = OwningConnection.SerializePacket(msg); SocketDebug(31); Log.LogMsg("Sending -> " + msg.GetType().ToString() + " (" + raw.Length.ToString() + " bytes)"); Log.LogMsg("That message is " + raw.Length.ToString() + " bytes long"); Log.LogMsg("1 Socket " + OwningConnection.MyTCPSocket.Handle.ToString() + "IsAlive=" + OwningConnection.MyTCPSocket.Connected.ToString() + ", with socket error reading " + m_LastTCPReceiveStatus.ToString()); return(Send(raw, msg.Flags)); } catch (Exception sendExc) { OwningConnection.KillConnection(sendExc.Message); return(-1);; } }
/// <summary> /// Gets called when a send operation resolves. /// </summary> private void OnSendResolved(SocketAsyncEventArgs args, SockState state) { //// Log.LogMsg("Testy 13"); try { OwningConnection.SentBytes(state.PacketBufferPointer.Position); bool isUDP = (state.Flags & PacketFlags.UDP) != 0; //Log.LogMsg("==>#### Async SEND Op Completed - #" + ((SockState)args.UserToken).ID.ToString() + "#"); if (args.SocketError == SocketError.Success) { //// Log.LogMsg("Testy 14"); state.PacketBufferPointer.Advance(args.BytesTransferred); if (state.PacketBufferPointer.Position >= state.PacketBuffer.Length) { OwningConnection.PacketSent(); // Done sending packet. state.Reset(); //Log.LogMsg("==>Done sending packet. Sent " + state.PacketBufferPointer.Position.ToString() + " bytes."); // done sending packet, see if we have anything in the queue ready to go bool more = false; Queue <NetQItem> sendQ = isUDP ? m_SendQueueUDP : m_SendQueue; lock (sendQ) { if (sendQ.Count > 0) { NetQItem itm = sendQ.Dequeue(); state.PacketBuffer = itm.Data; state.Flags = itm.Flags; more = true; } else { // release the sending lock if (isUDP) { //Log.LogMsg("UDP send queue emptied."); Interlocked.Exchange(ref m_SendingUDP, 0); } else { //Log.LogMsg("TCP send queue emptied."); Interlocked.Exchange(ref m_Sending, 0); } } } if (more) { //// Log.LogMsg("Testy 15"); SendBuffer(args, state, isUDP); } return; } else { //// Log.LogMsg("Testy 16"); // not done sending. send again. //Log.LogMsg("==>Continuing send. " + state.PacketBufferPointer.Position.ToString() + " / " + state.PacketBuffer.Length.ToString() + " sent so far."); SendBuffer(args, state, isUDP); } } else { //If we are in this else-statement, there was a socket error. OwningConnection.KillConnection("Error sending packet. " + args.SocketError.ToString()); } } catch (Exception ex) { //// Log.LogMsg("Testy 17"); Log.LogMsg("Failed to ProcessSend. " + ex.Message); OwningConnection.KillConnection("Send error. " + ex.Message); } }
/// <summary> /// We dont usually send everything all at once in the buffer. This method sends what's in the buffer out in a piece by piece fashion. /// </summary> private void SendBuffer(SocketAsyncEventArgs args, SockState state, bool isUDP) { try { #if !SILVERLIGHT //Log.LogMsg("==>$$$$ Async SEND op started - #" + ((SockState)args.UserToken).ID.ToString() + "#"); if (!OwningConnection.BlockingMode) #endif { int toSend = state.PacketBuffer.Length - state.PacketBufferPointer.Position; if (toSend > state.BufferBlockLength) { toSend = state.BufferBlockLength; } args.SetBuffer(state.BufferBlockOffset, toSend); Util.Copy(state.PacketBuffer, state.PacketBufferPointer.Position, args.Buffer, state.BufferBlockOffset, toSend); Socket socket = OwningConnection.MyTCPSocket; #if !SILVERLIGHT if (isUDP) { socket = OwningConnection.MyUDPSocket; //Log.LogMsg("UDP Send Target = " + SendTarget.ToString()); args.RemoteEndPoint = OwningConnection.UDPSendTarget; if (!socket.SendToAsync(args)) { //// Log.LogMsg("Testy 7"); OnSendResolved(args, state); } } else #endif { if (!socket.SendAsync(args)) { //// Log.LogMsg("Testy 8"); OnSendResolved(args, state); } } } #if !SILVERLIGHT else { if (isUDP) { //// Log.LogMsg("Testy 9"); OwningConnection.MyUDPSocket.SendTo(state.PacketBuffer, OwningConnection.UDPSendTarget); } else { //// Log.LogMsg("Testy 10"); OwningConnection.MyTCPSocket.Blocking = true; OwningConnection.MyTCPSocket.Send(state.PacketBuffer); } //// Log.LogMsg("Testy 11"); OwningConnection.SentBytes(state.PacketBuffer); OwningConnection.PacketSent(); } #endif } catch (Exception e) { //// Log.LogMsg("Testy 12"); Log.LogMsg("Error SendBuffer. " + e.Message); OwningConnection.KillConnection("Send error. " + e.Message); } }
/// <summary> /// Sends arbitrary bytes of data across the wire. Note that if the remote endpoint can't decipher the data /// as a known packet, the connection will be dropped by that endpoint immediately. /// </summary> /// <param name="data">bytes to send</param> public virtual int Send(byte[] data, PacketFlags flags) { //Log.LogMsg("@__@ Monitor Enter"); if (!OwningConnection.IsAlive) { //// Log.LogMsg("Testy 3"); return(-1); } //Log.LogMsg("==>Sending " + data.Length.ToString() + " bytes."); try { bool isUDP = (flags & PacketFlags.UDP) != 0; #if SILVERLIGHT // Silverlight can't do UDP and it can only send Async, i.e. Non-Blocking isUDP = false; OwningConnection.BlockingMode = false; #endif if (isUDP) { //// Log.LogMsg("Testy 4"); if (!OwningConnection.CanSendUDP) { Log.LogMsg("!!! Tried sending UDP packet when the connection wasn't yet ready to send UDP. Dropping packet."); return(0); } // Don't allow fragmenting UDP packets if (data.Length > m_SendArgsUDP.Buffer.Length && data.Length > 1024) { Log.LogMsg("Message exceeded UDP size. Sending via TCP instead."); flags &= ~PacketFlags.UDP; } } if (!OwningConnection.BlockingMode) { // send via asyncsend, but only one send op can be in progress at one time // out of order packets can happen because the actual send is done with I/O completion ports and if multiple // packets get submitted to the I/O queue they could be processed out of order, especially if the packet are of wildly differing sizes if (isUDP) { //// Log.LogMsg("Testy 5"); lock (m_SendQueueUDP) { if (1 == Interlocked.Exchange(ref m_SendingUDP, 1)) { // failed to get the lock - a message is in progress. queue message. NetQItem qi = new NetQItem(); qi.Flags = flags; qi.Data = data; m_SendQueueUDP.Enqueue(qi); Log.LogMsg("Queueing UDP packet. Now " + m_SendQueueUDP.Count.ToString() + " in Queue."); return(1); } //Log.LogMsg("Acquired UDP send lock."); } } else { lock (m_SendQueue) { if (1 == Interlocked.Exchange(ref m_Sending, 1)) { // failed to get the lock - a message is in progress. queue message. NetQItem qi = new NetQItem(); qi.Flags = flags; qi.Data = data; m_SendQueue.Enqueue(qi); Log.LogMsg("Queueing TCP packet. Now " + m_SendQueue.Count.ToString() + " in Queue."); return(1); } //Log.LogMsg("Acquired TCP send lock."); } } } SocketAsyncEventArgs args = isUDP ? m_SendArgsUDP : m_SendArgs; SockState state = args.UserToken as SockState; state.Flags = flags; state.PacketBuffer = data; //// Log.LogMsg("Testy 6"); SendBuffer(args, state, isUDP); } catch (Exception sendExc) { OwningConnection.KillConnection(sendExc.Message); return(-1);; } return(1); }