From 6a7224d9f3b06ebdd00bc213723901a64e52b038 Mon Sep 17 00:00:00 2001 From: mikhail4021 Date: Wed, 12 Feb 2014 02:16:24 +0400 Subject: [PATCH] service --- Win32/.gitignore | 2 + Win32/Win32Service.cpp | 502 +++++++++++++++++++++++++++++++++++++ Win32/Win32Service.h | 66 +++++ Win32/i2pd.sln | 6 + Win32/i2pd.vcxproj | 65 +++++ Win32/i2pd.vcxproj.filters | 6 + i2p.cpp | 58 ++++- portable_endian.h | 115 +++++++++ 8 files changed, 819 insertions(+), 1 deletion(-) create mode 100644 Win32/Win32Service.cpp create mode 100644 Win32/Win32Service.h create mode 100644 portable_endian.h diff --git a/Win32/.gitignore b/Win32/.gitignore index d62f96f6..4952e30b 100644 --- a/Win32/.gitignore +++ b/Win32/.gitignore @@ -6,3 +6,5 @@ !*.vcxproj !*.vcxproj.filters !.gitignore +!*.cpp +!*.h diff --git a/Win32/Win32Service.cpp b/Win32/Win32Service.cpp new file mode 100644 index 00000000..4fd53361 --- /dev/null +++ b/Win32/Win32Service.cpp @@ -0,0 +1,502 @@ +#include "Win32Service.h" +#include +#include +#include + +#include "Transports.h" +#include "NTCPSession.h" +#include "Tunnel.h" +#include "NetDb.h" +#include "util.h" + +I2PService *I2PService::s_service = NULL; + + +BOOL I2PService::Run(I2PService &service) +{ + s_service = &service; + + SERVICE_TABLE_ENTRY serviceTable[] = + { + { service.m_name, ServiceMain }, + { NULL, NULL } + }; + + return StartServiceCtrlDispatcher(serviceTable); +} + + +void WINAPI I2PService::ServiceMain(DWORD dwArgc, PSTR *pszArgv) +{ + assert(s_service != NULL); + + s_service->m_statusHandle = RegisterServiceCtrlHandler( + s_service->m_name, ServiceCtrlHandler); + if (s_service->m_statusHandle == NULL) + { + throw GetLastError(); + } + + s_service->Start(dwArgc, pszArgv); +} + + +void WINAPI I2PService::ServiceCtrlHandler(DWORD dwCtrl) +{ + switch (dwCtrl) + { + case SERVICE_CONTROL_STOP: s_service->Stop(); break; + case SERVICE_CONTROL_PAUSE: s_service->Pause(); break; + case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break; + case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break; + case SERVICE_CONTROL_INTERROGATE: break; + default: break; + } +} + + +I2PService::I2PService(PSTR pszServiceName, + BOOL fCanStop, + BOOL fCanShutdown, + BOOL fCanPauseContinue) : _httpServer(nullptr) +{ + m_name = (pszServiceName == NULL) ? "" : pszServiceName; + + m_statusHandle = NULL; + + m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + + m_status.dwCurrentState = SERVICE_START_PENDING; + + DWORD dwControlsAccepted = 0; + if (fCanStop) + dwControlsAccepted |= SERVICE_ACCEPT_STOP; + if (fCanShutdown) + dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN; + if (fCanPauseContinue) + dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE; + m_status.dwControlsAccepted = dwControlsAccepted; + + m_status.dwWin32ExitCode = NO_ERROR; + m_status.dwServiceSpecificExitCode = 0; + m_status.dwCheckPoint = 0; + m_status.dwWaitHint = 0; + + m_fStopping = FALSE; + + // Create a manual-reset event that is not signaled at first to indicate + // the stopped signal of the service. + m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (m_hStoppedEvent == NULL) + { + throw GetLastError(); + } +} + + +I2PService::~I2PService(void) +{ + if (m_hStoppedEvent) + { + CloseHandle(m_hStoppedEvent); + m_hStoppedEvent = NULL; + } +} + + +void I2PService::Start(DWORD dwArgc, PSTR *pszArgv) +{ + try + { + SetServiceStatus(SERVICE_START_PENDING); + + OnStart(dwArgc, pszArgv); + + SetServiceStatus(SERVICE_RUNNING); + } + catch (DWORD dwError) + { + WriteErrorLogEntry("Service Start", dwError); + + SetServiceStatus(SERVICE_STOPPED, dwError); + } + catch (...) + { + WriteEventLogEntry("Service failed to start.", EVENTLOG_ERROR_TYPE); + + SetServiceStatus(SERVICE_STOPPED); + } +} + + +void I2PService::OnStart(DWORD dwArgc, PSTR *pszArgv) +{ + WriteEventLogEntry("CppWindowsService in OnStart", + EVENTLOG_INFORMATION_TYPE); + + i2p::util::config::OptionParser(dwArgc, pszArgv); + i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); + i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"), + i2p::util::config::GetArg("-port", 17070)); + + _httpServer = new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpport", 7070)); + _httpServer->Start(); + WriteEventLogEntry("HTTPServer started", + EVENTLOG_INFORMATION_TYPE); + i2p::data::netdb.Start(); + WriteEventLogEntry("NetDB started", + EVENTLOG_INFORMATION_TYPE); + i2p::transports.Start(); + WriteEventLogEntry("Transports started", + EVENTLOG_INFORMATION_TYPE); + i2p::tunnel::tunnels.Start(); + WriteEventLogEntry("Tunnels started", + EVENTLOG_INFORMATION_TYPE); + _worker = new std::thread(std::bind(&I2PService::WorkerThread, this)); +} + + +void I2PService::WorkerThread() +{ + while (!m_fStopping) + { + ::Sleep(1000); // Simulate some lengthy operations. + } + + // Signal the stopped event. + SetEvent(m_hStoppedEvent); +} + + +void I2PService::Stop() +{ + DWORD dwOriginalState = m_status.dwCurrentState; + try + { + SetServiceStatus(SERVICE_STOP_PENDING); + + OnStop(); + + SetServiceStatus(SERVICE_STOPPED); + } + catch (DWORD dwError) + { + WriteErrorLogEntry("Service Stop", dwError); + + SetServiceStatus(dwOriginalState); + } + catch (...) + { + WriteEventLogEntry("Service failed to stop.", EVENTLOG_ERROR_TYPE); + + SetServiceStatus(dwOriginalState); + } +} + + +void I2PService::OnStop() +{ + // Log a service stop message to the Application log. + WriteEventLogEntry("CppWindowsService in OnStop", + EVENTLOG_INFORMATION_TYPE); + + i2p::tunnel::tunnels.Stop(); + WriteEventLogEntry("Tunnels stoped", + EVENTLOG_INFORMATION_TYPE); + i2p::transports.Stop(); + WriteEventLogEntry("Transports stoped", + EVENTLOG_INFORMATION_TYPE); + i2p::data::netdb.Stop(); + WriteEventLogEntry("NetDB stoped", + EVENTLOG_INFORMATION_TYPE); + _httpServer->Stop(); + WriteEventLogEntry("HTTPServer stoped", + EVENTLOG_INFORMATION_TYPE); + delete _httpServer; + + m_fStopping = TRUE; + if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0) + { + throw GetLastError(); + } + _worker->join(); + delete _worker; +} + + +void I2PService::Pause() +{ + try + { + SetServiceStatus(SERVICE_PAUSE_PENDING); + + OnPause(); + + SetServiceStatus(SERVICE_PAUSED); + } + catch (DWORD dwError) + { + WriteErrorLogEntry("Service Pause", dwError); + + SetServiceStatus(SERVICE_RUNNING); + } + catch (...) + { + WriteEventLogEntry("Service failed to pause.", EVENTLOG_ERROR_TYPE); + + SetServiceStatus(SERVICE_RUNNING); + } +} + + +void I2PService::OnPause() +{ +} + + +void I2PService::Continue() +{ + try + { + SetServiceStatus(SERVICE_CONTINUE_PENDING); + + OnContinue(); + + SetServiceStatus(SERVICE_RUNNING); + } + catch (DWORD dwError) + { + WriteErrorLogEntry("Service Continue", dwError); + + SetServiceStatus(SERVICE_PAUSED); + } + catch (...) + { + WriteEventLogEntry("Service failed to resume.", EVENTLOG_ERROR_TYPE); + + SetServiceStatus(SERVICE_PAUSED); + } +} + + +void I2PService::OnContinue() +{ +} + + +void I2PService::Shutdown() +{ + try + { + OnShutdown(); + + SetServiceStatus(SERVICE_STOPPED); + } + catch (DWORD dwError) + { + WriteErrorLogEntry("Service Shutdown", dwError); + } + catch (...) + { + WriteEventLogEntry("Service failed to shut down.", EVENTLOG_ERROR_TYPE); + } +} + + +void I2PService::OnShutdown() +{ +} + + +void I2PService::SetServiceStatus(DWORD dwCurrentState, + DWORD dwWin32ExitCode, + DWORD dwWaitHint) +{ + static DWORD dwCheckPoint = 1; + + + m_status.dwCurrentState = dwCurrentState; + m_status.dwWin32ExitCode = dwWin32ExitCode; + m_status.dwWaitHint = dwWaitHint; + + m_status.dwCheckPoint = + ((dwCurrentState == SERVICE_RUNNING) || + (dwCurrentState == SERVICE_STOPPED)) ? + 0 : dwCheckPoint++; + + ::SetServiceStatus(m_statusHandle, &m_status); +} + + +void I2PService::WriteEventLogEntry(PSTR pszMessage, WORD wType) +{ + HANDLE hEventSource = NULL; + LPCSTR lpszStrings[2] = { NULL, NULL }; + + hEventSource = RegisterEventSource(NULL, m_name); + if (hEventSource) + { + lpszStrings[0] = m_name; + lpszStrings[1] = pszMessage; + + ReportEvent(hEventSource, // Event log handle + wType, // Event type + 0, // Event category + 0, // Event identifier + NULL, // No security identifier + 2, // Size of lpszStrings array + 0, // No binary data + lpszStrings, // Array of strings + NULL // No binary data + ); + + DeregisterEventSource(hEventSource); + } +} + + +void I2PService::WriteErrorLogEntry(PSTR pszFunction, DWORD dwError) +{ + char szMessage[260]; + StringCchPrintf(szMessage, ARRAYSIZE(szMessage), + "%s failed w/err 0x%08lx", pszFunction, dwError); + WriteEventLogEntry(szMessage, EVENTLOG_ERROR_TYPE); +} + +//***************************************************************************** + +void FreeHandles(SC_HANDLE schSCManager, SC_HANDLE schService) +{ + if (schSCManager) + { + CloseServiceHandle(schSCManager); + schSCManager = NULL; + } + if (schService) + { + CloseServiceHandle(schService); + schService = NULL; + } +} + +void InstallService(PSTR pszServiceName, + PSTR pszDisplayName, + DWORD dwStartType, + PSTR pszDependencies, + PSTR pszAccount, + PSTR pszPassword) +{ + char szPath[MAX_PATH]; + SC_HANDLE schSCManager = NULL; + SC_HANDLE schService = NULL; + + if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0) + { + printf("GetModuleFileName failed w/err 0x%08lx\n", GetLastError()); + FreeHandles(schSCManager, schService); + return; + } + + // Open the local default service control manager database + schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | + SC_MANAGER_CREATE_SERVICE); + if (schSCManager == NULL) + { + printf("OpenSCManager failed w/err 0x%08lx\n", GetLastError()); + FreeHandles(schSCManager, schService); + return; + } + + // Install the service into SCM by calling CreateService + schService = CreateService( + schSCManager, // SCManager database + pszServiceName, // Name of service + pszDisplayName, // Name to display + SERVICE_QUERY_STATUS, // Desired access + SERVICE_WIN32_OWN_PROCESS, // Service type + dwStartType, // Service start type + SERVICE_ERROR_NORMAL, // Error control type + szPath, // Service's binary + NULL, // No load ordering group + NULL, // No tag identifier + pszDependencies, // Dependencies + pszAccount, // Service running account + pszPassword // Password of the account + ); + if (schService == NULL) + { + printf("CreateService failed w/err 0x%08lx\n", GetLastError()); + FreeHandles(schSCManager, schService); + return; + } + + printf("%s is installed.\n", pszServiceName); + + // Centralized cleanup for all allocated resources. + FreeHandles(schSCManager, schService); +} + +void UninstallService(PSTR pszServiceName) +{ + SC_HANDLE schSCManager = NULL; + SC_HANDLE schService = NULL; + SERVICE_STATUS ssSvcStatus = {}; + + // Open the local default service control manager database + schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); + if (schSCManager == NULL) + { + printf("OpenSCManager failed w/err 0x%08lx\n", GetLastError()); + FreeHandles(schSCManager, schService); + return; + } + + // Open the service with delete, stop, and query status permissions + schService = OpenService(schSCManager, pszServiceName, SERVICE_STOP | + SERVICE_QUERY_STATUS | DELETE); + if (schService == NULL) + { + printf("OpenService failed w/err 0x%08lx\n", GetLastError()); + FreeHandles(schSCManager, schService); + return; + } + + // Try to stop the service + if (ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus)) + { + printf("Stopping %s.", pszServiceName); + Sleep(1000); + + while (QueryServiceStatus(schService, &ssSvcStatus)) + { + if (ssSvcStatus.dwCurrentState == SERVICE_STOP_PENDING) + { + printf("."); + Sleep(1000); + } + else break; + } + + if (ssSvcStatus.dwCurrentState == SERVICE_STOPPED) + { + printf("\n%s is stopped.\n", pszServiceName); + } + else + { + printf("\n%s failed to stop.\n", pszServiceName); + } + } + + // Now remove the service by calling DeleteService. + if (!DeleteService(schService)) + { + printf("DeleteService failed w/err 0x%08lx\n", GetLastError()); + FreeHandles(schSCManager, schService); + return; + } + + printf("%s is removed.\n", pszServiceName); + + // Centralized cleanup for all allocated resources. + FreeHandles(schSCManager, schService); +} \ No newline at end of file diff --git a/Win32/Win32Service.h b/Win32/Win32Service.h new file mode 100644 index 00000000..1fb8fa50 --- /dev/null +++ b/Win32/Win32Service.h @@ -0,0 +1,66 @@ +#ifndef WIN_32_SERVICE_H__ +#define WIN_32_SERVICE_H__ + +#include "HTTPServer.h" +#include +#define WIN32_LEAN_AND_MEAN +#include + +class I2PService +{ +public: + + I2PService(PSTR pszServiceName, + BOOL fCanStop = TRUE, + BOOL fCanShutdown = TRUE, + BOOL fCanPauseContinue = FALSE); + + virtual ~I2PService(void); + + static BOOL Run(I2PService &service); + void Stop(); + +protected: + + virtual void OnStart(DWORD dwArgc, PSTR *pszArgv); + virtual void OnStop(); + virtual void OnPause(); + virtual void OnContinue(); + virtual void OnShutdown(); + void SetServiceStatus(DWORD dwCurrentState, + DWORD dwWin32ExitCode = NO_ERROR, + DWORD dwWaitHint = 0); + void WriteEventLogEntry(PSTR pszMessage, WORD wType); + void WriteErrorLogEntry(PSTR pszFunction, + DWORD dwError = GetLastError()); + +private: + + static void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv); + static void WINAPI ServiceCtrlHandler(DWORD dwCtrl); + void WorkerThread(); + void Start(DWORD dwArgc, PSTR *pszArgv); + void Pause(); + void Continue(); + void Shutdown(); + static I2PService* s_service; + PSTR m_name; + SERVICE_STATUS m_status; + SERVICE_STATUS_HANDLE m_statusHandle; + + BOOL m_fStopping; + HANDLE m_hStoppedEvent; + i2p::util::HTTPServer* _httpServer; + std::thread* _worker; +}; + +void InstallService(PSTR pszServiceName, + PSTR pszDisplayName, + DWORD dwStartType, + PSTR pszDependencies, + PSTR pszAccount, + PSTR pszPassword); + +void UninstallService(PSTR pszServiceName); + +#endif // WIN_32_SERVICE_H__ \ No newline at end of file diff --git a/Win32/i2pd.sln b/Win32/i2pd.sln index af0c8110..1f9a8d7c 100644 --- a/Win32/i2pd.sln +++ b/Win32/i2pd.sln @@ -8,13 +8,19 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|Win32.ActiveCfg = Debug|Win32 {930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|Win32.Build.0 = Debug|Win32 + {930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|x64.ActiveCfg = Debug|x64 + {930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|x64.Build.0 = Debug|x64 {930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|Win32.ActiveCfg = Release|Win32 {930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|Win32.Build.0 = Release|Win32 + {930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|x64.ActiveCfg = Release|x64 + {930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Win32/i2pd.vcxproj b/Win32/i2pd.vcxproj index c6f95ed7..e5903630 100644 --- a/Win32/i2pd.vcxproj +++ b/Win32/i2pd.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + @@ -33,6 +41,7 @@ + @@ -63,6 +72,7 @@ + {930568EC-31C9-406A-AD1C-9636DF5D8FAA} @@ -75,6 +85,12 @@ v120 MultiByte + + Application + true + v120 + MultiByte + Application false @@ -82,25 +98,47 @@ true MultiByte + + Application + false + v120 + true + MultiByte + + + + + + + ./..;$(BOOST);$(CRYPTOPP);$(IncludePath) $(BOOST)\stage\lib;$(CRYPTOPP)\cryptopp\Win32\Output\$(Configuration)\;$(LibraryPath) ./..;$(VC_SourcePath); + + ./..;$(BOOST);$(CRYPTOPP);$(IncludePath) + $(BOOST)\stage\lib;$(CRYPTOPP)\cryptopp\Win32\Output\$(Configuration)\;$(LibraryPath) + ./..;$(VC_SourcePath); + .\boost;.\cryptopp;$(IncludePath) .\stage-x86\lib;$(LibraryPath) + + .\boost;.\cryptopp;$(IncludePath) + .\stage-x86\lib;$(LibraryPath) + Level3 @@ -114,6 +152,19 @@ cryptlib.lib;%(AdditionalDependencies) + + + Level3 + Disabled + true + MultiThreadedDebugDLL + _MBCS;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions) + + + true + cryptlib.lib;%(AdditionalDependencies) + + Level3 @@ -128,6 +179,20 @@ true + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + diff --git a/Win32/i2pd.vcxproj.filters b/Win32/i2pd.vcxproj.filters index 0eb7dc3d..dbb228cd 100644 --- a/Win32/i2pd.vcxproj.filters +++ b/Win32/i2pd.vcxproj.filters @@ -81,6 +81,9 @@ Source Files + + Source Files + @@ -167,5 +170,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/i2p.cpp b/i2p.cpp index 97914b5e..d50f3d44 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -11,6 +11,8 @@ #include #include #include +#else +#include "./Win32/Win32Service.h" #endif #include "Log.h" @@ -25,6 +27,26 @@ #include "util.h" +#ifdef _WIN32 +// Internal name of the service +#define SERVICE_NAME "i2pService" + +// Displayed name of the service +#define SERVICE_DISPLAY_NAME "i2p router service" + +// Service start options. +#define SERVICE_START_TYPE SERVICE_DEMAND_START + +// List of service dependencies - "dep1\0dep2\0\0" +#define SERVICE_DEPENDENCIES "" + +// The name of the account under which the service should run +#define SERVICE_ACCOUNT "NT AUTHORITY\\LocalService" + +// The password to the service account name +#define SERVICE_PASSWORD NULL +#endif + // Global int running = 1; int isDaemon; @@ -60,7 +82,7 @@ void handle_signal(int sig) int main( int argc, char* argv[] ) { i2p::util::config::OptionParser(argc,argv); - isDaemon = i2p::util::config::GetArg("-daemon", 0); + isDaemon = i2p::util::config::GetArg("-daemon", 1); #ifdef _WIN32 setlocale(LC_CTYPE, ""); SetConsoleCP(1251); @@ -139,6 +161,40 @@ int main( int argc, char* argv[] ) sigaction(SIGABRT,&sa,0); sigaction(SIGTERM,&sa,0); sigaction(SIGINT,&sa,0); +#else + std::string serviceControl = i2p::util::config::GetArg("-service", "none"); + if (serviceControl == "install") + { + InstallService( + SERVICE_NAME, // Name of service + SERVICE_DISPLAY_NAME, // Name to display + SERVICE_START_TYPE, // Service start type + SERVICE_DEPENDENCIES, // Dependencies + SERVICE_ACCOUNT, // Service running account + SERVICE_PASSWORD // Password of the account + ); + return 0; + } + else if (serviceControl == "remove") + { + UninstallService(SERVICE_NAME); + return 0; + } + else if (serviceControl != "none") + { + LogPrint(" --service=install to install the service."); + LogPrint(" --service=remove to remove the service."); + return -1; + } + else if (isDaemon) + { + I2PService service(SERVICE_NAME); + if (!I2PService::Run(service)) + { + LogPrint("Service failed to run w/err 0x%08lx\n", GetLastError()); + } + return 0; + } #endif //TODO: This is an ugly workaround. fix it. diff --git a/portable_endian.h b/portable_endian.h new file mode 100644 index 00000000..3355d2b9 --- /dev/null +++ b/portable_endian.h @@ -0,0 +1,115 @@ +#ifndef PORTABLE_ENDIAN_H__ +#define PORTABLE_ENDIAN_H__ + +#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) + +# define __WINDOWS__ + +#endif + +#if defined(__linux__) || defined(__CYGWIN__) + +# include + +#elif defined(__APPLE__) + +# include + +# define htobe16 OSSwapHostToBigInt16 +# define htole16 OSSwapHostToLittleInt16 +# define be16toh OSSwapBigToHostInt16 +# define le16toh OSSwapLittleToHostInt16 + +# define htobe32 OSSwapHostToBigInt32 +# define htole32 OSSwapHostToLittleInt32 +# define be32toh OSSwapBigToHostInt32 +# define le32toh OSSwapLittleToHostInt32 + +# define htobe64 OSSwapHostToBigInt64 +# define htole64 OSSwapHostToLittleInt64 +# define be64toh OSSwapBigToHostInt64 +# define le64toh OSSwapLittleToHostInt64 + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#elif defined(__OpenBSD__) + +# include + +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) + +# include + +# define be16toh betoh16 +# define le16toh letoh16 + +# define be32toh betoh32 +# define le32toh letoh32 + +# define be64toh betoh64 +# define le64toh letoh64 + +#elif defined(__WINDOWS__) + +#define INCL_EXTRA_HTON_FUNCTIONS +#define NOMINMAX +# include +#undef NOMINMAX +//# include + +# if BYTE_ORDER == LITTLE_ENDIAN + +# define htobe16 htons +# define htole16(x) (x) +# define be16toh ntohs +# define le16toh(x) (x) + +# define htobe32 htonl +# define htole32(x) (x) +# define be32toh ntohl +# define le32toh(x) (x) + +# define htobe64 htonll +# define htole64(x) (x) +# define be64toh ntohll +# define le64toh(x) (x) + +# elif BYTE_ORDER == BIG_ENDIAN + + /* that would be xbox 360 */ +# define htobe16(x) (x) +# define htole16(x) __builtin_bswap16(x) +# define be16toh(x) (x) +# define le16toh(x) __builtin_bswap16(x) + +# define htobe32(x) (x) +# define htole32(x) __builtin_bswap32(x) +# define be32toh(x) (x) +# define le32toh(x) __builtin_bswap32(x) + +# define htobe64(x) (x) +# define htole64(x) __builtin_bswap64(x) +# define be64toh(x) (x) +# define le64toh(x) __builtin_bswap64(x) + +# else + +# error byte order not supported + +# endif + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#else + +# error platform not supported + +#endif + +#endif \ No newline at end of file