* tar xzf utvpn-src-unix-v101-7101-public-2010.06.27.tar.gz
[lab.git] / utvpn / utvpn-unix-v101-7101-public / src / Cedar / Session.c
1 // SoftEther UT-VPN SourceCode\r
2 // \r
3 // Copyright (C) 2004-2010 SoftEther Corporation.\r
4 // Copyright (C) 2004-2010 University of Tsukuba, Japan.\r
5 // Copyright (C) 2003-2010 Daiyuu Nobori.\r
6 // All Rights Reserved.\r
7 // \r
8 // http://utvpn.tsukuba.ac.jp/\r
9 // \r
10 // This program is free software; you can redistribute it and/or\r
11 // modify it under the terms of the GNU General Public License\r
12 // version 2 as published by the Free Software Foundation.\r
13 // \r
14 // This program is distributed in the hope that it will be useful,\r
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
17 // GNU General Public License for more details.\r
18 // \r
19 // You should have received a copy of the GNU General Public License version 2\r
20 // along with this program; if not, write to the Free Software\r
21 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
22 // \r
23 // このファイルは GPL バージョン 2 ライセンスで公開されています。\r
24 // 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布\r
25 // することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示\r
26 // を除去することはできません。改変した著作物を配布する場合は、改変実施者の\r
27 // 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。\r
28 // \r
29 // この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の\r
30 // ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )\r
31 // および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって\r
32 // ホストされています。\r
33 // 本プログラムの配布者は、本プログラムを、業としての利用以外のため、\r
34 // および、試験または研究のために利用が行われることを想定して配布\r
35 // しています。\r
36 // SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に\r
37 // あります。\r
38 // 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード\r
39 // の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して\r
40 // いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して\r
41 // ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース\r
42 // に組み込みさせていただきます。\r
43 // \r
44 // GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する\r
45 // 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。\r
46 // \r
47 // 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社\r
48 // (SoftEther Corporation) およびその他の著作権保持者が保有しています。\r
49 // ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの\r
50 // 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意\r
51 // ください。\r
52 // \r
53 // お願い: どのような通信ソフトウェアにも通常は必ず未発見の\r
54 // セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、\r
55 // UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの\r
56 // 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社\r
57 // および脆弱性情報の届出を受け付ける公的機関まで通報いただき、\r
58 // 公益保護にご協力いただきますようお願い申し上げます。\r
59 // \r
60 // ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を\r
61 // 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客\r
62 // を保護するための努力を行います。\r
63 // \r
64 // ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/\r
65 // 日本国内の脆弱性情報届出受付公的機関:\r
66 //         独立行政法人 情報処理推進機構\r
67 //         http://www.ipa.go.jp/security/vuln/report/\r
68 // \r
69 // 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。\r
70 // 連絡先: http://www.softether.co.jp/jp/contact/\r
71 \r
72 // -----------------------------------------------\r
73 // [ChangeLog]\r
74 // 2010.05.20\r
75 //  新規リリース by SoftEther\r
76 // -----------------------------------------------\r
77 \r
78 // Session.c\r
79 // セッションマネージャ\r
80 \r
81 #include "CedarPch.h"\r
82 \r
83 // セッションのメインルーチン\r
84 void SessionMain(SESSION *s)\r
85 {\r
86         CONNECTION *c;\r
87         POLICY *policy;\r
88         UINT64 now;\r
89         UINT i = 0;\r
90         PACKET_ADAPTER *pa;\r
91         bool pa_inited = false;\r
92         UINT packet_size;\r
93         void *packet;\r
94         bool packet_put;\r
95         bool pa_fail = false;\r
96         UINT test = 0;\r
97         bool update_hub_last_comm = false;\r
98         UINT err = ERR_SESSION_TIMEOUT;\r
99         UINT64 next_update_hub_last_comm = 0;\r
100         UINT64 auto_disconnect_tick = 0;\r
101         TRAFFIC t;\r
102         SOCK *msgdlg_sock = NULL;\r
103         SOCK *nicinfo_sock = NULL;\r
104         // 引数チェック\r
105         if (s == NULL)\r
106         {\r
107                 return;\r
108         }\r
109         Debug("SessionMain: %s\n", s->Name);\r
110 \r
111         Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);\r
112 \r
113         // リトライ回数のリセット\r
114         s->CurrentRetryCount = 0;\r
115         s->ConnectSucceed = true;\r
116         s->SessionTimeOuted = false;\r
117 \r
118         c = s->Connection;\r
119         policy = s->Policy;\r
120 \r
121         // パケットアダプタの初期化\r
122         pa = s->PacketAdapter;\r
123         if (pa->Init(s) == false)\r
124         {\r
125                 // 初期化失敗\r
126                 if (s->VLanDeviceErrorCount >= 2)\r
127                 {\r
128                         s->ForceStopFlag = true;\r
129                 }\r
130                 else\r
131                 {\r
132                         s->VLanDeviceErrorCount++;\r
133                 }\r
134                 err = ERR_DEVICE_DRIVER_ERROR;\r
135                 goto CLEANUP;\r
136         }\r
137         pa_inited = true;\r
138 \r
139         if (s->BridgeMode == false)\r
140         {\r
141                 s->Cancel2 = pa->GetCancel(s);\r
142         }\r
143         else\r
144         {\r
145                 CANCEL *c = pa->GetCancel(s);\r
146                 CANCEL *old = s->Cancel1;\r
147                 s->Cancel1 = c;\r
148                 ReleaseCancel(old);\r
149         }\r
150 \r
151         s->RetryFlag = false;\r
152 \r
153         s->LastCommTime = Tick64();\r
154         if (s->ServerMode == false)\r
155         {\r
156                 s->NextConnectionTime = Tick64() + (UINT64)(s->ClientOption->AdditionalConnectionInterval * 1000);\r
157         }\r
158 \r
159         s->NumConnectionsEatablished++;\r
160         s->CurrentConnectionEstablishTime = Tick64();\r
161         if (s->FirstConnectionEstablisiedTime == 0)\r
162         {\r
163                 s->FirstConnectionEstablisiedTime = Tick64();\r
164         }\r
165 \r
166         if (s->ServerMode == false && s->Cedar->Client != NULL)\r
167         {\r
168                 if (s->Policy != NULL)\r
169                 {\r
170                         if (s->Policy->AutoDisconnect)\r
171                         {\r
172                                 auto_disconnect_tick = s->CurrentConnectionEstablishTime +\r
173                                         (UINT64)s->Policy->AutoDisconnect * 1000ULL;\r
174                         }\r
175                 }\r
176         }\r
177 \r
178         s->LastIncrementTraffic = Tick64();\r
179 \r
180         c->Err = ERR_SESSION_TIMEOUT;\r
181         s->VLanDeviceErrorCount = 0;\r
182 \r
183         s->LastTryAddConnectTime = Tick64();\r
184 \r
185         Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);\r
186 \r
187         if (policy != NULL)\r
188         {\r
189                 // ポリシーの内容を見てモードを決定する\r
190                 if (policy->MonitorPort)\r
191                 {\r
192                         s->IsMonitorMode = true;\r
193                 }\r
194 \r
195                 if (policy->NoRouting == false || policy->NoBridge == false)\r
196                 {\r
197                         s->IsBridgeMode = true;\r
198                 }\r
199         }\r
200 \r
201         if (s->ServerMode == false && s->Cedar->Client != NULL)\r
202         {\r
203                 if (IsEmptyUniStr(s->Client_Message) == false)\r
204                 {\r
205                         UI_MSG_DLG dlg;\r
206 \r
207                         Zero(&dlg, sizeof(dlg));\r
208                         if (s->ClientOption != NULL)\r
209                         {\r
210                                 StrCpy(dlg.HubName, sizeof(dlg.HubName), s->ClientOption->HubName);\r
211                                 StrCpy(dlg.ServerName, sizeof(dlg.ServerName), s->ClientOption->Hostname);\r
212                         }\r
213 \r
214                         dlg.Msg = s->Client_Message;\r
215 \r
216                         msgdlg_sock = CncMsgDlg(&dlg);\r
217                 }\r
218 \r
219                 if (s->Win32HideNicInfoWindow == false)\r
220                 {\r
221                         UI_NICINFO info;\r
222 \r
223                         Zero(&info, sizeof(info));\r
224                         if (s->ClientOption != NULL)\r
225                         {\r
226                                 StrCpy(info.NicName, sizeof(info.NicName), s->ClientOption->DeviceName);\r
227                                 UniStrCpy(info.AccountName, sizeof(info.AccountName), s->ClientOption->AccountName);\r
228                         }\r
229 \r
230                         nicinfo_sock = CncNicInfo(&info);\r
231                 }\r
232         }\r
233 \r
234         while (true)\r
235         {\r
236                 Zero(&t, sizeof(t));\r
237 \r
238                 if (next_update_hub_last_comm == 0 ||\r
239                         (next_update_hub_last_comm <= Tick64()))\r
240                 {\r
241                         next_update_hub_last_comm = Tick64() + 1000;\r
242 \r
243                         if (s->Hub != NULL)\r
244                         {\r
245                                 if (update_hub_last_comm)\r
246                                 {\r
247                                         Lock(s->Hub->lock);\r
248                                         {\r
249                                                 s->Hub->LastCommTime = SystemTime64();\r
250                                         }\r
251                                         Unlock(s->Hub->lock);\r
252 \r
253                                         update_hub_last_comm = false;\r
254                                 }\r
255                         }\r
256                 }\r
257 \r
258                 // 追加接続のチャンス\r
259                 ClientAdditionalConnectChance(s);\r
260 \r
261                 // ブロックを受信\r
262                 ConnectionReceive(c, s->Cancel1, s->Cancel2);\r
263 \r
264                 // 受信したブロックを PacketAdapter に渡す\r
265                 LockQueue(c->ReceivedBlocks);\r
266                 {\r
267                         BLOCK *b;\r
268                         packet_put = false;\r
269                         while (true)\r
270                         {\r
271                                 b = GetNext(c->ReceivedBlocks);\r
272                                 if (b == NULL)\r
273                                 {\r
274                                         break;\r
275                                 }\r
276 \r
277                                 PROBE_DATA2("GetNext", b->Buf, b->Size);\r
278 \r
279                                 update_hub_last_comm = true;\r
280 \r
281                                 if (s->ServerMode == false && b->Size >= 14)\r
282                                 {\r
283                                         if (b->Buf[0] & 0x40)\r
284                                         {\r
285                                                 t.Recv.BroadcastCount++;\r
286                                                 t.Recv.BroadcastBytes += (UINT64)b->Size;\r
287                                         }\r
288                                         else\r
289                                         {\r
290                                                 t.Recv.UnicastCount++;\r
291                                                 t.Recv.UnicastBytes += (UINT64)b->Size;\r
292                                         }\r
293                                 }\r
294 \r
295                                 packet_put = true;\r
296                                 PROBE_DATA2("pa->PutPacket", b->Buf, b->Size);\r
297                                 if (pa->PutPacket(s, b->Buf, b->Size) == false)\r
298                                 {\r
299                                         pa_fail = true;\r
300                                         err = ERR_DEVICE_DRIVER_ERROR;\r
301                                         Free(b->Buf);\r
302                                         Debug("  Error: pa->PutPacket(Packet) Failed.\n");\r
303                                 }\r
304                                 Free(b);\r
305                         }\r
306 \r
307                         if (packet_put || s->ServerMode)\r
308                         {\r
309                                 PROBE_DATA2("pa->PutPacket", NULL, 0);\r
310                                 if (pa->PutPacket(s, NULL, 0) == false)\r
311                                 {\r
312                                         Debug("  Error: pa->PutPacket(NULL) Failed.\n");\r
313                                         pa_fail = true;\r
314                                         err = ERR_DEVICE_DRIVER_ERROR;\r
315                                 }\r
316                         }\r
317                 }\r
318                 UnlockQueue(c->ReceivedBlocks);\r
319 \r
320                 // 送信するべきパケットを PacketAdapter から取得して SendBlocks に追加\r
321                 LockQueue(c->SendBlocks);\r
322                 {\r
323                         UINT i, max_num = MAX_SEND_SOCKET_QUEUE_NUM;\r
324                         i = 0;\r
325                         while (packet_size = pa->GetNextPacket(s, &packet))\r
326                         {\r
327                                 BLOCK *b;\r
328                                 if (packet_size == INFINITE)\r
329                                 {\r
330                                         err = ERR_DEVICE_DRIVER_ERROR;\r
331                                         pa_fail = true;\r
332                                         Debug("  Error: pa->GetNextPacket() Failed.\n");\r
333                                         break;\r
334                                 }\r
335 \r
336                                 update_hub_last_comm = true;\r
337 \r
338                                 if ((c->CurrentSendQueueSize > MAX_BUFFERING_PACKET_SIZE))\r
339                                 {\r
340 //                                      WHERE;\r
341                                         // バッファリングサイズ制限値を超過しているので破棄\r
342                                         Free(packet);\r
343                                 }\r
344                                 else\r
345                                 {\r
346                                         bool priority;\r
347                                         // バッファリングする\r
348                                         if (s->ServerMode == false && packet_size >= 14)\r
349                                         {\r
350                                                 UCHAR *buf = (UCHAR *)packet;\r
351                                                 if (buf[0] & 0x01)\r
352                                                 {\r
353                                                         t.Send.BroadcastCount++;\r
354                                                         t.Send.BroadcastBytes += (UINT64)packet_size;\r
355                                                 }\r
356                                                 else\r
357                                                 {\r
358                                                         t.Send.UnicastCount++;\r
359                                                         t.Send.UnicastBytes += (UINT64)packet_size;\r
360                                                 }\r
361                                         }\r
362                                         priority = IsPriorityHighestPacketForQoS(packet, packet_size);\r
363                                         b = NewBlock(packet, packet_size, s->UseCompress ? 1 : 0);\r
364                                         b->PriorityQoS = priority;\r
365                                         c->CurrentSendQueueSize += b->Size;\r
366 \r
367                                         if (b->PriorityQoS && c->Protocol == CONNECTION_TCP && s->QoS)\r
368                                         {\r
369                                                 InsertQueue(c->SendBlocks2, b);\r
370                                         }\r
371                                         else\r
372                                         {\r
373                                                 InsertQueue(c->SendBlocks, b);\r
374                                         }\r
375                                 }\r
376                                 i++;\r
377                                 if (i >= max_num)\r
378                                 {\r
379                                         break;\r
380                                 }\r
381                         }\r
382                 }\r
383                 UnlockQueue(c->SendBlocks);\r
384 \r
385                 AddTrafficForSession(s, &t);\r
386 \r
387                 // ブロックを送信\r
388                 ConnectionSend(c);\r
389 \r
390                 // 自動切断判定\r
391                 if (auto_disconnect_tick != 0 && auto_disconnect_tick <= Tick64())\r
392                 {\r
393                         err = ERR_AUTO_DISCONNECTED;\r
394                         s->CurrentRetryCount = INFINITE;\r
395                         break;\r
396                 }\r
397 \r
398                 // 停止判定\r
399                 if (s->Halt)\r
400                 {\r
401                         if (s->ForceStopFlag)\r
402                         {\r
403                                 err = ERR_USER_CANCEL;\r
404                         }\r
405                         break;\r
406                 }\r
407 \r
408                 // 現在時刻を取得\r
409                 now = Tick64();\r
410 \r
411                 if (s->ServerMode)\r
412                 {\r
413                         HUB *hub;\r
414 \r
415                         // ユーザーのトラフィックデータの更新\r
416                         if ((s->LastIncrementTraffic + INCREMENT_TRAFFIC_INTERVAL) <= now)\r
417                         {\r
418                                 IncrementUserTraffic(s->Hub, s->UserNameReal, s);\r
419                                 s->LastIncrementTraffic = now;\r
420                         }\r
421 \r
422                         hub = s->Hub;\r
423 \r
424                         if (hub != NULL)\r
425                         {\r
426                                 Lock(hub->lock);\r
427                                 {\r
428                                         if ((hub->LastIncrementTraffic + INCREMENT_TRAFFIC_INTERVAL) <= now)\r
429                                         {\r
430                                                 IncrementHubTraffic(s->Hub);\r
431                                                 hub->LastIncrementTraffic = now;\r
432                                         }\r
433                                 }\r
434                                 Unlock(hub->lock);\r
435                         }\r
436                 }\r
437 \r
438                 // リンクモードサーバーセッションの場合はタイムアウトしない\r
439                 // それ以外のセッションの場合はタイムアウトを判定する\r
440                 if (s->LinkModeServer == false && s->SecureNATMode == false && s->BridgeMode == false && s->L3SwitchMode == false)\r
441                 {\r
442                         bool timeouted = false;\r
443 \r
444                         if ((now > s->LastCommTime) && ((now - s->LastCommTime) >= ((UINT64)s->Timeout)))\r
445                         {\r
446                                 // 一定時間通信ができていない場合\r
447                                 timeouted = true;\r
448                         }\r
449 \r
450                         if (s->ServerMode == false && s->ClientOption != NULL && s->ClientOption->ConnectionDisconnectSpan == 0)\r
451                         {\r
452                                 if (LIST_NUM(s->Connection->Tcp->TcpSockList) < s->MaxConnection)\r
453                                 {\r
454                                         if ((s->LastTryAddConnectTime +\r
455                                                 (UINT64)(s->ClientOption->AdditionalConnectionInterval * 1000 * 2 + CONNECTING_TIMEOUT * 2))\r
456                                                 <= Tick64())\r
457                                         {\r
458                                                 timeouted = true;\r
459                                         }\r
460                                 }\r
461                         }\r
462 \r
463                         if (timeouted)\r
464                         {\r
465                                 // タイムアウトが発生した\r
466                                 Debug("** Session Timeouted.\n");\r
467                                 s->SessionTimeOuted = true;\r
468                                 err = ERR_SESSION_TIMEOUT;\r
469                         }\r
470                 }\r
471 \r
472                 // タイムアウト判定\r
473                 if (pa_fail || s->SessionTimeOuted)\r
474                 {\r
475                         s->Halt = true;\r
476                         s->RetryFlag = true;    // リトライフラグ\r
477                         break;\r
478                 }\r
479         }\r
480 \r
481 CLEANUP:\r
482         Debug("Session %s Finishing...\n", s->Name);\r
483 \r
484         // HUB のセッション一覧から削除する\r
485         if (s->ServerMode)\r
486         {\r
487                 // ユーザー情報を更新する\r
488                 IncrementUserTraffic(s->Hub, s->UserNameReal, s);\r
489 \r
490                 DelSession(s->Hub, s);\r
491         }\r
492 \r
493         s->ConnectSucceed = false;\r
494         Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);\r
495 \r
496         if (s->Connection)\r
497         {\r
498                 s->Connection->Halt = true;\r
499         }\r
500 \r
501         // パケットアダプタの解放\r
502         if (pa_inited)\r
503         {\r
504                 pa->Free(s);\r
505         }\r
506 \r
507         if (s->ServerMode == false)\r
508         {\r
509                 // すべての追加コネクションの作成をキャンセルする\r
510                 StopAllAdditionalConnectThread(s->Connection);\r
511         }\r
512 \r
513         if (s->BridgeMode)\r
514         {\r
515                 // ブリッジの終了\r
516                 if (s->Bridge->Active)\r
517                 {\r
518                         CloseEth(s->Bridge->Eth);\r
519                         s->Bridge->Eth = NULL;\r
520                 }\r
521         }\r
522 \r
523         if (s->Cancel2 != NULL)\r
524         {\r
525                 // キャンセル2 の解放\r
526                 ReleaseCancel(s->Cancel2);\r
527                 s->Cancel2 = NULL;\r
528         }\r
529 \r
530         // コネクションの終了\r
531         EndTunnelingMode(c);\r
532 \r
533         if (nicinfo_sock != NULL)\r
534         {\r
535                 CncNicInfoFree(nicinfo_sock);\r
536         }\r
537 \r
538         if (msgdlg_sock != NULL)\r
539         {\r
540                 CndMsgDlgFree(msgdlg_sock);\r
541         }\r
542 \r
543         c->Err = err;\r
544 }\r
545 \r
546 // 次の遅延パケットまでの時間を取得する\r
547 UINT GetNextDelayedPacketTickDiff(SESSION *s)\r
548 {\r
549         UINT i;\r
550         UINT ret = 0x7fffffff;\r
551         UINT64 now;\r
552         // 引数チェック\r
553         if (s == NULL)\r
554         {\r
555                 return 0;\r
556         }\r
557 \r
558         if (LIST_NUM(s->DelayedPacketList) >= 1)\r
559         {\r
560                 now = TickHighres64();\r
561 \r
562                 LockList(s->DelayedPacketList);\r
563                 {\r
564                         for (i = 0;i < LIST_NUM(s->DelayedPacketList);i++)\r
565                         {\r
566                                 PKT *p = LIST_DATA(s->DelayedPacketList, i);\r
567                                 UINT64 t = p->DelayedForwardTick;\r
568                                 UINT d = 0x7fffffff;\r
569 \r
570                                 if (now >= t)\r
571                                 {\r
572                                         d = 0;\r
573                                 }\r
574                                 else\r
575                                 {\r
576                                         d = (UINT)(t - now);\r
577                                 }\r
578 \r
579                                 ret = MIN(ret, d);\r
580                         }\r
581                 }\r
582                 UnlockList(s->DelayedPacketList);\r
583         }\r
584 \r
585         return ret;\r
586 }\r
587 \r
588 // VoIP / QoS 機能で優先すべきパケットかどうか判定する\r
589 bool IsPriorityHighestPacketForQoS(void *data, UINT size)\r
590 {\r
591         UCHAR *buf;\r
592         // 引数チェック\r
593         if (data == NULL)\r
594         {\r
595                 return false;\r
596         }\r
597 \r
598         buf = (UCHAR *)data;\r
599         if (size >= 16)\r
600         {\r
601                 if (buf[12] == 0x08 && buf[13] == 0x00 && buf[15] != 0x00 && buf[15] != 0x08)\r
602                 {\r
603                         // IPv4 パケットかつ ToS != 0\r
604                         return true;\r
605                 }\r
606 \r
607                 if (size >= 34 && size <= 128)\r
608                 {\r
609                         if (buf[12] == 0x08 && buf[13] == 0x00 && buf[23] == 0x01)\r
610                         {\r
611                                 // IMCPv4 パケット\r
612                                 return true;\r
613                         }\r
614                 }\r
615         }\r
616 \r
617         return false;\r
618 }\r
619 \r
620 // ユーザーのトラフィック情報を更新する\r
621 void IncrementUserTraffic(HUB *hub, char *username, SESSION *s)\r
622 {\r
623         TRAFFIC report_traffic;\r
624         // 引数チェック\r
625         if (hub == NULL || username == NULL || s == NULL)\r
626         {\r
627                 return;\r
628         }\r
629 \r
630         Lock(s->TrafficLock);\r
631         {\r
632                 // 報告するトラフィック情報 (前回との差分) を計算する\r
633                 Zero(&report_traffic, sizeof(report_traffic));\r
634                 report_traffic.Send.BroadcastBytes =\r
635                         s->Traffic->Send.BroadcastBytes - s->OldTraffic->Send.BroadcastBytes;\r
636                 report_traffic.Send.BroadcastCount =\r
637                         s->Traffic->Send.BroadcastCount - s->OldTraffic->Send.BroadcastCount;\r
638                 report_traffic.Send.UnicastBytes =\r
639                         s->Traffic->Send.UnicastBytes - s->OldTraffic->Send.UnicastBytes;\r
640                 report_traffic.Send.UnicastCount =\r
641                         s->Traffic->Send.UnicastCount - s->OldTraffic->Send.UnicastCount;\r
642                 report_traffic.Recv.BroadcastBytes =\r
643                         s->Traffic->Recv.BroadcastBytes - s->OldTraffic->Recv.BroadcastBytes;\r
644                 report_traffic.Recv.BroadcastCount =\r
645                         s->Traffic->Recv.BroadcastCount - s->OldTraffic->Recv.BroadcastCount;\r
646                 report_traffic.Recv.UnicastBytes =\r
647                         s->Traffic->Recv.UnicastBytes - s->OldTraffic->Recv.UnicastBytes;\r
648                 report_traffic.Recv.UnicastCount =\r
649                         s->Traffic->Recv.UnicastCount - s->OldTraffic->Recv.UnicastCount;\r
650                 Copy(s->OldTraffic, s->Traffic, sizeof(TRAFFIC));\r
651 \r
652                 if (hub->FarmMember == false)\r
653                 {\r
654                         // ファームメンバーでない場合はローカルデータベースのユーザー情報を更新する\r
655                         AcLock(hub);\r
656                         {\r
657                                 USER *u = AcGetUser(hub, username);\r
658                                 if (u != NULL)\r
659                                 {\r
660                                         Lock(u->lock);\r
661                                         {\r
662                                                 AddTraffic(u->Traffic, &report_traffic);\r
663                                         }\r
664                                         Unlock(u->lock);\r
665                                         if (u->Group != NULL)\r
666                                         {\r
667                                                 Lock(u->Group->lock);\r
668                                                 {\r
669                                                         AddTraffic(u->Group->Traffic, &report_traffic);\r
670                                                 }\r
671                                                 Unlock(u->Group->lock);\r
672                                         }\r
673                                         ReleaseUser(u);\r
674                                 }\r
675                         }\r
676                         AcUnlock(hub);\r
677                 }\r
678                 else\r
679                 {\r
680                         // ファームメンバの場合はトラフィック差分報告リストを更新する\r
681                         AddTrafficDiff(hub, username, TRAFFIC_DIFF_USER, &report_traffic);\r
682                 }\r
683         }\r
684         Unlock(s->TrafficLock);\r
685 }\r
686 \r
687 // コネクションのトラフィック情報を加算\r
688 void AddTrafficForSession(SESSION *s, TRAFFIC *t)\r
689 {\r
690         HUB *h;\r
691         TRAFFIC t2;\r
692         // 引数チェック\r
693         if (s == NULL || t == NULL)\r
694         {\r
695                 return;\r
696         }\r
697 \r
698         Lock(s->TrafficLock);\r
699         {\r
700                 AddTraffic(s->Traffic, t);\r
701         }\r
702         Unlock(s->TrafficLock);\r
703 \r
704         if (s->ServerMode)\r
705         {\r
706                 Zero(&t2, sizeof(t2));\r
707                 Copy(&t2.Recv, &t->Send, sizeof(TRAFFIC_ENTRY));\r
708                 Copy(&t2.Send, &t->Recv, sizeof(TRAFFIC_ENTRY));\r
709                 Lock(s->Cedar->TrafficLock);\r
710                 {\r
711                         AddTraffic(s->Cedar->Traffic, &t2);\r
712                 }\r
713                 Unlock(s->Cedar->TrafficLock);\r
714 \r
715                 h = s->Hub;\r
716                 Lock(h->TrafficLock);\r
717                 {\r
718                         AddTraffic(h->Traffic, &t2);\r
719                 }\r
720                 Unlock(h->TrafficLock);\r
721         }\r
722 }\r
723 \r
724 // クライアントの追加コネクション確立のチャンス\r
725 void ClientAdditionalConnectChance(SESSION *s)\r
726 {\r
727         // 引数チェック\r
728         if (s == NULL)\r
729         {\r
730                 return;\r
731         }\r
732 \r
733         if (s->ServerMode)\r
734         {\r
735                 // サーバーモードの場合は追加接続しない\r
736                 return;\r
737         }\r
738         if (s->Connection->Protocol != CONNECTION_TCP)\r
739         {\r
740                 // TCP プロトコル以外の場合は追加接続しない\r
741                 return;\r
742         }\r
743 \r
744         while (true)\r
745         {\r
746                 if (s->Halt)\r
747                 {\r
748                         return;\r
749                 }\r
750                 // 追加コネクションを張る必要があるかどうかを\r
751                 // 現在張っている または 張ろうとしているコネクション数と\r
752                 // MaxConnection プロパティを見て検討する。\r
753                 if (Count(s->Connection->CurrentNumConnection) < s->MaxConnection)\r
754                 {\r
755                         // 現在時刻を取得\r
756                         UINT64 now = Tick64();\r
757 \r
758                         // NextConnectionTime を調べてその時刻を過ぎていればコネクションを\r
759                         // 張ろうとする\r
760                         if (s->NextConnectionTime == 0 ||\r
761                                 s->ClientOption->AdditionalConnectionInterval == 0 ||\r
762                                 (s->NextConnectionTime <= now))\r
763                         {\r
764                                 // 追加コネクションを張る作業を開始する\r
765                                 s->NextConnectionTime = now + (UINT64)(s->ClientOption->AdditionalConnectionInterval * 1000);\r
766                                 SessionAdditionalConnect(s);\r
767                         }\r
768                         else\r
769                         {\r
770                                 break;\r
771                         }\r
772                 }\r
773                 else\r
774                 {\r
775                         break;\r
776                 }\r
777         }\r
778 }\r
779 \r
780 // パケットアダプタの解放\r
781 void FreePacketAdapter(PACKET_ADAPTER *pa)\r
782 {\r
783         // 引数チェック\r
784         if (pa == NULL)\r
785         {\r
786                 return;\r
787         }\r
788 \r
789         Free(pa);\r
790 }\r
791 \r
792 // 新しいパケットアダプタの作成\r
793 PACKET_ADAPTER *NewPacketAdapter(PA_INIT *init, PA_GETCANCEL *getcancel, PA_GETNEXTPACKET *getnext,\r
794                                                                  PA_PUTPACKET *put, PA_FREE *free)\r
795 {\r
796         PACKET_ADAPTER *pa;\r
797         // 引数チェック\r
798         if (init == NULL || getcancel == NULL || getnext == NULL || put == NULL || free == NULL)\r
799         {\r
800                 return NULL;\r
801         }\r
802 \r
803         pa = ZeroMalloc(sizeof(PACKET_ADAPTER));\r
804 \r
805         pa->Init = init;\r
806         pa->Free = free;\r
807         pa->GetCancel = getcancel;\r
808         pa->GetNextPacket = getnext;\r
809         pa->PutPacket = put;\r
810 \r
811         return pa;\r
812 }\r
813 \r
814 // 追加コネクションを張るためのスレッド\r
815 void ClientAdditionalThread(THREAD *t, void *param)\r
816 {\r
817         SESSION *s;\r
818         CONNECTION *c;\r
819         // 引数チェック\r
820         if (t == NULL || param == NULL)\r
821         {\r
822                 return;\r
823         }\r
824 \r
825         s = (SESSION *)param;\r
826 \r
827         // s->LastTryAddConnectTime = Tick64();\r
828 \r
829         c = s->Connection;\r
830         // 接続中カウンタのインクリメント\r
831         Inc(c->CurrentNumConnection);\r
832         LockList(c->ConnectingThreads);\r
833         {\r
834                 // 処理中スレッドに追加\r
835                 Add(c->ConnectingThreads, t);\r
836                 AddRef(t->ref);\r
837         }\r
838         UnlockList(c->ConnectingThreads);\r
839 \r
840         // 初期化の完了を通知\r
841         NoticeThreadInit(t);\r
842 \r
843         Debug("Additional Connection #%u\n", Count(c->CurrentNumConnection));\r
844 \r
845         // 追加コネクションを張る\r
846         if (ClientAdditionalConnect(c, t) == false)\r
847         {\r
848                 // 現在処理中のカウンタをデクリメントする\r
849                 Dec(c->CurrentNumConnection);\r
850         }\r
851         else\r
852         {\r
853                 s->LastTryAddConnectTime = Tick64();\r
854         }\r
855 \r
856         // 処理中スレッドから削除\r
857         LockList(c->ConnectingThreads);\r
858         {\r
859                 // 処理中スレッドから削除\r
860                 if (Delete(c->ConnectingThreads, t))\r
861                 {\r
862                         ReleaseThread(t);\r
863                 }\r
864         }\r
865         UnlockList(c->ConnectingThreads);\r
866         ReleaseSession(s);\r
867 }\r
868 \r
869 // クライアントからサーバーに追加コネクションを張る\r
870 void SessionAdditionalConnect(SESSION *s)\r
871 {\r
872         THREAD *t;\r
873         // 引数チェック\r
874         if (s == NULL)\r
875         {\r
876                 return;\r
877         }\r
878 \r
879         // s->LastTryAddConnectTime = Tick64();\r
880 \r
881         AddRef(s->ref);\r
882         t = NewThread(ClientAdditionalThread, (void *)s);\r
883         WaitThreadInit(t);\r
884         ReleaseThread(t);\r
885 }\r
886 \r
887 // クライアントセッションをサーバーに接続する\r
888 bool SessionConnect(SESSION *s)\r
889 {\r
890         CONNECTION *c;\r
891         bool ret = false;\r
892         // 引数チェック\r
893         if (s == NULL)\r
894         {\r
895                 return false;\r
896         }\r
897 \r
898         s->ClientStatus = CLIENT_STATUS_CONNECTING;\r
899 \r
900         Debug("SessionConnect() Started.\n");\r
901 \r
902         // セッションの初期化\r
903         Lock(s->lock);\r
904         {\r
905                 s->Err = ERR_NO_ERROR;\r
906                 if (s->Policy != NULL)\r
907                 {\r
908                         Free(s->Policy);\r
909                         s->Policy = NULL;\r
910                 }\r
911         }\r
912         Unlock(s->lock);\r
913 \r
914         s->CancelConnect = false;\r
915 \r
916         // クライアントコネクションの作成\r
917         c = NewClientConnection(s);\r
918         s->Connection = c;\r
919 \r
920         // クライアントをサーバーに接続する\r
921         ret = ClientConnect(c);\r
922         s->Err = c->Err;\r
923 \r
924         s->CancelConnect = false;\r
925 \r
926         if (s->Cedar->Client != NULL)\r
927         {\r
928                 if (s->Policy != NULL)\r
929                 {\r
930                         if (s->Policy->NoSavePassword)\r
931                         {\r
932                                 s->Client_NoSavePassword = true;\r
933 \r
934                                 if (s->Account != NULL)\r
935                                 {\r
936                                         Lock(s->Account->lock);\r
937                                         {\r
938                                                 if (s->Account->ClientAuth != NULL)\r
939                                                 {\r
940                                                         if (s->Account->ClientAuth->AuthType == AUTHTYPE_PASSWORD ||\r
941                                                                 s->Account->ClientAuth->AuthType == AUTHTYPE_RADIUS)\r
942                                                         {\r
943                                                                 Zero(s->Account->ClientAuth->HashedPassword, sizeof(s->Account->ClientAuth->HashedPassword));\r
944                                                                 Zero(s->Account->ClientAuth->PlainPassword, sizeof(s->Account->ClientAuth->PlainPassword));\r
945                                                         }\r
946                                                 }\r
947                                         }\r
948                                         Unlock(s->Account->lock);\r
949 \r
950                                         CiSaveConfigurationFile(s->Cedar->Client);\r
951                                 }\r
952                         }\r
953                 }\r
954         }\r
955 \r
956         if (c->ClientConnectError_NoSavePassword)\r
957         {\r
958                 s->Client_NoSavePassword = true;\r
959         }\r
960 \r
961         // クライアントコネクションの解放\r
962         s->Connection = NULL;\r
963         ReleaseConnection(c);\r
964 \r
965         Lock(s->lock);\r
966         {\r
967                 if (s->Policy != NULL)\r
968                 {\r
969                         Free(s->Policy);\r
970                         s->Policy = NULL;\r
971                 }\r
972         }\r
973         Unlock(s->lock);\r
974 \r
975         return ret;\r
976 }\r
977 \r
978 // セッションの停止\r
979 void StopSession(SESSION *s)\r
980 {\r
981         StopSessionEx(s, false);\r
982 }\r
983 void StopSessionEx(SESSION *s, bool no_wait)\r
984 {\r
985         // 引数チェック\r
986         if (s == NULL)\r
987         {\r
988                 return;\r
989         }\r
990 \r
991         // 停止フラグ\r
992         s->UserCanceled = true;\r
993         s->CancelConnect = true;\r
994         s->Halt = true;\r
995 \r
996         Debug("Stop Session %s\n", s->Name);\r
997 \r
998         // キャンセル\r
999         Cancel(s->Cancel1);\r
1000 \r
1001         // イベント\r
1002         Set(s->HaltEvent);\r
1003 \r
1004         if (s->ServerMode == false)\r
1005         {\r
1006                 // クライアントモード\r
1007                 if (s->Connection)\r
1008                 {\r
1009                         StopConnection(s->Connection, no_wait);\r
1010                 }\r
1011         }\r
1012         else\r
1013         {\r
1014                 // サーバーモード\r
1015                 if (s->Connection)\r
1016                 {\r
1017                         StopConnection(s->Connection, no_wait);\r
1018                 }\r
1019         }\r
1020 \r
1021         // 停止まで待機\r
1022         if (no_wait == false)\r
1023         {\r
1024                 while (true)\r
1025                 {\r
1026                         s->ForceStopFlag = true;\r
1027                         s->Halt = true;\r
1028                         if (WaitThread(s->Thread, 20))\r
1029                         {\r
1030                                 break;\r
1031                         }\r
1032                 }\r
1033         }\r
1034         else\r
1035         {\r
1036                 s->ForceStopFlag = true;\r
1037                 s->Halt = true;\r
1038         }\r
1039 }\r
1040 \r
1041 // セッションのクリーンアップ\r
1042 void CleanupSession(SESSION *s)\r
1043 {\r
1044         // 引数チェック\r
1045         if (s == NULL)\r
1046         {\r
1047                 return;\r
1048         }\r
1049 \r
1050         // 遅延パケットリストの解放\r
1051         if (s->DelayedPacketList != NULL)\r
1052         {\r
1053                 UINT i;\r
1054                 for (i = 0;i < LIST_NUM(s->DelayedPacketList);i++)\r
1055                 {\r
1056                         PKT *p = LIST_DATA(s->DelayedPacketList, i);\r
1057 \r
1058                         Free(p->PacketData);\r
1059                         FreePacket(p);\r
1060                 }\r
1061 \r
1062                 ReleaseList(s->DelayedPacketList);\r
1063         }\r
1064 \r
1065         // クライアント接続オプションの解放\r
1066         if (s->ClientOption != NULL)\r
1067         {\r
1068                 Free(s->ClientOption);\r
1069         }\r
1070 \r
1071         // クライアント認証データの解放\r
1072         if (s->ClientAuth != NULL)\r
1073         {\r
1074                 if (s->ClientAuth->ClientX != NULL)\r
1075                 {\r
1076                         FreeX(s->ClientAuth->ClientX);\r
1077                 }\r
1078                 if (s->ClientAuth->ClientX != NULL)\r
1079                 {\r
1080                         FreeK(s->ClientAuth->ClientK);\r
1081                 }\r
1082                 Free(s->ClientAuth);\r
1083         }\r
1084 \r
1085         FreeTraffic(s->Traffic);\r
1086         Free(s->Name);\r
1087 \r
1088         if (s->Thread != NULL)\r
1089         {\r
1090                 ReleaseThread(s->Thread);\r
1091         }\r
1092 \r
1093         DeleteLock(s->lock);\r
1094 \r
1095         ReleaseEvent(s->HaltEvent);\r
1096 \r
1097         if (s->Cancel1)\r
1098         {\r
1099                 ReleaseCancel(s->Cancel1);\r
1100         }\r
1101 \r
1102         if (s->Cancel2)\r
1103         {\r
1104                 ReleaseCancel(s->Cancel2);\r
1105         }\r
1106 \r
1107         if (s->Policy)\r
1108         {\r
1109                 Free(s->Policy);\r
1110         }\r
1111 \r
1112         if (s->Connection)\r
1113         {\r
1114                 ReleaseConnection(s->Connection);\r
1115         }\r
1116 \r
1117         Free(s->Username);\r
1118 \r
1119         if (s->PacketAdapter)\r
1120         {\r
1121                 FreePacketAdapter(s->PacketAdapter);\r
1122         }\r
1123 \r
1124         if (s->OldTraffic != NULL)\r
1125         {\r
1126                 FreeTraffic(s->OldTraffic);\r
1127         }\r
1128 \r
1129         DeleteLock(s->TrafficLock);\r
1130 \r
1131         if (s->CancelList != NULL)\r
1132         {\r
1133                 ReleaseCancelList(s->CancelList);\r
1134         }\r
1135 \r
1136         if (s->Client_Message != NULL)\r
1137         {\r
1138                 Free(s->Client_Message);\r
1139         }\r
1140 \r
1141         DeleteCounter(s->LoggingRecordCount);\r
1142 \r
1143         Free(s);\r
1144 }\r
1145 \r
1146 // セッションの解放\r
1147 void ReleaseSession(SESSION *s)\r
1148 {\r
1149         // 引数チェック\r
1150         if (s == NULL)\r
1151         {\r
1152                 return;\r
1153         }\r
1154 \r
1155         if (Release(s->ref) == 0)\r
1156         {\r
1157                 CleanupSession(s);\r
1158         }\r
1159 }\r
1160 \r
1161 // セッションの転送データサイズ合計を表示する\r
1162 void PrintSessionTotalDataSize(SESSION *s)\r
1163 {\r
1164         // 引数チェック\r
1165         if (s == NULL)\r
1166         {\r
1167                 return;\r
1168         }\r
1169 \r
1170         Debug(\r
1171                 "-- SESSION TOTAL PKT INFORMATION --\n\n"\r
1172                 "      TotalSendSize: %I64u\n"\r
1173                 "  TotalSendSizeReal: %I64u\n"\r
1174                 "      TotalRecvSize: %I64u\n"\r
1175                 "  TotalRecvSizeReal: %I64u\n"\r
1176                 "   Compression Rate: %.2f%% (Send)\n"\r
1177                 "                     %.2f%% (Recv)\n",\r
1178                 s->TotalSendSize, s->TotalSendSizeReal,\r
1179                 s->TotalRecvSize, s->TotalRecvSizeReal,\r
1180                 (float)((double)s->TotalSendSizeReal / (double)s->TotalSendSize * 100.0f),\r
1181                 (float)((double)s->TotalRecvSizeReal / (double)s->TotalRecvSize * 100.0f)\r
1182                 );\r
1183 \r
1184 }\r
1185 \r
1186 // クライアントスレッド\r
1187 void ClientThread(THREAD *t, void *param)\r
1188 {\r
1189         SESSION *s;\r
1190         bool use_password_dlg;\r
1191         bool no_save_password = false;\r
1192         // 引数チェック\r
1193         if (t == NULL || param == NULL)\r
1194         {\r
1195                 return;\r
1196         }\r
1197 \r
1198         Debug("ClientThread 0x%x Started.\n", t);\r
1199 \r
1200         s = (SESSION *)param;\r
1201         AddRef(s->ref);\r
1202         s->Thread = t;\r
1203         AddRef(t->ref);\r
1204         NoticeThreadInit(t);\r
1205 \r
1206         s->ClientStatus = CLIENT_STATUS_CONNECTING;\r
1207         s->RetryFlag = true;\r
1208         s->CurrentRetryCount = 0;\r
1209 \r
1210         Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);\r
1211 \r
1212         if (s->Cedar->Client != NULL)\r
1213         {\r
1214                 no_save_password = s->Cedar->Client->DontSavePassword;\r
1215         }\r
1216 \r
1217         s->Win32HideConnectWindow = s->ClientOption->HideStatusWindow;\r
1218         s->Win32HideNicInfoWindow = s->ClientOption->HideNicInfoWindow;\r
1219 \r
1220         while (true)\r
1221         {\r
1222                 CLog(s->Cedar->Client, "LC_CONNECT_1", s->ClientOption->AccountName, s->CurrentRetryCount + 1);\r
1223                 if (s->LinkModeClient && s->Link != NULL)\r
1224                 {\r
1225                         HLog(s->Link->Hub, "LH_CONNECT_1", s->ClientOption->AccountName, s->CurrentRetryCount + 1);\r
1226                 }\r
1227 \r
1228                 Debug("Trying to Connect to Server... (%u / %u)\n", s->CurrentRetryCount + 0,\r
1229                         s->ClientOption->NumRetry);\r
1230 \r
1231                 // 初期化\r
1232 //              s->TotalRecvSize = s->TotalRecvSizeReal = \r
1233 //                      s->TotalSendSize = s->TotalSendSizeReal = 0;\r
1234                 s->NextConnectionTime = 0;\r
1235 \r
1236                 // 接続を行う\r
1237                 s->ClientStatus = CLIENT_STATUS_CONNECTING;\r
1238                 s->Halt = false;\r
1239                 SessionConnect(s);\r
1240                 if (s->UserCanceled)\r
1241                 {\r
1242                         s->Err = ERR_USER_CANCEL;\r
1243                 }\r
1244                 Debug("Disconnected. Err = %u : %S\n", s->Err, _E(s->Err));\r
1245 \r
1246                 PrintSessionTotalDataSize(s);\r
1247 \r
1248                 CLog(s->Cedar->Client, "LC_CONNECT_ERROR", s->ClientOption->AccountName,\r
1249                         GetUniErrorStr(s->Err), s->Err);\r
1250 \r
1251                 if (s->LinkModeClient && s->Link != NULL)\r
1252                 {\r
1253                         HLog(s->Link->Hub, "LH_CONNECT_ERROR", s->ClientOption->AccountName,\r
1254                                 GetUniErrorStr(s->Err), s->Err);\r
1255                 }\r
1256 \r
1257                 s->ClientStatus = CLIENT_STATUS_RETRY;\r
1258 \r
1259                 if (s->Link != NULL)\r
1260                 {\r
1261                         ((LINK *)s->Link)->LastError = s->Err;\r
1262                 }\r
1263 \r
1264                 if (s->Halt && (s->RetryFlag == false) || s->ForceStopFlag)\r
1265                 {\r
1266                         // 中断しなければならない\r
1267                         if (s->Err == ERR_DEVICE_DRIVER_ERROR)\r
1268                         {\r
1269 #ifdef  OS_WIN32\r
1270                                 wchar_t tmp[MAX_SIZE];\r
1271                                 if (s->Account != NULL && s->Cedar->Client != NULL)\r
1272                                 {\r
1273                                         UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_DEVICE_ERROR"), s->ClientOption->DeviceName,\r
1274                                                 s->Err, _E(s->Err));\r
1275                                         MsgBox(NULL, 0x10000 | 0x40000 | 0x200000 | 0x30, tmp);\r
1276                                 }\r
1277 #endif  // OS_WIN32\r
1278                         }\r
1279                         break;\r
1280                 }\r
1281                 // パスワード再入力ダイアログを表示するかどうか判断する\r
1282                 use_password_dlg = false;\r
1283 \r
1284                 if (s->Account != NULL && s->Cedar->Client != NULL)\r
1285                 {\r
1286 #ifdef  OS_WIN32\r
1287                         if (s->ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD || s->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD)\r
1288                         {\r
1289                                 if (s->Err == ERR_AUTH_FAILED || s->Err == ERR_PROXY_AUTH_FAILED)\r
1290                                 {\r
1291                                         use_password_dlg = true;\r
1292                                 }\r
1293                         }\r
1294 #endif  // OS_WIN32\r
1295                 }\r
1296 \r
1297                 // 接続に失敗した または接続が切断された\r
1298                 // リトライ間隔の間待機する\r
1299 \r
1300                 if (use_password_dlg == false)\r
1301                 {\r
1302                         UINT retry_interval = s->RetryInterval;\r
1303 \r
1304                         if (s->Err == ERR_HUB_IS_BUSY || s->Err == ERR_LICENSE_ERROR ||\r
1305                                 s->Err == ERR_HUB_STOPPING || s->Err == ERR_TOO_MANY_USER_SESSION)\r
1306                         {\r
1307                                 retry_interval = RETRY_INTERVAL_SPECIAL;\r
1308                         }\r
1309 \r
1310                         if (s->CurrentRetryCount >= s->ClientOption->NumRetry)\r
1311                         {\r
1312                                 // リトライ回数超過\r
1313 \r
1314 #ifndef OS_WIN32\r
1315 \r
1316                                 break;\r
1317 \r
1318 #else   // OS_WIN32\r
1319 \r
1320                                 if (s->Win32HideConnectWindow == false &&\r
1321                                         s->Cedar->Client != NULL && s->Account != NULL)\r
1322                                 {\r
1323                                         // 再接続ダイアログを出す\r
1324                                         UI_CONNECTERROR_DLG p;\r
1325                                         Zero(&p, sizeof(p));\r
1326                                         UniStrCpy(p.AccountName, sizeof(p.AccountName), s->ClientOption->AccountName);\r
1327                                         StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->Hostname);\r
1328                                         p.Err = s->Err;\r
1329                                         p.CurrentRetryCount = s->CurrentRetryCount + 1;\r
1330                                         s->Halt = false;\r
1331                                         p.RetryLimit = 0;\r
1332                                         p.RetryIntervalSec = 0;\r
1333                                         p.CancelEvent = s->HaltEvent;\r
1334                                         p.HideWindow = s->Win32HideConnectWindow;\r
1335                                         if (CncConnectErrorDlg(s, &p) == false)\r
1336                                         {\r
1337                                                 // 中断\r
1338                                                 break;\r
1339                                         }\r
1340                                         else\r
1341                                         {\r
1342                                                 s->Win32HideConnectWindow = p.HideWindow;\r
1343                                                 goto SKIP;\r
1344                                         }\r
1345                                 }\r
1346                                 else\r
1347                                 {\r
1348                                         break;\r
1349                                 }\r
1350 \r
1351 #endif\r
1352                         }\r
1353 \r
1354 #ifndef OS_WIN32\r
1355 \r
1356                         // 単純な待機\r
1357                         Wait(s->HaltEvent, retry_interval);\r
1358 \r
1359 #else   // OS_WIN32\r
1360 \r
1361                         if (s->Win32HideConnectWindow == false &&\r
1362                                 s->Cedar->Client != NULL && s->Account != NULL)\r
1363                         {\r
1364                                 // 再接続ダイアログを出す\r
1365                                 UI_CONNECTERROR_DLG p;\r
1366                                 Zero(&p, sizeof(p));\r
1367                                 UniStrCpy(p.AccountName, sizeof(p.AccountName), s->ClientOption->AccountName);\r
1368                                 StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->Hostname);\r
1369                                 p.Err = s->Err;\r
1370                                 p.CurrentRetryCount = s->CurrentRetryCount + 1;\r
1371                                 p.RetryLimit = s->ClientOption->NumRetry;\r
1372                                 p.RetryIntervalSec = retry_interval;\r
1373                                 p.CancelEvent = s->HaltEvent;\r
1374                                 s->Halt = false;\r
1375                                 p.HideWindow = s->Win32HideConnectWindow;\r
1376                                 if (CncConnectErrorDlg(s, &p) == false)\r
1377                                 {\r
1378                                         // 中断\r
1379                                         break;\r
1380                                 }\r
1381                                 s->Win32HideConnectWindow = p.HideWindow;\r
1382                         }\r
1383                         else\r
1384                         {\r
1385                                 // 単純な待機\r
1386                                 Wait(s->HaltEvent, s->RetryInterval);\r
1387                         }\r
1388 \r
1389 #endif  // OS_WIN32\r
1390                 }\r
1391                 else\r
1392                 {\r
1393 #ifdef  OS_WIN32\r
1394                         // パスワードの再入力を求めて待機\r
1395                         UI_PASSWORD_DLG p;\r
1396                         Zero(&p, sizeof(p));\r
1397                         if (s->Client_NoSavePassword == false)\r
1398                         {\r
1399                                 p.ShowNoSavePassword = true;\r
1400                         }\r
1401                         p.NoSavePassword = no_save_password;\r
1402                         p.CancelEvent = s->HaltEvent;\r
1403                         if (s->Err == ERR_PROXY_AUTH_FAILED)\r
1404                         {\r
1405                                 p.ProxyServer = true;\r
1406                         }\r
1407 \r
1408                         if (p.ProxyServer)\r
1409                         {\r
1410                                 StrCpy(p.Username, sizeof(p.Username), s->ClientOption->ProxyUsername);\r
1411                                 StrCpy(p.Password, sizeof(p.Password), s->ClientOption->ProxyPassword);\r
1412                                 StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->ProxyName);\r
1413                         }\r
1414                         else\r
1415                         {\r
1416                                 bool empty = false;\r
1417 \r
1418                                 StrCpy(p.Username, sizeof(p.Username), s->ClientAuth->Username);\r
1419                                 if (s->ClientAuth->AuthType == AUTHTYPE_RADIUS)\r
1420                                 {\r
1421                                         if (StrLen(s->ClientAuth->PlainPassword) == 0)\r
1422                                         {\r
1423                                                 empty = true;\r
1424                                         }\r
1425                                 }\r
1426                                 else if (s->ClientAuth->AuthType == AUTHTYPE_PASSWORD)\r
1427                                 {\r
1428                                         if (IsZero(s->ClientAuth->HashedPassword, sizeof(s->ClientAuth->HashedPassword)))\r
1429                                         {\r
1430                                                 empty = true;\r
1431                                         }\r
1432                                 }\r
1433 \r
1434                                 StrCpy(p.Password, sizeof(p.Password), empty ? "" : HIDDEN_PASSWORD);\r
1435                                 StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->Hostname);\r
1436                         }\r
1437 \r
1438                         p.RetryIntervalSec = s->RetryInterval / 1000;\r
1439                         p.Type = s->ClientAuth->AuthType;\r
1440 \r
1441                         // パスワード再入力ダイアログを表示する\r
1442                         if (CncPasswordDlg(s, &p) == false)\r
1443                         {\r
1444                                 // 接続を中断する\r
1445                                 break;\r
1446                         }\r
1447                         else\r
1448                         {\r
1449                                 // ユーザー名を上書きする\r
1450                                 if (p.ProxyServer)\r
1451                                 {\r
1452                                         // プロキシのユーザー名\r
1453                                         StrCpy(s->ClientOption->ProxyUsername, sizeof(s->ClientOption->ProxyUsername), p.Username);\r
1454                                 }\r
1455                                 else\r
1456                                 {\r
1457                                         // Server への接続のためのユーザー名\r
1458                                         StrCpy(s->ClientAuth->Username, sizeof(s->ClientAuth->Username), p.Username);\r
1459                                         s->ClientAuth->AuthType = p.Type;\r
1460                                 }\r
1461 \r
1462                                 if (StrCmp(p.Password, HIDDEN_PASSWORD) != 0)\r
1463                                 {\r
1464                                         // パスワードを再入力した\r
1465                                         if (p.ProxyServer)\r
1466                                         {\r
1467                                                 // プロキシサーバーのパスワード\r
1468                                                 StrCpy(s->ClientOption->ProxyPassword, sizeof(s->ClientOption->ProxyPassword), p.Password);\r
1469                                         }\r
1470                                         else\r
1471                                         {\r
1472                                                 if (s->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD)\r
1473                                                 {\r
1474                                                         // 平文パスワード認証\r
1475                                                         StrCpy(s->ClientAuth->PlainPassword, sizeof(s->ClientAuth->PlainPassword), p.Password);\r
1476                                                 }\r
1477                                                 else\r
1478                                                 {\r
1479                                                         // 暗号化パスワード認証\r
1480                                                         HashPassword(s->ClientAuth->HashedPassword, s->ClientAuth->Username, p.Password);\r
1481                                                 }\r
1482                                         }\r
1483                                 }\r
1484 \r
1485                                 no_save_password = p.NoSavePassword;\r
1486 \r
1487                                 if (s->Account != NULL && s->Cedar->Client != NULL)\r
1488                                 {\r
1489                                         s->Cedar->Client->DontSavePassword = no_save_password;\r
1490                                         if (p.NoSavePassword == false)\r
1491                                         {\r
1492                                                 // クライアントのアカウントデータベースを更新する\r
1493                                                 if (p.ProxyServer == false)\r
1494                                                 {\r
1495                                                         // Server 接続情報の更新\r
1496                                                         ACCOUNT *a = s->Account;\r
1497                                                         Lock(a->lock);\r
1498                                                         {\r
1499                                                                 CiFreeClientAuth(a->ClientAuth);\r
1500                                                                 a->ClientAuth = CopyClientAuth(s->ClientAuth);\r
1501                                                         }\r
1502                                                         Unlock(a->lock);\r
1503                                                         CiSaveConfigurationFile(s->Cedar->Client);\r
1504                                                 }\r
1505                                                 else\r
1506                                                 {\r
1507                                                         // Proxy 接続情報の更新\r
1508                                                         ACCOUNT *a = s->Account;\r
1509                                                         Lock(a->lock);\r
1510                                                         {\r
1511                                                                 Copy(a->ClientOption, s->ClientOption, sizeof(CLIENT_OPTION));\r
1512                                                         }\r
1513                                                         Unlock(a->lock);\r
1514                                                         CiSaveConfigurationFile(s->Cedar->Client);\r
1515                                                 }\r
1516                                         }\r
1517                                 }\r
1518                         }\r
1519 #endif  // OS_WIN32\r
1520                 }\r
1521 \r
1522 SKIP:\r
1523                 // リトライ回数増加\r
1524                 if (s->ConnectSucceed == false)\r
1525                 {\r
1526                         s->CurrentRetryCount++;\r
1527                 }\r
1528 \r
1529                 if (s->ForceStopFlag)\r
1530                 {\r
1531                         break;\r
1532                 }\r
1533         }\r
1534 \r
1535         Debug("Session Halt.\n");\r
1536 \r
1537         s->ClientStatus = CLIENT_STATUS_IDLE;\r
1538 \r
1539         // ここでセッションは終了したとみなす\r
1540         if (s->Account != NULL)\r
1541         {\r
1542                 s->Account->ClientSession = NULL;\r
1543                 ReleaseSession(s);\r
1544         }\r
1545 \r
1546         Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);\r
1547 \r
1548         ReleaseSession(s);\r
1549 }\r
1550 \r
1551 // セッションの名前比較\r
1552 int CompareSession(void *p1, void *p2)\r
1553 {\r
1554         SESSION *s1, *s2;\r
1555         if (p1 == NULL || p2 == NULL)\r
1556         {\r
1557                 return 0;\r
1558         }\r
1559         s1 = *(SESSION **)p1;\r
1560         s2 = *(SESSION **)p2;\r
1561         if (s1 == NULL || s2 == NULL)\r
1562         {\r
1563                 return 0;\r
1564         }\r
1565         return StrCmpi(s1->Name, s2->Name);\r
1566 }\r
1567 \r
1568 // RPC セッションの作成\r
1569 SESSION *NewRpcSession(CEDAR *cedar, CLIENT_OPTION *option)\r
1570 {\r
1571         return NewRpcSessionEx(cedar, option, NULL, NULL);\r
1572 }\r
1573 SESSION *NewRpcSessionEx(CEDAR *cedar, CLIENT_OPTION *option, UINT *err, char *client_str)\r
1574 {\r
1575         return NewRpcSessionEx2(cedar, option, err, client_str, NULL);\r
1576 }\r
1577 SESSION *NewRpcSessionEx2(CEDAR *cedar, CLIENT_OPTION *option, UINT *err, char *client_str, void *hWnd)\r
1578 {\r
1579         SESSION *s;\r
1580         CONNECTION *c;\r
1581         SOCK *sock;\r
1582         // 引数チェック\r
1583         if (cedar == NULL || option == NULL)\r
1584         {\r
1585                 return NULL;\r
1586         }\r
1587 \r
1588         s = ZeroMalloc(sizeof(SESSION));\r
1589 \r
1590         s->LoggingRecordCount = NewCounter();\r
1591         s->lock = NewLock();\r
1592         s->ref = NewRef();\r
1593         s->Cedar = cedar;\r
1594         s->ServerMode = false;\r
1595         s->Name = CopyStr("CLIENT_RPC_SESSION");\r
1596         s->CreatedTime = s->LastCommTime = Tick64();\r
1597         s->Traffic = NewTraffic();\r
1598         s->HaltEvent = NewEvent();\r
1599         s->TrafficLock = NewLock();\r
1600         s->Cancel1 = NewCancel();\r
1601 \r
1602         // クライアント接続オプションのコピー\r
1603         s->ClientOption = Malloc(sizeof(CLIENT_OPTION));\r
1604         Copy(s->ClientOption, option, sizeof(CLIENT_OPTION));\r
1605 \r
1606         s->MaxConnection = option->MaxConnection;\r
1607         s->UseEncrypt = option->UseEncrypt;\r
1608         s->UseCompress = option->UseCompress;\r
1609 \r
1610         // コネクションの作成\r
1611         c = s->Connection = NewClientConnectionEx(s, client_str, cedar->Version, cedar->Build);\r
1612         c->hWndForUI = hWnd;\r
1613 \r
1614         // サーバーへ接続\r
1615         sock = ClientConnectToServer(c);\r
1616         if (sock == NULL)\r
1617         {\r
1618                 // 接続失敗\r
1619                 if (err != NULL)\r
1620                 {\r
1621                         *err = c->Err;\r
1622                 }\r
1623                 ReleaseSession(s);\r
1624                 return NULL;\r
1625         }\r
1626 \r
1627         // シグネチャの送信\r
1628         if (ClientUploadSignature(sock) == false)\r
1629         {\r
1630                 // 失敗\r
1631                 if (err != NULL)\r
1632                 {\r
1633                         *err = c->Err;\r
1634                 }\r
1635                 ReleaseSession(s);\r
1636                 return NULL;\r
1637         }\r
1638 \r
1639         // Hello パケットの受信\r
1640         if (ClientDownloadHello(c, sock) == false)\r
1641         {\r
1642                 // 失敗\r
1643                 if (err != NULL)\r
1644                 {\r
1645                         *err = c->Err;\r
1646                 }\r
1647                 ReleaseSession(s);\r
1648                 return NULL;\r
1649         }\r
1650 \r
1651         return s;\r
1652 }\r
1653 \r
1654 // クライアントセッションの作成\r
1655 SESSION *NewClientSessionEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, PACKET_ADAPTER *pa, ACCOUNT *account)\r
1656 {\r
1657         SESSION *s;\r
1658         THREAD *t;\r
1659         // 引数チェック\r
1660         if (cedar == NULL || option == NULL || auth == NULL || pa == NULL ||\r
1661                 (auth->AuthType == CLIENT_AUTHTYPE_SECURE && auth->SecureSignProc == NULL))\r
1662         {\r
1663                 return NULL;\r
1664         }\r
1665 \r
1666         // SESSION オブジェクトの初期化\r
1667         s = ZeroMalloc(sizeof(SESSION));\r
1668 \r
1669         s->LoggingRecordCount = NewCounter();\r
1670 \r
1671         s->lock = NewLock();\r
1672         s->ref = NewRef();\r
1673         s->Cedar = cedar;\r
1674         s->ServerMode = false;\r
1675         s->Name = CopyStr("CLIENT_SESSION");\r
1676         s->CreatedTime = s->LastCommTime = Tick64();\r
1677         s->Traffic = NewTraffic();\r
1678         s->HaltEvent = NewEvent();\r
1679         s->PacketAdapter = pa;\r
1680         s->TrafficLock = NewLock();\r
1681         s->OldTraffic = NewTraffic();\r
1682         s->Cancel1 = NewCancel();\r
1683         s->CancelList = NewCancelList();\r
1684 \r
1685         // クライアント接続オプションのコピー\r
1686         s->ClientOption = Malloc(sizeof(CLIENT_OPTION));\r
1687         Copy(s->ClientOption, option, sizeof(CLIENT_OPTION));\r
1688 \r
1689         s->MaxConnection = option->MaxConnection;\r
1690         s->UseEncrypt = option->UseEncrypt;\r
1691         s->UseCompress = option->UseCompress;\r
1692 \r
1693         // リトライ間隔の設定\r
1694         s->RetryInterval = MAKESURE(option->RetryInterval, 0, 4000000) * 1000;\r
1695         s->RetryInterval = MAKESURE(s->RetryInterval, MIN_RETRY_INTERVAL, MAX_RETRY_INTERVAL);\r
1696 \r
1697         // 追加コネクション作成間隔は最低 1 秒\r
1698         s->ClientOption->AdditionalConnectionInterval = MAX(s->ClientOption->AdditionalConnectionInterval, 1);\r
1699 \r
1700         // クライアントモードで仮想 LAN カードを使用しているかどうか保持\r
1701         s->ClientModeAndUseVLan = (StrLen(s->ClientOption->DeviceName) == 0) ? false : true;\r
1702         if (s->ClientOption->NoRoutingTracking)\r
1703         {\r
1704                 s->ClientModeAndUseVLan = false;\r
1705         }\r
1706 \r
1707         if (StrLen(option->DeviceName) == 0)\r
1708         {\r
1709                 // NAT モード\r
1710                 s->ClientModeAndUseVLan = false;\r
1711                 s->VirtualHost = true;\r
1712         }\r
1713 \r
1714         if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))\r
1715         {\r
1716                 // Win9x の場合は半二重モードを禁止する\r
1717                 s->ClientOption->HalfConnection = false;\r
1718         }\r
1719 \r
1720         // クライアント認証データのコピー\r
1721         s->ClientAuth = Malloc(sizeof(CLIENT_AUTH));\r
1722         Copy(s->ClientAuth, auth, sizeof(CLIENT_AUTH));\r
1723 \r
1724         // 証明書と秘密鍵のクローン\r
1725         if (s->ClientAuth->ClientX != NULL)\r
1726         {\r
1727                 s->ClientAuth->ClientX = CloneX(s->ClientAuth->ClientX);\r
1728         }\r
1729         if (s->ClientAuth->ClientK != NULL)\r
1730         {\r
1731                 s->ClientAuth->ClientK = CloneK(s->ClientAuth->ClientK);\r
1732         }\r
1733 \r
1734         if (StrCmpi(s->ClientOption->DeviceName, LINK_DEVICE_NAME) == 0)\r
1735         {\r
1736                 // リンククライアントモード\r
1737                 s->LinkModeClient = true;\r
1738                 s->Link = (LINK *)s->PacketAdapter->Param;\r
1739         }\r
1740 \r
1741         if (StrCmpi(s->ClientOption->DeviceName, SNAT_DEVICE_NAME) == 0)\r
1742         {\r
1743                 // SecureNAT モード\r
1744                 s->SecureNATMode = true;\r
1745         }\r
1746 \r
1747         if (StrCmpi(s->ClientOption->DeviceName, BRIDGE_DEVICE_NAME) == 0)\r
1748         {\r
1749                 // Bridge モード\r
1750                 s->BridgeMode = true;\r
1751         }\r
1752 \r
1753         if (s->VirtualHost)\r
1754         {\r
1755                 VH *v = (VH *)s->PacketAdapter->Param;\r
1756 \r
1757                 // セッションオブジェクトを VH に追加\r
1758                 v->Session = s;\r
1759                 AddRef(s->ref);\r
1760         }\r
1761 \r
1762         s->Account = account;\r
1763 \r
1764         if (s->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)\r
1765         {\r
1766                 // スマートカード認証の場合はリトライしない\r
1767                 s->ClientOption->NumRetry = 0;\r
1768         }\r
1769 \r
1770         // クライアントスレッドの作成\r
1771         t = NewThread(ClientThread, (void *)s);\r
1772         WaitThreadInit(t);\r
1773         ReleaseThread(t);\r
1774 \r
1775         return s;\r
1776 }\r
1777 SESSION *NewClientSession(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, PACKET_ADAPTER *pa)\r
1778 {\r
1779         return NewClientSessionEx(cedar, option, auth, pa, NULL);\r
1780 }\r
1781 \r
1782 // 32bit のセッションキーからセッションを取得\r
1783 SESSION *GetSessionFromKey32(CEDAR *cedar, UINT key32)\r
1784 {\r
1785         HUB *h;\r
1786         UINT i, j;\r
1787         // 引数チェック\r
1788         if (cedar == NULL)\r
1789         {\r
1790                 return NULL;\r
1791         }\r
1792 \r
1793         LockList(cedar->HubList);\r
1794         {\r
1795                 for (i = 0;i < LIST_NUM(cedar->HubList);i++)\r
1796                 {\r
1797                         h = LIST_DATA(cedar->HubList, i);\r
1798                         LockList(h->SessionList);\r
1799                         {\r
1800                                 for (j = 0;j < LIST_NUM(h->SessionList);j++)\r
1801                                 {\r
1802                                         SESSION *s = LIST_DATA(h->SessionList, j);\r
1803                                         Lock(s->lock);\r
1804                                         {\r
1805                                                 if (s->SessionKey32 == key32)\r
1806                                                 {\r
1807                                                         // セッション発見\r
1808                                                         AddRef(s->ref);\r
1809 \r
1810                                                         // ロック解除\r
1811                                                         Unlock(s->lock);\r
1812                                                         UnlockList(h->SessionList);\r
1813                                                         UnlockList(cedar->HubList);\r
1814                                                         return s;\r
1815                                                 }\r
1816                                         }\r
1817                                         Unlock(s->lock);\r
1818                                 }\r
1819                         }\r
1820                         UnlockList(h->SessionList);\r
1821                 }\r
1822         }\r
1823         UnlockList(cedar->HubList);\r
1824 \r
1825         return NULL;\r
1826 }\r
1827 \r
1828 // セッションキーからセッションを取得\r
1829 SESSION *GetSessionFromKey(CEDAR *cedar, UCHAR *session_key)\r
1830 {\r
1831         HUB *h;\r
1832         UINT i, j;\r
1833         // 引数チェック\r
1834         if (cedar == NULL || session_key == NULL)\r
1835         {\r
1836                 return NULL;\r
1837         }\r
1838 \r
1839         LockList(cedar->HubList);\r
1840         {\r
1841                 for (i = 0;i < LIST_NUM(cedar->HubList);i++)\r
1842                 {\r
1843                         h = LIST_DATA(cedar->HubList, i);\r
1844                         LockList(h->SessionList);\r
1845                         {\r
1846                                 for (j = 0;j < LIST_NUM(h->SessionList);j++)\r
1847                                 {\r
1848                                         SESSION *s = LIST_DATA(h->SessionList, j);\r
1849                                         Lock(s->lock);\r
1850                                         {\r
1851                                                 if (Cmp(s->SessionKey, session_key, SHA1_SIZE) == 0)\r
1852                                                 {\r
1853                                                         // セッション発見\r
1854                                                         AddRef(s->ref);\r
1855 \r
1856                                                         // ロック解除\r
1857                                                         Unlock(s->lock);\r
1858                                                         UnlockList(h->SessionList);\r
1859                                                         UnlockList(cedar->HubList);\r
1860                                                         return s;\r
1861                                                 }\r
1862                                         }\r
1863                                         Unlock(s->lock);\r
1864                                 }\r
1865                         }\r
1866                         UnlockList(h->SessionList);\r
1867                 }\r
1868         }\r
1869         UnlockList(cedar->HubList);\r
1870 \r
1871         return NULL;\r
1872 }\r
1873 \r
1874 // 新しいセッションキーを作成\r
1875 void NewSessionKey(CEDAR *cedar, UCHAR *session_key, UINT *session_key_32)\r
1876 {\r
1877         // 引数チェック\r
1878         if (cedar == NULL || session_key == NULL || session_key_32 == NULL)\r
1879         {\r
1880                 return;\r
1881         }\r
1882 \r
1883         Rand(session_key, SHA1_SIZE);\r
1884         *session_key_32 = Rand32();\r
1885 }\r
1886 \r
1887 bool if_init(SESSION *s);\r
1888 CANCEL *if_getcancel(SESSION *s);\r
1889 UINT if_getnext(SESSION *s, void **data);\r
1890 bool if_putpacket(SESSION *s, void *data, UINT size);\r
1891 void if_free(SESSION *s);\r
1892 \r
1893 \r
1894 // サーバーセッションの作成\r
1895 SESSION *NewServerSession(CEDAR *cedar, CONNECTION *c, HUB *h, char *username, POLICY *policy)\r
1896 {\r
1897         SESSION *s;\r
1898         char name[MAX_SIZE];\r
1899         char hub_name_upper[MAX_SIZE];\r
1900         char user_name_upper[MAX_USERNAME_LEN + 1];\r
1901         // 引数チェック\r
1902         if (cedar == NULL || c == NULL || h == NULL || username == NULL || policy == NULL)\r
1903         {\r
1904                 return NULL;\r
1905         }\r
1906 \r
1907         // SESSION オブジェクトの初期化\r
1908         s = ZeroMalloc(sizeof(SESSION));\r
1909 \r
1910         s->LoggingRecordCount = NewCounter();\r
1911         s->lock = NewLock();\r
1912         s->ref = NewRef();\r
1913         s->Cedar = cedar;\r
1914         s->ServerMode = true;\r
1915         s->CreatedTime = s->LastCommTime = Tick64();\r
1916         s->Traffic = NewTraffic();\r
1917         s->HaltEvent = NewEvent();\r
1918         s->Cancel1 = NewCancel();\r
1919         s->CancelList = NewCancelList();\r
1920         s->Thread = c->Thread;\r
1921         s->TrafficLock = NewLock();\r
1922         s->OldTraffic = NewTraffic();\r
1923         s->QoS = GetServerCapsBool(cedar->Server, "b_support_qos");\r
1924         AddRef(s->Thread->ref);\r
1925         s->Hub = h;\r
1926         s->ClientStatus = CLIENT_STATUS_ESTABLISHED;\r
1927 \r
1928         // 遅延パケットリスト\r
1929         s->DelayedPacketList = NewList(NULL);\r
1930 \r
1931         // HUB 用のパケットアダプタ\r
1932         s->PacketAdapter = GetHubPacketAdapter();\r
1933 \r
1934         s->Connection = c;\r
1935         AddRef(c->ref);\r
1936 \r
1937         // 新しいセッション名の決定\r
1938         StrCpy(hub_name_upper, sizeof(hub_name_upper), h->Name);\r
1939         StrUpper(hub_name_upper);\r
1940         StrCpy(user_name_upper, sizeof(user_name_upper), username);\r
1941         StrUpper(user_name_upper);\r
1942 \r
1943         if ((StrCmpi(username, ADMINISTRATOR_USERNAME) != 0) && (StrCmpi(username, BRIDGE_USER_NAME) != 0) || (cedar->Server == NULL || cedar->Server->ServerType == SERVER_TYPE_STANDALONE))\r
1944         {\r
1945                 Format(name, sizeof(name), "SID-%s-%u", user_name_upper, Inc(h->SessionCounter));\r
1946         }\r
1947         else\r
1948         {\r
1949                 UCHAR rand[SHA1_SIZE];\r
1950                 char tmp[MAX_SIZE];\r
1951                 Rand(rand, sizeof(rand));\r
1952                 BinToStr(tmp, sizeof(tmp), rand, 3);\r
1953 \r
1954                 if (StrCmpi(username, BRIDGE_USER_NAME) != 0)\r
1955                 {\r
1956                         Format(name, sizeof(name), "SID-%s-%s", user_name_upper,\r
1957                                 tmp);\r
1958                 }\r
1959                 else\r
1960                 {\r
1961                         char pc_name[MAX_SIZE];\r
1962                         TOKEN_LIST *t;\r
1963 \r
1964                         GetMachineName(tmp, sizeof(tmp));\r
1965                         t = ParseToken(tmp, ".");\r
1966                         if (t->NumTokens >= 1)\r
1967                         {\r
1968                                 StrCpy(pc_name, sizeof(pc_name), t->Token[0]);\r
1969                         }\r
1970                         else\r
1971                         {\r
1972                                 StrCpy(pc_name, sizeof(pc_name), "pc");\r
1973                         }\r
1974                         FreeToken(t);\r
1975 \r
1976                         StrUpper(pc_name);\r
1977 \r
1978                         Format(name, sizeof(name), "SID-%s-%s-%u", user_name_upper, pc_name,\r
1979                                 Inc(h->SessionCounter));\r
1980                 }\r
1981         }\r
1982 \r
1983         s->Name = CopyStr(name);\r
1984         s->Policy = policy;\r
1985 \r
1986         // HUB に SESSION を追加\r
1987         AddSession(h, s);\r
1988 \r
1989         // キーを作成\r
1990         NewSessionKey(cedar, s->SessionKey, &s->SessionKey32);\r
1991 \r
1992         return s;\r
1993 }\r
1994 \r
1995 // セッションキーをデバッグ用に表示\r
1996 void DebugPrintSessionKey(UCHAR *session_key)\r
1997 {\r
1998         char tmp[MAX_SIZE];\r
1999         // 引数チェック\r
2000         if (session_key == NULL)\r
2001         {\r
2002                 return;\r
2003         }\r
2004 \r
2005         Bit160ToStr(tmp, session_key);\r
2006         Debug("SessionKey: %s\n", tmp);\r
2007 }\r
2008 \r
2009 // クライアントにステータスを表示する\r
2010 void PrintStatus(SESSION *s, wchar_t *str)\r
2011 {\r
2012         // 引数チェック\r
2013         if (s == NULL || str == NULL || s->Account == NULL || s->Cedar->Client == NULL\r
2014                 || s->Account->StatusPrinter == NULL)\r
2015         {\r
2016                 return;\r
2017         }\r
2018 \r
2019         // コールバック関数に対してステータスを通知する\r
2020         s->Account->StatusPrinter(s, str);\r
2021 }\r
2022 \r
2023 // キャンセルリストの作成\r
2024 LIST *NewCancelList()\r
2025 {\r
2026         return NewList(NULL);\r
2027 }\r
2028 \r
2029 // キャンセルリストにキャンセルを追加\r
2030 void AddCancelList(LIST *o, CANCEL *c)\r
2031 {\r
2032         UINT i;\r
2033         // 引数チェック\r
2034         if (o == NULL || c == NULL)\r
2035         {\r
2036                 return;\r
2037         }\r
2038 \r
2039         for (i = 0;i < LIST_NUM(o);i++)\r
2040         {\r
2041                 CANCEL *t = LIST_DATA(o, i);\r
2042                 if (t == c)\r
2043                 {\r
2044                         return;\r
2045                 }\r
2046         }\r
2047 \r
2048         AddRef(c->ref);\r
2049         Add(o, c);\r
2050 }\r
2051 \r
2052 // キャンセルリスト内の全キャンセルの発行\r
2053 void CancelList(LIST *o)\r
2054 {\r
2055         UINT i;\r
2056         // 引数チェック\r
2057         if (o == NULL)\r
2058         {\r
2059                 return;\r
2060         }\r
2061 \r
2062         for (i = 0;i < LIST_NUM(o);i++)\r
2063         {\r
2064                 CANCEL *c = LIST_DATA(o, i);\r
2065                 Cancel(c);\r
2066                 ReleaseCancel(c);\r
2067         }\r
2068 \r
2069         DeleteAll(o);\r
2070 }\r
2071 \r
2072 // キャンセルリストの解放\r
2073 void ReleaseCancelList(LIST *o)\r
2074 {\r
2075         UINT i;\r
2076         // 引数チェック\r
2077         if (o == NULL)\r
2078         {\r
2079                 return;\r
2080         }\r
2081 \r
2082         for (i = 0;i < LIST_NUM(o);i++)\r
2083         {\r
2084                 CANCEL *c = LIST_DATA(o, i);\r
2085                 ReleaseCancel(c);\r
2086         }\r
2087 \r
2088         ReleaseList(o);\r
2089 }\r
2090 \r
2091 // クライアントに通知\r
2092 void Notify(SESSION *s, UINT code)\r
2093 {\r
2094         // 引数チェック\r
2095         if (s == NULL || s->Account == NULL || s->Cedar->Client == NULL)\r
2096         {\r
2097                 return;\r
2098         }\r
2099 \r
2100         CiNotify(s->Cedar->Client);\r
2101 }\r
2102 \r
2103 \r