From e02b542ffdc0877981764e6d9cf564bc5abdbdef Mon Sep 17 00:00:00 2001 From: Duc Date: Thu, 13 Mar 2025 18:30:39 -0700 Subject: [PATCH] Initial check-in --- .gitattributes | 63 ++ .gitignore | 377 ++++++- CommonLib/CommonLib.sln | 31 + CommonLib/CommonLib.vcxproj | 262 +++++ CommonLib/CommonLib.vcxproj.filters | 270 +++++ CommonLib/config/config.ini | 1 + .../AutomationMsgHandler.cpp | 88 ++ .../AutomationMsgHandler.hpp | 76 ++ .../AutomationMsgParser.cpp | 151 +++ .../AutomationMsgParser.hpp | 78 ++ .../AutomationMessages/GenericRspMessage.cpp | 104 ++ .../AutomationMessages/GenericRspMessage.hpp | 122 +++ .../AutomationMessages/KwScenarioStarted.cpp | 81 ++ .../AutomationMessages/KwScenarioStarted.hpp | 103 ++ .../AutomationMessages/KwScenarioStopped.cpp | 101 ++ .../AutomationMessages/KwScenarioStopped.hpp | 105 ++ .../src/Common/AutomationMessages/Message.cpp | 169 +++ .../src/Common/AutomationMessages/Message.hpp | 242 +++++ .../AutomationMessages/MessageHeader.cpp | 87 ++ .../AutomationMessages/MessageHeader.hpp | 145 +++ .../Common/AutomationMessages/MessageIDs.hpp | 19 + .../MoveGutsVideosToSubFolderCmdMessage.cpp | 99 ++ .../MoveGutsVideosToSubFolderCmdMessage.hpp | 104 ++ .../TransferAFileCmdMessage.cpp | 121 +++ .../TransferAFileCmdMessage.hpp | 108 ++ .../TransferGutsVideosCmdMessage.cpp | 118 +++ .../TransferGutsVideosCmdMessage.hpp | 126 +++ .../WaitForLastTaskCompletionCmdMessage.cpp | 73 ++ .../WaitForLastTaskCompletionCmdMessage.hpp | 105 ++ CommonLib/src/Common/Comm/Socket.cpp | 396 +++++++ CommonLib/src/Common/Comm/Socket.hpp | 298 ++++++ CommonLib/src/Common/Comm/TCPSocket.cpp | 974 ++++++++++++++++++ CommonLib/src/Common/Comm/TCPSocket.hpp | 231 +++++ CommonLib/src/Common/Comm/UDPSocket.cpp | 412 ++++++++ CommonLib/src/Common/Comm/UDPSocket.hpp | 128 +++ CommonLib/src/Common/Exceptions/Exception.cpp | 110 ++ CommonLib/src/Common/Exceptions/Exception.hpp | 135 +++ .../src/Common/Exceptions/TimeoutError.cpp | 16 + .../src/Common/Exceptions/TimeoutError.hpp | 37 + CommonLib/src/Common/Lib/CRC32.cpp | 86 ++ CommonLib/src/Common/Lib/CRC32.h | 35 + CommonLib/src/Common/Lib/CustomDataTypes.hpp | 30 + CommonLib/src/Common/Lib/ErrorLog.cpp | 92 ++ CommonLib/src/Common/Lib/ErrorLog.hpp | 37 + CommonLib/src/Common/Lib/IniFile.cpp | 510 +++++++++ CommonLib/src/Common/Lib/IniFile.hpp | 286 +++++ CommonLib/src/Common/Lib/LockMutex.cpp | 28 + CommonLib/src/Common/Lib/LockMutex.hpp | 43 + CommonLib/src/Common/Lib/NTEvent.cpp | 155 +++ CommonLib/src/Common/Lib/NTEvent.hpp | 108 ++ CommonLib/src/Common/Lib/NTMutex.cpp | 100 ++ CommonLib/src/Common/Lib/NTMutex.hpp | 85 ++ CommonLib/src/Common/Lib/NTSemaphore.cpp | 60 ++ CommonLib/src/Common/Lib/NTSemaphore.hpp | 71 ++ CommonLib/src/Common/Lib/OSObject.cpp | 20 + CommonLib/src/Common/Lib/OSObject.hpp | 48 + CommonLib/src/Common/Lib/Thread.cpp | 116 +++ CommonLib/src/Common/Lib/Thread.hpp | 124 +++ CommonLib/src/Common/Lib/Timestamp.cpp | 83 ++ CommonLib/src/Common/Lib/Timestamp.hpp | 105 ++ .../src/Common/Lib/Util/FileSystemUtil.cpp | 457 ++++++++ .../src/Common/Lib/Util/FileSystemUtil.hpp | 158 +++ CommonLib/src/Common/Lib/Util/MiscUtil.cpp | 44 + CommonLib/src/Common/Lib/Util/MiscUtil.hpp | 25 + CommonLib/src/Common/Lib/Util/NetworkUtil.cpp | 80 ++ CommonLib/src/Common/Lib/Util/NetworkUtil.hpp | 35 + CommonLib/src/Common/Lib/Util/StringUtil.cpp | 310 ++++++ CommonLib/src/Common/Lib/Util/StringUtil.hpp | 156 +++ CommonLib/src/Common/Names/EventNames.cpp | 42 + CommonLib/src/Common/Names/EventNames.hpp | 30 + CommonLib/src/Common/Names/MailboxNames.cpp | 38 + CommonLib/src/Common/Names/MailboxNames.hpp | 27 + CommonLib/src/Common/Names/SemaphoreNames.cpp | 38 + CommonLib/src/Common/Names/SemaphoreNames.hpp | 28 + CommonLib/src/Common/Names/ThreadNames.cpp | 42 + CommonLib/src/Common/Names/ThreadNames.hpp | 29 + CommonLib/src/Common/Proc/Proc.cpp | 105 ++ CommonLib/src/Common/Proc/Proc.hpp | 74 ++ CommonLib/src/WinProc.cpp | 67 ++ CommonLib/src/WinProc.hpp | 60 ++ CommonLib/src/main.cpp | 16 + 81 files changed, 10329 insertions(+), 20 deletions(-) create mode 100644 .gitattributes create mode 100644 CommonLib/CommonLib.sln create mode 100644 CommonLib/CommonLib.vcxproj create mode 100644 CommonLib/CommonLib.vcxproj.filters create mode 100644 CommonLib/config/config.ini create mode 100644 CommonLib/src/Common/AutomationMessages/AutomationMsgHandler.cpp create mode 100644 CommonLib/src/Common/AutomationMessages/AutomationMsgHandler.hpp create mode 100644 CommonLib/src/Common/AutomationMessages/AutomationMsgParser.cpp create mode 100644 CommonLib/src/Common/AutomationMessages/AutomationMsgParser.hpp create mode 100644 CommonLib/src/Common/AutomationMessages/GenericRspMessage.cpp create mode 100644 CommonLib/src/Common/AutomationMessages/GenericRspMessage.hpp create mode 100644 CommonLib/src/Common/AutomationMessages/KwScenarioStarted.cpp create mode 100644 CommonLib/src/Common/AutomationMessages/KwScenarioStarted.hpp create mode 100644 CommonLib/src/Common/AutomationMessages/KwScenarioStopped.cpp create mode 100644 CommonLib/src/Common/AutomationMessages/KwScenarioStopped.hpp create mode 100644 CommonLib/src/Common/AutomationMessages/Message.cpp create mode 100644 CommonLib/src/Common/AutomationMessages/Message.hpp create mode 100644 CommonLib/src/Common/AutomationMessages/MessageHeader.cpp create mode 100644 CommonLib/src/Common/AutomationMessages/MessageHeader.hpp create mode 100644 CommonLib/src/Common/AutomationMessages/MessageIDs.hpp create mode 100644 CommonLib/src/Common/AutomationMessages/MoveGutsVideosToSubFolderCmdMessage.cpp create mode 100644 CommonLib/src/Common/AutomationMessages/MoveGutsVideosToSubFolderCmdMessage.hpp create mode 100644 CommonLib/src/Common/AutomationMessages/TransferAFileCmdMessage.cpp create mode 100644 CommonLib/src/Common/AutomationMessages/TransferAFileCmdMessage.hpp create mode 100644 CommonLib/src/Common/AutomationMessages/TransferGutsVideosCmdMessage.cpp create mode 100644 CommonLib/src/Common/AutomationMessages/TransferGutsVideosCmdMessage.hpp create mode 100644 CommonLib/src/Common/AutomationMessages/WaitForLastTaskCompletionCmdMessage.cpp create mode 100644 CommonLib/src/Common/AutomationMessages/WaitForLastTaskCompletionCmdMessage.hpp create mode 100644 CommonLib/src/Common/Comm/Socket.cpp create mode 100644 CommonLib/src/Common/Comm/Socket.hpp create mode 100644 CommonLib/src/Common/Comm/TCPSocket.cpp create mode 100644 CommonLib/src/Common/Comm/TCPSocket.hpp create mode 100644 CommonLib/src/Common/Comm/UDPSocket.cpp create mode 100644 CommonLib/src/Common/Comm/UDPSocket.hpp create mode 100644 CommonLib/src/Common/Exceptions/Exception.cpp create mode 100644 CommonLib/src/Common/Exceptions/Exception.hpp create mode 100644 CommonLib/src/Common/Exceptions/TimeoutError.cpp create mode 100644 CommonLib/src/Common/Exceptions/TimeoutError.hpp create mode 100644 CommonLib/src/Common/Lib/CRC32.cpp create mode 100644 CommonLib/src/Common/Lib/CRC32.h create mode 100644 CommonLib/src/Common/Lib/CustomDataTypes.hpp create mode 100644 CommonLib/src/Common/Lib/ErrorLog.cpp create mode 100644 CommonLib/src/Common/Lib/ErrorLog.hpp create mode 100644 CommonLib/src/Common/Lib/IniFile.cpp create mode 100644 CommonLib/src/Common/Lib/IniFile.hpp create mode 100644 CommonLib/src/Common/Lib/LockMutex.cpp create mode 100644 CommonLib/src/Common/Lib/LockMutex.hpp create mode 100644 CommonLib/src/Common/Lib/NTEvent.cpp create mode 100644 CommonLib/src/Common/Lib/NTEvent.hpp create mode 100644 CommonLib/src/Common/Lib/NTMutex.cpp create mode 100644 CommonLib/src/Common/Lib/NTMutex.hpp create mode 100644 CommonLib/src/Common/Lib/NTSemaphore.cpp create mode 100644 CommonLib/src/Common/Lib/NTSemaphore.hpp create mode 100644 CommonLib/src/Common/Lib/OSObject.cpp create mode 100644 CommonLib/src/Common/Lib/OSObject.hpp create mode 100644 CommonLib/src/Common/Lib/Thread.cpp create mode 100644 CommonLib/src/Common/Lib/Thread.hpp create mode 100644 CommonLib/src/Common/Lib/Timestamp.cpp create mode 100644 CommonLib/src/Common/Lib/Timestamp.hpp create mode 100644 CommonLib/src/Common/Lib/Util/FileSystemUtil.cpp create mode 100644 CommonLib/src/Common/Lib/Util/FileSystemUtil.hpp create mode 100644 CommonLib/src/Common/Lib/Util/MiscUtil.cpp create mode 100644 CommonLib/src/Common/Lib/Util/MiscUtil.hpp create mode 100644 CommonLib/src/Common/Lib/Util/NetworkUtil.cpp create mode 100644 CommonLib/src/Common/Lib/Util/NetworkUtil.hpp create mode 100644 CommonLib/src/Common/Lib/Util/StringUtil.cpp create mode 100644 CommonLib/src/Common/Lib/Util/StringUtil.hpp create mode 100644 CommonLib/src/Common/Names/EventNames.cpp create mode 100644 CommonLib/src/Common/Names/EventNames.hpp create mode 100644 CommonLib/src/Common/Names/MailboxNames.cpp create mode 100644 CommonLib/src/Common/Names/MailboxNames.hpp create mode 100644 CommonLib/src/Common/Names/SemaphoreNames.cpp create mode 100644 CommonLib/src/Common/Names/SemaphoreNames.hpp create mode 100644 CommonLib/src/Common/Names/ThreadNames.cpp create mode 100644 CommonLib/src/Common/Names/ThreadNames.hpp create mode 100644 CommonLib/src/Common/Proc/Proc.cpp create mode 100644 CommonLib/src/Common/Proc/Proc.hpp create mode 100644 CommonLib/src/WinProc.cpp create mode 100644 CommonLib/src/WinProc.hpp create mode 100644 CommonLib/src/main.cpp diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore index 7f91721..9491a2f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,26 +1,363 @@ -# ---> Windows -# Windows thumbnail cache files -Thumbs.db -Thumbs.db:encryptable -ehthumbs.db -ehthumbs_vista.db +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore -# Dump file -*.stackdump +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates -# Folder config file -[Dd]esktop.ini +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs -# Recycle Bin used on file shares -$RECYCLE.BIN/ +# Mono auto generated files +mono_crash.* -# Windows Installer files -*.cab -*.msi -*.msix -*.msm -*.msp +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ -# Windows shortcuts -*.lnk +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/CommonLib/CommonLib.sln b/CommonLib/CommonLib.sln new file mode 100644 index 0000000..6454652 --- /dev/null +++ b/CommonLib/CommonLib.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.33920.266 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonLib", "CommonLib.vcxproj", "{29F772A1-F693-4804-9DDD-211AA902451D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {29F772A1-F693-4804-9DDD-211AA902451D}.Debug|x64.ActiveCfg = Debug|x64 + {29F772A1-F693-4804-9DDD-211AA902451D}.Debug|x64.Build.0 = Debug|x64 + {29F772A1-F693-4804-9DDD-211AA902451D}.Debug|x86.ActiveCfg = Debug|Win32 + {29F772A1-F693-4804-9DDD-211AA902451D}.Debug|x86.Build.0 = Debug|Win32 + {29F772A1-F693-4804-9DDD-211AA902451D}.Release|x64.ActiveCfg = Release|x64 + {29F772A1-F693-4804-9DDD-211AA902451D}.Release|x64.Build.0 = Release|x64 + {29F772A1-F693-4804-9DDD-211AA902451D}.Release|x86.ActiveCfg = Release|Win32 + {29F772A1-F693-4804-9DDD-211AA902451D}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0504EF5F-F11C-4C98-A228-D90488A6B55E} + EndGlobalSection +EndGlobal diff --git a/CommonLib/CommonLib.vcxproj b/CommonLib/CommonLib.vcxproj new file mode 100644 index 0000000..5bd5333 --- /dev/null +++ b/CommonLib/CommonLib.vcxproj @@ -0,0 +1,262 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16.0 + Win32Proj + {29f772a1-f693-4804-9ddd-211aa902451d} + CommonLib + 10.0 + + + + Application + true + v143 + MultiByte + + + Application + false + v143 + true + MultiByte + + + Application + true + v143 + MultiByte + + + Application + false + v143 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)_$(PlatformTarget)\$(Configuration)\bin\ + $(ProjectDir)_$(PlatformTarget)\$(Configuration)\obj\ + + + false + $(ProjectDir)_$(PlatformTarget)\$(Configuration)\bin\ + $(ProjectDir)_$(PlatformTarget)\$(Configuration)\obj\ + + + true + $(ProjectDir)_$(PlatformTarget)\$(Configuration)\bin\ + $(ProjectDir)_$(PlatformTarget)\$(Configuration)\obj\ + + + false + $(ProjectDir)_$(PlatformTarget)\$(Configuration)\bin\ + $(ProjectDir)_$(PlatformTarget)\$(Configuration)\obj\ + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\src\Common\AutomationMessages;.\src\Common\Lib;.\src\Common\Lib\Util;.\src\Common\Names;.\src\Common\Exceptions;.\src\Common\Proc + /MP /D "__FUNCTION_NAME__=__FUNCTION__\"()\"" %(AdditionalOptions) + 26812 + stdcpp17 + + + Console + true + Rpcrt4.lib;Shlwapi.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) + + + xcopy /y ".\config\config.ini" "$(OutDir)config.ini*" + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + .\src\Common\AutomationMessages;.\src\Common\Lib;.\src\Common\Lib\Util;.\src\Common\Names;.\src\Common\Exceptions;.\src\Common\Proc + /MP /D "__FUNCTION_NAME__=__FUNCTION__\"()\"" %(AdditionalOptions) + + + Console + true + true + true + Rpcrt4.lib;Shlwapi.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) + + + xcopy /y ".\config\config.ini" "$(OutDir)config.ini*" + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\src\Common\AutomationMessages;.\src\Common\Lib;.\src\Common\Lib\Util;.\src\Common\Names;.\src\Common\Exceptions;.\src\Common\Proc + /MP /D "__FUNCTION_NAME__=__FUNCTION__\"()\"" %(AdditionalOptions) + 26812;4267 + stdcpp17 + + + Console + true + Rpcrt4.lib;Shlwapi.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) + + + xcopy /y ".\config\config.ini" "$(OutDir)config.ini*" + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\src\Common\AutomationMessages;.\src\Common\Lib;.\src\Common\Lib\Util;.\src\Common\Names;.\src\Common\Exceptions;.\src\Common\Proc + /MP /D "__FUNCTION_NAME__=__FUNCTION__\"()\"" %(AdditionalOptions) + stdcpp17 + 4267 + + + Console + true + true + true + Rpcrt4.lib;Shlwapi.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) + + + xcopy /y ".\config\config.ini" "$(OutDir)config.ini*" + + + + + + \ No newline at end of file diff --git a/CommonLib/CommonLib.vcxproj.filters b/CommonLib/CommonLib.vcxproj.filters new file mode 100644 index 0000000..5825fcc --- /dev/null +++ b/CommonLib/CommonLib.vcxproj.filters @@ -0,0 +1,270 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {f8545ab1-ebd0-4011-be56-f7c33a7a8b71} + + + {c2763a6d-85aa-4bac-bfd6-6f639734a531} + + + {050e83d9-5165-4663-8a4e-5953c906a8ac} + + + {7e5b443c-1486-4a8e-8214-c9b6a7970abf} + + + {46890769-d7b8-479a-9246-e8807e759e63} + + + {9e88fca6-0de6-4a9d-92b8-049a32b742d0} + + + {b0fd71c4-06e4-439a-8bab-22c9a294c0ce} + + + {fac5f9f9-e7b2-4311-8a37-7dac79755e0f} + + + + + Source Files + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\Exceptions + + + Source Files\Common\Exceptions + + + Source Files\Common\Lib\Util + + + Source Files\Common\Lib\Util + + + Source Files\Common\Lib\Util + + + Source Files\Common\Lib\Util + + + Source Files\Common\Names + + + Source Files\Common\Names + + + Source Files\Common\Names + + + Source Files\Common\Names + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Proc + + + Source Files\Common\Comm + + + Source Files\Common\Comm + + + Source Files\Common\Comm + + + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\AutomationMessages + + + Source Files\Common\Exceptions + + + Source Files\Common\Exceptions + + + Source Files\Common\Lib\Util + + + Source Files\Common\Lib\Util + + + Source Files\Common\Lib\Util + + + Source Files\Common\Lib\Util + + + Source Files\Common\Names + + + Source Files\Common\Names + + + Source Files\Common\Names + + + Source Files\Common\Names + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Lib + + + Source Files\Common\Proc + + + Source Files\Common\Comm + + + Source Files\Common\Comm + + + Source Files\Common\Comm + + + \ No newline at end of file diff --git a/CommonLib/config/config.ini b/CommonLib/config/config.ini new file mode 100644 index 0000000..fa1a90b --- /dev/null +++ b/CommonLib/config/config.ini @@ -0,0 +1 @@ +[GENERAL] \ No newline at end of file diff --git a/CommonLib/src/Common/AutomationMessages/AutomationMsgHandler.cpp b/CommonLib/src/Common/AutomationMessages/AutomationMsgHandler.cpp new file mode 100644 index 0000000..c107d3f --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/AutomationMsgHandler.cpp @@ -0,0 +1,88 @@ +#include +#include + +#include "AutomationMsgHandler.hpp" +#include "Exception.hpp" +#include "MessageHeader.hpp" +#include "MessageIDs.hpp" +#include "TransferGutsVideosCmdMessage.hpp" +#include "TransferAFileCmdMessage.hpp" +//----------------------------------------------------------------------------- + +AutomationMsgHandler::AutomationMsgHandler() +{ +} + +//----------------------------------------------------------------------------- + +AutomationMsgHandler::~AutomationMsgHandler(){} + +//----------------------------------------------------------------------------- + +AutomationMsgHandler& AutomationMsgHandler::instance() +{ + static AutomationMsgHandler handler; + return handler; +} + +//----------------------------------------------------------------------------- + +void AutomationMsgHandler::handleMsg(const unsigned char* pData, const unsigned int& id) +{ + try + { + MessageIDs::MsgIds msgId = (MessageIDs::MsgIds)id; + + if (msgId == MessageIDs::SCENARIO_STARTED_CMD) + { + HandleKwScenarioStartedMessage(pData); + } + else if (msgId == MessageIDs::SCENARIO_STOPPED_CMD) + { + HandleKwScenarioStoppedMessage(pData); + } + else + { + std::stringstream ss; + ss << "unknown message id: " << id; + + throw Exception (__FUNCTION_NAME__, ss.str()); + } + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + + throw e; + } +} + +//----------------------------------------------------------------------------- + +void AutomationMsgHandler::HandleKwScenarioStartedMessage(const unsigned char* pData) +{ + try { + + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + + throw e; + } +} + +//----------------------------------------------------------------------------- + +void AutomationMsgHandler::HandleKwScenarioStoppedMessage(const unsigned char* pData) +{ + try { + + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + + throw e; + } +} diff --git a/CommonLib/src/Common/AutomationMessages/AutomationMsgHandler.hpp b/CommonLib/src/Common/AutomationMessages/AutomationMsgHandler.hpp new file mode 100644 index 0000000..f16c2c8 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/AutomationMsgHandler.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include "MessageIDs.hpp" +#include + +class AutomationMsgHandler +{ +public: + //>--------------------------------------------------------------------------- + // Function: instance + // + // Purpose: singleton + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + static AutomationMsgHandler& instance(); + + //>--------------------------------------------------------------------------- + // Function: ~Proc + // + // Purpose: Destroyer + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + ~AutomationMsgHandler(); + + //>--------------------------------------------------------------------------- + // Function: parseMsg + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + void handleMsg(const unsigned char* pData, const unsigned int& id); + + private: + //>--------------------------------------------------------------------------- + // Function: AutomationMsgHandler + // + // Purpose: Ctor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + AutomationMsgHandler(); + + //>--------------------------------------------------------------------------- + // Function: HandleKwScenarioStartedMessage + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + void HandleKwScenarioStartedMessage(const unsigned char* pData); + + //>--------------------------------------------------------------------------- + // Function: HandleKwScenarioStoppedMessage + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + void HandleKwScenarioStoppedMessage(const unsigned char* pData); +}; + diff --git a/CommonLib/src/Common/AutomationMessages/AutomationMsgParser.cpp b/CommonLib/src/Common/AutomationMessages/AutomationMsgParser.cpp new file mode 100644 index 0000000..880de8d --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/AutomationMsgParser.cpp @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include + +#include "AutomationMsgParser.hpp" +#include "Exception.hpp" +#include "MessageHeader.hpp" +#include "MessageIDs.hpp" + +//----------------------------------------------------------------------------- + +AutomationMsgParser::AutomationMsgParser() +{ + gatherCmdMessageIds(); +} + +//----------------------------------------------------------------------------- + +AutomationMsgParser::~AutomationMsgParser(){} + +//----------------------------------------------------------------------------- + +AutomationMsgParser& AutomationMsgParser::instance() +{ + static AutomationMsgParser parser; + return parser; +} + +//----------------------------------------------------------------------------- + +void AutomationMsgParser::gatherCmdMessageIds() +{ + try { + msgIdsVec.push_back(MessageIDs::SCENARIO_STARTED_CMD); + msgIdsVec.push_back(MessageIDs::SCENARIO_STOPPED_CMD); + + msgIdsVec.push_back(MessageIDs::GENERIC_RSP); + + } catch (Exception& e) { + e.buildStackTrace(__FUNCTION_NAME__); + + throw e; + } +} + +//----------------------------------------------------------------------------- + +void AutomationMsgParser::parseMsg(unsigned char* pData, unsigned int numBytes, unsigned int* pMsgId) +{ + try + { + MessageHeader header; + + if (numBytes < header.getHeaderLength()) + { + std::stringstream ss; + ss << "Number of bytes received: " << numBytes << ". Expected minimum: " << header.getHeaderLength(); + + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + // check to see if we recognize the header + unsigned int msgId = 0; + unsigned int msgLen = 0; + + memcpy(&msgId, &pData[0], 4); + memcpy(&msgLen, &pData[4], 4); + + if (std::find(msgIdsVec.begin(), msgIdsVec.end(), msgId) == msgIdsVec.end()) + { + std::stringstream ss; + ss << "unexpected msg id: " << msgId; + + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + if ( msgLen != numBytes) + { + std::stringstream ss; + ss << "Number of bytes received: " << numBytes << ". Expected only: " << msgLen; + + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + if (numBytes > header.getHeaderLength()) + verifyDataFormat(pData, numBytes); + + *pMsgId = msgId; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + + throw e; + } +} + +//----------------------------------------------------------------------------- + +void AutomationMsgParser::verifyDataFormat(unsigned char* pData, unsigned int numBytes) +{ + MessageHeader header; + unsigned char* pTempDataStart = pData + header.getHeaderLength(); + unsigned char* pTempDataEnd = pData + numBytes - 1; + + // data format is + // [data header - 4 bytes][data - variable size] + // [data header][data][data header][data][data header][data][data header][data] + const unsigned int DATA_HEADER_LENGTH = 4; + + try { + std::stringstream ssError; + + ssError << "Data structure is incorrect."; + + // want to make sure data size is at least 5 bytes + if (pTempDataStart+DATA_HEADER_LENGTH > pTempDataEnd) + { + throw Exception(__FUNCTION_NAME__, ssError.str()); + } + + while (pTempDataStart < pTempDataEnd) + { + unsigned int dataSize = *(reinterpret_cast(pTempDataStart)); + + if (dataSize == 0) + { + throw Exception(__FUNCTION_NAME__, ssError.str()); + + } + + pTempDataStart += DATA_HEADER_LENGTH + dataSize; + + if (pTempDataStart-1 > pTempDataEnd) + { + throw Exception(__FUNCTION_NAME__, ssError.str()); + } + else if (pTempDataStart-1 == pTempDataEnd) + break; + } + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + + throw e; + } +} + diff --git a/CommonLib/src/Common/AutomationMessages/AutomationMsgParser.hpp b/CommonLib/src/Common/AutomationMessages/AutomationMsgParser.hpp new file mode 100644 index 0000000..a04b84d --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/AutomationMsgParser.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include "MessageIDs.hpp" +#include + +class AutomationMsgParser +{ +public: + //>--------------------------------------------------------------------------- + // Function: instance + // + // Purpose: singleton + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + static AutomationMsgParser& instance(); + + //>--------------------------------------------------------------------------- + // Function: ~Proc + // + // Purpose: Destroyer + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + ~AutomationMsgParser(); + + //>--------------------------------------------------------------------------- + // Function: parseMsg + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + void parseMsg(unsigned char* pData, unsigned int numBytes,unsigned int* pMsgId); + + private: + //>--------------------------------------------------------------------------- + // Function: AutomationMsgParser + // + // Purpose: Ctor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + AutomationMsgParser(); + + //>--------------------------------------------------------------------------- + // Function: gatherCmdMessageIds + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + void gatherCmdMessageIds(); + + //>--------------------------------------------------------------------------- + // Function: verifyDataFormat + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + void verifyDataFormat(unsigned char* pData, unsigned int numBytes); + + std::vector msgIdsVec; +}; + diff --git a/CommonLib/src/Common/AutomationMessages/GenericRspMessage.cpp b/CommonLib/src/Common/AutomationMessages/GenericRspMessage.cpp new file mode 100644 index 0000000..92e9780 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/GenericRspMessage.cpp @@ -0,0 +1,104 @@ +#include +#include + +#include "GenericRspMessage.hpp" +#include "Exception.hpp" + +//------------------------------------------------------------------------ + +GenericRspMessage::GenericRspMessage(const bool& wasCommandSuccessful): + Message(MessageIDs::GENERIC_RSP, "GENERIC_RSP", sizeof(MessageStruct)), + m_messageStruct() +{ + m_messageStruct.wasCommandSuccessful = static_cast(wasCommandSuccessful); +} + +//------------------------------------------------------------------------ + +GenericRspMessage::GenericRspMessage(const GenericRspMessage& copy) : + Message(copy), + m_messageStruct(copy.m_messageStruct) +{ +} + +//------------------------------------------------------------------------ + +GenericRspMessage::~GenericRspMessage() +{ +} + +//------------------------------------------------------------------------ + +Message* GenericRspMessage::cloneSelf() +{ + GenericRspMessage* pMsg = new GenericRspMessage(*this); + return pMsg; +} + +//------------------------------------------------------------------------ + +void GenericRspMessage::executeMessage() +{ + try + { + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//------------------------------------------------------------------------ + +void GenericRspMessage::formatData(unsigned char* pData) +{ + // Here's how the data is formatted + // each data item is preceded by a 4-byte header which tells us the size of the data item + // 1 data item will have [header][data] + // 2 data items will have [header][data][header][data] + unsigned int dataLen = 0; + const unsigned char* pTempDataStart = pData + getHeaderLength(); + + buildByteArray(&pTempDataStart, reinterpret_cast(&m_messageStruct.wasCommandSuccessful), sizeof(m_messageStruct.wasCommandSuccessful), dataLen); + + // we want update total size of the entire message + m_header.setMessageLength(static_cast(dataLen)); + m_header.format(pData); +} + +//------------------------------------------------------------------------ + +void GenericRspMessage::parseData(const unsigned char* pData) +{ + bool selfThrown = false; + const unsigned char* pTempDataStart = pData; + const unsigned char* pTempDataEnd = pData + m_header.getMessageLength() - m_header.getHeaderLength() - 1; + std::stringstream ss; + + int sizeOfData = 0; + try { + sizeOfData = getNextDataItem(&pTempDataStart, pTempDataEnd, sizeOfData); + // make sure byte number match between what we're expected and what we receive + compareByteNumber(sizeof(m_messageStruct.wasCommandSuccessful), sizeOfData); + memcpy(&m_messageStruct.wasCommandSuccessful, pTempDataStart, sizeOfData); + + } + catch (Exception & e) { + if (!selfThrown) + e.buildStackTrace(__FUNCTION_NAME__); + + throw e; + } +} + +//------------------------------------------------------------------------ + +std::string GenericRspMessage::toString() const +{ + std::stringstream ss; + + ss << Message::toString() << "wasCommandSuccessful: " << m_messageStruct.wasCommandSuccessful; + + return ss.str(); +} diff --git a/CommonLib/src/Common/AutomationMessages/GenericRspMessage.hpp b/CommonLib/src/Common/AutomationMessages/GenericRspMessage.hpp new file mode 100644 index 0000000..b60a7e8 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/GenericRspMessage.hpp @@ -0,0 +1,122 @@ +#pragma once + +#include "Message.hpp" +#include "MessageIDs.hpp" +#include "MessageHeader.hpp" + +class GenericRspMessage : public Message +{ +public: + //>--------------------------------------------------------------------------- + // Function: GenericRspMessage + // + // Purpose: constructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + GenericRspMessage(const bool& wasCommandSuccessful); + + //>--------------------------------------------------------------------------- + // Function: GenericRspMessage + // + // Purpose: copy constructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + GenericRspMessage(const GenericRspMessage ©); + + //>--------------------------------------------------------------------------- + // Function: ~GenericRspMessage + // + // Purpose: destructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual ~GenericRspMessage(); + + //>--------------------------------------------------------------------------- + // Function: GetSuccessfulFlag + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + bool getSuccessfulFlag(){return static_cast(m_messageStruct.wasCommandSuccessful);} + + //>--------------------------------------------------------------------------- + // Function: ExecuteMessage + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void executeMessage(); + + //>--------------------------------------------------------------------------- + // Function: ToString + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual std::string toString() const; + +protected: + //>--------------------------------------------------------------------------- + // Function: CloneSelf + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual Message* cloneSelf(); + + //>--------------------------------------------------------------------------- + // Function: FormatData + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void formatData(unsigned char* pData); + + //>--------------------------------------------------------------------------- + // Function: ParseData + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void parseData(const unsigned char* pData); + +private: + // do not allow + GenericRspMessage& operator=(const GenericRspMessage& rhs) {}; + +#pragma pack(1) + struct MessageStruct + { + unsigned int wasCommandSuccessful; + }; +#pragma pack() + + MessageStruct m_messageStruct; +}; diff --git a/CommonLib/src/Common/AutomationMessages/KwScenarioStarted.cpp b/CommonLib/src/Common/AutomationMessages/KwScenarioStarted.cpp new file mode 100644 index 0000000..16ae317 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/KwScenarioStarted.cpp @@ -0,0 +1,81 @@ +#include +#include + +#include "KwScenarioStarted.hpp" +#include "Exception.hpp" +#include "Proc.hpp" +#include "IniFile.hpp" +#include "GenericRspMessage.hpp" + +//------------------------------------------------------------------------ + +KwScenarioStarted::KwScenarioStarted(): + Message(MessageIDs::SCENARIO_STARTED_CMD, "SCENARIO_STARTED_CMD") +{ +} + +//------------------------------------------------------------------------ + +KwScenarioStarted::KwScenarioStarted(const KwScenarioStarted& copy) : + Message(copy) +{ +} + +//------------------------------------------------------------------------ + +KwScenarioStarted::~KwScenarioStarted() +{ +} + +//------------------------------------------------------------------------ + +Message* KwScenarioStarted::cloneSelf() +{ + KwScenarioStarted* pMsg = new KwScenarioStarted(*this); + return pMsg; +} + +//------------------------------------------------------------------------ + +void KwScenarioStarted::executeMessage() +{ + try + { + + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//------------------------------------------------------------------------ + +void KwScenarioStarted::formatData(unsigned char* pData) +{ + // Here's how the data is formatted + // each data item is preceded by a 4-byte header which tells us the size of the data item + // 1 data item will have [header][data] + // 2 data items will have [header][data][header][data] + unsigned int dataLen = 0; + + // we want update total size of the entire message + m_header.setMessageLength(static_cast(dataLen)); + m_header.format(pData); +} + +//------------------------------------------------------------------------ + +void KwScenarioStarted::parseData(const unsigned char*) +{ +} + +//------------------------------------------------------------------------ + +std::string KwScenarioStarted::toString() const +{ + std::stringstream ss; + + return ss.str(); +} diff --git a/CommonLib/src/Common/AutomationMessages/KwScenarioStarted.hpp b/CommonLib/src/Common/AutomationMessages/KwScenarioStarted.hpp new file mode 100644 index 0000000..282e61a --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/KwScenarioStarted.hpp @@ -0,0 +1,103 @@ +#pragma once + +#include "Message.hpp" +#include "MessageIDs.hpp" +#include "MessageHeader.hpp" + +class KwScenarioStarted : public Message +{ +public: + //>--------------------------------------------------------------------------- + // Function: KwScenarioStarted + // + // Purpose: constructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + KwScenarioStarted(); + + //>--------------------------------------------------------------------------- + // Function: KwScenarioStarted + // + // Purpose: copy constructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + KwScenarioStarted(const KwScenarioStarted ©); + + //>--------------------------------------------------------------------------- + // Function: ~KwScenarioStarted + // + // Purpose: destructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual ~KwScenarioStarted(); + + //>--------------------------------------------------------------------------- + // Function: ExecuteMessage + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void executeMessage(); + + //>--------------------------------------------------------------------------- + // Function: ToString + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual std::string toString() const; + +protected: + //>--------------------------------------------------------------------------- + // Function: CloneSelf + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual Message* cloneSelf(); + + //>--------------------------------------------------------------------------- + // Function: FormatData + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void formatData(unsigned char* pData); + + //>--------------------------------------------------------------------------- + // Function: ParseData + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void parseData(const unsigned char*); + +private: + // do not allow + KwScenarioStarted& operator=(const KwScenarioStarted& rhs) {}; + +}; diff --git a/CommonLib/src/Common/AutomationMessages/KwScenarioStopped.cpp b/CommonLib/src/Common/AutomationMessages/KwScenarioStopped.cpp new file mode 100644 index 0000000..817b4b7 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/KwScenarioStopped.cpp @@ -0,0 +1,101 @@ +#include +#include + +#include "KwScenarioStopped.hpp" +#include "Exception.hpp" +#include "Proc.hpp" +#include "IniFile.hpp" +#include "GenericRspMessage.hpp" +#include "StringUtil.hpp" + +//------------------------------------------------------------------------ + +KwScenarioStopped::KwScenarioStopped(std::string testDataPath): + Message(MessageIDs::SCENARIO_STOPPED_CMD, "SCENARIO_STOPPED_CMD"), + m_testDataPath(testDataPath) +{ +} + +//------------------------------------------------------------------------ + +KwScenarioStopped::KwScenarioStopped(const KwScenarioStopped& copy) : + Message(copy) +{ +} + +//------------------------------------------------------------------------ + +KwScenarioStopped::~KwScenarioStopped() +{ +} + +//------------------------------------------------------------------------ + +Message* KwScenarioStopped::cloneSelf() +{ + KwScenarioStopped* pMsg = new KwScenarioStopped(*this); + return pMsg; +} + +//------------------------------------------------------------------------ + +void KwScenarioStopped::executeMessage() +{ + try + { + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//------------------------------------------------------------------------ + +void KwScenarioStopped::formatData(unsigned char* pData) +{ + // Here's how the data is formatted + // each data item is preceded by a 4-byte header which tells us the size of the data item + // 1 data item will have [header][data] + // 2 data items will have [header][data][header][data] + unsigned int dataLen = 0; + const unsigned char* pTempDataStart = pData + getHeaderLength(); + + buildByteArray(&pTempDataStart, m_testDataPath.c_str(), m_testDataPath.length(), dataLen); + + // we want update total size of the entire message + m_header.setMessageLength(static_cast(dataLen)); + m_header.format(pData); +} + +//------------------------------------------------------------------------ + +void KwScenarioStopped::parseData(const unsigned char* pData) +{ + const unsigned char* pTempDataStart = pData; + const unsigned char* pTempDataEnd = pData + m_header.getMessageLength() - m_header.getHeaderLength() - 1; + + int sizeOfData = 0; + try { + sizeOfData = getNextDataItem(&pTempDataStart, pTempDataEnd, sizeOfData); + m_testDataPath = Util::Strings::ByteArrayToString(const_cast(pTempDataStart), sizeOfData); + + } + catch (Exception& e) { + e.buildStackTrace(__FUNCTION_NAME__); + + throw e; + } +} + +//------------------------------------------------------------------------ + +std::string KwScenarioStopped::toString() const +{ + std::stringstream ss; + + ss << Message::toString() << ". testDataPath: " << m_testDataPath; + + return ss.str(); +} diff --git a/CommonLib/src/Common/AutomationMessages/KwScenarioStopped.hpp b/CommonLib/src/Common/AutomationMessages/KwScenarioStopped.hpp new file mode 100644 index 0000000..0b66b00 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/KwScenarioStopped.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include "Message.hpp" +#include "MessageIDs.hpp" +#include "MessageHeader.hpp" + +class KwScenarioStopped : public Message +{ +public: + //>--------------------------------------------------------------------------- + // Function: KwScenarioStopped + // + // Purpose: constructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + KwScenarioStopped(std::string testDataPath); + + //>--------------------------------------------------------------------------- + // Function: KwScenarioStopped + // + // Purpose: copy constructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + KwScenarioStopped(const KwScenarioStopped ©); + + //>--------------------------------------------------------------------------- + // Function: ~KwScenarioStopped + // + // Purpose: destructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual ~KwScenarioStopped(); + + //>--------------------------------------------------------------------------- + // Function: ExecuteMessage + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void executeMessage(); + + //>--------------------------------------------------------------------------- + // Function: ToString + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual std::string toString() const; + +protected: + //>--------------------------------------------------------------------------- + // Function: CloneSelf + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual Message* cloneSelf(); + + //>--------------------------------------------------------------------------- + // Function: FormatData + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void formatData(unsigned char* pData); + + //>--------------------------------------------------------------------------- + // Function: ParseData + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void parseData(const unsigned char*); + +private: + // do not allow + KwScenarioStopped &operator=(const KwScenarioStopped &rhs); + + std::string m_testDataPath; + +}; diff --git a/CommonLib/src/Common/AutomationMessages/Message.cpp b/CommonLib/src/Common/AutomationMessages/Message.cpp new file mode 100644 index 0000000..ca3fab3 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/Message.cpp @@ -0,0 +1,169 @@ +#include + +#include "Message.hpp" +#include "Exception.hpp" + +//------------------------------------------------------------------------ + +Message::Message(const MessageIDs::MsgIds& id, + const std::string& description, + const unsigned short& messageLen) : + m_header(id, messageLen), + m_description(description) +{ +} + +//------------------------------------------------------------------------ + +Message::Message(const Message& copy) : + m_header(copy.m_header), + m_description(copy.m_description) +{ +} + +//------------------------------------------------------------------------ + +Message::~Message() +{ +} + +//------------------------------------------------------------------------ + +Message* Message::clone() +{ + return cloneSelf(); +} + +//------------------------------------------------------------------------ + +void Message::format(unsigned char* pBuffer) +{ + try + { + m_header.format(pBuffer); + formatData(pBuffer); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//------------------------------------------------------------------------ + +std::string Message::getDescription() const +{ + return m_description; +} + +//------------------------------------------------------------------------ + +void Message::parse(const unsigned char* pData) +{ + try + { + m_header.parse(pData); + parseData(pData + getHeaderLength()); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//------------------------------------------------------------------------ + +void Message::setMessageLength(const unsigned short& length) +{ + m_header.setMessageLength(length); +} + +//------------------------------------------------------------------------ + +std::string Message::toString() const +{ + std::stringstream ss; + ss << "Description: " << getDescription() << ". " << m_header.toString(); + + return ss.str(); +} + +//------------------------------------------------------------------------ + +int Message::getNextDataItem(const unsigned char** pStartBuf, const unsigned char* pEndBuf, int& sizeOfPreviousData) +{ + int sizeOfDataHeader = 4; + int sizeOfData = 0; + std::stringstream ssError; + + *pStartBuf += sizeOfPreviousData; + try + { + // make sure 4 bytes of header information is present + if (*pStartBuf + sizeOfDataHeader > pEndBuf) + { + throw Exception(__FUNCTION_NAME__, ssError.str()); + } + + sizeOfData = *(*pStartBuf); + + // we want to make sure the nth header and nth data information match + // header tells us how many bytes in the nth data item, and the bytes + // of data is present in the buffer + if (*pStartBuf + sizeOfDataHeader + sizeOfData -1 <= pEndBuf) + { + // points to the address of the nth data item + *pStartBuf += sizeOfDataHeader; + } + else + { + throw Exception(__FUNCTION_NAME__, ssError.str()); + } + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + + throw e; + } + + return sizeOfData; +} + +//------------------------------------------------------------------------ + +void Message::buildByteArray(const unsigned char** pStartBuf, const char* data, const int& sizeOfDataBytes, unsigned int& totalBytesInArray) +{ + // copy the header information for this data item + memcpy(const_cast(*pStartBuf), &sizeOfDataBytes, sizeof(sizeOfDataBytes)); + *pStartBuf += sizeof(sizeOfDataBytes); + totalBytesInArray += sizeof(sizeOfDataBytes); + + // copy the data for this data item + memcpy(const_cast(*pStartBuf), data, sizeOfDataBytes); + *pStartBuf += sizeOfDataBytes; + totalBytesInArray += sizeOfDataBytes; +} + +//------------------------------------------------------------------------ + +void Message::compareByteNumber(int expectedNumBytes, int actualNumbyte) +{ + std::stringstream ss; + + try + { + if (expectedNumBytes != actualNumbyte) + { + ss << "Expected number of bytes received: " << expectedNumBytes << ". Actual number of bytes received: " << actualNumbyte; + throw Exception(__FUNCTION_NAME__, ss.str()); + } + } + catch (Exception & e) { + e.buildStackTrace(__FUNCTION_NAME__); + + throw e; + } +} \ No newline at end of file diff --git a/CommonLib/src/Common/AutomationMessages/Message.hpp b/CommonLib/src/Common/AutomationMessages/Message.hpp new file mode 100644 index 0000000..da36272 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/Message.hpp @@ -0,0 +1,242 @@ +#pragma once + +#include + +#include "MessageIDs.hpp" +#include "MessageHeader.hpp" + +class Message +{ +public: + //>--------------------------------------------------------------------- + // Function: ~Message() + // + // Purpose: destructor + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual ~Message(); + + //>--------------------------------------------------------------------- + // Function: Clone() + // + // Purpose: Get a copy of this object + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: a copy of this object + //<--------------------------------------------------------------------- + virtual Message* clone(); + + //>--------------------------------------------------------------------- + // Function: ExecuteMessage() + // + // Purpose: Executes this message + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual void executeMessage() = 0; + + //>--------------------------------------------------------------------- + // Function: Format() + // + // Purpose: Formats this message for sending + //---------------------------------------------------------------------- + // Arguments: pBuffer - the buffer to put the formatting data in + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual void format(unsigned char* pBuffer); + + //>--------------------------------------------------------------------- + // Function: GetDescription() + // + // Purpose: Getter for this objects description + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: The description + //<--------------------------------------------------------------------- + virtual std::string getDescription() const; + + //>--------------------------------------------------------------------- + // Function: GetMessageID() + // + // Purpose: Getter for this objects message id + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: The id + //<--------------------------------------------------------------------- + virtual MessageIDs::MsgIds getMessageID() { return m_header.getMessageId(); } + + //>--------------------------------------------------------------------- + // Function: GetEntireMessageLength() + // + // Purpose: Getter for this objects message number of bytes, including the header + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: The entire message number of bytes + //<--------------------------------------------------------------------- + virtual unsigned int getEntireMessageLength() const { return m_header.getMessageLength();} + + //>--------------------------------------------------------------------- + // Function: GetHeaderLength() + // + // Purpose: Getter for this objects message number of header bytes + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: The header number of bytes + //<--------------------------------------------------------------------- + virtual unsigned short getHeaderLength() const { return m_header.getHeaderLength();} + + //>--------------------------------------------------------------------- + // Function: Parse() + // + // Purpose: Takes an array of bytes and populates this object + //---------------------------------------------------------------------- + // Arguments: The array of bytes + //---------------------------------------------------------------------- + // Return Value: None + //<--------------------------------------------------------------------- + virtual void parse(const unsigned char* pData); + + //>--------------------------------------------------------------------- + // Function: ToString() + // + // Purpose: Converts this object into a string + //---------------------------------------------------------------------- + // Arguments: None + //---------------------------------------------------------------------- + // Return Value: The string form of this object + //<--------------------------------------------------------------------- + virtual std::string toString() const; + +protected: + //>--------------------------------------------------------------------- + // Function: Constructor + // + // Purpose: The constructor for the childern to call + //---------------------------------------------------------------------- + // Arguments: id - the message id + // description - the message description + // messageLen - the number of bytes in the message payload (not including the header) + //---------------------------------------------------------------------- + // Return Value: The object + //<--------------------------------------------------------------------- + Message(const MessageIDs::MsgIds& id, + const std::string& description, + const unsigned short& messageLen = 0); + + //>--------------------------------------------------------------------- + // Function: Copy Constructor + // + // Purpose: Create a copy of this object + //---------------------------------------------------------------------- + // Arguments: copy - the object to copy + //---------------------------------------------------------------------- + // Return Value: The object + //<--------------------------------------------------------------------- + Message(const Message ©); + + //>--------------------------------------------------------------------- + // Function: CloneSelf + // + // Purpose: Pure virtual function for children to implement. + // Create a clone of this object + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: The object + //<--------------------------------------------------------------------- + virtual Message* cloneSelf() = 0; + + //>--------------------------------------------------------------------- + // Function: FormatData + // + // Purpose: Pure virtual function for children to implement. + // Format the data + //---------------------------------------------------------------------- + // Arguments: pData - the buffer to format to + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual void formatData(unsigned char* pData) = 0; + + //>--------------------------------------------------------------------- + // Function: ParseData + // + // Purpose: Pure virtual function for children to implement. + // Parse the data + //---------------------------------------------------------------------- + // Arguments: pData - the buffer to parse from + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual void parseData(const unsigned char* pData) = 0; + + //>--------------------------------------------------------------------- + // Function: SetMessageLength + // + // Purpose: Sets the message length of the payload of the message (not the header) + //---------------------------------------------------------------------- + // Arguments: length - the number of bytes in the payload + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual void setMessageLength(const unsigned short& length); + + //>--------------------------------------------------------------------- + // Function: getStartOfNthDataItem + // + // Purpose: + // get the starting address of the nth data item + // data format: + // [data header][data][data header][data]... + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + int getNextDataItem(const unsigned char** pStartBuf, const unsigned char* pEndBuf, int& sizeOfPreviousData); + + //>--------------------------------------------------------------------- + // Function: buildByteArray + // + // Purpose: + // this will add to the byte array a data item + // data format: + // [data header][data] + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void buildByteArray(const unsigned char** pStartBuf, const char* data, const int& sizeOfDataBytes, unsigned int& totalBytesInArray); + + //>--------------------------------------------------------------------- + // Function: compareByteNumber + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void compareByteNumber(int expectedNumBytes, int actualNumbyte); + + MessageHeader m_header; + +private: + // do not allow + Message(); + Message& operator=(const Message& rhs) {}; + + std::string m_description; +}; diff --git a/CommonLib/src/Common/AutomationMessages/MessageHeader.cpp b/CommonLib/src/Common/AutomationMessages/MessageHeader.cpp new file mode 100644 index 0000000..5e27560 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/MessageHeader.cpp @@ -0,0 +1,87 @@ +#include +#include + +#include "MessageHeader.hpp" + +//------------------------------------------------------------------------ + +MessageHeader::MessageHeader(const MessageIDs::MsgIds& id, const unsigned short& messageLen) : + m_headerStruct() +{ + m_headerStruct.messageId = id; + m_headerStruct.messageLength = messageLen + getHeaderLength(); +} + +//------------------------------------------------------------------------ + +MessageHeader::MessageHeader() : + m_headerStruct() +{ + m_headerStruct.messageId = 0; + m_headerStruct.messageLength = 0; +} + +//------------------------------------------------------------------------ + +MessageHeader::MessageHeader(const MessageHeader& copy) : + m_headerStruct(copy.m_headerStruct) +{ +} + +//------------------------------------------------------------------------ + +MessageHeader::~MessageHeader() +{ +} + +//------------------------------------------------------------------------ + +void MessageHeader::format(unsigned char* pData) +{ + memcpy(pData, &m_headerStruct, getHeaderLength()); +} + +//------------------------------------------------------------------------ + +MessageIDs::MsgIds MessageHeader::getMessageId() +{ + return (MessageIDs::MsgIds)m_headerStruct.messageId; +} + +//------------------------------------------------------------------------ + +unsigned short MessageHeader::getHeaderLength() const +{ + return sizeof(m_headerStruct); +} + +//------------------------------------------------------------------------ + +unsigned int MessageHeader::getMessageLength() const +{ + return m_headerStruct.messageLength; +} + +//------------------------------------------------------------------------ + +void MessageHeader::parse(const unsigned char* pData) +{ + ::memcpy(&m_headerStruct, pData, getHeaderLength()); +} + +//------------------------------------------------------------------------ + +void MessageHeader::setMessageLength(const unsigned short& length) +{ + m_headerStruct.messageLength = length + getHeaderLength(); +} + +//------------------------------------------------------------------------ + +std::string MessageHeader::toString() const +{ + std::stringstream ss; + ss << "msg id: 0x" << std::hex << std::uppercase << m_headerStruct.messageId << std::nouppercase << ". " << "msg len: " << std::dec << m_headerStruct.messageLength; + + return ss.str(); +} diff --git a/CommonLib/src/Common/AutomationMessages/MessageHeader.hpp b/CommonLib/src/Common/AutomationMessages/MessageHeader.hpp new file mode 100644 index 0000000..bdddfe9 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/MessageHeader.hpp @@ -0,0 +1,145 @@ +#pragma once + +#include "MessageIDs.hpp" + +class MessageHeader +{ +public: + //>--------------------------------------------------------------------- + // Function: MessageHeader + // + // Purpose: constructor + //---------------------------------------------------------------------- + // Arguments: id - the message id + // messageLen - the number of bytes of the entire message including the header + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + MessageHeader(const MessageIDs::MsgIds& id, const unsigned short& messageLen); + + //>--------------------------------------------------------------------- + // Function: MessageHeader + // + // Purpose: constructor + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + MessageHeader(); + + //>--------------------------------------------------------------------- + // Function: Copy Constructor + // + // Purpose: Create a copy of this object + //---------------------------------------------------------------------- + // Arguments: copy - the object to copy + //---------------------------------------------------------------------- + // Return Value: The object + //<--------------------------------------------------------------------- + MessageHeader(const MessageHeader ©); + + //>--------------------------------------------------------------------- + // Function: ~MessageHeader() + // + // Purpose: destructor + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual ~MessageHeader(); + + //>--------------------------------------------------------------------- + // Function: Format() + // + // Purpose: Formats this message for sending + //---------------------------------------------------------------------- + // Arguments: pBuffer - the buffer to put the formatting data in + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void format(unsigned char* pData); + + //>--------------------------------------------------------------------- + // Function: GetHeaderLength() + // + // Purpose: Get the number of bytes in the header + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: number of bytes in the header + //<--------------------------------------------------------------------- + unsigned short getHeaderLength() const; + + //>--------------------------------------------------------------------- + // Function: GetMessageLength() + // + // Purpose: Get the number of bytes in the entire message, including header + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: number of bytes in the message + //<--------------------------------------------------------------------- + unsigned int getMessageLength() const; + + //>--------------------------------------------------------------------- + // Function: GetMessageId() + // + // Purpose: Get the message id + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: the message id + //<--------------------------------------------------------------------- + MessageIDs::MsgIds getMessageId(); + + //>--------------------------------------------------------------------- + // Function: Parse() + // + // Purpose: Takes an array of bytes and populates this object + //---------------------------------------------------------------------- + // Arguments: The array of bytes + //---------------------------------------------------------------------- + // Return Value: None + //<--------------------------------------------------------------------- + void parse(const unsigned char* pData); + + //>--------------------------------------------------------------------- + // Function: SetMessageLength + // + // Purpose: Sets the message length of the payload of the message (not the header) + //---------------------------------------------------------------------- + // Arguments: length - the number of bytes in the payload + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void setMessageLength(const unsigned short& length); + + //>--------------------------------------------------------------------- + // Function: ToString() + // + // Purpose: Converts this object into a string + //---------------------------------------------------------------------- + // Arguments: None + //---------------------------------------------------------------------- + // Return Value: The string form of this object + //<--------------------------------------------------------------------- + std::string toString() const; + +protected: + +private: + // do not allow + MessageHeader& operator=(const MessageHeader& rhs) {}; + +#pragma pack(1) + struct HeaderStruct + { + unsigned int messageId; + unsigned int messageLength; + }; +#pragma pack() + + HeaderStruct m_headerStruct; +}; diff --git a/CommonLib/src/Common/AutomationMessages/MessageIDs.hpp b/CommonLib/src/Common/AutomationMessages/MessageIDs.hpp new file mode 100644 index 0000000..bcee712 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/MessageIDs.hpp @@ -0,0 +1,19 @@ +#pragma once + + +namespace MessageIDs +{ + enum MsgIds + { + TRANSFER_A_FILE_CMD = 0xCA001001, + TRANSFER_A_FOLDER_CMD = 0xCA001002, + TRANSFER_GUTS_VIDEOS_CMD = 0xCA001003, + MOVE_GUTS_VIDEOS_TO_SUB_FOLDER_CMD = 0xCA001004, + SCENARIO_STARTED_CMD = 0xCA001005, + SCENARIO_STOPPED_CMD = 0xCA001006, + + WAIT_FOR_COMPLETION_CMD = 0xCA002000, + + GENERIC_RSP = 0xCA002001 + }; +} diff --git a/CommonLib/src/Common/AutomationMessages/MoveGutsVideosToSubFolderCmdMessage.cpp b/CommonLib/src/Common/AutomationMessages/MoveGutsVideosToSubFolderCmdMessage.cpp new file mode 100644 index 0000000..eefed1e --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/MoveGutsVideosToSubFolderCmdMessage.cpp @@ -0,0 +1,99 @@ +#include +#include + +#include "MoveGutsVideosToSubFolderCmdMessage.hpp" +#include "Exception.hpp" +#include "StringUtil.hpp" + +//------------------------------------------------------------------------ + +MoveGutsVideosToSubFolderCmdMessage::MoveGutsVideosToSubFolderCmdMessage(std::string subFolder): + Message(MessageIDs::MOVE_GUTS_VIDEOS_TO_SUB_FOLDER_CMD, "MOVE_GUTS_VIDEOS_TO_SUB_FOLDER_CMD"), + m_subFolder(subFolder) +{ +} + +//------------------------------------------------------------------------ + +MoveGutsVideosToSubFolderCmdMessage::MoveGutsVideosToSubFolderCmdMessage(const MoveGutsVideosToSubFolderCmdMessage& copy) : + Message(copy), + m_subFolder(copy.m_subFolder) +{ +} + +//------------------------------------------------------------------------ + +MoveGutsVideosToSubFolderCmdMessage::~MoveGutsVideosToSubFolderCmdMessage() +{ +} + +//------------------------------------------------------------------------ + +Message* MoveGutsVideosToSubFolderCmdMessage::cloneSelf() +{ + MoveGutsVideosToSubFolderCmdMessage* pMsg = new MoveGutsVideosToSubFolderCmdMessage(*this); + return pMsg; +} + +//------------------------------------------------------------------------ + +void MoveGutsVideosToSubFolderCmdMessage::executeMessage() +{ + try + { + + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//------------------------------------------------------------------------ + +void MoveGutsVideosToSubFolderCmdMessage::formatData(unsigned char* pData) +{ + // Here's how the data is formatted + // each data item is preceded by a 4-byte header which tells us the size of the data item + // 1 data item will have [header][data] + // 2 data items will have [header][data][header][data] + unsigned int dataLen = 0; + const unsigned char* pTempDataStart = pData + getHeaderLength(); + + buildByteArray(&pTempDataStart, m_subFolder.c_str(), m_subFolder.length(), dataLen); + + // we want update total size of the entire message + m_header.setMessageLength(static_cast(dataLen)); + m_header.format(pData); +} + +//------------------------------------------------------------------------ + +void MoveGutsVideosToSubFolderCmdMessage::parseData(const unsigned char* pData) +{ + const unsigned char* pTempDataStart = pData; + const unsigned char* pTempDataEnd = pData + m_header.getMessageLength() - m_header.getHeaderLength() - 1; + + int sizeOfData = 0; + try { + sizeOfData = getNextDataItem(&pTempDataStart, pTempDataEnd, sizeOfData); + m_subFolder = Util::Strings::ByteArrayToString(const_cast(pTempDataStart), sizeOfData); + + } catch (Exception& e) { + e.buildStackTrace(__FUNCTION_NAME__); + + throw e; + } +} + +//------------------------------------------------------------------------ + +std::string MoveGutsVideosToSubFolderCmdMessage::toString() const +{ + std::stringstream ss; + + ss << Message::toString() << ". Subfolder: " << m_subFolder; + + return ss.str(); +} diff --git a/CommonLib/src/Common/AutomationMessages/MoveGutsVideosToSubFolderCmdMessage.hpp b/CommonLib/src/Common/AutomationMessages/MoveGutsVideosToSubFolderCmdMessage.hpp new file mode 100644 index 0000000..5c0d157 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/MoveGutsVideosToSubFolderCmdMessage.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include "Message.hpp" +#include "MessageIDs.hpp" +#include "MessageHeader.hpp" + +class MoveGutsVideosToSubFolderCmdMessage : public Message +{ +public: + //>--------------------------------------------------------------------------- + // Function: MoveGutsVideosToSubFolderCmdMessage + // + // Purpose: constructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + MoveGutsVideosToSubFolderCmdMessage(std::string subFolder = ""); + + //>--------------------------------------------------------------------------- + // Function: MoveGutsVideosToSubFolderCmdMessage + // + // Purpose: copy constructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + MoveGutsVideosToSubFolderCmdMessage(const MoveGutsVideosToSubFolderCmdMessage ©); + + //>--------------------------------------------------------------------------- + // Function: ~MoveGutsVideosToSubFolderCmdMessage + // + // Purpose: destructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual ~MoveGutsVideosToSubFolderCmdMessage(); + + //>--------------------------------------------------------------------------- + // Function: ExecuteMessage + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void executeMessage(); + + //>--------------------------------------------------------------------------- + // Function: ToString + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual std::string toString() const; + +protected: + //>--------------------------------------------------------------------------- + // Function: CloneSelf + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual Message* cloneSelf(); + + //>--------------------------------------------------------------------------- + // Function: FormatData + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void formatData(unsigned char* pData); + + //>--------------------------------------------------------------------------- + // Function: ParseData + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void parseData(const unsigned char* pData); + +private: + // do not allow + MoveGutsVideosToSubFolderCmdMessage& operator=(const MoveGutsVideosToSubFolderCmdMessage& rhs) {}; + + std::string m_subFolder; +}; diff --git a/CommonLib/src/Common/AutomationMessages/TransferAFileCmdMessage.cpp b/CommonLib/src/Common/AutomationMessages/TransferAFileCmdMessage.cpp new file mode 100644 index 0000000..ce4ea3c --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/TransferAFileCmdMessage.cpp @@ -0,0 +1,121 @@ +#include +#include + +#include "TransferAFileCmdMessage.hpp" +#include "Exception.hpp" +#include "StringUtil.hpp" + +//------------------------------------------------------------------------ + +TransferAFileCmdMessage::TransferAFileCmdMessage(std::string fromFile, std::string toFile, bool deleteSource): + Message(MessageIDs::TRANSFER_A_FILE_CMD, "TRANSFER_A_FILE_CMD"), + m_fromFile(fromFile), + m_toFile(toFile), + m_deleteSource(static_cast(deleteSource)) +{ +} + +//------------------------------------------------------------------------ + +TransferAFileCmdMessage::TransferAFileCmdMessage(const TransferAFileCmdMessage& copy) : + Message(copy), + m_fromFile(copy.m_fromFile), + m_toFile(copy.m_toFile), + m_deleteSource(copy.m_deleteSource) +{ +} + +//------------------------------------------------------------------------ + +TransferAFileCmdMessage::~TransferAFileCmdMessage() +{ +} + +//------------------------------------------------------------------------ + +Message* TransferAFileCmdMessage::cloneSelf() +{ + TransferAFileCmdMessage* pMsg = new TransferAFileCmdMessage(*this); + return pMsg; +} + +//------------------------------------------------------------------------ + +void TransferAFileCmdMessage::executeMessage() +{ + try + { + + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//------------------------------------------------------------------------ + +void TransferAFileCmdMessage::formatData(unsigned char* pData) +{ + // Here's how the data is formatted + // each data item is preceded by a 4-byte header which tells us the size of the data item + // 1 data item will have [header][data] + // 2 data items will have [header][data][header][data] + unsigned int dataLen = 0; + const unsigned char* pTempDataStart = pData + getHeaderLength(); + + buildByteArray(&pTempDataStart, m_fromFile.c_str(), m_fromFile.length(), dataLen); + buildByteArray(&pTempDataStart, m_toFile.c_str(), m_toFile.length(), dataLen); + buildByteArray(&pTempDataStart, reinterpret_cast(&m_deleteSource), sizeof(m_deleteSource), dataLen); + + // we want update total size of the entire message + m_header.setMessageLength(static_cast(dataLen)); + m_header.format(pData); +} + +//------------------------------------------------------------------------ + +void TransferAFileCmdMessage::parseData(const unsigned char* pData) +{ + bool selfThrown = false; + const unsigned char* pTempDataStart = pData; + const unsigned char* pTempDataEnd = pData + m_header.getMessageLength() - m_header.getHeaderLength() - 1; + + int sizeOfData = 0; + try { + sizeOfData = getNextDataItem(&pTempDataStart, pTempDataEnd, sizeOfData); + m_fromFile = Util::Strings::ByteArrayToString(const_cast(pTempDataStart), sizeOfData); + + sizeOfData = getNextDataItem(&pTempDataStart, pTempDataEnd, sizeOfData); + getNextDataItem(&pTempDataStart, pTempDataEnd, sizeOfData); + + sizeOfData = getNextDataItem(&pTempDataStart, pTempDataEnd, sizeOfData); + m_toFile = Util::Strings::ByteArrayToString(const_cast(pTempDataStart), sizeOfData); + + sizeOfData = getNextDataItem(&pTempDataStart, pTempDataEnd, sizeOfData); + getNextDataItem(&pTempDataStart, pTempDataEnd, sizeOfData); + + sizeOfData = getNextDataItem(&pTempDataStart, pTempDataEnd, sizeOfData); + // make sure byte number match between what we're expected and what we receive + compareByteNumber(sizeof(m_deleteSource), sizeOfData); + memcpy(&m_deleteSource, pTempDataStart, sizeOfData); + + } catch (Exception& e) { + if (!selfThrown) + e.buildStackTrace(__FUNCTION_NAME__); + + throw e; + } +} + +//------------------------------------------------------------------------ + +std::string TransferAFileCmdMessage::toString() const +{ + std::stringstream ss; + + ss << Message::toString() << ". From file: " << m_fromFile << ". To file: " << m_toFile << ". Delete source: " << m_deleteSource; + + return ss.str(); +} diff --git a/CommonLib/src/Common/AutomationMessages/TransferAFileCmdMessage.hpp b/CommonLib/src/Common/AutomationMessages/TransferAFileCmdMessage.hpp new file mode 100644 index 0000000..4d2c758 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/TransferAFileCmdMessage.hpp @@ -0,0 +1,108 @@ +#pragma once + +#include "Message.hpp" +#include "MessageIDs.hpp" +#include "MessageHeader.hpp" + +class TransferAFileCmdMessage : public Message +{ +public: + //>--------------------------------------------------------------------------- + // Function: TransferAFileCmdMessage + // + // Purpose: constructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + TransferAFileCmdMessage(std::string fromFile = "", std::string toFile = "", bool deleteSource = false); + + //>--------------------------------------------------------------------------- + // Function: TransferAFileCmdMessage + // + // Purpose: copy constructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + TransferAFileCmdMessage(const TransferAFileCmdMessage ©); + + //>--------------------------------------------------------------------------- + // Function: ~TransferAFileCmdMessage + // + // Purpose: destructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual ~TransferAFileCmdMessage(); + + //>--------------------------------------------------------------------------- + // Function: ExecuteMessage + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void executeMessage(); + + //>--------------------------------------------------------------------------- + // Function: ToString + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual std::string toString() const; + +protected: + //>--------------------------------------------------------------------------- + // Function: CloneSelf + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual Message* cloneSelf(); + + //>--------------------------------------------------------------------------- + // Function: FormatData + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void formatData(unsigned char* pData); + + //>--------------------------------------------------------------------------- + // Function: ParseData + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void parseData(const unsigned char* pData); + +private: + // do not allow + TransferAFileCmdMessage& operator=(const TransferAFileCmdMessage& rhs) {}; + + std::string m_fromFile; + + std::string m_toFile; + + unsigned int m_deleteSource; +}; diff --git a/CommonLib/src/Common/AutomationMessages/TransferGutsVideosCmdMessage.cpp b/CommonLib/src/Common/AutomationMessages/TransferGutsVideosCmdMessage.cpp new file mode 100644 index 0000000..511a126 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/TransferGutsVideosCmdMessage.cpp @@ -0,0 +1,118 @@ +#include +#include + +#include "TransferGutsVideosCmdMessage.hpp" +#include "Exception.hpp" +#include "StringUtil.hpp" + +//------------------------------------------------------------------------ + +TransferGutsVideosCmdMessage::TransferGutsVideosCmdMessage(std::string currentTestFolder, unsigned int transferEverything, unsigned int deleteSource): + Message(MessageIDs::TRANSFER_GUTS_VIDEOS_CMD, "TRANSFER_GUTS_VIDEOS_CMD"), + m_currentTestFolder(currentTestFolder), + m_transferEverything(transferEverything), + m_deleteSource(deleteSource) +{ +} + +//------------------------------------------------------------------------ + +TransferGutsVideosCmdMessage::TransferGutsVideosCmdMessage(const TransferGutsVideosCmdMessage& copy) : + Message(copy), + m_currentTestFolder(copy.m_currentTestFolder), + m_transferEverything(copy.m_transferEverything), + m_deleteSource(copy.m_deleteSource) +{ +} + +//------------------------------------------------------------------------ + +TransferGutsVideosCmdMessage::~TransferGutsVideosCmdMessage() +{ +} + +//------------------------------------------------------------------------ + +Message* TransferGutsVideosCmdMessage::cloneSelf() +{ + TransferGutsVideosCmdMessage* pMsg = new TransferGutsVideosCmdMessage(*this); + return pMsg; +} + +//------------------------------------------------------------------------ + +void TransferGutsVideosCmdMessage::executeMessage() +{ + try + { + + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//------------------------------------------------------------------------ + +void TransferGutsVideosCmdMessage::formatData(unsigned char* pData) +{ + // Here's how the data is formatted + // each data item is preceded by a 4-byte header which tells us the size of the data item + // 1 data item will have [header][data] + // 2 data items will have [header][data][header][data] + unsigned int dataLen = 0; + const unsigned char* pTempDataStart = pData + getHeaderLength(); + + buildByteArray(&pTempDataStart, m_currentTestFolder.c_str(), m_currentTestFolder.length(), dataLen); + buildByteArray(&pTempDataStart, reinterpret_cast(&m_transferEverything), sizeof(m_transferEverything), dataLen); + buildByteArray(&pTempDataStart, reinterpret_cast(&m_deleteSource), sizeof(m_deleteSource), dataLen); + + // we want update total size of the entire message + m_header.setMessageLength(static_cast(dataLen)); + m_header.format(pData); +} + +//------------------------------------------------------------------------ + +void TransferGutsVideosCmdMessage::parseData(const unsigned char* pData) +{ + bool selfThrown = false; + const unsigned char* pTempDataStart = pData; + const unsigned char* pTempDataEnd = pData + m_header.getMessageLength() - m_header.getHeaderLength() - 1; + + int sizeOfData = 0; + try { + // get the address of the 1st data item + sizeOfData = getNextDataItem(&pTempDataStart, pTempDataEnd, sizeOfData); + m_currentTestFolder = Util::Strings::ByteArrayToString(const_cast(pTempDataStart), sizeOfData); + + sizeOfData = getNextDataItem(&pTempDataStart, pTempDataEnd, sizeOfData); + // make sure byte number match between what we're expected and what we receive + compareByteNumber(sizeof(m_transferEverything), sizeOfData); + memcpy(&m_transferEverything, pTempDataStart, sizeOfData); + + sizeOfData = getNextDataItem(&pTempDataStart, pTempDataEnd, sizeOfData); + // make sure byte number match between what we're expected and what we receive + compareByteNumber(sizeof(m_deleteSource), sizeOfData); + memcpy(&m_deleteSource, pTempDataStart, sizeOfData); + + } catch (Exception& e) { + if (!selfThrown) + e.buildStackTrace(__FUNCTION_NAME__); + + throw e; + } +} + +//------------------------------------------------------------------------ + +std::string TransferGutsVideosCmdMessage::toString() const +{ + std::stringstream ss; + + ss << Message::toString() << ". current test folder: " << m_currentTestFolder << ". transfer everything: " << m_transferEverything << ". Delete source: " << m_deleteSource; + + return ss.str(); +} diff --git a/CommonLib/src/Common/AutomationMessages/TransferGutsVideosCmdMessage.hpp b/CommonLib/src/Common/AutomationMessages/TransferGutsVideosCmdMessage.hpp new file mode 100644 index 0000000..6c013fa --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/TransferGutsVideosCmdMessage.hpp @@ -0,0 +1,126 @@ +#pragma once + +#include "Message.hpp" +#include "MessageIDs.hpp" +#include "MessageHeader.hpp" + +class TransferGutsVideosCmdMessage : public Message +{ +public: + //>--------------------------------------------------------------------- + // Function: TransferGutsVideosCmdMessage + // + // Purpose: constructor + //---------------------------------------------------------------------- + // Arguments: + // + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + TransferGutsVideosCmdMessage(std::string currentTestFolder, unsigned int transferEverything = 0, unsigned int deleteSource = 0); + + //>--------------------------------------------------------------------- + // Function: TransferGutsVideosCmdMessage + // + // Purpose: copy constructor + //---------------------------------------------------------------------- + // Arguments: + // + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + TransferGutsVideosCmdMessage(const TransferGutsVideosCmdMessage ©); + + //>--------------------------------------------------------------------- + // Function: ~TransferGutsVideosCmdMessage + // + // Purpose: destructor + //---------------------------------------------------------------------- + // Arguments: + // + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual ~TransferGutsVideosCmdMessage(); + + //>--------------------------------------------------------------------- + // Function: ExecuteMessage + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + // + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual void executeMessage(); + + //>--------------------------------------------------------------------- + // Function: ToString + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + // + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual std::string toString() const; + +protected: + //>--------------------------------------------------------------------- + // Function: CloneSelf + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + // + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual Message* cloneSelf(); + + //>--------------------------------------------------------------------- + // Function: FormatData + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + // + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual void formatData(unsigned char* pData); + + //>--------------------------------------------------------------------- + // Function: ParseData + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + // + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual void parseData(const unsigned char* pData); + + //>--------------------------------------------------------------------- + // Function: gatherInfo + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + // + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void gatherInfo(); + +private: + // do not allow + TransferGutsVideosCmdMessage &operator=(const TransferGutsVideosCmdMessage &rhs); + + std::string m_currentTestFolder; + unsigned int m_transferEverything; + unsigned int m_deleteSource; +}; diff --git a/CommonLib/src/Common/AutomationMessages/WaitForLastTaskCompletionCmdMessage.cpp b/CommonLib/src/Common/AutomationMessages/WaitForLastTaskCompletionCmdMessage.cpp new file mode 100644 index 0000000..fc04671 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/WaitForLastTaskCompletionCmdMessage.cpp @@ -0,0 +1,73 @@ +#include +#include + +#include "WaitForLastTaskCompletionCmdMessage.hpp" +#include "Exception.hpp" + +//------------------------------------------------------------------------ + +WaitForLastTaskCompletionCmdMessage::WaitForLastTaskCompletionCmdMessage(): + Message(MessageIDs::WAIT_FOR_COMPLETION_CMD, "WAIT_FOR_COMPLETION_CMD") +{ +} + +//------------------------------------------------------------------------ + +WaitForLastTaskCompletionCmdMessage::WaitForLastTaskCompletionCmdMessage(const WaitForLastTaskCompletionCmdMessage& copy) : + Message(copy) +{ +} + +//------------------------------------------------------------------------ + +WaitForLastTaskCompletionCmdMessage::~WaitForLastTaskCompletionCmdMessage() +{ +} + +//------------------------------------------------------------------------ + +Message* WaitForLastTaskCompletionCmdMessage::cloneSelf() +{ + WaitForLastTaskCompletionCmdMessage* pMsg = new WaitForLastTaskCompletionCmdMessage(*this); + return pMsg; +} + +//------------------------------------------------------------------------ + +void WaitForLastTaskCompletionCmdMessage::executeMessage() +{ + try + { + + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//------------------------------------------------------------------------ + +void WaitForLastTaskCompletionCmdMessage::formatData(unsigned char*) +{ + // no data to send +} + +//------------------------------------------------------------------------ + +void WaitForLastTaskCompletionCmdMessage::parseData(const unsigned char*) +{ + // no data to process +} + +//------------------------------------------------------------------------ + +std::string WaitForLastTaskCompletionCmdMessage::toString() const +{ + std::stringstream ss; + + ss << Message::toString(); + + return ss.str(); +} diff --git a/CommonLib/src/Common/AutomationMessages/WaitForLastTaskCompletionCmdMessage.hpp b/CommonLib/src/Common/AutomationMessages/WaitForLastTaskCompletionCmdMessage.hpp new file mode 100644 index 0000000..b57f557 --- /dev/null +++ b/CommonLib/src/Common/AutomationMessages/WaitForLastTaskCompletionCmdMessage.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include "Message.hpp" +#include "MessageIDs.hpp" +#include "MessageHeader.hpp" + +class WaitForLastTaskCompletionCmdMessage : public Message +{ +public: + //>--------------------------------------------------------------------------- + // Function: WaitForLastTaskCompletionCmdMessage + // + // Purpose: constructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + WaitForLastTaskCompletionCmdMessage(); + + //>--------------------------------------------------------------------------- + // Function: WaitForLastTaskCompletionCmdMessage + // + // Purpose: copy constructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + WaitForLastTaskCompletionCmdMessage(const WaitForLastTaskCompletionCmdMessage ©); + + //>--------------------------------------------------------------------------- + // Function: ~WaitForLastTaskCompletionCmdMessage + // + // Purpose: destructor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual ~WaitForLastTaskCompletionCmdMessage(); + + //>--------------------------------------------------------------------------- + // Function: ExecuteMessage + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void executeMessage(); + + //>--------------------------------------------------------------------------- + // Function: ToString + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual std::string toString() const; + + // indicate command executed successfully or not + static bool s_commandCompletionSuccess; + +protected: + //>--------------------------------------------------------------------------- + // Function: CloneSelf + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual Message* cloneSelf(); + + //>--------------------------------------------------------------------------- + // Function: FormatData + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void formatData(unsigned char* pData); + + //>--------------------------------------------------------------------------- + // Function: ParseData + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual void parseData(const unsigned char* pData); + +private: + // do not allow + WaitForLastTaskCompletionCmdMessage &operator=(const WaitForLastTaskCompletionCmdMessage &rhs); +}; diff --git a/CommonLib/src/Common/Comm/Socket.cpp b/CommonLib/src/Common/Comm/Socket.cpp new file mode 100644 index 0000000..d6fd5fe --- /dev/null +++ b/CommonLib/src/Common/Comm/Socket.cpp @@ -0,0 +1,396 @@ +#include + +#include "Socket.hpp" +#include "ErrorLog.hpp" +#include "NTMutex.hpp" +#include "NetworkUtil.hpp" +#include "Exception.hpp" + +#include "iphlpapi.h" + +//----------------------------------------------------------------------------- + +Socket::Socket(DWORD readTimeout, + DWORD writeTimeout, + unsigned int readSize): + remoteAddress_("no address yet"), + remotePort_(0), + pQuitEvent_(0), + pReadEvent_(0), + pWriteEvent_(0), + readTimeout_(readTimeout), + socket_(INVALID_SOCKET), + writeTimeout_(writeTimeout), + pReadBuff_(0), + pWriteBuff_(0), + bytesRead_(0), + bytesWritten_(0), + readBuffSize_(readSize), + writeBuffSize_(0), + numToSend_(0), + numRead_(0), + numWritten_(0), + pSocketMutex_(0), + isUdp_(false), + listenSocket_() +{ +} + +//----------------------------------------------------------------------------- + +Socket::Socket(SOCKET socket, unsigned int readSize): + remoteAddress_("no address yet"), + remotePort_(0), + pQuitEvent_(0), + pReadEvent_(0), + pWriteEvent_(0), + readTimeout_(ULONG_MAX), + socket_(socket), + writeTimeout_(ULONG_MAX), + pReadBuff_(0), + pWriteBuff_(0), + bytesRead_(0), + bytesWritten_(0), + readBuffSize_(readSize), + writeBuffSize_(0), + numToSend_(0), + numRead_(0), + numWritten_(0), + pSocketMutex_(0), + isUdp_(false) +{ +} + +//----------------------------------------------------------------------------- + +Socket::Socket(const std::string& address, + unsigned int remotePort, + DWORD readTimeout, + DWORD writeTimeout, + unsigned int readSize): + remotePort_(remotePort), + pQuitEvent_(0), + pReadEvent_(0), + pWriteEvent_(0), + readTimeout_(readTimeout), + socket_(INVALID_SOCKET), + writeTimeout_(writeTimeout), + pReadBuff_(0), + pWriteBuff_(0), + bytesRead_(0), + bytesWritten_(0), + readBuffSize_(readSize), + writeBuffSize_(0), + numToSend_(0), + numRead_(0), + numWritten_(0), + pSocketMutex_(0), + isUdp_(false) +{ + remoteAddress_ = convertHostnameToIp(address); +} + +//----------------------------------------------------------------------------- + +Socket::Socket(const std::string& address, + unsigned int remotePort, + unsigned int localPort, + DWORD readTimeout, + DWORD writeTimeout, + unsigned int readSize) : + remotePort_(remotePort), + localPort_(localPort), + pQuitEvent_(0), + pReadEvent_(0), + pWriteEvent_(0), + readTimeout_(readTimeout), + socket_(INVALID_SOCKET), + writeTimeout_(writeTimeout), + pReadBuff_(0), + pWriteBuff_(0), + bytesRead_(0), + bytesWritten_(0), + readBuffSize_(readSize), + writeBuffSize_(0), + numToSend_(0), + numRead_(0), + numWritten_(0), + pSocketMutex_(0), + isUdp_(false) +{ + remoteAddress_ = convertHostnameToIp(address); +} + +//----------------------------------------------------------------------------- + +Socket::Socket(const std::string& address, + unsigned int remotePort, + bool bindPort, + DWORD readTimeout, + DWORD writeTimeout, + unsigned int readSize): + remotePort_(remotePort), + pQuitEvent_(0), + pReadEvent_(0), + pWriteEvent_(0), + readTimeout_(readTimeout), + socket_(INVALID_SOCKET), + writeTimeout_(writeTimeout), + pReadBuff_(0), + pWriteBuff_(0), + bytesRead_(0), + bytesWritten_(0), + readBuffSize_(readSize), + writeBuffSize_(0), + numToSend_(0), + numRead_(0), + numWritten_(0), + pSocketMutex_(0), + isUdp_(false), + listenSocket_() +{ + remoteAddress_ = convertHostnameToIp(address); +} + + +//----------------------------------------------------------------------------- + +Socket::~Socket() +{ + try + { + if(pQuitEvent_ != NULL) + { + stop(); + ::Sleep(100); + } + + if(pReadBuff_ != NULL) + { + delete [] pReadBuff_; + pReadBuff_ = 0; + } + + if(pQuitEvent_ != NULL) + { + delete pQuitEvent_; + pQuitEvent_ = 0; + } + + if(pReadEvent_ != NULL) + { + delete pReadEvent_; + pReadEvent_ = 0; + } + + if(pWriteEvent_ != NULL) + { + delete pWriteEvent_; + pWriteEvent_ = 0; + } + + if(pSocketMutex_ != NULL) + { + delete pSocketMutex_; + pSocketMutex_ = 0; + } + } + catch (...) + { + + } +} + +//----------------------------------------------------------------------------- + +std::string Socket::convertHostnameToIp(std::string hostname) +{ + startUp(); + + std::string ip = hostname; + // convert to dot address notation if needed + if (hostname.length() > 0 && !Util::Network::IsIpAddress(hostname)) + { + struct addrinfo hints = {}, *addrInfo; + char port_str[16] = {}; + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + int dwRetval = getaddrinfo(hostname.c_str(), port_str, &hints, &addrInfo); + + if (dwRetval != 0) + { + std::stringstream ss; + ss << "getaddrinfo() failed with error : " << WSAGetLastError(); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + struct sockaddr_in *ipv = (struct sockaddr_in *)addrInfo->ai_addr; + struct in_addr *addr = &(ipv->sin_addr); + + char ipstr[INET_ADDRSTRLEN]; + inet_ntop(addrInfo->ai_family, addr, ipstr, sizeof(ipstr)); + ip = std::string(ipstr); + } + + return ip; +} + +//----------------------------------------------------------------------------- + +void Socket::createEvents() +{ + try + { + UUID uuid; + ::UuidCreate(&uuid); + + unsigned char* pUuidString; + ::UuidToString(&uuid, &pUuidString); + + std::string str = reinterpret_cast(pUuidString); + + ::RpcStringFree(&pUuidString); + + pQuitEvent_ = new NTEvent("Socket quit event: " + str); + pReadEvent_ = new NTEvent("Socket read event: " + str); + pWriteEvent_ = new NTEvent("Socket write event: " + str); + + pSocketMutex_ = new NTMutex("Socket Mutex: " + str); + } + catch(Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } +} + +//----------------------------------------------------------------------------- + +void Socket::initReadBuff(unsigned int readSize) +{ + try + { + pReadBuff_ = new char[readSize]; + // fill w/ zeros + for (unsigned int i = 0; i < readSize; ++i) + { + pReadBuff_[i] = 0; + } + } + catch (const std::bad_alloc &ba) + { + std::ostringstream oss; + oss << "-> TCPSocket::initReadBuff(), " << ba.what() << std::endl; + throw std::exception(oss.str().c_str()); // rethrow w/ more info + } +} + +//----------------------------------------------------------------------------- + +SOCKET Socket::getSocket() const +{ + return socket_; +} + +//----------------------------------------------------------------------------- + +void Socket::stop() +{ + pQuitEvent_->set(); +} + +//----------------------------------------------------------------------------- + +void Socket::setWriteBuff(char *pWriteBuff, unsigned int length) +{ + if(pWriteBuff != NULL) + { + pWriteBuff_ = pWriteBuff; + writeBuffSize_ = length; + } +} + +//----------------------------------------------------------------------------- + +int Socket::getLocalPort() +{ + int port = 0; + + struct sockaddr_in sin; + int len = sizeof(sin); + if (getsockname(socket_, (struct sockaddr *)&sin, &len) != -1) + port = ntohs(sin.sin_port); + + return port; +} + +//----------------------------------------------------------------------------- + +void Socket::startUp() +{ + WSADATA wsaData; + WORD version = MAKEWORD(2, 2); + + int err = ::WSAStartup(version, &wsaData); + + if (err != 0) + { + std::string errStr(std::string(__FUNCTION_NAME__)); + + switch (err) + { + case WSASYSNOTREADY: + errStr += "network subsystem not ready for network communication\n"; + break; + + case WSAVERNOTSUPPORTED: + errStr += "winsock version support requested not provided\n"; + break; + + case WSAEINPROGRESS: + errStr += "blocking Windows Sockets 1.1 operation is in progress\n"; + break; + + case WSAEPROCLIM: + errStr += "limit on number of tasks has been reached\n"; + break; + + case WSAEFAULT: + errStr += "the lpWSAData is not a valid pointer\n"; + break; + + default: + errStr += "unknown error\n"; + break; + } + + throw Exception(__FUNCTION_NAME__, errStr); + } +} + +//----------------------------------------------------------------------------- + +bool Socket::isHostReachable(std::string host, unsigned long maxHops) +{ + bool hostReachable = false; + startUp(); + + unsigned long hops_count, rtt; + + std::string ip = convertHostnameToIp(host); + + sockaddr_in clientAddr; + ::ZeroMemory(&clientAddr, sizeof(clientAddr)); + clientAddr.sin_family = AF_INET; + ::inet_pton(clientAddr.sin_family, ip.c_str(), &(clientAddr.sin_addr)); + + if (::GetRTTAndHopCount(clientAddr.sin_addr.s_addr, &hops_count, maxHops, &rtt)) + { + hostReachable = true; + } + + return hostReachable; +} \ No newline at end of file diff --git a/CommonLib/src/Common/Comm/Socket.hpp b/CommonLib/src/Common/Comm/Socket.hpp new file mode 100644 index 0000000..e4be2ca --- /dev/null +++ b/CommonLib/src/Common/Comm/Socket.hpp @@ -0,0 +1,298 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#include "NTEvent.hpp" +class NTMutex; + +class Socket //: public Comm +{ +public: + enum + { + READ_BUF_SIZE_DEFAULT = 15000 + }; + + //>--------------------------------------------------------------------- + // Function: Socket() + // + // Purpose: + // just create SOCKET (wait for connect) + //---------------------------------------------------------------------- + // Arguments: + // readTimeout - timeout for the read() (milliseconds) + // writeTimeout - timeout for the write() (milliseconds) + // readSize - + //---------------------------------------------------------------------- + // Return Value: none + //<---------------------------------------------------------------------*/ + Socket(DWORD readTimeout = ULONG_MAX, + DWORD writeTimeout = ULONG_MAX, + unsigned int readSize = READ_BUF_SIZE_DEFAULT); + + //>--------------------------------------------------------------------- + // Function: Socket() + // + // Purpose: + // assuming already connected + //---------------------------------------------------------------------- + // Arguments: + // socket - + // readSize - + //---------------------------------------------------------------------- + // Return Value: none + //<---------------------------------------------------------------------*/ + Socket(SOCKET socket, unsigned int readSize = READ_BUF_SIZE_DEFAULT); + + //>--------------------------------------------------------------------- + // Function: Socket() + // + // Purpose: + // create SOCKET and connect + //---------------------------------------------------------------------- + // Arguments: + // address - + // readSize - + //---------------------------------------------------------------------- + // Return Value: none + //<---------------------------------------------------------------------*/ + Socket(const std::string& address, + unsigned int remotePort, + DWORD readTimeout = ULONG_MAX, + DWORD writeTimeout = ULONG_MAX, + unsigned int readSize = READ_BUF_SIZE_DEFAULT); + + //>--------------------------------------------------------------------- + // Function: Socket() + // + // Purpose: + // create SOCKET and connect + //---------------------------------------------------------------------- + // Arguments: + // address - + // readSize - + //---------------------------------------------------------------------- + // Return Value: none + //<---------------------------------------------------------------------*/ + Socket(const std::string& address, + unsigned int remotePort, + unsigned int localPort, + DWORD readTimeout = ULONG_MAX, + DWORD writeTimeout = ULONG_MAX, + unsigned int readSize = READ_BUF_SIZE_DEFAULT); + + //>--------------------------------------------------------------------- + // Function: Socket() + // + // Purpose: + // create SOCKET and bind + //---------------------------------------------------------------------- + // Arguments: + // socket - + // readSize - + //---------------------------------------------------------------------- + // Return Value: none + //<---------------------------------------------------------------------*/ + Socket(const std::string& address, + unsigned int remotePort, + bool bind, + DWORD readTimeout = ULONG_MAX, + DWORD writeTimeout = ULONG_MAX, + unsigned int readSize = READ_BUF_SIZE_DEFAULT); + + //>--------------------------------------------------------------------- + // Function: ~Socket() + // + // Purpose: + /// destructor + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + virtual ~Socket(); + + //>--------------------------------------------------------------------------- + // Function: connect + // + // Purpose: + /// Performs the processing to connect a socket to a given client + //---------------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------------- + // + // Return Value: none + //----------------------------------------------------------------------------*/ + virtual void connect(const std::string& address, int port) = 0; + + //>--------------------------------------------------------------------- + // Function: getSocket() + // + // Purpose: + /// to get the socket handle + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: SOCKET, the client socket + //<---------------------------------------------------------------------*/ + SOCKET getSocket() const; + + //>--------------------------------------------------------------------- + // Function: AcceptConnection() + // + // Purpose: + /// waits for connection + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: SOCKET, the client socket + //<---------------------------------------------------------------------*/ + virtual void AcceptConnection() = 0; + + //>--------------------------------------------------------------------- + // Function: read() + // + // Purpose: + /// to read data from the socket + //---------------------------------------------------------------------- + // Arguments: readTimeout - amt of time(milliseconds) to wait on a + // socket read + //---------------------------------------------------------------------- + // + // Return Value: ErrorNameTable::Number + //<---------------------------------------------------------------------*/ + virtual void read(DWORD readTimeout = ULONG_MAX) = 0; + + //>--------------------------------------------------------------------------- + // Function: stop + // + // Purpose: + // DESCRIBE_PURPOSE_HERE + //---------------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------------- + // + // Return Value: none + //----------------------------------------------------------------------------*/ + void stop(); + + //>--------------------------------------------------------------------- + // Function: write() + // + // Purpose: + /// to write to the socket + //---------------------------------------------------------------------- + // Arguments: unsigned int numToSend_ + //---------------------------------------------------------------------- + // + // Return Value: ErrorNameTable::Number + //<---------------------------------------------------------------------*/ + virtual void write(unsigned int numToSend) = 0; + + //>--------------------------------------------------------------------- + // Function: isHostReachable() + // + // Purpose: + /// find out if an IP is reachable. We want to be able to quickly determine + // if an IP is reachable. This is dependent on maxHops parameter. + //---------------------------------------------------------------------- + // Arguments + // host - can be a hostname or ip address + // maxHops - number of hops to get to the host, the more hops, the longer + // it takes to return from the function. If the host is within + // the same subnet, use maxhop of 1. If going outside of subnet + // then increase maxHops accordingly + //---------------------------------------------------------------------- + // Return Value: true/false + //<---------------------------------------------------------------------*/ + static bool isHostReachable(std::string host, unsigned long maxHops = 1); + + // bunch o' set/get member functions + char *getWriteBuff() { return pWriteBuff_; } + void setWriteBuff(char *pWriteBuff, unsigned int length); + unsigned int getRemotePort() { return remotePort_; } + std::string getRemoteAddress() { return remoteAddress_;} + char *getReadBuff() { return pReadBuff_; } + unsigned int getNumRead() const { return numRead_; } + void setNumRead(unsigned int numRead) { numRead_ = numRead; } + unsigned int getNumWritten() const { return numWritten_; } + void setNumWritten(unsigned int numWritten) { numWritten_ = numWritten; } + unsigned int getReadBuffSize() const { return readBuffSize_; } + NTMutex* getSocketMutex() { return pSocketMutex_; } + unsigned int getWriteBuffSize() const { return writeBuffSize_; } + unsigned int getNumToSend() const { return numToSend_; } + void setNumToSend(unsigned int numToSend) { numToSend_ = numToSend; } + bool isUDP(){return isUdp_;} + int getLocalPort(); + +protected: + + enum Handles + { + QUIT, + OVERLAP + }; + + static std::string convertHostnameToIp(std::string hostname); + void createEvents(); + void initReadBuff(unsigned int readSize); + + // the idea with the next 2 buffers is to use an external write + // buffer and an internal read buffer + char *pReadBuff_; // do not delete + char *pWriteBuff_; // do not delete + unsigned int bytesRead_; + unsigned int bytesWritten_; + unsigned int readBuffSize_; + unsigned int writeBuffSize_; + unsigned int numToSend_; + unsigned int numRead_; + unsigned int numWritten_; + + std::string remoteAddress_; + unsigned int remotePort_; + unsigned int localPort_; + NTEvent* pQuitEvent_; // we delete + NTEvent* pReadEvent_; // we delete + NTEvent* pWriteEvent_; // we delete + HANDLE readHandles[2]; + DWORD readTimeout_; + SOCKET socket_; + SOCKET listenSocket_; + HANDLE writeHandles[2]; + DWORD writeTimeout_; + NTMutex* pSocketMutex_; + bool isUdp_; + +private: + // do not allow + Socket(const Socket& rhs); + Socket &operator=(const Socket& rhs) {} + + //>--------------------------------------------------------------------------- + // Function: startUp + // + // Purpose: + /// call WSAStartup + //---------------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------------- + // + // Return Value: none + //----------------------------------------------------------------------------*/ + static void startUp(); +}; diff --git a/CommonLib/src/Common/Comm/TCPSocket.cpp b/CommonLib/src/Common/Comm/TCPSocket.cpp new file mode 100644 index 0000000..871bd01 --- /dev/null +++ b/CommonLib/src/Common/Comm/TCPSocket.cpp @@ -0,0 +1,974 @@ +#include +#include + +#include "TCPSocket.hpp" +#include "Exception.hpp" +#include "ErrorLog.hpp" +#include "NTEvent.hpp" +#include "TimeoutError.hpp" +#include "Mstcpip.h" + +//----------------------------------------------------------------------------- + +TCPSocket::TCPSocket(DWORD readTimeout, + DWORD writeTimeout, + unsigned int readSize) : + Socket(readTimeout, writeTimeout, readSize), + enableTcpKeepAlive_(false), + waitForOverlapIoToComplete_(TRUE) +{ + try + { + initReadBuff(readSize); + + socket_ = ::WSASocketW(AF_INET, // Address family specification + SOCK_STREAM, // Socket Type + IPPROTO_IP, // Socket Protocol + NULL, // lpProtocolInfo + 0, // group - reserved + WSA_FLAG_OVERLAPPED); + + if (socket_ == INVALID_SOCKET) + { + std::stringstream ss; + ss << "::WSASocket() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + if (enableTcpKeepAlive_) + { + DWORD dwBytesRet = 0; + struct tcp_keepalive keepAliveOpts; + // enable TCP kee-palive + keepAliveOpts.onoff = TRUE; + // interval, in milliseconds, between when successive keep-alive packets are sent if no acknowledgement is received + keepAliveOpts.keepaliveinterval = 1000; + // timeout, in milliseconds, with no activity with the remote host before first keep-alive packet is sent + keepAliveOpts.keepalivetime = 10000; + + // set the TCP keep-alive option for the socket + if (::WSAIoctl(socket_, SIO_KEEPALIVE_VALS, &keepAliveOpts, sizeof(keepAliveOpts), NULL, 0, + &dwBytesRet, NULL, NULL) == SOCKET_ERROR) + { + std::stringstream ss; + ss << "::WSAIoctl() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + } + + createEvents(); + + readHandles[QUIT] = pQuitEvent_->getHandle(); + readHandles[OVERLAP] = pReadEvent_->getHandle(); + writeHandles[QUIT] = pQuitEvent_->getHandle(); + writeHandles[OVERLAP] = pWriteEvent_->getHandle(); + + readBuffer_.len = getReadBuffSize(); + readBuffer_.buf = getReadBuff(); + + ::ZeroMemory(&readOverlapped_, sizeof(OVERLAPPED)); + readOverlapped_.hEvent = pReadEvent_->getHandle(); + } + catch (Exception& e) + { + if (pReadBuff_ != NULL) + { + delete[] pReadBuff_; + pReadBuff_ = NULL; + } + + if (pQuitEvent_ != NULL) + { + delete pQuitEvent_; + pQuitEvent_ = NULL; + } + + if (pReadEvent_ != NULL) + { + delete pReadEvent_; + pReadEvent_ = NULL; + } + + if (pWriteEvent_ != NULL) + { + delete pWriteEvent_; + pWriteEvent_ = NULL; + } + + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } + catch (...) + { + if (pReadBuff_ != NULL) + { + delete[] pReadBuff_; + pReadBuff_ = NULL; + } + + if (pQuitEvent_ != NULL) + { + delete pQuitEvent_; + pQuitEvent_ = NULL; + } + + if (pReadEvent_ != NULL) + { + delete pReadEvent_; + pReadEvent_ = NULL; + } + + if (pWriteEvent_ != NULL) + { + delete pWriteEvent_; + pWriteEvent_ = NULL; + } + + throw Exception(__FUNCTION_NAME__, "caught (...)"); + } +} + +//----------------------------------------------------------------------------- + +TCPSocket::TCPSocket(SOCKET socket, unsigned int readSize) : + Socket(socket, readSize), + enableTcpKeepAlive_(false), + waitForOverlapIoToComplete_(TRUE) +{ + try + { + initReadBuff(readSize); + + // assuming that socket has already been connected + createEvents(); + + readHandles[QUIT] = pQuitEvent_->getHandle(); + readHandles[OVERLAP] = pReadEvent_->getHandle(); + writeHandles[QUIT] = pQuitEvent_->getHandle(); + writeHandles[OVERLAP] = pWriteEvent_->getHandle(); + + // get address and port + sockaddr_in name; + int len = sizeof(sockaddr); + ::getpeername(socket_, reinterpret_cast(&name), &len); + + char ipstr[INET_ADDRSTRLEN]; + inet_ntop(name.sin_family, &name.sin_addr, ipstr, sizeof(ipstr)); + + remotePort_ = name.sin_port; + remoteAddress_ = std::string(ipstr); + + readBuffer_.len = getReadBuffSize(); + readBuffer_.buf = getReadBuff(); + + ::ZeroMemory(&readOverlapped_, sizeof(OVERLAPPED)); + readOverlapped_.hEvent = pReadEvent_->getHandle(); + } + catch (Exception& e) + { + if (pReadBuff_ != NULL) + { + delete[] pReadBuff_; + pReadBuff_ = NULL; + } + + if (pQuitEvent_ != NULL) + { + delete pQuitEvent_; + pQuitEvent_ = NULL; + } + + if (pReadEvent_ != NULL) + { + delete pReadEvent_; + pReadEvent_ = NULL; + } + + if (pWriteEvent_ != NULL) + { + delete pWriteEvent_; + pWriteEvent_ = NULL; + } + + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } + catch (...) + { + if (pReadBuff_ != NULL) + { + delete[] pReadBuff_; + pReadBuff_ = NULL; + } + + if (pQuitEvent_ != NULL) + { + delete pQuitEvent_; + pQuitEvent_ = NULL; + } + + if (pReadEvent_ != NULL) + { + delete pReadEvent_; + pReadEvent_ = NULL; + } + + if (pWriteEvent_ != NULL) + { + delete pWriteEvent_; + pWriteEvent_ = NULL; + } + + throw Exception(__FUNCTION_NAME__, "caught (...)"); + } +} + +//----------------------------------------------------------------------------- + +TCPSocket::TCPSocket(const std::string& address, + unsigned int remotePort, + bool enableTcpKeepAlive, + BOOL waitForOverlapIoToComplete, + DWORD readTimeout, + DWORD writeTimeout, + unsigned int readSize) : + Socket(address, remotePort, readTimeout, writeTimeout, readSize), + enableTcpKeepAlive_(enableTcpKeepAlive), + waitForOverlapIoToComplete_(waitForOverlapIoToComplete) +{ + try + { + initReadBuff(readSize); + + socket_ = ::WSASocketW(AF_INET, // Address family specification + SOCK_STREAM, // Socket Type + IPPROTO_IP, // Socket Protocol + NULL, // lpProtocolInfo + 0, // group - reserved + WSA_FLAG_OVERLAPPED); + + if (socket_ == INVALID_SOCKET) + { + std::stringstream ss; + ss << "::WSASocket() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + if (enableTcpKeepAlive_) + { + DWORD dwBytesRet = 0; + struct tcp_keepalive keepAliveOpts; + // enable TCP kee-palive + keepAliveOpts.onoff = TRUE; + // interval, in milliseconds, between when successive keep-alive packets are sent if no acknowledgement is received + keepAliveOpts.keepaliveinterval = 1000; + // timeout, in milliseconds, with no activity with the remote host before first keep-alive packet is sent + keepAliveOpts.keepalivetime = 10000; + + // set the TCP keep-alive option for the socket + if (::WSAIoctl(socket_, SIO_KEEPALIVE_VALS, &keepAliveOpts, sizeof(keepAliveOpts), NULL, 0, + &dwBytesRet, NULL, NULL) == SOCKET_ERROR) + { + std::stringstream ss; + ss << "::WSAIoctl() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + } + + connect(); + + createEvents(); + + readHandles[QUIT] = pQuitEvent_->getHandle(); + readHandles[OVERLAP] = pReadEvent_->getHandle(); + writeHandles[QUIT] = pQuitEvent_->getHandle(); + writeHandles[OVERLAP] = pWriteEvent_->getHandle(); + + readBuffer_.len = getReadBuffSize(); + readBuffer_.buf = getReadBuff(); + + ::ZeroMemory(&readOverlapped_, sizeof(OVERLAPPED)); + readOverlapped_.hEvent = pReadEvent_->getHandle(); + } + catch (Exception& e) + { + if (pReadBuff_ != NULL) + { + delete[] pReadBuff_; + pReadBuff_ = 0; + } + + if (pQuitEvent_ != NULL) + { + delete pQuitEvent_; + pQuitEvent_ = 0; + } + + if (pReadEvent_ != NULL) + { + delete pReadEvent_; + pReadEvent_ = 0; + } + + if (pWriteEvent_ != NULL) + { + delete pWriteEvent_; + pWriteEvent_ = 0; + } + + if (pSocketMutex_ != NULL) + { + delete pSocketMutex_; + pSocketMutex_ = 0; + } + + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } + catch (...) + { + if (pReadBuff_ != NULL) + { + delete[] pReadBuff_; + pReadBuff_ = 0; + } + + if (pQuitEvent_ != NULL) + { + delete pQuitEvent_; + pQuitEvent_ = 0; + } + + if (pReadEvent_ != NULL) + { + delete pReadEvent_; + pReadEvent_ = 0; + } + + if (pWriteEvent_ != NULL) + { + delete pWriteEvent_; + pWriteEvent_ = 0; + } + + if (pSocketMutex_ != NULL) + { + delete pSocketMutex_; + pSocketMutex_ = 0; + } + + throw Exception(__FUNCTION_NAME__, "caught (...)"); + } +} + +//----------------------------------------------------------------------------- + +TCPSocket::TCPSocket(const std::string& address, + unsigned int remotePort, + bool bindPort, + bool enableTcpKeepAlive, + BOOL waitForOverlapIoToComplete, + DWORD readTimeout, + DWORD writeTimeout, + unsigned int readSize) : + Socket(address, remotePort, bindPort, readTimeout, writeTimeout, readSize), + enableTcpKeepAlive_(enableTcpKeepAlive), + waitForOverlapIoToComplete_(waitForOverlapIoToComplete) +{ + try + { + if (!bindPort) + { + TCPSocket(address, remotePort, enableTcpKeepAlive, waitForOverlapIoToComplete_, readTimeout, writeTimeout, readSize); + return; + } + + initReadBuff(readSize); + + listenSocket_ = ::socket(AF_INET, // Address family specification + SOCK_STREAM, // Socket Type + IPPROTO_TCP); + + if (listenSocket_ == INVALID_SOCKET) + { + std::stringstream ss; + ss << "::WSASocket() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + bind(); + + createEvents(); + + readHandles[QUIT] = pQuitEvent_->getHandle(); + readHandles[OVERLAP] = pReadEvent_->getHandle(); + writeHandles[QUIT] = pQuitEvent_->getHandle(); + writeHandles[OVERLAP] = pWriteEvent_->getHandle(); + + readBuffer_.len = getReadBuffSize(); + readBuffer_.buf = getReadBuff(); + + ::ZeroMemory(&readOverlapped_, sizeof(OVERLAPPED)); + readOverlapped_.hEvent = pReadEvent_->getHandle(); + } + catch (Exception& e) + { + if (pReadBuff_ != NULL) + { + delete[] pReadBuff_; + pReadBuff_ = 0; + } + + if (pQuitEvent_ != NULL) + { + delete pQuitEvent_; + pQuitEvent_ = 0; + } + + if (pReadEvent_ != NULL) + { + delete pReadEvent_; + pReadEvent_ = 0; + } + + if (pWriteEvent_ != NULL) + { + delete pWriteEvent_; + pWriteEvent_ = 0; + } + + if (pSocketMutex_ != NULL) + { + delete pSocketMutex_; + pSocketMutex_ = 0; + } + + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } + catch (...) + { + if (pReadBuff_ != NULL) + { + delete[] pReadBuff_; + pReadBuff_ = 0; + } + + if (pQuitEvent_ != NULL) + { + delete pQuitEvent_; + pQuitEvent_ = 0; + } + + if (pReadEvent_ != NULL) + { + delete pReadEvent_; + pReadEvent_ = 0; + } + + if (pWriteEvent_ != NULL) + { + delete pWriteEvent_; + pWriteEvent_ = 0; + } + + if (pSocketMutex_ != NULL) + { + delete pSocketMutex_; + pSocketMutex_ = 0; + } + + throw Exception(__FUNCTION_NAME__, "caught (...)"); + } +} + + +//----------------------------------------------------------------------------- + +TCPSocket::~TCPSocket() +{ +} + +//----------------------------------------------------------------------------- + +void TCPSocket::connect(const std::string& address, int port) +{ + assert(socket_ != INVALID_SOCKET); + + remoteAddress_ = convertHostnameToIp(address); + remotePort_ = port; + + connect(); +} + +//----------------------------------------------------------------------------- + +void TCPSocket::connect() +{ + sockaddr_in addr; + + if (!isHostReachable(remoteAddress_)) + { + throw Exception(__FUNCTION_NAME__, "Unable to reach host: " + remoteAddress_); + } + + // build the client sockadr struct + ::ZeroMemory(&addr, sizeof(addr)); + addr.sin_family = AF_INET; + inet_pton(addr.sin_family, remoteAddress_.c_str(), &(addr.sin_addr)); + addr.sin_port = htons(static_cast(remotePort_)); + + // set option to not linger after closing + linger lingerData; + lingerData.l_onoff = 1; + lingerData.l_linger = 0; + + int err = ::setsockopt(socket_, + SOL_SOCKET, + SO_LINGER, + reinterpret_cast(&lingerData), + sizeof(linger)); + + if (err == SOCKET_ERROR) + { + std::stringstream ss; + ss << "::setsockopt() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + int recBuff = 1048576; + err = ::setsockopt(socket_, + SOL_SOCKET, + SO_RCVBUF, + reinterpret_cast(&recBuff), + sizeof(recBuff)); + + if (err == SOCKET_ERROR) + { + std::stringstream ss; + ss << "::setsockopt() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + + err = ::connect(socket_, + reinterpret_cast(&addr), + sizeof(sockaddr_in)); + + if (err == SOCKET_ERROR) + { + std::stringstream ss; + ss << "::connect() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } +} + +//----------------------------------------------------------------------------- + +void TCPSocket::bind() +{ + // build the client sockadr struct + sockaddr_in addr; + + ::ZeroMemory(&addr, sizeof(addr)); + addr.sin_family = AF_INET; + inet_pton(addr.sin_family, "127.0.0.1", &(addr.sin_addr)); + addr.sin_port = htons(static_cast(remotePort_)); + + // set option to not linger after closing + linger lingerData; + lingerData.l_onoff = 1; + lingerData.l_linger = 0; + + int err = ::bind(listenSocket_, + reinterpret_cast(&addr), + sizeof(addr)); + + if (err == SOCKET_ERROR) + { + std::stringstream ss; + ss << "::bind() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + err = ::listen(listenSocket_, SOMAXCONN); + + if (err == SOCKET_ERROR) + { + std::stringstream ss; + ss << "::listen() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + +} +//----------------------------------------------------------------------------- + +void TCPSocket::AcceptConnection() +{ + socket_ = ::accept(listenSocket_, NULL, NULL); + + if (socket_ == INVALID_SOCKET) + { + std::stringstream ss; + ss << "::accept() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } +} + +//----------------------------------------------------------------------------- + +void TCPSocket::closeSocket() +{ + ::closesocket(socket_); +} + +//----------------------------------------------------------------------------- + +void TCPSocket::read(DWORD readTimeout) +{ + DWORD flags = 0; + DWORD numRecvd = 0; + int ret1; + int err; + DWORD ret2 = 0; + DWORD timeout = 0; + + if (readTimeout == ULONG_MAX) + { + timeout = readTimeout_; + } + else + { + timeout = readTimeout; + } + + setNumRead(0); // no data read, so reset the counter + + ret1 = ::WSARecv(socket_, + &readBuffer_, + 1, + &numRecvd, + &flags, + &readOverlapped_, + NULL); + + if (ret1 == SOCKET_ERROR) + { + std::ostringstream oss; + + err = ::WSAGetLastError(); + + oss << "::WSARecv() error code " << static_cast(::WSAGetLastError()); + + switch (err) + { + case WSA_IO_PENDING: + + ret2 = ::WaitForMultipleObjects(2, readHandles, false, timeout); + + if (ret2 == WAIT_FAILED) + { + throw Exception(__FUNCTION_NAME__, "::WaitForSingleObject() failed"); + } + else if (ret2 == WAIT_TIMEOUT) + { + // cancel all pending I/O and therefore free the overlap so we can use it in the next read + ::CancelIo(reinterpret_cast(socket_)); + throw TimeoutError(__FUNCTION_NAME__, "WaitForMultipleObjects() timed out"); + } + else if ((ret2 - WAIT_OBJECT_0) == OVERLAP) + { + if (!::WSAGetOverlappedResult(socket_, + &readOverlapped_, + &numRecvd, + waitForOverlapIoToComplete_, + &flags)) + { + int resultErr = ::WSAGetLastError(); + + switch (resultErr) + { + case WSAECONNRESET: + ::closesocket(socket_); + throw Exception(__FUNCTION_NAME__, "connection closed by remote host"); + break; + case WSAECONNABORTED: // intentional fall-through + ::closesocket(socket_); + throw Exception(__FUNCTION_NAME__, "connection closed by local host"); + break; + + default: + { + std::stringstream ss; + ss << "::WSAGetOverlappedResult() error code: " << static_cast(resultErr); + + throw Exception(__FUNCTION_NAME__, ss.str()); + } + break; + } + } + } + else if ((ret2 - WAIT_OBJECT_0) == QUIT) + { + //don't log errlog.write("TCPSocket::read() - quit event set, exit function",ErrorLog::INFO); + return; + } + else if (ret2 >= WAIT_ABANDONED_0) + { + return; + } + else + { + return; + } + + break; + + case WSAENOTSOCK: + ::closesocket(socket_); + throw Exception(__FUNCTION_NAME__, "socket died"); + break; + case WSAECONNRESET: + + case WSAENOTCONN: + ::closesocket(socket_); + throw Exception(__FUNCTION_NAME__, "connection closed by remote host"); + break; + case WSAENOBUFS: + ::closesocket(socket_); + throw Exception(__FUNCTION_NAME__, oss.str()); + break; + + case WSAEMSGSIZE: + ::closesocket(socket_); + throw Exception(__FUNCTION_NAME__, "Receive Buffer is too small for incoming message."); + break; + + case WSA_OPERATION_ABORTED: // fall through for now + default: + ::closesocket(socket_); + throw Exception(__FUNCTION_NAME__, oss.str()); + } + } + + setNumRead(static_cast(numRecvd)); + + // make sure we are zero terminated...want to go one past the data + if ((numRecvd < getReadBuffSize()) && (getReadBuff()[getNumRead()] != 0)) + { + getReadBuff()[numRecvd] = 0; + } +} + +//----------------------------------------------------------------------------- + +void TCPSocket::write(unsigned int numToSend) +{ + if (numToSend != 0) + { + setNumToSend(numToSend); + } + else + { + setNumToSend(getWriteBuffSize()); + } + + WSABUF writeBuffer; + writeBuffer.len = getNumToSend(); + writeBuffer.buf = getWriteBuff(); + + DWORD numSent; + DWORD flags = 0; + DWORD ret2 = 0; + + OVERLAPPED writeOverlapped; + ::ZeroMemory(&writeOverlapped, sizeof(OVERLAPPED)); + writeOverlapped.hEvent = pWriteEvent_->getHandle(); + + int num = ::WSASend(socket_, + &writeBuffer, + 1, + &numSent, + flags, + &writeOverlapped, + NULL); + + if (num == SOCKET_ERROR) + { + std::ostringstream oss; + int err = ::WSAGetLastError(); + + switch (err) + { + case WSA_IO_PENDING: + ret2 = ::WaitForSingleObject(pWriteEvent_->getHandle(), writeTimeout_); + + if (ret2 == WAIT_FAILED) + { + err = ::closesocket(socket_); // ignore err value here + + throw Exception(__FUNCTION_NAME__, "::WaitForSingleObject() failed"); + } + else if (ret2 == WAIT_TIMEOUT) + { + err = ::closesocket(socket_); // ignore err value here + + throw TimeoutError(__FUNCTION_NAME__, "WaitForMultipleObjects() timed out"); + } + else if (ret2 == WAIT_OBJECT_0) + { + pWriteEvent_->reset(); + + if (!::WSAGetOverlappedResult(socket_, + &writeOverlapped, + &numSent, + FALSE, + &flags)) + { + int resultErr = ::WSAGetLastError(); + + switch (resultErr) + { + case WSAECONNRESET: + ::closesocket(socket_); + throw Exception(__FUNCTION_NAME__, "connection closed by remote host"); + break; + case WSAECONNABORTED: // intentional fall-through + ::closesocket(socket_); // ignore err value here + + throw Exception(__FUNCTION_NAME__, "connection closed by local host"); + break; + + default: + { + std::stringstream ss; + ss << "::WSAGetOverlappedResult() error code: " << static_cast(resultErr); + + throw Exception(__FUNCTION_NAME__, ss.str()); + } + break; + } + } + } + else // event abandoned + { + return; + } + + break; + + case WSAECONNREFUSED: // intentional fall-throughs + case WSAECONNABORTED: + throw Exception(__FUNCTION_NAME__, oss.str()); + break; + case WSAECONNRESET: // connection aborted by remote host + ::closesocket(socket_); + throw Exception(__FUNCTION_NAME__, "connection closed by remote host"); + break; + case WSAENOTSOCK: + ::closesocket(socket_); + throw Exception(__FUNCTION_NAME__, "socket died"); + break; + + default: + ::closesocket(socket_); // ignore return + throw Exception(__FUNCTION_NAME__, oss.str()); + break; + } + } + + setNumWritten(static_cast(num)); +} + +//------------------------------------------------------------------------ + +void TCPSocket::reconnect() +{ + try + { + disconnect(); + + socket_ = ::WSASocketW(AF_INET, // Address family specification + SOCK_STREAM, // Socket Type + IPPROTO_IP, // Socket Protocol + NULL, // lpProtocolInfo + 0, // group - reserved + WSA_FLAG_OVERLAPPED); + + if (socket_ == INVALID_SOCKET) + { + std::stringstream ss; + ss << "::WSASocket() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + connect(); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } + catch (...) + { + throw Exception(__FUNCTION_NAME__, "caught unknown error"); + } + +} + +//----------------------------------------------------------------------------- + +void TCPSocket::disconnect() + +{ + int shutdownret = ::shutdown(socket_, SD_BOTH); + if (shutdownret != 0) + { + DWORD err = ::GetLastError(); + if ((err != WSAENOTCONN) && (err != WSAENOTSOCK)) // reconnect will be attempted multiple times, allow + { + std::stringstream ss; + ss << "::shutdown() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + } + int closesocketret = ::closesocket(socket_); + if (closesocketret != 0) + { + DWORD err = ::GetLastError(); + if (err != WSAENOTSOCK) // reconnect will be attempted multiple times, allow + { + std::stringstream ss; + ss << "::closesocket() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + } +} + +//----------------------------------------------------------------------------- + +std::string TCPSocket::getLocalIp() +{ + sockaddr_in sin; + socklen_t len = sizeof(sockaddr_in); + // want to get local socket info + getsockname(getSocket(), (sockaddr*)&sin, &len); + + char servInfo[NI_MAXSERV]; + char hostname[NI_MAXHOST]; + + // we want to get the name of the local computer + DWORD dwRetval = getnameinfo((struct sockaddr*)&sin, + sizeof(struct sockaddr), + hostname, + NI_MAXHOST, servInfo, NI_MAXSERV, NI_NUMERICSERV); + + if (dwRetval != 0) + { + std::stringstream ss; + ss << "getnameinfo() failed with error : " << WSAGetLastError(); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + return convertHostnameToIp(std::string(hostname)); +} \ No newline at end of file diff --git a/CommonLib/src/Common/Comm/TCPSocket.hpp b/CommonLib/src/Common/Comm/TCPSocket.hpp new file mode 100644 index 0000000..ff7830b --- /dev/null +++ b/CommonLib/src/Common/Comm/TCPSocket.hpp @@ -0,0 +1,231 @@ +#pragma once + +#include + +#include +#include +#include + +#include "NTEvent.hpp" +#include "Socket.hpp" + +class NTMutex; + +class TCPSocket : public Socket +{ +public: + + //>--------------------------------------------------------------------- + // Function: TCPSocket() + // + // Purpose: + /// constructor + //---------------------------------------------------------------------- + // Arguments: + /** \param readTimeout - timeout for the read() (milliseconds) + // \param writeTimeout - timeout for the write() (milliseconds) + // \param readSize - + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + TCPSocket(DWORD readTimeout = ULONG_MAX, + DWORD writeTimeout = ULONG_MAX, + unsigned int readSize = READ_BUF_SIZE_DEFAULT); // just create SOCKET (wait for connect) + + TCPSocket(SOCKET socket, unsigned int readSize = READ_BUF_SIZE_DEFAULT); // assuming already connected + + // create SOCKET and connect + TCPSocket(const std::string& address, + unsigned int remotePort, + bool enableTcpKeepAlive = false, + BOOL waitForOverlapIoToComplete = TRUE, + DWORD readTimeout = ULONG_MAX, + DWORD writeTimeout = ULONG_MAX, + unsigned int readSize = READ_BUF_SIZE_DEFAULT); + + // create SOCKET and bing + TCPSocket(const std::string& address, + unsigned int remotePort, + bool bind, + bool enableTcpKeepAlive = false, + BOOL waitForOverlapIoToComplete = TRUE, + DWORD readTimeout = ULONG_MAX, + DWORD writeTimeout = ULONG_MAX, + unsigned int readSize = READ_BUF_SIZE_DEFAULT); + + //>--------------------------------------------------------------------- + // Function: ~TCPSocket() + // + // Purpose: + /// destructor + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + virtual ~TCPSocket(); + + //>--------------------------------------------------------------------------- + // Function: connect + // + // Purpose: + /// Performs the processing to connect a socket to a given client + //---------------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------------- + // + // Return Value: none + //----------------------------------------------------------------------------*/ + virtual void connect(const std::string& address, int port); + + //>--------------------------------------------------------------------- + // Function: AcceptConnection() + // + // Purpose: + /// waits for connection + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: SOCKET, the client socket + //<---------------------------------------------------------------------*/ + virtual void AcceptConnection(); + + //>--------------------------------------------------------------------- + // Function: read() + // + // Purpose: + /// to read data from the socket + //---------------------------------------------------------------------- + // Arguments: readTimeout - amt of time(milliseconds) to wait on a + // socket read + //---------------------------------------------------------------------- + // + // Return Value: ErrorNameTable::Number + //<---------------------------------------------------------------------*/ + virtual void read(DWORD readTimeout = ULONG_MAX); + + //>--------------------------------------------------------------------------- + // Function: stop + // + // Purpose: + // DESCRIBE_PURPOSE_HERE + //---------------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------------- + // + // Return Value: none + //---------------------------------------------------------------------------- + //void stop(); + + //>--------------------------------------------------------------------- + // Function: write() + // + // Purpose: + /// to write to the socket + //---------------------------------------------------------------------- + // Arguments: unsigned int numToSend_ + //---------------------------------------------------------------------- + // + // Return Value: ErrorNameTable::Number + //<---------------------------------------------------------------------*/ + virtual void write(unsigned int numToSend); + + //>--------------------------------------------------------------------- + // Function: closeSocket() + // + // Purpose: + /// closes the socket + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: void + //<---------------------------------------------------------------------*/ + void closeSocket(); + + //>--------------------------------------------------------------------- + // Function: reconnect() + // + // Purpose: reconnect socket_ to its port + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void reconnect(); + + //>--------------------------------------------------------------------- + // Function: disconnect() + // + // Purpose: disconnect socket_ from its port + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void disconnect(); + + //>--------------------------------------------------------------------- + // Function: getLocalIp() + // + // Purpose: get local Ip address + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: local ip + //<--------------------------------------------------------------------- + std::string getLocalIp(); + +private: + // do not allow + TCPSocket(const TCPSocket& rhs); + TCPSocket& operator=(const TCPSocket& rhs) {} + + //>--------------------------------------------------------------------- + // Function: bind() + // + // Purpose: + // binds socket_ to its port + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + void bind(); + + //>--------------------------------------------------------------------- + // Function: connect() + // + // Purpose: + // connects socket_ to its port + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + void connect(); + + enum Handles + { + QUIT, + OVERLAP + }; + + BOOL waitForOverlapIoToComplete_; + + WSABUF readBuffer_; + WSAOVERLAPPED readOverlapped_; + bool enableTcpKeepAlive_; +}; diff --git a/CommonLib/src/Common/Comm/UDPSocket.cpp b/CommonLib/src/Common/Comm/UDPSocket.cpp new file mode 100644 index 0000000..64255ef --- /dev/null +++ b/CommonLib/src/Common/Comm/UDPSocket.cpp @@ -0,0 +1,412 @@ +#include + +#include "UDPSocket.hpp" +#include "Exception.hpp" +#include "ErrorLog.hpp" +#include "NTEvent.hpp" +#include "TimeoutError.hpp" + +//------------------------------------------------------------------------ + +UDPSocket::UDPSocket(const std::string& addr, + unsigned int remotePort, + unsigned int localPort, + DWORD readTimeOut, + DWORD writeTimeOut, + unsigned int readSize) : + Socket(addr, remotePort, localPort, readTimeOut, writeTimeOut, readSize) +{ + try + { + //for debugging + isUdp_ = true; + + initReadBuff(readSize); + + socket_ = ::WSASocketW(AF_INET, + SOCK_DGRAM, + IPPROTO_UDP, + NULL, + 0, + WSA_FLAG_OVERLAPPED); + + if (socket_ == INVALID_SOCKET) + { + std::stringstream ss; + ss << "::WSASocket() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + connect(); + + createEvents(); + + readHandles[QUIT] = pQuitEvent_->getHandle(); + readHandles[OVERLAP] = pReadEvent_->getHandle(); + writeHandles[QUIT] = pQuitEvent_->getHandle(); + writeHandles[OVERLAP] = pWriteEvent_->getHandle(); + + readBuffer_.len = getReadBuffSize(); + readBuffer_.buf = getReadBuff(); + + ::ZeroMemory(&readOverlapped_, sizeof(OVERLAPPED)); + readOverlapped_.hEvent = pReadEvent_->getHandle(); + } + catch (Exception& e) + { + if (pReadBuff_ != NULL) + { + delete[] pReadBuff_; + pReadBuff_ = NULL; + } + + if (pQuitEvent_ != NULL) + { + delete pQuitEvent_; + pQuitEvent_ = NULL; + } + + if (pReadEvent_ != NULL) + { + delete pReadEvent_; + pReadEvent_ = NULL; + } + + if (pWriteEvent_ != NULL) + { + delete pWriteEvent_; + pWriteEvent_ = NULL; + } + + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } + catch (...) + { + if (pReadBuff_ != NULL) + { + delete[] pReadBuff_; + pReadBuff_ = NULL; + } + + if (pQuitEvent_ != NULL) + { + delete pQuitEvent_; + pQuitEvent_ = NULL; + } + + if (pReadEvent_ != NULL) + { + delete pReadEvent_; + pReadEvent_ = NULL; + } + + if (pWriteEvent_ != NULL) + { + delete pWriteEvent_; + pWriteEvent_ = NULL; + } + + throw Exception(__FUNCTION_NAME__, "caught (...)"); + } +} + +//------------------------------------------------------------------------ + +UDPSocket::~UDPSocket() +{ + if (socket_ != INVALID_SOCKET) + ::closesocket(socket_); +} + +//----------------------------------------------------------------------------- + +void UDPSocket::connect(const std::string& address, int port) +{ +} + +//------------------------------------------------------------------------ + +void UDPSocket::connect() +{ + DWORD dwBuf = 2; + int error = 0; + sockaddr_in localSockAddr; + + // Bind + ::ZeroMemory(&localSockAddr, sizeof(localSockAddr)); + localSockAddr.sin_family = AF_INET; + localSockAddr.sin_port = htons(static_cast(localPort_)); + localSockAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); + + error = ::setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&dwBuf), sizeof(dwBuf)); + if (error == SOCKET_ERROR) + { + std::stringstream ss; + ss << "::setsockopt(SO_REUSEADDR) error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + error = ::setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&dwBuf), sizeof(dwBuf)); + if (error == SOCKET_ERROR) + { + std::stringstream ss; + ss << "::setsockopt(SO_BROADCAST) error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + error = ::bind(socket_, reinterpret_cast(&localSockAddr), sizeof(localSockAddr)); + if (error == SOCKET_ERROR) + { + std::stringstream ss; + ss << "::bind() error code: " << static_cast(::WSAGetLastError()); + throw Exception(__FUNCTION_NAME__, ss.str()); + } +} + + +//----------------------------------------------------------------------------- + +void UDPSocket::AcceptConnection() +{ + +} + +//------------------------------------------------------------------------ + +void UDPSocket::read(DWORD readTimeOut) +{ + DWORD numRecvd = 0; + DWORD flags = 0; + DWORD ret2 = 0; + int ret1; + int err; + DWORD timeout = 0; + + if (readTimeOut == ULONG_MAX) + { + timeout = readTimeout_; + } + else + { + timeout = readTimeOut; + } + + ret1 = ::WSARecv(socket_, + &readBuffer_, + 1, + &numRecvd, + &flags, + &readOverlapped_, + NULL); + + if (ret1 == SOCKET_ERROR) + { + err = ::WSAGetLastError(); + + std::ostringstream oss; + + oss << "::WSARecvFrom() error code: " << static_cast(err); + + switch (err) + { + case WSAEINVAL: + case WSA_IO_PENDING: + + ret2 = ::WaitForMultipleObjects(2, readHandles, false, timeout); + + if (ret2 == WAIT_FAILED) + { + throw Exception(__FUNCTION_NAME__, "::WaitForSingleObject() failed"); + } + else if (ret2 == WAIT_TIMEOUT) + { + throw TimeoutError(__FUNCTION_NAME__, "WaitForMultipleObjects() timed out"); + } + else if ((ret2 - WAIT_OBJECT_0) == OVERLAP) + { + if (!::WSAGetOverlappedResult(socket_, + &readOverlapped_, + &numRecvd, + FALSE, + &flags)) + { + int resultErr = ::WSAGetLastError(); + + switch (resultErr) + { + case WSAECONNRESET: + case WSAECONNABORTED: // intentional fall-through + throw Exception(__FUNCTION_NAME__, "connection forcedfully closed"); + break; + + default: + { + std::stringstream ss; + ss << "::WSAGetOverlappedResult() error code: " << static_cast(resultErr); + + throw Exception(__FUNCTION_NAME__, ss.str()); + } + break; + } + } + } + else if ((ret2 - WAIT_OBJECT_0) == QUIT) + { + //don't log errLog.write("UDPSocket::read() - quit event set, exit function",ErrorLog::INFO); + return; + } + else if (ret2 >= WAIT_ABANDONED_0) + { + return; + } + else + { + return; + } + + break; + + case WSAECONNRESET: + case WSAENOTSOCK: // intentional fall-through + case WSAENOTCONN: + case WSAENOBUFS: + throw Exception(__FUNCTION_NAME__, oss.str()); + break; + + case WSAEMSGSIZE: + // The received message is larger then the buffer we provided + throw Exception(__FUNCTION_NAME__, "Receive Buffer is too small for incoming message."); + break; + + case WSA_OPERATION_ABORTED: // fall through for now + default: + throw Exception(__FUNCTION_NAME__, oss.str()); + } + } + + numRead_ = numRecvd; +} + +//------------------------------------------------------------------------ + +void UDPSocket::write(unsigned int numToSend) +{ + write(remoteAddress_, numToSend); +} + +//------------------------------------------------------------------------ + +void UDPSocket::write(std::string address, unsigned int numToSend) +{ + if (numToSend != 0) + { + setNumToSend(numToSend); + } + else + { + setNumToSend(getWriteBuffSize()); + } + + WSABUF writeBuffer; + writeBuffer.len = getNumToSend(); + writeBuffer.buf = getWriteBuff(); + + sockaddr_in SockAddr; + + ::ZeroMemory(&SockAddr, sizeof(SockAddr)); + SockAddr.sin_family = AF_INET; + SockAddr.sin_port = htons(static_cast(remotePort_)); + inet_pton(SockAddr.sin_family, address.c_str(), &(SockAddr.sin_addr)); + DWORD numSent; + DWORD flags = 0; + DWORD ret2 = 0; + + WSAOVERLAPPED writeOverlapped; + ::ZeroMemory(&writeOverlapped, sizeof(WSAOVERLAPPED)); + writeOverlapped.hEvent = pWriteEvent_->getHandle(); + + int ret1 = ::WSASendTo(socket_, &writeBuffer, 1, &numSent, flags, (SOCKADDR*)&SockAddr, sizeof(SockAddr), &writeOverlapped, NULL); + + if (ret1 == SOCKET_ERROR) + { + std::ostringstream oss; + int err = ::WSAGetLastError(); + + switch (err) + { + case WSA_IO_PENDING: + + ret2 = ::WaitForSingleObject(pWriteEvent_->getHandle(), writeTimeout_); + + if (ret2 == WAIT_FAILED) + { + err = ::closesocket(socket_); // ignore err value here + + throw Exception(__FUNCTION_NAME__, "::WaitForSingleObject() failed"); + } + else if (ret2 == WAIT_TIMEOUT) + { + err = ::closesocket(socket_); // ignore err value here + + throw TimeoutError(__FUNCTION_NAME__, "WaitForMultipleObjects() timed out"); + } + else if (ret2 == WAIT_OBJECT_0) + { + pWriteEvent_->reset(); + + if (!::WSAGetOverlappedResult(socket_, + &writeOverlapped, + &numSent, + FALSE, + &flags)) + { + int resultErr = ::WSAGetLastError(); + + switch (resultErr) + { + case WSAECONNRESET: + case WSAECONNABORTED: // intentional fall-through + ::closesocket(socket_); // ignore err value here + + throw Exception(__FUNCTION_NAME__, "connection forcedfully closed"); + break; + + default: + { + std::stringstream ss; + ss << "::WSAGetOverlappedResult() error code: " << static_cast(resultErr); + + throw Exception(__FUNCTION_NAME__, ss.str()); + } + break; + } + } + } + else // event abandoned + { + return; + } + + break; + + case WSAECONNREFUSED: // intentional fall-throughs + case WSAECONNABORTED: + case WSAECONNRESET: + oss << "err = " << err; + + ::closesocket(socket_); // ignore return + throw Exception(__FUNCTION_NAME__, oss.str()); + break; + + case WSAENOTSOCK: + throw Exception(__FUNCTION_NAME__, "socket died"); + break; + + default: + ::closesocket(socket_); // ignore return + throw Exception(__FUNCTION_NAME__, oss.str()); + break; + } + } +} \ No newline at end of file diff --git a/CommonLib/src/Common/Comm/UDPSocket.hpp b/CommonLib/src/Common/Comm/UDPSocket.hpp new file mode 100644 index 0000000..7dbab09 --- /dev/null +++ b/CommonLib/src/Common/Comm/UDPSocket.hpp @@ -0,0 +1,128 @@ +#pragma once + +#include +#include +#include +#include + +class NTEvent; +#include "Socket.hpp" + +class UDPSocket : public Socket +{ +public: + + //>--------------------------------------------------------------------------- + // Function: UDPSocket + // + // Purpose: + /// Constructor to create UDP socket + //---------------------------------------------------------------------------- + // Arguments: + /** \param remoteAddr - remote IP address for sending messages + // \param remotePort - remote UDP port number for sending messages + // \param localPort - local UDP port number + // \param oneToOneConn - True if socket is connected to only one IP addr & port. + // False if socket is listening to any IP addresses. + // \param readTimeOut - read time out + // \param writeTimeOut - write time out + // \param readSize - read buffer size + //---------------------------------------------------------------------------- + // + // Return Value: none + //----------------------------------------------------------------------------*/ + UDPSocket(const std::string& address, + unsigned int remotePort, + unsigned int localPort, + DWORD readTimeOut = ULONG_MAX, + DWORD writeTimeOut = ULONG_MAX, + unsigned int readSize = READ_BUF_SIZE_DEFAULT); + + //>--------------------------------------------------------------------------- + // Function: ~UDPSocket + // + // Purpose: + /// Destructor + //---------------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------------- + // + // Return Value: none + //----------------------------------------------------------------------------*/ + virtual ~UDPSocket(); + + //>--------------------------------------------------------------------- + // Function: AcceptConnection() + // + // Purpose: + /// waits for connection + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: SOCKET, the client socket + //<---------------------------------------------------------------------*/ + virtual void AcceptConnection(); + + //>--------------------------------------------------------------------------- + // Function: connect + // + // Purpose: + // setsockopt and bind the local port. Also, connect to remote IP if + // necessary. + //---------------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------------- + // + // Return Value: none + //----------------------------------------------------------------------------*/ + virtual void connect(const std::string& address, int port); + void connect(); + + //>--------------------------------------------------------------------------- + // Function: read + // + // Purpose: + // The function is used when oneToOneConn is true. The socket is connected + // to a specific IP address, and receiving the messages from this address. + //---------------------------------------------------------------------------- + // Arguments: + /** \param readTimeOut - read time out + //---------------------------------------------------------------------------- + // + // Return Value: none + //----------------------------------------------------------------------------*/ + virtual void read(DWORD readTimeOut = ULONG_MAX); + + //>--------------------------------------------------------------------------- + // Function: write + // + // Purpose: + // The function is used when oneToOneConn is true. The socket is connected + // to a specific IP address, and sending the messages from this address. + //---------------------------------------------------------------------------- + // Arguments: + /** \param sendBuf - a pointer to the send buffer + // \param bufLen - the size of the buffer + //---------------------------------------------------------------------------- + // + // Return Value: none + //----------------------------------------------------------------------------*/ + virtual void write(unsigned int numToSend); + void write(std::string address, unsigned int numToSend); + + +private: + //Not allowed + UDPSocket(); + UDPSocket(const UDPSocket& rhs); + UDPSocket &operator=(const UDPSocket& rhs) {} + + BOOL waitForOverlapIoToComplete_; + + WSABUF readBuffer_; + WSAOVERLAPPED readOverlapped_; +}; \ No newline at end of file diff --git a/CommonLib/src/Common/Exceptions/Exception.cpp b/CommonLib/src/Common/Exceptions/Exception.cpp new file mode 100644 index 0000000..1b2ecef --- /dev/null +++ b/CommonLib/src/Common/Exceptions/Exception.cpp @@ -0,0 +1,110 @@ +#include "Exception.hpp" +#include "StringUtil.hpp" + +#include +#include +#include +#include + +//------------------------------------------------------------------------ + +Exception::Exception(std::string functionName, const std::string& errorMsg, const std::string& exceptionClass) : + exception() +{ + std::string className = ""; + if (exceptionClass.length() == 0) + className = std::string(typeid(this).name()); + else + className = exceptionClass; + + // get the name of the class without the extra add-ons + std::smatch sm; + if (std::regex_search(className, sm, std::regex("[^ ]+ ([^ ]+).+", std::regex_constants::icase))) + { + m_message = sm[1]; + } + else + m_message = "Exception"; + + m_message += ": "; + + m_lastFunction = functionName; + + m_message += functionName + " - " + errorMsg; + m_fullStackTraceMessage = m_message; + m_message = errorMsg; +} + +//------------------------------------------------------------------------ + +Exception::Exception(const Exception& rhs) +{ + copy(rhs); +} + +//------------------------------------------------------------------------ + +const char* Exception::what() const +{ + return m_fullStackTraceMessage.c_str(); +} + +//------------------------------------------------------------------------ + +Exception& Exception::operator=(const Exception& rhs) +{ + return copy(rhs); +} + +//------------------------------------------------------------------------ + +void Exception::buildStackTrace(std::string functionName, const std::string& errorMsg) +{ + if (!Util::Strings::StringsAreEqual(functionName, m_lastFunction)) + { + m_lastFunction = functionName; + + m_fullStackTraceMessage.append(" -> "); + m_fullStackTraceMessage.append(functionName); + + if (errorMsg.length() > 0) + { + m_fullStackTraceMessage.append(" - " + errorMsg); + m_message = errorMsg; + } + } +} + +//------------------------------------------------------------------------ + +Exception& Exception::copy(const Exception& rhs) +{ + if (this == &rhs) + { + return *this; + } + + m_message = rhs.m_message; + m_fullStackTraceMessage = rhs.m_fullStackTraceMessage; + m_lastFunction = rhs.m_lastFunction; + + return *this; +} + +//------------------------------------------------------------------------ + +Exception::~Exception() +{ +} + +//------------------------------------------------------------------------ + +std::string Exception::getMessage(Message_Format msgFormat) +{ + std::string msg = m_message; + + if (msgFormat == ERROR_MESSAGE_WITH_STACKTRACE) + msg = m_fullStackTraceMessage; + + return msg; +} \ No newline at end of file diff --git a/CommonLib/src/Common/Exceptions/Exception.hpp b/CommonLib/src/Common/Exceptions/Exception.hpp new file mode 100644 index 0000000..552c310 --- /dev/null +++ b/CommonLib/src/Common/Exceptions/Exception.hpp @@ -0,0 +1,135 @@ +#if !defined (EXCEPTION_HPP) +#define EXCEPTION_HPP + +#include +#include + +class Exception : public std::exception +{ +public: + enum Message_Format + { + ERROR_MESSAGE_WITH_STACKTRACE, // entire stack trace + ERROR_MESSAGE_ONLY // the function that throw the exception + }; + + //>--------------------------------------------------------------------- + // Function: Exception() + // + // Purpose: constructor + //---------------------------------------------------------------------- + // Arguments: + // functionName - should use custom macro __FUNCTION_NAME__ + // to get the name of offending function + // errorMsg - description of what caused the exception + // This is optional. Error message should be + // provided by the function where the exception + // originates from + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + Exception(std::string functionName, const std::string &errorMsg, const std::string& exceptionClass = ""); + + //>--------------------------------------------------------------------- + // Function: Exception() + // + // Purpose: copy constructor + //---------------------------------------------------------------------- + // Arguments: const Exception & - reference to Exception obj + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + Exception(const Exception &rhs); + + //>--------------------------------------------------------------------- + // Function: ~Exception() + // + // Purpose: destructor + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual ~Exception(); + + //>--------------------------------------------------------------------- + // Function: what() + // + // Purpose: to get the message that the exception generated + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: the message string + //<--------------------------------------------------------------------- + virtual const char *what() const; + + //>--------------------------------------------------------------------- + // Function: getMessage() + // + // Purpose: to get the message data member + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: std::string - the message string + //<--------------------------------------------------------------------- + std::string getMessage(Message_Format msgFormat = ERROR_MESSAGE_WITH_STACKTRACE); + + //>--------------------------------------------------------------------- + // Function: operator&() + // + // Purpose: assignment operator + //---------------------------------------------------------------------- + // Arguments: const Exception & - reference to Exception obj + //---------------------------------------------------------------------- + // Return Value: reference to Exception obj + //<--------------------------------------------------------------------- + Exception &operator=(const Exception &rhs); + + //>--------------------------------------------------------------------- + // Function: buildStackTrace() + // + // Purpose: Build the stack trace of function calls for debugging purposes + //---------------------------------------------------------------------- + // Arguments: + // functionName - should use custom macro __FUNCTION_NAME__ + // to get the name of offending function + // errorMsg - description of what caused the exception + // This is optional. Error message should be + // provided by the function where the exception + // originates from + // + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void buildStackTrace(std::string functionName, const std::string& errorMsg = ""); + +protected: + std::string m_message; + std::string m_fullStackTraceMessage; + std::string m_lastFunction; + +private: + //>--------------------------------------------------------------------- + // Function: Exception() + // + // Purpose: default + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + Exception(); + + //>--------------------------------------------------------------------- + // Function: copy() + // + // Purpose: to do the work for assignment operator and copy ctor + //---------------------------------------------------------------------- + // Arguments: const Exception &rhs - const reference to Exception obj + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + Exception ©(const Exception &rhs); +}; + +#endif // #if !defined (EXCEPTION_HPP) diff --git a/CommonLib/src/Common/Exceptions/TimeoutError.cpp b/CommonLib/src/Common/Exceptions/TimeoutError.cpp new file mode 100644 index 0000000..5ff2952 --- /dev/null +++ b/CommonLib/src/Common/Exceptions/TimeoutError.cpp @@ -0,0 +1,16 @@ +#include "TimeoutError.hpp" +#include + +//------------------------------------------------------------------------ + +TimeoutError::TimeoutError(std::string functionName, const std::string& errorMsg, TIME_OUT_TYPE timeOutType) : + Exception(functionName, errorMsg, std::string(typeid(this).name())), + m_timeOutType(timeOutType) +{ +} + +//------------------------------------------------------------------------ + +TimeoutError::~TimeoutError() throw() +{ +} diff --git a/CommonLib/src/Common/Exceptions/TimeoutError.hpp b/CommonLib/src/Common/Exceptions/TimeoutError.hpp new file mode 100644 index 0000000..a164bcc --- /dev/null +++ b/CommonLib/src/Common/Exceptions/TimeoutError.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "Exception.hpp" + +class TimeoutError : public Exception +{ +public: + enum TIME_OUT_TYPE + { + TIME_OUT_GENERIC, + TIME_OUT_SOCKET + }; + + //>--------------------------------------------------------------------- + // Function: TimeoutError() + // + // Purpose: default and non-default constructor + //---------------------------------------------------------------------- + // Arguments: std::string msg - a message to be printed + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + TimeoutError(std::string functionName, const std::string& errorMsg, TIME_OUT_TYPE timeOutType = TIME_OUT_GENERIC); + + //>--------------------------------------------------------------------- + // Function: ~TimeoutError() + // + // Purpose: destructor + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual ~TimeoutError() throw(); + + TIME_OUT_TYPE m_timeOutType; +}; diff --git a/CommonLib/src/Common/Lib/CRC32.cpp b/CommonLib/src/Common/Lib/CRC32.cpp new file mode 100644 index 0000000..583a4d6 --- /dev/null +++ b/CommonLib/src/Common/Lib/CRC32.cpp @@ -0,0 +1,86 @@ +#include "CRC32.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CCRC32::CCRC32() +{ + mPoly = DEFAULT_POLY; + theCRC = 0xFFFFFFFF; + createLUT(); + +} /* Constructor */ +/****************************************************************************/ +CCRC32::~CCRC32() +{ + +} /* Destructor */ +/****************************************************************************/ +// +// generates data to fill lookup table using pre-defined polynomial +// +void CCRC32::createLUT() +{ +unsigned int crc; +int i, j; + + for (i=0; i<256; i++) + { + crc = i; + + for (j=8; j>0; j--) + { + if (crc & 1) + crc = (crc >> 1) ^ mPoly; + else + crc >>= 1; + } + + crcLUT[i] = crc; + } + +} /* createLUT */ +/****************************************************************************/ +// +// Compute the actual CRC32 using the pre-generated LUT +// +// NOTE: The original source for this function comes from work done by +// Mark R. Nelson and published in Dr. Dobb's Journal, May 1992, pp. 64-67. +// The original source has been modified meet the needs of this utility. --lwp +unsigned int CCRC32::computeCRC(void *pData, unsigned int byteCnt, + unsigned int crc) +{ +unsigned char* ptr = static_cast (pData); +unsigned char byte; +unsigned int i=0; + + if (crc != 0xFFFFFFFF) + theCRC = (crc ^ 0xFFFFFFFF); /* non-contiguous mode, must undo XOR */ + else + theCRC = 0xFFFFFFFF; + + while (i < byteCnt) + { + byte = *(ptr+i); + theCRC = ((theCRC >> 8) & 0x00FFFFFF) ^ crcLUT[(theCRC ^ byte) & 0xFF]; + i++; + } + + theCRC = theCRC ^ 0xFFFFFFFF; + return (theCRC); + +} /* computeCRC */ +/****************************************************************************/ +unsigned int CCRC32::SetPoly(unsigned int newPoly) +{ + + mPoly = newPoly & 0xFFFFFFFF; + + // need to regenerate the LUT + createLUT(); + + return mPoly; + +} /* SetPoly */ +/****************************************************************************/ diff --git a/CommonLib/src/Common/Lib/CRC32.h b/CommonLib/src/Common/Lib/CRC32.h new file mode 100644 index 0000000..5484dfb --- /dev/null +++ b/CommonLib/src/Common/Lib/CRC32.h @@ -0,0 +1,35 @@ +#if !defined(AFX_CRC32_H__62982224_AF62_4426_A827_88824EEA4AB5__INCLUDED_) +#define AFX_CRC32_H__62982224_AF62_4426_A827_88824EEA4AB5__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +/*****************************************************************************/ + +// CRC32c i(SCSI) for right shift algorithm +//#define DEFAULT_POLY 0x82F63B78L + +// CRC-32-IEEE802.3 for right shift algorithm +#define DEFAULT_POLY 0xEDB88320L + +/*****************************************************************************/ +class CCRC32 +{ +public: + unsigned int GetPoly(void) {return mPoly;}; + unsigned int SetPoly(unsigned int newPoly); + + unsigned int computeCRC(void* pData, unsigned int byteCnt, + unsigned int crc = 0xFFFFFFFF); + unsigned int theCRC; + CCRC32(); + virtual ~CCRC32(); + +private: + unsigned int mPoly; + unsigned int crcLUT[256]; + void createLUT(); + +}; +/*****************************************************************************/ +#endif // !defined(AFX_CRC32_H__62982224_AF62_4426_A827_88824EEA4AB5__INCLUDED_) diff --git a/CommonLib/src/Common/Lib/CustomDataTypes.hpp b/CommonLib/src/Common/Lib/CustomDataTypes.hpp new file mode 100644 index 0000000..4597c6e --- /dev/null +++ b/CommonLib/src/Common/Lib/CustomDataTypes.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include +#include +#include +//------------------------------------------------------------------------ + +namespace CustomDataTypes +{ + // by default, key search for std::map is case-sensitive + // this struct makes it so any key search for std::map is case-insensitive + // example: std::map + struct ci_less + { + struct nocase_compare + { + bool operator()(const unsigned char& c1, const unsigned char& c2) const + { + return tolower(c1) < tolower(c2); + } + }; + + bool operator()(const std::string& s1, const std::string& s2) const + { + return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), nocase_compare()); + } + }; +} diff --git a/CommonLib/src/Common/Lib/ErrorLog.cpp b/CommonLib/src/Common/Lib/ErrorLog.cpp new file mode 100644 index 0000000..82ff539 --- /dev/null +++ b/CommonLib/src/Common/Lib/ErrorLog.cpp @@ -0,0 +1,92 @@ +#include +#include +#include + +#include "ErrorLog.hpp" +#include "Exception.hpp" +#include "LockMutex.hpp" +#include "Timestamp.hpp" + +//----------------------------------------------------------------------------- + +ErrorLog& ErrorLog::Instance(const std::string& filename) +{ + try + { + static ErrorLog fileAndConsoleWriter(filename); + return fileAndConsoleWriter; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +ErrorLog::ErrorLog(const std::string& filename) : + m_mutex("ErrorLog - Mutex") +{ + try + { + m_outlog.open(filename.c_str(), std::ios_base::app); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +ErrorLog::~ErrorLog() +{ + m_outlog.close(); +} + +//----------------------------------------------------------------------------- + +void ErrorLog::log(const std::string& msg, const bool putToConsole, ErrorLog::LogLevel level) +{ + try + { + LockMutex lock(&m_mutex); + + // build the string to log + std::stringstream msgToLogSs; + + if (level == LOG_INFO) + { + msgToLogSs << "INFO, " << msg + "\n"; + } + else + { + msgToLogSs << "ERROR, " << msg + "\n"; + } + + // log out data to console + if (putToConsole == true) + { + std::cout << msgToLogSs.str(); + } + + std::string date; + std::string time; + + Timestamp::GetCurrentDateTimeString(date, time, Timestamp::DateFormat::YYYYMMDD, Timestamp::TimeFormat::HHMMSSMM, "_"); + + m_outlog << date << "_" << time + "_" + msgToLogSs.str(); + + m_outlog.flush(); + } + catch (...) + { + // if we cant log, just continue on + } +} + + + + diff --git a/CommonLib/src/Common/Lib/ErrorLog.hpp b/CommonLib/src/Common/Lib/ErrorLog.hpp new file mode 100644 index 0000000..59c7b55 --- /dev/null +++ b/CommonLib/src/Common/Lib/ErrorLog.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include + +#include "NTMutex.hpp" + +class ErrorLog +{ +public: + enum LogLevel + { + LOG_INFO, + LOG_ERROR + }; + + static ErrorLog& Instance(const std::string& filename = ""); + + ~ErrorLog(); + + void log(const std::string& msg, const bool putToConsole = true, LogLevel logLevel = LOG_INFO); + +private: + // do not allow + ErrorLog(const ErrorLog& rhs); + ErrorLog& operator=(const ErrorLog& rhs) {}; + + + ErrorLog(const std::string& filename); + + std::string m_filename; + std::ofstream m_outlog; + + NTMutex m_mutex; +}; \ No newline at end of file diff --git a/CommonLib/src/Common/Lib/IniFile.cpp b/CommonLib/src/Common/Lib/IniFile.cpp new file mode 100644 index 0000000..35e8a25 --- /dev/null +++ b/CommonLib/src/Common/Lib/IniFile.cpp @@ -0,0 +1,510 @@ +#include +#include + +#include "IniFile.hpp" +#include "Exception.hpp" +#include "StringUtil.hpp" + +// INI-file delimiters +static const char COMMENT_CHAR = ';'; +static const char KEY_VALUE_DELIMITER = '='; +static const char SECTION_HDR_START_CHAR = '['; +static const char SECTION_HDR_END_CHAR = ']'; + +//------------------------------------------------------------------------ + +IniFile::IniFile() : + fileName_("Not set") +{ +} + +//------------------------------------------------------------------------ + +IniFile::IniFile(const std::string& fileName) : + fileName_(fileName) +{ + try + { + readFile(fileName); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } +} + +//------------------------------------------------------------------------ + +IniFile::~IniFile() +{ +} + +//------------------------------------------------------------------------ + +void IniFile::addKeyValuePair(const std::string& section, + const std::string& key, + const std::string& value) +{ + configMap[section].insert(KeyValuePair(key, value)); +} + +//------------------------------------------------------------------------ + +bool IniFile::getBool(const std::string& section , + const std::string& key) const +{ + try + { + std::stringstream ss; + + ss.str(getString(section , key)); + ss.setf(std::ios_base::boolalpha); + bool tmp; + ss >> tmp; + + return tmp; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } +} + +//------------------------------------------------------------------------ + +double IniFile::getDouble(const std::string& section, + const std::string& key) const +{ + try + { + std::stringstream ss; + + ss.str(getString(section , key)); + double tmp; + ss >> tmp; + + return tmp; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } +} + +//------------------------------------------------------------------------ + +void IniFile::getKeys(const std::string& section, + std::vector& keys) const +{ + keys.clear(); // empty list + + // make sure section exists + SectionIter sectionIt = configMap.find(section); + + if (sectionIt == configMap.end()) + { + std::ostringstream oss; + + oss << "section '" << section.c_str() << "' does not exist"; + + throw Exception(__FUNCTION_NAME__,oss.str().c_str()); + } + + // fill up vector with keys + for (KeyValueIter keyValueIt = sectionIt->second.begin(); + keyValueIt != sectionIt->second.end(); + ++keyValueIt) + { + keys.push_back(keyValueIt->first); + } +} + +//------------------------------------------------------------------------ + +void IniFile::getKeyValue(const std::string& line, + std::string& key, + std::string& value) const +{ + size_t equalPos; + + // everything to left of delimiter is key + equalPos = line.find(KEY_VALUE_DELIMITER); + key = line.substr(0 , equalPos); + + // everything to right of delimiter is value (except possible comment) + value = line.substr(equalPos + 1); + + size_t commentPos; + commentPos = value.find(COMMENT_CHAR); + + if (commentPos != std::string::npos) + { + value = value.substr(0 , commentPos); + } + + // trim leading/trailing spaces on key and value + key = Util::Strings::TrimSpaces(key); + value = Util::Strings::TrimSpaces(value); +} + +//------------------------------------------------------------------------ + +IniFile::LineType IniFile::getLineType(const std::string& line) const +{ + // trim leading/trailing spaces + std::string tempLine = Util::Strings::TrimSpaces(line); + + // blank line? + if (tempLine.length() == 0) + { + return BLANK_LINE; + } + + // commment? + if (tempLine[0] == COMMENT_CHAR) + { + return COMMENT; + } + + // section header? + if (tempLine[0] == SECTION_HDR_START_CHAR) + { + // check for end of section header + if (tempLine.find(SECTION_HDR_END_CHAR) != std::string::npos) + { + return SECTION_HEADER; + } + else // starts out as a section header, but no end char + { + return BAD_LINE; + } + } + + // Assume everything else is a key/value pair. + // Previously checked for "=" and returned BAD_LINE if it didn't exist. + // However, this did not allow for keys with no values. + return KEY_VALUE_PAIR; +} + +//------------------------------------------------------------------------ + +long IniFile::getLong(const std::string& section, + const std::string& key) const +{ + try + { + std::stringstream ss; + + ss.str(getString(section , key)); + long tmp; + ss >> tmp; + + return tmp; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } +} + +//------------------------------------------------------------------------ + +std::string IniFile::getString(const std::string& section, + const std::string& key) const +{ + // make sure section exists + SectionIter sectionIt = configMap.find(section); + + if (sectionIt == configMap.end()) + { + std::ostringstream oss; + + oss << "section '" << section.c_str() << "' does not exist"; + + throw Exception(__FUNCTION_NAME__, oss.str().c_str()); + } + + // make sure key exists + KeyValueIter keyValueIt = sectionIt->second.find(key); + + if (keyValueIt == sectionIt->second.end()) + { + std::ostringstream oss; + + oss << "key '" << key.c_str() << "' does not exist"; + + throw Exception(__FUNCTION_NAME__, oss.str().c_str()); + } + + return keyValueIt->second; +} + +//------------------------------------------------------------------------ + +bool IniFile::keyExists(const std::string& section, + const std::string& key) const +{ + bool keyExists = true; + + // make sure section exists + SectionIter sectionIt = configMap.find(section); + + if (sectionIt == configMap.end()) + { + keyExists = false; + } + + if (keyExists) + { + // make sure key exists + KeyValueIter keyValueIt = sectionIt->second.find(key); + + if (keyValueIt == sectionIt->second.end()) + { + keyExists = false; + } + } + + return keyExists; +} + +//------------------------------------------------------------------------ + +void IniFile::init(const std::string& fileName) +{ + try + { + readFile(fileName); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } +} + +//------------------------------------------------------------------------ + +bool IniFile::isSection(const std::string& section) const +{ + return configMap.find(section) != configMap.end(); +} + +//------------------------------------------------------------------------ + +void IniFile::readFile(const std::string& fileName) +{ + // open file + std::ifstream cfgStream(fileName.c_str()); + + if (cfgStream.fail()) + { + std::string s = "could not open file: " + fileName ; + throw Exception(__FUNCTION_NAME__, s); + } + + // read line-by-line + // - skip comments, blank lines + // - save last section name + // - add key/value pairs as ecnountered + std::string section; + bool bHaveSection = false; + + while (!cfgStream.eof()) + { + std::string line = ""; + + std::getline(cfgStream, line); + + if(line != "") + { + char lastChar = line[line.length() - 1]; + + if(lastChar == '\r') + { + line = line.substr(0, line.length() - 1); + } + } + + LineType lineType = getLineType(line); + + std::string errMsg; + switch (lineType) + { + case BLANK_LINE: + case COMMENT: + // do nothing + break; + + case SECTION_HEADER: + { + // save section + size_t first = line.find_first_of('['); + size_t last = line.find_first_of(']'); + section = line.substr(first + 1 , last - first - 1); + + bHaveSection = true; + } + break; + + case KEY_VALUE_PAIR: + if (bHaveSection) + { + // add to map + std::string key; + std::string value; + getKeyValue(line , key , value); + + addKeyValuePair(section, key, value); + } + else + { + throw Exception(__FUNCTION_NAME__, "key/value pair before section"); + } + + break; + + case BAD_LINE: + + + errMsg = "IniFile::init(): bad line: '" + line + "'"; + + throw Exception(__FUNCTION_NAME__, errMsg.c_str()); + default: + break; + } + } +} + +//------------------------------------------------------------------------ + +void IniFile::writeValue(const std::string& section, const std::string& key, const std::string& value) +{ + try + { + // open file + std::ifstream cfgStream(fileName_.c_str()); + + if (cfgStream.fail()) + { + std::string s = "could not open file: " + fileName_; + throw Exception(__FUNCTION_NAME__, s); + } + + // read line-by-line looking for the section + // - skip comments, blank lines + // - save last section name + // - add key/value pairs as ecnountered + std::string fileSection = ""; + bool didWeFindTheSection = false; + bool didWeFindTheItemToUpdate = false; + + // buffer up the file so we can write it out later + std::vector fileVec; + + while (!cfgStream.eof()) + { + std::string line = ""; + + std::getline(cfgStream, line); + + fileVec.push_back(line); + + if(line != "") + { + char lastChar = line[line.length() - 1]; + + if(lastChar == '\r') + { + line = line.substr(0, line.length() - 1); + } + } + + if (didWeFindTheSection == true) + { + // look for key + std::string fileKey = ""; + std::string fileValue = ""; + getKeyValue(line , fileKey , fileValue); + + if (fileKey == key) + { + // found it..update the value + line = fileKey + " = " + value; + fileVec.at(fileVec.size() - 1) = line; + didWeFindTheItemToUpdate = true; + } + } + else + { + LineType lineType = getLineType(line); + + std::string errMsg; + switch (lineType) + { + case BLANK_LINE: + case COMMENT: + case KEY_VALUE_PAIR: + // do nothing + break; + + case SECTION_HEADER: + { + // save section + size_t first = line.find_first_of('['); + size_t last = line.find_first_of(']'); + fileSection = line.substr(first + 1 , last - first - 1); + fileSection = Util::Strings::TrimSpaces(section); + + if (fileSection == section) + { + didWeFindTheSection = true; + } + } + break; + + case BAD_LINE: + errMsg = "bad line: " + line; + throw Exception(__FUNCTION_NAME__, errMsg); + default: + break; + } + }// end didWeFindTheSection + } + + cfgStream.close(); + + // if we were successful, write the file back out + if (didWeFindTheItemToUpdate == true) + { + // open file + std::ofstream outStream(fileName_.c_str()); + + if (outStream.fail()) + { + std::string s = "could not open file: " + fileName_; + throw Exception(__FUNCTION_NAME__, s); + } + + for (int i = 0; i < static_cast(fileVec.size()); ++i) + { + outStream << fileVec.at(i) << "\n"; + } + + outStream.close(); + } + else + { + throw Exception(__FUNCTION_NAME__, "did not update file. Section: " + section + ", Key: " + key); + } + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } +} diff --git a/CommonLib/src/Common/Lib/IniFile.hpp b/CommonLib/src/Common/Lib/IniFile.hpp new file mode 100644 index 0000000..7ebc33e --- /dev/null +++ b/CommonLib/src/Common/Lib/IniFile.hpp @@ -0,0 +1,286 @@ +#if !defined (INIFILE_HPP) +#define INIFILE_HPP + +#include "CustomDataTypes.hpp" + +#include +#include +#include + +class IniFile +{ +public: + //>--------------------------------------------------------------------------- + // Function: IniFile + // + // Purpose: + // reads an INI-format file and creates sections and key/value pairs + // by calling ConfigData::addKeyValuePair function. + // + // May throw FileErr or IniFileErr. + //---------------------------------------------------------------------------- + // Arguments: + /** \param fileName - name of INI-format file + //---------------------------------------------------------------------------- + // + // Return Value: none + //----------------------------------------------------------------------------*/ + IniFile(const std::string& fileName); + IniFile(); + + //>--------------------------------------------------------------------------- + // Function: ~IniFile + // + // Purpose: + // destructor + //---------------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------------- + // Return Value: none + //---------------------------------------------------------------------------- + virtual ~IniFile(); + + //>--------------------------------------------------------------------------- + // Function: getBool + // + // Purpose: + // return value of a given section/key interpreted as a boolean + // + // Throws ConfigDataErr exception if section or key does not exist + //---------------------------------------------------------------------------- + // Arguments: + // section - section containing desired key/value pair + // key - key in given section + //---------------------------------------------------------------------------- + // Return Value: + // value string of given section/key interpreted as a boolean + //---------------------------------------------------------------------------- + bool getBool(const std::string& section, const std::string& key) const; + + //>--------------------------------------------------------------------------- + // Function: getDouble + // + // Purpose: + // return value of a given section/key interpreted as a double + // Throws IniFileErr exception if section or key does not exist + //---------------------------------------------------------------------------- + // Arguments: + // section - section containing desired key/value pair + // key - key in given section + //---------------------------------------------------------------------------- + // Return Value: + // value string of given section/key interpreted as a double + //---------------------------------------------------------------------------- + double getDouble(const std::string& section, const std::string& key) const; + + //>--------------------------------------------------------------------------- + // Function: getKeys + // + // Purpose: + // return list of keys in a given section + // + // Throws IniFileErr exception if section does not exist + //---------------------------------------------------------------------------- + // Arguments: + // section - section from which to return list of keys + // keys - list of keys in given section + //---------------------------------------------------------------------------- + // Return Value: none + //---------------------------------------------------------------------------- + void getKeys(const std::string& section, + std::vector& keys) const; + + //>--------------------------------------------------------------------------- + // Function: getLong + // + // Purpose: + // return value of a given section/key interpreted as a long + // + // Throws IniFileErr exception if section or key does not exist + //---------------------------------------------------------------------------- + // Arguments: + // section - section containing desired key/value pair + // key - key in given section + //---------------------------------------------------------------------------- + // Return Value: + // value string of given section/key interpreted as a long + //---------------------------------------------------------------------------- + long getLong(const std::string& section, const std::string& key) const; + + //>--------------------------------------------------------------------------- + // Function: getString + // + // Purpose: + // return value of a given section/key interpreted as a string + // + // Throws IniFileErr exception if section or key does not exist + //---------------------------------------------------------------------------- + // Arguments: + // section - section containing desired key/value pair + // key - key in given section + //---------------------------------------------------------------------------- + // Return Value: + // value string of given section/key interpreted as a string + //---------------------------------------------------------------------------- + std::string getString(const std::string& section, + const std::string& key) const; + + //>--------------------------------------------------------------------------- + // Function: keyExists + // + // Purpose: + // query if key exists in a section + // + //---------------------------------------------------------------------------- + // Arguments: + // section - section containing desired key/value pair + // key - key in given section + //---------------------------------------------------------------------------- + // + // Return Value: + // true/false + //----------------------------------------------------------------------------*/ + bool keyExists(const std::string& section, + const std::string& key) const; + + //>--------------------------------------------------------------------------- + // Function: isSection + // + // Purpose: + // return whether given string is a section + //---------------------------------------------------------------------------- + // Arguments: + // str - string for which to return whether it is a section + //---------------------------------------------------------------------------- + // Return Value: + // whether specified string is a section(true) or not(false) + //---------------------------------------------------------------------------- + bool isSection(const std::string& str) const; + + //>--------------------------------------------------------------------------- + // Function: init + // + // Purpose: + // provide a way to pass in the filename in case default constructor is used + //---------------------------------------------------------------------------- + // Arguments: + // fileName - path and name of INI file + //---------------------------------------------------------------------------- + // Return Value: None + //---------------------------------------------------------------------------- + void init(const std::string& fileName); + + //>--------------------------------------------------------------------------- + // Function: writeValue + // + // Purpose: + // change value of a key in a section in the INI file + //---------------------------------------------------------------------------- + // Arguments: + // section - name of section in INI file + // key - name of they key in the section + // value - text to be written + //---------------------------------------------------------------------------- + // Return Value: None + //---------------------------------------------------------------------------- + void writeValue(const std::string& section, const std::string& key, const std::string& value); + +protected: + //>--------------------------------------------------------------------------- + // Function: addKeyValuePair + // + // Purpose: + // adds a key/value pair to a section + //---------------------------------------------------------------------------- + // Arguments: + // section - section to which to add key/value pair + // key - key of key/value pair to add + // value - value of key/value pair to add + //---------------------------------------------------------------------------- + // Return Value: none + //---------------------------------------------------------------------------- + void addKeyValuePair(const std::string& section, + const std::string& key, + const std::string& value); + +private: + // do not allow these constructors to be called + IniFile(const IniFile ©); + IniFile& operator=(const IniFile& rhs) {}; + + // types of line allowed in INI-format file + enum LineType + { + COMMENT, + KEY_VALUE_PAIR, + SECTION_HEADER, + BLANK_LINE, + BAD_LINE + }; + + // internally-used data structures + typedef std::map KeyValueMap; + typedef std::pair KeyValuePair; + typedef std::map SectionMap; + typedef KeyValueMap::const_iterator KeyValueIter; + typedef SectionMap::const_iterator SectionIter; + + SectionMap configMap; // map containing sections and key/value pairs + + //>--------------------------------------------------------------------------- + // Function: getKeyValue + // + // Purpose: + // returns key/value pair(strings) from a string. + // + // Key/value pairs are delimited by an equal sign, "=". If no equal sign + // is found, then value is an empty string. Spaces are trimmed from both + // ends of the key and value strings. + //---------------------------------------------------------------------------- + // Arguments: + // line - string containing a key/value pair + // key - returned key string + // value - return value string. may be empty if no equal sign found in + // line. + //---------------------------------------------------------------------------- + // Return Value: none + //---------------------------------------------------------------------------- + void getKeyValue(const std::string& line, + std::string& key, + std::string& value) const; + + //>--------------------------------------------------------------------------- + // Function: getLineType + // + // Purpose: + // returns type of line in passed string + //---------------------------------------------------------------------------- + // Arguments: + // line - string containing line read from file + //---------------------------------------------------------------------------- + // Return Value: + // type of line (see LineType enum) of passed string + //---------------------------------------------------------------------------- + LineType getLineType(const std::string& line) const; + + //>--------------------------------------------------------------------------- + // Function: readFile + // + // Purpose: + // reads file and repeatedly calls ConfigData::addKeyValuePair to store + // sections and key/value pairs. Throws FileErr exception if could not + // open file. + // + // Throws IniFileErr exception if problem with data in file. + //---------------------------------------------------------------------------- + // Arguments: + // fileName - name of INI-format file to read/parse + //---------------------------------------------------------------------------- + // Return Value: none + //---------------------------------------------------------------------------- + void readFile(const std::string& fileName); + + std::string fileName_; +}; + +#endif // #if !defined (INIFILE_HPP) diff --git a/CommonLib/src/Common/Lib/LockMutex.cpp b/CommonLib/src/Common/Lib/LockMutex.cpp new file mode 100644 index 0000000..5bdeaca --- /dev/null +++ b/CommonLib/src/Common/Lib/LockMutex.cpp @@ -0,0 +1,28 @@ +#include + +#include "LockMutex.hpp" +#include "Exception.hpp" + +LockMutex::LockMutex(NTMutex *pMutex, DWORD timeout) : + pMutex_(pMutex) +{ + try + { + assert(pMutex != 0); + pMutex_->lock(timeout); + } + catch(Exception&) + { + } + catch(...) + { + } +} + +//------------------------------------------------------------------------ + +LockMutex::~LockMutex() +{ + pMutex_->unlock(); + pMutex_ = 0; +} diff --git a/CommonLib/src/Common/Lib/LockMutex.hpp b/CommonLib/src/Common/Lib/LockMutex.hpp new file mode 100644 index 0000000..6870ece --- /dev/null +++ b/CommonLib/src/Common/Lib/LockMutex.hpp @@ -0,0 +1,43 @@ +#pragma once +#include "NTMutex.hpp" + +class LockMutex +{ +public: + //>--------------------------------------------------------------------- + // Function: LockMutex() + // + // Purpose: + /// constructor + //---------------------------------------------------------------------- + // Arguments: + /** NTMutex *pMutex, pointer to a mutex + // DWORD timeout, some timeout (in ms) + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + explicit LockMutex(NTMutex *pMutex, DWORD timeout = 5000);//DWORD timeout = INFINITE); + + //>--------------------------------------------------------------------- + // Function: ~LockMutex() + // + // Purpose: + /// destructor + //---------------------------------------------------------------------- + // Arguments: none /** + // + //-------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + ~LockMutex(); + +private: + // do not allow + LockMutex(); + LockMutex(const LockMutex ©); + LockMutex &operator=(const LockMutex &rhs) {} + + NTMutex *pMutex_; // do not delete +}; diff --git a/CommonLib/src/Common/Lib/NTEvent.cpp b/CommonLib/src/Common/Lib/NTEvent.cpp new file mode 100644 index 0000000..3ea053b --- /dev/null +++ b/CommonLib/src/Common/Lib/NTEvent.cpp @@ -0,0 +1,155 @@ +//>>*************************************************************************** +// UNCLASSIFIED +// +// COPYRIGHT © 2005, 2006, 2007, 2008, 2009, 2010, 2017 RAYTHEON MISSILE SYSTEMS +// ALL RIGHTS RESERVED +// This data was developed pursuant to Contract Number HQ 0276-10-C-0005 +// with the US Government. The US Government's rights in and to this +// copyrighted data are as specified in DFAR 252.227-7013 +// which was made part of the above contract. +// +// Distribution Statement: D -Distribution authorized to the DoD and DoD +// contractors only based on Critical Technology Requirements, May 2001. +// Other requests shall be referred to PEO THEATER AIR DEFENSE (PMS 422). +// Warning: - This document contains technical data whose export is restricted +// by the Arms Export Control Act (Title 22, U.S.C.) or Export +// Administration Act of 1979, as amended (Title 50, U.S.C.). Violations +// of these laws are subject to severe criminal penalties. Disseminate in +// accordance with provisions of DoD 5230.25. +// Destruction Notice: - For unclassified, limited distribution information, +// destroy by any method that will prevent disclosure of contents or +// reconstruction of the document. Classified information, destroy in +// accordance with DoD-5220.22-M or OPNAVINST 5510.1h. +// +// NAME +// @(#) $Workfile: NTEvent.cpp $ - +// +// DESCRIPTION +// +// $Revision: 0 $ +// +// REVISION HISTORY +// $Log: /SM3/src/app/common/lib/NTEvent.cpp $ +//<<*************************************************************************** + +#include +#include "NTEvent.hpp" +#include "Exception.hpp" + +//------------------------------------------------------------------------ + +NTEvent::NTEvent(const std::string& name, + bool manualReset, + bool initialState, + SECURITY_ATTRIBUTES *pSA) : + OSObject(name), + pSA_(pSA), + sd_(), + iOwnSecurityAttributesPointer_(false) +{ + iOwnSecurityAttributesPointer_ = (pSA_ == NULL) ? true : false; + initSecurity(); + + HANDLE handle = ::CreateEvent(pSA_, + manualReset, + initialState, + name.c_str()); + if (handle == NULL) + { + throw Exception(__FUNCTION_NAME__, "::CreateEvent() failed"); + } + + setHandle(handle); +} + +//------------------------------------------------------------------------ + +NTEvent::~NTEvent() +{ + if (iOwnSecurityAttributesPointer_) + { + // this was throwing for some reason + try + { + if(pSA_ != 0) + { + delete pSA_; + pSA_ = 0; + } + } + catch (...) + { + // keep going + } + } + pSA_ = 0; +} + +//------------------------------------------------------------------------ + +void NTEvent::wait(DWORD timeout) const +{ + std::stringstream ss; + DWORD retVal = ::WaitForSingleObject(getHandle(), timeout); + ss << "::WaitForSingleObject() returns " << retVal; + if (retVal == WAIT_FAILED) + { + throw Exception(__FUNCTION_NAME__, ss.str()); + } + else if (retVal == WAIT_TIMEOUT) + { + throw Exception(__FUNCTION_NAME__, ss.str()); + } +} + +//------------------------------------------------------------------------ + +void NTEvent::set() const +{ + if (!::SetEvent(getHandle())) + { + throw Exception(__FUNCTION_NAME__, "::SetEvent() failed"); + } +} +//------------------------------------------------------------------------ + +void NTEvent::reset() const +{ + if (!::ResetEvent(getHandle())) + { + throw Exception(__FUNCTION_NAME__, "::ResetEvent() failed"); + } +} + +//------------------------------------------------------------------------ + +void NTEvent::pulse() const +{ + if (!::PulseEvent(getHandle())) + { + throw Exception(__FUNCTION_NAME__, "::PulseEvent() failed"); + } +} + +//------------------------------------------------------------------------ + +void NTEvent::initSecurity() +{ + if (iOwnSecurityAttributesPointer_) + { + if (!::InitializeSecurityDescriptor(&sd_, SECURITY_DESCRIPTOR_REVISION)) + { + throw Exception(__FUNCTION_NAME__, "::InitializeSecurityDescriptor() failed"); + } + + if (!::SetSecurityDescriptorDacl(&sd_, TRUE, (PACL)NULL, FALSE)) + { + throw Exception(__FUNCTION_NAME__, "::SetSecurityDescriptorDacl() failed"); + } + + pSA_ = new SECURITY_ATTRIBUTES; + pSA_->nLength = sizeof(SECURITY_ATTRIBUTES); + pSA_->lpSecurityDescriptor = &sd_; + pSA_->bInheritHandle = TRUE; + } +} diff --git a/CommonLib/src/Common/Lib/NTEvent.hpp b/CommonLib/src/Common/Lib/NTEvent.hpp new file mode 100644 index 0000000..10223fe --- /dev/null +++ b/CommonLib/src/Common/Lib/NTEvent.hpp @@ -0,0 +1,108 @@ +#if !defined(NTEVENT_HPP) +#define NTEVENT_HPP + +#include +#include "OSObject.hpp" + +class NTEvent : public OSObject +{ +public: + //>--------------------------------------------------------------------- + // Function: + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + // const std::string &name, the name of the event (from EvantNames class) + // bool manualReset = true + // bool initialState = false + // SECURITY_ATTRIBUTES *pSA = NULL + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + explicit NTEvent(const std::string &name, + bool manualReset = true, + bool initialState = false, + SECURITY_ATTRIBUTES *pSA = NULL); + + //>--------------------------------------------------------------------- + // Function: ~NTEvent() + // + // Purpose: destructor + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual ~NTEvent(); + + //>--------------------------------------------------------------------- + // Function: wait() + // + // Purpose: calls Win32 wait function + //---------------------------------------------------------------------- + // Arguments: DWORD timeout, the timeout, in msec + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void wait(DWORD timeout = INFINITE) const; + + //>--------------------------------------------------------------------- + // Function: set() + // + // Purpose: to call ::SetEvent() + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void set() const; + + //>--------------------------------------------------------------------- + // Function: reset() + // + // Purpose: to call ::ResetEvent() + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void reset() const; + + //>--------------------------------------------------------------------- + // Function: pulse() + // + // Purpose: to call ::PulseEvent() + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void pulse() const; + +private: + // do not allow + NTEvent(); + NTEvent(const NTEvent ©); + NTEvent &operator=(const NTEvent &rhs) {} + + //>--------------------------------------------------------------------- + // Function: initSecurity() + // + // Purpose: to set up security stuff (see Miscrosoft KB Q106387) + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void initSecurity(); + + // I may own depending on value of ctor...if the passed in + // SECURITY_ATTRIBUTES is NULL, then I own pSA and need to delete + // it in the dtor + SECURITY_ATTRIBUTES *pSA_; + SECURITY_DESCRIPTOR sd_; + bool iOwnSecurityAttributesPointer_; +}; + +#endif // #if !defined(NTEVENT_HPP) diff --git a/CommonLib/src/Common/Lib/NTMutex.cpp b/CommonLib/src/Common/Lib/NTMutex.cpp new file mode 100644 index 0000000..e424d86 --- /dev/null +++ b/CommonLib/src/Common/Lib/NTMutex.cpp @@ -0,0 +1,100 @@ +#include +#include "NTMutex.hpp" +#include "Exception.hpp" + +NTMutex::NTMutex(const std::string& name, + bool initialOwner, + SECURITY_ATTRIBUTES* pSA) : + OSObject(name), + initialOwner_(initialOwner), + inheritHandle_(false), + desiredAccess_(0), + pSecurityAttributes_(pSA), + iOwnPSA_(false), + sd_() +{ + try + { + initSecurity(); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } + catch (...) + { + throw Exception(__FUNCTION_NAME__, "caught unknown "); + } + + // create the mutex and check for errors + HANDLE handle = ::CreateMutex(pSecurityAttributes_, + initialOwner_, + name.c_str()); + if (handle == NULL) + { + throw Exception(__FUNCTION_NAME__, "::CreateMutex() failed"); + } + + setHandle(handle); +} + +//------------------------------------------------------------------------ + +NTMutex::~NTMutex() +{ + if (iOwnPSA_) + { + if (pSecurityAttributes_ != 0) + { + delete pSecurityAttributes_; + pSecurityAttributes_ = 0; + } + } + pSecurityAttributes_ = 0; +} + +//------------------------------------------------------------------------ + +void NTMutex::lock(DWORD timeout) const +{ + std::stringstream ss; + DWORD retVal = ::WaitForSingleObject(getHandle(), timeout); + ss << "::WaitForSingleObject() returns " << retVal; + if (retVal == WAIT_FAILED || retVal == WAIT_TIMEOUT || retVal == WAIT_ABANDONED) //lint !e1924 + { + throw Exception(__FUNCTION_NAME__, ss.str()); + } +} + +//------------------------------------------------------------------------ + +void NTMutex::unlock() const +{ + if (!::ReleaseMutex(getHandle())) + { + throw Exception(__FUNCTION_NAME__, "::ReleaseMutex() failed"); + } +} + +//------------------------------------------------------------------------ + +void NTMutex::initSecurity() +{ + if (pSecurityAttributes_ == NULL) + { + pSecurityAttributes_ = new SECURITY_ATTRIBUTES; + iOwnPSA_ = true; + if (!::InitializeSecurityDescriptor(&sd_, SECURITY_DESCRIPTOR_REVISION)) + { + throw Exception(__FUNCTION_NAME__, "::InitializeSecurityDescriptor() failed"); + } + if (!::SetSecurityDescriptorDacl(&sd_, TRUE, (PACL)0, FALSE)) + { + throw Exception(__FUNCTION_NAME__, "::SetSecurityDescriptorDacl() failed"); + } + pSecurityAttributes_->nLength = sizeof(*pSecurityAttributes_); + pSecurityAttributes_->lpSecurityDescriptor = &sd_; + pSecurityAttributes_->bInheritHandle = TRUE; + } +} diff --git a/CommonLib/src/Common/Lib/NTMutex.hpp b/CommonLib/src/Common/Lib/NTMutex.hpp new file mode 100644 index 0000000..c007907 --- /dev/null +++ b/CommonLib/src/Common/Lib/NTMutex.hpp @@ -0,0 +1,85 @@ +#if !defined (NTMUTEX_HPP) +#define NTMUTEX_HPP + +#include "OSObject.hpp" + +class NTMutex : public OSObject +{ +public: + //>--------------------------------------------------------------------- + // Function: NTMutex() + // + // Purpose: constructor + //---------------------------------------------------------------------- + // Arguments: + // std::string name, the name of this mutex + // bool initialOwner, do I want to be the initial owner (usually not) + // SECURITY_ATTRIBUTES *pSA, pointer to SECURITY_ATTRIBUTES (usually NULL) + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + explicit NTMutex(const std::string &name = "", + bool initialOwner = false, + SECURITY_ATTRIBUTES *pSA = NULL); + + //>--------------------------------------------------------------------- + // Function: ~NTMutex() + // + // Purpose: destructor + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual ~NTMutex(); + + //>--------------------------------------------------------------------- + // Function: lock() + // + // Purpose: to lock the mutex + //---------------------------------------------------------------------- + // Arguments: DWORD timeout, in millisec + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void lock(DWORD timeout = INFINITE) const; + + //>--------------------------------------------------------------------- + // Function: unlock() + // + // Purpose: to unlock the mutex + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void unlock() const; + +private: + // do not allow + NTMutex(const NTMutex ©); + NTMutex &operator=(const NTMutex &rhs) {} + + //>--------------------------------------------------------------------- + // Function: initSecurity() + // + // Purpose: to set up security stuff (see Miscrosoft KB Q106387) + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void initSecurity(); + + bool initialOwner_; + bool inheritHandle_; + DWORD desiredAccess_; + SECURITY_ATTRIBUTES *pSecurityAttributes_; // I may own + + // there's a possibility that I may not own pSecurityAttributes, + // so iOwnPSA is needed to keep track of that + bool iOwnPSA_; // psa = pSecurityAttributes + SECURITY_DESCRIPTOR sd_; +}; + +#endif // #if !defined (NTMUTEX_HPP) diff --git a/CommonLib/src/Common/Lib/NTSemaphore.cpp b/CommonLib/src/Common/Lib/NTSemaphore.cpp new file mode 100644 index 0000000..505454d --- /dev/null +++ b/CommonLib/src/Common/Lib/NTSemaphore.cpp @@ -0,0 +1,60 @@ +#include +#include "NTSemaphore.hpp" +#include "Exception.hpp" + +//------------------------------------------------------------------------ + +NTSemaphore::NTSemaphore(const std::string &name_, + LONG initialCount, + LONG maxCount, + SECURITY_ATTRIBUTES *pSA) : + OSObject(name_) +{ + HANDLE handle = ::CreateSemaphore(pSA, + initialCount, + maxCount, + name_.c_str()); + if (handle == NULL) + { + throw Exception(__FUNCTION_NAME__, "::CreateSemaphore() failed"); + } + + // all is well + setHandle(handle); +} + +//------------------------------------------------------------------------ + +NTSemaphore::~NTSemaphore() +{ +} + +//------------------------------------------------------------------------ + +void NTSemaphore::wait(DWORD timeout) const +{ + std::stringstream ss; + DWORD retVal = ::WaitForSingleObject(getHandle(), timeout); + ss << "::WaitForSingleObject() returns " << retVal; + if (retVal == WAIT_FAILED) + { + throw Exception(__FUNCTION_NAME__, ss.str()); + } + else if (retVal == WAIT_TIMEOUT) + { + throw Exception(__FUNCTION_NAME__, ss.str()); + } +} + +//------------------------------------------------------------------------ + +LONG NTSemaphore::set(LONG releaseCount) const +{ + LONG previousCount = 0; + if (!::ReleaseSemaphore(getHandle(), releaseCount, &previousCount)) + { + throw Exception(__FUNCTION_NAME__, "::ReleaseSemaphore() failed"); + } + + return previousCount; +} diff --git a/CommonLib/src/Common/Lib/NTSemaphore.hpp b/CommonLib/src/Common/Lib/NTSemaphore.hpp new file mode 100644 index 0000000..7ecf700 --- /dev/null +++ b/CommonLib/src/Common/Lib/NTSemaphore.hpp @@ -0,0 +1,71 @@ +#if !defined(NTSEMAPHORE_HPP) +#define NTSEMAPHORE_HPP + +#include "OSObject.hpp" + +class NTSemaphore : public OSObject +{ +public: + // this is an arbitrary number + enum { MAX_SEMAPHORE_COUNT = 500}; + + //>--------------------------------------------------------------------- + // Function: NTSemaphore() + // + // Purpose: constructor + //---------------------------------------------------------------------- + // Arguments: + // const std::string &name, the name + // LONG initialCount = 0, some initial count + // LONG maxCount = MAX_SEMAPHORE_COUNT, how high to go + // SECURITY_ATTRIBUTES *pSA = NULL + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + explicit NTSemaphore(const std::string &name, + LONG initialCount = 0, + LONG maxCount = MAX_SEMAPHORE_COUNT, + SECURITY_ATTRIBUTES *pSA = NULL); + + //>--------------------------------------------------------------------- + // Function: ~NTSemaphore() + // + // Purpose: destructor + //---------------------------------------------------------------------- + // Arguments: none + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + virtual ~NTSemaphore(); + + //>--------------------------------------------------------------------- + // Function: wait() + // + // Purpose: to block for the semaphore + //---------------------------------------------------------------------- + // Arguments: DWORD timeout, careful about using INFINITE + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void wait(DWORD timeout = INFINITE)const; + + //>--------------------------------------------------------------------- + // Function: set() + // + // Purpose: set semaphore to signalled state + //---------------------------------------------------------------------- + // Arguments: LONG releaseCount, what to inc semaphore by + //---------------------------------------------------------------------- + // Return Value: LONG, the previous count + //<--------------------------------------------------------------------- + LONG set(LONG releaseCount = 1)const; + +private: + // do not allow + NTSemaphore(); + NTSemaphore(const NTSemaphore ©); + NTSemaphore &operator=(const NTSemaphore &rhs) {} + +}; + +#endif // #if !defined(NTSEMAPHORE_HPP) diff --git a/CommonLib/src/Common/Lib/OSObject.cpp b/CommonLib/src/Common/Lib/OSObject.cpp new file mode 100644 index 0000000..f634dca --- /dev/null +++ b/CommonLib/src/Common/Lib/OSObject.cpp @@ -0,0 +1,20 @@ +#include +#include "OSObject.hpp" + +OSObject::OSObject(const std::string &name) : + name_(name), + handle_(0) +{ + assert(name_.size() < MAX_PATH); // MAX_PATH defined in windef.h +} + +//------------------------------------------------------------------------ + +OSObject::~OSObject() +{ + if (handle_) + { + ::CloseHandle(handle_); // don't test for failure, we don't care + } + handle_ = 0; +} diff --git a/CommonLib/src/Common/Lib/OSObject.hpp b/CommonLib/src/Common/Lib/OSObject.hpp new file mode 100644 index 0000000..d5340bf --- /dev/null +++ b/CommonLib/src/Common/Lib/OSObject.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +class OSObject +{ +public: + //>--------------------------------------------------------------------- + // Function: OSObject() + // + // Purpose: + /// constructor + //---------------------------------------------------------------------- + // Arguments: std::string name, optional name for the object + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + explicit OSObject(const std::string &name = "NoName"); + + //>--------------------------------------------------------------------- + // Function: ~OSObject() + // + // Purpose: + /// destructor + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + virtual ~OSObject(); + + // get and set methods + std::string getName() const { return name_; } + HANDLE getHandle() const { return handle_; } + void setHandle(HANDLE handle) { handle_ = handle; } + +private: + // do not allow + OSObject(const OSObject ©); + OSObject &operator=(const OSObject &rhs) {} + + std::string name_; + HANDLE handle_; +}; diff --git a/CommonLib/src/Common/Lib/Thread.cpp b/CommonLib/src/Common/Lib/Thread.cpp new file mode 100644 index 0000000..7afdebd --- /dev/null +++ b/CommonLib/src/Common/Lib/Thread.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include // for ::_beginthreadex() + +#include "Thread.hpp" +#include "Exception.hpp" + +//------------------------------------------------------------------------ + +Thread::Thread(const std::string &name, DWORD stackSize) : + OSObject(name), + stackSize_(stackSize), + id_(0) +{ +} + +//------------------------------------------------------------------------ + +Thread::~Thread() +{ +} + +//------------------------------------------------------------------------ + +DWORD WINAPI Thread::startRoutine(LPVOID pArg) +{ + const DWORD NO_RUNTIME_ERROR = 0; + const DWORD SOME_RUNTIME_ERROR = 9999; + DWORD retVal = NO_RUNTIME_ERROR; + + // use this when we bomb + std::ostringstream oss; + + // this code below makes use of RTTI through dynamic_cast<>. For + // more information, see "The C++ Programming Language" 3th ed, by + // B. Stroustrup, section 15.4. + Thread *pBase = static_cast(pArg); + Thread *pObj = dynamic_cast(pBase); + + if (pObj != 0) + { + try + { + (*pObj)(); // run the thread + return retVal; + } + catch (Exception& e) + { + oss << e.getMessage(); + // handle situation where thread is deleted before we get here + if (pObj) + { + oss << ", thread name = " << pObj->getName() << ", ID = " + << pObj->getID(); + } + oss << std::endl; + retVal = SOME_RUNTIME_ERROR; + } + catch (std::exception& e) + { + oss << "std::exception: " + << e.what() + << " , thread name = " + << pObj->getName() + << std::endl; + retVal = SOME_RUNTIME_ERROR; + } + catch (...) + { + oss << "pObj->operator()(), caught (...)," + << " thread name = " + << pObj->getName() + << std::endl; + retVal = SOME_RUNTIME_ERROR; + } + } + + return retVal; +} + +//------------------------------------------------------------------------ + +void Thread::create(LPTHREAD_START_ROUTINE func) +{ + HANDLE handle1 = (HANDLE)::_beginthreadex(NULL, + stackSize_, + (P_THREAD_FUNC)func, + this, + CREATE_SUSPENDED, + (P_THREAD_ID)&id_); + if (handle1 == NULL) + { + throw Exception(__FUNCTION_NAME__, "::_beginthreadex() failed"); + } + + setHandle(handle1); +} + +//------------------------------------------------------------------------ + +// compiler seems to complain about max macro +#undef max + +void Thread::resume() const +{ + assert(getHandle() != NULL); + const DWORD RESUME_FAILED = std::numeric_limits::max(); + + DWORD retVal = ::ResumeThread(getHandle()); + if (retVal == RESUME_FAILED) + { + throw Exception(__FUNCTION_NAME__, "::ResumeThread() failed"); + } +} diff --git a/CommonLib/src/Common/Lib/Thread.hpp b/CommonLib/src/Common/Lib/Thread.hpp new file mode 100644 index 0000000..803f93e --- /dev/null +++ b/CommonLib/src/Common/Lib/Thread.hpp @@ -0,0 +1,124 @@ +#pragma once + +#include +#include "OSObject.hpp" + +class Thread : public OSObject +{ +public: + enum { DEFAULT_STACK_SIZE = 4096 }; + + //>--------------------------------------------------------------------- + // Function: Thread() + // + // Purpose: + /// constructor + //---------------------------------------------------------------------- + // Arguments: + /** const std::string &name, a required name for the thread (mostly for + // for debug) + // DWORD new_stack_size = 0, some stack size...0 means use parent + // stack size + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + explicit Thread(const std::string &name, + DWORD stackSize = DEFAULT_STACK_SIZE); + + //>--------------------------------------------------------------------- + // Function: ~Thread() + // + // Purpose: + /// destructor + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + virtual ~Thread(); + + //>--------------------------------------------------------------------- + // Function: operator()() + // + // Purpose: + /// where all the action is in the derived classes + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + virtual void operator()() = 0; + + //>--------------------------------------------------------------------- + // Function: startRoutine() + // + // Purpose: + // to call the run() method of this class. It uses RTTI to + // determine what the derived type is and calls correct method. + //---------------------------------------------------------------------- + // Arguments: LPVOID pArg, 'this' pointer from create() method + //---------------------------------------------------------------------- + // + // Return Value: DWORD WINAPI, return zero for now + //<---------------------------------------------------------------------*/ + static DWORD WINAPI startRoutine(LPVOID pArg); + + //>--------------------------------------------------------------------- + // Function: create() + // + // Purpose: + /// to make call the system thread creation routine + //---------------------------------------------------------------------- + // Arguments: LPTHREAD_START_ROUTINE func, pointer to start function + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + void create(LPTHREAD_START_ROUTINE func); + + //>--------------------------------------------------------------------- + // Function: resume() + // + // Purpose: + // to use the same call to resume MFC and non-MFC threads + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + void resume() const; + + //>--------------------------------------------------------------------- + // Function: getID() + // + // Purpose: + /// to get the ID of the thread + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: unsigned int, the ID, homeboy + //<---------------------------------------------------------------------*/ + unsigned int getID() const { return id_; } + + // typedefs for the params to ::_beginthreadex() + typedef unsigned (__stdcall *P_THREAD_FUNC)(void *); + typedef unsigned *P_THREAD_ID; + +private: + // do not allow + Thread(); + Thread(const Thread ©); + Thread &operator=(const Thread &rhs) {} + + DWORD stackSize_; + unsigned int id_; +}; diff --git a/CommonLib/src/Common/Lib/Timestamp.cpp b/CommonLib/src/Common/Lib/Timestamp.cpp new file mode 100644 index 0000000..4ec5249 --- /dev/null +++ b/CommonLib/src/Common/Lib/Timestamp.cpp @@ -0,0 +1,83 @@ +#include +#include +#include +#include "Timestamp.hpp" + +//------------------------------------------------------------------------ + +Timestamp::Timestamp() : + startTime_(0) +{ + timeBuff_[0] = '\0'; + // set the timezone based on the TZ environment variable + ::_tzset(); +} + +//------------------------------------------------------------------------ + +Timestamp::~Timestamp() +{ +} + +//------------------------------------------------------------------------ + +void Timestamp::startTiming() +{ + startTime_ = ::clock(); +} + +//------------------------------------------------------------------------ + +long Timestamp::getElapsedTimeInMs() const +{ + return ::clock() - startTime_; +} + +//------------------------------------------------------------------------ + +void Timestamp::GetCurrentDateTimeString(std::string& date, std::string& time, Timestamp::DateFormat dateFormat, Timestamp::TimeFormat timeFormat, std::string separator) +{ + std::stringstream ss; + std::stringstream millisec; + struct timeb timeBuffer; + ftime(&timeBuffer); + struct tm myTm; + _localtime64_s(&myTm, &timeBuffer.time); + + switch (dateFormat) + { + case Timestamp::DateFormat::YYYYMM: + ss << std::setfill('0') << "20" << std::setw(2) << myTm.tm_year % 100 + << separator << std::setfill('0') << std::setw(2) << myTm.tm_mon + 1; + break; + case Timestamp::DateFormat::YYYYMMDD: + ss << std::setfill('0') << "20" << std::setw(2) << myTm.tm_year % 100 + << separator << std::setfill('0') << std::setw(2) << myTm.tm_mon + 1 + << separator << std::setfill('0') << std::setw(2) << myTm.tm_mday; + break; + case Timestamp::DateFormat::MMDDYYYY: + ss << std::setfill('0') << std::setfill('0') << std::setw(2) << myTm.tm_mon + 1 + << separator << std::setfill('0') << std::setw(2) << myTm.tm_mday + << separator << "20" << std::setw(2) << myTm.tm_year % 100; + } + + date = ss.str(); + + ss.clear(); + ss.str(""); + switch (timeFormat) + { + case Timestamp::TimeFormat::HHMMSS: + case Timestamp::TimeFormat::HHMMSSMM: + ss << std::setfill('0') << std::setw(2) << myTm.tm_hour << separator + << std::setfill('0') << std::setw(2) << myTm.tm_min << separator + << std::setfill('0') << std::setw(2) << myTm.tm_sec; + } + + if (timeFormat == Timestamp::TimeFormat::HHMMSSMM) + ss << "." << std::setw(3) << std::setfill('0') << timeBuffer.millitm; + + time = ss.str(); +} + + diff --git a/CommonLib/src/Common/Lib/Timestamp.hpp b/CommonLib/src/Common/Lib/Timestamp.hpp new file mode 100644 index 0000000..dfdc741 --- /dev/null +++ b/CommonLib/src/Common/Lib/Timestamp.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include +#include + +class Timestamp +{ +public: + enum class DateFormat + { + YYYYMM, + YYYYMMDD, + MMDDYYYY + }; + + enum class TimeFormat + { + HHMMSS, + HHMMSSMM + }; + + //>--------------------------------------------------------------------- + // Function: Timestamp() + // + // Purpose: + /// constructor + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + Timestamp(); + + //>--------------------------------------------------------------------- + // Function: ~Timestamp() + // + // Purpose: + /// destructor + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: none + //<---------------------------------------------------------------------*/ + ~Timestamp(); + + //>--------------------------------------------------------------------- + // Function: getLength() + // + // Purpose: + /// to return the length of the time string + //---------------------------------------------------------------------- + // Arguments: none /** + // + //---------------------------------------------------------------------- + // + // Return Value: int, the length + //<---------------------------------------------------------------------*/ + int getLength() const { return CTIME_LENGTH_; } + + //>--------------------------------------------------------------------- + // Function: GetCurrentDateTimeString + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + static void GetCurrentDateTimeString(std::string& date, std::string& time, Timestamp::DateFormat dateFormat, Timestamp::TimeFormat timeFormat, std::string separator = ""); + + //>--------------------------------------------------------------------- + // Function: startTiming + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + void startTiming(); + + //>--------------------------------------------------------------------- + // Function: getElapsedTimeInMs + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + long getElapsedTimeInMs() const; + +private: + // do not allow + Timestamp(const Timestamp &rhs); + Timestamp& operator=(const Timestamp& rhs) {}; + + enum { CTIME_LENGTH_ = 26 }; + char timeBuff_[CTIME_LENGTH_]; + clock_t startTime_; +}; \ No newline at end of file diff --git a/CommonLib/src/Common/Lib/Util/FileSystemUtil.cpp b/CommonLib/src/Common/Lib/Util/FileSystemUtil.cpp new file mode 100644 index 0000000..84ed37d --- /dev/null +++ b/CommonLib/src/Common/Lib/Util/FileSystemUtil.cpp @@ -0,0 +1,457 @@ +#include +#include +#include + +#include "shlwapi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FileSystemUtil.hpp" +#include "Exception.hpp" +#include "Timestamp.hpp" +#include "CRC32.h" +#include "ErrorLog.hpp" + +//------------------------------------------------------------------------ + +char* Util::FileSystem::GetFileContents(const std::string& file, long& dataArraySize) +{ + try + { + // open file + std::ifstream binStream(file.c_str(), std::ios_base::binary); + + if (binStream.fail()) + { + throw Exception(__FUNCTION_NAME__, "could not open file: " + file); + } + + // calc data size + binStream.seekg(0, std::ios_base::end); + + // this call only works on files 2 GB or less + dataArraySize = static_cast(binStream.tellg()); + + if (dataArraySize <= 0) + { + std::stringstream ss; + ss << file << " has invalid file size: " << dataArraySize; + + throw Exception(__FUNCTION_NAME__, ss.str()); + } + // get the data + char* pData = new char[dataArraySize]; + + // go back to beginning of the file + binStream.seekg(0); + binStream.read(pData, dataArraySize); + + // close the file + binStream.close(); + + return pData; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } + catch (...) + { + throw Exception(__FUNCTION_NAME__, "caught (...)"); + } +} + +//----------------------------------------------------------------------------- + +void Util::FileSystem::CopyFile(const std::string& fromFile, const std::string& toFile, const bool& shallWeCheckCrc, const bool& shallWeRemoveOldFile) +{ + try + { + // create the folder path to the toFile if it does not exisit. + std::string toFileModified = toFile; + char* folderPath = (char*)toFileModified.c_str(); + PathRemoveFileSpec(folderPath); + std::string newFolderPath = folderPath; + newFolderPath += "\\"; + CreateFolder(newFolderPath.c_str()); + + if (shallWeCheckCrc == true) + { + CCRC32 crcCalc; + + // crc the original file + long orignalDataArraySize = 0; + char* pOriginalData = GetFileContents(fromFile, orignalDataArraySize); + unsigned int originalCrc = crcCalc.computeCRC(pOriginalData, orignalDataArraySize); + delete[] pOriginalData; + pOriginalData = 0; + + // copy it + BOOL copyRet = ::CopyFile(fromFile.c_str(), toFile.c_str(), true); + + if (copyRet != TRUE) + { + int err = ::GetLastError(); + std::stringstream ss; + ss << "copy failed. From: " << fromFile << ", To: " << toFile << ", Error: " << err; + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + // crc the new one + long newDataArraySize = 0; + char* pNewData = GetFileContents(toFile, newDataArraySize); + unsigned int newCrc = crcCalc.computeCRC(pNewData, newDataArraySize); + delete[] pNewData; + pNewData = 0; + + // check the crc + if (originalCrc != newCrc) + { + std::stringstream ssError; + ssError << "Crcs do not match for files. Original: " << fromFile << ", New: " << toFile << ", Original Crc: " << originalCrc << ", newCrc: " << newCrc; + throw Exception(__FUNCTION_NAME__, ssError.str()); + } + } + else + { + // copy it + BOOL copyRet = ::CopyFile(fromFile.c_str(), toFile.c_str(), true); + + int err = ::GetLastError(); + + if (copyRet != TRUE) + { + std::stringstream ss; + ss << "copy failed. From: " << fromFile << ", To: " << toFile << ", Error: " << err; + throw Exception(__FUNCTION_NAME__, ss.str()); + } + } + + if (shallWeRemoveOldFile == true) + { + // delete the original + int removeRet = std::remove(fromFile.c_str()); + + if (removeRet != 0) + { + ErrorLog::Instance().log(std::string(__FUNCTION_NAME__) + " - call to remove: " + fromFile + ", failed"); + } + } + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +bool Util::FileSystem::CreateFolder(const std::string& directory) +{ + try + { + bool success = true; + + // Find first slash after the drive or server name (3 places search after + // the "\". + size_t strPos = directory.find_first_of("\\", 3); + if (directory[1] == '\\') + { + strPos = directory.find_first_of("\\", ++strPos); + } + + std::string subFolder = ""; + while (subFolder.length() <= directory.length()) + { + // Get subfolder by looking from beginning of string to current "\" + if (strPos != directory.npos) + subFolder = directory.substr(0, strPos); + + if (IsDirectory(subFolder.c_str()) || ::_mkdir(subFolder.c_str()) == 0) + { + if (subFolder.length() == directory.length()) + break; + + strPos = directory.find_first_of("\\", strPos + 1); + + if (strPos == directory.npos) + subFolder = directory; + } + else + { + success = false; + break; + } + }// end while(strPos != folder_.npos) + + return success; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +std::string Util::FileSystem::GetExePathAndFilename() +{ + try + { + char modName[MAX_PATH] = { '\0' }; + ::GetModuleFileName(NULL, modName, MAX_PATH); + std::string app = modName; + return app; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +int Util::FileSystem::IsFile(std::string path) +{ + try + { + std::ifstream ifile(path); + return ifile.good(); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +int Util::FileSystem::IsDirectory(std::string path) +{ + try + { + bool pathExists = false; + + DWORD fileAttr = GetFileAttributesA(path.c_str()); + + if (fileAttr != INVALID_FILE_ATTRIBUTES && fileAttr & FILE_ATTRIBUTE_DIRECTORY) + pathExists = true; // this is a directory! + + return pathExists; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +std::string Util::FileSystem::ExtractDirectory(std::string path) +{ + try + { + std::string actualPath = path; + + if (!IsDirectory(path)) + { + actualPath = path.substr(0, path.find_last_of('\\') + 1); + + if (actualPath.length() == 0) + actualPath = path.substr(0, path.find_last_of('/') + 1); + } + + return actualPath; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +std::string Util::FileSystem::ExtractFilename(std::string path) +{ + try + { + return path.substr(path.find_last_of('\\') + 1); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +std::string Util::FileSystem::AddSlashToPath(const std::string &path) +{ + std::string tempPath = path; + + char ch = path.back(); + + if (ch != '\\') + tempPath = path + "\\"; + + return tempPath; +} + +//----------------------------------------------------------------------------- + +std::string Util::FileSystem::RemoveSlashInFrontOfPath(const std::string &path) +{ + std::string tempPath = path; + + char ch = path.front(); + + if (ch == '\\') + tempPath = path.substr(1, path.length() - 1); + + return tempPath; +} + +//----------------------------------------------------------------------------- + +std::string Util::FileSystem::BuildPath(const std::string &left, const std::string &right) +{ + std::string path; + + path = AddSlashToPath(left); + + if (right.length() > 0) + path += RemoveSlashInFrontOfPath(right); + + return path; +} + +//------------------------------------------------------------------------ + +void Util::FileSystem::GetAllFilesInFolder(const std::string& folderPath, std::vector& files, const bool& recursive) +{ + std::string actualFolderPath = folderPath; + std::string searchPath = ""; + WIN32_FIND_DATA fd; + HANDLE hFind = INVALID_HANDLE_VALUE; + std::string item = ""; + + // make sure last character of path is '\' + if (actualFolderPath.back() != '\\') + { + actualFolderPath += '\\'; + } + + searchPath = actualFolderPath + "*.*"; + + hFind = ::FindFirstFile(searchPath.c_str(), &fd); + + if (hFind != INVALID_HANDLE_VALUE) + { + do + { + item = std::string(fd.cFileName); + + // if item is a file + if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + // if file is not hidden + if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)) + files.push_back(actualFolderPath + item); + } + else if (item != "." && item != "..") // if item is a folder + { + if (recursive) + { + GetAllFilesInFolder(actualFolderPath + item, files, recursive); + } + } + } while (::FindNextFile(hFind, &fd)); + + ::FindClose(hFind); + } +} + +//----------------------------------------------------------------------------- + +void Util::FileSystem::CleanUpLogs(const std::string& logPath, const std::string& fileNameregexPattern) +{ + std::vector tempFileVec; + std::vector fileVec; + GetAllFilesInFolder(logPath, tempFileVec, false); + int maxConsecutiveFileRemovals = 10; + int consecutiveFileRemovalFails = 0; + + for (auto it = tempFileVec.begin(); it != tempFileVec.end(); it++) + { + if (std::regex_search(*it, std::regex(fileNameregexPattern, std::regex_constants::icase))) + { + std::uintmax_t size = std::filesystem::file_size(*it); + + if (size == 0) + { + std::string file = *it; + if (std::remove(file.c_str()) != 0) + consecutiveFileRemovalFails++; + else if (consecutiveFileRemovalFails > 0) + consecutiveFileRemovalFails = 0; + + if (consecutiveFileRemovalFails == maxConsecutiveFileRemovals) + break; + } + else + fileVec.push_back(*it); + } + } + + struct timeb timeBuffer; + ftime(&timeBuffer); + struct tm myTm; + // get current time + _localtime64_s(&myTm, &timeBuffer.time); + + struct stat fileInfo; + // keep logs that were created in the last 7 days + const unsigned int MAX_NUM_DAYS_TO_KEEP_LOGS = 5; + const unsigned int MAX_NUM_LOGS_TO_KEEP = 30; + unsigned int daysElapsedSinceFileCreated = 0; + consecutiveFileRemovalFails = 0; + for (auto it = fileVec.begin(); it != fileVec.end();) + { + std::string file = *it; + if (stat(file.c_str(), &fileInfo) == 0) + { + daysElapsedSinceFileCreated = static_cast(difftime(timeBuffer.time, fileInfo.st_ctime) / (24 * 60 * 60)); + } + + if (fileVec.size() > MAX_NUM_LOGS_TO_KEEP || daysElapsedSinceFileCreated > MAX_NUM_DAYS_TO_KEEP_LOGS) + { + if (std::remove(file.c_str()) != 0) + consecutiveFileRemovalFails++; + else if (consecutiveFileRemovalFails > 0) + consecutiveFileRemovalFails = 0; + + it = fileVec.erase(it); + + if (consecutiveFileRemovalFails == maxConsecutiveFileRemovals) + break; + } + else + ++it; + } +} \ No newline at end of file diff --git a/CommonLib/src/Common/Lib/Util/FileSystemUtil.hpp b/CommonLib/src/Common/Lib/Util/FileSystemUtil.hpp new file mode 100644 index 0000000..370ace7 --- /dev/null +++ b/CommonLib/src/Common/Lib/Util/FileSystemUtil.hpp @@ -0,0 +1,158 @@ +#ifndef FILE_SYSTEM_UTIL_H +#define FILE_SYSTEM_UTIL_H + +#include +#include + +namespace Util +{ + namespace FileSystem + { + //>--------------------------------------------------------------------- + // Function: CopyFile + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: fromName - + // toName - + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + char* GetFileContents(const std::string& file, long& dataArraySize); + + //>--------------------------------------------------------------------- + // Function: CopyFile + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: fromName - + // toName - + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void CopyFile(const std::string& fromFile, const std::string& toFile, const bool& shallWeCheckCrc, const bool& shallWeRemoveOldFile); + + //>--------------------------------------------------------------------- + // Function: CreateDirectory + // + // Purpose: creates a directory + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + bool CreateFolder(const std::string& directory); + + //>--------------------------------------------------------------------- + // Function: getExePathAndFilename + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string GetExePathAndFilename(); + + //>--------------------------------------------------------------------- + // Function: isFile + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + int IsFile(std::string path); + + //>--------------------------------------------------------------------- + // Function: isDirectory + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + int IsDirectory(std::string path); + + //>--------------------------------------------------------------------- + // Function: extractDirectory + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string ExtractDirectory(std::string path); + + //>--------------------------------------------------------------------- + // Function: extractFilename + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string ExtractFilename(std::string path); + + //>--------------------------------------------------------------------- + // Function: AddBackSlashToPath + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string AddSlashToPath(const std::string& path); + + //>--------------------------------------------------------------------- + // Function: RemoveSlashInFrontOfPath + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string RemoveSlashInFrontOfPath(const std::string& path); + + //>--------------------------------------------------------------------- + // Function: BuildPath + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string BuildPath(const std::string& left, const std::string& right = ""); + + //>--------------------------------------------------------------------- + // Function: CleanUpLogs + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + void CleanUpLogs(const std::string& logPath, const std::string& fileNameregexPattern); + + //>--------------------------------------------------------------------- + // Function: GetAllFilesInFolder + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + void GetAllFilesInFolder(const std::string& folderPath, std::vector& files, const bool& recursive); + } +} + +#endif diff --git a/CommonLib/src/Common/Lib/Util/MiscUtil.cpp b/CommonLib/src/Common/Lib/Util/MiscUtil.cpp new file mode 100644 index 0000000..293157d --- /dev/null +++ b/CommonLib/src/Common/Lib/Util/MiscUtil.cpp @@ -0,0 +1,44 @@ +#include + +#include +#include +#include +#include + +#include "MiscUtil.hpp" +#include "StringUtil.hpp" +#include "Exception.hpp" +#include "Timestamp.hpp" + +//----------------------------------------------------------------------------- + +std::string Util::Misc::GetComputerName() +{ + try + { + const int MAX_CPU_NAME_LEN = 33; + + static bool gotName = false; + + static std::string name = "UNAVAILABLE"; + + if (!gotName) + { + TCHAR computerName[MAX_CPU_NAME_LEN + 1]; + DWORD computerNameLen = MAX_CPU_NAME_LEN; + + if (::GetComputerName(computerName, &computerNameLen)) + { + name = computerName; + gotName = true; + } + } + + return name; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} diff --git a/CommonLib/src/Common/Lib/Util/MiscUtil.hpp b/CommonLib/src/Common/Lib/Util/MiscUtil.hpp new file mode 100644 index 0000000..fd65ed2 --- /dev/null +++ b/CommonLib/src/Common/Lib/Util/MiscUtil.hpp @@ -0,0 +1,25 @@ +#ifndef MISC_UTIL_H +#define MISC_UTIL_H + +#include +#include +#include + +namespace Util +{ + namespace Misc + { + //>--------------------------------------------------------------------- + // Function: GetComputerName + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string GetComputerName(); + } +} + +#endif diff --git a/CommonLib/src/Common/Lib/Util/NetworkUtil.cpp b/CommonLib/src/Common/Lib/Util/NetworkUtil.cpp new file mode 100644 index 0000000..d118b28 --- /dev/null +++ b/CommonLib/src/Common/Lib/Util/NetworkUtil.cpp @@ -0,0 +1,80 @@ +#include // always make sure this is placed before any include +#include + +#include +#include +#include +#include +#include + +#include "NetworkUtil.hpp" +#include "StringUtil.hpp" +#include "Exception.hpp" +#include "Timestamp.hpp" + +//------------------------------------------------------------------------ + +bool Util::Network::IsIpAddress(const std::string& ipAddress) +{ + try + { + std::string octet; + for (int i = 0; i < 4; i++) + { + octet = Strings::GetSubstringDelimited(ipAddress, ".", i); + if (Strings::IsNumeric(octet)) + { + std::stringstream ss; + ss << octet; + int num; + ss >> num; + if (num > 254) + return false; + } + else + return false; + } + + return true; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +std::string Util::Network::ConvertHostnameToIp(std::string hostname) +{ + std::string ip = hostname; + // convert to dot address notation if needed + if (hostname.length() > 0 && !IsIpAddress(hostname)) + { + struct addrinfo hints = {}, * addrInfo; + char port_str[16] = {}; + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + int dwRetval = getaddrinfo(hostname.c_str(), port_str, &hints, &addrInfo); + + if (dwRetval != 0) + { + std::stringstream ss; + ss << "getaddrinfo() failed with error : " << WSAGetLastError(); + throw Exception(__FUNCTION_NAME__, ss.str()); + } + + struct sockaddr_in* ipv = (struct sockaddr_in*)addrInfo->ai_addr; + struct in_addr* addr = &(ipv->sin_addr); + + char ipstr[INET_ADDRSTRLEN]; + inet_ntop(addrInfo->ai_family, addr, ipstr, sizeof(ipstr)); + ip = std::string(ipstr); + } + + return ip; +} \ No newline at end of file diff --git a/CommonLib/src/Common/Lib/Util/NetworkUtil.hpp b/CommonLib/src/Common/Lib/Util/NetworkUtil.hpp new file mode 100644 index 0000000..07c2a98 --- /dev/null +++ b/CommonLib/src/Common/Lib/Util/NetworkUtil.hpp @@ -0,0 +1,35 @@ +#ifndef NETWORK_UTIL_H +#define NETWORK_UTIL_H + +#include +#include + +namespace Util +{ + namespace Network + { + //>--------------------------------------------------------------------- + // Function: IsIpAddress + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + bool IsIpAddress(const std::string& ipAddress); + + //>--------------------------------------------------------------------- + // Function: convertHostnameToIp + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string ConvertHostnameToIp(std::string hostname); + } +} + +#endif diff --git a/CommonLib/src/Common/Lib/Util/StringUtil.cpp b/CommonLib/src/Common/Lib/Util/StringUtil.cpp new file mode 100644 index 0000000..1a1d5ee --- /dev/null +++ b/CommonLib/src/Common/Lib/Util/StringUtil.cpp @@ -0,0 +1,310 @@ +#include +#include +#include +#include +#include + +#include "StringUtil.hpp" +#include "Exception.hpp" +#include "Timestamp.hpp" + +//----------------------------------------------------------------------------- + +std::vector Util::Strings::StringSplit(const std::string& s, const std::string& delim, const bool keepEmpty) +{ + std::vector result; + if (delim.empty()) + { + result.push_back(s); + } + else + { + std::string::const_iterator substart = s.begin(), subend; + while (true) + { + subend = std::search(substart, s.end(), delim.begin(), delim.end()); + std::string temp(substart, subend); + if (keepEmpty || !temp.empty()) + { + result.push_back(temp); + } + if (subend == s.end()) + { + break; + } + substart = subend + delim.size(); + } + } + return result; +} + +//----------------------------------------------------------------------------- + +std::string Util::Strings::ToLower(const std::string& s) +{ + try + { + std::string lower(s); + for(size_t i = 0; i < s.length(); i++) + { + lower[i] = tolower(lower[i]); + } + + return lower; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +std::string Util::Strings::ToUpper(const std::string& s) +{ + try + { + std::string upper(s); + for(size_t i = 0; i < s.length(); i++) + { + upper[i] = toupper(upper[i]); + } + + return upper; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +std::string Util::Strings::TrimSpaces(const std::string& s) +{ + try + { + size_t firstNonSpace = s.find_first_not_of(' '); + size_t lastNonSpace = s.find_last_not_of(' '); + + // if no leading space, then start at beginning of string + if (firstNonSpace == std::string::npos) + { + firstNonSpace = 0; + } + + return s.substr(firstNonSpace, lastNonSpace - firstNonSpace + 1); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +bool Util::Strings::ToInt(std::string string, int& value) +{ + bool status = true; + value = 0; + + TrimSpaces(string); + // CConvert string type to char array + const char* str = (char*)string.c_str(); + // CConvert string to integer type + int fieldCount = sscanf_s(str, "%d", &value); + + if (fieldCount < 1) + status = false; + + return status; +} + +//----------------------------------------------------------------------------- + +double Util::Strings::ToDouble(const std::string& string) +{ + try + { + std::stringstream ss; + ss << string; + + double temp = 0.0; + + ss >> temp; + + return temp; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +std::string Util::Strings::ToString(const int& val) +{ + try + { + std::stringstream ss; + ss << val; + return ss.str(); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +std::string Util::Strings::ToString(const double& val) +{ + try + { + std::stringstream ss; + ss << val; + return ss.str(); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//------------------------------------------------------------------------ + +std::string Util::Strings::GetSubstringDelimited(std::string s, std::string delimiter, int index) +{ + try + { + std::vector row; + + row = StringSplit(s, delimiter, false); + + if ((int)row.size() > index) + return row[index]; + else + return ""; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//------------------------------------------------------------------------ + +bool Util::Strings::IsNumeric(const std::string& s) +{ + try + { + int sizeOfString = static_cast(s.length()); + int iteration = 0; + bool isNumeric = true; + + if (sizeOfString == 0) + isNumeric = false; + + while (iteration < sizeOfString) + { + if (!isdigit(s[iteration])) + { + isNumeric = false; + break; + } + + iteration++; + } + + return isNumeric; + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +bool Util::Strings::StringsAreEqual(std::string str1, std::string str2, bool caseSensitive) +{ + bool stringsAreEqual = false; + + if (!caseSensitive) + { + std::transform(str1.begin(), str1.end(), str1.begin(), toupper); + std::transform(str2.begin(), str2.end(), str2.begin(), toupper); + } + + if (str1 == str2) + stringsAreEqual = true; + + return stringsAreEqual; + +} + +//----------------------------------------------------------------------------- + +std::string Util::Strings::ByteArrayToHexString(unsigned char* byteArray, unsigned int numBytes) +{ + try + { + std::stringstream ss; + + for (unsigned int i = 0; i < numBytes; i++) + { + if (i == 0) + ss << "0x"; + else + ss << " "; + + ss << std::hex << std::setw(2) << std::setfill('0') << static_cast(byteArray[i]); + } + + return ss.str(); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} + +//----------------------------------------------------------------------------- + +std::string Util::Strings::ByteArrayToString(unsigned char* byteArray, unsigned int numBytes) +{ + unsigned char* pTempBuf = 0; + try + { + pTempBuf = new unsigned char[numBytes + 1]; + + memcpy(pTempBuf, byteArray, numBytes); + pTempBuf[numBytes] = '\0'; + + std::string str(reinterpret_cast(pTempBuf)); + + if (pTempBuf != 0) + delete[] pTempBuf; + + return str; + } + catch (Exception& e) + { + if (pTempBuf != 0) + delete[] pTempBuf; + + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} diff --git a/CommonLib/src/Common/Lib/Util/StringUtil.hpp b/CommonLib/src/Common/Lib/Util/StringUtil.hpp new file mode 100644 index 0000000..669bc2b --- /dev/null +++ b/CommonLib/src/Common/Lib/Util/StringUtil.hpp @@ -0,0 +1,156 @@ +#ifndef STRING_UTIL_H +#define STRING_UTIL_H + +#include +#include + +namespace Util +{ + namespace Strings + { + //>--------------------------------------------------------------------- + // Function: StringSplit + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::vector StringSplit(const std::string& s, const std::string& delim, const bool keepEmpty = false); + + //>--------------------------------------------------------------------- + // Function: ToInt + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + bool ToInt(std::string string, int& value); + + //>--------------------------------------------------------------------- + // Function: ToDouble + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + double ToDouble(const std::string& string); + + //>--------------------------------------------------------------------- + // Function: ToLower + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string ToLower(const std::string& s); + + //>--------------------------------------------------------------------- + // Function: ToString + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string ToString(const int& val); + + //>--------------------------------------------------------------------- + // Function: ToString + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string ToString(const double& val); + + //>--------------------------------------------------------------------- + // Function: ToUpper + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string ToUpper(const std::string& s); + + //>--------------------------------------------------------------------- + // Function: TrimSpaces + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string TrimSpaces(const std::string& s); + + //>--------------------------------------------------------------------- + // Function: GetSubstringDelimited + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string GetSubstringDelimited(std::string s, std::string delimiter, int index); + + //>--------------------------------------------------------------------- + // Function: IsNumeric + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + bool IsNumeric(const std::string& s); + + //>--------------------------------------------------------------------- + // Function: StringsAreEqual + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + bool StringsAreEqual(std::string str1, std::string str2, bool caseSensitive = false); + + //>--------------------------------------------------------------------- + // Function: ByteArrayToHexString + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string ByteArrayToHexString(unsigned char* byteArray, unsigned int numBytes); + + //>--------------------------------------------------------------------- + // Function: ByteArrayToString + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: + //<--------------------------------------------------------------------- + std::string ByteArrayToString(unsigned char* byteArray, unsigned int numBytes); + } +} + +#endif diff --git a/CommonLib/src/Common/Names/EventNames.cpp b/CommonLib/src/Common/Names/EventNames.cpp new file mode 100644 index 0000000..8558dc3 --- /dev/null +++ b/CommonLib/src/Common/Names/EventNames.cpp @@ -0,0 +1,42 @@ +#include + +#include "EventNames.hpp" +#include "Exception.hpp" + +EventNames& EventNames::Instance() +{ + static EventNames names; + return names; +} + +//------------------------------------------------------------------------ + +EventNames::~EventNames() +{ +} + +//------------------------------------------------------------------------ + +EventNames::EventNames(): + m_nameMap() +{ + m_nameMap[GLOBAL_QUIT] = "GLOBAL_QUIT"; + m_nameMap[COMMAND_EXECUTTION_IN_PROGRESS] = "COMMAND_EXECUTTION_IN_PROGRESS"; + m_nameMap[COMMAND_EXECUTION_COMPLETE] = "COMMAND_EXECUTION_COMPLETE"; + m_nameMap[START_FILE_TRANSFER] = "START_FILE_TRANSFER"; +} + +//------------------------------------------------------------------------ + +std::string EventNames::operator[](EventNames::Names name) +{ + std::map::const_iterator it = m_nameMap.find(name); + if (it == m_nameMap.end()) + { + std::stringstream ss; + ss << "value " << name << " not found"; + throw Exception(__FUNCTION_NAME__,ss.str()); + } + + return it->second; +} diff --git a/CommonLib/src/Common/Names/EventNames.hpp b/CommonLib/src/Common/Names/EventNames.hpp new file mode 100644 index 0000000..db292e5 --- /dev/null +++ b/CommonLib/src/Common/Names/EventNames.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +class EventNames +{ +public: + static EventNames& Instance(); + virtual ~EventNames(); + + enum Names + { + GLOBAL_QUIT, + COMMAND_EXECUTTION_IN_PROGRESS, + COMMAND_EXECUTION_COMPLETE, + START_FILE_TRANSFER, + NUM_EVENTS + }; + + std::string operator[](EventNames::Names name); + +private: + // do not allow + EventNames(const EventNames &rhs); + EventNames &operator=(const EventNames &rhs); + EventNames(); + + std::map m_nameMap; +}; diff --git a/CommonLib/src/Common/Names/MailboxNames.cpp b/CommonLib/src/Common/Names/MailboxNames.cpp new file mode 100644 index 0000000..9d1fc8b --- /dev/null +++ b/CommonLib/src/Common/Names/MailboxNames.cpp @@ -0,0 +1,38 @@ +#include +#include "MailboxNames.hpp" +#include "Exception.hpp" + +MailboxNames& MailboxNames::Instance() +{ + static MailboxNames names; + return names; +} + +//------------------------------------------------------------------------ + +MailboxNames::~MailboxNames() +{ +} + +//------------------------------------------------------------------------ + +MailboxNames::MailboxNames(): + m_nameMap() +{ + m_nameMap[SAMPLE] = "SAMPLE"; +} + +//------------------------------------------------------------------------ + +std::string MailboxNames::operator[](Names name) +{ + std::map::const_iterator it = m_nameMap.find(name); + if (it == m_nameMap.end()) + { + std::stringstream ss; + ss << "value " << name << " not found"; + throw Exception(__FUNCTION_NAME__,ss.str()); + } + + return it->second; +} diff --git a/CommonLib/src/Common/Names/MailboxNames.hpp b/CommonLib/src/Common/Names/MailboxNames.hpp new file mode 100644 index 0000000..ed6e6bf --- /dev/null +++ b/CommonLib/src/Common/Names/MailboxNames.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +class MailboxNames +{ +public: + static MailboxNames& Instance(); + virtual ~MailboxNames(); + + enum Names + { + SAMPLE, + NUM_MAILBOXES + }; + + std::string operator[](Names name); + +private: + // do not allow + MailboxNames(const MailboxNames &rhs); + MailboxNames &operator=(const MailboxNames &rhs); + MailboxNames(); + + std::map m_nameMap; +}; diff --git a/CommonLib/src/Common/Names/SemaphoreNames.cpp b/CommonLib/src/Common/Names/SemaphoreNames.cpp new file mode 100644 index 0000000..412bd0d --- /dev/null +++ b/CommonLib/src/Common/Names/SemaphoreNames.cpp @@ -0,0 +1,38 @@ +#include +#include "SemaphoreNames.hpp" +#include "Exception.hpp" + +SemaphoreNames& SemaphoreNames::Instance() +{ + static SemaphoreNames names; + return names; +} + +//------------------------------------------------------------------------ + +SemaphoreNames::~SemaphoreNames() +{ +} + +//------------------------------------------------------------------------ + +SemaphoreNames::SemaphoreNames(): + m_nameMap() +{ + m_nameMap[SAMPLE_SEM] = "PROCESS_SCIENCE"; +} + +//------------------------------------------------------------------------ + +std::string SemaphoreNames::operator[](Names name) +{ + std::map::const_iterator it = m_nameMap.find(name); + if (it == m_nameMap.end()) + { + std::stringstream ss; + ss << "value " << name << " not found"; + throw Exception(__FUNCTION_NAME__,ss.str()); + } + + return it->second; +} diff --git a/CommonLib/src/Common/Names/SemaphoreNames.hpp b/CommonLib/src/Common/Names/SemaphoreNames.hpp new file mode 100644 index 0000000..1f665aa --- /dev/null +++ b/CommonLib/src/Common/Names/SemaphoreNames.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +class SemaphoreNames +{ + +public: + static SemaphoreNames& Instance(); + virtual ~SemaphoreNames(); + + enum Names + { + SAMPLE_SEM, + NUM_SEMS + }; + + std::string operator[](Names name); + +private: + // do not allow + SemaphoreNames(const SemaphoreNames &rhs); + SemaphoreNames &operator=(const SemaphoreNames &rhs); + SemaphoreNames(); + + std::map m_nameMap; +}; diff --git a/CommonLib/src/Common/Names/ThreadNames.cpp b/CommonLib/src/Common/Names/ThreadNames.cpp new file mode 100644 index 0000000..fc9e342 --- /dev/null +++ b/CommonLib/src/Common/Names/ThreadNames.cpp @@ -0,0 +1,42 @@ +#include +#include "ThreadNames.hpp" +#include "Exception.hpp" + +ThreadNames& ThreadNames::Instance() +{ + static ThreadNames names; + + return names; +} + +//------------------------------------------------------------------------ + +ThreadNames::~ThreadNames() +{ +} + +//------------------------------------------------------------------------ + +ThreadNames::ThreadNames(): + m_nameMap() +{ + m_nameMap[VIDEO_READ_THREAD] = "VRS_VIDEO_READ_THREAD"; + m_nameMap[VIDEO_PROCESS_THREAD] = "VRS_VIDEO_PROCESS_THREAD"; + m_nameMap[COMMAND_SOCKET_READ_THREAD] = "VRS_COMMAND_SOCKET_READ_THREAD"; +} + +//------------------------------------------------------------------------ +std::string ThreadNames::operator[](Names name) +{ + std::map::const_iterator it = m_nameMap.find(name); + if (it == m_nameMap.end()) + { + std::stringstream ss; + ss << "value " << name << " not found"; + throw Exception(__FUNCTION_NAME__,ss.str()); + } + + std::string nameString = it->second; + + return nameString; +} diff --git a/CommonLib/src/Common/Names/ThreadNames.hpp b/CommonLib/src/Common/Names/ThreadNames.hpp new file mode 100644 index 0000000..f8ade22 --- /dev/null +++ b/CommonLib/src/Common/Names/ThreadNames.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +class ThreadNames +{ + +public: + static ThreadNames& Instance(); + virtual ~ThreadNames(); + + enum Names + { + VIDEO_READ_THREAD, + VIDEO_PROCESS_THREAD, + COMMAND_SOCKET_READ_THREAD + }; + + std::string operator[](Names name); + +private: + // do not allow + ThreadNames(const ThreadNames &rhs); + ThreadNames &operator=(const ThreadNames &rhs); + ThreadNames(); + + std::map m_nameMap; +}; diff --git a/CommonLib/src/Common/Proc/Proc.cpp b/CommonLib/src/Common/Proc/Proc.cpp new file mode 100644 index 0000000..3298b95 --- /dev/null +++ b/CommonLib/src/Common/Proc/Proc.cpp @@ -0,0 +1,105 @@ +#include "Proc.hpp" +#include "Exception.hpp" +#include "EventNames.hpp" +#include "NTEvent.hpp" + +#include + +//----------------------------------------------------------------------------- + +Proc::Proc(): + m_eventMap() +{ + // Every project must create a singleton LinuxProc class that inherits Proc() + // All single classes must be instantiated in LinuxProc constructor + + // all singleton classes aka [class]::instance() need to be instantiated here as they create static variables + // they all should also be instantiated in one thread, preferable the main thread. Instantiating them in multiple + // threads will make it hard for us to synchronize their destructions, as static variables are destroyed in the order + // they were created per thread + + // all static variables are destroyed in the reverse order they were created per thread + // so any static variables that are dependent upon need to be instantiated first so they will be destroyed last + // LinuxProc and Proc are the last static variables to be instantiated and the first static variable to be destroyed + // as it needs to coordinate the destruction of all variables created on the heap + try { + initEvents(); + + } catch (Exception& e) { + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } +} + +//----------------------------------------------------------------------------- + +Proc::~Proc() +{ + // delete events + std::map::iterator eventIt; + for (eventIt = m_eventMap.begin(); eventIt != m_eventMap.end(); ++eventIt) + { + //std::string name = eventIt->second->GetName(); + delete eventIt->second; + eventIt->second = 0; + } +} + +//----------------------------------------------------------------------------- + +void Proc::initEvents() +{ + try + { + for (int i = 0; i < EventNames::NUM_EVENTS; i++) + { + EventNames::Names eventName = static_cast(i); + addEvent(eventName); + } + } + catch (Exception &e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } +} + +//---------------------------------------------------------------------------- + +void Proc::addEvent(const EventNames::Names& event, bool manualReset, bool initialState) +{ + try + { + EventNames& eventNames = EventNames::Instance(); + std::string eventName = eventNames[event]; + m_eventMap[eventName] = new NTEvent(eventName, manualReset, initialState); + } + catch (Exception &e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } +} + +//---------------------------------------------------------------------------- + +NTEvent& Proc::getEvent(EventNames::Names name) +{ + try + { + std::map::iterator i = m_eventMap.find(EventNames::Instance()[name]); + + if (i == m_eventMap.end()) + { + std::ostringstream oss; + oss << "couldn't find event: " << EventNames::Instance()[name]; + throw Exception(__FUNCTION_NAME__, oss.str()); + } + return *(i->second); + } + catch (Exception& e) + { + e.buildStackTrace(__FUNCTION_NAME__); + throw e; + } +} diff --git a/CommonLib/src/Common/Proc/Proc.hpp b/CommonLib/src/Common/Proc/Proc.hpp new file mode 100644 index 0000000..4a103fe --- /dev/null +++ b/CommonLib/src/Common/Proc/Proc.hpp @@ -0,0 +1,74 @@ +#ifndef PROC_H +#define PROC_H + +#include "EventNames.hpp" + +class IniFile; +class NTEvent; + +class Proc +{ + +public: + //>--------------------------------------------------------------------------- + // Function: ~Proc + // + // Purpose: Destroyer + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + virtual ~Proc(); + + //>--------------------------------------------------------------------- + // Function: GetEvent + // + // Purpose: Get a event) + //---------------------------------------------------------------------- + // Arguments: name - the name of the condition + //---------------------------------------------------------------------- + // Return Value: a referance to the condition + //<--------------------------------------------------------------------- + NTEvent& getEvent(EventNames::Names name); + +protected: + //>--------------------------------------------------------------------------- + // Function: Proc + // + // Purpose: Ctor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + Proc(); + + //>--------------------------------------------------------------------- + // Function: AddEvent() + // + // Purpose: Add an event to this process + //---------------------------------------------------------------------- + // Arguments: + // event - the name of the event + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void addEvent(const EventNames::Names& event, bool manualReset = true, bool initialState = false); + + //>--------------------------------------------------------------------- + // Function: InitEvents() + // + // Purpose: + //---------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------- + // Return Value: none + //<--------------------------------------------------------------------- + void initEvents(); + +private: + std::map m_eventMap; +}; + +#endif diff --git a/CommonLib/src/WinProc.cpp b/CommonLib/src/WinProc.cpp new file mode 100644 index 0000000..423478a --- /dev/null +++ b/CommonLib/src/WinProc.cpp @@ -0,0 +1,67 @@ +#include "WinProc.hpp" +#include "Exception.hpp" +#include "IniFile.hpp" +#include "Timestamp.hpp" +#include "ErrorLog.hpp" +#include "FileSystemUtil.hpp" + +#include + +//----------------------------------------------------------------------------- + +WinProc& WinProc::Instance() +{ + static WinProc proc; + return proc; +} + +//----------------------------------------------------------------------------- + +WinProc::WinProc() : + Proc() +{ + // all singleton classes aka [class]::instance() need to be instantiated here as they create static variables + // they all should also be instantiated in one thread, preferable the main thread. Instantiating them in multiple + // threads will make it hard for us to synchronize their destructions, as static variables are destroyed in the order + // they were created per thread + + // all static variables are destroyed in the reverse order they were created per thread + // so any static variables that are dependent upon need to be instantiated first so they will be destroyed last + // WinProc is the last static variables to be instantiated and the first static variable to be destroyed + // as it needs to coordinate the destruction of all variables created on the heap + try { + std::string exePath = Util::FileSystem::ExtractDirectory(Util::FileSystem::GetExePathAndFilename().c_str()); + + std::string configFilePath = Util::FileSystem::BuildPath(exePath, "config.ini"); + + m_iniFile = new IniFile(configFilePath); + + std::string logPath = Util::FileSystem::BuildPath(exePath, "Output"); + + Util::FileSystem::CreateFolder(logPath); + + Util::FileSystem::CleanUpLogs(logPath, ".+\\.txt"); + + std::stringstream ss; + std::string date; + std::string time; + + Timestamp::GetCurrentDateTimeString(date, time, Timestamp::DateFormat::YYYYMMDD, Timestamp::TimeFormat::HHMMSS, "_"); + + ss << date << "_" << time << "_log.txt"; + + ErrorLog::Instance(Util::FileSystem::BuildPath(logPath, ss.str())); + + } + catch (Exception& e) { + e.buildStackTrace(__FUNCTION_NAME__); + throw; + } +} + +//----------------------------------------------------------------------------- + +WinProc::~WinProc() +{ + +} diff --git a/CommonLib/src/WinProc.hpp b/CommonLib/src/WinProc.hpp new file mode 100644 index 0000000..7cbf3bd --- /dev/null +++ b/CommonLib/src/WinProc.hpp @@ -0,0 +1,60 @@ +#ifndef LINUXPROC_H +#define LINUXPROC_H + +#include "Proc.hpp" + +class IniFile; + +class WinProc : public Proc +{ + +public: + //>--------------------------------------------------------------------------- + // Function: instance + // + // Purpose: singleton + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + static WinProc& Instance(); + + //>--------------------------------------------------------------------------- + // Function: getConfig + // + // Purpose: + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + IniFile& getConfig(){return *m_iniFile;}; + + //>--------------------------------------------------------------------------- + // Function: ~Proc + // + // Purpose: Destroyer + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + ~WinProc(); + +private: + //>--------------------------------------------------------------------------- + // Function: Proc + // + // Purpose: Ctor + //---------------------------------------------------------------------------- + // Arguments: + //---------------------------------------------------------------------------- + // Return Value: + //---------------------------------------------------------------------------- + WinProc(); + + IniFile* m_iniFile; +}; + +#endif diff --git a/CommonLib/src/main.cpp b/CommonLib/src/main.cpp new file mode 100644 index 0000000..deeba16 --- /dev/null +++ b/CommonLib/src/main.cpp @@ -0,0 +1,16 @@ +#include + +#include "WinProc.hpp" + +int main() +{ + WinProc::Instance(); + + std::cout << "Hello World!\n"; + + std::string s; + std::cin >> s; + + return 0; +} +