private void OnWrite(Unit w, Action OnSuccess, Action OnFailure) { var ByteArrays = vts.TakeWriteBuffer(); var TotalLength = ByteArrays.Sum(b => b.Length); var WriteBuffer = new Byte[GetMinNotLessPowerOfTwo(TotalLength)]; var Offset = 0; foreach (var b in ByteArrays) { Array.Copy(b, 0, WriteBuffer, Offset, b.Length); Offset += b.Length; } var RemoteEndPoint = this.RemoteEndPoint; var SessionId = this.SessionId; var SecureContext = this.SecureContext; var Indices = new List <int>(); RawReadingContext.DoAction(c => { if (c.NotAcknowledgedIndices.Count == 0) { return; } var MaxHandled = c.Parts.MaxHandled; var Acknowledged = new List <int>(); foreach (var i in c.NotAcknowledgedIndices) { if (c.Parts.IsEqualOrAfter(MaxHandled, i)) { Acknowledged.Add(i); } else if (PartContext.IsSuccessor(i, MaxHandled)) { Acknowledged.Add(i); MaxHandled = i; } } foreach (var i in Acknowledged) { c.NotAcknowledgedIndices.Remove(i); } Indices.Add(MaxHandled); Indices.AddRange(c.NotAcknowledgedIndices); c.NotAcknowledgedIndices.Clear(); }); if ((ByteArrays.Length == 0) && (Indices.Count == 0)) { OnSuccess(); return; } var Success = true; var Parts = new List <Byte[]>(); CookedWritingContext.DoAction(c => { var Time = DateTime.UtcNow; var WritingOffset = 0; while ((Indices.Count > 0) || (WritingOffset < TotalLength)) { var Index = PartContext.GetSuccessor(c.WritenIndex); var NumIndex = Indices.Count; if (NumIndex > 0xFFFF) { Success = false; return; } var IsACK = NumIndex > 0; var Length = Math.Min(12 + (IsACK ? 2 + NumIndex * 2 : 0) + TotalLength - WritingOffset, MaxPacketLength); var DataLength = Length - (12 + (IsACK ? 2 + NumIndex * 2 : 0)); if (DataLength < 0) { Success = false; return; } var Buffer = new Byte[Length]; Buffer[0] = (Byte)(SessionId & 0xFF); Buffer[1] = (Byte)((SessionId >> 8) & 0xFF); Buffer[2] = (Byte)((SessionId >> 16) & 0xFF); Buffer[3] = (Byte)((SessionId >> 24) & 0xFF); var Flag = 0; if (IsACK) { Flag |= 1; //ACK Buffer[12] = (Byte)(NumIndex & 0xFF); Buffer[13] = (Byte)((NumIndex >> 8) & 0xFF); var j = 0; foreach (var i in Indices) { Buffer[14 + j * 2] = (Byte)(i & 0xFF); Buffer[14 + j * 2 + 1] = (Byte)((i >> 8) & 0xFF); j += 1; } Indices.Clear(); } Array.Copy(WriteBuffer, WritingOffset, Buffer, 12 + (IsACK ? 2 + NumIndex * 2 : 0), DataLength); WritingOffset += DataLength; var IsEncrypted = (SecureContext != null); if (IsEncrypted) { Flag |= 2; //ENC } Buffer[4] = (Byte)(Flag & 0xFF); Buffer[5] = (Byte)((Flag >> 8) & 0xFF); Buffer[6] = (Byte)(Index & 0xFF); Buffer[7] = (Byte)((Index >> 8) & 0xFF); var Verification = 0; if (SecureContext != null) { var Key = SecureContext.ServerToken.Concat(Cryptography.SHA256(Buffer.Skip(4).Take(4))); var HMACBytes = Cryptography.HMACSHA256Simple(Key, Buffer).Take(4).ToArray(); Verification = HMACBytes[0] | ((Int32)(HMACBytes[1]) << 8) | ((Int32)(HMACBytes[2]) << 16) | ((Int32)(HMACBytes[3]) << 24); } else { Verification = Cryptography.CRC32(Buffer); } Buffer[8] = (Byte)(Verification & 0xFF); Buffer[9] = (Byte)((Verification >> 8) & 0xFF); Buffer[10] = (Byte)((Verification >> 16) & 0xFF); Buffer[11] = (Byte)((Verification >> 24) & 0xFF); var Part = new Part { Index = Index, ResendTime = Time.AddIntMilliseconds(GetTimeoutMilliseconds(0)), Data = Buffer, ResentCount = 0 }; if (!c.Parts.TryPushPart(Index, Buffer)) { Success = false; return; } Parts.Add(Part.Data); if (Server.ServerContext.EnableLogTransport) { Server.ServerContext.RaiseSessionLog(new SessionLogEntry { Token = SessionId.ToString("X8"), RemoteEndPoint = RemoteEndPoint, Time = DateTime.UtcNow, Type = "UdpTransport", Name = "Send", Message = "Index: " + Index.ToInvariantString() + " Length: " + Part.Data.Length.ToInvariantString() }); } c.WritenIndex = Index; } }); foreach (var p in Parts) { try { SendPacket(RemoteEndPoint, p); } catch { Success = false; break; } } if (!Success) { OnFailure(); } else { OnSuccess(); } }
private void OnWrite(IStreamedVirtualTransportClient vtc, Action OnSuccess, Action <SocketError> OnFailure) { var ByteArrays = vtc.TakeWriteBuffer(); var TotalLength = ByteArrays.Sum(b => b.Length); var WriteBuffer = new Byte[GetMinNotLessPowerOfTwo(TotalLength)]; var Offset = 0; foreach (var b in ByteArrays) { Array.Copy(b, 0, WriteBuffer, Offset, b.Length); Offset += b.Length; } var RemoteEndPoint = this.RemoteEndPoint; int SessionId = 0; var State = ConnectionState.Initial; this.ConnectionStateValue.Update(v => { SessionId = this.SessionId; State = v; if (v == ConnectionState.Initial) { return(ConnectionState.Connecting); } return(v); }); if (State == ConnectionState.Connecting) { throw new InvalidOperationException(); } var SecureContext = this.SecureContext; var Indices = new List <int>(); RawReadingContext.DoAction(c => { if (c.NotAcknowledgedIndices.Count == 0) { return; } var MaxHandled = c.Parts.MaxHandled; var Acknowledged = new List <int>(); foreach (var i in c.NotAcknowledgedIndices) { if (c.Parts.IsEqualOrAfter(MaxHandled, i)) { Acknowledged.Add(i); } else if (PartContext.IsSuccessor(i, MaxHandled)) { Acknowledged.Add(i); MaxHandled = i; } } foreach (var i in Acknowledged) { c.NotAcknowledgedIndices.Remove(i); } Indices.Add(MaxHandled); Indices.AddRange(c.NotAcknowledgedIndices); c.NotAcknowledgedIndices.Clear(); }); if ((ByteArrays.Length == 0) && (Indices.Count == 0)) { OnSuccess(); return; } var se = SocketError.Success; var Parts = new List <Byte[]>(); CookedWritingContext.DoAction(c => { var Time = DateTime.UtcNow; var WritingOffset = 0; while (WritingOffset < TotalLength) { var Index = PartContext.GetSuccessor(c.WritenIndex); var NumIndex = Indices.Count; if (NumIndex > 0xFFFF) { se = SocketError.NoBufferSpaceAvailable; return; } var IsACK = NumIndex > 0; var Flag = 0; if (State == ConnectionState.Initial) { Flag |= 4; //INI IsACK = false; } var Length = Math.Min(12 + (IsACK ? 2 + NumIndex * 2 : 0) + TotalLength - WritingOffset, MaxPacketLength); var DataLength = Length - (12 + (IsACK ? 2 + NumIndex * 2 : 0)); if (DataLength < 0) { se = SocketError.NoBufferSpaceAvailable; return; } var Buffer = new Byte[Length]; Buffer[0] = (Byte)(SessionId & 0xFF); Buffer[1] = (Byte)((SessionId >> 8) & 0xFF); Buffer[2] = (Byte)((SessionId >> 16) & 0xFF); Buffer[3] = (Byte)((SessionId >> 24) & 0xFF); if (IsACK) { Flag |= 1; //ACK Buffer[12] = (Byte)(NumIndex & 0xFF); Buffer[13] = (Byte)((NumIndex >> 8) & 0xFF); var j = 0; foreach (var i in Indices) { Buffer[14 + j * 2] = (Byte)(i & 0xFF); Buffer[14 + j * 2 + 1] = (Byte)((i >> 8) & 0xFF); j += 1; } Indices.Clear(); } Array.Copy(WriteBuffer, WritingOffset, Buffer, 12 + (IsACK ? 2 + NumIndex * 2 : 0), DataLength); WritingOffset += DataLength; if (SecureContext != null) { Flag |= 2; //ENC } Buffer[4] = (Byte)(Flag & 0xFF); Buffer[5] = (Byte)((Flag >> 8) & 0xFF); Buffer[6] = (Byte)(Index & 0xFF); Buffer[7] = (Byte)((Index >> 8) & 0xFF); var Verification = 0; if (SecureContext != null) { var Key = SecureContext.ClientToken.Concat(Cryptography.SHA256(Buffer.Skip(4).Take(4))); var HMACBytes = Cryptography.HMACSHA256Simple(Key, Buffer).Take(4).ToArray(); Verification = HMACBytes[0] | ((Int32)(HMACBytes[1]) << 8) | ((Int32)(HMACBytes[2]) << 16) | ((Int32)(HMACBytes[3]) << 24); } else { Verification = Cryptography.CRC32(Buffer); } Buffer[8] = (Byte)(Verification & 0xFF); Buffer[9] = (Byte)((Verification >> 8) & 0xFF); Buffer[10] = (Byte)((Verification >> 16) & 0xFF); Buffer[11] = (Byte)((Verification >> 24) & 0xFF); var Part = new Part { Index = Index, ResendTime = Time.AddIntMilliseconds(GetTimeoutMilliseconds(0)), Data = Buffer, ResentCount = 0 }; if (!c.Parts.TryPushPart(Index, Buffer)) { se = SocketError.NoBufferSpaceAvailable; return; } Parts.Add(Part.Data); //Debug.WriteLine(Times.DateTimeUtcWithMillisecondsToString(DateTime.UtcNow) + " Send SessionId: " + SessionId.ToString("X8") + " Index: " + Index.ToString()); c.WritenIndex = Index; } if (c.Timer == null) { c.Timer = new Timer(o => Check(), null, CheckTimeout, Timeout.Infinite); } }); foreach (var p in Parts) { try { SendPacket(RemoteEndPoint, p); } catch { se = SocketError.Interrupted; break; } } if (se != SocketError.Success) { OnFailure(se); } else { OnSuccess(); } }