source: lab.git/Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Session.c @ 23aa5e1

trunk
Last change on this file since 23aa5e1 was a1bae3e, checked in by mitty <mitty@…>, 12 years ago
  • copy vendor drop to trunk

git-svn-id: https://lab.mitty.jp/svn/lab/trunk@147 7d2118f6-f56c-43e7-95a2-4bb3031d96e7

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