public void Connect() { IsRunningValue.Update ( b => { if (b) { throw new InvalidOperationException(); } return(true); } ); using (var h = new AutoResetEvent(false)) { Exception Exception = null; Action Completed = () => { h.Set(); }; Action <Exception> Faulted = ex => { Exception = ex; h.Set(); }; Socket.ConnectAsync(RemoteEndPoint, Completed, Faulted); h.WaitOne(); if (Exception != null) { throw new AggregateException(Exception); } } }
private void OnShutdownWrite() { HttpWriteContext PairWriteContext = null; WriteContext.Update(c => { PairWriteContext = c; return(null); }); if (PairWriteContext != null) { HandleRawWrite(PairWriteContext.ListenerContext, PairWriteContext.NewSessionId, PairWriteContext.Query); } }
public void Stop() { StopInner(); Boolean Done = false; Socket.Update ( s => { if (s != null) { try { s.Shutdown(SocketShutdown.Both); } catch { } try { s.Close(); } catch { } try { s.Dispose(); } catch { } Done = true; } return(null); } ); if (Done) { Server.NotifySessionQuit((TSession)this); } }
private void OnShutdownRead() { HttpReadContext PairContext = null; ReadContext.Update(c => { PairContext = c; return(null); }); if (PairContext != null) { if (PairContext.ListenerContext != null) { PairContext.ListenerContext.Response.StatusCode = 400; PairContext.ListenerContext.Response.Close(); } if (PairContext.OnFailure != null) { PairContext.OnFailure(); } } }
public void Connect() { IsRunningValue.Update ( b => { if (b) { throw new InvalidOperationException(); } return(true); } ); if (RemoteEndPoint.AddressFamily == AddressFamily.InterNetwork) { Socket.Bind(new IPEndPoint(IPAddress.Any, 0)); } else { Socket.Bind(new IPEndPoint(IPAddress.IPv6Any, 0)); } }
private void HandleRawWrite(HttpListenerContext ListenerContext, String NewSessionId, Dictionary <String, String> Query) { var jo = new JObject(); jo["commands"] = new JArray(vts.TakeWriteBuffer()); jo["sessionid"] = new JValue(NewSessionId); var Result = jo.ToString(Formatting.None); { if (Query.ContainsKey("callback")) { var CallbackName = Query["callback"]; Result = "{0}({1});".Formats(CallbackName, Result); } } var Bytes = TextEncoding.UTF8.GetBytes(Result); ListenerContext.Response.StatusCode = 200; ListenerContext.Response.AddHeader("Accept-Ranges", "none"); ListenerContext.Response.ContentEncoding = System.Text.Encoding.UTF8; ListenerContext.Response.ContentLength64 = Bytes.Length; ListenerContext.Response.ContentType = "application/json; charset=utf-8"; using (var OutputStream = ListenerContext.Response.OutputStream.AsWritable()) { try { OutputStream.Write(Bytes); } catch { } } try { ListenerContext.Response.Close(); } catch { } LastActiveTimeValue.Update(v => DateTime.UtcNow); }
public static void TestHttpForNumUser(String UrlPrefix, String ServiceVirtualPath, int NumUser, String Title, Action <int, int, ClientContext, IApplicationClient, Action> Test, Action <int, int, ClientContext, IApplicationClient, Action> InitializeClientContext = null, Action <ClientContext[]> FinalCheck = null) { Console.Write("{0}: ", Title); Console.Out.Flush(); var tl = new List <Task>(); var bcl = new List <Http.HttpClient>(); var ccl = new List <ClientContext>(); var vConnected = new LockedVariable <int>(0); var vCompleted = new LockedVariable <int>(0); var Check = new AutoResetEvent(false); var vError = new LockedVariable <int>(0); for (int k = 0; k < NumUser; k += 1) { var n = k; var Lockee = new Object(); var a = new JsonSerializationClientAdapter(); var ac = a.GetApplicationClient(); var vtc = new Http.JsonHttpPacketClient(a); var bc = new Http.HttpClient(UrlPrefix, ServiceVirtualPath, vtc); var cc = new ClientContext(); ac.Error += e => { var m = e.Message; Console.WriteLine(m); }; Action Completed; if (Test == TestQuit) { Completed = () => { vCompleted.Update(i => i + 1); Check.Set(); }; } else { Completed = () => { ac.Quit(new QuitRequest { }).ContinueWith(tt => { vCompleted.Update(i => i + 1); Check.Set(); }); }; } if (InitializeClientContext != null) { InitializeClientContext(NumUser, n, cc, ac, Completed); } try { ac.ServerTime(new ServerTimeRequest { }).ContinueWith(tt => { vConnected.Update(i => i + 1); Check.Set(); }); } catch (Exception ex) { Console.WriteLine(String.Format("{0}:{1}", n, ex.Message)); Completed(); } var t = new Task ( () => { try { Test(NumUser, n, cc, ac, Completed); } catch (Exception ex) { Console.WriteLine(String.Format("{0}:{1}", n, ex.Message)); Completed(); } } ); tl.Add(t); bcl.Add(bc); ccl.Add(cc); } while (vConnected.Check(i => i != NumUser)) { Check.WaitOne(); } var Time = Environment.TickCount; foreach (var t in tl) { t.Start(); } while (vCompleted.Check(i => i != NumUser)) { Check.WaitOne(); } var TimeDiff = Environment.TickCount - Time; Task.WaitAll(tl.ToArray()); foreach (var t in tl) { t.Dispose(); } foreach (var bc in bcl) { bc.Dispose(); } if (FinalCheck != null) { FinalCheck(ccl.ToArray()); } var NumError = vError.Check(v => v); if (NumError > 0) { Console.WriteLine("{0} Errors", NumError); } Console.WriteLine("{0} Users, {1} ms", NumUser, TimeDiff); }
public static void TestHttpForNumUser(String UrlPrefix, String ServiceVirtualPath, int NumRequestPerUser, int NumUser, String Title, Action <int, int, ClientContext, IApplicationClient, Action> Test) { Console.Write("{0}: ", Title); Console.Out.Flush(); var tll = new Object(); var tl = new List <Task>(); var bcl = new List <Http.HttpClient>(); var ccl = new List <ClientContext>(); var vConnected = new LockedVariable <int>(0); var vCompleted = new LockedVariable <int>(0); var Check = new AutoResetEvent(false); var vError = new LockedVariable <int>(0); for (int k = 0; k < NumUser; k += 1) { Action Completed = null; var n = k; var Lockee = new Object(); var a = new JsonSerializationClientAdapter(); var ac = a.GetApplicationClient(); var vtc = new Http.JsonHttpPacketClient(a); var bc = new Http.HttpClient(UrlPrefix, ServiceVirtualPath, vtc); var cc = new ClientContext(); ac.Error += e => { var m = e.Message; Console.WriteLine(m); }; Action <Exception> HandleError = ex => { int OldValue = 0; vError.Update(v => { OldValue = v; return(v + 1); }); if (OldValue <= 10) { Console.WriteLine(String.Format("{0}:{1}", n, ex.Message)); } vCompleted.Update(i => i + 1); Check.Set(); }; try { ac.ServerTime(new ServerTimeRequest { }).ContinueWith(tt => { vConnected.Update(i => i + 1); Check.Set(); }); } catch (Exception ex) { HandleError(ex); } Action f = () => { try { Test(NumUser, n, cc, ac, Completed); } catch (Exception ex) { HandleError(ex); } }; var t = new Task(f); lock (tll) { tl.Add(t); } bcl.Add(bc); ccl.Add(cc); int RequestCount = NumRequestPerUser; Completed = () => { if (RequestCount > 0) { RequestCount -= 1; var tt = new Task(f); lock (tll) { tl.Add(t); } tt.Start(); return; } ac.Quit(new QuitRequest { }).ContinueWith(tt => { vCompleted.Update(i => i + 1); Check.Set(); }); }; } while (vConnected.Check(i => i != NumUser)) { Check.WaitOne(); } var Time = Environment.TickCount; lock (tll) { foreach (var t in tl) { t.Start(); } } while (vCompleted.Check(i => i != NumUser)) { Check.WaitOne(); } var TimeDiff = Environment.TickCount - Time; Task.WaitAll(tl.ToArray()); foreach (var t in tl) { t.Dispose(); } foreach (var bc in bcl) { bc.Dispose(); } var NumError = vError.Check(v => v); if (NumError > 0) { Console.WriteLine("{0} Errors", NumError); } Console.WriteLine("{0} Users, {1} Request/User, {2} ms", NumUser, NumRequestPerUser, TimeDiff); }
public Boolean Push(IPEndPoint RemoteEndPoint, int Index, int[] Indices, Byte[] Buffer, int Offset, int Length) { var SessionId = this.SessionId; var Time = DateTime.UtcNow; if ((Indices != null) && (Indices.Length > 0)) { var l = new List <Byte[]>(); CookedWritingContext.DoAction(c => { c.Parts.Acknowledge(Indices.First(), Indices.Skip(1), c.WritenIndex); }); } { var l = new List <Byte[]>(); CookedWritingContext.DoAction(c => { c.Parts.ForEachTimedoutPacket(SessionId, Time, (i, d, ResentCount) => { l.Add(d); if (Server.ServerContext.EnableLogTransport) { Server.ServerContext.RaiseSessionLog(new SessionLogEntry { Token = SessionId.ToString("X8"), RemoteEndPoint = RemoteEndPoint, Time = DateTime.UtcNow, Type = "UdpTransport", Name = "Resend", Message = "Index: " + i.ToInvariantString() + " Length: " + d.Length.ToInvariantString() + " Count: " + ResentCount.ToInvariantString() }); } }); }); foreach (var p in l) { try { SendPacket(RemoteEndPoint, p); } catch { return(false); } } } var Pushed = false; var Parts = new List <Part>(); Action <StreamedVirtualTransportServerHandleResult[]> OnSuccess = null; Action OnFailure = null; RawReadingContext.DoAction(c => { if (c.Parts.HasPart(Index)) { Pushed = true; return; } Pushed = c.Parts.TryPushPart(Index, Buffer, Offset, Length); if (Pushed) { c.NotAcknowledgedIndices.Add(Index); var Acknowledged = new List <int>(); foreach (var i in c.NotAcknowledgedIndices) { if (c.Parts.IsEqualOrAfter(c.Parts.MaxHandled, i)) { Acknowledged.Add(i); } } foreach (var i in Acknowledged) { c.NotAcknowledgedIndices.Remove(i); } if ((c.OnSuccess != null) && (c.OnFailure != null)) { while (true) { var p = c.Parts.TryTakeFirstPart(); if (p == null) { break; } Parts.Add(p); } if (Parts.Count > 0) { OnSuccess = c.OnSuccess; OnFailure = c.OnFailure; c.OnSuccess = null; c.OnFailure = null; } } } }); if (Pushed) { LastActiveTimeValue.Update(v => DateTime.UtcNow); } if (Parts.Count > 0) { HandleRawRead(Parts, OnSuccess, OnFailure); } return(Pushed); }
public static void TestUdpForNumUser(IPEndPoint RemoteEndPoint, SerializationProtocolType ProtocolType, int NumUser, String Title, Action <int, int, ClientContext, IApplicationClient, Action> Test, Action <int, int, ClientContext, IApplicationClient, Action> InitializeClientContext = null, Action <ClientContext[]> FinalCheck = null) { Console.Write("{0}: ", Title); Console.Out.Flush(); var tl = new List <Task>(); var bcl = new List <UdpClient>(); var ccl = new List <ClientContext>(); var tmrl = new List <Timer>(); var vConnected = new LockedVariable <int>(0); var vCompleted = new LockedVariable <int>(0); var Check = new AutoResetEvent(false); var bAbondon = new LockedVariable <Boolean>(false); var vError = new LockedVariable <int>(0); for (int k = 0; k < NumUser; k += 1) { var n = k; var Lockee = new Object(); IApplicationClient ac; IStreamedVirtualTransportClient vtc; if (ProtocolType == SerializationProtocolType.Binary) { var a = new BinarySerializationClientAdapter(); ac = a.GetApplicationClient(); vtc = new BinaryCountPacketClient(a); } else if (ProtocolType == SerializationProtocolType.Json) { var a = new JsonSerializationClientAdapter(); ac = a.GetApplicationClient(); vtc = new JsonLinePacketClient(a); } else { throw new InvalidOperationException(); } var bc = new UdpClient(RemoteEndPoint, vtc, QueueUserWorkItem); var cc = new ClientContext(); var bCompleted = new LockedVariable <Boolean>(false); Action Completed; Action FaultedCompleted; if (Test == TestQuit) { Completed = () => { bCompleted.Update(b => true); vCompleted.Update(i => i + 1); Check.Set(); }; FaultedCompleted = Completed; } else { Completed = () => { ac.Quit(new QuitRequest { }).ContinueWith(tt => { bCompleted.Update(b => true); vCompleted.Update(i => i + 1); Check.Set(); }); }; FaultedCompleted = () => { bCompleted.Update(b => true); vCompleted.Update(i => i + 1); Check.Set(); }; } ac.Error += e => { var m = e.Message; Console.WriteLine(m); }; if (InitializeClientContext != null) { InitializeClientContext(NumUser, n, cc, ac, Completed); } bc.Connect(); Action <Exception> UnknownFaulted = ex => { int OldValue = 0; vError.Update(v => { OldValue = v; return(v + 1); }); if (OldValue <= 10) { Console.WriteLine(String.Format("{0}:{1}", n, ex.Message)); } FaultedCompleted(); }; bc.ReceiveAsync ( a => { a(); }, UnknownFaulted ); ac.ServerTime(new ServerTimeRequest { }).ContinueWith(tt => { vConnected.Update(i => i + 1); Check.Set(); }); var t = new Task ( () => { Test(NumUser, n, cc, ac, Completed); } ); var tmr = new Timer ( o => { if (!bAbondon.Check(b => b)) { return; } if (bCompleted.Check(b => b)) { return; } int OldValue = 0; vError.Update(v => { OldValue = v; return(v + 1); }); if (OldValue <= 10) { Console.WriteLine(String.Format("{0}:{1}", n, "Timedout")); } FaultedCompleted(); }, null, 10000, 10000 ); tl.Add(t); bcl.Add(bc); ccl.Add(cc); tmrl.Add(tmr); } while (vConnected.Check(i => i != NumUser)) { Check.WaitOne(); } var Time = Environment.TickCount; foreach (var t in tl) { t.Start(); } while (vCompleted.Check(i => i != NumUser)) { if (!Check.WaitOne(10000)) { if (vCompleted.Check(i => i > 0)) { bAbondon.Update(b => true); break; } } } var NumMutualWaiting = NumUser - vCompleted.Check(i => i); while (vCompleted.Check(i => i != NumUser)) { Check.WaitOne(); } foreach (var tmr in tmrl) { tmr.Dispose(); } var TimeDiff = Environment.TickCount - Time; Task.WaitAll(tl.ToArray()); foreach (var t in tl) { t.Dispose(); } foreach (var bc in bcl) { bc.Dispose(); } if (FinalCheck != null) { FinalCheck(ccl.ToArray()); } var NumError = vError.Check(v => v); if (NumError > 0) { Console.WriteLine("{0} Errors", NumError); } if (NumMutualWaiting > 0) { Console.WriteLine("{0} Users, {1} ms, {2} MutualWaiting", NumUser, TimeDiff, NumMutualWaiting); } else { Console.WriteLine("{0} Users, {1} ms", NumUser, TimeDiff); } }
/// <summary>接收消息</summary> /// <param name="DoResultHandle">运行处理消息函数,应保证不多线程同时访问BinarySocketClient</param> /// <param name="UnknownFaulted">未知错误处理函数</param> public void ReceiveAsync(Action <Action> DoResultHandle, Action <Exception> UnknownFaulted) { Action <Exception> Faulted = ex => { if (!IsRunningValue.Check(b => b) && IsSocketErrorKnown(ex)) { return; } UnknownFaulted(ex); }; Action <Byte[]> CompletedSocket = Buffer => { Action a = () => { if (Buffer.Length < 12) { return; } var SessionId = Buffer[0] | ((Int32)(Buffer[1]) << 8) | ((Int32)(Buffer[2]) << 16) | ((Int32)(Buffer[3]) << 24); var Flag = Buffer[4] | ((Int32)(Buffer[5]) << 8); var Index = Buffer[6] | ((Int32)(Buffer[7]) << 8); var Verification = Buffer[8] | ((Int32)(Buffer[9]) << 8) | ((Int32)(Buffer[10]) << 16) | ((Int32)(Buffer[11]) << 24); Buffer[8] = 0; Buffer[9] = 0; Buffer[10] = 0; Buffer[11] = 0; //Debug.WriteLine(Times.DateTimeUtcWithMillisecondsToString(DateTime.UtcNow) + " Receive SessionId: " + SessionId.ToString("X8") + " Index: " + Index.ToString()); var IsEncrypted = (Flag & 2) != 0; var SecureContext = this.SecureContext; if ((SecureContext != null) != IsEncrypted) { return; } if (IsEncrypted) { var Key = SecureContext.ServerToken.Concat(Cryptography.SHA256(Buffer.Skip(4).Take(4))); var HMACBytes = Cryptography.HMACSHA256Simple(Key, Buffer).Take(4).ToArray(); var HMAC = HMACBytes[0] | ((Int32)(HMACBytes[1]) << 8) | ((Int32)(HMACBytes[2]) << 16) | ((Int32)(HMACBytes[3]) << 24); if (HMAC != Verification) { return; } } else { //如果Flag中不包含ENC,则验证CRC32 if (Cryptography.CRC32(Buffer) != Verification) { return; } //只有尚未连接时可以设定 var Close = false; ConnectionStateValue.Update(v => { if (v == ConnectionState.Connecting) { this.SessionId = SessionId; return(ConnectionState.Connected); } else { if (SessionId != this.SessionId) { Close = true; } return(v); } }); if (Close) { return; } } var Offset = 12; int[] Indices = null; if ((Flag & 1) != 0) { if (Buffer.Length < 14) { return; } var NumIndex = Buffer[Offset] | ((Int32)(Buffer[Offset + 1]) << 8); if (Buffer.Length < 14 + NumIndex * 2) { return; } if (NumIndex > WritingWindowSize) //若Index数量较大,则丢弃包 { return; } Offset += 2; Indices = new int[NumIndex]; for (int k = 0; k < NumIndex; k += 1) { Indices[k] = Buffer[Offset + k * 2] | ((Int32)(Buffer[Offset + k * 2 + 1]) << 8); } Offset += NumIndex * 2; } var Length = Buffer.Length - Offset; if ((Indices != null) && (Indices.Length > 0)) { CookedWritingContext.DoAction(c => { c.Parts.Acknowledge(Indices.First(), Indices.Skip(1), c.WritenIndex); }); } var Pushed = false; var Parts = new List <Byte[]>(); RawReadingContext.DoAction(c => { if (c.Parts.HasPart(Index)) { Pushed = true; return; } Pushed = c.Parts.TryPushPart(Index, Buffer, Offset, Length); if (Pushed) { c.NotAcknowledgedIndices.Add(Index); var Acknowledged = new List <int>(); foreach (var i in c.NotAcknowledgedIndices) { if (c.Parts.IsEqualOrAfter(c.Parts.MaxHandled, i)) { Acknowledged.Add(i); } } foreach (var i in Acknowledged) { c.NotAcknowledgedIndices.Remove(i); } while (true) { var p = c.Parts.TryTakeFirstPart(); if (p == null) { break; } Parts.Add(p.Data); } } }); foreach (var p in Parts) { var ReadBuffer = VirtualTransportClient.GetReadBuffer(); var ReadBufferLength = ReadBuffer.Offset + ReadBuffer.Count; if (p.Length > ReadBuffer.Array.Length - ReadBufferLength) { Faulted(new InvalidOperationException()); return; } Array.Copy(p, 0, ReadBuffer.Array, ReadBufferLength, p.Length); var c = p.Length; while (true) { var r = VirtualTransportClient.Handle(c); if (r.OnContinue) { break; } else if (r.OnCommand) { DoResultHandle(r.Command.HandleResult); var RemainCount = VirtualTransportClient.GetReadBuffer().Count; if (RemainCount <= 0) { break; } c = 0; } else { throw new InvalidOperationException(); } } } }; if (System.Diagnostics.Debugger.IsAttached) { a(); } else { try { a(); } catch (Exception ex) { UnknownFaulted(ex); } } }; Action Receive = null; EventHandler <SocketAsyncEventArgs> Completed = (sender, e) => { if (e.SocketError != SocketError.Success) { e.Dispose(); Faulted(new SocketException((int)(e.SocketError))); return; } var Count = e.BytesTransferred; var Buffer = new Byte[Count]; Array.Copy(e.Buffer, Buffer, Count); e.Dispose(); CompletedSocket(Buffer); Buffer = null; Receive(); }; Receive = () => { if (!IsRunning) { return; } var ServerEndPoint = this.RemoteEndPoint; var ae = new SocketAsyncEventArgs(); ae.RemoteEndPoint = ServerEndPoint; ae.SetBuffer(ReadBuffer, 0, ReadBuffer.Length); ae.Completed += Completed; try { var willRaiseEvent = Socket.ReceiveFromAsync(ae); if (!willRaiseEvent) { QueueUserWorkItem(() => Completed(null, ae)); } } catch (Exception ex) { ae.Dispose(); Faulted(ex); return; } }; Receive(); }
public void Start() { var Success = false; try { IsRunningValue.Update ( b => { if (b) { throw new InvalidOperationException(); } if (BindingsValue.Length == 0) { throw new Exception("NoValidBinding"); } ListeningTaskTokenSource = new CancellationTokenSource(); var ListeningTaskToken = ListeningTaskTokenSource.Token; foreach (var Binding in BindingsValue) { Listener.Prefixes.Add(Binding); } if (SessionIdleTimeoutValue.HasValue) { SetTimer(Listener, SessionIdleTimeoutValue.Value); } Action <HttpListenerContext> PurifyContext = ListenerContext => { try { ListenerContext.Response.Close(); } catch { } }; Action <HttpListenerContext> Accept = a => { IPEndPoint e = null; try { e = (IPEndPoint)a.Request.RemoteEndPoint; var XForwardedFor = a.Request.Headers["X-Forwarded-For"]; var Address = e.Address; if (XForwardedFor != null) { try { Address = IPAddress.Parse(XForwardedFor.Split(',')[0].Trim(' ')); } catch { } } var XForwardedPort = a.Request.Headers["X-Forwarded-Port"]; var Port = e.Port; if (XForwardedPort != null) { try { Port = int.Parse(XForwardedPort.Split(',')[0].Trim(' ')); } catch { } } e = new IPEndPoint(Address, Port); if (ServerContext.EnableLogSystem) { ServerContext.RaiseSessionLog(new SessionLogEntry { Token = "", RemoteEndPoint = e, Time = DateTime.UtcNow, Type = "Sys", Name = "RequestIn", Message = "" }); } if (a.Request.ContentLength64 < 0) { a.Response.StatusCode = 411; NotifyListenerContextQuit(a); return; } if (a.Request.ContentLength64 > ReadBufferSize) { a.Response.StatusCode = 413; NotifyListenerContextQuit(a); return; } var oRelativePath = MatchBindingNameAndGetRelativePath(a.Request.Url); if (oRelativePath.OnNone) { a.Response.StatusCode = 404; NotifyListenerContextQuit(a); return; } var RelativePath = oRelativePath.Value; var Headers = a.Request.Headers.AllKeys.ToDictionary(k => k, k => a.Request.Headers[k]); if (Headers.ContainsKey("Accept-Charset")) { var AcceptCharsetParts = Headers["Accept-Charset"].Split(';'); if (AcceptCharsetParts.Length == 0) { a.Response.StatusCode = 400; NotifyListenerContextQuit(a); return; } var EncodingNames = AcceptCharsetParts[0].Split(',').Select(n => n.Trim(' ')).ToArray(); if (!(EncodingNames.Contains("utf-8", StringComparer.OrdinalIgnoreCase) || EncodingNames.Contains("*", StringComparer.OrdinalIgnoreCase))) { a.Response.StatusCode = 400; NotifyListenerContextQuit(a); return; } } if (RequestHandler != null) { RequestHandler(RelativePath, a, e, () => NotifyListenerContextQuit(a), ex => { if (ServerContext.EnableLogSystem) { ServerContext.RaiseSessionLog(new SessionLogEntry { Token = "", RemoteEndPoint = e, Time = DateTime.UtcNow, Type = "Sys", Name = "Exception", Message = ExceptionInfo.GetExceptionInfo(ex) }); } NotifyListenerContextQuit(a); }); } else { NotifyListenerContextQuit(a); } } catch (Exception ex) { if (ServerContext.EnableLogSystem) { ServerContext.RaiseSessionLog(new SessionLogEntry { Token = "", RemoteEndPoint = e ?? new IPEndPoint(IPAddress.Any, 0), Time = DateTime.UtcNow, Type = "Sys", Name = "Exception", Message = ExceptionInfo.GetExceptionInfo(ex) }); } try { a.Response.StatusCode = 500; } catch { } NotifyListenerContextQuit(a); } }; AcceptConsumer = new AsyncConsumer <HttpListenerContext>(QueueUserWorkItem, a => { Accept(a); return(true); }, int.MaxValue); ContextPurifyConsumer = new AsyncConsumer <HttpListenerContext>(QueueUserWorkItem, l => { PurifyContext(l); return(true); }, int.MaxValue); try { Listener.Start(); } catch (HttpListenerException ex) { String Message; if (ex.ErrorCode == 5) { var l = new List <String>(); l.Add("Under Windows, try run the following as administrator:"); var UserDomainName = Environment.UserDomainName; var UserName = Environment.UserName; foreach (var p in BindingsValue) { l.Add(@"netsh http add urlacl url={0} user={1}\{2}".Formats(p, UserDomainName, UserName)); } l.Add("and delete it when you don't need it:"); foreach (var p in BindingsValue) { l.Add(@"netsh http delete urlacl url={0}".Formats(p)); } Message = String.Join("\r\n", l.ToArray()); } else { Message = ExceptionInfo.GetExceptionInfo(ex); } throw new AggregateException(Message, ex); } Action Listen = () => { if (ListeningTaskToken.IsCancellationRequested) { return; } var l = Listener; var lc = ListenConsumer; l.BeginGetContext(ar => { if (!l.IsListening) { return; } try { var a = l.EndGetContext(ar); AcceptConsumer.Push(a); } catch (HttpListenerException) { } lc.Push(0); }, null); }; ListenConsumer = new AsyncConsumer <int>(QueueUserWorkItem, i => { Listen(); return(true); }, 1); Listen(); Success = true; return(true); } ); } finally { if (!Success) { Stop(); } } }
private void DoAsync(SocketAsyncOperation OperationIdentifier, Func <SocketAsyncEventArgs, Boolean> Operation, Func <SocketAsyncEventArgs, Action> ResultToCompleted, Action <Exception> Faulted) { var Context = new AsyncOperationContext(); if (!TryLockAsyncOperation(OperationIdentifier, Context)) { Context.Dispose(); Faulted(new SocketException((int)(SocketError.Shutdown))); return; } var Success = false; try { Context.ResultToCompleted = ResultToCompleted; Context.Faulted = Faulted; var TimeoutSeconds = this.TimeoutSeconds; if (TimeoutSeconds.HasValue) { var IsCompleted = new LockedVariable <Boolean>(false); var Timer = new Timer(o => { if (!IsCompleted.Check(b => b)) { if (TimedOut != null) { TimedOut(); } } }, null, TimeoutSeconds.Value * 1000, Timeout.Infinite); Context.ReleaseAsyncOperation = () => { IsCompleted.Update(b => true); if (Timer != null) { Timer.Dispose(); Timer = null; } ReleaseAsyncOperation(OperationIdentifier); }; } else { Context.ReleaseAsyncOperation = () => ReleaseAsyncOperation(OperationIdentifier); } Success = true; } finally { if (!Success) { ReleaseAsyncOperation(OperationIdentifier); } } Success = false; Exception Exception = null; try { bool willRaiseEvent = Operation(Context.EventArgs); if (!willRaiseEvent) { QueueUserWorkItem(Context.DoOnCompletion); } Success = true; } catch (ObjectDisposedException) { Exception = new SocketException((int)(SocketError.OperationAborted)); } finally { if (!Success) { Context.ReleaseAsyncOperation(); } } if (Exception != null) { Faulted(Exception); } }
public void Start() { var Success = false; try { IsRunningValue.Update ( b => { if (b) { throw new InvalidOperationException(); } if (BindingsValue.Length == 0) { throw new Exception("NoValidBinding"); } ListeningTaskTokenSource = new CancellationTokenSource(); var ListeningTaskToken = ListeningTaskTokenSource.Token; foreach (var Binding in BindingsValue) { Listener.Prefixes.Add(Binding); } if (UnauthenticatedSessionIdleTimeoutValue.HasValue) { SetTimer(Listener, UnauthenticatedSessionIdleTimeoutValue.Value); } Action <HttpListenerContext> PurifyContext = ListenerContext => { try { ListenerContext.Response.Close(); } catch { } }; Action <HttpSession> Purify = StoppingSession => { SessionSets.DoAction ( ss => { if (ss.Sessions.Contains(StoppingSession)) { ss.Sessions.Remove(StoppingSession); var IpAddress = StoppingSession.RemoteEndPoint.Address; var isi = ss.IpSessions[IpAddress]; if (isi.Authenticated.Contains(StoppingSession)) { isi.Authenticated.Remove(StoppingSession); } isi.Count -= 1; if (isi.Count == 0) { ss.IpSessions.Remove(IpAddress); } var SessionId = ss.SessionToId[StoppingSession]; ss.SessionIdToSession.Remove(SessionId); ss.SessionToId.Remove(StoppingSession); } } ); StoppingSession.Dispose(); }; Action <HttpListenerContext> Accept = a => { IPEndPoint e = null; try { e = (IPEndPoint)a.Request.RemoteEndPoint; var XForwardedFor = a.Request.Headers["X-Forwarded-For"]; var Address = e.Address; if ((XForwardedFor != null) && (XForwardedFor != "")) { try { IPAddress addr; if (IPAddress.TryParse(XForwardedFor.Split(',')[0].Trim(' '), out addr)) { Address = addr; } } catch { } } var XForwardedPort = a.Request.Headers["X-Forwarded-Port"]; var Port = e.Port; if ((XForwardedPort != null) && (XForwardedPort != "")) { try { int p; if (int.TryParse(XForwardedPort.Split(',')[0].Trim(' '), out p)) { Port = p; } } catch { } } e = new IPEndPoint(Address, Port); if (ServerContext.EnableLogSystem) { ServerContext.RaiseSessionLog(new SessionLogEntry { Token = "", RemoteEndPoint = e, Time = DateTime.UtcNow, Type = "Sys", Name = "RequestIn", Message = "" }); } if (a.Request.ContentLength64 < 0) { a.Response.StatusCode = 411; NotifyListenerContextQuit(a); return; } if (a.Request.ContentLength64 > ReadBufferSize) { a.Response.StatusCode = 413; NotifyListenerContextQuit(a); return; } if (!IsMatchBindingName(a.Request.Url)) { a.Response.StatusCode = 404; NotifyListenerContextQuit(a); return; } var Headers = a.Request.Headers.AllKeys.ToDictionary(k => k, k => a.Request.Headers[k]); if (Headers.ContainsKey("Range")) { a.Response.StatusCode = 400; NotifyListenerContextQuit(a); return; } if (Headers.ContainsKey("Accept-Charset")) { var AcceptCharsetParts = Headers["Accept-Charset"].Split(';'); if (AcceptCharsetParts.Length == 0) { a.Response.StatusCode = 400; NotifyListenerContextQuit(a); return; } var EncodingNames = AcceptCharsetParts[0].Split(',').Select(n => n.Trim(' ')).ToArray(); if (!(EncodingNames.Contains("utf-8", StringComparer.OrdinalIgnoreCase) || EncodingNames.Contains("*", StringComparer.OrdinalIgnoreCase))) { a.Response.StatusCode = 400; NotifyListenerContextQuit(a); return; } } { var Query = HttpListenerRequestExtension.GetQuery(a.Request); if (Query.ContainsKey("sessionid")) { HttpSession s = null; var SessionId = Query["sessionid"]; var Close = false; SessionSets.DoAction ( ss => { if (!ss.SessionIdToSession.ContainsKey(SessionId)) { a.Response.StatusCode = 403; Close = true; return; } var CurrentSession = ss.SessionIdToSession[SessionId]; if (!CurrentSession.RemoteEndPoint.Address.Equals(e.Address)) { a.Response.StatusCode = 403; Close = true; return; } s = ss.SessionIdToSession[SessionId]; } ); if (Close) { NotifyListenerContextQuit(a); return; } var NewSessionId = Convert.ToBase64String(Cryptography.CreateRandom(64)); SessionSets.DoAction ( ss => { ss.SessionIdToSession.Remove(SessionId); ss.SessionIdToSession.Add(NewSessionId, s); ss.SessionToId[s] = NewSessionId; } ); if (!s.Push(a, NewSessionId)) { NotifyListenerContextQuit(a); return; } return; } } if (MaxConnectionsValue.HasValue && (SessionSets.Check(ss => ss.Sessions.Count) >= MaxConnectionsValue.Value)) { ContextPurifyConsumer.DoOne(); PurifyConsumer.DoOne(); } if (MaxConnectionsValue.HasValue && (SessionSets.Check(ss => ss.Sessions.Count) >= MaxConnectionsValue.Value)) { a.Response.StatusCode = 503; NotifyListenerContextQuit(a); return; } if (MaxConnectionsPerIPValue.HasValue && (SessionSets.Check(ss => ss.IpSessions.ContainsKey(e.Address) ? ss.IpSessions[e.Address].Count : 0) >= MaxConnectionsPerIPValue.Value)) { a.Response.StatusCode = 503; NotifyListenerContextQuit(a); return; } if (MaxUnauthenticatedPerIPValue.HasValue && (SessionSets.Check(ss => ss.IpSessions.ContainsKey(e.Address) ? (ss.IpSessions[e.Address].Count - ss.IpSessions[e.Address].Authenticated.Count) : 0) >= MaxUnauthenticatedPerIPValue.Value)) { a.Response.StatusCode = 503; NotifyListenerContextQuit(a); return; } { var s = new HttpSession(this, e, VirtualTransportServerFactory, QueueUserWorkItem); var SessionId = Convert.ToBase64String(Cryptography.CreateRandom(64)); SessionSets.DoAction ( ss => { ss.Sessions.Add(s); if (ss.IpSessions.ContainsKey(e.Address)) { ss.IpSessions[e.Address].Count += 1; } else { var isi = new IpSessionInfo(); isi.Count += 1; ss.IpSessions.Add(e.Address, isi); } ss.SessionIdToSession.Add(SessionId, s); ss.SessionToId.Add(s, SessionId); } ); s.Start(); if (!s.Push(a, SessionId)) { NotifyListenerContextQuit(a); return; } } } catch (Exception ex) { if (ServerContext.EnableLogSystem) { ServerContext.RaiseSessionLog(new SessionLogEntry { Token = "", RemoteEndPoint = e ?? new IPEndPoint(IPAddress.Any, 0), Time = DateTime.UtcNow, Type = "Sys", Name = "Exception", Message = ExceptionInfo.GetExceptionInfo(ex) }); } try { a.Response.StatusCode = 500; } catch { } NotifyListenerContextQuit(a); } }; AcceptConsumer = new AsyncConsumer <HttpListenerContext>(QueueUserWorkItem, a => { Accept(a); return(true); }, int.MaxValue); ContextPurifyConsumer = new AsyncConsumer <HttpListenerContext>(QueueUserWorkItem, l => { PurifyContext(l); return(true); }, int.MaxValue); PurifyConsumer = new AsyncConsumer <HttpSession>(PurifierQueueUserWorkItem, s => { Purify(s); return(true); }, int.MaxValue); if (UnauthenticatedSessionIdleTimeoutValue.HasValue || SessionIdleTimeoutValue.HasValue) { var TimePeriod = TimeSpan.FromSeconds(Math.Max(TimeoutCheckPeriodValue, 1)); LastActiveTimeCheckTimer = new Timer(state => { if (UnauthenticatedSessionIdleTimeoutValue.HasValue) { var CheckTime = DateTime.UtcNow.AddIntSeconds(-UnauthenticatedSessionIdleTimeoutValue.Value); SessionSets.DoAction ( ss => { foreach (var s in ss.Sessions) { var IpAddress = s.RemoteEndPoint.Address; var isi = ss.IpSessions[IpAddress]; if (!isi.Authenticated.Contains(s)) { if (s.LastActiveTime < CheckTime) { PurifyConsumer.Push(s); } } } } ); } if (SessionIdleTimeoutValue.HasValue) { var CheckTime = DateTime.UtcNow.AddIntSeconds(-SessionIdleTimeoutValue.Value); SessionSets.DoAction ( ss => { foreach (var s in ss.Sessions) { var IpAddress = s.RemoteEndPoint.Address; var isi = ss.IpSessions[IpAddress]; if (isi.Authenticated.Contains(s)) { if (s.LastActiveTime < CheckTime) { PurifyConsumer.Push(s); } } } } ); } }, null, TimePeriod, TimePeriod); } try { Listener.Start(); } catch (HttpListenerException ex) { String Message; if (ex.ErrorCode == 5) { var l = new List <String>(); l.Add("Under Windows, try run the following as administrator:"); var UserDomainName = Environment.UserDomainName; var UserName = Environment.UserName; foreach (var p in BindingsValue) { l.Add(@"netsh http add urlacl url={0} user={1}\{2}".Formats(p, UserDomainName, UserName)); } l.Add("and delete it when you don't need it:"); foreach (var p in BindingsValue) { l.Add(@"netsh http delete urlacl url={0}".Formats(p)); } Message = String.Join("\r\n", l.ToArray()); } else { Message = ExceptionInfo.GetExceptionInfo(ex); } throw new AggregateException(Message, ex); } Action Listen = () => { if (ListeningTaskToken.IsCancellationRequested) { return; } var l = Listener; var lc = ListenConsumer; l.BeginGetContext(ar => { if (!l.IsListening) { return; } try { var a = l.EndGetContext(ar); AcceptConsumer.Push(a); } catch (HttpListenerException) { } catch (ObjectDisposedException) { } lc.Push(0); }, null); }; ListenConsumer = new AsyncConsumer <int>(QueueUserWorkItem, i => { Listen(); return(true); }, 1); Listen(); Success = true; return(true); } ); } finally { if (!Success) { Stop(); } } }
public void Start() { var Success = false; try { IsRunningValue.Update ( b => { if (b) { throw new InvalidOperationException(); } if (BindingsValue.Length == 0) { throw new Exception("NoValidBinding"); } ListeningTaskTokenSource = new CancellationTokenSource(); var ListeningTaskToken = ListeningTaskTokenSource.Token; Action <TcpSession> Purify = StoppingSession => { SessionSets.DoAction ( ss => { if (ss.Sessions.Contains(StoppingSession)) { ss.Sessions.Remove(StoppingSession); var IpAddress = StoppingSession.RemoteEndPoint.Address; var isi = ss.IpSessions[IpAddress]; if (isi.Authenticated.Contains(StoppingSession)) { isi.Authenticated.Remove(StoppingSession); } isi.Count -= 1; if (isi.Count == 0) { ss.IpSessions.Remove(IpAddress); } } } ); StoppingSession.Dispose(); }; Action <Socket> Accept = a => { IPEndPoint ep; try { ep = (IPEndPoint)(a.RemoteEndPoint); } catch { a.Dispose(); return; } var s = new TcpSession(this, new StreamedAsyncSocket(a, UnauthenticatedSessionIdleTimeoutValue, QueueUserWorkItem), ep, VirtualTransportServerFactory, QueueUserWorkItem); if (MaxConnectionsValue.HasValue && (SessionSets.Check(ss => ss.Sessions.Count) >= MaxConnectionsValue.Value)) { PurifyConsumer.DoOne(); } if (MaxConnectionsValue.HasValue && (SessionSets.Check(ss => ss.Sessions.Count) >= MaxConnectionsValue.Value)) { try { s.Start(); OnMaxConnectionsExceeded(s); } finally { s.Dispose(); } return; } if (MaxConnectionsPerIPValue.HasValue && (SessionSets.Check(ss => ss.IpSessions.ContainsKey(ep.Address) ? ss.IpSessions[ep.Address].Count : 0) >= MaxConnectionsPerIPValue.Value)) { try { s.Start(); OnMaxConnectionsPerIPExceeded(s); } finally { PurifyConsumer.Push(s); } return; } if (MaxUnauthenticatedPerIPValue.HasValue && (SessionSets.Check(ss => ss.IpSessions.ContainsKey(ep.Address) ? ss.IpSessions[ep.Address].Count : 0) >= MaxUnauthenticatedPerIPValue.Value)) { try { s.Start(); OnMaxConnectionsPerIPExceeded(s); } finally { PurifyConsumer.Push(s); } return; } SessionSets.DoAction ( ss => { ss.Sessions.Add(s); if (ss.IpSessions.ContainsKey(ep.Address)) { ss.IpSessions[ep.Address].Count += 1; } else { var isi = new IpSessionInfo(); isi.Count += 1; ss.IpSessions.Add(ep.Address, isi); } } ); s.Start(); }; AcceptConsumer = new AsyncConsumer <Socket>(QueueUserWorkItem, a => { Accept(a); return(true); }, int.MaxValue); var Exceptions = new List <Exception>(); foreach (var Binding in BindingsValue) { Func <Socket> CreateSocket = () => { var s = new Socket(Binding.AddressFamily, SocketType.Stream, ProtocolType.Tcp); return(s); }; var Socket = CreateSocket(); try { Socket.Bind(Binding); } catch (SocketException ex) { Exceptions.Add(ex); continue; } Socket.Listen(MaxConnectionsValue.HasValue ? (MaxConnectionsValue.Value + 1) : 128); var BindingInfo = new BindingInfo(); BindingInfo.EndPoint = Binding; BindingInfo.Socket = new LockedVariable <Socket>(Socket); Func <SocketAsyncEventArgs, Boolean> Completed = args => { try { if (ListeningTaskToken.IsCancellationRequested) { return(false); } if (args.SocketError == SocketError.Success) { var a = args.AcceptSocket; AcceptConsumer.Push(a); } else { BindingInfo.Socket.Update ( OriginalSocket => { try { OriginalSocket.Dispose(); } catch (Exception) { } var NewSocket = CreateSocket(); NewSocket.Bind(Binding); NewSocket.Listen(MaxConnectionsValue.HasValue ? (MaxConnectionsValue.Value + 1) : 128); return(NewSocket); } ); } } finally { args.Dispose(); } BindingInfo.Start(); return(true); }; BindingInfo.ListenConsumer = new AsyncConsumer <SocketAsyncEventArgs>(QueueUserWorkItem, Completed, 1); BindingInfo.Start = () => { var EventArgs = new SocketAsyncEventArgs(); var bs = BindingInfo.Socket.Check(s => s); EventArgs.Completed += (o, args) => { if (ListeningTaskToken.IsCancellationRequested) { return; } BindingInfo.ListenConsumer.Push(args); }; try { if (!bs.AcceptAsync(EventArgs)) { BindingInfo.ListenConsumer.Push(EventArgs); } } catch (ObjectDisposedException) { } }; BindingInfos.Add(BindingInfo); } if (BindingInfos.Count == 0) { throw new AggregateException(Exceptions); } PurifyConsumer = new AsyncConsumer <TcpSession>(PurifierQueueUserWorkItem, s => { Purify(s); return(true); }, int.MaxValue); foreach (var BindingInfo in BindingInfos) { BindingInfo.Start(); } Success = true; return(true); } ); } finally { if (!Success) { Stop(); } } }
public void Start() { var Success = false; try { IsRunningValue.Update ( b => { if (b) { throw new InvalidOperationException(); } if (BindingsValue.Length == 0) { throw new Exception("NoValidBinding"); } ListeningTaskTokenSource = new CancellationTokenSource(); var ListeningTaskToken = ListeningTaskTokenSource.Token; Action <UdpSession> Purify = StoppingSession => { SessionSets.DoAction ( ss => { if (ss.Sessions.Contains(StoppingSession)) { ss.Sessions.Remove(StoppingSession); var IpAddress = StoppingSession.RemoteEndPoint.Address; var isi = ss.IpSessions[IpAddress]; if (isi.Authenticated.Contains(StoppingSession)) { isi.Authenticated.Remove(StoppingSession); } isi.Count -= 1; if (isi.Count == 0) { ss.IpSessions.Remove(IpAddress); } var SessionId = StoppingSession.SessionId; ss.SessionIdToSession.Remove(SessionId); } } ); StoppingSession.Dispose(); }; Action <AcceptingInfo> Accept = a => { var ep = a.RemoteEndPoint; UdpSession s = null; try { var Buffer = a.ReadBuffer; if (Buffer.Length < 12) { return; } var SessionId = Buffer[0] | ((Int32)(Buffer[1]) << 8) | ((Int32)(Buffer[2]) << 16) | ((Int32)(Buffer[3]) << 24); var Flag = Buffer[4] | ((Int32)(Buffer[5]) << 8); var Index = Buffer[6] | ((Int32)(Buffer[7]) << 8); var Verification = Buffer[8] | ((Int32)(Buffer[9]) << 8) | ((Int32)(Buffer[10]) << 16) | ((Int32)(Buffer[11]) << 24); Buffer[8] = 0; Buffer[9] = 0; Buffer[10] = 0; Buffer[11] = 0; if (ServerContext.EnableLogTransport) { //按Flag中是否包含AUX分别生成日志 if ((Flag & 8) != 0) { ServerContext.RaiseSessionLog(new SessionLogEntry { Token = SessionId.ToString("X8"), RemoteEndPoint = ep, Time = DateTime.UtcNow, Type = "UdpTransport", Name = "ReceiveAux", Message = "AckIndex: " + Index.ToInvariantString() + " Length: " + Buffer.Length.ToInvariantString() }); } else { ServerContext.RaiseSessionLog(new SessionLogEntry { Token = SessionId.ToString("X8"), RemoteEndPoint = ep, Time = DateTime.UtcNow, Type = "UdpTransport", Name = "Receive", Message = "Index: " + Index.ToInvariantString() + " Length: " + Buffer.Length.ToInvariantString() }); } } //如果Flag中不包含ENC,则验证CRC32 if ((Flag & 2) == 0) { if (Cryptography.CRC32(Buffer) != Verification) { if (ServerContext.EnableLogTransport) { ServerContext.RaiseSessionLog(new SessionLogEntry { Token = SessionId.ToString("X8"), RemoteEndPoint = ep, Time = DateTime.UtcNow, Type = "UdpTransport", Name = "Receive", Message = "Index: " + Index.ToInvariantString() + " CRC32Failed" }); } return; } } //如果Flag中包含INI,则初始化 if ((Flag & 4) != 0) { if ((Flag & 1) != 0) { return; } if ((Flag & 2) != 0) { return; } if ((Flag & 8) != 0) { return; } var Offset = 12; s = new UdpSession(this, a.Socket, ep, VirtualTransportServerFactory, QueueUserWorkItem); SessionId = s.SessionId; if (MaxConnectionsValue.HasValue && (SessionSets.Check(ss => ss.Sessions.Count) >= MaxConnectionsValue.Value)) { PurifyConsumer.DoOne(); } if (MaxConnectionsValue.HasValue && (SessionSets.Check(ss => ss.Sessions.Count) >= MaxConnectionsValue.Value)) { try { s.Start(); OnMaxConnectionsExceeded(s); } finally { s.Dispose(); } return; } if (MaxConnectionsPerIPValue.HasValue && (SessionSets.Check(ss => ss.IpSessions.ContainsKey(ep.Address) ? ss.IpSessions[ep.Address].Count : 0) >= MaxConnectionsPerIPValue.Value)) { try { s.Start(); OnMaxConnectionsPerIPExceeded(s); } finally { PurifyConsumer.Push(s); } return; } if (MaxUnauthenticatedPerIPValue.HasValue && (SessionSets.Check(ss => ss.IpSessions.ContainsKey(ep.Address) ? (ss.IpSessions[ep.Address].Count - ss.IpSessions[ep.Address].Authenticated.Count) : 0) >= MaxUnauthenticatedPerIPValue.Value)) { try { s.Start(); OnMaxConnectionsPerIPExceeded(s); } finally { PurifyConsumer.Push(s); } return; } SessionSets.DoAction ( ss => { ss.Sessions.Add(s); if (ss.IpSessions.ContainsKey(ep.Address)) { ss.IpSessions[ep.Address].Count += 1; } else { var isi = new IpSessionInfo(); isi.Count += 1; ss.IpSessions.Add(ep.Address, isi); } while ((SessionId == 0) || ss.SessionIdToSession.ContainsKey(SessionId)) { s = new UdpSession(this, a.Socket, ep, VirtualTransportServerFactory, QueueUserWorkItem); SessionId = s.SessionId; } ss.SessionIdToSession.Add(SessionId, s); } ); s.Start(); s.PrePush(() => { if (!s.Push(ep, Index, null, Buffer, Offset, Buffer.Length - Offset)) { PurifyConsumer.Push(s); } }); } else { var Close = false; SessionSets.DoAction ( ss => { if (!ss.SessionIdToSession.ContainsKey(SessionId)) { Close = true; return; } s = ss.SessionIdToSession[SessionId]; } ); if (Close) { return; } s.PrePush(() => { var IsEncrypted = (Flag & 2) != 0; var NextSecureContext = s.NextSecureContext; var SecureContext = s.SecureContext; if ((SecureContext == null) && (NextSecureContext != null)) { s.SecureContext = NextSecureContext; s.NextSecureContext = null; SecureContext = NextSecureContext; NextSecureContext = null; } if ((SecureContext != null) != IsEncrypted) { return; } if (IsEncrypted) { var Key = SecureContext.ClientToken.Concat(Cryptography.SHA256(Buffer.Skip(4).Take(4))); var HMACBytes = Cryptography.HMACSHA256Simple(Key, Buffer).Take(4).ToArray(); var HMAC = HMACBytes[0] | ((Int32)(HMACBytes[1]) << 8) | ((Int32)(HMACBytes[2]) << 16) | ((Int32)(HMACBytes[3]) << 24); if (HMAC != Verification) { if (ServerContext.EnableLogTransport) { ServerContext.RaiseSessionLog(new SessionLogEntry { Token = SessionId.ToString("X8"), RemoteEndPoint = ep, Time = DateTime.UtcNow, Type = "UdpTransport", Name = "Receive", Message = "Index: " + Index.ToInvariantString() + " HMACFailed" }); } return; } } var Offset = 12; int[] Indices = null; if ((Flag & 1) != 0) { if (Buffer.Length < 14) { return; } var NumIndex = Buffer[Offset] | ((Int32)(Buffer[Offset + 1]) << 8); if (Buffer.Length < 14 + NumIndex * 2) { return; } if (NumIndex > UdpSession.WritingWindowSize) //若Index数量较大,则丢弃包 { return; } Offset += 2; Indices = new int[NumIndex]; for (int k = 0; k < NumIndex; k += 1) { Indices[k] = Buffer[Offset + k * 2] | ((Int32)(Buffer[Offset + k * 2 + 1]) << 8); } Offset += NumIndex * 2; } //如果Flag中包含AUX,则判断 if ((Flag & 8) != 0) { if (Indices == null) { return; } if (Indices.Length < 1) { return; } if (Index != Indices[0]) { return; } if (Offset != Buffer.Length) { return; } } var PreviousRemoteEndPoint = s.RemoteEndPoint; if (!PreviousRemoteEndPoint.Equals(ep)) { SessionSets.DoAction ( ss => { var Authenticated = false; { var PreviousIpAddress = PreviousRemoteEndPoint.Address; var isi = ss.IpSessions[PreviousIpAddress]; if (isi.Authenticated.Contains(s)) { isi.Authenticated.Remove(s); Authenticated = true; } isi.Count -= 1; if (isi.Count == 0) { ss.IpSessions.Remove(PreviousIpAddress); } } { IpSessionInfo isi; if (ss.IpSessions.ContainsKey(ep.Address)) { isi = ss.IpSessions[ep.Address]; isi.Count += 1; } else { isi = new IpSessionInfo(); isi.Count += 1; ss.IpSessions.Add(ep.Address, isi); } if (Authenticated) { isi.Authenticated.Add(s); } } s.RemoteEndPoint = ep; } ); } if ((Flag & 8) != 0) { if (!s.PushAux(ep, Indices)) { PurifyConsumer.Push(s); } } else { if (!s.Push(ep, Index, Indices, Buffer, Offset, Buffer.Length - Offset)) { PurifyConsumer.Push(s); } } }); } } catch (Exception ex) { if (ServerContext.EnableLogSystem) { ServerContext.RaiseSessionLog(new SessionLogEntry { Token = "", RemoteEndPoint = ep, Time = DateTime.UtcNow, Type = "Sys", Name = "Exception", Message = ExceptionInfo.GetExceptionInfo(ex) }); } if (s != null) { PurifyConsumer.Push(s); } } }; AcceptConsumer = new AsyncConsumer <AcceptingInfo>(QueueUserWorkItem, a => { Accept(a); return(true); }, int.MaxValue); var Exceptions = new List <Exception>(); var Bindings = new List <IPEndPoint>(); //将所有默认地址换为实际的所有接口地址 foreach (var Binding in BindingsValue) { if (IPAddress.Equals(Binding.Address, IPAddress.Any) || IPAddress.Equals(Binding.Address, IPAddress.IPv6Any)) { foreach (var ni in NetworkInterface.GetAllNetworkInterfaces()) { foreach (var a in ni.GetIPProperties().UnicastAddresses) { if (a.Address.AddressFamily == Binding.Address.AddressFamily) { Bindings.Add(new IPEndPoint(a.Address, Binding.Port)); } } } } else { Bindings.Add(Binding); } } foreach (var Binding in Bindings) { Func <Socket> CreateSocket = () => { var s = new Socket(Binding.AddressFamily, SocketType.Dgram, ProtocolType.Udp); //在Windows下关闭SIO_UDP_CONNRESET报告,防止接受数据出错 //http://support.microsoft.com/kb/263823/en-us if (System.Environment.OSVersion.Platform == PlatformID.Win32NT) { uint IOC_IN = 0x80000000; uint IOC_VENDOR = 0x18000000; uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; s.IOControl(unchecked ((int)(SIO_UDP_CONNRESET)), new byte[] { Convert.ToByte(false) }, null); } return(s); }; var Socket = CreateSocket(); try { Socket.Bind(Binding); } catch (SocketException ex) { Exceptions.Add(ex); continue; } var BindingInfo = new BindingInfo(); BindingInfo.EndPoint = Binding; BindingInfo.Socket = new LockedVariable <Socket>(Socket); Func <SocketAsyncEventArgs, Boolean> Completed = args => { try { if (ListeningTaskToken.IsCancellationRequested) { return(false); } if (args.SocketError == SocketError.Success) { var Count = args.BytesTransferred; var ReadBuffer = new Byte[Count]; Array.Copy(BindingInfo.ReadBuffer, ReadBuffer, Count); var a = new AcceptingInfo { Socket = BindingInfo.Socket.Check(s => s), ReadBuffer = ReadBuffer, RemoteEndPoint = (IPEndPoint)(args.RemoteEndPoint) }; AcceptConsumer.Push(a); } else { BindingInfo.Socket.Update ( OriginalSocket => { try { OriginalSocket.Dispose(); } catch (Exception) { } var NewSocket = CreateSocket(); NewSocket.Bind(Binding); return(NewSocket); } ); } } finally { args.Dispose(); } BindingInfo.Start(); return(true); }; BindingInfo.ListenConsumer = new AsyncConsumer <SocketAsyncEventArgs>(QueueUserWorkItem, Completed, 1); BindingInfo.Start = () => { var EventArgs = new SocketAsyncEventArgs(); EventArgs.RemoteEndPoint = new IPEndPoint(Binding.Address.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); EventArgs.SetBuffer(BindingInfo.ReadBuffer, 0, BindingInfo.ReadBuffer.Length); var bs = BindingInfo.Socket.Check(s => s); EventArgs.Completed += (o, args) => BindingInfo.ListenConsumer.Push(args); try { if (!bs.ReceiveFromAsync(EventArgs)) { BindingInfo.ListenConsumer.Push(EventArgs); } } catch (ObjectDisposedException) { } }; BindingInfos.Add(BindingInfo); } if (BindingInfos.Count == 0) { throw new AggregateException(Exceptions); } PurifyConsumer = new AsyncConsumer <UdpSession>(PurifierQueueUserWorkItem, s => { Purify(s); return(true); }, int.MaxValue); if (UnauthenticatedSessionIdleTimeoutValue.HasValue || SessionIdleTimeoutValue.HasValue) { var TimePeriod = TimeSpan.FromSeconds(Math.Max(TimeoutCheckPeriodValue, 1)); LastActiveTimeCheckTimer = new Timer(state => { if (UnauthenticatedSessionIdleTimeoutValue.HasValue) { var CheckTime = DateTime.UtcNow.AddIntSeconds(-UnauthenticatedSessionIdleTimeoutValue.Value); SessionSets.DoAction ( ss => { foreach (var s in ss.Sessions) { var IpAddress = s.RemoteEndPoint.Address; var isi = ss.IpSessions[IpAddress]; if (!isi.Authenticated.Contains(s)) { if (s.LastActiveTime < CheckTime) { PurifyConsumer.Push(s); } } } } ); } if (SessionIdleTimeoutValue.HasValue) { var CheckTime = DateTime.UtcNow.AddIntSeconds(-SessionIdleTimeoutValue.Value); SessionSets.DoAction ( ss => { foreach (var s in ss.Sessions) { var IpAddress = s.RemoteEndPoint.Address; var isi = ss.IpSessions[IpAddress]; if (isi.Authenticated.Contains(s)) { if (s.LastActiveTime < CheckTime) { PurifyConsumer.Push(s); } } } } ); } }, null, TimePeriod, TimePeriod); } foreach (var BindingInfo in BindingInfos) { BindingInfo.Start(); } Success = true; return(true); } ); } finally { if (!Success) { Stop(); } } }
public void Start() { var Success = false; try { IsRunningValue.Update ( b => { if (b) { throw new InvalidOperationException(); } if (BindingsValue.Length == 0) { throw new Exception("NoValidBinding"); } ListeningTaskTokenSource = new CancellationTokenSource(); AcceptingTaskTokenSource = new CancellationTokenSource(); AcceptingTaskNotifier = new AutoResetEvent(false); PurifieringTaskTokenSource = new CancellationTokenSource(); PurifieringTaskNotifier = new AutoResetEvent(false); var ListeningTaskToken = ListeningTaskTokenSource.Token; var AcceptingTaskToken = AcceptingTaskTokenSource.Token; var PurifieringTaskToken = PurifieringTaskTokenSource.Token; var Exceptions = new List <Exception>(); foreach (var Binding in BindingsValue) { var Socket = new Socket(Binding.AddressFamily, SocketType.Stream, ProtocolType.Tcp); try { Socket.Bind(Binding); } catch (SocketException ex) { Exceptions.Add(ex); continue; } Socket.Listen(MaxConnectionsValue.HasValue ? (MaxConnectionsValue.Value + 1) : 128); var BindingInfo = new BindingInfo { Socket = new LockedVariable <Socket>(Socket), Task = null }; var Task = new Task ( () => { try { while (true) { if (ListeningTaskToken.IsCancellationRequested) { return; } try { var a = BindingInfo.Socket.Check(s => s).Accept(); AcceptedSockets.Add(a); AcceptingTaskNotifier.Set(); } catch (SocketException) { if (ListeningTaskToken.IsCancellationRequested) { return; } BindingInfo.Socket.Update ( OriginalSocket => { try { OriginalSocket.Close(); } catch (Exception) { } try { OriginalSocket.Dispose(); } catch (Exception) { } var NewSocket = new Socket(Binding.AddressFamily, SocketType.Stream, ProtocolType.Tcp); NewSocket.Bind(Binding); NewSocket.Listen(MaxConnectionsValue.HasValue ? (MaxConnectionsValue.Value + 1) : 128); Socket = NewSocket; return(NewSocket); } ); } } } catch (ObjectDisposedException) { } }, TaskCreationOptions.LongRunning ); BindingInfo.Task = Task; BindingInfos.Add(Binding, BindingInfo); } if (BindingInfos.Count == 0) { throw new AggregateException(Exceptions); } AcceptingTask = new Task ( () => { while (true) { if (AcceptingTaskToken.IsCancellationRequested) { return; } AcceptingTaskNotifier.WaitOne(); while (true) { Socket a; if (!AcceptedSockets.TryTake(out a)) { break; } var s = new TSession() { Server = (TServer)this, RemoteEndPoint = (IPEndPoint)(a.RemoteEndPoint) }; if (SessionIdleTimeoutValue.HasValue) { a.ReceiveTimeout = SessionIdleTimeoutValue.Value * 1000; } s.SetSocket(a); if (MaxConnectionsValue.HasValue && (Sessions.Check(ss => ss.Count) >= MaxConnectionsValue.Value)) { try { s.Start(); if (MaxConnectionsExceeded != null) { MaxConnectionsExceeded(s); } } finally { s.Stop(); s.Dispose(); } continue; } IPEndPoint e = (IPEndPoint)(a.RemoteEndPoint); if (MaxConnectionsPerIPValue.HasValue && (IpSessions.Check(iss => iss.ContainsKey(e.Address) ? iss[e.Address] : 0) >= MaxConnectionsPerIPValue.Value)) { try { s.Start(); if (MaxConnectionsPerIPExceeded != null) { MaxConnectionsPerIPExceeded(s); } } finally { s.Stop(); s.Dispose(); } continue; } Sessions.DoAction ( ss => { ss.Add(s); } ); IpSessions.DoAction ( iss => { if (iss.ContainsKey(e.Address)) { iss[e.Address] += 1; } else { iss.Add(e.Address, 1); } } ); s.Start(); } } }, AcceptingTaskToken, TaskCreationOptions.LongRunning ); PurifieringTask = new Task ( () => { while (true) { if (PurifieringTaskToken.IsCancellationRequested) { return; } PurifieringTaskNotifier.WaitOne(); TSession StoppingSession; while (StoppingSessions.TryTake(out StoppingSession)) { var Removed = false; Sessions.DoAction ( ss => { if (ss.Contains(StoppingSession)) { ss.Remove(StoppingSession); Removed = true; } } ); if (Removed) { var IpAddress = StoppingSession.RemoteEndPoint.Address; IpSessions.DoAction ( iss => { if (iss.ContainsKey(IpAddress)) { iss[IpAddress] -= 1; if (iss[IpAddress] == 0) { iss.Remove(IpAddress); } } } ); } StoppingSession.Stop(); StoppingSession.Dispose(); } } }, PurifieringTaskToken, TaskCreationOptions.LongRunning ); AcceptingTask.Start(); PurifieringTask.Start(); foreach (var BindingInfo in BindingInfos.Values) { BindingInfo.Task.Start(); } Success = true; return(true); } ); } finally { if (!Success) { Stop(); } } }
public static void TestTcpForNumUser(IPEndPoint RemoteEndPoint, SerializationProtocolType ProtocolType, int NumRequestPerUser, int NumUser, String Title, Action <int, int, ClientContext, IApplicationClient, Action> Test) { Console.Write("{0}: ", Title); Console.Out.Flush(); var tll = new Object(); var tl = new List <Task>(); var bcl = new List <TcpClient>(); var ccl = new List <ClientContext>(); var vConnected = new LockedVariable <int>(0); var vCompleted = new LockedVariable <int>(0); var Check = new AutoResetEvent(false); var vError = new LockedVariable <int>(0); for (int k = 0; k < NumUser; k += 1) { Action Completed = null; var n = k; var Lockee = new Object(); IApplicationClient ac; IStreamedVirtualTransportClient vtc; if (ProtocolType == SerializationProtocolType.Binary) { var a = new BinarySerializationClientAdapter(); ac = a.GetApplicationClient(); vtc = new BinaryCountPacketClient(a); } else if (ProtocolType == SerializationProtocolType.Json) { var a = new JsonSerializationClientAdapter(); ac = a.GetApplicationClient(); vtc = new JsonLinePacketClient(a); } else { throw new InvalidOperationException(); } var bc = new TcpClient(RemoteEndPoint, vtc, QueueUserWorkItem); var cc = new ClientContext(); ac.Error += e => { var m = e.Message; Console.WriteLine(m); }; bc.Connect(); Action <Exception> UnknownFaulted = ex => { int OldValue = 0; vError.Update(v => { OldValue = v; return(v + 1); }); if (OldValue <= 10) { Console.WriteLine(String.Format("{0}:{1}", n, ex.Message)); } vCompleted.Update(i => i + 1); Check.Set(); }; bc.ReceiveAsync ( a => { a(); }, UnknownFaulted ); ac.ServerTime(new ServerTimeRequest { }).ContinueWith(tt => { vConnected.Update(i => i + 1); Check.Set(); }); Action f = () => { Test(NumUser, n, cc, ac, Completed); }; var t = new Task(f); lock (tll) { tl.Add(t); } bcl.Add(bc); ccl.Add(cc); int RequestCount = NumRequestPerUser; Completed = () => { if (RequestCount > 0) { RequestCount -= 1; var tt = new Task(f); lock (tll) { tl.Add(t); } tt.Start(); return; } vCompleted.Update(i => i + 1); Check.Set(); }; } while (vConnected.Check(i => i != NumUser)) { Check.WaitOne(); } var Time = Environment.TickCount; lock (tll) { foreach (var t in tl) { t.Start(); } } while (vCompleted.Check(i => i != NumUser)) { Check.WaitOne(); } var TimeDiff = Environment.TickCount - Time; Task.WaitAll(tl.ToArray()); foreach (var t in tl) { t.Dispose(); } foreach (var bc in bcl) { bc.Dispose(); } var NumError = vError.Check(v => v); if (NumError > 0) { Console.WriteLine("{0} Errors", NumError); } Console.WriteLine("{0} Users, {1} Request/User, {2} ms", NumUser, NumRequestPerUser, TimeDiff); }
public static void Run(Configuration c) { Console.WriteLine(Times.DateTimeUtcWithMillisecondsToString(DateTime.UtcNow) + @" 服务器进程启动。"); var ProcessorCount = Environment.ProcessorCount; var WorkThreadCount = c.NumThread.OnSome ? Math.Max(1, c.NumThread.Value) : ProcessorCount; Console.WriteLine(@"逻辑处理器数量: " + ProcessorCount.ToString()); Console.WriteLine(@"工作线程数量: {0}".Formats(WorkThreadCount)); using (var tp = new CountedThreadPool("Worker", WorkThreadCount)) using (var tpPurifier = new CountedThreadPool("Purifier", 2)) using (var tpLog = new CountedThreadPool("Log", 1)) using (var ExitEvent = new AutoResetEvent(false)) using (var Logger = new ConsoleLogger(tpLog.QueueUserWorkItem)) { Logger.Start(); LockedVariable <ConsoleCancelEventHandler> CancelKeyPressInner = null; CancelKeyPressInner = new LockedVariable <ConsoleCancelEventHandler>((sender, e) => { CancelKeyPressInner.Update(v => { return(null); }); e.Cancel = true; Console.WriteLine(Times.DateTimeUtcWithMillisecondsToString(DateTime.UtcNow) + @" 命令行中断退出。"); ExitEvent.Set(); }); ConsoleCancelEventHandler CancelKeyPress = (sender, e) => { var f = CancelKeyPressInner.Check(v => v); if (f == null) { return; } f(sender, e); }; Console.CancelKeyPress += CancelKeyPress; var ChatContexts = new List <ServerContext>(); var ServerCloses = new List <Action>(); try { foreach (var s in c.Servers) { if (s.OnChat) { var ss = s.Chat; var ServerContext = new ServerContext(); ChatContexts.Add(ServerContext); ServerContext.EnableLogNormalIn = c.EnableLogNormalIn; ServerContext.EnableLogNormalOut = c.EnableLogNormalOut; ServerContext.EnableLogUnknownError = c.EnableLogUnknownError; ServerContext.EnableLogCriticalError = c.EnableLogCriticalError; ServerContext.EnableLogPerformance = c.EnableLogPerformance; ServerContext.EnableLogSystem = c.EnableLogSystem; ServerContext.EnableLogTransport = c.EnableLogTransport; ServerContext.ServerDebug = c.ServerDebug; ServerContext.ClientDebug = c.ClientDebug; ServerContext.Shutdown += () => { Console.WriteLine(Times.DateTimeUtcWithMillisecondsToString(DateTime.UtcNow) + @" 远程命令退出。"); ExitEvent.Set(); }; if (c.EnableLogConsole) { ServerContext.SessionLog += Logger.Push; } var Protocols = new List <IServer>(); var Factory = new TaskFactory(tp); var PurifierFactory = new TaskFactory(tp); foreach (var p in ss.Protocols) { if (System.Diagnostics.Debugger.IsAttached) { Protocols.Add(StartProtocol(c, p, ServerContext, Factory, PurifierFactory)); } else { try { Protocols.Add(StartProtocol(c, p, ServerContext, Factory, PurifierFactory)); } catch (Exception ex) { var Message = Times.DateTimeUtcWithMillisecondsToString(DateTime.UtcNow) + "\r\n" + ExceptionInfo.GetExceptionInfo(ex); Console.WriteLine(Message); FileLoggerSync.WriteLog("Error.log", Message); } } } ServerCloses.Add(() => { foreach (var Session in ServerContext.Sessions.AsParallel()) { Session.SessionLock.EnterReadLock();; try { if (Session.EventPump != null) { Session.EventPump.ServerShutdown(new Communication.ServerShutdownEvent { }); } } finally { Session.SessionLock.ExitReadLock(); } } foreach (var p in Protocols) { if (System.Diagnostics.Debugger.IsAttached) { StopProtocol(p); } else { try { StopProtocol(p); } catch (Exception ex) { var Message = Times.DateTimeUtcWithMillisecondsToString(DateTime.UtcNow) + "\r\n" + ExceptionInfo.GetExceptionInfo(ex); Console.WriteLine(Message); FileLoggerSync.WriteLog("Error.log", Message); } } } if (c.EnableLogConsole) { ServerContext.SessionLog -= Logger.Push; } Console.WriteLine(@"ChatServerContext.RequestCount = {0}".Formats(ServerContext.RequestCount)); Console.WriteLine(@"ChatServerContext.ReplyCount = {0}".Formats(ServerContext.ReplyCount)); Console.WriteLine(@"ChatServerContext.EventCount = {0}".Formats(ServerContext.EventCount)); }); } else { throw new InvalidOperationException("未知服务器类型: " + s._Tag.ToString()); } } ExitEvent.WaitOne(); Console.CancelKeyPress -= CancelKeyPress; } finally { foreach (var a in ServerCloses) { a(); } } } Console.WriteLine(Times.DateTimeUtcWithMillisecondsToString(DateTime.UtcNow) + @" 服务器进程退出完成。"); }