public ThinClientConnectOptions(string pcid, IPAddress clientIp, string clientFqdn, bool debugGuacMode, WideTunnelClientOptions clientOptions, bool isWebpSupported, GuaPreference?guaPreference = null, object?appParams = null) { this.Pcid = pcid; this.ClientOptions = clientOptions; this.ClientIpAddress = clientIp; this.ClientFqdn = clientFqdn; this.AppParams = appParams; this.DebugGuacMode = debugGuacMode; this.GuaPreference = guaPreference; this.IsWebpSupported = isWebpSupported; }
public async Task <WtcSocket> WideClientConnectAsync(string pcid, WideTunnelClientOptions clientOptions, bool noCache, CancellationToken cancel = default) { bool retryFlag = false; L_RETRY: WtConnectParam connectParam = await WideClientConnectInnerAsync(pcid, clientOptions, noCache, cancel); $"WideClientConnect: pcid {pcid}: Redirecting to {connectParam.HostName}:{connectParam.Port} (CacheUsed = {connectParam.CacheUsed}) ..."._Debug(); try { ConnSock tcpSock = await this.TcpIp.ConnectAsync(new TcpConnectParam(connectParam.HostName, connectParam.Port, AddressFamily.InterNetwork, connectTimeout : CoresConfig.WtcConfig.WpcTimeoutMsec, dnsTimeout : CoresConfig.WtcConfig.WpcTimeoutMsec), cancel); try { ConnSock targetSock = tcpSock; try { PalSslClientAuthenticationOptions sslOptions = new PalSslClientAuthenticationOptions(connectParam.HostName, false, (cert) => this.CheckValidationCallback(this, cert.NativeCertificate, null, SslPolicyErrors.None)); SslSock sslSock = new SslSock(tcpSock); try { await sslSock.StartSslClientAsync(sslOptions, cancel); targetSock = sslSock; } catch { await sslSock._DisposeSafeAsync(); throw; } WtcSocket wtcSocket = new WtcSocket(targetSock, new WtcOptions(this, connectParam)); await wtcSocket.StartWtcAsync(cancel); return(wtcSocket); } catch { await targetSock._DisposeSafeAsync(); throw; } } catch { await tcpSock._DisposeSafeAsync(); throw; } } catch { if (connectParam.CacheUsed && retryFlag == false) { retryFlag = true; // 接続キャッシュを使用して接続することに失敗した // 場合はキャッシュを消去して再試行する WideTunnel.ConnectParamCache.Delete(pcid); $"WideClientConnect: pcid {pcid}: Connect with Session Cache Failed. Retrying..."._Debug(); goto L_RETRY; } throw; } }
async Task <WtConnectParam> WideClientConnectInnerAsync(string pcid, WideTunnelClientOptions clientOptions, bool noCache, CancellationToken cancel = default) { if (noCache == false) { WtConnectParam?cached = ConnectParamCache[pcid]; if (cached != null) { var ret = cached._CloneDeep(); ret.CacheUsed = true; return(ret); } } Pack r = new Pack(); r.AddStr("SvcName", Options.SvcName); r.AddStr("Pcid", pcid); r.AddSInt("Ver", CoresConfig.WtcConfig.PseudoVer); r.AddSInt("Build", CoresConfig.WtcConfig.PseudoBuild); r.AddInt("ClientOptions", (uint)clientOptions.Flags); r.AddData("ClientId", Options.ClientId); var p = await WtWpcCall("ClientConnect", r, cancel); p.ThrowIfError(); WtConnectParam c = new WtConnectParam { HostName = p["Hostname"].StrValueNonNullCheck, HostNameForProxy = p["HostNameForProxy"].StrValueNonNullCheck, Port = p["Port"].SIntValue, SessionId = p["SessionId"].DataValueNonNull.ToArray(), ServerMask64 = p["ServerMask64"].Int64Value, WebSocketWildCardDomainName = p["WebSocketWildCardDomainName"].StrValueNonNull, ClientOptions = clientOptions._CloneDeep(), IsStandaloneMode = p["IsStandaloneMode"].BoolValue, }; if (c.WebSocketWildCardDomainName._IsEmpty()) { throw new CoresLibException("c.WebSocketWildCardDomainName is empty."); } if (c.HostName._IsSamei("<<!!samehost!!>>")) { string hostTmp = p["__remote_hostname"].StrValueNonNull; int portTmp = p["__remote_port"].SIntValue; if (hostTmp._IsFilled() && portTmp != 0) { c.HostName = hostTmp; c.Port = portTmp; } } c.CacheUsed = false; if (noCache == false) { WideTunnel.ConnectParamCache[pcid] = c._CloneDeep(); } return(c); }
public async Task <IActionResult> IndexAsync(ThinWebClientModelIndex form, string?pcid, string?deleteAll, string?button_wol) { ThinWebClientProfile?historySelectedProfile = null; ThinWebClientProfile profile = form.CurrentProfile; profile.Normalize(); ThinWebClientHistory history = ThinWebClientHistory.LoadFromCookie(this, this.Client.SettingsFastSnapshot.CookieEncryptPassword); if (this._IsPostBack()) { if (profile.Pcid._IsFilled()) { // 現在のプロファイルの保存 this._EasySaveCookie("thin_current_profile", profile.CloneAsDefault(), GetCookieOption(), true, this.Client.SettingsFastSnapshot.CookieEncryptPassword); // ヒストリへの追加 history.Add(profile); history.SaveToCookie(this, GetCookieOption(), this.Client.SettingsFastSnapshot.CookieEncryptPassword); // thin_last_pcid の保存 this._EasySaveCookie("thin_last_pcid", profile.Pcid, GetCookieOption()); var clientIp = Request.HttpContext.Connection.RemoteIpAddress._UnmapIPv4() !; var clientPort = Request.HttpContext.Connection.RemotePort; string clientFqdn = await Client.DnsResolver.GetHostNameSingleOrIpAsync(clientIp); // Rate limit if (this.Client.RateLimit.TryInput(clientIp.ToString(), out _) == false) { throw new CoresException(this.Page.Stb["THINWEB_RATELIMIT_EXCEEDED"]); } var tc = this.Client.CreateThinClient(this.StrTable); if (button_wol._ToBool() == false) { // 普通の接続 WideTunnelClientOptions wideOptions = new WideTunnelClientOptions(WideTunnelClientFlags.None, clientIp.ToString(), clientFqdn, clientPort); // セッションの開始 var session = tc.StartConnect(new ThinClientConnectOptions(profile.Pcid, clientIp, clientFqdn, this.Client.SettingsFastSnapshot.Debug_EnableGuacdMode, wideOptions, form.IsWebpSupported, profile.Preference, profile._CloneWithJson()), this.Client.SettingsFastSnapshot.MaxConcurrentSessionsPerClientIp); string sessionId = session.SessionId; // セッション ID をもとにした URL にリダイレクト return(Redirect($"/ThinWebClient/Session/{sessionId}/?pcid={profile.Pcid._MakeVerySafeAsciiOnlyNonSpaceString()}")); } else { try { // WoL 信号の発射 WideTunnelClientOptions wideOptions = new WideTunnelClientOptions(WideTunnelClientFlags.WoL, clientIp.ToString(), clientFqdn, clientPort); await tc.ExecuteWoLAsync(new ThinClientConnectOptions(profile.Preference.WoLTriggerPcid, clientIp, clientFqdn, false, wideOptions, form.IsWebpSupported, profile.Preference, profile._CloneWithJson()), profile.Pcid, this._GetRequestCancellationToken()); // WoL OK メッセージ form.WolOkMessage = this.Page.Stb["DU_WOL_MSG"]._FormatC(profile.Pcid, profile.Preference.WoLTriggerPcid); } catch (Exception ex) { // WoL エラーメッセージの文字列化 string msg = ThinWebClientErrorUtil.GetFriendlyErrorMessage(ex, this.Page); form.WolErrorMessage = msg; form.JumpToWol = true; } } } } else { if (pcid._IsEmpty()) { // Query String の pcid が空の場合、Cookie から読み出す pcid = this._EasyLoadCookie <string>("thin_last_pcid")._NonNullTrim(); } if (deleteAll._ToBool()) { // History をすべて消去するよう指示された // Cookie の History をすべて消去する history.Clear(); history.SaveToCookie(this, GetCookieOption(), this.Client.SettingsFastSnapshot.CookieEncryptPassword); this._EasySaveCookie("thin_last_pcid", "", GetCookieOption()); // トップページにリダイレクトする return(Redirect("/")); } else if (pcid._IsFilled()) { // History から履歴を指定された。id を元に履歴からプロファイルを読み出す historySelectedProfile = history.Items.Where(h => h.Pcid._IsSamei(pcid)).FirstOrDefault(); } if (historySelectedProfile == null) { // デフォルト値 GuaKeyboardLayout defaultKeyboardLayout = GuaKeyboardLayout.Japanese; if (Page.CurrentLanguage.Key._IsSamei("ja") == false) { // 日本語以外の環境では英語キーボードをデフォルトで選択する defaultKeyboardLayout = GuaKeyboardLayout.EnglishUs; } profile = this._EasyLoadCookie <ThinWebClientProfile>("thin_current_profile", true, this.Client.SettingsFastSnapshot.CookieEncryptPassword) ?? new ThinWebClientProfile(defaultKeyboardLayout); } else { // History で選択された値 profile = historySelectedProfile; } profile.Normalize(); form.CurrentProfile = profile; // GET の場合は必ず PCID 入力ボックスをフォーカスする form.FocusToPcid = true; } form.FillHistory(history); if (historySelectedProfile != null) { form.SelectedHistory = form.HistoryItems.Where(x => x.Text._IsSamei(historySelectedProfile.Pcid)).FirstOrDefault()?.Value ?? ""; } return(View(form)); }