diff --git a/NetTunnelApp/MainForm.Designer.cs b/NetTunnelApp/MainForm.Designer.cs
index 178487f..d7b5ba5 100644
--- a/NetTunnelApp/MainForm.Designer.cs
+++ b/NetTunnelApp/MainForm.Designer.cs
@@ -28,13 +28,49 @@
///
private void InitializeComponent()
{
+ this.button1 = new System.Windows.Forms.Button();
+ this.button2 = new System.Windows.Forms.Button();
+ this.lstLogs = new System.Windows.Forms.ListBox();
this.SuspendLayout();
//
+ // button1
+ //
+ this.button1.Location = new System.Drawing.Point(35, 43);
+ this.button1.Name = "button1";
+ this.button1.Size = new System.Drawing.Size(98, 27);
+ this.button1.TabIndex = 0;
+ this.button1.Text = "button1";
+ this.button1.UseVisualStyleBackColor = true;
+ this.button1.Click += new System.EventHandler(this.button1_Click);
+ //
+ // button2
+ //
+ this.button2.Location = new System.Drawing.Point(180, 46);
+ this.button2.Name = "button2";
+ this.button2.Size = new System.Drawing.Size(96, 24);
+ this.button2.TabIndex = 1;
+ this.button2.Text = "button2";
+ this.button2.UseVisualStyleBackColor = true;
+ this.button2.Click += new System.EventHandler(this.button2_Click);
+ //
+ // lstLogs
+ //
+ this.lstLogs.FormattingEnabled = true;
+ this.lstLogs.ItemHeight = 12;
+ this.lstLogs.Location = new System.Drawing.Point(-1, 204);
+ this.lstLogs.Name = "lstLogs";
+ this.lstLogs.ScrollAlwaysVisible = true;
+ this.lstLogs.Size = new System.Drawing.Size(800, 244);
+ this.lstLogs.TabIndex = 2;
+ //
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
+ this.Controls.Add(this.lstLogs);
+ this.Controls.Add(this.button2);
+ this.Controls.Add(this.button1);
this.Name = "MainForm";
this.Text = "NetTunnelApp";
this.ResumeLayout(false);
@@ -42,6 +78,10 @@
}
#endregion
+
+ private System.Windows.Forms.Button button1;
+ private System.Windows.Forms.Button button2;
+ private System.Windows.Forms.ListBox lstLogs;
}
}
diff --git a/NetTunnelApp/MainForm.cs b/NetTunnelApp/MainForm.cs
index 11beb93..3cc18bf 100644
--- a/NetTunnelApp/MainForm.cs
+++ b/NetTunnelApp/MainForm.cs
@@ -1,26 +1,67 @@
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
+using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
+using static System.Windows.Forms.VisualStyles.VisualStyleElement.TextBox;
-namespace NetTunnelApp
+namespace NetTunnelApp;
+
+public partial class MainForm : Form
{
- public partial class MainForm : Form
+ public MainForm()
{
- public MainForm()
- {
- InitializeComponent();
+ InitializeComponent();
+ var path = Environment.CurrentDirectory + "\\tunnelsdk_" +
+ string.Format("{0:yyyyMMdd}", DateTime.Now) + ".log";
+ NetTunnelLib.InitTunnelSDKLog(path, LogLevel.LOG_DEBUG);
- NetTunnelLib.TunnelSDKInitEnv();
-
- string path = System.Environment.CurrentDirectory + "\\tunnelsdk_" +
- string.Format("{0:yyyyMMdd_HHmm}", System.DateTime.Now) + ".log";
- NetTunnelLib.InitTunnelSDKLog(path, LogLevel.LOG_DEBUG);
- }
+ NetTunnelLib.TunnelSDKInitEnv(Environment.CurrentDirectory);
}
-}
+
+ private void button1_Click(object sender, EventArgs e)
+ {
+ var buffer = new StringBuilder(256 + 1);
+ //NetTunnelLib.TunnelSDKInitEnv();
+ var v = NetTunnelLib.FindWireguardExe(buffer, 256);
+ MessageBox.Show(buffer.ToString() + "----" + v.ToString());
+ }
+
+ private void button2_Click(object sender, EventArgs e)
+ {
+ var buffer = new StringBuilder(64 + 1);
+ var buffer2 = new StringBuilder(64 + 1);
+ //var v = NetTunnelLib.RunPipeCmd("cmd.exe /C dir E:\\", buffer, 4096);
+ //MessageBox.Show(buffer.ToString() + "\nResult: " + v.ToString());
+
+ var v = NetTunnelLib.GenerateWireguardKeyPairs(buffer, 64, buffer2, 64);
+ lstLogs.Items.Add(v.ToString() + ": [" + buffer.ToString() + "] / [" + buffer2.ToString() + "]");
+
+ IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NetCard)) * 32);
+ int size = 0;
+
+ v = NetTunnelLib.GetAllNICInfo(pt, ref size);
+
+ Console.WriteLine("Result {0}, total {1}", v, size);
+
+ for (int i = 0; i < size; i++)
+ {
+ IntPtr ptr = new IntPtr(pt.ToInt64() + Marshal.SizeOf(typeof(NetCard)) * i);
+ NetCard card = (NetCard)Marshal.PtrToStructure(ptr, typeof(NetCard));
+
+ Console.WriteLine("Name:{0}", card.Name);
+ Console.WriteLine("Description:{0}", card.Description);
+ Console.WriteLine("Ip:{0}", card.IpAddr);
+ Console.WriteLine("NetMask:{0}", card.NetMask);
+ Console.WriteLine("MacAddr:{0}", card.MacAddr);
+ }
+
+ Marshal.FreeHGlobal(pt);
+ }
+}
\ No newline at end of file
diff --git a/NetTunnelApp/NetTunnelApp.csproj b/NetTunnelApp/NetTunnelApp.csproj
index 308486f..46eb533 100644
--- a/NetTunnelApp/NetTunnelApp.csproj
+++ b/NetTunnelApp/NetTunnelApp.csproj
@@ -24,6 +24,7 @@
prompt
4
false
+ true
AnyCPU
@@ -33,6 +34,7 @@
TRACE
prompt
4
+ true
LocalIntranet
@@ -43,8 +45,14 @@
Properties\app.manifest
+
+ OnOutputUpdated
+
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
+
@@ -78,6 +86,7 @@
True
Resources.resx
+
SettingsSingleFileGenerator
@@ -94,6 +103,11 @@
- copy /y $(SolutionDir)x64\$(ConfigurationName)\*.dll $(TargetDir)
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NetTunnelApp/NetTunnelLib.cs b/NetTunnelApp/NetTunnelLib.cs
index 6728833..aa1341c 100644
--- a/NetTunnelApp/NetTunnelLib.cs
+++ b/NetTunnelApp/NetTunnelLib.cs
@@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
+using System.Text;
namespace NetTunnelApp;
@@ -14,10 +15,31 @@ public enum ProtoCryptoType
public enum LogLevel
{
- LOG_DEBUG = 0,
- LOG_INFO = 1,
- LOG_WARN = 2,
- LOG_ERROR = 3
+ LOG_TRACE = 0,
+ LOG_DEBUG,
+ LOG_INFO,
+ LOG_WARN,
+ LOG_ERROR,
+ LOG_CRITICAL
+}
+
+[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+public struct NetCard
+{
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
+ public string Name;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
+ public string Description;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
+ public string IpAddr;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
+ public string NetMask;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
+ public string MacAddr;
}
public class NetTunnelLib
@@ -32,11 +54,30 @@ public class NetTunnelLib
internal static extern Int32 Add(int a, int b);
[DllImport("NetTunnelSDK.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern int TunnelSDKInitEnv();
+ public static extern int TunnelSDKInitEnv(String workDir);
+
+ [DllImport("NetTunnelSDK.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void TunnelSDKUnInit();
[DllImport("NetTunnelSDK.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int SetProtocolEncryptType(ProtoCryptoType type, String pProKey);
[DllImport("NetTunnelSDK.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void InitTunnelSDKLog(String pProKey, LogLevel level);
+
+ [DllImport("NetTunnelSDK.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int FindWireguardExe(StringBuilder lpString, int maxSize);
+
+ [DllImport("NetTunnelSDK.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int SetWireguardPath(String path);
+
+ [DllImport("NetTunnelSDK.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int GenerateWireguardKeyPairs(StringBuilder wgPubKey, int maxPubKey, StringBuilder wgPrivKey,
+ int MaxPrivKey);
+
+ [DllImport("NetTunnelSDK.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int GetAllNICInfo(IntPtr netCard, ref int size);
+
+ //[DllImport("NetTunnelSDK.dll", CallingConvention = CallingConvention.Cdecl)]
+ //public static extern int RunPipeCmd(String pszCmd, StringBuilder pszResultBuffer, int dwResultBufferSize);
}
\ No newline at end of file
diff --git a/NetTunnelApp/packages.config b/NetTunnelApp/packages.config
new file mode 100644
index 0000000..ffb547c
--- /dev/null
+++ b/NetTunnelApp/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/NetTunnelSDK/NetTunnelSDK.vcxproj b/NetTunnelSDK/NetTunnelSDK.vcxproj
index ba88b08..bfffee4 100644
--- a/NetTunnelSDK/NetTunnelSDK.vcxproj
+++ b/NetTunnelSDK/NetTunnelSDK.vcxproj
@@ -120,6 +120,12 @@
true
false
+
+ copy /y $(TargetDir)*.dll $(SolutionDir)\NetTunnelApp\bin\$(ConfigurationName)\
+
+
+
+
@@ -142,8 +148,7 @@
-
-
+
@@ -151,9 +156,8 @@
-
- NotUsing
-
+
+
Create
Create
@@ -167,7 +171,7 @@
NotUsing
- NotUsing
+ Use
diff --git a/NetTunnelSDK/NetTunnelSDK.vcxproj.filters b/NetTunnelSDK/NetTunnelSDK.vcxproj.filters
index c7c2332..f2bd655 100644
--- a/NetTunnelSDK/NetTunnelSDK.vcxproj.filters
+++ b/NetTunnelSDK/NetTunnelSDK.vcxproj.filters
@@ -30,10 +30,7 @@
头文件
-
- 头文件
-
-
+
头文件
@@ -50,10 +47,13 @@
源文件
-
+
源文件
-
+
+ 源文件
+
+
源文件
diff --git a/NetTunnelSDK/dllmain.cpp b/NetTunnelSDK/dllmain.cpp
index 606b0fe..3c50790 100644
--- a/NetTunnelSDK/dllmain.cpp
+++ b/NetTunnelSDK/dllmain.cpp
@@ -1,11 +1,11 @@
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
-#include "logs/fmtlog.h"
+#include "tunnel.h"
-BOOL APIENTRY DllMain( HMODULE hModule,
- DWORD ul_reason_for_call,
- LPVOID lpReserved
- )
+BOOL APIENTRY DllMain(HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+)
{
switch (ul_reason_for_call)
{
@@ -13,9 +13,8 @@ BOOL APIENTRY DllMain( HMODULE hModule,
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
- fmtlog::poll();
+ TunnelSDKUnInit();
break;
}
return TRUE;
}
-
diff --git a/NetTunnelSDK/globalcfg.h b/NetTunnelSDK/globalcfg.h
new file mode 100644
index 0000000..c30a4bb
--- /dev/null
+++ b/NetTunnelSDK/globalcfg.h
@@ -0,0 +1,21 @@
+#pragma once
+#include
+
+typedef struct
+{
+ TCHAR wireguardPath[MAX_PATH];
+ BOOL wireguardExists;
+ TCHAR wgPath[MAX_PATH];
+ BOOL wgExists;
+} WIREGUARD_CFG, *PWIREGUARD_CFG;
+
+typedef struct
+{
+ TCHAR workDirectory[MAX_PATH];
+ PROTO_CRYPTO_TYPE proCryptoType;
+ TCHAR proKeyBuf[CRYPTO_MAX][256];
+ spdlog::level::level_enum logLevel;
+ WIREGUARD_CFG wireguardCfg;
+} SDK_CONFIG, *PSDK_CONFIG;
+
+PSDK_CONFIG GetGlobalCfgInfo();
diff --git a/NetTunnelSDK/logs/fmtlog-inl.h b/NetTunnelSDK/logs/fmtlog-inl.h
deleted file mode 100644
index ad8b1bf..0000000
--- a/NetTunnelSDK/logs/fmtlog-inl.h
+++ /dev/null
@@ -1,636 +0,0 @@
-/*
-MIT License
-
-Copyright (c) 2021 Meng Rao
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-#pragma warning( disable : 4996)
-#include "fmtlog.h"
-#include
-#include
-#include
-#include
-
-#ifdef _WIN32
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-#include
-#include
-#else
-#include
-#include
-#endif
-
-namespace {
-void fmtlogEmptyFun(void*) {
-}
-} // namespace
-
-template
-class fmtlogDetailT
-{
-public:
- // https://github.com/MengRao/str
- template
- class Str
- {
- public:
- static const int Size = SIZE;
- char s[SIZE];
-
- Str() {}
- Str(const char* p) { *this = *(const Str*)p; }
-
- char& operator[](int i) { return s[i]; }
- char operator[](int i) const { return s[i]; }
-
- template
- void fromi(T num) {
- if constexpr (Size & 1) {
- s[Size - 1] = '0' + (num % 10);
- num /= 10;
- }
- switch (Size & -2) {
- case 18: *(uint16_t*)(s + 16) = *(uint16_t*)(digit_pairs + ((num % 100) << 1)); num /= 100;
- case 16: *(uint16_t*)(s + 14) = *(uint16_t*)(digit_pairs + ((num % 100) << 1)); num /= 100;
- case 14: *(uint16_t*)(s + 12) = *(uint16_t*)(digit_pairs + ((num % 100) << 1)); num /= 100;
- case 12: *(uint16_t*)(s + 10) = *(uint16_t*)(digit_pairs + ((num % 100) << 1)); num /= 100;
- case 10: *(uint16_t*)(s + 8) = *(uint16_t*)(digit_pairs + ((num % 100) << 1)); num /= 100;
- case 8: *(uint16_t*)(s + 6) = *(uint16_t*)(digit_pairs + ((num % 100) << 1)); num /= 100;
- case 6: *(uint16_t*)(s + 4) = *(uint16_t*)(digit_pairs + ((num % 100) << 1)); num /= 100;
- case 4: *(uint16_t*)(s + 2) = *(uint16_t*)(digit_pairs + ((num % 100) << 1)); num /= 100;
- case 2: *(uint16_t*)(s + 0) = *(uint16_t*)(digit_pairs + ((num % 100) << 1)); num /= 100;
- }
- }
-
- static constexpr const char* digit_pairs = "00010203040506070809"
- "10111213141516171819"
- "20212223242526272829"
- "30313233343536373839"
- "40414243444546474849"
- "50515253545556575859"
- "60616263646566676869"
- "70717273747576777879"
- "80818283848586878889"
- "90919293949596979899";
- };
-
- fmtlogDetailT()
- : flushDelay(3000000000) {
- args.reserve(4096);
- args.resize(parttenArgSize);
-
- fmtlogWrapper<>::impl.init();
- resetDate();
- fmtlog::setLogFile(stdout);
- setHeaderPattern("{HMSf} {s:<16} {l}[{t:<6}] ");
- logInfos.reserve(32);
- bgLogInfos.reserve(128);
- bgLogInfos.emplace_back(nullptr, nullptr, fmtlog::DBG, fmt::string_view());
- bgLogInfos.emplace_back(nullptr, nullptr, fmtlog::INF, fmt::string_view());
- bgLogInfos.emplace_back(nullptr, nullptr, fmtlog::WRN, fmt::string_view());
- bgLogInfos.emplace_back(nullptr, nullptr, fmtlog::ERR, fmt::string_view());
- threadBuffers.reserve(8);
- bgThreadBuffers.reserve(8);
- memset(membuf.data(), 0, membuf.capacity());
- }
-
- ~fmtlogDetailT() {
- stopPollingThread();
- poll(true);
- closeLogFile();
- }
-
- void setHeaderPattern(const char* pattern) {
- if (shouldDeallocateHeader) delete[] headerPattern.data();
- using namespace fmt::literals;
- for (int i = 0; i < parttenArgSize; i++) {
- reorderIdx[i] = parttenArgSize - 1;
- }
- headerPattern = fmtlog::unNameFormat(
- pattern, reorderIdx, "a"_a = "", "b"_a = "", "C"_a = "", "Y"_a = "", "m"_a = "", "d"_a = "",
- "t"_a = "thread name", "F"_a = "", "f"_a = "", "e"_a = "", "S"_a = "", "M"_a = "", "H"_a = "",
- "l"_a = fmtlog::LogLevel(), "s"_a = "fmtlog.cc:123", "g"_a = "/home/raomeng/fmtlog/fmtlog.cc:123", "Ymd"_a = "",
- "HMS"_a = "", "HMSe"_a = "", "HMSf"_a = "", "HMSF"_a = "", "YmdHMS"_a = "", "YmdHMSe"_a = "", "YmdHMSf"_a = "",
- "YmdHMSF"_a = "");
- shouldDeallocateHeader = headerPattern.data() != pattern;
-
- setArg<0>(fmt::string_view(weekdayName.s, 3));
- setArg<1>(fmt::string_view(monthName.s, 3));
- setArg<2>(fmt::string_view(&year[2], 2));
- setArg<3>(fmt::string_view(year.s, 4));
- setArg<4>(fmt::string_view(month.s, 2));
- setArg<5>(fmt::string_view(day.s, 2));
- setArg<6>(fmt::string_view());
- setArg<7>(fmt::string_view(nanosecond.s, 9));
- setArg<8>(fmt::string_view(nanosecond.s, 6));
- setArg<9>(fmt::string_view(nanosecond.s, 3));
- setArg<10>(fmt::string_view(second.s, 2));
- setArg<11>(fmt::string_view(minute.s, 2));
- setArg<12>(fmt::string_view(hour.s, 2));
- setArg<13>(fmt::string_view(logLevel.s, 3));
- setArg<14>(fmt::string_view());
- setArg<15>(fmt::string_view());
- setArg<16>(fmt::string_view(year.s, 10)); // Ymd
- setArg<17>(fmt::string_view(hour.s, 8)); // HMS
- setArg<18>(fmt::string_view(hour.s, 12)); // HMSe
- setArg<19>(fmt::string_view(hour.s, 15)); // HMSf
- setArg<20>(fmt::string_view(hour.s, 18)); // HMSF
- setArg<21>(fmt::string_view(year.s, 19)); // YmdHMS
- setArg<22>(fmt::string_view(year.s, 23)); // YmdHMSe
- setArg<23>(fmt::string_view(year.s, 26)); // YmdHMSf
- setArg<24>(fmt::string_view(year.s, 29)); // YmdHMSF
- }
-
- class ThreadBufferDestroyer
- {
- public:
- explicit ThreadBufferDestroyer() {}
-
- void threadBufferCreated() {}
-
- ~ThreadBufferDestroyer() {
- if (fmtlog::threadBuffer != nullptr) {
- fmtlog::threadBuffer->shouldDeallocate = true;
- fmtlog::threadBuffer = nullptr;
- }
- }
- };
-
- struct StaticLogInfo
- {
- // Constructor
- constexpr StaticLogInfo(fmtlog::FormatToFn fn, const char* loc, fmtlog::LogLevel level, fmt::string_view fmtString)
- : formatToFn(fn)
- , formatString(fmtString)
- , location(loc)
- , logLevel(level)
- , argIdx(-1) {}
-
- void processLocation() {
- size_t size = strlen(location);
- const char* p = location + size;
- if (size > 255) {
- location = p - 255;
- }
- endPos = p - location;
- const char* base = location;
- while (p > location) {
- char c = *--p;
- if (c == '/' || c == '\\') {
- base = p + 1;
- break;
- }
- }
- basePos = base - location;
- }
-
- inline fmt::string_view getBase() { return fmt::string_view(location + basePos, endPos - basePos); }
-
- inline fmt::string_view getLocation() { return fmt::string_view(location, endPos); }
-
- fmtlog::FormatToFn formatToFn;
- fmt::string_view formatString;
- const char* location;
- uint8_t basePos;
- uint8_t endPos;
- fmtlog::LogLevel logLevel;
- int argIdx;
- };
-
- static thread_local ThreadBufferDestroyer sbc;
- int64_t midnightNs;
- fmt::string_view headerPattern;
- bool shouldDeallocateHeader = false;
- FILE* outputFp = nullptr;
- bool manageFp = false;
- size_t fpos = 0; // file position of membuf, used only when manageFp == true
- int64_t flushDelay;
- int64_t nextFlushTime = (std::numeric_limits::max)();
- uint32_t flushBufSize = 8 * 1024;
- fmtlog::LogLevel flushLogLevel = fmtlog::OFF;
- std::mutex bufferMutex;
- std::vector threadBuffers;
- struct HeapNode
- {
- HeapNode(fmtlog::ThreadBuffer* buffer)
- : tb(buffer) {}
-
- fmtlog::ThreadBuffer* tb;
- const fmtlog::SPSCVarQueueOPT::MsgHeader* header = nullptr;
- };
- std::vector bgThreadBuffers;
- std::mutex logInfoMutex;
- std::vector logInfos;
- std::vector bgLogInfos;
-
- fmtlog::LogCBFn logCB = nullptr;
- fmtlog::LogLevel minCBLogLevel;
- fmtlog::LogQFullCBFn logQFullCB = fmtlogEmptyFun;
- void* logQFullCBArg = nullptr;
-
- fmtlog::MemoryBuffer membuf;
-
- const static int parttenArgSize = 25;
- uint32_t reorderIdx[parttenArgSize];
- Str<3> weekdayName;
- Str<3> monthName;
- Str<4> year;
- char dash1 = '-';
- Str<2> month;
- char dash2 = '-';
- Str<2> day;
- char space = ' ';
- Str<2> hour;
- char colon1 = ':';
- Str<2> minute;
- char colon2 = ':';
- Str<2> second;
- char dot1 = '.';
- Str<9> nanosecond;
- Str<3> logLevel;
- std::vector> args;
-
- volatile bool threadRunning = false;
- std::thread thr;
-
- void resetDate() {
- time_t rawtime = fmtlogWrapper<>::impl.tscns.rdns() / 1000000000;
- struct tm* timeinfo = localtime(&rawtime);
- timeinfo->tm_sec = timeinfo->tm_min = timeinfo->tm_hour = 0;
- midnightNs = mktime(timeinfo) * 1000000000;
- year.fromi(1900 + timeinfo->tm_year);
- month.fromi(1 + timeinfo->tm_mon);
- day.fromi(timeinfo->tm_mday);
- const char* weekdays[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
- weekdayName = weekdays[timeinfo->tm_wday];
- const char* monthNames[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
- monthName = monthNames[timeinfo->tm_mon];
- }
-
- void preallocate() {
- if (fmtlog::threadBuffer) return;
- fmtlog::threadBuffer = new fmtlog::ThreadBuffer();
-#ifdef _WIN32
- uint32_t tid = static_cast(::GetCurrentThreadId());
-#else
- uint32_t tid = static_cast(::syscall(SYS_gettid));
-#endif
- fmtlog::threadBuffer->nameSize =
- fmt::format_to_n(fmtlog::threadBuffer->name, sizeof(fmtlog::threadBuffer->name), "{}", tid).size;
- sbc.threadBufferCreated();
-
- std::unique_lock guard(bufferMutex);
- threadBuffers.push_back(fmtlog::threadBuffer);
- }
-
- template
- inline void setArg(const T& arg) {
- args[reorderIdx[I]] = fmt::detail::make_arg(arg);
- }
-
- template
- inline void setArgVal(const T& arg) {
- fmt::detail::value& value_ = *(fmt::detail::value*)&args[reorderIdx[I]];
- value_ = fmt::detail::arg_mapper().map(arg);
- }
-
- void flushLogFile() {
- if (outputFp) {
- fwrite(membuf.data(), 1, membuf.size(), outputFp);
- if (!manageFp) fflush(outputFp);
- else
- fpos += membuf.size();
- }
- membuf.clear();
- nextFlushTime = (std::numeric_limits::max)();
- }
-
- void closeLogFile() {
- if (membuf.size()) flushLogFile();
- if (manageFp) fclose(outputFp);
- outputFp = nullptr;
- manageFp = false;
- }
-
- void startPollingThread(int64_t pollInterval) {
- stopPollingThread();
- threadRunning = true;
- thr = std::thread([pollInterval, this]() {
- while (threadRunning) {
- int64_t before = fmtlogWrapper<>::impl.tscns.rdns();
- poll(false);
- int64_t delay = fmtlogWrapper<>::impl.tscns.rdns() - before;
- if (delay < pollInterval) {
- std::this_thread::sleep_for(std::chrono::nanoseconds(pollInterval - delay));
- }
- }
- poll(true);
- });
- }
-
- void stopPollingThread() {
- if (!threadRunning) return;
- threadRunning = false;
- if (thr.joinable()) thr.join();
- }
-
- void handleLog(fmt::string_view threadName, const fmtlog::SPSCVarQueueOPT::MsgHeader* header) {
- setArgVal<6>(threadName);
- StaticLogInfo& info = bgLogInfos[header->logId];
- const char* data = (const char*)(header + 1);
- const char* end = (const char*)header + header->size;
- int64_t tsc = *(int64_t*)data;
- data += 8;
- if (!info.formatToFn) { // log once
- info.location = *(const char**)data;
- data += 8;
- info.processLocation();
- }
- int64_t ts = fmtlogWrapper<>::impl.tscns.tsc2ns(tsc);
- // the date could go back when polling different threads
- uint64_t t = (ts > midnightNs) ? (ts - midnightNs) : 0;
- nanosecond.fromi(t % 1000000000);
- t /= 1000000000;
- second.fromi(t % 60);
- t /= 60;
- minute.fromi(t % 60);
- t /= 60;
- uint32_t h = t; // hour
- if (h > 23) {
- h %= 24;
- resetDate();
- }
- hour.fromi(h);
- setArgVal<14>(info.getBase());
- setArgVal<15>(info.getLocation());
- logLevel = (const char*)"DBG INF WRN ERR OFF" + (info.logLevel << 2);
-
- size_t headerPos = membuf.size();
- fmtlog::vformat_to(membuf, headerPattern, fmt::basic_format_args(args.data(), parttenArgSize));
- size_t bodyPos = membuf.size();
-
- if (info.formatToFn) {
- info.formatToFn(info.formatString, data, membuf, info.argIdx, args);
- }
- else { // log once
- membuf.append(fmt::string_view(data, end - data));
- }
-
- if (logCB && info.logLevel >= minCBLogLevel) {
- logCB(ts, info.logLevel, info.getLocation(), info.basePos, threadName,
- fmt::string_view(membuf.data() + headerPos, membuf.size() - headerPos), bodyPos - headerPos,
- fpos + headerPos);
- }
- membuf.push_back('\n');
- if (membuf.size() >= flushBufSize || info.logLevel >= flushLogLevel) {
- flushLogFile();
- }
- }
-
- void adjustHeap(size_t i) {
- while (true) {
- size_t min_i = i;
- for (size_t ch = i * 2 + 1, end = std::min(ch + 2, bgThreadBuffers.size()); ch < end; ch++) {
- auto h_ch = bgThreadBuffers[ch].header;
- auto h_min = bgThreadBuffers[min_i].header;
- if (h_ch && (!h_min || *(int64_t*)(h_ch + 1) < *(int64_t*)(h_min + 1))) min_i = ch;
- }
- if (min_i == i) break;
- std::swap(bgThreadBuffers[i], bgThreadBuffers[min_i]);
- i = min_i;
- }
- }
-
- void poll(bool forceFlush) {
- fmtlogWrapper<>::impl.tscns.calibrate();
- int64_t tsc = fmtlogWrapper<>::impl.tscns.rdtsc();
- if (logInfos.size()) {
- std::unique_lock lock(logInfoMutex);
- for (auto& info : logInfos) {
- info.processLocation();
- }
- bgLogInfos.insert(bgLogInfos.end(), logInfos.begin(), logInfos.end());
- logInfos.clear();
- }
- if (threadBuffers.size()) {
- std::unique_lock lock(bufferMutex);
- for (auto tb : threadBuffers) {
- bgThreadBuffers.emplace_back(tb);
- }
- threadBuffers.clear();
- }
-
- for (size_t i = 0; i < bgThreadBuffers.size(); i++) {
- auto& node = bgThreadBuffers[i];
- if (node.header) continue;
- node.header = node.tb->varq.front();
- if (!node.header && node.tb->shouldDeallocate) {
- delete node.tb;
- node = bgThreadBuffers.back();
- bgThreadBuffers.pop_back();
- i--;
- }
- }
-
- if (bgThreadBuffers.empty()) return;
-
- // build heap
- for (int i = bgThreadBuffers.size() / 2; i >= 0; i--) {
- adjustHeap(i);
- }
-
- while (true) {
- auto h = bgThreadBuffers[0].header;
- if (!h || h->logId >= bgLogInfos.size() || *(int64_t*)(h + 1) >= tsc) break;
- auto tb = bgThreadBuffers[0].tb;
- handleLog(fmt::string_view(tb->name, tb->nameSize), h);
- tb->varq.pop();
- bgThreadBuffers[0].header = tb->varq.front();
- adjustHeap(0);
- }
-
- if (membuf.size() == 0) return;
- if (!manageFp || forceFlush) {
- flushLogFile();
- return;
- }
- int64_t now = fmtlogWrapper<>::impl.tscns.tsc2ns(tsc);
- if (now > nextFlushTime) {
- flushLogFile();
- }
- else if (nextFlushTime == (std::numeric_limits::max)()) {
- nextFlushTime = now + flushDelay;
- }
- }
-};
-
-template
-thread_local typename fmtlogDetailT<_>::ThreadBufferDestroyer fmtlogDetailT<_>::sbc;
-
-template
-struct fmtlogDetailWrapper
-{ static fmtlogDetailT<> impl; };
-
-template
-fmtlogDetailT<> fmtlogDetailWrapper<_>::impl;
-
-template
-void fmtlogT<_>::registerLogInfo(uint32_t& logId, FormatToFn fn, const char* location,
- LogLevel level, fmt::string_view fmtString) noexcept {
- auto& d = fmtlogDetailWrapper<>::impl;
- std::lock_guard lock(d.logInfoMutex);
- if (logId) return;
- logId = d.logInfos.size() + d.bgLogInfos.size();
- d.logInfos.emplace_back(fn, location, level, fmtString);
-}
-
-template
-void fmtlogT<_>::vformat_to(fmtlog::MemoryBuffer& out, fmt::string_view fmt,
- fmt::format_args args) {
- fmt::detail::vformat_to(out, fmt, args);
-}
-
-template
-size_t fmtlogT<_>::formatted_size(fmt::string_view fmt, fmt::format_args args) {
- auto buf = fmt::detail::counting_buffer<>();
- fmt::detail::vformat_to(buf, fmt, args);
- return buf.count();
-}
-
-template
-void fmtlogT<_>::vformat_to(char* out, fmt::string_view fmt, fmt::format_args args) {
- fmt::vformat_to(out, fmt, args);
-}
-
-template
-typename fmtlogT<_>::SPSCVarQueueOPT::MsgHeader* fmtlogT<_>::allocMsg(uint32_t size,
- bool q_full_cb) noexcept {
- auto& d = fmtlogDetailWrapper<>::impl;
- if (threadBuffer == nullptr) preallocate();
- auto ret = threadBuffer->varq.alloc(size);
- if ((ret == nullptr) & q_full_cb) d.logQFullCB(d.logQFullCBArg);
- return ret;
-}
-
-template
-typename fmtlogT<_>::SPSCVarQueueOPT::MsgHeader*
-fmtlogT<_>::SPSCVarQueueOPT::allocMsg(uint32_t size) noexcept {
- return alloc(size);
-}
-
-template
-void fmtlogT<_>::preallocate() noexcept {
- fmtlogDetailWrapper<>::impl.preallocate();
-}
-
-template
-void fmtlogT<_>::setLogFile(const char* filename, bool truncate) {
- auto& d = fmtlogDetailWrapper<>::impl;
- FILE* newFp = fopen(filename, truncate ? "w" : "a");
- if (!newFp) {
- std::string err = fmt::format("Unable to open file: {}: {}", filename, strerror(errno));
- fmt::detail::throw_format_error(err.c_str());
- }
- setbuf(newFp, nullptr);
- d.fpos = ftell(newFp);
-
- closeLogFile();
- d.outputFp = newFp;
- d.manageFp = true;
-}
-
-template
-void fmtlogT<_>::setLogFile(FILE* fp, bool manageFp) {
- auto& d = fmtlogDetailWrapper<>::impl;
- closeLogFile();
- if (manageFp) {
- setbuf(fp, nullptr);
- d.fpos = ftell(fp);
- }
- else
- d.fpos = 0;
- d.outputFp = fp;
- d.manageFp = manageFp;
-}
-
-template
-void fmtlogT<_>::setFlushDelay(int64_t ns) noexcept {
- fmtlogDetailWrapper<>::impl.flushDelay = ns;
-}
-
-template
-void fmtlogT<_>::flushOn(LogLevel flushLogLevel) noexcept {
- fmtlogDetailWrapper<>::impl.flushLogLevel = flushLogLevel;
-}
-
-template
-void fmtlogT<_>::setFlushBufSize(uint32_t bytes) noexcept {
- fmtlogDetailWrapper<>::impl.flushBufSize = bytes;
-}
-
-template
-void fmtlogT<_>::closeLogFile() noexcept {
- fmtlogDetailWrapper<>::impl.closeLogFile();
-}
-
-template
-void fmtlogT<_>::poll(bool forceFlush) {
- fmtlogDetailWrapper<>::impl.poll(forceFlush);
-}
-
-template
-void fmtlogT<_>::setThreadName(const char* name) noexcept {
- preallocate();
- threadBuffer->nameSize = fmt::format_to_n(threadBuffer->name, sizeof(fmtlog::threadBuffer->name), "{}", name).size;
-}
-
-template
-void fmtlogT<_>::setLogCB(LogCBFn cb, LogLevel minCBLogLevel_) noexcept {
- auto& d = fmtlogDetailWrapper<>::impl;
- d.logCB = cb;
- d.minCBLogLevel = minCBLogLevel_;
-}
-
-template
-void fmtlogT<_>::setLogQFullCB(LogQFullCBFn cb, void* userData) noexcept {
- auto& d = fmtlogDetailWrapper<>::impl;
- d.logQFullCB = cb;
- d.logQFullCBArg = userData;
-}
-
-template
-void fmtlogT<_>::setHeaderPattern(const char* pattern) {
- fmtlogDetailWrapper<>::impl.setHeaderPattern(pattern);
-}
-
-template
-void fmtlogT<_>::startPollingThread(int64_t pollInterval) noexcept {
- fmtlogDetailWrapper<>::impl.startPollingThread(pollInterval);
-}
-
-template
-void fmtlogT<_>::stopPollingThread() noexcept {
- fmtlogDetailWrapper<>::impl.stopPollingThread();
-}
-
-template class fmtlogT<0>;
-
diff --git a/NetTunnelSDK/logs/fmtlog.cc b/NetTunnelSDK/logs/fmtlog.cc
deleted file mode 100644
index da6c2ce..0000000
--- a/NetTunnelSDK/logs/fmtlog.cc
+++ /dev/null
@@ -1 +0,0 @@
-#include "fmtlog-inl.h"
diff --git a/NetTunnelSDK/logs/fmtlog.h b/NetTunnelSDK/logs/fmtlog.h
deleted file mode 100644
index a572086..0000000
--- a/NetTunnelSDK/logs/fmtlog.h
+++ /dev/null
@@ -1,826 +0,0 @@
-/*
-MIT License
-
-Copyright (c) 2021 Meng Rao
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-#pragma once
-//#define FMT_HEADER_ONLY
-#include "fmt/format.h"
-#include
-#include
-#include
-#include
-#include
-#include
-
-#ifdef _MSC_VER
-#include
-#endif
-
-#ifdef _WIN32
-#define FAST_THREAD_LOCAL thread_local
-#else
-#define FAST_THREAD_LOCAL __thread
-#endif
-
-// define FMTLOG_BLOCK=1 if log statment should be blocked when queue is full, instead of discarding the msg
-#ifndef FMTLOG_BLOCK
-#define FMTLOG_BLOCK 0
-#endif
-
-#define FMTLOG_LEVEL_DBG 0
-#define FMTLOG_LEVEL_INF 1
-#define FMTLOG_LEVEL_WRN 2
-#define FMTLOG_LEVEL_ERR 3
-#define FMTLOG_LEVEL_OFF 4
-
-// define FMTLOG_ACTIVE_LEVEL to turn off low log level in compile time
-#ifndef FMTLOG_ACTIVE_LEVEL
-#define FMTLOG_ACTIVE_LEVEL FMTLOG_LEVEL_DBG
-#endif
-
-#ifndef FMTLOG_QUEUE_SIZE
-#define FMTLOG_QUEUE_SIZE (1 << 20)
-#endif
-
-namespace fmtlogdetail {
-template
-struct UnrefPtr : std::false_type
-{ using type = Arg; };
-
-template<>
-struct UnrefPtr : std::false_type
-{ using type = char*; };
-
-template<>
-struct UnrefPtr : std::false_type
-{ using type = void*; };
-
-template
-struct UnrefPtr> : std::true_type
-{ using type = Arg; };
-
-template
-struct UnrefPtr> : std::true_type
-{ using type = Arg; };
-
-template
-struct UnrefPtr : std::true_type
-{ using type = Arg; };
-
-}; // namespace fmtlogdetail
-
-template
-class fmtlogT
-{
-public:
- enum LogLevel : uint8_t
- {
- DBG = 0,
- INF,
- WRN,
- ERR,
- OFF
- };
-
- // Preallocate thread queue for current thread
- static void preallocate() noexcept;
-
- // Set the file for logging
- static void setLogFile(const char* filename, bool truncate = false);
-
- // Set an existing FILE* for logging, if manageFp is false fmtlog will not buffer log internally
- // and will not close the FILE*
- static void setLogFile(FILE* fp, bool manageFp = false);
-
- // Collect log msgs from all threads and write to log file
- // If forceFlush = true, internal file buffer is flushed
- // User need to call poll() repeatedly if startPollingThread is not used
- static void poll(bool forceFlush = false);
-
- // Set flush delay in nanosecond
- // If there's msg older than ns in the buffer, flush will be triggered
- static void setFlushDelay(int64_t ns) noexcept;
-
- // If current msg has level >= flushLogLevel, flush will be triggered
- static void flushOn(LogLevel flushLogLevel) noexcept;
-
- // If file buffer has more than specified bytes, flush will be triggered
- static void setFlushBufSize(uint32_t bytes) noexcept;
-
- // callback signature user can register
- // ns: nanosecond timestamp
- // level: logLevel
- // location: full file path with line num, e.g: /home/raomeng/fmtlog/fmtlog.h:45
- // basePos: file base index in the location
- // threadName: thread id or the name user set with setThreadName
- // msg: full log msg with header
- // bodyPos: log body index in the msg
- // logFilePos: log file position of this msg
- typedef void (*LogCBFn)(int64_t ns, LogLevel level, fmt::string_view location, size_t basePos,
- fmt::string_view threadName, fmt::string_view msg, size_t bodyPos,
- size_t logFilePos);
-
- // Set a callback function for all log msgs with a mininum log level
- static void setLogCB(LogCBFn cb, LogLevel minCBLogLevel) noexcept;
-
- typedef void (*LogQFullCBFn)(void* userData);
- static void setLogQFullCB(LogQFullCBFn cb, void* userData) noexcept;
-
- // Close the log file and subsequent msgs will not be written into the file,
- // but callback function can still be used
- static void closeLogFile() noexcept;
-
- // Set log header pattern with fmt named arguments
- static void setHeaderPattern(const char* pattern);
-
- // Set a name for current thread, it'll be shown in {t} part in header pattern
- static void setThreadName(const char* name) noexcept;
-
- // Set current log level, lower level log msgs will be discarded
- static inline void setLogLevel(LogLevel logLevel) noexcept;
-
- // Get current log level
- static inline LogLevel getLogLevel() noexcept;
-
- // return true if passed log level is not lower than current log level
- static inline bool checkLogLevel(LogLevel logLevel) noexcept;
-
- // Run a polling thread in the background with a polling interval in ns
- // Note that user must not call poll() himself when the thread is running
- static void startPollingThread(int64_t pollInterval = 1000000000) noexcept;
-
- // Stop the polling thread
- static void stopPollingThread() noexcept;
-
- // https://github.com/MengRao/SPSC_Queue
- class SPSCVarQueueOPT
- {
- public:
- struct MsgHeader
- {
- inline void push(uint32_t sz) { *(volatile uint32_t*)&size = sz + sizeof(MsgHeader); }
-
- uint32_t size;
- uint32_t logId;
- };
- static constexpr uint32_t BLK_CNT = FMTLOG_QUEUE_SIZE / sizeof(MsgHeader);
-
- MsgHeader* allocMsg(uint32_t size) noexcept;
-
- MsgHeader* alloc(uint32_t size) {
- size += sizeof(MsgHeader);
- uint32_t blk_sz = (size + sizeof(MsgHeader) - 1) / sizeof(MsgHeader);
- if (blk_sz >= free_write_cnt) {
- uint32_t read_idx_cache = *(volatile uint32_t*)&read_idx;
- if (read_idx_cache <= write_idx) {
- free_write_cnt = BLK_CNT - write_idx;
- if (blk_sz >= free_write_cnt && read_idx_cache != 0) { // wrap around
- blk[0].size = 0;
- blk[write_idx].size = 1;
- write_idx = 0;
- free_write_cnt = read_idx_cache;
- }
- }
- else {
- free_write_cnt = read_idx_cache - write_idx;
- }
- if (free_write_cnt <= blk_sz) {
- return nullptr;
- }
- }
- MsgHeader* ret = &blk[write_idx];
- write_idx += blk_sz;
- free_write_cnt -= blk_sz;
- blk[write_idx].size = 0;
- return ret;
- }
-
- inline const MsgHeader* front() {
- uint32_t size = blk[read_idx].size;
- if (size == 1) { // wrap around
- read_idx = 0;
- size = blk[0].size;
- }
- if (size == 0) return nullptr;
- return &blk[read_idx];
- }
-
- inline void pop() {
- uint32_t blk_sz = (blk[read_idx].size + sizeof(MsgHeader) - 1) / sizeof(MsgHeader);
- *(volatile uint32_t*)&read_idx = read_idx + blk_sz;
- }
-
- private:
- alignas(64) MsgHeader blk[BLK_CNT] = {};
- uint32_t write_idx = 0;
- uint32_t free_write_cnt = BLK_CNT;
-
- alignas(128) uint32_t read_idx = 0;
- };
-
- struct ThreadBuffer
- {
- SPSCVarQueueOPT varq;
- bool shouldDeallocate = false;
- char name[32];
- size_t nameSize;
- };
-
- // https://github.com/MengRao/tscns
- class TSCNS
- {
- public:
- static const int64_t NsPerSec = 1000000000;
-
- void init(int64_t init_calibrate_ns = 20000000, int64_t calibrate_interval_ns = 3 * NsPerSec) {
- calibate_interval_ns_ = calibrate_interval_ns;
- int64_t base_tsc, base_ns;
- syncTime(base_tsc, base_ns);
- int64_t expire_ns = base_ns + init_calibrate_ns;
- while (rdsysns() < expire_ns) std::this_thread::yield();
- int64_t delayed_tsc, delayed_ns;
- syncTime(delayed_tsc, delayed_ns);
- double init_ns_per_tsc = (double)(delayed_ns - base_ns) / (delayed_tsc - base_tsc);
- saveParam(base_tsc, base_ns, base_ns, init_ns_per_tsc);
- }
-
- void calibrate() {
- if (rdtsc() < next_calibrate_tsc_) return;
- int64_t tsc, ns;
- syncTime(tsc, ns);
- int64_t calulated_ns = tsc2ns(tsc);
- int64_t ns_err = calulated_ns - ns;
- int64_t expected_err_at_next_calibration =
- ns_err + (ns_err - base_ns_err_) * calibate_interval_ns_ / (ns - base_ns_ + base_ns_err_);
- double new_ns_per_tsc =
- ns_per_tsc_ * (1.0 - (double)expected_err_at_next_calibration / calibate_interval_ns_);
- saveParam(tsc, calulated_ns, ns, new_ns_per_tsc);
- }
-
- static inline int64_t rdtsc() {
-#ifdef _MSC_VER
- return __rdtsc();
-#elif defined(__i386__) || defined(__x86_64__) || defined(__amd64__)
- return __builtin_ia32_rdtsc();
-#else
- return rdsysns();
-#endif
- }
-
- inline int64_t tsc2ns(int64_t tsc) const {
- while (true) {
- uint32_t before_seq = param_seq_.load(std::memory_order_acquire) & ~1;
- std::atomic_signal_fence(std::memory_order_acq_rel);
- int64_t ns = base_ns_ + (int64_t)((tsc - base_tsc_) * ns_per_tsc_);
- std::atomic_signal_fence(std::memory_order_acq_rel);
- uint32_t after_seq = param_seq_.load(std::memory_order_acquire);
- if (before_seq == after_seq) return ns;
- }
- }
-
- inline int64_t rdns() const { return tsc2ns(rdtsc()); }
-
- static inline int64_t rdsysns() {
- using namespace std::chrono;
- return duration_cast(system_clock::now().time_since_epoch()).count();
- }
-
- double getTscGhz() const { return 1.0 / ns_per_tsc_; }
-
- // Linux kernel sync time by finding the first trial with tsc diff < 50000
- // We try several times and return the one with the mininum tsc diff.
- // Note that MSVC has a 100ns resolution clock, so we need to combine those ns with the same
- // value, and drop the first and the last value as they may not scan a full 100ns range
- static void syncTime(int64_t& tsc_out, int64_t& ns_out) {
-#ifdef _MSC_VER
- const int N = 15;
-#else
- const int N = 3;
-#endif
- int64_t tsc[N + 1];
- int64_t ns[N + 1];
-
- tsc[0] = rdtsc();
- for (int i = 1; i <= N; i++) {
- ns[i] = rdsysns();
- tsc[i] = rdtsc();
- }
-
-#ifdef _MSC_VER
- int j = 1;
- for (int i = 2; i <= N; i++) {
- if (ns[i] == ns[i - 1]) continue;
- tsc[j - 1] = tsc[i - 1];
- ns[j++] = ns[i];
- }
- j--;
-#else
- int j = N + 1;
-#endif
-
- int best = 1;
- for (int i = 2; i < j; i++) {
- if (tsc[i] - tsc[i - 1] < tsc[best] - tsc[best - 1]) best = i;
- }
- tsc_out = (tsc[best] + tsc[best - 1]) >> 1;
- ns_out = ns[best];
- }
-
- void saveParam(int64_t base_tsc, int64_t base_ns, int64_t sys_ns, double new_ns_per_tsc) {
- base_ns_err_ = base_ns - sys_ns;
- next_calibrate_tsc_ = base_tsc + (int64_t)((calibate_interval_ns_ - 1000) / new_ns_per_tsc);
- uint32_t seq = param_seq_.load(std::memory_order_relaxed);
- param_seq_.store(++seq, std::memory_order_release);
- std::atomic_signal_fence(std::memory_order_acq_rel);
- base_tsc_ = base_tsc;
- base_ns_ = base_ns;
- ns_per_tsc_ = new_ns_per_tsc;
- std::atomic_signal_fence(std::memory_order_acq_rel);
- param_seq_.store(++seq, std::memory_order_release);
- }
-
- alignas(64) std::atomic param_seq_ = 0;
- double ns_per_tsc_;
- int64_t base_tsc_;
- int64_t base_ns_;
- int64_t calibate_interval_ns_;
- int64_t base_ns_err_;
- int64_t next_calibrate_tsc_;
- };
-
- void init() {
- tscns.init();
- currentLogLevel = INF;
- }
-
- using Context = fmt::format_context;
- using MemoryBuffer = fmt::basic_memory_buffer;
- typedef const char* (*FormatToFn)(fmt::string_view format, const char* data, MemoryBuffer& out,
- int& argIdx, std::vector>& args);
-
- static void registerLogInfo(uint32_t& logId, FormatToFn fn, const char* location, LogLevel level,
- fmt::string_view fmtString) noexcept;
-
- static void vformat_to(MemoryBuffer& out, fmt::string_view fmt, fmt::format_args args);
-
- static size_t formatted_size(fmt::string_view fmt, fmt::format_args args);
-
- static void vformat_to(char* out, fmt::string_view fmt, fmt::format_args args);
-
- static typename SPSCVarQueueOPT::MsgHeader* allocMsg(uint32_t size, bool logQFullCB) noexcept;
-
- TSCNS tscns;
-
- volatile LogLevel currentLogLevel;
- static FAST_THREAD_LOCAL ThreadBuffer* threadBuffer;
-
- template
- static inline constexpr bool isNamedArg() {
- return fmt::detail::is_named_arg>::value;
- }
-
- template
- struct unNamedType
- { using type = Arg; };
-
- template
- struct unNamedType>
- { using type = Arg; };
-
-#if FMT_USE_NONTYPE_TEMPLATE_ARGS
- template Str>
- struct unNamedType>
- { using type = Arg; };
-#endif
-
- template
- static inline constexpr bool isCstring() {
- return fmt::detail::mapped_type_constant::value ==
- fmt::detail::type::cstring_type;
- }
-
- template
- static inline constexpr bool isString() {
- return fmt::detail::mapped_type_constant::value == fmt::detail::type::string_type;
- }
-
- template
- static inline constexpr bool needCallDtor() {
- using ArgType = fmt::remove_cvref_t;
- if constexpr (isNamedArg()) {
- return needCallDtor::type>();
- }
- if constexpr (isString()) return false;
- return !std::is_trivially_destructible::value;
- }
-
- template
- static inline constexpr size_t getArgSizes(size_t* cstringSize) {
- return 0;
- }
-
- template
- static inline constexpr size_t getArgSizes(size_t* cstringSize, const Arg& arg,
- const Args&... args) {
- if constexpr (isNamedArg()) {
- return getArgSizes(cstringSize, arg.value, args...);
- }
- else if constexpr (isCstring()) {
- size_t len = strlen(arg) + 1;
- cstringSize[CstringIdx] = len;
- return len + getArgSizes(cstringSize, args...);
- }
- else if constexpr (isString()) {
- size_t len = arg.size() + 1;
- return len + getArgSizes(cstringSize, args...);
- }
- else {
- return sizeof(Arg) + getArgSizes(cstringSize, args...);
- }
- }
-
- template
- static inline constexpr char* encodeArgs(size_t* cstringSize, char* out) {
- return out;
- }
-
- template
- static inline constexpr char* encodeArgs(size_t* cstringSize, char* out, Arg&& arg,
- Args&&... args) {
- if constexpr (isNamedArg()) {
- return encodeArgs(cstringSize, out, arg.value, std::forward(args)...);
- }
- else if constexpr (isCstring()) {
- memcpy(out, arg, cstringSize[CstringIdx]);
- return encodeArgs(cstringSize, out + cstringSize[CstringIdx],
- std::forward(args)...);
- }
- else if constexpr (isString()) {
- size_t len = arg.size();
- memcpy(out, arg.data(), len);
- out[len] = 0;
- return encodeArgs(cstringSize, out + len + 1, std::forward(args)...);
- }
- else {
- // If Arg has alignment >= 16, gcc could emit aligned move instructions(e.g. movdqa) for
- // placement new even if the *out* is misaligned, which would cause segfault. So we use memcpy
- // when possible
- if constexpr (std::is_trivially_copyable_v>) {
- memcpy(out, &arg, sizeof(Arg));
- }
- else {
- new (out) fmt::remove_cvref_t(std::forward(arg));
- }
- return encodeArgs(cstringSize, out + sizeof(Arg), std::forward(args)...);
- }
- }
-
- template
- static inline constexpr void storeNamedArgs(fmt::detail::named_arg_info* named_args_store) {
- }
-
- template
- static inline constexpr void storeNamedArgs(fmt::detail::named_arg_info* named_args_store,
- const Arg& arg, const Args&... args) {
- if constexpr (isNamedArg()) {
- named_args_store[NamedIdx] = {arg.name, Idx};
- storeNamedArgs(named_args_store, args...);
- }
- else {
- storeNamedArgs(named_args_store, args...);
- }
- }
-
- template
- static inline const char* decodeArgs(const char* in, fmt::basic_format_arg* args,
- const char** destruct_args) {
- return in;
- }
-
- template
- static inline const char* decodeArgs(const char* in, fmt::basic_format_arg* args,
- const char** destruct_args) {
- using namespace fmtlogdetail;
- using ArgType = fmt::remove_cvref_t;
- if constexpr (isNamedArg()) {
- return decodeArgs::type, Args...>(
- in, args, destruct_args);
- }
- else if constexpr (isCstring() || isString()) {
- size_t size = strlen(in);
- fmt::string_view v(in, size);
- if constexpr (ValueOnly) {
- fmt::detail::value& value_ = *(fmt::detail::value*)(args + Idx);
- value_ = fmt::detail::arg_mapper().map(v);
- }
- else {
- args[Idx] = fmt::detail::make_arg(v);
- }
- return decodeArgs(in + size + 1, args,
- destruct_args);
- }
- else {
- if constexpr (ValueOnly) {
- fmt::detail::value& value_ = *(fmt::detail::value*)(args + Idx);
- if constexpr (UnrefPtr::value) {
- value_ = fmt::detail::arg_mapper().map(**(ArgType*)in);
- }
- else {
- value_ = fmt::detail::arg_mapper().map(*(ArgType*)in);
- }
- }
- else {
- if constexpr (UnrefPtr::value) {
- args[Idx] = fmt::detail::make_arg(**(ArgType*)in);
- }
- else {
- args[Idx] = fmt::detail::make_arg(*(ArgType*)in);
- }
- }
-
- if constexpr (needCallDtor()) {
- destruct_args[DestructIdx] = in;
- return decodeArgs(in + sizeof(ArgType), args,
- destruct_args);
- }
- else {
- return decodeArgs(in + sizeof(ArgType), args,
- destruct_args);
- }
- }
- }
-
- template
- static inline void destructArgs(const char** destruct_args) {}
-
- template
- static inline void destructArgs(const char** destruct_args) {
- using ArgType = fmt::remove_cvref_t;
- if constexpr (isNamedArg()) {
- destructArgs::type, Args...>(destruct_args);
- }
- else if constexpr (needCallDtor()) {
- ((ArgType*)destruct_args[DestructIdx])->~ArgType();
- destructArgs(destruct_args);
- }
- else {
- destructArgs(destruct_args);
- }
- }
-
- template
- static const char* formatTo(fmt::string_view format, const char* data, MemoryBuffer& out,
- int& argIdx, std::vector>& args) {
- constexpr size_t num_args = sizeof...(Args);
- constexpr size_t num_dtors = fmt::detail::count()...>();
- const char* dtor_args[(std::max)(num_dtors, (size_t)1)];
- const char* ret;
- if (argIdx < 0) {
- argIdx = (int)args.size();
- args.resize(argIdx + num_args);
- ret = decodeArgs(data, args.data() + argIdx, dtor_args);
- }
- else {
- ret = decodeArgs(data, args.data() + argIdx, dtor_args);
- }
- vformat_to(out, format, fmt::basic_format_args(args.data() + argIdx, num_args));
- destructArgs<0, Args...>(dtor_args);
-
- return ret;
- }
-
- template
- static fmt::string_view unNameFormat(fmt::string_view in, uint32_t* reorderIdx,
- const Args&... args) {
- constexpr size_t num_named_args = fmt::detail::count()...>();
- if constexpr (num_named_args == 0) {
- return in;
- }
- const char* begin = in.data();
- const char* p = begin;
- std::unique_ptr unnamed_str(new char[in.size() + 1 + num_named_args * 5]);
- fmt::detail::named_arg_info named_args[(std::max)(num_named_args, (size_t)1)];
- storeNamedArgs<0, 0>(named_args, args...);
-
- char* out = (char*)unnamed_str.get();
- uint8_t arg_idx = 0;
- while (true) {
- auto c = *p++;
- if (!c) {
- size_t copy_size = p - begin - 1;
- memcpy(out, begin, copy_size);
- out += copy_size;
- break;
- }
- if (c != '{') continue;
- size_t copy_size = p - begin;
- memcpy(out, begin, copy_size);
- out += copy_size;
- begin = p;
- c = *p++;
- if (!c) fmt::detail::throw_format_error("invalid format string");
- if (fmt::detail::is_name_start(c)) {
- while ((fmt::detail::is_name_start(c = *p) || ('0' <= c && c <= '9'))) {
- ++p;
- }
- fmt::string_view name(begin, p - begin);
- int id = -1;
- for (size_t i = 0; i < num_named_args; ++i) {
- if (named_args[i].name == name) {
- id = named_args[i].id;
- break;
- }
- }
- if (id < 0) fmt::detail::throw_format_error("invalid format string");
- if constexpr (Reorder) {
- reorderIdx[id] = arg_idx++;
- }
- else {
- out = fmt::format_to(out, "{}", id);
- }
- }
- else {
- *out++ = c;
- }
- begin = p;
- }
- const char* ptr = unnamed_str.release();
- return fmt::string_view(ptr, out - ptr);
- }
-
-public:
- template
- inline void log(
- uint32_t& logId, int64_t tsc, const char* location, LogLevel level,
- fmt::format_string>::type...> format,
- Args&&... args) noexcept {
- if (!logId) {
- auto unnamed_format = unNameFormat(fmt::string_view(format), nullptr, args...);
- registerLogInfo(logId, formatTo, location, level, unnamed_format);
- }
- constexpr size_t num_cstring = fmt::detail::count()...>();
- size_t cstringSizes[(std::max)(num_cstring, (size_t)1)];
- uint32_t alloc_size = 8 + (uint32_t)getArgSizes<0>(cstringSizes, args...);
- bool q_full_cb = true;
- do {
- if (auto header = allocMsg(alloc_size, q_full_cb)) {
- header->logId = logId;
- char* out = (char*)(header + 1);
- *(int64_t*)out = tsc;
- out += 8;
- encodeArgs<0>(cstringSizes, out, std::forward(args)...);
- header->push(alloc_size);
- break;
- }
- q_full_cb = false;
- } while (FMTLOG_BLOCK);
- }
-
- template
- inline void logOnce(const char* location, LogLevel level, fmt::format_string format,
- Args&&... args) {
- fmt::string_view sv(format);
- auto&& fmt_args = fmt::make_format_args(args...);
- uint32_t fmt_size = formatted_size(sv, fmt_args);
- uint32_t alloc_size = 8 + 8 + fmt_size;
- bool q_full_cb = true;
- do {
- if (auto header = allocMsg(alloc_size, q_full_cb)) {
- header->logId = (uint32_t)level;
- char* out = (char*)(header + 1);
- *(int64_t*)out = tscns.rdtsc();
- out += 8;
- *(const char**)out = location;
- out += 8;
- vformat_to(out, sv, fmt_args);
- header->push(alloc_size);
- break;
- }
- q_full_cb = false;
- } while (FMTLOG_BLOCK);
- }
-};
-
-using fmtlog = fmtlogT<>;
-
-template
-FAST_THREAD_LOCAL typename fmtlogT<_>::ThreadBuffer* fmtlogT<_>::threadBuffer;
-
-template
-struct fmtlogWrapper
-{ static fmtlog impl; };
-
-template
-fmtlog fmtlogWrapper<_>::impl;
-
-template
-inline void fmtlogT<_>::setLogLevel(LogLevel logLevel) noexcept {
- fmtlogWrapper<>::impl.currentLogLevel = logLevel;
-}
-
-template
-inline typename fmtlogT<_>::LogLevel fmtlogT<_>::getLogLevel() noexcept {
- return fmtlogWrapper<>::impl.currentLogLevel;
-}
-
-template
-inline bool fmtlogT<_>::checkLogLevel(LogLevel logLevel) noexcept {
-#ifdef FMTLOG_NO_CHECK_LEVEL
- return true;
-#else
- return logLevel >= fmtlogWrapper<>::impl.currentLogLevel;
-#endif
-}
-
-#define __FMTLOG_S1(x) #x
-#define __FMTLOG_S2(x) __FMTLOG_S1(x)
-#define __FMTLOG_LOCATION __FILE__ ":" __FMTLOG_S2(__LINE__)
-
-#define FMTLOG(level, format, ...) \
- do { \
- static uint32_t logId = 0; \
- if (!fmtlog::checkLogLevel(level)) break; \
- fmtlogWrapper<>::impl.log(logId, fmtlogWrapper<>::impl.tscns.rdtsc(), __FMTLOG_LOCATION, \
- level, format, ##__VA_ARGS__); \
- } while (0)
-
-#define FMTLOG_LIMIT(min_interval, level, format, ...) \
- do { \
- static uint32_t logId = 0; \
- static int64_t limitNs = 0; \
- if (!fmtlog::checkLogLevel(level)) break; \
- int64_t tsc = fmtlogWrapper<>::impl.tscns.rdtsc(); \
- int64_t ns = fmtlogWrapper<>::impl.tscns.tsc2ns(tsc); \
- if (ns < limitNs) break; \
- limitNs = ns + min_interval; \
- fmtlogWrapper<>::impl.log(logId, tsc, __FMTLOG_LOCATION, level, format, ##__VA_ARGS__); \
- } while (0)
-
-#define FMTLOG_ONCE(level, format, ...) \
- do { \
- if (!fmtlog::checkLogLevel(level)) break; \
- fmtlogWrapper<>::impl.logOnce(__FMTLOG_LOCATION, level, format, ##__VA_ARGS__); \
- } while (0)
-
-#if FMTLOG_ACTIVE_LEVEL <= FMTLOG_LEVEL_DBG
-#define logd(format, ...) FMTLOG(fmtlog::DBG, format, ##__VA_ARGS__)
-#define logdo(format, ...) FMTLOG_ONCE(fmtlog::DBG, format, ##__VA_ARGS__)
-#define logdl(min_interval, format, ...) FMTLOG_LIMIT(min_interval, fmtlog::DBG, format, ##__VA_ARGS__)
-#else
-#define logd(format, ...) (void)0
-#define logdo(format, ...) (void)0
-#define logdl(min_interval, format, ...) (void)0
-#endif
-
-#if FMTLOG_ACTIVE_LEVEL <= FMTLOG_LEVEL_INF
-#define logi(format, ...) FMTLOG(fmtlog::INF, format, ##__VA_ARGS__)
-#define logio(format, ...) FMTLOG_ONCE(fmtlog::INF, format, ##__VA_ARGS__)
-#define logil(min_interval, format, ...) FMTLOG_LIMIT(min_interval, fmtlog::INF, format, ##__VA_ARGS__)
-#else
-#define logi(format, ...) (void)0
-#define logio(format, ...) (void)0
-#define logil(min_interval, format, ...) (void)0
-#endif
-
-#if FMTLOG_ACTIVE_LEVEL <= FMTLOG_LEVEL_WRN
-#define logw(format, ...) FMTLOG(fmtlog::WRN, format, ##__VA_ARGS__)
-#define logwo(format, ...) FMTLOG_ONCE(fmtlog::WRN, format, ##__VA_ARGS__)
-#define logwl(min_interval, format, ...) FMTLOG_LIMIT(min_interval, fmtlog::WRN, format, ##__VA_ARGS__)
-#else
-#define logw(format, ...) (void)0
-#define logwo(format, ...) (void)0
-#define logwl(min_interval, format, ...) (void)0
-#endif
-
-#if FMTLOG_ACTIVE_LEVEL <= FMTLOG_LEVEL_ERR
-#define loge(format, ...) FMTLOG(fmtlog::ERR, format, ##__VA_ARGS__)
-#define logeo(format, ...) FMTLOG_ONCE(fmtlog::ERR, format, ##__VA_ARGS__)
-#define logel(min_interval, format, ...) FMTLOG_LIMIT(min_interval, fmtlog::ERR, format, ##__VA_ARGS__)
-#else
-#define loge(format, ...) (void)0
-#define logeo(format, ...) (void)0
-#define logel(min_interval, format, ...) (void)0
-#endif
-
-#ifdef FMTLOG_HEADER_ONLY
-#include "fmtlog-inl.h"
-#endif
diff --git a/NetTunnelSDK/misc.cpp b/NetTunnelSDK/misc.cpp
new file mode 100644
index 0000000..7bd3123
--- /dev/null
+++ b/NetTunnelSDK/misc.cpp
@@ -0,0 +1,85 @@
+#include "pch.h"
+#include "misc.h"
+#include "usrerr.h"
+
+#include
+#include
+
+
+void RemoveTailLineBreak(TCHAR* pInputStr, int strSize)
+{
+ size_t length;
+ if (pInputStr)
+ {
+ if (StringCbLength(pInputStr, strSize, &length) == S_OK && length > 0)
+ {
+ if (pInputStr[length - 2] == '\r' && pInputStr[length - 1] == '\n')
+ {
+ pInputStr[length - 2] = pInputStr[length - 1] = 0;
+ }
+ else if (pInputStr[length - 1] == '\n')
+ {
+ pInputStr[length - 1] = 0;
+ }
+ }
+ }
+}
+
+int RunPipeCmd(TCHAR* pszCmd, TCHAR* pszResultBuffer, int dwResultBufferSize)
+{
+ BOOL bRet;
+ HANDLE hReadPipe = nullptr;
+ HANDLE hWritePipe = nullptr;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ SECURITY_ATTRIBUTES securityAttributes;
+
+ memset(&securityAttributes, 0, sizeof(SECURITY_ATTRIBUTES));
+ memset(&si, 0, sizeof(STARTUPINFO));
+ memset(&pi, 0, sizeof(PROCESS_INFORMATION));
+
+ // 设定管道的安全属性
+ securityAttributes.bInheritHandle = TRUE;
+ securityAttributes.nLength = sizeof(securityAttributes);
+ securityAttributes.lpSecurityDescriptor = nullptr;
+
+ // 创建匿名管道
+ bRet = ::CreatePipe(&hReadPipe, &hWritePipe, &securityAttributes, 0);
+ if (FALSE == bRet)
+ {
+ SPDLOG_ERROR(TEXT("CreatePipe Error"));
+ return -ERR_SYS_CALL;
+ }
+
+ // 设置新进程参数
+ si.cb = sizeof(si);
+ si.hStdError = hWritePipe;
+ si.hStdOutput = hWritePipe;
+ si.wShowWindow = SW_HIDE;
+ si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
+
+ // 创建新进程执行命令, 将执行结果写入匿名管道中
+ bRet = ::CreateProcess(nullptr, (pszCmd), nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &pi);
+ if (FALSE == bRet)
+ {
+ SPDLOG_ERROR(TEXT("CreateProcess Error"));
+ }
+
+ // 等待命令执行结束
+ ::WaitForSingleObject(pi.hThread, INFINITE);
+ ::WaitForSingleObject(pi.hProcess, INFINITE);
+
+ // 从匿名管道中读取结果到输出缓冲区
+ ::RtlZeroMemory(pszResultBuffer, dwResultBufferSize);
+ ::ReadFile(hReadPipe, pszResultBuffer, dwResultBufferSize, nullptr, nullptr);
+
+ // 关闭句柄, 释放内存
+ ::CloseHandle(pi.hThread);
+ ::CloseHandle(pi.hProcess);
+ ::CloseHandle(hWritePipe);
+ ::CloseHandle(hReadPipe);
+
+ RemoveTailLineBreak(pszResultBuffer, dwResultBufferSize);
+ //pszResultBuffer[dwResultBufferSize - 1] = 0;
+ return ERR_SUCCESS;
+}
diff --git a/NetTunnelSDK/misc.h b/NetTunnelSDK/misc.h
index d83c3df..cfd97c2 100644
--- a/NetTunnelSDK/misc.h
+++ b/NetTunnelSDK/misc.h
@@ -1,10 +1,18 @@
#pragma once
+#include
+
#ifndef ARRAY_SIZE
-//#ifdef __cplusplus
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-//#else
-//#define ARRAY_SIZE_TYPE_CHECK(a) (sizeof(typeof(int[1 - 2 * !!__builtin_types_compatible_p(typeof(a), typeof(&a[0]))])))
-//#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]) + ARRAY_SIZE_TYPE_CHECK(a) * 0)
-//#endif
-#endif
\ No newline at end of file
+#endif
+
+#ifdef __cplusplus // If used by C++ code,
+extern "C" {
+// we need to export the C interface
+#endif
+
+void RemoveTailLineBreak(TCHAR* pInputStr, int strSize);
+int RunPipeCmd(TCHAR* pszCmd, TCHAR* pszResultBuffer, int dwResultBufferSize);
+#ifdef __cplusplus
+}
+#endif
diff --git a/NetTunnelSDK/network.cpp b/NetTunnelSDK/network.cpp
new file mode 100644
index 0000000..bc28f87
--- /dev/null
+++ b/NetTunnelSDK/network.cpp
@@ -0,0 +1,78 @@
+#include "pch.h"
+#include "tunnel.h"
+#include "usrerr.h"
+#include
+#include
+#include
+#include
+
+#include "globalcfg.h"
+
+#pragma comment(lib,"Iphlpapi.lib")
+
+TUNNEL_API int GetAllNICInfo(PNIC_CONTENT pInfo, int* pItemCounts)
+{
+ int nRel, id = 0;
+ IP_ADDR_STRING* pIpAddrString;
+ PIP_ADAPTER_INFO pIpAdapterInfo;
+ unsigned long stSize;
+
+ if (pItemCounts == nullptr || pInfo == nullptr)
+ {
+ return -ERR_INPUT_PARAMS;
+ }
+
+ pIpAdapterInfo = new IP_ADAPTER_INFO[NET_CARD_MAX];
+ stSize = sizeof(IP_ADAPTER_INFO) * NET_CARD_MAX;
+
+ // WIN32 API get net card information
+ nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize);
+
+ if (ERROR_BUFFER_OVERFLOW == nRel)
+ {
+ delete[] pIpAdapterInfo;
+ return -ERR_MALLOC_MEMORY;
+ }
+
+ PIP_ADAPTER_INFO cur = pIpAdapterInfo;
+
+ while (cur)
+ {
+ StringCbCopy(pInfo[id].NetCardName, MAX_PATH, cur->AdapterName);
+ StringCbCopy(pInfo[id].NetCardDescription, MAX_PATH, cur->Description);
+
+ switch (cur->Type)
+ {
+ case MIB_IF_TYPE_ETHERNET:
+ pIpAddrString = &(cur->IpAddressList);
+ StringCbCopy(pInfo[id].NetCardIpaddr, MAX_PATH, pIpAddrString->IpAddress.String);
+ StringCbCopy(pInfo[id].NetCardNetmask, MAX_PATH, pIpAddrString->IpMask.String);
+ break;
+ case MIB_IF_TYPE_OTHER:
+ case MIB_IF_TYPE_TOKENRING:
+ case MIB_IF_TYPE_FDDI:
+ case MIB_IF_TYPE_PPP:
+ case MIB_IF_TYPE_LOOPBACK:
+ case MIB_IF_TYPE_SLIP:
+ break;
+ default: // WIFI ,Unknown type
+ pIpAddrString = &(cur->IpAddressList);
+ StringCbCopy(pInfo[id].NetCardIpaddr, MAX_PATH, pIpAddrString->IpAddress.String);
+ StringCbCopy(pInfo[id].NetCardNetmask, MAX_PATH, pIpAddrString->IpMask.String);
+ break;
+ }
+
+ StringCbPrintf(pInfo[id].NetCardMacAddr, MAX_PATH, "%02X:%02X:%02X:%02X:%02X:%02X",
+ cur->Address[0], cur->Address[1], cur->Address[2], cur->Address[3], cur->Address[4],
+ cur->Address[5]);
+
+ id++;
+ cur = cur->Next;
+ }
+
+ *pItemCounts = id;
+
+ delete[] pIpAdapterInfo;
+
+ return ERR_SUCCESS;
+}
diff --git a/NetTunnelSDK/packages.config b/NetTunnelSDK/packages.config
index 7ee1a22..8f2695c 100644
--- a/NetTunnelSDK/packages.config
+++ b/NetTunnelSDK/packages.config
@@ -1,4 +1,5 @@
+
-
+
\ No newline at end of file
diff --git a/NetTunnelSDK/pch.h b/NetTunnelSDK/pch.h
index 9660927..95f726c 100644
--- a/NetTunnelSDK/pch.h
+++ b/NetTunnelSDK/pch.h
@@ -10,4 +10,5 @@
// 添加要在此处预编译的标头
#include "framework.h"
+#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
#endif //PCH_H
diff --git a/NetTunnelSDK/tunnel.cpp b/NetTunnelSDK/tunnel.cpp
index cf9ea82..7624480 100644
--- a/NetTunnelSDK/tunnel.cpp
+++ b/NetTunnelSDK/tunnel.cpp
@@ -1,66 +1,138 @@
#include "pch.h"
#include "tunnel.h"
-#include
+#include
+#include
+#include
+#include
+#include
#include "usrerr.h"
-#include "logs/fmtlog.h"
-
-typedef struct
-{
- PROTO_CRYPTO_TYPE proCryptoType;
- char proKeyBuf[CRYPTO_MAX][256];
- fmtlog::LogLevel logLevel;
-} SDK_CONFIG, *PSDK_CONFIG;
+#include "globalcfg.h"
+#include "misc.h"
static SDK_CONFIG g_globalConfig;
-NETTUNNELSDK_API int TunnelSDKInitEnv()
+PSDK_CONFIG GetGlobalCfgInfo()
{
+ return &g_globalConfig;
+}
+
+TUNNEL_API int TunnelSDKInitEnv(const TCHAR* pWorkDir)
+{
+ size_t length;
+ spdlog::level::level_enum lv = g_globalConfig.logLevel;
+
memset(&g_globalConfig, 0, sizeof(SDK_CONFIG));
- g_globalConfig.logLevel = fmtlog::OFF;
+ g_globalConfig.logLevel = lv;
+
+
+ if (pWorkDir == nullptr)
+ {
+ // 获取当前文件默认路径
+ GetCurrentDirectory(MAX_PATH, g_globalConfig.workDirectory);
+ }
+ else
+ {
+ if (StringCbLengthA(pWorkDir, MAX_PATH, &length) == S_OK && length == 0)
+ {
+ GetCurrentDirectory(MAX_PATH, g_globalConfig.workDirectory);
+ }
+ else
+ {
+ StringCbCopy(g_globalConfig.workDirectory, MAX_PATH, pWorkDir);
+ }
+ }
+
+ if (FindWireguardExe(NULL, 0) != ERR_SUCCESS)
+ {
+ SPDLOG_ERROR(TEXT("WireGuard not found, Please install WireGuard first or set the WireGuard Path."));
+ return -ERR_ITEM_EXISTS;
+ }
+
return ERR_SUCCESS;
}
-NETTUNNELSDK_API void InitTunnelSDKLog(const char* pLogFile, LOG_LEVEL level)
+TUNNEL_API void TunnelSDKUnInit()
{
- char buf[MAX_PATH] = {0};
- static fmtlog::LogLevel lv[LOG_MAX] = {fmtlog::DBG, fmtlog::INF, fmtlog::WRN, fmtlog::ERR,};
+}
+
+static spdlog::level::level_enum logLevelToSpdlogLevel(LOG_LEVEL level)
+{
+ switch (level)
+ {
+ case LOG_TRACE:
+ return spdlog::level::level_enum::trace;
+ case LOG_DEBUG:
+ return spdlog::level::level_enum::debug;
+ case LOG_INFO:
+ return spdlog::level::level_enum::info;
+ case LOG_WARN:
+ return spdlog::level::level_enum::warn;
+ case LOG_ERROR:
+ return spdlog::level::level_enum::err;
+ case LOG_CRITICAL:
+ return spdlog::level::level_enum::critical;
+ default:
+ return spdlog::level::level_enum::info;
+ }
+}
+
+TUNNEL_API void InitTunnelSDKLog(const TCHAR* pLogFile, LOG_LEVEL level)
+{
+ TCHAR buf[MAX_PATH] = {0};
//::MessageBoxA(NULL, pLogFile, NULL, MB_OK);
if (pLogFile && strlen(pLogFile) > 0)
{
- strncpy_s(buf, pLogFile, MAX_PATH);
+ StringCbCopy(buf, MAX_PATH, pLogFile);
}
else
{
- GetCurrentDirectory(MAX_PATH, buf);
- strcat_s(buf, "\\tunnelsdk.log");
+ StringCbCopy(buf, MAX_PATH, TEXT("tunnelsdk.log"));
}
- fmtlog::setLogFile(buf, false);
- fmtlog::setHeaderPattern("[{YmdHMSe}][{l}][{s}] ");
- fmtlog::setFlushDelay(1000000);
- fmtlog::setLogLevel(lv[level]);
+ g_globalConfig.logLevel = logLevelToSpdlogLevel(level);
- g_globalConfig.logLevel = lv[level];
+ auto dupFileFilter = std::make_shared(std::chrono::seconds(5));
+ auto dupStdFilter = std::make_shared(std::chrono::seconds(5));
- FMTLOG(lv[level], "Log({1}):{0}", buf, (int)level);
+ dupFileFilter->add_sink(std::make_shared(buf, 1024 * 1024 * 5, 10));
+ dupStdFilter->add_sink(std::make_shared());
+
+ std::vector sinks{dupStdFilter, dupFileFilter};
+ auto logger = std::make_shared(TEXT("tunnelSDK"), sinks.begin(), sinks.end());
+ spdlog::set_default_logger(logger);
+
+ spdlog::set_level(g_globalConfig.logLevel);
+ spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e][%l][%s:%#] %v");
+ spdlog::flush_every(std::chrono::seconds(1));
+
+#if 0
+ std::cout << "TRACE: " << logger->should_log(spdlog::level::trace) << std::endl;
+ std::cout << "DEBUG: " << logger->should_log(spdlog::level::debug) << std::endl;
+ std::cout << "INFO: " << logger->should_log(spdlog::level::info) << std::endl;
+ std::cout << "WARN: " << logger->should_log(spdlog::level::warn) << std::endl;
+ std::cout << "ERROR: " << logger->should_log(spdlog::level::err) << std::endl;
+ std::cout << "CRITICAL: " << logger->should_log(spdlog::level::critical) << std::endl;
+#endif
+
+ SPDLOG_INFO(TEXT("Log({1}): {0}"), buf, static_cast(level));
}
-NETTUNNELSDK_API void TunnelLogEnable(bool enLog)
+TUNNEL_API void TunnelLogEnable(bool enLog)
{
if (enLog)
{
- fmtlog::setLogLevel(g_globalConfig.logLevel);
+ spdlog::set_level(g_globalConfig.logLevel);
}
else
{
- fmtlog::setLogLevel(fmtlog::OFF);
+ spdlog::set_level(spdlog::level::level_enum::off);
}
}
-NETTUNNELSDK_API int SetProtocolEncryptType(PROTO_CRYPTO_TYPE type, const char* pProKey)
+TUNNEL_API int SetProtocolEncryptType(PROTO_CRYPTO_TYPE type, const TCHAR* pProKey)
{
if (type > CRYPTO_BASE64 && type < CRYPTO_MAX)
{
@@ -71,25 +143,26 @@ NETTUNNELSDK_API int SetProtocolEncryptType(PROTO_CRYPTO_TYPE type, const char*
}
g_globalConfig.proCryptoType = type;
- strncpy_s(g_globalConfig.proKeyBuf[type], pProKey, 256);
+ StringCbCopy(g_globalConfig.proKeyBuf[type], 256, pProKey);
- logd("Protocol crypto type: {0} with key [{1}]", (int)type, pProKey? pProKey : "");
+ SPDLOG_DEBUG(TEXT("Protocol crypto type: {0} with key [{1}]"), static_cast(type),
+ pProKey ? pProKey : TEXT(""));
return ERR_SUCCESS;
}
-NETTUNNELSDK_API int CreateTunnel(LPCSTR lpszMsg)
+TUNNEL_API int CreateTunnel(LPCSTR lpszMsg)
{
OutputDebugStringA(lpszMsg);
return 0;
}
-NETTUNNELSDK_API const char* TestMessage()
+TUNNEL_API const TCHAR* TestMessage()
{
- return "Test Message";
+ return TEXT("Test Message");
}
-NETTUNNELSDK_API int Add(int a, int b)
+TUNNEL_API int Add(int a, int b)
{
return a + b;
}
diff --git a/NetTunnelSDK/tunnel.h b/NetTunnelSDK/tunnel.h
index 8e658ed..0951c0a 100644
--- a/NetTunnelSDK/tunnel.h
+++ b/NetTunnelSDK/tunnel.h
@@ -3,12 +3,15 @@
#include
#ifdef NETTUNNELSDK_EXPORTS
-#define NETTUNNELSDK_API __declspec(dllexport)
+#define TUNNEL_API __declspec(dllexport)
#else
-#define NETTUNNELSDK_API __declspec(dllimport)
+#define TUNNEL_API __declspec(dllimport)
#endif
-using PROTO_CRYPTO_TYPE = enum
+#define WG_KEY_MAX (64)
+#define NET_CARD_MAX (32)
+
+typedef enum
{
CRYPTO_NONE = 0,
CRYPTO_BASE64 = 1,
@@ -16,29 +19,46 @@ using PROTO_CRYPTO_TYPE = enum
CRYPTO_3DES = 3,
CRYPTO_AES256 = 4,
CRYPTO_MAX,
-};
+} PROTO_CRYPTO_TYPE;
typedef enum
{
- LOG_DEBUG = 0,
- LOG_INFO = 1,
- LOG_WARN = 2,
- LOG_ERROR = 3,
+ LOG_TRACE = 0,
+ LOG_DEBUG,
+ LOG_INFO,
+ LOG_WARN,
+ LOG_ERROR,
+ LOG_CRITICAL,
LOG_MAX
} LOG_LEVEL;
+typedef struct
+{
+ TCHAR NetCardName[256];
+ TCHAR NetCardDescription[256];
+ TCHAR NetCardIpaddr[256];
+ TCHAR NetCardNetmask[256];
+ TCHAR NetCardMacAddr[256];
+} NIC_CONTENT, *PNIC_CONTENT;
+
+
#ifdef __cplusplus // If used by C++ code,
extern "C" {
// we need to export the C interface
#endif
-NETTUNNELSDK_API int __cdecl CreateTunnel(LPCSTR lpszMsg);
-NETTUNNELSDK_API const char* __cdecl TestMessage();
-NETTUNNELSDK_API int __cdecl Add(int a, int b);
-NETTUNNELSDK_API int __cdecl TunnelSDKInitEnv();
-NETTUNNELSDK_API int __cdecl SetProtocolEncryptType(PROTO_CRYPTO_TYPE type, const char* pProKey);
-NETTUNNELSDK_API void __cdecl InitTunnelSDKLog(const char* pLogFile, LOG_LEVEL level);
-NETTUNNELSDK_API void __cdecl TunnelLogEnable(bool enLog);
+TUNNEL_API int __cdecl CreateTunnel(LPCSTR lpszMsg);
+TUNNEL_API const TCHAR* __cdecl TestMessage();
+TUNNEL_API int __cdecl Add(int a, int b);
+TUNNEL_API int __cdecl TunnelSDKInitEnv(const TCHAR* pWorkDir);
+TUNNEL_API int __cdecl SetProtocolEncryptType(PROTO_CRYPTO_TYPE type, const TCHAR* pProKey);
+TUNNEL_API void __cdecl InitTunnelSDKLog(const TCHAR* pLogFile, LOG_LEVEL level);
+TUNNEL_API void __cdecl TunnelLogEnable(bool enLog);
+TUNNEL_API int __cdecl FindWireguardExe(TCHAR* pFullPath, int maxSize);
+TUNNEL_API int __cdecl SetWireguardPath(TCHAR* pPath);
+TUNNEL_API void __cdecl TunnelSDKUnInit();
+TUNNEL_API int __cdecl GenerateWireguardKeyPairs(TCHAR* pPubKey, int pubkeySize, TCHAR* pPrivKey, int privKeySize);
+TUNNEL_API int __cdecl GetAllNICInfo(PNIC_CONTENT pInfo, int* pItemCounts);
#ifdef __cplusplus
}
diff --git a/NetTunnelSDK/usrerr.cpp b/NetTunnelSDK/usrerr.cpp
index 556692d..3ed2fb1 100644
--- a/NetTunnelSDK/usrerr.cpp
+++ b/NetTunnelSDK/usrerr.cpp
@@ -5,24 +5,29 @@
#define GENERATE_STRING(STRING,x, desc) {#STRING, desc},
-static const char *g_enumStrVal[][MAX_DESC_LENGTH] = {
+static const char* g_enumStrVal[][MAX_DESC_LENGTH] = {
DEF_ERR_CODE(GENERATE_STRING) {"ERR_UNKNOWN", "未知错误"},
};
-const char *getErrorEnumNameString(int errCode) {
- if (errCode < 0) {
+const char* getErrorEnumNameString(int errCode)
+{
+ if (errCode < 0)
+ {
errCode = -errCode;
}
- if (errCode >= ARRAY_SIZE(g_enumStrVal) || errCode < 0) {
+ if (errCode >= ARRAY_SIZE(g_enumStrVal) || errCode < 0)
+ {
return g_enumStrVal[ARRAY_SIZE(g_enumStrVal) - 1][0];
}
return g_enumStrVal[errCode][0];
}
-const char *getErrorEnumDesc(int errCode) {
- if (errCode >= ARRAY_SIZE(g_enumStrVal) || errCode < 0) {
+const char* getErrorEnumDesc(int errCode)
+{
+ if (errCode >= ARRAY_SIZE(g_enumStrVal) || errCode < 0)
+ {
return g_enumStrVal[ARRAY_SIZE(g_enumStrVal) - 1][0];
}
return g_enumStrVal[errCode][1];
-}
\ No newline at end of file
+}
diff --git a/NetTunnelSDK/usrerr.h b/NetTunnelSDK/usrerr.h
index ac38100..235118c 100644
--- a/NetTunnelSDK/usrerr.h
+++ b/NetTunnelSDK/usrerr.h
@@ -19,6 +19,7 @@
ERR_CODE(ERR_MALLOC_MEMORY, 14, "分配内存失败") \
ERR_CODE(ERR_MMAP_MEMORY, 15, "共享内存失败")
+
#define GENERATE_ENUM(ENUM, n, x) ENUM,
typedef enum
diff --git a/NetTunnelSDK/wireguard.cpp b/NetTunnelSDK/wireguard.cpp
index bcb5590..ce8e3e0 100644
--- a/NetTunnelSDK/wireguard.cpp
+++ b/NetTunnelSDK/wireguard.cpp
@@ -1 +1,230 @@
#include "pch.h"
+#include "tunnel.h"
+#include "usrerr.h"
+#include
+#include
+
+#include "globalcfg.h"
+#include "misc.h"
+
+#define WINENVBUF_SIZE (4096)
+#define CONFIG_FILE_NAME TEXT("tunnelsdk.ini")
+#define CFG_WIREGUARD_SECTION TEXT("WireGuard")
+#define CFG_WIREGUARD_PATH TEXT("WireGuardExe")
+#define CFG_WG_PATH TEXT("WgExe")
+
+
+TUNNEL_API int GenerateWireguardKeyPairs(TCHAR* pPubKey, int pubkeySize, TCHAR* pPrivKey, int privKeySize)
+{
+ int ret;
+ TCHAR cmdBuffer[MAX_PATH];
+ TCHAR cmdResult[MAX_PATH];
+ PSDK_CONFIG pCfg = GetGlobalCfgInfo();
+
+ // WireGuard 不存在或者未配置目录
+ if (!pCfg->wireguardCfg.wgExists || !pCfg->wireguardCfg.wireguardExists)
+ {
+ return -ERR_ITEM_UNEXISTS;
+ }
+
+ memset(cmdBuffer, 0, MAX_PATH);
+ memset(cmdResult, 0, MAX_PATH);
+
+ StringCbPrintf(cmdBuffer, MAX_PATH, TEXT("cmd.exe /C \"%s\" genkey"), pCfg->wireguardCfg.wgPath);
+
+ if ((ret = RunPipeCmd(cmdBuffer, cmdResult, MAX_PATH)) != ERR_SUCCESS)
+ {
+ SPDLOG_ERROR("Run command [{0}] error: {1}", cmdBuffer, ret);
+ return -ERR_CALL_SHELL;
+ }
+
+ SPDLOG_DEBUG("Run command [{0}] resutl \'{1}\'", cmdBuffer, cmdResult);
+
+ StringCbCopy(pPrivKey, privKeySize, cmdResult);
+ memset(cmdBuffer, 0, MAX_PATH);
+ StringCbPrintf(cmdBuffer, MAX_PATH, TEXT("cmd.exe /C echo %s | \"%s\" pubkey"), cmdResult,
+ pCfg->wireguardCfg.wgPath);
+
+ memset(cmdResult, 0, MAX_PATH);
+ if ((ret = RunPipeCmd(cmdBuffer, cmdResult, MAX_PATH)) != ERR_SUCCESS)
+ {
+ SPDLOG_ERROR("Run command [{0}] error: {1}", cmdBuffer, ret);
+ return -ERR_CALL_SHELL;
+ }
+
+ StringCbCopy(pPubKey, pubkeySize, cmdResult);
+ SPDLOG_DEBUG("Run command [{0}] resutl \'{1}\'", cmdBuffer, cmdResult);
+
+ return ERR_SUCCESS;
+}
+
+TUNNEL_API int SetWireguardPath(TCHAR* pPath)
+{
+ WIN32_FIND_DATA FindFileData;
+ HANDLE hFind;
+
+ if (pPath == nullptr)
+ {
+ return -ERR_INPUT_PARAMS;
+ }
+
+ hFind = FindFirstFile(pPath, &FindFileData);
+
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ TCHAR path[MAX_PATH] = {0};
+ TCHAR wgPath[MAX_PATH];
+
+ StringCbPrintf(path, MAX_PATH, TEXT("%s\\%s"), GetGlobalCfgInfo()->workDirectory, CONFIG_FILE_NAME);
+
+ SPDLOG_DEBUG(TEXT("Used configure file:{0}"), path);
+
+ WritePrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WIREGUARD_PATH, pPath, path);
+ SPDLOG_DEBUG(TEXT("Save configure: {1} --> {0}"), pPath, CFG_WIREGUARD_PATH);
+
+ StringCbCopy(wgPath, MAX_PATH, pPath);
+ TCHAR* pIndex = _tcsrchr(wgPath, '\\');
+
+ if (pIndex)
+ {
+ *pIndex = 0;
+ StringCbCat(wgPath, MAX_PATH, "\\wg.exe");
+ WritePrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WG_PATH, wgPath, path);
+ SPDLOG_DEBUG(TEXT("Save configure: {1} --> {0}"), wgPath, CFG_WG_PATH);
+ }
+
+ return ERR_SUCCESS;
+ }
+ else
+ {
+ return -ERR_ITEM_UNEXISTS;
+ }
+}
+
+TUNNEL_API int FindWireguardExe(TCHAR* pFullPath, int maxSize)
+{
+ TCHAR path[MAX_PATH];
+ TCHAR wrieguardPath[MAX_PATH];
+ WIN32_FIND_DATA FindFileData;
+ HANDLE hFind;
+ DWORD dwRet, dwErr;
+ LPSTR pEnvBuf;
+ TCHAR *token, *p = nullptr;
+
+ memset(path, 0, MAX_PATH);
+ StringCbPrintf(path, MAX_PATH, TEXT("%s\\%s"), GetGlobalCfgInfo()->workDirectory, CONFIG_FILE_NAME);
+ GetPrivateProfileString(CFG_WIREGUARD_SECTION,CFG_WIREGUARD_PATH,TEXT(""), wrieguardPath,MAX_PATH, path);
+
+ hFind = FindFirstFile(wrieguardPath, &FindFileData);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ if (pFullPath && maxSize > 0)
+ {
+ StringCbCopy(pFullPath, maxSize, wrieguardPath);
+ }
+
+ StringCbCopy(GetGlobalCfgInfo()->wireguardCfg.wireguardPath, MAX_PATH, wrieguardPath);
+ GetGlobalCfgInfo()->wireguardCfg.wireguardExists = TRUE;
+
+ SPDLOG_DEBUG(TEXT("Ini found WireGuard at: {0}"), wrieguardPath);
+
+ memset(path, 0, MAX_PATH);
+ StringCbPrintf(path, MAX_PATH, TEXT("%s\\%s"), GetGlobalCfgInfo()->workDirectory, CONFIG_FILE_NAME);
+ GetPrivateProfileString(CFG_WIREGUARD_SECTION,CFG_WG_PATH,TEXT(""), wrieguardPath,MAX_PATH, path);
+
+ hFind = FindFirstFile(wrieguardPath, &FindFileData);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ StringCbCopy(GetGlobalCfgInfo()->wireguardCfg.wgPath, MAX_PATH, wrieguardPath);
+ GetGlobalCfgInfo()->wireguardCfg.wgExists = TRUE;
+ SPDLOG_DEBUG(TEXT("Ini found WireGuard Tools at: {0}"), wrieguardPath);
+ }
+
+ return ERR_SUCCESS;
+ }
+
+ pEnvBuf = static_cast(malloc(WINENVBUF_SIZE));
+ if (nullptr == pEnvBuf)
+ {
+ SPDLOG_ERROR(TEXT("Malloc {0} bytes memory error"), WINENVBUF_SIZE);
+ return -ERR_MALLOC_MEMORY;
+ }
+
+ dwRet = GetEnvironmentVariable(TEXT("path"), pEnvBuf, WINENVBUF_SIZE);
+
+ if (0 == dwRet)
+ {
+ dwErr = GetLastError();
+ if (ERROR_ENVVAR_NOT_FOUND == dwErr)
+ {
+ SPDLOG_DEBUG(TEXT("Environment variable path does not exist."));
+ free(pEnvBuf);
+ return -ERR_FILE_NOT_EXISTS;
+ }
+ }
+ else if (WINENVBUF_SIZE < dwRet)
+ {
+ pEnvBuf = static_cast(realloc(pEnvBuf, dwRet * sizeof(CHAR)));
+ if (nullptr == pEnvBuf)
+ {
+ SPDLOG_ERROR(TEXT("Malloc {0} bytes memory error"), dwRet * sizeof(CHAR));
+ return -ERR_MALLOC_MEMORY;
+ }
+ dwRet = GetEnvironmentVariable("path", pEnvBuf, dwRet);
+ if (!dwRet)
+ {
+ SPDLOG_ERROR(TEXT("GetEnvironmentVariable failed (%d)"), GetLastError());
+ free(pEnvBuf);
+ return -ERR_FILE_NOT_EXISTS;
+ }
+ }
+
+ token = strtok_s(pEnvBuf, TEXT(";"), &p);
+
+ while (token != nullptr)
+ {
+ memset(path, 0, MAX_PATH);
+ StringCbPrintfA(path, MAX_PATH, TEXT("%s\\wireguard.exe"), token);
+
+ hFind = FindFirstFile(path, &FindFileData);
+
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ if (pFullPath && maxSize > 0)
+ {
+ StringCbCopy(pFullPath, maxSize, path);
+ }
+
+ // 保存路径到配置文件
+ SetWireguardPath(path);
+ SPDLOG_DEBUG(TEXT("Path Environment found WireGuard at: {0}"), path);
+
+ StringCbCopy(GetGlobalCfgInfo()->wireguardCfg.wireguardPath, MAX_PATH, wrieguardPath);
+ GetGlobalCfgInfo()->wireguardCfg.wireguardExists = TRUE;
+
+ memset(path, 0, MAX_PATH);
+ StringCbPrintf(path, MAX_PATH, TEXT("%s\\wg.exe"), token);
+
+ SPDLOG_DEBUG(TEXT("Find WireGuard tools at: {0}"), path);
+
+ hFind = FindFirstFile(path, &FindFileData);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ StringCbCopy(GetGlobalCfgInfo()->wireguardCfg.wgPath, MAX_PATH, path);
+ GetGlobalCfgInfo()->wireguardCfg.wgExists = TRUE;
+
+ SPDLOG_DEBUG(TEXT("Path Environment found WireGuard tools at: {0}"), path);
+ }
+
+
+ //TODO: throw exception by C# call, why??????
+ //CloseHandle(hFind);
+ free(pEnvBuf);
+ return ERR_SUCCESS;
+ }
+ token = strtok_s(nullptr, TEXT(";"), &p);
+ }
+
+ free(pEnvBuf);
+ return -ERR_FILE_NOT_EXISTS;
+}
diff --git a/TestNetTunnelSDK/TestNetTunnelSDK.cpp b/TestNetTunnelSDK/TestNetTunnelSDK.cpp
new file mode 100644
index 0000000..691b029
--- /dev/null
+++ b/TestNetTunnelSDK/TestNetTunnelSDK.cpp
@@ -0,0 +1,67 @@
+#include "pch.h"
+#include "CppUnitTest.h"
+#include "../NetTunnelSDK/tunnel.h"
+#include "../NetTunnelSDK/usrerr.h"
+#include "../NetTunnelSDK/misc.h"
+
+using namespace Microsoft::VisualStudio::CppUnitTestFramework;
+
+namespace TestNetTunnelSDK
+{
+ TEST_MODULE_INITIALIZE(ModuleInitialize)
+ {
+ Logger::WriteMessage("In Module Initialize");
+ TunnelSDKInitEnv(TEXT(
+ "C:\\Users\\HuangXin\\Documents\\development\\visual_studio\\tunnel_windows\\NetTunnelApp\\bin\\Debug"));
+ InitTunnelSDKLog(
+ TEXT(
+ "C:\\Users\\HuangXin\\Documents\\development\\visual_studio\\tunnel_windows\\NetTunnelApp\\bin\\Debug\\utest.log"),
+ LOG_DEBUG);
+ }
+
+ TEST_MODULE_CLEANUP(ModuleCleanup)
+ {
+ Logger::WriteMessage("In Module Cleanup");
+ TunnelSDKUnInit();
+ }
+
+ TEST_CLASS(TestNetTunnelSDK)
+ {
+ public:
+ TEST_METHOD(TestFindWireguardExe)
+ {
+ int ret = ERR_SUCCESS;
+ Assert::AreEqual(ret, FindWireguardExe(nullptr, 0));
+ }
+
+ TEST_METHOD(TestSetWireguardPath)
+ {
+ int ret = ERR_SUCCESS;
+ Assert::AreEqual(ret, SetWireguardPath(TEXT("C:\\Program Files\\WireGuard\\wireguard.exe")));
+ }
+
+ TEST_METHOD(TestRunPipeCmd)
+ {
+#if 0
+ TCHAR buf[1024];
+ int ret = ERR_SUCCESS;
+
+ Assert::AreEqual(ret, RunPipeCmd(TEXT("cmd.exe /C dir E:\\"), buf, 1024));
+ Logger::WriteMessage("Return:");
+ Logger::WriteMessage(buf);
+#endif
+ }
+
+ TEST_METHOD(TestGetAllNICInfo)
+ {
+ PNIC_CONTENT pInfo = (PNIC_CONTENT)malloc(sizeof(NIC_CONTENT) * 32);
+
+ int size = 0;
+ int ret = ERR_SUCCESS;
+
+ Assert::AreEqual(ret, GetAllNICInfo(pInfo, &size));
+
+ free(pInfo);
+ }
+ };
+}
diff --git a/TestNetTunnelSDK/TestNetTunnelSDK.vcxproj b/TestNetTunnelSDK/TestNetTunnelSDK.vcxproj
new file mode 100644
index 0000000..d10b963
--- /dev/null
+++ b/TestNetTunnelSDK/TestNetTunnelSDK.vcxproj
@@ -0,0 +1,178 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ {61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}
+ Win32Proj
+ TestNetTunnelSDK
+ 10.0
+ NativeUnitTestProject
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+ false
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+ false
+
+
+ DynamicLibrary
+ true
+ v143
+ MultiByte
+ false
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ false
+
+
+
+ Use
+ Level3
+ true
+ $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)
+ _DEBUG;%(PreprocessorDefinitions)
+ true
+ pch.h
+
+
+ Windows
+ $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
+
+
+
+
+ Use
+ Level3
+ true
+ $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;%(PreprocessorDefinitions)
+ true
+ pch.h
+
+
+ Windows
+ $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
+
+
+
+
+ Use
+ Level3
+ true
+ true
+ true
+ $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;%(PreprocessorDefinitions)
+ true
+ pch.h
+
+
+ Windows
+ true
+ true
+ $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
+
+
+
+
+ Use
+ Level3
+ true
+ true
+ true
+ $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)
+ NDEBUG;%(PreprocessorDefinitions)
+ true
+ pch.h
+
+
+ Windows
+ true
+ true
+ $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+
+
+
+
+ {1584bad4-dbec-43d2-bc06-08c23f02489a}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TestNetTunnelSDK/TestNetTunnelSDK.vcxproj.filters b/TestNetTunnelSDK/TestNetTunnelSDK.vcxproj.filters
new file mode 100644
index 0000000..37fa268
--- /dev/null
+++ b/TestNetTunnelSDK/TestNetTunnelSDK.vcxproj.filters
@@ -0,0 +1,30 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ 源文件
+
+
+ 源文件
+
+
+
+
+ 头文件
+
+
+
\ No newline at end of file
diff --git a/TestNetTunnelSDK/TestNetTunnelSDK.vcxproj.user b/TestNetTunnelSDK/TestNetTunnelSDK.vcxproj.user
new file mode 100644
index 0000000..88a5509
--- /dev/null
+++ b/TestNetTunnelSDK/TestNetTunnelSDK.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/TestNetTunnelSDK/pch.cpp b/TestNetTunnelSDK/pch.cpp
new file mode 100644
index 0000000..b6fb8f4
--- /dev/null
+++ b/TestNetTunnelSDK/pch.cpp
@@ -0,0 +1,5 @@
+// pch.cpp: 与预编译标头对应的源文件
+
+#include "pch.h"
+
+// 当使用预编译的头时,需要使用此源文件,编译才能成功。
diff --git a/TestNetTunnelSDK/pch.h b/TestNetTunnelSDK/pch.h
new file mode 100644
index 0000000..69fcd40
--- /dev/null
+++ b/TestNetTunnelSDK/pch.h
@@ -0,0 +1,12 @@
+// pch.h: 这是预编译标头文件。
+// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
+// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
+// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
+// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。
+
+#ifndef PCH_H
+#define PCH_H
+
+// 添加要在此处预编译的标头
+
+#endif //PCH_H
diff --git a/tunnel_windows.sln b/tunnel_windows.sln
index f21ca20..bd8966b 100644
--- a/tunnel_windows.sln
+++ b/tunnel_windows.sln
@@ -10,6 +10,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetTunnelApp", "NetTunnelAp
{1584BAD4-DBEC-43D2-BC06-08C23F02489A} = {1584BAD4-DBEC-43D2-BC06-08C23F02489A}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestNetTunnelSDK", "TestNetTunnelSDK\TestNetTunnelSDK.vcxproj", "{61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {1584BAD4-DBEC-43D2-BC06-08C23F02489A} = {1584BAD4-DBEC-43D2-BC06-08C23F02489A}
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -44,6 +49,18 @@ Global
{79995848-FD05-46F5-A7FE-46265E540E32}.Release|x64.Build.0 = Release|Any CPU
{79995848-FD05-46F5-A7FE-46265E540E32}.Release|x86.ActiveCfg = Release|Any CPU
{79995848-FD05-46F5-A7FE-46265E540E32}.Release|x86.Build.0 = Release|Any CPU
+ {61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}.Debug|Any CPU.Build.0 = Debug|x64
+ {61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}.Debug|x64.ActiveCfg = Debug|x64
+ {61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}.Debug|x64.Build.0 = Debug|x64
+ {61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}.Debug|x86.ActiveCfg = Debug|Win32
+ {61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}.Debug|x86.Build.0 = Debug|Win32
+ {61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}.Release|Any CPU.ActiveCfg = Release|x64
+ {61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}.Release|Any CPU.Build.0 = Release|x64
+ {61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}.Release|x64.ActiveCfg = Release|x64
+ {61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}.Release|x64.Build.0 = Release|x64
+ {61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}.Release|x86.ActiveCfg = Release|Win32
+ {61FE87EB-A3BA-4A7E-971C-69CB05F5C81C}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE