public TelnetStreamWatcherBase(TelnetStreamWatcherOptions options) { this.Options = options; Listener = TcpIp.CreateListener(new TcpListenParam(async(listener, sock) => { try { Con.WriteDebug($"TelnetStreamWatcher({this.ToString()}: Connected: {sock.EndPointInfo._GetObjectDump()}"); using (var destStream = sock.GetStream()) { if (sock.Info.Ip.RemoteIPAddress == null || Options.IPAccessFilter(sock.Info.Ip.RemoteIPAddress) == false) { Con.WriteDebug($"TelnetStreamWatcher({this.ToString()}: Access denied: {sock.EndPointInfo._GetObjectDump()}"); await destStream.WriteAsync("You are not allowed to access to this service.\r\n\r\n"._GetBytes_Ascii()); await Task.Delay(100); return; } using (var pipePoint = await SubscribeImplAsync()) { // ソケットから Enter キー入力を待機する Task keyInputTask = TaskUtil.StartAsyncTaskAsync(async() => { using StreamReader lineReader = new StreamReader(destStream); while (true) { string?line = await lineReader.ReadLineAsync(); if (line == null) { break; } line = line.Trim(); if (line._IsSamei("s")) { // Socket リストの表示 var list = LocalNet.GetSockList().OrderBy(x => x.Connected); StringWriter w = new StringWriter(); w.WriteLine(); foreach (var sock in list) { string tmp = sock._GetObjectDump(); w.WriteLine(tmp); } w.WriteLine(); w.WriteLine($"Total sockets: {list.Count()}"); w.WriteLine(); byte[] data = w.ToString()._GetBytes_Ascii(); var pipe = pipePoint; if (pipe.CounterPart != null) { lock (pipe.CounterPart.StreamWriter.LockObj) { if (pipe.CounterPart.StreamWriter.NonStopWriteWithLock(data, false, FastStreamNonStopWriteMode.DiscardExistingData) != 0) { // To avoid deadlock, CompleteWrite() must be called from other thread. // (CompleteWrite() ==> Disconnect ==> Socket Log will recorded ==> ReceiveLog() ==> this function will be called!) TaskUtil.StartSyncTaskAsync(() => pipe.CounterPart.StreamWriter.CompleteWrite(false), false, false)._LaissezFaire(true); } } } } else { // GC Dbg.WriteLine($"Manual GC is called by the administrator."); long start = FastTick64.Now; Dbg.GcCollect(); long end = FastTick64.Now; long spentTime = end - start; Dbg.WriteLine($"Manual GC Took Time: {spentTime} msecs."); } } }); try { // ソケットに対して、pipePoint のストリームをそのまま非同期で流し込む using (var pipeStub = pipePoint.GetNetAppProtocolStub()) using (var srcStream = pipeStub.GetStream()) { await srcStream.CopyToAsync(destStream, sock.GrandCancel); } } finally { await UnsubscribeImplAsync(pipePoint); await pipePoint.CleanupAsync(new DisconnectedException()); await keyInputTask._TryAwait(noDebugMessage: true); } } } } finally { Con.WriteDebug($"TelnetStreamWatcher({this.ToString()}: Disconnected: {sock.EndPointInfo._GetObjectDump()}"); } }, "TelnetStreamWatcher", this.Options.EndPoints.ToArray())); this.AddIndirectDisposeLink(this.Listener); }
public async Task StartWebSocketClientAsync(string uri, CancellationToken cancel = default) { if (Started.IsFirstCall() == false) { throw new ApplicationException("Already started."); } LowerStream.ReadTimeout = Options.TimeoutOpen; LowerStream.WriteTimeout = Options.TimeoutOpen; Uri u = new Uri(uri); HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, uri); byte[] nonce = Secure.Rand(16); string requestKey = Convert.ToBase64String(nonce); req.Headers.Add("Host", u.Host); req.Headers.Add("User-Agent", Options.UserAgent); req.Headers.Add("Accept", Consts.MimeTypes.Html); req.Headers.Add("Sec-WebSocket-Version", "13"); req.Headers.Add("Origin", "null"); req.Headers.Add("Sec-WebSocket-Key", requestKey); req.Headers.Add("Connection", "keep-alive, Upgrade"); req.Headers.Add("Pragma", "no-cache"); req.Headers.Add("Cache-Control", "no-cache"); req.Headers.Add("Upgrade", "websocket"); StringWriter tmpWriter = new StringWriter(); tmpWriter.WriteLine($"{req.Method} {req.RequestUri.PathAndQuery} HTTP/1.1"); tmpWriter.WriteLine(req.Headers.ToString()); await LowerStream.WriteAsync(tmpWriter.ToString()._GetBytes_UTF8(), cancel); Dictionary <string, string> headers = new Dictionary <string, string>(StrComparer.IgnoreCaseComparer); int num = 0; int responseCode = 0; StreamReader tmpReader = new StreamReader(LowerStream); while (true) { string line = await TaskUtil.DoAsyncWithTimeout((procCancel) => tmpReader.ReadLineAsync(), timeout : Options.TimeoutOpen, cancel : cancel); if (line == "") { break; } if (num == 0) { string[] tokens = line.Split(' '); if (tokens[0] != "HTTP/1.1") { throw new ApplicationException($"Cannot establish the WebSocket Protocol. Response: \"{tokens}\""); } responseCode = int.Parse(tokens[1]); } else { string[] tokens = line.Split(':'); string name = tokens[0].Trim(); string value = tokens[1].Trim(); headers[name] = value; } num++; } if (responseCode != 101) { throw new ApplicationException($"Cannot establish the WebSocket Protocol. Perhaps the destination host does not support WebSocket. Wrong response code: \"{responseCode}\""); } if (headers["Upgrade"].Equals("websocket", StringComparison.InvariantCultureIgnoreCase) == false) { throw new ApplicationException($"Wrong Upgrade header: \"{headers["Upgrade"]}\""); } string acceptKey = headers["Sec-WebSocket-Accept"]; string keyCalcStr = requestKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; SHA1 sha1 = new SHA1Managed(); string acceptKey2 = Convert.ToBase64String(sha1.ComputeHash(keyCalcStr._GetBytes_Ascii())); if (acceptKey != acceptKey2) { throw new ApplicationException($"Wrong accept_key: \'{acceptKey}\'"); } this.SendTask = SendLoopAsync(); this.RecvTask = RecvLoopAsync(); }
async Task RecvLoopAsync() { try { CancellationToken cancel = this.GrandCancel; LowerStream.ReadTimeout = Options.TimeoutComm; MemoryBuffer <byte> currentRecvingMessage = new MemoryBuffer <byte>(); while (true) { byte b1 = await LowerStream.ReceiveByteAsync(cancel).FlushOtherStreamIfPending(UpperStream); WebSocketOpcode opcode = (WebSocketOpcode)(b1 & 0x0f); byte b2 = await LowerStream.ReceiveByteAsync(cancel); bool isMasked = (b2 & 0b10000000)._ToBool(); int tmp = (b2 & 0b01111111); ulong payloadLen64 = 0; if (tmp <= 125) { payloadLen64 = (ulong)tmp; } else if (tmp == 126) { payloadLen64 = await LowerStream.ReceiveUInt16Async(cancel).FlushOtherStreamIfPending(UpperStream); } else if (tmp == 127) { payloadLen64 = await LowerStream.ReceiveUInt64Async(cancel).FlushOtherStreamIfPending(UpperStream); } if (payloadLen64 > (ulong)Options.RecvMaxPayloadLenPerFrame) { throw new ApplicationException($"payloadLen64 {payloadLen64} > Options.RecvMaxPayloadLenPerFrame {Options.RecvMaxPayloadLenPerFrame}"); } int payloadLen = (int)payloadLen64; Memory <byte> maskKey = default; if (isMasked) { maskKey = await LowerStream.ReceiveAllAsync(4, cancel).FlushOtherStreamIfPending(UpperStream); } Memory <byte> data = await LowerStream.ReceiveAllAsync(payloadLen, cancel).FlushOtherStreamIfPending(UpperStream); if (isMasked) { TaskUtil.Sync(() => { Span <byte> maskKeySpan = maskKey.Span; Span <byte> dataSpan = data.Span; for (int i = 0; i < dataSpan.Length; i++) { dataSpan[i] = (byte)(dataSpan[i] ^ maskKeySpan[i % 4]); } }); } if (opcode.EqualsAny(WebSocketOpcode.Text, WebSocketOpcode.Bin, WebSocketOpcode.Continue)) { if (Options.RespectMessageDelimiter == false) { if (data.Length >= 1) { await UpperStream.WaitReadyToSendAsync(cancel, Timeout.Infinite); UpperStream.FastSendNonBlock(data, false); } } else { bool isFin = (b1 & 0b10000000)._ToBool(); if (isFin && opcode.EqualsAny(WebSocketOpcode.Text, WebSocketOpcode.Bin)) { // Single message if (data.Length >= 1) { await UpperStream.WaitReadyToSendAsync(cancel, Timeout.Infinite); UpperStream.FastSendNonBlock(data, false); } } else if (isFin == false && opcode.EqualsAny(WebSocketOpcode.Text, WebSocketOpcode.Bin)) { // First message currentRecvingMessage.Clear(); if ((currentRecvingMessage.Length + data.Length) >= Options.RecvMaxTotalFragmentSize) { throw new ApplicationException("WebSocket: Exceeding Options.RecvMaxTotalFragmentSize."); } currentRecvingMessage.Write(data); } else if (isFin && opcode == WebSocketOpcode.Continue) { // Final continuous message if ((currentRecvingMessage.Length + data.Length) >= Options.RecvMaxTotalFragmentSize) { throw new ApplicationException("WebSocket: Exceeding Options.RecvMaxTotalFragmentSize."); } currentRecvingMessage.Write(data); if (currentRecvingMessage.Length >= 1) { await UpperStream.WaitReadyToSendAsync(cancel, Timeout.Infinite); UpperStream.FastSendNonBlock(data, false); } currentRecvingMessage.Clear(); } else if (isFin == false && opcode == WebSocketOpcode.Continue) { // Intermediate continuous message if ((currentRecvingMessage.Length + data.Length) >= Options.RecvMaxTotalFragmentSize) { throw new ApplicationException("WebSocket: Exceeding Options.RecvMaxTotalFragmentSize."); } currentRecvingMessage.Write(data); } } } else if (opcode == WebSocketOpcode.Pong) { lock (this.PongQueueLock) { this.PongQueue.Enqueue(data); } this.SendPongEvent.Set(true); } else if (opcode == WebSocketOpcode.Ping) { lock (this.PongQueueLock) { this.PongQueue.Enqueue(data); } this.SendPongEvent.Set(true); } else if (opcode == WebSocketOpcode.Close) { throw new DisconnectedException(); } else { throw new ApplicationException($"WebSocket: Unknown Opcode: {(int)opcode}"); } } } catch (Exception ex) { this.UpperStream.Disconnect(); this.Cancel(ex); } }
// メインループ async Task MainLoopAsync(CancellationToken cancel) { while (cancel.IsCancellationRequested == false) { // インターネットが接続されるまで待機する if (await WaitForInternetAsync(cancel) == false) { // キャンセルされた return; } // 接続された _IsInternetConnected = true; FirstConnectedEvent.Set(true); EventListener.FireSoftly(this, NonsenseEventType.Nonsense, true); int lastNetworkVersion = TcpIp.GetHostInfo(false).InfoVersion; AsyncAutoResetEvent networkChangedEvent = new AsyncAutoResetEvent(); int eventRegisterId = TcpIp.RegisterHostInfoChangedEvent(networkChangedEvent); try { // 定期的に、現在もインターネットに接続されているかどうか確認する while (cancel.IsCancellationRequested == false) { // 一定時間待つ ただしネットワーク状態の変化が発生したときは待ちを解除する await TaskUtil.WaitObjectsAsync(cancels : cancel._SingleArray(), events : networkChangedEvent._SingleArray(), timeout : Options.CheckIntervalAfterEstablished); if (cancel.IsCancellationRequested) { break; } // 接続検査を再実行する // ただし、今度はタイムアウトを設定する CancellationTokenSource timeoutCts = new CancellationTokenSource(); timeoutCts.CancelAfter(Options.TimeoutToDetectDisconnected); bool ret = await StartEveryTestAsync(timeoutCts.Token, null); if (cancel.IsCancellationRequested) { break; } if (ret == false) { // 接続試験に失敗 (タイムアウト発生) // 切断された _IsInternetConnected = false; FirstDisconnectedEvent.Set(true); EventListener.FireSoftly(this, NonsenseEventType.Nonsense, false); break; } } } finally { TcpIp.UnregisterHostInfoChangedEvent(eventRegisterId); } } }
// ランダムに配列した各テストを 1 秒間隔で順に実行していき、1 つでも成功したら抜ける // 1 つでも成功した場合は true、成功するまでにネットワークの状態が変化した場合は false を返す async Task <bool> StartEveryTestAsync(CancellationToken cancel, AsyncAutoResetEvent?networkChangedEvent) { int startNetworkVersion = (networkChangedEvent == null) ? 0 : TcpIp.GetHostInfo(false).InfoVersion; CancellationTokenSource cts = new CancellationTokenSource(); using (TaskUtil.CreateCombinedCancellationToken(out CancellationToken opCancel, cancel, cts.Token)) { // テストをシャッフルする var shuffledTests = Options.GetTestItemList()._Shuffle(); List <Task <bool> > runningTaskList = new List <Task <bool> >(); RefBool retBool = new RefBool(); // シャッフルしたテストを実行する int num = 0; foreach (var test in shuffledTests) { Task <bool> t = AsyncAwait(async() => { //Con.WriteDebug($"{test} - Waiting {num} secs..."); if (await opCancel._WaitUntilCanceledAsync(1000 * num)) { // キャンセルされた return(false); } int numRetry = 0; while (true) { if (opCancel.IsCancellationRequested) { return(false); } bool ret = await PerformSingleTestAsync(test, opCancel); //Con.WriteDebug($"{test} - {ret}"); if (ret) { // 成功 retBool.Set(true); // 自分自信のほか、他のタスクもすべてキャンセルする cts._TryCancelNoBlock(); return(true); } // 再試行まで待機 numRetry++; int retryInterval = Util.GenRandIntervalWithRetry(Options.RetryIntervalMin, numRetry, Options.RetryIntervalMax); if (test is InternetCheckerPingTestItem) { retryInterval = Util.GenRandIntervalWithRetry(Options.RetryIntervalMin, numRetry, Options.RetryIntervalMaxPing); } await TaskUtil.WaitObjectsAsync(cancels: opCancel._SingleArray(), events: networkChangedEvent._SingleArray(), timeout: retryInterval); if (opCancel.IsCancellationRequested) { // キャンセルされた return(false); } if (startNetworkVersion != 0) { int currentNetworkVersion = BackgroundState <PalHostNetInfo> .Current.Version; if (startNetworkVersion != currentNetworkVersion) { // ネットワーク状態が変化した // 自分自身のほか、他のタスクもすべてキャンセルする cts._TryCancelNoBlock(); return(false); } } } }); runningTaskList.Add(t); num++; } // 実行中のテストすべてを待機する await Task.WhenAll(runningTaskList); return(retBool); } }
async Task <Result> ClientSingleConnectionAsync(Direction dir, AsyncManualResetEvent fireMeWhenReady, CancellationToken cancel) { Result ret = new Result(); using (NetPalTcpProtocolStub tcp = new NetPalTcpProtocolStub(cancel: cancel)) { await tcp.ConnectAsync(ServerIP, ServerPort, cancel, ConnectTimeout); using (ConnSock sock = new ConnSock(tcp)) { NetAppStub app = sock.GetNetAppProtocolStub(); AttachHandle attachHandle = app.AttachHandle; PipeStream st = app.GetStream(); if (dir == Direction.Recv) { app.AttachHandle.SetStreamReceiveTimeout(RecvTimeout); } try { var hello = await st.ReceiveAllAsync(16); if (hello.Span.ToArray()._GetString_Ascii().StartsWith("TrafficServer\r\n") == false) { throw new ApplicationException("Target server is not a Traffic Server."); } //throw new ApplicationException("aaaa" + dir.ToString()); fireMeWhenReady.Set(); cancel.ThrowIfCancellationRequested(); await TaskUtil.WaitObjectsAsync( manualEvents : ClientStartEvent._SingleArray(), cancels : cancel._SingleArray() ); long tickStart = FastTick64.Now; long tickEnd = tickStart + this.TimeSpan; var sendData = new MemoryBuffer <byte>(); sendData.WriteBool8(dir == Direction.Recv); sendData.WriteUInt64(SessionId); sendData.WriteSInt64(TimeSpan); await st.SendAsync(sendData); if (dir == Direction.Recv) { RefInt totalRecvSize = new RefInt(); while (true) { long now = FastTick64.Now; if (now >= tickEnd) { break; } await TaskUtil.WaitObjectsAsync( tasks : st.FastReceiveAsync(totalRecvSize : totalRecvSize)._SingleArray(), timeout : (int)(tickEnd - now), exceptions : ExceptionWhen.TaskException | ExceptionWhen.CancelException); ret.NumBytesDownload += totalRecvSize; } } else { attachHandle.SetStreamReceiveTimeout(Timeout.Infinite); while (true) { long now = FastTick64.Now; if (now >= tickEnd) { break; } /*await WebSocketHelper.WaitObjectsAsync( * tasks: st.FastSendAsync(SendData, flush: true).ToSingleArray(), * timeout: (int)(tick_end - now), * exceptions: ExceptionWhen.TaskException | ExceptionWhen.CancelException);*/ await st.FastSendAsync(SendData, flush : true); } Task recvResult = Task.Run(async() => { var recvMemory = await st.ReceiveAllAsync(8); MemoryBuffer <byte> recvMemoryBuf = recvMemory; ret.NumBytesUpload = recvMemoryBuf.ReadSInt64(); st.Disconnect(); }); Task sendSurprise = Task.Run(async() => { byte[] surprise = new byte[260]; surprise.AsSpan().Fill((byte)'!'); while (true) { await st.SendAsync(surprise); await TaskUtil.WaitObjectsAsync( manualEvents: sock.Pipe.OnDisconnectedEvent._SingleArray(), timeout: 200); } }); await WhenAll.Await(false, recvResult, sendSurprise); await recvResult; } st.Disconnect(); return(ret); } catch (Exception ex) { ExceptionQueue !.Add(ex); throw; } } } }
async Task ServerMainLoop(CancellationToken mainLoopCancel) { if (Once.IsFirstCall() == false) { throw new ApplicationException("You cannot reuse the object."); } using (var sessions = new GroupManager <ulong, SessionData>( onNewGroup: (key, state) => { Dbg.Where($"New session: {key}"); return(new SessionData()); }, onDeleteGroup: (key, ctx, state) => { Dbg.Where($"Delete session: {key}"); })) { var listener = System.CreateListener(new TcpListenParam(async(lx, sock) => { Con.WriteLine($"Connected {sock.Info.Tcp.RemoteIPAddress}:{sock.Info.Tcp.RemotePort} -> {sock.Info.Tcp.LocalIPAddress}:{sock.Info.Tcp.LocalPort}"); var app = sock.GetNetAppProtocolStub(); var st = app.GetStream(); var attachHandle = app.AttachHandle; attachHandle.SetStreamReceiveTimeout(RecvTimeout); await st.SendAsync("TrafficServer\r\n\0"._GetBytes_Ascii()); ReadOnlyMemoryBuffer <byte> buf = await st.ReceiveAsync(17); Direction dir = buf.ReadBool8() ? Direction.Send : Direction.Recv; ulong sessionId = 0; long timespan = 0; try { sessionId = buf.ReadUInt64(); timespan = buf.ReadSInt64(); } catch { } long recvEndTick = FastTick64.Now + timespan; if (timespan == 0) { recvEndTick = long.MaxValue; } using (var session = sessions.Enter(sessionId)) { using (var delay = new DelayAction((int)(Math.Min(timespan * 3 + 180 * 1000, int.MaxValue)), x => app._CancelSafe(new TimeoutException()))) { if (dir == Direction.Recv) { RefInt refTmp = new RefInt(); long totalSize = 0; while (true) { var ret = await st.FastReceiveAsync(totalRecvSize: refTmp); if (ret.Count == 0) { break; } totalSize += refTmp; if (ret[0].Span[0] == (byte)'!') { break; } if (FastTick64.Now >= recvEndTick) { break; } } attachHandle.SetStreamReceiveTimeout(Timeout.Infinite); attachHandle.SetStreamSendTimeout(60 * 5 * 1000); session.Context.NoMoreData = true; while (true) { MemoryBuffer <byte> sendBuf = new MemoryBuffer <byte>(); sendBuf.WriteSInt64(totalSize); await st.SendAsync(sendBuf); await Task.Delay(100); } } else { attachHandle.SetStreamReceiveTimeout(Timeout.Infinite); attachHandle.SetStreamSendTimeout(Timeout.Infinite); while (true) { if (sessionId == 0 || session.Context.NoMoreData == false) { await st.SendAsync(SendData); } else { var recvMemory = await st.ReceiveAsync(); if (recvMemory.Length == 0) { break; } } } } } } }, "SpeedTest", this.ServerPorts)); try { Con.WriteLine("Listening."); await TaskUtil.WaitObjectsAsync(cancels : mainLoopCancel._SingleArray()); } finally { await listener._DisposeWithCleanupSafeAsync(); } } }
async Task ReadMainLoop(CancellationToken cancel) { try { var st = this.Reader.StreamReader; int numFailed = 0; while (true) { await TaskUtil.AwaitWithPollAsync(Timeout.Infinite, this.Emitter !.Options.Delay, () => this.Reader.StreamReader.IsReadyToRead(), cancel); IReadOnlyList <ReadOnlyMemory <byte> > dataToWrite = DequeueAll(out long totalSize, this.Emitter.Options.DefragmentWriteBlockSize); if (totalSize == 0) { if (cancel.IsCancellationRequested) { break; } else { continue; } } L_RETRY: try { await Emitter.EmitAsync(dataToWrite); numFailed = 0; if (this.Reader.StreamReader.IsReadyToRead() == false) { await Emitter.FlushAsync(); } } catch (Exception ex) { ex._Debug(); numFailed++; if (cancel.IsCancellationRequested == false) { await cancel._WaitUntilCanceledAsync(Util.GenRandIntervalWithRetry(CoresConfig.LazyWriteBufferSettings.ErrorRetryIntervalStd, numFailed, CoresConfig.LazyWriteBufferSettings.ErrorRetryIntervalMax)); goto L_RETRY; } else { break; } } } } finally { try { await Emitter !.CloseAsync(); } catch { } } }
public async Task <Result?> RunClientAsync() { CurrentCount.Increment(); try { if (Once.IsFirstCall() == false) { throw new ApplicationException("You cannot reuse the object."); } Con.WriteLine("Client mode start"); ExceptionQueue = new ExceptionQueue(); SessionId = Util.RandUInt64(); List <Task <Result> > tasks = new List <Task <Result> >(); List <AsyncManualResetEvent> readyEvents = new List <AsyncManualResetEvent>(); using (CancelWatcher cancelWatcher = new CancelWatcher(this.Cancel)) { for (int i = 0; i < NumConnection; i++) { Direction dir; if (Mode == SpeedTestModeFlag.Download) { dir = Direction.Recv; } else if (Mode == SpeedTestModeFlag.Upload) { dir = Direction.Send; } else { dir = ((i % 2) == 0) ? Direction.Recv : Direction.Send; } AsyncManualResetEvent readyEvent = new AsyncManualResetEvent(); var t = ClientSingleConnectionAsync(dir, readyEvent, cancelWatcher.CancelToken); ExceptionQueue.RegisterWatchedTask(t); tasks.Add(t); readyEvents.Add(readyEvent); } try { using (var whenAllReady = new WhenAll(readyEvents.Select(x => x.WaitAsync()))) { await TaskUtil.WaitObjectsAsync( tasks : tasks.Append(whenAllReady.WaitMe).ToArray(), cancels : cancelWatcher.CancelToken._SingleArray(), manualEvents : ExceptionQueue.WhenExceptionAdded._SingleArray()); } Cancel.ThrowIfCancellationRequested(); ExceptionQueue.ThrowFirstExceptionIfExists(); ExceptionQueue.WhenExceptionAdded.CallbackList.AddSoftCallback(x => { cancelWatcher.Cancel(); }); using (new DelayAction(TimeSpan * 3 + 180 * 1000, x => { cancelWatcher.Cancel(); }, doNotBlockOnDispose: true)) { ClientStartEvent.Set(true); using (var whenAllCompleted = new WhenAll(tasks)) { await TaskUtil.WaitObjectsAsync( tasks : whenAllCompleted.WaitMe._SingleArray(), cancels : cancelWatcher.CancelToken._SingleArray() ); await whenAllCompleted.WaitMe; } } Result ret = new Result(); ret.Span = TimeSpan; foreach (var r in tasks.Select(x => x._GetResult())) { ret.NumBytesDownload += r.NumBytesDownload; ret.NumBytesUpload += r.NumBytesUpload; } ret.NumBytesTotal = ret.NumBytesUpload + ret.NumBytesDownload; ret.BpsUpload = (long)((double)ret.NumBytesUpload * 1000.0 * 8.0 / (double)ret.Span * 1514.0 / 1460.0); ret.BpsDownload = (long)((double)ret.NumBytesDownload * 1000.0 * 8.0 / (double)ret.Span * 1514.0 / 1460.0); ret.BpsTotal = ret.BpsUpload + ret.BpsDownload; return(ret); } catch (Exception ex) { await Task.Yield(); ExceptionQueue.Add(ex); } finally { cancelWatcher.Cancel(); try { await Task.WhenAll(tasks); } catch { } } ExceptionQueue.ThrowFirstExceptionIfExists(); } return(null); } finally { CurrentCount.Decrement(); } }
public void Show() { HiveData.SyncWithStorage(HiveSyncFlags.LoadFromFile, true); long pid = HiveData.ManagedData.Pid; int port = HiveData.ManagedData.LocalLogWatchPort; if (pid != 0 && port != 0) { Con.WriteLine("Starting the real-time log session."); Con.WriteLine("Pressing Ctrl + D or Ctrl + Q to disconnect the session."); Con.WriteLine(); Con.WriteLine($"Connecting to localhost:{port} ..."); CancellationTokenSource cancelSource = new CancellationTokenSource(); CancellationToken cancel = cancelSource.Token; Task task = TaskUtil.StartAsyncTaskAsync(async() => { try { using (var sock = await LocalNet.ConnectAsync(new TcpConnectParam(IPAddress.Loopback, port), cancel)) using (var stream = sock.GetStream()) using (MemoryHelper.FastAllocMemoryWithUsing(65536, out Memory <byte> tmp)) { Con.WriteLine("The real-time log session is connected."); Con.WriteLine(); try { while (true) { int r = await stream.ReadAsync(tmp, cancel); if (r <= 0) { break; } ReadOnlyMemory <byte> data = tmp.Slice(0, r); string s = Str.Utf8Encoding.GetString(data.Span); Console.Write(s); } } catch { } Con.WriteLine(); Con.WriteLine("The real-time log session is disconnected."); } } catch (Exception ex) { Con.WriteError(ex.Message); } }); try { while (true) { var key = Console.ReadKey(); if ((key.Key == ConsoleKey.D || key.Key == ConsoleKey.Q) && key.Modifiers == ConsoleModifiers.Control) { break; } } } catch { } cancelSource._TryCancelNoBlock(); task._TryWait(true); } else { Con.WriteLine($"The daemon \"{Name}\" is not running."); } }
static void StartUpdateLoop() { UpdateMainLoopTaskCancel = new CancellationTokenSource(); UpdateMainLoopTask = TaskUtil.StartAsyncTaskAsync(UpdateRepositoryMainLoopAsync); }
public void ExecMain() { if (Once.IsFirstCall() == false) { throw new ApplicationException("StartMainLoop can be called only once."); } this.SingleInstance = new SingleInstance($"UserModeService_{this.Name}"); try { string? eventName = null; EventWaitHandle?eventHandle = null; if (Env.IsUnix) { System.Runtime.Loader.AssemblyLoadContext.Default.Unloading += UnixSigTermHandler; } else { eventName = @"Global\usermodesvc_" + Util.Rand(16)._GetHexString().ToLower(); eventHandle = new EventWaitHandle(false, EventResetMode.ManualReset, eventName); TaskUtil.StartSyncTaskAsync(() => { eventHandle.WaitOne(); Win32PipeRecvHandler(); }, leakCheck: false)._LaissezFaire(true); } // Start the TelnetLogWatcher List <IPEndPoint> telnetWatcherEpList = new List <IPEndPoint>(); telnetWatcherEpList.Add(new IPEndPoint(IPAddress.Loopback, HiveData.ManagedData.LocalLogWatchPort)); telnetWatcherEpList.Add(new IPEndPoint(IPAddress.IPv6Loopback, HiveData.ManagedData.LocalLogWatchPort)); if (this.TelnetLogWatcherPort != 0) { telnetWatcherEpList.Add(new IPEndPoint(IPAddress.Any, this.TelnetLogWatcherPort)); telnetWatcherEpList.Add(new IPEndPoint(IPAddress.IPv6Any, this.TelnetLogWatcherPort)); } TelnetWatcher = new TelnetLocalLogWatcher(new TelnetStreamWatcherOptions((ip) => ip._GetIPAddressType().BitAny(IPAddressType.LocalUnicast | IPAddressType.Loopback), null, telnetWatcherEpList.ToArray())); InternalStart(); lock (HiveData.DataLock) { HiveData.ManagedData.Pid = Env.ProcessId; HiveData.ManagedData.EventName = eventName; } HiveData.SyncWithStorage(HiveSyncFlags.SaveToFile, true); // Save pid string pidFileName = Lfs.PathParser.Combine(CoresConfig.UserModeServiceSettings.GetLocalHiveDirProc.Value(), this.Name + ".pid"); string pidBody = Env.ProcessId.ToString() + Env.NewLine; Lfs.WriteStringToFile(pidFileName, pidBody, FileFlags.AutoCreateDirectory); Console.WriteLine(ExecMainSignature); // The daemon routine is now started. Wait here until InternalStop() is called. StoppedEvent.Wait(); } finally { this.TelnetWatcher._DisposeSafe(); this.TelnetWatcher = null; this.SingleInstance._DisposeSafe(); this.SingleInstance = null; } }
public static bool WaitProcessExit(int pid, int timeout, CancellationToken cancel = default) { return(TaskUtil.WaitWithPoll(timeout, 100, () => (IsProcess(pid) == false), cancel)); }
protected override async Task MainLoopImplAsync(CancellationToken cancel) { MessageListPerConversation.Clear(); cancel.ThrowIfCancellationRequested(); CancellationTokenSource realTimeTaskCancel = new CancellationTokenSource(); Task realTimeTask = RealtimeRecvLoopAsync(realTimeTaskCancel.Token); try { bool all = true; string[]? targetChannelIdList = null; while (true) { cancel.ThrowIfCancellationRequested(); ExceptionWhen reason; try { InboxMessageBox box = await ReloadInternalAsync(all, targetChannelIdList, cancel); ClearLastError(); this.InitialLoading = false; MessageBoxUpdatedCallback(box); if (this.UpdateChannelsList.Count == 0) { reason = await TaskUtil.WaitObjectsAsync( cancels : cancel._SingleArray(), events : this.UpdateChannelsEvent._SingleArray(), timeout : Util.GenRandInterval(CoresConfig.InboxSlackAdapterSettings.RefreshAllInterval)); } else { reason = ExceptionWhen.None; } } catch (Exception ex) { SetLastError(ex._GetSingleException()); ex._Debug(); reason = ExceptionWhen.TimeoutException; await cancel._WaitUntilCanceledAsync(15000); } if (reason == ExceptionWhen.TimeoutException) { all = true; targetChannelIdList = null; lock (this.UpdateChannelsListLock) { this.UpdateChannelsList.Clear(); } } else { all = false; lock (this.UpdateChannelsListLock) { targetChannelIdList = this.UpdateChannelsList.ToArray(); this.UpdateChannelsList.Clear(); } } } } finally { realTimeTaskCancel._TryCancel(); await realTimeTask._TryWaitAsync(true); } }
protected override async Task GetValueAsync(SortedDictionary <string, string> ret, RefInt nextPollingInterval, CancellationToken cancel = default) { SnmpWorkSettings settings = Host.Settings; if (settings.PingTargets._IsSamei("none") || settings.PingTargets._IsSamei("null")) { return; } string hopsStr = "Hops"; if (settings.HopsToTTL) { hopsStr = "TTL"; } string[] pingTargets = settings.PingTargets._Split(StringSplitOptions.RemoveEmptyEntries, ","); numPerform++; foreach (string pingTarget in pingTargets) { cancel.ThrowIfCancellationRequested(); ParseTargetString(pingTarget, out string hostname, out string alias); bool ok = false; try { IPAddress ipAddress = await LocalNet.GetIpAsync(hostname, cancel : cancel); if (FirstPing.IsFirstCall()) { // JIT 対策 try { await LocalNet.SendPingAsync(ipAddress, pingCancel : cancel); } catch { } } int numTry = 3; if (numPerform >= 2) { // SpeedTest が動作中の場合は SpeedTest が完了するまで待機する await TaskUtil.AwaitWithPollAsync(Timeout.Infinite, 10, () => !SpeedTestClient.IsInProgress, cancel); // 試行回数を指定する numTry = Math.Min(Math.Max(settings.PingNumTry, 1), 100); } SendPingReply reply = await LocalNet.SendPingAndGetBestResultAsync(ipAddress, pingCancel : cancel, numTry : numTry); if (reply.Ok) { double rtt = reply.RttDouble; rtt = Math.Min(rtt, 2.0); int ttl = reply.Ttl; bool ttl_ok = false; if (ttl == 0) { // Use ping command to get TTL try { var result = await EasyExec.ExecAsync(ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6?Consts.LinuxCommands.Ping6 : Consts.LinuxCommands.Ping, $"-W 1 -c 1 {ipAddress.ToString()}", cancel : cancel, throwOnErrorExitCode : false); string[] lines = result.OutputStr._GetLines(true); foreach (string line in lines) { OneLineParams param = new OneLineParams(line, ' ', false); string ttlStr = param._GetStrFirst("ttl"); if (ttlStr._IsFilled()) { ttl = ttlStr._ToInt(); ttl_ok = true; break; } } } catch (Exception ex) { ex._Debug(); } } else { ttl_ok = true; } ret.TryAdd($"Time - {alias}", (rtt * 1000.0).ToString("F3")); if (ttl > 128) { ttl -= 128; } else if (ttl > 64) { ttl -= 64; } int hops = 64 - ttl; if (ttl_ok == false) { hops = 0; } hops._SetMax(0); hops._SetMin(64); ret.TryAdd($"{hopsStr} - {alias}", hops.ToString()); ok = true; } } catch (Exception ex) { ex._Debug(); } if (ok == false) { ret.TryAdd($"Time - {alias}", ""); ret.TryAdd($"{hopsStr} - {alias}", "0"); } } }
protected override async Task GetValueAsync(SortedDictionary <string, string> ret, RefInt nextPollingInterval, CancellationToken cancel = default) { SnmpWorkSettings settings = Host.Settings; if (settings.PingTargets._IsSamei("none") || settings.PingTargets._IsSamei("null")) { return; } string[] pingTargets = settings.PingTargets._Split(StringSplitOptions.RemoveEmptyEntries, ","); KeyValueList <string, IPAddress> kvList = new KeyValueList <string, IPAddress>(); // 名前解決 foreach (string pingTarget in pingTargets) { cancel.ThrowIfCancellationRequested(); try { ParseTargetString(pingTarget, out string hostname, out string alias); IPAddress ip = await LocalNet.GetIpAsync(hostname, cancel : cancel); kvList.Add(alias, ip); } catch (Exception ex) { ex._Debug(); } } List <Task <double> > taskList = new List <Task <double> >(); int interval = 0; int count = 3; // SpeedTest が動作中の場合は SpeedTest が完了するまで待機する numPerform++; if (numPerform >= 2) { interval = settings.PktLossIntervalMsec; count = settings.PktLossTryCount; await TaskUtil.AwaitWithPollAsync(Timeout.Infinite, 10, () => !SpeedTestClient.IsInProgress, cancel); } // 並列実行の開始 foreach (var kv in kvList) { taskList.Add(PerformOneAsync(kv.Value, count, settings.PktLossTimeoutMsecs, interval, cancel)); } // すべて終了するまで待機し、結果を整理 for (int i = 0; i < kvList.Count; i++) { var kv = kvList[i]; var task = taskList[i]; double lossRate = await task._TryAwait(); double quality = 1.0 - lossRate; quality = Math.Max(quality, 0.0); quality = Math.Min(quality, 1.0); ret.TryAdd($"{kv.Key}", ((double)quality * 100.0).ToString("F3")); } }