internal void SendCommand(UdpCommandType cmd) { if (CheckCanSend(true) == UdpSendFailReason.None) { UdpStream stream = socket.GetWriteStream(mtu << 3, UdpSocket.HeaderBitSize); stream.WriteByte((byte)cmd, 8); UdpHeader header = MakeHeader(false); header.Pack(stream, socket); UdpHandle handle = MakeHandle(ref header); handle.Object = null; if (SendStream(stream, handle, false)) { // track stats stats.PacketSent((uint)stream.Ptr >> 3); socket.Statistics.PacketSent((uint)stream.Ptr >> 3); } else { // should we do something here????? } } }
internal void SendObject(object o) { serializer.SendNext(o); while (serializer.HasQueuedObjects) { UdpSendFailReason reason = CheckCanSend(false); if (reason != UdpSendFailReason.None) { while (serializer.HasQueuedObjects) { socket.Raise(UdpEvent.PUBLIC_OBJECT_SEND_FAILED, this, serializer.NextObject(), reason); } break; } UdpStream stream = socket.GetWriteStream(mtu << 3, UdpSocket.HeaderBitSize); var initialPtr = stream.Ptr; // Erhune: added info object obj = serializer.NextObject(); if (serializer.Pack(stream, ref obj)) { if (stream.Overflowing && (socket.Config.AllowPacketOverflow == false)) { UdpLog.Error("Stream to {0} is overflowing (InitialPtr={1} Ptr={2} Len={3}), not sending {4}", endpoint.ToString(), initialPtr, stream.Ptr, stream.Length, obj); // Erhune: added info socket.Raise(UdpEvent.PUBLIC_OBJECT_SEND_FAILED, this, obj, UdpSendFailReason.StreamOverflow); return; } UdpHeader header = MakeHeader(true); header.Pack(stream, socket, shouldSendClock); UdpHandle handle = MakeHandle(ref header); handle.Object = obj; if (SendStream(stream, handle, alwaysSendMtu)) { // track stats stats.PacketSent((uint)stream.Ptr >> 3); socket.Statistics.PacketSent((uint)stream.Ptr >> 3); // push object to user thread socket.Raise(UdpEvent.PUBLIC_OBJECT_SENT, this, obj); } else { socket.Raise(UdpEvent.PUBLIC_OBJECT_SEND_FAILED, this, obj, UdpSendFailReason.SocketError); } } else { socket.Raise(UdpEvent.PUBLIC_OBJECT_SEND_FAILED, this, obj, UdpSendFailReason.SerializerReturnedFalse); } } }
UdpHandle MakeHandle(ref UdpHeader header) { UdpHandle handle = new UdpHandle(); handle.IsObject = header.IsObject; handle.ObjSequence = header.ObjSequence; handle.SendTime = header.Now; return(handle); }
void AckHandles(UdpHeader header, bool updateRtt) { while (!sendWindow.Empty) { UdpHandle handle = sendWindow.Peek(); int seqDistance = UdpMath.SeqDistance(handle.ObjSequence, header.AckSequence, UdpHeader.SEQ_PADD); if (seqDistance > 0) { break; } if (handle.IsObject) { if (seqDistance <= -UdpSocket.AckRedundancy) { // track stats stats.PacketLost(); socket.Statistics.PacketLost(); // handle lost ObjectLost(handle.Object); } else { if ((header.AckHistory & (1UL << -seqDistance)) != 0UL) { // track stats stats.PacketDelivered(); socket.Statistics.PacketDelivered(); // handle delivered objects ObjectDelivered(handle.Object); } else { // track stats stats.PacketLost(); socket.Statistics.PacketLost(); // handle ObjectLost(handle.Object); } } } if (seqDistance == 0 && header.AckTime > 0) { UpdatePing(recvTime, handle.SendTime, header.AckTime); } sendWindow.Dequeue(); } }
bool SendStream(UdpStream stream, UdpHandle handle, bool expandToMtu) { int bytesToSend = UdpMath.BytesRequired(stream.Ptr); if (bytesToSend < mtu && expandToMtu) { bytesToSend = mtu; } sendTime = handle.SendTime; sendSequence = handle.ObjSequence; sendWindow.Enqueue(handle); recvSinceLastSend = 0; return(socket.Send(endpoint, stream.Data, bytesToSend)); }
void OnStateDisconnected(UdpConnectionState oldState) { if (oldState == UdpConnectionState.Connected) { while (sendWindow.Empty == false) { UdpHandle handle = sendWindow.Dequeue(); if (handle.IsObject) { socket.Raise(UdpEvent.PUBLIC_OBJECT_LOST, this, handle.Object); } } socket.Raise(UdpEvent.PUBLIC_DISCONNECTED, this); } }
internal void StartReceiver() { this.Connection.StartNetworkStream(); if (UdpHandle != null) { this.UdpAsyncReceiveEvent = new SocketAsyncEventArgs(); this.UdpAsyncReceiveEvent.SetBuffer(new byte[70000], 0, 70000); this.UdpAsyncReceiveEvent.RemoteEndPoint = this.UdpEndPoint; this.UdpAsyncReceiveEvent.Completed += AsyncSocketCallback; this.UdpAsyncReceiveEvent.AcceptSocket = this.UdpHandle; if (!UdpHandle.ReceiveFromAsync(UdpAsyncReceiveEvent)) { AsyncSocketCallback(null, UdpAsyncReceiveEvent); } } }
bool SendStream(UdpStream stream, UdpHandle handle, bool expandToMtu) { int bytesToSend = UdpMath.BytesRequired(stream.Ptr); if (bytesToSend < mtu && expandToMtu) { bytesToSend = mtu; } sendTime = handle.SendTime; sendSequence = handle.ObjSequence; sendWindow.Enqueue(handle); recvSinceLastSend = 0; return socket.Send(endpoint, stream.Data, bytesToSend); }
UdpHandle MakeHandle(ref UdpHeader header) { UdpHandle handle = new UdpHandle(); handle.IsObject = header.IsObject; handle.ObjSequence = header.ObjSequence; handle.SendTime = header.Now; return handle; }
internal unsafe void AsyncSocketCallback(object o, SocketAsyncEventArgs e) { if (e.LastOperation == SocketAsyncOperation.ReceiveFrom) { try { if (e.BytesTransferred >= 21) { if (!Connected) { return; //TCP Client is disconnected so don't process UDP packets } //before we process the packet, does the IP/LocalPort match ? if (UdpHandshaked && BitConverter.ToUInt32(this.UdpEndPoint.Address.GetAddressBytes(), 0) != BitConverter.ToUInt32(((IPEndPoint)e.RemoteEndPoint).Address.GetAddressBytes(), 0)) { //simply skip and don't disconnect TCP //I'll add later a option to the server to disconnect or not just for safety reasons ;) return; } //decrypt traffic here PayloadReader pr = new PayloadReader(e.Buffer); decimal clientId = pr.ReadDecimal(); //extra check if (this.ClientId != clientId) { return; } UdpPAcketId packetId = (UdpPAcketId)pr.ReadByte(); uint MessageId = pr.ReadUInteger(); IMessage message = null; try { message = Connection.messageHandler.HandleUdpMessage(pr, MessageId); if (message != null) { message.RawSize = e.BytesTransferred; } } catch (Exception ex) { return; } //process packet if (UdpHandshaked) { switch (packetId) { case UdpPAcketId.Payload: { //onReceiveUdpMessage(message); break; } } } else { MsgUdpHandshake HandshakeMsg = message as MsgUdpHandshake; if (HandshakeMsg != null) { fixed(byte *ptr = HandshakeMsg.HandshakeCode, ptr2 = this.UdpHandshakeCode) { if (NativeMethods.memcmp(ptr, ptr2, (uint)this.UdpHandshakeCode.Length) == 0) { this.UdpEndPoint = e.RemoteEndPoint as IPEndPoint; Connection.SendPayload(new MsgUdpValidation(new byte[] { 0x8F, 0xFF, 0x46, 0x4F, 0x37 }), PacketId.Unknown); UdpHandshaked = true; UdpSyncObject.Value = true; UdpSyncObject.Pulse(); } } } } } } catch (Exception ex) { onException(ex, ErrorType.Core); } if (PeerSide == SecureSocketProtocol2.PeerSide.Client) { if (!UdpHandle.ReceiveFromAsync(UdpAsyncReceiveEvent)) { AsyncSocketCallback(null, UdpAsyncReceiveEvent); } } } else { } }
internal void Disconnect(DisconnectReason Reason) { //disconnect all plugins try { for (int i = 0; i < Plugins.Plugins.Length; i++) { if (Plugins.Plugins[i].AllowPluginHooks() && Plugins.Plugins[i].Hooks.Count > 0) { foreach (IPluginHook hook in Plugins.Plugins[i].Hooks) { hook.onClientDisconnected(); } } try { Plugins.Plugins[i].onClientDisconnected(); } catch { } } } catch (Exception ex) { onException(ex, ErrorType.UserLand); } try { lock (Connection) { if (this.Connected && !ConnectionClosedNormal) { Connection.SendPayload(new MsgDisconnected(Reason), PacketId.Disconnected); ConnectionClosedNormal = true; } } } catch (Exception ex) { onException(ex, ErrorType.Core); } try { Handle.Close(); } catch { } try { if (UdpHandle != null) { UdpHandle.Close(); } } catch (Exception ex) { onException(ex, ErrorType.Core); } this.Connection.State = ConnectionState.Closed; try { onDisconnect(Reason); } catch (Exception ex) { onException(ex, ErrorType.UserLand); } }