* tar xzf utvpn-src-unix-v101-7101-public-2010.06.27.tar.gz
[lab.git] / utvpn / utvpn-unix-v101-7101-public / src / Cedar / Connection.c
diff --git a/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Connection.c b/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Connection.c
new file mode 100644 (file)
index 0000000..896052c
--- /dev/null
@@ -0,0 +1,2926 @@
+// 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
+// Connection.c\r
+// コネクションマネージャ\r
+\r
+#include "CedarPch.h"\r
+\r
+// 送信に使用するかどうかの判別\r
+#define        IS_SEND_TCP_SOCK(ts)            \\r
+       ((ts->Direction == TCP_BOTH) || ((ts->Direction == TCP_SERVER_TO_CLIENT) && (s->ServerMode)) || ((ts->Direction == TCP_CLIENT_TO_SERVER) && (s->ServerMode == false)))\r
+\r
+// 受信に使用するかどうかの判別\r
+#define        IS_RECV_TCP_SOCK(ts)            \\r
+       ((ts->Direction == TCP_BOTH) || ((ts->Direction == TCP_SERVER_TO_CLIENT) && (s->ServerMode == false)) || ((ts->Direction == TCP_CLIENT_TO_SERVER) && (s->ServerMode)))\r
+\r
+// SECURE_SIGN の変換\r
+void InRpcSecureSign(SECURE_SIGN *t, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(t, sizeof(SECURE_SIGN));\r
+       PackGetStr(p, "SecurePublicCertName", t->SecurePublicCertName, sizeof(t->SecurePublicCertName));\r
+       PackGetStr(p, "SecurePrivateKeyName", t->SecurePrivateKeyName, sizeof(t->SecurePrivateKeyName));\r
+       t->ClientCert = PackGetX(p, "ClientCert");\r
+       PackGetData2(p, "Random", t->Random, sizeof(t->Random));\r
+       PackGetData2(p, "Signature", t->Signature, sizeof(t->Signature));\r
+       t->UseSecureDeviceId = PackGetInt(p, "UseSecureDeviceId");\r
+       t->BitmapId = PackGetInt(p, "BitmapId");\r
+}\r
+void OutRpcSecureSign(PACK *p, SECURE_SIGN *t)\r
+{\r
+       // 引数チェック\r
+       if (p == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddStr(p, "SecurePublicCertName", t->SecurePublicCertName);\r
+       PackAddStr(p, "SecurePrivateKeyName", t->SecurePrivateKeyName);\r
+       PackAddX(p, "ClientCert", t->ClientCert);\r
+       PackAddData(p, "Random", t->Random, sizeof(t->Random));\r
+       PackAddData(p, "Signature", t->Signature, sizeof(t->Signature));\r
+       PackAddInt(p, "UseSecureDeviceId", t->UseSecureDeviceId);\r
+       PackAddInt(p, "BitmapId", t->BitmapId);\r
+}\r
+void FreeRpcSecureSign(SECURE_SIGN *t)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       FreeX(t->ClientCert);\r
+}\r
+\r
+// 次のパケットを生成する\r
+BUF *NewKeepPacket(bool server_mode)\r
+{\r
+       BUF *b = NewBuf();\r
+       char *string = KEEP_ALIVE_STRING;\r
+\r
+       WriteBuf(b, string, StrLen(string));\r
+\r
+       SeekBuf(b, 0, 0);\r
+\r
+       return b;\r
+}\r
+\r
+// KEEP スレッド\r
+void KeepThread(THREAD *thread, void *param)\r
+{\r
+       KEEP *k = (KEEP *)param;\r
+       SOCK *s;\r
+       char server_name[MAX_HOST_NAME_LEN + 1];\r
+       UINT server_port;\r
+       bool udp_mode;\r
+       bool enabled;\r
+       // 引数チェック\r
+       if (thread == NULL || k == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+WAIT_FOR_ENABLE:\r
+       Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);\r
+\r
+       // 有効になるまで待機する\r
+       while (true)\r
+       {\r
+               enabled = false;\r
+               Lock(k->lock);\r
+               {\r
+                       if (k->Enable)\r
+                       {\r
+                               if (StrLen(k->ServerName) != 0 && k->ServerPort != 0 && k->Interval != 0)\r
+                               {\r
+                                       StrCpy(server_name, sizeof(server_name), k->ServerName);\r
+                                       server_port = k->ServerPort;\r
+                                       udp_mode = k->UdpMode;\r
+                                       enabled = true;\r
+                               }\r
+                       }\r
+               }\r
+               Unlock(k->lock);\r
+               if (enabled)\r
+               {\r
+                       break;\r
+               }\r
+               if (k->Halt)\r
+               {\r
+                       return;\r
+               }\r
+               Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);\r
+       }\r
+\r
+       if (udp_mode == false)\r
+       {\r
+               // TCP モード\r
+               // 接続に成功するまで試行する\r
+               while (true)\r
+               {\r
+                       UINT64 connect_started_tick;\r
+                       bool changed = false;\r
+                       Lock(k->lock);\r
+                       {\r
+                               if (StrCmpi(k->ServerName, server_name) != 0 ||\r
+                                       k->ServerPort != server_port || k->Enable == false ||\r
+                                       k->UdpMode)\r
+                               {\r
+                                       changed = true;\r
+                               }\r
+                       }\r
+                       Unlock(k->lock);\r
+                       if (changed)\r
+                       {\r
+                               // 設定が変更された\r
+                               goto WAIT_FOR_ENABLE;\r
+                       }\r
+\r
+                       if (k->Halt)\r
+                       {\r
+                               // 停止\r
+                               return;\r
+                       }\r
+\r
+                       // サーバーへ接続を試行\r
+                       connect_started_tick = Tick64();\r
+                       s = ConnectEx2(server_name, server_port, KEEP_TCP_TIMEOUT, (bool *)&k->Halt);\r
+                       if (s != NULL)\r
+                       {\r
+                               // 接続成功\r
+                               break;\r
+                       }\r
+\r
+                       // 接続失敗 設定が変更されるかタイムアウトするまで待機する\r
+                       while (true)\r
+                       {\r
+                               changed = false;\r
+                               if (k->Halt)\r
+                               {\r
+                                       // 停止\r
+                                       return;\r
+                               }\r
+                               Lock(k->lock);\r
+                               {\r
+                                       if (StrCmpi(k->ServerName, server_name) != 0 ||\r
+                                               k->ServerPort != server_port || k->Enable == false ||\r
+                                               k->UdpMode)\r
+                                       {\r
+                                               changed = true;\r
+                                       }\r
+                               }\r
+                               Unlock(k->lock);\r
+\r
+                               if (changed)\r
+                               {\r
+                                       // 設定が変更された\r
+                                       goto WAIT_FOR_ENABLE;\r
+                               }\r
+\r
+                               if ((Tick64() - connect_started_tick) >= KEEP_RETRY_INTERVAL)\r
+                               {\r
+                                       break;\r
+                               }\r
+\r
+                               Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);\r
+                       }\r
+               }\r
+\r
+               // サーバーへの接続に成功した\r
+               // 一定時間ごとにパケットデータを送受信する\r
+               if (s != NULL)\r
+               {\r
+                       UINT64 last_packet_sent_time = 0;\r
+                       while (true)\r
+                       {\r
+                               SOCKSET set;\r
+                               UINT ret;\r
+                               UCHAR buf[MAX_SIZE];\r
+                               bool changed;\r
+\r
+                               InitSockSet(&set);\r
+                               AddSockSet(&set, s);\r
+\r
+                               Select(&set, KEEP_POLLING_INTERVAL, k->Cancel, NULL);\r
+\r
+                               ret = Recv(s, buf, sizeof(buf), false);\r
+                               if (ret == 0)\r
+                               {\r
+                                       // 切断された\r
+                                       Disconnect(s);\r
+                                       ReleaseSock(s);\r
+                                       s = NULL;\r
+                               }\r
+\r
+                               if (s != NULL)\r
+                               {\r
+                                       if ((Tick64() - last_packet_sent_time) >= (UINT64)k->Interval)\r
+                                       {\r
+                                               BUF *b;\r
+\r
+                                               // 次のパケットを送出する\r
+                                               last_packet_sent_time = Tick64();\r
+\r
+                                               b = NewKeepPacket(k->Server);\r
+\r
+                                               ret = Send(s, b->Buf, b->Size, false);\r
+                                               FreeBuf(b);\r
+\r
+                                               if (ret == 0)\r
+                                               {\r
+                                                       // 切断された\r
+                                                       Disconnect(s);\r
+                                                       ReleaseSock(s);\r
+                                                       s = NULL;\r
+                                               }\r
+                                       }\r
+                               }\r
+\r
+                               changed = false;\r
+\r
+                               Lock(k->lock);\r
+                               {\r
+                                       if (StrCmpi(k->ServerName, server_name) != 0 ||\r
+                                               k->ServerPort != server_port || k->Enable == false ||\r
+                                               k->UdpMode)\r
+                                       {\r
+                                               changed = true;\r
+                                       }\r
+                               }\r
+                               Unlock(k->lock);\r
+\r
+                               if (changed || s == NULL)\r
+                               {\r
+                                       // 設定が変更された または 切断された\r
+                                       Disconnect(s);\r
+                                       ReleaseSock(s);\r
+                                       s = NULL;\r
+                                       goto WAIT_FOR_ENABLE;\r
+                               }\r
+                               else\r
+                               {\r
+                                       if (k->Halt)\r
+                                       {\r
+                                               // 停止\r
+                                               Disconnect(s);\r
+                                               ReleaseSock(s);\r
+                                               return;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               IP dest_ip;\r
+               // UDP モード\r
+               // ソケット作成が成功するまで試行する\r
+               while (true)\r
+               {\r
+                       UINT64 connect_started_tick;\r
+                       bool changed = false;\r
+                       Lock(k->lock);\r
+                       {\r
+                               if (StrCmpi(k->ServerName, server_name) != 0 ||\r
+                                       k->ServerPort != server_port || k->Enable == false ||\r
+                                       k->UdpMode == false)\r
+                               {\r
+                                       changed = true;\r
+                               }\r
+                       }\r
+                       Unlock(k->lock);\r
+                       if (changed)\r
+                       {\r
+                               // 設定が変更された\r
+                               goto WAIT_FOR_ENABLE;\r
+                       }\r
+\r
+                       if (k->Halt)\r
+                       {\r
+                               // 停止\r
+                               return;\r
+                       }\r
+\r
+                       // ソケット作成を試行\r
+                       connect_started_tick = Tick64();\r
+\r
+                       // まず名前解決を試行\r
+                       if (GetIP(&dest_ip, server_name))\r
+                       {\r
+                               // 名前解決に成功したら、次にソケットを作成\r
+                               s = NewUDP(0);\r
+                               if (s != NULL)\r
+                               {\r
+                                       // 作成成功\r
+                                       break;\r
+                               }\r
+                       }\r
+\r
+                       // 作成失敗 設定が変更されるかタイムアウトするまで待機する\r
+                       while (true)\r
+                       {\r
+                               changed = false;\r
+                               if (k->Halt)\r
+                               {\r
+                                       // 停止\r
+                                       return;\r
+                               }\r
+                               Lock(k->lock);\r
+                               {\r
+                                       if (StrCmpi(k->ServerName, server_name) != 0 ||\r
+                                               k->ServerPort != server_port || k->Enable == false ||\r
+                                               k->UdpMode)\r
+                                       {\r
+                                               changed = true;\r
+                                       }\r
+                               }\r
+                               Unlock(k->lock);\r
+\r
+                               if (changed)\r
+                               {\r
+                                       // 設定が変更された\r
+                                       goto WAIT_FOR_ENABLE;\r
+                               }\r
+\r
+                               if ((Tick64() - connect_started_tick) >= KEEP_RETRY_INTERVAL)\r
+                               {\r
+                                       break;\r
+                               }\r
+\r
+                               Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);\r
+                       }\r
+               }\r
+\r
+               // 一定時間ごとにパケットデータを送信する\r
+               if (s != NULL)\r
+               {\r
+                       UINT64 last_packet_sent_time = 0;\r
+                       while (true)\r
+                       {\r
+                               SOCKSET set;\r
+                               UINT ret;\r
+                               UCHAR buf[MAX_SIZE];\r
+                               bool changed;\r
+                               IP src_ip;\r
+                               UINT src_port;\r
+\r
+                               InitSockSet(&set);\r
+                               AddSockSet(&set, s);\r
+\r
+                               Select(&set, KEEP_POLLING_INTERVAL, k->Cancel, NULL);\r
+\r
+                               // 受信\r
+                               ret = RecvFrom(s, &src_ip, &src_port, buf, sizeof(buf));\r
+                               if (ret == 0 && s->IgnoreRecvErr == false)\r
+                               {\r
+                                       // 切断された\r
+                                       Disconnect(s);\r
+                                       ReleaseSock(s);\r
+                                       s = NULL;\r
+                               }\r
+\r
+                               if (s != NULL)\r
+                               {\r
+                                       if ((Tick64() - last_packet_sent_time) >= (UINT64)k->Interval)\r
+                                       {\r
+                                               BUF *b;\r
+\r
+                                               // 次のパケットを送出する\r
+                                               last_packet_sent_time = Tick64();\r
+\r
+                                               b = NewKeepPacket(k->Server);\r
+\r
+                                               ret = SendTo(s, &dest_ip, server_port, b->Buf, b->Size);\r
+                                               FreeBuf(b);\r
+\r
+                                               if (ret == 0 && s->IgnoreSendErr == false)\r
+                                               {\r
+                                                       // 切断された\r
+                                                       Disconnect(s);\r
+                                                       ReleaseSock(s);\r
+                                                       s = NULL;\r
+                                               }\r
+                                       }\r
+                               }\r
+\r
+                               changed = false;\r
+\r
+                               Lock(k->lock);\r
+                               {\r
+                                       if (StrCmpi(k->ServerName, server_name) != 0 ||\r
+                                               k->ServerPort != server_port || k->Enable == false ||\r
+                                               k->UdpMode == false)\r
+                                       {\r
+                                               changed = true;\r
+                                       }\r
+                               }\r
+                               Unlock(k->lock);\r
+\r
+                               if (changed || s == NULL)\r
+                               {\r
+                                       // 設定が変更された または 切断された\r
+                                       Disconnect(s);\r
+                                       ReleaseSock(s);\r
+                                       s = NULL;\r
+                                       goto WAIT_FOR_ENABLE;\r
+                               }\r
+                               else\r
+                               {\r
+                                       if (k->Halt)\r
+                                       {\r
+                                               // 停止\r
+                                               Disconnect(s);\r
+                                               ReleaseSock(s);\r
+                                               return;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+// KEEP 停止\r
+void StopKeep(KEEP *k)\r
+{\r
+       // 引数チェック\r
+       if (k == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       k->Halt = true;\r
+       Set(k->HaltEvent);\r
+       Cancel(k->Cancel);\r
+\r
+       WaitThread(k->Thread, INFINITE);\r
+       ReleaseThread(k->Thread);\r
+       DeleteLock(k->lock);\r
+\r
+       ReleaseCancel(k->Cancel);\r
+       ReleaseEvent(k->HaltEvent);\r
+\r
+       Free(k);\r
+}\r
+\r
+// KEEP 開始\r
+KEEP *StartKeep()\r
+{\r
+       KEEP *k = ZeroMalloc(sizeof(KEEP));\r
+\r
+       k->lock = NewLock();\r
+       k->HaltEvent = NewEvent();\r
+       k->Cancel = NewCancel();\r
+\r
+       // スレッド開始\r
+       k->Thread = NewThread(KeepThread, k);\r
+\r
+       return k;\r
+}\r
+\r
+// クライアント認証データのコピー\r
+CLIENT_AUTH *CopyClientAuth(CLIENT_AUTH *a)\r
+{\r
+       CLIENT_AUTH *ret;\r
+       // 引数チェック\r
+       if (a == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       ret = ZeroMallocEx(sizeof(CLIENT_AUTH), true);\r
+\r
+       ret->AuthType = a->AuthType;\r
+       StrCpy(ret->Username, sizeof(ret->Username), a->Username);\r
+\r
+       switch (a->AuthType)\r
+       {\r
+       case CLIENT_AUTHTYPE_ANONYMOUS:\r
+               // 匿名認証\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_PASSWORD:\r
+               // パスワード認証\r
+               Copy(ret->HashedPassword, a->HashedPassword, SHA1_SIZE);\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_PLAIN_PASSWORD:\r
+               // 平文パスワード認証\r
+               StrCpy(ret->PlainPassword, sizeof(ret->PlainPassword), a->PlainPassword);\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_CERT:\r
+               // 証明書認証\r
+               ret->ClientX = CloneX(a->ClientX);\r
+               ret->ClientK = CloneK(a->ClientK);\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_SECURE:\r
+               // セキュアデバイス認証\r
+               StrCpy(ret->SecurePublicCertName, sizeof(ret->SecurePublicCertName), a->SecurePublicCertName);\r
+               StrCpy(ret->SecurePrivateKeyName, sizeof(ret->SecurePrivateKeyName), a->SecurePrivateKeyName);\r
+               break;\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+// 送信 FIFO にデータを書き込む (自動暗号化)\r
+void WriteSendFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || ts == NULL || data == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (s->UseFastRC4)\r
+       {\r
+               Encrypt(ts->SendKey, data, data, size);\r
+       }\r
+\r
+       WriteFifo(ts->SendFifo, data, size);\r
+}\r
+\r
+// 受信 FIFO にデータを書き込む (自動解読)\r
+void WriteRecvFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || ts == NULL || data == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (s->UseFastRC4)\r
+       {\r
+               Encrypt(ts->RecvKey, data, data, size);\r
+       }\r
+\r
+       WriteFifo(ts->RecvFifo, data, size);\r
+}\r
+\r
+// TCP ソケット受信\r
+UINT TcpSockRecv(SESSION *s, TCPSOCK *ts, void *data, UINT size)\r
+{\r
+       // 受信\r
+       return Recv(ts->Sock, data, size, s->UseSSLDataEncryption);\r
+}\r
+\r
+// TCP ソケット送信\r
+UINT TcpSockSend(SESSION *s, TCPSOCK *ts, void *data, UINT size)\r
+{\r
+       // 送信\r
+       return Send(ts->Sock, data, size, s->UseSSLDataEncryption);\r
+}\r
+\r
+// データを UDP パケットとして送信する\r
+void SendDataWithUDP(SOCK *s, CONNECTION *c)\r
+{\r
+       UCHAR *buf;\r
+       BUF *b;\r
+       UINT64 dummy_64 = 0;\r
+       UCHAR dummy_buf[16];\r
+       UINT64 now = Tick64();\r
+       UINT ret;\r
+       bool force_flag = false;\r
+       bool packet_sent = false;\r
+       // 引数チェック\r
+       if (s == NULL || c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 一時バッファをヒープから確保しておく\r
+       if (c->RecvBuf == NULL)\r
+       {\r
+               c->RecvBuf = Malloc(RECV_BUF_SIZE);\r
+       }\r
+       buf = c->RecvBuf;\r
+\r
+       if (c->Udp->NextKeepAliveTime == 0 || c->Udp->NextKeepAliveTime <= now)\r
+       {\r
+               force_flag = true;\r
+       }\r
+\r
+       // バッファの作成\r
+       while ((c->SendBlocks->num_item > 0) || force_flag)\r
+       {\r
+               UINT *key32;\r
+               UINT64 *seq;\r
+               char *sign;\r
+\r
+               force_flag = false;\r
+\r
+               // 現在のキューからバッファを組み立てる\r
+               b = NewBuf();\r
+\r
+               // パケットヘッダ (16バイト) 分の領域を確保\r
+               WriteBuf(b, dummy_buf, sizeof(dummy_buf));\r
+\r
+               // 送信キューのパケットを詰め込む\r
+               LockQueue(c->SendBlocks);\r
+               {\r
+                       while (true)\r
+                       {\r
+                               BLOCK *block;\r
+\r
+                               if (b->Size > UDP_BUF_SIZE)\r
+                               {\r
+                                       break;\r
+                               }\r
+                               block = GetNext(c->SendBlocks);\r
+                               if (block == NULL)\r
+                               {\r
+                                       break;\r
+                               }\r
+\r
+                               if (block->Size != 0)\r
+                               {\r
+                                       WriteBufInt(b, block->Size);\r
+                                       WriteBuf(b, block->Buf, block->Size);\r
+\r
+                                       c->Session->TotalSendSize += (UINT64)block->SizeofData;\r
+                                       c->Session->TotalSendSizeReal += (UINT64)block->Size;\r
+                               }\r
+\r
+                               FreeBlock(block);\r
+                               break;\r
+                       }\r
+               }\r
+               UnlockQueue(c->SendBlocks);\r
+\r
+               // セッションキーとシーケンス番号の書き込み\r
+               sign = (char *)(((UCHAR *)b->Buf));\r
+               key32 = (UINT *)(((UCHAR *)b->Buf + 4));\r
+               seq = (UINT64 *)(((UCHAR *)b->Buf + 8));\r
+               Copy(sign, SE_UDP_SIGN, 4);\r
+               *key32 = Endian32(c->Session->SessionKey32);\r
+               *seq = Endian64(c->Udp->Seq++); // シーケンス番号をインクリメントする\r
+\r
+//             InsertQueue(c->Udp->BufferQueue, b);\r
+\r
+               packet_sent = true;\r
+/*     }\r
+\r
+       // バッファの送信\r
+       while (c->Udp->BufferQueue->num_item != 0)\r
+       {\r
+               FIFO *f = c->Udp->BufferQueue->fifo;\r
+               BUF **pb = (BUF**)(((UCHAR *)f->p) + f->pos);\r
+               BUF *b = *pb;\r
+\r
+*/             ret = SendTo(s, &c->Udp->ip, c->Udp->port, b->Buf, b->Size);\r
+               if (ret == SOCK_LATER)\r
+               {\r
+                       // ブロッキング\r
+                       Debug(".");\r
+//                     break;\r
+               }\r
+               if (ret != b->Size)\r
+               {\r
+                       if (s->IgnoreSendErr == false)\r
+                       {\r
+                               // エラー\r
+                               Debug("******* SendTo Error !!!\n");\r
+                       }\r
+               }\r
+\r
+               // メモリ解放\r
+               FreeBuf(b);\r
+//             GetNext(c->Udp->BufferQueue);\r
+       }\r
+\r
+       if (packet_sent)\r
+       {\r
+               // KeepAlive 時刻更新\r
+               c->Udp->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);\r
+       }\r
+}\r
+\r
+// UDP パケットのデータをコネクションに書き込む\r
+void PutUDPPacketData(CONNECTION *c, void *data, UINT size)\r
+{\r
+       BUF *b;\r
+       char sign[4];\r
+       // 引数チェック\r
+       if (c == NULL || data == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // プロトコルを調べる\r
+       if (c->Protocol != CONNECTION_UDP)\r
+       {\r
+               // UDP プロトコルは利用されていない\r
+               return;\r
+       }\r
+\r
+       // バッファ構成\r
+       b = NewBuf();\r
+       WriteBuf(b, data, size);\r
+\r
+       SeekBuf(b, 0, 0);\r
+       ReadBuf(b, sign, 4);\r
+\r
+       // サイン確認\r
+       if (Cmp(sign, SE_UDP_SIGN, 4) == 0)\r
+       {\r
+               UINT key32;\r
+\r
+               // セッションキー番号\r
+               key32 = ReadBufInt(b);\r
+\r
+               if (c->Session->SessionKey32 == key32)\r
+               {\r
+                       UINT64 seq;\r
+\r
+                       // シーケンス番号読み込み\r
+                       ReadBuf(b, &seq, sizeof(seq));\r
+                       seq = Endian64(seq);\r
+\r
+                       if ((UINT)(seq - c->Udp->RecvSeq - (UINT64)1))\r
+                       {\r
+                               //Debug("** UDP Seq Lost %u\n", (UINT)(seq - c->Udp->RecvSeq - (UINT64)1));\r
+                       }\r
+                       c->Udp->RecvSeq = seq;\r
+\r
+                       //Debug("SEQ: %I32u\n", seq);\r
+\r
+                       while (true)\r
+                       {\r
+                               UINT size;\r
+\r
+                               size = ReadBufInt(b);\r
+                               if (size == 0)\r
+                               {\r
+                                       break;\r
+                               }\r
+                               else if (size <= MAX_PACKET_SIZE)\r
+                               {\r
+                                       void *tmp;\r
+                                       BLOCK *block;\r
+\r
+                                       tmp = Malloc(size);\r
+                                       if (ReadBuf(b, tmp, size) != size)\r
+                                       {\r
+                                               Free(tmp);\r
+                                               break;\r
+                                       }\r
+\r
+                                       // ブロック構成\r
+                                       block = NewBlock(tmp, size, 0);\r
+\r
+                                       // ブロック挿入\r
+                                       InsertReveicedBlockToQueue(c, block);\r
+                               }\r
+                       }\r
+\r
+                       // 最終通信時刻を更新\r
+                       c->Session->LastCommTime = Tick64();\r
+               }\r
+               else\r
+               {\r
+                       Debug("Invalid SessionKey: 0x%X\n", key32);\r
+               }\r
+       }\r
+\r
+       FreeBuf(b);\r
+}\r
+\r
+// 受信キューにブロックを追加する\r
+void InsertReveicedBlockToQueue(CONNECTION *c, BLOCK *block)\r
+{\r
+       SESSION *s;\r
+       // 引数チェック\r
+       if (c == NULL || block == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s = c->Session;\r
+       \r
+       if (c->Protocol == CONNECTION_TCP)\r
+       {\r
+               s->TotalRecvSizeReal += block->SizeofData;\r
+               s->TotalRecvSize += block->Size;\r
+       }\r
+\r
+       LockQueue(c->ReceivedBlocks);\r
+       {\r
+               InsertQueue(c->ReceivedBlocks, block);\r
+       }\r
+       UnlockQueue(c->ReceivedBlocks);\r
+}\r
+\r
+// 次の Keep-Alive パケットまでの間隔を生成 (ネットワーク負荷減少のため乱数にする)\r
+UINT GenNextKeepAliveSpan(CONNECTION *c)\r
+{\r
+       UINT a, b;\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return INFINITE;\r
+       }\r
+\r
+       a = c->Session->Timeout;\r
+       b = rand() % (a / 2);\r
+       b = MAX(b, a / 5);\r
+\r
+       return b;\r
+}\r
+\r
+// Keep-Alive パケットを送信する\r
+void SendKeepAlive(CONNECTION *c, TCPSOCK *ts)\r
+{\r
+       UINT size, i, num;\r
+       UINT size_be;\r
+       UCHAR *buf;\r
+       // 引数チェック\r
+       if (c == NULL || ts == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       size = rand() % MAX_KEEPALIVE_SIZE;\r
+       num = KEEP_ALIVE_MAGIC;\r
+       buf = MallocFast(size);\r
+\r
+       for (i = 0;i < size;i++)\r
+       {\r
+               buf[i] = rand();\r
+       }\r
+\r
+       num = Endian32(num);\r
+       size_be = Endian32(size);\r
+       WriteSendFifo(c->Session, ts, &num, sizeof(UINT));\r
+       WriteSendFifo(c->Session, ts, &size_be, sizeof(UINT));\r
+       WriteSendFifo(c->Session, ts, buf, size);\r
+\r
+       c->Session->TotalSendSize += sizeof(UINT) * 2 + size;\r
+       c->Session->TotalSendSizeReal += sizeof(UINT) * 2 + size;\r
+\r
+       Free(buf);\r
+}\r
+\r
+// ブロックの送信\r
+void ConnectionSend(CONNECTION *c)\r
+{\r
+       // このあたりは急いで実装したのでコードがあまり美しくない。\r
+       UINT i, num;\r
+       UINT64 now;\r
+       UINT min_count;\r
+       TCPSOCK **tcpsocks;\r
+       UINT size;\r
+       SESSION *s;\r
+       bool use_qos;\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s = c->Session;\r
+       use_qos = s->QoS;\r
+\r
+       now = Tick64();\r
+\r
+       // プロトコル\r
+       if (c->Protocol == CONNECTION_TCP)\r
+       {\r
+               // TCP\r
+               TCP *tcp = c->Tcp;\r
+               TCPSOCK *ts;\r
+               TCPSOCK *ts_hp;\r
+               UINT num_available;\r
+               LockList(tcp->TcpSockList);\r
+               {\r
+                       num = LIST_NUM(tcp->TcpSockList);\r
+                       tcpsocks = ToArrayEx(tcp->TcpSockList, true);\r
+               }\r
+               UnlockList(tcp->TcpSockList);\r
+\r
+               // 送信に使用するソケットを選択する\r
+               // 遅延回数が最も少ないソケットを選出\r
+               min_count = INFINITE;\r
+               ts = NULL;\r
+               ts_hp = NULL;\r
+\r
+               num_available = 0;\r
+\r
+               for (i = 0;i < num;i++)\r
+               {\r
+                       TCPSOCK *tcpsock = tcpsocks[i];\r
+                       if (tcpsock->Sock->Connected && tcpsock->Sock->AsyncMode &&\r
+                               IS_SEND_TCP_SOCK(tcpsock))\r
+                       {\r
+                               // KeepAlive の処理\r
+                               if (now >= tcpsock->NextKeepAliveTime || tcpsock->NextKeepAliveTime == 0)\r
+                               {\r
+                                       // KeepAlive を打つ\r
+                                       SendKeepAlive(c, tcpsock);\r
+                                       tcpsock->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);\r
+                               }\r
+\r
+                               // 送信に利用可能なソケット数を計測する\r
+                               num_available++;\r
+\r
+                               ts_hp = tcpsock;\r
+                       }\r
+               }\r
+\r
+               for (i = 0;i < num;i++)\r
+               {\r
+                       TCPSOCK *tcpsock = tcpsocks[i];\r
+                       if (tcpsock->Sock->Connected && tcpsock->Sock->AsyncMode &&\r
+                               IS_SEND_TCP_SOCK(tcpsock))\r
+                       {\r
+                               // ソケットの選出\r
+                               bool b = false;\r
+\r
+                               if (use_qos == false)\r
+                               {\r
+                                       b = true;\r
+                               }\r
+                               else if (num_available < 2)\r
+                               {\r
+                                       b = true;\r
+                               }\r
+                               else if (tcpsock != ts_hp)\r
+                               {\r
+                                       b = true;\r
+                               }\r
+\r
+                               if (b)\r
+                               {\r
+                                       if (tcpsock->LateCount <= min_count)\r
+                                       {\r
+                                               min_count = tcpsock->LateCount;\r
+                                               ts = tcpsock;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               if (use_qos == false)\r
+               {\r
+                       ts_hp = ts;\r
+               }\r
+\r
+               if (ts == NULL || ts_hp == NULL)\r
+               {\r
+                       // 現在 送信可能なソケットが存在しない\r
+               }\r
+               else\r
+               {\r
+                       TCPSOCK *tss;\r
+                       UINT j;\r
+                       QUEUE *q;\r
+\r
+                       for (j = 0;j < 2;j++)\r
+                       {\r
+                               if (j == 0)\r
+                               {\r
+                                       q = c->SendBlocks2;\r
+                                       tss = ts_hp;\r
+                               }\r
+                               else\r
+                               {\r
+                                       q = c->SendBlocks;\r
+                                       tss = ts;\r
+                               }\r
+                               // 選択されたソケット ts に対して送信データを予約する\r
+                               LockQueue(c->SendBlocks);\r
+                               if (q->num_item != 0)\r
+                               {\r
+                                       UINT num_data;\r
+                                       BLOCK *b;\r
+\r
+                                       if (tss->SendFifo->size >= MAX((MAX_SEND_SOCKET_QUEUE_SIZE / s->MaxConnection), MIN_SEND_SOCKET_QUEUE_SIZE))\r
+                                       {\r
+                                               // 送信ソケットキューのサイズが超過\r
+                                               // 送信できない\r
+                                               while (b = GetNext(q))\r
+                                               {\r
+                                                       if (b != NULL)\r
+                                                       {\r
+                                                               c->CurrentSendQueueSize -= b->Size;\r
+                                                               FreeBlock(b);\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               bool update_keepalive_timer = false;\r
+                                               // 個数データ\r
+                                               num_data = Endian32(q->num_item);\r
+                                               PROBE_DATA2("WriteSendFifo num", &num_data, sizeof(UINT));\r
+                                               WriteSendFifo(s, tss, &num_data, sizeof(UINT));\r
+\r
+                                               s->TotalSendSize += sizeof(UINT);\r
+                                               s->TotalSendSizeReal += sizeof(UINT);\r
+\r
+                                               while (b = GetNext(q))\r
+                                               {\r
+                                                       // サイズデータ\r
+                                                       UINT size_data;\r
+                                                       size_data = Endian32(b->Size);\r
+                                                       PROBE_DATA2("WriteSendFifo size", &size_data, sizeof(UINT));\r
+                                                       WriteSendFifo(s, tss, &size_data, sizeof(UINT));\r
+\r
+                                                       c->CurrentSendQueueSize -= b->Size;\r
+\r
+                                                       s->TotalSendSize += sizeof(UINT);\r
+                                                       s->TotalSendSizeReal += sizeof(UINT);\r
+\r
+                                                       // データ本体\r
+                                                       PROBE_DATA2("WriteSendFifo data", b->Buf, b->Size);\r
+                                                       WriteSendFifo(s, tss, b->Buf, b->Size);\r
+\r
+                                                       s->TotalSendSize += b->SizeofData;\r
+                                                       s->TotalSendSizeReal += b->Size;\r
+\r
+                                                       update_keepalive_timer = true;\r
+\r
+                                                       // ブロック解放\r
+                                                       FreeBlock(b);\r
+                                               }\r
+\r
+                                               if (update_keepalive_timer)\r
+                                               {\r
+                                                       // KeepAlive タイマを増加させる\r
+                                                       tss->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               UnlockQueue(c->SendBlocks);\r
+                       }\r
+               }\r
+\r
+               // 現在各ソケットに登録されている送信予約データを送信する\r
+               for (i = 0;i < num;i++)\r
+               {\r
+                       ts = tcpsocks[i];\r
+\r
+SEND_START:\r
+                       if (ts->Sock->Connected == false)\r
+                       {\r
+                               s->LastTryAddConnectTime = Tick64();\r
+                               // 通信が切断された\r
+                               LockList(tcp->TcpSockList);\r
+                               {\r
+                                       // ソケットリストからこのソケットを削除する\r
+                                       Delete(tcp->TcpSockList, ts);\r
+                                       // TCPSOCK の解放\r
+                                       FreeTcpSock(ts);\r
+                                       // 個数のデクリメント\r
+                                       Dec(c->CurrentNumConnection);\r
+                                       Debug("--- TCP Connection Decremented: %u (%s Line %u)\n", Count(c->CurrentNumConnection), __FILE__, __LINE__);\r
+                                       Debug("LIST_NUM(tcp->TcpSockList): %u\n", LIST_NUM(tcp->TcpSockList));\r
+                               }\r
+                               UnlockList(tcp->TcpSockList);\r
+\r
+                               continue;\r
+                       }\r
+\r
+                       // Fifo サイズを取得\r
+                       if (ts->SendFifo->size != 0)\r
+                       {\r
+                               UCHAR *buf;\r
+                               UINT want_send_size;\r
+                               // 1 バイト以上送信予定データが存在する場合のみ送信する\r
+                               // バッファへのポインタを取得\r
+                               buf = (UCHAR *)ts->SendFifo->p + ts->SendFifo->pos;\r
+                               want_send_size = ts->SendFifo->size;\r
+\r
+                               PROBE_DATA2("TcpSockSend", buf, want_send_size);\r
+                               size = TcpSockSend(s, ts, buf, want_send_size);\r
+                               if (size == 0)\r
+                               {\r
+                                       // 切断された\r
+                                       continue;\r
+                               }\r
+                               else if (size == SOCK_LATER)\r
+                               {\r
+                                       // パケットが詰まっている\r
+                                       ts->LateCount++; // 遅延カウンタのインクリメント\r
+                                       PROBE_STR("ts->LateCount++;");\r
+                               }\r
+                               else\r
+                               {\r
+                                       // パケットが size だけ送信された\r
+                                       // FIFO を進める\r
+                                       ReadFifo(ts->SendFifo, NULL, size);\r
+                                       if (size < want_send_size)\r
+                                       {\r
+                                               // 予定されたデータのすべてを送信することができなかった\r
+#ifdef USE_PROBE\r
+                                               {\r
+                                                       char tmp[MAX_SIZE];\r
+\r
+                                                       snprintf(tmp, sizeof(tmp), "size < want_send_size: %u < %u",\r
+                                                               size, want_send_size);\r
+\r
+                                                       PROBE_STR(tmp);\r
+                                               }\r
+#endif // USE_PROBE\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               // すべてのパケットの送信が完了した (キューが無くなった)\r
+                                               // ので、遅延カウンタをリセットする\r
+                                               ts->LateCount = 0;\r
+\r
+                                               PROBE_STR("TcpSockSend All Completed");\r
+                                       }\r
+                                       // 最終通信日時を更新\r
+                                       c->Session->LastCommTime = now;\r
+\r
+                                       goto SEND_START;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               Free(tcpsocks);\r
+       }\r
+       else if (c->Protocol == CONNECTION_UDP)\r
+       {\r
+               // UDP\r
+               UDP *udp = c->Udp;\r
+               SOCK *sock = NULL;\r
+\r
+               Lock(c->lock);\r
+               {\r
+                       sock = udp->s;\r
+                       if (sock != NULL)\r
+                       {\r
+                               AddRef(sock->ref);\r
+                       }\r
+               }\r
+               Unlock(c->lock);\r
+\r
+               if (sock != NULL)\r
+               {\r
+                       // UDP で送信する\r
+\r
+                       // KeepAlive 送信\r
+                       if ((udp->NextKeepAliveTime == 0 || udp->NextKeepAliveTime <= now) ||\r
+                               (c->SendBlocks->num_item != 0) || (udp->BufferQueue->num_item != 0))\r
+                       {\r
+                               // 現在のキューを UDP で送信\r
+                               SendDataWithUDP(sock, c);\r
+                       }\r
+               }\r
+\r
+               if (sock != NULL)\r
+               {\r
+                       ReleaseSock(sock);\r
+               }\r
+       }\r
+       else if (c->Protocol == CONNECTION_HUB_SECURE_NAT)\r
+       {\r
+               // SecureNAT セッション\r
+               SNAT *snat = s->SecureNAT;\r
+               VH *v = snat->Nat->Virtual;\r
+\r
+               LockQueue(c->SendBlocks);\r
+               {\r
+                       BLOCK *block;\r
+                       UINT num_packet = 0;\r
+\r
+                       while (block = GetNext(c->SendBlocks))\r
+                       {\r
+                               num_packet++;\r
+                               c->CurrentSendQueueSize -= block->Size;\r
+                               VirtualPutPacket(v, block->Buf, block->Size);\r
+                               Free(block);\r
+                       }\r
+\r
+                       if (num_packet != 0)\r
+                       {\r
+                               VirtualPutPacket(v, NULL, 0);\r
+                       }\r
+               }\r
+               UnlockQueue(c->SendBlocks);\r
+       }\r
+       else if (c->Protocol == CONNECTION_HUB_LAYER3)\r
+       {\r
+               // Layer-3 セッション\r
+               L3IF *f = s->L3If;\r
+\r
+               LockQueue(c->SendBlocks);\r
+               {\r
+                       BLOCK *block;\r
+                       UINT num_packet = 0;\r
+\r
+                       while (block = GetNext(c->SendBlocks))\r
+                       {\r
+                               num_packet++;\r
+                               c->CurrentSendQueueSize -= block->Size;\r
+                               L3PutPacket(f, block->Buf, block->Size);\r
+                               Free(block);\r
+                       }\r
+\r
+                       if (num_packet != 0)\r
+                       {\r
+                               L3PutPacket(f, NULL, 0);\r
+                       }\r
+               }\r
+               UnlockQueue(c->SendBlocks);\r
+       }\r
+       else if (c->Protocol == CONNECTION_HUB_LINK_SERVER)\r
+       {\r
+               // HUB リンク\r
+               LINK *k = (LINK *)s->Link;\r
+\r
+               if (k != NULL)\r
+               {\r
+                       LockQueue(c->SendBlocks);\r
+                       {\r
+                               UINT num_blocks = 0;\r
+                               LockQueue(k->SendPacketQueue);\r
+                               {\r
+                                       BLOCK *block;\r
+\r
+                                       // パケットキューをクライアントスレッドに転送する\r
+                                       while (block = GetNext(c->SendBlocks))\r
+                                       {\r
+                                               num_blocks++;\r
+                                               c->CurrentSendQueueSize -= block->Size;\r
+                                               InsertQueue(k->SendPacketQueue, block);\r
+                                       }\r
+                               }\r
+                               UnlockQueue(k->SendPacketQueue);\r
+\r
+                               if (num_blocks != 0)\r
+                               {\r
+                                       // キャンセルの発行\r
+                                       Cancel(k->ClientSession->Cancel1);\r
+                               }\r
+                       }\r
+                       UnlockQueue(c->SendBlocks);\r
+               }\r
+       }\r
+       else if (c->Protocol == CONNECTION_HUB_BRIDGE)\r
+       {\r
+               // ローカルブリッジ\r
+               BRIDGE *b = s->Bridge;\r
+\r
+               if (b != NULL)\r
+               {\r
+                       if (b->Active)\r
+                       {\r
+                               LockQueue(c->SendBlocks);\r
+                               {\r
+                                       BLOCK *block;\r
+                                       UINT num_packet = c->SendBlocks->num_item; // パケット数\r
+\r
+                                       if (num_packet != 0)\r
+                                       {\r
+                                               // パケットデータ配列\r
+                                               void **datas = MallocFast(sizeof(void *) * num_packet);\r
+                                               UINT *sizes = MallocFast(sizeof(UINT *) * num_packet);\r
+                                               UINT i;\r
+\r
+                                               i = 0;\r
+                                               while (block = GetNext(c->SendBlocks))\r
+                                               {\r
+                                                       datas[i] = block->Buf;\r
+                                                       sizes[i] = block->Size;\r
+\r
+                                                       if (block->Size > 1514)\r
+                                                       {\r
+                                                               NormalizeEthMtu(b, c, block->Size);\r
+                                                       }\r
+\r
+                                                       c->CurrentSendQueueSize -= block->Size;\r
+                                                       Free(block);\r
+                                                       i++;\r
+                                               }\r
+\r
+                                               // パケットを書き込む\r
+                                               EthPutPackets(b->Eth, num_packet, datas, sizes);\r
+\r
+                                               Free(datas);\r
+                                               Free(sizes);\r
+                                       }\r
+                               }\r
+                               UnlockQueue(c->SendBlocks);\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+// ブロックの受信\r
+void ConnectionReceive(CONNECTION *c, CANCEL *c1, CANCEL *c2)\r
+{\r
+       // このあたりは急いで実装したのでコードがあまり美しくない。\r
+       UINT i, num;\r
+       SOCKSET set;\r
+       SESSION *s;\r
+       TCPSOCK **tcpsocks;\r
+       UCHAR *buf;\r
+       UINT size;\r
+       UINT64 now;\r
+       UINT time;\r
+       UINT num_delayed = 0;\r
+       bool no_spinlock_for_delay = false;\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PROBE_STR("ConnectionReceive");\r
+\r
+       s = c->Session;\r
+\r
+       if (s->Hub != NULL)\r
+       {\r
+               no_spinlock_for_delay = s->Hub->Option->NoSpinLockForPacketDelay;\r
+       }\r
+\r
+       now = Tick64();\r
+\r
+       if (c->RecvBuf == NULL)\r
+       {\r
+               c->RecvBuf = Malloc(RECV_BUF_SIZE);\r
+       }\r
+       buf = c->RecvBuf;\r
+\r
+       // プロトコル\r
+       if (c->Protocol == CONNECTION_TCP)\r
+       {\r
+               // TCP\r
+               TCP *tcp = c->Tcp;\r
+\r
+               // コネクション切断間隔が指定されている場合はコネクションの切断を行う\r
+               if (s->ServerMode == false)\r
+               {\r
+                       if (s->ClientOption->ConnectionDisconnectSpan != 0)\r
+                       {\r
+                               LockList(tcp->TcpSockList);\r
+                               {\r
+                                       UINT i;\r
+                                       for (i = 0;i < LIST_NUM(tcp->TcpSockList);i++)\r
+                                       {\r
+                                               TCPSOCK *ts = LIST_DATA(tcp->TcpSockList, i);\r
+                                               if (ts->DisconnectTick != 0 &&\r
+                                                       ts->DisconnectTick <= now)\r
+                                               {\r
+                                                       Debug("ts->DisconnectTick <= now\n");\r
+                                                       Disconnect(ts->Sock);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               UnlockList(tcp->TcpSockList);\r
+                       }\r
+               }\r
+\r
+               if (s->HalfConnection && (s->ServerMode == false))\r
+               {\r
+                       // 現在の TCP コネクションの方向を調べ、\r
+                       // 一方向しか無く かつコネクション数が限界の場合は\r
+                       // 1 つ切断する\r
+                       LockList(tcp->TcpSockList);\r
+                       {\r
+                               UINT i, num;\r
+                               UINT c2s, s2c;\r
+                               c2s = s2c = 0;\r
+                               num = LIST_NUM(tcp->TcpSockList);\r
+                               if (num >= s->MaxConnection)\r
+                               {\r
+                                       TCPSOCK *ts;\r
+                                       for (i = 0;i < num;i++)\r
+                                       {\r
+                                               ts = LIST_DATA(tcp->TcpSockList, i);\r
+                                               if (ts->Direction == TCP_SERVER_TO_CLIENT)\r
+                                               {\r
+                                                       s2c++;\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       c2s++;\r
+                                               }\r
+                                       }\r
+                                       if (s2c == 0 || c2s == 0)\r
+                                       {\r
+                                               // 最後のソケットを切断する\r
+                                               Disconnect(ts->Sock);\r
+                                               Debug("Disconnect (s2c=%u, c2s=%u)\n", s2c, c2s);\r
+                                       }\r
+                               }\r
+                       }\r
+                       UnlockList(tcp->TcpSockList);\r
+               }\r
+\r
+               // ソケットセットの初期化\r
+               InitSockSet(&set);\r
+               LockList(tcp->TcpSockList);\r
+               {\r
+                       num = LIST_NUM(tcp->TcpSockList);\r
+                       tcpsocks = ToArrayEx(tcp->TcpSockList, true);\r
+               }\r
+               UnlockList(tcp->TcpSockList);\r
+\r
+               for (i = 0;i < num;i++)\r
+               {\r
+                       AddSockSet(&set, tcpsocks[i]->Sock);\r
+               }\r
+\r
+               // Select\r
+               time = SELECT_TIME;\r
+               if (s->VirtualHost)\r
+               {\r
+                       time = MIN(time, SELECT_TIME_FOR_NAT);\r
+               }\r
+               time = MIN(time, GetNextDelayedPacketTickDiff(s));\r
+               num_delayed = LIST_NUM(s->DelayedPacketList);\r
+\r
+               PROBE_STR("ConnectionReceive: Select 0");\r
+\r
+               if (s->Flag1 != set.NumSocket)\r
+               {\r
+                       Select(&set, (num_delayed == 0 ? time : 1), c1, c2);\r
+                       s->Flag1 = set.NumSocket;\r
+               }\r
+               else\r
+               {\r
+                       if (no_spinlock_for_delay || time >= 50 || num_delayed == false)\r
+                       {\r
+                               Select(&set, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);\r
+                               s->Flag1 = set.NumSocket;\r
+                       }\r
+                       else\r
+                       {\r
+                               YieldCpu();\r
+                       }\r
+               }\r
+\r
+               PROBE_STR("ConnectionReceive: Select 1");\r
+\r
+               // TCP ソケットに到着しているデータをすべて読み込む\r
+               for (i = 0;i < num;i++)\r
+               {\r
+                       TCPSOCK *ts = tcpsocks[i];\r
+                       if (ts->WantSize == 0)\r
+                       {\r
+                               // 最初に必ず sizeof(UINT) だけ読み込む\r
+                               ts->WantSize = sizeof(UINT);\r
+                       }\r
+\r
+RECV_START:\r
+                       // 受信\r
+                       size = TcpSockRecv(s, ts, buf, RECV_BUF_SIZE);\r
+                       if (size == 0)\r
+                       {\r
+DISCONNECT_THIS_TCP:\r
+                               s->LastTryAddConnectTime = Tick64();\r
+                               // 通信が切断された\r
+                               LockList(tcp->TcpSockList);\r
+                               {\r
+                                       // ソケットリストからこのソケットを削除する\r
+                                       Delete(tcp->TcpSockList, ts);\r
+                                       // TCPSOCK の解放\r
+                                       FreeTcpSock(ts);\r
+                                       // デクリメント\r
+                                       Dec(c->CurrentNumConnection);\r
+                                       Debug("--- TCP Connection Decremented: %u (%s Line %u)\n", Count(c->CurrentNumConnection), __FILE__, __LINE__);\r
+                                       Debug("LIST_NUM(tcp->TcpSockList): %u\n", LIST_NUM(tcp->TcpSockList));\r
+                               }\r
+                               UnlockList(tcp->TcpSockList);\r
+\r
+                               continue;\r
+                       }\r
+                       else if (size == SOCK_LATER)\r
+                       {\r
+                               // 受信待ち状態: 何もしない\r
+                               if (IS_RECV_TCP_SOCK(ts))\r
+                               {\r
+                                       if ((now > ts->LastCommTime) && ((now - ts->LastCommTime) >= ((UINT64)s->Timeout)))\r
+                                       {\r
+                                               // このコネクションはタイムアウトした\r
+                                               Debug("Connection %u Timeouted.\n", i);\r
+                                               goto DISCONNECT_THIS_TCP;\r
+                                       }\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               // 最終通信時刻を更新\r
+                               ts->LastCommTime = now;\r
+                               c->Session->LastCommTime = now;\r
+\r
+                               // データが受信できたので FIFO に書き込む\r
+                               PROBE_DATA2("WriteRecvFifo", buf, size);\r
+                               WriteRecvFifo(s, ts, buf, size);\r
+\r
+                               // 受信バッファがいっぱいになったら受信をやめる\r
+                               if (ts->RecvFifo->size < MAX_SEND_SOCKET_QUEUE_SIZE)\r
+                               {\r
+                                       goto RECV_START;\r
+                               }\r
+                       }\r
+\r
+                       // FIFO に書き込まれたデータを処理する\r
+                       while (ts->RecvFifo->size >= ts->WantSize)\r
+                       {\r
+                               UCHAR *buf;\r
+                               void *data;\r
+                               BLOCK *block;\r
+                               UINT sz;\r
+                               // すでに十分な量のデータが格納されている\r
+                               // データのポインタを取得\r
+                               buf = (UCHAR *)ts->RecvFifo->p + ts->RecvFifo->pos;\r
+\r
+                               switch (ts->Mode)\r
+                               {\r
+                               case 0:\r
+                                       // データブロック個数\r
+                                       ts->WantSize = sizeof(UINT);\r
+                                       Copy(&sz, buf, sizeof(UINT));\r
+                                       PROBE_DATA2("ReadFifo 0", buf, sizeof(UINT));\r
+                                       sz = Endian32(sz);\r
+                                       ts->NextBlockNum = sz;\r
+                                       ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));\r
+\r
+                                       s->TotalRecvSize += sizeof(UINT);\r
+                                       s->TotalRecvSizeReal += sizeof(UINT);\r
+\r
+                                       ts->CurrentPacketNum = 0;\r
+                                       if (ts->NextBlockNum != 0)\r
+                                       {\r
+                                               if (ts->NextBlockNum == KEEP_ALIVE_MAGIC)\r
+                                               {\r
+                                                       ts->Mode = 3;\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       ts->Mode = 1;\r
+                                               }\r
+                                       }\r
+                                       break;\r
+\r
+                               case 1:\r
+                                       // データブロックサイズ\r
+                                       Copy(&sz, buf, sizeof(UINT));\r
+                                       sz = Endian32(sz);\r
+                                       PROBE_DATA2("ReadFifo 1", buf, sizeof(UINT));\r
+                                       if (sz > (MAX_PACKET_SIZE * 2))\r
+                                       {\r
+                                               // おかしなデータサイズを受信した\r
+                                               // TCP/IP 通信エラー?\r
+                                               Debug("%s %u sz > (MAX_PACKET_SIZE * 2)\n", __FILE__, __LINE__);\r
+                                               Disconnect(ts->Sock);\r
+                                       }\r
+                                       ts->NextBlockSize = MIN(sz, MAX_PACKET_SIZE * 2);\r
+                                       ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));\r
+\r
+                                       s->TotalRecvSize += sizeof(UINT);\r
+                                       s->TotalRecvSizeReal += sizeof(UINT);\r
+\r
+                                       ts->WantSize = ts->NextBlockSize;\r
+                                       if (ts->WantSize != 0)\r
+                                       {\r
+                                               ts->Mode = 2;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               ts->Mode = 1;\r
+                                               ts->WantSize = sizeof(UINT);\r
+                                               ts->CurrentPacketNum++;\r
+                                               if (ts->CurrentPacketNum >= ts->NextBlockNum)\r
+                                               {\r
+                                                       ts->Mode = 0;\r
+                                               }\r
+                                       }\r
+                                       break;\r
+\r
+                               case 2:\r
+                                       // データブロック本体\r
+                                       ts->WantSize = sizeof(UINT);\r
+                                       ts->CurrentPacketNum++;\r
+                                       data = MallocFast(ts->NextBlockSize);\r
+                                       Copy(data, buf, ts->NextBlockSize);\r
+                                       PROBE_DATA2("ReadFifo 2", buf, ts->NextBlockSize);\r
+                                       ReadFifo(ts->RecvFifo, NULL, ts->NextBlockSize);\r
+                                       block = NewBlock(data, ts->NextBlockSize, s->UseCompress ? -1 : 0);\r
+\r
+                                       if (block->Size > MAX_PACKET_SIZE)\r
+                                       {\r
+                                               // パケットサイズ超過\r
+                                               FreeBlock(block);\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               // データブロックをキューに追加\r
+                                               InsertReveicedBlockToQueue(c, block);\r
+                                       }\r
+\r
+                                       if (ts->CurrentPacketNum >= ts->NextBlockNum)\r
+                                       {\r
+                                               // すべてのデータブロックの受信が完了\r
+                                               ts->Mode = 0;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               // 次のデータブロックサイズを受信\r
+                                               ts->Mode = 1;\r
+                                       }\r
+                                       break;\r
+\r
+                               case 3:\r
+                                       // Keep-Alive パケットサイズ\r
+                                       ts->Mode = 4;\r
+                                       Copy(&sz, buf, sizeof(UINT));\r
+                                       PROBE_DATA2("ReadFifo 3", buf, sizeof(UINT));\r
+                                       sz = Endian32(sz);\r
+                                       if (sz > MAX_KEEPALIVE_SIZE)\r
+                                       {\r
+                                               // おかしなデータサイズを受信した\r
+                                               // TCP/IP 通信エラー?\r
+                                               Debug("%s %u sz > MAX_KEEPALIVE_SIZE\n", __FILE__, __LINE__);\r
+                                               Disconnect(ts->Sock);\r
+                                       }\r
+                                       ts->NextBlockSize = MIN(sz, MAX_KEEPALIVE_SIZE);\r
+                                       ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));\r
+\r
+                                       s->TotalRecvSize += sizeof(UINT);\r
+                                       s->TotalRecvSizeReal += sizeof(UINT);\r
+\r
+                                       ts->WantSize = sz;\r
+                                       break;\r
+\r
+                               case 4:\r
+                                       // Keep-Alive パケット本体\r
+                                       //Debug("KeepAlive Recved.\n");\r
+                                       ts->Mode = 0;\r
+                                       sz = ts->NextBlockSize;\r
+                                       PROBE_DATA2("ReadFifo 4", NULL, 0);\r
+                                       ReadFifo(ts->RecvFifo, NULL, sz);\r
+\r
+                                       s->TotalRecvSize += sz;\r
+                                       s->TotalRecvSizeReal += sz;\r
+\r
+                                       ts->WantSize = sizeof(UINT);\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               Free(tcpsocks);\r
+       }\r
+       else if (c->Protocol == CONNECTION_UDP)\r
+       {\r
+               // UDP\r
+               UDP *udp = c->Udp;\r
+               SOCK *sock = NULL;\r
+\r
+               if (s->ServerMode == false)\r
+               {\r
+                       Lock(c->lock);\r
+                       {\r
+                               if (c->Udp->s != NULL)\r
+                               {\r
+                                       sock = c->Udp->s;\r
+                                       if (sock != NULL)\r
+                                       {\r
+                                               AddRef(sock->ref);\r
+                                       }\r
+                               }\r
+                       }\r
+                       Unlock(c->lock);\r
+\r
+                       InitSockSet(&set);\r
+\r
+                       if (sock != NULL)\r
+                       {\r
+                               AddSockSet(&set, sock);\r
+                       }\r
+\r
+                       Select(&set, SELECT_TIME, c1, c2);\r
+\r
+                       if (sock != NULL)\r
+                       {\r
+                               IP ip;\r
+                               UINT port;\r
+                               UCHAR *buf;\r
+                               UINT size;\r
+\r
+                               while (true)\r
+                               {\r
+                                       buf = c->RecvBuf;\r
+                                       size = RecvFrom(sock, &ip, &port, buf, RECV_BUF_SIZE);\r
+                                       if (size == 0 && sock->IgnoreRecvErr == false)\r
+                                       {\r
+                                               Debug("UDP Socket Disconnected.\n");\r
+                                               Lock(c->lock);\r
+                                               {\r
+                                                       ReleaseSock(udp->s);\r
+                                                       udp->s = NULL;\r
+                                               }\r
+                                               Unlock(c->lock);\r
+                                               break;\r
+                                       }\r
+                                       else if (size == SOCK_LATER)\r
+                                       {\r
+                                               break;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               if (size)\r
+                                               {\r
+                                                       PutUDPPacketData(c, buf, size);\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       if (sock != NULL)\r
+                       {\r
+                               Release(sock->ref);\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       Select(NULL, SELECT_TIME, c1, c2);\r
+               }\r
+       }\r
+       else if (c->Protocol == CONNECTION_HUB_SECURE_NAT)\r
+       {\r
+               SNAT *snat = c->Session->SecureNAT;\r
+               VH *v = snat->Nat->Virtual;\r
+               UINT size;\r
+               void *data;\r
+               UINT num;\r
+               UINT select_wait_time = SELECT_TIME_FOR_NAT;\r
+\r
+               if (snat->Nat != NULL && snat->Nat->Option.UseNat == false)\r
+               {\r
+                       select_wait_time = SELECT_TIME;\r
+               }\r
+               else\r
+               {\r
+                       if (snat->Nat != NULL)\r
+                       {\r
+                               LockList(v->NatTable);\r
+                               {\r
+                                       if (LIST_NUM(v->NatTable) == 0 && LIST_NUM(v->ArpWaitTable) == 0)\r
+                                       {\r
+                                               select_wait_time = SELECT_TIME;\r
+                                       }\r
+                               }\r
+                               UnlockList(v->NatTable);\r
+                       }\r
+               }\r
+\r
+               select_wait_time = MIN(select_wait_time, GetNextDelayedPacketTickDiff(s));\r
+               num_delayed = LIST_NUM(s->DelayedPacketList);\r
+\r
+               if (no_spinlock_for_delay || select_wait_time >= 50 || num_delayed == false)\r
+               {\r
+                       Select(NULL, (num_delayed == 0 ? select_wait_time :\r
+                               (select_wait_time > 100 ? (select_wait_time - 100) : 1)), c1, c2);\r
+               }\r
+               else\r
+               {\r
+                       YieldCpu();\r
+               }\r
+\r
+               num = 0;\r
+\r
+               // 仮想マシンからパケットを受信する\r
+               while (size = VirtualGetNextPacket(v, &data))\r
+               {\r
+                       BLOCK *block;\r
+\r
+                       // パケットブロックを生成\r
+                       block = NewBlock(data, size, 0);\r
+                       if (block->Size > MAX_PACKET_SIZE)\r
+                       {\r
+                               // パケットサイズ超過\r
+                               FreeBlock(block);\r
+                       }\r
+                       else\r
+                       {\r
+                               // データブロックをキューに追加\r
+                               InsertReveicedBlockToQueue(c, block);\r
+                       }\r
+                       num++;\r
+                       if (num >= MAX_SEND_SOCKET_QUEUE_NUM)\r
+                       {\r
+//                             WHERE;\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+       else if (c->Protocol == CONNECTION_HUB_LINK_SERVER)\r
+       {\r
+               // HUB リンク\r
+               // 単純に Cancel を待つだけ\r
+               if (c->SendBlocks->num_item == 0)\r
+               {\r
+                       UINT time = SELECT_TIME;\r
+\r
+                       time = MIN(time, GetNextDelayedPacketTickDiff(s));\r
+                       num_delayed = LIST_NUM(s->DelayedPacketList);\r
+\r
+                       if (no_spinlock_for_delay || time >= 50 || num_delayed == false)\r
+                       {\r
+                               Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);\r
+                       }\r
+                       else\r
+                       {\r
+                               YieldCpu();\r
+                       }\r
+               }\r
+       }\r
+       else if (c->Protocol == CONNECTION_HUB_LAYER3)\r
+       {\r
+               // Layer-3 スイッチ セッション\r
+               L3IF *f = s->L3If;\r
+               UINT size, num = 0;\r
+               void *data;\r
+\r
+               if (f->SendQueue->num_item == 0)\r
+               {\r
+                       UINT time = SELECT_TIME_FOR_NAT;\r
+\r
+                       if (f->ArpWaitTable != NULL)\r
+                       {\r
+                               LockList(f->ArpWaitTable);\r
+                               {\r
+                                       if (LIST_NUM(f->ArpWaitTable) == 0)\r
+                                       {\r
+                                               time = SELECT_TIME;\r
+                                       }\r
+                               }\r
+                               UnlockList(f->ArpWaitTable);\r
+                       }\r
+\r
+                       time = MIN(time, GetNextDelayedPacketTickDiff(s));\r
+                       num_delayed = LIST_NUM(s->DelayedPacketList);\r
+\r
+                       if (no_spinlock_for_delay || time >= 50 || num_delayed == false)\r
+                       {\r
+                               Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);\r
+                       }\r
+                       else\r
+                       {\r
+                               YieldCpu();\r
+                       }\r
+               }\r
+\r
+               // 次のパケットを取得する\r
+               while (size = L3GetNextPacket(f, &data))\r
+               {\r
+                       BLOCK *block = NewBlock(data, size, 0);\r
+                       if (block->Size > MAX_PACKET_SIZE)\r
+                       {\r
+                               FreeBlock(block);\r
+                       }\r
+                       else\r
+                       {\r
+                               InsertReveicedBlockToQueue(c, block);\r
+                       }\r
+\r
+                       num++;\r
+                       if (num >= MAX_SEND_SOCKET_QUEUE_NUM)\r
+                       {\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+       else if (c->Protocol == CONNECTION_HUB_BRIDGE)\r
+       {\r
+               BRIDGE *b = c->Session->Bridge;\r
+\r
+               // Bridge セッション\r
+               if (b->Active)\r
+               {\r
+                       void *data;\r
+                       UINT ret;\r
+                       UINT num = 0;\r
+                       bool check_device_num = false;\r
+                       UINT time = SELECT_TIME;\r
+\r
+                       time = MIN(time, GetNextDelayedPacketTickDiff(s));\r
+                       num_delayed = LIST_NUM(s->DelayedPacketList);\r
+\r
+                       // ブリッジ動作中\r
+                       if (no_spinlock_for_delay || time >= 50 || num_delayed == false)\r
+                       {\r
+                               Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);\r
+                       }\r
+                       else\r
+                       {\r
+                               YieldCpu();\r
+                       }\r
+\r
+                       if ((b->LastNumDeviceCheck + BRIDGE_NUM_DEVICE_CHECK_SPAN) <= Tick64())\r
+                       {\r
+                               check_device_num = true;\r
+                               b->LastNumDeviceCheck = Tick64();\r
+                       }\r
+\r
+                       // ブリッジから次のパケットを取得する\r
+                       while (true)\r
+                       {\r
+                               if (check_device_num && b->LastNumDevice != GetEthDeviceHash())\r
+                               {\r
+                                       ret = INFINITE;\r
+                               }\r
+                               else\r
+                               {\r
+                                       ret = EthGetPacket(b->Eth, &data);\r
+                               }\r
+\r
+#ifdef OS_WIN32\r
+                               if (b->Eth != NULL && b->Eth->LoopbackBlock)\r
+                               {\r
+                                       // ブリッジにおける eth デバイスがループバックパケットを遮断\r
+                                       // する能力がある場合は CheckMac ポリシーを無効にする\r
+                                       if (c->Session != NULL && c->Session->Policy != NULL)\r
+                                       {\r
+                                               c->Session->Policy->CheckMac = false;\r
+                                       }\r
+                               }\r
+#endif // OS_WIN32\r
+\r
+                               if (ret == INFINITE)\r
+                               {\r
+                                       // エラー発生 ブリッジを停止させる\r
+                                       CloseEth(b->Eth);\r
+                                       b->Eth = NULL;\r
+                                       b->Active = false;\r
+                                       ReleaseCancel(s->Cancel2);\r
+                                       s->Cancel2 = NULL;\r
+\r
+                                       HLog(s->Hub, "LH_BRIDGE_2", s->Name, b->Name);\r
+                                       Debug("Bridge Device Error.\n");\r
+\r
+                                       break;\r
+                               }\r
+                               else if (ret == 0)\r
+                               {\r
+                                       // これ以上パケットが無い\r
+                                       break;\r
+                               }\r
+                               else\r
+                               {\r
+                                       // パケットをキューに追加\r
+                                       BLOCK *block = NewBlock(data, ret, 0);\r
+\r
+                                       PROBE_DATA2("ConnectionReceive: NewBlock", data, ret);\r
+\r
+                                       if (ret > 1514)\r
+                                       {\r
+                                               NormalizeEthMtu(b, c, ret);\r
+                                       }\r
+\r
+                                       if (block->Size > MAX_PACKET_SIZE)\r
+                                       {\r
+                                               // パケットサイズ超過\r
+                                               FreeBlock(block);\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               InsertReveicedBlockToQueue(c, block);\r
+                                       }\r
+                                       num++;\r
+                                       if (num >= MAX_SEND_SOCKET_QUEUE_NUM)\r
+                                       {\r
+//                                             WHERE;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       ETH *e;\r
+                       // 現在ブリッジは停止している\r
+                       Select(NULL, SELECT_TIME, c1, NULL);\r
+\r
+                       if (b->LastBridgeTry == 0 || (b->LastBridgeTry + BRIDGE_TRY_SPAN) <= Tick64())\r
+                       {\r
+                               b->LastBridgeTry = Tick64();\r
+\r
+                               // Ethernet デバイスを開こうとしてみる\r
+                               e = OpenEth(b->Name, b->Local, b->TapMode, b->TapMacAddress);\r
+                               if (e != NULL)\r
+                               {\r
+                                       // 成功\r
+                                       b->Eth = e;\r
+                                       b->Active = true;\r
+                                       b->LastNumDeviceCheck = Tick64();\r
+                                       b->LastNumDevice = GetEthDeviceHash();\r
+\r
+                                       Debug("Bridge Open Succeed.\n");\r
+\r
+                                       HLog(c->Session->Hub, "LH_BRIDGE_1", c->Session->Name, b->Name);\r
+\r
+                                       s->Cancel2 = EthGetCancel(b->Eth);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+// Ethernet デバイスの MTU を正規化する\r
+void NormalizeEthMtu(BRIDGE *b, CONNECTION *c, UINT packet_size)\r
+{\r
+       // 引数チェック\r
+       if (packet_size == 0 || b == NULL || c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 現在の MTU を超えるパケットの場合は MTU を引き上げる\r
+       if (EthIsChangeMtuSupported(b->Eth))\r
+       {\r
+               UINT currentMtu = EthGetMtu(b->Eth);\r
+               if (currentMtu != 0)\r
+               {\r
+                       if (packet_size > currentMtu)\r
+                       {\r
+                               bool ok = EthSetMtu(b->Eth, packet_size);\r
+\r
+                               if (ok)\r
+                               {\r
+                                       HLog(c->Session->Hub, "LH_SET_MTU", c->Session->Name,\r
+                                               b->Name, currentMtu, packet_size, packet_size);\r
+                               }\r
+                               else\r
+                               {\r
+                                       UINT64 now = Tick64();\r
+\r
+                                       if (b->LastChangeMtuError == 0 ||\r
+                                               now >= (b->LastChangeMtuError + 60000ULL))\r
+                                       {\r
+                                               HLog(c->Session->Hub, "LH_SET_MTU_ERROR", c->Session->Name,\r
+                                                       b->Name, currentMtu, packet_size, packet_size);\r
+\r
+                                               b->LastChangeMtuError = now;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+// ブロックの解放\r
+void FreeBlock(BLOCK *b)\r
+{\r
+       // 引数チェック\r
+       if (b == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Free(b->Buf);\r
+       Free(b);\r
+}\r
+\r
+// 新しいブロック作成\r
+BLOCK *NewBlock(void *data, UINT size, int compress)\r
+{\r
+       BLOCK *b;\r
+       // 引数チェック\r
+       if (data == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       b = ZeroMallocFast(sizeof(BLOCK));\r
+\r
+       if (compress == 0)\r
+       {\r
+               // 非圧縮\r
+               b->Compressed = FALSE;\r
+               b->Buf = data;\r
+               b->Size = size;\r
+               b->SizeofData = size;\r
+       }\r
+       else if (compress == 1)\r
+       {\r
+               UINT max_size;\r
+\r
+               // 圧縮\r
+               b->Compressed = TRUE;\r
+               max_size = CalcCompress(size);\r
+               b->Buf = MallocFast(max_size);\r
+               b->Size = Compress(b->Buf, max_size, data, size);\r
+               b->SizeofData = size;\r
+\r
+               // 古いデータブロックを破棄\r
+               Free(data);\r
+       }\r
+       else\r
+       {\r
+               // 展開\r
+               UINT max_size;\r
+\r
+               max_size = MAX_PACKET_SIZE;\r
+               b->Buf = MallocFast(max_size);\r
+               b->Size = Uncompress(b->Buf, max_size, data, size);\r
+               b->SizeofData = size;\r
+\r
+               // 古いデータを破棄\r
+               Free(data);\r
+       }\r
+\r
+       return b;\r
+}\r
+\r
+// TCP ソケットの作成\r
+TCPSOCK *NewTcpSock(SOCK *s)\r
+{\r
+       TCPSOCK *ts;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       ts = ZeroMalloc(sizeof(TCPSOCK));\r
+\r
+       ts->Sock = s;\r
+       AddRef(s->ref);\r
+\r
+       ts->RecvFifo = NewFifo();\r
+       ts->SendFifo = NewFifo();\r
+       ts->LastCommTime = Tick64();\r
+\r
+       // タイムアウト値の解消\r
+       SetTimeout(s, TIMEOUT_INFINITE);\r
+\r
+       return ts;\r
+}\r
+\r
+// TCP ソケット用暗号化鍵の設定\r
+void InitTcpSockRc4Key(TCPSOCK *ts, bool server_mode)\r
+{\r
+       RC4_KEY_PAIR *pair;\r
+       CRYPT *c1, *c2;\r
+       // 引数チェック\r
+       if (ts == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       pair = &ts->Rc4KeyPair;\r
+\r
+       c1 = NewCrypt(pair->ClientToServerKey, sizeof(pair->ClientToServerKey));\r
+       c2 = NewCrypt(pair->ServerToClientKey, sizeof(pair->ServerToClientKey));\r
+\r
+       if (server_mode)\r
+       {\r
+               ts->RecvKey = c1;\r
+               ts->SendKey = c2;\r
+       }\r
+       else\r
+       {\r
+               ts->SendKey = c1;\r
+               ts->RecvKey = c2;\r
+       }\r
+}\r
+\r
+// TCP ソケットの解放\r
+void FreeTcpSock(TCPSOCK *ts)\r
+{\r
+       // 引数チェック\r
+       if (ts == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Disconnect(ts->Sock);\r
+       ReleaseSock(ts->Sock);\r
+       ReleaseFifo(ts->RecvFifo);\r
+       ReleaseFifo(ts->SendFifo);\r
+\r
+       if (ts->SendKey)\r
+       {\r
+               FreeCrypt(ts->SendKey);\r
+       }\r
+       if (ts->RecvKey)\r
+       {\r
+               FreeCrypt(ts->RecvKey);\r
+       }\r
+\r
+       Free(ts);\r
+}\r
+\r
+// コネクションのトンネリングモードを終了する\r
+void EndTunnelingMode(CONNECTION *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // プロトコル\r
+       if (c->Protocol == CONNECTION_TCP)\r
+       {\r
+               // TCP\r
+               DisconnectTcpSockets(c);\r
+       }\r
+       else\r
+       {\r
+               // UDP\r
+               DisconnectUDPSockets(c);\r
+       }\r
+}\r
+\r
+// コネクションをトンネリングモードに移行させる\r
+void StartTunnelingMode(CONNECTION *c)\r
+{\r
+       SOCK *s;\r
+       TCP *tcp;\r
+       TCPSOCK *ts;\r
+       IP ip;\r
+       UINT port;\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       tcp = c->Tcp;\r
+\r
+       // プロトコル\r
+       if (c->Protocol == CONNECTION_TCP)\r
+       {\r
+               // TCP\r
+               s = c->FirstSock;\r
+\r
+               ts = NewTcpSock(s);\r
+\r
+               if (c->ServerMode == false)\r
+               {\r
+                       if (c->Session->ClientOption->ConnectionDisconnectSpan != 0)\r
+                       {\r
+                               ts->DisconnectTick = Tick64() + c->Session->ClientOption->ConnectionDisconnectSpan * (UINT64)1000;\r
+                       }\r
+               }\r
+\r
+               LockList(tcp->TcpSockList);\r
+               {\r
+                       Add(tcp->TcpSockList, ts);\r
+               }\r
+               UnlockList(tcp->TcpSockList);\r
+               ReleaseSock(s);\r
+               c->FirstSock = NULL;\r
+       }\r
+       else\r
+       {\r
+               // UDP\r
+               s = c->FirstSock;\r
+               Copy(&ip, &s->RemoteIP, sizeof(IP));\r
+               // この時点で TCP コネクションは切断してよい\r
+               c->FirstSock = NULL;\r
+               Disconnect(s);\r
+               ReleaseSock(s);\r
+\r
+               // UDP 構造体の初期化\r
+               c->Udp = ZeroMalloc(sizeof(UDP));\r
+\r
+               if (c->ServerMode)\r
+               {\r
+                       // サーバーモード\r
+                       // エントリの追加\r
+                       AddUDPEntry(c->Cedar, c->Session);\r
+                       c->Udp->s = NULL;\r
+               }\r
+               else\r
+               {\r
+                       port = c->Session->ClientOption->PortUDP;\r
+                       // クライアントモード\r
+                       c->Udp->s = NewUDP(0);\r
+                       // IP アドレスとポート番号を書く\r
+                       Copy(&c->Udp->ip, &ip, sizeof(IP));\r
+                       c->Udp->port = port;\r
+               }\r
+\r
+               // キュー\r
+               c->Udp->BufferQueue = NewQueue();\r
+       }\r
+}\r
+\r
+// 新しいコネクションを受け付ける関数\r
+void ConnectionAccept(CONNECTION *c)\r
+{\r
+       SOCK *s;\r
+       X *x;\r
+       K *k;\r
+       char tmp[128];\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Debug("ConnectionAccept()\n");\r
+\r
+       // ソケットを取得する\r
+       s = c->FirstSock;\r
+       AddRef(s->ref);\r
+\r
+       Dec(c->Cedar->AcceptingSockets);\r
+\r
+       IPToStr(tmp, sizeof(tmp), &s->RemoteIP);\r
+       SLog(c->Cedar, "LS_CONNECTION_START_1", tmp, s->RemoteHostname, s->RemotePort, c->Name);\r
+\r
+       // タイムアウト設定\r
+       SetTimeout(s, CONNECTING_TIMEOUT);\r
+\r
+       // 暗号化アルゴリズムを指定する\r
+       Lock(c->lock);\r
+       {\r
+               if (c->Cedar->CipherList != NULL)\r
+               {\r
+                       SetWantToUseCipher(s, c->Cedar->CipherList);\r
+               }\r
+\r
+               x = CloneX(c->Cedar->ServerX);\r
+               k = CloneK(c->Cedar->ServerK);\r
+       }\r
+       Unlock(c->lock);\r
+\r
+       // SSL 通信を開始する\r
+       Debug("StartSSL()\n");\r
+       if (StartSSL(s, x, k) == false)\r
+       {\r
+               // 失敗\r
+               Debug("Failed to StartSSL.\n");\r
+               FreeX(x);\r
+               FreeK(k);\r
+               goto ERROR;\r
+       }\r
+\r
+       FreeX(x);\r
+       FreeK(k);\r
+\r
+       SLog(c->Cedar, "LS_SSL_START", c->Name, s->CipherName);\r
+\r
+       // 接続を受諾する\r
+       if (ServerAccept(c) == false)\r
+       {\r
+               // 失敗\r
+               Debug("ServerAccept Failed. Err = %u\n", c->Err);\r
+               goto ERROR;\r
+       }\r
+\r
+       if (c->flag1 == false)\r
+       {\r
+               Debug("%s %u c->flag1 == false\n", __FILE__, __LINE__);\r
+               Disconnect(s);\r
+       }\r
+       DelConnection(c->Cedar, c);\r
+       ReleaseSock(s);\r
+       return;\r
+\r
+ERROR:\r
+       Debug("ConnectionAccept() Error.\n");\r
+       Disconnect(s);\r
+       DelConnection(c->Cedar, c);\r
+       ReleaseSock(s);\r
+}\r
+\r
+// 現在動作しているすべての追加コネクションを張るスレッドを中断する\r
+void StopAllAdditionalConnectThread(CONNECTION *c)\r
+{\r
+       UINT i, num;\r
+       SOCK **socks;\r
+       THREAD **threads;\r
+       // 引数チェック\r
+       if (c == NULL || c->ServerMode != false)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // まずソケットを切断する\r
+       LockList(c->ConnectingSocks);\r
+       {\r
+               num = LIST_NUM(c->ConnectingSocks);\r
+               socks = ToArray(c->ConnectingSocks);\r
+               DeleteAll(c->ConnectingSocks);\r
+       }\r
+       UnlockList(c->ConnectingSocks);\r
+       for (i = 0;i < num;i++)\r
+       {\r
+               Disconnect(socks[i]);\r
+               ReleaseSock(socks[i]);\r
+       }\r
+       Free(socks);\r
+\r
+       // 次にスレッドの停止を待つ\r
+       LockList(c->ConnectingThreads);\r
+       {\r
+               num = LIST_NUM(c->ConnectingThreads);\r
+               Debug("c->ConnectingThreads: %u\n", num);\r
+               threads = ToArray(c->ConnectingThreads);\r
+               DeleteAll(c->ConnectingThreads);\r
+       }\r
+       UnlockList(c->ConnectingThreads);\r
+       for (i = 0;i < num;i++)\r
+       {\r
+               WaitThread(threads[i], INFINITE);\r
+               ReleaseThread(threads[i]);\r
+       }\r
+       Free(threads);\r
+}\r
+\r
+// コネクションの停止\r
+void StopConnection(CONNECTION *c, bool no_wait)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Debug("Stop Connection: %s\n", c->Name);\r
+\r
+       // 停止フラグ\r
+       c->Halt = true;\r
+       Disconnect(c->FirstSock);\r
+\r
+       if (no_wait == false)\r
+       {\r
+               // スレッド停止まで待機\r
+               WaitThread(c->Thread, INFINITE);\r
+       }\r
+}\r
+\r
+// UDP ソケットをすべて閉じる\r
+void DisconnectUDPSockets(CONNECTION *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+       if (c->Protocol != CONNECTION_UDP)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // エントリの削除\r
+       if (c->ServerMode)\r
+       {\r
+               DelUDPEntry(c->Cedar, c->Session);\r
+       }\r
+\r
+       // UDP 構造体の削除\r
+       if (c->Udp != NULL)\r
+       {\r
+               if (c->Udp->s != NULL)\r
+               {\r
+                       ReleaseSock(c->Udp->s);\r
+               }\r
+               if (c->Udp->BufferQueue != NULL)\r
+               {\r
+                       // キューの解放\r
+                       BUF *b;\r
+                       while (b = GetNext(c->Udp->BufferQueue))\r
+                       {\r
+                               FreeBuf(b);\r
+                       }\r
+                       ReleaseQueue(c->Udp->BufferQueue);\r
+               }\r
+               Free(c->Udp);\r
+               c->Udp = NULL;\r
+       }\r
+\r
+       if (c->FirstSock != NULL)\r
+       {\r
+               Disconnect(c->FirstSock);\r
+               ReleaseSock(c->FirstSock);\r
+               c->FirstSock = NULL;\r
+       }\r
+}\r
+\r
+// TCP コネクションをすべて閉じる\r
+void DisconnectTcpSockets(CONNECTION *c)\r
+{\r
+       UINT i, num;\r
+       TCP *tcp;\r
+       TCPSOCK **tcpsocks;\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+       if (c->Protocol != CONNECTION_TCP)\r
+       {\r
+               return;\r
+       }\r
+\r
+       tcp = c->Tcp;\r
+       LockList(tcp->TcpSockList);\r
+       {\r
+               tcpsocks = ToArray(tcp->TcpSockList);\r
+               num = LIST_NUM(tcp->TcpSockList);\r
+               DeleteAll(tcp->TcpSockList);\r
+       }\r
+       UnlockList(tcp->TcpSockList);\r
+\r
+       if (num != 0)\r
+       {\r
+               Debug("--- SOCKET STATUS ---\n");\r
+               for (i = 0;i < num;i++)\r
+               {\r
+                       TCPSOCK *ts = tcpsocks[i];\r
+                       Debug(" SOCK %2u: %u\n", i, ts->Sock->SendSize);\r
+                       FreeTcpSock(ts);\r
+               }\r
+       }\r
+\r
+       Free(tcpsocks);\r
+}\r
+\r
+// コネクションのクリーンアップ\r
+void CleanupConnection(CONNECTION *c)\r
+{\r
+       UINT i, num;\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       DeleteLock(c->lock);\r
+       ReleaseCedar(c->Cedar);\r
+\r
+       switch (c->Protocol)\r
+       {\r
+       case CONNECTION_TCP:\r
+               // TCP コネクションリストの解放\r
+               DisconnectTcpSockets(c);\r
+               break;\r
+\r
+       case CONNECTION_UDP:\r
+               break;\r
+       }\r
+\r
+       ReleaseList(c->Tcp->TcpSockList);\r
+       Free(c->Tcp);\r
+\r
+       ReleaseSock(c->FirstSock);\r
+       c->FirstSock = NULL;\r
+\r
+       ReleaseThread(c->Thread);\r
+       Free(c->Name);\r
+\r
+       // すべての送信ブロックと受信ブロックを解放\r
+       if (c->SendBlocks)\r
+       {\r
+               LockQueue(c->SendBlocks);\r
+               {\r
+                       BLOCK *b;\r
+                       while (b = GetNext(c->SendBlocks))\r
+                       {\r
+                               FreeBlock(b);\r
+                       }\r
+               }\r
+               UnlockQueue(c->SendBlocks);\r
+       }\r
+       if (c->SendBlocks2)\r
+       {\r
+               LockQueue(c->SendBlocks2);\r
+               {\r
+                       BLOCK *b;\r
+                       while (b = GetNext(c->SendBlocks2))\r
+                       {\r
+                               FreeBlock(b);\r
+                       }\r
+               }\r
+               UnlockQueue(c->SendBlocks2);\r
+       }\r
+       if (c->ReceivedBlocks)\r
+       {\r
+               LockQueue(c->ReceivedBlocks);\r
+               {\r
+                       BLOCK *b;\r
+                       while (b = GetNext(c->ReceivedBlocks))\r
+                       {\r
+                               FreeBlock(b);\r
+                       }\r
+               }\r
+               UnlockQueue(c->ReceivedBlocks);\r
+       }\r
+\r
+       if (c->ConnectingThreads)\r
+       {\r
+               THREAD **threads;\r
+               LockList(c->ConnectingThreads);\r
+               {\r
+                       num = LIST_NUM(c->ConnectingThreads);\r
+                       threads = ToArray(c->ConnectingThreads);\r
+                       for (i = 0;i < num;i++)\r
+                       {\r
+                               ReleaseThread(threads[i]);\r
+                       }\r
+                       Free(threads);\r
+               }\r
+               UnlockList(c->ConnectingThreads);\r
+               ReleaseList(c->ConnectingThreads);\r
+       }\r
+\r
+       if (c->ConnectingSocks)\r
+       {\r
+               SOCK **socks;\r
+               LockList(c->ConnectingSocks);\r
+               {\r
+                       num = LIST_NUM(c->ConnectingSocks);\r
+                       socks = ToArray(c->ConnectingSocks);\r
+                       for (i = 0;i < num;i++)\r
+                       {\r
+                               Disconnect(socks[i]);\r
+                               ReleaseSock(socks[i]);\r
+                       }\r
+                       Free(socks);\r
+               }\r
+               UnlockList(c->ConnectingSocks);\r
+               ReleaseList(c->ConnectingSocks);\r
+       }\r
+\r
+       if (c->RecvBuf)\r
+       {\r
+               Free(c->RecvBuf);\r
+       }\r
+\r
+       if (c->ServerX != NULL)\r
+       {\r
+               FreeX(c->ServerX);\r
+       }\r
+\r
+       if (c->ClientX != NULL)\r
+       {\r
+               FreeX(c->ClientX);\r
+       }\r
+\r
+       ReleaseQueue(c->ReceivedBlocks);\r
+       ReleaseQueue(c->SendBlocks);\r
+       ReleaseQueue(c->SendBlocks2);\r
+\r
+       DeleteCounter(c->CurrentNumConnection);\r
+\r
+       if (c->CipherName != NULL)\r
+       {\r
+               Free(c->CipherName);\r
+       }\r
+\r
+       Free(c);\r
+}\r
+\r
+// コネクションの解放\r
+void ReleaseConnection(CONNECTION *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (Release(c->ref) == 0)\r
+       {\r
+               CleanupConnection(c);\r
+       }\r
+}\r
+\r
+// コネクションの比較\r
+int CompareConnection(void *p1, void *p2)\r
+{\r
+       CONNECTION *c1, *c2;\r
+       if (p1 == NULL || p2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+       c1 = *(CONNECTION **)p1;\r
+       c2 = *(CONNECTION **)p2;\r
+       if (c1 == NULL || c2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       return StrCmpi(c1->Name, c2->Name);\r
+}\r
+\r
+// サーバーコネクションの作成\r
+CONNECTION *NewServerConnection(CEDAR *cedar, SOCK *s, THREAD *t)\r
+{\r
+       CONNECTION *c;\r
+       // 引数チェック\r
+       if (cedar == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       c = ZeroMalloc(sizeof(CONNECTION));\r
+       c->ConnectedTick = Tick64();\r
+       c->lock = NewLock();\r
+       c->ref = NewRef();\r
+       c->Cedar = cedar;\r
+       AddRef(c->Cedar->ref);\r
+       c->Protocol = CONNECTION_TCP;\r
+       c->Type = CONNECTION_TYPE_INIT;\r
+       c->FirstSock = s;\r
+       if (s != NULL)\r
+       {\r
+               AddRef(c->FirstSock->ref);\r
+               Copy(&c->ClientIp, &s->RemoteIP, sizeof(IP));\r
+               StrCpy(c->ClientHostname, sizeof(c->ClientHostname), s->RemoteHostname);\r
+       }\r
+       c->Tcp = ZeroMalloc(sizeof(TCP));\r
+       c->Tcp->TcpSockList = NewList(NULL);\r
+       c->ServerMode = true;\r
+       c->Status = CONNECTION_STATUS_ACCEPTED;\r
+       c->Name = CopyStr("INITING");\r
+       c->Thread = t;\r
+       AddRef(t->ref);\r
+       c->CurrentNumConnection = NewCounter();\r
+       Inc(c->CurrentNumConnection);\r
+\r
+       c->ServerVer = cedar->Version;\r
+       c->ServerBuild = cedar->Build;\r
+       StrCpy(c->ServerStr, sizeof(c->ServerStr), cedar->ServerStr);\r
+       GetServerProductName(cedar->Server, c->ServerStr, sizeof(c->ServerStr));\r
+\r
+       if (s != NULL && s->RemoteX != NULL)\r
+       {\r
+               c->ServerX = CloneX(s->RemoteX);\r
+       }\r
+\r
+       // キューの作成\r
+       c->ReceivedBlocks = NewQueue();\r
+       c->SendBlocks = NewQueue();\r
+       c->SendBlocks2 = NewQueue();\r
+\r
+       return c;\r
+}\r
+\r
+// クライアントコネクションの作成\r
+CONNECTION *NewClientConnection(SESSION *s)\r
+{\r
+       return NewClientConnectionEx(s, NULL, 0, 0);\r
+}\r
+CONNECTION *NewClientConnectionEx(SESSION *s, char *client_str, UINT client_ver, UINT client_build)\r
+{\r
+       CONNECTION *c;\r
+\r
+       // CONNECTION オブジェクトの初期化\r
+       c = ZeroMalloc(sizeof(CONNECTION));\r
+       c->ConnectedTick = Tick64();\r
+       c->lock = NewLock();\r
+       c->ref = NewRef();\r
+       c->Cedar = s->Cedar;\r
+       AddRef(c->Cedar->ref);\r
+       if (s->ClientOption->PortUDP == 0)\r
+       {\r
+               // TCP\r
+               c->Protocol = CONNECTION_TCP;\r
+               c->Tcp = ZeroMalloc(sizeof(TCP));\r
+               c->Tcp->TcpSockList = NewList(NULL);\r
+       }\r
+       else\r
+       {\r
+               // UDP\r
+               c->Protocol = CONNECTION_UDP;\r
+       }\r
+       c->ServerMode = false;\r
+       c->Status = CONNECTION_STATUS_CONNECTING;\r
+       c->Name = CopyStr("CLIENT_CONNECTION");\r
+       c->Session = s;\r
+       c->CurrentNumConnection = NewCounter();\r
+       Inc(c->CurrentNumConnection);\r
+\r
+       c->ConnectingThreads = NewList(NULL);\r
+       c->ConnectingSocks = NewList(NULL);\r
+\r
+       if (client_str == NULL)\r
+       {\r
+               c->ClientVer = s->Cedar->Version;\r
+               c->ClientBuild = s->Cedar->Build;\r
+\r
+               if (c->Session->VirtualHost == false)\r
+               {\r
+                       if (c->Session->LinkModeClient == false)\r
+                       {\r
+                               StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_CLIENT_STR);\r
+                       }\r
+                       else\r
+                       {\r
+                               StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_SERVER_LINK_STR);\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_ROUTER_STR);\r
+               }\r
+       }\r
+       else\r
+       {\r
+               c->ClientVer = client_ver;\r
+               c->ClientBuild = client_build;\r
+               StrCpy(c->ClientStr, sizeof(c->ClientStr), client_str);\r
+       }\r
+\r
+       // サーバー名とポート番号\r
+       StrCpy(c->ServerName, sizeof(c->ServerName), s->ClientOption->Hostname);\r
+       c->ServerPort = s->ClientOption->Port;\r
+\r
+       // TLS 1.0 使用フラグ\r
+       c->DontUseTls1 = s->ClientOption->NoTls1;\r
+\r
+       // キューの作成\r
+       c->ReceivedBlocks = NewQueue();\r
+       c->SendBlocks = NewQueue();\r
+       c->SendBlocks2 = NewQueue();\r
+\r
+       return c;\r
+}\r
+\r
+\r