├── NetDebugger ├── stdafx.h ├── ContainerWnd.h ├── CEditEx.cpp ├── TCPClient.h ├── TCPServer.h ├── TCPSwitch.h ├── UDPStream.h ├── Websocket.h ├── IAsyncStream.h ├── NetDebugger.rc ├── PopWindow.cpp ├── SerialPort.cpp ├── SerialPort.h ├── UDPStream.cpp ├── pch.cpp ├── NetDebugger.aps ├── res │ ├── language.ini │ ├── NetDebugger.ico │ ├── NetDebugger.rc2 │ └── mfc-popwnd.ttf ├── CTextSendEditor.h ├── LanguageService.cpp ├── targetver.h ├── NetDebugger.vcxproj.user ├── UserWMDefine.h ├── CPlaceholderEdit.h ├── IDeviceUI.h ├── IndicatorButton.h ├── CSettingDlg.h ├── CEditEx.h ├── pch.h ├── LanguageService.h ├── CHelpDialog.h ├── OEMStringHelper.hpp ├── CSelectControl.h ├── CHelpDialog.html ├── PopWindow.h ├── GdiplusAux.hpp ├── CHelpDialog.cpp ├── CDPropertyGridCtrl.h ├── ContainerWnd.cpp ├── CPlaceholderEdit.cpp ├── CSettingDlg.cpp ├── CRealTimeStatusCtrl.h ├── framework.h ├── Base64.h ├── CSendHistoryDlg.h ├── DataBuffer.h ├── NetDebugger.h ├── BlockingQueue.hpp ├── resource.h ├── IndicatorButton.cpp ├── CTextSendEditor.cpp ├── packages.config ├── MQTTClient.h ├── CSendHistoryDlg.cpp ├── NetDebugger.cpp ├── NetDebuggerDlg.h ├── CSelectControl.cpp ├── NetDebugger.vcxproj.filters ├── SHA1.h ├── TextEncodeType.h ├── TCPServer.cpp ├── CRealTimeStatusCtrl.cpp ├── CDPropertyGridCtrl.cpp ├── TCPClient.cpp ├── TCPSwitch.cpp ├── DataBuffer.cpp └── fast_memcpy.hpp ├── 85347.png ├── Screen ├── 191951.png ├── 192119.png └── 192618.png ├── .gitignore ├── .github └── workflows │ └── build.yml ├── readme.md ├── NetDebugger.sln └── BuildAllTargets.proj /NetDebugger/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | -------------------------------------------------------------------------------- /85347.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/85347.png -------------------------------------------------------------------------------- /NetDebugger/ContainerWnd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | void InitContainerWnd(void); 3 | 4 | -------------------------------------------------------------------------------- /Screen/191951.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/Screen/191951.png -------------------------------------------------------------------------------- /Screen/192119.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/Screen/192119.png -------------------------------------------------------------------------------- /Screen/192618.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/Screen/192618.png -------------------------------------------------------------------------------- /NetDebugger/CEditEx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/CEditEx.cpp -------------------------------------------------------------------------------- /NetDebugger/TCPClient.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/TCPClient.h -------------------------------------------------------------------------------- /NetDebugger/TCPServer.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/TCPServer.h -------------------------------------------------------------------------------- /NetDebugger/TCPSwitch.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/TCPSwitch.h -------------------------------------------------------------------------------- /NetDebugger/UDPStream.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/UDPStream.h -------------------------------------------------------------------------------- /NetDebugger/Websocket.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/Websocket.h -------------------------------------------------------------------------------- /NetDebugger/IAsyncStream.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/IAsyncStream.h -------------------------------------------------------------------------------- /NetDebugger/NetDebugger.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/NetDebugger.rc -------------------------------------------------------------------------------- /NetDebugger/PopWindow.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/PopWindow.cpp -------------------------------------------------------------------------------- /NetDebugger/SerialPort.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/SerialPort.cpp -------------------------------------------------------------------------------- /NetDebugger/SerialPort.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/SerialPort.h -------------------------------------------------------------------------------- /NetDebugger/UDPStream.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/UDPStream.cpp -------------------------------------------------------------------------------- /NetDebugger/pch.cpp: -------------------------------------------------------------------------------- 1 | // pch.cpp: 与预编译标头对应的源文件 2 | 3 | #include "pch.h" 4 | 5 | // 当使用预编译的头时,需要使用此源文件,编译才能成功。 6 | -------------------------------------------------------------------------------- /NetDebugger/NetDebugger.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/NetDebugger.aps -------------------------------------------------------------------------------- /NetDebugger/res/language.ini: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/res/language.ini -------------------------------------------------------------------------------- /NetDebugger/CTextSendEditor.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/CTextSendEditor.h -------------------------------------------------------------------------------- /NetDebugger/LanguageService.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/LanguageService.cpp -------------------------------------------------------------------------------- /NetDebugger/res/NetDebugger.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/res/NetDebugger.ico -------------------------------------------------------------------------------- /NetDebugger/res/NetDebugger.rc2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/res/NetDebugger.rc2 -------------------------------------------------------------------------------- /NetDebugger/res/mfc-popwnd.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhou-zhi-peng/NetDebugger/HEAD/NetDebugger/res/mfc-popwnd.ttf -------------------------------------------------------------------------------- /NetDebugger/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。 4 | 5 | // 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将 6 | // 将 _WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /NetDebugger/NetDebugger.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NetDebugger.rc 5 | 6 | -------------------------------------------------------------------------------- /NetDebugger/UserWMDefine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | constexpr UINT kWM_APP_USER = WM_USER + 20; 3 | constexpr UINT kWM_UI_THREAD_TASK = kWM_APP_USER + 1; 4 | constexpr UINT kWM_CDEVICE_PROPERTY_CHANGED = kWM_APP_USER + 2; 5 | constexpr UINT kWM_SELECT_BUTTON_CHANGED = kWM_APP_USER + 3; 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | NetDebugger/Debug 3 | NetDebugger/Release 4 | NetDebugger/x64 5 | 6 | # Ignore NuGet Packages 7 | *.nupkg 8 | # Ignore the packages folder 9 | **/packages/* 10 | # except build/, which is used as an MSBuild target. 11 | !**/packages/build/ 12 | # Uncomment if necessary however generally it will be regenerated when needed 13 | #!**/packages/repositories.config -------------------------------------------------------------------------------- /NetDebugger/CPlaceholderEdit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | class CPlaceholderEdit : 4 | public CEdit 5 | { 6 | public: 7 | void Placeholder(const CString& placeholder) { m_Placeholder = placeholder; } 8 | CString Placeholder() const { return m_Placeholder; } 9 | private: 10 | CString m_Placeholder; 11 | protected: 12 | DECLARE_MESSAGE_MAP() 13 | afx_msg void OnPaint(); 14 | }; 15 | 16 | -------------------------------------------------------------------------------- /NetDebugger/IDeviceUI.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "DataBuffer.h" 4 | 5 | class ISendEditor : public CMFCPropertyPage 6 | { 7 | public: 8 | virtual UINT GetDataType(void) = 0; 9 | virtual void SetDataType(UINT type) = 0; 10 | virtual void GetDataBuffer(std::function handler) = 0; 11 | virtual void ClearContent(void) = 0; 12 | virtual void SetContent(const void* data, size_t size) = 0; 13 | virtual void Create(void) = 0; 14 | virtual void Destroy(void) = 0; 15 | virtual void UpdateLanguage(void) = 0; 16 | }; -------------------------------------------------------------------------------- /NetDebugger/IndicatorButton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | class CIndicatorButton : 4 | public CButton 5 | { 6 | public: 7 | void SetActive(bool active) 8 | { 9 | if (m_Active != active) 10 | { 11 | m_Active = active; 12 | Invalidate(); 13 | } 14 | } 15 | private: 16 | bool m_Active = false; 17 | protected: 18 | DECLARE_MESSAGE_MAP() 19 | afx_msg void OnPaint(); 20 | afx_msg void OnNcPaint(); 21 | afx_msg BOOL OnEraseBkgnd(CDC* pDC); 22 | virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/); 23 | virtual void PreSubclassWindow(); 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /NetDebugger/CSettingDlg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | // CSettingDlg 对话框 5 | 6 | class CSettingDlg : public CDialogEx 7 | { 8 | DECLARE_DYNAMIC(CSettingDlg) 9 | 10 | public: 11 | CSettingDlg(CWnd* pParent = nullptr); // 标准构造函数 12 | virtual ~CSettingDlg(); 13 | 14 | // 对话框数据 15 | #ifdef AFX_DESIGN_TIME 16 | enum { IDD = IDD_SETTING_DIALOG }; 17 | #endif 18 | private: 19 | CComboBox m_LanguageCtrl; 20 | std::vector> m_Languages; 21 | protected: 22 | virtual BOOL OnInitDialog() override; 23 | virtual void DoDataExchange(CDataExchange* pDX) override; // DDX/DDV 支持 24 | virtual void OnOK() override; 25 | DECLARE_MESSAGE_MAP() 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /NetDebugger/CEditEx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | class CRichEditEx : public CRichEditCtrl 4 | { 5 | public: 6 | CRichEditEx(); 7 | virtual ~CRichEditEx(); 8 | public: 9 | void AppendLabelText(const std::wstring& text); 10 | void AppendText(const std::wstring& text); 11 | void SetText(const std::wstring& text); 12 | std::wstring GetContent(void); 13 | void ClearAll(void); 14 | void EnterHEXMode(); 15 | void ExitHEXMode(); 16 | private: 17 | void InitializeControl(); 18 | protected: 19 | virtual void PreSubclassWindow(); 20 | private: 21 | bool m_bHEXMode; 22 | protected: 23 | virtual BOOL PreTranslateMessage(MSG* pMsg); 24 | DECLARE_MESSAGE_MAP() 25 | public: 26 | afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /NetDebugger/pch.h: -------------------------------------------------------------------------------- 1 | // pch.h: 这是预编译标头文件。 2 | // 下方列出的文件仅编译一次,提高了将来生成的生成性能。 3 | // 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。 4 | // 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。 5 | // 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。 6 | 7 | #ifndef PCH_H 8 | #define PCH_H 9 | 10 | // 添加要在此处预编译的标头 11 | #include "framework.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #endif //PCH_H 36 | -------------------------------------------------------------------------------- /NetDebugger/LanguageService.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class LanguageData; 6 | class LanguageService 7 | { 8 | public: 9 | LanguageService(const LanguageService&) = delete; 10 | LanguageService(); 11 | ~LanguageService(); 12 | public: 13 | void LoadData(const void* buffer, size_t size); 14 | bool SetLanguage(const CString& lid); 15 | CString GetLanguage(void); 16 | CString Translate(const CString& tid); 17 | CString Translate(const CString& tid, const CString& lid); 18 | std::vector> Names(void); 19 | void SetDefaultLID(const CString& lid) { m_DefaultLID = lid; } 20 | CString GetDefaultLID(void) const { return m_DefaultLID; } 21 | private: 22 | CString m_CurrentLID; 23 | CString m_DefaultLID; 24 | std::unique_ptr m_Data; 25 | }; 26 | 27 | -------------------------------------------------------------------------------- /NetDebugger/CHelpDialog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _WIN32_WCE 4 | #error "Windows CE 不支持 CDHtmlDialog。" 5 | #endif 6 | 7 | // CHelpDialog 对话框 8 | 9 | class CHelpDialog : public CDHtmlDialog 10 | { 11 | DECLARE_DYNCREATE(CHelpDialog) 12 | 13 | public: 14 | CHelpDialog(CWnd* pParent = nullptr); // 标准构造函数 15 | virtual ~CHelpDialog(); 16 | // 重写 17 | // HRESULT OnButtonOK(IHTMLElement *pElement); 18 | // HRESULT OnButtonCancel(IHTMLElement *pElement); 19 | 20 | // 对话框数据 21 | #ifdef AFX_DESIGN_TIME 22 | enum { IDD = IDD_HELP_DIALOG, IDH = IDR_HTML_HELP}; 23 | #endif 24 | 25 | protected: 26 | virtual void DoDataExchange(CDataExchange* pDX) override; // DDX/DDV 支持 27 | virtual BOOL OnInitDialog() override; 28 | virtual BOOL CanAccessExternal() override; 29 | DECLARE_MESSAGE_MAP() 30 | DECLARE_DHTML_EVENT_MAP() 31 | }; 32 | -------------------------------------------------------------------------------- /NetDebugger/OEMStringHelper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | inline std::string WStringToString(const std::wstring& unicode) 4 | { 5 | auto len = WideCharToMultiByte(CP_UTF8, 0, unicode.c_str(), (int)unicode.length(), nullptr, 0, nullptr, nullptr); 6 | std::string utf8; 7 | utf8.resize(len); 8 | WideCharToMultiByte(CP_UTF8, 0, unicode.c_str(), (int)unicode.length(), const_cast(utf8.data()), (int)utf8.length(), nullptr, nullptr); 9 | return utf8; 10 | } 11 | 12 | inline std::wstring StringToWString(const std::string& mstring) 13 | { 14 | auto len = ::MultiByteToWideChar(CP_OEMCP, 0, mstring.data(), (int)mstring.length(), nullptr, 0); 15 | std::wstring wstr; 16 | wstr.resize(len); 17 | ::MultiByteToWideChar(CP_OEMCP, 0, mstring.data(), (int)mstring.length(), const_cast(wstr.data()), (int)wstr.length()); 18 | return wstr; 19 | } 20 | -------------------------------------------------------------------------------- /NetDebugger/CSelectControl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class CSelectControl : 6 | public CWnd 7 | { 8 | public: 9 | CSelectControl(); 10 | virtual ~CSelectControl(); 11 | public: 12 | void AddButton(CString text, UINT value); 13 | bool RemoveButtonAt(int index); 14 | void RemoveAllButton(); 15 | 16 | UINT GetValue() const; 17 | void SetValue(UINT value); 18 | private: 19 | struct ButtonItem 20 | { 21 | CString text; 22 | UINT value; 23 | CRect rect; 24 | }; 25 | std::vector m_Buttons; 26 | int m_SelectedIndex; 27 | int m_HoverIndex; 28 | bool m_Pressed; 29 | public: 30 | DECLARE_MESSAGE_MAP() 31 | afx_msg void OnPaint(); 32 | afx_msg BOOL OnEraseBkgnd(CDC* pDC); 33 | afx_msg void OnMouseMove(UINT nFlags, CPoint point); 34 | afx_msg void OnLButtonDown(UINT nFlags, CPoint point); 35 | afx_msg void OnMouseHover(UINT nFlags, CPoint point); 36 | afx_msg void OnMouseLeave(); 37 | afx_msg void OnLButtonUp(UINT nFlags, CPoint point); 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - '.github/*' 7 | - '*.md' 8 | pull_request: 9 | paths-ignore: 10 | - '.github/*' 11 | - '*.md' 12 | 13 | jobs: 14 | build: 15 | runs-on: windows-latest 16 | env: 17 | POWERSHELL_TELEMETRY_OPTOUT: 1 18 | steps: 19 | - uses: actions/checkout@v2 20 | - uses: microsoft/setup-msbuild@v1 21 | - name: Restore nuget package 22 | run: nuget restore 23 | - name: Build all targets 24 | run: msbuild -m BuildAllTargets.proj 25 | - name: Generate release tag 26 | id: tag 27 | run: echo "::set-output name=release_tag::NetDebugger_$(Get-Date -Format "yyyy.MM.dd_HH_mm")" 28 | - name: Release bin files 29 | uses: softprops/action-gh-release@v1 30 | with: 31 | tag_name: ${{ steps.tag.outputs.release_tag }} 32 | files: | 33 | Bin/NetDebugger_Debug_x86.exe 34 | Bin/NetDebugger_Debug_x64.exe 35 | Bin/NetDebugger_Release_x86.exe 36 | Bin/NetDebugger_Release_x64.exe -------------------------------------------------------------------------------- /NetDebugger/CHelpDialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 帮助文档 5 | 14 | 15 | 16 |

概述

17 |

该工具是用于网络调试的工具集,包括了串口(RS232/RS485/RS422 ...)、以太网(TCP/UDP)调试功能。可收发数据,或进行转发数据。

18 |

主界面说明

19 | 20 |

网络类型说明

21 |

串口通讯

22 |

简单的串口数据收发功能。

23 |

串口转发

24 |

将两个串口中的数据进行相互转发,并在界面上显示。

25 |

TCP 客户端

26 |

简单的TCP客户端,可连接服务器进行数据收发。

27 |

TCP 多并发客户端

28 |

可生成多个客户端,同时连接服务器进行数据收发。

29 |

TCP 服务器

30 |

简单的TCP服务端,可接受多个客户端进行数据收发。

31 |

TCP 转发服务器

32 |

启动一个TCP服务端,接受多个客户端,并将进行收到的数据转发到另一服务器,或将另一服务器的数据转发给客户端。

33 |

UDP 基础通讯

34 |

基本的UDP通讯模块,可设置本地绑定的地址

35 |

UDP 简易客户端

36 |

基本的UDP通讯模块,不需要设置本地绑定的地址

