public GitLabMainteDaemonApp() { try { // Settings を読み込む this.SettingsHive = new HiveData <GitLabMainteDaemonSettings>(Hive.SharedLocalConfigHive, $"GitLabMainteDaemon", null, HiveSyncPolicy.AutoReadFromFile); this.GitLabClient = new GitLabMainteClient(this.Settings.GitLabClientSettings); // TODO: ここでサーバーを立ち上げるなどの初期化処理を行なう this.MainLoop1Task = TaskUtil.StartAsyncTaskAsync(Loop1_MainteUsersAsync(this.GrandCancel)); this.MainLoop2Task = TaskUtil.StartAsyncTaskAsync(Loop2_MainteUsersAsync(this.GrandCancel)); // Log Browser を立ち上げる var logBrowserOptions = new LogBrowserOptions( this.Settings.GitWebDataRootDir, this.Settings.Title, flags: LogBrowserFlags.SecureJson | LogBrowserFlags.SecureJson_FlatDir | LogBrowserFlags.NoRootDirectory, extsAsMimeTypeUtf8: this.Settings.ExtsAsMimeTypeUtf8, logFileMaxSizePerDir: this.Settings.MaxAccessLogFileSizeInSpecificDir); this.LogBrowser = new LogBrowser(logBrowserOptions, "/d"); // HTTP サーバーを立ち上げる this.Cgi = new CgiHttpServer(new CgiHandler(this), new HttpServerOptions() { AutomaticRedirectToHttpsIfPossible = false, UseKestrelWithIPACoreStack = false, HttpPortsList = new int[] { 80 }.ToList(), HttpsPortsList = new int[] { 443 }.ToList(), UseStaticFiles = false, MaxRequestBodySize = 32 * 1024, ReadTimeoutMsecs = this.Settings.HttpTimeoutMsecs, DenyRobots = true, }, true); } catch { this._DisposeSafe(); throw; } }
protected override async Task DisconnectImplAsync() { await this.PipePointMySide._DisposeSafeAsync2(); await this.PipePointWrapper._DisposeSafeAsync2(); TaskUtil.StartAsyncTaskAsync(async() => { // To prevent deadlock: SSH.net bug await this.Stream._DisposeSafeAsync2(); await this.Ssh._DisposeSafeAsync2(); })._LaissezFaire(); this.PipePointMySide = null; this.PipePointWrapper = null; // To prevent deadlock: SSH.net bug //this.Stream = null; //this.Ssh = null; }
public static Task <T> AsyncAwait <T>(Func <Task <T> > asyncFunc) => TaskUtil.StartAsyncTaskAsync(asyncFunc, leakCheck: true);
public static T Async <T>(Func <Task <T> > asyncFunc) => TaskUtil.StartAsyncTaskAsync(asyncFunc, leakCheck: false)._GetResult();
async Task DialogSessionMainProcAsync(DialogSession session, CancellationToken cancel) { session.Debug("Start"); ThinClientConnectOptions connectOptions = (ThinClientConnectOptions)session.Param !; await using WideTunnel wt = new WideTunnel(this.Options.WideTunnelOptions); ThinClientAuthResponse authResponseCache = null !; session.Debug($"Begin DcConnectEx. connectOptions: {connectOptions._GetObjectDump()}"); await using ThinClientConnection firstConnection = await DcConnectEx(wt, connectOptions, cancel, true, true, async (req, c) => { // 認証コールバック var response = (ThinClientAuthResponse)(await session.RequestAndWaitResponseAsync(req, Consts.ThinClient.RequestHardTimeoutMsecs, Consts.ThinClient.RequestSoftTimeoutMsecs, cancel)); authResponseCache = response; return(response); }, async (req, c) => { // OTP コールバック var response = (ThinClientOtpResponse)(await session.RequestAndWaitResponseAsync(req, Consts.ThinClient.RequestHardTimeoutMsecs, Consts.ThinClient.RequestSoftTimeoutMsecs, cancel)); return(response); }, async (req, c) => { // 検疫・MAC アドレスコールバック var response = (ThinClientInspectResponse)(await session.RequestAndWaitResponseAsync(req, Consts.ThinClient.RequestHardTimeoutMsecs, Consts.ThinClient.RequestSoftTimeoutMsecs, cancel)); return(response); }); //if (connectOptions.DebugGuacMode == false) //{ // session.Debug("Switching to WebSocket mode..."); // string webSocketUrl = await firstConnection.Socket.RequestSwitchToWebSocketAsync(cancel, Consts.ThinClient.RequestSwitchToWebSocketTimeoutMsecs); // session.Debug($"Switching to WebSocket mode OK. webSocketUrl = {webSocketUrl}"); //} session.Debug("First WideTunnel Connected."); if (connectOptions.DebugGuacMode == false) { // ThinGate ネイティブ WebSocket モード (ThinGate が WebSocket を直接話す) if (firstConnection.Caps.Bit(ThinServerCaps.GuacdSupported) == false) { // 古いバージョンであり、サポートされていない throw new VpnException(VpnError.ERR_DESK_GUACD_NOT_SUPPORTED_VER); } // 'A' を送信 // この段階でサーバー機の Guacd にソケットが接続された状態となる byte[] a = new byte[] { (byte)'A' }; await firstConnection.Stream.SendAsync(a, cancel); // 最初に少し Guacamole Protocol で ThinWebClient と guacd との間で対話を行なう。 // これを行なうことにより、guacd が、local PC の RDP/VNC に接続し通信を初期化する。 // その後、WebSocket への切替えを行ない、それ以降は guacd とクライアント Web ブラウザが直接対話する。 await using var guaClient = new GuaClient( new GuaClientSettings( "", 0, firstConnection.SvcType == ThinSvcType.Rdp ? GuaProtocol.Rdp : GuaProtocol.Vnc, "127.0.0.1", firstConnection.SvcPort, connectOptions.GuaPreference !, connectOptions.IsWebpSupported, firstConnection.Caps.Bit(ThinServerCaps.AudioInSupported)), firstConnection.Stream); string webSocketUrl = ""; // この非同期 StartAsync は、Guacd Protocol で "select, rdp" のような最初の hello に相当するプロトコルを送付し、 // その後、最初の応答を受信してから、いくつかの追加パラメータを送付し、最後に、Connect パケットを送付する直前に呼び出される。 // Connect パケットの本体は文字列にして HTML5 クライアントに渡される。 // その後、HTML5 クライアントが WebSocket を ThinGate との間で確立した後に、 // HTML5 クライアントから最初のパケットとして Connect パケットの本体が渡されることになるのである。 string connectPacketData = await guaClient.StartAsync(cancel); webSocketUrl = await firstConnection.Socket.RequestSwitchToWebSocketAsync(cancel, Consts.ThinClient.RequestSwitchToWebSocketTimeoutMsecs); $"webSocketUrl = {webSocketUrl}"._Debug(); webSocketUrl._NotEmptyCheck(nameof(webSocketUrl)); // フル WebSocket URL を生成する var gateEndPoint = firstConnection.Socket.GatePhysicalEndPoint; // WebSocket URL を HTML クライアントに通知する var ready = new ThinClientAcceptReadyNotification { WebSocketFullUrl = "wss://" + IPUtil.GenerateWildCardDnsFqdn(gateEndPoint.Address, firstConnection.Socket.Options.ConnectParam.WebSocketWildCardDomainName, "ws-", "") + (gateEndPoint.Port == 443 ? "" : ":" + gateEndPoint.Port.ToString()) + webSocketUrl, SvcType = firstConnection.SvcType, ConnectPacketData = connectPacketData, WatermarkStr1 = firstConnection.WatermarkStr1, WatermarkStr2 = firstConnection.WatermarkStr2, Misc = firstConnection.Misc, Caps = firstConnection.Caps, IsStandaloneMode = firstConnection.Socket.Options.ConnectParam.IsStandaloneMode, }; if (firstConnection.Socket.Options.ConnectParam.WebSocketWildCardDomainName._IsSamei("<<!!samehost!!>>")) { ready.WebSocketFullUrl = webSocketUrl; } Dbg.Where(); await session.RequestAndWaitResponseAsync(ready, Consts.ThinClient.RequestHardTimeoutMsecs, Consts.ThinClient.RequestSoftTimeoutMsecs, isFinalAnswer : true); // 確立済みの firstConnection は何か 1 バイトでもデータを受信するか切断されるまで待機する // (このコネクションは ThinGate からみると用済みのため、新たなデータが届くことはないはずである) Dbg.Where("Waiting for unnecessary connection (already switched to WebSocket) disconnects."); // タイムアウトは 30 秒であります。 try { var data2 = await firstConnection.Stream._ReadAsyncWithTimeout(maxSize : 1024, timeout : 30 * 1000, cancel : cancel); } catch (Exception ex) { ex._Debug(); } Dbg.Where("Unnecessary connection (already switched to WebSocket) is disconnected."); } else { // Guacd Proxy Mode (デバッグ・開発用) await using var abort = new CancelWatcher(cancel); AsyncAutoResetEvent connectionAddedEvent = new AsyncAutoResetEvent(); AsyncAutoResetEvent connectedEvent = new AsyncAutoResetEvent(); Task? connectionKeepTask = null; NetTcpListener?listener = null; // このコネクションをキューに追加する ConcurrentQueue <ThinClientConnection> connectionQueue = new ConcurrentQueue <ThinClientConnection>(); try { connectionQueue.Enqueue(firstConnection); // コネクションのキューの長さが ConnectionQueueLength 未満になると自動的にコネクションを張る非同期タスクを開始する connectionKeepTask = TaskUtil.StartAsyncTaskAsync(async() => { int numRetry = 0; while (abort.IsCancellationRequested == false) { // キューの長さが少なくなれば追加コネクションを接続する while (abort.IsCancellationRequested == false) { if (connectionQueue.Count < Consts.ThinClient.ConnectionQueueLength) { session.Debug($"connectionQueue.Count ({connectionQueue.Count}) < Consts.ThinClient.ConnectionQueueLength ({Consts.ThinClient.ConnectionQueueLength})"); try { // 追加接続 ThinClientConnection additionalConnection = await DcConnectEx(wt, connectOptions, abort, false, false, async(req, c) => { // 認証コールバック await Task.CompletedTask; // キャッシュされた認証情報をそのまま応答 return(authResponseCache); }, async(req, c) => { // OTP コールバック await Task.CompletedTask; // OTP チケットを応答 return(new ThinClientOtpResponse { Otp = firstConnection.OtpTicket }); }, async(req, c) => { // 検疫・MAC コールバック await Task.CompletedTask; // チケットを応答 return(new ThinClientInspectResponse { Ticket = firstConnection.InspectTicket }); }); // 接続に成功したのでキューに追加 connectionQueue.Enqueue(additionalConnection); session.Debug($"Additional WideTunnel Connected. connectionQueue.Count = ({connectionQueue.Count})"); connectionAddedEvent.Set(true); numRetry = 0; } catch (Exception ex) { // 接続に失敗したので一定時間待ってリトライする ex._Debug(); session.Error(ex._GetObjectDump()); numRetry++; int waitTime = Util.GenRandIntervalWithRetry(Consts.ThinClient.ReconnectRetrySpanMsecs, numRetry, Consts.ThinClient.ReconnectRetrySpanMaxMsecs); if (waitTime == 0) { waitTime = 1; } session.Debug($"Additional tunnel establish failed. numRetry = {numRetry}. Wait for {waitTime} msecs..."); await connectedEvent.WaitOneAsync(waitTime, abort); } } else { break; } } if (abort.IsCancellationRequested) { break; } await connectedEvent.WaitOneAsync(1000, abort); } }); // Listen ソケットの開始 listener = LocalNet.CreateTcpListener(new TcpListenParam(isRandomPortMode: EnsureSpecial.Yes, async(listen, sock) => { session.Debug($"Listener ({sock.EndPointInfo._GetObjectDump()}) Accepted."); ThinClientConnection?connection = null; long giveupTick = TickNow + Consts.ThinClient.ConnectionQueueWaitTimeout; // キューにコネクションが貯まるまで待機する while (connectionQueue.TryDequeue(out connection) == false) { if (TickNow >= giveupTick) { session.Debug($"Listener ({sock.EndPointInfo._GetObjectDump()}): TickNow ({TickNow}) >= giveupTick ({giveupTick})"); return; } abort.ThrowIfCancellationRequested(); await connectionAddedEvent.WaitOneAsync(100, abort.CancelToken); } await using ThinClientConnection connection2 = connection; session.Debug($"Listener ({sock.EndPointInfo._GetObjectDump()}) Starting Relay Operation."); // 'A' を送信 byte[] a = new byte[] { (byte)'A' }; await connection.Stream.SendAsync(a, abort); var sockStream = sock.GetStream(true); RefLong totalBytes = new RefLong(); try { await Util.RelayDuplexStreamAsync(sockStream, connection.Stream, abort, totalBytes: totalBytes); } catch (Exception ex) { session.Debug($"Listener ({sock.EndPointInfo._GetObjectDump()}) RelayDuplexStreamAsync Exception = {ex._GetObjectDump()}"); } session.Debug($"Listener ({sock.EndPointInfo._GetObjectDump()}) Finished Relay Operation. Total Bytes = {totalBytes.Value}"); // RDP の場合はダミーデータを最後に流す if (connection.SvcType == ThinSvcType.Rdp) { byte[] dummySize = new byte[4096]; await sockStream.SendAsync(dummySize, abort); await Task.Delay(50, abort); } }, family: Options.ListenAddressFamily, address: Options.ListenAddress)); session.Debug($"Create Listener. Assigned Random Port = {listener.AssignedRandomPort}"); // 接続が完了いたしました var ready = new ThinClientAcceptReadyNotification { ListenEndPoint = new IPEndPoint(listener.AssignedRandomPort !.IPAddress, listener.AssignedRandomPort.Port), FirstConnection = firstConnection, Caps = firstConnection.Caps, }; Dbg.Where(); await session.RequestAndWaitResponseAsync(ready, Consts.ThinClient.RequestHardTimeoutMsecs, Consts.ThinClient.RequestSoftTimeoutMsecs, abort, isFinalAnswer : true); // コネクション数が 0 の状態が 30 秒以上継続した場合は終了します long connectionZeroStartTick = 0; while (true) { abort.ThrowIfCancellationRequested(); long now = TickNow; //$"listener.CurrentConnections = {listener.CurrentConnections}"._Debug(); if (listener.CurrentConnections == 0) { if (connectionZeroStartTick == 0) { connectionZeroStartTick = now; } } else { connectionZeroStartTick = 0; } if (connectionZeroStartTick != 0 && now >= (connectionZeroStartTick + Consts.ThinClient.ConnectionZeroTimeout)) { session.Debug($"All client connections disconnected. No more connection exists. connectionZeroStartTick = {connectionZeroStartTick}, now = {now}"); throw new CoresException("All client connections disconnected. No more connection exists."); } await abort.CancelToken._WaitUntilCanceledAsync(1000); } } catch (Exception ex) { session.Error(ex); throw; } finally { abort.Cancel(); await connectionKeepTask._TryAwait(noDebugMessage : true); await listener._DisposeSafeAsync(); foreach (var connection in connectionQueue) { await connection._DisposeSafeAsync(); } Dbg.Where(); } } }
static int TestHadbSuite(ConsoleService c, string cmdName, string str) { ConsoleParam[] args = { new ConsoleParam("THREADS"), new ConsoleParam("LOOP1"), new ConsoleParam("LOOP2"), }; ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args); int numThreads = vl["THREADS"].IntValue; int loop1 = vl["LOOP1"].IntValue; int loop2 = vl["LOOP2"].IntValue; if (numThreads <= 0) { numThreads = 10; } if (loop1 <= 0) { loop1 = 3; } if (loop2 <= 0) { loop2 = 1; } const string TestDbServer = "dn-mssql2019dev1.ipantt.net,7012"; // dn-mssql2019dev1 const string TestDbName = "HADB001"; const string TestDbReadUser = "******"; const string TestDbWriteUser = "******"; const string TestDbReadPassword = "******"; const string TestDbWritePassword = "******"; for (int k = 0; k < loop2; k++) { try { for (int i = 0; i < loop1; i++) { $"=========== try i = {i} ============="._Print(); bool error = false; Async(async() => { AsyncManualResetEvent start = new AsyncManualResetEvent(); List <Task> taskList = new List <Task>(); for (int i = 0; i < numThreads; i++) { var task = TaskUtil.StartAsyncTaskAsync(async() => { await Task.Yield(); await start.WaitAsync(); try { int seed = Interlocked.Increment(ref Seed_TestHadbSuite); string systemName = ("HADB_CODE_TEST_" + Str.DateTimeToYymmddHHmmssLong(DtNow) + "_" + Env.MachineName + "_" + Str.GenerateRandomDigit(8) + "_" + seed.ToString("D8")).ToUpperInvariant(); systemName = "" + (char)('A' + Secure.RandSInt31() % 26) + "_" + systemName; var flags = HadbOptionFlags.NoAutoDbReloadAndUpdate; flags |= HadbOptionFlags.NoLocalBackup; flags |= HadbOptionFlags.DataUidForPartitioningByUidOptimized; if (numThreads >= 2) { flags |= HadbOptionFlags.NoInitConfigDb | HadbOptionFlags.NoInitSnapshot | HadbOptionFlags.DoNotTakeSnapshotAtAll | HadbOptionFlags.DoNotSaveStat; } HadbSqlSettings settings = new HadbSqlSettings(systemName, new SqlDatabaseConnectionSetting(TestDbServer, TestDbName, TestDbReadUser, TestDbReadPassword, true), new SqlDatabaseConnectionSetting(TestDbServer, TestDbName, TestDbWriteUser, TestDbWritePassword, true), IsolationLevel.Snapshot, IsolationLevel.Serializable, flags); await HadbCodeTest.Test1Async(settings, systemName, flags.Bit(HadbOptionFlags.NoLocalBackup) == false, numThreads >= 2); } catch (Exception ex) { "--------------------- ERROR !!! ---------------"._Error(); ex._Error(); throw; } } ); taskList.Add(task); } start.Set(true); foreach (var task in taskList) { var ret = await task._TryAwaitAndRetBool(); if (ret.IsError) { error = true; } } }); if (error) { throw new CoresException("Error occured."); } } $"--- Whole Loop #{loop2}: All OK! ---"._Print(); } catch (Exception ex) { $"--- Whole Loop #{loop2}: Error! ---"._Print(); ex._Error(); $"--- Whole Loop #{loop2}: Error! ---"._Print(); throw; } } return(0); }
static void StartUpdateLoop() { UpdateMainLoopTaskCancel = new CancellationTokenSource(); UpdateMainLoopTask = TaskUtil.StartAsyncTaskAsync(UpdateRepositoryMainLoopAsync); }