public ThinDatabase(ThinController controller) { try { this.BackupFileName = PP.Combine(Env.AppLocalDir, "Config", "ThinControllerDatabaseBackupCache", "DatabaseBackupCache.json"); this.Controller = controller; this.ReadMainLoopTask = ReadMainLoopAsync(this.GrandCancel)._LeakCheck(); this.WriteMainLoopTask = WriteMainLoopAsync(this.GrandCancel)._LeakCheck(); } catch { this._DisposeSafe(); throw; } }
// PCID 変更実行 public async Task <VpnError> RenamePcidAsync(string msid, string newPcid, DateTime now, CancellationToken cancel = default) { // この関数は同時に 1 ユーザーからしか実行されないようにする // (ローカルメモリデータベースをいじるため) using var asyncLock = await RenamePcidAsyncLock.LockWithAwait(cancel); msid = msid._NonNullTrim(); newPcid = newPcid._NonNullTrim(); VpnError err2 = ThinController.CheckPCID(newPcid); if (err2 != VpnError.ERR_NO_ERROR) { return(err2); } VpnError err = VpnError.ERR_INTERNAL_ERROR; // ローカルメモリデータベース上の PCID 情報を確認 var memDb = this.MemDb !; if (memDb.MachineList.Where(x => x.PCID._IsSamei(newPcid)).Any()) { // ローカルメモリデータベース上で重複 return(VpnError.ERR_PCID_ALREADY_EXISTS); } if (this.IsDatabaseConnected == false) { // データベースエラー発生中はこの処理は実行できない return(VpnError.ERR_TEMP_ERROR); } await using var db = await OpenDatabaseForWriteAsync(cancel); Controller.Throughput_DatabaseWrite.Add(1); ThinDbMachine?updatedMachine = null; // トランザクションを確立し厳格なチェックを実施 // (DB サーバー側で一意インデックスによりチェックするが、インデックスが間違っていた場合に備えて、トランザクションでも厳密にチェックするのである) if (await db.TranAsync(async() => { // MACHINE を取得 var machine = await db.EasySelectSingleAsync <ThinDbMachine>("SELECT * FROM MACHINE WHERE MSID = @MSID", new { MSID = msid }, false, true, cancel); if (machine == null) { // おかしいな err = VpnError.ERR_SECURITY_ERROR; return(false); } // 同一 PCID が存在しないかどうかチェック if ((await db.QueryWithValueAsync("SELECT COUNT(MACHINE_ID) FROM MACHINE WHERE PCID = @ AND SVC_NAME = @", newPcid, machine.SVC_NAME)).Int != 0) { err = VpnError.ERR_PCID_ALREADY_EXISTS; return(false); } // 変更の実行 await db.QueryWithNoReturnAsync("UPDATE MACHINE SET PCID = @, UPDATE_DATE = @, PCID_UPDATE_DATE = @, PCID_VER = PCID_VER + 1 WHERE MSID = @", newPcid, now, now, msid); // 変更した結果を取得 updatedMachine = await db.EasySelectSingleAsync <ThinDbMachine>("SELECT * FROM MACHINE WHERE MSID = @MSID", new { MSID = msid }, false, true, cancel); if (updatedMachine == null) { // おかしいな err = VpnError.ERR_SECURITY_ERROR; return(false); } return(true); }) == false) { return(err); } updatedMachine._MarkNotNull(); Controller.AddPcidToRecentPcidCandidateCache(newPcid); // ローカルメモリデータベース上の PCID 情報を変更 var machine = memDb.MachineByMsid._GetOrDefault(msid); if (machine != null) { machine.PCID = newPcid; machine.PCID_UPDATE_DATE = updatedMachine.PCID_UPDATE_DATE; machine.PCID_VER = updatedMachine.PCID_VER; // メモリ上の PCID Dictionary をリビルド memDb.RebuildPcidListOnMemory(); // PCID 変更履歴の更新 this.PcidChangeHistoryCache.Add(machine.MSID, new ThinDatabasePcidChangeHistory(machine.MSID, machine.PCID_VER, newPcid, updatedMachine.PCID_UPDATE_DATE)); } return(VpnError.ERR_NO_ERROR); }
// サーバー登録実行 public async Task <VpnError> RegisterMachineAsync(string svcName, string msid, string pcid, string hostKey, string hostSecret2, DateTime now, string ip, string fqdn, string initialJsonAttributes, CancellationToken cancel = default) { svcName = svcName._NonNullTrim(); msid = msid._NonNullTrim(); pcid = pcid._NonNullTrim(); hostKey = hostKey._NonNullTrim(); hostSecret2 = hostSecret2._NonNullTrim(); ip = ip._NonNullTrim(); fqdn = fqdn._NonNullTrim(); initialJsonAttributes = initialJsonAttributes._NonNullTrim(); VpnError err2 = ThinController.CheckPCID(pcid); if (err2 != VpnError.ERR_NO_ERROR) { return(err2); } // データベースエラー時は処理禁止 if (IsDatabaseConnected == false) { return(VpnError.ERR_TEMP_ERROR); } VpnError err = VpnError.ERR_INTERNAL_ERROR; await using var db = await OpenDatabaseForWriteAsync(cancel); Controller.Throughput_DatabaseWrite.Add(1); // トランザクションを確立し厳格なチェックを実施 // (DB サーバー側で一意インデックスによりチェックするが、インデックスが間違っていた場合に備えて、トランザクションでも厳密にチェックするのである) if (await db.TranAsync(async() => { // 同一 hostKey が存在しないかどうか確認 if ((await db.QueryWithValueAsync("SELECT COUNT(MACHINE_ID) FROM MACHINE WHERE CERT_HASH = @", hostKey)).Int != 0) { err = VpnError.ERR_SECURITY_ERROR; return(false); } // 同一シークレットが存在しないかどうかチェック if ((await db.QueryWithValueAsync("SELECT COUNT(MACHINE_ID) FROM MACHINE WHERE HOST_SECRET2 = @", hostSecret2)).Int != 0) { err = VpnError.ERR_SECURITY_ERROR; return(false); } // 同一 PCID が存在しないかどうかチェック if ((await db.QueryWithValueAsync("SELECT COUNT(MACHINE_ID) FROM MACHINE WHERE PCID = @ AND SVC_NAME = @", pcid, svcName)).Int != 0) { err = VpnError.ERR_PCID_ALREADY_EXISTS; return(false); } // 登録の実行 await db.QueryWithNoReturnAsync("INSERT INTO MACHINE (SVC_NAME, MSID, PCID, CERT_HASH, CREATE_DATE, UPDATE_DATE, LAST_SERVER_DATE, LAST_CLIENT_DATE, NUM_SERVER, NUM_CLIENT, CREATE_IP, CREATE_HOST, HOST_SECRET2, PCID_UPDATE_DATE, JSON_ATTRIBUTES) " + "VALUES (@, @, @, @, @, @, @, @, @, @, @, @, @, @, @)", svcName, msid, pcid, hostKey, now, now, now, now, 0, 0, ip, fqdn, hostSecret2, now, initialJsonAttributes); return(true); }) == false) { return(err); } Controller.AddPcidToRecentPcidCandidateCache(pcid); return(VpnError.ERR_NO_ERROR); }