37 | 38 | -------------------------------------------------------------------------------- /NetDebugger/PopWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | 5 | class PopWindowListener; 6 | class PopWindow 7 | { 8 | public: 9 | enum WindowType 10 | { 11 | MNONE = 0, 12 | MINFO = 0xE650, 13 | MQUESTION = 0xE616, 14 | MOK = 0xE61D, 15 | MLOADING = 0xE65D, 16 | MERROR = 0xE67A, 17 | MWARNING = 0xE966 18 | }; 19 | 20 | static const int CLOSE_REASON_TIMEOUT = -1; 21 | static const int CLOSE_REASON_CLOSECMD = 0; 22 | public: 23 | static int Show( 24 | const CString& title, 25 | const CString& body, 26 | PopWindow::WindowType type, 27 | int duration = 0, 28 | std::shared_ptr listener = nullptr, 29 | const CString* buttons = nullptr); 30 | 31 | static void Update( 32 | int windowId, 33 | const CString& title, 34 | const CString& body, 35 | PopWindow::WindowType type = MNONE, 36 | int duration = 0); 37 | 38 | static void Close(int windowId); 39 | }; 40 | 41 | class PopWindowListener 42 | { 43 | public: 44 | std::function OnCreate; 45 | std::function OnUpdate; 46 | std::function OnClosing; 47 | std::function OnClosed; 48 | }; 49 | -------------------------------------------------------------------------------- /NetDebugger/GdiplusAux.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | inline Gdiplus::REAL MeasureStringHeight(Gdiplus::Graphics& graphics, const CString& str, const Gdiplus::Font& font, int width) 4 | { 5 | Gdiplus::RectF newSizeText; 6 | auto h = font.GetHeight(&graphics); 7 | Gdiplus::RectF rcText(0.0f, 0.0f, (Gdiplus::REAL)width, h); 8 | rcText.Height = 0; 9 | newSizeText.Width = rcText.Width; 10 | graphics.MeasureString(str.GetString(), str.GetLength(), &font, rcText, &newSizeText); 11 | return newSizeText.Height; 12 | } 13 | 14 | inline std::shared_ptr CreateUIFontFamily() 15 | { 16 | std::shared_ptr fontFamily(new Gdiplus::FontFamily(L"Microsoft YaHei")); 17 | if (fontFamily->GetLastStatus() != Gdiplus::Status::Ok) 18 | fontFamily.reset(new Gdiplus::FontFamily(L"Arial")); 19 | if (fontFamily->GetLastStatus() != Gdiplus::Status::Ok) 20 | fontFamily.reset(new Gdiplus::FontFamily(L"宋体")); 21 | if (fontFamily->GetLastStatus() != Gdiplus::Status::Ok) 22 | { 23 | LOGFONT logfont; 24 | auto hFont = GetStockObject(DEFAULT_GUI_FONT); 25 | ::GetObject(hFont, sizeof(LOGFONT), &logfont); 26 | fontFamily.reset(new Gdiplus::FontFamily(logfont.lfFaceName)); 27 | } 28 | 29 | if (fontFamily->GetLastStatus() != Gdiplus::Status::Ok) 30 | return nullptr; 31 | return fontFamily; 32 | } -------------------------------------------------------------------------------- /NetDebugger/CHelpDialog.cpp: -------------------------------------------------------------------------------- 1 | // CHelpDialog.cpp: 实现文件 2 | // 3 | 4 | #include "pch.h" 5 | #include "NetDebugger.h" 6 | #include "CHelpDialog.h" 7 | 8 | 9 | // CHelpDialog 对话框 10 | 11 | IMPLEMENT_DYNCREATE(CHelpDialog, CDHtmlDialog) 12 | 13 | CHelpDialog::CHelpDialog(CWnd* pParent /*=nullptr*/) 14 | : CDHtmlDialog(IDD_HELP_DIALOG, IDR_HTML_HELP, pParent) 15 | { 16 | 17 | } 18 | 19 | CHelpDialog::~CHelpDialog() 20 | { 21 | } 22 | 23 | void CHelpDialog::DoDataExchange(CDataExchange* pDX) 24 | { 25 | CDHtmlDialog::DoDataExchange(pDX); 26 | } 27 | 28 | BOOL CHelpDialog::OnInitDialog() 29 | { 30 | CDHtmlDialog::OnInitDialog(); 31 | //SetExternalDispatch(this); 32 | return TRUE; 33 | } 34 | 35 | BOOL CHelpDialog::CanAccessExternal() 36 | { 37 | return TRUE; 38 | } 39 | 40 | BEGIN_MESSAGE_MAP(CHelpDialog, CDHtmlDialog) 41 | END_MESSAGE_MAP() 42 | 43 | BEGIN_DHTML_EVENT_MAP(CHelpDialog) 44 | END_DHTML_EVENT_MAP() 45 | 46 | //DHTML_EVENT_ONCLICK(_T("ButtonOK"), OnButtonOK) 47 | //DHTML_EVENT_ONCLICK(_T("ButtonCancel"), OnButtonCancel) 48 | 49 | // CHelpDialog 消息处理程序 50 | 51 | //HRESULT CHelpDialog::OnButtonOK(IHTMLElement* /*pElement*/) 52 | //{ 53 | // OnOK(); 54 | // return S_OK; 55 | //} 56 | // 57 | //HRESULT CHelpDialog::OnButtonCancel(IHTMLElement* /*pElement*/) 58 | //{ 59 | // OnCancel(); 60 | // return S_OK; 61 | //} 62 | -------------------------------------------------------------------------------- /NetDebugger/CDPropertyGridCtrl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "IAsyncStream.h" 3 | 4 | class CPropertyTableCtrl : public CMFCPropertyGridCtrl 5 | { 6 | public: 7 | using PropertyDescription = IDevice::PD; 8 | void UpdateProperties(); 9 | void UpdatePropertiesTitle(); 10 | void Clear(); 11 | void AddProperty(PropertyDescription pd); 12 | void UpdateDeviceStatus(bool started); 13 | protected: 14 | virtual void OnPropertyChanged(CMFCPropertyGridProperty* pProp) const override; 15 | virtual void OnDrawBorder(CDC* pDC) override; 16 | }; 17 | 18 | class DeviceProperty : public CMFCPropertyGridProperty 19 | { 20 | friend class CPropertyTableCtrl; 21 | public: 22 | using CMFCPropertyGridProperty::CMFCPropertyGridProperty; 23 | public: 24 | CPropertyTableCtrl::PropertyDescription pd; 25 | public: 26 | void UpdatePropertyValue(void); 27 | void UpdatePropertyTitle(void); 28 | protected: 29 | virtual void OnDrawValue(CDC* pDC, CRect rect) override; 30 | 31 | virtual void OnDrawName(CDC* pDC, CRect rect) override; 32 | 33 | virtual void OnDrawDescription(CDC* pDC, CRect rect) override; 34 | 35 | virtual void OnClickButton(CPoint point) override; 36 | 37 | virtual BOOL OnSetCursor() const override; 38 | 39 | virtual void OnSelectCombo() override; 40 | 41 | virtual CString GetValueTooltip() override; 42 | private: 43 | void SetDroppedAutoWidth(); 44 | private: 45 | IDevice::PropertyDescription::EnumOptions m_LastOptions; 46 | }; -------------------------------------------------------------------------------- /NetDebugger/ContainerWnd.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "ContainerWnd.h" 3 | 4 | static LRESULT WINAPI ContainerControlWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) 5 | { 6 | if (Msg == WM_SIZE) 7 | { 8 | HWND subWnd = ::GetWindow(hWnd, GW_CHILD); 9 | CRect rect; 10 | GetClientRect(hWnd, &rect); 11 | MoveWindow(subWnd, 0, 0, rect.Width(), rect.Height(), TRUE); 12 | } 13 | return ::DefWindowProc(hWnd, Msg, wParam, lParam); 14 | } 15 | 16 | static BOOL RegisterWindowClass(void) 17 | { 18 | static const TCHAR className[] = L"ND_CONTAINER_CONTROL"; 19 | WNDCLASS windowclass; 20 | HINSTANCE hInstance = AfxGetInstanceHandle(); 21 | 22 | if (!(::GetClassInfo(hInstance, className, &windowclass))) 23 | { 24 | windowclass.style = CS_DBLCLKS | CS_NOCLOSE; 25 | windowclass.lpfnWndProc = ::ContainerControlWindowProc; 26 | windowclass.cbClsExtra = 0; 27 | windowclass.cbWndExtra = sizeof(void*); 28 | windowclass.hInstance = hInstance; 29 | windowclass.hIcon = nullptr; 30 | windowclass.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); 31 | windowclass.hbrBackground = (HBRUSH)::GetStockObject(NULL_BRUSH); 32 | windowclass.lpszMenuName = nullptr; 33 | windowclass.lpszClassName = className; 34 | if (!AfxRegisterClass(&windowclass)) 35 | { 36 | AfxThrowResourceException(); 37 | return FALSE; 38 | } 39 | } 40 | return TRUE; 41 | } 42 | 43 | void InitContainerWnd(void) 44 | { 45 | RegisterWindowClass(); 46 | } -------------------------------------------------------------------------------- /NetDebugger/CPlaceholderEdit.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "CPlaceholderEdit.h" 3 | #include "GdiplusAux.hpp" 4 | 5 | BEGIN_MESSAGE_MAP(CPlaceholderEdit, CEdit) 6 | ON_WM_PAINT() 7 | END_MESSAGE_MAP() 8 | 9 | 10 | void CPlaceholderEdit::OnPaint() 11 | { 12 | if (IsWindowEnabled() && GetWindowTextLength() <= 0 && this->GetFocus()!=this) 13 | { 14 | CPaintDC dc(this); 15 | Gdiplus::Graphics graphics(dc); 16 | CRect rect; 17 | graphics.Clear(Gdiplus::Color::White); 18 | GetClientRect(&rect); 19 | Gdiplus::RectF rcItem((Gdiplus::REAL)rect.left, (Gdiplus::REAL)rect.top, (Gdiplus::REAL)rect.Width(), (Gdiplus::REAL)rect.Height()); 20 | graphics.SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeAntiAlias); 21 | graphics.SetTextRenderingHint(Gdiplus::TextRenderingHint::TextRenderingHintClearTypeGridFit); 22 | Gdiplus::StringFormat sf; 23 | sf.SetAlignment(Gdiplus::StringAlignment::StringAlignmentNear); 24 | sf.SetLineAlignment(Gdiplus::StringAlignment::StringAlignmentCenter); 25 | sf.SetTrimming(Gdiplus::StringTrimming::StringTrimmingEllipsisCharacter); 26 | 27 | 28 | auto fontFamily = CreateUIFontFamily(); 29 | Gdiplus::SolidBrush textBrush(Gdiplus::Color(130, 0, 0, 0)); 30 | Gdiplus::Font fontLabel(fontFamily.get(), 12.0f, Gdiplus::FontStyleItalic, Gdiplus::UnitPixel); 31 | graphics.DrawString(m_Placeholder, m_Placeholder.GetLength(), &fontLabel, rcItem, &sf, &textBrush); 32 | } 33 | else 34 | { 35 | CEdit::OnPaint(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /NetDebugger/CSettingDlg.cpp: -------------------------------------------------------------------------------- 1 | // CSettingDlg.cpp: 实现文件 2 | // 3 | 4 | #include "pch.h" 5 | #include "NetDebugger.h" 6 | #include "CSettingDlg.h" 7 | #include "afxdialogex.h" 8 | 9 | 10 | // CSettingDlg 对话框 11 | 12 | IMPLEMENT_DYNAMIC(CSettingDlg, CDialogEx) 13 | 14 | CSettingDlg::CSettingDlg(CWnd* pParent /*=nullptr*/) 15 | : CDialogEx(IDD_SETTING_DIALOG, pParent) 16 | { 17 | 18 | } 19 | 20 | CSettingDlg::~CSettingDlg() 21 | { 22 | } 23 | 24 | void CSettingDlg::DoDataExchange(CDataExchange* pDX) 25 | { 26 | CDialogEx::DoDataExchange(pDX); 27 | DDX_Control(pDX, IDC_COMBO_LANGUAGE, m_LanguageCtrl); 28 | } 29 | 30 | 31 | BEGIN_MESSAGE_MAP(CSettingDlg, CDialogEx) 32 | END_MESSAGE_MAP() 33 | 34 | 35 | BOOL CSettingDlg::OnInitDialog() 36 | { 37 | CDialogEx::OnInitDialog(); 38 | m_Languages = theApp.GetLS().Names(); 39 | auto curLid = theApp.GetLS().GetLanguage(); 40 | int index = 0; 41 | //auto wndLC = ::GetDlgItem(m_hWnd, IDC_COMBO_LANGUAGE); 42 | for (auto n : m_Languages) 43 | { 44 | auto item = m_LanguageCtrl.AddString(n.second); 45 | m_LanguageCtrl.SetItemData(item, index); 46 | if (n.first == curLid) 47 | m_LanguageCtrl.SetCurSel(item); 48 | ++index; 49 | } 50 | return TRUE; 51 | } 52 | 53 | void CSettingDlg::OnOK() 54 | { 55 | UpdateData(TRUE); 56 | auto sel = m_LanguageCtrl.GetCurSel(); 57 | if (sel >= 0) 58 | { 59 | auto i = (int)m_LanguageCtrl.GetItemData(sel); 60 | theApp.GetLS().SetLanguage(m_Languages[i].first); 61 | } 62 | CDialogEx::OnOK(); 63 | } 64 | -------------------------------------------------------------------------------- /NetDebugger/CRealTimeStatusCtrl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | class CRealTimeStatusCtrl : 4 | public CWnd 5 | { 6 | public: 7 | CRealTimeStatusCtrl(); 8 | virtual ~CRealTimeStatusCtrl(); 9 | public: 10 | void Clear(void) 11 | { 12 | m_ReadSpeeds.clear(); 13 | m_WriteSpeeds.clear(); 14 | m_MaxReadSpeed = 0; 15 | m_MaxWriteSpeed = 0; 16 | m_readBytes = 0; 17 | m_writeBytes = 0; 18 | m_lastUpdateTime = std::chrono::high_resolution_clock::now(); 19 | } 20 | void UpdateStatistics(bool connected, uint64_t readBytes, uint64_t writeBytes); 21 | private: 22 | void AddSpeedPoint(uint64_t readspeed, uint64_t writespeed); 23 | int DrawStatisicsString(Gdiplus::Graphics& graphics, const Gdiplus::RectF& clientRect); 24 | void DrawSpeedCurve(Gdiplus::Graphics& graphics, const Gdiplus::RectF& clientRect); 25 | void DrawDisconnectedStatus(Gdiplus::Graphics& graphics, const Gdiplus::RectF& clientRect); 26 | private: 27 | CString GetReadSpeedString(void) const; 28 | CString GetWriteSpeedString(void) const; 29 | private: 30 | bool m_connected; 31 | uint64_t m_readBytes; 32 | uint64_t m_writeBytes; 33 | uint64_t m_MaxReadSpeed; 34 | uint64_t m_MaxWriteSpeed; 35 | uint64_t m_AveReadSpeed; 36 | uint64_t m_AveWriteSpeed; 37 | std::vector m_ReadSpeeds; 38 | std::vector m_WriteSpeeds; 39 | std::chrono::high_resolution_clock::time_point m_lastUpdateTime; 40 | public: 41 | DECLARE_MESSAGE_MAP() 42 | afx_msg BOOL OnEraseBkgnd(CDC* pDC); 43 | afx_msg void OnPaint(); 44 | }; 45 | 46 | -------------------------------------------------------------------------------- /NetDebugger/framework.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef VC_EXTRALEAN 4 | #define VC_EXTRALEAN // 从 Windows 头中排除极少使用的资料 5 | #endif 6 | 7 | #include "targetver.h" 8 | 9 | #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 10 | 11 | // 关闭 MFC 的一些常见且经常可放心忽略的隐藏警告消息 12 | #define _AFX_ALL_WARNINGS 13 | 14 | #include // MFC 核心组件和标准组件 15 | #include // MFC 扩展 16 | 17 | 18 | #include // MFC 自动化类 19 | 20 | 21 | 22 | #ifndef _AFX_NO_OLE_SUPPORT 23 | #include // MFC 对 Internet Explorer 4 公共控件的支持 24 | #endif 25 | #ifndef _AFX_NO_AFXCMN_SUPPORT 26 | #include // MFC 对 Windows 公共控件的支持 27 | #endif // _AFX_NO_AFXCMN_SUPPORT 28 | 29 | #include // MFC 支持功能区和控制条 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | #ifdef _UNICODE 40 | #if defined _M_IX86 41 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") 42 | #elif defined _M_X64 43 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") 44 | #else 45 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 46 | #endif 47 | #endif 48 | 49 | 50 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 3 | 工具原用于内部的一个压力测试工具,完善了一下,现在开放全部源代码发布出来,希望对您有些作用。 4 | 5 | ## 工具有什么用 6 | 7 | 该工具是用于网络调试的工具集,包括了串口(RS232/RS485/RS422 ...)、以太网(TCP/UDP)调试功能。可收发数据,或进行转发数据。可用于模拟各类TCP、UDP、串口、websocket 服务端与客户 8 | 9 | ## 如何编译 10 | 11 | **编译器:** 12 | 该工具使用 VS2017 编译 13 | **依赖第三方库:** 14 | 15 | + boost 1.68.0 16 | 17 | **编译配置:** 18 | 19 | + “项目配置-> C++ -> 附加包含目录” 添加boost 1.68.0 包含目录 20 | + “项目配置-> 链接器 -> 附加库目录” 添加boost 1.68.0 库输出目录 21 | 22 | ## 屏幕截图 23 | 24 | ![支持作者](https://github.com/Zhou-zhi-peng/NetDebugger/blob/main/Screen/191951.png?raw=true) 25 | 26 | ![支持作者](https://github.com/Zhou-zhi-peng/NetDebugger/blob/main/Screen/192119.png?raw=true) 27 | 28 | ![支持作者](https://github.com/Zhou-zhi-peng/NetDebugger/blob/main/Screen/192618.png?raw=true) 29 | 30 | ## 问答 31 | 32 | **为什么使用 MFC?** 33 | 单纯的就是想做成单文件绿色版可执行文件,目前成熟的UI框架看下来,还就它比较合适。 34 | 35 | **转发功能有什么用?** 36 | 转发使用场景 37 | 如果希望监听两个设备(或客户端与服务端)之间的通信,同时还希望可以模拟客户端或服务端发送数据,则需要用到转发。 38 | 39 | **多并发客户端是什么?** 40 | 该类客户端主要用于同时生成大量客户端连接到服务器,并进行数据收发,用以对服务器端进行压力测试。 41 | 42 | **不想编译BOOST库,如何直接使用?** 43 | 直接下载Bin目录中的EXE文件就可以直接使用。
44 | 如果报应用程序配置不正确,请安装VS2017 C++ 运行时库,也在Bin目录中可以直接下载。
45 | 软件下载页面:
46 | >
47 | > 如果没什么特殊需求直接下载NetDebugger_Release_x64.exe
48 |
49 | 运行时下载地址:
50 | X64: https://aka.ms/vs/17/release/vc_redist.x64.exe
51 | X86: https://aka.ms/vs/17/release/vc_redist.x86.exe
52 | 53 | ## 支持&捐赠 54 | 55 | 如果你觉得该软件对你有帮助,想支持一下作者,可扫码向作者进行捐赠,
56 | 如果觉得没什么用,也可以向作者提出你的意见:
57 |
58 | 59 | ![支持作者](https://github.com/Zhou-zhi-peng/NetDebugger/blob/main/85347.png?raw=true) 60 | -------------------------------------------------------------------------------- /NetDebugger.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.1231 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetDebugger", "NetDebugger\NetDebugger.vcxproj", "{F849118B-97D8-47C1-84C3-B6E6638C9531}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM64 = Debug|ARM64 11 | Debug|x64 = Debug|x64 12 | Debug|x86 = Debug|x86 13 | Release|ARM64 = Release|ARM64 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {F849118B-97D8-47C1-84C3-B6E6638C9531}.Debug|ARM64.ActiveCfg = Debug|Win32 19 | {F849118B-97D8-47C1-84C3-B6E6638C9531}.Debug|x64.ActiveCfg = Debug|x64 20 | {F849118B-97D8-47C1-84C3-B6E6638C9531}.Debug|x64.Build.0 = Debug|x64 21 | {F849118B-97D8-47C1-84C3-B6E6638C9531}.Debug|x86.ActiveCfg = Debug|Win32 22 | {F849118B-97D8-47C1-84C3-B6E6638C9531}.Debug|x86.Build.0 = Debug|Win32 23 | {F849118B-97D8-47C1-84C3-B6E6638C9531}.Release|ARM64.ActiveCfg = Release|Win32 24 | {F849118B-97D8-47C1-84C3-B6E6638C9531}.Release|x64.ActiveCfg = Release|x64 25 | {F849118B-97D8-47C1-84C3-B6E6638C9531}.Release|x64.Build.0 = Release|x64 26 | {F849118B-97D8-47C1-84C3-B6E6638C9531}.Release|x86.ActiveCfg = Release|Win32 27 | {F849118B-97D8-47C1-84C3-B6E6638C9531}.Release|x86.Build.0 = Release|Win32 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | GlobalSection(ExtensibilityGlobals) = postSolution 33 | SolutionGuid = {5FA64C84-05C8-4409-95BB-2F1511213488} 34 | EndGlobalSection 35 | EndGlobal 36 | -------------------------------------------------------------------------------- /NetDebugger/Base64.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | inline std::string Base64EncodeString(const void* pdata, size_t data_len) 9 | { 10 | static const char baseCharTable[] = 11 | { 12 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 13 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 14 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 15 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' 16 | }; 17 | 18 | size_t i; 19 | std::string encode; 20 | auto data = reinterpret_cast(pdata); 21 | for (i = 0; i + 3 <= data_len; i += 3) 22 | { 23 | encode.push_back(baseCharTable[data[i] >> 2]); 24 | encode.push_back(baseCharTable[((data[i] << 4) & 0x30) | (data[i + 1] >> 4)]); 25 | encode.push_back(baseCharTable[((data[i + 1] << 2) & 0x3c) | (data[i + 2] >> 6)]); 26 | encode.push_back(baseCharTable[data[i + 2] & 0x3f]); 27 | } 28 | 29 | if (i < data_len) 30 | { 31 | auto tail = data_len - i; 32 | if (tail == 1) 33 | { 34 | encode.push_back(baseCharTable[data[i] >> 2]); 35 | encode.push_back(baseCharTable[(data[i] << 4) & 0x30]); 36 | encode.push_back('='); 37 | encode.push_back('='); 38 | } 39 | else 40 | { 41 | encode.push_back(baseCharTable[data[i] >> 2]); 42 | encode.push_back(baseCharTable[((data[i] << 4) & 0x30) | (data[i + 1] >> 4)]); 43 | encode.push_back(baseCharTable[(data[i + 1] << 2) & 0x3c]); 44 | encode.push_back('='); 45 | } 46 | } 47 | return encode; 48 | } 49 | 50 | inline std::string Base64EncodeString(const std::string& data) 51 | { 52 | return Base64EncodeString(data.data(), data.length()); 53 | } 54 | 55 | inline std::string Base64EncodeString(const std::vector& data) 56 | { 57 | return Base64EncodeString(data.data(), data.size()); 58 | } 59 | -------------------------------------------------------------------------------- /NetDebugger/CSendHistoryDlg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CSelectControl.h" 3 | #include "CEditEx.h" 4 | // CSendHistoryDlg 对话框 5 | 6 | class SendHistoryRecord 7 | { 8 | public: 9 | int TextEncoding; 10 | std::vector DataBuffer; 11 | 12 | SendHistoryRecord() : 13 | TextEncoding(0) 14 | { 15 | 16 | } 17 | ~SendHistoryRecord() = default; 18 | 19 | bool operator == (const SendHistoryRecord& b) const 20 | { 21 | return TextEncoding == b.TextEncoding 22 | && DataBuffer.size() == b.DataBuffer.size() 23 | && (memcmp(DataBuffer.data(), b.DataBuffer.data(), b.DataBuffer.size()) == 0); 24 | } 25 | 26 | bool operator != (const SendHistoryRecord& b) const 27 | { 28 | return TextEncoding != b.TextEncoding 29 | || DataBuffer.size() != b.DataBuffer.size() 30 | || (memcmp(DataBuffer.data(), b.DataBuffer.data(), b.DataBuffer.size()) != 0); 31 | } 32 | }; 33 | 34 | class CSendHistoryDlg : public CDialogEx 35 | { 36 | DECLARE_DYNAMIC(CSendHistoryDlg) 37 | 38 | public: 39 | CSendHistoryDlg(std::vector>& historys, CWnd* pParent = nullptr); // 标准构造函数 40 | virtual ~CSendHistoryDlg(); 41 | public: 42 | std::shared_ptr GetResult(void)const { return m_Result; } 43 | // 对话框数据 44 | #ifdef AFX_DESIGN_TIME 45 | enum { IDD = IDD_SEND_HISTORY_DIALOG }; 46 | #endif 47 | 48 | protected: 49 | virtual BOOL OnInitDialog(); 50 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 51 | 52 | DECLARE_MESSAGE_MAP() 53 | private: 54 | CSelectControl m_DataDisplayModeCtrl; 55 | CRichEditEx m_DataEditCtrl; 56 | CListCtrl m_HistoryListCtrl; 57 | std::shared_ptr m_Result; 58 | std::vector>& m_HistoryRecords; 59 | public: 60 | afx_msg void OnBnClickedButtonClear(); 61 | afx_msg void OnBnClickedOk(); 62 | afx_msg void OnLvnItemchangedListHistory(NMHDR *pNMHDR, LRESULT *pResult); 63 | afx_msg void OnNMDblclkListHistory(NMHDR *pNMHDR, LRESULT *pResult); 64 | }; 65 | -------------------------------------------------------------------------------- /BuildAllTargets.proj: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | $(MSBuildThisFileDirectory)*.sln 7 | 8 | 9 | 10 | Configuration=Debug;Platform=x86 11 | 12 | 13 | Configuration=Release;Platform=x86 14 | 15 | 16 | Configuration=Debug;Platform=x64 17 | 18 | 19 | Configuration=Release;Platform=x64 20 | 21 | 27 | 28 | 29 | 34 | 35 | 36 | 42 | 43 | 44 | 50 | 51 | -------------------------------------------------------------------------------- /NetDebugger/DataBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class DataBufferPrivateImpl; 6 | class DataBuffer 7 | { 8 | friend class DataBufferView; 9 | friend class DataBufferIterator; 10 | public: 11 | DataBuffer(const DataBuffer&) = delete; 12 | DataBuffer(void); 13 | DataBuffer(DataBuffer&& value); 14 | ~DataBuffer(void); 15 | public: 16 | size_t Size(void) const; 17 | size_t GapSize(void) const; 18 | size_t CopyData(size_t index, size_t size, void* buffer) const; 19 | uint8_t GetAt(size_t index) const; 20 | void SetAt(size_t index, uint8_t value); 21 | void Append(const void* data, size_t size); 22 | void AppendFill(uint8_t fill, size_t size); 23 | void Prepend(const void* data, size_t size); 24 | void PrependFill(uint8_t fill, size_t size); 25 | void Insert(const void* data, size_t index, size_t size); 26 | void InsertFill(size_t index, size_t size, uint8_t fill); 27 | void Replace(const void* dest,size_t destSize, size_t srcIndex, size_t srcSize); 28 | void Fill(uint8_t fill, size_t index, size_t size); 29 | void Remove(size_t index, size_t size); 30 | void Compress(void); 31 | void Resize(size_t size); 32 | void Clear(void); 33 | private: 34 | std::unique_ptr m_Impl; 35 | }; 36 | 37 | class DataBufferView 38 | { 39 | public: 40 | DataBufferView(void) = delete; 41 | DataBufferView(const DataBufferView& view); 42 | DataBufferView(const DataBuffer& buffer); 43 | ~DataBufferView() = default; 44 | public: 45 | size_t Position(void) const { return m_Position; } 46 | void Position(size_t pos); 47 | size_t GetData(void* buffer, size_t size); 48 | int GetByte(void); 49 | bool EndOfBuffer(void) const; 50 | private: 51 | const DataBuffer& m_DataBuffer; 52 | size_t m_Position; 53 | void* m_pBuffer; 54 | }; 55 | 56 | class DataBufferIterator 57 | { 58 | public: 59 | DataBufferIterator(void) = delete; 60 | DataBufferIterator(const DataBufferIterator& it); 61 | DataBufferIterator(DataBufferIterator&& it); 62 | DataBufferIterator(const DataBuffer& buffer); 63 | ~DataBufferIterator() = default; 64 | public: 65 | bool Next(void); 66 | bool Prev(void); 67 | public: 68 | const uint8_t* Data(void) const; 69 | const size_t Length(void) const; 70 | private: 71 | void* m_pPrivateImpl; 72 | }; 73 | -------------------------------------------------------------------------------- /NetDebugger/NetDebugger.h: -------------------------------------------------------------------------------- 1 | 2 | // NetDebugger.h: PROJECT_NAME 应用程序的主头文件 3 | // 4 | 5 | #pragma once 6 | 7 | #ifndef __AFXWIN_H__ 8 | #error "include 'pch.h' before including this file for PCH" 9 | #endif 10 | 11 | #include "resource.h" // 主符号 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "LanguageService.h" 19 | 20 | // CNetDebuggerApp: 21 | // 有关此类的实现,请参阅 NetDebugger.cpp 22 | // 23 | class IDevice; 24 | class CNetDebuggerApp : public CWinApp 25 | { 26 | public: 27 | using FactoryCreator = std::function(void)>; 28 | public: 29 | CNetDebuggerApp(); 30 | 31 | // 重写 32 | public: 33 | virtual BOOL InitInstance(); 34 | 35 | public: 36 | boost::asio::io_context& GetIOContext(void) { return m_IOContext; } 37 | public: 38 | using TypeDesc = std::vector>; 39 | std::shared_ptr CreateCommunicationDevice(const std::wstring& className); 40 | void RegisterDeviceClass(const std::wstring& className, const std::wstring& title, FactoryCreator crector); 41 | TypeDesc GetDeviceTypes(void); 42 | LanguageService& GetLS(void) { return m_LangService; } 43 | private: 44 | using CreatorNode = std::tuple; 45 | boost::asio::io_context m_IOContext; 46 | std::map m_CDCreatorMap; 47 | LanguageService m_LangService; 48 | // 实现 49 | 50 | DECLARE_MESSAGE_MAP() 51 | 52 | afx_msg void OnHelp(); 53 | }; 54 | 55 | extern CNetDebuggerApp theApp; 56 | 57 | class AutoRegisterCDClass 58 | { 59 | public: 60 | AutoRegisterCDClass(const std::wstring& className, const std::wstring& title, CNetDebuggerApp::FactoryCreator creator) 61 | { 62 | theApp.RegisterDeviceClass(className, title, creator); 63 | } 64 | AutoRegisterCDClass(const std::wstring& className, CNetDebuggerApp::FactoryCreator creator) 65 | { 66 | theApp.RegisterDeviceClass(className, className, creator); 67 | } 68 | 69 | ~AutoRegisterCDClass(void) = default; 70 | }; 71 | 72 | #define REGISTER_CLASS(className) \ 73 | AutoRegisterCDClass _AutoRegisterDevice_##className##_object__( \ 74 | L#className, \ 75 | [](){ \ 76 | return std::dynamic_pointer_cast(std::make_shared()); \ 77 | } \ 78 | ) 79 | 80 | #define REGISTER_CLASS_TITLE(className,title) \ 81 | AutoRegisterCDClass _AutoRegisterDevice_##className##_object__( \ 82 | L#className, \ 83 | title, \ 84 | [](){ \ 85 | return std::dynamic_pointer_cast(std::make_shared()); \ 86 | } \ 87 | ) 88 | 89 | #define LSTEXT(t) theApp.GetLS().Translate(L#t) 90 | #define LSVT(t) theApp.GetLS().Translate(t) -------------------------------------------------------------------------------- /NetDebugger/BlockingQueue.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | template 11 | class BlockingQueue 12 | { 13 | public: 14 | BlockingQueue(size_t max_queue = 0) 15 | :m_max_queue(max_queue), 16 | m_quit(false) 17 | { 18 | } 19 | 20 | ~BlockingQueue() = default; 21 | 22 | void Push(const T& element) 23 | { 24 | { 25 | std::unique_lock lock(m_Mutex); 26 | if (m_max_queue != 0) 27 | { 28 | while (m_elements.size() > m_max_queue) 29 | { 30 | if (m_quit) 31 | { 32 | m_elements.push(std::move(element)); 33 | return; 34 | } 35 | m_elements_nonfull.wait(lock); 36 | } 37 | } 38 | m_elements.push(std::move(element)); 39 | } 40 | m_elements_nonempty.notify_one(); 41 | } 42 | 43 | bool TryPop(T& element) 44 | { 45 | { 46 | std::unique_lock lock(m_Mutex); 47 | if (m_elements.empty()) 48 | { 49 | return false; 50 | } 51 | element = std::move(m_elements.front()); 52 | m_elements.pop(); 53 | } 54 | m_elements_nonfull.notify_one(); 55 | return true; 56 | } 57 | 58 | T WaitForPop(void) 59 | { 60 | T result; 61 | { 62 | std::unique_lock lock(m_Mutex); 63 | while (m_elements.empty() && !m_quit) 64 | { 65 | m_elements_nonempty.wait(lock); 66 | } 67 | 68 | if (m_quit) 69 | { 70 | return result; 71 | } 72 | 73 | result = std::move(m_elements.front()); 74 | m_elements.pop(); 75 | } 76 | m_elements_nonfull.notify_one(); 77 | return result; 78 | } 79 | 80 | void PopAll(std::queue& result) 81 | { 82 | std::queue empty; 83 | result.swap(empty); 84 | { 85 | { 86 | std::unique_lock lock(m_Mutex); 87 | result.swap(m_elements); 88 | } 89 | m_elements_nonfull.notify_all(); 90 | } 91 | } 92 | 93 | void Clear() 94 | { 95 | std::queue empty; 96 | std::unique_lock lock(m_Mutex); 97 | m_elements.swap(empty); 98 | m_elements_nonfull.notify_all(); 99 | } 100 | 101 | void Stop() 102 | { 103 | { 104 | std::unique_lock lock(m_Mutex); 105 | m_quit = true; 106 | } 107 | m_elements_nonempty.notify_all(); 108 | std::queue empty; 109 | PopAll(empty); 110 | } 111 | 112 | bool IsStoped(void)const { return m_quit; } 113 | private: 114 | std::mutex m_Mutex; 115 | std::condition_variable m_elements_nonempty; 116 | std::condition_variable m_elements_nonfull; 117 | size_t m_max_queue; 118 | bool m_quit; 119 | std::queue m_elements; 120 | }; -------------------------------------------------------------------------------- /NetDebugger/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ 生成的包含文件。 3 | // 供 NetDebugger.rc 使用 4 | // 5 | #define IDM_ABOUTBOX 0x0010 6 | #define IDM_SETTING 0x0020 7 | #define IDD_ABOUTBOX 100 8 | #define IDS_ABOUTBOX 101 9 | #define IDD_NETDEBUGGER_DIALOG 102 10 | #define IDR_HTML_HELP 103 11 | #define IDD_TEXT_SEND_EDITOR 106 12 | #define IDR_MAINFRAME 128 13 | #define IDR_FONT_POPWND 136 14 | #define IDD_SEND_HISTORY_DIALOG 138 15 | #define IDR_LANGUAGE 141 16 | #define IDD_SETTING_DIALOG 142 17 | #define IDD_HELP_DIALOG 144 18 | #define IDC_CMB_NET_TYPE 1007 19 | #define IDC_CMB_CHANNELS 1008 20 | #define IDC_BUTTON_SEND 1014 21 | #define IDC_BUTTON_SEND_FILE 1015 22 | #define IDC_BUTTON_RECV_SAVE 1016 23 | #define IDC_RECV_DISPLAY_TYPE 1017 24 | #define IDC_BUTTON_RECV_CLEAR 1018 25 | #define IDC_BUTTON_SEND_CLEAR 1019 26 | #define IDC_NET_DEVICE_SETTING 1020 27 | #define IDC_BUTTON_CLEAR_STATISTICS 1021 28 | #define IDC_BUTTON_CONNECT 1022 29 | #define IDC_RECV_EDITBOX 1023 30 | #define IDC_SEND_EDITBOX 1024 31 | #define IDC_SEND_DISPLAY_TYPE 1025 32 | #define IDC_DEVICE_STATISTICS 1026 33 | #define IDC_BUTTON_CLOSE_CHANNEL 1027 34 | #define IDC_BUTTON_SEND_HISTORY 1028 35 | #define IDC_DATA_DISPLAY_MODE 1031 36 | #define IDC_DATA_EDIT_BOX 1032 37 | #define IDC_BUTTON_CLEAR 1035 38 | #define IDC_COMBO_MEMORY_MAX 1036 39 | #define IDC_CHECK_AUTO_SAVE 1037 40 | #define IDC_FILE_PATH 1038 41 | #define IDC_LIST_HISTORY 1039 42 | #define IDC_CHECK_AUTO_ADDITIONAL 1039 43 | #define IDC_CHECK_SHOW_RECVDATA 1041 44 | #define IDC_EDIT_SEND_INTERVAL 1042 45 | #define IDC_COMBO_LANGUAGE 1046 46 | #define IDC_SEND_EDIROR 1054 47 | #define IDC_STATIC_DEVICE_TYPE 1055 48 | #define IDC_STATIC_MEMORY_MAX 1056 49 | #define IDC_STATIC_CHANNEL 1057 50 | #define IDC_STATIC_V 1058 51 | #define IDC_STATIC_C 1059 52 | 53 | // Next default values for new objects 54 | // 55 | #ifdef APSTUDIO_INVOKED 56 | #ifndef APSTUDIO_READONLY_SYMBOLS 57 | #define _APS_NEXT_RESOURCE_VALUE 150 58 | #define _APS_NEXT_COMMAND_VALUE 32774 59 | #define _APS_NEXT_CONTROL_VALUE 1060 60 | #define _APS_NEXT_SYMED_VALUE 104 61 | #endif 62 | #endif 63 | -------------------------------------------------------------------------------- /NetDebugger/IndicatorButton.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "IndicatorButton.h" 3 | #include "GdiplusAux.hpp" 4 | 5 | BEGIN_MESSAGE_MAP(CIndicatorButton, CButton) 6 | ON_WM_PAINT() 7 | ON_WM_NCPAINT() 8 | ON_WM_ERASEBKGND() 9 | END_MESSAGE_MAP() 10 | 11 | 12 | void CIndicatorButton::OnPaint() 13 | { 14 | CButton::OnPaint(); 15 | } 16 | 17 | 18 | void CIndicatorButton::OnNcPaint() 19 | { 20 | } 21 | 22 | 23 | BOOL CIndicatorButton::OnEraseBkgnd(CDC* pDC) 24 | { 25 | return FALSE; 26 | } 27 | 28 | 29 | void CIndicatorButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 30 | { 31 | if (lpDrawItemStruct->CtlType != ODT_BUTTON) 32 | return; 33 | 34 | CDC pdc; 35 | pdc.Attach(lpDrawItemStruct->hDC); 36 | CMemDC memDC(pdc, this); 37 | auto& dc = memDC.GetDC(); 38 | Gdiplus::Graphics graphics(dc); 39 | CRect rcClient = lpDrawItemStruct->rcItem; 40 | Gdiplus::RectF gdiRect((Gdiplus::REAL)rcClient.left, (Gdiplus::REAL)rcClient.top, (Gdiplus::REAL)rcClient.Width(), (Gdiplus::REAL)rcClient.Height()); 41 | 42 | if (lpDrawItemStruct->itemState & ODS_SELECTED) 43 | graphics.Clear(Gdiplus::Color(0, 100, 146)); 44 | else if((lpDrawItemStruct->itemState & ODS_DISABLED) || (lpDrawItemStruct->itemState & ODS_GRAYED)) 45 | graphics.Clear(Gdiplus::Color(204, 204, 204)); 46 | else if ((lpDrawItemStruct->itemState & ODS_HOTLIGHT) || (lpDrawItemStruct->itemState & ODS_INACTIVE) || (lpDrawItemStruct->itemState & ODS_FOCUS)) 47 | graphics.Clear(Gdiplus::Color(50, 200, 196)); 48 | else 49 | { 50 | if(m_Active) 51 | graphics.Clear(Gdiplus::Color(0, 190, 100)); 52 | else 53 | graphics.Clear(Gdiplus::Color(0, 140, 186)); 54 | } 55 | 56 | graphics.SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeAntiAlias); 57 | graphics.SetTextRenderingHint(Gdiplus::TextRenderingHint::TextRenderingHintClearTypeGridFit); 58 | 59 | auto fontFamily = CreateUIFontFamily(); 60 | Gdiplus::Font font(fontFamily.get(), 18.0f, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel); 61 | CString text; 62 | GetWindowText(text); 63 | 64 | Gdiplus::StringFormat sf; 65 | sf.SetAlignment(Gdiplus::StringAlignment::StringAlignmentCenter); 66 | sf.SetLineAlignment(Gdiplus::StringAlignment::StringAlignmentCenter); 67 | sf.SetTrimming(Gdiplus::StringTrimming::StringTrimmingEllipsisWord); 68 | Gdiplus::Pen textBrPen(Gdiplus::Color(60, 0, 0, 0), 3); 69 | Gdiplus::SolidBrush textBrush(Gdiplus::Color::White); 70 | Gdiplus::SolidBrush textSBrush(Gdiplus::Color::Black); 71 | if (m_Active) 72 | { 73 | textBrPen.SetColor(Gdiplus::Color(80, 255, 255, 255)); 74 | textBrPen.SetWidth(5); 75 | textBrush.SetColor(Gdiplus::Color(234, 0, 55)); 76 | } 77 | textBrPen.SetAlignment(Gdiplus::PenAlignment::PenAlignmentCenter); 78 | gdiRect.Width -= 1; 79 | gdiRect.Height -= 1; 80 | graphics.DrawRectangle(&textBrPen, gdiRect); 81 | 82 | gdiRect.Offset(1.0f, 1.0f); 83 | graphics.DrawString(text.GetString(), text.GetLength(), &font, gdiRect, &sf, &textSBrush); 84 | gdiRect.Offset(-1.0f, -1.0f); 85 | graphics.DrawString(text.GetString(), text.GetLength(), &font, gdiRect, &sf, &textBrush); 86 | 87 | 88 | } 89 | 90 | 91 | void CIndicatorButton::PreSubclassWindow() 92 | { 93 | CButton::PreSubclassWindow(); 94 | ModifyStyle(0, BS_OWNERDRAW); 95 | } 96 | -------------------------------------------------------------------------------- /NetDebugger/CTextSendEditor.cpp: -------------------------------------------------------------------------------- 1 | // CTextSendEditor.cpp: 实现文件 2 | // 3 | 4 | #include "pch.h" 5 | #include "NetDebugger.h" 6 | #include "CTextSendEditor.h" 7 | #include "TextEncodeType.h" 8 | #include "UserWMDefine.h" 9 | 10 | // CTextSendEditor 11 | CTextSendEditor::CTextSendEditor(CWnd* pParentWnd) : 12 | m_ParentWnd(pParentWnd)//IDD_TEXT_SEND_EDITOR 13 | { 14 | 15 | } 16 | 17 | CTextSendEditor::~CTextSendEditor() 18 | { 19 | } 20 | 21 | IMPLEMENT_DYNAMIC(CTextSendEditor, ISendEditor) 22 | 23 | BEGIN_MESSAGE_MAP(CTextSendEditor, CMFCPropertyPage) 24 | ON_MESSAGE(kWM_SELECT_BUTTON_CHANGED, &CTextSendEditor::OnEditDisplayTypeChanged) 25 | ON_BN_CLICKED(IDC_BUTTON_SEND_CLEAR, &CTextSendEditor::OnBnClickedButtonSendClear) 26 | END_MESSAGE_MAP() 27 | 28 | void CTextSendEditor::DoDataExchange(CDataExchange* pDX) 29 | { 30 | CMFCPropertyPage::DoDataExchange(pDX); 31 | DDX_Control(pDX, IDC_SEND_DISPLAY_TYPE, m_SendDisplayTypeCtrl); 32 | DDX_Control(pDX, IDC_SEND_EDITBOX, m_SendEditCtrl); 33 | } 34 | 35 | static void InitDisplayTypeCtrl(CSelectControl& ctrl) 36 | { 37 | for (int i = 0; i < (int)TextEncodeType::_MAX; ++i) 38 | { 39 | ctrl.AddButton(TextEncodeTypeName((TextEncodeType)i), i); 40 | } 41 | ctrl.SetValue((UINT)TextEncodeType::ASCII); 42 | } 43 | 44 | BOOL CTextSendEditor::OnInitDialog(void) 45 | { 46 | CMFCPropertyPage::OnInitDialog(); 47 | InitDisplayTypeCtrl(m_SendDisplayTypeCtrl); 48 | m_SendEditCtrl.SetReadOnly(FALSE); 49 | m_SendDisplayTypeCtrl.SetValue(theApp.GetProfileInt(L"Setting", L"SendDisplayType", 0)); 50 | OnEditDisplayTypeChanged(m_SendDisplayTypeCtrl.GetDlgCtrlID(), m_SendDisplayTypeCtrl.GetValue()); 51 | 52 | SetDlgItemText(IDC_BUTTON_SEND_CLEAR, LSTEXT(MAINWND.BUTTON.SEND.CLEAR)); 53 | return TRUE; 54 | } 55 | 56 | void CTextSendEditor::UpdateLanguage(void) 57 | { 58 | SetDlgItemText(IDC_BUTTON_SEND_CLEAR, LSTEXT(MAINWND.BUTTON.SEND.CLEAR)); 59 | } 60 | 61 | UINT CTextSendEditor::GetDataType(void) 62 | { 63 | return m_SendDisplayTypeCtrl.GetValue(); 64 | } 65 | void CTextSendEditor::SetDataType(UINT type) 66 | { 67 | m_SendDisplayTypeCtrl.SetValue(type); 68 | } 69 | 70 | 71 | void CTextSendEditor::GetDataBuffer(std::function handler) 72 | { 73 | std::vector buffer; 74 | buffer.reserve(1024); 75 | Transform::DecodeWStringTo(m_SendEditCtrl.GetContent(), (TextEncodeType)m_SendDisplayTypeCtrl.GetValue(), buffer); 76 | handler(buffer.data(), buffer.size()); 77 | } 78 | 79 | void CTextSendEditor::ClearContent(void) 80 | { 81 | m_SendEditCtrl.ClearAll(); 82 | } 83 | 84 | void CTextSendEditor::SetContent(const void * data, size_t size) 85 | { 86 | std::vector buffer; 87 | buffer.resize(size); 88 | memcpy(buffer.data(), data, size); 89 | auto text = Transform::DecodeToWString( 90 | buffer, 91 | (TextEncodeType)GetDataType() 92 | ); 93 | m_SendEditCtrl.SetText(text); 94 | } 95 | 96 | void CTextSendEditor::Create(void) 97 | { 98 | CMFCPropertyPage::Create(IDD_TEXT_SEND_EDITOR, m_ParentWnd); 99 | } 100 | 101 | void CTextSendEditor::Destroy(void) 102 | { 103 | } 104 | 105 | 106 | LRESULT CTextSendEditor::OnEditDisplayTypeChanged(WPARAM wParam, LPARAM lParam) 107 | { 108 | auto id = static_cast(wParam); 109 | auto value = static_cast(lParam); 110 | if (id == IDC_SEND_DISPLAY_TYPE) 111 | { 112 | theApp.WriteProfileInt(L"Setting", L"SendDisplayType", m_SendDisplayTypeCtrl.GetValue()); 113 | if (value == TextEncodeType::HEX) 114 | { 115 | m_SendEditCtrl.EnterHEXMode(); 116 | } 117 | else 118 | { 119 | m_SendEditCtrl.ExitHEXMode(); 120 | } 121 | } 122 | return 0; 123 | } 124 | 125 | void CTextSendEditor::OnBnClickedButtonSendClear() 126 | { 127 | m_SendEditCtrl.ClearAll(); 128 | } 129 | 130 | 131 | -------------------------------------------------------------------------------- /NetDebugger/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /NetDebugger/MQTTClient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace MQTT 8 | { 9 | enum class MQTTVersion : uint8_t 10 | { 11 | VERSION_3_1 = 3, 12 | VERSION_3_1_1 = 4 13 | }; 14 | 15 | enum class MessageQOS : uint8_t 16 | { 17 | MQTTQOS0 = 0, 18 | MQTTQOS1 = 1, 19 | MQTTQOS2 = 2 20 | }; 21 | 22 | enum class MQTTErrorCode : uint8_t 23 | { 24 | SUCCESS = 0, 25 | UNACCEPTABLE_PROTOCOL_VERSION = 1, 26 | IDENTIFIER_REJECTED = 2, 27 | SERVER_UNAVAILABLE = 3, 28 | BAD_USER_NAME_OR_PASSWORD = 4, 29 | NOT_AUTHORIZED = 5, 30 | SUBSCRIBE_QOS0 = 0x00, 31 | SUBSCRIBE_QOS1 = 0x01, 32 | SUBSCRIBE_QOS2 = 0x02, 33 | SUBSCRIBE_FAILURE = 0x80, 34 | PAYLOAD_EXCEED = 252, 35 | CONNECTION_DISCONN = 253, 36 | CONNECTION_REFUSED = 254, 37 | CONNECTION_TIMEOUT = 255, 38 | }; 39 | 40 | struct ConnectionOptions 41 | { 42 | MQTTVersion Version; 43 | bool CleanSession; 44 | struct 45 | { 46 | std::string Topic; 47 | MessageQOS Qos; 48 | bool Retain; 49 | std::vector Data; 50 | }Will; 51 | std::string UserName; 52 | std::string Password; 53 | uint16_t KeepAlive; 54 | std::string ClientID; 55 | std::string serverURL; 56 | }; 57 | 58 | 59 | class MQTTClient : public std::enable_shared_from_this 60 | { 61 | public: 62 | using tcp = boost::asio::ip::tcp; 63 | using MQTTEventCallback = std::function; 64 | using MQTTTransactionCallback = std::function& errorCodes)>; 65 | using MQTTMessageCallback = std::function; 66 | using MQTTClientPtr = std::shared_ptr; 67 | using IOBuffer = std::shared_ptr>; 68 | public: 69 | MQTTClient(boost::asio::io_service& ios); 70 | ~MQTTClient(); 71 | public: 72 | bool Connected(void)const { return mConnected; } 73 | void Connect(const ConnectionOptions& options); 74 | void Disconnect(bool forced); 75 | void Publish(const std::string& topic, const std::vector& payload, MessageQOS qos, bool retain, MQTTTransactionCallback handler); 76 | void Publish(const std::string& topic, const std::string& payload, MessageQOS qos, bool retain, MQTTTransactionCallback handler); 77 | void Subscribe(const std::string& topic, MessageQOS qos, MQTTTransactionCallback handler); 78 | void Unsubscribe(const std::string& topic, MQTTTransactionCallback handler); 79 | void Subscribe(const std::vector& topic, MessageQOS qos, MQTTTransactionCallback handler); 80 | void Unsubscribe(const std::vector& topic, MQTTTransactionCallback handler); 81 | public: 82 | void OnConnected(MQTTEventCallback handler); 83 | void OnDisconnected(MQTTEventCallback handler); 84 | void OnMessage(MQTTMessageCallback handler); 85 | private: 86 | void Publish(const std::string& topic, const uint8_t* payload, size_t payloadSize, MessageQOS qos, bool retain, MQTTTransactionCallback handler); 87 | void Ping(MQTTClientPtr client); 88 | private: 89 | void onReadMQTTPacket(MQTTClientPtr client, IOBuffer buffer); 90 | void onReadMQTTPacketLength(MQTTClientPtr client, size_t offset, IOBuffer buffer); 91 | void onReadMQTTPacketLengthCompleted(MQTTClientPtr client, IOBuffer buffer); 92 | void onReadMQTTPacketCompleted(MQTTClientPtr client, IOBuffer buffer, size_t lengthOffset); 93 | void onStartReadMQTTPacket(MQTTClientPtr client); 94 | void onStartPingTimer(MQTTClientPtr client); 95 | private: 96 | uint16_t BeginTransaction(MQTTTransactionCallback handler); 97 | void EndTransaction(uint16_t transactionId, const std::vector& results); 98 | private: 99 | tcp::socket mSocket; 100 | ConnectionOptions mConnectOptions; 101 | bool mConnected; 102 | uint16_t mPacketIdentifier; 103 | std::mutex mTransactionMutex; 104 | std::unordered_map mTransactions; 105 | std::shared_ptr mPingTimer; 106 | MQTTEventCallback mConnectedCallback; 107 | MQTTEventCallback mDisconnectedCallback; 108 | MQTTEventCallback mPingCallback; 109 | MQTTMessageCallback mMessageCallback; 110 | }; 111 | } -------------------------------------------------------------------------------- /NetDebugger/CSendHistoryDlg.cpp: -------------------------------------------------------------------------------- 1 | // CSendHistoryDlg.cpp: 实现文件 2 | // 3 | 4 | #include "pch.h" 5 | #include "NetDebugger.h" 6 | #include "CSendHistoryDlg.h" 7 | #include "afxdialogex.h" 8 | #include "TextEncodeType.h" 9 | // CSendHistoryDlg 对话框 10 | 11 | IMPLEMENT_DYNAMIC(CSendHistoryDlg, CDialogEx) 12 | 13 | CSendHistoryDlg::CSendHistoryDlg(std::vector>& historys, CWnd* pParent /*=nullptr*/) 14 | : CDialogEx(IDD_SEND_HISTORY_DIALOG, pParent), 15 | m_HistoryRecords(historys) 16 | { 17 | 18 | } 19 | 20 | CSendHistoryDlg::~CSendHistoryDlg() 21 | { 22 | } 23 | 24 | void CSendHistoryDlg::DoDataExchange(CDataExchange* pDX) 25 | { 26 | CDialogEx::DoDataExchange(pDX); 27 | DDX_Control(pDX, IDC_DATA_DISPLAY_MODE, m_DataDisplayModeCtrl); 28 | DDX_Control(pDX, IDC_DATA_EDIT_BOX, m_DataEditCtrl); 29 | DDX_Control(pDX, IDC_LIST_HISTORY, m_HistoryListCtrl); 30 | } 31 | 32 | 33 | BEGIN_MESSAGE_MAP(CSendHistoryDlg, CDialogEx) 34 | ON_BN_CLICKED(IDC_BUTTON_CLEAR, &CSendHistoryDlg::OnBnClickedButtonClear) 35 | ON_BN_CLICKED(IDOK, &CSendHistoryDlg::OnBnClickedOk) 36 | ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_HISTORY, &CSendHistoryDlg::OnLvnItemchangedListHistory) 37 | ON_NOTIFY(NM_DBLCLK, IDC_LIST_HISTORY, &CSendHistoryDlg::OnNMDblclkListHistory) 38 | END_MESSAGE_MAP() 39 | 40 | 41 | // CSendHistoryDlg 消息处理程序 42 | 43 | 44 | static CString ToStringName(std::shared_ptr history) 45 | { 46 | CString result; 47 | auto p = history->DataBuffer.data(); 48 | auto l = history->DataBuffer.size() > 32 ? 32 : history->DataBuffer.size(); 49 | std::vector temp(p, p + l); 50 | auto data = Transform::DecodeToWString(temp, (TextEncodeType)(history->TextEncoding)); 51 | result.SetString(data.data(), (int)data.length()); 52 | return result; 53 | } 54 | 55 | BOOL CSendHistoryDlg::OnInitDialog() 56 | { 57 | CDialogEx::OnInitDialog(); 58 | for (int i = 0; i < (int)TextEncodeType::_MAX; ++i) 59 | { 60 | m_DataDisplayModeCtrl.AddButton(TextEncodeTypeName((TextEncodeType)i), i); 61 | } 62 | m_DataDisplayModeCtrl.SetValue((UINT)TextEncodeType::ASCII); 63 | m_DataDisplayModeCtrl.EnableWindow(FALSE); 64 | 65 | m_HistoryListCtrl.InsertColumn(0, LSTEXT(SEND.HISTORY.DIALOG.TYPE), 0, 100); 66 | m_HistoryListCtrl.InsertColumn(1, LSTEXT(SEND.HISTORY.DIALOG.DATA), 0, 260); 67 | 68 | m_HistoryListCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); 69 | int iItem = 0; 70 | for (auto history : m_HistoryRecords) 71 | { 72 | m_HistoryListCtrl.InsertItem(iItem,TextEncodeTypeName((TextEncodeType)(history->TextEncoding))); 73 | m_HistoryListCtrl.SetItemText(iItem, 1, ToStringName(history)); 74 | m_HistoryListCtrl.SetItemData(iItem, (DWORD_PTR)history.get()); 75 | ++iItem; 76 | } 77 | m_HistoryListCtrl.SetHotItem(0); 78 | 79 | m_DataEditCtrl.SetReadOnly(TRUE); 80 | 81 | SetWindowText(LSTEXT(SEND.HISTORY.DIALOG.TITLE)); 82 | SetDlgItemText(IDOK, LSTEXT(SEND.HISTORY.DIALOG.OK)); 83 | SetDlgItemText(IDC_BUTTON_CLEAR, LSTEXT(SEND.HISTORY.DIALOG.CLEAR)); 84 | return TRUE; 85 | } 86 | 87 | 88 | void CSendHistoryDlg::OnBnClickedButtonClear() 89 | { 90 | m_HistoryListCtrl.DeleteAllItems(); 91 | m_HistoryRecords.clear(); 92 | m_Result = nullptr; 93 | CDialogEx::OnCancel(); 94 | } 95 | 96 | 97 | void CSendHistoryDlg::OnBnClickedOk() 98 | { 99 | auto i = m_HistoryListCtrl.GetSelectionMark(); 100 | if (i >= 0 && i< (int)m_HistoryRecords.size()) 101 | { 102 | m_Result = m_HistoryRecords[i]; 103 | } 104 | else 105 | { 106 | m_Result = nullptr; 107 | } 108 | CDialogEx::OnOK(); 109 | } 110 | 111 | 112 | 113 | void CSendHistoryDlg::OnLvnItemchangedListHistory(NMHDR *pNMHDR, LRESULT *pResult) 114 | { 115 | LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); 116 | auto i = pNMLV->iItem; 117 | if (i >= 0 && i < (int)m_HistoryRecords.size()) 118 | { 119 | m_Result = m_HistoryRecords[i]; 120 | m_DataDisplayModeCtrl.SetValue((UINT)m_Result->TextEncoding); 121 | m_DataEditCtrl.SetReadOnly(FALSE); 122 | m_DataEditCtrl.SetText(Transform::DecodeToWString(m_Result->DataBuffer, (TextEncodeType)m_Result->TextEncoding)); 123 | m_DataEditCtrl.SetReadOnly(TRUE); 124 | } 125 | *pResult = 0; 126 | } 127 | 128 | void CSendHistoryDlg::OnNMDblclkListHistory(NMHDR *pNMHDR, LRESULT *pResult) 129 | { 130 | LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); 131 | OnBnClickedOk(); 132 | *pResult = 0; 133 | } 134 | -------------------------------------------------------------------------------- /NetDebugger/NetDebugger.cpp: -------------------------------------------------------------------------------- 1 | 2 | // NetDebugger.cpp: 定义应用程序的类行为。 3 | // 4 | 5 | #include "pch.h" 6 | #include "framework.h" 7 | #include "NetDebugger.h" 8 | #include "NetDebuggerDlg.h" 9 | #include "CSettingDlg.h" 10 | #include "CHelpDialog.h" 11 | #include "ContainerWnd.h" 12 | 13 | 14 | #ifdef _DEBUG 15 | #define new DEBUG_NEW 16 | #endif 17 | 18 | 19 | // CNetDebuggerApp 20 | 21 | BEGIN_MESSAGE_MAP(CNetDebuggerApp, CWinApp) 22 | ON_COMMAND(ID_HELP, &CNetDebuggerApp::OnHelp) 23 | END_MESSAGE_MAP() 24 | 25 | 26 | // CNetDebuggerApp 构造 27 | 28 | CNetDebuggerApp::CNetDebuggerApp() 29 | { 30 | // 支持重新启动管理器 31 | m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART; 32 | 33 | // TODO: 在此处添加构造代码, 34 | // 将所有重要的初始化放置在 InitInstance 中 35 | } 36 | 37 | 38 | // 唯一的 CNetDebuggerApp 对象 39 | 40 | CNetDebuggerApp theApp; 41 | 42 | 43 | // CNetDebuggerApp 初始化 44 | static void LoadLangData(HMODULE hInstance, LanguageService& ls) 45 | { 46 | HRSRC res = FindResource(hInstance, MAKEINTRESOURCE(IDR_LANGUAGE), L"LANGUAGE"); 47 | if (res) 48 | { 49 | HGLOBAL mem = LoadResource(hInstance, res); 50 | void *data = LockResource(mem); 51 | DWORD len = SizeofResource(hInstance, res); 52 | ls.LoadData(data, len); 53 | UnlockResource(mem); 54 | FreeResource(mem); 55 | } 56 | else 57 | { 58 | //AfxMessageBox(); 59 | } 60 | } 61 | 62 | BOOL CNetDebuggerApp::InitInstance() 63 | { 64 | // 如果一个运行在 Windows XP 上的应用程序清单指定要 65 | // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, 66 | //则需要 InitCommonControlsEx()。 否则,将无法创建窗口。 67 | INITCOMMONCONTROLSEX InitCtrls; 68 | InitCtrls.dwSize = sizeof(InitCtrls); 69 | // 将它设置为包括所有要在应用程序中使用的 70 | // 公共控件类。 71 | InitCtrls.dwICC = ICC_WIN95_CLASSES; 72 | InitCommonControlsEx(&InitCtrls); 73 | 74 | InitContainerWnd(); 75 | 76 | LoadLangData(m_hInstance, m_LangService); 77 | 78 | ULONG_PTR gdiplusToken = 0; 79 | Gdiplus::GdiplusStartupInput gdiplusStartupInput; 80 | Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr); 81 | 82 | CWinApp::InitInstance(); 83 | 84 | AfxInitRichEdit2(); 85 | 86 | AfxEnableControlContainer(); 87 | 88 | // 创建 shell 管理器,以防对话框包含 89 | // 任何 shell 树视图控件或 shell 列表视图控件。 90 | CShellManager *pShellManager = new CShellManager; 91 | 92 | // 激活“Windows Native”视觉管理器,以便在 MFC 控件中启用主题 93 | CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows)); 94 | 95 | SetRegistryKey(_T("DPY")); 96 | 97 | auto lid = GetProfileString(L"Setting", L"LanguageId", L""); 98 | if (lid.IsEmpty()) 99 | { 100 | CSettingDlg settingDlg; 101 | settingDlg.DoModal(); 102 | } 103 | else 104 | { 105 | m_LangService.SetLanguage(lid); 106 | } 107 | m_LangService.SetDefaultLID(L"zh-CN"); 108 | 109 | WriteProfileString(L"Setting", L"LanguageId", m_LangService.GetLanguage()); 110 | 111 | SYSTEM_INFO si; 112 | GetSystemInfo(&si); 113 | boost::asio::io_service::work work(m_IOContext); 114 | std::vector> ioThreads; 115 | ioThreads.resize(si.dwNumberOfProcessors * 2); 116 | for (size_t i = 0; i < ioThreads.size(); ++i) 117 | { 118 | ioThreads[i].reset(new std::thread([this]() { m_IOContext.run(); })); 119 | } 120 | 121 | CNetDebuggerDlg dlg; 122 | m_pMainWnd = &dlg; 123 | INT_PTR nResponse = dlg.DoModal(); 124 | if (nResponse == IDOK) 125 | { 126 | // TODO: 在此放置处理何时用 127 | // “确定”来关闭对话框的代码 128 | } 129 | else if (nResponse == IDCANCEL) 130 | { 131 | // TODO: 在此放置处理何时用 132 | // “取消”来关闭对话框的代码 133 | } 134 | else if (nResponse == -1) 135 | { 136 | TRACE(traceAppMsg, 0, "警告: 对话框创建失败,应用程序将意外终止。\n"); 137 | TRACE(traceAppMsg, 0, "警告: 如果您在对话框上使用 MFC 控件,则无法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n"); 138 | } 139 | 140 | m_IOContext.stop(); 141 | for (size_t i = 0; i < ioThreads.size(); ++i) 142 | { 143 | if (ioThreads[i]->joinable()) 144 | ioThreads[i]->join(); 145 | } 146 | 147 | // 删除上面创建的 shell 管理器。 148 | if (pShellManager != nullptr) 149 | { 150 | delete pShellManager; 151 | } 152 | 153 | #if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS) 154 | ControlBarCleanUp(); 155 | #endif 156 | 157 | Gdiplus::GdiplusShutdown(gdiplusToken); 158 | // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, 159 | // 而不是启动应用程序的消息泵。 160 | return FALSE; 161 | } 162 | 163 | std::shared_ptr CNetDebuggerApp::CreateCommunicationDevice(const std::wstring& className) 164 | { 165 | auto it = m_CDCreatorMap.find(className); 166 | if (it == m_CDCreatorMap.end()) 167 | return nullptr; 168 | auto crector = std::get<2>(it->second); 169 | return crector(); 170 | } 171 | 172 | void CNetDebuggerApp::RegisterDeviceClass(const std::wstring& className, const std::wstring& title, FactoryCreator crector) 173 | { 174 | m_CDCreatorMap.insert(std::make_pair(className, std::make_tuple(className, title, crector))); 175 | } 176 | 177 | CNetDebuggerApp::TypeDesc CNetDebuggerApp::GetDeviceTypes(void) 178 | { 179 | TypeDesc results; 180 | for (auto& kv : m_CDCreatorMap) 181 | { 182 | results.push_back(std::make_tuple(std::get<0>(kv.second), std::get<1>(kv.second))); 183 | } 184 | return results; 185 | } 186 | 187 | 188 | void CNetDebuggerApp::OnHelp() 189 | { 190 | CHelpDialog dlg; 191 | dlg.DoModal(); 192 | } -------------------------------------------------------------------------------- /NetDebugger/NetDebuggerDlg.h: -------------------------------------------------------------------------------- 1 | 2 | // NetDebuggerDlg.h: 头文件 3 | // 4 | 5 | #pragma once 6 | #include "CSelectControl.h" 7 | #include "CDPropertyGridCtrl.h" 8 | #include "CRealTimeStatusCtrl.h" 9 | #include "CPlaceholderEdit.h" 10 | #include "CEditEx.h" 11 | #include "IDeviceUI.h" 12 | #include "IndicatorButton.h" 13 | #include "IAsyncStream.h" 14 | #include "BlockingQueue.hpp" 15 | #include "DataBuffer.h" 16 | 17 | class FileSendContext; 18 | class SendHistoryRecord; 19 | // CNetDebuggerDlg 对话框 20 | class CNetDebuggerDlg : public CDialogEx 21 | { 22 | // 构造 23 | public: 24 | CNetDebuggerDlg(CWnd* pParent = nullptr); // 标准构造函数 25 | 26 | // 对话框数据 27 | #ifdef AFX_DESIGN_TIME 28 | enum { IDD = IDD_NETDEBUGGER_DIALOG }; 29 | #endif 30 | 31 | protected: 32 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 33 | private: 34 | void SetControlText(UINT id, const std::wstring& text); 35 | void SetControlText(UINT id, const CString& text); 36 | void SetControlEnable(UINT id, bool enable); 37 | private: 38 | void InitDisplayTypeCtrl(CSelectControl& ctrl); 39 | void OnDeviceStatusChanged(IDevice::DeviceStatus status,const std::wstring& message); 40 | void OnDevicePropertyChanged(void); 41 | void OnDeviceChannelConnected(std::shared_ptr channel, const std::wstring& message); 42 | void OnDeviceChannelDisconnected(std::shared_ptr channel, const std::wstring& message); 43 | private: 44 | void ReadChannelData(std::shared_ptr channel, std::shared_ptr> buffer); 45 | void SendDataToChannel(std::shared_ptr channel, const void* buffer, size_t size, IAsyncChannel::IoCompletionHandler cphandler); 46 | void SendFileBlockToChannel(std::shared_ptr ctx); 47 | void StartSendFileToChannel(std::shared_ptr channel, const CString& filename); 48 | private: 49 | void LoadSendHistory(void); 50 | void SaveSendHistory(void); 51 | protected: 52 | void SendUIThreadTask(std::function task); 53 | void PostUIThreadTask(std::function task); 54 | void AppendDataToRecvBuffer(std::shared_ptr channel, std::shared_ptr> buffer); 55 | void AppendSendHistory(UINT type, std::shared_ptr> buffer); 56 | void SaveReadHistory(const CString& path,bool tip, bool append, bool lockBuffer); 57 | 58 | void UpdateUILangText(void); 59 | // 实现 60 | private: 61 | struct ReceivedMessage 62 | { 63 | std::string label; 64 | std::string message; 65 | }; 66 | 67 | HICON m_hIcon; 68 | CSize m_MinSize; 69 | CComboBoxEx m_DeviceTypeCtrl; 70 | CComboBoxEx m_ChannelsCtrl; 71 | CSelectControl m_RecvDisplayTypeCtrl; 72 | CRichEditEx m_RecvEditCtrl; 73 | CPropertyTableCtrl m_DevicePropertyPanel; 74 | CRealTimeStatusCtrl m_DeviceStatisticsCtrl; 75 | CComboBox m_MemoryMaxCtrl; 76 | CButton m_ShowRecvDataCtrl; 77 | CButton m_AutoSaveCtrl; 78 | CMFCEditBrowseCtrl m_AutoSaveFilePathCtrl; 79 | CIndicatorButton m_ConnectButton; 80 | CButton m_RecvInfoAdditionalCtrl; 81 | CPlaceholderEdit m_AutoSendIntervalCtrl; 82 | CMFCToolTipCtrl m_ToolTipCtrl; 83 | std::unique_ptr m_SendEditor; 84 | std::shared_ptr m_CDevice; 85 | std::map> m_ChannelsMap; 86 | int m_ConnectStatusPop; 87 | size_t m_MaxReadMemorySize; 88 | std::atomic m_ReadByteCount; 89 | std::atomic m_WriteByteCount; 90 | bool m_bAutoSave; 91 | bool m_bRecvInfoAdditional; 92 | bool m_bShowRecvData; 93 | DataBuffer m_ReadBuffer; 94 | std::mutex m_ReadBufferMutex; 95 | std::vector> m_HistoryRecords; 96 | BlockingQueue m_ReceivedMessageQueue; 97 | std::atomic m_Closed; 98 | std::vector> m_UILUpdates; 99 | protected: 100 | // 生成的消息映射函数 101 | DECLARE_MESSAGE_MAP() 102 | 103 | virtual void OnClose(); 104 | virtual void OnOK(); 105 | virtual void OnCancel(); 106 | virtual BOOL OnInitDialog(); 107 | virtual BOOL PreTranslateMessage(MSG* pMsg); 108 | 109 | afx_msg void OnSysCommand(UINT nID, LPARAM lParam); 110 | afx_msg void OnPaint(); 111 | afx_msg HCURSOR OnQueryDragIcon(); 112 | afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI); 113 | afx_msg void OnCbnSelchangeCmbNetType(); 114 | afx_msg LRESULT OnDevicePropertyChanged(WPARAM wParam, LPARAM lParam); 115 | afx_msg LRESULT OnEditDisplayTypeChanged(WPARAM wParam, LPARAM lParam); 116 | afx_msg void OnBnClickedButtonConnect(); 117 | afx_msg void OnDestroy(); 118 | afx_msg void OnTimer(UINT_PTR nIDEvent); 119 | afx_msg LRESULT OnUIThreadTask(WPARAM wParam, LPARAM lParam); 120 | afx_msg LRESULT OnEditRecvBoxDisplayTypeChanged(WPARAM wParam, LPARAM lParam); 121 | afx_msg void OnBnClickedButtonSend(); 122 | afx_msg void OnBnClickedButtonClearStatistics(); 123 | afx_msg void OnBnClickedButtonRecvClear(); 124 | afx_msg void OnBnClickedButtonSendFile(); 125 | afx_msg void OnBnClickedButtonRecvSave(); 126 | afx_msg void OnBnClickedButtonSendHistory(); 127 | afx_msg void OnCbnSelchangeComboMemoryMax(); 128 | afx_msg void OnBnClickedCheckAutoSave(); 129 | afx_msg void OnBnClickedButtonCloseChannel(); 130 | afx_msg void OnBnClickedCheckAutoAdditional(); 131 | afx_msg void OnEnChangeEditSendInterval(); 132 | afx_msg void OnBnClickedCheckShowRecvdata(); 133 | }; 134 | -------------------------------------------------------------------------------- /NetDebugger/CSelectControl.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "CSelectControl.h" 3 | #include "UserWMDefine.h" 4 | 5 | BEGIN_MESSAGE_MAP(CSelectControl, CWnd) 6 | ON_WM_PAINT() 7 | ON_WM_ERASEBKGND() 8 | ON_WM_MOUSEMOVE() 9 | ON_WM_LBUTTONDOWN() 10 | ON_WM_MOUSEHOVER() 11 | ON_WM_MOUSELEAVE() 12 | ON_WM_LBUTTONUP() 13 | END_MESSAGE_MAP() 14 | 15 | static BOOL RegisterWindowClass(void) 16 | { 17 | LPCWSTR className = L"SELECT_BUTTON_GROUP"; 18 | WNDCLASS windowclass; 19 | HINSTANCE hInstance = AfxGetInstanceHandle(); 20 | 21 | if (!(::GetClassInfo(hInstance, className, &windowclass))) 22 | { 23 | windowclass.style = CS_DBLCLKS; 24 | windowclass.lpfnWndProc = ::DefWindowProc; 25 | windowclass.cbClsExtra = windowclass.cbWndExtra = 0; 26 | windowclass.hInstance = hInstance; 27 | windowclass.hIcon = NULL; 28 | windowclass.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); 29 | windowclass.hbrBackground = ::GetSysColorBrush(COLOR_WINDOW); 30 | windowclass.lpszMenuName = NULL; 31 | windowclass.lpszClassName = className; 32 | if (!AfxRegisterClass(&windowclass)) 33 | { 34 | AfxThrowResourceException(); 35 | return FALSE; 36 | } 37 | } 38 | return TRUE; 39 | } 40 | 41 | CSelectControl::CSelectControl() 42 | { 43 | RegisterWindowClass(); 44 | m_HoverIndex = -1; 45 | m_SelectedIndex = -1; 46 | m_Pressed = false; 47 | } 48 | 49 | CSelectControl::~CSelectControl() 50 | { 51 | 52 | } 53 | 54 | void CSelectControl::OnPaint() 55 | { 56 | CPaintDC dc(this); 57 | CRect client; 58 | GetClientRect(client); 59 | CFont* font = GetTopLevelParent()->GetFont(); 60 | int offset = client.left; 61 | auto save = dc.SaveDC(); 62 | dc.SelectObject(*font); 63 | int i = 0; 64 | dc.SetBkMode(TRANSPARENT); 65 | dc.FillSolidRect(client, GetSysColor(COLOR_BTNHIGHLIGHT)); 66 | for (auto& item : m_Buttons) 67 | { 68 | const auto& text = item.text; 69 | CRect rc(client); 70 | 71 | dc.DrawText(text, rc, DT_LEFT | DT_SINGLELINE | DT_CALCRECT); 72 | rc.left = offset; 73 | rc.right += offset + 15; 74 | rc.top = client.top; 75 | rc.bottom = client.bottom; 76 | item.rect = rc; 77 | if (i == m_SelectedIndex) 78 | { 79 | dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT)); 80 | dc.FillSolidRect(rc, GetSysColor(COLOR_HIGHLIGHT)); 81 | dc.DrawText(text, rc, DT_LEFT | DT_VCENTER | DT_CENTER | DT_SINGLELINE); 82 | if (m_Pressed) 83 | dc.InvertRect(rc); 84 | } 85 | else if (i == m_HoverIndex) 86 | { 87 | dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT)); 88 | dc.FillSolidRect(rc, GetSysColor(COLOR_MENUHILIGHT)); 89 | dc.DrawText(text, rc, DT_LEFT | DT_VCENTER | DT_CENTER | DT_SINGLELINE); 90 | if (m_Pressed) 91 | dc.InvertRect(rc); 92 | } 93 | else 94 | { 95 | dc.SetTextColor(GetSysColor(COLOR_BTNTEXT)); 96 | dc.FillSolidRect(rc, GetSysColor(COLOR_BTNHIGHLIGHT)); 97 | dc.DrawText(text, rc, DT_LEFT | DT_VCENTER | DT_CENTER | DT_SINGLELINE); 98 | } 99 | 100 | offset = rc.right; 101 | ++i; 102 | } 103 | dc.RestoreDC(save); 104 | } 105 | 106 | 107 | BOOL CSelectControl::OnEraseBkgnd(CDC* pDC) 108 | { 109 | return TRUE; 110 | } 111 | 112 | 113 | void CSelectControl::AddButton(CString text, UINT value) 114 | { 115 | ButtonItem item; 116 | item.text = text; 117 | item.value = value; 118 | m_Buttons.push_back(item); 119 | } 120 | 121 | 122 | bool CSelectControl::RemoveButtonAt(int index) 123 | { 124 | if (index < 0 || index > (int)m_Buttons.size()) 125 | return false; 126 | m_Buttons.erase(m_Buttons.begin() + index); 127 | Invalidate(); 128 | return true; 129 | } 130 | 131 | 132 | void CSelectControl::RemoveAllButton() 133 | { 134 | if (!m_Buttons.empty()) 135 | { 136 | m_Buttons.clear(); 137 | Invalidate(); 138 | } 139 | } 140 | 141 | UINT CSelectControl::GetValue() const 142 | { 143 | if (m_SelectedIndex < 0 || m_SelectedIndex > (int)m_Buttons.size()) 144 | return 0; 145 | return m_Buttons[m_SelectedIndex].value; 146 | } 147 | 148 | void CSelectControl::SetValue(UINT value) 149 | { 150 | int i = 0; 151 | for (auto& item : m_Buttons) 152 | { 153 | if (item.value == value) 154 | break; 155 | ++i; 156 | } 157 | if (i >= (int)m_Buttons.size()) 158 | m_SelectedIndex = -1; 159 | else 160 | m_SelectedIndex = i; 161 | Invalidate(); 162 | } 163 | 164 | void CSelectControl::OnMouseMove(UINT nFlags, CPoint point) 165 | { 166 | TRACKMOUSEEVENT tme = { 0 }; 167 | tme.cbSize = sizeof(TRACKMOUSEEVENT); 168 | tme.dwFlags = TME_HOVER | TME_LEAVE; 169 | tme.dwHoverTime = 50; 170 | tme.hwndTrack = this->m_hWnd; 171 | TrackMouseEvent(&tme); 172 | int i = 0; 173 | for (auto& item : m_Buttons) 174 | { 175 | if (item.rect.PtInRect(point)) 176 | { 177 | if (m_HoverIndex != i) 178 | { 179 | m_HoverIndex = i; 180 | Invalidate(); 181 | } 182 | return; 183 | } 184 | ++i; 185 | } 186 | if (m_HoverIndex != -1) 187 | { 188 | m_HoverIndex = -1; 189 | Invalidate(); 190 | } 191 | CWnd::OnMouseMove(nFlags, point); 192 | } 193 | 194 | 195 | void CSelectControl::OnLButtonDown(UINT nFlags, CPoint point) 196 | { 197 | m_Pressed = true; 198 | if (m_HoverIndex != m_SelectedIndex) 199 | { 200 | m_SelectedIndex = m_HoverIndex; 201 | ::SendMessage(::GetParent(this->GetSafeHwnd()), kWM_SELECT_BUTTON_CHANGED, this->GetDlgCtrlID(), m_SelectedIndex); 202 | } 203 | Invalidate(); 204 | } 205 | 206 | void CSelectControl::OnMouseHover(UINT nFlags, CPoint point) 207 | { 208 | CWnd::OnMouseHover(nFlags, point); 209 | } 210 | 211 | 212 | void CSelectControl::OnMouseLeave() 213 | { 214 | m_Pressed = false; 215 | m_HoverIndex = -1; 216 | Invalidate(); 217 | CWnd::OnMouseLeave(); 218 | } 219 | 220 | 221 | void CSelectControl::OnLButtonUp(UINT nFlags, CPoint point) 222 | { 223 | m_Pressed = false; 224 | Invalidate(); 225 | CWnd::OnLButtonUp(nFlags, point); 226 | } 227 | -------------------------------------------------------------------------------- /NetDebugger/NetDebugger.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {dfc99db8-aed3-4860-b6f6-001998266b3b} 18 | 19 | 20 | 21 | 22 | 头文件 23 | 24 | 25 | 头文件 26 | 27 | 28 | 头文件 29 | 30 | 31 | 头文件 32 | 33 | 34 | 头文件 35 | 36 | 37 | 头文件 38 | 39 | 40 | 头文件 41 | 42 | 43 | 头文件 44 | 45 | 46 | Streams 47 | 48 | 49 | Streams 50 | 51 | 52 | 头文件 53 | 54 | 55 | 头文件 56 | 57 | 58 | 头文件 59 | 60 | 61 | 头文件 62 | 63 | 64 | 头文件 65 | 66 | 67 | 头文件 68 | 69 | 70 | 头文件 71 | 72 | 73 | 头文件 74 | 75 | 76 | Streams 77 | 78 | 79 | Streams 80 | 81 | 82 | 头文件 83 | 84 | 85 | 头文件 86 | 87 | 88 | 头文件 89 | 90 | 91 | 头文件 92 | 93 | 94 | Streams 95 | 96 | 97 | 头文件 98 | 99 | 100 | 头文件 101 | 102 | 103 | Streams 104 | 105 | 106 | 头文件 107 | 108 | 109 | 头文件 110 | 111 | 112 | 头文件 113 | 114 | 115 | 头文件 116 | 117 | 118 | 头文件 119 | 120 | 121 | Streams 122 | 123 | 124 | 头文件 125 | 126 | 127 | 头文件 128 | 129 | 130 | 131 | 132 | 源文件 133 | 134 | 135 | 源文件 136 | 137 | 138 | 源文件 139 | 140 | 141 | 源文件 142 | 143 | 144 | 源文件 145 | 146 | 147 | Streams 148 | 149 | 150 | 源文件 151 | 152 | 153 | 源文件 154 | 155 | 156 | 源文件 157 | 158 | 159 | 源文件 160 | 161 | 162 | 源文件 163 | 164 | 165 | Streams 166 | 167 | 168 | Streams 169 | 170 | 171 | 源文件 172 | 173 | 174 | 源文件 175 | 176 | 177 | Streams 178 | 179 | 180 | 源文件 181 | 182 | 183 | 源文件 184 | 185 | 186 | Streams 187 | 188 | 189 | 源文件 190 | 191 | 192 | 源文件 193 | 194 | 195 | 源文件 196 | 197 | 198 | Streams 199 | 200 | 201 | 202 | 203 | 资源文件 204 | 205 | 206 | 207 | 208 | 资源文件 209 | 210 | 211 | 资源文件 212 | 213 | 214 | 资源文件 215 | 216 | 217 | 218 | 219 | 220 | 资源文件 221 | 222 | 223 | 224 | 225 | 资源文件 226 | 227 | 228 | -------------------------------------------------------------------------------- /NetDebugger/SHA1.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | class SHA1 8 | { 9 | public: 10 | enum { BlockSize = 512 / 8, HashBytes = 20 }; 11 | SHA1() 12 | { 13 | reset(); 14 | } 15 | ~SHA1() = default; 16 | public: 17 | void Update(const void* data, size_t numBytes) 18 | { 19 | const uint8_t* current = (const uint8_t*)data; 20 | if (m_bufferSize > 0) 21 | { 22 | while (numBytes > 0 && m_bufferSize < BlockSize) 23 | { 24 | m_buffer[m_bufferSize++] = *current++; 25 | numBytes--; 26 | } 27 | } 28 | 29 | // full buffer 30 | if (m_bufferSize == BlockSize) 31 | { 32 | processBlock((void*)m_buffer); 33 | m_numBytes += BlockSize; 34 | m_bufferSize = 0; 35 | } 36 | 37 | // no more data ? 38 | if (numBytes == 0) 39 | return; 40 | 41 | // process full blocks 42 | while (numBytes >= BlockSize) 43 | { 44 | processBlock(current); 45 | current += BlockSize; 46 | m_numBytes += BlockSize; 47 | numBytes -= BlockSize; 48 | } 49 | 50 | // keep remaining bytes in buffer 51 | while (numBytes > 0) 52 | { 53 | m_buffer[m_bufferSize++] = *current++; 54 | numBytes--; 55 | } 56 | } 57 | void Update(const std::string& data) 58 | { 59 | Update(data.data(), data.length()); 60 | } 61 | 62 | std::vector Final(void) 63 | { 64 | std::vector buffer; 65 | buffer.resize(HashBytes); 66 | // process remaining bytes 67 | processBuffer(); 68 | 69 | unsigned char* current = buffer.data(); 70 | for (int i = 0; i < HashValues; i++) 71 | { 72 | *current++ = (m_hash[i] >> 24) & 0xFF; 73 | *current++ = (m_hash[i] >> 16) & 0xFF; 74 | *current++ = (m_hash[i] >> 8) & 0xFF; 75 | *current++ = m_hash[i] & 0xFF; 76 | } 77 | reset(); 78 | return buffer; 79 | } 80 | private: 81 | void reset() 82 | { 83 | m_numBytes = 0; 84 | m_bufferSize = 0; 85 | 86 | // according to RFC 1321 87 | m_hash[0] = 0x67452301; 88 | m_hash[1] = 0xefcdab89; 89 | m_hash[2] = 0x98badcfe; 90 | m_hash[3] = 0x10325476; 91 | m_hash[4] = 0xc3d2e1f0; 92 | } 93 | /// process 64 bytes 94 | void processBlock(const void* data) 95 | { 96 | uint32_t a = m_hash[0]; 97 | uint32_t b = m_hash[1]; 98 | uint32_t c = m_hash[2]; 99 | uint32_t d = m_hash[3]; 100 | uint32_t e = m_hash[4]; 101 | 102 | // data represented as 16x 32-bit words 103 | const uint32_t* input = (uint32_t*)data; 104 | // convert to big endian 105 | uint32_t words[80]; 106 | for (int i = 0; i < 16; i++) 107 | #if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) 108 | words[i] = input[i]; 109 | #else 110 | words[i] = swap(input[i]); 111 | #endif 112 | 113 | // extend to 80 words 114 | for (int i = 16; i < 80; i++) 115 | words[i] = rotate(words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16], 1); 116 | 117 | // first round 118 | for (int i = 0; i < 4; i++) 119 | { 120 | int offset = 5 * i; 121 | e += rotate(a, 5) + f1(b, c, d) + words[offset] + 0x5a827999; b = rotate(b, 30); 122 | d += rotate(e, 5) + f1(a, b, c) + words[offset + 1] + 0x5a827999; a = rotate(a, 30); 123 | c += rotate(d, 5) + f1(e, a, b) + words[offset + 2] + 0x5a827999; e = rotate(e, 30); 124 | b += rotate(c, 5) + f1(d, e, a) + words[offset + 3] + 0x5a827999; d = rotate(d, 30); 125 | a += rotate(b, 5) + f1(c, d, e) + words[offset + 4] + 0x5a827999; c = rotate(c, 30); 126 | } 127 | 128 | // second round 129 | for (int i = 4; i < 8; i++) 130 | { 131 | int offset = 5 * i; 132 | e += rotate(a, 5) + f2(b, c, d) + words[offset] + 0x6ed9eba1; b = rotate(b, 30); 133 | d += rotate(e, 5) + f2(a, b, c) + words[offset + 1] + 0x6ed9eba1; a = rotate(a, 30); 134 | c += rotate(d, 5) + f2(e, a, b) + words[offset + 2] + 0x6ed9eba1; e = rotate(e, 30); 135 | b += rotate(c, 5) + f2(d, e, a) + words[offset + 3] + 0x6ed9eba1; d = rotate(d, 30); 136 | a += rotate(b, 5) + f2(c, d, e) + words[offset + 4] + 0x6ed9eba1; c = rotate(c, 30); 137 | } 138 | 139 | // third round 140 | for (int i = 8; i < 12; i++) 141 | { 142 | int offset = 5 * i; 143 | e += rotate(a, 5) + f3(b, c, d) + words[offset] + 0x8f1bbcdc; b = rotate(b, 30); 144 | d += rotate(e, 5) + f3(a, b, c) + words[offset + 1] + 0x8f1bbcdc; a = rotate(a, 30); 145 | c += rotate(d, 5) + f3(e, a, b) + words[offset + 2] + 0x8f1bbcdc; e = rotate(e, 30); 146 | b += rotate(c, 5) + f3(d, e, a) + words[offset + 3] + 0x8f1bbcdc; d = rotate(d, 30); 147 | a += rotate(b, 5) + f3(c, d, e) + words[offset + 4] + 0x8f1bbcdc; c = rotate(c, 30); 148 | } 149 | 150 | // fourth round 151 | for (int i = 12; i < 16; i++) 152 | { 153 | int offset = 5 * i; 154 | e += rotate(a, 5) + f2(b, c, d) + words[offset] + 0xca62c1d6; b = rotate(b, 30); 155 | d += rotate(e, 5) + f2(a, b, c) + words[offset + 1] + 0xca62c1d6; a = rotate(a, 30); 156 | c += rotate(d, 5) + f2(e, a, b) + words[offset + 2] + 0xca62c1d6; e = rotate(e, 30); 157 | b += rotate(c, 5) + f2(d, e, a) + words[offset + 3] + 0xca62c1d6; d = rotate(d, 30); 158 | a += rotate(b, 5) + f2(c, d, e) + words[offset + 4] + 0xca62c1d6; c = rotate(c, 30); 159 | } 160 | 161 | // update hash 162 | m_hash[0] += a; 163 | m_hash[1] += b; 164 | m_hash[2] += c; 165 | m_hash[3] += d; 166 | m_hash[4] += e; 167 | } 168 | 169 | void processBuffer(void) 170 | { 171 | size_t paddedLength = m_bufferSize * 8; 172 | 173 | // plus one bit set to 1 (always appended) 174 | paddedLength++; 175 | 176 | // number of bits must be (numBits % 512) = 448 177 | size_t lower11Bits = paddedLength & 511; 178 | if (lower11Bits <= 448) 179 | paddedLength += 448 - lower11Bits; 180 | else 181 | paddedLength += 512 + 448 - lower11Bits; 182 | // convert from bits to bytes 183 | paddedLength /= 8; 184 | 185 | // only needed if additional data flows over into a second block 186 | unsigned char extra[BlockSize]; 187 | 188 | // append a "1" bit, 128 => binary 10000000 189 | if (m_bufferSize < BlockSize) 190 | m_buffer[m_bufferSize] = 128; 191 | else 192 | extra[0] = 128; 193 | 194 | size_t i; 195 | for (i = m_bufferSize + 1; i < BlockSize; i++) 196 | m_buffer[i] = 0; 197 | for (; i < paddedLength; i++) 198 | extra[i - BlockSize] = 0; 199 | 200 | // add message length in bits as 64 bit number 201 | uint64_t msgBits = 8 * (m_numBytes + m_bufferSize); 202 | // find right position 203 | unsigned char* addLength; 204 | if (paddedLength < BlockSize) 205 | addLength = m_buffer + paddedLength; 206 | else 207 | addLength = extra + paddedLength - BlockSize; 208 | 209 | // must be big endian 210 | *addLength++ = (unsigned char)((msgBits >> 56) & 0xFF); 211 | *addLength++ = (unsigned char)((msgBits >> 48) & 0xFF); 212 | *addLength++ = (unsigned char)((msgBits >> 40) & 0xFF); 213 | *addLength++ = (unsigned char)((msgBits >> 32) & 0xFF); 214 | *addLength++ = (unsigned char)((msgBits >> 24) & 0xFF); 215 | *addLength++ = (unsigned char)((msgBits >> 16) & 0xFF); 216 | *addLength++ = (unsigned char)((msgBits >> 8) & 0xFF); 217 | *addLength = (unsigned char)(msgBits & 0xFF); 218 | 219 | // process blocks 220 | processBlock(m_buffer); 221 | // flowed over into a second block ? 222 | if (paddedLength > BlockSize) 223 | processBlock(extra); 224 | } 225 | 226 | static uint32_t f1(uint32_t b, uint32_t c, uint32_t d) 227 | { 228 | return d ^ (b & (c ^ d)); // original: f = (b & c) | ((~b) & d); 229 | } 230 | 231 | static uint32_t f2(uint32_t b, uint32_t c, uint32_t d) 232 | { 233 | return b ^ c ^ d; 234 | } 235 | 236 | static uint32_t f3(uint32_t b, uint32_t c, uint32_t d) 237 | { 238 | return (b & c) | (b & d) | (c & d); 239 | } 240 | 241 | static uint32_t rotate(uint32_t a, uint32_t c) 242 | { 243 | return (a << c) | (a >> (32 - c)); 244 | } 245 | 246 | static uint32_t swap(uint32_t x) 247 | { 248 | return (x >> 24) | 249 | ((x >> 8) & 0x0000FF00) | 250 | ((x << 8) & 0x00FF0000) | 251 | (x << 24); 252 | } 253 | private: 254 | /// size of processed data in bytes 255 | uint64_t m_numBytes; 256 | /// valid bytes in m_buffer 257 | size_t m_bufferSize; 258 | /// bytes not processed yet 259 | uint8_t m_buffer[BlockSize]; 260 | 261 | enum { HashValues = HashBytes / 4 }; 262 | /// hash, stored as integers 263 | uint32_t m_hash[HashValues]; 264 | }; 265 | -------------------------------------------------------------------------------- /NetDebugger/TextEncodeType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | enum class TextEncodeType : int 7 | { 8 | ASCII = 0, 9 | UTF8 = 1, 10 | UTF16LE = 2, 11 | UTF32LE = 3, 12 | UTF16BE = 4, 13 | UTF32BE = 5, 14 | HEX = 6, 15 | _MAX 16 | }; 17 | 18 | inline const wchar_t* TextEncodeTypeName(TextEncodeType type) 19 | { 20 | switch (type) 21 | { 22 | case TextEncodeType::ASCII: return L"ASCII"; 23 | case TextEncodeType::UTF8: return L"UTF8"; 24 | case TextEncodeType::UTF16LE: return L"UTF16"; 25 | case TextEncodeType::UTF32LE: return L"UTF32"; 26 | case TextEncodeType::UTF16BE: return L"UTF16-BE"; 27 | case TextEncodeType::UTF32BE: return L"UTF32-BE"; 28 | case TextEncodeType::HEX: return L"HEX"; 29 | } 30 | return L"ASCII"; 31 | } 32 | 33 | namespace Transform 34 | { 35 | inline static uint16_t swap(uint16_t value) 36 | { 37 | return (uint16_t)(((uint8_t)(value >> 8)) | ((uint16_t)(value << 8))); 38 | } 39 | 40 | inline static uint32_t swap(uint32_t value) 41 | { 42 | return (uint32_t)( 43 | ((uint8_t)(value >> 24)) 44 | | ((uint32_t)((value >> 8) & 0x0000FF00)) 45 | | ((uint32_t)((value << 8) & 0x00FF0000)) 46 | | ((uint32_t)((value << 24) & 0xFF000000))); 47 | } 48 | 49 | inline std::wstring ascii_string_to_utf16(const std::vector& data) 50 | { 51 | std::wstring result; 52 | auto length = data.size(); 53 | auto src = data.data(); 54 | auto end = src + length; 55 | for (auto p = src; p < end; ++p) 56 | { 57 | if (*p > 127) 58 | result.append(1, '?'); 59 | else 60 | result.append(1, *p); 61 | } 62 | return result; 63 | } 64 | inline std::wstring utf8_string_to_utf16(const std::vector& data) 65 | { 66 | std::wstring result; 67 | auto length = data.size(); 68 | auto src = data.data(); 69 | auto end = src + length; 70 | for (auto p = src; p < end; ++p) 71 | { 72 | if (*p > 127) 73 | result.append(1, '?'); 74 | else 75 | result.append(1, *p); 76 | } 77 | return result; 78 | } 79 | 80 | inline std::string bin_string_to_hexutf8(const std::vector& data) 81 | { 82 | std::string s(data.size() << 1, 0); 83 | const static char kHEX_TABLE[] = "0123456789ABCDEF"; 84 | auto end = data.data() + data.size(); 85 | auto d = (char*)s.data(); 86 | for (auto p = data.data(); p != end; ++p) 87 | { 88 | auto c = *p; 89 | *d++ = kHEX_TABLE[static_cast(c >> 4)]; 90 | *d++ = kHEX_TABLE[static_cast(c & 0x0F)]; 91 | } 92 | return s; 93 | } 94 | inline std::wstring bin_string_to_hexwstring_format(const std::vector& data) 95 | { 96 | std::wstring s(data.size() * 3, 0); 97 | const static wchar_t kHEX_TABLE[] = L"0123456789ABCDEF"; 98 | auto end = data.data() + data.size(); 99 | auto d = (wchar_t*)s.data(); 100 | for (auto p = data.data(); p != end; ++p) 101 | { 102 | auto c = static_cast(*p); 103 | *d++ = kHEX_TABLE[static_cast(c >> 4)]; 104 | *d++ = kHEX_TABLE[static_cast(c & 0x0F)]; 105 | *d++ = L' '; 106 | } 107 | return s; 108 | } 109 | inline std::wstring bin_string_to_hexwstring_format(const std::wstring& data) 110 | { 111 | std::wstring s(data.size() * 3, 0); 112 | const static wchar_t kHEX_TABLE[] = L"0123456789ABCDEF"; 113 | auto end = data.data() + data.size(); 114 | auto d = (wchar_t*)s.data(); 115 | for (auto p = data.data(); p != end; ++p) 116 | { 117 | auto c = static_cast(*p); 118 | *d++ = kHEX_TABLE[static_cast(c >> 4)]; 119 | *d++ = kHEX_TABLE[static_cast(c & 0x0F)]; 120 | *d++ = L' '; 121 | } 122 | return s; 123 | } 124 | 125 | inline void hexutf16_to_bin_string(const std::wstring& data, std::vector& result) 126 | { 127 | auto p = data.data(); 128 | auto end = p + data.length(); 129 | size_t i = 0; 130 | uint8_t d = 0; 131 | result.reserve(data.length() / 2); 132 | while (p < end) 133 | { 134 | d = 0; 135 | if (*p >= '0' && *p <= '9') 136 | d |= (*p - '0') << 4; 137 | else if (*p >= 'A' && *p <= 'F') 138 | d |= (*p - 'A' + 10) << 4; 139 | else if (*p >= 'a' && *p <= 'f') 140 | d |= (*p - 'a' + 10) << 4; 141 | else 142 | { 143 | ++p; 144 | continue; 145 | } 146 | 147 | if (++p >= end) 148 | { 149 | result.push_back(d); 150 | break; 151 | } 152 | 153 | if (*p >= '0' && *p <= '9') 154 | d |= (*p - '0'); 155 | else if (*p >= 'A' && *p <= 'F') 156 | d |= (*p - 'A' + 10); 157 | else if (*p >= 'a' && *p <= 'f') 158 | d |= (*p - 'a' + 10); 159 | 160 | result.push_back(d); 161 | ++p; 162 | ++i; 163 | } 164 | } 165 | 166 | inline std::wstring DecodeToWString(const std::vector& data, TextEncodeType type) 167 | { 168 | try 169 | { 170 | switch (type) 171 | { 172 | case TextEncodeType::ASCII: 173 | { 174 | std::wstring result; 175 | auto length = data.size(); 176 | auto src = data.data(); 177 | auto end = src + length; 178 | for (auto p = src; p < end; ++p) 179 | { 180 | if (*p > 127) 181 | result.append(1, '?'); 182 | else 183 | result.append(1, *p); 184 | } 185 | return result; 186 | } 187 | case TextEncodeType::UTF8: 188 | { 189 | std::wstring result; 190 | std::wstring_convert, wchar_t> strCnv; 191 | auto first = reinterpret_cast(data.data()); 192 | auto last = first + data.size(); 193 | return strCnv.from_bytes(first, last); 194 | } 195 | case TextEncodeType::UTF16LE: 196 | { 197 | std::wstring result; 198 | result.reserve(data.size() / sizeof(wchar_t)); 199 | auto first = reinterpret_cast(data.data()); 200 | auto last = first + data.size(); 201 | result.assign(first, last); 202 | return result; 203 | } 204 | case TextEncodeType::UTF32LE: 205 | { 206 | std::wstring result; 207 | result.reserve(data.size() / sizeof(uint32_t)); 208 | auto first = reinterpret_cast(data.data()); 209 | auto last = first + (data.size() / sizeof(uint32_t)); 210 | result.assign(first, last); 211 | return result; 212 | } 213 | case TextEncodeType::UTF16BE: 214 | { 215 | std::wstring result; 216 | result.reserve(data.size() / sizeof(wchar_t)); 217 | auto first = reinterpret_cast(data.data()); 218 | auto last = first + (data.size() / sizeof(wchar_t)); 219 | while (first != last) 220 | { 221 | result.push_back((wchar_t)swap((uint16_t)(*first))); 222 | ++first; 223 | } 224 | return result; 225 | } 226 | case TextEncodeType::UTF32BE: 227 | { 228 | std::wstring result; 229 | result.reserve(data.size() / sizeof(uint32_t)); 230 | auto first = reinterpret_cast(data.data()); 231 | auto last = first + (data.size() / sizeof(uint32_t)); 232 | while (first != last) 233 | { 234 | result.push_back((wchar_t)swap((uint32_t)(*first))); 235 | ++first; 236 | } 237 | return result; 238 | } 239 | case TextEncodeType::HEX: 240 | { 241 | return bin_string_to_hexwstring_format(data); 242 | } 243 | } 244 | } 245 | catch (...) 246 | { 247 | 248 | } 249 | return std::wstring(data.begin(), data.end()); 250 | } 251 | 252 | inline void DecodeWStringTo(const std::wstring& data, TextEncodeType type, std::vector& result) 253 | { 254 | try 255 | { 256 | switch (type) 257 | { 258 | case TextEncodeType::ASCII: 259 | { 260 | auto src = data.data(); 261 | auto end = data.data() + data.length(); 262 | for (auto p = src; p < end; ++p) 263 | { 264 | if (*p > 127) 265 | result.push_back('?'); 266 | else 267 | result.push_back((uint8_t)*p); 268 | } 269 | break; 270 | } 271 | case TextEncodeType::UTF8: 272 | { 273 | std::wstring_convert, wchar_t> strCnv; 274 | auto temp = strCnv.to_bytes(data); 275 | result.resize(temp.length()); 276 | memcpy(result.data(), temp.data(), result.size()); 277 | break; 278 | } 279 | case TextEncodeType::UTF16LE: 280 | { 281 | result.resize(data.length() * sizeof(wchar_t)); 282 | memcpy(result.data(), data.data(), result.size() * sizeof(wchar_t)); 283 | break; 284 | } 285 | case TextEncodeType::UTF32LE: 286 | { 287 | auto first = reinterpret_cast(data.data()); 288 | auto last = first + data.length(); 289 | result.resize(data.length() * sizeof(uint32_t)); 290 | auto p = reinterpret_cast(result.data()); 291 | while (first != last) 292 | { 293 | *p++ = *first++; 294 | } 295 | break; 296 | } 297 | case TextEncodeType::UTF16BE: 298 | { 299 | auto first = reinterpret_cast(data.data()); 300 | auto last = first + data.length(); 301 | result.resize(data.length() * sizeof(uint16_t)); 302 | auto p = reinterpret_cast(result.data()); 303 | while (first != last) 304 | { 305 | *p++ = swap(*first++); 306 | } 307 | break; 308 | } 309 | case TextEncodeType::UTF32BE: 310 | { 311 | auto first = reinterpret_cast(data.data()); 312 | auto last = first + data.length(); 313 | result.resize(data.length() * sizeof(uint32_t)); 314 | auto p = reinterpret_cast(result.data()); 315 | while (first != last) 316 | { 317 | *p++ = swap(*first++); 318 | } 319 | break; 320 | } 321 | case TextEncodeType::HEX: 322 | { 323 | hexutf16_to_bin_string(data, result); 324 | break; 325 | } 326 | default: 327 | result.resize(data.size()*sizeof(wchar_t)); 328 | memcpy(result.data(), data.data(), result.size()); 329 | break; 330 | } 331 | } 332 | catch (...) 333 | { 334 | result.resize(data.size() * sizeof(wchar_t)); 335 | memcpy(result.data(), data.data(), result.size()); 336 | } 337 | } 338 | } -------------------------------------------------------------------------------- /NetDebugger/TCPServer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "TCPServer.h" 3 | #include "NetDebugger.h" 4 | #include "OEMStringHelper.hpp" 5 | 6 | static std::wstring ProtocolToWstring(const boost::asio::ip::tcp::endpoint::protocol_type& protocol) 7 | { 8 | std::wstring result = L"TCP/IP"; 9 | if (protocol.family() == AF_INET) 10 | result += L"V4"; 11 | if (protocol.family() == AF_INET6) 12 | result += L"V6"; 13 | return result; 14 | } 15 | 16 | TCPServer::TCPServer(): 17 | m_ListenAddress(L"127.0.0.1"), 18 | m_ListenPort(0), 19 | m_ReuseAddress(false), 20 | m_Keepalive(false), 21 | m_Acceptor(theApp.GetIOContext()) 22 | { 23 | 24 | } 25 | 26 | TCPServer::~TCPServer() 27 | { 28 | } 29 | 30 | bool TCPServer::IsServer(void) 31 | { 32 | return true; 33 | } 34 | 35 | bool TCPServer::IsSingleChannel(void) 36 | { 37 | return false; 38 | } 39 | 40 | IDevice::PDTable TCPServer::EnumProperties() 41 | { 42 | using StaticProperty = PropertyDescriptionHelper::StaticPropertyDescription; 43 | PDTable results; 44 | auto self = shared_from_this(); 45 | auto pd = std::make_shared( 46 | L"ListenAddress", 47 | L"DEVICE.TCPSERVER.PROP.LISTENADDRESS", 48 | L"127.0.0.1", 49 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 50 | ); 51 | pd->AddEnumOptions(L"0.0.0.0", L"0.0.0.0", false); 52 | pd->AddEnumOptions(L"127.0.0.1", L"127.0.0.1", false); 53 | pd->AddEnumOptions(L"0:0:0:0:0:0:0:0", L"0:0:0:0:0:0:0:0", false); 54 | pd->AddEnumOptions(L"0:0:0:0:0:0:0:1", L"0:0:0:0:0:0:0:1", false); 55 | pd->BindMethod( 56 | [self]() { return self->m_ListenAddress; }, 57 | [self](const std::wstring& value) { self->m_ListenAddress = value; } 58 | ); 59 | results.push_back(pd); 60 | 61 | pd = std::make_shared( 62 | L"ListenPort", 63 | L"DEVICE.TCPSERVER.PROP.LISTENPORT", 64 | uint16_t(0), 65 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 66 | ); 67 | pd->BindMethod( 68 | [self]() { return std::to_wstring(self->m_ListenPort); }, 69 | [self](const std::wstring& value) { self->m_ListenPort = static_cast(std::wcstoul(value.c_str(), nullptr, 10)); } 70 | ); 71 | results.push_back(pd); 72 | 73 | pd = std::make_shared( 74 | L"ReuseAddress", 75 | L"DEVICE.TCPSERVER.PROP.REUSEADDRESS", 76 | bool(false), 77 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 78 | ); 79 | pd->BindMethod( 80 | [self]() { return std::to_wstring(self->m_ReuseAddress ? 1 : 0); }, 81 | [self](const std::wstring& value) { self->m_ReuseAddress = value == L"1"; } 82 | ); 83 | results.push_back(pd); 84 | 85 | pd = std::make_shared( 86 | L"Keepalive", 87 | L"DEVICE.TCPSERVER.PROP.KEEPALIVE", 88 | bool(false), 89 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 90 | ); 91 | 92 | pd->BindMethod( 93 | [self]() { return std::to_wstring(self->m_Keepalive ? 1 : 0); }, 94 | [self](const std::wstring& value) { self->m_Keepalive = value == L"1"; }); 95 | results.push_back(pd); 96 | 97 | pd = std::make_shared( 98 | L"Protocol", 99 | L"DEVICE.TCPSERVER.PROP.PROTOCOL", 100 | L"", 101 | IDevice::PropertyChangeFlags::Readonly 102 | ); 103 | pd->BindMethod( 104 | [self]() 105 | { 106 | boost::system::error_code ec; 107 | auto local = self->m_Acceptor.local_endpoint(ec); 108 | if (ec) 109 | return StringToWString(ec.message()); 110 | else 111 | return ProtocolToWstring(local.protocol()); 112 | }, 113 | nullptr 114 | ); 115 | results.push_back(pd); 116 | 117 | return results; 118 | } 119 | 120 | void TCPServer::Start(void) 121 | { 122 | if (Started()) 123 | return; 124 | 125 | StatusChanged(DeviceStatus::Connecting, std::wstring()); 126 | boost::system::error_code ec; 127 | auto address = boost::asio::ip::address::from_string(WStringToString(m_ListenAddress), ec); 128 | if (ec) 129 | { 130 | Close(ec); 131 | return; 132 | } 133 | 134 | boost::asio::ip::tcp::endpoint ep(address, m_ListenPort); 135 | m_Acceptor.open(ep.protocol(), ec); 136 | if (ec) 137 | { 138 | Close(ec); 139 | return; 140 | } 141 | 142 | m_Acceptor.bind(ep, ec); 143 | if (ec) 144 | { 145 | Close(ec); 146 | return; 147 | } 148 | m_Acceptor.listen(m_Acceptor.max_listen_connections, ec); 149 | if (ec) 150 | { 151 | Close(ec); 152 | return; 153 | } 154 | 155 | m_Acceptor.set_option(boost::asio::socket_base::reuse_address(m_ReuseAddress), ec); 156 | if (ec) 157 | { 158 | Close(ec); 159 | return; 160 | } 161 | 162 | StartAcceptClient(); 163 | PropertyChanged(); 164 | StatusChanged(DeviceStatus::Connected, StringToWString(ec.message())); 165 | } 166 | 167 | void TCPServer::Close(const boost::system::error_code& errorCode) 168 | { 169 | boost::system::error_code ec; 170 | m_Acceptor.cancel(ec); 171 | m_Acceptor.close(ec); 172 | PropertyChanged(); 173 | StatusChanged(DeviceStatus::Disconnected, StringToWString(errorCode.message())); 174 | } 175 | 176 | void TCPServer::StartAcceptClient(void) 177 | { 178 | auto server = this->shared_from_this(); 179 | std::shared_ptr channel(new TcpChannel(server), [](TcpChannel* ch) 180 | { 181 | ch->Close(); 182 | delete ch; 183 | }); 184 | 185 | m_Acceptor.async_accept(channel->m_Socket, [server, channel](const boost::system::error_code& ec) 186 | { 187 | if (!ec) 188 | { 189 | boost::system::error_code ecSet; 190 | channel->m_Socket.set_option(boost::asio::socket_base::reuse_address(server->m_ReuseAddress), ecSet); 191 | channel->m_Socket.set_option(boost::asio::socket_base::keep_alive(server->m_Keepalive), ecSet); 192 | server->ChannelConnected(channel,StringToWString(ec.message())); 193 | server->StartAcceptClient(); 194 | } 195 | }); 196 | } 197 | 198 | void TCPServer::Stop(void) 199 | { 200 | if (Started()) 201 | { 202 | StatusChanged(DeviceStatus::Disconnecting, std::wstring()); 203 | boost::system::error_code ec; 204 | m_Acceptor.cancel(ec); 205 | m_Acceptor.close(ec); 206 | PropertyChanged(); 207 | StatusChanged(DeviceStatus::Disconnected, std::wstring()); 208 | } 209 | } 210 | 211 | TcpChannel::TcpChannel(std::shared_ptr owner) : 212 | m_Owner(owner), 213 | m_Socket(theApp.GetIOContext()) 214 | { 215 | 216 | } 217 | 218 | TcpChannel::~TcpChannel(void) 219 | { 220 | CloseChannel(false, boost::system::errc::make_error_code(boost::system::errc::success)); 221 | } 222 | 223 | std::wstring TcpChannel::Id(void) const 224 | { 225 | if (sizeof(size_t) == sizeof(void*)) 226 | return std::to_wstring(reinterpret_cast(this)); 227 | else 228 | return std::to_wstring(reinterpret_cast(this)); 229 | } 230 | 231 | std::wstring TcpChannel::Description(void) const 232 | { 233 | std::wstring result; 234 | boost::system::error_code ec; 235 | auto local = m_Socket.local_endpoint(ec); 236 | if (ec) 237 | { 238 | result = L"none" + result; 239 | } 240 | else 241 | { 242 | result += L"local("; 243 | result += StringToWString(local.address().to_string()) + L":" + std::to_wstring(local.port()); 244 | result += L")"; 245 | } 246 | 247 | auto remote = m_Socket.remote_endpoint(ec); 248 | if (ec) 249 | { 250 | result += L" <---> none"; 251 | } 252 | else 253 | { 254 | result += L" <---> remote("; 255 | result += StringToWString(remote.address().to_string()) + L":" + std::to_wstring(remote.port()); 256 | result += L")"; 257 | } 258 | return result; 259 | } 260 | 261 | 262 | std::wstring TcpChannel::LocalEndPoint(void) const 263 | { 264 | std::wstring result; 265 | boost::system::error_code ec; 266 | auto local = m_Socket.local_endpoint(ec); 267 | if (ec) 268 | { 269 | result = L"none"; 270 | } 271 | else 272 | { 273 | result = StringToWString(local.address().to_string()) + L"#" + std::to_wstring(local.port()); 274 | } 275 | return result; 276 | } 277 | 278 | std::wstring TcpChannel::RemoteEndPoint(void) const 279 | { 280 | std::wstring result; 281 | boost::system::error_code ec; 282 | auto local = m_Socket.remote_endpoint(ec); 283 | if (ec) 284 | { 285 | result = L"none"; 286 | } 287 | else 288 | { 289 | result = StringToWString(local.address().to_string()) + L"#" + std::to_wstring(local.port()); 290 | } 291 | return result; 292 | } 293 | 294 | void TcpChannel::Read(OutputBuffer buffer, IoCompletionHandler handler) 295 | { 296 | auto client = shared_from_this(); 297 | boost::asio::async_read( 298 | m_Socket, 299 | boost::asio::buffer(buffer->data(), buffer->size()), 300 | [client, handler](const boost::system::error_code& ec, size_t bytestransfer) 301 | { 302 | if (handler != nullptr) 303 | handler(!ec, bytestransfer); 304 | if (ec) 305 | { 306 | if (ec != boost::system::errc::operation_canceled) 307 | client->CloseChannel(true, ec); 308 | } 309 | } 310 | ); 311 | } 312 | void TcpChannel::Write(InputBuffer buffer, IoCompletionHandler handler) 313 | { 314 | auto client = shared_from_this(); 315 | boost::asio::async_write( 316 | m_Socket, 317 | boost::asio::const_buffer(buffer.buffer, buffer.bufferSize), 318 | [client, handler, this](const boost::system::error_code& ec, size_t bytestransfer) 319 | { 320 | if (handler != nullptr) 321 | handler(!ec, bytestransfer); 322 | if (ec) 323 | { 324 | if (ec != boost::system::errc::operation_canceled) 325 | client->CloseChannel(true, ec); 326 | } 327 | } 328 | ); 329 | } 330 | void TcpChannel::ReadSome(OutputBuffer buffer, IoCompletionHandler handler) 331 | { 332 | auto client = shared_from_this(); 333 | m_Socket.async_read_some( 334 | boost::asio::buffer(buffer->data(), buffer->size()), 335 | [client, handler](const boost::system::error_code& ec, size_t bytestransfer) 336 | { 337 | handler(!ec, bytestransfer); 338 | if (ec) 339 | { 340 | if (ec != boost::system::errc::operation_canceled) 341 | client->CloseChannel(true, ec); 342 | } 343 | } 344 | ); 345 | } 346 | void TcpChannel::WriteSome(InputBuffer buffer, IoCompletionHandler handler) 347 | { 348 | auto client = shared_from_this(); 349 | m_Socket.async_write_some( 350 | boost::asio::const_buffer(buffer.buffer, buffer.bufferSize), 351 | [client, handler](const boost::system::error_code& ec, size_t bytestransfer) 352 | { 353 | handler(!ec, bytestransfer); 354 | if (ec) 355 | { 356 | if (ec != boost::system::errc::operation_canceled) 357 | client->CloseChannel(true, ec); 358 | } 359 | } 360 | ); 361 | } 362 | 363 | void TcpChannel::Cancel(void) 364 | { 365 | boost::system::error_code ec; 366 | m_Socket.cancel(ec); 367 | } 368 | 369 | void TcpChannel::Close(void) 370 | { 371 | CloseChannel(true, boost::system::errc::make_error_code(boost::system::errc::operation_canceled)); 372 | } 373 | 374 | void TcpChannel::CloseChannel(bool notify, const boost::system::error_code& error) 375 | { 376 | boost::system::error_code ec; 377 | if (m_Socket.is_open()) 378 | { 379 | m_Socket.cancel(ec); 380 | m_Socket.shutdown(m_Socket.shutdown_both, ec); 381 | m_Socket.close(ec); 382 | if (notify) 383 | { 384 | auto owner = m_Owner.lock(); 385 | if(owner!=nullptr) 386 | owner->ChannelDisconnected(shared_from_this(), StringToWString(error.message())); 387 | } 388 | } 389 | } 390 | 391 | 392 | REGISTER_CLASS_TITLE(TCPServer, L"DEVICE.CLASS.TCPSERVER.TITLE"); -------------------------------------------------------------------------------- /NetDebugger/CRealTimeStatusCtrl.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "NetDebugger.h" 3 | #include "CRealTimeStatusCtrl.h" 4 | #include "GdiplusAux.hpp" 5 | constexpr int kXSTEP_LENGTH = 10; 6 | 7 | BEGIN_MESSAGE_MAP(CRealTimeStatusCtrl, CWnd) 8 | ON_WM_ERASEBKGND() 9 | ON_WM_PAINT() 10 | END_MESSAGE_MAP() 11 | 12 | CRealTimeStatusCtrl::CRealTimeStatusCtrl(): 13 | m_connected(false), 14 | m_readBytes(0), 15 | m_writeBytes(0), 16 | m_MaxReadSpeed(0), 17 | m_MaxWriteSpeed(0), 18 | m_AveReadSpeed(0), 19 | m_AveWriteSpeed(0) 20 | { 21 | 22 | } 23 | 24 | CRealTimeStatusCtrl::~CRealTimeStatusCtrl() 25 | { 26 | 27 | } 28 | 29 | void CRealTimeStatusCtrl::AddSpeedPoint(uint64_t readspeed, uint64_t writespeed) 30 | { 31 | CRect rcClient; 32 | GetClientRect(&rcClient); 33 | auto count = (rcClient.Width() / kXSTEP_LENGTH) + 2; 34 | uint64_t sum = 0; 35 | if (count <= (int)m_ReadSpeeds.size() && (!m_ReadSpeeds.empty())) 36 | { 37 | auto removed = m_ReadSpeeds[0]; 38 | m_ReadSpeeds.erase(m_ReadSpeeds.begin()); 39 | if (removed >= m_MaxReadSpeed) 40 | { 41 | m_MaxReadSpeed = 0; 42 | for (auto t : m_ReadSpeeds) 43 | { 44 | if (t > m_MaxReadSpeed) 45 | m_MaxReadSpeed = t; 46 | } 47 | } 48 | } 49 | m_ReadSpeeds.push_back(readspeed); 50 | for (auto t : m_ReadSpeeds) 51 | { 52 | sum += t; 53 | } 54 | m_AveReadSpeed = sum / m_ReadSpeeds.size(); 55 | if (readspeed > m_MaxReadSpeed) 56 | m_MaxReadSpeed = readspeed; 57 | 58 | if (count <= (int)m_WriteSpeeds.size() && (!m_WriteSpeeds.empty())) 59 | { 60 | auto removed = m_WriteSpeeds[0]; 61 | m_WriteSpeeds.erase(m_WriteSpeeds.begin()); 62 | if (removed >= m_MaxWriteSpeed) 63 | { 64 | m_MaxWriteSpeed = 0; 65 | for (auto t : m_WriteSpeeds) 66 | { 67 | if (t > m_MaxWriteSpeed) 68 | m_MaxWriteSpeed = t; 69 | } 70 | } 71 | } 72 | m_WriteSpeeds.push_back(writespeed); 73 | sum = 0; 74 | for (auto t : m_WriteSpeeds) 75 | { 76 | sum += t; 77 | } 78 | m_AveWriteSpeed = sum / m_WriteSpeeds.size(); 79 | if (writespeed > m_MaxWriteSpeed) 80 | m_MaxWriteSpeed = writespeed; 81 | 82 | Invalidate(); 83 | } 84 | 85 | void CRealTimeStatusCtrl::UpdateStatistics(bool connected, uint64_t readBytes, uint64_t writeBytes) 86 | { 87 | auto usedTime = std::chrono::high_resolution_clock::now() - m_lastUpdateTime; 88 | auto readSpeed = static_cast((readBytes - m_readBytes) / (usedTime.count() / 1000000000.0)); 89 | auto writeSpeed = static_cast((writeBytes - m_writeBytes) / (usedTime.count() / 1000000000.0)); 90 | m_lastUpdateTime = std::chrono::high_resolution_clock::now(); 91 | 92 | m_connected = connected; 93 | m_readBytes = readBytes; 94 | m_writeBytes = writeBytes; 95 | AddSpeedPoint(readSpeed, writeSpeed); 96 | RedrawWindow(); 97 | } 98 | 99 | BOOL CRealTimeStatusCtrl::OnEraseBkgnd(CDC* pDC) 100 | { 101 | return FALSE; 102 | } 103 | 104 | int CRealTimeStatusCtrl::DrawStatisicsString(Gdiplus::Graphics& graphics,const Gdiplus::RectF& clientRect) 105 | { 106 | graphics.SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeAntiAlias); 107 | graphics.SetTextRenderingHint(Gdiplus::TextRenderingHint::TextRenderingHintClearTypeGridFit); 108 | 109 | auto fontFamily = CreateUIFontFamily(); 110 | Gdiplus::Font font(fontFamily.get(), 16.0f, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel); 111 | CString statisticsRXC; 112 | CString statisticsTXC; 113 | CString statisticsRXS; 114 | CString statisticsTXS; 115 | 116 | statisticsRXC.Format(LSTEXT(MAINWND.STATISTICSCTRL.RECV.BYTES), std::to_wstring(m_readBytes).c_str()); 117 | statisticsTXC.Format(LSTEXT(MAINWND.STATISTICSCTRL.SEND.BYTES), std::to_wstring(m_writeBytes).c_str()); 118 | statisticsRXS.Format(LSTEXT(MAINWND.STATISTICSCTRL.RECV.SPEED), GetReadSpeedString().GetString()); 119 | statisticsTXS.Format(LSTEXT(MAINWND.STATISTICSCTRL.SEND.SPEED), GetWriteSpeedString().GetString()); 120 | 121 | Gdiplus::StringFormat sf; 122 | sf.SetAlignment(Gdiplus::StringAlignment::StringAlignmentNear); 123 | sf.SetLineAlignment(Gdiplus::StringAlignment::StringAlignmentNear); 124 | sf.SetTrimming(Gdiplus::StringTrimming::StringTrimmingEllipsisWord); 125 | Gdiplus::Pen textBrPen(Gdiplus::Color(128, 0, 0, 0), 0); 126 | 127 | auto textRectRXC = clientRect; 128 | textRectRXC.Inflate(-6.0f, -6.0f); 129 | textRectRXC.Height = (Gdiplus::REAL)(MeasureStringHeight(graphics, statisticsRXC, font, (int)textRectRXC.Width)); 130 | 131 | auto textRectTXC = clientRect; 132 | textRectTXC.Inflate(-6.0f, -6.0f); 133 | textRectTXC.Y = textRectRXC.GetBottom(); 134 | textRectTXC.Height = (Gdiplus::REAL)(MeasureStringHeight(graphics, statisticsTXC, font, (int)textRectTXC.Width)); 135 | 136 | auto textRectRXS = clientRect; 137 | textRectRXS.Inflate(-6.0f, -6.0f); 138 | textRectRXS.Y = textRectTXC.GetBottom(); 139 | textRectRXS.Height = (Gdiplus::REAL)(MeasureStringHeight(graphics, statisticsRXS, font, (int)textRectRXS.Width)); 140 | 141 | auto textRectTXS = clientRect; 142 | textRectTXS.Inflate(-6.0f, -6.0f); 143 | textRectTXS.Y = textRectRXS.GetBottom(); 144 | textRectTXS.Height = (Gdiplus::REAL)(MeasureStringHeight(graphics, statisticsTXS, font, (int)textRectTXS.Width) + 3); 145 | 146 | auto bottom = textRectTXS.GetBottom(); 147 | auto textBKRect = clientRect; 148 | textBKRect.Height = bottom - textBKRect.GetTop(); 149 | 150 | graphics.DrawLine(&textBrPen, textBKRect.X, textBKRect.GetBottom(), textBKRect.GetRight(), textBKRect.GetBottom()); 151 | 152 | Gdiplus::SolidBrush textBrush(Gdiplus::Color::White); 153 | 154 | textBrush.SetColor(Gdiplus::Color::Black); 155 | textRectRXC.Offset(1.0f, 1.0f); 156 | graphics.DrawString(statisticsRXC.GetString(), statisticsRXC.GetLength(), &font, textRectRXC, &sf, &textBrush); 157 | textBrush.SetColor(Gdiplus::Color::White); 158 | textRectRXC.Offset(-1.0f, -1.0f); 159 | graphics.DrawString(statisticsRXC.GetString(), statisticsRXC.GetLength(), &font, textRectRXC, &sf, &textBrush); 160 | 161 | textBrush.SetColor(Gdiplus::Color::Black); 162 | textRectTXC.Offset(1.0f, 1.0f); 163 | graphics.DrawString(statisticsTXC.GetString(), statisticsTXC.GetLength(), &font, textRectTXC, &sf, &textBrush); 164 | textBrush.SetColor(Gdiplus::Color::White); 165 | textRectTXC.Offset(-1.0f, -1.0f); 166 | graphics.DrawString(statisticsTXC.GetString(), statisticsTXC.GetLength(), &font, textRectTXC, &sf, &textBrush); 167 | 168 | textBrush.SetColor(Gdiplus::Color::Black); 169 | textRectRXS.Offset(1.0f, 1.0f); 170 | graphics.DrawString(statisticsRXS.GetString(), statisticsRXS.GetLength(), &font, textRectRXS, &sf, &textBrush); 171 | textBrush.SetColor(Gdiplus::Color(204, 255, 153)); 172 | textRectRXS.Offset(-1.0f, -1.0f); 173 | graphics.DrawString(statisticsRXS.GetString(), statisticsRXS.GetLength(), &font, textRectRXS, &sf, &textBrush); 174 | 175 | textBrush.SetColor(Gdiplus::Color::Black); 176 | textRectTXS.Offset(1.0f, 1.0f); 177 | graphics.DrawString(statisticsTXS.GetString(), statisticsTXS.GetLength(), &font, textRectTXS, &sf, &textBrush); 178 | textBrush.SetColor(Gdiplus::Color(255, 102, 102)); 179 | textRectTXS.Offset(-1.0f, -1.0f); 180 | graphics.DrawString(statisticsTXS.GetString(), statisticsTXS.GetLength(), &font, textRectTXS, &sf, &textBrush); 181 | 182 | return (int)bottom; 183 | } 184 | 185 | void CRealTimeStatusCtrl::DrawSpeedCurve(Gdiplus::Graphics& graphics, const Gdiplus::RectF& clientRect) 186 | { 187 | Gdiplus::Pen linePen(Gdiplus::Color(204, 255, 153), 1); 188 | Gdiplus::SolidBrush shadowBrush(Gdiplus::Color(50, 0, 0, 0)); 189 | Gdiplus::SolidBrush textBrush(Gdiplus::Color(255, 255, 255)); 190 | 191 | Gdiplus::GraphicsPath path; 192 | std::vector points; 193 | int x = 0; 194 | int h = (int)(clientRect.Height); 195 | int b = (int)(clientRect.GetBottom()); 196 | uint64_t maxSpeed = (m_MaxReadSpeed > m_MaxWriteSpeed) ? m_MaxReadSpeed : m_MaxWriteSpeed; 197 | uint64_t maxValue = (maxSpeed + maxSpeed / 4); 198 | if (maxValue == 0) 199 | maxValue = 64; 200 | double fy=0; 201 | for (auto t : m_ReadSpeeds) 202 | { 203 | fy = (double)t; 204 | fy *= h; 205 | fy /= maxValue; 206 | auto y = b - static_cast(fy); 207 | points.push_back(Gdiplus::Point(x, y)); 208 | x += kXSTEP_LENGTH; 209 | } 210 | path.AddCurve(points.data(), (int)points.size()); 211 | points.clear(); 212 | points.push_back(Gdiplus::Point(x - kXSTEP_LENGTH, b)); 213 | points.push_back(Gdiplus::Point(0, b)); 214 | path.AddLines(points.data(), (int)points.size()); 215 | path.CloseFigure(); 216 | 217 | graphics.FillPath(&shadowBrush, &path); 218 | graphics.DrawPath(&linePen, &path); 219 | 220 | linePen.SetColor(Gdiplus::Color(255, 102, 102)); 221 | shadowBrush.SetColor(Gdiplus::Color(50, 0, 0, 0)); 222 | textBrush.SetColor(Gdiplus::Color(255, 255, 255)); 223 | 224 | path.Reset(); 225 | points.clear(); 226 | x = 0; 227 | fy=0; 228 | for (auto t : m_WriteSpeeds) 229 | { 230 | fy = (double)t; 231 | fy *= h; 232 | fy /= maxValue; 233 | auto y = b - static_cast(fy); 234 | points.push_back(Gdiplus::Point(x, y)); 235 | x += kXSTEP_LENGTH; 236 | } 237 | path.AddCurve(points.data(), (int)points.size()); 238 | points.clear(); 239 | points.push_back(Gdiplus::Point(x - kXSTEP_LENGTH, b)); 240 | points.push_back(Gdiplus::Point(0, b)); 241 | path.AddLines(points.data(), (int)points.size()); 242 | path.CloseFigure(); 243 | 244 | graphics.FillPath(&shadowBrush, &path); 245 | graphics.DrawPath(&linePen, &path); 246 | } 247 | 248 | void CRealTimeStatusCtrl::DrawDisconnectedStatus(Gdiplus::Graphics& graphics, const Gdiplus::RectF& clientRect) 249 | { 250 | CString str = L"未连接"; 251 | auto fontFamily = CreateUIFontFamily(); 252 | Gdiplus::Font font(fontFamily.get(), 22.0f, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel); 253 | Gdiplus::SolidBrush brush(Gdiplus::Color(255, 255, 255)); 254 | Gdiplus::StringFormat sf; 255 | sf.SetAlignment(Gdiplus::StringAlignment::StringAlignmentCenter); 256 | sf.SetLineAlignment(Gdiplus::StringAlignment::StringAlignmentCenter); 257 | sf.SetTrimming(Gdiplus::StringTrimming::StringTrimmingEllipsisWord); 258 | auto textRect = clientRect; 259 | graphics.DrawString(str.GetString(), str.GetLength(), &font, textRect, &sf, &brush); 260 | brush.SetColor(Gdiplus::Color(128, 128, 128)); 261 | textRect.Offset(-1.0f, -1.0f); 262 | graphics.DrawString(str.GetString(), str.GetLength(), &font, textRect, &sf, &brush); 263 | } 264 | 265 | void CRealTimeStatusCtrl::OnPaint() 266 | { 267 | CPaintDC pdc(this); 268 | CMemDC memDC(pdc, this); 269 | auto& dc = memDC.GetDC(); 270 | Gdiplus::Graphics graphics(dc); 271 | CRect rcClient; 272 | GetClientRect(&rcClient); 273 | Gdiplus::RectF gdiRect((Gdiplus::REAL)rcClient.left, (Gdiplus::REAL)rcClient.top, (Gdiplus::REAL)rcClient.Width(), (Gdiplus::REAL)rcClient.Height()); 274 | 275 | if (m_connected) 276 | { 277 | graphics.Clear(Gdiplus::Color(0, 102, 153)); 278 | } 279 | else 280 | { 281 | graphics.Clear(Gdiplus::Color(204, 204, 204)); 282 | } 283 | Gdiplus::Pen brPen(Gdiplus::Color(50, 0, 0, 0), 1); 284 | brPen.SetAlignment(Gdiplus::PenAlignment::PenAlignmentCenter); 285 | gdiRect.Width -= 1; 286 | gdiRect.Height -= 1; 287 | graphics.DrawRectangle(&brPen, gdiRect); 288 | 289 | auto y = DrawStatisicsString(graphics, gdiRect); 290 | gdiRect.Y = (Gdiplus::REAL)y; 291 | gdiRect.Height -= y; 292 | DrawSpeedCurve(graphics, gdiRect); 293 | if (!m_connected) 294 | DrawDisconnectedStatus(graphics, gdiRect); 295 | } 296 | 297 | static CString HumanReadableSize(uint64_t size) 298 | { 299 | static const LPCTSTR units[] = { L"B/s", L"KB/s", L"MB/s", L"GB/s", L"TB/s", L"PB/s" }; 300 | double mod = 1024.0; 301 | double fsize = (double)size; 302 | int i = 0; 303 | while (fsize >= mod) 304 | { 305 | fsize /= mod; 306 | i++; 307 | } 308 | CString result; 309 | result.Format(L"%.2lf %s", fsize, units[i]); 310 | return result; 311 | } 312 | 313 | CString CRealTimeStatusCtrl::GetReadSpeedString(void) const 314 | { 315 | if (m_ReadSpeeds.empty()) 316 | return HumanReadableSize(0); 317 | return HumanReadableSize(m_AveReadSpeed); 318 | } 319 | CString CRealTimeStatusCtrl::GetWriteSpeedString(void) const 320 | { 321 | if (m_WriteSpeeds.empty()) 322 | return HumanReadableSize(0); 323 | auto speed = m_WriteSpeeds.back(); 324 | return HumanReadableSize(m_AveWriteSpeed); 325 | } -------------------------------------------------------------------------------- /NetDebugger/CDPropertyGridCtrl.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "NetDebugger.h" 3 | #include "CDPropertyGridCtrl.h" 4 | #include "UserWMDefine.h" 5 | #include "GdiplusAux.hpp" 6 | 7 | static void splitTitle(const CString& pdTitle, CString& title, CString& desc) 8 | { 9 | if (!pdTitle.IsEmpty()) 10 | { 11 | auto idx = pdTitle.Find(L"\r\n"); 12 | if (idx >= 0) 13 | { 14 | title = pdTitle.Mid(0, idx); 15 | desc = pdTitle.Mid(idx + 2); 16 | } 17 | else 18 | { 19 | title = pdTitle; 20 | desc = title; 21 | } 22 | } 23 | } 24 | 25 | static CString GetOptionTitle(const IDevice::PropertyDescription::EnumOptions& options, const std::wstring& value) 26 | { 27 | for (auto opt : options) 28 | { 29 | if (opt.first == value) 30 | { 31 | return LSVT(opt.second.data()); 32 | } 33 | } 34 | return CString(value.data()); 35 | } 36 | 37 | static CString GetOptionValue(const IDevice::PropertyDescription::EnumOptions& options, const CString& title) 38 | { 39 | for (auto opt : options) 40 | { 41 | if (LSVT(opt.second.data()) == title) 42 | { 43 | return opt.first.data(); 44 | } 45 | } 46 | return title; 47 | } 48 | 49 | static bool HasFlag(IDevice::PropertyType type, IDevice::PropertyType flag) 50 | { 51 | return (((int)type) & ((int)flag)) == (int)flag; 52 | } 53 | 54 | void DeviceProperty::UpdatePropertyValue(void) 55 | { 56 | auto type = (IDevice::PropertyType)(((int)pd->Type()) & 0xFF); 57 | auto enumMode = HasFlag(pd->Type(), IDevice::PropertyType::Enum); 58 | auto& options = m_LastOptions; 59 | auto value = pd->GetValue(); 60 | if (options.empty()) 61 | { 62 | switch (type) 63 | { 64 | case IDevice::PropertyType::Int: 65 | { 66 | auto iv = std::wcstol(value.data(), nullptr, 10); 67 | SetValue(iv); 68 | } 69 | break; 70 | case IDevice::PropertyType::Real: 71 | { 72 | auto iv = std::wcstod(value.data(), nullptr); 73 | SetValue(iv); 74 | } 75 | break; 76 | case IDevice::PropertyType::String: 77 | { 78 | SetValue(CString(value.data())); 79 | } 80 | break; 81 | case IDevice::PropertyType::Boolean: 82 | { 83 | auto iv = std::wcstol(value.data(), nullptr, 10) != 0; 84 | auto bv = iv ? CString(L"True") : CString(L"False"); 85 | SetValue(bv); 86 | } 87 | break; 88 | } 89 | } 90 | else if(enumMode) 91 | { 92 | auto displayValue = GetOptionTitle(options, value); 93 | SetValue(displayValue); 94 | } 95 | int subCount = GetSubItemsCount(); 96 | for (int i = 0; i < subCount; ++i) 97 | { 98 | auto subProp = dynamic_cast(GetSubItem(i)); 99 | subProp->UpdatePropertyValue(); 100 | } 101 | } 102 | 103 | void DeviceProperty::UpdatePropertyTitle(void) 104 | { 105 | CString title; 106 | CString desc; 107 | splitTitle(LSVT(pd->Title().c_str()), title, desc); 108 | SetName(title, FALSE); 109 | SetDescription(desc); 110 | 111 | if (GetOptionCount()>0) 112 | { 113 | if (HasFlag(pd->Type(), IDevice::PropertyType::Enum)) 114 | { 115 | if (m_LastOptions.empty()) 116 | m_LastOptions = pd->Options(); 117 | auto value = pd->GetValue(); 118 | SetValue(GetOptionTitle(m_LastOptions, value)); 119 | } 120 | } 121 | int subCount = GetSubItemsCount(); 122 | for (int i = 0; i < subCount; ++i) 123 | { 124 | auto subProp = dynamic_cast(GetSubItem(i)); 125 | subProp->UpdatePropertyTitle(); 126 | } 127 | } 128 | 129 | void DeviceProperty::OnDrawValue(CDC* pDC, CRect rect) 130 | { 131 | Gdiplus::Graphics graphics(*pDC); 132 | Gdiplus::RectF rcItem((Gdiplus::REAL)rect.left, (Gdiplus::REAL)rect.top, (Gdiplus::REAL)rect.Width(), (Gdiplus::REAL)rect.Height()); 133 | graphics.SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeAntiAlias); 134 | graphics.SetTextRenderingHint(Gdiplus::TextRenderingHint::TextRenderingHintClearTypeGridFit); 135 | Gdiplus::StringFormat sf; 136 | sf.SetAlignment(Gdiplus::StringAlignment::StringAlignmentNear); 137 | sf.SetLineAlignment(Gdiplus::StringAlignment::StringAlignmentCenter); 138 | sf.SetTrimming(Gdiplus::StringTrimming::StringTrimmingEllipsisWord); 139 | Gdiplus::SolidBrush textBrush(Gdiplus::Color::Black); 140 | 141 | auto fontFamily = CreateUIFontFamily(); 142 | CString value(m_varValue); 143 | if ((!IsEnabled()) || HasFlag(pd->Type(), IDevice::PropertyType::Group)) 144 | { 145 | Gdiplus::SolidBrush itemBKBrush(Gdiplus::Color(235, 235, 235)); 146 | graphics.FillRectangle(&itemBKBrush, rcItem); 147 | Gdiplus::Font fontLabel(fontFamily.get(), 14.0f, Gdiplus::FontStyleItalic, Gdiplus::UnitPixel); 148 | textBrush.SetColor(Gdiplus::Color(120, 120, 120)); 149 | graphics.DrawString(value, value.GetLength(), &fontLabel, rcItem, &sf, &textBrush); 150 | } 151 | else 152 | { 153 | Gdiplus::SolidBrush itemBKBrush(Gdiplus::Color::White); 154 | graphics.FillRectangle(&itemBKBrush, rcItem); 155 | Gdiplus::Font fontLabel(fontFamily.get(), 14.0f, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel); 156 | graphics.DrawString(value, value.GetLength(), &fontLabel, rcItem, &sf, &textBrush); 157 | } 158 | } 159 | 160 | void DeviceProperty::OnDrawName(CDC* pDC, CRect rect) 161 | { 162 | Gdiplus::Graphics graphics(*pDC); 163 | Gdiplus::RectF rcItem((Gdiplus::REAL)rect.left, (Gdiplus::REAL)rect.top, (Gdiplus::REAL)rect.Width(), (Gdiplus::REAL)rect.Height()); 164 | graphics.SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeAntiAlias); 165 | graphics.SetTextRenderingHint(Gdiplus::TextRenderingHint::TextRenderingHintClearTypeGridFit); 166 | Gdiplus::StringFormat sf; 167 | sf.SetAlignment(Gdiplus::StringAlignment::StringAlignmentNear); 168 | sf.SetLineAlignment(Gdiplus::StringAlignment::StringAlignmentCenter); 169 | sf.SetTrimming(Gdiplus::StringTrimming::StringTrimmingEllipsisWord); 170 | Gdiplus::SolidBrush textBrush(Gdiplus::Color::Black); 171 | 172 | auto fontFamily = CreateUIFontFamily(); 173 | Gdiplus::Font fontLabel(fontFamily.get(), 14.0f, Gdiplus::FontStyleBold, Gdiplus::UnitPixel); 174 | if (!IsSelected()) 175 | { 176 | if ((!IsEnabled()) || HasFlag(pd->Type(), IDevice::PropertyType::Group)) 177 | { 178 | Gdiplus::SolidBrush itemBKBrush(Gdiplus::Color(235, 235, 235)); 179 | graphics.FillRectangle(&itemBKBrush, rcItem); 180 | textBrush.SetColor(Gdiplus::Color(120, 120, 120)); 181 | graphics.DrawString(m_strName, m_strName.GetLength(), &fontLabel, rcItem, &sf, &textBrush); 182 | } 183 | else 184 | { 185 | Gdiplus::SolidBrush itemBKBrush(Gdiplus::Color::White); 186 | graphics.FillRectangle(&itemBKBrush, rcItem); 187 | graphics.DrawString(m_strName, m_strName.GetLength(), &fontLabel, rcItem, &sf, &textBrush); 188 | } 189 | } 190 | else 191 | { 192 | Gdiplus::SolidBrush itemBKBrush(Gdiplus::Color(0, 122, 204)); 193 | graphics.FillRectangle(&itemBKBrush, rcItem); 194 | textBrush.SetColor(Gdiplus::Color::White); 195 | graphics.DrawString(m_strName, m_strName.GetLength(), &fontLabel, rcItem, &sf, &textBrush); 196 | } 197 | } 198 | 199 | void DeviceProperty::OnDrawDescription(CDC* pDC, CRect rect) 200 | { 201 | Gdiplus::Graphics graphics(*pDC); 202 | Gdiplus::RectF rcDescription((Gdiplus::REAL)rect.left, (Gdiplus::REAL)rect.top, (Gdiplus::REAL)rect.Width(), (Gdiplus::REAL)rect.Height()); 203 | Gdiplus::StringFormat sf; 204 | graphics.SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeAntiAlias); 205 | graphics.SetTextRenderingHint(Gdiplus::TextRenderingHint::TextRenderingHintClearTypeGridFit); 206 | 207 | sf.SetAlignment(Gdiplus::StringAlignment::StringAlignmentNear); 208 | sf.SetLineAlignment(Gdiplus::StringAlignment::StringAlignmentNear); 209 | sf.SetTrimming(Gdiplus::StringTrimming::StringTrimmingEllipsisWord); 210 | Gdiplus::SolidBrush textBrush(Gdiplus::Color::Black); 211 | 212 | auto fontFamily = CreateUIFontFamily(); 213 | Gdiplus::Font font(fontFamily.get(), 14.0f, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel); 214 | graphics.DrawString(m_strDescr, m_strDescr.GetLength(), &font, rcDescription, &sf, &textBrush); 215 | } 216 | 217 | void DeviceProperty::OnClickButton(CPoint point) 218 | { 219 | if (m_pWndCombo != nullptr) 220 | { 221 | m_LastOptions = pd->Options(); 222 | m_pWndCombo->ResetContent(); 223 | for (auto opt : m_LastOptions) 224 | { 225 | m_pWndCombo->AddString(LSVT(opt.second.data())); 226 | } 227 | SetDroppedAutoWidth(); 228 | } 229 | CMFCPropertyGridProperty::OnClickButton(point); 230 | } 231 | 232 | BOOL DeviceProperty::OnSetCursor() const 233 | { 234 | return !IsEnabled(); 235 | } 236 | 237 | void DeviceProperty::OnSelectCombo() 238 | { 239 | auto item = this->m_pWndCombo->GetCurSel(); 240 | if (item >= 0) 241 | { 242 | CString title; 243 | m_pWndCombo->GetLBText(item, title); 244 | if (!HasFlag(pd->Type(), IDevice::PropertyType::Enum)) 245 | { 246 | title = GetOptionValue(m_LastOptions, title); 247 | } 248 | SetValue(title); 249 | m_pWndList->OnPropertyChanged(this); 250 | return; 251 | } 252 | } 253 | 254 | CString DeviceProperty::GetValueTooltip() 255 | { 256 | return CString(GetValue()); 257 | } 258 | 259 | void DeviceProperty::SetDroppedAutoWidth() 260 | { 261 | if (m_pWndCombo == nullptr) 262 | return; 263 | CString str; 264 | CSize sz; 265 | int dx = 0; 266 | CDC* pDC = m_pWndCombo->GetDC(); 267 | auto count = m_pWndCombo->GetCount(); 268 | auto edge = GetSystemMetrics(SM_CXEDGE) * 2 + GetSystemMetrics(SM_CXVSCROLL) * 2; 269 | for (int i = 0; i < count; i++) 270 | { 271 | m_pWndCombo->GetLBText(i, str); 272 | sz = pDC->GetTextExtent(str); 273 | if (m_pWndCombo->GetDroppedWidth() < (sz.cx + edge)) 274 | { 275 | m_pWndCombo->SetDroppedWidth(sz.cx + edge); 276 | } 277 | } 278 | m_pWndCombo->ReleaseDC(pDC); 279 | } 280 | 281 | 282 | static DeviceProperty* NewProperty(CPropertyTableCtrl::PropertyDescription pd) 283 | { 284 | auto type = (IDevice::PropertyType)(((int)pd->Type()) & 0xFF); 285 | auto enumMode = HasFlag(pd->Type(), IDevice::PropertyType::Enum); 286 | auto isGroup = HasFlag(pd->Type(), IDevice::PropertyType::Group); 287 | auto options = pd->Options(); 288 | auto defaultVal = pd->DefaultValue(); 289 | CString title; 290 | CString desc; 291 | splitTitle(LSVT(pd->Title().c_str()), title, desc); 292 | DeviceProperty* prop = nullptr; 293 | if (isGroup) 294 | { 295 | prop = new DeviceProperty(title); 296 | prop->pd = pd; 297 | for (auto cpd : pd->Childs()) 298 | { 299 | prop->AddSubItem(NewProperty(cpd)); 300 | } 301 | } 302 | else 303 | { 304 | auto value = pd->GetValue(); 305 | if (options.empty()) 306 | { 307 | switch (type) 308 | { 309 | case IDevice::PropertyType::Int: 310 | { 311 | auto iv = std::wcstol(value.data(), nullptr, 10); 312 | auto dv = std::wcstol(defaultVal.data(), nullptr, 10); 313 | prop = new DeviceProperty(title, iv, desc, 0, nullptr, nullptr, L"-1234567890"); 314 | auto smin = pd->MinValue(); 315 | auto smax = pd->MaxValue(); 316 | if ((!smin.empty()) && (!smax.empty()) && (options.empty())) 317 | { 318 | auto mi = std::wcstoll(smin.c_str(), nullptr, 10); 319 | auto mx = std::wcstoll(smax.c_str(), nullptr, 10); 320 | prop->EnableSpinControl(TRUE, (int)mi, (int)mx); 321 | } 322 | } 323 | break; 324 | case IDevice::PropertyType::Real: 325 | { 326 | auto iv = std::wcstod(value.data(), nullptr); 327 | auto dv = std::wcstod(defaultVal.data(), nullptr); 328 | prop = new DeviceProperty(title, iv, desc, 0, nullptr, nullptr, L"-1234567890."); 329 | } 330 | break; 331 | case IDevice::PropertyType::String: 332 | { 333 | prop = new DeviceProperty(title, CString(value.data()), desc); 334 | } 335 | break; 336 | } 337 | } 338 | else 339 | { 340 | std::wstring displayValue; 341 | if (enumMode) 342 | displayValue = GetOptionTitle(options, value); 343 | else 344 | displayValue = value; 345 | 346 | prop = new DeviceProperty(title, CString(displayValue.data()), desc); 347 | prop->RemoveAllOptions(); 348 | if (enumMode) 349 | prop->AllowEdit(FALSE); 350 | prop->AddOption(L" "); 351 | } 352 | 353 | if (prop != nullptr) 354 | { 355 | if (pd->ChangeFlags() == IDevice::PropertyChangeFlags::Readonly) 356 | { 357 | prop->Enable(FALSE); 358 | } 359 | prop->pd = pd; 360 | } 361 | } 362 | return prop; 363 | } 364 | 365 | static void UpdatePropertyStatus(DeviceProperty* prop, bool started) 366 | { 367 | auto subCount = prop->GetSubItemsCount(); 368 | for (int i = 0; i < subCount; ++i) 369 | { 370 | auto subprop = dynamic_cast(prop->GetSubItem(i)); 371 | UpdatePropertyStatus(subprop, started); 372 | } 373 | 374 | auto pd = prop->pd; 375 | auto flags = pd->ChangeFlags(); 376 | if (flags == IDevice::PropertyChangeFlags::CanChangeAlways 377 | || flags == IDevice::PropertyChangeFlags::Readonly) 378 | return; 379 | 380 | if (started) 381 | { 382 | if (flags == IDevice::PropertyChangeFlags::CanChangeAfterStart) 383 | prop->Enable(TRUE); 384 | else if (flags == IDevice::PropertyChangeFlags::CanChangeBeforeStart) 385 | prop->Enable(FALSE); 386 | } 387 | else 388 | { 389 | if (flags == IDevice::PropertyChangeFlags::CanChangeAfterStart) 390 | prop->Enable(FALSE); 391 | else if (flags == IDevice::PropertyChangeFlags::CanChangeBeforeStart) 392 | prop->Enable(TRUE); 393 | } 394 | } 395 | void CPropertyTableCtrl::UpdateDeviceStatus(bool started) 396 | { 397 | for (int i = 0; i < GetPropertyCount(); ++i) 398 | { 399 | auto prop = dynamic_cast(GetProperty(i)); 400 | UpdatePropertyStatus(prop, started); 401 | } 402 | } 403 | 404 | void CPropertyTableCtrl::Clear() 405 | { 406 | this->RemoveAll(); 407 | } 408 | 409 | void CPropertyTableCtrl::UpdateProperties() 410 | { 411 | DeviceProperty* prop = nullptr; 412 | for (int i = 0; i < GetPropertyCount(); ++i) 413 | { 414 | auto prop = dynamic_cast(GetProperty(i)); 415 | prop->UpdatePropertyValue(); 416 | } 417 | } 418 | 419 | void CPropertyTableCtrl::UpdatePropertiesTitle() 420 | { 421 | DeviceProperty* prop = nullptr; 422 | for (int i = 0; i < GetPropertyCount(); ++i) 423 | { 424 | auto prop = dynamic_cast(GetProperty(i)); 425 | prop->UpdatePropertyTitle(); 426 | } 427 | } 428 | 429 | void CPropertyTableCtrl::AddProperty(PropertyDescription pd) 430 | { 431 | auto prop = NewProperty(pd); 432 | CMFCPropertyGridCtrl::AddProperty(prop); 433 | } 434 | 435 | void CPropertyTableCtrl::OnPropertyChanged(CMFCPropertyGridProperty* pProp) const 436 | { 437 | auto prop = dynamic_cast(pProp); 438 | auto pd = prop->pd; 439 | CString title(prop->GetValue()); 440 | auto enumMode = HasFlag(pd->Type(), IDevice::PropertyType::Enum); 441 | std::wstring value; 442 | if (enumMode) 443 | { 444 | value = GetOptionValue(prop->m_LastOptions, title); 445 | } 446 | else 447 | { 448 | value = title.GetString(); 449 | } 450 | ::SendMessage(::GetParent(GetSafeHwnd()), kWM_CDEVICE_PROPERTY_CHANGED, (WPARAM)(prop), (LPARAM)(value.data())); 451 | } 452 | 453 | void CPropertyTableCtrl::OnDrawBorder(CDC* pDC) 454 | { 455 | Gdiplus::Graphics graphics(*pDC); 456 | CRect rect; 457 | GetClientRect(&rect); 458 | Gdiplus::RectF rcItem((Gdiplus::REAL)rect.left, (Gdiplus::REAL)rect.top, (Gdiplus::REAL)rect.Width(), (Gdiplus::REAL)rect.Height()); 459 | graphics.SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeAntiAlias); 460 | graphics.SetTextRenderingHint(Gdiplus::TextRenderingHint::TextRenderingHintClearTypeGridFit); 461 | 462 | Gdiplus::Pen pen(Gdiplus::Color(60, 0, 0, 0), 1); 463 | 464 | rcItem.Width -= 1; 465 | rcItem.Height -= 1; 466 | graphics.DrawRectangle(&pen, rcItem); 467 | } -------------------------------------------------------------------------------- /NetDebugger/TCPClient.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "TCPClient.h" 3 | #include "NetDebugger.h" 4 | #include "OEMStringHelper.hpp" 5 | 6 | #include 7 | 8 | static std::wstring ProtocolToWstring(const boost::asio::ip::tcp::endpoint::protocol_type& protocol) 9 | { 10 | std::wstring result = L"TCP/IP"; 11 | if (protocol.family() == AF_INET) 12 | result += L"V4"; 13 | if (protocol.family() == AF_INET6) 14 | result += L"V6"; 15 | return result; 16 | } 17 | 18 | TCPClientChannel::TCPClientChannel(void): 19 | m_Socket(theApp.GetIOContext()), 20 | m_Opened(false) 21 | { 22 | 23 | } 24 | 25 | TCPClientChannel::~TCPClientChannel(void) 26 | { 27 | CloseSocket(); 28 | } 29 | 30 | void TCPClientChannel::Connect(const std::wstring& host, int port, bool keepAlive, std::function handler) 31 | { 32 | bool state = false; 33 | if (m_Opened.compare_exchange_weak(state, true)) 34 | { 35 | auto channel = shared_from_this(); 36 | boost::system::error_code ec; 37 | auto rslv = std::make_shared(theApp.GetIOContext()); 38 | boost::asio::ip::tcp::resolver::query qry(WStringToString(host), std::to_string(port)); 39 | rslv->async_resolve(qry, [rslv, channel, keepAlive, handler](const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator iter) 40 | { 41 | if (ec) 42 | { 43 | handler(ec); 44 | } 45 | else 46 | { 47 | boost::asio::async_connect( 48 | channel->m_Socket, 49 | iter, 50 | [rslv, channel, keepAlive, handler](const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator iter) 51 | { 52 | if (ec) 53 | { 54 | channel->CloseSocket(); 55 | } 56 | else 57 | { 58 | boost::system::error_code ecSet; 59 | channel->m_Socket.set_option(boost::asio::socket_base::keep_alive(keepAlive), ecSet); 60 | } 61 | handler(ec); 62 | }); 63 | } 64 | }); 65 | } 66 | } 67 | 68 | bool TCPClientChannel::CloseSocket(void) 69 | { 70 | bool state = true; 71 | if (m_Opened.compare_exchange_weak(state, false)) 72 | { 73 | boost::system::error_code ec; 74 | m_Socket.cancel(ec); 75 | m_Socket.shutdown(m_Socket.shutdown_both, ec); 76 | m_Socket.close(ec); 77 | return true; 78 | } 79 | return false; 80 | } 81 | 82 | void TCPClientChannel::CloseSocket(const boost::system::error_code& ecClose) 83 | { 84 | if (CloseSocket()) 85 | { 86 | auto dev = m_Device.lock(); 87 | if (dev != nullptr) 88 | { 89 | dev->NotifyChannelClose(shared_from_this(), ecClose); 90 | } 91 | } 92 | } 93 | 94 | std::wstring TCPClientChannel::Id(void) const 95 | { 96 | if (sizeof(size_t) == sizeof(void*)) 97 | return std::to_wstring(reinterpret_cast(this)); 98 | else 99 | return std::to_wstring(reinterpret_cast(this)); 100 | } 101 | 102 | std::wstring TCPClientChannel::Description(void) const 103 | { 104 | std::wstring result; 105 | boost::system::error_code ec; 106 | auto local = m_Socket.local_endpoint(ec); 107 | if (ec) 108 | { 109 | result = L"none" + result; 110 | } 111 | else 112 | { 113 | result += L"local("; 114 | result += StringToWString(local.address().to_string()) + L":" + std::to_wstring(local.port()); 115 | result += L")"; 116 | } 117 | 118 | auto remote = m_Socket.remote_endpoint(ec); 119 | if (ec) 120 | { 121 | result += L" <---> none"; 122 | } 123 | else 124 | { 125 | result += L" <---> remote("; 126 | result += StringToWString(remote.address().to_string()) + L":" + std::to_wstring(remote.port()); 127 | result += L")"; 128 | } 129 | return result; 130 | } 131 | 132 | std::wstring TCPClientChannel::LocalEndPoint(void) const 133 | { 134 | std::wstring result; 135 | boost::system::error_code ec; 136 | auto local = m_Socket.local_endpoint(ec); 137 | if (ec) 138 | { 139 | result = L"none"; 140 | } 141 | else 142 | { 143 | result = StringToWString(local.address().to_string()) + L"#" + std::to_wstring(local.port()); 144 | } 145 | return result; 146 | } 147 | 148 | std::wstring TCPClientChannel::RemoteEndPoint(void) const 149 | { 150 | std::wstring result; 151 | boost::system::error_code ec; 152 | auto local = m_Socket.remote_endpoint(ec); 153 | if (ec) 154 | { 155 | result = L"none"; 156 | } 157 | else 158 | { 159 | result = StringToWString(local.address().to_string()) + L"#" + std::to_wstring(local.port()); 160 | } 161 | return result; 162 | } 163 | 164 | void TCPClientChannel::Read(OutputBuffer buffer, IoCompletionHandler handler) 165 | { 166 | auto client = shared_from_this(); 167 | boost::asio::async_read( 168 | m_Socket, 169 | boost::asio::buffer(buffer->data(), buffer->size()), 170 | [client, handler](const boost::system::error_code& ec, size_t bytestransfer) 171 | { 172 | if (handler != nullptr) 173 | handler(!ec, bytestransfer); 174 | if (ec) 175 | { 176 | if (ec != boost::system::errc::operation_canceled) 177 | client->CloseSocket(ec); 178 | } 179 | } 180 | ); 181 | } 182 | void TCPClientChannel::Write(InputBuffer buffer, IoCompletionHandler handler) 183 | { 184 | auto client = shared_from_this(); 185 | boost::asio::async_write( 186 | m_Socket, 187 | boost::asio::const_buffer(buffer.buffer, buffer.bufferSize), 188 | [client, handler, this](const boost::system::error_code& ec, size_t bytestransfer) 189 | { 190 | if (handler != nullptr) 191 | handler(!ec, bytestransfer); 192 | if (ec) 193 | { 194 | if (ec != boost::system::errc::operation_canceled) 195 | client->CloseSocket(ec); 196 | } 197 | }); 198 | } 199 | void TCPClientChannel::ReadSome(OutputBuffer buffer, IoCompletionHandler handler) 200 | { 201 | auto client = shared_from_this(); 202 | m_Socket.async_read_some( 203 | boost::asio::buffer(buffer->data(), buffer->size()), 204 | [client, handler](const boost::system::error_code& ec, size_t bytestransfer) 205 | { 206 | handler(!ec, bytestransfer); 207 | if (ec) 208 | { 209 | if (ec != boost::system::errc::operation_canceled) 210 | client->CloseSocket(ec); 211 | } 212 | } 213 | ); 214 | } 215 | void TCPClientChannel::WriteSome(InputBuffer buffer, IoCompletionHandler handler) 216 | { 217 | auto client = shared_from_this(); 218 | m_Socket.async_write_some( 219 | boost::asio::const_buffer(buffer.buffer, buffer.bufferSize), 220 | [client, handler](const boost::system::error_code& ec, size_t bytestransfer) 221 | { 222 | handler(!ec, bytestransfer); 223 | if (ec) 224 | { 225 | if (ec != boost::system::errc::operation_canceled) 226 | client->CloseSocket(ec); 227 | } 228 | }); 229 | } 230 | 231 | void TCPClientChannel::Cancel(void) 232 | { 233 | boost::system::error_code ec; 234 | m_Socket.cancel(ec); 235 | } 236 | 237 | void TCPClientChannel::Close(void) 238 | { 239 | CloseSocket(boost::system::errc::make_error_code(boost::system::errc::connection_aborted)); 240 | } 241 | 242 | std::wstring TCPClientChannel::GetProtocol() 243 | { 244 | boost::system::error_code ec; 245 | auto local = m_Socket.local_endpoint(ec); 246 | if (ec) 247 | return StringToWString(ec.message()); 248 | else 249 | return ProtocolToWstring(local.protocol()); 250 | } 251 | 252 | 253 | 254 | TCPClient::TCPClient(void): 255 | m_ServerURL(L"127.0.0.1"), 256 | m_RemotePort(0), 257 | m_Keepalive(false) 258 | { 259 | 260 | } 261 | 262 | TCPClient::~TCPClient(void) 263 | { 264 | } 265 | 266 | bool TCPClient::IsServer(void) 267 | { 268 | return false; 269 | } 270 | 271 | IDevice::PDTable TCPClient::EnumProperties() 272 | { 273 | using StaticProperty = PropertyDescriptionHelper::StaticPropertyDescription; 274 | PDTable results; 275 | auto self = GetSharedPtr(); 276 | auto pd = std::make_shared( 277 | L"Host", 278 | L"DEVICE.TCPCLIENT.PROP.HOST", 279 | L"127.0.0.1", 280 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 281 | ); 282 | pd->BindMethod( 283 | [self]() { return self->m_ServerURL; }, 284 | [self](const std::wstring& value) { self->m_ServerURL = value; } 285 | ); 286 | results.push_back(pd); 287 | 288 | pd = std::make_shared( 289 | L"RemotePort", 290 | L"DEVICE.TCPCLIENT.PROP.REMOTEPORT", 291 | uint16_t(0), 292 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 293 | ); 294 | pd->BindMethod( 295 | [self]() { return std::to_wstring(self->m_RemotePort); }, 296 | [self](const std::wstring& value) { self->m_RemotePort = static_cast(std::wcstoul(value.c_str(), nullptr, 10)); } 297 | ); 298 | results.push_back(pd); 299 | 300 | pd = std::make_shared( 301 | L"Keepalive", 302 | L"DEVICE.TCPCLIENT.PROP.KEEPALIVE", 303 | bool(false), 304 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 305 | ); 306 | pd->BindMethod( 307 | [self]() { return std::to_wstring(self->m_Keepalive ? 1 : 0); }, 308 | [self](const std::wstring& value) { self->m_Keepalive = value == L"1"; }); 309 | results.push_back(pd); 310 | 311 | pd = std::make_shared( 312 | L"Protocol", 313 | L"DEVICE.TCPCLIENT.PROP.PROTOCOL", 314 | L"", 315 | IDevice::PropertyChangeFlags::Readonly 316 | ); 317 | pd->BindMethod( 318 | [self]() { return self->GetProtocol(); }, 319 | nullptr 320 | ); 321 | results.push_back(pd); 322 | return results; 323 | } 324 | 325 | 326 | 327 | 328 | 329 | TCPSingleClient::TCPSingleClient(void): 330 | m_Channel(std::make_shared()) 331 | { 332 | 333 | } 334 | 335 | TCPSingleClient::~TCPSingleClient(void) 336 | { 337 | m_Channel.reset(); 338 | } 339 | 340 | 341 | void TCPSingleClient::Start(void) 342 | { 343 | if (Started()) 344 | return; 345 | 346 | StatusChanged(DeviceStatus::Connecting, std::wstring()); 347 | auto client = shared_from_this(); 348 | m_Channel->Connect(m_ServerURL, m_RemotePort, m_Keepalive, [client](const boost::system::error_code& ec) 349 | { 350 | if (ec) 351 | { 352 | client->StatusChanged(DeviceStatus::Disconnected, StringToWString(ec.message())); 353 | client->PropertyChanged(); 354 | client->ChannelConnected(client->m_Channel, StringToWString(ec.message())); 355 | } 356 | else 357 | { 358 | client->StatusChanged(DeviceStatus::Connected, StringToWString(ec.message())); 359 | client->PropertyChanged(); 360 | client->ChannelConnected(client->m_Channel, StringToWString(ec.message())); 361 | client->m_Channel->SetOwner(client); 362 | } 363 | }); 364 | } 365 | 366 | void TCPSingleClient::Stop(void) 367 | { 368 | if (m_Channel->CloseSocket()) 369 | { 370 | ChannelDisconnected(m_Channel, std::wstring()); 371 | PropertyChanged(); 372 | StatusChanged(DeviceStatus::Disconnected, std::wstring()); 373 | } 374 | } 375 | 376 | std::wstring TCPSingleClient::GetProtocol() 377 | { 378 | return m_Channel->GetProtocol(); 379 | } 380 | 381 | void TCPSingleClient::NotifyChannelClose(std::shared_ptr channel, const boost::system::error_code& ecClose) 382 | { 383 | ChannelDisconnected(m_Channel, std::wstring()); 384 | PropertyChanged(); 385 | StatusChanged(DeviceStatus::Disconnected, std::wstring()); 386 | } 387 | 388 | 389 | 390 | TCPMultipleClient::TCPMultipleClient(void): 391 | m_Channels(), 392 | m_ConnectConuter(0), 393 | m_FailedConuter(0) 394 | { 395 | 396 | } 397 | 398 | TCPMultipleClient::~TCPMultipleClient(void) 399 | { 400 | 401 | } 402 | 403 | IDevice::PDTable TCPMultipleClient::EnumProperties() 404 | { 405 | using StaticProperty = PropertyDescriptionHelper::StaticPropertyDescription; 406 | auto properties = TCPClient::EnumProperties(); 407 | auto self = shared_from_this(); 408 | auto pd = std::make_shared( 409 | L"CanonsCount", 410 | L"DEVICE.TCPMULTIPLECLIENT.PROP.CANONSCOUNT", 411 | uint16_t(10), 412 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 413 | ); 414 | pd->BindMethod( 415 | [self]() { return std::to_wstring(self->m_Channels.size()); }, 416 | [self](const std::wstring& value) { self->UpdateCanonsCount(static_cast(std::wcstoul(value.c_str(), nullptr, 10))); } 417 | ); 418 | properties.push_back(pd); 419 | pd = std::make_shared( 420 | L"ConnectedConuter", 421 | L"DEVICE.TCPMULTIPLECLIENT.PROP.CONNCOUNT", 422 | uint16_t(0), 423 | IDevice::PropertyChangeFlags::Readonly 424 | ); 425 | pd->BindMethod( 426 | [self]() { return std::to_wstring(self->m_ConnectConuter.load() - self->m_FailedConuter.load()); }, 427 | nullptr 428 | ); 429 | properties.push_back(pd); 430 | return properties; 431 | } 432 | 433 | void TCPMultipleClient::Start(void) 434 | { 435 | if (Started()) 436 | return; 437 | 438 | StatusChanged(DeviceStatus::Connecting, std::wstring()); 439 | auto client = shared_from_this(); 440 | m_ConnectConuter = 0; 441 | m_FailedConuter = 0; 442 | theApp.GetIOContext().post([client]() 443 | { 444 | for (size_t i = 0; i < client->m_Channels.size(); ++i) 445 | { 446 | auto& channel = client->m_Channels.at(i); 447 | if (channel == nullptr) 448 | channel = std::make_shared(); 449 | ConnectChannel(client, channel); 450 | } 451 | }); 452 | } 453 | 454 | void TCPMultipleClient::ConnectChannel(std::shared_ptr client, std::shared_ptr channel) 455 | { 456 | channel->Connect(client->m_ServerURL, client->m_RemotePort, client->m_Keepalive, [client, channel](const boost::system::error_code& ec) 457 | { 458 | auto count = client->m_Channels.size(); 459 | auto complete = (++client->m_ConnectConuter >= count); 460 | 461 | 462 | if (ec) 463 | { 464 | ++client->m_FailedConuter; 465 | } 466 | else 467 | { 468 | channel->SetOwner(client); 469 | client->ChannelConnected(channel, StringToWString(ec.message())); 470 | } 471 | if (complete) 472 | { 473 | if (client->m_FailedConuter == count) 474 | { 475 | client->PropertyChanged(); 476 | client->StatusChanged(DeviceStatus::Disconnected, StringToWString(ec.message())); 477 | } 478 | else 479 | { 480 | client->StatusChanged(DeviceStatus::Connected, std::wstring(L"")); 481 | client->PropertyChanged(); 482 | } 483 | } 484 | }); 485 | } 486 | 487 | void TCPMultipleClient::Stop(void) 488 | { 489 | if (!Started()) 490 | return; 491 | StatusChanged(DeviceStatus::Disconnecting, std::wstring()); 492 | auto client = shared_from_this(); 493 | theApp.GetIOContext().post([client]() 494 | { 495 | for (size_t i = 0; i < client->m_Channels.size(); ++i) 496 | { 497 | auto& channel = client->m_Channels.at(i); 498 | if (channel != nullptr) 499 | { 500 | channel->CloseSocket(); 501 | client->ChannelDisconnected(channel, std::wstring()); 502 | channel = nullptr; 503 | } 504 | } 505 | client->m_ConnectConuter = 0; 506 | client->m_FailedConuter = 0; 507 | client->PropertyChanged(); 508 | client->StatusChanged(DeviceStatus::Disconnected, std::wstring()); 509 | }); 510 | } 511 | 512 | void TCPMultipleClient::NotifyChannelClose(std::shared_ptr channel, const boost::system::error_code& ecClose) 513 | { 514 | ChannelDisconnected(channel, StringToWString(ecClose.message())); 515 | } 516 | 517 | std::wstring TCPMultipleClient::GetProtocol() 518 | { 519 | if (m_Channels.empty()) 520 | return L""; 521 | auto ch = m_Channels[0]; 522 | if (ch != nullptr) 523 | return ch->GetProtocol(); 524 | return L""; 525 | } 526 | 527 | void TCPMultipleClient::UpdateCanonsCount(size_t newCount) 528 | { 529 | if (newCount >= 0xFFFF) 530 | newCount = 0xFFFF; 531 | m_Channels.resize(newCount); 532 | } 533 | 534 | 535 | REGISTER_CLASS_TITLE(TCPSingleClient, L"DEVICE.CLASS.TCPCLIENT.TITLE"); 536 | REGISTER_CLASS_TITLE(TCPMultipleClient, L"DEVICE.CLASS.TCPMULTIPLECLIENT.TITLE"); -------------------------------------------------------------------------------- /NetDebugger/TCPSwitch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "NetDebugger.h" 3 | #include "TCPSwitch.h" 4 | #include "OEMStringHelper.hpp" 5 | 6 | static std::wstring ProtocolToWstring(const boost::asio::ip::tcp::endpoint::protocol_type& protocol) 7 | { 8 | std::wstring result = L"TCP/IP"; 9 | if (protocol.family() == AF_INET) 10 | result += L"V4"; 11 | if (protocol.family() == AF_INET6) 12 | result += L"V6"; 13 | return result; 14 | } 15 | 16 | TCPForwardServer::TCPForwardServer() : 17 | m_ListenAddress(L"127.0.0.1"), 18 | m_ListenPort(0), 19 | m_RemoteHost(L"127.0.0.1"), 20 | m_RemotePort(0), 21 | m_ReuseAddress(false), 22 | m_Keepalive(false), 23 | m_Acceptor(theApp.GetIOContext()) 24 | { 25 | 26 | } 27 | 28 | TCPForwardServer::~TCPForwardServer() 29 | { 30 | 31 | } 32 | 33 | 34 | bool TCPForwardServer::IsServer(void) 35 | { 36 | return true; 37 | } 38 | 39 | bool TCPForwardServer::IsSingleChannel(void) 40 | { 41 | return false; 42 | } 43 | 44 | IDevice::PDTable TCPForwardServer::EnumProperties() 45 | { 46 | using StaticProperty = PropertyDescriptionHelper::StaticPropertyDescription; 47 | using PropertyGroup = PropertyDescriptionHelper::PropertyGroupDescription; 48 | PDTable results; 49 | auto self = shared_from_this(); 50 | auto localGroup = std::make_shared(L"Local", L"DEVICE.TCPFORWARDSERVER.PROP.LOCAL"); 51 | auto remoteGroup = std::make_shared(L"Remote", L"DEVICE.TCPFORWARDSERVER.PROP.REMOTE"); 52 | auto pd = std::make_shared( 53 | L"ListenAddress", 54 | L"DEVICE.TCPFORWARDSERVER.PROP.LISTENADDRESS", 55 | L"127.0.0.1", 56 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 57 | ); 58 | pd->AddEnumOptions(L"0.0.0.0", L"0.0.0.0", false); 59 | pd->AddEnumOptions(L"127.0.0.1", L"127.0.0.1", false); 60 | pd->AddEnumOptions(L"0:0:0:0:0:0:0:0", L"0:0:0:0:0:0:0:0", false); 61 | pd->AddEnumOptions(L"0:0:0:0:0:0:0:1", L"0:0:0:0:0:0:0:1", false); 62 | pd->BindMethod( 63 | [self]() { return self->m_ListenAddress; }, 64 | [self](const std::wstring& value) { self->m_ListenAddress = value; } 65 | ); 66 | localGroup->AddChild(pd); 67 | 68 | pd = std::make_shared( 69 | L"ListenPort", 70 | L"DEVICE.TCPFORWARDSERVER.PROP.LISTENPORT", 71 | uint16_t(0), 72 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 73 | ); 74 | pd->BindMethod( 75 | [self]() { return std::to_wstring(self->m_ListenPort); }, 76 | [self](const std::wstring& value) { self->m_ListenPort = static_cast(std::wcstoul(value.c_str(), nullptr, 10)); } 77 | ); 78 | localGroup->AddChild(pd); 79 | 80 | 81 | 82 | pd = std::make_shared( 83 | L"RemoteHost", 84 | L"DEVICE.TCPFORWARDSERVER.PROP.REMOTEHOST", 85 | L"127.0.0.1", 86 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 87 | ); 88 | pd->BindMethod( 89 | [self]() { return self->m_RemoteHost; }, 90 | [self](const std::wstring& value) { self->m_RemoteHost = value; } 91 | ); 92 | remoteGroup->AddChild(pd); 93 | 94 | pd = std::make_shared( 95 | L"RemotePort", 96 | L"DEVICE.TCPFORWARDSERVER.PROP.REMOTEPORT", 97 | uint16_t(0), 98 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 99 | ); 100 | pd->BindMethod( 101 | [self]() { return std::to_wstring(self->m_RemotePort); }, 102 | [self](const std::wstring& value) { self->m_RemotePort = static_cast(std::wcstoul(value.c_str(), nullptr, 10)); } 103 | ); 104 | remoteGroup->AddChild(pd); 105 | 106 | results.push_back(localGroup); 107 | results.push_back(remoteGroup); 108 | 109 | pd = std::make_shared( 110 | L"ReuseAddress", 111 | L"DEVICE.TCPFORWARDSERVER.PROP.REUSEADDRESS", 112 | bool(false), 113 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 114 | ); 115 | pd->BindMethod( 116 | [self]() { return std::to_wstring(self->m_ReuseAddress ? 1 : 0); }, 117 | [self](const std::wstring& value) { self->m_ReuseAddress = value == L"1"; } 118 | ); 119 | results.push_back(pd); 120 | 121 | pd = std::make_shared( 122 | L"Keepalive", 123 | L"DEVICE.TCPFORWARDSERVER.PROP.KEEPALIVE", 124 | bool(false), 125 | IDevice::PropertyChangeFlags::CanChangeBeforeStart 126 | ); 127 | 128 | pd->BindMethod( 129 | [self]() { return std::to_wstring(self->m_Keepalive ? 1 : 0); }, 130 | [self](const std::wstring& value) { self->m_Keepalive = value == L"1"; }); 131 | results.push_back(pd); 132 | return results; 133 | } 134 | 135 | void TCPForwardServer::Start(void) 136 | { 137 | if (Started()) 138 | return; 139 | 140 | StatusChanged(DeviceStatus::Connecting, std::wstring()); 141 | boost::system::error_code ec; 142 | auto address = boost::asio::ip::address::from_string(WStringToString(m_ListenAddress), ec); 143 | if (ec) 144 | { 145 | Close(ec); 146 | return; 147 | } 148 | 149 | boost::asio::ip::tcp::endpoint ep(address, m_ListenPort); 150 | m_Acceptor.open(ep.protocol(), ec); 151 | if (ec) 152 | { 153 | Close(ec); 154 | return; 155 | } 156 | 157 | m_Acceptor.bind(ep, ec); 158 | if (ec) 159 | { 160 | Close(ec); 161 | return; 162 | } 163 | m_Acceptor.listen(m_Acceptor.max_listen_connections, ec); 164 | if (ec) 165 | { 166 | Close(ec); 167 | return; 168 | } 169 | 170 | m_Acceptor.set_option(boost::asio::socket_base::reuse_address(m_ReuseAddress), ec); 171 | if (ec) 172 | { 173 | Close(ec); 174 | return; 175 | } 176 | 177 | StartAcceptClient(); 178 | PropertyChanged(); 179 | StatusChanged(DeviceStatus::Connected, StringToWString(ec.message())); 180 | } 181 | 182 | void TCPForwardServer::Stop(void) 183 | { 184 | if (Started()) 185 | { 186 | StatusChanged(DeviceStatus::Disconnecting, std::wstring()); 187 | boost::system::error_code ec; 188 | m_Acceptor.cancel(ec); 189 | m_Acceptor.close(ec); 190 | PropertyChanged(); 191 | StatusChanged(DeviceStatus::Disconnected, std::wstring()); 192 | } 193 | } 194 | 195 | 196 | void TCPForwardServer::Close(const boost::system::error_code& errorCode) 197 | { 198 | boost::system::error_code ec; 199 | m_Acceptor.cancel(ec); 200 | m_Acceptor.close(ec); 201 | PropertyChanged(); 202 | StatusChanged(DeviceStatus::Disconnected, StringToWString(errorCode.message())); 203 | } 204 | 205 | void TCPForwardServer::StartAcceptClient(void) 206 | { 207 | auto server = this->shared_from_this(); 208 | std::shared_ptr channelClient(new TcpForwardChannel(server), [](TcpForwardChannel* ch) 209 | { 210 | ch->CloseChannel(); 211 | delete ch; 212 | }); 213 | 214 | m_Acceptor.async_accept(channelClient->m_Socket, [server, channelClient](const boost::system::error_code& ec) 215 | { 216 | if (!ec) 217 | { 218 | boost::system::error_code ecSet; 219 | channelClient->m_Opened = true; 220 | channelClient->m_Socket.set_option(boost::asio::socket_base::reuse_address(server->m_ReuseAddress), ecSet); 221 | channelClient->m_Socket.set_option(boost::asio::socket_base::keep_alive(server->m_Keepalive), ecSet); 222 | channelClient->m_ChannelGroupName = L"#"; 223 | channelClient->m_ChannelGroupName += std::to_wstring((size_t)channelClient->m_Socket.native_handle()); 224 | channelClient->m_ChannelGroupName += L"-Client : "; 225 | 226 | std::shared_ptr channelServer(new TcpForwardChannel(server), [](TcpForwardChannel* ch) 227 | { 228 | ch->CloseChannel(); 229 | delete ch; 230 | }); 231 | channelServer->m_ChannelGroupName = L"#"; 232 | channelServer->m_ChannelGroupName += std::to_wstring((size_t)channelClient->m_Socket.native_handle()); 233 | channelServer->m_ChannelGroupName += L"-Server : "; 234 | 235 | ConnectServer(server, channelClient, channelServer); 236 | server->StartAcceptClient(); 237 | } 238 | }); 239 | } 240 | 241 | void TCPForwardServer::ConnectServer(std::shared_ptr self, std::shared_ptr channelClient, std::shared_ptr channelServer) 242 | { 243 | boost::system::error_code ec; 244 | auto rslv = std::make_shared(theApp.GetIOContext()); 245 | boost::asio::ip::tcp::resolver::query qry(WStringToString(self->m_RemoteHost), std::to_string(self->m_RemotePort)); 246 | rslv->async_resolve(qry, [rslv, self, channelClient, channelServer](const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator iter) 247 | { 248 | if (!ec) 249 | { 250 | boost::asio::async_connect( 251 | channelServer->m_Socket, 252 | iter, 253 | [rslv, self, channelClient, channelServer](const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator iter) 254 | { 255 | if (!ec) 256 | { 257 | boost::system::error_code ecSet; 258 | channelServer->m_Socket.set_option(boost::asio::socket_base::reuse_address(self->m_ReuseAddress), ecSet); 259 | channelServer->m_Socket.set_option(boost::asio::socket_base::keep_alive(self->m_Keepalive), ecSet); 260 | channelServer->m_Opened = true; 261 | 262 | channelClient->m_Target = channelServer; 263 | channelServer->m_Target = channelClient; 264 | self->ChannelConnected(channelClient, StringToWString(ec.message())); 265 | self->ChannelConnected(channelServer, StringToWString(ec.message())); 266 | } 267 | }); 268 | } 269 | }); 270 | } 271 | 272 | void TCPForwardServer::NotifyChannelClose(std::shared_ptr channel, const boost::system::error_code& ecClose) 273 | { 274 | ChannelDisconnected(channel, StringToWString(ecClose.message())); 275 | } 276 | 277 | 278 | TcpForwardChannel::TcpForwardChannel(std::shared_ptr owner): 279 | m_Owner(owner), 280 | m_Target(), 281 | m_Socket(theApp.GetIOContext()), 282 | m_Opened(false), 283 | m_ChannelGroupName() 284 | { 285 | } 286 | 287 | TcpForwardChannel::~TcpForwardChannel(void) 288 | { 289 | CloseChannel(); 290 | } 291 | 292 | bool TcpForwardChannel::CloseChannel(void) 293 | { 294 | bool state = true; 295 | if (m_Opened.compare_exchange_weak(state, false)) 296 | { 297 | m_Target.reset(); 298 | boost::system::error_code ec; 299 | m_Socket.cancel(ec); 300 | m_Socket.shutdown(m_Socket.shutdown_both, ec); 301 | m_Socket.close(ec); 302 | return true; 303 | } 304 | return false; 305 | } 306 | 307 | void TcpForwardChannel::TargetCloseChannel(const boost::system::error_code& ecClose) 308 | { 309 | if (CloseChannel()) 310 | { 311 | auto dev = m_Owner.lock(); 312 | if (dev != nullptr) 313 | { 314 | dev->NotifyChannelClose(shared_from_this(), ecClose); 315 | } 316 | } 317 | } 318 | 319 | void TcpForwardChannel::CloseChannel(const boost::system::error_code& ecClose) 320 | { 321 | auto target = m_Target.lock(); 322 | if (CloseChannel()) 323 | { 324 | if (target != nullptr) 325 | { 326 | target->TargetCloseChannel(ecClose); 327 | } 328 | 329 | auto dev = m_Owner.lock(); 330 | if (dev != nullptr) 331 | { 332 | dev->NotifyChannelClose(shared_from_this(), ecClose); 333 | } 334 | } 335 | } 336 | 337 | std::wstring TcpForwardChannel::Id(void) const 338 | { 339 | if (sizeof(size_t) == sizeof(void*)) 340 | return std::to_wstring(reinterpret_cast(this)); 341 | else 342 | return std::to_wstring(reinterpret_cast(this)); 343 | } 344 | 345 | std::wstring TcpForwardChannel::Description(void) const 346 | { 347 | std::wstring result = m_ChannelGroupName; 348 | boost::system::error_code ec; 349 | auto local = m_Socket.remote_endpoint(ec); 350 | if (ec) 351 | { 352 | result += L"none" + result; 353 | } 354 | else 355 | { 356 | result += L"local("; 357 | result += StringToWString(local.address().to_string()) + L":" + std::to_wstring(local.port()); 358 | result += L")"; 359 | } 360 | 361 | auto remote = m_Socket.remote_endpoint(ec); 362 | if (ec) 363 | { 364 | result += L" <---> none"; 365 | } 366 | else 367 | { 368 | result += L" <---> remote("; 369 | result += StringToWString(remote.address().to_string()) + L":" + std::to_wstring(remote.port()); 370 | result += L")"; 371 | } 372 | return result; 373 | } 374 | 375 | std::wstring TcpForwardChannel::LocalEndPoint(void) const 376 | { 377 | std::wstring result; 378 | boost::system::error_code ec; 379 | auto local = m_Socket.local_endpoint(ec); 380 | if (ec) 381 | { 382 | result = L"none"; 383 | } 384 | else 385 | { 386 | result = StringToWString(local.address().to_string()) + L"#" + std::to_wstring(local.port()); 387 | } 388 | return result; 389 | } 390 | 391 | std::wstring TcpForwardChannel::RemoteEndPoint(void) const 392 | { 393 | std::wstring result; 394 | boost::system::error_code ec; 395 | auto local = m_Socket.remote_endpoint(ec); 396 | if (ec) 397 | { 398 | result = L"none"; 399 | } 400 | else 401 | { 402 | result = StringToWString(local.address().to_string()) + L"#" + std::to_wstring(local.port()); 403 | } 404 | return result; 405 | } 406 | 407 | void TcpForwardChannel::Read(OutputBuffer buffer, IoCompletionHandler handler) 408 | { 409 | auto client = shared_from_this(); 410 | boost::asio::async_read( 411 | m_Socket, 412 | boost::asio::buffer(buffer->data(), buffer->size()), 413 | [client, buffer, handler](const boost::system::error_code& ec, size_t bytestransfer) 414 | { 415 | if (!ec && bytestransfer > 0) 416 | { 417 | auto tsp = client->m_Target.lock(); 418 | if (tsp != nullptr) 419 | { 420 | InputBuffer inbuffer; 421 | inbuffer.buffer = buffer->data(); 422 | inbuffer.bufferSize = bytestransfer; 423 | tsp->Write(inbuffer, [client, bytestransfer, handler](bool ok, size_t byteswrite) 424 | { 425 | if (handler != nullptr) 426 | handler(true, bytestransfer); 427 | }); 428 | } 429 | else 430 | { 431 | if (handler != nullptr) 432 | handler(true, bytestransfer); 433 | } 434 | } 435 | else 436 | { 437 | if (handler != nullptr) 438 | handler(false, bytestransfer); 439 | if (ec != boost::system::errc::operation_canceled) 440 | client->CloseChannel(ec); 441 | } 442 | }); 443 | } 444 | void TcpForwardChannel::Write(InputBuffer buffer, IoCompletionHandler handler) 445 | { 446 | auto client = shared_from_this(); 447 | boost::asio::async_write( 448 | m_Socket, 449 | boost::asio::const_buffer(buffer.buffer, buffer.bufferSize), 450 | [client, handler, this](const boost::system::error_code& ec, size_t bytestransfer) 451 | { 452 | if (handler != nullptr) 453 | handler(!ec, bytestransfer); 454 | if (ec) 455 | { 456 | if (ec != boost::system::errc::operation_canceled) 457 | client->CloseChannel(ec); 458 | } 459 | }); 460 | } 461 | 462 | void TcpForwardChannel::ReadSome(OutputBuffer buffer, IoCompletionHandler handler) 463 | { 464 | auto client = shared_from_this(); 465 | m_Socket.async_read_some( 466 | boost::asio::buffer(buffer->data(), buffer->size()), 467 | [client, buffer, handler](const boost::system::error_code& ec, size_t bytestransfer) 468 | { 469 | if (!ec && bytestransfer > 0) 470 | { 471 | auto tsp = client->m_Target.lock(); 472 | if (tsp != nullptr) 473 | { 474 | InputBuffer inbuffer; 475 | inbuffer.buffer = buffer->data(); 476 | inbuffer.bufferSize = bytestransfer; 477 | tsp->Write(inbuffer, [client, bytestransfer, handler](bool ok, size_t byteswrite) 478 | { 479 | if (handler != nullptr) 480 | handler(true, bytestransfer); 481 | }); 482 | } 483 | else 484 | { 485 | if (handler != nullptr) 486 | handler(true, bytestransfer); 487 | } 488 | } 489 | else 490 | { 491 | if (handler != nullptr) 492 | handler(false, bytestransfer); 493 | if (ec != boost::system::errc::operation_canceled) 494 | client->CloseChannel(ec); 495 | } 496 | }); 497 | } 498 | 499 | void TcpForwardChannel::WriteSome(InputBuffer buffer, IoCompletionHandler handler) 500 | { 501 | auto client = shared_from_this(); 502 | m_Socket.async_write_some( 503 | boost::asio::const_buffer(buffer.buffer, buffer.bufferSize), 504 | [client, handler](const boost::system::error_code& ec, size_t bytestransfer) 505 | { 506 | handler(!ec, bytestransfer); 507 | if (ec) 508 | { 509 | if (ec != boost::system::errc::operation_canceled) 510 | client->CloseChannel(ec); 511 | } 512 | }); 513 | } 514 | 515 | void TcpForwardChannel::Cancel(void) 516 | { 517 | boost::system::error_code ec; 518 | m_Socket.cancel(ec); 519 | } 520 | 521 | void TcpForwardChannel::Close(void) 522 | { 523 | CloseChannel(boost::system::errc::make_error_code(boost::system::errc::connection_aborted)); 524 | } 525 | 526 | REGISTER_CLASS_TITLE(TCPForwardServer, L"DEVICE.CLASS.TCPFORWARDSERVER.TITLE"); -------------------------------------------------------------------------------- /NetDebugger/DataBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "DataBuffer.h" 3 | #include "fast_memcpy.hpp" 4 | 5 | constexpr size_t kBLOCK_DATA_SIZE = 8192; 6 | class DataBufferPrivateImpl 7 | { 8 | public: 9 | struct BufferBlock 10 | { 11 | BufferBlock* prev; 12 | BufferBlock* next; 13 | size_t used; 14 | uint8_t data[kBLOCK_DATA_SIZE]; 15 | }; 16 | 17 | DataBufferPrivateImpl(): 18 | m_BlockFirst(nullptr), 19 | m_BlockLast(nullptr), 20 | m_BlockCount(0), 21 | m_TotalUsed(0) 22 | { 23 | m_BlockFirst = new BufferBlock(); 24 | m_BlockFirst->prev = nullptr; 25 | m_BlockFirst->next = nullptr; 26 | m_BlockFirst->used = 0; 27 | m_BlockLast = m_BlockFirst; 28 | m_BlockCount = 1; 29 | } 30 | ~DataBufferPrivateImpl() 31 | { 32 | Clear(true); 33 | } 34 | 35 | void Clear(bool all) 36 | { 37 | if (m_BlockCount == 0) 38 | return; 39 | 40 | BufferBlock* next = m_BlockLast; 41 | for (BufferBlock* block = m_BlockFirst; block != m_BlockLast; block = next) 42 | { 43 | next = block->next; 44 | delete block; 45 | } 46 | m_BlockFirst = m_BlockLast; 47 | 48 | if (all) 49 | { 50 | delete m_BlockFirst; 51 | m_BlockFirst = nullptr; 52 | m_BlockLast = nullptr; 53 | m_TotalUsed = 0; 54 | m_BlockCount = 0; 55 | } 56 | else 57 | { 58 | m_BlockLast->used = 0; 59 | m_TotalUsed = 0; 60 | m_BlockCount = 1; 61 | } 62 | } 63 | 64 | BufferBlock* RemoveBlock(BufferBlock* atBlock) 65 | { 66 | if (atBlock == m_BlockFirst) 67 | { 68 | atBlock->used = 0; 69 | return atBlock->next; 70 | } 71 | --m_BlockCount; 72 | if (atBlock == m_BlockLast) 73 | { 74 | m_BlockLast = m_BlockLast->prev; 75 | m_BlockLast->next = nullptr; 76 | atBlock->used = 0; 77 | delete atBlock; 78 | return nullptr; 79 | } 80 | 81 | auto prev = atBlock->prev; 82 | auto next = atBlock->next; 83 | prev->next = next; 84 | next->prev = prev; 85 | atBlock->used = 0; 86 | delete atBlock; 87 | return next; 88 | } 89 | 90 | BufferBlock* AfterBlock(BufferBlock* atBlock) 91 | { 92 | BufferBlock* block = new BufferBlock(); 93 | block->prev = atBlock; 94 | block->next = atBlock->next; 95 | block->used = 0; 96 | atBlock->next = block; 97 | if (block->next != nullptr) 98 | block->next->prev = block; 99 | if (atBlock == m_BlockLast) 100 | m_BlockLast = block; 101 | ++m_BlockCount; 102 | return block; 103 | } 104 | 105 | BufferBlock* BeforeBlock(BufferBlock* atBlock) 106 | { 107 | BufferBlock* block = new BufferBlock(); 108 | block->prev = atBlock->prev; 109 | block->next = atBlock; 110 | block->used = 0; 111 | atBlock->prev = block; 112 | if (block->prev != nullptr) 113 | block->prev->next = block; 114 | if (atBlock == m_BlockFirst) 115 | m_BlockFirst = block; 116 | ++m_BlockCount; 117 | return block; 118 | } 119 | 120 | BufferBlock* PrependBlock() 121 | { 122 | BufferBlock* block = new BufferBlock(); 123 | block->prev = nullptr; 124 | block->next = m_BlockFirst; 125 | block->used = 0; 126 | m_BlockFirst->prev = block; 127 | m_BlockFirst = block; 128 | ++m_BlockCount; 129 | return block; 130 | } 131 | 132 | BufferBlock* AppendBlock() 133 | { 134 | BufferBlock* block = new BufferBlock(); 135 | block->prev = m_BlockLast; 136 | block->next = nullptr; 137 | block->used = 0; 138 | m_BlockLast->next = block; 139 | m_BlockLast = block; 140 | ++m_BlockCount; 141 | return block; 142 | } 143 | 144 | BufferBlock* FindBlockByOffset(size_t& offset) 145 | { 146 | for (BufferBlock* block = m_BlockFirst; block != nullptr; block = block->next) 147 | { 148 | if (offset < block->used) 149 | return block; 150 | offset -= block->used; 151 | } 152 | return nullptr; 153 | } 154 | 155 | size_t CopyData(BufferBlock* start, size_t offset, size_t size, void* buffer, BufferBlock** next = nullptr) 156 | { 157 | auto p = reinterpret_cast(buffer); 158 | auto count = size; 159 | 160 | auto rlen = start->used - offset; 161 | size_t len = (size < rlen) ? size : rlen; 162 | if (len > 0) 163 | { 164 | fast_memcpy(p, start->data + offset, len); 165 | size -= len; 166 | p += len; 167 | } 168 | start = start->next; 169 | 170 | while (size > 0 && start != nullptr) 171 | { 172 | size_t len = (size < start->used) ? size : start->used; 173 | if (len > 0) 174 | { 175 | fast_memcpy(p, start->data, len); 176 | size -= len; 177 | p += len; 178 | } 179 | start = start->next; 180 | } 181 | if (*next != nullptr) 182 | { 183 | *next = start; 184 | } 185 | return count - size; 186 | } 187 | 188 | BufferBlock* m_BlockFirst; 189 | BufferBlock* m_BlockLast; 190 | size_t m_BlockCount; 191 | size_t m_TotalUsed; 192 | }; 193 | 194 | DataBuffer::DataBuffer() 195 | { 196 | m_Impl.reset(new DataBufferPrivateImpl()); 197 | } 198 | 199 | DataBuffer::DataBuffer(DataBuffer&& value) 200 | { 201 | m_Impl.swap(value.m_Impl); 202 | } 203 | 204 | DataBuffer::~DataBuffer(void) 205 | { 206 | m_Impl->Clear(true); 207 | } 208 | 209 | size_t DataBuffer::Size() const 210 | { 211 | return m_Impl->m_TotalUsed; 212 | } 213 | 214 | size_t DataBuffer::GapSize(void) const 215 | { 216 | auto total = m_Impl->m_BlockCount * kBLOCK_DATA_SIZE; 217 | return total - Size() - (kBLOCK_DATA_SIZE - m_Impl->m_BlockLast->used); 218 | } 219 | 220 | size_t DataBuffer::CopyData(size_t index, size_t size, void* buffer) const 221 | { 222 | auto block = m_Impl->FindBlockByOffset(index); 223 | if (block == nullptr) 224 | return 0; 225 | 226 | return m_Impl->CopyData(block, index, size, buffer); 227 | } 228 | 229 | uint8_t DataBuffer::GetAt(size_t index) const 230 | { 231 | auto block = m_Impl->FindBlockByOffset(index); 232 | if (block == nullptr) 233 | return 0; 234 | return block->data[index]; 235 | } 236 | 237 | void DataBuffer::SetAt(size_t index, uint8_t value) 238 | { 239 | auto block = m_Impl->FindBlockByOffset(index); 240 | if (block == nullptr) 241 | return; 242 | block->data[index] = value; 243 | } 244 | 245 | void DataBuffer::Append(const void* data, size_t size) 246 | { 247 | auto addsize = size; 248 | auto block = m_Impl->m_BlockLast; 249 | auto p = reinterpret_cast(data); 250 | auto freeSize = kBLOCK_DATA_SIZE - block->used; 251 | if (size > freeSize) 252 | { 253 | fast_memcpy(block->data + block->used, p, freeSize); 254 | size -= freeSize; 255 | block->used += freeSize; 256 | p += freeSize; 257 | while (size > 0) 258 | { 259 | block = m_Impl->AfterBlock(block); 260 | auto len = size < kBLOCK_DATA_SIZE ? size : kBLOCK_DATA_SIZE; 261 | fast_memcpy(block->data + block->used, p, len); 262 | size -= len; 263 | p += len; 264 | block->used += len; 265 | } 266 | } 267 | else 268 | { 269 | fast_memcpy(block->data + block->used, p, size); 270 | block->used += size; 271 | } 272 | m_Impl->m_TotalUsed += addsize; 273 | } 274 | 275 | void DataBuffer::AppendFill(uint8_t fill, size_t size) 276 | { 277 | auto addsize = size; 278 | auto block = m_Impl->m_BlockLast; 279 | auto freeSize = kBLOCK_DATA_SIZE - block->used; 280 | if (size > freeSize) 281 | { 282 | memset(block->data + block->used, fill, freeSize); 283 | size -= freeSize; 284 | block->used += freeSize; 285 | while (size > 0) 286 | { 287 | block = m_Impl->AfterBlock(block); 288 | auto len = size < kBLOCK_DATA_SIZE ? size : kBLOCK_DATA_SIZE; 289 | memset(block->data + block->used, fill, len); 290 | size -= len; 291 | block->used += len; 292 | } 293 | } 294 | else 295 | { 296 | memset(block->data + block->used, fill, size); 297 | block->used += size; 298 | } 299 | m_Impl->m_TotalUsed += addsize; 300 | } 301 | 302 | void DataBuffer::Prepend(const void* data, size_t size) 303 | { 304 | auto addsize = size; 305 | auto block = m_Impl->m_BlockFirst; 306 | auto p = reinterpret_cast(data); 307 | auto freeSize = kBLOCK_DATA_SIZE - block->used; 308 | if (size > freeSize) 309 | { 310 | memmove(block->data + freeSize, block->data, block->used); 311 | fast_memcpy(block->data, p + (size - freeSize), freeSize); 312 | size -= freeSize; 313 | block->used += freeSize; 314 | block = m_Impl->BeforeBlock(block); 315 | while (true) 316 | { 317 | auto len = size < kBLOCK_DATA_SIZE ? size : kBLOCK_DATA_SIZE; 318 | fast_memcpy(block->data + block->used, p, len); 319 | size -= len; 320 | p += len; 321 | block->used += len; 322 | if(size>0) 323 | block = m_Impl->AfterBlock(block); 324 | else 325 | break; 326 | } 327 | } 328 | else 329 | { 330 | memmove(block->data + size, block->data, block->used); 331 | fast_memcpy(block->data, p, size); 332 | block->used += size; 333 | } 334 | m_Impl->m_TotalUsed += addsize; 335 | } 336 | 337 | void DataBuffer::PrependFill(uint8_t fill, size_t size) 338 | { 339 | auto addsize = size; 340 | auto block = m_Impl->m_BlockFirst; 341 | auto freeSize = kBLOCK_DATA_SIZE - block->used; 342 | if (size > freeSize) 343 | { 344 | memmove(block->data + freeSize, block->data, block->used); 345 | memset(block->data, fill, freeSize); 346 | size -= freeSize; 347 | block->used += freeSize; 348 | block = m_Impl->BeforeBlock(block); 349 | while (true) 350 | { 351 | auto len = size < kBLOCK_DATA_SIZE ? size : kBLOCK_DATA_SIZE; 352 | memset(block->data + block->used, fill, len); 353 | size -= len; 354 | block->used += len; 355 | if (size > 0) 356 | block = m_Impl->AfterBlock(block); 357 | else 358 | break; 359 | } 360 | } 361 | else 362 | { 363 | memmove(block->data + size, block->data, block->used); 364 | memset(block->data, fill, size); 365 | block->used += size; 366 | } 367 | m_Impl->m_TotalUsed += addsize; 368 | } 369 | 370 | void DataBuffer::Insert(const void* data, size_t index, size_t size) 371 | { 372 | if (index >= Size()) 373 | { 374 | Append(data, size); 375 | return; 376 | } 377 | 378 | if (index == 0) 379 | { 380 | Prepend(data, size); 381 | return; 382 | } 383 | 384 | auto addsize = size; 385 | auto block = m_Impl->FindBlockByOffset(index); 386 | if (block == nullptr) 387 | block = m_Impl->AppendBlock(); 388 | auto p = reinterpret_cast(data); 389 | auto freeSize = kBLOCK_DATA_SIZE - block->used; 390 | if (size > freeSize) 391 | { 392 | memmove(block->data + index + freeSize, block->data + index, block->used - index); 393 | fast_memcpy(block->data + index, p, freeSize); 394 | size -= freeSize; 395 | block->used += freeSize; 396 | p += freeSize; 397 | while (size > 0) 398 | { 399 | auto len = size < kBLOCK_DATA_SIZE ? size : kBLOCK_DATA_SIZE; 400 | if (block == nullptr || block->next == nullptr) 401 | { 402 | block = m_Impl->AfterBlock(block); 403 | } 404 | else 405 | { 406 | freeSize = kBLOCK_DATA_SIZE - block->next->used; 407 | if (freeSize >= len) 408 | { 409 | block = block->next; 410 | memmove(block->data + len, block->data, block->used); 411 | } 412 | else 413 | { 414 | block = m_Impl->AfterBlock(block); 415 | } 416 | } 417 | fast_memcpy(block->data, p, len); 418 | size -= len; 419 | p += len; 420 | block->used += len; 421 | } 422 | } 423 | else 424 | { 425 | memmove(block->data + index + size, block->data + index, block->used - index); 426 | fast_memcpy(block->data + index, p, size); 427 | block->used += size; 428 | } 429 | m_Impl->m_TotalUsed += addsize; 430 | } 431 | 432 | void DataBuffer::InsertFill(size_t index, size_t size, uint8_t fill) 433 | { 434 | if (index >= Size()) 435 | { 436 | AppendFill(fill, size); 437 | return; 438 | } 439 | 440 | if (index == 0) 441 | { 442 | PrependFill(fill, size); 443 | return; 444 | } 445 | 446 | auto addsize = size; 447 | auto block = m_Impl->FindBlockByOffset(index); 448 | if (block == nullptr) 449 | block = m_Impl->AppendBlock(); 450 | auto freeSize = kBLOCK_DATA_SIZE - block->used; 451 | if (size > freeSize) 452 | { 453 | memmove(block->data + index + freeSize, block->data + index, block->used - index); 454 | memset(block->data + index, fill, freeSize); 455 | size -= freeSize; 456 | block->used += freeSize; 457 | while (size > 0) 458 | { 459 | auto len = size < kBLOCK_DATA_SIZE ? size : kBLOCK_DATA_SIZE; 460 | if (block == nullptr || block->next == nullptr) 461 | { 462 | block = m_Impl->AfterBlock(block); 463 | } 464 | else 465 | { 466 | freeSize = kBLOCK_DATA_SIZE - block->next->used; 467 | if (freeSize >= len) 468 | { 469 | block = block->next; 470 | memmove(block->data + len, block->data, block->used); 471 | } 472 | else 473 | { 474 | block = m_Impl->AfterBlock(block); 475 | } 476 | } 477 | memset(block->data, 0, len); 478 | size -= len; 479 | block->used += len; 480 | } 481 | } 482 | else 483 | { 484 | memmove(block->data + index + size, block->data + index, block->used - index); 485 | memset(block->data + index, fill, size); 486 | block->used += size; 487 | } 488 | m_Impl->m_TotalUsed += addsize; 489 | } 490 | 491 | void DataBuffer::Replace(const void* dest, size_t destSize, size_t srcIndex, size_t srcSize) 492 | { 493 | if (destSize == srcSize && srcSize == 1) 494 | { 495 | SetAt(srcIndex, *reinterpret_cast(dest)); 496 | return; 497 | } 498 | 499 | if (srcIndex >= Size()) 500 | { 501 | Append(dest, destSize); 502 | return; 503 | } 504 | 505 | if (srcIndex + srcSize > Size()) 506 | { 507 | srcSize = Size() - srcIndex; 508 | } 509 | 510 | auto index = srcIndex; 511 | auto block = m_Impl->FindBlockByOffset(srcIndex); 512 | if (block == nullptr) 513 | return; 514 | auto p = reinterpret_cast(dest); 515 | if (destSize > srcSize) 516 | { 517 | auto padsize = destSize - srcSize; 518 | InsertFill(index + srcSize, padsize, 0); 519 | } 520 | else if (destSize < srcSize) 521 | { 522 | auto delsize = srcSize - destSize; 523 | Remove(index + destSize, delsize); 524 | } 525 | 526 | if (srcIndex + destSize <= block->used) 527 | { 528 | fast_memcpy(block->data + srcIndex, p, destSize); 529 | destSize = 0; 530 | } 531 | else 532 | { 533 | auto len = block->used - srcIndex; 534 | fast_memcpy(block->data + srcIndex, p, len); 535 | p += len; 536 | destSize -= len; 537 | } 538 | 539 | while (destSize > 0) 540 | { 541 | block = block->next; 542 | if (block == nullptr) 543 | block = m_Impl->AppendBlock(); 544 | auto len = destSize > block->used ? block->used : destSize; 545 | fast_memcpy(block->data, p, len); 546 | p += len; 547 | destSize -= len; 548 | } 549 | } 550 | 551 | void DataBuffer::Fill(uint8_t fill, size_t index, size_t size) 552 | { 553 | if (size == 1) 554 | { 555 | SetAt(index, fill); 556 | return; 557 | } 558 | 559 | if (index >= Size()) 560 | { 561 | return; 562 | } 563 | 564 | if (index + size > Size()) 565 | { 566 | size = Size() - index; 567 | } 568 | 569 | auto block = m_Impl->FindBlockByOffset(index); 570 | if (block == nullptr) 571 | return; 572 | 573 | if (index + size <= block->used) 574 | { 575 | memset(block->data + index, fill, size); 576 | size = 0; 577 | } 578 | else 579 | { 580 | auto len = block->used - index; 581 | memset(block->data + index, fill, len); 582 | size -= len; 583 | } 584 | 585 | while (size > 0) 586 | { 587 | block = block->next; 588 | if (block == nullptr) 589 | break; 590 | auto len = size > block->used ? block->used : size; 591 | memset(block->data, fill, len); 592 | size -= len; 593 | } 594 | } 595 | 596 | void DataBuffer::Remove(size_t index, size_t size) 597 | { 598 | auto block = m_Impl->FindBlockByOffset(index); 599 | if (block == nullptr) 600 | return; 601 | auto delsize = size; 602 | auto endIndex = index + size; 603 | if (endIndex > block->used) 604 | { 605 | delsize = block->used - index; 606 | size -= delsize; 607 | block->used -= delsize; 608 | if (block->used == 0) 609 | block = m_Impl->RemoveBlock(block); 610 | else 611 | block = block->next; 612 | while (size > 0 && block!=nullptr) 613 | { 614 | if (size >= block->used) 615 | { 616 | size -= block->used; 617 | block = m_Impl->RemoveBlock(block); 618 | } 619 | else 620 | { 621 | delsize = size; 622 | auto len = block->used - delsize; 623 | fast_memcpy(block->data, block->data + delsize, len); 624 | size = 0; 625 | block->used -= size; 626 | block = block->next; 627 | } 628 | } 629 | } 630 | else 631 | { 632 | auto len = block->used - endIndex; 633 | if (len > 0) 634 | memmove(block->data + index, block->data + endIndex, len); 635 | block->used -= size; 636 | size = 0; 637 | if (block->used == 0) 638 | m_Impl->RemoveBlock(block); 639 | } 640 | m_Impl->m_TotalUsed -= delsize - size; 641 | } 642 | 643 | void DataBuffer::Compress(void) 644 | { 645 | auto block = m_Impl->m_BlockFirst; 646 | while (block != m_Impl->m_BlockLast) 647 | { 648 | auto freeSize = kBLOCK_DATA_SIZE - block->used; 649 | if (freeSize > 0) 650 | { 651 | auto next = block->next; 652 | while (freeSize > 0) 653 | { 654 | if (next != nullptr) 655 | { 656 | if (freeSize < next->used) 657 | { 658 | fast_memcpy(block->data + block->used, next->data, freeSize); 659 | memmove(next->data, next->data + freeSize, next->used - freeSize); 660 | block->used += freeSize; 661 | next->used -= freeSize; 662 | freeSize = 0; 663 | break; 664 | } 665 | else 666 | { 667 | fast_memcpy(block->data + block->used, next->data, next->used); 668 | block->used += next->used; 669 | freeSize -= next->used; 670 | next->used = 0; 671 | next = m_Impl->RemoveBlock(next); 672 | } 673 | } 674 | else 675 | { 676 | return; 677 | } 678 | } 679 | } 680 | block = block->next; 681 | } 682 | } 683 | 684 | void DataBuffer::Resize(size_t size) 685 | { 686 | if (size > Size()) 687 | { 688 | auto padsize = size - Size(); 689 | AppendFill(0, padsize); 690 | } 691 | else if(size < Size()) 692 | { 693 | auto delsize = Size() - size; 694 | Remove(Size() - delsize, delsize); 695 | } 696 | } 697 | 698 | void DataBuffer::Clear(void) 699 | { 700 | m_Impl->Clear(false); 701 | } 702 | 703 | 704 | DataBufferView::DataBufferView(const DataBufferView& view) : 705 | m_DataBuffer(view.m_DataBuffer), 706 | m_Position(view.m_Position), 707 | m_pBuffer(view.m_pBuffer) 708 | { 709 | } 710 | DataBufferView::DataBufferView(const DataBuffer& buffer) : 711 | m_DataBuffer(buffer), 712 | m_Position(0), 713 | m_pBuffer(buffer.m_Impl->m_BlockFirst) 714 | { 715 | } 716 | 717 | void DataBufferView::Position(size_t pos) 718 | { 719 | if (pos != m_Position) 720 | { 721 | auto block = m_DataBuffer.m_Impl->FindBlockByOffset(pos); 722 | if (block != nullptr) 723 | { 724 | m_Position = pos; 725 | m_pBuffer = block; 726 | } 727 | } 728 | } 729 | size_t DataBufferView::GetData(void* buffer, size_t size) 730 | { 731 | DataBufferPrivateImpl::BufferBlock* block = reinterpret_cast(m_pBuffer); 732 | auto len = m_DataBuffer.m_Impl->CopyData( 733 | block, 734 | m_Position % kBLOCK_DATA_SIZE, 735 | size, 736 | buffer, 737 | &block); 738 | m_Position += len; 739 | if (block != nullptr) 740 | m_pBuffer = block; 741 | else 742 | m_pBuffer = m_DataBuffer.m_Impl->m_BlockLast; 743 | return len; 744 | } 745 | 746 | int DataBufferView::GetByte(void) 747 | { 748 | uint8_t val; 749 | DataBufferPrivateImpl::BufferBlock* block = reinterpret_cast(m_pBuffer); 750 | auto len = m_DataBuffer.m_Impl->CopyData( 751 | block, 752 | m_Position % kBLOCK_DATA_SIZE, 753 | 1, 754 | &val, 755 | &block); 756 | m_Position += len; 757 | if (block != nullptr) 758 | m_pBuffer = block; 759 | else 760 | m_pBuffer = m_DataBuffer.m_Impl->m_BlockLast; 761 | if (len == sizeof(val)) 762 | return val; 763 | return -1; 764 | } 765 | bool DataBufferView::EndOfBuffer(void) const 766 | { 767 | return m_Position >= m_DataBuffer.Size(); 768 | } 769 | 770 | DataBufferIterator::DataBufferIterator(const DataBufferIterator& it): 771 | m_pPrivateImpl(it.m_pPrivateImpl) 772 | { 773 | } 774 | 775 | DataBufferIterator::DataBufferIterator(DataBufferIterator&& it) : 776 | m_pPrivateImpl(it.m_pPrivateImpl) 777 | { 778 | it.m_pPrivateImpl = nullptr; 779 | } 780 | 781 | DataBufferIterator::DataBufferIterator(const DataBuffer& buffer) : 782 | m_pPrivateImpl(buffer.m_Impl->m_BlockFirst) 783 | { 784 | } 785 | 786 | bool DataBufferIterator::Next(void) 787 | { 788 | if (m_pPrivateImpl == nullptr) 789 | return false; 790 | DataBufferPrivateImpl::BufferBlock* block = reinterpret_cast(m_pPrivateImpl); 791 | m_pPrivateImpl = block->next; 792 | return m_pPrivateImpl!=nullptr; 793 | } 794 | 795 | bool DataBufferIterator::Prev(void) 796 | { 797 | if (m_pPrivateImpl == nullptr) 798 | return false; 799 | DataBufferPrivateImpl::BufferBlock* block = reinterpret_cast(m_pPrivateImpl); 800 | m_pPrivateImpl = block->prev; 801 | return m_pPrivateImpl != nullptr; 802 | } 803 | 804 | const uint8_t* DataBufferIterator::Data(void) const 805 | { 806 | if (m_pPrivateImpl == nullptr) 807 | return nullptr; 808 | DataBufferPrivateImpl::BufferBlock* block = reinterpret_cast(m_pPrivateImpl); 809 | return block->data; 810 | } 811 | const size_t DataBufferIterator::Length(void) const 812 | { 813 | if (m_pPrivateImpl == nullptr) 814 | return 0; 815 | DataBufferPrivateImpl::BufferBlock* block = reinterpret_cast(m_pPrivateImpl); 816 | return block->used; 817 | } -------------------------------------------------------------------------------- /NetDebugger/fast_memcpy.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef __FAST_MEMCPY_H__ 4 | #define __FAST_MEMCPY_H__ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | //--------------------------------------------------------------------- 12 | // force inline for compilers 13 | //--------------------------------------------------------------------- 14 | #ifndef INLINE 15 | #ifdef __GNUC__ 16 | #if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) 17 | #define INLINE __inline__ __attribute__((always_inline)) 18 | #else 19 | #define INLINE __inline__ 20 | #endif 21 | #elif defined(_MSC_VER) 22 | #define INLINE __forceinline 23 | #elif (defined(__BORLANDC__) || defined(__WATCOMC__)) 24 | #define INLINE __inline 25 | #else 26 | #define INLINE 27 | #endif 28 | #endif 29 | 30 | //--------------------------------------------------------------------- 31 | // fast copy for different sizes 32 | //--------------------------------------------------------------------- 33 | static INLINE void _impl_memcpy_sse2_16(void *dst, const void *src) { 34 | __m128i m0 = _mm_loadu_si128(((const __m128i*)src) + 0); 35 | _mm_storeu_si128(((__m128i*)dst) + 0, m0); 36 | } 37 | 38 | static INLINE void _impl_memcpy_sse2_32(void *dst, const void *src) { 39 | __m128i m0 = _mm_loadu_si128(((const __m128i*)src) + 0); 40 | __m128i m1 = _mm_loadu_si128(((const __m128i*)src) + 1); 41 | _mm_storeu_si128(((__m128i*)dst) + 0, m0); 42 | _mm_storeu_si128(((__m128i*)dst) + 1, m1); 43 | } 44 | 45 | static INLINE void _impl_memcpy_sse2_64(void *dst, const void *src) { 46 | __m128i m0 = _mm_loadu_si128(((const __m128i*)src) + 0); 47 | __m128i m1 = _mm_loadu_si128(((const __m128i*)src) + 1); 48 | __m128i m2 = _mm_loadu_si128(((const __m128i*)src) + 2); 49 | __m128i m3 = _mm_loadu_si128(((const __m128i*)src) + 3); 50 | _mm_storeu_si128(((__m128i*)dst) + 0, m0); 51 | _mm_storeu_si128(((__m128i*)dst) + 1, m1); 52 | _mm_storeu_si128(((__m128i*)dst) + 2, m2); 53 | _mm_storeu_si128(((__m128i*)dst) + 3, m3); 54 | } 55 | 56 | static INLINE void _impl_memcpy_sse2_128(void *dst, const void *src) { 57 | __m128i m0 = _mm_loadu_si128(((const __m128i*)src) + 0); 58 | __m128i m1 = _mm_loadu_si128(((const __m128i*)src) + 1); 59 | __m128i m2 = _mm_loadu_si128(((const __m128i*)src) + 2); 60 | __m128i m3 = _mm_loadu_si128(((const __m128i*)src) + 3); 61 | __m128i m4 = _mm_loadu_si128(((const __m128i*)src) + 4); 62 | __m128i m5 = _mm_loadu_si128(((const __m128i*)src) + 5); 63 | __m128i m6 = _mm_loadu_si128(((const __m128i*)src) + 6); 64 | __m128i m7 = _mm_loadu_si128(((const __m128i*)src) + 7); 65 | _mm_storeu_si128(((__m128i*)dst) + 0, m0); 66 | _mm_storeu_si128(((__m128i*)dst) + 1, m1); 67 | _mm_storeu_si128(((__m128i*)dst) + 2, m2); 68 | _mm_storeu_si128(((__m128i*)dst) + 3, m3); 69 | _mm_storeu_si128(((__m128i*)dst) + 4, m4); 70 | _mm_storeu_si128(((__m128i*)dst) + 5, m5); 71 | _mm_storeu_si128(((__m128i*)dst) + 6, m6); 72 | _mm_storeu_si128(((__m128i*)dst) + 7, m7); 73 | } 74 | 75 | //--------------------------------------------------------------------- 76 | // tiny memory copy with jump table optimized 77 | //--------------------------------------------------------------------- 78 | static INLINE void *_impl_memcpy_tiny(void *dst, const void *src, size_t size) { 79 | unsigned char *dd = ((unsigned char*)dst) + size; 80 | const unsigned char *ss = ((const unsigned char*)src) + size; 81 | 82 | switch (size) { 83 | case 64: 84 | _impl_memcpy_sse2_64(dd - 64, ss - 64); 85 | case 0: 86 | break; 87 | 88 | case 65: 89 | _impl_memcpy_sse2_64(dd - 65, ss - 65); 90 | case 1: 91 | dd[-1] = ss[-1]; 92 | break; 93 | 94 | case 66: 95 | _impl_memcpy_sse2_64(dd - 66, ss - 66); 96 | case 2: 97 | *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); 98 | break; 99 | 100 | case 67: 101 | _impl_memcpy_sse2_64(dd - 67, ss - 67); 102 | case 3: 103 | *((uint16_t*)(dd - 3)) = *((uint16_t*)(ss - 3)); 104 | dd[-1] = ss[-1]; 105 | break; 106 | 107 | case 68: 108 | _impl_memcpy_sse2_64(dd - 68, ss - 68); 109 | case 4: 110 | *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); 111 | break; 112 | 113 | case 69: 114 | _impl_memcpy_sse2_64(dd - 69, ss - 69); 115 | case 5: 116 | *((uint32_t*)(dd - 5)) = *((uint32_t*)(ss - 5)); 117 | dd[-1] = ss[-1]; 118 | break; 119 | 120 | case 70: 121 | _impl_memcpy_sse2_64(dd - 70, ss - 70); 122 | case 6: 123 | *((uint32_t*)(dd - 6)) = *((uint32_t*)(ss - 6)); 124 | *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); 125 | break; 126 | 127 | case 71: 128 | _impl_memcpy_sse2_64(dd - 71, ss - 71); 129 | case 7: 130 | *((uint32_t*)(dd - 7)) = *((uint32_t*)(ss - 7)); 131 | *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); 132 | break; 133 | 134 | case 72: 135 | _impl_memcpy_sse2_64(dd - 72, ss - 72); 136 | case 8: 137 | *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); 138 | break; 139 | 140 | case 73: 141 | _impl_memcpy_sse2_64(dd - 73, ss - 73); 142 | case 9: 143 | *((uint64_t*)(dd - 9)) = *((uint64_t*)(ss - 9)); 144 | dd[-1] = ss[-1]; 145 | break; 146 | 147 | case 74: 148 | _impl_memcpy_sse2_64(dd - 74, ss - 74); 149 | case 10: 150 | *((uint64_t*)(dd - 10)) = *((uint64_t*)(ss - 10)); 151 | *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); 152 | break; 153 | 154 | case 75: 155 | _impl_memcpy_sse2_64(dd - 75, ss - 75); 156 | case 11: 157 | *((uint64_t*)(dd - 11)) = *((uint64_t*)(ss - 11)); 158 | *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); 159 | break; 160 | 161 | case 76: 162 | _impl_memcpy_sse2_64(dd - 76, ss - 76); 163 | case 12: 164 | *((uint64_t*)(dd - 12)) = *((uint64_t*)(ss - 12)); 165 | *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); 166 | break; 167 | 168 | case 77: 169 | _impl_memcpy_sse2_64(dd - 77, ss - 77); 170 | case 13: 171 | *((uint64_t*)(dd - 13)) = *((uint64_t*)(ss - 13)); 172 | *((uint32_t*)(dd - 5)) = *((uint32_t*)(ss - 5)); 173 | dd[-1] = ss[-1]; 174 | break; 175 | 176 | case 78: 177 | _impl_memcpy_sse2_64(dd - 78, ss - 78); 178 | case 14: 179 | *((uint64_t*)(dd - 14)) = *((uint64_t*)(ss - 14)); 180 | *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); 181 | break; 182 | 183 | case 79: 184 | _impl_memcpy_sse2_64(dd - 79, ss - 79); 185 | case 15: 186 | *((uint64_t*)(dd - 15)) = *((uint64_t*)(ss - 15)); 187 | *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); 188 | break; 189 | 190 | case 80: 191 | _impl_memcpy_sse2_64(dd - 80, ss - 80); 192 | case 16: 193 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 194 | break; 195 | 196 | case 81: 197 | _impl_memcpy_sse2_64(dd - 81, ss - 81); 198 | case 17: 199 | _impl_memcpy_sse2_16(dd - 17, ss - 17); 200 | dd[-1] = ss[-1]; 201 | break; 202 | 203 | case 82: 204 | _impl_memcpy_sse2_64(dd - 82, ss - 82); 205 | case 18: 206 | _impl_memcpy_sse2_16(dd - 18, ss - 18); 207 | *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); 208 | break; 209 | 210 | case 83: 211 | _impl_memcpy_sse2_64(dd - 83, ss - 83); 212 | case 19: 213 | _impl_memcpy_sse2_16(dd - 19, ss - 19); 214 | *((uint16_t*)(dd - 3)) = *((uint16_t*)(ss - 3)); 215 | dd[-1] = ss[-1]; 216 | break; 217 | 218 | case 84: 219 | _impl_memcpy_sse2_64(dd - 84, ss - 84); 220 | case 20: 221 | _impl_memcpy_sse2_16(dd - 20, ss - 20); 222 | *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); 223 | break; 224 | 225 | case 85: 226 | _impl_memcpy_sse2_64(dd - 85, ss - 85); 227 | case 21: 228 | _impl_memcpy_sse2_16(dd - 21, ss - 21); 229 | *((uint32_t*)(dd - 5)) = *((uint32_t*)(ss - 5)); 230 | dd[-1] = ss[-1]; 231 | break; 232 | 233 | case 86: 234 | _impl_memcpy_sse2_64(dd - 86, ss - 86); 235 | case 22: 236 | _impl_memcpy_sse2_16(dd - 22, ss - 22); 237 | *((uint32_t*)(dd - 6)) = *((uint32_t*)(ss - 6)); 238 | *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); 239 | break; 240 | 241 | case 87: 242 | _impl_memcpy_sse2_64(dd - 87, ss - 87); 243 | case 23: 244 | _impl_memcpy_sse2_16(dd - 23, ss - 23); 245 | *((uint32_t*)(dd - 7)) = *((uint32_t*)(ss - 7)); 246 | *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); 247 | break; 248 | 249 | case 88: 250 | _impl_memcpy_sse2_64(dd - 88, ss - 88); 251 | case 24: 252 | _impl_memcpy_sse2_16(dd - 24, ss - 24); 253 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 254 | break; 255 | 256 | case 89: 257 | _impl_memcpy_sse2_64(dd - 89, ss - 89); 258 | case 25: 259 | _impl_memcpy_sse2_16(dd - 25, ss - 25); 260 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 261 | break; 262 | 263 | case 90: 264 | _impl_memcpy_sse2_64(dd - 90, ss - 90); 265 | case 26: 266 | _impl_memcpy_sse2_16(dd - 26, ss - 26); 267 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 268 | break; 269 | 270 | case 91: 271 | _impl_memcpy_sse2_64(dd - 91, ss - 91); 272 | case 27: 273 | _impl_memcpy_sse2_16(dd - 27, ss - 27); 274 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 275 | break; 276 | 277 | case 92: 278 | _impl_memcpy_sse2_64(dd - 92, ss - 92); 279 | case 28: 280 | _impl_memcpy_sse2_16(dd - 28, ss - 28); 281 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 282 | break; 283 | 284 | case 93: 285 | _impl_memcpy_sse2_64(dd - 93, ss - 93); 286 | case 29: 287 | _impl_memcpy_sse2_16(dd - 29, ss - 29); 288 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 289 | break; 290 | 291 | case 94: 292 | _impl_memcpy_sse2_64(dd - 94, ss - 94); 293 | case 30: 294 | _impl_memcpy_sse2_16(dd - 30, ss - 30); 295 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 296 | break; 297 | 298 | case 95: 299 | _impl_memcpy_sse2_64(dd - 95, ss - 95); 300 | case 31: 301 | _impl_memcpy_sse2_16(dd - 31, ss - 31); 302 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 303 | break; 304 | 305 | case 96: 306 | _impl_memcpy_sse2_64(dd - 96, ss - 96); 307 | case 32: 308 | _impl_memcpy_sse2_32(dd - 32, ss - 32); 309 | break; 310 | 311 | case 97: 312 | _impl_memcpy_sse2_64(dd - 97, ss - 97); 313 | case 33: 314 | _impl_memcpy_sse2_32(dd - 33, ss - 33); 315 | dd[-1] = ss[-1]; 316 | break; 317 | 318 | case 98: 319 | _impl_memcpy_sse2_64(dd - 98, ss - 98); 320 | case 34: 321 | _impl_memcpy_sse2_32(dd - 34, ss - 34); 322 | *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); 323 | break; 324 | 325 | case 99: 326 | _impl_memcpy_sse2_64(dd - 99, ss - 99); 327 | case 35: 328 | _impl_memcpy_sse2_32(dd - 35, ss - 35); 329 | *((uint16_t*)(dd - 3)) = *((uint16_t*)(ss - 3)); 330 | dd[-1] = ss[-1]; 331 | break; 332 | 333 | case 100: 334 | _impl_memcpy_sse2_64(dd - 100, ss - 100); 335 | case 36: 336 | _impl_memcpy_sse2_32(dd - 36, ss - 36); 337 | *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); 338 | break; 339 | 340 | case 101: 341 | _impl_memcpy_sse2_64(dd - 101, ss - 101); 342 | case 37: 343 | _impl_memcpy_sse2_32(dd - 37, ss - 37); 344 | *((uint32_t*)(dd - 5)) = *((uint32_t*)(ss - 5)); 345 | dd[-1] = ss[-1]; 346 | break; 347 | 348 | case 102: 349 | _impl_memcpy_sse2_64(dd - 102, ss - 102); 350 | case 38: 351 | _impl_memcpy_sse2_32(dd - 38, ss - 38); 352 | *((uint32_t*)(dd - 6)) = *((uint32_t*)(ss - 6)); 353 | *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); 354 | break; 355 | 356 | case 103: 357 | _impl_memcpy_sse2_64(dd - 103, ss - 103); 358 | case 39: 359 | _impl_memcpy_sse2_32(dd - 39, ss - 39); 360 | *((uint32_t*)(dd - 7)) = *((uint32_t*)(ss - 7)); 361 | *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); 362 | break; 363 | 364 | case 104: 365 | _impl_memcpy_sse2_64(dd - 104, ss - 104); 366 | case 40: 367 | _impl_memcpy_sse2_32(dd - 40, ss - 40); 368 | *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); 369 | break; 370 | 371 | case 105: 372 | _impl_memcpy_sse2_64(dd - 105, ss - 105); 373 | case 41: 374 | _impl_memcpy_sse2_32(dd - 41, ss - 41); 375 | *((uint64_t*)(dd - 9)) = *((uint64_t*)(ss - 9)); 376 | dd[-1] = ss[-1]; 377 | break; 378 | 379 | case 106: 380 | _impl_memcpy_sse2_64(dd - 106, ss - 106); 381 | case 42: 382 | _impl_memcpy_sse2_32(dd - 42, ss - 42); 383 | *((uint64_t*)(dd - 10)) = *((uint64_t*)(ss - 10)); 384 | *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); 385 | break; 386 | 387 | case 107: 388 | _impl_memcpy_sse2_64(dd - 107, ss - 107); 389 | case 43: 390 | _impl_memcpy_sse2_32(dd - 43, ss - 43); 391 | *((uint64_t*)(dd - 11)) = *((uint64_t*)(ss - 11)); 392 | *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); 393 | break; 394 | 395 | case 108: 396 | _impl_memcpy_sse2_64(dd - 108, ss - 108); 397 | case 44: 398 | _impl_memcpy_sse2_32(dd - 44, ss - 44); 399 | *((uint64_t*)(dd - 12)) = *((uint64_t*)(ss - 12)); 400 | *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); 401 | break; 402 | 403 | case 109: 404 | _impl_memcpy_sse2_64(dd - 109, ss - 109); 405 | case 45: 406 | _impl_memcpy_sse2_32(dd - 45, ss - 45); 407 | *((uint64_t*)(dd - 13)) = *((uint64_t*)(ss - 13)); 408 | *((uint32_t*)(dd - 5)) = *((uint32_t*)(ss - 5)); 409 | dd[-1] = ss[-1]; 410 | break; 411 | 412 | case 110: 413 | _impl_memcpy_sse2_64(dd - 110, ss - 110); 414 | case 46: 415 | _impl_memcpy_sse2_32(dd - 46, ss - 46); 416 | *((uint64_t*)(dd - 14)) = *((uint64_t*)(ss - 14)); 417 | *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); 418 | break; 419 | 420 | case 111: 421 | _impl_memcpy_sse2_64(dd - 111, ss - 111); 422 | case 47: 423 | _impl_memcpy_sse2_32(dd - 47, ss - 47); 424 | *((uint64_t*)(dd - 15)) = *((uint64_t*)(ss - 15)); 425 | *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); 426 | break; 427 | 428 | case 112: 429 | _impl_memcpy_sse2_64(dd - 112, ss - 112); 430 | case 48: 431 | _impl_memcpy_sse2_32(dd - 48, ss - 48); 432 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 433 | break; 434 | 435 | case 113: 436 | _impl_memcpy_sse2_64(dd - 113, ss - 113); 437 | case 49: 438 | _impl_memcpy_sse2_32(dd - 49, ss - 49); 439 | _impl_memcpy_sse2_16(dd - 17, ss - 17); 440 | dd[-1] = ss[-1]; 441 | break; 442 | 443 | case 114: 444 | _impl_memcpy_sse2_64(dd - 114, ss - 114); 445 | case 50: 446 | _impl_memcpy_sse2_32(dd - 50, ss - 50); 447 | _impl_memcpy_sse2_16(dd - 18, ss - 18); 448 | *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); 449 | break; 450 | 451 | case 115: 452 | _impl_memcpy_sse2_64(dd - 115, ss - 115); 453 | case 51: 454 | _impl_memcpy_sse2_32(dd - 51, ss - 51); 455 | _impl_memcpy_sse2_16(dd - 19, ss - 19); 456 | *((uint16_t*)(dd - 3)) = *((uint16_t*)(ss - 3)); 457 | dd[-1] = ss[-1]; 458 | break; 459 | 460 | case 116: 461 | _impl_memcpy_sse2_64(dd - 116, ss - 116); 462 | case 52: 463 | _impl_memcpy_sse2_32(dd - 52, ss - 52); 464 | _impl_memcpy_sse2_16(dd - 20, ss - 20); 465 | *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); 466 | break; 467 | 468 | case 117: 469 | _impl_memcpy_sse2_64(dd - 117, ss - 117); 470 | case 53: 471 | _impl_memcpy_sse2_32(dd - 53, ss - 53); 472 | _impl_memcpy_sse2_16(dd - 21, ss - 21); 473 | *((uint32_t*)(dd - 5)) = *((uint32_t*)(ss - 5)); 474 | dd[-1] = ss[-1]; 475 | break; 476 | 477 | case 118: 478 | _impl_memcpy_sse2_64(dd - 118, ss - 118); 479 | case 54: 480 | _impl_memcpy_sse2_32(dd - 54, ss - 54); 481 | _impl_memcpy_sse2_16(dd - 22, ss - 22); 482 | *((uint32_t*)(dd - 6)) = *((uint32_t*)(ss - 6)); 483 | *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); 484 | break; 485 | 486 | case 119: 487 | _impl_memcpy_sse2_64(dd - 119, ss - 119); 488 | case 55: 489 | _impl_memcpy_sse2_32(dd - 55, ss - 55); 490 | _impl_memcpy_sse2_16(dd - 23, ss - 23); 491 | *((uint32_t*)(dd - 7)) = *((uint32_t*)(ss - 7)); 492 | *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); 493 | break; 494 | 495 | case 120: 496 | _impl_memcpy_sse2_64(dd - 120, ss - 120); 497 | case 56: 498 | _impl_memcpy_sse2_32(dd - 56, ss - 56); 499 | _impl_memcpy_sse2_16(dd - 24, ss - 24); 500 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 501 | break; 502 | 503 | case 121: 504 | _impl_memcpy_sse2_64(dd - 121, ss - 121); 505 | case 57: 506 | _impl_memcpy_sse2_32(dd - 57, ss - 57); 507 | _impl_memcpy_sse2_16(dd - 25, ss - 25); 508 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 509 | break; 510 | 511 | case 122: 512 | _impl_memcpy_sse2_64(dd - 122, ss - 122); 513 | case 58: 514 | _impl_memcpy_sse2_32(dd - 58, ss - 58); 515 | _impl_memcpy_sse2_16(dd - 26, ss - 26); 516 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 517 | break; 518 | 519 | case 123: 520 | _impl_memcpy_sse2_64(dd - 123, ss - 123); 521 | case 59: 522 | _impl_memcpy_sse2_32(dd - 59, ss - 59); 523 | _impl_memcpy_sse2_16(dd - 27, ss - 27); 524 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 525 | break; 526 | 527 | case 124: 528 | _impl_memcpy_sse2_64(dd - 124, ss - 124); 529 | case 60: 530 | _impl_memcpy_sse2_32(dd - 60, ss - 60); 531 | _impl_memcpy_sse2_16(dd - 28, ss - 28); 532 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 533 | break; 534 | 535 | case 125: 536 | _impl_memcpy_sse2_64(dd - 125, ss - 125); 537 | case 61: 538 | _impl_memcpy_sse2_32(dd - 61, ss - 61); 539 | _impl_memcpy_sse2_16(dd - 29, ss - 29); 540 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 541 | break; 542 | 543 | case 126: 544 | _impl_memcpy_sse2_64(dd - 126, ss - 126); 545 | case 62: 546 | _impl_memcpy_sse2_32(dd - 62, ss - 62); 547 | _impl_memcpy_sse2_16(dd - 30, ss - 30); 548 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 549 | break; 550 | 551 | case 127: 552 | _impl_memcpy_sse2_64(dd - 127, ss - 127); 553 | case 63: 554 | _impl_memcpy_sse2_32(dd - 63, ss - 63); 555 | _impl_memcpy_sse2_16(dd - 31, ss - 31); 556 | _impl_memcpy_sse2_16(dd - 16, ss - 16); 557 | break; 558 | 559 | case 128: 560 | _impl_memcpy_sse2_128(dd - 128, ss - 128); 561 | break; 562 | } 563 | 564 | return dst; 565 | } 566 | 567 | //--------------------------------------------------------------------- 568 | // main routine 569 | //--------------------------------------------------------------------- 570 | inline void* fast_memcpy(void *destination, const void *source, size_t size) 571 | { 572 | unsigned char *dst = (unsigned char*)destination; 573 | const unsigned char *src = (const unsigned char*)source; 574 | static size_t cachesize = 0x200000; // L2-cache size 575 | size_t padding; 576 | if (size == 0) 577 | return destination; 578 | // small memory copy 579 | if (size <= 128) { 580 | return _impl_memcpy_tiny(dst, src, size); 581 | } 582 | 583 | // align destination to 16 bytes boundary 584 | padding = (16 - (((size_t)dst) & 15)) & 15; 585 | 586 | if (padding > 0) { 587 | __m128i head = _mm_loadu_si128((const __m128i*)src); 588 | _mm_storeu_si128((__m128i*)dst, head); 589 | dst += padding; 590 | src += padding; 591 | size -= padding; 592 | } 593 | 594 | // medium size copy 595 | if (size <= cachesize) { 596 | __m128i c0, c1, c2, c3, c4, c5, c6, c7; 597 | 598 | for (; size >= 128; size -= 128) { 599 | c0 = _mm_loadu_si128(((const __m128i*)src) + 0); 600 | c1 = _mm_loadu_si128(((const __m128i*)src) + 1); 601 | c2 = _mm_loadu_si128(((const __m128i*)src) + 2); 602 | c3 = _mm_loadu_si128(((const __m128i*)src) + 3); 603 | c4 = _mm_loadu_si128(((const __m128i*)src) + 4); 604 | c5 = _mm_loadu_si128(((const __m128i*)src) + 5); 605 | c6 = _mm_loadu_si128(((const __m128i*)src) + 6); 606 | c7 = _mm_loadu_si128(((const __m128i*)src) + 7); 607 | _mm_prefetch((const char*)(src + 256), _MM_HINT_NTA); 608 | src += 128; 609 | _mm_store_si128((((__m128i*)dst) + 0), c0); 610 | _mm_store_si128((((__m128i*)dst) + 1), c1); 611 | _mm_store_si128((((__m128i*)dst) + 2), c2); 612 | _mm_store_si128((((__m128i*)dst) + 3), c3); 613 | _mm_store_si128((((__m128i*)dst) + 4), c4); 614 | _mm_store_si128((((__m128i*)dst) + 5), c5); 615 | _mm_store_si128((((__m128i*)dst) + 6), c6); 616 | _mm_store_si128((((__m128i*)dst) + 7), c7); 617 | dst += 128; 618 | } 619 | } 620 | else { // big memory copy 621 | __m128i c0, c1, c2, c3, c4, c5, c6, c7; 622 | 623 | _mm_prefetch((const char*)(src), _MM_HINT_NTA); 624 | 625 | if ((((size_t)src) & 15) == 0) { // source aligned 626 | for (; size >= 128; size -= 128) { 627 | c0 = _mm_load_si128(((const __m128i*)src) + 0); 628 | c1 = _mm_load_si128(((const __m128i*)src) + 1); 629 | c2 = _mm_load_si128(((const __m128i*)src) + 2); 630 | c3 = _mm_load_si128(((const __m128i*)src) + 3); 631 | c4 = _mm_load_si128(((const __m128i*)src) + 4); 632 | c5 = _mm_load_si128(((const __m128i*)src) + 5); 633 | c6 = _mm_load_si128(((const __m128i*)src) + 6); 634 | c7 = _mm_load_si128(((const __m128i*)src) + 7); 635 | _mm_prefetch((const char*)(src + 256), _MM_HINT_NTA); 636 | src += 128; 637 | _mm_stream_si128((((__m128i*)dst) + 0), c0); 638 | _mm_stream_si128((((__m128i*)dst) + 1), c1); 639 | _mm_stream_si128((((__m128i*)dst) + 2), c2); 640 | _mm_stream_si128((((__m128i*)dst) + 3), c3); 641 | _mm_stream_si128((((__m128i*)dst) + 4), c4); 642 | _mm_stream_si128((((__m128i*)dst) + 5), c5); 643 | _mm_stream_si128((((__m128i*)dst) + 6), c6); 644 | _mm_stream_si128((((__m128i*)dst) + 7), c7); 645 | dst += 128; 646 | } 647 | } 648 | else { // source unaligned 649 | for (; size >= 128; size -= 128) { 650 | c0 = _mm_loadu_si128(((const __m128i*)src) + 0); 651 | c1 = _mm_loadu_si128(((const __m128i*)src) + 1); 652 | c2 = _mm_loadu_si128(((const __m128i*)src) + 2); 653 | c3 = _mm_loadu_si128(((const __m128i*)src) + 3); 654 | c4 = _mm_loadu_si128(((const __m128i*)src) + 4); 655 | c5 = _mm_loadu_si128(((const __m128i*)src) + 5); 656 | c6 = _mm_loadu_si128(((const __m128i*)src) + 6); 657 | c7 = _mm_loadu_si128(((const __m128i*)src) + 7); 658 | _mm_prefetch((const char*)(src + 256), _MM_HINT_NTA); 659 | src += 128; 660 | _mm_stream_si128((((__m128i*)dst) + 0), c0); 661 | _mm_stream_si128((((__m128i*)dst) + 1), c1); 662 | _mm_stream_si128((((__m128i*)dst) + 2), c2); 663 | _mm_stream_si128((((__m128i*)dst) + 3), c3); 664 | _mm_stream_si128((((__m128i*)dst) + 4), c4); 665 | _mm_stream_si128((((__m128i*)dst) + 5), c5); 666 | _mm_stream_si128((((__m128i*)dst) + 6), c6); 667 | _mm_stream_si128((((__m128i*)dst) + 7), c7); 668 | dst += 128; 669 | } 670 | } 671 | _mm_sfence(); 672 | } 673 | 674 | _impl_memcpy_tiny(dst, src, size); 675 | 676 | return destination; 677 | } 678 | 679 | 680 | #endif --------------------------------------------------------------------------------