* tar xzf utvpn-src-unix-v101-7101-public-2010.06.27.tar.gz
[lab.git] / utvpn / utvpn-unix-v101-7101-public / src / Cedar / Server.c
diff --git a/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Server.c b/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Server.c
new file mode 100644 (file)
index 0000000..5d83a9f
--- /dev/null
@@ -0,0 +1,9239 @@
+// SoftEther UT-VPN SourceCode\r
+// \r
+// Copyright (C) 2004-2010 SoftEther Corporation.\r
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.\r
+// Copyright (C) 2003-2010 Daiyuu Nobori.\r
+// All Rights Reserved.\r
+// \r
+// http://utvpn.tsukuba.ac.jp/\r
+// \r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// version 2 as published by the Free Software Foundation.\r
+// \r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+// \r
+// You should have received a copy of the GNU General Public License version 2\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
+// \r
+// このファイルは GPL バージョン 2 ライセンスで公開されています。\r
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布\r
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示\r
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の\r
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。\r
+// \r
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の\r
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )\r
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって\r
+// ホストされています。\r
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、\r
+// および、試験または研究のために利用が行われることを想定して配布\r
+// しています。\r
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に\r
+// あります。\r
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード\r
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して\r
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して\r
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース\r
+// に組み込みさせていただきます。\r
+// \r
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する\r
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。\r
+// \r
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社\r
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。\r
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの\r
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意\r
+// ください。\r
+// \r
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の\r
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、\r
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの\r
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社\r
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、\r
+// 公益保護にご協力いただきますようお願い申し上げます。\r
+// \r
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を\r
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客\r
+// を保護するための努力を行います。\r
+// \r
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/\r
+// 日本国内の脆弱性情報届出受付公的機関:\r
+//         独立行政法人 情報処理推進機構\r
+//         http://www.ipa.go.jp/security/vuln/report/\r
+// \r
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。\r
+// 連絡先: http://www.softether.co.jp/jp/contact/\r
+\r
+// -----------------------------------------------\r
+// [ChangeLog]\r
+// 2010.05.20\r
+//  新規リリース by SoftEther\r
+// -----------------------------------------------\r
+\r
+// Server.c\r
+// サーバーマネージャ\r
+\r
+#include "CedarPch.h"\r
+\r
+static SERVER *server = NULL;\r
+static LOCK *server_lock = NULL;\r
+char *SERVER_CONFIG_FILE_NAME = "@vpn_server.config";\r
+char *BRIDGE_CONFIG_FILE_NAME = "@vpn_bridge.config";\r
+\r
+static bool server_reset_setting = false;\r
+\r
+// VPN Server に登録されているユーザーオブジェクト数が多すぎるかどうか取得\r
+bool SiTooManyUserObjectsInServer(SERVER *s, bool oneMore)\r
+{\r
+       LICENSE_STATUS st;\r
+       UINT num;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       num = SiGetServerNumUserObjects(s);\r
+\r
+       Zero(&st, sizeof(st));\r
+\r
+       LiParseCurrentLicenseStatus(s->LicenseSystem, &st);\r
+\r
+       if (st.NumUserLicense == INFINITE)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       if (oneMore)\r
+       {\r
+               st.NumUserLicense++;\r
+       }\r
+\r
+       if (st.NumUserLicense <= num)\r
+       {\r
+               return true;\r
+       }\r
+\r
+       return false;\r
+}\r
+\r
+// VPN Server に登録されているユーザーオブジェクト数を取得\r
+UINT SiGetServerNumUserObjects(SERVER *s)\r
+{\r
+       CEDAR *c;\r
+       UINT ret = 0;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       c = s->Cedar;\r
+\r
+       LockList(c->HubList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(c->HubList);i++)\r
+               {\r
+                       HUB *h = LIST_DATA(c->HubList, i);\r
+\r
+                       if (h->HubDb != NULL)\r
+                       {\r
+                               ret += LIST_NUM(h->HubDb->UserList);\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(c->HubList);\r
+\r
+       return ret;\r
+}\r
+\r
+\r
+typedef struct SI_DEBUG_PROC_LIST\r
+{\r
+       UINT Id;\r
+       char *Description;\r
+       char *Args;\r
+       SI_DEBUG_PROC *Proc;\r
+} SI_DEBUG_PROC_LIST;\r
+\r
+// デバッグ機能\r
+UINT SiDebug(SERVER *s, RPC_TEST *ret, UINT i, char *str)\r
+{\r
+       SI_DEBUG_PROC_LIST proc_list[] =\r
+       {\r
+               {1, "Hello World", "<test string>", SiDebugProcHelloWorld},\r
+               {2, "Terminate process now", "", SiDebugProcExit},\r
+               {3, "Write memory dumpfile", "", SiDebugProcDump},\r
+               {4, "Restore process priority", "", SiDebugProcRestorePriority},\r
+               {5, "Set the process priority high", "", SiDebugProcSetHighPriority},\r
+               {6, "Get the .exe filename of the process", "", SiDebugProcGetExeFileName},\r
+               {7, "Crash the process", "", SiDebugProcCrash},\r
+       };\r
+       UINT num_proc_list = sizeof(proc_list) / sizeof(proc_list[0]);\r
+       UINT j;\r
+       UINT ret_value = ERR_NO_ERROR;\r
+       // 引数チェック\r
+       if (s == NULL || ret == NULL)\r
+       {\r
+               return ERR_INVALID_PARAMETER;\r
+       }\r
+\r
+       if (i == 0)\r
+       {\r
+               char tmp[MAX_SIZE];\r
+               Zero(ret, sizeof(RPC_TEST));\r
+\r
+               StrCat(ret->StrValue, sizeof(ret->StrValue),\r
+                       "\n--- Debug Functions List --\n");\r
+\r
+               for (j = 0;j < num_proc_list;j++)\r
+               {\r
+                       SI_DEBUG_PROC_LIST *p = &proc_list[j];\r
+\r
+                       if (IsEmptyStr(p->Args) == false)\r
+                       {\r
+                               Format(tmp, sizeof(tmp),\r
+                                       " %u: %s - Usage: %u /ARGS:\"%s\"\n",\r
+                                       p->Id, p->Description, p->Id, p->Args);\r
+                       }\r
+                       else\r
+                       {\r
+                               Format(tmp, sizeof(tmp),\r
+                                       " %u: %s - Usage: %u\n",\r
+                                       p->Id, p->Description, p->Id);\r
+                       }\r
+\r
+                       StrCat(ret->StrValue, sizeof(ret->StrValue), tmp);\r
+               }\r
+       }\r
+       else\r
+       {\r
+               ret_value = ERR_NOT_SUPPORTED;\r
+\r
+               for (j = 0;j < num_proc_list;j++)\r
+               {\r
+                       SI_DEBUG_PROC_LIST *p = &proc_list[j];\r
+\r
+                       if (p->Id == i)\r
+                       {\r
+                               ret_value = p->Proc(s, str, ret->StrValue, sizeof(ret->StrValue));\r
+\r
+                               if (ret_value == ERR_NO_ERROR && IsEmptyStr(ret->StrValue))\r
+                               {\r
+                                       StrCpy(ret->StrValue, sizeof(ret->StrValue), "Ok.");\r
+                               }\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+\r
+       return ret_value;\r
+}\r
+UINT SiDebugProcHelloWorld(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || in_str == NULL || ret_str == NULL)\r
+       {\r
+               return ERR_INVALID_PARAMETER;\r
+       }\r
+\r
+       Format(ret_str, ret_str_size, "Hello World %s\n", in_str);\r
+\r
+       return ERR_NO_ERROR;\r
+}\r
+UINT SiDebugProcExit(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || in_str == NULL || ret_str == NULL)\r
+       {\r
+               return ERR_INVALID_PARAMETER;\r
+       }\r
+\r
+       _exit(1);\r
+\r
+       return ERR_NO_ERROR;\r
+}\r
+UINT SiDebugProcDump(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || in_str == NULL || ret_str == NULL)\r
+       {\r
+               return ERR_INVALID_PARAMETER;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       MsWriteMinidump(NULL, NULL);\r
+#else  // OS_WIN32\r
+       return ERR_NOT_SUPPORTED;\r
+#endif // OS_WIN32\r
+\r
+       return ERR_NO_ERROR;\r
+}\r
+UINT SiDebugProcRestorePriority(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || in_str == NULL || ret_str == NULL)\r
+       {\r
+               return ERR_INVALID_PARAMETER;\r
+       }\r
+\r
+       OSRestorePriority();\r
+\r
+       return ERR_NO_ERROR;\r
+}\r
+UINT SiDebugProcSetHighPriority(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || in_str == NULL || ret_str == NULL)\r
+       {\r
+               return ERR_INVALID_PARAMETER;\r
+       }\r
+\r
+       OSSetHighPriority();\r
+\r
+       return ERR_NO_ERROR;\r
+}\r
+UINT SiDebugProcGetExeFileName(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || in_str == NULL || ret_str == NULL)\r
+       {\r
+               return ERR_INVALID_PARAMETER;\r
+       }\r
+\r
+       GetExeName(ret_str, ret_str_size);\r
+\r
+       return ERR_NO_ERROR;\r
+}\r
+UINT SiDebugProcCrash(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || in_str == NULL || ret_str == NULL)\r
+       {\r
+               return ERR_INVALID_PARAMETER;\r
+       }\r
+\r
+       CrashNow();\r
+\r
+       return ERR_NO_ERROR;\r
+}\r
+\r
+// デバッグログの書き込み\r
+void SiDebugLog(SERVER *s, char *msg)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || msg == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (s->DebugLog != NULL)\r
+       {\r
+               WriteTinyLog(s->DebugLog, msg);\r
+       }\r
+}\r
+\r
+// デッドロック検査メイン\r
+void SiCheckDeadLockMain(SERVER *s, UINT timeout)\r
+{\r
+       CEDAR *cedar;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Debug("SiCheckDeadLockMain Start.\n");\r
+\r
+       cedar = s->Cedar;\r
+\r
+       if (s->ServerListenerList != NULL)\r
+       {\r
+               CheckDeadLock(s->ServerListenerList->lock, timeout, "s->ServerListenerList->lock");\r
+       }\r
+\r
+       CheckDeadLock(s->lock, timeout, "s->lock");\r
+\r
+       if (s->FarmMemberList != NULL)\r
+       {\r
+               CheckDeadLock(s->FarmMemberList->lock, timeout, "s->FarmMemberList->lock");\r
+       }\r
+\r
+       if (s->HubCreateHistoryList != NULL)\r
+       {\r
+               CheckDeadLock(s->HubCreateHistoryList->lock, timeout, "s->HubCreateHistoryList->lock");\r
+       }\r
+\r
+       CheckDeadLock(s->CapsCacheLock, timeout, "s->CapsCacheLock");\r
+\r
+       CheckDeadLock(s->TasksFromFarmControllerLock, timeout, "s->TasksFromFarmControllerLock");\r
+\r
+       if (cedar != NULL)\r
+       {\r
+               if (cedar->HubList != NULL)\r
+               {\r
+                       CheckDeadLock(cedar->HubList->lock, timeout, "cedar->HubList->lock");\r
+               }\r
+\r
+               if (cedar->ListenerList != NULL)\r
+               {\r
+                       UINT i;\r
+                       LIST *o = NewListFast(NULL);\r
+\r
+                       CheckDeadLock(cedar->ListenerList->lock, timeout, "cedar->ListenerList->lock");\r
+\r
+                       LockList(cedar->ListenerList);\r
+                       {\r
+                               for (i = 0;i < LIST_NUM(cedar->ListenerList);i++)\r
+                               {\r
+                                       LISTENER *r = LIST_DATA(cedar->ListenerList, i);\r
+\r
+                                       AddRef(r->ref);\r
+\r
+                                       Add(o, r);\r
+                               }\r
+                       }\r
+                       UnlockList(cedar->ListenerList);\r
+\r
+                       for (i = 0;i < LIST_NUM(o);i++)\r
+                       {\r
+                               LISTENER *r = LIST_DATA(o, i);\r
+\r
+                               ReleaseListener(r);\r
+                       }\r
+\r
+                       ReleaseList(o);\r
+               }\r
+\r
+               if (cedar->ConnectionList != NULL)\r
+               {\r
+                       CheckDeadLock(cedar->ConnectionList->lock, timeout, "cedar->ConnectionList->lock");\r
+               }\r
+\r
+               if (cedar->CaList != NULL)\r
+               {\r
+                       CheckDeadLock(cedar->CaList->lock, timeout, "cedar->CaList->lock");\r
+               }\r
+\r
+               if (cedar->TrafficLock != NULL)\r
+               {\r
+                       CheckDeadLock(cedar->TrafficLock, timeout, "cedar->TrafficLock");\r
+               }\r
+\r
+               if (cedar->TrafficDiffList != NULL)\r
+               {\r
+                       CheckDeadLock(cedar->TrafficDiffList->lock, timeout, "cedar->TrafficDiffList->lock");\r
+               }\r
+\r
+               if (cedar->LocalBridgeList != NULL)\r
+               {\r
+                       CheckDeadLock(cedar->LocalBridgeList->lock, timeout, "cedar->LocalBridgeList->lock");\r
+               }\r
+\r
+               if (cedar->L3SwList != NULL)\r
+               {\r
+                       CheckDeadLock(cedar->L3SwList->lock, timeout, "cedar->L3SwList->lock");\r
+               }\r
+       }\r
+\r
+       Debug("SiCheckDeadLockMain Finish.\n");\r
+}\r
+\r
+// デッドロックチェックスレッド\r
+void SiDeadLockCheckThread(THREAD *t, void *param)\r
+{\r
+       SERVER *s = (SERVER *)param;\r
+       // 引数チェック\r
+       if (s == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       while (true)\r
+       {\r
+               Wait(s->DeadLockWaitEvent, SERVER_DEADLOCK_CHECK_SPAN);\r
+\r
+               if (s->HaltDeadLockThread)\r
+               {\r
+                       break;\r
+               }\r
+\r
+               SiCheckDeadLockMain(s, SERVER_DEADLOCK_CHECK_TIMEOUT);\r
+       }\r
+}\r
+\r
+// デッドロックチェックの初期化\r
+void SiInitDeadLockCheck(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+       if (s->DisableDeadLockCheck)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s->HaltDeadLockThread = false;\r
+       s->DeadLockWaitEvent = NewEvent();\r
+       s->DeadLockCheckThread = NewThread(SiDeadLockCheckThread, s);\r
+}\r
+\r
+// デッドロックチェックの解放\r
+void SiFreeDeadLockCheck(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (s->DeadLockCheckThread == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s->HaltDeadLockThread = true;\r
+       Set(s->DeadLockWaitEvent);\r
+\r
+       WaitThread(s->DeadLockCheckThread, INFINITE);\r
+\r
+       ReleaseThread(s->DeadLockCheckThread);\r
+       s->DeadLockCheckThread = NULL;\r
+\r
+       ReleaseEvent(s->DeadLockWaitEvent);\r
+       s->DeadLockWaitEvent = NULL;\r
+\r
+       s->HaltDeadLockThread = false;\r
+}\r
+\r
+// 指定した仮想 HUB が作成履歴に登録されているかどうか調べる\r
+bool SiIsHubRegistedOnCreateHistory(SERVER *s, char *name)\r
+{\r
+       UINT i;\r
+       bool ret = false;\r
+       // 引数チェック\r
+       if (s == NULL || name == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       SiDeleteOldHubCreateHistory(s);\r
+\r
+       LockList(s->HubCreateHistoryList);\r
+       {\r
+               for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)\r
+               {\r
+                       SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);\r
+\r
+                       if (StrCmpi(h->HubName, name) == 0)\r
+                       {\r
+                               ret = true;\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(s->HubCreateHistoryList);\r
+\r
+       return ret;\r
+}\r
+\r
+// 仮想 HUB 作成履歴の削除\r
+void SiDelHubCreateHistory(SERVER *s, char *name)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (s == NULL || name == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(s->HubCreateHistoryList);\r
+       {\r
+               SERVER_HUB_CREATE_HISTORY *hh = NULL;\r
+               for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)\r
+               {\r
+                       SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);\r
+\r
+                       if (StrCmpi(h->HubName, name) == 0)\r
+                       {\r
+                               Delete(s->HubCreateHistoryList, h);\r
+                               Free(h);\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(s->HubCreateHistoryList);\r
+\r
+       SiDeleteOldHubCreateHistory(s);\r
+}\r
+\r
+// 仮想 HUB 作成履歴への登録\r
+void SiAddHubCreateHistory(SERVER *s, char *name)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (s == NULL || name == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(s->HubCreateHistoryList);\r
+       {\r
+               SERVER_HUB_CREATE_HISTORY *hh = NULL;\r
+               for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)\r
+               {\r
+                       SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);\r
+\r
+                       if (StrCmpi(h->HubName, name) == 0)\r
+                       {\r
+                               hh = h;\r
+                               break;\r
+                       }\r
+               }\r
+\r
+               if (hh == NULL)\r
+               {\r
+                       hh = ZeroMalloc(sizeof(SERVER_HUB_CREATE_HISTORY));\r
+                       StrCpy(hh->HubName, sizeof(hh->HubName), name);\r
+\r
+                       Add(s->HubCreateHistoryList, hh);\r
+               }\r
+\r
+               hh->CreatedTime = Tick64();\r
+       }\r
+       UnlockList(s->HubCreateHistoryList);\r
+\r
+       SiDeleteOldHubCreateHistory(s);\r
+}\r
+\r
+// 古くなった仮想 HUB 作成履歴の削除\r
+void SiDeleteOldHubCreateHistory(SERVER *s)\r
+{\r
+       UINT i;\r
+       LIST *o;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(s->HubCreateHistoryList);\r
+       {\r
+               o = NewListFast(NULL);\r
+\r
+               for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)\r
+               {\r
+                       SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);\r
+\r
+                       if ((h->CreatedTime + ((UINT64)TICKET_EXPIRES)) <= Tick64())\r
+                       {\r
+                               // 有効期限切れ\r
+                               Add(o, h);\r
+                       }\r
+               }\r
+\r
+               for (i = 0;i < LIST_NUM(o);i++)\r
+               {\r
+                       SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(o, i);\r
+\r
+                       Delete(s->HubCreateHistoryList, h);\r
+\r
+                       Free(h);\r
+               }\r
+\r
+               ReleaseList(o);\r
+       }\r
+       UnlockList(s->HubCreateHistoryList);\r
+}\r
+\r
+// 仮想 HUB 作成履歴の初期化\r
+void SiInitHubCreateHistory(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s->HubCreateHistoryList = NewList(NULL);\r
+}\r
+\r
+// 仮想 HUB 作成履歴の解放\r
+void SiFreeHubCreateHistory(SERVER *s)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)\r
+       {\r
+               SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);\r
+\r
+               Free(h);\r
+       }\r
+\r
+       ReleaseList(s->HubCreateHistoryList);\r
+\r
+       s->HubCreateHistoryList = NULL;\r
+}\r
+\r
+// Admin Pack のインストーラ作成キットで作成した VPN Client が\r
+// 接続可能なサーバーかどうか判別\r
+bool IsAdminPackSupportedServerProduct(char *name)\r
+{\r
+       // 引数チェック\r
+       if (name == NULL)\r
+       {\r
+               return true;\r
+       }\r
+\r
+       return true;\r
+\r
+#if    0\r
+       // SoftEther UT-VPN ではこの制限はなくなった\r
+       if (SearchStrEx(name, "home", 0, false) != INFINITE)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       if (SearchStrEx(name, "soho", 0, false) != INFINITE)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       if (SearchStrEx(name, "small business", 0, false) != INFINITE)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       if (SearchStrEx(name, "standard", 0, false) != INFINITE)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       return true;\r
+#endif\r
+}\r
+\r
+\r
+// Server スナップショットの初期化\r
+void InitServerSnapshot(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (s->Cedar->Bridge)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (s->ServerType == SERVER_TYPE_FARM_MEMBER)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s->SnapshotLogger = NewLog(CE_SNAPSHOT_DIR_NAME, CE_SNAPSHOT_PREFIX, LOG_SWITCH_MONTH);\r
+       s->LastSnapshotTime = SystemTime64();\r
+       s->HaltSnapshot = false;\r
+       s->SnapshotHaltEvent = NewEvent();\r
+       s->SnapshotThread = NewThread(ServerSnapshotThread, s);\r
+       s->SnapshotInited = true;\r
+}\r
+\r
+// Server スナップショットの解放\r
+void FreeServerSnapshot(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+       if (s->SnapshotInited == false)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s->HaltSnapshot = true;\r
+       Set(s->SnapshotHaltEvent);\r
+\r
+       WaitThread(s->SnapshotThread, INFINITE);\r
+       ReleaseThread(s->SnapshotThread);\r
+\r
+       FreeLog(s->SnapshotLogger);\r
+       ReleaseEvent(s->SnapshotHaltEvent);\r
+}\r
+\r
+// スナップショットをバッファに書き出す\r
+BUF *ServerSnapshotToBuf(SERVER_SNAPSHOT *t)\r
+{\r
+       BUF *b = NewBuf();\r
+       char tmp[MAX_SIZE * 3];\r
+       char tmp2[MAX_SIZE];\r
+       UCHAR hash[SHA1_SIZE];\r
+       UCHAR hash2[SHA1_SIZE];\r
+       UINT i;\r
+       // 引数チェック\r
+       if (t == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       WriteBufLine(b, "------------------------------------------------------");\r
+       WriteBufLine(b, "[RECORD_INFO]");\r
+\r
+       GetDateTimeStr64(tmp2, sizeof(tmp2), SystemToLocal64(t->DateTime));\r
+       Format(tmp, sizeof(tmp), "DATETIME: %s", tmp2);\r
+       WriteBufLine(b, tmp);\r
+\r
+       IPToStr(tmp2, sizeof(tmp2), &t->ServerIp);\r
+       Format(tmp, sizeof(tmp), "SERVER_IP: %s", tmp2);\r
+       WriteBufLine(b, tmp);\r
+\r
+       Format(tmp, sizeof(tmp), "SERVER_HOSTNAME: %s", t->ServerHostname);\r
+       WriteBufLine(b, tmp);\r
+\r
+       Format(tmp, sizeof(tmp), "SERVER_PRODUCT: %s", t->ServerProduct);\r
+       WriteBufLine(b, tmp);\r
+\r
+       Format(tmp, sizeof(tmp), "SERVER_VERSION: %s", t->ServerVersion);\r
+       WriteBufLine(b, tmp);\r
+\r
+       Format(tmp, sizeof(tmp), "SERVER_BUILD: %s", t->ServerBuild);\r
+       WriteBufLine(b, tmp);\r
+\r
+       Format(tmp, sizeof(tmp), "SERVER_OS: %s", t->ServerOs);\r
+       WriteBufLine(b, tmp);\r
+\r
+       Format(tmp, sizeof(tmp), "SERVER_LICENSE_ID: %I64u", t->ServerLicenseId);\r
+       WriteBufLine(b, tmp);\r
+\r
+       if (t->ServerLicenseExpires != 0)\r
+       {\r
+               GetDateTimeStr64(tmp2, sizeof(tmp2), SystemToLocal64(t->ServerLicenseExpires));\r
+       }\r
+       else\r
+       {\r
+               StrCpy(tmp2, sizeof(tmp2), "None");\r
+       }\r
+       Format(tmp, sizeof(tmp), "SERVER_LICENSE_EXPIRES: %s", tmp2);\r
+       WriteBufLine(b, tmp);\r
+\r
+       Format(tmp, sizeof(tmp), "SERVER_TYPE: %u", t->ServerType);\r
+       WriteBufLine(b, tmp);\r
+\r
+       GetDateTimeStr64(tmp2, sizeof(tmp), SystemToLocal64(t->ServerStartupDatetime));\r
+       Format(tmp, sizeof(tmp), "SERVER_STARTUP_DATETIME: %s", tmp2);\r
+       WriteBufLine(b, tmp);\r
+\r
+       Format(tmp, sizeof(tmp), "NUMBER_OF_CLUSTER_NODES: %u", t->NumClusterNodes);\r
+       WriteBufLine(b, tmp);\r
+\r
+       Format(tmp, sizeof(tmp), "NUMBER_OF_HUBS: %u", LIST_NUM(t->HubList));\r
+       WriteBufLine(b, tmp);\r
+\r
+       for (i = 0;i < LIST_NUM(t->HubList);i++)\r
+       {\r
+               HUB_SNAPSHOT *h = LIST_DATA(t->HubList, i);\r
+               Format(tmp, sizeof(tmp), "[HUB%u]", i);\r
+               WriteBufLine(b, tmp);\r
+\r
+               Format(tmp, sizeof(tmp), "HUB_NAME: %s", h->HubName);\r
+               WriteBufLine(b, tmp);\r
+\r
+               Format(tmp, sizeof(tmp), "HUB_STATUS: %s",\r
+                       h->HubStatus ? "Online" : "Offline");\r
+               WriteBufLine(b, tmp);\r
+\r
+               Format(tmp, sizeof(tmp), "HUB_MAX_SESSIONS_CLIENT: %u",\r
+                       h->HubMaxSessionsClient);\r
+               WriteBufLine(b, tmp);\r
+\r
+               Format(tmp, sizeof(tmp), "HUB_MAX_SESSIONS_BRIDGE: %u",\r
+                       h->HubMaxSessionsBridge);\r
+               WriteBufLine(b, tmp);\r
+       }\r
+\r
+       // ハッシュ計算\r
+       HashSha1(hash, b->Buf, b->Size);\r
+       HashSha1(hash2, hash, sizeof(hash));\r
+\r
+       WriteBufLine(b, "[DIGITAL_SIGNATURE]");\r
+       BinToStr(tmp2, sizeof(tmp2), hash2, sizeof(hash2));\r
+       Format(tmp, sizeof(tmp), "SIGNATURE: %s", tmp2);\r
+       WriteBufLine(b, tmp);\r
+\r
+       SeekBuf(b, 0, 0);\r
+\r
+       return b;\r
+}\r
+\r
+// スナップショットのログを書き込む\r
+void WriteServerSnapshotLog(SERVER *s, SERVER_SNAPSHOT *t)\r
+{\r
+       BUF *b;\r
+       LOG *g;\r
+       // 引数チェック\r
+       if (s == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       b = ServerSnapshotToBuf(t);\r
+       if (b == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       g = s->SnapshotLogger;\r
+\r
+       WriteMultiLineLog(g, b);\r
+\r
+       FreeBuf(b);\r
+}\r
+\r
+// Server スナップショットスレッド\r
+void ServerSnapshotThread(THREAD *t, void *param)\r
+{\r
+       SERVER *s;\r
+       UINT64 last_check_license = 0;\r
+       LICENSE_STATUS license;\r
+       // 引数チェック\r
+       if (t == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s = (SERVER *)param;\r
+\r
+       Zero(&license, sizeof(license));\r
+\r
+       while (true)\r
+       {\r
+               UINT64 now;\r
+               if (s->HaltSnapshot)\r
+               {\r
+                       break;\r
+               }\r
+\r
+               if (last_check_license == 0 || (last_check_license + (UINT64)(CE_SNAPSHOT_POLLING_INTERVAL_LICENSE)) <= Tick64())\r
+               {\r
+                       last_check_license = Tick64();\r
+\r
+                       LiParseCurrentLicenseStatus(s->LicenseSystem, &license);\r
+               }\r
+\r
+               if (license.CarrierEdition)\r
+               {\r
+                       now = SystemTime64();\r
+\r
+                       if ((s->LastSnapshotTime / CE_SNAPSHOT_INTERVAL) !=\r
+                               (now / CE_SNAPSHOT_INTERVAL))\r
+                       {\r
+                               SERVER_SNAPSHOT t;\r
+                               if (MakeServerSnapshot(s, 0, &t))\r
+                               {\r
+                                       s->LastSnapshotTime = now;\r
+                                       WriteServerSnapshotLog(s, &t);\r
+\r
+                                       FreeSnapshot(&t);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               Wait(s->SnapshotHaltEvent, CE_SNAPSHOT_POLLING_INTERVAL);\r
+       }\r
+}\r
+\r
+// Server のスナップショットの保存\r
+bool MakeServerSnapshot(SERVER *s, UINT64 now, SERVER_SNAPSHOT *t)\r
+{\r
+       LICENSE_STATUS license;\r
+       OS_INFO *os = GetOsInfo();\r
+       CEDAR *cedar;\r
+       HUB **hubs;\r
+       UINT i, num_hubs;\r
+       // 引数チェック\r
+       if (s == NULL || t == NULL)\r
+       {\r
+               return false;\r
+       }\r
+       if (now == 0)\r
+       {\r
+               now = SystemTime64();\r
+       }\r
+\r
+       cedar = s->Cedar;\r
+\r
+       if (s->ServerType == SERVER_TYPE_FARM_MEMBER)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       Zero(&license, sizeof(license));\r
+       LiParseCurrentLicenseStatus(s->LicenseSystem, &license);\r
+\r
+       if (license.CarrierEdition == false)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       now = (now / CE_SNAPSHOT_INTERVAL) * CE_SNAPSHOT_INTERVAL;\r
+\r
+       t->DateTime = now;\r
+       GetMachineIp(&t->ServerIp);\r
+       GetMachineName(t->ServerHostname, sizeof(t->ServerHostname));\r
+       StrCpy(t->ServerProduct, sizeof(t->ServerProduct), license.EditionStr);\r
+       t->ServerLicenseId = license.SystemId;\r
+       t->ServerLicenseExpires = license.Expires;\r
+       t->ServerType = s->ServerType;\r
+       if (t->ServerType == SERVER_TYPE_FARM_CONTROLLER)\r
+       {\r
+               LockList(s->FarmMemberList);\r
+               {\r
+                       t->NumClusterNodes = LIST_NUM(s->FarmMemberList);\r
+               }\r
+               UnlockList(s->FarmMemberList);\r
+       }\r
+\r
+       StrCpy(t->ServerVersion, sizeof(t->ServerVersion), s->Cedar->VerString);\r
+       StrCpy(t->ServerBuild, sizeof(t->ServerBuild), s->Cedar->BuildInfo);\r
+       Format(t->ServerOs, sizeof(t->ServerOs),\r
+               "%s %s %s",\r
+               os->OsVendorName, os->OsProductName, os->OsVersion);\r
+\r
+       t->ServerStartupDatetime = s->StartTime;\r
+\r
+       LockList(cedar->HubList);\r
+       {\r
+               num_hubs = LIST_NUM(cedar->HubList);\r
+               hubs = ZeroMalloc(sizeof(HUB *) * num_hubs);\r
+\r
+               for (i = 0;i < num_hubs;i++)\r
+               {\r
+                       HUB *h = LIST_DATA(cedar->HubList, i);\r
+                       hubs[i] = h;\r
+\r
+                       AddRef(h->ref);\r
+               }\r
+       }\r
+       UnlockList(cedar->HubList);\r
+\r
+       t->HubList = NewListFast(NULL);\r
+\r
+       for (i = 0;i < num_hubs;i++)\r
+       {\r
+               HUB *h = hubs[i];\r
+               UINT client, bridge;\r
+               HUB_SNAPSHOT *sn;\r
+\r
+               client = GetHubAdminOption(h, "max_sessions_client");\r
+               bridge = GetHubAdminOption(h, "max_sessions_bridge");\r
+\r
+               sn = ZeroMalloc(sizeof(HUB_SNAPSHOT));\r
+               sn->HubMaxSessionsClient = client;\r
+               sn->HubMaxSessionsBridge = bridge;\r
+               StrCpy(sn->HubName, sizeof(sn->HubName), h->Name);\r
+               sn->HubStatus = h->Offline ? false : true;\r
+\r
+               Insert(t->HubList, sn);\r
+\r
+               ReleaseHub(h);\r
+       }\r
+\r
+       Free(hubs);\r
+\r
+       return true;\r
+}\r
+\r
+// スナップショットの解放\r
+void FreeSnapshot(SERVER_SNAPSHOT *t)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < LIST_NUM(t->HubList);i++)\r
+       {\r
+               HUB_SNAPSHOT *h = LIST_DATA(t->HubList, i);\r
+\r
+               Free(h);\r
+       }\r
+\r
+       ReleaseList(t->HubList);\r
+\r
+       Zero(t, sizeof(SERVER_SNAPSHOT));\r
+}\r
+\r
+// サーバーの現在のライセンスステータスを取得する\r
+void SiGetServerLicenseStatus(SERVER *s, LICENSE_STATUS *st)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || st == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (s->LicenseSystem == NULL || s->LicenseSystem->Status == NULL)\r
+       {\r
+               Zero(st, sizeof(LICENSE_STATUS));\r
+               return;\r
+       }\r
+\r
+       Copy(st, s->LicenseSystem->Status, sizeof(LICENSE_STATUS));\r
+}\r
+\r
+// サーバー製品名を取得する\r
+void GetServerProductName(SERVER *s, char *name, UINT size)\r
+{\r
+       char *cpu;\r
+       // 引数チェック\r
+       if (s == NULL || name == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       GetServerProductNameInternal(s, name, size);\r
+\r
+#ifdef CPU_64\r
+       cpu = " (64 bit)";\r
+#else  // CPU_64\r
+       cpu = " (32 bit)";\r
+#endif // CPU_64\r
+\r
+       StrCat(name, size, cpu);\r
+}\r
+void GetServerProductNameInternal(SERVER *s, char *name, UINT size)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || name == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+#ifdef BETA_NUMBER\r
+       if (s->Cedar->Bridge)\r
+       {\r
+               StrCpy(name, size, CEDAR_BRIDGE_STR);\r
+       }\r
+       else\r
+       {\r
+               StrCpy(name, size, CEDAR_BETA_SERVER);\r
+       }\r
+       return;\r
+#else  // BETA_NUMBER\r
+       if (s->Cedar->Bridge)\r
+       {\r
+               StrCpy(name, size, CEDAR_BRIDGE_STR);\r
+       }\r
+       else\r
+       {\r
+               LICENSE_STATUS st;\r
+\r
+               LiParseCurrentLicenseStatus(s->LicenseSystem, &st);\r
+\r
+               StrCpy(name, size, st.EditionStr);\r
+       }\r
+#endif // BETA_NUMBER\r
+}\r
+\r
+// ログファイル列挙を結合する\r
+void AdjoinEnumLogFile(LIST *o, LIST *src)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (o == NULL || src == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < LIST_NUM(src);i++)\r
+       {\r
+               LOG_FILE *f = LIST_DATA(src, i);\r
+\r
+               Insert(o, Clone(f, sizeof(LOG_FILE)));\r
+       }\r
+}\r
+\r
+// 指定した名前のログファイルが列挙リストに入っているかどうか確認する\r
+bool CheckLogFileNameFromEnumList(LIST *o, char *name, char *server_name)\r
+{\r
+       LOG_FILE t;\r
+       // 引数チェック\r
+       if (o == NULL || name == NULL || server_name == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       Zero(&t, sizeof(t));\r
+       StrCpy(t.Path, sizeof(t.Path), name);\r
+       StrCpy(t.ServerName, sizeof(t.ServerName), server_name);\r
+\r
+       if (Search(o, &t) == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+// ログファイル列挙を解放する\r
+void FreeEnumLogFile(LIST *o)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (o == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < LIST_NUM(o);i++)\r
+       {\r
+               LOG_FILE *f = LIST_DATA(o, i);\r
+\r
+               Free(f);\r
+       }\r
+\r
+       ReleaseList(o);\r
+}\r
+\r
+// 仮想 HUB に関連するログファイルを列挙する (サーバー管理者の場合はすべて列挙する)\r
+LIST *EnumLogFile(char *hubname)\r
+{\r
+       char exe_dir[MAX_PATH];\r
+       char tmp[MAX_PATH];\r
+       LIST *o = NewListFast(CmpLogFile);\r
+       DIRLIST *dir;\r
+\r
+       if (StrLen(hubname) == 0)\r
+       {\r
+               hubname = NULL;\r
+       }\r
+\r
+       GetExeDir(exe_dir, sizeof(exe_dir));\r
+\r
+       // server_log の下を列挙する\r
+       if (hubname == NULL)\r
+       {\r
+               EnumLogFileDir(o, "server_log");\r
+       }\r
+\r
+       // packet_log の下を列挙する\r
+       Format(tmp, sizeof(tmp), "%s/packet_log", exe_dir);\r
+       dir = EnumDir(tmp);\r
+       if (dir != NULL)\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < dir->NumFiles;i++)\r
+               {\r
+                       DIRENT *e = dir->File[i];\r
+\r
+                       if (e->Folder)\r
+                       {\r
+                               char dir_name[MAX_PATH];\r
+\r
+                               if (hubname == NULL || StrCmpi(hubname, e->FileName) == 0)\r
+                               {\r
+                                       Format(dir_name, sizeof(dir_name), "packet_log/%s", e->FileName);\r
+                                       EnumLogFileDir(o, dir_name);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               FreeDir(dir);\r
+       }\r
+\r
+       // security_log の下を列挙する\r
+       Format(tmp, sizeof(tmp), "%s/security_log", exe_dir);\r
+       dir = EnumDir(tmp);\r
+       if (dir != NULL)\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < dir->NumFiles;i++)\r
+               {\r
+                       DIRENT *e = dir->File[i];\r
+\r
+                       if (e->Folder)\r
+                       {\r
+                               char dir_name[MAX_PATH];\r
+\r
+                               if (hubname == NULL || StrCmpi(hubname, e->FileName) == 0)\r
+                               {\r
+                                       Format(dir_name, sizeof(dir_name), "security_log/%s", e->FileName);\r
+                                       EnumLogFileDir(o, dir_name);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               FreeDir(dir);\r
+       }\r
+\r
+       return o;\r
+}\r
+\r
+// 指定した名前のディレクトリのログファイルを列挙する\r
+void EnumLogFileDir(LIST *o, char *dirname)\r
+{\r
+       UINT i;\r
+       char exe_dir[MAX_PATH];\r
+       char dir_full_path[MAX_PATH];\r
+       DIRLIST *dir;\r
+       // 引数チェック\r
+       if (o == NULL || dirname == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       GetExeDir(exe_dir, sizeof(exe_dir));\r
+       Format(dir_full_path, sizeof(dir_full_path), "%s/%s", exe_dir, dirname);\r
+\r
+       dir = EnumDir(dir_full_path);\r
+       if (dir == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < dir->NumFiles;i++)\r
+       {\r
+               DIRENT *e = dir->File[i];\r
+\r
+               if (e->Folder == false && e->FileSize > 0)\r
+               {\r
+                       char full_path[MAX_PATH];\r
+                       char file_path[MAX_PATH];\r
+\r
+                       Format(file_path, sizeof(file_path), "%s/%s", dirname, e->FileName);\r
+                       Format(full_path, sizeof(full_path), "%s/%s", exe_dir, file_path);\r
+\r
+                       if (EndWith(file_path, ".log"))\r
+                       {\r
+                               LOG_FILE *f = ZeroMalloc(sizeof(LOG_FILE));\r
+\r
+                               StrCpy(f->Path, sizeof(f->Path), file_path);\r
+                               f->FileSize = (UINT)(MIN(e->FileSize, 0xffffffffUL));\r
+                               f->UpdatedTime = e->UpdateDate;\r
+\r
+                               GetMachineName(f->ServerName, sizeof(f->ServerName));\r
+\r
+                               Insert(o, f);\r
+                       }\r
+               }\r
+       }\r
+\r
+       FreeDir(dir);\r
+}\r
+\r
+// ログファイルリストエントリ比較\r
+int CmpLogFile(void *p1, void *p2)\r
+{\r
+       LOG_FILE *f1, *f2;\r
+       UINT i;\r
+       if (p1 == NULL || p2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+       f1 = *(LOG_FILE **)p1;\r
+       f2 = *(LOG_FILE **)p2;\r
+       if (f1 == NULL || f2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       i = StrCmpi(f1->Path, f2->Path);\r
+       if (i != 0)\r
+       {\r
+               return i;\r
+       }\r
+\r
+       return StrCmpi(f1->ServerName, f2->ServerName);\r
+}\r
+\r
+// サーバーの Caps を取得する\r
+UINT GetServerCapsInt(SERVER *s, char *name)\r
+{\r
+       CAPSLIST t;\r
+       UINT ret;\r
+       // 引数チェック\r
+       if (s == NULL || name == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       Zero(&t, sizeof(t));\r
+       GetServerCaps(s, &t);\r
+\r
+       ret = GetCapsInt(&t, name);\r
+\r
+       return ret;\r
+}\r
+bool GetServerCapsBool(SERVER *s, char *name)\r
+{\r
+       return (GetServerCapsInt(s, name) == 0) ? false : true;\r
+}\r
+\r
+// サーバーの Caps キャッシュの初期化\r
+void InitServerCapsCache(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s->CapsCacheLock = NewLock();\r
+       s->CapsListCache = NULL;\r
+}\r
+\r
+// サーバーの Caps キャッシュの解放\r
+void FreeServerCapsCache(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (s->CapsListCache != NULL)\r
+       {\r
+               FreeCapsList(s->CapsListCache);\r
+               s->CapsListCache = NULL;\r
+       }\r
+       DeleteLock(s->CapsCacheLock);\r
+}\r
+\r
+// サーバーの Caps キャッシュの廃棄\r
+void DestroyServerCapsCache(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Lock(s->CapsCacheLock);\r
+       {\r
+               if (s->CapsListCache != NULL)\r
+               {\r
+                       FreeCapsList(s->CapsListCache);\r
+                       s->CapsListCache = NULL;\r
+               }\r
+       }\r
+       Unlock(s->CapsCacheLock);\r
+}\r
+\r
+// このサーバーの Caps リストを取得する\r
+void GetServerCaps(SERVER *s, CAPSLIST *t)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Lock(s->CapsCacheLock);\r
+       {\r
+               if (s->CapsListCache == NULL)\r
+               {\r
+                       s->CapsListCache = ZeroMalloc(sizeof(CAPSLIST));\r
+                       GetServerCapsMain(s, s->CapsListCache);\r
+               }\r
+\r
+               Copy(t, s->CapsListCache, sizeof(s->CapsListCache));\r
+       }\r
+       Unlock(s->CapsCacheLock);\r
+}\r
+\r
+// サーバーの Caps 取得メイン\r
+void GetServerCapsMain(SERVER *s, CAPSLIST *t)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 初期化\r
+       InitCapsList(t);\r
+\r
+       // 最大 Ethernet パケットサイズ\r
+       AddCapsInt(t, "i_max_packet_size", MAX_PACKET_SIZE);\r
+\r
+       if (s->Cedar->Bridge == false)\r
+       {\r
+               LICENSE_STATUS st;\r
+               UINT max_sessions, max_clients, max_bridges, max_user_creations;\r
+\r
+               LiParseCurrentLicenseStatus(s->LicenseSystem, &st);\r
+\r
+               max_clients = st.NumClientLicense;\r
+               max_bridges = st.NumBridgeLicense;\r
+               max_sessions = st.MaxSessions;\r
+               max_user_creations = st.NumUserLicense;\r
+\r
+               // 最大仮想 HUB 数\r
+               AddCapsInt(t, "i_max_hubs", st.MaxHubs);\r
+\r
+               // 最大同時接続セッション数\r
+               AddCapsInt(t, "i_max_sessions", max_sessions);\r
+\r
+               // 最大作成可能ユーザー数\r
+               AddCapsInt(t, "i_max_user_creation", max_user_creations);\r
+\r
+               // 最大クライアント数\r
+               AddCapsInt(t, "i_max_clients", max_clients);\r
+\r
+               // 最大ブリッジ数\r
+               AddCapsInt(t, "i_max_bridges", max_bridges);\r
+\r
+               if (s->ServerType != SERVER_TYPE_FARM_MEMBER)\r
+               {\r
+                       // 登録可能な最大ユーザー数 / 仮想 HUB\r
+                       AddCapsInt(t, "i_max_users_per_hub", MAX_USERS);\r
+\r
+                       // 登録可能な最大グループ数 / 仮想 HUB\r
+                       AddCapsInt(t, "i_max_groups_per_hub", MAX_GROUPS);\r
+\r
+                       // 登録可能な最大アクセスリスト数 / 仮想 HUB\r
+                       AddCapsInt(t, "i_max_access_lists", MAX_ACCESSLISTS);\r
+               }\r
+               else\r
+               {\r
+                       // 登録可能な最大ユーザー数 / 仮想 HUB\r
+                       AddCapsInt(t, "i_max_users_per_hub", 0);\r
+\r
+                       // 登録可能な最大グループ数 / 仮想 HUB\r
+                       AddCapsInt(t, "i_max_groups_per_hub", 0);\r
+\r
+                       // 登録可能な最大アクセスリスト数 / 仮想 HUB\r
+                       AddCapsInt(t, "i_max_access_lists", 0);\r
+               }\r
+\r
+               // 多重ログインに関するポリシー\r
+               AddCapsBool(t, "b_support_limit_multilogin", true);\r
+\r
+               // QoS / VoIP\r
+               AddCapsBool(t, "b_support_qos", true);\r
+       }\r
+       else\r
+       {\r
+               // 最大仮想 HUB 数\r
+               AddCapsInt(t, "i_max_hubs", 0);\r
+\r
+               // 最大同時接続セッション数\r
+               AddCapsInt(t, "i_max_sessions", 0);\r
+\r
+               // 最大クライアント数\r
+               AddCapsInt(t, "i_max_clients", 0);\r
+\r
+               // 最大ブリッジ数\r
+               AddCapsInt(t, "i_max_bridges", 0);\r
+\r
+               // 登録可能な最大ユーザー数 / 仮想 HUB\r
+               AddCapsInt(t, "i_max_users_per_hub", 0);\r
+\r
+               // 登録可能な最大グループ数 / 仮想 HUB\r
+               AddCapsInt(t, "i_max_groups_per_hub", 0);\r
+\r
+               // 登録可能な最大アクセスリスト数 / 仮想 HUB\r
+               AddCapsInt(t, "i_max_access_lists", 0);\r
+\r
+               // QoS / VoIP\r
+               AddCapsBool(t, "b_support_qos", true);\r
+\r
+               // syslog\r
+               AddCapsBool(t, "b_support_syslog", true);\r
+       }\r
+\r
+       // syslog は使用不可\r
+       AddCapsBool(t, "b_support_syslog", false);\r
+\r
+       // クラスタ内仮想 HUB の種類の変更が禁止されている\r
+       AddCapsBool(t, "b_cluster_hub_type_fixed", true);\r
+\r
+       // MAC アドレステーブル最大サイズ / 仮想 HUB\r
+       AddCapsInt(t, "i_max_mac_tables", MAX_MAC_TABLES);\r
+\r
+       // IP アドレステーブル最大サイズ / 仮想 HUB\r
+       AddCapsInt(t, "i_max_ip_tables", MAX_IP_TABLES);\r
+\r
+       // SecureNAT 機能が使用できる\r
+       AddCapsBool(t, "b_support_securenat", true);\r
+\r
+       if (s->ServerType != SERVER_TYPE_STANDALONE)\r
+       {\r
+               AddCapsBool(t, "b_virtual_nat_disabled", true);\r
+       }\r
+\r
+       // NAT テーブル最大サイズ / 仮想 HUB\r
+       AddCapsInt(t, "i_max_secnat_tables", NAT_MAX_SESSIONS);\r
+\r
+       // カスケード接続\r
+       if (s->ServerType == SERVER_TYPE_STANDALONE)\r
+       {\r
+               AddCapsBool(t, "b_support_cascade", true);\r
+       }\r
+       else\r
+       {\r
+               AddCapsBool(t, "b_support_cascade", false);\r
+       }\r
+\r
+       if (s->Cedar->Bridge)\r
+       {\r
+               // ブリッジ モード\r
+               AddCapsBool(t, "b_bridge", true);\r
+       }\r
+       else if (s->ServerType == SERVER_TYPE_STANDALONE)\r
+       {\r
+               // スタンドアロン モード\r
+               AddCapsBool(t, "b_standalone", true);\r
+       }\r
+       else if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)\r
+       {\r
+               // クラスタ コントローラ モード\r
+               AddCapsBool(t, "b_cluster_controller", true);\r
+       }\r
+       else\r
+       {\r
+               // クラスタ メンバ モード\r
+               AddCapsBool(t, "b_cluster_member", true);\r
+       }\r
+\r
+       // 仮想 HUB の設定変更が可能である\r
+       AddCapsBool(t, "b_support_config_hub", s->ServerType != SERVER_TYPE_FARM_MEMBER &&\r
+               s->Cedar->Bridge == false);\r
+\r
+       // VPN クライアントが接続可能である\r
+       AddCapsBool(t, "b_vpn_client_connect", s->Cedar->Bridge == false ? true : false);\r
+\r
+       // 外部認証サーバーは使用不可\r
+       AddCapsBool(t, "b_support_radius", false);\r
+\r
+       // ローカル ブリッジ機能が使用できる\r
+       AddCapsBool(t, "b_local_bridge", IsBridgeSupported());\r
+\r
+       if (OS_IS_WINDOWS(GetOsInfo()->OsType))\r
+       {\r
+               // パケットキャプチャドライバが未インストール\r
+               AddCapsBool(t, "b_must_install_pcap", IsEthSupported() == false ? true : false);\r
+       }\r
+       else\r
+       {\r
+               // Linux 版ではドライバはインストール済みとする\r
+               AddCapsBool(t, "b_must_install_pcap", false);\r
+       }\r
+\r
+       if (IsBridgeSupported())\r
+       {\r
+               // tun/tap が使用可能 (Linux のみ)\r
+               AddCapsBool(t, "b_tap_supported", GetOsInfo()->OsType == OSTYPE_LINUX ? true : false);\r
+       }\r
+\r
+       // カスケード接続\r
+       if (s->ServerType == SERVER_TYPE_STANDALONE)\r
+       {\r
+               AddCapsBool(t, "b_support_cascade", true);\r
+       }\r
+       else\r
+       {\r
+               AddCapsBool(t, "b_support_cascade", false);\r
+       }\r
+\r
+       // カスケード接続時のサーバー認証が使用できる\r
+       AddCapsBool(t, "b_support_cascade_cert", true);\r
+\r
+       // ログファイル設定の変更ができる\r
+       AddCapsBool(t, "b_support_config_log", s->ServerType != SERVER_TYPE_FARM_MEMBER);\r
+\r
+       // ログファイルの自動削除が使用可能である\r
+       AddCapsBool(t, "b_support_autodelete", true);\r
+\r
+       // config 操作が使用可能である\r
+       AddCapsBool(t, "b_support_config_rw", true);\r
+\r
+       // 仮想 HUB ごとの属性が設定可能である\r
+       AddCapsBool(t, "b_support_hub_admin_option", true);\r
+\r
+       // カスケード接続でクライアント証明書が設定可能である\r
+       AddCapsBool(t, "b_support_cascade_client_cert", true);\r
+\r
+       // 仮想 HUB を隠すことができる\r
+       AddCapsBool(t, "b_support_hide_hub", true);\r
+\r
+       // 統合管理\r
+       AddCapsBool(t, "b_support_cluster_admin", true);\r
+\r
+       if (s->Cedar->Bridge == false)\r
+       {\r
+               LICENSE_STATUS status;\r
+               // 仮想レイヤ 3 スイッチ機能が使える\r
+               AddCapsBool(t, "b_support_layer3", true);\r
+\r
+               AddCapsInt(t, "i_max_l3_sw", MAX_NUM_L3_SWITCH);\r
+               AddCapsInt(t, "i_max_l3_if", MAX_NUM_L3_IF);\r
+               AddCapsInt(t, "i_max_l3_table", MAX_NUM_L3_TABLE);\r
+\r
+               LiParseCurrentLicenseStatus(s->LicenseSystem, &status);\r
+\r
+               if (status.AllowEnterpriseFunction || s->ServerType != SERVER_TYPE_STANDALONE)\r
+               {\r
+                       // クラスタの一部として動作できる\r
+                       AddCapsBool(t, "b_support_cluster", true);\r
+               }\r
+               else\r
+               {\r
+                       // クラスタとして動作できない\r
+                       AddCapsBool(t, "b_support_cluster", false);\r
+               }\r
+       }\r
+       else\r
+       {\r
+               AddCapsBool(t, "b_support_layer3", false);\r
+\r
+               AddCapsInt(t, "i_max_l3_sw", 0);\r
+               AddCapsInt(t, "i_max_l3_if", 0);\r
+               AddCapsInt(t, "i_max_l3_table", 0);\r
+\r
+               AddCapsBool(t, "b_support_cluster", false);\r
+       }\r
+\r
+       if (s->ServerType != SERVER_TYPE_FARM_MEMBER && s->Cedar->Bridge == false)\r
+       {\r
+               // CRL をサポート\r
+               AddCapsBool(t, "b_support_crl", true);\r
+       }\r
+\r
+       // AC は非サポート\r
+       AddCapsBool(t, "b_support_ac", false);\r
+\r
+       // ログ ファイルのダウンロードをサポート\r
+       AddCapsBool(t, "b_support_read_log", true);\r
+\r
+       // カスケード接続の名前の変更が可能である\r
+       AddCapsBool(t, "b_support_rename_cascade", true);\r
+\r
+       // ライセンス管理は不可能\r
+       AddCapsBool(t, "b_support_license", false);\r
+\r
+       if (s->Cedar->Beta)\r
+       {\r
+               // ベータ版\r
+               AddCapsBool(t, "b_beta_version", true);\r
+       }\r
+\r
+       // ローカルブリッジにネットワーク接続の名前表示をサポート\r
+#ifdef OS_WIN32\r
+       if (IsBridgeSupported() && IsNt() && GetOsInfo()->OsType >= OSTYPE_WINDOWS_2000_PROFESSIONAL)\r
+       {\r
+               AddCapsBool(t, "b_support_network_connection_name", true);\r
+       }\r
+#else  // OS_WIN32\r
+       if (IsBridgeSupported() && EthIsInterfaceDescriptionSupportedUnix())\r
+       {\r
+               AddCapsBool(t, "b_support_network_connection_name", true);\r
+       }\r
+#endif // OS_WIN32\r
+\r
+       // MAC アドレスフィルタリングをサポート\r
+       AddCapsBool(t, "b_support_check_mac", true);\r
+\r
+       // TCP コネクションの状態チェックをサポート\r
+       AddCapsBool(t, "b_support_check_tcp_state", true);\r
+\r
+       // Radius 認証は使用不可\r
+       AddCapsBool(t, "b_support_radius_retry_interval_and_several_servers", false);\r
+\r
+       // MAC アドレステーブルでタグ付き VLAN の ID を管理できる\r
+       AddCapsBool(t, "b_support_vlan", true);\r
+\r
+       // 仮想 HUB 拡張オプションをサポート\r
+       if ((s->Cedar->Bridge == false) &&\r
+               (s->ServerType == SERVER_TYPE_STANDALONE || s->ServerType == SERVER_TYPE_FARM_CONTROLLER))\r
+       {\r
+               AddCapsBool(t, "b_support_hub_ext_options", true);\r
+       }\r
+       else\r
+       {\r
+               AddCapsBool(t, "b_support_hub_ext_options", false);\r
+       }\r
+\r
+       // セキュリティポリシー バージョン 3.0 をサポート\r
+       AddCapsBool(t, "b_support_policy_ver_3", true);\r
+\r
+       // IPv6 アクセスリストをサポート\r
+       AddCapsBool(t, "b_support_ipv6_acl", true);\r
+\r
+       // アクセスリストで遅延・ジッタ・パケットロスの設定をサポート\r
+       AddCapsBool(t, "b_support_ex_acl", true);\r
+\r
+       // アクセスリストでグループ名による指定をサポート\r
+       AddCapsBool(t, "b_support_acl_group", true);\r
+\r
+       // IPv6 接続元 IP 制限リストをサポート\r
+       AddCapsBool(t, "b_support_ipv6_ac", true);\r
+\r
+       // タグ付き VLAN パケット透過設定ツールをサポート\r
+       AddCapsBool(t, "b_support_eth_vlan", (OS_IS_WINDOWS_NT(GetOsType()) && GET_KETA(GetOsType(), 100) >= 2));\r
+\r
+       // 仮想 HUB への VPN 接続時のメッセージ表示機能をサポート\r
+       AddCapsBool(t, "b_support_msg", true);\r
+\r
+       // VPN3\r
+       AddCapsBool(t, "b_vpn3", true);\r
+\r
+       // オープンソース版\r
+       AddCapsBool(t, "b_gpl", true);\r
+}\r
+\r
+// SYSLOG_SETTING\r
+void InRpcSysLogSetting(SYSLOG_SETTING *t, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(t, sizeof(SYSLOG_SETTING));\r
+       t->SaveType = PackGetInt(p, "SaveType");\r
+       t->Port = PackGetInt(p, "Port");\r
+       PackGetStr(p, "Hostname", t->Hostname, sizeof(t->Hostname));\r
+}\r
+void OutRpcSysLogSetting(PACK *p, SYSLOG_SETTING *t)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddInt(p, "SaveType", t->SaveType);\r
+       PackAddInt(p, "Port", t->Port);\r
+       PackAddStr(p, "Hostname", t->Hostname);\r
+}\r
+\r
+// CAPSLIST\r
+void InitCapsList(CAPSLIST *t)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(t, sizeof(CAPSLIST));\r
+       t->CapsList = NewListFast(NULL);\r
+}\r
+void InRpcCapsList(CAPSLIST *t, PACK *p)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(t, sizeof(CAPSLIST));\r
+       t->CapsList = NewListFast(CompareCaps);\r
+\r
+       for (i = 0;i < LIST_NUM(p->elements);i++)\r
+       {\r
+               ELEMENT *e = LIST_DATA(p->elements, i);\r
+\r
+               if (StartWith(e->name, "caps_") && e->type == VALUE_INT && e->num_value == 1)\r
+               {\r
+                       CAPS *c = NewCaps(e->name + 5, e->values[0]->IntValue);\r
+                       Insert(t->CapsList, c);\r
+               }\r
+       }\r
+}\r
+void OutRpcCapsList(PACK *p, CAPSLIST *t)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < LIST_NUM(t->CapsList);i++)\r
+       {\r
+               char tmp[MAX_SIZE];\r
+               CAPS *c = LIST_DATA(t->CapsList, i);\r
+\r
+               Format(tmp, sizeof(tmp), "caps_%s", c->Name);\r
+               PackAddInt(p, tmp, c->Value);\r
+       }\r
+}\r
+void FreeRpcCapsList(CAPSLIST *t)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < LIST_NUM(t->CapsList);i++)\r
+       {\r
+               CAPS *c = LIST_DATA(t->CapsList, i);\r
+\r
+               FreeCaps(c);\r
+       }\r
+\r
+       ReleaseList(t->CapsList);\r
+}\r
+\r
+// Caps リストに bool 型を追加\r
+void AddCapsBool(CAPSLIST *caps, char *name, bool b)\r
+{\r
+       CAPS *c;\r
+       // 引数チェック\r
+       if (caps == NULL || name == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       c = NewCaps(name, b == false ? 0 : 1);\r
+       AddCaps(caps, c);\r
+}\r
+\r
+// Caps リストに int 型を追加\r
+void AddCapsInt(CAPSLIST *caps, char *name, UINT i)\r
+{\r
+       CAPS *c;\r
+       // 引数チェック\r
+       if (caps == NULL || name == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       c = NewCaps(name, i);\r
+       AddCaps(caps, c);\r
+}\r
+\r
+// Caps リストから int 型を取得\r
+UINT GetCapsInt(CAPSLIST *caps, char *name)\r
+{\r
+       CAPS *c;\r
+       // 引数チェック\r
+       if (caps == NULL || name == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       c = GetCaps(caps, name);\r
+       if (c == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       return c->Value;\r
+}\r
+\r
+// Caps リストから bool 型を取得\r
+bool GetCapsBool(CAPSLIST *caps, char *name)\r
+{\r
+       CAPS *c;\r
+       // 引数チェック\r
+       if (caps == NULL || name == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       c = GetCaps(caps, name);\r
+       if (c == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       return c->Value == 0 ? false : true;\r
+}\r
+\r
+// Caps リストの解放\r
+void FreeCapsList(CAPSLIST *caps)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (caps == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < LIST_NUM(caps->CapsList);i++)\r
+       {\r
+               CAPS *c = LIST_DATA(caps->CapsList, i);\r
+\r
+               FreeCaps(c);\r
+       }\r
+\r
+       ReleaseList(caps->CapsList);\r
+       Free(caps);\r
+}\r
+\r
+// Caps の取得\r
+CAPS *GetCaps(CAPSLIST *caps, char *name)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (caps == NULL || name == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       for (i = 0;i < LIST_NUM(caps->CapsList);i++)\r
+       {\r
+               CAPS *c = LIST_DATA(caps->CapsList, i);\r
+\r
+               if (StrCmpi(c->Name, name) == 0)\r
+               {\r
+                       return c;\r
+               }\r
+       }\r
+\r
+       return NULL;\r
+}\r
+\r
+// Caps の追加\r
+void AddCaps(CAPSLIST *caps, CAPS *c)\r
+{\r
+       // 引数チェック\r
+       if (caps == NULL || c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Insert(caps->CapsList, c);\r
+}\r
+\r
+// Caps の比較\r
+int CompareCaps(void *p1, void *p2)\r
+{\r
+       CAPS *c1, *c2;\r
+       if (p1 == NULL || p2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+       c1 = *(CAPS **)p1;\r
+       c2 = *(CAPS **)p2;\r
+       if (c1 == NULL || c2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       return StrCmpi(c1->Name, c2->Name);\r
+}\r
+\r
+// Caps リストの作成\r
+CAPSLIST *NewCapsList()\r
+{\r
+       CAPSLIST *caps = ZeroMalloc(sizeof(CAPSLIST));\r
+\r
+       caps->CapsList = NewListFast(CompareCaps);\r
+\r
+       return caps;\r
+}\r
+\r
+// Caps の解放\r
+void FreeCaps(CAPS *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Free(c->Name);\r
+       Free(c);\r
+}\r
+\r
+// Caps の作成\r
+CAPS *NewCaps(char *name, UINT value)\r
+{\r
+       CAPS *c;\r
+       // 引数チェック\r
+       if (name == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       c = ZeroMalloc(sizeof(CAPS));\r
+       c->Name = CopyStr(name);\r
+       c->Value = value;\r
+\r
+       return c;\r
+}\r
+\r
+// 現在の接続数と重みから得点を計算する\r
+UINT SiCalcPoint(SERVER *s, UINT num, UINT weight)\r
+{\r
+       UINT server_max_sessions = SERVER_MAX_SESSIONS;\r
+       if (s == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+       if (weight == 0)\r
+       {\r
+               weight = 100;\r
+       }\r
+\r
+       server_max_sessions = GetServerCapsInt(s, "i_max_sessions");\r
+\r
+       return (UINT)(((double)server_max_sessions -\r
+               MIN((double)num * 100.0 / (double)weight, (double)server_max_sessions))\r
+               * (double)FARM_BASE_POINT / (double)server_max_sessions);\r
+}\r
+\r
+// サーバー得点の取得\r
+UINT SiGetPoint(SERVER *s)\r
+{\r
+       UINT num_session;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       num_session = Count(s->Cedar->CurrentSessions);\r
+\r
+       return SiCalcPoint(s, num_session, s->Weight);\r
+}\r
+\r
+// デフォルトの証明書を生成する\r
+void SiGenerateDefualtCert(X **server_x, K **server_k)\r
+{\r
+       X *x;\r
+       K *private_key, *public_key;\r
+       NAME *name;\r
+       char tmp[MAX_SIZE];\r
+       wchar_t cn[MAX_SIZE];\r
+       // 引数チェック\r
+       if (server_x == NULL || server_k == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 鍵ペアの作成\r
+       RsaGen(&private_key, &public_key, 1024);\r
+\r
+       // ホスト名の取得\r
+       StrCpy(tmp, sizeof(tmp), "server.softether.vpn");\r
+       GetMachineName(tmp, sizeof(tmp));\r
+\r
+       StrToUni(cn, sizeof(cn), tmp);\r
+       name = NewName(cn, L"Default Random Certification", L"VPN Server",\r
+               L"JP", NULL, NULL);\r
+       x = NewRootX(public_key, private_key, name, MAX(GetDaysUntil2038(), SERVER_DEFAULT_CERT_DAYS), NULL);\r
+\r
+       *server_x = x;\r
+       *server_k = private_key;\r
+\r
+       FreeName(name);\r
+\r
+       FreeK(public_key);\r
+}\r
+\r
+// サーバー証明書をデフォルトにする\r
+void SiInitDefaultServerCert(SERVER *s)\r
+{\r
+       X *x = NULL;\r
+       K *k = NULL;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // サーバー証明書と秘密鍵を生成する\r
+       SiGenerateDefualtCert(&x, &k);\r
+\r
+       // 設定する\r
+       SetCedarCert(s->Cedar, x, k);\r
+\r
+       FreeX(x);\r
+       FreeK(k);\r
+}\r
+\r
+// 暗号化アルゴリズム名をデフォルトにする\r
+void SiInitCipherName(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       SetCedarCipherList(s->Cedar, SERVER_DEFAULT_CIPHER_NAME);\r
+}\r
+\r
+// リスナーリストを初期化する\r
+void SiInitListenerList(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       SiLockListenerList(s);\r
+       {\r
+               // デフォルト ポートとして 443, 992, 5555 の 3 つのポートを登録する\r
+               SiAddListener(s, 443, true);\r
+               SiAddListener(s, 992, true);\r
+               SiAddListener(s, 5555, true);\r
+       }\r
+       SiUnlockListenerList(s);\r
+}\r
+\r
+// リスナーを削除する\r
+bool SiDeleteListener(SERVER *s, UINT port)\r
+{\r
+       SERVER_LISTENER *e;\r
+       // 引数チェック\r
+       if (s == NULL || port == 0)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       e = SiGetListener(s, port);\r
+       if (e == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       // まだ動作中であれば停止する\r
+       SiDisableListener(s, port);\r
+\r
+       if (e->Listener != NULL)\r
+       {\r
+               ReleaseListener(e->Listener);\r
+       }\r
+\r
+       Delete(s->ServerListenerList, e);\r
+       Free(e);\r
+\r
+       return true;\r
+}\r
+\r
+// SERVER_LISTENER を比較する\r
+int CompareServerListener(void *p1, void *p2)\r
+{\r
+       SERVER_LISTENER *s1, *s2;\r
+       if (p1 == NULL || p2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+       s1 = *(SERVER_LISTENER **)p1;\r
+       s2 = *(SERVER_LISTENER **)p2;\r
+       if (s1 == NULL || s2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       if (s1->Port > s2->Port)\r
+       {\r
+               return 1;\r
+       }\r
+       else if (s1->Port < s2->Port)\r
+       {\r
+               return -1;\r
+       }\r
+       else\r
+       {\r
+               return 0;\r
+       }\r
+}\r
+\r
+// リスナーを停止する\r
+bool SiDisableListener(SERVER *s, UINT port)\r
+{\r
+       SERVER_LISTENER *e;\r
+       // 引数チェック\r
+       if (s == NULL || port == 0)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       // リスナーを取得する\r
+       e = SiGetListener(s, port);\r
+       if (e == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       if (e->Enabled == false || e->Listener == NULL)\r
+       {\r
+               // 停止中である\r
+               return true;\r
+       }\r
+\r
+       // リスナーを停止する\r
+       StopListener(e->Listener);\r
+\r
+       // リスナーを解放する\r
+       ReleaseListener(e->Listener);\r
+       e->Listener = NULL;\r
+\r
+       e->Enabled = false;\r
+\r
+       return true;\r
+}\r
+\r
+// リスナーを開始する\r
+bool SiEnableListener(SERVER *s, UINT port)\r
+{\r
+       SERVER_LISTENER *e;\r
+       // 引数チェック\r
+       if (s == NULL || port == 0)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       // リスナーを取得する\r
+       e = SiGetListener(s, port);\r
+       if (e == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       if (e->Enabled)\r
+       {\r
+               // すでに開始されている\r
+               return true;\r
+       }\r
+\r
+       // リスナーを作成する\r
+       e->Listener = NewListener(s->Cedar, LISTENER_TCP, e->Port);\r
+       if (e->Listener == NULL)\r
+       {\r
+               // 失敗\r
+               return false;\r
+       }\r
+\r
+       e->Enabled = true;\r
+\r
+       return true;\r
+}\r
+\r
+// リスナーを取得する\r
+SERVER_LISTENER *SiGetListener(SERVER *s, UINT port)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (s == NULL || port == 0)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)\r
+       {\r
+               SERVER_LISTENER *e = LIST_DATA(s->ServerListenerList, i);\r
+               if (e->Port == port)\r
+               {\r
+                       return e;\r
+               }\r
+       }\r
+\r
+       return NULL;\r
+}\r
+\r
+// リスナーを追加する\r
+bool SiAddListener(SERVER *s, UINT port, bool enabled)\r
+{\r
+       SERVER_LISTENER *e;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (s == NULL || port == 0)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       // 既存のリスナーが存在していないかどうかチェックする\r
+       for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)\r
+       {\r
+               e = LIST_DATA(s->ServerListenerList, i);\r
+               if (e->Port == port)\r
+               {\r
+                       // すでに存在する\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       // 新しいリスナーを初期化して登録する\r
+       e = ZeroMalloc(sizeof(SERVER_LISTENER));\r
+       e->Enabled = enabled;\r
+       e->Port = port;\r
+\r
+       if (e->Enabled)\r
+       {\r
+               // リスナーを作成する\r
+               e->Listener = NewListener(s->Cedar, LISTENER_TCP, e->Port);\r
+       }\r
+\r
+       Insert(s->ServerListenerList, e);\r
+\r
+       return true;\r
+}\r
+\r
+// リスナーリストをロックする\r
+void SiLockListenerList(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(s->ServerListenerList);\r
+}\r
+\r
+// リスナーリストのロックを解除する\r
+void SiUnlockListenerList(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       UnlockList(s->ServerListenerList);\r
+}\r
+\r
+// Bridge の初期化\r
+void SiInitBridge(SERVER *s)\r
+{\r
+       HUB *h;\r
+       HUB_OPTION o;\r
+       HUB_LOG g;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(&o, sizeof(o));\r
+       o.MaxSession = 0;\r
+\r
+       h = NewHub(s->Cedar, SERVER_DEFAULT_BRIDGE_NAME, &o);\r
+       AddHub(s->Cedar, h);\r
+\r
+       h->Offline = true;\r
+       SetHubOnline(h);\r
+\r
+       // ログ設定\r
+       SiSetDefaultLogSetting(&g);\r
+       SetHubLogSetting(h, &g);\r
+\r
+       ReleaseHub(h);\r
+}\r
+\r
+// デフォルトの仮想 HUB を作成する\r
+void SiInitDefaultHubList(SERVER *s)\r
+{\r
+       HUB *h;\r
+       HUB_OPTION o;\r
+       HUB_LOG g;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(&o, sizeof(o));\r
+       o.MaxSession = 0;\r
+       o.VlanTypeId = MAC_PROTO_TAGVLAN;\r
+       o.NoIPv6DefaultRouterInRAWhenIPv6 = true;\r
+       o.ManageOnlyPrivateIP = true;\r
+       o.ManageOnlyLocalUnicastIPv6 = true;\r
+       o.NoMacAddressLog = true;\r
+\r
+       h = NewHub(s->Cedar, s->Cedar->Bridge == false ? SERVER_DEFAULT_HUB_NAME : SERVER_DEFAULT_BRIDGE_NAME, &o);\r
+       h->CreatedTime = SystemTime64();\r
+       AddHub(s->Cedar, h);\r
+\r
+       if (s->Cedar->Bridge)\r
+       {\r
+               // パスワードを乱数にする\r
+               Rand(h->HashedPassword, sizeof(h->HashedPassword));\r
+               Rand(h->SecurePassword, sizeof(h->SecurePassword));\r
+       }\r
+\r
+       h->Offline = true;\r
+       SetHubOnline(h);\r
+\r
+       // ログ設定\r
+       SiSetDefaultLogSetting(&g);\r
+       SetHubLogSetting(h, &g);\r
+\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < 0;i++)\r
+               {\r
+                       char tmp[MAX_SIZE];\r
+                       USER *u;\r
+                       sprintf(tmp, "user%u", i);\r
+                       AcLock(h);\r
+                       u = NewUser(tmp, L"test", L"", AUTHTYPE_ANONYMOUS, NULL);\r
+                       AcAddUser(h, u);\r
+                       ReleaseUser(u);\r
+                       AcUnlock(h);\r
+               }\r
+       }\r
+\r
+       ReleaseHub(h);\r
+}\r
+\r
+// ログ設定をデフォルトにする\r
+void SiSetDefaultLogSetting(HUB_LOG *g)\r
+{\r
+       // 引数チェック\r
+       if (g == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(g, sizeof(HUB_LOG));\r
+       g->SaveSecurityLog = true;\r
+       g->SecurityLogSwitchType = LOG_SWITCH_DAY;\r
+       g->SavePacketLog = false;\r
+       g->PacketLogSwitchType = LOG_SWITCH_DAY;\r
+       g->PacketLogConfig[PACKET_LOG_TCP_CONN] =\r
+               g->PacketLogConfig[PACKET_LOG_DHCP] = PACKET_LOG_HEADER;\r
+}\r
+\r
+// テスト\r
+void SiTest(SERVER *s)\r
+{\r
+#if    0\r
+       USER *u;\r
+       USERGROUP *g;\r
+       HUB *h;\r
+       LINK *k;\r
+       CLIENT_OPTION o;\r
+       CLIENT_AUTH a;\r
+       ACCESS *ac;\r
+       X *x;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       h = GetHub(s->Cedar, SERVER_DEFAULT_HUB_NAME);\r
+       if (h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // ユーザーを作成する\r
+       g = NewGroup("test_group", L"テスト グループ", L"テストです。");\r
+       AcAddGroup(h, g);\r
+\r
+       u = NewUser("test", L"テスト", L"はむです", AUTHTYPE_ANONYMOUS, NULL);\r
+       AcAddUser(h, u);\r
+       JoinUserToGroup(u, g);\r
+       ReleaseUser(u);\r
+\r
+       u = NewUser("anonymous", L"匿名ユーザー", L"ソフトイーサ株式会社", AUTHTYPE_ANONYMOUS, NULL);\r
+       AcAddUser(h, u);\r
+       JoinUserToGroup(u, g);\r
+       ReleaseUser(u);\r
+\r
+       u = NewUser("password", L"パスワードユーザー", L"ソフトイーサ株式会社", AUTHTYPE_PASSWORD, NewPasswordAuthData("password", "microsoft"));\r
+       AcAddUser(h, u);\r
+       ReleaseUser(u);\r
+\r
+       x = FileToX("mayaqua.cer");\r
+       u = NewUser("usercert", L"ユーザー証明書テストユーザー", L"ソフトイーサ株式会社", AUTHTYPE_USERCERT, NewUserCertAuthData(x));\r
+       AcAddUser(h, u);\r
+       ReleaseUser(u);\r
+       FreeX(x);\r
+\r
+       u = NewUser("rootcert", L"ルート証明書テストユーザー", L"ソフトイーサ株式会社", AUTHTYPE_ROOTCERT, NewRootCertAuthData(NULL, NULL));\r
+       AcAddUser(h, u);\r
+       ReleaseUser(u);\r
+\r
+       u = NewUser("*", L"*", L"すべて", AUTHTYPE_RADIUS, NewRadiusAuthData(L""));\r
+       AcAddUser(h, u);\r
+       ReleaseUser(u);\r
+\r
+       ReleaseGroup(g);\r
+\r
+       // Radius サーバーを設定する\r
+       SetRadiusServer(h, "dc.sec.softether.co.jp", RADIUS_DEFAULT_PORT, "microsoft");\r
+\r
+       // HUB 間リンクを作成する\r
+       Zero(&o, sizeof(o));\r
+       UniStrCpy(o.AccountName, sizeof(o.AccountName), L"テスト リンク");\r
+       o.MaxConnection = 8;\r
+       o.NumRetry = INFINITE;\r
+       o.UseEncrypt = true;\r
+       StrCpy(o.HubName, sizeof(o.HubName), "TEST_HUB");\r
+       o.Port = 443;\r
+       StrCpy(o.Hostname, sizeof(o.Hostname), "ts.softether.co.jp");\r
+\r
+       Zero(&a, sizeof(a));\r
+       a.AuthType = CLIENT_AUTHTYPE_ANONYMOUS;\r
+       StrCpy(a.Username, sizeof(a.Username), "anonymous_test");\r
+\r
+       k = NewLink(s->Cedar, h, &o, &a, GetDefaultPolicy());\r
+       StartLink(k);\r
+\r
+       ReleaseLink(k);\r
+\r
+       // 証明書を追加する\r
+       x = FileToX("root.cer");\r
+       AddRootCert(h, x);\r
+       FreeX(x);\r
+\r
+       // アクセスリストを追加する\r
+       ac = ZeroMalloc(sizeof(ACCESS));\r
+       ac->Id = 1;\r
+       UniStrCpy(ac->Note, sizeof(ac->Note), L"アクセスリストのテスト");\r
+       ac->Active = true;\r
+       ac->Priority = 3;\r
+       ac->Discard = true;\r
+       ac->SrcIpAddress = 0x12345678;\r
+       ac->SrcSubnetMask = 0xffffffff;\r
+       ac->DestIpAddress = 0x36547894;\r
+       ac->DestSubnetMask = 0xffffffff;\r
+       ac->Protocol = IP_PROTO_TCP;\r
+       StrCpy(ac->SrcUsername, 0, "yagi");\r
+       StrCpy(ac->DestUsername, 0, "neko");\r
+       AddAccessList(h, ac);\r
+       Free(ac);\r
+\r
+       ReleaseHub(h);\r
+#endif\r
+}\r
+\r
+// 初期コンフィグレーションを設定する\r
+void SiLoadInitialConfiguration(SERVER *s)\r
+{\r
+       RPC_KEEP k;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 自動保存間隔関係\r
+       s->AutoSaveConfigSpan = SERVER_FILE_SAVE_INTERVAL_DEFAULT;\r
+\r
+       s->Weight = FARM_DEFAULT_WEIGHT;\r
+\r
+       // KEEP 関係\r
+       Zero(&k, sizeof(k));\r
+       k.UseKeepConnect = true;\r
+       k.KeepConnectPort = 80;\r
+       StrCpy(k.KeepConnectHost, sizeof(k.KeepConnectHost), CLIENT_DEFAULT_KEEPALIVE_HOST);\r
+       k.KeepConnectInterval = KEEP_INTERVAL_DEFAULT * 1000;\r
+       k.KeepConnectProtocol = CONNECTION_UDP;\r
+\r
+       Lock(s->Keep->lock);\r
+       {\r
+               KEEP *keep = s->Keep;\r
+               keep->Enable = k.UseKeepConnect;\r
+               keep->Server = true;\r
+               StrCpy(keep->ServerName, sizeof(keep->ServerName), k.KeepConnectHost);\r
+               keep->ServerPort = k.KeepConnectPort;\r
+               keep->UdpMode = k.KeepConnectProtocol;\r
+               keep->Interval = k.KeepConnectInterval;\r
+       }\r
+       Unlock(s->Keep->lock);\r
+\r
+       // パスワードを初期化する\r
+       Hash(s->HashedPassword, "", 0, true);\r
+\r
+       // 暗号化アルゴリズム名をデフォルトにする\r
+       SiInitCipherName(s);\r
+\r
+       // サーバー証明書をデフォルトにする\r
+       SiInitDefaultServerCert(s);\r
+\r
+       // リスナーリストをデフォルト設定する\r
+       SiInitListenerList(s);\r
+\r
+       // デフォルト HUB の作成\r
+       SiInitDefaultHubList(s);\r
+\r
+       s->Eraser = NewEraser(s->Logger, 0);\r
+}\r
+\r
+// コンフィグレーションファイルを読み込む (メイン)\r
+bool SiLoadConfigurationFileMain(SERVER *s, FOLDER *root)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || root == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       return SiLoadConfigurationCfg(s, root);\r
+}\r
+\r
+// コンフィグレーションファイルを読み込む\r
+bool SiLoadConfigurationFile(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       bool ret = false;\r
+       FOLDER *root;\r
+       if (s == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       s->CfgRw = NewCfgRw(&root,\r
+               s->Cedar->Bridge == false ? SERVER_CONFIG_FILE_NAME : BRIDGE_CONFIG_FILE_NAME);\r
+\r
+       if (server_reset_setting)\r
+       {\r
+               CfgDeleteFolder(root);\r
+               root = NULL;\r
+               server_reset_setting = false;\r
+       }\r
+\r
+       if (root == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       ret = SiLoadConfigurationFileMain(s, root);\r
+\r
+       CfgDeleteFolder(root);\r
+\r
+       return ret;\r
+}\r
+\r
+// コンフィグレーション初期化\r
+void SiInitConfiguration(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // Ethernet 初期化\r
+       InitEth();\r
+\r
+       s->AutoSaveConfigSpan = SERVER_FILE_SAVE_INTERVAL_DEFAULT;\r
+\r
+       SLog(s->Cedar, "LS_LOAD_CONFIG_1");\r
+       if (SiLoadConfigurationFile(s) == false)\r
+       {\r
+               SLog(s->Cedar, "LS_LOAD_CONFIG_3");\r
+               SiLoadInitialConfiguration(s);\r
+\r
+               server_reset_setting = false;\r
+       }\r
+       else\r
+       {\r
+               SLog(s->Cedar, "LS_LOAD_CONFIG_2");\r
+       }\r
+\r
+       // Linux における arp_filter\r
+       if (GetOsInfo()->OsType == OSTYPE_LINUX)\r
+       {\r
+               if (s->NoLinuxArpFilter == false)\r
+               {\r
+                       SetLinuxArpFilter();\r
+               }\r
+       }\r
+\r
+       // 保存スレッド作成\r
+       SLog(s->Cedar, "LS_INIT_SAVE_THREAD", s->AutoSaveConfigSpan / 1000);\r
+       s->SaveHaltEvent = NewEvent();\r
+       s->SaveThread = NewThread(SiSaverThread, s);\r
+}\r
+\r
+// サーバー設定を CFG から読み込む\r
+bool SiLoadConfigurationCfg(SERVER *s, FOLDER *root)\r
+{\r
+       FOLDER *f1, *f2, *f3, *f4, *f5, *f6;\r
+       // 引数チェック\r
+       if (s == NULL || root == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       f1 = CfgGetFolder(root, "ServerConfiguration");\r
+       f2 = CfgGetFolder(root, "VirtualHUB");\r
+       f3 = CfgGetFolder(root, "ListenerList");\r
+       f4 = CfgGetFolder(root, "LocalBridgeList");\r
+       f5 = CfgGetFolder(root, "VirtualLayer3SwitchList");\r
+       f6 = CfgGetFolder(root, "LicenseManager");\r
+\r
+       if (f1 == NULL)\r
+       {\r
+               SLog(s->Cedar, "LS_BAD_CONFIG");\r
+               return false;\r
+       }\r
+\r
+       s->ConfigRevision = CfgGetInt(root, "ConfigRevision");\r
+\r
+       if (s->Cedar->Bridge == false && f6 != NULL)\r
+       {\r
+               if (GetServerCapsBool(s, "b_support_license"))\r
+               {\r
+                       SiLoadLicenseManager(s, f6);\r
+               }\r
+       }\r
+\r
+       DestroyServerCapsCache(s);\r
+\r
+       SiLoadServerCfg(s, f1);\r
+\r
+       if (s->ServerType != SERVER_TYPE_FARM_MEMBER)\r
+       {\r
+               SiLoadHubs(s, f2);\r
+       }\r
+\r
+       SiLoadListeners(s, f3);\r
+\r
+       if (f4 != NULL)\r
+       {\r
+               SiLoadLocalBridges(s, f4);\r
+       }\r
+\r
+       if (s->Cedar->Bridge == false && f5 != NULL)\r
+       {\r
+               SiLoadL3Switchs(s, f5);\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+// リスナー設定を書き出す\r
+void SiWriteListenerCfg(FOLDER *f, SERVER_LISTENER *r)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || r == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       CfgAddBool(f, "Enabled", r->Enabled);\r
+       CfgAddInt(f, "Port", r->Port);\r
+}\r
+\r
+// リスナー設定を読み込む\r
+void SiLoadListenerCfg(SERVER *s, FOLDER *f)\r
+{\r
+       bool enable;\r
+       UINT port;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       enable = CfgGetBool(f, "Enabled");\r
+       port = CfgGetInt(f, "Port");\r
+\r
+       if (port == 0)\r
+       {\r
+               return;\r
+       }\r
+\r
+       SiAddListener(s, port, enable);\r
+}\r
+\r
+// リスナー一覧を読み込む\r
+void SiLoadListeners(SERVER *s, FOLDER *f)\r
+{\r
+       TOKEN_LIST *t;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       t = CfgEnumFolderToTokenList(f);\r
+       for (i = 0;i < t->NumTokens;i++)\r
+       {\r
+               FOLDER *ff = CfgGetFolder(f, t->Token[i]);\r
+               if (ff != NULL)\r
+               {\r
+                       SiLoadListenerCfg(s, ff);\r
+               }\r
+       }\r
+       FreeToken(t);\r
+}\r
+\r
+// リスナー一覧を書き出す\r
+void SiWriteListeners(FOLDER *f, SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(s->ServerListenerList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)\r
+               {\r
+                       SERVER_LISTENER *r = LIST_DATA(s->ServerListenerList, i);\r
+                       char name[MAX_SIZE];\r
+                       Format(name, sizeof(name), "Listener%u", i);\r
+                       SiWriteListenerCfg(CfgCreateFolder(f, name), r);\r
+               }\r
+       }\r
+       UnlockList(s->ServerListenerList);\r
+}\r
+\r
+// ブリッジを書き出す\r
+void SiWriteLocalBridgeCfg(FOLDER *f, LOCALBRIDGE *br)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || br == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       CfgAddStr(f, "DeviceName", br->DeviceName);\r
+       CfgAddStr(f, "HubName", br->HubName);\r
+       CfgAddBool(f, "NoPromiscuousMode", br->Local);\r
+       CfgAddBool(f, "MonitorMode", br->Monitor);\r
+       CfgAddBool(f, "FullBroadcastMode", br->FullBroadcast);\r
+\r
+       if (OS_IS_UNIX(GetOsInfo()->OsType))\r
+       {\r
+               CfgAddBool(f, "TapMode", br->TapMode);\r
+\r
+               if (br->TapMode)\r
+               {\r
+                       char tmp[MAX_SIZE];\r
+                       MacToStr(tmp, sizeof(tmp), br->TapMacAddress);\r
+                       CfgAddStr(f, "TapMacAddress", tmp);\r
+               }\r
+       }\r
+}\r
+\r
+// ブリッジ一覧を書き出す\r
+void SiWriteLocalBridges(FOLDER *f, SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(s->Cedar->LocalBridgeList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(s->Cedar->LocalBridgeList);i++)\r
+               {\r
+                       LOCALBRIDGE *br = LIST_DATA(s->Cedar->LocalBridgeList, i);\r
+                       char name[MAX_SIZE];\r
+\r
+                       Format(name, sizeof(name), "LocalBridge%u", i);\r
+                       SiWriteLocalBridgeCfg(CfgCreateFolder(f, name), br);\r
+               }\r
+       }\r
+       UnlockList(s->Cedar->LocalBridgeList);\r
+}\r
+\r
+// ブリッジを読み込む\r
+void SiLoadLocalBridgeCfg(SERVER *s, FOLDER *f)\r
+{\r
+       char hub[MAX_SIZE];\r
+       char nic[MAX_SIZE];\r
+       bool tapmode = false;\r
+       UCHAR tapaddr[6];\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(hub, sizeof(hub));\r
+       Zero(nic, sizeof(nic));\r
+\r
+       CfgGetStr(f, "HubName", hub, sizeof(hub));\r
+       CfgGetStr(f, "DeviceName", nic, sizeof(nic));\r
+\r
+       if (IsEmptyStr(hub) || IsEmptyStr(nic))\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (OS_IS_UNIX(GetOsInfo()->OsType))\r
+       {\r
+               if (CfgGetBool(f, "TapMode"))\r
+               {\r
+                       char tmp[MAX_SIZE];\r
+                       tapmode = true;\r
+                       Zero(tapaddr, sizeof(tapaddr));\r
+                       if (CfgGetStr(f, "TapMacAddress", tmp, sizeof(tmp)))\r
+                       {\r
+                               BUF *b;\r
+                               b = StrToBin(tmp);\r
+                               if (b != NULL && b->Size == 6)\r
+                               {\r
+                                       Copy(tapaddr, b->Buf, sizeof(tapaddr));\r
+                               }\r
+                               FreeBuf(b);\r
+                       }\r
+               }\r
+       }\r
+\r
+       AddLocalBridge(s->Cedar, hub, nic, CfgGetBool(f, "NoPromiscuousMode"), CfgGetBool(f, "MonitorMode"),\r
+               tapmode, tapaddr, CfgGetBool(f, "FullBroadcastMode"));\r
+}\r
+\r
+// ブリッジ一覧を読み込む\r
+void SiLoadLocalBridges(SERVER *s, FOLDER *f)\r
+{\r
+       TOKEN_LIST *t;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       t = CfgEnumFolderToTokenList(f);\r
+\r
+       for (i = 0;i < t->NumTokens;i++)\r
+       {\r
+               char *name = t->Token[i];\r
+\r
+               SiLoadLocalBridgeCfg(s, CfgGetFolder(f, name));\r
+       }\r
+\r
+       FreeToken(t);\r
+}\r
+\r
+// サーバーの設定リビジョンをインクリメントする\r
+void IncrementServerConfigRevision(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s->ConfigRevision++;\r
+}\r
+\r
+// サーバー設定を CFG に書き出す\r
+FOLDER *SiWriteConfigurationToCfg(SERVER *s)\r
+{\r
+       FOLDER *root;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       root = CfgCreateFolder(NULL, TAG_ROOT);\r
+\r
+       CfgAddInt(root, "ConfigRevision", s->ConfigRevision);\r
+\r
+       SiWriteListeners(CfgCreateFolder(root, "ListenerList"), s);\r
+\r
+       SiWriteLocalBridges(CfgCreateFolder(root, "LocalBridgeList"), s);\r
+\r
+       SiWriteServerCfg(CfgCreateFolder(root, "ServerConfiguration"), s);\r
+\r
+       if (s->UpdatedServerType != SERVER_TYPE_FARM_MEMBER)\r
+       {\r
+               SiWriteHubs(CfgCreateFolder(root, "VirtualHUB"), s);\r
+       }\r
+\r
+       if (s->Cedar->Bridge == false)\r
+       {\r
+               SiWriteL3Switchs(CfgCreateFolder(root, "VirtualLayer3SwitchList"), s);\r
+\r
+               if (GetServerCapsBool(s, "b_support_license"))\r
+               {\r
+                       SiWriteLicenseManager(CfgCreateFolder(root, "LicenseManager"), s);\r
+               }\r
+       }\r
+\r
+       return root;\r
+}\r
+\r
+// ポリシーの読み込み\r
+void SiLoadPolicyCfg(POLICY *p, FOLDER *f)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(p, sizeof(POLICY));\r
+\r
+       // Ver 2\r
+       p->Access = CfgGetBool(f, "Access");\r
+       p->DHCPFilter = CfgGetBool(f, "DHCPFilter");\r
+       p->DHCPNoServer = CfgGetBool(f, "DHCPNoServer");\r
+       p->DHCPForce = CfgGetBool(f, "DHCPForce");\r
+       p->NoBridge = CfgGetBool(f, "NoBridge");\r
+       p->NoRouting = CfgGetBool(f, "NoRouting");\r
+       p->CheckMac = CfgGetBool(f, "CheckMac");\r
+       p->CheckIP = CfgGetBool(f, "CheckIP");\r
+       p->ArpDhcpOnly = CfgGetBool(f, "ArpDhcpOnly");\r
+       p->PrivacyFilter = CfgGetBool(f, "PrivacyFilter");\r
+       p->NoServer = CfgGetBool(f, "NoServer");\r
+       p->NoBroadcastLimiter = CfgGetBool(f, "NoBroadcastLimiter");\r
+       p->MonitorPort = CfgGetBool(f, "MonitorPort");\r
+       p->MaxConnection = CfgGetInt(f, "MaxConnection");\r
+       p->TimeOut = CfgGetInt(f, "TimeOut");\r
+       p->MaxMac = CfgGetInt(f, "MaxMac");\r
+       p->MaxIP = CfgGetInt(f, "MaxIP");\r
+       p->MaxUpload = CfgGetInt(f, "MaxUpload");\r
+       p->MaxDownload = CfgGetInt(f, "MaxDownload");\r
+       p->FixPassword = CfgGetBool(f, "FixPassword");\r
+       p->MultiLogins = CfgGetInt(f, "MultiLogins");\r
+       p->NoQoS = CfgGetBool(f, "NoQoS");\r
+\r
+       // Ver 3\r
+       p->RSandRAFilter = CfgGetBool(f, "RSandRAFilter");\r
+       p->RAFilter = CfgGetBool(f, "RAFilter");\r
+       p->DHCPv6Filter = CfgGetBool(f, "DHCPv6Filter");\r
+       p->DHCPv6NoServer = CfgGetBool(f, "DHCPv6NoServer");\r
+       p->NoRoutingV6 = CfgGetBool(f, "NoRoutingV6");\r
+       p->CheckIPv6 = CfgGetBool(f, "CheckIPv6");\r
+       p->NoServerV6 = CfgGetBool(f, "NoServerV6");\r
+       p->MaxIPv6 = CfgGetInt(f, "MaxIPv6");\r
+       p->NoSavePassword = CfgGetBool(f, "NoSavePassword");\r
+       p->AutoDisconnect = CfgGetInt(f, "AutoDisconnect");\r
+       p->FilterIPv4 = CfgGetBool(f, "FilterIPv4");\r
+       p->FilterIPv6 = CfgGetBool(f, "FilterIPv6");\r
+       p->FilterNonIP = CfgGetBool(f, "FilterNonIP");\r
+       p->NoIPv6DefaultRouterInRA = CfgGetBool(f, "NoIPv6DefaultRouterInRA");\r
+       p->NoIPv6DefaultRouterInRAWhenIPv6 = CfgGetBool(f, "NoIPv6DefaultRouterInRAWhenIPv6");\r
+       p->VLanId = CfgGetInt(f, "VLanId");\r
+}\r
+\r
+// ポリシーの書き込み\r
+void SiWritePolicyCfg(FOLDER *f, POLICY *p, bool cascade_mode)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // Ver 2.0\r
+       if (cascade_mode == false)\r
+       {\r
+               CfgAddBool(f, "Access", p->Access);\r
+       }\r
+\r
+       CfgAddBool(f, "DHCPFilter", p->DHCPFilter);\r
+       CfgAddBool(f, "DHCPNoServer", p->DHCPNoServer);\r
+       CfgAddBool(f, "DHCPForce", p->DHCPForce);\r
+\r
+       if (cascade_mode == false)\r
+       {\r
+               CfgAddBool(f, "NoBridge", p->NoBridge);\r
+               CfgAddBool(f, "NoRouting", p->NoRouting);\r
+       }\r
+\r
+       CfgAddBool(f, "CheckMac", p->CheckMac);\r
+       CfgAddBool(f, "CheckIP", p->CheckIP);\r
+       CfgAddBool(f, "ArpDhcpOnly", p->ArpDhcpOnly);\r
+\r
+       if (cascade_mode == false)\r
+       {\r
+               CfgAddBool(f, "PrivacyFilter", p->PrivacyFilter);\r
+       }\r
+\r
+       CfgAddBool(f, "NoServer", p->NoServer);\r
+       CfgAddBool(f, "NoBroadcastLimiter", p->NoBroadcastLimiter);\r
+\r
+       if (cascade_mode == false)\r
+       {\r
+               CfgAddBool(f, "MonitorPort", p->MonitorPort);\r
+               CfgAddInt(f, "MaxConnection", p->MaxConnection);\r
+               CfgAddInt(f, "TimeOut", p->TimeOut);\r
+       }\r
+\r
+       CfgAddInt(f, "MaxMac", p->MaxMac);\r
+       CfgAddInt(f, "MaxIP", p->MaxIP);\r
+       CfgAddInt(f, "MaxUpload", p->MaxUpload);\r
+       CfgAddInt(f, "MaxDownload", p->MaxDownload);\r
+\r
+       if (cascade_mode == false)\r
+       {\r
+               CfgAddBool(f, "FixPassword", p->FixPassword);\r
+               CfgAddInt(f, "MultiLogins", p->MultiLogins);\r
+               CfgAddBool(f, "NoQoS", p->NoQoS);\r
+       }\r
+\r
+       // Ver 3.0\r
+       CfgAddBool(f, "RSandRAFilter", p->RSandRAFilter);\r
+       CfgAddBool(f, "RAFilter", p->RAFilter);\r
+       CfgAddBool(f, "DHCPv6Filter", p->DHCPv6Filter);\r
+       CfgAddBool(f, "DHCPv6NoServer", p->DHCPv6NoServer);\r
+\r
+       if (cascade_mode == false)\r
+       {\r
+               CfgAddBool(f, "NoRoutingV6", p->NoRoutingV6);\r
+       }\r
+\r
+       CfgAddBool(f, "CheckIPv6", p->CheckIPv6);\r
+       CfgAddBool(f, "NoServerV6", p->NoServerV6);\r
+       CfgAddInt(f, "MaxIPv6", p->MaxIPv6);\r
+\r
+       if (cascade_mode == false)\r
+       {\r
+               CfgAddBool(f, "NoSavePassword", p->NoSavePassword);\r
+               CfgAddInt(f, "AutoDisconnect", p->AutoDisconnect);\r
+       }\r
+\r
+       CfgAddBool(f, "FilterIPv4", p->FilterIPv4);\r
+       CfgAddBool(f, "FilterIPv6", p->FilterIPv6);\r
+       CfgAddBool(f, "FilterNonIP", p->FilterNonIP);\r
+       CfgAddBool(f, "NoIPv6DefaultRouterInRA", p->NoIPv6DefaultRouterInRA);\r
+       CfgAddBool(f, "NoIPv6DefaultRouterInRAWhenIPv6", p->NoIPv6DefaultRouterInRAWhenIPv6);\r
+       CfgAddInt(f, "VLanId", p->VLanId);\r
+}\r
+\r
+// 仮想 HUB のリンク情報の書き込み\r
+void SiWriteHubLinkCfg(FOLDER *f, LINK *k)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || k == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Lock(k->lock);\r
+       {\r
+               // オンライン\r
+               CfgAddBool(f, "Online", k->Offline ? false : true);\r
+\r
+               // クライアントオプション\r
+               CiWriteClientOption(CfgCreateFolder(f, "ClientOption"), k->Option);\r
+\r
+               // クライアント認証データ\r
+               CiWriteClientAuth(CfgCreateFolder(f, "ClientAuth"), k->Auth);\r
+\r
+               // ポリシー\r
+               if (k->Policy != NULL)\r
+               {\r
+                       SiWritePolicyCfg(CfgCreateFolder(f, "Policy"), k->Policy, true);\r
+               }\r
+\r
+               CfgAddBool(f, "CheckServerCert", k->CheckServerCert);\r
+\r
+               if (k->ServerCert != NULL)\r
+               {\r
+                       BUF *b = XToBuf(k->ServerCert, false);\r
+                       CfgAddBuf(f, "ServerCert", b);\r
+                       FreeBuf(b);\r
+               }\r
+       }\r
+       Unlock(k->lock);\r
+}\r
+\r
+// リンク情報の読み込み\r
+void SiLoadHubLinkCfg(FOLDER *f, HUB *h)\r
+{\r
+       bool online;\r
+       CLIENT_OPTION *o;\r
+       CLIENT_AUTH *a;\r
+       FOLDER *pf;\r
+       POLICY p;\r
+       LINK *k;\r
+       // 引数チェック\r
+       if (f == NULL || h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       pf = CfgGetFolder(f, "Policy");\r
+       if (pf == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       SiLoadPolicyCfg(&p, pf);\r
+\r
+       online = CfgGetBool(f, "Online");\r
+\r
+       o = CiLoadClientOption(CfgGetFolder(f, "ClientOption"));\r
+       a = CiLoadClientAuth(CfgGetFolder(f, "ClientAuth"));\r
+       if (o == NULL || a == NULL)\r
+       {\r
+               Free(o);\r
+               CiFreeClientAuth(a);\r
+               return;\r
+       }\r
+\r
+       k = NewLink(h->Cedar, h, o, a, &p);\r
+       if (k != NULL)\r
+       {\r
+               BUF *b;\r
+               k->CheckServerCert = CfgGetBool(f, "CheckServerCert");\r
+               b = CfgGetBuf(f, "ServerCert");\r
+               if (b != NULL)\r
+               {\r
+                       k->ServerCert = BufToX(b, false);\r
+                       FreeBuf(b);\r
+               }\r
+\r
+               if (online)\r
+               {\r
+                       k->Offline = true;\r
+                       SetLinkOnline(k);\r
+               }\r
+               else\r
+               {\r
+                       k->Offline = false;\r
+                       SetLinkOffline(k);\r
+               }\r
+               ReleaseLink(k);\r
+       }\r
+\r
+       Free(o);\r
+       CiFreeClientAuth(a);\r
+}\r
+\r
+// 仮想 HUB の SecureNAT の書き込み\r
+void SiWriteSecureNAT(HUB *h, FOLDER *f)\r
+{\r
+       // 引数チェック\r
+       if (h == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       CfgAddBool(f, "Disabled", h->EnableSecureNAT ? false : true);\r
+\r
+       NiWriteVhOptionEx(h->SecureNATOption, f);\r
+}\r
+\r
+// 仮想 HUB の管理オプションの読み込み\r
+void SiLoadHubAdminOptions(HUB *h, FOLDER *f)\r
+{\r
+       TOKEN_LIST *t;\r
+       // 引数チェック\r
+       if (h == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       t = CfgEnumItemToTokenList(f);\r
+       if (t != NULL)\r
+       {\r
+               UINT i;\r
+\r
+               LockList(h->AdminOptionList);\r
+               {\r
+                       DeleteAllHubAdminOption(h, false);\r
+\r
+                       for (i = 0;i < t->NumTokens;i++)\r
+                       {\r
+                               char *name = t->Token[i];\r
+                               ADMIN_OPTION *a;\r
+                               UINT value = CfgGetInt(f, name);;\r
+\r
+                               Trim(name);\r
+\r
+                               a = ZeroMalloc(sizeof(ADMIN_OPTION));\r
+                               StrCpy(a->Name, sizeof(a->Name), name);\r
+                               a->Value = value;\r
+\r
+                               Insert(h->AdminOptionList, a);\r
+                       }\r
+\r
+                       AddHubAdminOptionsDefaults(h, false);\r
+               }\r
+               UnlockList(h->AdminOptionList);\r
+\r
+               FreeToken(t);\r
+       }\r
+}\r
+\r
+// 仮想 HUB の管理オプションの書き込み\r
+void SiWriteHubAdminOptions(FOLDER *f, HUB *h)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(h->AdminOptionList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(h->AdminOptionList);i++)\r
+               {\r
+                       ADMIN_OPTION *a = LIST_DATA(h->AdminOptionList, i);\r
+\r
+                       CfgAddInt(f, a->Name, a->Value);\r
+               }\r
+       }\r
+       UnlockList(h->AdminOptionList);\r
+}\r
+\r
+// 仮想 HUB のリンクリストの書き込み\r
+void SiWriteHubLinks(FOLDER *f, HUB *h)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(h->LinkList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(h->LinkList);i++)\r
+               {\r
+                       LINK *k = LIST_DATA(h->LinkList, i);\r
+                       char name[MAX_SIZE];\r
+                       Format(name, sizeof(name), "Cascade%u", i);\r
+                       SiWriteHubLinkCfg(CfgCreateFolder(f, name), k);\r
+               }\r
+       }\r
+       UnlockList(h->LinkList);\r
+}\r
+\r
+// リンクリストの読み込み\r
+void SiLoadHubLinks(HUB *h, FOLDER *f)\r
+{\r
+       TOKEN_LIST *t;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (h == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       t = CfgEnumFolderToTokenList(f);\r
+\r
+       for (i = 0;i < t->NumTokens;i++)\r
+       {\r
+               char *name = t->Token[i];\r
+               SiLoadHubLinkCfg(CfgGetFolder(f, name), h);\r
+       }\r
+\r
+       FreeToken(t);\r
+}\r
+\r
+// アクセスリスト項目の書き込み\r
+void SiWriteHubAccessCfg(FOLDER *f, ACCESS *a)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || a == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       CfgAddUniStr(f, "Note", a->Note);\r
+       CfgAddBool(f, "Active", a->Active);\r
+       CfgAddInt(f, "Priority", a->Priority);\r
+       CfgAddBool(f, "Discard", a->Discard);\r
+       CfgAddBool(f, "IsIPv6", a->IsIPv6);\r
+\r
+       if (a->IsIPv6 == false)\r
+       {\r
+               CfgAddIp32(f, "SrcIpAddress", a->SrcIpAddress);\r
+               CfgAddIp32(f, "SrcSubnetMask", a->SrcSubnetMask);\r
+               CfgAddIp32(f, "DestIpAddress", a->DestIpAddress);\r
+               CfgAddIp32(f, "DestSubnetMask", a->DestSubnetMask);\r
+       }\r
+       else\r
+       {\r
+               CfgAddIp6Addr(f, "SrcIpAddress6", &a->SrcIpAddress6);\r
+               CfgAddIp6Addr(f, "SrcSubnetMask6", &a->SrcSubnetMask6);\r
+               CfgAddIp6Addr(f, "DestIpAddress6", &a->DestIpAddress6);\r
+               CfgAddIp6Addr(f, "DestSubnetMask6", &a->DestSubnetMask6);\r
+       }\r
+\r
+       CfgAddInt(f, "Protocol", a->Protocol);\r
+       CfgAddInt(f, "SrcPortStart", a->SrcPortStart);\r
+       CfgAddInt(f, "SrcPortEnd", a->SrcPortEnd);\r
+       CfgAddInt(f, "DestPortStart", a->DestPortStart);\r
+       CfgAddInt(f, "DestPortEnd", a->DestPortEnd);\r
+       CfgAddStr(f, "SrcUsername", a->SrcUsername);\r
+       CfgAddStr(f, "DestUsername", a->DestUsername);\r
+       CfgAddBool(f, "CheckSrcMac", a->CheckSrcMac);\r
+\r
+       if (a->CheckSrcMac)\r
+       {\r
+               char tmp[MAX_PATH];\r
+\r
+               MacToStr(tmp, sizeof(tmp), a->SrcMacAddress);\r
+               CfgAddStr(f, "SrcMacAddress", tmp);\r
+\r
+               MacToStr(tmp, sizeof(tmp), a->SrcMacMask);\r
+               CfgAddStr(f, "SrcMacMask", tmp);\r
+       }\r
+\r
+       CfgAddBool(f, "CheckDstMac", a->CheckDstMac);\r
+\r
+       if (a->CheckDstMac)\r
+       {\r
+               char tmp[MAX_PATH];\r
+\r
+               MacToStr(tmp, sizeof(tmp), a->DstMacAddress);\r
+               CfgAddStr(f, "DstMacAddress", tmp);\r
+\r
+               MacToStr(tmp, sizeof(tmp), a->DstMacMask);\r
+               CfgAddStr(f, "DstMacMask", tmp);\r
+       }\r
+\r
+       CfgAddBool(f, "CheckTcpState", a->CheckTcpState);\r
+       CfgAddBool(f, "Established", a->Established);\r
+\r
+       CfgAddInt(f, "Delay", a->Delay);\r
+       CfgAddInt(f, "Jitter", a->Jitter);\r
+       CfgAddInt(f, "Loss", a->Loss);\r
+}\r
+\r
+// アクセスリスト項目の読み込み\r
+void SiLoadHubAccessCfg(HUB *h, FOLDER *f)\r
+{\r
+       ACCESS a;\r
+       char tmp[MAX_PATH];\r
+       // 引数チェック\r
+       if (h == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(&a, sizeof(a));\r
+\r
+       CfgGetUniStr(f, "Note", a.Note, sizeof(a.Note));\r
+       a.Active = CfgGetBool(f, "Active");\r
+       a.Priority = CfgGetInt(f, "Priority");\r
+       a.Discard = CfgGetBool(f, "Discard");\r
+       a.IsIPv6 = CfgGetBool(f, "IsIPv6");\r
+\r
+       if (a.IsIPv6 == false)\r
+       {\r
+               a.SrcIpAddress = CfgGetIp32(f, "SrcIpAddress");\r
+               a.SrcSubnetMask = CfgGetIp32(f, "SrcSubnetMask");\r
+               a.DestIpAddress = CfgGetIp32(f, "DestIpAddress");\r
+               a.DestSubnetMask = CfgGetIp32(f, "DestSubnetMask");\r
+       }\r
+       else\r
+       {\r
+               CfgGetIp6Addr(f, "SrcIpAddress6", &a.SrcIpAddress6);\r
+               CfgGetIp6Addr(f, "SrcSubnetMask6", &a.SrcSubnetMask6);\r
+               CfgGetIp6Addr(f, "DestIpAddress6", &a.DestIpAddress6);\r
+               CfgGetIp6Addr(f, "DestSubnetMask6", &a.DestSubnetMask6);\r
+       }\r
+\r
+       a.Protocol = CfgGetInt(f, "Protocol");\r
+       a.SrcPortStart = CfgGetInt(f, "SrcPortStart");\r
+       a.SrcPortEnd = CfgGetInt(f, "SrcPortEnd");\r
+       a.DestPortStart = CfgGetInt(f, "DestPortStart");\r
+       a.DestPortEnd = CfgGetInt(f, "DestPortEnd");\r
+       CfgGetStr(f, "SrcUsername", a.SrcUsername, sizeof(a.SrcUsername));\r
+       CfgGetStr(f, "DestUsername", a.DestUsername, sizeof(a.DestUsername));\r
+       a.CheckSrcMac = CfgGetBool(f, "CheckSrcMac");\r
+\r
+       if (CfgGetByte(f, "SrcMacAddress", a.SrcMacAddress, sizeof(a.SrcMacAddress)) == 0)\r
+       {\r
+               CfgGetStr(f, "SrcMacAddress", tmp, sizeof(tmp));\r
+               if (StrToMac(a.SrcMacAddress, tmp) == false)\r
+               {\r
+                       a.CheckSrcMac = false;\r
+               }\r
+       }\r
+\r
+       if (CfgGetByte(f, "SrcMacMask", a.SrcMacMask, sizeof(a.SrcMacMask)) == 0)\r
+       {\r
+               CfgGetStr(f, "SrcMacMask", tmp, sizeof(tmp));\r
+               if (StrToMac(a.SrcMacMask, tmp) == false)\r
+               {\r
+                       a.CheckSrcMac = false;\r
+               }\r
+       }\r
+\r
+       a.CheckDstMac = CfgGetBool(f, "CheckDstMac");\r
+\r
+       if (CfgGetByte(f, "DstMacAddress", a.DstMacAddress, sizeof(a.DstMacAddress)) == 0)\r
+       {\r
+               CfgGetStr(f, "DstMacAddress", tmp, sizeof(tmp));\r
+               if (StrToMac(a.DstMacAddress, tmp) == false)\r
+               {\r
+                       a.CheckDstMac = false;\r
+               }\r
+       }\r
+\r
+       if (CfgGetByte(f, "DstMacMask", a.DstMacMask, sizeof(a.DstMacMask)) == 0)\r
+       {\r
+               CfgGetStr(f, "DstMacMask", tmp, sizeof(tmp));\r
+               if (StrToMac(a.DstMacMask, tmp) == false)\r
+               {\r
+                       a.CheckDstMac = false;\r
+               }\r
+       }\r
+\r
+       a.CheckTcpState = CfgGetBool(f, "CheckTcpState");\r
+       a.Established = CfgGetBool(f, "Established");\r
+       a.Delay = MAKESURE(CfgGetInt(f, "Delay"), 0, HUB_ACCESSLIST_DELAY_MAX);\r
+       a.Jitter = MAKESURE(CfgGetInt(f, "Jitter"), 0, HUB_ACCESSLIST_JITTER_MAX);\r
+       a.Loss = MAKESURE(CfgGetInt(f, "Loss"), 0, HUB_ACCESSLIST_LOSS_MAX);\r
+\r
+       AddAccessList(h, &a);\r
+}\r
+\r
+// アクセスリストの書き込み\r
+void SiWriteHubAccessLists(FOLDER *f, HUB *h)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(h->AccessList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(h->AccessList);i++)\r
+               {\r
+                       ACCESS *a = LIST_DATA(h->AccessList, i);\r
+                       char name[MAX_SIZE];\r
+                       ToStr(name, a->Id);\r
+                       SiWriteHubAccessCfg(CfgCreateFolder(f, name), a);\r
+               }\r
+       }\r
+       UnlockList(h->AccessList);\r
+}\r
+\r
+// アクセスリストの読み込み\r
+void SiLoadHubAccessLists(HUB *h, FOLDER *f)\r
+{\r
+       TOKEN_LIST *t;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (f == NULL || h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       t = CfgEnumFolderToTokenList(f);\r
+\r
+       for (i = 0;i < t->NumTokens;i++)\r
+       {\r
+               char *name = t->Token[i];\r
+               UINT id = ToInt(name);\r
+               SiLoadHubAccessCfg(h, CfgGetFolder(f, name));\r
+       }\r
+\r
+       FreeToken(t);\r
+}\r
+\r
+// HUB_OPTION の読み込み\r
+void SiLoadHubOptionCfg(FOLDER *f, HUB_OPTION *o)\r
+{\r
+       char tmp[MAX_SIZE];\r
+       // 引数チェック\r
+       if (f == NULL || o == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       o->MaxSession = CfgGetInt(f, "MaxSession");\r
+       o->NoArpPolling = CfgGetBool(f, "NoArpPolling");\r
+       o->NoIPv6AddrPolling = CfgGetBool(f, "NoIPv6AddrPolling");\r
+       o->NoIpTable = CfgGetBool(f, "NoIpTable");\r
+       o->NoEnum = CfgGetBool(f, "NoEnum");\r
+       o->FilterPPPoE = CfgGetBool(f, "FilterPPPoE");\r
+       o->FilterOSPF = CfgGetBool(f, "FilterOSPF");\r
+       o->FilterIPv4 = CfgGetBool(f, "FilterIPv4");\r
+       o->FilterIPv6 = CfgGetBool(f, "FilterIPv6");\r
+       o->FilterNonIP = CfgGetBool(f, "FilterNonIP");\r
+       o->FilterBPDU = CfgGetBool(f, "FilterBPDU");\r
+       o->NoIPv4PacketLog = CfgGetBool(f, "NoIPv4PacketLog");\r
+       o->NoIPv6PacketLog = CfgGetBool(f, "NoIPv6PacketLog");\r
+       o->NoIPv6DefaultRouterInRAWhenIPv6 = CfgGetBool(f, "NoIPv6DefaultRouterInRAWhenIPv6");\r
+       o->DisableIPParsing = CfgGetBool(f, "DisableIPParsing");\r
+       o->YieldAfterStorePacket = CfgGetBool(f, "YieldAfterStorePacket");\r
+       o->NoSpinLockForPacketDelay = CfgGetBool(f, "NoSpinLockForPacketDelay");\r
+       o->BroadcastStormDetectionThreshold = CfgGetInt(f, "BroadcastStormDetectionThreshold");\r
+       o->ClientMinimumRequiredBuild = CfgGetInt(f, "ClientMinimumRequiredBuild");\r
+       o->RequiredClientId = CfgGetInt(f, "RequiredClientId");\r
+       o->NoManageVlanId = CfgGetBool(f, "NoManageVlanId");\r
+       o->VlanTypeId = 0;\r
+       if (CfgGetStr(f, "VlanTypeId", tmp, sizeof(tmp)))\r
+       {\r
+               o->VlanTypeId = HexToInt(tmp);\r
+       }\r
+       if (o->VlanTypeId == 0)\r
+       {\r
+               o->VlanTypeId = MAC_PROTO_TAGVLAN;\r
+       }\r
+       o->FixForDLinkBPDU = CfgGetBool(f, "FixForDLinkBPDU");\r
+       o->NoLookBPDUBridgeId = CfgGetBool(f, "NoLookBPDUBridgeId");\r
+\r
+       // デフォルトで有効\r
+       if (CfgIsItem(f, "ManageOnlyPrivateIP"))\r
+       {\r
+               o->ManageOnlyPrivateIP = CfgGetBool(f, "ManageOnlyPrivateIP");\r
+       }\r
+       else\r
+       {\r
+               o->ManageOnlyPrivateIP = true;\r
+       }\r
+       if (CfgIsItem(f, "ManageOnlyLocalUnicastIPv6"))\r
+       {\r
+               o->ManageOnlyLocalUnicastIPv6 = CfgGetBool(f, "ManageOnlyLocalUnicastIPv6");\r
+       }\r
+       else\r
+       {\r
+               o->ManageOnlyLocalUnicastIPv6 = true;\r
+       }\r
+       if (CfgIsItem(f, "NoMacAddressLog"))\r
+       {\r
+               o->NoMacAddressLog = CfgGetBool(f, "NoMacAddressLog");\r
+       }\r
+       else\r
+       {\r
+               o->NoMacAddressLog = true;\r
+       }\r
+}\r
+\r
+// HUB_OPTION の書き込み\r
+void SiWriteHubOptionCfg(FOLDER *f, HUB_OPTION *o)\r
+{\r
+       char tmp[MAX_SIZE];\r
+       // 引数チェック\r
+       if (f == NULL || o == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       CfgAddInt(f, "MaxSession", o->MaxSession);\r
+       CfgAddBool(f, "NoArpPolling", o->NoArpPolling);\r
+       CfgAddBool(f, "NoIPv6AddrPolling", o->NoIPv6AddrPolling);\r
+       CfgAddBool(f, "NoIpTable", o->NoIpTable);\r
+       CfgAddBool(f, "NoEnum", o->NoEnum);\r
+       CfgAddBool(f, "FilterPPPoE", o->FilterPPPoE);\r
+       CfgAddBool(f, "FilterOSPF", o->FilterOSPF);\r
+       CfgAddBool(f, "FilterIPv4", o->FilterIPv4);\r
+       CfgAddBool(f, "FilterIPv6", o->FilterIPv6);\r
+       CfgAddBool(f, "FilterNonIP", o->FilterNonIP);\r
+       CfgAddBool(f, "NoIPv4PacketLog", o->NoIPv4PacketLog);\r
+       CfgAddBool(f, "NoIPv6PacketLog", o->NoIPv6PacketLog);\r
+       CfgAddBool(f, "FilterBPDU", o->FilterBPDU);\r
+       CfgAddBool(f, "NoIPv6DefaultRouterInRAWhenIPv6", o->NoIPv6DefaultRouterInRAWhenIPv6);\r
+       CfgAddBool(f, "NoMacAddressLog", o->NoMacAddressLog);\r
+       CfgAddBool(f, "ManageOnlyPrivateIP", o->ManageOnlyPrivateIP);\r
+       CfgAddBool(f, "ManageOnlyLocalUnicastIPv6", o->ManageOnlyLocalUnicastIPv6);\r
+       CfgAddBool(f, "DisableIPParsing", o->DisableIPParsing);\r
+       CfgAddBool(f, "YieldAfterStorePacket", o->YieldAfterStorePacket);\r
+       CfgAddBool(f, "NoSpinLockForPacketDelay", o->NoSpinLockForPacketDelay);\r
+       CfgAddInt(f, "BroadcastStormDetectionThreshold", o->BroadcastStormDetectionThreshold);\r
+       CfgAddInt(f, "ClientMinimumRequiredBuild", o->ClientMinimumRequiredBuild);\r
+       CfgAddInt(f, "RequiredClientId", o->RequiredClientId);\r
+       CfgAddBool(f, "NoManageVlanId", o->NoManageVlanId);\r
+       Format(tmp, sizeof(tmp), "0x%x", o->VlanTypeId);\r
+       CfgAddStr(f, "VlanTypeId", tmp);\r
+       if (o->FixForDLinkBPDU)\r
+       {\r
+               CfgAddBool(f, "FixForDLinkBPDU", o->FixForDLinkBPDU);\r
+       }\r
+       CfgAddBool(f, "NoLookBPDUBridgeId", o->NoLookBPDUBridgeId);\r
+}\r
+\r
+// ユーザーの書き込み\r
+void SiWriteUserCfg(FOLDER *f, USER *u)\r
+{\r
+       AUTHPASSWORD *password;\r
+       // 引数チェック\r
+       if (f == NULL || u == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Lock(u->lock);\r
+       {\r
+               CfgAddUniStr(f, "RealName", u->RealName);\r
+               CfgAddUniStr(f, "Note", u->Note);\r
+               if (u->Group != NULL)\r
+               {\r
+                       CfgAddStr(f, "GroupName", u->GroupName);\r
+               }\r
+               CfgAddInt64(f, "CreatedTime", u->CreatedTime);\r
+               CfgAddInt64(f, "UpdatedTime", u->UpdatedTime);\r
+               CfgAddInt64(f, "ExpireTime", u->ExpireTime);\r
+               CfgAddInt64(f, "LastLoginTime", u->LastLoginTime);\r
+               CfgAddInt(f, "NumLogin", u->NumLogin);\r
+               if (u->Policy != NULL)\r
+               {\r
+                       SiWritePolicyCfg(CfgCreateFolder(f, "Policy"), u->Policy, false);\r
+               }\r
+               SiWriteTraffic(f, "Traffic", u->Traffic);\r
+\r
+               CfgAddInt(f, "AuthType", u->AuthType);\r
+               if (u->AuthData != NULL)\r
+               {\r
+                       switch (u->AuthType)\r
+                       {\r
+                       case AUTHTYPE_ANONYMOUS:\r
+                               break;\r
+\r
+                       case AUTHTYPE_PASSWORD:\r
+                               password = (AUTHPASSWORD *)u->AuthData;\r
+                               CfgAddByte(f, "AuthPassword", password->HashedKey, sizeof(password->HashedKey));\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+       Unlock(u->lock);\r
+}\r
+\r
+// ユーザーの読み込み\r
+void SiLoadUserCfg(HUB *h, FOLDER *f)\r
+{\r
+       char *username;\r
+       wchar_t realname[MAX_SIZE];\r
+       wchar_t note[MAX_SIZE];\r
+       char groupname[MAX_SIZE];\r
+       FOLDER *pf;\r
+       UINT64 created_time;\r
+       UINT64 updated_time;\r
+       UINT64 expire_time;\r
+       UINT64 last_login_time;\r
+       UINT num_login;\r
+       POLICY p;\r
+       TRAFFIC t;\r
+       UINT authtype;\r
+       void *authdata;\r
+       X_SERIAL *serial = NULL;\r
+       UCHAR hashed_password[SHA1_SIZE];\r
+       USER *u;\r
+       USERGROUP *g;\r
+       // 引数チェック\r
+       if (h == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       username = f->Name;\r
+       CfgGetUniStr(f, "RealName", realname, sizeof(realname));\r
+       CfgGetUniStr(f, "Note", note, sizeof(note));\r
+       CfgGetStr(f, "GroupName", groupname, sizeof(groupname));\r
+\r
+       created_time = CfgGetInt64(f, "CreatedTime");\r
+       updated_time = CfgGetInt64(f, "UpdatedTime");\r
+       expire_time = CfgGetInt64(f, "ExpireTime");\r
+       last_login_time = CfgGetInt64(f, "LastLoginTime");\r
+       num_login = CfgGetInt(f, "NumLogin");\r
+       pf = CfgGetFolder(f, "Policy");\r
+       if (pf != NULL)\r
+       {\r
+               SiLoadPolicyCfg(&p, pf);\r
+       }\r
+       SiLoadTraffic(f, "Traffic", &t);\r
+\r
+       authtype = CfgGetInt(f, "AuthType");\r
+       authdata = NULL;\r
+\r
+       switch (authtype)\r
+       {\r
+       case AUTHTYPE_PASSWORD:\r
+               // 通常のパスワード認証\r
+               CfgGetByte(f, "AuthPassword", hashed_password, sizeof(hashed_password));\r
+               authdata = NewPasswordAuthDataRaw(hashed_password);\r
+               break;\r
+\r
+       default:\r
+               // それ以外の認証方法が指定された\r
+               authtype = AUTHTYPE_ANONYMOUS;\r
+               authdata = NULL;\r
+               break;\r
+       }\r
+\r
+       // ユーザーの追加\r
+       AcLock(h);\r
+       {\r
+               if (StrLen(groupname) > 0)\r
+               {\r
+                       g = AcGetGroup(h, groupname);\r
+               }\r
+               else\r
+               {\r
+                       g = NULL;\r
+               }\r
+\r
+               u = NewUser(username, realname, note, authtype, authdata);\r
+               if (u != NULL)\r
+               {\r
+                       if (g != NULL)\r
+                       {\r
+                               JoinUserToGroup(u, g);\r
+                       }\r
+\r
+                       SetUserTraffic(u, &t);\r
+\r
+                       if (pf != NULL)\r
+                       {\r
+                               SetUserPolicy(u, &p);\r
+                       }\r
+\r
+                       Lock(u->lock);\r
+                       {\r
+                               u->CreatedTime = created_time;\r
+                               u->UpdatedTime = updated_time;\r
+                               u->ExpireTime = expire_time;\r
+                               u->LastLoginTime = last_login_time;\r
+                               u->NumLogin = num_login;\r
+                       }\r
+                       Unlock(u->lock);\r
+\r
+                       AcAddUser(h, u);\r
+\r
+                       ReleaseUser(u);\r
+               }\r
+\r
+               if (g != NULL)\r
+               {\r
+                       ReleaseGroup(g);\r
+               }\r
+       }\r
+       AcUnlock(h);\r
+\r
+       if (serial != NULL)\r
+       {\r
+               FreeXSerial(serial);\r
+       }\r
+}\r
+\r
+// ユーザーリストの書き込み\r
+void SiWriteUserList(FOLDER *f, LIST *o)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || o == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(o);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(o);i++)\r
+               {\r
+                       USER *u = LIST_DATA(o, i);\r
+                       SiWriteUserCfg(CfgCreateFolder(f, u->Name), u);\r
+               }\r
+       }\r
+       UnlockList(o);\r
+}\r
+\r
+// ユーザーリストの読み込み\r
+void SiLoadUserList(HUB *h, FOLDER *f)\r
+{\r
+       TOKEN_LIST *t;\r
+       UINT i;\r
+       char *name;\r
+       // 引数チェック\r
+       if (f == NULL || h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       t = CfgEnumFolderToTokenList(f);\r
+\r
+       for (i = 0;i < t->NumTokens;i++)\r
+       {\r
+               FOLDER *ff;\r
+               name = t->Token[i];\r
+               ff = CfgGetFolder(f, name);\r
+               SiLoadUserCfg(h, ff);\r
+       }\r
+\r
+       FreeToken(t);\r
+}\r
+\r
+// グループ情報の書き込み\r
+void SiWriteGroupCfg(FOLDER *f, USERGROUP *g)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || g == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Lock(g->lock);\r
+       {\r
+               CfgAddUniStr(f, "RealName", g->RealName);\r
+               CfgAddUniStr(f, "Note", g->Note);\r
+               if (g->Policy != NULL)\r
+               {\r
+                       SiWritePolicyCfg(CfgCreateFolder(f, "Policy"), g->Policy, false);\r
+               }\r
+               SiWriteTraffic(f, "Traffic", g->Traffic);\r
+       }\r
+       Unlock(g->lock);\r
+}\r
+\r
+// グループ情報の読み込み\r
+void SiLoadGroupCfg(HUB *h, FOLDER *f)\r
+{\r
+       wchar_t realname[MAX_SIZE];\r
+       wchar_t note[MAX_SIZE];\r
+       char *name;\r
+       FOLDER *pf;\r
+       POLICY p;\r
+       TRAFFIC t;\r
+       USERGROUP *g;\r
+       // 引数チェック\r
+       if (h == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       name = f->Name;\r
+\r
+       CfgGetUniStr(f, "RealName", realname, sizeof(realname));\r
+       CfgGetUniStr(f, "Note", note, sizeof(note));\r
+\r
+       pf = CfgGetFolder(f, "Policy");\r
+       if (pf != NULL)\r
+       {\r
+               SiLoadPolicyCfg(&p, pf);\r
+       }\r
+\r
+       SiLoadTraffic(f, "Traffic", &t);\r
+\r
+       g = NewGroup(name, realname, note);\r
+       if (g == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (pf != NULL)\r
+       {\r
+               SetGroupPolicy(g, &p);\r
+       }\r
+\r
+       SetGroupTraffic(g, &t);\r
+\r
+       AcLock(h);\r
+       {\r
+               AcAddGroup(h, g);\r
+       }\r
+       AcUnlock(h);\r
+\r
+       ReleaseGroup(g);\r
+}\r
+\r
+// グループリストの書き込み\r
+void SiWriteGroupList(FOLDER *f, LIST *o)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || o == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(o);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(o);i++)\r
+               {\r
+                       USERGROUP *g = LIST_DATA(o, i);\r
+                       SiWriteGroupCfg(CfgCreateFolder(f, g->Name), g);\r
+               }\r
+       }\r
+       UnlockList(o);\r
+}\r
+\r
+// グループリストの読み込み\r
+void SiLoadGroupList(HUB *h, FOLDER *f)\r
+{\r
+       TOKEN_LIST *t;\r
+       UINT i;\r
+       char *name;\r
+       // 引数チェック\r
+       if (f == NULL || h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       t = CfgEnumFolderToTokenList(f);\r
+\r
+       for (i = 0;i < t->NumTokens;i++)\r
+       {\r
+               name = t->Token[i];\r
+               SiLoadGroupCfg(h, CfgGetFolder(f, name));\r
+       }\r
+\r
+       FreeToken(t);\r
+}\r
+\r
+// 無効な証明書リストの書き込み\r
+void SiWriteCrlList(FOLDER *f, LIST *o)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || o == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(o);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(o);i++)\r
+               {\r
+                       char name[MAX_SIZE];\r
+                       CRL *crl = LIST_DATA(o, i);\r
+                       FOLDER *ff;\r
+                       NAME *n;\r
+\r
+                       Format(name, sizeof(name), "Crl%u", i);\r
+\r
+                       ff = CfgCreateFolder(f, name);\r
+                       n = crl->Name;\r
+\r
+                       if (UniIsEmptyStr(n->CommonName) == false)\r
+                       {\r
+                               CfgAddUniStr(ff, "CommonName", n->CommonName);\r
+                       }\r
+\r
+                       if (UniIsEmptyStr(n->Organization) == false)\r
+                       {\r
+                               CfgAddUniStr(ff, "Organization", n->Organization);\r
+                       }\r
+\r
+                       if (UniIsEmptyStr(n->Unit) == false)\r
+                       {\r
+                               CfgAddUniStr(ff, "Unit", n->Unit);\r
+                       }\r
+\r
+                       if (UniIsEmptyStr(n->Country) == false)\r
+                       {\r
+                               CfgAddUniStr(ff, "Country", n->Country);\r
+                       }\r
+\r
+                       if (UniIsEmptyStr(n->State) == false)\r
+                       {\r
+                               CfgAddUniStr(ff, "State", n->State);\r
+                       }\r
+\r
+                       if (UniIsEmptyStr(n->Local) == false)\r
+                       {\r
+                               CfgAddUniStr(ff, "Local", n->Local);\r
+                       }\r
+\r
+                       if (IsZero(crl->DigestMD5, MD5_SIZE) == false)\r
+                       {\r
+                               char tmp[MAX_SIZE];\r
+\r
+                               BinToStr(tmp, sizeof(tmp), crl->DigestMD5, MD5_SIZE);\r
+                               CfgAddStr(ff, "DigestMD5", tmp);\r
+                       }\r
+\r
+                       if (IsZero(crl->DigestSHA1, SHA1_SIZE) == false)\r
+                       {\r
+                               char tmp[MAX_SIZE];\r
+\r
+                               BinToStr(tmp, sizeof(tmp), crl->DigestSHA1, SHA1_SIZE);\r
+                               CfgAddStr(ff, "DigestSHA1", tmp);\r
+                       }\r
+\r
+                       if (crl->Serial != NULL)\r
+                       {\r
+                               char tmp[MAX_SIZE];\r
+\r
+                               BinToStr(tmp, sizeof(tmp), crl->Serial->data, crl->Serial->size);\r
+                               CfgAddStr(ff, "Serial", tmp);\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(o);\r
+}\r
+\r
+// 無効な証明書リストの読み込み\r
+void SiLoadCrlList(LIST *o, FOLDER *f)\r
+{\r
+       // 引数チェック\r
+       if (o == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(o);\r
+       {\r
+               UINT i;\r
+               TOKEN_LIST *t;\r
+\r
+               t = CfgEnumFolderToTokenList(f);\r
+\r
+               for (i = 0;i < t->NumTokens;i++)\r
+               {\r
+                       CRL *crl;\r
+                       FOLDER *ff = CfgGetFolder(f, t->Token[i]);\r
+                       wchar_t cn[MAX_SIZE], org[MAX_SIZE], u[MAX_SIZE], c[MAX_SIZE],\r
+                               st[MAX_SIZE], l[MAX_SIZE];\r
+                       char tmp[MAX_SIZE];\r
+\r
+                       if (ff != NULL)\r
+                       {\r
+                               BUF *b;\r
+\r
+                               crl = ZeroMalloc(sizeof(CRL));\r
+\r
+                               CfgGetUniStr(ff, "CommonName", cn, sizeof(cn));\r
+                               CfgGetUniStr(ff, "Organization", org, sizeof(org));\r
+                               CfgGetUniStr(ff, "Unit", u, sizeof(u));\r
+                               CfgGetUniStr(ff, "Country", c, sizeof(c));\r
+                               CfgGetUniStr(ff, "State", st, sizeof(st));\r
+                               CfgGetUniStr(ff, "Local", l, sizeof(l));\r
+\r
+                               crl->Name = NewName(cn, org, u, c, st, l);\r
+\r
+                               if (CfgGetStr(ff, "Serial", tmp, sizeof(tmp)))\r
+                               {\r
+                                       b = StrToBin(tmp);\r
+\r
+                                       if (b != NULL)\r
+                                       {\r
+                                               if (b->Size >= 1)\r
+                                               {\r
+                                                       crl->Serial = NewXSerial(b->Buf, b->Size);\r
+                                               }\r
+\r
+                                               FreeBuf(b);\r
+                                       }\r
+                               }\r
+\r
+                               if (CfgGetStr(ff, "DigestMD5", tmp, sizeof(tmp)))\r
+                               {\r
+                                       b = StrToBin(tmp);\r
+\r
+                                       if (b != NULL)\r
+                                       {\r
+                                               if (b->Size == MD5_SIZE)\r
+                                               {\r
+                                                       Copy(crl->DigestMD5, b->Buf, MD5_SIZE);\r
+                                               }\r
+\r
+                                               FreeBuf(b);\r
+                                       }\r
+                               }\r
+\r
+                               if (CfgGetStr(ff, "DigestSHA1", tmp, sizeof(tmp)))\r
+                               {\r
+                                       b = StrToBin(tmp);\r
+\r
+                                       if (b != NULL)\r
+                                       {\r
+                                               if (b->Size == SHA1_SIZE)\r
+                                               {\r
+                                                       Copy(crl->DigestSHA1, b->Buf, SHA1_SIZE);\r
+                                               }\r
+\r
+                                               FreeBuf(b);\r
+                                       }\r
+                               }\r
+\r
+                               Insert(o, crl);\r
+                       }\r
+               }\r
+\r
+               FreeToken(t);\r
+       }\r
+       UnlockList(o);\r
+}\r
+\r
+// 証明書リストの書き込み\r
+void SiWriteCertList(FOLDER *f, LIST *o)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || o == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(o);\r
+       {\r
+               UINT i;\r
+               X *x;\r
+               for (i = 0;i < LIST_NUM(o);i++)\r
+               {\r
+                       char name[MAX_SIZE];\r
+                       BUF *b;\r
+                       x = LIST_DATA(o, i);\r
+                       Format(name, sizeof(name), "Cert%u", i);\r
+                       b = XToBuf(x, false);\r
+                       if (b != NULL)\r
+                       {\r
+                               CfgAddBuf(CfgCreateFolder(f, name), "X509", b);\r
+                               FreeBuf(b);\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(o);\r
+}\r
+\r
+// 証明書リストの読み込み\r
+void SiLoadCertList(LIST *o, FOLDER *f)\r
+{\r
+       // 引数チェック\r
+       if (o == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(o);\r
+       {\r
+               UINT i;\r
+               TOKEN_LIST *t;\r
+\r
+               t = CfgEnumFolderToTokenList(f);\r
+\r
+               for (i = 0;i < t->NumTokens;i++)\r
+               {\r
+                       FOLDER *ff = CfgGetFolder(f, t->Token[i]);\r
+                       BUF *b;\r
+\r
+                       b = CfgGetBuf(ff, "X509");\r
+                       if (b != NULL)\r
+                       {\r
+                               X *x = BufToX(b, false);\r
+                               if (x != NULL)\r
+                               {\r
+                                       Insert(o, x);\r
+                               }\r
+                               FreeBuf(b);\r
+                       }\r
+               }\r
+\r
+               FreeToken(t);\r
+       }\r
+       UnlockList(o);\r
+}\r
+\r
+// データベースの書き込み\r
+void SiWriteHubDb(FOLDER *f, HUBDB *db)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || db == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       SiWriteUserList(CfgCreateFolder(f, "UserList"), db->UserList);\r
+       SiWriteGroupList(CfgCreateFolder(f, "GroupList"), db->GroupList);\r
+       SiWriteCertList(CfgCreateFolder(f, "CertList"), db->RootCertList);\r
+       SiWriteCrlList(CfgCreateFolder(f, "CrlList"), db->CrlList);\r
+}\r
+\r
+// データベースの読み込み\r
+void SiLoadHubDb(HUB *h, FOLDER *f)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       SiLoadGroupList(h, CfgGetFolder(f, "GroupList"));\r
+       SiLoadUserList(h, CfgGetFolder(f, "UserList"));\r
+\r
+       if (h->HubDb != NULL)\r
+       {\r
+               SiLoadCertList(h->HubDb->RootCertList, CfgGetFolder(f, "CertList"));\r
+               SiLoadCrlList(h->HubDb->CrlList, CfgGetFolder(f, "CrlList"));\r
+       }\r
+}\r
+\r
+// 仮想 HUB 設定の書き込み\r
+void SiWriteHubCfg(FOLDER *f, HUB *h)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // パスワード\r
+       CfgAddByte(f, "HashedPassword", h->HashedPassword, sizeof(h->HashedPassword));\r
+       CfgAddByte(f, "SecurePassword", h->SecurePassword, sizeof(h->SecurePassword));\r
+\r
+       // Online / Offline フラグ\r
+       if (h->Cedar->Bridge == false)\r
+       {\r
+               CfgAddBool(f, "Online", (h->Offline && (h->HubIsOnlineButHalting == false)) ? false : true);\r
+       }\r
+\r
+       // トラフィック情報\r
+       SiWriteTraffic(f, "Traffic", h->Traffic);\r
+\r
+       // HUB オプション\r
+       SiWriteHubOptionCfg(CfgCreateFolder(f, "Option"), h->Option);\r
+\r
+       // メッセージ\r
+       {\r
+               FOLDER *folder = CfgCreateFolder(f, "Message");\r
+\r
+               if (IsEmptyUniStr(h->Msg) == false)\r
+               {\r
+                       CfgAddUniStr(folder, "MessageText", h->Msg);\r
+               }\r
+       }\r
+\r
+       // HUB_LOG\r
+       SiWriteHubLogCfg(CfgCreateFolder(f, "LogSetting"), &h->LogSetting);\r
+\r
+       if (h->Type == HUB_TYPE_STANDALONE)\r
+       {\r
+               // リンクリスト\r
+               SiWriteHubLinks(CfgCreateFolder(f, "CascadeList"), h);\r
+       }\r
+\r
+       if (h->Type != HUB_TYPE_FARM_STATIC)\r
+       {\r
+               if (GetServerCapsBool(h->Cedar->Server, "b_support_securenat"))\r
+               {\r
+                       // SecureNAT\r
+                       SiWriteSecureNAT(h, CfgCreateFolder(f, "SecureNAT"));\r
+               }\r
+       }\r
+\r
+       // アクセスリスト\r
+       SiWriteHubAccessLists(CfgCreateFolder(f, "AccessList"), h);\r
+\r
+       // 管理オプション\r
+       SiWriteHubAdminOptions(CfgCreateFolder(f, "AdminOption"), h);\r
+\r
+       // HUB の種類\r
+       CfgAddInt(f, "Type", h->Type);\r
+\r
+       // データベース\r
+       if (h->Cedar->Bridge == false)\r
+       {\r
+               SiWriteHubDb(CfgCreateFolder(f, "SecurityAccountDatabase"), h->HubDb);\r
+       }\r
+\r
+       // 利用状況\r
+       CfgAddInt64(f, "LastCommTime", h->LastCommTime);\r
+       CfgAddInt64(f, "LastLoginTime", h->LastLoginTime);\r
+       CfgAddInt64(f, "CreatedTime", h->CreatedTime);\r
+       CfgAddInt(f, "NumLogin", h->NumLogin);\r
+}\r
+\r
+// ログオプションの読み込み\r
+void SiLoadHubLogCfg(HUB_LOG *g, FOLDER *f)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || g == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(g, sizeof(HUB_LOG));\r
+       g->SaveSecurityLog = CfgGetBool(f, "SaveSecurityLog");\r
+       g->SecurityLogSwitchType = CfgGetInt(f, "SecurityLogSwitchType");\r
+       g->SavePacketLog = CfgGetBool(f, "SavePacketLog");\r
+       g->PacketLogSwitchType = CfgGetInt(f, "PacketLogSwitchType");\r
+\r
+       g->PacketLogConfig[PACKET_LOG_TCP_CONN] = CfgGetInt(f, "PACKET_LOG_TCP_CONN");\r
+       g->PacketLogConfig[PACKET_LOG_TCP] = CfgGetInt(f, "PACKET_LOG_TCP");\r
+       g->PacketLogConfig[PACKET_LOG_DHCP] = CfgGetInt(f, "PACKET_LOG_DHCP");\r
+       g->PacketLogConfig[PACKET_LOG_UDP] = CfgGetInt(f, "PACKET_LOG_UDP");\r
+       g->PacketLogConfig[PACKET_LOG_ICMP] = CfgGetInt(f, "PACKET_LOG_ICMP");\r
+       g->PacketLogConfig[PACKET_LOG_IP] = CfgGetInt(f, "PACKET_LOG_IP");\r
+       g->PacketLogConfig[PACKET_LOG_ARP] = CfgGetInt(f, "PACKET_LOG_ARP");\r
+       g->PacketLogConfig[PACKET_LOG_ETHERNET] = CfgGetInt(f, "PACKET_LOG_ETHERNET");\r
+}\r
+\r
+// ログオプションの書き込み\r
+void SiWriteHubLogCfg(FOLDER *f, HUB_LOG *g)\r
+{\r
+       SiWriteHubLogCfgEx(f, g, false);\r
+}\r
+void SiWriteHubLogCfgEx(FOLDER *f, HUB_LOG *g, bool el_mode)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || g == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (el_mode == false)\r
+       {\r
+               CfgAddBool(f, "SaveSecurityLog", g->SaveSecurityLog);\r
+               CfgAddInt(f, "SecurityLogSwitchType", g->SecurityLogSwitchType);\r
+               CfgAddBool(f, "SavePacketLog", g->SavePacketLog);\r
+       }\r
+\r
+       CfgAddInt(f, "PacketLogSwitchType", g->PacketLogSwitchType);\r
+\r
+       CfgAddInt(f, "PACKET_LOG_TCP_CONN", g->PacketLogConfig[PACKET_LOG_TCP_CONN]);\r
+       CfgAddInt(f, "PACKET_LOG_TCP", g->PacketLogConfig[PACKET_LOG_TCP]);\r
+       CfgAddInt(f, "PACKET_LOG_DHCP", g->PacketLogConfig[PACKET_LOG_DHCP]);\r
+       CfgAddInt(f, "PACKET_LOG_UDP", g->PacketLogConfig[PACKET_LOG_UDP]);\r
+       CfgAddInt(f, "PACKET_LOG_ICMP", g->PacketLogConfig[PACKET_LOG_ICMP]);\r
+       CfgAddInt(f, "PACKET_LOG_IP", g->PacketLogConfig[PACKET_LOG_IP]);\r
+       CfgAddInt(f, "PACKET_LOG_ARP", g->PacketLogConfig[PACKET_LOG_ARP]);\r
+       CfgAddInt(f, "PACKET_LOG_ETHERNET", g->PacketLogConfig[PACKET_LOG_ETHERNET]);\r
+}\r
+\r
+// 仮想 HUB 設定の読み込み\r
+void SiLoadHubCfg(SERVER *s, FOLDER *f, char *name)\r
+{\r
+       HUB *h;\r
+       CEDAR *c;\r
+       HUB_OPTION o;\r
+       bool online;\r
+       UINT hub_old_type = 0;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL || name == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       c = s->Cedar;\r
+\r
+       // オプションの取得\r
+       Zero(&o, sizeof(o));\r
+       SiLoadHubOptionCfg(CfgGetFolder(f, "Option"), &o);\r
+\r
+       // HUB の作成\r
+       h = NewHub(c, name, &o);\r
+       if (h != NULL)\r
+       {\r
+               HUB_LOG g;\r
+\r
+               // パスワード\r
+               if (CfgGetByte(f, "HashedPassword", h->HashedPassword, sizeof(h->HashedPassword)) != sizeof(h->HashedPassword))\r
+               {\r
+                       Hash(h->HashedPassword, "", 0, true);\r
+               }\r
+               if (CfgGetByte(f, "SecurePassword", h->SecurePassword, sizeof(h->SecurePassword)) != sizeof(h->SecurePassword))\r
+               {\r
+                       HashPassword(h->SecurePassword, ADMINISTRATOR_USERNAME, "");\r
+               }\r
+\r
+               // ログ設定\r
+               Zero(&g, sizeof(g));\r
+               SiLoadHubLogCfg(&g, CfgGetFolder(f, "LogSetting"));\r
+               SetHubLogSetting(h, &g);\r
+\r
+               // Online / Offline フラグ\r
+               if (h->Cedar->Bridge == false)\r
+               {\r
+                       online = CfgGetBool(f, "Online");\r
+               }\r
+               else\r
+               {\r
+                       online = true;\r
+               }\r
+\r
+               // トラフィック情報\r
+               SiLoadTraffic(f, "Traffic", h->Traffic);\r
+\r
+               // アクセスリスト\r
+               SiLoadHubAccessLists(h, CfgGetFolder(f, "AccessList"));\r
+\r
+               // HUB の種類\r
+               hub_old_type = h->Type = CfgGetInt(f, "Type");\r
+               if (s->ServerType == SERVER_TYPE_STANDALONE)\r
+               {\r
+                       if (h->Type != HUB_TYPE_STANDALONE)\r
+                       {\r
+                               // サーバーがスタンドアロンの場合は HUB の種類をスタンドアロンに変換する\r
+                               h->Type = HUB_TYPE_STANDALONE;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       if (h->Type == HUB_TYPE_STANDALONE)\r
+                       {\r
+                               // サーバーがファームコントローラの場合は HUB の種類をファーム対応にする\r
+                               h->Type = HUB_TYPE_FARM_DYNAMIC;\r
+                       }\r
+               }\r
+\r
+               // メッセージ\r
+               {\r
+                       FOLDER *folder = CfgGetFolder(f, "Message");\r
+                       if (folder != NULL)\r
+                       {\r
+                               wchar_t *tmp = Malloc(sizeof(wchar_t) * (HUB_MAXMSG_LEN + 1));\r
+                               if (CfgGetUniStr(folder, "MessageText", tmp, sizeof(wchar_t) * (HUB_MAXMSG_LEN + 1)))\r
+                               {\r
+                                       SetHubMsg(h, tmp);\r
+                               }\r
+                               Free(tmp);\r
+                       }\r
+               }\r
+\r
+               // リンクリスト\r
+               if (h->Type == HUB_TYPE_STANDALONE)\r
+               {\r
+                       // リンクリストはスタンドアロン HUB の場合しか使用しない\r
+                       SiLoadHubLinks(h, CfgGetFolder(f, "CascadeList"));\r
+               }\r
+\r
+               // SecureNAT\r
+               if (GetServerCapsBool(h->Cedar->Server, "b_support_securenat"))\r
+               {\r
+                       if (h->Type == HUB_TYPE_STANDALONE || h->Type == HUB_TYPE_FARM_DYNAMIC)\r
+                       {\r
+                               // SecureNAT はスタンドアロン HUB かダイナミック HUB の場合しか使用しない\r
+                               SiLoadSecureNAT(h, CfgGetFolder(f, "SecureNAT"));\r
+\r
+                               if (h->Type != HUB_TYPE_STANDALONE && h->Cedar != NULL && h->Cedar->Server != NULL &&\r
+                                       h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)\r
+                               {\r
+                                       NiClearUnsupportedVhOptionForDynamicHub(h->SecureNATOption,\r
+                                               hub_old_type == HUB_TYPE_STANDALONE);\r
+                               }\r
+\r
+                       }\r
+               }\r
+\r
+               // 管理オプション\r
+               SiLoadHubAdminOptions(h, CfgGetFolder(f, "AdminOption"));\r
+\r
+               // データベース\r
+               if (h->Cedar->Bridge == false)\r
+               {\r
+                       SiLoadHubDb(h, CfgGetFolder(f, "SecurityAccountDatabase"));\r
+               }\r
+\r
+               // 利用状況\r
+               h->LastCommTime = CfgGetInt64(f, "LastCommTime");\r
+               if (h->LastCommTime == 0)\r
+               {\r
+                       h->LastCommTime = SystemTime64();\r
+               }\r
+               h->LastLoginTime = CfgGetInt64(f, "LastLoginTime");\r
+               if (h->LastLoginTime == 0)\r
+               {\r
+                       h->LastLoginTime = SystemTime64();\r
+               }\r
+               h->CreatedTime = CfgGetInt64(f, "CreatedTime");\r
+               h->NumLogin = CfgGetInt(f, "NumLogin");\r
+\r
+               // HUB の動作開始\r
+               AddHub(c, h);\r
+\r
+               if (online)\r
+               {\r
+                       h->Offline = true;\r
+                       SetHubOnline(h);\r
+               }\r
+               else\r
+               {\r
+                       h->Offline = false;\r
+                       SetHubOffline(h);\r
+               }\r
+\r
+               WaitLogFlush(h->SecurityLogger);\r
+               WaitLogFlush(h->PacketLogger);\r
+\r
+               ReleaseHub(h);\r
+       }\r
+}\r
+\r
+// SecureNAT 設定の読み込み\r
+void SiLoadSecureNAT(HUB *h, FOLDER *f)\r
+{\r
+       VH_OPTION o;\r
+       // 引数チェック\r
+       if (h == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // VH_OPTION を読み込む\r
+       NiLoadVhOptionEx(&o, f);\r
+\r
+       // VH_OPTION をセット\r
+       Copy(h->SecureNATOption, &o, sizeof(VH_OPTION));\r
+\r
+       EnableSecureNAT(h, CfgGetBool(f, "Disabled") ? false : true);\r
+}\r
+\r
+// 仮想レイヤ 3 スイッチ設定の読み込み\r
+void SiLoadL3SwitchCfg(L3SW *sw, FOLDER *f)\r
+{\r
+       UINT i;\r
+       FOLDER *if_folder, *table_folder;\r
+       TOKEN_LIST *t;\r
+       bool active = false;\r
+       // 引数チェック\r
+       if (sw == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       active = CfgGetBool(f, "Active");\r
+\r
+       // インターフェイスリスト\r
+       if_folder = CfgGetFolder(f, "InterfaceList");\r
+       if (if_folder != NULL)\r
+       {\r
+               t = CfgEnumFolderToTokenList(if_folder);\r
+               if (t != NULL)\r
+               {\r
+                       for (i = 0;i < t->NumTokens;i++)\r
+                       {\r
+                               FOLDER *ff = CfgGetFolder(if_folder, t->Token[i]);\r
+                               char name[MAX_HUBNAME_LEN + 1];\r
+                               UINT ip, subnet;\r
+\r
+                               CfgGetStr(ff, "HubName", name, sizeof(name));\r
+                               ip = CfgGetIp32(ff, "IpAddress");\r
+                               subnet = CfgGetIp32(ff, "SubnetMask");\r
+\r
+                               L3AddIf(sw, name, ip, subnet);\r
+                       }\r
+                       FreeToken(t);\r
+               }\r
+       }\r
+\r
+       // ルーティングテーブル\r
+       table_folder = CfgGetFolder(f, "RoutingTable");\r
+       if (table_folder != NULL)\r
+       {\r
+               t = CfgEnumFolderToTokenList(table_folder);\r
+               if (t != NULL)\r
+               {\r
+                       for (i = 0;i < t->NumTokens;i++)\r
+                       {\r
+                               FOLDER *ff = CfgGetFolder(table_folder, t->Token[i]);\r
+                               L3TABLE tbl;\r
+\r
+                               Zero(&tbl, sizeof(tbl));\r
+                               tbl.NetworkAddress = CfgGetIp32(ff, "NetworkAddress");\r
+                               tbl.SubnetMask = CfgGetIp32(ff, "SubnetMask");\r
+                               tbl.GatewayAddress = CfgGetIp32(ff, "GatewayAddress");\r
+                               tbl.Metric = CfgGetInt(ff, "Metric");\r
+\r
+                               L3AddTable(sw, &tbl);\r
+                       }\r
+                       FreeToken(t);\r
+               }\r
+       }\r
+\r
+       if (active)\r
+       {\r
+               L3SwStart(sw);\r
+       }\r
+}\r
+\r
+// 仮想レイヤ 3 スイッチ設定の書き込み\r
+void SiWriteL3SwitchCfg(FOLDER *f, L3SW *sw)\r
+{\r
+       UINT i;\r
+       FOLDER *if_folder, *table_folder;\r
+       char tmp[MAX_SIZE];\r
+       // 引数チェック\r
+       if (f == NULL || sw == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 動作フラグ\r
+       CfgAddBool(f, "Active", sw->Active);\r
+\r
+       // インターフェイスリスト\r
+       if_folder = CfgCreateFolder(f, "InterfaceList");\r
+       for (i = 0;i < LIST_NUM(sw->IfList);i++)\r
+       {\r
+               L3IF *e = LIST_DATA(sw->IfList, i);\r
+               FOLDER *ff;\r
+\r
+               Format(tmp, sizeof(tmp), "Interface%u", i);\r
+               ff = CfgCreateFolder(if_folder, tmp);\r
+\r
+               CfgAddStr(ff, "HubName", e->HubName);\r
+               CfgAddIp32(ff, "IpAddress", e->IpAddress);\r
+               CfgAddIp32(ff, "SubnetMask", e->SubnetMask);\r
+       }\r
+\r
+       // ルーティングテーブル\r
+       table_folder = CfgCreateFolder(f, "RoutingTable");\r
+       for (i = 0;i < LIST_NUM(sw->TableList);i++)\r
+       {\r
+               L3TABLE *e = LIST_DATA(sw->TableList, i);\r
+               FOLDER *ff;\r
+\r
+               Format(tmp, sizeof(tmp), "Entry%u", i);\r
+               ff = CfgCreateFolder(table_folder, tmp);\r
+\r
+               CfgAddIp32(ff, "NetworkAddress", e->NetworkAddress);\r
+               CfgAddIp32(ff, "SubnetMask", e->SubnetMask);\r
+               CfgAddIp32(ff, "GatewayAddress", e->GatewayAddress);\r
+               CfgAddInt(ff, "Metric", e->Metric);\r
+       }\r
+}\r
+\r
+// 仮想レイヤ 3 スイッチ一覧の読み込み\r
+void SiLoadL3Switchs(SERVER *s, FOLDER *f)\r
+{\r
+       UINT i;\r
+       TOKEN_LIST *t;\r
+       CEDAR *c;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+       c = s->Cedar;\r
+\r
+       t = CfgEnumFolderToTokenList(f);\r
+       if (t != NULL)\r
+       {\r
+               for (i = 0;i < t->NumTokens;i++)\r
+               {\r
+                       char *name = t->Token[i];\r
+                       L3SW *sw = L3AddSw(c, name);\r
+\r
+                       SiLoadL3SwitchCfg(sw, CfgGetFolder(f, name));\r
+\r
+                       ReleaseL3Sw(sw);\r
+               }\r
+       }\r
+       FreeToken(t);\r
+}\r
+\r
+// 仮想レイヤ 3 スイッチ一覧の書き込み\r
+void SiWriteL3Switchs(FOLDER *f, SERVER *s)\r
+{\r
+       UINT i;\r
+       FOLDER *folder;\r
+       CEDAR *c;\r
+       // 引数チェック\r
+       if (f == NULL || s == NULL)\r
+       {\r
+               return;\r
+       }\r
+       c = s->Cedar;\r
+\r
+       LockList(c->L3SwList);\r
+       {\r
+               for (i = 0;i < LIST_NUM(c->L3SwList);i++)\r
+               {\r
+                       L3SW *sw = LIST_DATA(c->L3SwList, i);\r
+\r
+                       Lock(sw->lock);\r
+                       {\r
+                               folder = CfgCreateFolder(f, sw->Name);\r
+\r
+                               SiWriteL3SwitchCfg(folder, sw);\r
+                       }\r
+                       Unlock(sw->lock);\r
+               }\r
+       }\r
+       UnlockList(c->L3SwList);\r
+}\r
+\r
+// ライセンス一覧の書き込み\r
+void SiWriteLicenseManager(FOLDER *f, SERVER *s)\r
+{\r
+       LICENSE_SYSTEM *ss;\r
+       // 引数チェック\r
+       if (f == NULL || s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       ss = s->LicenseSystem;\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(ss->LicenseList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(ss->LicenseList);i++)\r
+               {\r
+                       LICENSE *e = LIST_DATA(ss->LicenseList, i);\r
+                       char name[MAX_SIZE];\r
+                       FOLDER *ff;\r
+\r
+                       Format(name, sizeof(name), "License%u", i);\r
+                       ff = CfgCreateFolder(f, name);\r
+                       CfgAddStr(ff, "LicenseKey", e->LicenseKeyStr);\r
+                       CfgAddInt(ff, "LicenseType", e->ProductId);\r
+               }\r
+       }\r
+       UnlockList(ss->LicenseList);\r
+}\r
+\r
+// ライセンス一覧の読み込み\r
+void SiLoadLicenseManager(SERVER *s, FOLDER *f)\r
+{\r
+       UINT i;\r
+       TOKEN_LIST *t;\r
+       CEDAR *c;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+       c = s->Cedar;\r
+\r
+       t = CfgEnumFolderToTokenList(f);\r
+       if (t != NULL)\r
+       {\r
+               for (i = 0;i < t->NumTokens;i++)\r
+               {\r
+                       char *str = t->Token[i];\r
+                       FOLDER *ff = CfgGetFolder(f, str);\r
+\r
+                       if (ff != NULL)\r
+                       {\r
+                               UINT product_id = CfgGetInt(ff, "LicenseType");\r
+                               char key[MAX_SIZE];\r
+\r
+                               if (CfgGetStr(ff, "LicenseKey", key, sizeof(key)))\r
+                               {\r
+                                       // ライセンス登録\r
+                                       //LiInputLicenseKeyEx(c, s->LicenseSystem, key, product_id, NULL);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       FreeToken(t);\r
+\r
+       DestroyServerCapsCache(s);\r
+}\r
+\r
+// 仮想 HUB 一覧の書き込み\r
+void SiWriteHubs(FOLDER *f, SERVER *s)\r
+{\r
+       UINT i;\r
+       FOLDER *hub_folder;\r
+       CEDAR *c;\r
+       UINT num;\r
+       HUB **hubs;\r
+       // 引数チェック\r
+       if (f == NULL || s == NULL)\r
+       {\r
+               return;\r
+       }\r
+       c = s->Cedar;\r
+\r
+       LockList(c->HubList);\r
+       {\r
+               hubs = ToArray(c->HubList);\r
+               num = LIST_NUM(c->HubList);\r
+\r
+               for (i = 0;i < num;i++)\r
+               {\r
+                       AddRef(hubs[i]->ref);\r
+               }\r
+       }\r
+       UnlockList(c->HubList);\r
+\r
+       for (i = 0;i < num;i++)\r
+       {\r
+               HUB *h = hubs[i];\r
+\r
+               Lock(h->lock);\r
+               {\r
+                       hub_folder = CfgCreateFolder(f, h->Name);\r
+                       SiWriteHubCfg(hub_folder, h);\r
+               }\r
+               Unlock(h->lock);\r
+\r
+               ReleaseHub(h);\r
+\r
+               if ((i % 30) == 1)\r
+               {\r
+                       YieldCpu();\r
+               }\r
+       }\r
+\r
+       Free(hubs);\r
+}\r
+\r
+// 仮想 HUB 一覧の読み込み\r
+void SiLoadHubs(SERVER *s, FOLDER *f)\r
+{\r
+       UINT i;\r
+       FOLDER *hub_folder;\r
+       CEDAR *c;\r
+       TOKEN_LIST *t;\r
+       bool b = false;\r
+       // 引数チェック\r
+       if (f == NULL || s == NULL)\r
+       {\r
+               return;\r
+       }\r
+       c = s->Cedar;\r
+\r
+       t = CfgEnumFolderToTokenList(f);\r
+       for (i = 0;i < t->NumTokens;i++)\r
+       {\r
+               char *name = t->Token[i];\r
+               if (s->Cedar->Bridge)\r
+               {\r
+                       if (StrCmpi(name, SERVER_DEFAULT_BRIDGE_NAME) == 0)\r
+                       {\r
+                               // Bridge の場合は "BRIDGE" という名前の仮想 HUB の設定\r
+                               // しか読み込まない\r
+                               b = true;\r
+                       }\r
+                       else\r
+                       {\r
+                               continue;\r
+                       }\r
+               }\r
+               hub_folder = CfgGetFolder(f, name);\r
+               if (hub_folder != NULL)\r
+               {\r
+                       SiLoadHubCfg(s, hub_folder, name);\r
+               }\r
+       }\r
+       FreeToken(t);\r
+\r
+       if (s->Cedar->Bridge && b == false)\r
+       {\r
+               // "BRIDGE" という名前の仮想 HUB の設定が存在しない場合は新たに作成する\r
+               SiInitDefaultHubList(s);\r
+       }\r
+}\r
+\r
+// サーバー固有の設定の読み込み\r
+void SiLoadServerCfg(SERVER *s, FOLDER *f)\r
+{\r
+       BUF *b;\r
+       CEDAR *c;\r
+       char tmp[MAX_SIZE];\r
+       X *x = NULL;\r
+       K *k = NULL;\r
+       bool cluster_allowed = false;\r
+       UINT num_connections_per_ip = 0;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 保存間隔関係\r
+       s->AutoSaveConfigSpan = CfgGetInt(f, "AutoSaveConfigSpan") * 1000;\r
+       if (s->AutoSaveConfigSpan == 0)\r
+       {\r
+               s->AutoSaveConfigSpan = SERVER_FILE_SAVE_INTERVAL_DEFAULT;\r
+       }\r
+       else\r
+       {\r
+               s->AutoSaveConfigSpan = MAKESURE(s->AutoSaveConfigSpan, SERVER_FILE_SAVE_INTERVAL_MIN, SERVER_FILE_SAVE_INTERVAL_MAX);\r
+       }\r
+\r
+       c = s->Cedar;\r
+       Lock(c->lock);\r
+       {\r
+               {\r
+                       RPC_KEEP k;\r
+\r
+                       // キープアライブ関係\r
+                       Zero(&k, sizeof(k));\r
+                       k.UseKeepConnect = CfgGetBool(f, "UseKeepConnect");\r
+                       CfgGetStr(f, "KeepConnectHost", k.KeepConnectHost, sizeof(k.KeepConnectHost));\r
+                       k.KeepConnectPort = CfgGetInt(f, "KeepConnectPort");\r
+                       k.KeepConnectProtocol = CfgGetInt(f, "KeepConnectProtocol");\r
+                       k.KeepConnectInterval = CfgGetInt(f, "KeepConnectInterval") * 1000;\r
+                       if (k.KeepConnectPort == 0)\r
+                       {\r
+                               k.KeepConnectPort = 80;\r
+                       }\r
+                       if (StrLen(k.KeepConnectHost) == 0)\r
+                       {\r
+                               StrCpy(k.KeepConnectHost, sizeof(k.KeepConnectHost), CLIENT_DEFAULT_KEEPALIVE_HOST);\r
+                       }\r
+                       if (k.KeepConnectInterval == 0)\r
+                       {\r
+                               k.KeepConnectInterval = KEEP_INTERVAL_DEFAULT * 1000;\r
+                       }\r
+                       if (k.KeepConnectInterval < 5000)\r
+                       {\r
+                               k.KeepConnectInterval = 5000;\r
+                       }\r
+                       if (k.KeepConnectInterval > 600000)\r
+                       {\r
+                               k.KeepConnectInterval = 600000;\r
+                       }\r
+\r
+                       Lock(s->Keep->lock);\r
+                       {\r
+                               KEEP *keep = s->Keep;\r
+                               keep->Enable = k.UseKeepConnect;\r
+                               keep->Server = true;\r
+                               StrCpy(keep->ServerName, sizeof(keep->ServerName), k.KeepConnectHost);\r
+                               keep->ServerPort = k.KeepConnectPort;\r
+                               keep->UdpMode = k.KeepConnectProtocol;\r
+                               keep->Interval = k.KeepConnectInterval;\r
+                       }\r
+                       Unlock(s->Keep->lock);\r
+               }\r
+\r
+               // IPv6 リスナーを無効にするかどうか\r
+               s->Cedar->DisableIPv6Listener = CfgGetBool(f, "DisableIPv6Listener");\r
+\r
+               // DeadLock\r
+               s->DisableDeadLockCheck = CfgGetBool(f, "DisableDeadLockCheck");\r
+\r
+               // 自動ファイル削除器\r
+               s->Eraser = NewEraser(s->Logger, CfgGetInt64(f, "AutoDeleteCheckDiskFreeSpaceMin"));\r
+\r
+               // NoLinuxArpFilter\r
+               s->NoLinuxArpFilter = CfgGetBool(f, "NoLinuxArpFilter");\r
+\r
+               // NoHighPriorityProcess\r
+               s->NoHighPriorityProcess = CfgGetBool(f, "NoHighPriorityProcess");\r
+\r
+               // NoDebugDump\r
+               s->NoDebugDump = CfgGetBool(f, "NoDebugDump");\r
+               if (s->NoDebugDump)\r
+               {\r
+#ifdef OS_WIN32\r
+                       MsSetEnableMinidump(false);\r
+#endif // OS_WIN32\r
+               }\r
+\r
+               // クライアントにシグネチャを送信させない\r
+               s->NoSendSignature = CfgGetBool(f, "NoSendSignature");\r
+\r
+               // デバッグログ\r
+               s->SaveDebugLog = CfgGetBool(f, "SaveDebugLog");\r
+               if (s->SaveDebugLog)\r
+               {\r
+                       s->DebugLog = NewTinyLog();\r
+               }\r
+\r
+               // サーバー証明書\r
+               b = CfgGetBuf(f, "ServerCert");\r
+               if (b != NULL)\r
+               {\r
+                       x = BufToX(b, false);\r
+                       FreeBuf(b);\r
+               }\r
+\r
+               // サーバー秘密鍵\r
+               b = CfgGetBuf(f, "ServerKey");\r
+               if (b != NULL)\r
+               {\r
+                       k = BufToK(b, true, false, NULL);\r
+                       FreeBuf(b);\r
+               }\r
+\r
+               if (x == NULL || k == NULL || CheckXandK(x, k) == false)\r
+               {\r
+                       FreeX(x);\r
+                       FreeK(k);\r
+                       SiGenerateDefualtCert(&x, &k);\r
+\r
+                       SetCedarCert(c, x, k);\r
+\r
+                       FreeX(x);\r
+                       FreeK(k);\r
+               }\r
+               else\r
+               {\r
+                       SetCedarCert(c, x, k);\r
+\r
+                       FreeX(x);\r
+                       FreeK(k);\r
+               }\r
+\r
+               // 暗号化名\r
+               if (CfgGetStr(f, "CipherName", tmp, sizeof(tmp)))\r
+               {\r
+                       StrUpper(tmp);\r
+                       if (CheckCipherListName(tmp))\r
+                       {\r
+                               SetCedarCipherList(c, tmp);\r
+                       }\r
+               }\r
+\r
+               // トラフィック情報\r
+               Lock(c->TrafficLock);\r
+               {\r
+                       SiLoadTraffic(f, "ServerTraffic", c->Traffic);\r
+               }\r
+               Unlock(c->TrafficLock);\r
+\r
+               // 現在のライセンスでクラスタモードが許可されているかどうかを取得する\r
+               cluster_allowed = false;\r
+               if (s->Cedar->Bridge == false)\r
+               {\r
+                       LICENSE_STATUS status;\r
+\r
+                       LiParseCurrentLicenseStatus(s->LicenseSystem, &status);\r
+\r
+                       if (status.AllowEnterpriseFunction)\r
+                       {\r
+                               cluster_allowed = true;\r
+                       }\r
+               }\r
+\r
+               // サーバーの種類\r
+               s->UpdatedServerType = s->ServerType = \r
+                       cluster_allowed ? CfgGetInt(f, "ServerType") : SERVER_TYPE_STANDALONE;\r
+\r
+               // パスワード\r
+               if (CfgGetByte(f, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword)) != sizeof(s->HashedPassword))\r
+               {\r
+                       Hash(s->HashedPassword, "", 0, true);\r
+               }\r
+\r
+               if (s->ServerType != SERVER_TYPE_STANDALONE)\r
+               {\r
+                       // サーバーの性能基準比\r
+                       s->Weight = CfgGetInt(f, "ClusterMemberWeight");\r
+                       if (s->Weight == 0)\r
+                       {\r
+                               s->Weight = FARM_DEFAULT_WEIGHT;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       s->Weight = FARM_DEFAULT_WEIGHT;\r
+               }\r
+\r
+               if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)\r
+               {\r
+                       s->ControllerOnly = CfgGetBool(f, "ControllerOnly");\r
+               }\r
+\r
+               if (s->ServerType == SERVER_TYPE_FARM_MEMBER)\r
+               {\r
+                       char tmp[6 * MAX_PUBLIC_PORT_NUM + 1];\r
+                       // ファームメンバの場合の設定項目の読み込み\r
+                       CfgGetStr(f, "ControllerName", s->ControllerName, sizeof(s->ControllerName));\r
+                       s->ControllerPort = CfgGetInt(f, "ControllerPort");\r
+                       CfgGetByte(f, "MemberPassword", s->MemberPassword, SHA1_SIZE);\r
+                       s->PublicIp = CfgGetIp32(f, "PublicIp");\r
+                       if (CfgGetStr(f, "PublicPorts", tmp, sizeof(tmp)))\r
+                       {\r
+                               TOKEN_LIST *t = ParseToken(tmp, ", ");\r
+                               UINT i;\r
+                               s->NumPublicPort = t->NumTokens;\r
+                               s->PublicPorts = ZeroMalloc(s->NumPublicPort * sizeof(UINT));\r
+                               for (i = 0;i < s->NumPublicPort;i++)\r
+                               {\r
+                                       s->PublicPorts[i] = ToInt(t->Token[i]);\r
+                               }\r
+                               FreeToken(t);\r
+                       }\r
+               }\r
+       }\r
+       Unlock(c->lock);\r
+}\r
+\r
+// サーバー固有の設定の書き込み\r
+void SiWriteServerCfg(FOLDER *f, SERVER *s)\r
+{\r
+       BUF *b;\r
+       CEDAR *c;\r
+       // 引数チェック\r
+       if (f == NULL || s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       CfgAddInt(f, "AutoSaveConfigSpan", s->AutoSaveConfigSpan / 1000);\r
+\r
+       c = s->Cedar;\r
+\r
+       Lock(c->lock);\r
+       {\r
+               Lock(s->Keep->lock);\r
+               {\r
+                       KEEP *k = s->Keep;\r
+                       CfgAddBool(f, "UseKeepConnect", k->Enable);\r
+                       CfgAddStr(f, "KeepConnectHost", k->ServerName);\r
+                       CfgAddInt(f, "KeepConnectPort", k->ServerPort);\r
+                       CfgAddInt(f, "KeepConnectProtocol", k->UdpMode);\r
+                       CfgAddInt(f, "KeepConnectInterval", k->Interval / 1000);\r
+               }\r
+               Unlock(s->Keep->lock);\r
+\r
+               // IPv6 リスナー無効化設定\r
+               CfgAddBool(f, "DisableIPv6Listener", s->Cedar->DisableIPv6Listener);\r
+\r
+               // DeadLock\r
+               CfgAddBool(f, "DisableDeadLockCheck", s->DisableDeadLockCheck);\r
+\r
+               // 自動ファイル削除器関係\r
+               CfgAddInt64(f, "AutoDeleteCheckDiskFreeSpaceMin", s->Eraser->MinFreeSpace);\r
+\r
+               // NoLinuxArpFilter\r
+               if (GetOsInfo()->OsType == OSTYPE_LINUX)\r
+               {\r
+                       CfgAddBool(f, "NoLinuxArpFilter", s->NoLinuxArpFilter);\r
+               }\r
+\r
+               // NoHighPriorityProcess\r
+               CfgAddBool(f, "NoHighPriorityProcess", s->NoHighPriorityProcess);\r
+\r
+#ifdef OS_WIN32\r
+               CfgAddBool(f, "NoDebugDump", s->NoDebugDump);\r
+#endif // OS_WIN32\r
+\r
+               // デバッグログ\r
+               CfgAddBool(f, "SaveDebugLog", s->SaveDebugLog);\r
+\r
+               // クライアントにシグネチャを送信させない\r
+               CfgAddBool(f, "NoSendSignature", s->NoSendSignature);\r
+\r
+               // サーバー証明書\r
+               b = XToBuf(c->ServerX, false);\r
+               CfgAddBuf(f, "ServerCert", b);\r
+               FreeBuf(b);\r
+\r
+               // サーバー秘密鍵\r
+               b = KToBuf(c->ServerK, false, NULL);\r
+               CfgAddBuf(f, "ServerKey", b);\r
+               FreeBuf(b);\r
+\r
+               // トラフィック情報\r
+               Lock(c->TrafficLock);\r
+               {\r
+                       SiWriteTraffic(f, "ServerTraffic", c->Traffic);\r
+               }\r
+               Unlock(c->TrafficLock);\r
+\r
+               // サーバーの種類\r
+               if (s->Cedar->Bridge == false)\r
+               {\r
+                       CfgAddInt(f, "ServerType", s->UpdatedServerType);\r
+               }\r
+\r
+               // 暗号化\r
+               CfgAddStr(f, "CipherName", s->Cedar->CipherList);\r
+\r
+               // パスワード\r
+               CfgAddByte(f, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword));\r
+\r
+               if (s->UpdatedServerType == SERVER_TYPE_FARM_MEMBER)\r
+               {\r
+                       char tmp[6 * MAX_PUBLIC_PORT_NUM + 1];\r
+                       UINT i;\r
+                       // ファームメンバの場合の設定項目\r
+                       CfgAddStr(f, "ControllerName", s->ControllerName);\r
+                       CfgAddInt(f, "ControllerPort", s->ControllerPort);\r
+                       CfgAddByte(f, "MemberPassword", s->MemberPassword, SHA1_SIZE);\r
+                       CfgAddIp32(f, "PublicIp", s->PublicIp);\r
+                       tmp[0] = 0;\r
+                       for (i = 0;i < s->NumPublicPort;i++)\r
+                       {\r
+                               char tmp2[MAX_SIZE];\r
+                               ToStr(tmp2, s->PublicPorts[i]);\r
+                               StrCat(tmp, sizeof(tmp), tmp2);\r
+                               StrCat(tmp, sizeof(tmp), ",");\r
+                       }\r
+                       if (StrLen(tmp) >= 1)\r
+                       {\r
+                               if (tmp[StrLen(tmp) - 1] == ',')\r
+                               {\r
+                                       tmp[StrLen(tmp) - 1] = 0;\r
+                               }\r
+                       }\r
+                       CfgAddStr(f, "PublicPorts", tmp);\r
+               }\r
+\r
+               if (s->UpdatedServerType != SERVER_TYPE_STANDALONE)\r
+               {\r
+                       CfgAddInt(f, "ClusterMemberWeight", s->Weight);\r
+               }\r
+\r
+               if (s->UpdatedServerType == SERVER_TYPE_FARM_CONTROLLER)\r
+               {\r
+                       CfgAddBool(f, "ControllerOnly", s->ControllerOnly);\r
+               }\r
+       }\r
+       Unlock(c->lock);\r
+}\r
+\r
+// トラフィック情報の読み込み\r
+void SiLoadTraffic(FOLDER *parent, char *name, TRAFFIC *t)\r
+{\r
+       FOLDER *f;\r
+       // 引数チェック\r
+       if (t != NULL)\r
+       {\r
+               Zero(t, sizeof(TRAFFIC));\r
+       }\r
+       if (parent == NULL || name == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       f = CfgGetFolder(parent, name);\r
+\r
+       if (f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       SiLoadTrafficInner(f, "SendTraffic", &t->Send);\r
+       SiLoadTrafficInner(f, "RecvTraffic", &t->Recv);\r
+}\r
+void SiLoadTrafficInner(FOLDER *parent, char *name, TRAFFIC_ENTRY *e)\r
+{\r
+       FOLDER *f;\r
+       // 引数チェック\r
+       if (e != NULL)\r
+       {\r
+               Zero(e, sizeof(TRAFFIC_ENTRY));\r
+       }\r
+       if (parent == NULL || name == NULL || e == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       f = CfgGetFolder(parent, name);\r
+       if (f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       e->BroadcastCount = CfgGetInt64(f, "BroadcastCount");\r
+       e->BroadcastBytes = CfgGetInt64(f, "BroadcastBytes");\r
+       e->UnicastCount = CfgGetInt64(f, "UnicastCount");\r
+       e->UnicastBytes = CfgGetInt64(f, "UnicastBytes");\r
+}\r
+\r
+// トラフィック情報の書き込み\r
+void SiWriteTraffic(FOLDER *parent, char *name, TRAFFIC *t)\r
+{\r
+       FOLDER *f;\r
+       // 引数チェック\r
+       if (parent == NULL || name == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       f = CfgCreateFolder(parent, name);\r
+\r
+       SiWriteTrafficInner(f, "SendTraffic", &t->Send);\r
+       SiWriteTrafficInner(f, "RecvTraffic", &t->Recv);\r
+}\r
+void SiWriteTrafficInner(FOLDER *parent, char *name, TRAFFIC_ENTRY *e)\r
+{\r
+       FOLDER *f;\r
+       // 引数チェック\r
+       if (parent == NULL || name == NULL || e == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       f = CfgCreateFolder(parent, name);\r
+       CfgAddInt64(f, "BroadcastCount", e->BroadcastCount);\r
+       CfgAddInt64(f, "BroadcastBytes", e->BroadcastBytes);\r
+       CfgAddInt64(f, "UnicastCount", e->UnicastCount);\r
+       CfgAddInt64(f, "UnicastBytes", e->UnicastBytes);\r
+}\r
+\r
+// 設定ファイル書き込み用スレッド\r
+void SiSaverThread(THREAD *thread, void *param)\r
+{\r
+       SERVER *s = (SERVER *)param;\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       while (s->Halt == false)\r
+       {\r
+               // 設定ファイル保存\r
+               SiWriteConfigurationFile(s);\r
+\r
+               Wait(s->SaveHaltEvent, s->AutoSaveConfigSpan);\r
+       }\r
+}\r
+\r
+// 設定ファイルに書き込む\r
+UINT SiWriteConfigurationFile(SERVER *s)\r
+{\r
+       UINT ret;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       if (s->CfgRw == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       Lock(s->SaveCfgLock);\r
+       {\r
+               FOLDER *f;\r
+\r
+               Debug("save: SiWriteConfigurationToCfg() start.\n");\r
+               f = SiWriteConfigurationToCfg(s);\r
+               Debug("save: SiWriteConfigurationToCfg() finished.\n");\r
+\r
+               Debug("save: SaveCfgRw() start.\n");\r
+               ret = SaveCfgRw(s->CfgRw, f);\r
+               Debug("save: SaveCfgRw() finished.\n");\r
+\r
+               Debug("save: CfgDeleteFolder() start.\n");\r
+               CfgDeleteFolder(f);\r
+               Debug("save: CfgDeleteFolder() finished.\n");\r
+       }\r
+       Unlock(s->SaveCfgLock);\r
+\r
+       return ret;\r
+}\r
+\r
+// コンフィグレーション解放\r
+void SiFreeConfiguration(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 設定ファイルに書き込む\r
+       SiWriteConfigurationFile(s);\r
+\r
+       // 設定ファイル保存スレッドの終了\r
+       s->Halt = true;\r
+       Set(s->SaveHaltEvent);\r
+       WaitThread(s->SaveThread, INFINITE);\r
+\r
+       ReleaseEvent(s->SaveHaltEvent);\r
+       ReleaseThread(s->SaveThread);\r
+\r
+       FreeCfgRw(s->CfgRw);\r
+       s->CfgRw = NULL;\r
+\r
+       // Ethernet 解放\r
+       FreeEth();\r
+}\r
+\r
+// StXxx 関係関数の初期化\r
+void StInit()\r
+{\r
+       if (server_lock != NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       server_lock = NewLock();\r
+}\r
+\r
+// StXxx 関係関数の解放\r
+void StFree()\r
+{\r
+       DeleteLock(server_lock);\r
+       server_lock = NULL;\r
+}\r
+\r
+// サーバーの開始\r
+void StStartServer(bool bridge)\r
+{\r
+       Lock(server_lock);\r
+       {\r
+               if (server != NULL)\r
+               {\r
+                       // すでに開始されている\r
+                       Unlock(server_lock);\r
+                       return;\r
+               }\r
+\r
+               // サーバーの作成\r
+               server = SiNewServer(bridge);\r
+       }\r
+       Unlock(server_lock);\r
+\r
+//     StartCedarLog();\r
+}\r
+\r
+// サーバーの取得\r
+SERVER *StGetServer()\r
+{\r
+       if (server == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+       return server;\r
+}\r
+\r
+// サーバーの停止\r
+void StStopServer()\r
+{\r
+       Lock(server_lock);\r
+       {\r
+               if (server == NULL)\r
+               {\r
+                       // 開始されていない\r
+                       Unlock(server_lock);\r
+                       return;\r
+               }\r
+\r
+               // サーバーの解放\r
+               SiReleaseServer(server);\r
+               server = NULL;\r
+       }\r
+       Unlock(server_lock);\r
+\r
+       StopCedarLog();\r
+}\r
+\r
+// サーバーの種類の設定\r
+void SiSetServerType(SERVER *s, UINT type,\r
+                                        UINT ip, UINT num_port, UINT *ports,\r
+                                        char *controller_name, UINT controller_port, UCHAR *password, UINT weight, bool controller_only)\r
+{\r
+       bool bridge;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+       if (type == SERVER_TYPE_FARM_MEMBER &&\r
+               (num_port == 0 || ports == NULL || controller_name == NULL ||\r
+               controller_port == 0 || password == NULL || num_port > MAX_PUBLIC_PORT_NUM))\r
+       {\r
+               return;\r
+       }\r
+       if (weight == 0)\r
+       {\r
+               weight = FARM_DEFAULT_WEIGHT;\r
+       }\r
+\r
+       bridge = s->Cedar->Bridge;\r
+\r
+       Lock(s->lock);\r
+       {\r
+               // 種類の更新\r
+               s->UpdatedServerType = type;\r
+\r
+               s->Weight = weight;\r
+\r
+               // 値の設定\r
+               if (type == SERVER_TYPE_FARM_MEMBER)\r
+               {\r
+                       StrCpy(s->ControllerName, sizeof(s->ControllerName), controller_name);\r
+                       s->ControllerPort = controller_port;\r
+                       if (IsZero(password, SHA1_SIZE) == false)\r
+                       {\r
+                               Copy(s->MemberPassword, password, SHA1_SIZE);\r
+                       }\r
+                       s->PublicIp = ip;\r
+                       s->NumPublicPort = num_port;\r
+                       if (s->PublicPorts != NULL)\r
+                       {\r
+                               Free(s->PublicPorts);\r
+                       }\r
+                       s->PublicPorts = ZeroMalloc(num_port * sizeof(UINT));\r
+                       Copy(s->PublicPorts, ports, num_port * sizeof(UINT));\r
+               }\r
+\r
+               if (type == SERVER_TYPE_FARM_CONTROLLER)\r
+               {\r
+                       s->ControllerOnly = controller_only;\r
+               }\r
+       }\r
+       Unlock(s->lock);\r
+\r
+       // サーバーの再起動\r
+       SiRebootServer(bridge);\r
+}\r
+\r
+// サーバーの再起動スレッド\r
+void SiRebootServerThread(THREAD *thread, void *param)\r
+{\r
+       // 引数チェック\r
+       if (thread == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (server == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // サーバーの停止\r
+       StStopServer();\r
+\r
+       // サーバーの開始\r
+       StStartServer((bool)param);\r
+}\r
+\r
+// サーバーの再起動\r
+void SiRebootServer(bool bridge)\r
+{\r
+       SiRebootServerEx(bridge, false);\r
+}\r
+void SiRebootServerEx(bool bridge, bool reset_setting)\r
+{\r
+       THREAD *t;\r
+\r
+       server_reset_setting = reset_setting;\r
+\r
+       t = NewThread(SiRebootServerThread, (void *)bridge);\r
+       ReleaseThread(t);\r
+}\r
+\r
+// すべてのリスナーの停止\r
+void SiStopAllListener(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       SiLockListenerList(s);\r
+       {\r
+               UINT i;\r
+               LIST *o = NewListFast(NULL);\r
+               for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)\r
+               {\r
+                       SERVER_LISTENER *e = LIST_DATA(s->ServerListenerList, i);\r
+                       Add(o, e);\r
+               }\r
+\r
+               for (i = 0;i < LIST_NUM(o);i++)\r
+               {\r
+                       SERVER_LISTENER *e = LIST_DATA(o, i);\r
+                       SiDeleteListener(s, e->Port);\r
+               }\r
+\r
+               ReleaseList(o);\r
+       }\r
+       SiUnlockListenerList(s);\r
+\r
+       ReleaseList(s->ServerListenerList);\r
+}\r
+\r
+// サーバーのクリーンアップ\r
+void SiCleanupServer(SERVER *s)\r
+{\r
+       UINT i;\r
+       CEDAR *c;\r
+       LISTENER **listener_list;\r
+       UINT num_listener;\r
+       HUB **hub_list;\r
+       UINT num_hub;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       SiFreeDeadLockCheck(s);\r
+\r
+       FreeServerSnapshot(s);\r
+\r
+       c = s->Cedar;\r
+\r
+       if (s->ServerType == SERVER_TYPE_FARM_MEMBER)\r
+       {\r
+               // ファームメンバの場合、ファームコントローラへの接続を停止\r
+               SLog(c, "LS_STOP_FARM_MEMBER");\r
+               SiStopConnectToController(s->FarmController);\r
+               s->FarmController = NULL;\r
+               SLog(c, "LS_STOP_FARM_MEMBER_2");\r
+       }\r
+\r
+       IncrementServerConfigRevision(s);\r
+\r
+       SLog(c, "LS_END_2");\r
+\r
+       SLog(c, "LS_STOP_ALL_LISTENER");\r
+       // すべてのリスナーを停止\r
+       LockList(c->ListenerList);\r
+       {\r
+               listener_list = ToArray(c->ListenerList);\r
+               num_listener = LIST_NUM(c->ListenerList);\r
+               for (i = 0;i < num_listener;i++)\r
+               {\r
+                       AddRef(listener_list[i]->ref);\r
+               }\r
+       }\r
+       UnlockList(c->ListenerList);\r
+\r
+       for (i = 0;i < num_listener;i++)\r
+       {\r
+               StopListener(listener_list[i]);\r
+               ReleaseListener(listener_list[i]);\r
+       }\r
+       Free(listener_list);\r
+       SLog(c, "LS_STOP_ALL_LISTENER_2");\r
+\r
+       SLog(c, "LS_STOP_ALL_HUB");\r
+       // すべての HUB を停止\r
+       LockList(c->HubList);\r
+       {\r
+               hub_list = ToArray(c->HubList);\r
+               num_hub = LIST_NUM(c->HubList);\r
+               for (i = 0;i < num_hub;i++)\r
+               {\r
+                       AddRef(hub_list[i]->ref);\r
+               }\r
+       }\r
+       UnlockList(c->HubList);\r
+\r
+       for (i = 0;i < num_hub;i++)\r
+       {\r
+               StopHub(hub_list[i]);\r
+               ReleaseHub(hub_list[i]);\r
+       }\r
+       Free(hub_list);\r
+       SLog(c, "LS_STOP_ALL_HUB_2");\r
+\r
+       // コンフィグレーション解放\r
+       SiFreeConfiguration(s);\r
+\r
+       // Cedar の停止\r
+       SLog(c, "LS_STOP_CEDAR");\r
+       StopCedar(s->Cedar);\r
+       SLog(c, "LS_STOP_CEDAR_2");\r
+\r
+       // すべてのリスナーの停止\r
+       SiStopAllListener(s);\r
+\r
+       if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)\r
+       {\r
+               // ファームコントローラの場合\r
+               UINT i;\r
+\r
+               SLog(c, "LS_STOP_FARM_CONTROL");\r
+\r
+               // ファームコントロールを停止\r
+               SiStopFarmControl(s);\r
+\r
+               // ファームメンバ情報を解放\r
+               ReleaseList(s->FarmMemberList);\r
+               s->FarmMemberList = NULL;\r
+\r
+               for (i = 0;i < LIST_NUM(s->Me->HubList);i++)\r
+               {\r
+                       Free(LIST_DATA(s->Me->HubList, i));\r
+               }\r
+               ReleaseList(s->Me->HubList);\r
+\r
+               Free(s->Me);\r
+\r
+               SLog(c, "LS_STOP_FARM_CONTROL_2");\r
+       }\r
+\r
+       if (s->PublicPorts != NULL)\r
+       {\r
+               Free(s->PublicPorts);\r
+       }\r
+\r
+       SLog(s->Cedar, "LS_END_1");\r
+       SLog(s->Cedar, "L_LINE");\r
+\r
+       ReleaseCedar(s->Cedar);\r
+       DeleteLock(s->lock);\r
+       DeleteLock(s->SaveCfgLock);\r
+\r
+       StopKeep(s->Keep);\r
+\r
+       FreeEraser(s->Eraser);\r
+\r
+       // ライセンスシステム解放\r
+       if (s->LicenseSystem != NULL)\r
+       {\r
+               LiFreeLicenseSystem(s->LicenseSystem);\r
+       }\r
+\r
+       FreeLog(s->Logger);\r
+\r
+       FreeServerCapsCache(s);\r
+\r
+       SiFreeHubCreateHistory(s);\r
+\r
+       // デバッグログの停止\r
+       FreeTinyLog(s->DebugLog);\r
+\r
+       DeleteLock(s->TasksFromFarmControllerLock);\r
+\r
+       Free(s);\r
+}\r
+\r
+// サーバーの解放\r
+void SiReleaseServer(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (Release(s->ref) == 0)\r
+       {\r
+               SiCleanupServer(s);\r
+       }\r
+}\r
+\r
+// 次に処理をさせるファームメンバーを指定する\r
+FARM_MEMBER *SiGetNextFarmMember(SERVER *s)\r
+{\r
+       UINT i, num;\r
+       UINT min_point = 0;\r
+       FARM_MEMBER *ret = NULL;\r
+       // 引数チェック\r
+       if (s == NULL || s->ServerType != SERVER_TYPE_FARM_CONTROLLER)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       num = LIST_NUM(s->FarmMemberList);\r
+       if (num == 0)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       for (i = 0;i < num;i++)\r
+       {\r
+               UINT num_sessions;\r
+               UINT max_sessions;\r
+               FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);\r
+               if (s->ControllerOnly)\r
+               {\r
+                       if (f->Me)\r
+                       {\r
+                               // ControllerOnly のとき自分自身は選定しない\r
+                               continue;\r
+                       }\r
+               }\r
+\r
+               if (f->Me == false)\r
+               {\r
+                       num_sessions = f->NumSessions;\r
+                       max_sessions = f->MaxSessions;\r
+               }\r
+               else\r
+               {\r
+                       num_sessions = Count(s->Cedar->CurrentSessions);\r
+                       max_sessions = GetServerCapsInt(s, "i_max_sessions");\r
+               }\r
+\r
+               if (max_sessions == 0)\r
+               {\r
+                       max_sessions = GetServerCapsInt(s, "i_max_sessions");\r
+               }\r
+\r
+               if (num_sessions < max_sessions)\r
+               {\r
+                       if (f->Point >= min_point)\r
+                       {\r
+                               min_point = f->Point;\r
+                               ret = f;\r
+                       }\r
+               }\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+// HUB 列挙指令受信\r
+void SiCalledEnumHub(SERVER *s, PACK *p, PACK *req)\r
+{\r
+       UINT i;\r
+       CEDAR *c;\r
+       LICENSE_STATUS st;\r
+       UINT num = 0;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL || req == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LiParseCurrentLicenseStatus(s->LicenseSystem, &st);\r
+\r
+       c = s->Cedar;\r
+\r
+       LockList(c->HubList);\r
+       {\r
+               UINT num = LIST_NUM(c->HubList);\r
+               for (i = 0;i < num;i++)\r
+               {\r
+                       HUB *h = LIST_DATA(c->HubList, i);\r
+                       Lock(h->lock);\r
+                       {\r
+                               PackAddStrEx(p, "HubName", h->Name, i, num);\r
+                               PackAddIntEx(p, "HubType", h->Type, i, num);\r
+                               PackAddIntEx(p, "NumSession", Count(h->NumSessions), i, num);\r
+\r
+                               PackAddIntEx(p, "NumSessions", LIST_NUM(h->SessionList), i, num);\r
+                               PackAddIntEx(p, "NumSessionsClient", Count(h->NumSessionsClient), i, num);\r
+                               PackAddIntEx(p, "NumSessionsBridge", Count(h->NumSessionsBridge), i, num);\r
+\r
+                               PackAddIntEx(p, "NumMacTables", LIST_NUM(h->MacTable), i, num);\r
+\r
+                               PackAddIntEx(p, "NumIpTables", LIST_NUM(h->IpTable), i, num);\r
+\r
+                               PackAddInt64Ex(p, "LastCommTime", h->LastCommTime, i, num);\r
+                               PackAddInt64Ex(p, "CreatedTime", h->CreatedTime, i, num);\r
+                       }\r
+                       Unlock(h->lock);\r
+               }\r
+       }\r
+       UnlockList(c->HubList);\r
+\r
+       PackAddInt(p, "Point", SiGetPoint(s));\r
+       PackAddInt(p, "NumTcpConnections", Count(s->Cedar->CurrentTcpConnections));\r
+       PackAddInt(p, "NumTotalSessions", Count(s->Cedar->CurrentSessions));\r
+       PackAddInt(p, "MaxSessions", GetServerCapsInt(s, "i_max_sessions"));\r
+\r
+       PackAddInt(p, "AssignedClientLicense", Count(s->Cedar->AssignedClientLicense));\r
+       PackAddInt(p, "AssignedBridgeLicense", Count(s->Cedar->AssignedBridgeLicense));\r
+\r
+       PackAddData(p, "RandomKey", s->MyRandomKey, SHA1_SIZE);\r
+       PackAddInt64(p, "SystemId", st.SystemId);\r
+\r
+       Lock(c->TrafficLock);\r
+       {\r
+               OutRpcTraffic(p, c->Traffic);\r
+       }\r
+       Unlock(c->TrafficLock);\r
+\r
+       LockList(c->TrafficDiffList);\r
+       {\r
+               UINT num = LIST_NUM(c->TrafficDiffList);\r
+               UINT i;\r
+\r
+               for (i = 0;i < num;i++)\r
+               {\r
+                       TRAFFIC_DIFF *d = LIST_DATA(c->TrafficDiffList, i);\r
+\r
+                       PackAddIntEx(p, "TdType", d->Type, i, num);\r
+                       PackAddStrEx(p, "TdHubName", d->HubName, i, num);\r
+                       PackAddStrEx(p, "TdName", d->Name, i, num);\r
+\r
+                       OutRpcTrafficEx(&d->Traffic, p, i, num);\r
+\r
+                       Free(d->HubName);\r
+                       Free(d->Name);\r
+                       Free(d);\r
+               }\r
+\r
+               DeleteAll(c->TrafficDiffList);\r
+       }\r
+       UnlockList(c->TrafficDiffList);\r
+}\r
+\r
+// HUB 削除指令受信\r
+void SiCalledDeleteHub(SERVER *s, PACK *p)\r
+{\r
+       char name[MAX_SIZE];\r
+       HUB *h;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (PackGetStr(p, "HubName", name, sizeof(name)) == false)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockHubList(s->Cedar);\r
+\r
+       h = GetHub(s->Cedar, name);\r
+       if (h == NULL)\r
+       {\r
+               UnlockHubList(s->Cedar);\r
+               return;\r
+       }\r
+       UnlockHubList(s->Cedar);\r
+\r
+       SetHubOffline(h);\r
+\r
+       LockHubList(s->Cedar);\r
+\r
+       DelHubEx(s->Cedar, h, true);\r
+\r
+       UnlockHubList(s->Cedar);\r
+\r
+       ReleaseHub(h);\r
+}\r
+\r
+// HUB 更新指令受信\r
+void SiCalledUpdateHub(SERVER *s, PACK *p)\r
+{\r
+       char name[MAX_SIZE];\r
+       UINT type;\r
+       HUB_OPTION o;\r
+       HUB_LOG log;\r
+       bool save_packet_log;\r
+       UINT packet_log_switch_type;\r
+       UINT packet_log_config[NUM_PACKET_LOG];\r
+       bool save_security_log;\r
+       bool type_changed = false;\r
+       UINT security_log_switch_type;\r
+       UINT i;\r
+       HUB *h;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackGetStr(p, "HubName", name, sizeof(name));\r
+       type = PackGetInt(p, "HubType");\r
+       Zero(&o, sizeof(o));\r
+       o.MaxSession = PackGetInt(p, "MaxSession");\r
+       o.NoArpPolling = PackGetBool(p, "NoArpPolling");\r
+       o.NoIPv6AddrPolling = PackGetBool(p, "NoIPv6AddrPolling");\r
+       o.FilterPPPoE = PackGetBool(p, "FilterPPPoE");\r
+       o.YieldAfterStorePacket = PackGetBool(p, "YieldAfterStorePacket");\r
+       o.NoSpinLockForPacketDelay = PackGetBool(p, "NoSpinLockForPacketDelay");\r
+       o.BroadcastStormDetectionThreshold = PackGetInt(p, "BroadcastStormDetectionThreshold");\r
+       o.ClientMinimumRequiredBuild = PackGetInt(p, "ClientMinimumRequiredBuild");\r
+       o.FixForDLinkBPDU = PackGetBool(p, "FixForDLinkBPDU");\r
+       o.NoLookBPDUBridgeId = PackGetBool(p, "NoLookBPDUBridgeId");\r
+       o.NoManageVlanId = PackGetBool(p, "NoManageVlanId");\r
+       o.VlanTypeId = PackGetInt(p, "VlanTypeId");\r
+       if (o.VlanTypeId == 0)\r
+       {\r
+               o.VlanTypeId = MAC_PROTO_TAGVLAN;\r
+       }\r
+       o.FilterOSPF = PackGetBool(p, "FilterOSPF");\r
+       o.FilterIPv4 = PackGetBool(p, "FilterIPv4");\r
+       o.FilterIPv6 = PackGetBool(p, "FilterIPv6");\r
+       o.FilterNonIP = PackGetBool(p, "FilterNonIP");\r
+       o.NoIPv4PacketLog = PackGetBool(p, "NoIPv4PacketLog");\r
+       o.NoIPv6PacketLog = PackGetBool(p, "NoIPv6PacketLog");\r
+       o.FilterBPDU = PackGetBool(p, "FilterBPDU");\r
+       o.NoIPv6DefaultRouterInRAWhenIPv6 = PackGetBool(p, "NoIPv6DefaultRouterInRAWhenIPv6");\r
+       o.NoMacAddressLog = PackGetBool(p, "NoMacAddressLog");\r
+       o.ManageOnlyPrivateIP = PackGetBool(p, "ManageOnlyPrivateIP");\r
+       o.ManageOnlyLocalUnicastIPv6 = PackGetBool(p, "ManageOnlyLocalUnicastIPv6");\r
+       o.DisableIPParsing = PackGetBool(p, "DisableIPParsing");\r
+       o.NoIpTable = PackGetBool(p, "NoIpTable");\r
+       o.NoEnum = PackGetBool(p, "NoEnum");\r
+       save_packet_log = PackGetInt(p, "SavePacketLog");\r
+       packet_log_switch_type = PackGetInt(p, "PacketLogSwitchType");\r
+       for (i = 0;i < NUM_PACKET_LOG;i++)\r
+       {\r
+               packet_log_config[i] = PackGetIntEx(p, "PacketLogConfig", i);\r
+       }\r
+       save_security_log = PackGetInt(p, "SaveSecurityLog");\r
+       security_log_switch_type = PackGetInt(p, "SecurityLogSwitchType");\r
+\r
+       Zero(&log, sizeof(log));\r
+       log.SavePacketLog = save_packet_log;\r
+       log.PacketLogSwitchType = packet_log_switch_type;\r
+       Copy(log.PacketLogConfig, packet_log_config, sizeof(log.PacketLogConfig));\r
+       log.SaveSecurityLog = save_security_log;\r
+       log.SecurityLogSwitchType = security_log_switch_type;\r
+\r
+       h = GetHub(s->Cedar, name);\r
+       if (h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       h->FarmMember_MaxSessionClient = PackGetInt(p, "MaxSessionClient");\r
+       h->FarmMember_MaxSessionBridge = PackGetInt(p, "MaxSessionBridge");\r
+       h->FarmMember_MaxSessionClientBridgeApply = PackGetBool(p, "MaxSessionClientBridgeApply");\r
+\r
+       if (h->FarmMember_MaxSessionClientBridgeApply == false)\r
+       {\r
+               h->FarmMember_MaxSessionClient = INFINITE;\r
+               h->FarmMember_MaxSessionBridge = INFINITE;\r
+       }\r
+\r
+       Lock(h->lock);\r
+       {\r
+               Copy(h->Option, &o, sizeof(HUB_OPTION));\r
+               PackGetData2(p, "SecurePassword", h->SecurePassword, SHA1_SIZE);\r
+               PackGetData2(p, "HashedPassword", h->HashedPassword, SHA1_SIZE);\r
+       }\r
+       Unlock(h->lock);\r
+\r
+       SetHubLogSetting(h, &log);\r
+\r
+       if (h->Type != type)\r
+       {\r
+               h->Type = type;\r
+               type_changed = true;\r
+       }\r
+\r
+       LockList(h->AccessList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(h->AccessList);i++)\r
+               {\r
+                       ACCESS *a = LIST_DATA(h->AccessList, i);\r
+                       Free(a);\r
+               }\r
+               DeleteAll(h->AccessList);\r
+       }\r
+       UnlockList(h->AccessList);\r
+\r
+       for (i = 0;i < SiNumAccessFromPack(p);i++)\r
+       {\r
+               ACCESS *a = SiPackToAccess(p, i);\r
+               AddAccessList(h, a);\r
+               Free(a);\r
+       }\r
+\r
+       if (PackGetBool(p, "EnableSecureNAT"))\r
+       {\r
+               VH_OPTION t;\r
+               bool changed;\r
+\r
+               InVhOption(&t, p);\r
+\r
+               changed = Cmp(h->SecureNATOption, &t, sizeof(VH_OPTION)) == 0 ? false : true;\r
+               Copy(h->SecureNATOption, &t, sizeof(VH_OPTION));\r
+\r
+               EnableSecureNAT(h, true);\r
+\r
+               if (changed)\r
+               {\r
+                       Lock(h->lock_online);\r
+                       {\r
+                               if (h->SecureNAT != NULL)\r
+                               {\r
+                                       SetVirtualHostOption(h->SecureNAT->Nat->Virtual, &t);\r
+                                       Debug("SiCalledUpdateHub: SecureNAT Updated.\n");\r
+                               }\r
+                       }\r
+                       Unlock(h->lock_online);\r
+               }\r
+       }\r
+       else\r
+       {\r
+               EnableSecureNAT(h, false);\r
+               Debug("SiCalledUpdateHub: SecureNAT Disabled.\n");\r
+       }\r
+\r
+       if (type_changed)\r
+       {\r
+               // HUB の種類が変更されたのですべてのセッションを削除する\r
+               if (h->Offline == false)\r
+               {\r
+                       SetHubOffline(h);\r
+                       SetHubOnline(h);\r
+               }\r
+       }\r
+\r
+       ReleaseHub(h);\r
+}\r
+\r
+// チケットの検査\r
+bool SiCheckTicket(HUB *h, UCHAR *ticket, char *username, UINT username_size, char *usernamereal, UINT usernamereal_size, POLICY *policy, char *sessionname, UINT sessionname_size, char *groupname, UINT groupname_size)\r
+{\r
+       bool ret = false;\r
+       // 引数チェック\r
+       if (h == NULL || ticket == NULL || username == NULL || usernamereal == NULL || policy == NULL || sessionname == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       LockList(h->TicketList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(h->TicketList);i++)\r
+               {\r
+                       TICKET *t = LIST_DATA(h->TicketList, i);\r
+                       if (Cmp(t->Ticket, ticket, SHA1_SIZE) == 0)\r
+                       {\r
+                               ret = true;\r
+                               StrCpy(username, username_size, t->Username);\r
+                               StrCpy(usernamereal, usernamereal_size, t->UsernameReal);\r
+                               StrCpy(sessionname, sessionname_size, t->SessionName);\r
+                               StrCpy(groupname, groupname_size, t->GroupName);\r
+                               Copy(policy, &t->Policy, sizeof(POLICY));\r
+                               Delete(h->TicketList, t);\r
+                               Free(t);\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(h->TicketList);\r
+\r
+       return ret;\r
+}\r
+\r
+// MAC アドレス削除指令受信\r
+void SiCalledDeleteMacTable(SERVER *s, PACK *p)\r
+{\r
+       UINT key;\r
+       char hubname[MAX_HUBNAME_LEN + 1];\r
+       HUB *h;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)\r
+       {\r
+               return;\r
+       }\r
+       key = PackGetInt(p, "Key");\r
+\r
+       LockHubList(s->Cedar);\r
+       {\r
+               h = GetHub(s->Cedar, hubname);\r
+       }\r
+       UnlockHubList(s->Cedar);\r
+\r
+       if (h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(h->MacTable);\r
+       {\r
+               if (IsInList(h->MacTable, (void *)key))\r
+               {\r
+                       MAC_TABLE_ENTRY *e = (MAC_TABLE_ENTRY *)key;\r
+                       Delete(h->MacTable, e);\r
+                       Free(e);\r
+               }\r
+       }\r
+       UnlockList(h->MacTable);\r
+\r
+       ReleaseHub(h);\r
+}\r
+\r
+// IP アドレス削除指令受信\r
+void SiCalledDeleteIpTable(SERVER *s, PACK *p)\r
+{\r
+       UINT key;\r
+       char hubname[MAX_HUBNAME_LEN + 1];\r
+       HUB *h;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)\r
+       {\r
+               return;\r
+       }\r
+       key = PackGetInt(p, "Key");\r
+\r
+       LockHubList(s->Cedar);\r
+       {\r
+               h = GetHub(s->Cedar, hubname);\r
+       }\r
+       UnlockHubList(s->Cedar);\r
+\r
+       if (h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(h->IpTable);\r
+       {\r
+               if (IsInList(h->IpTable, (void *)key))\r
+               {\r
+                       IP_TABLE_ENTRY *e = (IP_TABLE_ENTRY *)key;\r
+                       Delete(h->IpTable, e);\r
+                       Free(e);\r
+               }\r
+       }\r
+       UnlockList(h->IpTable);\r
+\r
+       ReleaseHub(h);\r
+}\r
+\r
+// セッション削除指令受信\r
+void SiCalledDeleteSession(SERVER *s, PACK *p)\r
+{\r
+       char name[MAX_SESSION_NAME_LEN + 1];\r
+       char hubname[MAX_HUBNAME_LEN + 1];\r
+       HUB *h;\r
+       SESSION *sess;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)\r
+       {\r
+               return;\r
+       }\r
+       if (PackGetStr(p, "SessionName", name, sizeof(name)) == false)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockHubList(s->Cedar);\r
+       {\r
+               h = GetHub(s->Cedar, hubname);\r
+       }\r
+       UnlockHubList(s->Cedar);\r
+\r
+       if (h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       sess = GetSessionByName(h, name);\r
+\r
+       if (sess != NULL)\r
+       {\r
+               if (sess->BridgeMode == false && sess->LinkModeServer == false && sess->SecureNATMode == false)\r
+               {\r
+                       StopSession(sess);\r
+               }\r
+               ReleaseSession(sess);\r
+       }\r
+\r
+       ReleaseHub(h);\r
+}\r
+\r
+// ログファイル読み込み指令受信\r
+PACK *SiCalledReadLogFile(SERVER *s, PACK *p)\r
+{\r
+       RPC_READ_LOG_FILE t;\r
+       PACK *ret;\r
+       char filepath[MAX_PATH];\r
+       UINT offset;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       PackGetStr(p, "FilePath", filepath, sizeof(filepath));\r
+       offset = PackGetInt(p, "Offset");\r
+\r
+       Zero(&t, sizeof(t));\r
+\r
+       SiReadLocalLogFile(s, filepath, offset, &t);\r
+\r
+       ret = NewPack();\r
+\r
+       OutRpcReadLogFile(ret, &t);\r
+       FreeRpcReadLogFile(&t);\r
+\r
+       return ret;\r
+}\r
+\r
+// ログファイル列挙指令受信\r
+PACK *SiCalledEnumLogFileList(SERVER *s, PACK *p)\r
+{\r
+       RPC_ENUM_LOG_FILE t;\r
+       PACK *ret;\r
+       char hubname[MAX_HUBNAME_LEN + 1];\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       PackGetStr(p, "HubName", hubname, sizeof(hubname));\r
+\r
+       Zero(&t, sizeof(t));\r
+\r
+       SiEnumLocalLogFileList(s, hubname, &t);\r
+\r
+       ret = NewPack();\r
+\r
+       OutRpcEnumLogFile(ret, &t);\r
+       FreeRpcEnumLogFile(&t);\r
+\r
+       return ret;\r
+}\r
+\r
+// セッション情報指令受信\r
+PACK *SiCalledGetSessionStatus(SERVER *s, PACK *p)\r
+{\r
+       RPC_SESSION_STATUS t;\r
+       ADMIN a;\r
+       PACK *ret;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       Zero(&t, sizeof(t));\r
+       InRpcSessionStatus(&t, p);\r
+\r
+       Zero(&a, sizeof(a));\r
+       a.Server = s;\r
+       a.ServerAdmin = true;\r
+\r
+       if (StGetSessionStatus(&a, &t) != ERR_NO_ERROR)\r
+       {\r
+               FreeRpcSessionStatus(&t);\r
+               return NULL;\r
+       }\r
+\r
+       ret = NewPack();\r
+\r
+       OutRpcSessionStatus(ret, &t);\r
+\r
+       FreeRpcSessionStatus(&t);\r
+\r
+       return ret;\r
+}\r
+\r
+// IP テーブル列挙指令\r
+PACK *SiCalledEnumIpTable(SERVER *s, PACK *p)\r
+{\r
+       char hubname[MAX_HUBNAME_LEN + 1];\r
+       RPC_ENUM_IP_TABLE t;\r
+       PACK *ret;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return NewPack();\r
+       }\r
+       if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)\r
+       {\r
+               return NewPack();\r
+       }\r
+       Zero(&t, sizeof(t));\r
+\r
+       SiEnumIpTable(s, hubname, &t);\r
+\r
+       ret = NewPack();\r
+       OutRpcEnumIpTable(ret, &t);\r
+       FreeRpcEnumIpTable(&t);\r
+\r
+       return ret;\r
+}\r
+\r
+// MAC テーブル列挙指令\r
+PACK *SiCalledEnumMacTable(SERVER *s, PACK *p)\r
+{\r
+       char hubname[MAX_HUBNAME_LEN + 1];\r
+       RPC_ENUM_MAC_TABLE t;\r
+       PACK *ret;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return NewPack();\r
+       }\r
+       if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)\r
+       {\r
+               return NewPack();\r
+       }\r
+       Zero(&t, sizeof(t));\r
+\r
+       SiEnumMacTable(s, hubname, &t);\r
+\r
+       ret = NewPack();\r
+       OutRpcEnumMacTable(ret, &t);\r
+       FreeRpcEnumMacTable(&t);\r
+\r
+       return ret;\r
+}\r
+\r
+// NAT の状況取得指令\r
+PACK *SiCalledGetNatStatus(SERVER *s, PACK *p)\r
+{\r
+       char hubname[MAX_HUBNAME_LEN + 1];\r
+       RPC_NAT_STATUS t;\r
+       PACK *ret;\r
+       HUB *h;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return NewPack();\r
+       }\r
+       if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)\r
+       {\r
+               return NewPack();\r
+       }\r
+       Zero(&t, sizeof(t));\r
+\r
+       LockHubList(s->Cedar);\r
+       {\r
+               h = GetHub(s->Cedar, hubname);\r
+       }\r
+       UnlockHubList(s->Cedar);\r
+\r
+       if (h != NULL)\r
+       {\r
+               Lock(h->lock_online);\r
+               {\r
+                       if (h->SecureNAT != NULL)\r
+                       {\r
+                               NtGetStatus(h->SecureNAT->Nat, &t);\r
+                       }\r
+               }\r
+               Unlock(h->lock_online);\r
+       }\r
+\r
+       ReleaseHub(h);\r
+\r
+       ret = NewPack();\r
+       OutRpcNatStatus(ret, &t);\r
+       FreeRpcNatStatus(&t);\r
+\r
+       return ret;\r
+}\r
+\r
+// DHCP テーブル列挙指令\r
+PACK *SiCalledEnumDhcp(SERVER *s, PACK *p)\r
+{\r
+       char hubname[MAX_HUBNAME_LEN + 1];\r
+       RPC_ENUM_DHCP t;\r
+       PACK *ret;\r
+       HUB *h;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return NewPack();\r
+       }\r
+       if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)\r
+       {\r
+               return NewPack();\r
+       }\r
+       Zero(&t, sizeof(t));\r
+\r
+       LockHubList(s->Cedar);\r
+       {\r
+               h = GetHub(s->Cedar, hubname);\r
+       }\r
+       UnlockHubList(s->Cedar);\r
+\r
+       if (h != NULL)\r
+       {\r
+               Lock(h->lock_online);\r
+               {\r
+                       if (h->SecureNAT != NULL)\r
+                       {\r
+                               NtEnumDhcpList(h->SecureNAT->Nat, &t);\r
+                       }\r
+               }\r
+               Unlock(h->lock_online);\r
+       }\r
+\r
+       ReleaseHub(h);\r
+\r
+       ret = NewPack();\r
+       OutRpcEnumDhcp(ret, &t);\r
+       FreeRpcEnumDhcp(&t);\r
+\r
+       return ret;\r
+}\r
+\r
+// NAT テーブル列挙指令\r
+PACK *SiCalledEnumNat(SERVER *s, PACK *p)\r
+{\r
+       char hubname[MAX_HUBNAME_LEN + 1];\r
+       RPC_ENUM_NAT t;\r
+       PACK *ret;\r
+       HUB *h;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return NewPack();\r
+       }\r
+       if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)\r
+       {\r
+               return NewPack();\r
+       }\r
+       Zero(&t, sizeof(t));\r
+\r
+       LockHubList(s->Cedar);\r
+       {\r
+               h = GetHub(s->Cedar, hubname);\r
+       }\r
+       UnlockHubList(s->Cedar);\r
+\r
+       if (h != NULL)\r
+       {\r
+               Lock(h->lock_online);\r
+               {\r
+                       if (h->SecureNAT != NULL)\r
+                       {\r
+                               NtEnumNatList(h->SecureNAT->Nat, &t);\r
+                       }\r
+               }\r
+               Unlock(h->lock_online);\r
+       }\r
+\r
+       ReleaseHub(h);\r
+\r
+       ret = NewPack();\r
+       OutRpcEnumNat(ret, &t);\r
+       FreeRpcEnumNat(&t);\r
+\r
+       return ret;\r
+}\r
+\r
+// セッション列挙指令受信\r
+PACK *SiCalledEnumSession(SERVER *s, PACK *p)\r
+{\r
+       char hubname[MAX_HUBNAME_LEN + 1];\r
+       RPC_ENUM_SESSION t;\r
+       PACK *ret;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return NewPack();\r
+       }\r
+       if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)\r
+       {\r
+               return NewPack();\r
+       }\r
+       Zero(&t, sizeof(t));\r
+\r
+       SiEnumLocalSession(s, hubname, &t);\r
+\r
+       ret = NewPack();\r
+       OutRpcEnumSession(ret, &t);\r
+       FreeRpcEnumSession(&t);\r
+\r
+       return ret;\r
+}\r
+\r
+// チケット作成指令受信\r
+PACK *SiCalledCreateTicket(SERVER *s, PACK *p)\r
+{\r
+       char username[MAX_SIZE];\r
+       char hubname[MAX_SIZE];\r
+       char groupname[MAX_SIZE];\r
+       char realusername[MAX_SIZE];\r
+       char sessionname[MAX_SESSION_NAME_LEN + 1];\r
+       POLICY policy;\r
+       UCHAR ticket[SHA1_SIZE];\r
+       char ticket_str[MAX_SIZE];\r
+       HUB *h;\r
+       UINT i;\r
+       PACK *ret;\r
+       TICKET *t;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return NewPack();\r
+       }\r
+\r
+       PackGetStr(p, "UserName", username, sizeof(username));\r
+       PackGetStr(p, "GroupName", groupname, sizeof(groupname));\r
+       PackGetStr(p, "HubName", hubname, sizeof(hubname));\r
+       PackGetStr(p, "RealUserName", realusername, sizeof(realusername));\r
+       PackGetStr(p, "SessionName", sessionname, sizeof(sessionname));\r
+\r
+       InRpcPolicy(&policy, p);\r
+       if (PackGetDataSize(p, "Ticket") == SHA1_SIZE)\r
+       {\r
+               PackGetData(p, "Ticket", ticket);\r
+       }\r
+\r
+       BinToStr(ticket_str, sizeof(ticket_str), ticket, SHA1_SIZE);\r
+\r
+       SLog(s->Cedar, "LS_TICKET_2", hubname, username, realusername, sessionname,\r
+               ticket_str, TICKET_EXPIRES / 1000);\r
+\r
+       // HUB を取得\r
+       h = GetHub(s->Cedar, hubname);\r
+       if (h == NULL)\r
+       {\r
+               return NewPack();\r
+       }\r
+\r
+       LockList(h->TicketList);\r
+       {\r
+               LIST *o = NewListFast(NULL);\r
+               // 古いチケットを破棄\r
+               for (i = 0;i < LIST_NUM(h->TicketList);i++)\r
+               {\r
+                       TICKET *t = LIST_DATA(h->TicketList, i);\r
+                       if ((t->CreatedTick + TICKET_EXPIRES) < Tick64())\r
+                       {\r
+                               Add(o, t);\r
+                       }\r
+               }\r
+               for (i = 0;i < LIST_NUM(o);i++)\r
+               {\r
+                       TICKET *t = LIST_DATA(o, i);\r
+                       Delete(h->TicketList, t);\r
+                       Free(t);\r
+               }\r
+               ReleaseList(o);\r
+\r
+               // チケットを作成\r
+               t = ZeroMalloc(sizeof(TICKET));\r
+               t->CreatedTick = Tick64();\r
+               Copy(&t->Policy, &policy, sizeof(POLICY));\r
+               Copy(t->Ticket, ticket, SHA1_SIZE);\r
+               StrCpy(t->Username, sizeof(t->Username), username);\r
+               StrCpy(t->UsernameReal, sizeof(t->UsernameReal), realusername);\r
+               StrCpy(t->GroupName, sizeof(t->GroupName), groupname);\r
+               StrCpy(t->SessionName, sizeof(t->SessionName), sessionname);\r
+\r
+               Add(h->TicketList, t);\r
+       }\r
+       UnlockList(h->TicketList);\r
+\r
+       ReleaseHub(h);\r
+\r
+       ret = NewPack();\r
+\r
+       PackAddInt(ret, "Point", SiGetPoint(s));\r
+\r
+       return ret;\r
+}\r
+\r
+// HUB 作成指令受信\r
+void SiCalledCreateHub(SERVER *s, PACK *p)\r
+{\r
+       char name[MAX_SIZE];\r
+       UINT type;\r
+       HUB_OPTION o;\r
+       HUB_LOG log;\r
+       bool save_packet_log;\r
+       UINT packet_log_switch_type;\r
+       UINT packet_log_config[NUM_PACKET_LOG];\r
+       bool save_security_log;\r
+       UINT security_log_switch_type;\r
+       UINT i;\r
+       HUB *h;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackGetStr(p, "HubName", name, sizeof(name));\r
+       type = PackGetInt(p, "HubType");\r
+       Zero(&o, sizeof(o));\r
+       o.MaxSession = PackGetInt(p, "MaxSession");\r
+       save_packet_log = PackGetInt(p, "SavePacketLog");\r
+       packet_log_switch_type = PackGetInt(p, "PacketLogSwitchType");\r
+       for (i = 0;i < NUM_PACKET_LOG;i++)\r
+       {\r
+               packet_log_config[i] = PackGetIntEx(p, "PacketLogConfig", i);\r
+       }\r
+       save_security_log = PackGetInt(p, "SaveSecurityLog");\r
+       security_log_switch_type = PackGetInt(p, "SecurityLogSwitchType");\r
+\r
+       Zero(&log, sizeof(log));\r
+       log.SavePacketLog = save_packet_log;\r
+       log.PacketLogSwitchType = packet_log_switch_type;\r
+       Copy(log.PacketLogConfig, packet_log_config, sizeof(log.PacketLogConfig));\r
+       log.SaveSecurityLog = save_security_log;\r
+       log.SecurityLogSwitchType = security_log_switch_type;\r
+\r
+       h = NewHub(s->Cedar, name, &o);\r
+       h->LastCommTime = h->LastLoginTime = h->CreatedTime = 0;\r
+       SetHubLogSetting(h, &log);\r
+       h->Type = type;\r
+       h->FarmMember_MaxSessionClient = PackGetInt(p, "MaxSessionClient");\r
+       h->FarmMember_MaxSessionBridge = PackGetInt(p, "MaxSessionBridge");\r
+       h->FarmMember_MaxSessionClientBridgeApply = PackGetBool(p, "MaxSessionClientBridgeApply");\r
+\r
+       if (h->FarmMember_MaxSessionClientBridgeApply == false)\r
+       {\r
+               h->FarmMember_MaxSessionClient = INFINITE;\r
+               h->FarmMember_MaxSessionBridge = INFINITE;\r
+       }\r
+\r
+       PackGetData2(p, "SecurePassword", h->SecurePassword, SHA1_SIZE);\r
+       PackGetData2(p, "HashedPassword", h->HashedPassword, SHA1_SIZE);\r
+\r
+       for (i = 0;i < SiNumAccessFromPack(p);i++)\r
+       {\r
+               ACCESS *a = SiPackToAccess(p, i);\r
+               AddAccessList(h, a);\r
+               Free(a);\r
+       }\r
+\r
+       if (PackGetBool(p, "EnableSecureNAT"))\r
+       {\r
+               VH_OPTION t;\r
+\r
+               InVhOption(&t, p);\r
+\r
+               Copy(h->SecureNATOption, &t, sizeof(VH_OPTION));\r
+               EnableSecureNAT(h, true);\r
+\r
+               Debug("SiCalledCreateHub: SecureNAT Created.\n");\r
+       }\r
+\r
+       AddHub(s->Cedar, h);\r
+       h->Offline = true;\r
+       SetHubOnline(h);\r
+\r
+       ReleaseHub(h);\r
+}\r
+\r
+// ファームコントロールスレッド\r
+void SiFarmControlThread(THREAD *thread, void *param)\r
+{\r
+       SERVER *s;\r
+       CEDAR *c;\r
+       EVENT *e;\r
+       LIST *o;\r
+       UINT i;\r
+       char tmp[MAX_PATH];\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s = (SERVER *)param;\r
+       c = s->Cedar;\r
+       e = s->FarmControlThreadHaltEvent;\r
+\r
+       while (true)\r
+       {\r
+               Lock(c->CedarSuperLock);\r
+\r
+               // 各ファームメンバーがホストしている HUB 一覧を列挙する\r
+               Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);\r
+               SiDebugLog(s, tmp);\r
+\r
+               LockList(s->FarmMemberList);\r
+               {\r
+                       UINT i;\r
+                       UINT num;\r
+                       UINT assigned_client_license = 0;\r
+                       UINT assigned_bridge_license = 0;\r
+\r
+                       Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);\r
+                       SiDebugLog(s, tmp);\r
+\r
+                       num = 0;\r
+\r
+                       for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)\r
+                       {\r
+                               FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);\r
+                               SiCallEnumHub(s, f);\r
+                               // サーバーファーム全体での合計セッション数を取得する\r
+                               num += f->NumSessions;\r
+\r
+                               assigned_client_license += f->AssignedClientLicense;\r
+                               assigned_bridge_license += f->AssignedBridgeLicense;\r
+                       }\r
+\r
+                       s->CurrentTotalNumSessionsOnFarm = num;\r
+\r
+                       // 割り当て済みライセンス数を更新する\r
+                       s->CurrentAssignedBridgeLicense = assigned_bridge_license;\r
+                       s->CurrentAssignedClientLicense = assigned_client_license;\r
+\r
+                       Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);\r
+                       SiDebugLog(s, tmp);\r
+               }\r
+               UnlockList(s->FarmMemberList);\r
+\r
+               Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);\r
+               SiDebugLog(s, tmp);\r
+\r
+               o = NewListFast(NULL);\r
+\r
+               Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);\r
+               SiDebugLog(s, tmp);\r
+\r
+               // 各 HUB に対して更新通知を発する\r
+               LockList(c->HubList);\r
+               {\r
+                       UINT i;\r
+                       for (i = 0;i < LIST_NUM(c->HubList);i++)\r
+                       {\r
+                               HUB *h = LIST_DATA(c->HubList, i);\r
+                               AddRef(h->ref);\r
+                               Add(o, h);\r
+                       }\r
+               }\r
+               UnlockList(c->HubList);\r
+\r
+               Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);\r
+               SiDebugLog(s, tmp);\r
+\r
+               for (i = 0;i < LIST_NUM(o);i++)\r
+               {\r
+                       HUB *h = LIST_DATA(o, i);\r
+                       SiHubUpdateProc(h);\r
+                       ReleaseHub(h);\r
+               }\r
+\r
+               Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);\r
+               SiDebugLog(s, tmp);\r
+\r
+               ReleaseList(o);\r
+\r
+               Unlock(c->CedarSuperLock);\r
+\r
+               Wait(e, SERVER_FARM_CONTROL_INTERVAL);\r
+               if (s->Halt)\r
+               {\r
+                       break;\r
+               }\r
+       }\r
+}\r
+\r
+// ファームコントロールの開始\r
+void SiStartFarmControl(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || s->ServerType != SERVER_TYPE_FARM_CONTROLLER)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s->FarmControlThreadHaltEvent = NewEvent();\r
+       s->FarmControlThread = NewThread(SiFarmControlThread, s);\r
+}\r
+\r
+// ファームコントロールの終了\r
+void SiStopFarmControl(SERVER *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || s->ServerType != SERVER_TYPE_FARM_CONTROLLER)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Set(s->FarmControlThreadHaltEvent);\r
+       WaitThread(s->FarmControlThread, INFINITE);\r
+       ReleaseEvent(s->FarmControlThreadHaltEvent);\r
+       ReleaseThread(s->FarmControlThread);\r
+}\r
+\r
+// HUB 列挙指令\r
+void SiCallEnumHub(SERVER *s, FARM_MEMBER *f)\r
+{\r
+       CEDAR *c;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       c = s->Cedar;\r
+\r
+       if (f->Me)\r
+       {\r
+               LICENSE_STATUS st;\r
+\r
+               LiParseCurrentLicenseStatus(s->LicenseSystem, &st);\r
+\r
+               // ローカルの HUB を列挙する\r
+               LockList(f->HubList);\r
+               {\r
+                       // ローカル HUB の場合、まず STATIC HUB リストを一旦\r
+                       // すべて消去して再列挙を行うようにする\r
+                       UINT i;\r
+                       LIST *o = NewListFast(NULL);\r
+                       for (i = 0;i < LIST_NUM(f->HubList);i++)\r
+                       {\r
+                               HUB_LIST *h = LIST_DATA(f->HubList, i);\r
+                               if (h->DynamicHub == false)\r
+                               {\r
+                                       Add(o, h);\r
+                               }\r
+                       }\r
+\r
+                       // STATIC HUB をすべて消去\r
+                       for (i = 0;i < LIST_NUM(o);i++)\r
+                       {\r
+                               HUB_LIST *h = LIST_DATA(o, i);\r
+                               Free(h);\r
+                               Delete(f->HubList, h);\r
+                       }\r
+                       ReleaseList(o);\r
+\r
+                       // 次に DYNAMIC HUB でユーザーが 1 人もいないものを停止する\r
+                       o = NewListFast(NULL);\r
+                       for (i = 0;i < LIST_NUM(f->HubList);i++)\r
+                       {\r
+                               HUB_LIST *h = LIST_DATA(f->HubList, i);\r
+                               if (h->DynamicHub == true)\r
+                               {\r
+                                       LockList(c->HubList);\r
+                                       {\r
+                                               HUB *hub = GetHub(s->Cedar, h->Name);\r
+                                               if (hub != NULL)\r
+                                               {\r
+                                                       if (Count(hub->NumSessions) == 0 || hub->Type != HUB_TYPE_FARM_DYNAMIC)\r
+                                                       {\r
+                                                               Add(o, h);\r
+                                                       }\r
+                                                       ReleaseHub(hub);\r
+                                               }\r
+                                       }\r
+                                       UnlockList(c->HubList);\r
+                               }\r
+                       }\r
+\r
+                       for (i = 0;i < LIST_NUM(o);i++)\r
+                       {\r
+                               HUB_LIST *h = LIST_DATA(o, i);\r
+                               Debug("Delete HUB: %s\n", h->Name);\r
+                               Free(h);\r
+                               Delete(f->HubList, h);\r
+                       }\r
+\r
+                       ReleaseList(o);\r
+\r
+                       // 列挙結果を設定\r
+                       LockList(c->HubList);\r
+                       {\r
+                               for (i = 0;i < LIST_NUM(c->HubList);i++)\r
+                               {\r
+                                       HUB *h = LIST_DATA(c->HubList, i);\r
+                                       if (h->Offline == false)\r
+                                       {\r
+                                               if (h->Type == HUB_TYPE_FARM_STATIC)\r
+                                               {\r
+                                                       HUB_LIST *hh = ZeroMalloc(sizeof(HUB_LIST));\r
+                                                       hh->FarmMember = f;\r
+                                                       hh->DynamicHub = false;\r
+                                                       StrCpy(hh->Name, sizeof(hh->Name), h->Name);\r
+                                                       Add(f->HubList, hh);\r
+\r
+                                                       LockList(h->SessionList);\r
+                                                       {\r
+                                                               hh->NumSessions = LIST_NUM(h->SessionList);\r
+                                                               hh->NumSessionsBridge = Count(h->NumSessionsBridge);\r
+                                                               hh->NumSessionsClient = Count(h->NumSessionsClient);\r
+                                                       }\r
+                                                       UnlockList(h->SessionList);\r
+\r
+                                                       LockList(h->MacTable);\r
+                                                       {\r
+                                                               hh->NumMacTables = LIST_NUM(h->MacTable);\r
+                                                       }\r
+                                                       UnlockList(h->MacTable);\r
+\r
+                                                       LockList(h->IpTable);\r
+                                                       {\r
+                                                               hh->NumIpTables = LIST_NUM(h->IpTable);\r
+                                                       }\r
+                                                       UnlockList(h->IpTable);\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       UnlockList(c->HubList);\r
+               }\r
+               UnlockList(f->HubList);\r
+\r
+               // ポイント\r
+               f->Point = SiGetPoint(s);\r
+               f->NumSessions = Count(s->Cedar->CurrentSessions);\r
+               f->MaxSessions = GetServerCapsInt(s, "i_max_sessions");\r
+               f->NumTcpConnections = Count(s->Cedar->CurrentTcpConnections);\r
+\r
+               Lock(s->Cedar->TrafficLock);\r
+               {\r
+                       Copy(&f->Traffic, s->Cedar->Traffic, sizeof(TRAFFIC));\r
+               }\r
+               Unlock(s->Cedar->TrafficLock);\r
+\r
+               f->AssignedBridgeLicense = Count(s->Cedar->AssignedBridgeLicense);\r
+               f->AssignedClientLicense = Count(s->Cedar->AssignedClientLicense);\r
+\r
+               Copy(f->RandomKey, s->MyRandomKey, SHA1_SIZE);\r
+               f->SystemId = st.SystemId;\r
+\r
+               Debug("Server %s: Point %u\n", f->hostname, f->Point);\r
+       }\r
+       else\r
+       {\r
+               // リモートのメンバの HUB を列挙する\r
+               PACK *p = NewPack();\r
+               UINT i, num, j;\r
+               LIST *o = NewListFast(NULL);\r
+\r
+               num = 0;\r
+\r
+               for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)\r
+               {\r
+                       FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);\r
+\r
+                       if (IsZero(f->RandomKey, SHA1_SIZE) == false && f->SystemId != 0)\r
+                       {\r
+                               num++;\r
+                       }\r
+               }\r
+\r
+               j = 0;\r
+\r
+               for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)\r
+               {\r
+                       FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);\r
+\r
+                       if (IsZero(f->RandomKey, SHA1_SIZE) == false && f->SystemId != 0)\r
+                       {\r
+                               PackAddDataEx(p, "MemberRandomKey", f->RandomKey, SHA1_SIZE, j, num);\r
+                               PackAddInt64Ex(p, "MemberSystemId", f->SystemId, j, num);\r
+                               j++;\r
+                       }\r
+               }\r
+               PackAddInt(p, "MemberSystemIdNum", num);\r
+\r
+               p = SiCallTask(f, p, "enumhub");\r
+               if (p != NULL)\r
+               {\r
+                       LockList(f->HubList);\r
+                       {\r
+                               UINT i;\r
+                               // リスト消去\r
+                               for (i = 0;i < LIST_NUM(f->HubList);i++)\r
+                               {\r
+                                       HUB_LIST *hh = LIST_DATA(f->HubList, i);\r
+                                       Free(hh);\r
+                               }\r
+                               DeleteAll(f->HubList);\r
+\r
+                               for (i = 0;i < PackGetIndexCount(p, "HubName");i++)\r
+                               {\r
+                                       HUB_LIST *hh = ZeroMalloc(sizeof(HUB_LIST));\r
+                                       UINT num;\r
+                                       UINT64 LastCommTime;\r
+\r
+                                       PackGetStrEx(p, "HubName", hh->Name, sizeof(hh->Name), i);\r
+                                       num = PackGetIntEx(p, "NumSession", i);\r
+                                       hh->DynamicHub = ((PackGetIntEx(p, "HubType", i) == HUB_TYPE_FARM_DYNAMIC) ? true : false);\r
+                                       hh->FarmMember = f;\r
+                                       hh->NumSessions = PackGetIntEx(p, "NumSessions", i);\r
+                                       hh->NumSessionsClient = PackGetIntEx(p, "NumSessionsClient", i);\r
+                                       hh->NumSessionsBridge = PackGetIntEx(p, "NumSessionsBridge", i);\r
+                                       hh->NumIpTables = PackGetIntEx(p, "NumIpTables", i);\r
+                                       hh->NumMacTables = PackGetIntEx(p, "NumMacTables", i);\r
+                                       LastCommTime = PackGetInt64Ex(p, "LastCommTime", i);\r
+                                       Add(f->HubList, hh);\r
+                                       Debug("%s\n", hh->Name);\r
+\r
+                                       LockList(c->HubList);\r
+                                       {\r
+                                               HUB *h = GetHub(c, hh->Name);\r
+\r
+                                               if (h != NULL)\r
+                                               {\r
+                                                       // 仮想 HUB の LastCommTime を更新する\r
+                                                       Lock(h->lock);\r
+                                                       {\r
+                                                               if (h->LastCommTime < LastCommTime)\r
+                                                               {\r
+                                                                       h->LastCommTime = LastCommTime;\r
+                                                               }\r
+                                                       }\r
+                                                       Unlock(h->lock);\r
+\r
+                                                       ReleaseHub(h);\r
+                                               }\r
+                                       }\r
+                                       UnlockList(c->HubList);\r
+\r
+                                       if (hh->DynamicHub && num >= 1)\r
+                                       {\r
+                                               // すでにユーザーセッションが 1 以上接続されているので\r
+                                               // 仮想 HUB 作成履歴リストに登録しておく必要はない\r
+                                               // 仮想 HUB 作成履歴リストから削除する\r
+                                               SiDelHubCreateHistory(s, hh->Name);\r
+                                       }\r
+\r
+                                       if (hh->DynamicHub && num == 0)\r
+                                       {\r
+                                               // 仮想 HUB 作成履歴リストを確認する\r
+                                               // 直近 60 秒以内に作成され、まだ 1 人目のユーザーが接続\r
+                                               // していない仮想 HUB の場合は、ユーザーが 1 人もいないという\r
+                                               // 理由で削除しない\r
+                                               if (SiIsHubRegistedOnCreateHistory(s, hh->Name) == false)\r
+                                               {\r
+                                                       // ダイナミック HUB でユーザーが 1 人もいないので停止する\r
+                                                       HUB *h;\r
+                                                       LockList(c->HubList);\r
+                                                       {\r
+                                                               h = GetHub(c, hh->Name);\r
+                                                       }\r
+                                                       UnlockList(c->HubList);\r
+\r
+                                                       if (h != NULL)\r
+                                                       {\r
+                                                               Add(o, h);\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       UnlockList(f->HubList);\r
+                       f->Point = PackGetInt(p, "Point");\r
+                       Debug("Server %s: Point %u\n", f->hostname, f->Point);\r
+                       f->NumSessions = PackGetInt(p, "NumTotalSessions");\r
+                       if (f->NumSessions == 0)\r
+                       {\r
+                               f->NumSessions = PackGetInt(p, "NumSessions");\r
+                       }\r
+                       f->MaxSessions = PackGetInt(p, "MaxSessions");\r
+                       f->NumTcpConnections = PackGetInt(p, "NumTcpConnections");\r
+                       InRpcTraffic(&f->Traffic, p);\r
+\r
+                       f->AssignedBridgeLicense = PackGetInt(p, "AssignedBridgeLicense");\r
+                       f->AssignedClientLicense = PackGetInt(p, "AssignedClientLicense");\r
+\r
+                       if (PackGetDataSize(p, "RandomKey") == SHA1_SIZE)\r
+                       {\r
+                               PackGetData(p, "RandomKey", f->RandomKey);\r
+                       }\r
+\r
+                       f->SystemId = PackGetInt64(p, "SystemId");\r
+\r
+                       // トラフィック差分情報を適用する\r
+                       num = PackGetIndexCount(p, "TdType");\r
+                       for (i = 0;i < num;i++)\r
+                       {\r
+                               TRAFFIC traffic;\r
+                               UINT type;\r
+                               HUB *h;\r
+                               char name[MAX_SIZE];\r
+                               char hubname[MAX_SIZE];\r
+\r
+                               type = PackGetIntEx(p, "TdType", i);\r
+                               PackGetStrEx(p, "TdName", name, sizeof(name), i);\r
+                               PackGetStrEx(p, "TdHubName", hubname, sizeof(hubname), i);\r
+                               InRpcTrafficEx(&traffic, p, i);\r
+\r
+                               LockList(c->HubList);\r
+                               {\r
+                                       h = GetHub(c, hubname);\r
+                                       if (h != NULL)\r
+                                       {\r
+                                               if (type == TRAFFIC_DIFF_HUB)\r
+                                               {\r
+                                                       Lock(h->TrafficLock);\r
+                                                       {\r
+                                                               AddTraffic(h->Traffic, &traffic);\r
+                                                       }\r
+                                                       Unlock(h->TrafficLock);\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       AcLock(h);\r
+                                                       {\r
+                                                               USER *u = AcGetUser(h, name);\r
+                                                               if (u != NULL)\r
+                                                               {\r
+                                                                       Lock(u->lock);\r
+                                                                       {\r
+                                                                               AddTraffic(u->Traffic, &traffic);\r
+                                                                       }\r
+                                                                       Unlock(u->lock);\r
+                                                                       if (u->Group != NULL)\r
+                                                                       {\r
+                                                                               Lock(u->Group->lock);\r
+                                                                               {\r
+                                                                                       AddTraffic(u->Group->Traffic, &traffic);\r
+                                                                               }\r
+                                                                               Unlock(u->Group->lock);\r
+                                                                       }\r
+                                                                       ReleaseUser(u);\r
+                                                               }\r
+                                                       }\r
+                                                       AcUnlock(h);\r
+                                               }\r
+                                               ReleaseHub(h);\r
+                                       }\r
+                                       UnlockList(c->HubList);\r
+                               }\r
+                       }\r
+\r
+                       FreePack(p);\r
+               }\r
+\r
+               for (i = 0;i < LIST_NUM(o);i++)\r
+               {\r
+                       HUB *h = LIST_DATA(o, i);\r
+                       SiCallDeleteHub(s, f, h);\r
+                       Debug("Delete HUB: %s\n", h->Name);\r
+                       ReleaseHub(h);\r
+               }\r
+\r
+               ReleaseList(o);\r
+       }\r
+}\r
+\r
+// セッション情報取得指令\r
+bool SiCallGetSessionStatus(SERVER *s, FARM_MEMBER *f, RPC_SESSION_STATUS *t)\r
+{\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcSessionStatus(p, t);\r
+       FreeRpcSessionStatus(t);\r
+       Zero(t, sizeof(RPC_SESSION_STATUS));\r
+\r
+       p = SiCallTask(f, p, "getsessionstatus");\r
+\r
+       if (p == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       InRpcSessionStatus(t, p);\r
+       FreePack(p);\r
+\r
+       return true;\r
+}\r
+\r
+// ログファイル読み込み指令\r
+bool SiCallReadLogFile(SERVER *s, FARM_MEMBER *f, RPC_READ_LOG_FILE *t)\r
+{\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcReadLogFile(p, t);\r
+       FreeRpcReadLogFile(t);\r
+       Zero(t, sizeof(RPC_READ_LOG_FILE));\r
+\r
+       p = SiCallTask(f, p, "readlogfile");\r
+\r
+       if (p == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       InRpcReadLogFile(t, p);\r
+       FreePack(p);\r
+\r
+       return true;\r
+}\r
+\r
+// ログファイルリスト列挙指令\r
+bool SiCallEnumLogFileList(SERVER *s, FARM_MEMBER *f, RPC_ENUM_LOG_FILE *t, char *hubname)\r
+{\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcEnumLogFile(p, t);\r
+       FreeRpcEnumLogFile(t);\r
+       Zero(t, sizeof(RPC_ENUM_LOG_FILE));\r
+\r
+       PackAddStr(p, "HubName", hubname);\r
+\r
+       p = SiCallTask(f, p, "enumlogfilelist");\r
+\r
+       if (p == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       InRpcEnumLogFile(t, p);\r
+       FreePack(p);\r
+\r
+       return true;\r
+}\r
+\r
+// HUB 削除指令\r
+void SiCallDeleteHub(SERVER *s, FARM_MEMBER *f, HUB *h)\r
+{\r
+       PACK *p;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (f->Me == false)\r
+       {\r
+               p = NewPack();\r
+\r
+               PackAddStr(p, "HubName", h->Name);\r
+\r
+               p = SiCallTask(f, p, "deletehub");\r
+               FreePack(p);\r
+       }\r
+\r
+       LockList(f->HubList);\r
+       {\r
+               for (i = 0;i < LIST_NUM(f->HubList);i++)\r
+               {\r
+                       HUB_LIST *hh = LIST_DATA(f->HubList, i);\r
+                       if (StrCmpi(hh->Name, h->Name) == 0)\r
+                       {\r
+                               Free(hh);\r
+                               Delete(f->HubList, hh);\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(f->HubList);\r
+}\r
+\r
+// HUB 更新指令送信\r
+void SiCallUpdateHub(SERVER *s, FARM_MEMBER *f, HUB *h)\r
+{\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (f->Me == false)\r
+       {\r
+               p = NewPack();\r
+\r
+               SiPackAddCreateHub(p, h);\r
+\r
+               p = SiCallTask(f, p, "updatehub");\r
+               FreePack(p);\r
+       }\r
+}\r
+\r
+// チケット作成指令送信\r
+void SiCallCreateTicket(SERVER *s, FARM_MEMBER *f, char *hubname, char *username, char *realusername, POLICY *policy, UCHAR *ticket, UINT counter, char *groupname)\r
+{\r
+       PACK *p;\r
+       char name[MAX_SESSION_NAME_LEN + 1];\r
+       char hub_name_upper[MAX_SIZE];\r
+       char user_name_upper[MAX_USERNAME_LEN + 1];\r
+       char ticket_str[MAX_SIZE];\r
+       UINT point;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL || realusername == NULL || hubname == NULL || username == NULL || policy == NULL || ticket == NULL)\r
+       {\r
+               return;\r
+       }\r
+       if (groupname == NULL)\r
+       {\r
+               groupname = "";\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "HubName", hubname);\r
+       PackAddStr(p, "UserName", username);\r
+       PackAddStr(p, "groupname", groupname);\r
+       PackAddStr(p, "RealUserName", realusername);\r
+       OutRpcPolicy(p, policy);\r
+       PackAddData(p, "Ticket", ticket, SHA1_SIZE);\r
+\r
+       BinToStr(ticket_str, sizeof(ticket_str), ticket, SHA1_SIZE);\r
+\r
+       StrCpy(hub_name_upper, sizeof(hub_name_upper), hubname);\r
+       StrUpper(hub_name_upper);\r
+       StrCpy(user_name_upper, sizeof(user_name_upper), username);\r
+       StrUpper(user_name_upper);\r
+       Format(name, sizeof(name), "SID-%s-%u", user_name_upper,\r
+               counter);\r
+       PackAddStr(p, "SessionName", name);\r
+\r
+       p = SiCallTask(f, p, "createticket");\r
+\r
+       SLog(s->Cedar, "LS_TICKET_1", f->hostname, hubname, username, realusername, name, ticket_str);\r
+\r
+       point = PackGetInt(p, "Point");\r
+       if (point != 0)\r
+       {\r
+               f->Point = point;\r
+               f->NumSessions++;\r
+       }\r
+\r
+       FreePack(p);\r
+}\r
+\r
+// MAC アドレス削除指令送信\r
+void SiCallDeleteMacTable(SERVER *s, FARM_MEMBER *f, char *hubname, UINT key)\r
+{\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL || hubname == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "HubName", hubname);\r
+       PackAddInt(p, "Key", key);\r
+\r
+       p = SiCallTask(f, p, "deletemactable");\r
+\r
+       FreePack(p);\r
+}\r
+\r
+// IP アドレス削除指令送信\r
+void SiCallDeleteIpTable(SERVER *s, FARM_MEMBER *f, char *hubname, UINT key)\r
+{\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL || hubname == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "HubName", hubname);\r
+       PackAddInt(p, "Key", key);\r
+\r
+       p = SiCallTask(f, p, "deleteiptable");\r
+\r
+       FreePack(p);\r
+}\r
+\r
+// セッション削除指令送信\r
+void SiCallDeleteSession(SERVER *s, FARM_MEMBER *f, char *hubname, char *session_name)\r
+{\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL || hubname == NULL || session_name == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "HubName", hubname);\r
+       PackAddStr(p, "SessionName", session_name);\r
+\r
+       p = SiCallTask(f, p, "deletesession");\r
+\r
+       FreePack(p);\r
+}\r
+\r
+// IP テーブル列挙指令送信\r
+void SiCallEnumIpTable(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_IP_TABLE *t)\r
+{\r
+       PACK *p;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL || hubname == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "HubName", hubname);\r
+\r
+       p = SiCallTask(f, p, "enumiptable");\r
+\r
+       Zero(t, sizeof(RPC_ENUM_IP_TABLE));\r
+       InRpcEnumIpTable(t, p);\r
+\r
+       for (i = 0;i < t->NumIpTable;i++)\r
+       {\r
+               t->IpTables[i].RemoteItem = true;\r
+               StrCpy(t->IpTables[i].RemoteHostname, sizeof(t->IpTables[i].RemoteHostname),\r
+                       f->hostname);\r
+       }\r
+\r
+       FreePack(p);\r
+}\r
+\r
+// MAC テーブル列挙指令送信\r
+void SiCallEnumMacTable(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_MAC_TABLE *t)\r
+{\r
+       PACK *p;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL || hubname == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "HubName", hubname);\r
+\r
+       p = SiCallTask(f, p, "enummactable");\r
+\r
+       Zero(t, sizeof(RPC_ENUM_MAC_TABLE));\r
+       InRpcEnumMacTable(t, p);\r
+\r
+       for (i = 0;i < t->NumMacTable;i++)\r
+       {\r
+               t->MacTables[i].RemoteItem = true;\r
+               StrCpy(t->MacTables[i].RemoteHostname, sizeof(t->MacTables[i].RemoteHostname),\r
+                       f->hostname);\r
+       }\r
+\r
+       FreePack(p);\r
+}\r
+\r
+// SecureNAT 状況の取得指令送信\r
+void SiCallGetNatStatus(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_NAT_STATUS *t)\r
+{\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL || hubname == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "HubName", hubname);\r
+\r
+       p = SiCallTask(f, p, "getnatstatus");\r
+\r
+       Zero(t, sizeof(RPC_NAT_STATUS));\r
+       InRpcNatStatus(t, p);\r
+\r
+       FreePack(p);\r
+}\r
+\r
+// DHCP エントリ列挙指令送信\r
+void SiCallEnumDhcp(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_DHCP *t)\r
+{\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL || hubname == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "HubName", hubname);\r
+\r
+       p = SiCallTask(f, p, "enumdhcp");\r
+\r
+       Zero(t, sizeof(RPC_ENUM_DHCP));\r
+       InRpcEnumDhcp(t, p);\r
+\r
+       FreePack(p);\r
+}\r
+\r
+// NAT エントリ列挙指令送信\r
+void SiCallEnumNat(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_NAT *t)\r
+{\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL || hubname == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "HubName", hubname);\r
+\r
+       p = SiCallTask(f, p, "enumnat");\r
+\r
+       Zero(t, sizeof(RPC_ENUM_NAT));\r
+       InRpcEnumNat(t, p);\r
+\r
+       FreePack(p);\r
+}\r
+\r
+// セッション列挙指令送信\r
+void SiCallEnumSession(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_SESSION *t)\r
+{\r
+       PACK *p;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL || hubname == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "HubName", hubname);\r
+\r
+       p = SiCallTask(f, p, "enumsession");\r
+\r
+       Zero(t, sizeof(RPC_ENUM_SESSION));\r
+       InRpcEnumSession(t, p);\r
+\r
+       for (i = 0;i < t->NumSession;i++)\r
+       {\r
+               t->Sessions[i].RemoteSession = true;\r
+               StrCpy(t->Sessions[i].RemoteHostname, sizeof(t->Sessions[i].RemoteHostname),\r
+                       f->hostname);\r
+       }\r
+\r
+       FreePack(p);\r
+}\r
+\r
+// HUB 作成指令送信\r
+void SiCallCreateHub(SERVER *s, FARM_MEMBER *f, HUB *h)\r
+{\r
+       PACK *p;\r
+       HUB_LIST *hh;\r
+       // 引数チェック\r
+       if (s == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (f->Me == false)\r
+       {\r
+               p = NewPack();\r
+\r
+               SiPackAddCreateHub(p, h);\r
+\r
+               p = SiCallTask(f, p, "createhub");\r
+               FreePack(p);\r
+       }\r
+\r
+       hh = ZeroMalloc(sizeof(HUB_LIST));\r
+       hh->DynamicHub = (h->Type == HUB_TYPE_FARM_DYNAMIC ? true : false);\r
+       StrCpy(hh->Name, sizeof(hh->Name), h->Name);\r
+       hh->FarmMember = f;\r
+\r
+       LockList(f->HubList);\r
+       {\r
+               bool exists = false;\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(f->HubList);i++)\r
+               {\r
+                       HUB_LIST *t = LIST_DATA(f->HubList, i);\r
+                       if (StrCmpi(t->Name, hh->Name) == 0)\r
+                       {\r
+                               exists = true;\r
+                       }\r
+               }\r
+               if (exists == false)\r
+               {\r
+                       Add(f->HubList, hh);\r
+               }\r
+               else\r
+               {\r
+                       Free(hh);\r
+               }\r
+       }\r
+       UnlockList(f->HubList);\r
+}\r
+\r
+// HUB 作成用 PACK の書き込み\r
+void SiPackAddCreateHub(PACK *p, HUB *h)\r
+{\r
+       UINT i;\r
+       UINT max_session;\r
+       SERVER *s;\r
+       LICENSE_STATUS license;\r
+       // 引数チェック\r
+       if (p == NULL || h == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(&license, sizeof(license));\r
+       s = h->Cedar->Server;\r
+       if (s != NULL)\r
+       {\r
+               LiParseCurrentLicenseStatus(s->LicenseSystem, &license);\r
+       }\r
+\r
+       PackAddStr(p, "HubName", h->Name);\r
+       PackAddInt(p, "HubType", h->Type);\r
+\r
+       max_session = h->Option->MaxSession;\r
+\r
+       if (GetHubAdminOption(h, "max_sessions") != 0)\r
+       {\r
+               if (max_session == 0)\r
+               {\r
+                       max_session = GetHubAdminOption(h, "max_sessions");\r
+               }\r
+               else\r
+               {\r
+                       max_session = MIN(max_session, GetHubAdminOption(h, "max_sessions"));\r
+               }\r
+       }\r
+\r
+       PackAddInt(p, "MaxSession", max_session);\r
+\r
+       if (GetHubAdminOption(h, "max_sessions_client_bridge_apply") != 0 || license.CarrierEdition)\r
+       {\r
+               PackAddInt(p, "MaxSessionClient", GetHubAdminOption(h, "max_sessions_client"));\r
+               PackAddInt(p, "MaxSessionBridge", GetHubAdminOption(h, "max_sessions_bridge"));\r
+               PackAddBool(p, "MaxSessionClientBridgeApply", true);\r
+       }\r
+       else\r
+       {\r
+               PackAddInt(p, "MaxSessionClient", INFINITE);\r
+               PackAddInt(p, "MaxSessionBridge", INFINITE);\r
+       }\r
+\r
+       PackAddBool(p, "NoArpPolling", h->Option->NoArpPolling);\r
+       PackAddBool(p, "NoIPv6AddrPolling", h->Option->NoIPv6AddrPolling);\r
+       PackAddBool(p, "NoIpTable", h->Option->NoIpTable);\r
+       PackAddBool(p, "NoEnum", h->Option->NoEnum);\r
+       PackAddBool(p, "FilterPPPoE", h->Option->FilterPPPoE);\r
+       PackAddBool(p, "YieldAfterStorePacket", h->Option->YieldAfterStorePacket);\r
+       PackAddBool(p, "NoSpinLockForPacketDelay", h->Option->NoSpinLockForPacketDelay);\r
+       PackAddInt(p, "BroadcastStormDetectionThreshold", h->Option->BroadcastStormDetectionThreshold);\r
+       PackAddInt(p, "ClientMinimumRequiredBuild", h->Option->ClientMinimumRequiredBuild);\r
+       PackAddBool(p, "FixForDLinkBPDU", h->Option->FixForDLinkBPDU);\r
+       PackAddBool(p, "NoLookBPDUBridgeId", h->Option->NoLookBPDUBridgeId);\r
+       PackAddBool(p, "NoManageVlanId", h->Option->NoManageVlanId);\r
+       PackAddInt(p, "VlanTypeId", h->Option->VlanTypeId);\r
+       PackAddBool(p, "FilterOSPF", h->Option->FilterOSPF);\r
+       PackAddBool(p, "FilterIPv4", h->Option->FilterIPv4);\r
+       PackAddBool(p, "FilterIPv6", h->Option->FilterIPv6);\r
+       PackAddBool(p, "FilterNonIP", h->Option->FilterNonIP);\r
+       PackAddBool(p, "NoIPv4PacketLog", h->Option->NoIPv4PacketLog);\r
+       PackAddBool(p, "NoIPv6PacketLog", h->Option->NoIPv6PacketLog);\r
+       PackAddBool(p, "FilterBPDU", h->Option->FilterBPDU);\r
+       PackAddBool(p, "NoIPv6DefaultRouterInRAWhenIPv6", h->Option->NoIPv6DefaultRouterInRAWhenIPv6);\r
+       PackAddBool(p, "NoMacAddressLog", h->Option->NoMacAddressLog);\r
+       PackAddBool(p, "ManageOnlyPrivateIP", h->Option->ManageOnlyPrivateIP);\r
+       PackAddBool(p, "ManageOnlyLocalUnicastIPv6", h->Option->ManageOnlyLocalUnicastIPv6);\r
+       PackAddBool(p, "DisableIPParsing", h->Option->DisableIPParsing);\r
+\r
+       PackAddInt(p, "SavePacketLog", h->LogSetting.SavePacketLog);\r
+       PackAddInt(p, "PacketLogSwitchType", h->LogSetting.PacketLogSwitchType);\r
+       for (i = 0;i < NUM_PACKET_LOG;i++)\r
+       {\r
+               PackAddIntEx(p, "PacketLogConfig", h->LogSetting.PacketLogConfig[i], i, NUM_PACKET_LOG);\r
+       }\r
+       PackAddInt(p, "SaveSecurityLog", h->LogSetting.SaveSecurityLog);\r
+       PackAddInt(p, "SecurityLogSwitchType", h->LogSetting.SecurityLogSwitchType);\r
+       PackAddData(p, "HashedPassword", h->HashedPassword, SHA1_SIZE);\r
+       PackAddData(p, "SecurePassword", h->SecurePassword, SHA1_SIZE);\r
+\r
+       SiAccessListToPack(p, h->AccessList);\r
+\r
+       if (h->EnableSecureNAT)\r
+       {\r
+               PackAddBool(p, "EnableSecureNAT", h->EnableSecureNAT);\r
+               OutVhOption(p, h->SecureNATOption);\r
+       }\r
+}\r
+\r
+// HUB の設定が更新された\r
+void SiHubUpdateProc(HUB *h)\r
+{\r
+       SERVER *s;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (h == NULL || h->Cedar->Server == NULL || h->Cedar->Server->ServerType != SERVER_TYPE_FARM_CONTROLLER)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s = h->Cedar->Server;\r
+\r
+       if (s->FarmMemberList == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (h->LastVersion != h->CurrentVersion || h->CurrentVersion == 0)\r
+       {\r
+               if (h->CurrentVersion == 0)\r
+               {\r
+                       h->CurrentVersion = 1;\r
+               }\r
+               h->LastVersion = h->CurrentVersion;\r
+\r
+               LockList(s->FarmMemberList);\r
+               {\r
+                       // すべてのメンバで HUB を更新する\r
+                       for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)\r
+                       {\r
+                               FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);\r
+                               if (f->Me == false)\r
+                               {\r
+                                       SiCallUpdateHub(s, f, h);\r
+                               }\r
+                       }\r
+               }\r
+               UnlockList(s->FarmMemberList);\r
+       }\r
+\r
+       if (h->Offline == false)\r
+       {\r
+               SiHubOnlineProc(h);\r
+       }\r
+}\r
+\r
+// HUB がオンラインになった\r
+void SiHubOnlineProc(HUB *h)\r
+{\r
+       SERVER *s;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (h == NULL || h->Cedar->Server == NULL || h->Cedar->Server->ServerType != SERVER_TYPE_FARM_CONTROLLER)\r
+       {\r
+               // ファームコントローラ以外では処理しない\r
+               return;\r
+       }\r
+\r
+       s = h->Cedar->Server;\r
+\r
+       if (s->FarmMemberList == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(s->FarmMemberList);\r
+       {\r
+               if (h->Type == HUB_TYPE_FARM_STATIC)\r
+               {\r
+                       // スタティック HUB\r
+                       // すべてのメンバで HUB を作成する\r
+                       for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)\r
+                       {\r
+                               UINT j;\r
+                               bool exists = false;\r
+                               FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);\r
+\r
+                               LockList(f->HubList);\r
+                               {\r
+                                       for (j = 0;j < LIST_NUM(f->HubList);j++)\r
+                                       {\r
+                                               HUB_LIST *hh = LIST_DATA(f->HubList, j);\r
+                                               if (StrCmpi(hh->Name, h->Name) == 0)\r
+                                               {\r
+                                                       exists = true;\r
+                                               }\r
+                                       }\r
+                               }\r
+                               UnlockList(f->HubList);\r
+\r
+                               if (exists == false)\r
+                               {\r
+                                       SiCallCreateHub(s, f, h);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(s->FarmMemberList);\r
+}\r
+\r
+// HUB がオフラインになった\r
+void SiHubOfflineProc(HUB *h)\r
+{\r
+       SERVER *s;\r
+       char hubname[MAX_HUBNAME_LEN + 1];\r
+       UINT i;\r
+       // 引数チェック\r
+       if (h == NULL || h->Cedar->Server == NULL || h->Cedar->Server->ServerType != SERVER_TYPE_FARM_CONTROLLER)\r
+       {\r
+               // ファームコントローラ以外では処理しない\r
+               return;\r
+       }\r
+\r
+       s = h->Cedar->Server;\r
+\r
+       if (s->FarmMemberList == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       StrCpy(hubname, sizeof(hubname), h->Name);\r
+\r
+       LockList(s->FarmMemberList);\r
+       {\r
+               // すべてのメンバで HUB を停止する\r
+               for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)\r
+               {\r
+                       FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);\r
+                       SiCallDeleteHub(s, f, h);\r
+               }\r
+       }\r
+       UnlockList(s->FarmMemberList);\r
+}\r
+\r
+// アクセスを PACK に変換する\r
+void SiAccessToPack(PACK *p, ACCESS *a, UINT i, UINT total)\r
+{\r
+       // 引数チェック\r
+       if (p == NULL || a == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddUniStrEx(p, "Note", a->Note, i, total);\r
+       PackAddIntEx(p, "Active", a->Active, i, total);\r
+       PackAddIntEx(p, "Priority", a->Priority, i, total);\r
+       PackAddIntEx(p, "Discard", a->Discard, i, total);\r
+       if (a->IsIPv6)\r
+       {\r
+               PackAddIp32Ex(p, "SrcIpAddress", 0xFDFFFFDF, i, total);\r
+               PackAddIp32Ex(p, "SrcSubnetMask", 0xFFFFFFFF, i, total);\r
+               PackAddIp32Ex(p, "DestIpAddress", 0xFDFFFFDF, i, total);\r
+               PackAddIp32Ex(p, "DestSubnetMask", 0xFFFFFFFF, i, total);\r
+       }\r
+       else\r
+       {\r
+               PackAddIp32Ex(p, "SrcIpAddress", a->SrcIpAddress, i, total);\r
+               PackAddIp32Ex(p, "SrcSubnetMask", a->SrcSubnetMask, i, total);\r
+               PackAddIp32Ex(p, "DestIpAddress", a->DestIpAddress, i, total);\r
+               PackAddIp32Ex(p, "DestSubnetMask", a->DestSubnetMask, i, total);\r
+       }\r
+       PackAddIntEx(p, "Protocol", a->Protocol, i, total);\r
+       PackAddIntEx(p, "SrcPortStart", a->SrcPortStart, i, total);\r
+       PackAddIntEx(p, "SrcPortEnd", a->SrcPortEnd, i, total);\r
+       PackAddIntEx(p, "DestPortStart", a->DestPortStart, i, total);\r
+       PackAddIntEx(p, "DestPortEnd", a->DestPortEnd, i, total);\r
+       PackAddStrEx(p, "SrcUsername", a->SrcUsername, i, total);\r
+       PackAddStrEx(p, "DestUsername", a->DestUsername, i, total);\r
+       PackAddBoolEx(p, "CheckSrcMac", a->CheckSrcMac, i, total);\r
+       PackAddDataEx(p, "SrcMacAddress", a->SrcMacAddress, sizeof(a->SrcMacAddress), i, total);\r
+       PackAddDataEx(p, "SrcMacMask", a->SrcMacMask, sizeof(a->SrcMacMask), i, total);\r
+       PackAddBoolEx(p, "CheckDstMac", a->CheckDstMac, i, total);\r
+       PackAddDataEx(p, "DstMacAddress", a->DstMacAddress, sizeof(a->DstMacAddress), i, total);\r
+       PackAddDataEx(p, "DstMacMask", a->DstMacMask, sizeof(a->DstMacMask), i, total);\r
+       PackAddBoolEx(p, "CheckTcpState", a->CheckTcpState, i, total);\r
+       PackAddBoolEx(p, "Established", a->Established, i, total);\r
+       PackAddIntEx(p, "Delay", a->Delay, i, total);\r
+       PackAddIntEx(p, "Jitter", a->Jitter, i, total);\r
+       PackAddIntEx(p, "Loss", a->Loss, i, total);\r
+       PackAddBoolEx(p, "IsIPv6", a->IsIPv6, i, total);\r
+       if (a->IsIPv6)\r
+       {\r
+               PackAddIp6AddrEx(p, "SrcIpAddress6", &a->SrcIpAddress6, i, total);\r
+               PackAddIp6AddrEx(p, "SrcSubnetMask6", &a->SrcSubnetMask6, i, total);\r
+               PackAddIp6AddrEx(p, "DestIpAddress6", &a->DestIpAddress6, i, total);\r
+               PackAddIp6AddrEx(p, "DestSubnetMask6", &a->DestSubnetMask6, i, total);\r
+       }\r
+       else\r
+       {\r
+               IPV6_ADDR zero;\r
+\r
+               Zero(&zero, sizeof(zero));\r
+\r
+               PackAddIp6AddrEx(p, "SrcIpAddress6", &zero, i, total);\r
+               PackAddIp6AddrEx(p, "SrcSubnetMask6", &zero, i, total);\r
+               PackAddIp6AddrEx(p, "DestIpAddress6", &zero, i, total);\r
+               PackAddIp6AddrEx(p, "DestSubnetMask6", &zero, i, total);\r
+       }\r
+}\r
+\r
+// PACK に入っているアクセス個数を取得\r
+UINT SiNumAccessFromPack(PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (p == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       return PackGetIndexCount(p, "Active");\r
+}\r
+\r
+// PACK をアクセスに変換する\r
+ACCESS *SiPackToAccess(PACK *p, UINT i)\r
+{\r
+       ACCESS *a;\r
+       // 引数チェック\r
+       if (p == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       a = ZeroMalloc(sizeof(ACCESS));\r
+\r
+       PackGetUniStrEx(p, "Note", a->Note, sizeof(a->Note), i);\r
+       a->Active = PackGetIntEx(p, "Active", i);\r
+       a->Priority = PackGetIntEx(p, "Priority", i);\r
+       a->Discard = PackGetIntEx(p, "Discard", i);\r
+       a->SrcIpAddress = PackGetIp32Ex(p, "SrcIpAddress", i);\r
+       a->SrcSubnetMask = PackGetIp32Ex(p, "SrcSubnetMask", i);\r
+       a->DestIpAddress = PackGetIp32Ex(p, "DestIpAddress", i);\r
+       a->DestSubnetMask = PackGetIp32Ex(p, "DestSubnetMask", i);\r
+       a->Protocol = PackGetIntEx(p, "Protocol", i);\r
+       a->SrcPortStart = PackGetIntEx(p, "SrcPortStart", i);\r
+       a->SrcPortEnd = PackGetIntEx(p, "SrcPortEnd", i);\r
+       a->DestPortStart = PackGetIntEx(p, "DestPortStart", i);\r
+       a->DestPortEnd = PackGetIntEx(p, "DestPortEnd", i);\r
+       PackGetStrEx(p, "SrcUsername", a->SrcUsername, sizeof(a->SrcUsername), i);\r
+       PackGetStrEx(p, "DestUsername", a->DestUsername, sizeof(a->DestUsername), i);\r
+       a->CheckSrcMac = PackGetBoolEx(p, "CheckSrcMac", i);\r
+       PackGetDataEx2(p, "SrcMacAddress", a->SrcMacAddress, sizeof(a->SrcMacAddress), i);\r
+       PackGetDataEx2(p, "SrcMacMask", a->SrcMacMask, sizeof(a->SrcMacMask), i);\r
+       a->CheckDstMac = PackGetBoolEx(p, "CheckDstMac", i);\r
+       PackGetDataEx2(p, "DstMacAddress", a->DstMacAddress, sizeof(a->DstMacAddress), i);\r
+       PackGetDataEx2(p, "DstMacMask", a->DstMacMask, sizeof(a->DstMacMask), i);\r
+       a->CheckTcpState = PackGetBoolEx(p, "CheckTcpState", i);\r
+       a->Established = PackGetBoolEx(p, "Established", i);\r
+       a->Delay = PackGetIntEx(p, "Delay", i);\r
+       a->Jitter = PackGetIntEx(p, "Jitter", i);\r
+       a->Loss = PackGetIntEx(p, "Loss", i);\r
+       a->IsIPv6 = PackGetBoolEx(p, "IsIPv6", i);\r
+       if (a->IsIPv6)\r
+       {\r
+               PackGetIp6AddrEx(p, "SrcIpAddress6", &a->SrcIpAddress6, i);\r
+               PackGetIp6AddrEx(p, "SrcSubnetMask6", &a->SrcSubnetMask6, i);\r
+               PackGetIp6AddrEx(p, "DestIpAddress6", &a->DestIpAddress6, i);\r
+               PackGetIp6AddrEx(p, "DestSubnetMask6", &a->DestSubnetMask6, i);\r
+       }\r
+\r
+       return a;\r
+}\r
+\r
+// アクセスリストを PACK に変換する\r
+void SiAccessListToPack(PACK *p, LIST *o)\r
+{\r
+       // 引数チェック\r
+       if (p == NULL || o == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(o);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(o);i++)\r
+               {\r
+                       ACCESS *a = LIST_DATA(o, i);\r
+                       SiAccessToPack(p, a, i, LIST_NUM(o));\r
+               }\r
+       }\r
+       UnlockList(o);\r
+}\r
+\r
+// 指定した HUB をホストしているメンバを取得する\r
+FARM_MEMBER *SiGetHubHostingMember(SERVER *s, HUB *h, bool admin_mode)\r
+{\r
+       FARM_MEMBER *ret = NULL;\r
+       char name[MAX_SIZE];\r
+       // 引数チェック\r
+       if (s == NULL || h == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       StrCpy(name, sizeof(name), h->Name);\r
+\r
+       if (h->Type == HUB_TYPE_FARM_STATIC)\r
+       {\r
+               // スタティック HUB の場合 任意のメンバを選択すれば良い\r
+               if (admin_mode == false)\r
+               {\r
+                       ret = SiGetNextFarmMember(s);\r
+               }\r
+               else\r
+               {\r
+                       UINT i;\r
+                       ret = NULL;\r
+\r
+                       for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)\r
+                       {\r
+                               FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);\r
+                               if (f->Me)\r
+                               {\r
+                                       ret = f;\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               // ダイナミック HUB の場合\r
+               // すでに HUB をホストしているメンバがあるかどうか調べる\r
+               UINT i;\r
+\r
+               for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)\r
+               {\r
+                       FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);\r
+                       HUB_LIST *hh, t;\r
+                       StrCpy(t.Name, sizeof(t.Name), name);\r
+                       LockList(f->HubList);\r
+                       {\r
+                               hh = Search(f->HubList, &t);\r
+                               if (hh != NULL)\r
+                               {\r
+                                       // 発見した\r
+                                       ret = f;\r
+                               }\r
+                       }\r
+                       UnlockList(f->HubList);\r
+               }\r
+\r
+               if (ret == NULL)\r
+               {\r
+                       // 新しく HUB をホストさせる\r
+                       FARM_MEMBER *f;\r
+\r
+                       // ホストさせるメンバの選択\r
+                       ret = SiGetNextFarmMember(s);\r
+\r
+                       f = ret;\r
+                       if (f != NULL)\r
+                       {\r
+                               // HUB 作成指令\r
+                               SiAddHubCreateHistory(s, name);\r
+                               SiCallCreateHub(s, f, h);\r
+                               SiCallUpdateHub(s, f, h);\r
+                       }\r
+               }\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+// タスクが呼び出された\r
+PACK *SiCalledTask(FARM_CONTROLLER *f, PACK *p, char *taskname)\r
+{\r
+       PACK *ret;\r
+       SERVER *s;\r
+       // 引数チェック\r
+       if (f == NULL || p == NULL || taskname == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       ret = NULL;\r
+       s = f->Server;\r
+\r
+       if (StrCmpi(taskname, "noop") == 0)\r
+       {\r
+               // NO OPERATION\r
+               ret = NewPack();\r
+       }\r
+       else\r
+       {\r
+               Debug("Task Called: [%s].\n", taskname);\r
+               if (StrCmpi(taskname, "createhub") == 0)\r
+               {\r
+                       SiCalledCreateHub(s, p);\r
+                       ret = NewPack();\r
+               }\r
+               else if (StrCmpi(taskname, "deletehub") == 0)\r
+               {\r
+                       SiCalledDeleteHub(s, p);\r
+                       ret = NewPack();\r
+               }\r
+               else if (StrCmpi(taskname, "enumhub") == 0)\r
+               {\r
+                       ret = NewPack();\r
+                       SiCalledEnumHub(s, ret, p);\r
+               }\r
+               else if (StrCmpi(taskname, "updatehub") == 0)\r
+               {\r
+                       SiCalledUpdateHub(s, p);\r
+                       ret = NewPack();\r
+               }\r
+               else if (StrCmpi(taskname, "createticket") == 0)\r
+               {\r
+                       ret = SiCalledCreateTicket(s, p);\r
+               }\r
+               else if (StrCmpi(taskname, "enumnat") == 0)\r
+               {\r
+                       ret = SiCalledEnumNat(s, p);\r
+               }\r
+               else if (StrCmpi(taskname, "enumdhcp") == 0)\r
+               {\r
+                       ret = SiCalledEnumDhcp(s, p);\r
+               }\r
+               else if (StrCmpi(taskname, "getnatstatus") == 0)\r
+               {\r
+                       ret = SiCalledGetNatStatus(s, p);\r
+               }\r
+               else if (StrCmpi(taskname, "enumsession") == 0)\r
+               {\r
+                       ret = SiCalledEnumSession(s, p);\r
+               }\r
+               else if (StrCmpi(taskname, "deletesession") == 0)\r
+               {\r
+                       SiCalledDeleteSession(s, p);\r
+                       ret = NewPack();\r
+               }\r
+               else if (StrCmpi(taskname, "deletemactable") == 0)\r
+               {\r
+                       SiCalledDeleteMacTable(s, p);\r
+                       ret = NewPack();\r
+               }\r
+               else if (StrCmpi(taskname, "deleteiptable") == 0)\r
+               {\r
+                       SiCalledDeleteIpTable(s, p);\r
+                       ret = NewPack();\r
+               }\r
+               else if (StrCmpi(taskname, "enummactable") == 0)\r
+               {\r
+                       ret = SiCalledEnumMacTable(s, p);\r
+               }\r
+               else if (StrCmpi(taskname, "enumiptable") == 0)\r
+               {\r
+                       ret = SiCalledEnumIpTable(s, p);\r
+               }\r
+               else if (StrCmpi(taskname, "getsessionstatus") == 0)\r
+               {\r
+                       ret = SiCalledGetSessionStatus(s, p);\r
+               }\r
+               else if (StrCmpi(taskname, "enumlogfilelist") == 0)\r
+               {\r
+                       ret = SiCalledEnumLogFileList(s, p);\r
+               }\r
+               else if (StrCmpi(taskname, "readlogfile") == 0)\r
+               {\r
+                       ret = SiCalledReadLogFile(s, p);\r
+               }\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+// タスクを呼び出す\r
+PACK *SiCallTask(FARM_MEMBER *f, PACK *p, char *taskname)\r
+{\r
+       PACK *ret;\r
+       char tmp[MAX_PATH];\r
+       // 引数チェック\r
+       if (f == NULL || p == NULL || taskname == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       PackAddStr(p, "taskname", taskname);\r
+\r
+       Debug("Call Task [%s] (%s)\n", taskname, f->hostname);\r
+\r
+       Format(tmp, sizeof(tmp), "CLUSTER_CALL: Entering Call [%s] to %s", taskname, f->hostname);\r
+       SiDebugLog(f->Cedar->Server, tmp);\r
+\r
+       ret = SiExecTask(f, p);\r
+\r
+       Format(tmp, sizeof(tmp), "CLUSTER_CALL: Leaving Call [%s] to %s", taskname, f->hostname);\r
+       SiDebugLog(f->Cedar->Server, tmp);\r
+\r
+       return ret;\r
+}\r
+\r
+// タスク待ちうけプロシージャ (メイン処理)\r
+void SiAcceptTasksFromControllerMain(FARM_CONTROLLER *f, SOCK *sock)\r
+{\r
+       PACK *request;\r
+       PACK *response;\r
+       char taskname[MAX_SIZE];\r
+       // 引数チェック\r
+       if (f == NULL || sock == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       while (true)\r
+       {\r
+               bool ret;\r
+               // PACK を受信する\r
+               request = HttpClientRecv(sock);\r
+               if (request == NULL)\r
+               {\r
+                       // 切断\r
+                       return;\r
+               }\r
+\r
+               response = NULL;\r
+\r
+               // 名前の取得\r
+               if (PackGetStr(request, "taskname", taskname, sizeof(taskname)))\r
+               {\r
+                       Lock(f->Server->TasksFromFarmControllerLock);\r
+                       {\r
+                               response = SiCalledTask(f, request, taskname);\r
+                       }\r
+                       Unlock(f->Server->TasksFromFarmControllerLock);\r
+               }\r
+\r
+               FreePack(request);\r
+\r
+               // 応答を返す\r
+               if (response == NULL)\r
+               {\r
+                       response = NewPack();\r
+               }\r
+               else\r
+               {\r
+                       PackAddInt(response, "succeed", 1);\r
+               }\r
+\r
+               ret = HttpClientSend(sock, response);\r
+               FreePack(response);\r
+\r
+               if (ret == false)\r
+               {\r
+                       // 切断\r
+                       return;\r
+               }\r
+       }\r
+}\r
+\r
+// タスク待ちうけプロシージャ\r
+void SiAcceptTasksFromController(FARM_CONTROLLER *f, SOCK *sock)\r
+{\r
+       UINT i;\r
+       HUB **hubs;\r
+       UINT num_hubs;\r
+       CEDAR *c;\r
+       SERVER *s;\r
+       // 引数チェック\r
+       if (f == NULL || sock == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s = f->Server;\r
+       c = s->Cedar;\r
+\r
+       // メイン処理\r
+       SiAcceptTasksFromControllerMain(f, sock);\r
+\r
+       // コントローラとの接続が切断されたためすべての仮想 HUB を停止する\r
+       LockList(c->HubList);\r
+       {\r
+               hubs = ToArray(c->HubList);\r
+               num_hubs = LIST_NUM(c->HubList);\r
+               for (i = 0;i < num_hubs;i++)\r
+               {\r
+                       AddRef(hubs[i]->ref);\r
+               }\r
+       }\r
+       UnlockList(c->HubList);\r
+\r
+       for (i = 0;i < num_hubs;i++)\r
+       {\r
+               SetHubOffline(hubs[i]);\r
+               DelHub(c, hubs[i]);\r
+               ReleaseHub(hubs[i]);\r
+       }\r
+\r
+       Free(hubs);\r
+}\r
+\r
+// タスクを実行する\r
+PACK *SiExecTask(FARM_MEMBER *f, PACK *p)\r
+{\r
+       FARM_TASK *t;\r
+       // 引数チェック\r
+       if (f == NULL || p == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       t = SiFarmServPostTask(f, p);\r
+       if (t == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       return SiFarmServWaitTask(t);\r
+}\r
+\r
+// タスク投入\r
+FARM_TASK *SiFarmServPostTask(FARM_MEMBER *f, PACK *request)\r
+{\r
+       FARM_TASK *t;\r
+       // 引数チェック\r
+       if (f == NULL || request == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       t = ZeroMalloc(sizeof(FARM_TASK));\r
+       t->CompleteEvent = NewEvent();\r
+       t->Request = request;\r
+\r
+       LockQueue(f->TaskQueue);\r
+       {\r
+               if (f->Halting)\r
+               {\r
+                       // 停止中 (失敗)\r
+                       UnlockQueue(f->TaskQueue);\r
+                       ReleaseEvent(t->CompleteEvent);\r
+                       Free(t);\r
+                       return NULL;\r
+               }\r
+\r
+               InsertQueue(f->TaskQueue, t);\r
+       }\r
+       UnlockQueue(f->TaskQueue);\r
+\r
+       Set(f->TaskPostEvent);\r
+\r
+       return t;\r
+}\r
+\r
+// タスク結果待ち\r
+PACK *SiFarmServWaitTask(FARM_TASK *t)\r
+{\r
+       PACK *response;\r
+       // 引数チェック\r
+       if (t == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       Wait(t->CompleteEvent, INFINITE);\r
+       ReleaseEvent(t->CompleteEvent);\r
+       FreePack(t->Request);\r
+\r
+       response = t->Response;\r
+       Free(t);\r
+\r
+       if (PackGetInt(response, "succeed") == 0)\r
+       {\r
+               // 何らかの原因でタスク呼び出しが失敗した\r
+               FreePack(response);\r
+               return NULL;\r
+       }\r
+\r
+       return response;\r
+}\r
+\r
+// ファームサーバー処理メイン\r
+void SiFarmServMain(SERVER *server, SOCK *sock, FARM_MEMBER *f)\r
+{\r
+       UINT wait_time = SERVER_CONTROL_TCP_TIMEOUT / 2;\r
+       bool send_noop = false;\r
+       UINT i;\r
+       CEDAR *c;\r
+       // 引数チェック\r
+       if (server == NULL || sock == NULL || f == NULL)\r
+       {\r
+               Debug("SiFarmServMain Failed.\n");\r
+               return;\r
+       }\r
+\r
+       Debug("SiFarmServMain Started.\n");\r
+\r
+       c = server->Cedar;\r
+\r
+       // メンバがコントローラに接続してきた段階で\r
+       // すべてのスタティック HUB の作成指令を送信する\r
+       LockList(c->HubList);\r
+       {\r
+               for (i = 0;i < LIST_NUM(c->HubList);i++)\r
+               {\r
+                       HUB *h = LIST_DATA(c->HubList, i);\r
+                       if (h->Offline == false)\r
+                       {\r
+                               if (h->Type == HUB_TYPE_FARM_STATIC)\r
+                               {\r
+                                       PACK *p;\r
+                                       HUB_LIST *hh;\r
+                                       p = NewPack();\r
+                                       SiPackAddCreateHub(p, h);\r
+                                       PackAddStr(p, "taskname", "createhub");\r
+                                       HttpServerSend(sock, p);\r
+                                       FreePack(p);\r
+                                       p = HttpServerRecv(sock);\r
+                                       FreePack(p);\r
+\r
+                                       p = NewPack();\r
+                                       SiPackAddCreateHub(p, h);\r
+                                       PackAddStr(p, "taskname", "updatehub");\r
+                                       HttpServerSend(sock, p);\r
+                                       FreePack(p);\r
+                                       p = HttpServerRecv(sock);\r
+                                       FreePack(p);\r
+\r
+                                       hh = ZeroMalloc(sizeof(HUB_LIST));\r
+                                       hh->DynamicHub = false;\r
+                                       hh->FarmMember = f;\r
+                                       StrCpy(hh->Name, sizeof(hh->Name), h->Name);\r
+                                       LockList(f->HubList);\r
+                                       {\r
+                                               Add(f->HubList, hh);\r
+                                       }\r
+                                       UnlockList(f->HubList);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(c->HubList);\r
+\r
+       Debug("SiFarmServMain: while (true)\n");\r
+\r
+       while (true)\r
+       {\r
+               FARM_TASK *t;\r
+               UINT64 tick;\r
+\r
+               do\r
+               {\r
+                       // 新しいタスクが到着していないかどうか調べる\r
+                       LockQueue(f->TaskQueue);\r
+                       {\r
+                               t = GetNext(f->TaskQueue);\r
+                       }\r
+                       UnlockQueue(f->TaskQueue);\r
+\r
+                       if (t != NULL)\r
+                       {\r
+                               // このタスクを処理する\r
+                               PACK *p = t->Request;\r
+                               bool ret;\r
+\r
+                               // 送信\r
+                               ret = HttpServerSend(sock, p);\r
+                               send_noop = false;\r
+\r
+                               if (ret == false)\r
+                               {\r
+                                       // 接続が切れた\r
+                                       // このタスクをキャンセルする\r
+                                       Set(t->CompleteEvent);\r
+                                       goto DISCONNECTED;\r
+                               }\r
+\r
+                               // 受信\r
+                               p = HttpServerRecv(sock);\r
+\r
+                               t->Response = p;\r
+                               Set(t->CompleteEvent);\r
+\r
+                               send_noop = false;\r
+                       }\r
+               }\r
+               while (t != NULL);\r
+\r
+               if (send_noop)\r
+               {\r
+                       // NOOP を送信する\r
+                       PACK *p;\r
+                       bool ret;\r
+                       p = NewPack();\r
+                       PackAddStr(p, "taskname", "noop");\r
+\r
+                       ret = HttpServerSend(sock, p);\r
+                       FreePack(p);\r
+\r
+                       if (ret == false)\r
+                       {\r
+                               goto DISCONNECTED;\r
+                       }\r
+\r
+                       p = HttpServerRecv(sock);\r
+                       if (p == NULL)\r
+                       {\r
+                               goto DISCONNECTED;\r
+                       }\r
+\r
+                       FreePack(p);\r
+               }\r
+\r
+               tick = Tick64();\r
+\r
+               while (true)\r
+               {\r
+                       bool break_flag;\r
+                       if ((tick + wait_time) <= Tick64())\r
+                       {\r
+                               break;\r
+                       }\r
+\r
+                       Wait(f->TaskPostEvent, 250);\r
+\r
+                       break_flag = false;\r
+                       LockQueue(f->TaskQueue);\r
+                       {\r
+                               if (f->TaskQueue->num_item != 0)\r
+                               {\r
+                                       break_flag = true;\r
+                               }\r
+                       }\r
+                       UnlockQueue(f->TaskQueue);\r
+\r
+                       if (break_flag || f->Halting || server->Halt)\r
+                       {\r
+                               break;\r
+                       }\r
+               }\r
+               send_noop = true;\r
+       }\r
+\r
+DISCONNECTED:\r
+\r
+       Debug("SiFarmServMain: DISCONNECTED\n");\r
+\r
+       f->Halting = true;\r
+       // すべての未処理のタスクをキャンセルする\r
+       LockQueue(f->TaskQueue);\r
+       {\r
+               FARM_TASK *t;\r
+\r
+               while (t = GetNext(f->TaskQueue))\r
+               {\r
+                       Set(t->CompleteEvent);\r
+               }\r
+       }\r
+       UnlockQueue(f->TaskQueue);\r
+}\r
+\r
+// ファームメンバからの接続を処理するファームサーバー関数\r
+void SiFarmServ(SERVER *server, SOCK *sock, X *cert, UINT ip, UINT num_port, UINT *ports, char *hostname, UINT point, UINT weight, UINT max_sessions)\r
+{\r
+       PACK *p;\r
+       FARM_MEMBER *f;\r
+       UINT i;\r
+       char tmp[MAX_SIZE];\r
+       // 引数チェック\r
+       if (server == NULL || sock == NULL || cert == NULL || num_port == 0 || ports == NULL || hostname == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (weight == 0)\r
+       {\r
+               weight = FARM_DEFAULT_WEIGHT;\r
+       }\r
+\r
+       if (max_sessions == 0)\r
+       {\r
+               max_sessions = SERVER_MAX_SESSIONS;\r
+       }\r
+\r
+       if (ip == 0)\r
+       {\r
+               // 公開 IP アドレスが指定されていない場合はこのファームメンバサーバーの\r
+               // 接続元 IP アドレスを指定する\r
+               ip = IPToUINT(&sock->RemoteIP);\r
+       }\r
+\r
+       IPToStr32(tmp, sizeof(tmp), ip);\r
+       SLog(server->Cedar, "LS_FARM_SERV_START", tmp, hostname);\r
+\r
+       // 成功を知らせる\r
+       p = NewPack();\r
+       HttpServerSend(sock, p);\r
+       FreePack(p);\r
+\r
+       IPToStr32(tmp, sizeof(tmp), ip);\r
+       Debug("Farm Member %s Connected. IP: %s\n", hostname, tmp);\r
+\r
+       SetTimeout(sock, SERVER_CONTROL_TCP_TIMEOUT);\r
+\r
+       f = ZeroMalloc(sizeof(FARM_MEMBER));\r
+       f->Cedar = server->Cedar;\r
+       f->Ip = ip;\r
+       f->NumPort = num_port;\r
+       f->Ports = ports;\r
+       StrCpy(f->hostname, sizeof(f->hostname), hostname);\r
+       f->ServerCert = cert;\r
+       f->ConnectedTime = SystemTime64();\r
+       f->Weight = weight;\r
+       f->MaxSessions = max_sessions;\r
+\r
+       f->HubList = NewList(CompareHubList);\r
+       f->Point = point;\r
+\r
+       f->TaskQueue = NewQueue();\r
+       f->TaskPostEvent = NewEvent();\r
+\r
+       // リストに追加する\r
+       LockList(server->FarmMemberList);\r
+       {\r
+               Add(server->FarmMemberList, f);\r
+       }\r
+       UnlockList(server->FarmMemberList);\r
+\r
+       // メイン処理\r
+       SiFarmServMain(server, sock, f);\r
+\r
+       // リストから削除する\r
+       LockList(server->FarmMemberList);\r
+       {\r
+               Delete(server->FarmMemberList, f);\r
+       }\r
+       UnlockList(server->FarmMemberList);\r
+\r
+       ReleaseQueue(f->TaskQueue);\r
+       ReleaseEvent(f->TaskPostEvent);\r
+\r
+       for (i = 0;i < LIST_NUM(f->HubList);i++)\r
+       {\r
+               HUB_LIST *hh = LIST_DATA(f->HubList, i);\r
+               Free(hh);\r
+       }\r
+\r
+       ReleaseList(f->HubList);\r
+\r
+       Free(f);\r
+\r
+       SLog(server->Cedar, "LS_FARM_SERV_END", hostname);\r
+}\r
+\r
+// HUB リストの検索\r
+int CompareHubList(void *p1, void *p2)\r
+{\r
+       HUB_LIST *h1, *h2;\r
+       if (p1 == NULL || p2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+       h1 = *(HUB_LIST **)p1;\r
+       h2 = *(HUB_LIST **)p2;\r
+       if (h1 == NULL || h2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+       return StrCmpi(h1->Name, h2->Name);\r
+}\r
+\r
+// コントローラへの接続スレッド\r
+void SiConnectToControllerThread(THREAD *thread, void *param)\r
+{\r
+       FARM_CONTROLLER *f;\r
+       SESSION *s;\r
+       CONNECTION *c;\r
+       SERVER *server;\r
+       bool first_failed;\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       MsSetThreadPriorityRealtime();\r
+#endif // OS_WIN32\r
+\r
+       f = (FARM_CONTROLLER *)param;\r
+       f->Thread = thread;\r
+       AddRef(f->Thread->ref);\r
+       NoticeThreadInit(thread);\r
+\r
+       f->StartedTime = SystemTime64();\r
+\r
+       server = f->Server;\r
+\r
+       f->StartedTime = SystemTime64();\r
+\r
+       SLog(server->Cedar, "LS_FARM_CONNECT_1", server->ControllerName);\r
+\r
+       first_failed = true;\r
+\r
+       while (true)\r
+       {\r
+               // 接続を試行\r
+               CLIENT_OPTION o;\r
+\r
+               f->LastError = ERR_TRYING_TO_CONNECT;\r
+\r
+               Zero(&o, sizeof(CLIENT_OPTION));\r
+               StrCpy(o.Hostname, sizeof(o.Hostname), server->ControllerName);\r
+               o.Port = server->ControllerPort;\r
+               f->NumTry++;\r
+\r
+               Debug("Try to Connect %s (Controller).\n", server->ControllerName);\r
+\r
+               s = NewRpcSessionEx(server->Cedar, &o, NULL, CEDAR_SERVER_FARM_STR);\r
+\r
+               if (s != NULL)\r
+               {\r
+                       // 接続成功: 認証データを送信\r
+                       PACK *p = NewPack();\r
+                       UCHAR secure_password[SHA1_SIZE];\r
+                       BUF *b;\r
+\r
+                       c = s->Connection;\r
+\r
+                       Lock(f->lock);\r
+                       {\r
+                               f->Sock = c->FirstSock;\r
+                               AddRef(f->Sock->ref);\r
+                               SetTimeout(f->Sock, SERVER_CONTROL_TCP_TIMEOUT);\r
+                       }\r
+                       Unlock(f->lock);\r
+\r
+                       // メソッド\r
+                       PackAddStr(p, "method", "farm_connect");\r
+                       PackAddClientVersion(p, s->Connection);\r
+\r
+                       // パスワード\r
+                       SecurePassword(secure_password, server->MemberPassword, s->Connection->Random);\r
+                       PackAddData(p, "SecurePassword", secure_password, sizeof(secure_password));\r
+\r
+                       Lock(server->Cedar->lock);\r
+                       {\r
+                               b = XToBuf(server->Cedar->ServerX, false);\r
+                       }\r
+                       Unlock(server->Cedar->lock);\r
+\r
+                       if (b != NULL)\r
+                       {\r
+                               char tmp[MAX_SIZE];\r
+                               bool ret;\r
+                               UINT i;\r
+                               // サーバー証明書\r
+                               PackAddBuf(p, "ServerCert", b);\r
+                               FreeBuf(b);\r
+\r
+                               // 最大セッション数\r
+                               PackAddInt(p, "MaxSessions", GetServerCapsInt(server, "i_max_sessions"));\r
+\r
+                               // ポイント\r
+                               PackAddInt(p, "Point", SiGetPoint(server));\r
+                               PackAddInt(p, "Weight", server->Weight);\r
+\r
+                               // ホスト名\r
+                               GetMachineName(tmp, sizeof(tmp));\r
+                               PackAddStr(p, "HostName", tmp);\r
+\r
+                               // 公開 IP\r
+                               PackAddIp32(p, "PublicIp", server->PublicIp);\r
+\r
+                               // 公開ポート\r
+                               for (i = 0;i < server->NumPublicPort;i++)\r
+                               {\r
+                                       PackAddIntEx(p, "PublicPort", server->PublicPorts[i], i, server->NumPublicPort);\r
+                               }\r
+\r
+                               ret = HttpClientSend(c->FirstSock, p);\r
+\r
+                               if (ret)\r
+                               {\r
+                                       PACK *p;\r
+                                       UINT err = ERR_PROTOCOL_ERROR;\r
+\r
+                                       first_failed = true;\r
+                                       p = HttpClientRecv(c->FirstSock);\r
+                                       if (p != NULL && (err = GetErrorFromPack(p)) == 0)\r
+                                       {\r
+                                               // 接続成功\r
+                                               SLog(server->Cedar, "LS_FARM_START");\r
+                                               f->CurrentConnectedTime = SystemTime64();\r
+                                               if (f->FirstConnectedTime == 0)\r
+                                               {\r
+                                                       f->FirstConnectedTime = SystemTime64();\r
+                                               }\r
+                                               f->NumConnected++;\r
+                                               Debug("Connect Succeed.\n");\r
+                                               f->Online = true;\r
+\r
+                                               // メイン処理\r
+                                               SiAcceptTasksFromController(f, c->FirstSock);\r
+\r
+                                               f->Online = false;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               // エラー\r
+                                               f->LastError = err;\r
+                                               SLog(server->Cedar, "LS_FARM_CONNECT_2", server->ControllerName,\r
+                                                       GetUniErrorStr(err), err);\r
+                                       }\r
+                                       FreePack(p);\r
+                               }\r
+                               else\r
+                               {\r
+                                       f->LastError = ERR_DISCONNECTED;\r
+\r
+                                       if (first_failed)\r
+                                       {\r
+                                               SLog(server->Cedar, "LS_FARM_CONNECT_3", server->ControllerName, RETRY_CONNECT_TO_CONTROLLER_INTERVAL / 1000);\r
+                                               first_failed = false;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       FreePack(p);\r
+\r
+                       // 接続切断\r
+                       Lock(f->lock);\r
+                       {\r
+                               if (f->Sock != NULL)\r
+                               {\r
+                                       ReleaseSock(f->Sock);\r
+                                       f->Sock = NULL;\r
+                               }\r
+                       }\r
+                       Unlock(f->lock);\r
+\r
+                       ReleaseSession(s);\r
+                       s = NULL;\r
+\r
+                       if (f->LastError == ERR_TRYING_TO_CONNECT)\r
+                       {\r
+                               f->LastError = ERR_DISCONNECTED;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       // 接続失敗\r
+                       f->LastError = ERR_CONNECT_TO_FARM_CONTROLLER;\r
+\r
+                       if (first_failed)\r
+                       {\r
+                               SLog(server->Cedar, "LS_FARM_CONNECT_3", server->ControllerName, RETRY_CONNECT_TO_CONTROLLER_INTERVAL / 1000);\r
+                               first_failed = false;\r
+                       }\r
+               }\r
+\r
+               Debug("Controller Disconnected. ERROR = %S\n", _E(f->LastError));\r
+\r
+               f->NumFailed = f->NumTry - f->NumConnected;\r
+\r
+               // イベント待機\r
+               Wait(f->HaltEvent, RETRY_CONNECT_TO_CONTROLLER_INTERVAL);\r
+\r
+               if (f->Halt)\r
+               {\r
+                       // 停止フラグ\r
+                       break;\r
+               }\r
+       }\r
+\r
+       SLog(server->Cedar, "LS_FARM_DISCONNECT");\r
+}\r
+\r
+// コントローラへの接続を切断\r
+void SiStopConnectToController(FARM_CONTROLLER *f)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       f->Halt = true;\r
+\r
+       // 接続を停止\r
+       Lock(f->lock);\r
+       {\r
+               Disconnect(f->Sock);\r
+       }\r
+       Unlock(f->lock);\r
+\r
+       Set(f->HaltEvent);\r
+\r
+       // スレッド停止を待機\r
+       WaitThread(f->Thread, INFINITE);\r
+       ReleaseThread(f->Thread);\r
+\r
+       DeleteLock(f->lock);\r
+       ReleaseEvent(f->HaltEvent);\r
+\r
+       Free(f);\r
+}\r
+\r
+// コントローラへの接続の開始\r
+FARM_CONTROLLER *SiStartConnectToController(SERVER *s)\r
+{\r
+       FARM_CONTROLLER *f;\r
+       THREAD *t;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       f = ZeroMalloc(sizeof(FARM_CONTROLLER));\r
+       f->Server = s;\r
+       f->LastError = ERR_TRYING_TO_CONNECT;\r
+       f->HaltEvent = NewEvent();\r
+       f->lock = NewLock();\r
+\r
+       t = NewThread(SiConnectToControllerThread, f);\r
+       WaitThreadInit(t);\r
+       ReleaseThread(t);\r
+\r
+       return f;\r
+}\r
+\r
+// サーバーの作成\r
+SERVER *SiNewServer(bool bridge)\r
+{\r
+       SERVER *s;\r
+\r
+       s = ZeroMalloc(sizeof(SERVER));\r
+\r
+       SiInitHubCreateHistory(s);\r
+\r
+       InitServerCapsCache(s);\r
+\r
+       Rand(s->MyRandomKey, sizeof(s->MyRandomKey));\r
+\r
+       s->lock = NewLock();\r
+       s->SaveCfgLock = NewLock();\r
+       s->ref = NewRef();\r
+       s->Cedar = NewCedar(NULL, NULL);\r
+       s->Cedar->Server = s;\r
+       s->Cedar->CheckExpires = true;\r
+       s->ServerListenerList = NewList(CompareServerListener);\r
+       s->StartTime = SystemTime64();\r
+       s->TasksFromFarmControllerLock = NewLock();\r
+\r
+       if (bridge)\r
+       {\r
+               SetCedarVpnBridge(s->Cedar);\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       if (IsHamMode() == false)\r
+       {\r
+               RegistWindowsFirewallAll();\r
+       }\r
+#endif\r
+\r
+       s->Keep = StartKeep();\r
+\r
+       // ログ関係\r
+       MakeDir(bridge == false ? SERVER_LOG_DIR_NAME : BRIDGE_LOG_DIR_NAME);\r
+       s->Logger = NewLog(bridge == false ? SERVER_LOG_DIR_NAME : BRIDGE_LOG_DIR_NAME, SERVER_LOG_PERFIX, LOG_SWITCH_DAY);\r
+\r
+       SLog(s->Cedar, "L_LINE");\r
+       SLog(s->Cedar, "LS_START_2", s->Cedar->ServerStr, s->Cedar->VerString);\r
+       SLog(s->Cedar, "LS_START_3", s->Cedar->BuildInfo);\r
+       SLog(s->Cedar, "LS_START_UTF8");\r
+       SLog(s->Cedar, "LS_START_1");\r
+\r
+       if (s->Cedar->Bridge == false)\r
+       {\r
+               s->LicenseSystem = LiNewLicenseSystem();\r
+       }\r
+\r
+       // コンフィグレーション初期化\r
+       SiInitConfiguration(s);\r
+\r
+       // 優先順位を上げる\r
+       if (s->NoHighPriorityProcess == false)\r
+       {\r
+               OSSetHighPriority();\r
+       }\r
+\r
+       if (s->ServerType == SERVER_TYPE_FARM_MEMBER)\r
+       {\r
+               // コントローラへの接続を開始する\r
+               s->FarmController = SiStartConnectToController(s);\r
+       }\r
+       else if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)\r
+       {\r
+               FARM_MEMBER *f;\r
+               // コントローラとしての動作を開始する\r
+               s->FarmMemberList = NewList(NULL);\r
+\r
+               f = ZeroMalloc(sizeof(FARM_MEMBER));\r
+               f->Cedar = s->Cedar;\r
+               GetMachineName(f->hostname, sizeof(f->hostname));\r
+               f->Me = true;\r
+               f->HubList = NewList(CompareHubList);\r
+               f->Weight = s->Weight;\r
+\r
+               s->Me = f;\r
+\r
+               Add(s->FarmMemberList, f);\r
+\r
+               SiStartFarmControl(s);\r
+\r
+               s->FarmControllerInited = true;\r
+       }\r
+\r
+       InitServerSnapshot(s);\r
+\r
+       SiInitDeadLockCheck(s);\r
+\r
+       return s;\r
+}\r
+\r