source: lab.git/Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Logging.c @ a1bae3e

trunk
Last change on this file since a1bae3e 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: 39.7 KB
Line 
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// Logging.c
79// ログ保存モジュール
80
81#include "CedarPch.h"
82
83static char *delete_targets[] =
84{
85    "backup.vpn_bridge.config",
86    "backup.vpn_client.config",
87    "backup.vpn_server.config",
88    "backup.etherlogger.config",
89    "packet_log",
90    "etherlogger_log",
91    "secure_nat_log",
92    "security_log",
93    "server_log",
94    "bridge_log",
95};
96
97// syslog の送信
98void SendSysLog(SLOG *g, wchar_t *str)
99{
100    UCHAR *buf;
101    UINT buf_size;
102    // 引数チェック
103    if (g == NULL || str == NULL)
104    {
105        return;
106    }
107
108    buf_size = CalcUniToUtf8(str);
109    buf = ZeroMalloc(buf_size);
110    UniToUtf8(buf, buf_size, str);
111
112    if (buf_size >= 1024)
113    {
114        buf_size = 1023;
115    }
116
117    Lock(g->lock);
118    {
119        if (Tick64() >= g->NextPollIp)
120        {
121            IP ip;
122
123            if (GetIP(&ip, g->HostName))
124            {
125                g->NextPollIp = Tick64() + SYSLOG_POLL_IP_INTERVAL;
126                Copy(&g->DestIp, &ip, sizeof(IP));
127            }
128            else
129            {
130                g->NextPollIp = Tick64() + SYSLOG_POLL_IP_INTERVAL_NG;
131            }
132        }
133
134        if (g->DestPort != 0 && IsZeroIp(&g->DestIp) == false)
135        {
136            SendTo(g->Udp, &g->DestIp, g->DestPort, buf, buf_size);
137        }
138    }
139    Unlock(g->lock);
140
141    Free(buf);
142}
143
144// syslog クライアントの解放
145void FreeSysLog(SLOG *g)
146{
147    // 引数チェック
148    if (g == NULL)
149    {
150        return;
151    }
152
153    DeleteLock(g->lock);
154    ReleaseSock(g->Udp);
155    Free(g);
156}
157
158// syslog クライアントの設定
159void SetSysLog(SLOG *g, char *hostname, UINT port)
160{
161    IP ip;
162    // 引数チェック
163    if (g == NULL)
164    {
165        return;
166    }
167    if (port == 0)
168    {
169        port = SYSLOG_PORT;
170    }
171
172    if (hostname == NULL)
173    {
174        hostname = "";
175    }
176
177    Zero(&ip, sizeof(IP));
178    GetIP(&ip, hostname);
179
180    Lock(g->lock);
181    {
182        Copy(&g->DestIp, &ip, sizeof(IP));
183        g->DestPort = port;
184        StrCpy(g->HostName, sizeof(g->HostName), hostname);
185        g->NextPollIp = Tick64() + IsZeroIp(&ip) ? SYSLOG_POLL_IP_INTERVAL_NG : SYSLOG_POLL_IP_INTERVAL;
186    }
187    Unlock(g->lock);
188}
189
190// syslog クライアントの作成
191SLOG *NewSysLog(char *hostname, UINT port)
192{
193    // 引数チェック
194    SLOG *g = ZeroMalloc(sizeof(SLOG));
195
196    g->lock = NewLock();
197    g->Udp = NewUDP(0);
198
199    SetSysLog(g, hostname, port);
200
201    return g;
202}
203
204// ディスクに十分な空き容量があるかチェックする
205bool CheckEraserDiskFreeSpace(ERASER *e)
206{
207    UINT64 s;
208    // 引数チェック
209    if (e == NULL)
210    {
211        return true;
212    }
213
214    // ディスクの空き容量を取得する
215    if (GetDiskFree(e->DirName, &s, NULL, NULL) == false)
216    {
217        // 取得失敗
218        return true;
219    }
220
221    if (e->MinFreeSpace > s)
222    {
223        // 空き容量が指定されたバイト数未満である
224        return false;
225    }
226
227    // 十分空いている
228    return true;
229}
230
231// 削除対象ファイルリストを解放する
232void FreeEraseFileList(LIST *o)
233{
234    UINT i;
235    // 引数チェック
236    if (o == NULL)
237    {
238        return;
239    }
240
241    for (i = 0;i < LIST_NUM(o);i++)
242    {
243        ERASE_FILE *f = LIST_DATA(o, i);
244        Free(f->FullPath);
245        Free(f);
246    }
247
248    ReleaseList(o);
249}
250
251// 削除対象ファイルリストを表示する
252void PrintEraseFileList(LIST *o)
253{
254    UINT i;
255    // 引数チェック
256    if (o == NULL)
257    {
258        return;
259    }
260
261    for (i = 0;i < LIST_NUM(o);i++)
262    {
263        ERASE_FILE *f = LIST_DATA(o, i);
264        Print("%I64u - %s\n", f->UpdateTime, f->FullPath);
265    }
266}
267
268// 指定されたディレクトリの削除対象ファイルリストを生成する
269void EnumEraseFile(LIST *o, char *dirname)
270{
271    DIRLIST *dir;
272    UINT i;
273    char tmp[MAX_PATH];
274    // 引数チェック
275    if (o == NULL || dirname == NULL)
276    {
277        return;
278    }
279
280    // 列挙
281    dir = EnumDir(dirname);
282
283    for (i = 0;i < dir->NumFiles;i++)
284    {
285        DIRENT *e = dir->File[i];
286        Format(tmp, sizeof(tmp), "%s/%s", dirname, e->FileName);
287        NormalizePath(tmp, sizeof(tmp), tmp);
288
289        if (e->Folder == false)
290        {
291            // ファイル
292            ERASE_FILE *f;
293
294            if (EndWith(tmp, ".log") || EndWith(tmp, ".config"))
295            {
296                // ログファイルと .config ファイルのみを対象とする
297                f = ZeroMalloc(sizeof(ERASE_FILE));
298                f->FullPath = CopyStr(tmp);
299                f->UpdateTime = e->UpdateDate;
300
301                Add(o, f);
302            }
303        }
304        else
305        {
306            // フォルダ
307            EnumEraseFile(o, tmp);
308        }
309    }
310
311    FreeDir(dir);
312}
313
314// 削除対象ファイルリストを生成する
315LIST *GenerateEraseFileList(ERASER *e)
316{
317    LIST *o;
318    UINT i;
319    // 引数チェック
320    if (e == NULL)
321    {
322        return NULL;
323    }
324
325    o = NewListFast(CompareEraseFile);
326
327    // 各ディレクトリを走査する
328    for (i = 0;i < sizeof(delete_targets) / sizeof(delete_targets[0]);i++)
329    {
330        char dirname[MAX_PATH];
331        Format(dirname, sizeof(dirname), "%s/%s", e->DirName, delete_targets[i]);
332
333        EnumEraseFile(o, dirname);
334    }
335
336    // ソートする
337    Sort(o);
338
339    return o;
340}
341
342// 不要ファイルの消去処理
343void EraserMain(ERASER *e)
344{
345    LIST *o;
346    UINT i;
347    bool ok = false;
348    char bs[64];
349    // 引数チェック
350    if (e == NULL)
351    {
352        return;
353    }
354
355    // まず空き容量をチェック
356    if (CheckEraserDiskFreeSpace(e))
357    {
358        // 十分空いている
359        return;
360    }
361
362    ToStrByte(bs, sizeof(bs), e->MinFreeSpace);
363
364    // ファイル一覧の生成
365    o = GenerateEraseFileList(e);
366
367    // ファイルを古い順に 1 つずつ削除してみる
368    for (i = 0;i < LIST_NUM(o);i++)
369    {
370        ERASE_FILE *f = LIST_DATA(o, i);
371
372        // ファイルを削除する
373        if (FileDelete(f->FullPath))
374        {
375            ELog(e, "LE_DELETE", bs, f->FullPath);
376        }
377
378        // 削除したあと空き容量を確認してみる
379        if (CheckEraserDiskFreeSpace(e))
380        {
381            // 空き容量が回復した
382            ok = true;
383            break;
384        }
385    }
386
387    // ファイル一覧の解放
388    FreeEraseFileList(o);
389
390    if (e->LastFailed == false && ok == false)
391    {
392        // 空き容量が足りないがこれ以上ファイルを削除できない状態になってしまった
393        ELog(e, "LE_NOT_ENOUGH_FREE", bs);
394    }
395
396    e->LastFailed = ok ? false : true;
397}
398
399// 削除するファイル項目の比較
400int CompareEraseFile(void *p1, void *p2)
401{
402    ERASE_FILE *f1, *f2;
403    if (p1 == NULL || p2 == NULL)
404    {
405        return 0;
406    }
407    f1 = *(ERASE_FILE **)p1;
408    f2 = *(ERASE_FILE **)p2;
409    if (f1 == NULL || f2 == NULL)
410    {
411        return 0;
412    }
413    if (f1->UpdateTime > f2->UpdateTime)
414    {
415        return 1;
416    }
417    else if (f1->UpdateTime == f2->UpdateTime)
418    {
419        return 0;
420    }
421    else
422    {
423        return -1;
424    }
425}
426
427// 自動ファイル削除器スレッド
428void EraserThread(THREAD *t, void *p)
429{
430    ERASER *e = (ERASER *)p;
431    char bs[64];
432    // 引数チェック
433    if (t == NULL || e == NULL)
434    {
435        return;
436    }
437
438    // 監視を開始
439    ToStrByte(bs, sizeof(bs), e->MinFreeSpace);
440    ELog(e, "LE_START", e->DirName, bs);
441
442    while (e->Halt == false)
443    {
444        // 一定間隔ごとにディスクの空き容量をチェックする
445        EraserMain(e);
446
447        Wait(e->HaltEvent, DISK_FREE_CHECK_INTERVAL);
448    }
449}
450
451// 新しい自動ファイル削除器の作成
452ERASER *NewEraser(LOG *log, UINT64 min_size)
453{
454    ERASER *e;
455    char dir[MAX_PATH];
456
457    if (min_size == 0)
458    {
459        min_size = DISK_FREE_SPACE_DEFAULT;
460    }
461
462    if (min_size < DISK_FREE_SPACE_MIN)
463    {
464        min_size = DISK_FREE_SPACE_MIN;
465    }
466
467    e = ZeroMalloc(sizeof(ERASER));
468
469    GetExeDir(dir, sizeof(dir));
470
471    e->Log = log;
472    e->MinFreeSpace = min_size;
473    e->DirName = CopyStr(dir);
474    e->HaltEvent = NewEvent();
475
476    e->Thread = NewThread(EraserThread, e);
477
478    return e;
479}
480
481// 自動ファイル削除器の解放
482void FreeEraser(ERASER *e)
483{
484    // 引数チェック
485    if (e == NULL)
486    {
487        return;
488    }
489
490    e->Halt = true;
491    Set(e->HaltEvent);
492    WaitThread(e->Thread, INFINITE);
493    ReleaseThread(e->Thread);
494    ReleaseEvent(e->HaltEvent);
495
496    Free(e->DirName);
497    Free(e);
498}
499
500// デバッグログをとる (可変長引数)
501void DebugLog(CEDAR *c, char *fmt, ...)
502{
503    char buf[MAX_SIZE * 2];
504    va_list args;
505    // 引数チェック
506    if (fmt == NULL)
507    {
508        return;
509    }
510    if (c->DebugLog == NULL)
511    {
512        return;
513    }
514
515    va_start(args, fmt);
516    FormatArgs(buf, sizeof(buf), fmt, args);
517
518    InsertStringRecord(c->DebugLog, buf);
519    va_end(args);
520}
521
522// 自動ファイル削除器のログをとる
523void ELog(ERASER *e, char *name, ...)
524{
525    wchar_t buf[MAX_SIZE * 2];
526    va_list args;
527    // 引数チェック
528    if (name == NULL)
529    {
530        return;
531    }
532
533    va_start(args, name);
534    UniFormatArgs(buf, sizeof(buf), _UU(name), args);
535
536    InsertUnicodeRecord(e->Log, buf);
537
538    if (IsDebug())
539    {
540        UniPrint(L"LOG: %s\n", buf);
541    }
542    va_end(args);
543}
544
545// サーバーのログをとる
546void ServerLog(CEDAR *c, wchar_t *fmt, ...)
547{
548    wchar_t buf[MAX_SIZE * 2];
549    va_list args;
550    // 引数チェック
551    if (fmt == NULL)
552    {
553        return;
554    }
555
556    va_start(args, fmt);
557    UniFormatArgs(buf, sizeof(buf), fmt, args);
558
559    WriteServerLog(c, buf);
560    va_end(args);
561}
562void SLog(CEDAR *c, char *name, ...)
563{
564    wchar_t buf[MAX_SIZE * 2];
565    va_list args;
566    // 引数チェック
567    if (name == NULL)
568    {
569        return;
570    }
571
572    va_start(args, name);
573    UniFormatArgs(buf, sizeof(buf), _UU(name), args);
574
575    WriteServerLog(c, buf);
576    va_end(args);
577}
578
579// クライアントログ
580void CLog(CLIENT *c, char *name, ...)
581{
582    wchar_t buf[MAX_SIZE * 2];
583    va_list args;
584    // 引数チェック
585    if (name == NULL)
586    {
587        return;
588    }
589
590    if (c == NULL || c->NoSaveLog)
591    {
592        return;
593    }
594
595    va_start(args, name);
596    UniFormatArgs(buf, sizeof(buf), _UU(name), args);
597
598    WriteClientLog(c, buf);
599    va_end(args);
600}
601
602// HUB のセキュリティログをとる
603void HubLog(HUB *h, wchar_t *fmt, ...)
604{
605    wchar_t buf[MAX_SIZE * 2];
606    va_list args;
607    // 引数チェック
608    if (fmt == NULL)
609    {
610        return;
611    }
612
613    va_start(args, fmt);
614    UniFormatArgs(buf, sizeof(buf), fmt, args);
615
616    WriteHubLog(h, buf);
617    va_end(args);
618}
619void ALog(ADMIN *a, HUB *h, char *name, ...)
620{
621    wchar_t buf[MAX_SIZE * 2];
622    wchar_t tmp[MAX_SIZE * 2];
623    va_list args;
624    RPC *r;
625    // 引数チェック
626    if (a == NULL || name == NULL)
627    {
628        return;
629    }
630
631    r = a->Rpc;
632
633    va_start(args, name);
634    UniFormatArgs(buf, sizeof(buf), _UU(name), args);
635
636    if (h == NULL)
637    {
638        UniFormat(tmp, sizeof(tmp), _UU("LA_TAG_1"), r->Name);
639    }
640    else
641    {
642        UniFormat(tmp, sizeof(tmp), _UU("LA_TAG_2"), r->Name, h->Name);
643    }
644
645    UniStrCat(tmp, sizeof(tmp), buf);
646
647    if (h == NULL)
648    {
649        WriteServerLog(((ADMIN *)r->Param)->Server->Cedar, tmp);
650    }
651    else
652    {
653        WriteHubLog(h, tmp);
654    }
655    va_end(args);
656}
657void HLog(HUB *h, char *name, ...)
658{
659    wchar_t buf[MAX_SIZE * 2];
660    va_list args;
661    // 引数チェック
662    if (name == NULL)
663    {
664        return;
665    }
666
667    va_start(args, name);
668    UniFormatArgs(buf, sizeof(buf), _UU(name), args);
669
670    WriteHubLog(h, buf);
671    va_end(args);
672}
673void NLog(VH *v, char *name, ...)
674{
675    wchar_t buf[MAX_SIZE * 2];
676    static wchar_t snat_prefix[] = L"SecureNAT: ";
677    va_list args;
678    // 引数チェック
679    if (name == NULL || v == NULL || v->nat == NULL || v->nat->SecureNAT == NULL)
680    {
681        return;
682    }
683
684    va_start(args, name);
685    Copy(buf, snat_prefix, sizeof(snat_prefix));
686    UniFormatArgs(&buf[11], sizeof(buf) - 12 * sizeof(wchar_t), _UU(name), args);
687
688    WriteHubLog(v->nat->SecureNAT->Hub, buf);
689    va_end(args);
690}
691
692// HUB のセキュリティログを保存する
693void WriteHubLog(HUB *h, wchar_t *str)
694{
695    wchar_t buf[MAX_SIZE * 2];
696    SERVER *s;
697    // 引数チェック
698    if (h == NULL || str == NULL)
699    {
700        return;
701    }
702
703    s = h->Cedar->Server;
704
705    UniFormat(buf, sizeof(buf), L"[HUB \"%S\"] %s", h->Name, str);
706
707    WriteServerLog(h->Cedar, buf);
708
709    if (h->LogSetting.SaveSecurityLog == false)
710    {
711        return;
712    }
713
714    InsertUnicodeRecord(h->SecurityLogger, str);
715}
716
717// クライアントログを保存する
718void WriteClientLog(CLIENT *c, wchar_t *str)
719{
720    // 引数チェック
721    if (c == NULL)
722    {
723        return;
724    }
725
726    InsertUnicodeRecord(c->Logger, str);
727}
728
729// サーバーのセキュリティログを保存する
730void WriteServerLog(CEDAR *c, wchar_t *str)
731{
732    SERVER *s;
733    // 引数チェック
734    if (c == NULL || str == NULL)
735    {
736        return;
737    }
738
739    s = c->Server;
740    if (s == NULL)
741    {
742        return;
743    }
744
745    if (IsDebug())
746    {
747        UniPrint(L"LOG: %s\n", str);
748    }
749
750    InsertUnicodeRecord(s->Logger, str);
751}
752
753// 複数行にわたるログを書き出す
754void WriteMultiLineLog(LOG *g, BUF *b)
755{
756    // 引数チェック
757    if (g == NULL || b == NULL)
758    {
759        return;
760    }
761
762    SeekBuf(b, 0, 0);
763
764    while (true)
765    {
766        char *s = CfgReadNextLine(b);
767        if (s == NULL)
768        {
769            break;
770        }
771
772        if (IsEmptyStr(s) == false)
773        {
774            InsertStringRecord(g, s);
775        }
776
777        Free(s);
778    }
779}
780
781// セキュリティログをとる (可変長引数) ※ 廃止
782void SecLog(HUB *h, char *fmt, ...)
783{
784    char buf[MAX_SIZE * 2];
785    va_list args;
786    // 引数チェック
787    if (fmt == NULL)
788    {
789        return;
790    }
791
792    if (h->LogSetting.SaveSecurityLog == false)
793    {
794        return;
795    }
796
797    va_start(args, fmt);
798    FormatArgs(buf, sizeof(buf), fmt, args);
799
800    WriteSecurityLog(h, buf);
801    va_end(args);
802}
803
804// セキュリティログをとる
805void WriteSecurityLog(HUB *h, char *str)
806{
807    // 引数チェック
808    if (h == NULL || str == NULL)
809    {
810        return;
811    }
812
813    InsertStringRecord(h->SecurityLogger, str);
814}
815
816// パケットログをとる
817void PacketLog(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *packet)
818{
819    UINT level;
820    PKT *p;
821    PACKET_LOG *pl;
822    SERVER *s;
823    bool no_log = false;
824    // 引数チェック
825    if (hub == NULL || src_session == NULL || packet == NULL)
826    {
827        return;
828    }
829
830    s = hub->Cedar->Server;
831
832    if (hub->LogSetting.SavePacketLog == false)
833    {
834        // パケットログをとらない
835        return;
836    }
837
838    if (Cmp(hub->HubMacAddr, packet->MacAddressSrc, 6) == 0 ||
839        Cmp(hub->HubMacAddr, packet->MacAddressDest, 6) == 0)
840    {
841        return;
842    }
843
844    // ロギングレベルの決定
845    level = CalcPacketLoggingLevel(hub, packet);
846    if (level == PACKET_LOG_NONE)
847    {
848        // 保存しない
849        return;
850    }
851
852    if (hub->Option != NULL)
853    {
854        if (hub->Option->NoIPv4PacketLog && (packet->TypeL3 == L3_IPV4 || packet->TypeL3 == L3_ARPV4))
855        {
856            // IPv4 パケットログを一切保存しない
857            return;
858        }
859
860        if (hub->Option->NoIPv6PacketLog && packet->TypeL3 == L3_IPV6)
861        {
862            // IPv6 パケットログを一切保存しない
863            return;
864        }
865    }
866
867    if (s->Cedar->Bridge == false)
868    {
869        if (s->LicenseSystem != NULL && s->LicenseSystem->Status != NULL)
870        {
871            if (s->LicenseSystem->Status->AllowEnterpriseFunction == false &&
872                s->LicenseSystem->Status->Edition != 0)
873            {
874                // VPN Server の製品エディションが低い場合はパケットログのうち一部
875                // を保存しない
876                no_log = true;
877            }
878        }
879    }
880
881    // パケットのクローン
882    p = ClonePacket(packet, level == PACKET_LOG_ALL ? true : false);
883
884    // 情報の取得
885    pl = ZeroMalloc(sizeof(PACKET_LOG));
886    pl->Cedar = hub->Cedar;
887    pl->Packet = p;
888    pl->NoLog = no_log;
889    if (src_session != NULL)
890    {
891        pl->SrcSessionName = CopyStr(src_session->Name);
892    }
893    else
894    {
895        pl->SrcSessionName = CopyStr("");
896    }
897    if (dest_session != NULL)
898    {
899        pl->DestSessionName = CopyStr(dest_session->Name);
900    }
901    else
902    {
903        pl->DestSessionName = CopyStr("");
904    }
905
906    if (src_session->LoggingRecordCount != NULL)
907    {
908        UINT n = 0;
909        while (src_session->LoggingRecordCount->c >= 30000)
910        {
911            SleepThread(50);
912            n++;
913            if (n >= 5)
914            {
915                break;
916            }
917        }
918    }
919
920    pl->SrcSession = src_session;
921    AddRef(src_session->ref);
922
923    Inc(src_session->LoggingRecordCount);
924
925    // パケットログの挿入
926    InsertRecord(hub->PacketLogger, pl, PacketLogParseProc);
927}
928
929// 指定されたパケットのロギングレベルを計算する
930UINT CalcPacketLoggingLevelEx(HUB_LOG *g, PKT *packet)
931{
932    UINT ret = 0;
933    // 引数チェック
934    if (g == NULL || packet == NULL)
935    {
936        return PACKET_LOG_NONE;
937    }
938
939    // Ethernet ログ
940    ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ETHERNET]);
941
942    switch (packet->TypeL3)
943    {
944    case L3_ARPV4:
945        // ARP
946        ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ARP]);
947        break;
948
949    case L3_IPV4:
950        // IPv4
951        ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_IP]);
952
953        switch (packet->TypeL4)
954        {
955        case L4_ICMPV4:
956            // ICMPv4
957            ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ICMP]);
958            break;
959
960        case L4_TCP:
961            // TCPv4
962            ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP]);
963
964            if (packet->L4.TCPHeader->Flag & TCP_SYN ||
965                packet->L4.TCPHeader->Flag & TCP_RST ||
966                packet->L4.TCPHeader->Flag & TCP_FIN)
967            {
968                // TCP SYN LOG
969                ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
970            }
971
972            break;
973
974        case L4_UDP:
975            // UDPv4
976            ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_UDP]);
977
978            switch (packet->TypeL7)
979            {
980            case L7_DHCPV4:
981                // DHCPv4
982                ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_DHCP]);
983                break;
984            }
985
986            break;
987        }
988
989        break;
990
991    case L3_IPV6:
992        // IPv6
993        ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_IP]);
994
995        switch (packet->TypeL4)
996        {
997        case L4_ICMPV6:
998            // ICMPv6
999            ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ICMP]);
1000            break;
1001
1002        case L4_TCP:
1003            // TCPv6
1004            ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP]);
1005
1006            if (packet->L4.TCPHeader->Flag & TCP_SYN ||
1007                packet->L4.TCPHeader->Flag & TCP_RST ||
1008                packet->L4.TCPHeader->Flag & TCP_FIN)
1009            {
1010                // TCP SYN LOG
1011                ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
1012            }
1013
1014            break;
1015
1016        case L4_UDP:
1017            // UDPv6
1018            ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_UDP]);
1019
1020            break;
1021        }
1022
1023        break;
1024    }
1025
1026    return ret;
1027}
1028UINT CalcPacketLoggingLevel(HUB *hub, PKT *packet)
1029{
1030    // 引数チェック
1031    if (hub == NULL || packet == NULL)
1032    {
1033        return PACKET_LOG_NONE;
1034    }
1035
1036    return CalcPacketLoggingLevelEx(&hub->LogSetting, packet);
1037}
1038
1039// パケットログエントリを文字列に変換するプロシージャ
1040char *PacketLogParseProc(RECORD *rec)
1041{
1042    PACKET_LOG *pl;
1043    PKT *p;
1044    char *s;
1045    TOKEN_LIST *t;
1046    char tmp[MAX_SIZE];
1047    // 引数チェック
1048    if (rec == NULL)
1049    {
1050        return NULL;
1051    }
1052
1053    pl = (PACKET_LOG *)rec->Data;
1054    p = pl->Packet;
1055
1056    // 各部を生成する
1057    t = ZeroMalloc(sizeof(TOKEN_LIST));
1058    t->NumTokens = 16;
1059    t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
1060
1061    // 送信元セッション
1062    t->Token[0] = pl->SrcSessionName;
1063
1064    // 宛先セッション
1065    t->Token[1] = pl->DestSessionName;
1066
1067    // 送信元 MAC アドレス
1068    BinToStr(tmp, sizeof(tmp), p->MacAddressSrc, 6);
1069
1070    t->Token[2] = CopyStr(tmp);
1071    // 宛先 MAC アドレス
1072    BinToStr(tmp, sizeof(tmp), p->MacAddressDest, 6);
1073
1074    t->Token[3] = CopyStr(tmp);
1075
1076    // MAC プロトコル
1077    snprintf(tmp, sizeof(tmp), "0x%04X", Endian16(p->MacHeader->Protocol));
1078    t->Token[4] = CopyStr(tmp);
1079
1080    // パケットサイズ
1081    ToStr(tmp, p->PacketSize);
1082    t->Token[5] = CopyStr(tmp);
1083
1084    // パケットログ本体は実装されていない
1085    t->Token[6] = CopyUniToUtf(_UU("LH_PACKET_LOG_NO_LOG"));
1086
1087    s = GenCsvLine(t);
1088    FreeToken(t);
1089
1090    // パケットデータを破棄する
1091    if (pl->PurePacket == false)
1092    {
1093        FreeClonePacket(p);
1094    }
1095    else
1096    {
1097        Free(p->PacketData);
1098        FreePacket(p);
1099    }
1100
1101    // セッションを解放する
1102    if (pl->SrcSession != NULL)
1103    {
1104        Dec(pl->SrcSession->LoggingRecordCount);
1105        ReleaseSession(pl->SrcSession);
1106    }
1107
1108    // PACKET_LOG を破棄する
1109    Free(pl);
1110
1111    return s;
1112}
1113
1114// TCP フラグを文字列に変換
1115char *TcpFlagStr(UCHAR flag)
1116{
1117    char tmp[MAX_SIZE];
1118    StrCpy(tmp, sizeof(tmp), "");
1119
1120    if (flag & TCP_FIN)
1121    {
1122        StrCat(tmp, sizeof(tmp), "FIN+");
1123    }
1124
1125    if (flag & TCP_SYN)
1126    {
1127        StrCat(tmp, sizeof(tmp), "SYN+");
1128    }
1129
1130    if (flag & TCP_RST)
1131    {
1132        StrCat(tmp, sizeof(tmp), "RST+");
1133    }
1134
1135    if (flag & TCP_PSH)
1136    {
1137        StrCat(tmp, sizeof(tmp), "PSH+");
1138    }
1139
1140    if (flag & TCP_ACK)
1141    {
1142        StrCat(tmp, sizeof(tmp), "ACK+");
1143    }
1144
1145    if (flag & TCP_URG)
1146    {
1147        StrCat(tmp, sizeof(tmp), "URG+");
1148    }
1149
1150    if (StrLen(tmp) >= 1)
1151    {
1152        if (tmp[StrLen(tmp) - 1] == '+')
1153        {
1154            tmp[StrLen(tmp) - 1] = 0;
1155        }
1156    }
1157
1158    return CopyStr(tmp);
1159}
1160
1161// ポート文字列の生成
1162char *PortStr(CEDAR *cedar, UINT port, bool udp)
1163{
1164    char tmp[MAX_SIZE];
1165    char *name;
1166    // 引数チェック
1167    if (cedar == NULL)
1168    {
1169        return NULL;
1170    }
1171
1172    name = GetSvcName(cedar, udp, port);
1173
1174    if (name == NULL)
1175    {
1176        snprintf(tmp, sizeof(tmp), "%u", port);
1177    }
1178    else
1179    {
1180        snprintf(tmp, sizeof(tmp), "%s(%u)", name, port);
1181    }
1182
1183    return CopyStr(tmp);
1184}
1185
1186// カンマで区切られた文字列を生成する
1187char *GenCsvLine(TOKEN_LIST *t)
1188{
1189    UINT i;
1190    BUF *b;
1191    char *ret;
1192    // 引数チェック
1193    if (t == NULL)
1194    {
1195        return NULL;
1196    }
1197
1198    b = NewBuf();
1199    for (i = 0;i < t->NumTokens;i++)
1200    {
1201        if (t->Token[i] != NULL)
1202        {
1203            ReplaceForCsv(t->Token[i]);
1204            if (StrLen(t->Token[i]) == 0)
1205            {
1206                WriteBuf(b, "-", 1);
1207            }
1208            else
1209            {
1210                WriteBuf(b, t->Token[i], StrLen(t->Token[i]));
1211            }
1212        }
1213        else
1214        {
1215            WriteBuf(b, "-", 1);
1216        }
1217        if (i != (t->NumTokens - 1))
1218        {
1219            WriteBuf(b, ",", 1);
1220        }
1221    }
1222    WriteBuf(b, "\0", 1);
1223
1224    ret = (char *)b->Buf;
1225
1226    Free(b);
1227
1228    return ret;
1229}
1230
1231// CSV の中に入る文字列を正しく置換する
1232void ReplaceForCsv(char *str)
1233{
1234    UINT i, len;
1235    // 引数チェック
1236    if (str == NULL)
1237    {
1238        return;
1239    }
1240
1241    // 空白があればトリミングする
1242    Trim(str);
1243    len = StrLen(str);
1244
1245    for (i = 0;i < len;i++)
1246    {
1247        // カンマをアンダーバーに変換する
1248        if (str[i] == ',')
1249        {
1250            str[i] = '_';
1251        }
1252    }
1253}
1254
1255// ログのディレクトリ名を設定
1256void SetLogDirName(LOG *g, char *dir)
1257{
1258    // 引数チェック
1259    if (g == NULL || dir == NULL)
1260    {
1261        return;
1262    }
1263
1264    LockLog(g);
1265    {
1266        if (g->DirName != NULL)
1267        {
1268            Free(g->DirName);
1269        }
1270        g->DirName = CopyStr(dir);
1271    }
1272    UnlockLog(g);
1273}
1274
1275// ログの名前を設定
1276void SetLogPrefix(LOG *g, char *prefix)
1277{
1278    // 引数チェック
1279    if (g == NULL || prefix == NULL)
1280    {
1281        return;
1282    }
1283
1284    LockLog(g);
1285    {
1286        if (g->DirName != NULL)
1287        {
1288            Free(g->Prefix);
1289        }
1290        g->DirName = CopyStr(prefix);
1291    }
1292    UnlockLog(g);
1293}
1294
1295// ログのスイッチ種類を設定
1296void SetLogSwitchType(LOG *g, UINT switch_type)
1297{
1298    // 引数チェック
1299    if (g == NULL)
1300    {
1301        return;
1302    }
1303
1304    LockLog(g);
1305    {
1306        g->SwitchType = switch_type;
1307    }
1308    UnlockLog(g);
1309}
1310
1311// 文字列レコードの解析
1312char *StringRecordParseProc(RECORD *rec)
1313{
1314    // 引数チェック
1315    if (rec == NULL)
1316    {
1317        return NULL;
1318    }
1319
1320    return (char *)rec->Data;
1321}
1322
1323// ログに Unicode 文字列レコードを追加
1324void InsertUnicodeRecord(LOG *g, wchar_t *unistr)
1325{
1326    char *str;
1327    UINT size;
1328    // 引数チェック
1329    if (g == NULL || unistr == NULL)
1330    {
1331        return;
1332    }
1333
1334    size = CalcUniToUtf8(unistr) + 32;
1335    str = ZeroMalloc(size);
1336
1337    UniToUtf8((BYTE *)str, size, unistr);
1338    InsertStringRecord(g, str);
1339    Free(str);
1340}
1341
1342// ログに文字列レコードを追加
1343void InsertStringRecord(LOG *g, char *str)
1344{
1345    char *str_copy;
1346    // 引数チェック
1347    if (g == NULL || str == NULL)
1348    {
1349        return;
1350    }
1351
1352    str_copy = CopyStr(str);
1353
1354    InsertRecord(g, str_copy, StringRecordParseProc);
1355}
1356
1357// ログにレコードを追加
1358void InsertRecord(LOG *g, void *data, RECORD_PARSE_PROC *proc)
1359{
1360    RECORD *rec;
1361    // 引数チェック
1362    if (g == NULL || data == NULL || proc == NULL)
1363    {
1364        return;
1365    }
1366
1367    rec = ZeroMalloc(sizeof(RECORD));
1368    rec->Tick = Tick64();
1369    rec->ParseProc = proc;
1370    rec->Data = data;
1371
1372    LockQueue(g->RecordQueue);
1373    {
1374        InsertQueue(g->RecordQueue, rec);
1375    }
1376    UnlockQueue(g->RecordQueue);
1377
1378    Set(g->Event);
1379}
1380
1381// ログのロック
1382void LockLog(LOG *g)
1383{
1384    // 引数チェック
1385    if (g == NULL)
1386    {
1387        return;
1388    }
1389
1390    Lock(g->lock);
1391}
1392
1393// ログのロック解除
1394void UnlockLog(LOG *g)
1395{
1396    // 引数チェック
1397    if (g == NULL)
1398    {
1399        return;
1400    }
1401
1402    Unlock(g->lock);
1403}
1404
1405// ログファイル名の文字列部分を時刻とスイッチ規則から生成する
1406void MakeLogFileNameStringFromTick(LOG *g, char *str, UINT size, UINT64 tick, UINT switch_type)
1407{
1408    UINT64 time;
1409    SYSTEMTIME st;
1410
1411    // 引数チェック
1412    if (str == NULL || g == NULL)
1413    {
1414        return;
1415    }
1416
1417    if (g->CacheFlag)
1418    {
1419        if (g->LastTick == tick &&
1420            g->LastSwitchType == switch_type)
1421        {
1422            StrCpy(str, size, g->LastStr);
1423            return;
1424        }
1425    }
1426
1427    time = TickToTime(tick);
1428    UINT64ToSystem(&st, SystemToLocal64(time));
1429
1430    switch (switch_type)
1431    {
1432    case LOG_SWITCH_SECOND: // 1 秒単位
1433        snprintf(str, size, "_%04u%02u%02u_%02u%02u%02u",
1434            st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
1435        break;
1436
1437    case LOG_SWITCH_MINUTE: // 1 分単位
1438        snprintf(str, size, "_%04u%02u%02u_%02u%02u",
1439            st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute);
1440        break;
1441
1442    case LOG_SWITCH_HOUR:   // 1 時間単位
1443        snprintf(str, size, "_%04u%02u%02u_%02u", st.wYear, st.wMonth, st.wDay, st.wHour);
1444        break;
1445
1446    case LOG_SWITCH_DAY:    // 1 日単位
1447        snprintf(str, size, "_%04u%02u%02u", st.wYear, st.wMonth, st.wDay);
1448        break;
1449
1450    case LOG_SWITCH_MONTH:  // 1 ヶ月単位
1451        snprintf(str, size, "_%04u%02u", st.wYear, st.wMonth);
1452        break;
1453
1454    default:                // 切り替え無し
1455        snprintf(str, size, "");
1456        break;
1457    }
1458
1459    g->CacheFlag = true;
1460    g->LastTick = tick;
1461    g->LastSwitchType = switch_type;
1462    StrCpy(g->LastStr, sizeof(g->LastStr), str);
1463}
1464
1465// ログファイル名を作成する
1466bool MakeLogFileName(LOG *g, char *name, UINT size, char *dir, char *prefix, UINT64 tick, UINT switch_type, UINT num, char *old_datestr)
1467{
1468    char tmp[MAX_SIZE];
1469    char tmp2[64];
1470    bool ret = false;
1471    // 引数チェック
1472    if (g == NULL || name == NULL || prefix == NULL || old_datestr == NULL)
1473    {
1474        return false;
1475    }
1476
1477    MakeLogFileNameStringFromTick(g, tmp, sizeof(tmp), tick, switch_type);
1478
1479    if (num == 0)
1480    {
1481        tmp2[0] = 0;
1482    }
1483    else
1484    {
1485        snprintf(tmp2, sizeof(tmp2), "~%02u", num);
1486    }
1487
1488    if (strcmp(old_datestr, tmp) != 0)
1489    {
1490        ret = true;
1491        strcpy(old_datestr, tmp);
1492    }
1493
1494    snprintf(name, size, "%s%s%s%s%s.log", dir,
1495        StrLen(dir) == 0 ? "" : "/",
1496        prefix, tmp, tmp2
1497        );
1498
1499    return ret;
1500}
1501
1502// ログがフラッシュされるまで待機
1503void WaitLogFlush(LOG *g)
1504{
1505    // 引数チェック
1506    if (g == NULL)
1507    {
1508        return;
1509    }
1510
1511    while (true)
1512    {
1513        UINT num;
1514        LockQueue(g->RecordQueue);
1515        {
1516            num = g->RecordQueue->num_item;
1517        }
1518        UnlockQueue(g->RecordQueue);
1519
1520        if (num == 0)
1521        {
1522            break;
1523        }
1524
1525        Wait(g->FlushEvent, 100);
1526    }
1527}
1528
1529// ログ記録用スレッド
1530void LogThread(THREAD *thread, void *param)
1531{
1532    LOG *g;
1533    IO *io;
1534    BUF *b;
1535    bool flag = false;
1536    char current_file_name[MAX_SIZE];
1537    char current_logfile_datename[MAX_SIZE];
1538    bool last_priority_flag = false;
1539    bool log_date_changed = false;
1540    // 引数チェック
1541    if (thread == NULL || param == NULL)
1542    {
1543        return;
1544    }
1545
1546    Zero(current_file_name, sizeof(current_file_name));
1547    Zero(current_logfile_datename, sizeof(current_logfile_datename));
1548
1549    g = (LOG *)param;
1550
1551    io = NULL;
1552    b = NewBuf();
1553
1554#ifdef  OS_WIN32
1555
1556    // 優先順位を最低にする
1557    MsSetThreadPriorityIdle();
1558
1559#endif  // OS_WIN32
1560
1561    NoticeThreadInit(thread);
1562
1563    while (true)
1564    {
1565        RECORD *rec;
1566        UINT64 s = Tick64();
1567
1568        while (true)
1569        {
1570            char file_name[MAX_SIZE];
1571            UINT num;
1572
1573            // キューの先頭からレコードを取得する
1574            LockQueue(g->RecordQueue);
1575            {
1576                rec = GetNext(g->RecordQueue);
1577                num = g->RecordQueue->num_item;
1578            }
1579            UnlockQueue(g->RecordQueue);
1580
1581#ifdef  OS_WIN32
1582            if (num >= LOG_ENGINE_SAVE_START_CACHE_COUNT)
1583            {
1584                // 優先順位を上げる
1585                if (last_priority_flag == false)
1586                {
1587                    Debug("LOG_THREAD: MsSetThreadPriorityRealtime\n");
1588                    MsSetThreadPriorityRealtime();
1589                    last_priority_flag = true;
1590                }
1591            }
1592
1593            if (num < (LOG_ENGINE_SAVE_START_CACHE_COUNT / 2))
1594            {
1595                // 優先順位を戻す
1596                if (last_priority_flag)
1597                {
1598                    Debug("LOG_THREAD: MsSetThreadPriorityIdle\n");
1599                    MsSetThreadPriorityIdle();
1600                    last_priority_flag = false;
1601                }
1602            }
1603#endif  // OS_WIN32
1604
1605            if (b->Size > g->MaxLogFileSize)
1606            {
1607                // バッファのサイズが最大ログファイルサイズを超える場合は消去する
1608                ClearBuf(b);
1609            }
1610
1611            if (b->Size >= LOG_ENGINE_BUFFER_CACHE_SIZE_MAX)
1612            {
1613                // バッファの中身をファイルに書き出す
1614                if (io != NULL)
1615                {
1616                    if ((g->CurrentFilePointer + (UINT64)b->Size) > g->MaxLogFileSize)
1617                    {
1618                        if (g->log_number_incremented == false)
1619                        {
1620                            g->CurrentLogNumber++;
1621                            g->log_number_incremented = true;
1622                        }
1623                    }
1624                    else
1625                    {
1626                        if (FileWrite(io, b->Buf, b->Size) == false)
1627                        {
1628                            FileCloseEx(io, true);
1629                            // ファイルへの書き込みに失敗した場合は仕方が無い
1630                            // のでバッファを消して諦める
1631                            ClearBuf(b);
1632                            io = NULL;
1633                        }
1634                        else
1635                        {
1636                            g->CurrentFilePointer += (UINT64)b->Size;
1637                            ClearBuf(b);
1638                        }
1639                    }
1640                }
1641            }
1642
1643            if (rec == NULL)
1644            {
1645                if (b->Size != 0)
1646                {
1647                    // バッファの中身をファイルに書き出す
1648                    if (io != NULL)
1649                    {
1650                        if ((g->CurrentFilePointer + (UINT64)b->Size) > g->MaxLogFileSize)
1651                        {
1652                            if (g->log_number_incremented == false)
1653                            {
1654                                g->CurrentLogNumber++;
1655                                g->log_number_incremented = true;
1656                            }
1657                        }
1658                        else
1659                        {
1660                            if (FileWrite(io, b->Buf, b->Size) == false)
1661                            {
1662                                FileCloseEx(io, true);
1663                                // ファイルへの書き込みに失敗した場合は仕方が無い
1664                                // のでバッファを消して諦める
1665                                ClearBuf(b);
1666                                io = NULL;
1667                            }
1668                            else
1669                            {
1670                                g->CurrentFilePointer += (UINT64)b->Size;
1671                                ClearBuf(b);
1672                            }
1673                        }
1674                    }
1675                }
1676
1677                Set(g->FlushEvent);
1678                break;
1679            }
1680
1681            // ログファイル名を生成する
1682            LockLog(g);
1683            {
1684                log_date_changed = MakeLogFileName(g, file_name, sizeof(file_name),
1685                    g->DirName, g->Prefix, rec->Tick, g->SwitchType, g->CurrentLogNumber, current_logfile_datename);
1686
1687                if (log_date_changed)
1688                {
1689                    UINT i;
1690
1691                    g->CurrentLogNumber = 0;
1692                    MakeLogFileName(g, file_name, sizeof(file_name),
1693                        g->DirName, g->Prefix, rec->Tick, g->SwitchType, 0, current_logfile_datename);
1694                    for (i = 0;;i++)
1695                    {
1696                        char tmp[MAX_SIZE];
1697                        MakeLogFileName(g, tmp, sizeof(tmp),
1698                            g->DirName, g->Prefix, rec->Tick, g->SwitchType, i, current_logfile_datename);
1699
1700                        if (IsFileExists(tmp) == false)
1701                        {
1702                            break;
1703                        }
1704                        StrCpy(file_name, sizeof(file_name), tmp);
1705                        g->CurrentLogNumber = i;
1706                    }
1707                }
1708            }
1709            UnlockLog(g);
1710
1711            if (io != NULL)
1712            {
1713                if (StrCmp(current_file_name, file_name) != 0)
1714                {
1715                    // 現在ログファイルを開いていて今回別のログファイルへの書き込みが必要になった
1716                    // 場合はログファイルにバッファの内容を書き込んでからログファイルを閉じる
1717                    // バッファの中身をファイルに書き出す
1718                    if (io != NULL)
1719                    {
1720                        if (log_date_changed)
1721                        {
1722                            if ((g->CurrentFilePointer + (UINT64)b->Size) <= g->MaxLogFileSize)
1723                            {
1724                                if (FileWrite(io, b->Buf, b->Size) == false)
1725                                {
1726                                    FileCloseEx(io, true);
1727                                    ClearBuf(b);
1728                                    io = NULL;
1729                                }
1730                                else
1731                                {
1732                                    g->CurrentFilePointer += (UINT64)b->Size;
1733                                    ClearBuf(b);
1734                                }
1735                            }
1736                        }
1737                        // ファイルを閉じる
1738                        FileCloseEx(io, true);
1739                    }
1740
1741                    g->log_number_incremented = false;
1742
1743                    // 新しいログファイルを開くか作成する
1744                    StrCpy(current_file_name, sizeof(current_file_name), file_name);
1745                    io = FileOpen(file_name, true);
1746                    if (io == NULL)
1747                    {
1748                        // ログファイルを作成する
1749                        LockLog(g);
1750                        {
1751                            MakeDir(g->DirName);
1752
1753#ifdef  OS_WIN32
1754                            Win32SetFolderCompress(g->DirName, true);
1755#endif  // OS_WIN32
1756                        }
1757                        UnlockLog(g);
1758                        io = FileCreate(file_name);
1759                        g->CurrentFilePointer = 0;
1760                    }
1761                    else
1762                    {
1763                        // ログファイルの末尾に移動する
1764                        g->CurrentFilePointer = FileSize64(io);
1765                        FileSeek(io, SEEK_END, 0);
1766                    }
1767                }
1768            }
1769            else
1770            {
1771                // 新しいログファイルを開くか作成する
1772                StrCpy(current_file_name, sizeof(current_file_name), file_name);
1773                io = FileOpen(file_name, true);
1774                if (io == NULL)
1775                {
1776                    // ログファイルを作成する
1777                    LockLog(g);
1778                    {
1779                        MakeDir(g->DirName);
1780#ifdef  OS_WIN32
1781                        Win32SetFolderCompress(g->DirName, true);
1782#endif  // OS_WIN32
1783                    }
1784                    UnlockLog(g);
1785                    io = FileCreate(file_name);
1786                    g->CurrentFilePointer = 0;
1787                    if (io == NULL)
1788                    {
1789                        Debug("Logging.c: SleepThread(30);\n");
1790                        SleepThread(30);
1791                    }
1792                }
1793                else
1794                {
1795                    // ログファイルの末尾に移動する
1796                    g->CurrentFilePointer = FileSize64(io);
1797                    FileSeek(io, SEEK_END, 0);
1798                }
1799
1800                g->log_number_incremented = false;
1801            }
1802
1803            // ログの内容をバッファに書き出す
1804            WriteRecordToBuffer(b, rec);
1805
1806            // レコードのメモリを解放
1807            Free(rec);
1808
1809            if (io == NULL)
1810            {
1811                break;
1812            }
1813        }
1814
1815        if (g->Halt)
1816        {
1817            // 停止フラグが立った場合
1818            // すべてのレコードを保存し終えるとブレイクする
1819            UINT num;
1820
1821            if (flag == false)
1822            {
1823#ifdef  OS_WIN32
1824                MsSetThreadPriorityRealtime();
1825#endif  // OS_WIN32
1826                flag = true;
1827            }
1828
1829            LockQueue(g->RecordQueue);
1830            {
1831                num = g->RecordQueue->num_item;
1832            }
1833            UnlockQueue(g->RecordQueue);
1834
1835            if (num == 0 || io == NULL)
1836            {
1837                break;
1838            }
1839        }
1840        else
1841        {
1842            Wait(g->Event, 9821);
1843        }
1844    }
1845
1846    if (io != NULL)
1847    {
1848        FileCloseEx(io, true);
1849    }
1850
1851    FreeBuf(b);
1852}
1853
1854// ログの内容をバッファに書き出す
1855void WriteRecordToBuffer(BUF *b, RECORD *r)
1856{
1857    UINT64 time;
1858    char time_str[MAX_SIZE];
1859    char date_str[MAX_SIZE];
1860    char *s;
1861    // 引数チェック
1862    if (b == NULL || r == NULL)
1863    {
1864        return;
1865    }
1866
1867    // 時刻の取得
1868    time = SystemToLocal64(TickToTime(r->Tick));
1869
1870    // 時刻を文字列に変換
1871    GetDateStr64(date_str, sizeof(date_str), time);
1872    GetTimeStrMilli64(time_str, sizeof(time_str), time);
1873
1874    if (r->ParseProc != PacketLogParseProc)
1875    {
1876        // パケットログ以外
1877        WriteBuf(b, date_str, StrLen(date_str));
1878        WriteBuf(b, " ", 1);
1879        WriteBuf(b, time_str, StrLen(time_str));
1880        WriteBuf(b, " ", 1);
1881    }
1882    else
1883    {
1884        // パケットログ
1885        WriteBuf(b, date_str, StrLen(date_str));
1886        WriteBuf(b, ",", 1);
1887        WriteBuf(b, time_str, StrLen(time_str));
1888        WriteBuf(b, ",", 1);
1889    }
1890
1891    // 本文を出力
1892    s = r->ParseProc(r);
1893    WriteBuf(b, s, StrLen(s));
1894    Free(s);
1895
1896    WriteBuf(b, "\r\n", 2);
1897}
1898
1899// ログ記録の終了
1900void FreeLog(LOG *g)
1901{
1902    RECORD *rec;
1903    // 引数チェック
1904    if (g == NULL)
1905    {
1906        return;
1907    }
1908
1909    // 停止フラグ
1910    g->Halt = true;
1911    Set(g->Event);
1912
1913    WaitThread(g->Thread, INFINITE);
1914    ReleaseThread(g->Thread);
1915
1916    DeleteLock(g->lock);
1917    Free(g->DirName);
1918    Free(g->Prefix);
1919
1920    // 未処理のレコードが残っている場合は解放する
1921    // (本来はここでは残っていないはず)
1922    while (rec = GetNext(g->RecordQueue))
1923    {
1924        char *s = rec->ParseProc(rec);
1925        Free(s);
1926        Free(rec);
1927    }
1928    ReleaseQueue(g->RecordQueue);
1929
1930    ReleaseEvent(g->Event);
1931    ReleaseEvent(g->FlushEvent);
1932
1933    Free(g);
1934}
1935
1936// 新しいログ記録の開始
1937LOG *NewLog(char *dir, char *prefix, UINT switch_type)
1938{
1939    LOG *g;
1940
1941    g = ZeroMalloc(sizeof(LOG));
1942    g->lock = NewLock();
1943    g->DirName = CopyStr(dir == NULL ? "" : dir);
1944    g->Prefix = CopyStr(prefix == NULL ? "log" : prefix);
1945    g->SwitchType = switch_type;
1946    g->RecordQueue = NewQueue();
1947    g->Event = NewEvent();
1948    g->MaxLogFileSize = MAX_LOG_SIZE;
1949    g->FlushEvent = NewEvent();
1950
1951    g->Thread = NewThread(LogThread, g);
1952
1953    WaitThreadInit(g->Thread);
1954
1955    return g;
1956}
1957
1958
Note: See TracBrowser for help on using the repository browser.