diff options
Diffstat (limited to 'source/OSSupport')
26 files changed, 0 insertions, 3573 deletions
diff --git a/source/OSSupport/BlockingTCPLink.cpp b/source/OSSupport/BlockingTCPLink.cpp deleted file mode 100644 index 55454a4b5..000000000 --- a/source/OSSupport/BlockingTCPLink.cpp +++ /dev/null @@ -1,149 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "BlockingTCPLink.h" - - - - - -#ifdef _WIN32 - #define MSG_NOSIGNAL (0) -#endif -#ifdef __MACH__ - #define MSG_NOSIGNAL (0) -#endif - - - - - -cBlockingTCPLink::cBlockingTCPLink(void) -{ -} - - - - - -cBlockingTCPLink::~cBlockingTCPLink() -{ - CloseSocket(); -} - - - - - -void cBlockingTCPLink::CloseSocket() -{ - if (!m_Socket.IsValid()) - { - m_Socket.CloseSocket(); - } -} - - - - - -bool cBlockingTCPLink::Connect(const char * iAddress, unsigned int iPort) -{ - ASSERT(!m_Socket.IsValid()); - if (m_Socket.IsValid()) - { - LOGWARN("WARNING: cTCPLink Connect() called while still connected."); - m_Socket.CloseSocket(); - } - - struct hostent *hp; - unsigned int addr; - struct sockaddr_in server; - - m_Socket = socket(AF_INET, SOCK_STREAM, 0); - if (!m_Socket.IsValid()) - { - LOGERROR("cTCPLink: Cannot create a socket"); - return false; - } - - addr = inet_addr(iAddress); - hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); - if (hp == NULL) - { - //LOGWARN("cTCPLink: gethostbyaddr returned NULL"); - hp = gethostbyname(iAddress); - if (hp == NULL) - { - LOGWARN("cTCPLink: Could not resolve %s", iAddress); - CloseSocket(); - return false; - } - } - - server.sin_addr.s_addr = *((unsigned long *)hp->h_addr); - server.sin_family = AF_INET; - server.sin_port = htons( (unsigned short)iPort); - if (connect(m_Socket, (struct sockaddr *)&server, sizeof(server))) - { - LOGWARN("cTCPLink: Connection to \"%s:%d\" failed (%s)", iAddress, iPort, cSocket::GetErrorString( cSocket::GetLastError() ).c_str() ); - CloseSocket(); - return false; - } - - return true; -} - - - - - -int cBlockingTCPLink::Send(char * a_Data, unsigned int a_Size, int a_Flags /* = 0 */ ) -{ - ASSERT(m_Socket.IsValid()); - if (!m_Socket.IsValid()) - { - LOGERROR("cBlockingTCPLink: Trying to send data without a valid connection!"); - return -1; - } - return m_Socket.Send(a_Data, a_Size); -} - - - - - -int cBlockingTCPLink::SendMessage( const char* a_Message, int a_Flags /* = 0 */ ) -{ - ASSERT(m_Socket.IsValid()); - if (!m_Socket.IsValid()) - { - LOGWARN("cBlockingTCPLink: Trying to send message without a valid connection!"); - return -1; - } - return m_Socket.Send(a_Message, strlen(a_Message)); -} - - - - - -void cBlockingTCPLink::ReceiveData(AString & oData) -{ - ASSERT(m_Socket.IsValid()); - if (!m_Socket.IsValid()) - { - return; - } - - int Received = 0; - char Buffer[256]; - while ((Received = recv(m_Socket, Buffer, sizeof(Buffer), 0)) > 0) - { - oData.append(Buffer, Received); - } -} - - - - diff --git a/source/OSSupport/BlockingTCPLink.h b/source/OSSupport/BlockingTCPLink.h deleted file mode 100644 index cb5f9e3f4..000000000 --- a/source/OSSupport/BlockingTCPLink.h +++ /dev/null @@ -1,28 +0,0 @@ - -#pragma once - -#include "Socket.h" - - - - - -class cBlockingTCPLink // tolua_export -{ // tolua_export -public: // tolua_export - cBlockingTCPLink(void); // tolua_export - ~cBlockingTCPLink(); // tolua_export - - bool Connect( const char* a_Address, unsigned int a_Port ); // tolua_export - int Send( char* a_Data, unsigned int a_Size, int a_Flags = 0 ); // tolua_export - int SendMessage( const char* a_Message, int a_Flags = 0 ); // tolua_export - void CloseSocket(); // tolua_export - void ReceiveData(AString & oData); // tolua_export -protected: - - cSocket m_Socket; -}; // tolua_export - - - - diff --git a/source/OSSupport/CriticalSection.cpp b/source/OSSupport/CriticalSection.cpp deleted file mode 100644 index bda97e3a1..000000000 --- a/source/OSSupport/CriticalSection.cpp +++ /dev/null @@ -1,188 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules -#include "IsThread.h" - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cCriticalSection: - -cCriticalSection::cCriticalSection() -{ - #ifdef _WIN32 - InitializeCriticalSection(&m_CriticalSection); - #else - pthread_mutexattr_init(&m_Attributes); - pthread_mutexattr_settype(&m_Attributes, PTHREAD_MUTEX_RECURSIVE); - - if (pthread_mutex_init(&m_CriticalSection, &m_Attributes) != 0) - { - LOGERROR("Could not initialize Critical Section!"); - } - #endif - - #ifdef _DEBUG - m_IsLocked = 0; - #endif // _DEBUG -} - - - - - -cCriticalSection::~cCriticalSection() -{ - #ifdef _WIN32 - DeleteCriticalSection(&m_CriticalSection); - #else - if (pthread_mutex_destroy(&m_CriticalSection) != 0) - { - LOGWARNING("Could not destroy Critical Section!"); - } - pthread_mutexattr_destroy(&m_Attributes); - #endif -} - - - - - -void cCriticalSection::Lock() -{ - #ifdef _WIN32 - EnterCriticalSection(&m_CriticalSection); - #else - pthread_mutex_lock(&m_CriticalSection); - #endif - - #ifdef _DEBUG - m_IsLocked += 1; - m_OwningThreadID = cIsThread::GetCurrentID(); - #endif // _DEBUG -} - - - - - -void cCriticalSection::Unlock() -{ - #ifdef _DEBUG - ASSERT(m_IsLocked > 0); - m_IsLocked -= 1; - #endif // _DEBUG - - #ifdef _WIN32 - LeaveCriticalSection(&m_CriticalSection); - #else - pthread_mutex_unlock(&m_CriticalSection); - #endif -} - - - - - -#ifdef _DEBUG -bool cCriticalSection::IsLocked(void) -{ - return (m_IsLocked > 0); -} - - - - - -bool cCriticalSection::IsLockedByCurrentThread(void) -{ - return ((m_IsLocked > 0) && (m_OwningThreadID == cIsThread::GetCurrentID())); -} -#endif // _DEBUG - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cCSLock - -cCSLock::cCSLock(cCriticalSection * a_CS) - : m_CS(a_CS) - , m_IsLocked(false) -{ - Lock(); -} - - - - - -cCSLock::cCSLock(cCriticalSection & a_CS) - : m_CS(&a_CS) - , m_IsLocked(false) -{ - Lock(); -} - - - - - -cCSLock::~cCSLock() -{ - if (!m_IsLocked) - { - return; - } - Unlock(); -} - - - - - -void cCSLock::Lock(void) -{ - ASSERT(!m_IsLocked); - m_IsLocked = true; - m_CS->Lock(); -} - - - - - -void cCSLock::Unlock(void) -{ - ASSERT(m_IsLocked); - m_IsLocked = false; - m_CS->Unlock(); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cCSUnlock: - -cCSUnlock::cCSUnlock(cCSLock & a_Lock) : - m_Lock(a_Lock) -{ - m_Lock.Unlock(); -} - - - - - -cCSUnlock::~cCSUnlock() -{ - m_Lock.Lock(); -} - - - - diff --git a/source/OSSupport/CriticalSection.h b/source/OSSupport/CriticalSection.h deleted file mode 100644 index 1bfe81439..000000000 --- a/source/OSSupport/CriticalSection.h +++ /dev/null @@ -1,80 +0,0 @@ - -#pragma once - - - - - -class cCriticalSection -{ -public: - cCriticalSection(void); - ~cCriticalSection(); - - void Lock(void); - void Unlock(void); - - #ifdef _DEBUG - bool IsLocked(void); - bool IsLockedByCurrentThread(void); - #endif // _DEBUG - -private: - #ifdef _DEBUG - int m_IsLocked; // Number of times this CS is locked - unsigned long m_OwningThreadID; - #endif // _DEBUG - - #ifdef _WIN32 - CRITICAL_SECTION m_CriticalSection; - #else // _WIN32 - pthread_mutex_t m_CriticalSection; - pthread_mutexattr_t m_Attributes; - #endif // else _WIN32 -} ALIGN_8; - - - - -/// RAII for cCriticalSection - locks the CS on creation, unlocks on destruction -class cCSLock -{ - cCriticalSection * m_CS; - - // Unlike a cCriticalSection, this object should be used from a single thread, therefore access to m_IsLocked is not threadsafe - // In Windows, it is an error to call cCriticalSection::Unlock() multiple times if the lock is not held, - // therefore we need to check this value whether we are locked or not. - bool m_IsLocked; - -public: - cCSLock(cCriticalSection * a_CS); - cCSLock(cCriticalSection & a_CS); - ~cCSLock(); - - // Temporarily unlock or re-lock: - void Lock(void); - void Unlock(void); - -private: - DISALLOW_COPY_AND_ASSIGN(cCSLock); -} ; - - - - - -/// Temporary RAII unlock for a cCSLock. Useful for unlock-wait-relock scenarios -class cCSUnlock -{ - cCSLock & m_Lock; -public: - cCSUnlock(cCSLock & a_Lock); - ~cCSUnlock(); - -private: - DISALLOW_COPY_AND_ASSIGN(cCSUnlock); -} ; - - - - diff --git a/source/OSSupport/Event.cpp b/source/OSSupport/Event.cpp deleted file mode 100644 index cbacbba17..000000000 --- a/source/OSSupport/Event.cpp +++ /dev/null @@ -1,118 +0,0 @@ - -// Event.cpp - -// Implements the cEvent object representing an OS-specific synchronization primitive that can be waited-for -// Implemented as an Event on Win and as a 1-semaphore on *nix - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "Event.h" - - - - - -cEvent::cEvent(void) -{ -#ifdef _WIN32 - m_Event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (m_Event == NULL) - { - LOGERROR("cEvent: cannot create event, GLE = %d. Aborting server.", GetLastError()); - abort(); - } -#else // *nix - m_bIsNamed = false; - m_Event = new sem_t; - if (sem_init(m_Event, 0, 0)) - { - // This path is used by MacOS, because it doesn't support unnamed semaphores. - delete m_Event; - m_bIsNamed = true; - - AString EventName; - Printf(EventName, "cEvent%p", this); - m_Event = sem_open(EventName.c_str(), O_CREAT, 777, 0 ); - if (m_Event == SEM_FAILED) - { - LOGERROR("cEvent: Cannot create event, errno = %i. Aborting server.", errno); - abort(); - } - // Unlink the semaphore immediately - it will continue to function but will not pollute the namespace - // We don't store the name, so can't call this in the destructor - if (sem_unlink(EventName.c_str()) != 0) - { - LOGWARN("ERROR: Could not unlink cEvent. (%i)", errno); - } - } -#endif // *nix -} - - - - - -cEvent::~cEvent() -{ -#ifdef _WIN32 - CloseHandle(m_Event); -#else - if (m_bIsNamed) - { - if (sem_close(m_Event) != 0) - { - LOGERROR("ERROR: Could not close cEvent. (%i)", errno); - } - } - else - { - sem_destroy(m_Event); - delete m_Event; - } -#endif -} - - - - - -void cEvent::Wait(void) -{ - #ifdef _WIN32 - DWORD res = WaitForSingleObject(m_Event, INFINITE); - if (res != WAIT_OBJECT_0) - { - LOGWARN("cEvent: waiting for the event failed: %d, GLE = %d. Continuing, but server may be unstable.", res, GetLastError()); - } - #else - int res = sem_wait(m_Event); - if (res != 0 ) - { - LOGWARN("cEvent: waiting for the event failed: %i, errno = %i. Continuing, but server may be unstable.", res, errno); - } - #endif -} - - - - - -void cEvent::Set(void) -{ - #ifdef _WIN32 - if (!SetEvent(m_Event)) - { - LOGWARN("cEvent: Could not set cEvent: GLE = %d", GetLastError()); - } - #else - int res = sem_post(m_Event); - if (res != 0) - { - LOGWARN("cEvent: Could not set cEvent: %i, errno = %d", res, errno); - } - #endif -} - - - - diff --git a/source/OSSupport/Event.h b/source/OSSupport/Event.h deleted file mode 100644 index 71f418c0c..000000000 --- a/source/OSSupport/Event.h +++ /dev/null @@ -1,47 +0,0 @@ - -// Event.h - -// Interfaces to the cEvent object representing an OS-specific synchronization primitive that can be waited-for -// Implemented as an Event on Win and as a 1-semaphore on *nix - - - - - -#pragma once -#ifndef CEVENT_H_INCLUDED -#define CEVENT_H_INCLUDED - - - - - -class cEvent -{ -public: - cEvent(void); - ~cEvent(); - - void Wait(void); - void Set (void); - -private: - - #ifdef _WIN32 - HANDLE m_Event; - #else - sem_t * m_Event; - bool m_bIsNamed; - #endif -} ; - - - - - - -#endif // CEVENT_H_INCLUDED - - - - diff --git a/source/OSSupport/File.cpp b/source/OSSupport/File.cpp deleted file mode 100644 index d2eea498a..000000000 --- a/source/OSSupport/File.cpp +++ /dev/null @@ -1,375 +0,0 @@ - -// cFile.cpp - -// Implements the cFile class providing an OS-independent abstraction of a file. - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "File.h" -#include <fstream> - - - - - -cFile::cFile(void) : - #ifdef USE_STDIO_FILE - m_File(NULL) - #else - m_File(INVALID_HANDLE_VALUE) - #endif // USE_STDIO_FILE -{ - // Nothing needed yet -} - - - - - -cFile::cFile(const AString & iFileName, eMode iMode) : - #ifdef USE_STDIO_FILE - m_File(NULL) - #else - m_File(INVALID_HANDLE_VALUE) - #endif // USE_STDIO_FILE -{ - Open(iFileName, iMode); -} - - - - - -cFile::~cFile() -{ - if (IsOpen()) - { - Close(); - } -} - - - - - -bool cFile::Open(const AString & iFileName, eMode iMode) -{ - ASSERT(!IsOpen()); // You should close the file before opening another one - - if (IsOpen()) - { - Close(); - } - - const char * Mode = NULL; - switch (iMode) - { - case fmRead: Mode = "rb"; break; - case fmWrite: Mode = "wb"; break; - case fmReadWrite: Mode = "rb+"; break; - default: - { - ASSERT(!"Unhandled file mode"); - return false; - } - } - m_File = fopen( (FILE_IO_PREFIX + iFileName).c_str(), Mode); - if ((m_File == NULL) && (iMode == fmReadWrite)) - { - // Fix for MS not following C spec, opening "a" mode files for writing at the end only - // The file open operation has been tried with "read update", fails if file not found - // So now we know either the file doesn't exist or we don't have rights, no need to worry about file contents. - // Simply re-open for read-writing, erasing existing contents: - m_File = fopen( (FILE_IO_PREFIX + iFileName).c_str(), "wb+"); - } - return (m_File != NULL); -} - - - - - -void cFile::Close(void) -{ - if (!IsOpen()) - { - // Closing an unopened file is a legal nop - return; - } - - fclose(m_File); - m_File = NULL; -} - - - - - -bool cFile::IsOpen(void) const -{ - return (m_File != NULL); -} - - - - - -bool cFile::IsEOF(void) const -{ - ASSERT(IsOpen()); - - if (!IsOpen()) - { - // Unopened files behave as at EOF - return true; - } - - return (feof(m_File) != 0); -} - - - - - -int cFile::Read (void * iBuffer, int iNumBytes) -{ - ASSERT(IsOpen()); - - if (!IsOpen()) - { - return -1; - } - - return fread(iBuffer, 1, iNumBytes, m_File); // fread() returns the portion of Count parameter actually read, so we need to send iNumBytes as Count -} - - - - - -int cFile::Write(const void * iBuffer, int iNumBytes) -{ - ASSERT(IsOpen()); - - if (!IsOpen()) - { - return -1; - } - - int res = fwrite(iBuffer, 1, iNumBytes, m_File); // fwrite() returns the portion of Count parameter actually written, so we need to send iNumBytes as Count - return res; -} - - - - - -int cFile::Seek (int iPosition) -{ - ASSERT(IsOpen()); - - if (!IsOpen()) - { - return -1; - } - - if (fseek(m_File, iPosition, SEEK_SET) != 0) - { - return -1; - } - return ftell(m_File); -} - - - - - - -int cFile::Tell (void) const -{ - ASSERT(IsOpen()); - - if (!IsOpen()) - { - return -1; - } - - return ftell(m_File); -} - - - - - -int cFile::GetSize(void) const -{ - ASSERT(IsOpen()); - - if (!IsOpen()) - { - return -1; - } - - int CurPos = ftell(m_File); - if (CurPos < 0) - { - return -1; - } - if (fseek(m_File, 0, SEEK_END) != 0) - { - return -1; - } - int res = ftell(m_File); - if (fseek(m_File, CurPos, SEEK_SET) != 0) - { - return -1; - } - return res; -} - - - - - -int cFile::ReadRestOfFile(AString & a_Contents) -{ - ASSERT(IsOpen()); - - if (!IsOpen()) - { - return -1; - } - - int DataSize = GetSize() - Tell(); - - // HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly - a_Contents.assign(DataSize, '\0'); - return Read((void *)a_Contents.data(), DataSize); -} - - - - - -bool cFile::Exists(const AString & a_FileName) -{ - cFile test(a_FileName, fmRead); - return test.IsOpen(); -} - - - - - -bool cFile::Delete(const AString & a_FileName) -{ - return (remove(a_FileName.c_str()) == 0); -} - - - - - -bool cFile::Rename(const AString & a_OrigFileName, const AString & a_NewFileName) -{ - return (rename(a_OrigFileName.c_str(), a_NewFileName.c_str()) == 0); -} - - - - - -bool cFile::Copy(const AString & a_SrcFileName, const AString & a_DstFileName) -{ - #ifdef _WIN32 - return (CopyFile(a_SrcFileName.c_str(), a_DstFileName.c_str(), true) != 0); - #else - // Other OSs don't have a direct CopyFile equivalent, do it the harder way: - std::ifstream src(a_SrcFileName.c_str(), std::ios::binary); - std::ofstream dst(a_DstFileName.c_str(), std::ios::binary); - if (dst.good()) - { - dst << src.rdbuf(); - return true; - } - else - { - return false; - } - #endif -} - - - - - -bool cFile::IsFolder(const AString & a_Path) -{ - #ifdef _WIN32 - DWORD FileAttrib = GetFileAttributes(a_Path.c_str()); - return ((FileAttrib != INVALID_FILE_ATTRIBUTES) && ((FileAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0)); - #else - struct stat st; - return ((stat(a_Path.c_str(), &st) == 0) && S_ISDIR(st.st_mode)); - #endif -} - - - - - -bool cFile::IsFile(const AString & a_Path) -{ - #ifdef _WIN32 - DWORD FileAttrib = GetFileAttributes(a_Path.c_str()); - return ((FileAttrib != INVALID_FILE_ATTRIBUTES) && ((FileAttrib & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0)); - #else - struct stat st; - return ((stat(a_Path.c_str(), &st) == 0) && S_ISREG(st.st_mode)); - #endif -} - - - - - -int cFile::GetSize(const AString & a_FileName) -{ - struct stat st; - if (stat(a_FileName.c_str(), &st) == 0) - { - return st.st_size; - } - return -1; -} - - - - - -bool cFile::CreateFolder(const AString & a_FolderPath) -{ - #ifdef _WIN32 - return (CreateDirectory(a_FolderPath.c_str(), NULL) != 0); - #else - return (mkdir(a_FolderPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0); - #endif -} - - - - - -int cFile::Printf(const char * a_Fmt, ...) -{ - AString buf; - va_list args; - va_start(args, a_Fmt); - AppendVPrintf(buf, a_Fmt, args); - va_end(args); - return Write(buf.c_str(), buf.length()); -} - - - - diff --git a/source/OSSupport/File.h b/source/OSSupport/File.h deleted file mode 100644 index cfb3a2019..000000000 --- a/source/OSSupport/File.h +++ /dev/null @@ -1,138 +0,0 @@ - -// cFile.h - -// Interfaces to the cFile class providing an OS-independent abstraction of a file. - -/* -The object is optimized towards binary reads. -The object has no multithreading locks, don't use from multiple threads! -Usage: -1, Construct a cFile instance (no-param constructor) -2, Open a file using Open(), check return value for success -3, Read / write -4, Destroy the instance - --- OR -- - -1, Construct a cFile instance opening the file (filename-param constructor) -2, Check if the file was opened using IsOpen() -3, Read / write -4, Destroy the instance -*/ - - - - - -#pragma once - - - - - -#ifndef _WIN32 - #define USE_STDIO_FILE -#endif // _WIN32 - -// DEBUG: -#define USE_STDIO_FILE - - - - - -// tolua_begin - -class cFile -{ -public: - - // tolua_end - - #ifdef _WIN32 - static const char PathSeparator = '\\'; - #else - static const char PathSeparator = '/'; - #endif - - /// The mode in which to open the file - enum eMode - { - fmRead, // Read-only. If the file doesn't exist, object will not be valid - fmWrite, // Write-only. If the file already exists, it will be overwritten - fmReadWrite // Read/write. If the file already exists, it will be left intact; writing will overwrite the data from the beginning - } ; - - /// Simple constructor - creates an unopened file object, use Open() to open / create a real file - cFile(void); - - /// Constructs and opens / creates the file specified, use IsOpen() to check for success - cFile(const AString & iFileName, eMode iMode); - - /// Auto-closes the file, if open - ~cFile(); - - bool Open(const AString & iFileName, eMode iMode); - void Close(void); - bool IsOpen(void) const; - bool IsEOF(void) const; - - /// Reads up to iNumBytes bytes into iBuffer, returns the number of bytes actually read, or -1 on failure; asserts if not open - int Read (void * iBuffer, int iNumBytes); - - /// Writes up to iNumBytes bytes from iBuffer, returns the number of bytes actually written, or -1 on failure; asserts if not open - int Write(const void * iBuffer, int iNumBytes); - - /// Seeks to iPosition bytes from file start, returns old position or -1 for failure; asserts if not open - int Seek (int iPosition); - - /// Returns the current position (bytes from file start) or -1 for failure; asserts if not open - int Tell (void) const; - - /// Returns the size of file, in bytes, or -1 for failure; asserts if not open - int GetSize(void) const; - - /// Reads the file from current position till EOF into an AString; returns the number of bytes read or -1 for error - int ReadRestOfFile(AString & a_Contents); - - // tolua_begin - - /// Returns true if the file specified exists - static bool Exists(const AString & a_FileName); - - /// Deletes a file, returns true if successful - static bool Delete(const AString & a_FileName); - - /// Renames a file or folder, returns true if successful. May fail if dest already exists (libc-dependant)! - static bool Rename(const AString & a_OrigPath, const AString & a_NewPath); - - /// Copies a file, returns true if successful. - static bool Copy(const AString & a_SrcFileName, const AString & a_DstFileName); - - /// Returns true if the specified path is a folder - static bool IsFolder(const AString & a_Path); - - /// Returns true if the specified path is a regular file - static bool IsFile(const AString & a_Path); - - /// Returns the size of the file, or a negative number on error - static int GetSize(const AString & a_FileName); - - /// Creates a new folder with the specified name. Returns true if successful. Path may be relative or absolute - static bool CreateFolder(const AString & a_FolderPath); - - // tolua_end - - int Printf(const char * a_Fmt, ...); - -private: - #ifdef USE_STDIO_FILE - FILE * m_File; - #else - HANDLE m_File; - #endif -} ; // tolua_export - - - - diff --git a/source/OSSupport/GZipFile.cpp b/source/OSSupport/GZipFile.cpp deleted file mode 100644 index cbf6be6c4..000000000 --- a/source/OSSupport/GZipFile.cpp +++ /dev/null @@ -1,107 +0,0 @@ - -// GZipFile.cpp - -// Implements the cGZipFile class representing a RAII wrapper over zlib's GZip file routines - -#include "Globals.h" -#include "GZipFile.h" - - - - - -cGZipFile::cGZipFile(void) : - m_File(NULL) -{ -} - - - - - -cGZipFile::~cGZipFile() -{ - Close(); -} - - - - - -bool cGZipFile::Open(const AString & a_FileName, eMode a_Mode) -{ - if (m_File != NULL) - { - ASSERT(!"A file is already open in this object"); - return false; - } - m_File = gzopen(a_FileName.c_str(), (a_Mode == fmRead) ? "r" : "w"); - m_Mode = a_Mode; - return (m_File != NULL); -} - - - - - -void cGZipFile::Close(void) -{ - if (m_File != NULL) - { - gzclose(m_File); - m_File = NULL; - } -} - - - - - -int cGZipFile::ReadRestOfFile(AString & a_Contents) -{ - if (m_File == NULL) - { - ASSERT(!"No file has been opened"); - return -1; - } - - if (m_Mode != fmRead) - { - ASSERT(!"Bad file mode, cannot read"); - return -1; - } - - // Since the gzip format doesn't really support getting the uncompressed length, we need to read incrementally. Yuck! - int NumBytesRead = 0; - char Buffer[64 KiB]; - while ((NumBytesRead = gzread(m_File, Buffer, sizeof(Buffer))) > 0) - { - a_Contents.append(Buffer, NumBytesRead); - } - return NumBytesRead; -} - - - - - -bool cGZipFile::Write(const char * a_Contents, int a_Size) -{ - if (m_File == NULL) - { - ASSERT(!"No file has been opened"); - return false; - } - - if (m_Mode != fmWrite) - { - ASSERT(!"Bad file mode, cannot write"); - return false; - } - - return (gzwrite(m_File, a_Contents, a_Size) != 0); -} - - - - diff --git a/source/OSSupport/GZipFile.h b/source/OSSupport/GZipFile.h deleted file mode 100644 index e5aa68afa..000000000 --- a/source/OSSupport/GZipFile.h +++ /dev/null @@ -1,52 +0,0 @@ - -// GZipFile.h - -// Declares the cGZipFile class representing a RAII wrapper over zlib's GZip file routines - - - - - -#pragma once - -#include "zlib.h" - - - - - -class cGZipFile -{ -public: - enum eMode - { - fmRead, // Read-only. If the file doesn't exist, object will not be valid - fmWrite, // Write-only. If the file already exists, it will be overwritten - } ; - - cGZipFile(void); - ~cGZipFile(); - - /// Opens the file. Returns true if successful. Fails if a file has already been opened through this object. - bool Open(const AString & a_FileName, eMode a_Mode); - - /// Closes the file, flushing all buffers. This object may be then reused for a different file and / or mode - void Close(void); - - /// Reads the rest of the file and decompresses it into a_Contents. Returns the number of decompressed bytes, <0 for error - int ReadRestOfFile(AString & a_Contents); - - /// Writes a_Contents into file, compressing it along the way. Returns true if successful. Multiple writes are supported. - bool Write(const AString & a_Contents) { return Write(a_Contents.data(), (int)(a_Contents.size())); } - - bool Write(const char * a_Data, int a_Size); - -protected: - gzFile m_File; - eMode m_Mode; -} ; - - - - - diff --git a/source/OSSupport/IsThread.cpp b/source/OSSupport/IsThread.cpp deleted file mode 100644 index 4da9f9949..000000000 --- a/source/OSSupport/IsThread.cpp +++ /dev/null @@ -1,172 +0,0 @@ - -// IsThread.cpp - -// Implements the cIsThread class representing an OS-independent wrapper for a class that implements a thread. -// This class will eventually suupersede the old cThread class - -#include "Globals.h" - -#include "IsThread.h" - - - - - -// When in MSVC, the debugger provides "thread naming" by catching special exceptions. Interface here: -#if defined(_MSC_VER) && defined(_DEBUG) -// -// Usage: SetThreadName (-1, "MainThread"); -// - -static void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName) -{ - struct - { - DWORD dwType; // must be 0x1000 - LPCSTR szName; // pointer to name (in user addr space) - DWORD dwThreadID; // thread ID (-1=caller thread) - DWORD dwFlags; // reserved for future use, must be zero - } info; - - info.dwType = 0x1000; - info.szName = szThreadName; - info.dwThreadID = dwThreadID; - info.dwFlags = 0; - - __try - { - RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (DWORD *)&info); - } - __except(EXCEPTION_CONTINUE_EXECUTION) - { - } -} -#endif // _MSC_VER && _DEBUG - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cIsThread: - -cIsThread::cIsThread(const AString & iThreadName) : - m_ThreadName(iThreadName), - m_ShouldTerminate(false), - m_Handle(NULL_HANDLE) -{ -} - - - - - -cIsThread::~cIsThread() -{ - m_ShouldTerminate = true; - Wait(); -} - - - - - -bool cIsThread::Start(void) -{ - ASSERT(m_Handle == NULL_HANDLE); // Has already started one thread? - #ifdef _WIN32 - // Create the thread suspended, so that the mHandle variable is valid in the thread procedure - DWORD ThreadID = 0; - m_Handle = CreateThread(NULL, 0, thrExecute, this, CREATE_SUSPENDED, &ThreadID); - if (m_Handle == NULL) - { - LOGERROR("ERROR: Could not create thread \"%s\", GLE = %d!", m_ThreadName.c_str(), GetLastError()); - return false; - } - ResumeThread(m_Handle); - - #if defined(_DEBUG) && defined(_MSC_VER) - // Thread naming is available only in MSVC - if (!m_ThreadName.empty()) - { - SetThreadName(ThreadID, m_ThreadName.c_str()); - } - #endif // _DEBUG and _MSC_VER - - #else // _WIN32 - if (pthread_create(&m_Handle, NULL, thrExecute, this)) - { - LOGERROR("ERROR: Could not create thread \"%s\", !", m_ThreadName.c_str()); - return false; - } - #endif // else _WIN32 - - return true; -} - - - - - -void cIsThread::Stop(void) -{ - if (m_Handle == NULL_HANDLE) - { - return; - } - m_ShouldTerminate = true; - Wait(); -} - - - - - -bool cIsThread::Wait(void) -{ - if (m_Handle == NULL) - { - return true; - } - - #ifdef LOGD // ProtoProxy doesn't have LOGD - LOGD("Waiting for thread %s to finish", m_ThreadName.c_str()); - #endif // LOGD - - #ifdef _WIN32 - int res = WaitForSingleObject(m_Handle, INFINITE); - m_Handle = NULL; - - #ifdef LOGD // ProtoProxy doesn't have LOGD - LOGD("Thread %s finished", m_ThreadName.c_str()); - #endif // LOGD - - return (res == WAIT_OBJECT_0); - #else // _WIN32 - int res = pthread_join(m_Handle, NULL); - m_Handle = NULL; - - #ifdef LOGD // ProtoProxy doesn't have LOGD - LOGD("Thread %s finished", m_ThreadName.c_str()); - #endif // LOGD - - return (res == 0); - #endif // else _WIN32 -} - - - - - -unsigned long cIsThread::GetCurrentID(void) -{ - #ifdef _WIN32 - return (unsigned long) GetCurrentThreadId(); - #else - return (unsigned long) pthread_self(); - #endif -} - - - - diff --git a/source/OSSupport/IsThread.h b/source/OSSupport/IsThread.h deleted file mode 100644 index b8784ea33..000000000 --- a/source/OSSupport/IsThread.h +++ /dev/null @@ -1,100 +0,0 @@ - -// IsThread.h - -// Interfaces to the cIsThread class representing an OS-independent wrapper for a class that implements a thread. -// This class will eventually suupersede the old cThread class - -/* -Usage: -To have a new thread, declare a class descending from cIsClass. -Then override its Execute() method to provide your thread processing. -In the descending class' constructor call the Start() method to start the thread once you're finished with initialization. -*/ - - - - - -#pragma once -#ifndef CISTHREAD_H_INCLUDED -#define CISTHREAD_H_INCLUDED - - - - - -class cIsThread -{ -protected: - /// This is the main thread entrypoint - virtual void Execute(void) = 0; - - /// The overriden Execute() method should check this value periodically and terminate if this is true - volatile bool m_ShouldTerminate; - -public: - cIsThread(const AString & iThreadName); - ~cIsThread(); - - /// Starts the thread; returns without waiting for the actual start - bool Start(void); - - /// Signals the thread to terminate and waits until it's finished - void Stop(void); - - /// Waits for the thread to finish. Doesn't signalize the ShouldTerminate flag - bool Wait(void); - - /// Returns the OS-dependent thread ID for the caller's thread - static unsigned long GetCurrentID(void); - -protected: - AString m_ThreadName; - - // Value used for "no handle": - #ifdef _WIN32 - #define NULL_HANDLE NULL - #else - #define NULL_HANDLE 0 - #endif - - #ifdef _WIN32 - - HANDLE m_Handle; - - static DWORD_PTR __stdcall thrExecute(LPVOID a_Param) - { - // Create a window so that the thread can be identified by 3rd party tools: - HWND IdentificationWnd = CreateWindow("STATIC", ((cIsThread *)a_Param)->m_ThreadName.c_str(), 0, 0, 0, 0, WS_OVERLAPPED, NULL, NULL, NULL, NULL); - - // Run the thread: - ((cIsThread *)a_Param)->Execute(); - - // Destroy the identification window: - DestroyWindow(IdentificationWnd); - - return 0; - } - - #else // _WIN32 - - pthread_t m_Handle; - - static void * thrExecute(void * a_Param) - { - ((cIsThread *)a_Param)->Execute(); - return NULL; - } - - #endif // else _WIN32 -} ; - - - - - -#endif // CISTHREAD_H_INCLUDED - - - - diff --git a/source/OSSupport/ListenThread.cpp b/source/OSSupport/ListenThread.cpp deleted file mode 100644 index ba3198764..000000000 --- a/source/OSSupport/ListenThread.cpp +++ /dev/null @@ -1,238 +0,0 @@ - -// ListenThread.cpp - -// Implements the cListenThread class representing the thread that listens for client connections - -#include "Globals.h" -#include "ListenThread.h" - - - - - -cListenThread::cListenThread(cCallback & a_Callback, cSocket::eFamily a_Family, const AString & a_ServiceName) : - super(Printf("ListenThread %s", a_ServiceName.c_str())), - m_Callback(a_Callback), - m_Family(a_Family), - m_ShouldReuseAddr(false), - m_ServiceName(a_ServiceName) -{ -} - - - - - -cListenThread::~cListenThread() -{ - Stop(); -} - - - - - -bool cListenThread::Initialize(const AString & a_PortsString) -{ - ASSERT(m_Sockets.empty()); // Not yet started - - if (!CreateSockets(a_PortsString)) - { - return false; - } - - return true; -} - - - - - -bool cListenThread::Start(void) -{ - if (m_Sockets.empty()) - { - // There are no sockets listening, either forgotten to initialize or the user specified no listening ports - // Report as successful, though - return true; - } - return super::Start(); -} - - - - - -void cListenThread::Stop(void) -{ - if (m_Sockets.empty()) - { - // No sockets means no thread was running in the first place - return; - } - - m_ShouldTerminate = true; - - // Close one socket to wake the thread up from the select() call - m_Sockets[0].CloseSocket(); - - // Wait for the thread to finish - super::Wait(); - - // Close all the listening sockets: - for (cSockets::iterator itr = m_Sockets.begin() + 1, end = m_Sockets.end(); itr != end; ++itr) - { - itr->CloseSocket(); - } // for itr - m_Sockets[] - m_Sockets.clear(); -} - - - - - -void cListenThread::SetReuseAddr(bool a_Reuse) -{ - ASSERT(m_Sockets.empty()); // Must not have been Initialize()d yet - - m_ShouldReuseAddr = a_Reuse; -} - - - - - -bool cListenThread::CreateSockets(const AString & a_PortsString) -{ - AStringVector Ports = StringSplitAndTrim(a_PortsString, ","); - - if (Ports.empty()) - { - return false; - } - - AString FamilyStr = m_ServiceName; - switch (m_Family) - { - case cSocket::IPv4: FamilyStr.append(" IPv4"); break; - case cSocket::IPv6: FamilyStr.append(" IPv6"); break; - default: - { - ASSERT(!"Unknown address family"); - break; - } - } - - for (AStringVector::const_iterator itr = Ports.begin(), end = Ports.end(); itr != end; ++itr) - { - int Port = atoi(itr->c_str()); - if ((Port <= 0) || (Port > 65535)) - { - LOGWARNING("%s: Invalid port specified: \"%s\".", FamilyStr.c_str(), itr->c_str()); - continue; - } - m_Sockets.push_back(cSocket::CreateSocket(m_Family)); - if (!m_Sockets.back().IsValid()) - { - LOGWARNING("%s: Cannot create listening socket for port %d: \"%s\"", FamilyStr.c_str(), Port, cSocket::GetLastErrorString().c_str()); - m_Sockets.pop_back(); - continue; - } - - if (m_ShouldReuseAddr) - { - if (!m_Sockets.back().SetReuseAddress()) - { - LOG("%s: Port %d cannot reuse addr, syscall failed: \"%s\".", FamilyStr.c_str(), Port, cSocket::GetLastErrorString().c_str()); - } - } - - // Bind to port: - bool res = false; - switch (m_Family) - { - case cSocket::IPv4: res = m_Sockets.back().BindToAnyIPv4(Port); break; - case cSocket::IPv6: res = m_Sockets.back().BindToAnyIPv6(Port); break; - default: - { - ASSERT(!"Unknown address family"); - res = false; - } - } - if (!res) - { - LOGWARNING("%s: Cannot bind port %d: \"%s\".", FamilyStr.c_str(), Port, cSocket::GetLastErrorString().c_str()); - m_Sockets.pop_back(); - continue; - } - - if (!m_Sockets.back().Listen()) - { - LOGWARNING("%s: Cannot listen on port %d: \"%s\".", FamilyStr.c_str(), Port, cSocket::GetLastErrorString().c_str()); - m_Sockets.pop_back(); - continue; - } - - LOGINFO("%s: Port %d is open for connections", FamilyStr.c_str(), Port); - } // for itr - Ports[] - - return !(m_Sockets.empty()); -} - - - - - -void cListenThread::Execute(void) -{ - if (m_Sockets.empty()) - { - LOGD("Empty cListenThread, ending thread now."); - return; - } - - // Find the highest socket number: - cSocket::xSocket Highest = m_Sockets[0].GetSocket(); - for (cSockets::iterator itr = m_Sockets.begin(), end = m_Sockets.end(); itr != end; ++itr) - { - if (itr->GetSocket() > Highest) - { - Highest = itr->GetSocket(); - } - } // for itr - m_Sockets[] - - while (!m_ShouldTerminate) - { - // Put all sockets into a FD set: - fd_set fdRead; - FD_ZERO(&fdRead); - for (cSockets::iterator itr = m_Sockets.begin(), end = m_Sockets.end(); itr != end; ++itr) - { - FD_SET(itr->GetSocket(), &fdRead); - } // for itr - m_Sockets[] - - timeval tv; // On Linux select() doesn't seem to wake up when socket is closed, so let's kinda busy-wait: - tv.tv_sec = 1; - tv.tv_usec = 0; - if (select(Highest + 1, &fdRead, NULL, NULL, &tv) == -1) - { - LOG("select(R) call failed in cListenThread: \"%s\"", cSocket::GetLastErrorString().c_str()); - continue; - } - for (cSockets::iterator itr = m_Sockets.begin(), end = m_Sockets.end(); itr != end; ++itr) - { - if (itr->IsValid() && FD_ISSET(itr->GetSocket(), &fdRead)) - { - cSocket Client = (m_Family == cSocket::IPv4) ? itr->AcceptIPv4() : itr->AcceptIPv6(); - if (Client.IsValid()) - { - m_Callback.OnConnectionAccepted(Client); - } - } - } // for itr - m_Sockets[] - } // while (!m_ShouldTerminate) -} - - - - diff --git a/source/OSSupport/ListenThread.h b/source/OSSupport/ListenThread.h deleted file mode 100644 index 4e337d814..000000000 --- a/source/OSSupport/ListenThread.h +++ /dev/null @@ -1,83 +0,0 @@ - -// ListenThread.h - -// Declares the cListenThread class representing the thread that listens for client connections - - - - - -#pragma once - -#include "IsThread.h" -#include "Socket.h" - - - - - -// fwd: -class cServer; - - - - - -class cListenThread : - public cIsThread -{ - typedef cIsThread super; - -public: - /// Used as the callback for connection events - class cCallback - { - public: - /// This callback is called whenever a socket connection is accepted - virtual void OnConnectionAccepted(cSocket & a_Socket) = 0; - } ; - - cListenThread(cCallback & a_Callback, cSocket::eFamily a_Family, const AString & a_ServiceName = ""); - ~cListenThread(); - - /// Creates all the sockets, returns trus if successful, false if not. - bool Initialize(const AString & a_PortsString); - - bool Start(void); - - void Stop(void); - - /// Call before Initialize() to set the "reuse" flag on the sockets - void SetReuseAddr(bool a_Reuse = true); - -protected: - typedef std::vector<cSocket> cSockets; - - /// The callback which to notify of incoming connections - cCallback & m_Callback; - - /// Socket address family to use - cSocket::eFamily m_Family; - - /// Sockets that are being monitored - cSockets m_Sockets; - - /// If set to true, the SO_REUSEADDR socket option is set to true - bool m_ShouldReuseAddr; - - /// Name of the service that's listening on the ports; for logging purposes only - AString m_ServiceName; - - - /** Fills in m_Sockets with individual sockets, each for one port specified in a_PortsString. - Returns true if successful and at least one socket has been created - */ - bool CreateSockets(const AString & a_PortsString); - - // cIsThread override: - virtual void Execute(void) override; -} ; - - - - diff --git a/source/OSSupport/Semaphore.cpp b/source/OSSupport/Semaphore.cpp deleted file mode 100644 index 468de6858..000000000 --- a/source/OSSupport/Semaphore.cpp +++ /dev/null @@ -1,91 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - - - - - -cSemaphore::cSemaphore( unsigned int a_MaxCount, unsigned int a_InitialCount /* = 0 */ ) -#ifndef _WIN32 - : m_bNamed( false ) -#endif -{ -#ifndef _WIN32 - (void)a_MaxCount; - m_Handle = new sem_t; - if (sem_init( (sem_t*)m_Handle, 0, 0)) - { - LOG("WARNING cSemaphore: Could not create unnamed semaphore, fallback to named."); - delete (sem_t*)m_Handle; // named semaphores return their own address - m_bNamed = true; - - AString Name; - Printf(Name, "cSemaphore%p", this ); - m_Handle = sem_open(Name.c_str(), O_CREAT, 777, a_InitialCount); - if( m_Handle == SEM_FAILED ) - { - LOG("ERROR: Could not create Semaphore. (%i)", errno ); - } - else - { - if( sem_unlink(Name.c_str()) != 0 ) - { - LOG("ERROR: Could not unlink cSemaphore. (%i)", errno); - } - } - } -#else - m_Handle = CreateSemaphore( - NULL, // security attribute - a_InitialCount, // initial count - a_MaxCount, // maximum count - 0 // name (optional) - ); -#endif -} - -cSemaphore::~cSemaphore() -{ -#ifdef _WIN32 - CloseHandle( m_Handle ); -#else - if( m_bNamed ) - { - if( sem_close( (sem_t*)m_Handle ) != 0 ) - { - LOG("ERROR: Could not close cSemaphore. (%i)", errno); - } - } - else - { - sem_destroy( (sem_t*)m_Handle ); - delete (sem_t*)m_Handle; - } - m_Handle = 0; - -#endif -} - -void cSemaphore::Wait() -{ -#ifndef _WIN32 - if( sem_wait( (sem_t*)m_Handle ) != 0) - { - LOG("ERROR: Could not wait for cSemaphore. (%i)", errno); - } -#else - WaitForSingleObject( m_Handle, INFINITE); -#endif -} - -void cSemaphore::Signal() -{ -#ifndef _WIN32 - if( sem_post( (sem_t*)m_Handle ) != 0 ) - { - LOG("ERROR: Could not signal cSemaphore. (%i)", errno); - } -#else - ReleaseSemaphore( m_Handle, 1, NULL ); -#endif -} diff --git a/source/OSSupport/Semaphore.h b/source/OSSupport/Semaphore.h deleted file mode 100644 index fbe8907f1..000000000 --- a/source/OSSupport/Semaphore.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -class cSemaphore -{ -public: - cSemaphore( unsigned int a_MaxCount, unsigned int a_InitialCount = 0 ); - ~cSemaphore(); - - void Wait(); - void Signal(); -private: - void* m_Handle; // HANDLE pointer - -#ifndef _WIN32 - bool m_bNamed; -#endif -}; diff --git a/source/OSSupport/Sleep.cpp b/source/OSSupport/Sleep.cpp deleted file mode 100644 index 70fb06b40..000000000 --- a/source/OSSupport/Sleep.cpp +++ /dev/null @@ -1,19 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#ifndef _WIN32 - #include <unistd.h> -#endif - - - - - -void cSleep::MilliSleep( unsigned int a_MilliSeconds ) -{ -#ifdef _WIN32 - Sleep(a_MilliSeconds); // Don't tick too much -#else - usleep(a_MilliSeconds*1000); -#endif -} diff --git a/source/OSSupport/Sleep.h b/source/OSSupport/Sleep.h deleted file mode 100644 index 5298c15da..000000000 --- a/source/OSSupport/Sleep.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -class cSleep -{ -public: - static void MilliSleep( unsigned int a_MilliSeconds ); -};
\ No newline at end of file diff --git a/source/OSSupport/Socket.cpp b/source/OSSupport/Socket.cpp deleted file mode 100644 index 48b5d704d..000000000 --- a/source/OSSupport/Socket.cpp +++ /dev/null @@ -1,396 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "Socket.h" - -#ifndef _WIN32 - #include <netdb.h> - #include <unistd.h> - #include <arpa/inet.h> //inet_ntoa() -#else - #define socklen_t int -#endif - - - - - -cSocket::cSocket(xSocket a_Socket) - : m_Socket(a_Socket) -{ -} - - - - - -cSocket::~cSocket() -{ - // Do NOT close the socket; this class is an API wrapper, not a RAII! -} - - - - - -cSocket::operator cSocket::xSocket() const -{ - return m_Socket; -} - - - - - -cSocket::xSocket cSocket::GetSocket() const -{ - return m_Socket; -} - - - - - -bool cSocket::IsValidSocket(cSocket::xSocket a_Socket) -{ - #ifdef _WIN32 - return (a_Socket != INVALID_SOCKET); - #else // _WIN32 - return (a_Socket >= 0); - #endif // else _WIN32 -} - - - - - -void cSocket::CloseSocket() -{ - #ifdef _WIN32 - - closesocket(m_Socket); - - #else // _WIN32 - - if (shutdown(m_Socket, SHUT_RDWR) != 0)//SD_BOTH); - { - LOGWARN("Error on shutting down socket %d (%s): %s", m_Socket, m_IPString.c_str(), GetLastErrorString().c_str()); - } - if (close(m_Socket) != 0) - { - LOGWARN("Error closing socket %d (%s): %s", m_Socket, m_IPString.c_str(), GetLastErrorString().c_str()); - } - - #endif // else _WIN32 - - // Invalidate the socket so that this object can be re-used for another connection - m_Socket = INVALID_SOCKET; -} - - - - - -AString cSocket::GetErrorString( int a_ErrNo ) -{ - char buffer[ 1024 ]; - AString Out; - - #ifdef _WIN32 - - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, a_ErrNo, 0, buffer, ARRAYCOUNT(buffer), NULL); - Printf(Out, "%d: %s", a_ErrNo, buffer); - if (!Out.empty() && (Out[Out.length() - 1] == '\n')) - { - Out.erase(Out.length() - 2); - } - return Out; - - #else // _WIN32 - - // According to http://linux.die.net/man/3/strerror_r there are two versions of strerror_r(): - - #if ( _GNU_SOURCE ) && !defined(ANDROID_NDK) // GNU version of strerror_r() - - char * res = strerror_r( errno, buffer, ARRAYCOUNT(buffer) ); - if( res != NULL ) - { - Printf(Out, "%d: %s", a_ErrNo, res); - return Out; - } - - #else // XSI version of strerror_r(): - - int res = strerror_r( errno, buffer, ARRAYCOUNT(buffer) ); - if( res == 0 ) - { - Printf(Out, "%d: %s", a_ErrNo, buffer); - return Out; - } - - #endif // strerror_r() version - - else - { - Printf(Out, "Error %d while getting error string for error #%d!", errno, a_ErrNo); - return Out; - } - - #endif // else _WIN32 -} - - - - -int cSocket::GetLastError() -{ -#ifdef _WIN32 - return WSAGetLastError(); -#else - return errno; -#endif -} - - - - - -bool cSocket::SetReuseAddress(void) -{ - #if defined(_WIN32) || defined(ANDROID_NDK) - char yes = 1; - #else - int yes = 1; - #endif - return (setsockopt(m_Socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == 0); -} - - - - - -int cSocket::WSAStartup() -{ -#ifdef _WIN32 - WSADATA wsaData; - memset(&wsaData, 0, sizeof(wsaData)); - return ::WSAStartup(MAKEWORD(2, 2),&wsaData); -#else - return 0; -#endif -} - - - - - -cSocket cSocket::CreateSocket(eFamily a_Family) -{ - return socket((int)a_Family, SOCK_STREAM, 0); -} - - - - - -bool cSocket::BindToAnyIPv4(unsigned short a_Port) -{ - sockaddr_in local; - memset(&local, 0, sizeof(local)); - - local.sin_family = AF_INET; - local.sin_port = htons((u_short)a_Port); - - return (bind(m_Socket, (sockaddr *)&local, sizeof(local)) == 0); -} - - - - - -bool cSocket::BindToAnyIPv6(unsigned short a_Port) -{ - // Cannot use socckaddr_in6, because it is not defined in the default VS2008 SDK - // Must jump through hoops here - - sockaddr_in6 local; - memset(&local, 0, sizeof(local)); - - local.sin6_family = AF_INET6; - local.sin6_port = htons((u_short)a_Port); - - return (bind(m_Socket, (sockaddr *)&local, sizeof(local)) == 0); -} - - - - - -bool cSocket::BindToLocalhostIPv4(unsigned short a_Port) -{ - sockaddr_in local; - memset(&local, 0, sizeof(local)); - - local.sin_family = AF_INET;; - local.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - local.sin_port = htons((u_short)a_Port); - - return (bind(m_Socket, (sockaddr*)&local, sizeof(local)) == 0); -} - - - - - -bool cSocket::Listen(int a_Backlog) -{ - return (listen(m_Socket, a_Backlog) == 0); -} - - - - - -cSocket cSocket::AcceptIPv4(void) -{ - sockaddr_in from; - socklen_t fromlen = sizeof(from); - - cSocket SClient = accept(m_Socket, (sockaddr *)&from, &fromlen); - - if (SClient.IsValid() && (from.sin_addr.s_addr != 0)) // Get IP in string form - { - SClient.m_IPString = inet_ntoa(from.sin_addr); - } - return SClient; -} - - - - - -cSocket cSocket::AcceptIPv6(void) -{ - sockaddr_in6 from; - socklen_t fromlen = sizeof(from); - - cSocket SClient = accept(m_Socket, (sockaddr *)&from, &fromlen); - - // Get IP in string form: - if (SClient.IsValid()) - { - #if defined(_WIN32) - // Windows XP doesn't have inet_ntop, so we need to improvise. And MSVC has different headers than GCC - #ifdef _MSC_VER - // MSVC version - Printf(SClient.m_IPString, "%x:%x:%x:%x:%x:%x:%x:%x", - from.sin6_addr.u.Word[0], - from.sin6_addr.u.Word[1], - from.sin6_addr.u.Word[2], - from.sin6_addr.u.Word[3], - from.sin6_addr.u.Word[4], - from.sin6_addr.u.Word[5], - from.sin6_addr.u.Word[6], - from.sin6_addr.u.Word[7] - ); - #else // _MSC_VER - // MinGW - Printf(SClient.m_IPString, "%x:%x:%x:%x:%x:%x:%x:%x", - from.sin6_addr.s6_addr16[0], - from.sin6_addr.s6_addr16[1], - from.sin6_addr.s6_addr16[2], - from.sin6_addr.s6_addr16[3], - from.sin6_addr.s6_addr16[4], - from.sin6_addr.s6_addr16[5], - from.sin6_addr.s6_addr16[6], - from.sin6_addr.s6_addr16[7] - ); - #endif // else _MSC_VER - #else - char buffer[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(from.sin6_addr), buffer, sizeof(buffer)); - SClient.m_IPString.assign(buffer); - #endif // _WIN32 - } - return SClient; -} - - - - - -bool cSocket::ConnectToLocalhostIPv4(unsigned short a_Port) -{ - sockaddr_in server; - server.sin_family = AF_INET; - server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - server.sin_port = htons(a_Port); - return (connect(m_Socket, (sockaddr *)&server, sizeof(server)) == 0); -} - - - - - -bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Port) -{ - // First try IP Address string to hostent conversion, because it's faster - unsigned long addr = inet_addr(a_HostNameOrAddr.c_str()); - hostent * hp = gethostbyaddr((char*)&addr, sizeof(addr), AF_INET); - if (hp == NULL) - { - // It is not an IP Address string, but rather a regular hostname, resolve: - hp = gethostbyname(a_HostNameOrAddr.c_str()); - if (hp == NULL) - { - LOGWARN("cTCPLink: Could not resolve hostname \"%s\"", a_HostNameOrAddr.c_str()); - CloseSocket(); - return false; - } - } - - sockaddr_in server; - server.sin_addr.s_addr = *((unsigned long*)hp->h_addr); - server.sin_family = AF_INET; - server.sin_port = htons( (unsigned short)a_Port ); - return (connect(m_Socket, (sockaddr *)&server, sizeof(server)) == 0); -} - - - - - -int cSocket::Receive(char* a_Buffer, unsigned int a_Length, unsigned int a_Flags) -{ - return recv(m_Socket, a_Buffer, a_Length, a_Flags); -} - - - - - -int cSocket::Send(const char * a_Buffer, unsigned int a_Length) -{ - return send(m_Socket, a_Buffer, a_Length, 0); -} - - - - - -unsigned short cSocket::GetPort(void) const -{ - ASSERT(IsValid()); - - sockaddr_in Addr; - socklen_t AddrSize = sizeof(Addr); - if (getsockname(m_Socket, (sockaddr *)&Addr, &AddrSize) != 0) - { - return 0; - } - return ntohs(Addr.sin_port); -} - - - - diff --git a/source/OSSupport/Socket.h b/source/OSSupport/Socket.h deleted file mode 100644 index 34f09cc74..000000000 --- a/source/OSSupport/Socket.h +++ /dev/null @@ -1,101 +0,0 @@ - -#pragma once - - - - - -class cSocket -{ -public: - enum eFamily - { - IPv4 = AF_INET, - IPv6 = AF_INET6, - } ; - -#ifdef _WIN32 - typedef SOCKET xSocket; -#else - typedef int xSocket; - static const int INVALID_SOCKET = -1; -#endif - - cSocket(void) : m_Socket(INVALID_SOCKET) {} - cSocket(xSocket a_Socket); - ~cSocket(); - - bool IsValid(void) const { return IsValidSocket(m_Socket); } - void CloseSocket(void); - - operator xSocket(void) const; - xSocket GetSocket(void) const; - - bool operator == (const cSocket & a_Other) {return m_Socket == a_Other.m_Socket; } - - void SetSocket(xSocket a_Socket); - - /// Sets the address-reuse socket flag; returns true on success - bool SetReuseAddress(void); - - static int WSAStartup(void); - - static AString GetErrorString(int a_ErrNo); - static int GetLastError(); - static AString GetLastErrorString(void) - { - return GetErrorString(GetLastError()); - } - - /// Creates a new socket of the specified address family - static cSocket CreateSocket(eFamily a_Family); - - inline static bool IsSocketError(int a_ReturnedValue) - { - #ifdef _WIN32 - return (a_ReturnedValue == SOCKET_ERROR || a_ReturnedValue == 0); - #else - return (a_ReturnedValue <= 0); - #endif - } - - static bool IsValidSocket(xSocket a_Socket); - - static const unsigned short ANY_PORT = 0; // When given to Bind() functions, they will find a free port - static const int DEFAULT_BACKLOG = 10; - - /// Binds to the specified port on "any" interface (0.0.0.0). Returns true if successful. - bool BindToAnyIPv4(unsigned short a_Port); - - /// Binds to the specified port on "any" interface (::/128). Returns true if successful. - bool BindToAnyIPv6(unsigned short a_Port); - - /// Binds to the specified port on localhost interface (127.0.0.1) through IPv4. Returns true if successful. - bool BindToLocalhostIPv4(unsigned short a_Port); - - /// Sets the socket to listen for incoming connections. Returns true if successful. - bool Listen(int a_Backlog = DEFAULT_BACKLOG); - - /// Accepts an IPv4 incoming connection. Blocks if none available. - cSocket AcceptIPv4(void); - - /// Accepts an IPv6 incoming connection. Blocks if none available. - cSocket AcceptIPv6(void); - - /// Connects to a localhost socket on the specified port using IPv4; returns true if successful. - bool ConnectToLocalhostIPv4(unsigned short a_Port); - - /// Connects to the specified host or string IP address and port, using IPv4. Returns true if successful. - bool ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Port); - - int Receive(char * a_Buffer, unsigned int a_Length, unsigned int a_Flags); - int Send (const char * a_Buffer, unsigned int a_Length); - - unsigned short GetPort(void) const; // Returns 0 on failure - - const AString & GetIPString(void) const { return m_IPString; } - -private: - xSocket m_Socket; - AString m_IPString; -};
\ No newline at end of file diff --git a/source/OSSupport/SocketThreads.cpp b/source/OSSupport/SocketThreads.cpp deleted file mode 100644 index 3e505616c..000000000 --- a/source/OSSupport/SocketThreads.cpp +++ /dev/null @@ -1,675 +0,0 @@ - -// cSocketThreads.cpp - -// Implements the cSocketThreads class representing the heart of MCS's client networking. -// This object takes care of network communication, groups sockets into threads and uses as little threads as possible for full read / write support -// For more detail, see http://forum.mc-server.org/showthread.php?tid=327 - -#include "Globals.h" -#include "SocketThreads.h" - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cSocketThreads: - -cSocketThreads::cSocketThreads(void) -{ -} - - - - - -cSocketThreads::~cSocketThreads() -{ - for (cSocketThreadList::iterator itr = m_Threads.begin(); itr != m_Threads.end(); ++itr) - { - delete *itr; - } // for itr - m_Threads[] - m_Threads.clear(); -} - - - - - - -bool cSocketThreads::AddClient(const cSocket & a_Socket, cCallback * a_Client) -{ - // Add a (socket, client) pair for processing, data from a_Socket is to be sent to a_Client - - // Try to add to existing threads: - cCSLock Lock(m_CS); - for (cSocketThreadList::iterator itr = m_Threads.begin(); itr != m_Threads.end(); ++itr) - { - if ((*itr)->IsValid() && (*itr)->HasEmptySlot()) - { - (*itr)->AddClient(a_Socket, a_Client); - return true; - } - } - - // No thread has free space, create a new one: - LOGD("Creating a new cSocketThread (currently have %d)", m_Threads.size()); - cSocketThread * Thread = new cSocketThread(this); - if (!Thread->Start()) - { - // There was an error launching the thread (but it was already logged along with the reason) - LOGERROR("A new cSocketThread failed to start"); - delete Thread; - return false; - } - Thread->AddClient(a_Socket, a_Client); - m_Threads.push_back(Thread); - return true; -} - - - - - -/* -void cSocketThreads::RemoveClient(const cSocket * a_Socket) -{ - // Remove the socket (and associated client) from processing - - cCSLock Lock(m_CS); - for (cSocketThreadList::iterator itr = m_Threads.begin(); itr != m_Threads.end(); ++itr) - { - if ((*itr)->RemoveSocket(a_Socket)) - { - return; - } - } // for itr - m_Threads[] - - // Cannot assert here, this may actually happen legally, since cClientHandle has to clean up the socket and it may have already closed in the meantime - // ASSERT(!"Removing an unknown socket"); -} -*/ - - - - - -void cSocketThreads::RemoveClient(const cCallback * a_Client) -{ - // Remove the associated socket and the client from processing - - cCSLock Lock(m_CS); - for (cSocketThreadList::iterator itr = m_Threads.begin(); itr != m_Threads.end(); ++itr) - { - if ((*itr)->RemoveClient(a_Client)) - { - return; - } - } // for itr - m_Threads[] - - ASSERT(!"Removing an unknown client"); -} - - - - - -void cSocketThreads::NotifyWrite(const cCallback * a_Client) -{ - // Notifies the thread responsible for a_Client that the client has something to write - - cCSLock Lock(m_CS); - for (cSocketThreadList::iterator itr = m_Threads.begin(); itr != m_Threads.end(); ++itr) - { - if ((*itr)->NotifyWrite(a_Client)) - { - return; - } - } // for itr - m_Threads[] - - // Cannot assert - this normally happens if a client disconnects and has pending packets, the cServer::cNotifyWriteThread will call this on invalid clients too - // ASSERT(!"Notifying write to an unknown client"); -} - - - - - -void cSocketThreads::Write(const cCallback * a_Client, const AString & a_Data) -{ - // Puts a_Data into outgoing data queue for a_Client - cCSLock Lock(m_CS); - for (cSocketThreadList::iterator itr = m_Threads.begin(); itr != m_Threads.end(); ++itr) - { - if ((*itr)->Write(a_Client, a_Data)) - { - return; - } - } // for itr - m_Threads[] - - // This may be perfectly legal, if the socket has been destroyed and the client is finishing up - // ASSERT(!"Writing to an unknown socket"); -} - - - - - -/// Stops reading from the socket - when this call returns, no more calls to the callbacks are made -void cSocketThreads::StopReading(const cCallback * a_Client) -{ - cCSLock Lock(m_CS); - for (cSocketThreadList::iterator itr = m_Threads.begin(); itr != m_Threads.end(); ++itr) - { - if ((*itr)->StopReading(a_Client)) - { - return; - } - } // for itr - m_Threads[] - - // Cannot assert, this normally happens if the socket is closed before the client deinitializes - // ASSERT(!"Stopping reading on an unknown client"); -} - - - - - -/// Queues the socket for closing, as soon as its outgoing data is sent -void cSocketThreads::QueueClose(const cCallback * a_Client) -{ - LOGD("QueueClose(client %p)", a_Client); - - cCSLock Lock(m_CS); - for (cSocketThreadList::iterator itr = m_Threads.begin(); itr != m_Threads.end(); ++itr) - { - if ((*itr)->QueueClose(a_Client)) - { - return; - } - } // for itr - m_Threads[] - - ASSERT(!"Queueing close of an unknown client"); -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cSocketThreads::cSocketThread: - -cSocketThreads::cSocketThread::cSocketThread(cSocketThreads * a_Parent) : - cIsThread("cSocketThread"), - m_Parent(a_Parent), - m_NumSlots(0) -{ - // Nothing needed yet -} - - - - - -cSocketThreads::cSocketThread::~cSocketThread() -{ - m_ShouldTerminate = true; - - // Notify the thread: - ASSERT(m_ControlSocket2.IsValid()); - m_ControlSocket2.Send("a", 1); - - // Wait for the thread to finish: - Wait(); - - // Close the control sockets: - m_ControlSocket1.CloseSocket(); - m_ControlSocket2.CloseSocket(); -} - - - - - -void cSocketThreads::cSocketThread::AddClient(const cSocket & a_Socket, cCallback * a_Client) -{ - ASSERT(m_NumSlots < MAX_SLOTS); // Use HasEmptySlot() to check before adding - - m_Slots[m_NumSlots].m_Client = a_Client; - m_Slots[m_NumSlots].m_Socket = a_Socket; - m_Slots[m_NumSlots].m_Outgoing.clear(); - m_Slots[m_NumSlots].m_ShouldClose = false; - m_Slots[m_NumSlots].m_ShouldCallClient = true; - m_NumSlots++; - - // Notify the thread of the change: - ASSERT(m_ControlSocket2.IsValid()); - m_ControlSocket2.Send("a", 1); -} - - - - - -bool cSocketThreads::cSocketThread::RemoveClient(const cCallback * a_Client) -{ - // Returns true if removed, false if not found - - if (m_NumSlots == 0) - { - return false; - } - - for (int i = m_NumSlots - 1; i >= 0 ; --i) - { - if (m_Slots[i].m_Client != a_Client) - { - continue; - } - - // Found, remove it: - m_Slots[i] = m_Slots[--m_NumSlots]; - - // Notify the thread of the change: - ASSERT(m_ControlSocket2.IsValid()); - m_ControlSocket2.Send("r", 1); - return true; - } // for i - m_Slots[] - - // Not found - return false; -} - - - - - -bool cSocketThreads::cSocketThread::RemoveSocket(const cSocket * a_Socket) -{ - // Returns true if removed, false if not found - - for (int i = m_NumSlots - 1; i >= 0 ; --i) - { - if (m_Slots[i].m_Socket != *a_Socket) - { - continue; - } - - // Found, remove it: - m_Slots[i] = m_Slots[--m_NumSlots]; - - // Notify the thread of the change: - ASSERT(m_ControlSocket2.IsValid()); - m_ControlSocket2.Send("r", 1); - return true; - } // for i - m_Slots[] - - // Not found - return false; -} - - - - - -bool cSocketThreads::cSocketThread::HasClient(const cCallback * a_Client) const -{ - for (int i = m_NumSlots - 1; i >= 0; --i) - { - if (m_Slots[i].m_Client == a_Client) - { - return true; - } - } // for i - m_Slots[] - return false; -} - - - - - -bool cSocketThreads::cSocketThread::HasSocket(const cSocket * a_Socket) const -{ - for (int i = m_NumSlots - 1; i >= 0; --i) - { - if (m_Slots[i].m_Socket == *a_Socket) - { - return true; - } - } // for i - m_Slots[] - return false; -} - - - - - -bool cSocketThreads::cSocketThread::NotifyWrite(const cCallback * a_Client) -{ - if (HasClient(a_Client)) - { - // Notify the thread that there's another packet in the queue: - ASSERT(m_ControlSocket2.IsValid()); - m_ControlSocket2.Send("q", 1); - return true; - } - return false; -} - - - - - -bool cSocketThreads::cSocketThread::Write(const cCallback * a_Client, const AString & a_Data) -{ - // Returns true if socket handled by this thread - for (int i = m_NumSlots - 1; i >= 0; --i) - { - if (m_Slots[i].m_Client == a_Client) - { - m_Slots[i].m_Outgoing.append(a_Data); - - // Notify the thread that there's data in the queue: - ASSERT(m_ControlSocket2.IsValid()); - m_ControlSocket2.Send("q", 1); - - return true; - } - } // for i - m_Slots[] - return false; -} - - - - - -bool cSocketThreads::cSocketThread::StopReading (const cCallback * a_Client) -{ - // Returns true if client handled by this thread - for (int i = m_NumSlots - 1; i >= 0; --i) - { - if (m_Slots[i].m_Client == a_Client) - { - m_Slots[i].m_ShouldCallClient = false; - return true; - } - } // for i - m_Slots[] - return false; -} - - - - - -bool cSocketThreads::cSocketThread::QueueClose(const cCallback * a_Client) -{ - // Returns true if socket handled by this thread - for (int i = m_NumSlots - 1; i >= 0; --i) - { - if (m_Slots[i].m_Client == a_Client) - { - m_Slots[i].m_ShouldClose = true; - - // Notify the thread that there's a close queued (in case its conditions are already met): - ASSERT(m_ControlSocket2.IsValid()); - m_ControlSocket2.Send("c", 1); - - return true; - } - } // for i - m_Slots[] - return false; -} - - - - - -bool cSocketThreads::cSocketThread::Start(void) -{ - // Create the control socket listener - m_ControlSocket2 = cSocket::CreateSocket(cSocket::IPv4); - if (!m_ControlSocket2.IsValid()) - { - LOGERROR("Cannot create a Control socket for a cSocketThread (\"%s\"); continuing, but server may be unreachable from now on.", cSocket::GetLastErrorString().c_str()); - return false; - } - if (!m_ControlSocket2.BindToLocalhostIPv4(cSocket::ANY_PORT)) - { - LOGERROR("Cannot bind a Control socket for a cSocketThread (\"%s\"); continuing, but server may be unreachable from now on.", cSocket::GetLastErrorString().c_str()); - m_ControlSocket2.CloseSocket(); - return false; - } - if (!m_ControlSocket2.Listen(1)) - { - LOGERROR("Cannot listen on a Control socket for a cSocketThread (\"%s\"); continuing, but server may be unreachable from now on.", cSocket::GetLastErrorString().c_str()); - m_ControlSocket2.CloseSocket(); - return false; - } - if (m_ControlSocket2.GetPort() == 0) - { - LOGERROR("Cannot determine Control socket port (\"%s\"); conitnuing, but the server may be unreachable from now on.", cSocket::GetLastErrorString().c_str()); - m_ControlSocket2.CloseSocket(); - return false; - } - - // Start the thread - if (!super::Start()) - { - LOGERROR("Cannot start new cSocketThread"); - m_ControlSocket2.CloseSocket(); - return false; - } - - // Finish connecting the control socket by accepting connection from the thread's socket - cSocket tmp = m_ControlSocket2.AcceptIPv4(); - if (!tmp.IsValid()) - { - LOGERROR("Cannot link Control sockets for a cSocketThread (\"%s\"); continuing, but server may be unreachable from now on.", cSocket::GetLastErrorString().c_str()); - m_ControlSocket2.CloseSocket(); - return false; - } - m_ControlSocket2.CloseSocket(); - m_ControlSocket2 = tmp; - - return true; -} - - - - - -void cSocketThreads::cSocketThread::Execute(void) -{ - // Connect the "client" part of the Control socket: - m_ControlSocket1 = cSocket::CreateSocket(cSocket::IPv4); - ASSERT(m_ControlSocket2.GetPort() != 0); // We checked in the Start() method, but let's be sure - if (!m_ControlSocket1.ConnectToLocalhostIPv4(m_ControlSocket2.GetPort())) - { - LOGERROR("Cannot connect Control sockets for a cSocketThread (\"%s\"); continuing, but the server may be unreachable from now on.", cSocket::GetLastErrorString().c_str()); - m_ControlSocket2.CloseSocket(); - return; - } - - // The main thread loop: - while (!m_ShouldTerminate) - { - // Put all sockets into the Read set: - fd_set fdRead; - cSocket::xSocket Highest = m_ControlSocket1.GetSocket(); - - PrepareSet(&fdRead, Highest); - - // Wait for the sockets: - if (select(Highest + 1, &fdRead, NULL, NULL, NULL) == -1) - { - LOG("select(R) call failed in cSocketThread: \"%s\"", cSocket::GetLastErrorString().c_str()); - continue; - } - - ReadFromSockets(&fdRead); - - // Test sockets for writing: - fd_set fdWrite; - Highest = m_ControlSocket1.GetSocket(); - PrepareSet(&fdWrite, Highest); - timeval Timeout; - Timeout.tv_sec = 0; - Timeout.tv_usec = 0; - if (select(Highest + 1, NULL, &fdWrite, NULL, &Timeout) == -1) - { - LOG("select(W) call failed in cSocketThread: \"%s\"", cSocket::GetLastErrorString().c_str()); - continue; - } - - WriteToSockets(&fdWrite); - } // while (!mShouldTerminate) -} - - - - - -void cSocketThreads::cSocketThread::PrepareSet(fd_set * a_Set, cSocket::xSocket & a_Highest) -{ - FD_ZERO(a_Set); - FD_SET(m_ControlSocket1.GetSocket(), a_Set); - - cCSLock Lock(m_Parent->m_CS); - for (int i = m_NumSlots - 1; i >= 0; --i) - { - if (!m_Slots[i].m_Socket.IsValid()) - { - continue; - } - cSocket::xSocket s = m_Slots[i].m_Socket.GetSocket(); - FD_SET(s, a_Set); - if (s > a_Highest) - { - a_Highest = s; - } - } // for i - m_Slots[] -} - - - - - -void cSocketThreads::cSocketThread::ReadFromSockets(fd_set * a_Read) -{ - // Read on available sockets: - - // Reset Control socket state: - if (FD_ISSET(m_ControlSocket1.GetSocket(), a_Read)) - { - char Dummy[128]; - m_ControlSocket1.Receive(Dummy, sizeof(Dummy), 0); - } - - // Read from clients: - cCSLock Lock(m_Parent->m_CS); - for (int i = m_NumSlots - 1; i >= 0; --i) - { - cSocket::xSocket Socket = m_Slots[i].m_Socket.GetSocket(); - if (!cSocket::IsValidSocket(Socket) || !FD_ISSET(Socket, a_Read)) - { - continue; - } - char Buffer[1024]; - int Received = m_Slots[i].m_Socket.Receive(Buffer, ARRAYCOUNT(Buffer), 0); - if (Received == 0) - { - // The socket has been closed by the remote party, close our socket and let it be removed after we process all reading - m_Slots[i].m_Socket.CloseSocket(); - if (m_Slots[i].m_ShouldCallClient) - { - m_Slots[i].m_Client->SocketClosed(); - } - } - else if (Received > 0) - { - if (m_Slots[i].m_ShouldCallClient) - { - m_Slots[i].m_Client->DataReceived(Buffer, Received); - } - } - else - { - // The socket has encountered an error, close it and let it be removed after we process all reading - m_Slots[i].m_Socket.CloseSocket(); - if (m_Slots[i].m_ShouldCallClient) - { - m_Slots[i].m_Client->SocketClosed(); - } - } - } // for i - m_Slots[] -} - - - - - -void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write) -{ - // Write to available client sockets: - cCSLock Lock(m_Parent->m_CS); - for (int i = m_NumSlots - 1; i >= 0; --i) - { - cSocket::xSocket Socket = m_Slots[i].m_Socket.GetSocket(); - if (!cSocket::IsValidSocket(Socket) || !FD_ISSET(Socket, a_Write)) - { - continue; - } - if (m_Slots[i].m_Outgoing.empty()) - { - // Request another chunk of outgoing data: - if (m_Slots[i].m_ShouldCallClient) - { - m_Slots[i].m_Client->GetOutgoingData(m_Slots[i].m_Outgoing); - } - if (m_Slots[i].m_Outgoing.empty()) - { - // Nothing ready - if (m_Slots[i].m_ShouldClose) - { - // Socket was queued for closing and there's no more data to send, close it now: - - // DEBUG - LOGD("Socket was queued for closing, closing now. Slot %d, client %p, socket %d", i, m_Slots[i].m_Client, m_Slots[i].m_Socket.GetSocket()); - - m_Slots[i].m_Socket.CloseSocket(); - // The slot must be freed actively by the client, using RemoveClient() - } - continue; - } - } // if (outgoing data is empty) - - int Sent = m_Slots[i].m_Socket.Send(m_Slots[i].m_Outgoing.data(), m_Slots[i].m_Outgoing.size()); - if (Sent < 0) - { - int Err = cSocket::GetLastError(); - LOGWARNING("Error %d while writing to client \"%s\", disconnecting. \"%s\"", Err, m_Slots[i].m_Socket.GetIPString().c_str(), cSocket::GetErrorString(Err).c_str()); - m_Slots[i].m_Socket.CloseSocket(); - if (m_Slots[i].m_ShouldCallClient) - { - m_Slots[i].m_Client->SocketClosed(); - } - return; - } - m_Slots[i].m_Outgoing.erase(0, Sent); - - // _X: If there's data left, it means the client is not reading fast enough, the server would unnecessarily spin in the main loop with zero actions taken; so signalling is disabled - // This means that if there's data left, it will be sent only when there's incoming data or someone queues another packet (for any socket handled by this thread) - /* - // If there's any data left, signalize the Control socket: - if (!m_Slots[i].m_Outgoing.empty()) - { - ASSERT(m_ControlSocket2.IsValid()); - m_ControlSocket2.Send("q", 1); - } - */ - } // for i - m_Slots[i] -} - - - - diff --git a/source/OSSupport/SocketThreads.h b/source/OSSupport/SocketThreads.h deleted file mode 100644 index ecbac3aeb..000000000 --- a/source/OSSupport/SocketThreads.h +++ /dev/null @@ -1,169 +0,0 @@ - -// SocketThreads.h - -// Interfaces to the cSocketThreads class representing the heart of MCS's client networking. -// This object takes care of network communication, groups sockets into threads and uses as little threads as possible for full read / write support -// For more detail, see http://forum.mc-server.org/showthread.php?tid=327 - -/* -Additional details: -When a client is terminating a connection: -- they call the StopReading() method to disable callbacks for the incoming data -- they call the Write() method to queue any outstanding outgoing data -- they call the QueueClose() method to queue the socket to close after outgoing data has been sent. -When a socket slot is marked as having no callback, it is kept alive until its outgoing data queue is empty and its m_ShouldClose flag is set. -This means that the socket can be written to several times before finally closing it via QueueClose() -*/ - - - - - -/// How many clients should one thread handle? (must be less than FD_SETSIZE for your platform) -#define MAX_SLOTS 63 - - - - - -#pragma once -#ifndef CSOCKETTHREADS_H_INCLUDED -#define CSOCKETTHREADS_H_INCLUDED - -#include "Socket.h" -#include "IsThread.h" - - - - -// Check MAX_SLOTS: -#if MAX_SLOTS >= FD_SETSIZE - #error "MAX_SLOTS must be less than FD_SETSIZE for your platform! (otherwise select() won't work)" -#endif - - - - - -// fwd: -class cSocket; -class cClientHandle; - - - - - -class cSocketThreads -{ -public: - - // Clients of cSocketThreads must implement this interface to be able to communicate - class cCallback - { - public: - /// Called when data is received from the remote party - virtual void DataReceived(const char * a_Data, int a_Size) = 0; - - /// Called when data can be sent to remote party; the function is supposed to append outgoing data to a_Data - virtual void GetOutgoingData(AString & a_Data) = 0; - - /// Called when the socket has been closed for any reason - virtual void SocketClosed(void) = 0; - } ; - - - cSocketThreads(void); - ~cSocketThreads(); - - /// Add a (socket, client) pair for processing, data from a_Socket is to be sent to a_Client; returns true if successful - bool AddClient(const cSocket & a_Socket, cCallback * a_Client); - - /// Remove the associated socket and the client from processing. The socket is left to send its data and is removed only after all its m_OutgoingData is sent - void RemoveClient(const cCallback * a_Client); - - /// Notify the thread responsible for a_Client that the client has something to write - void NotifyWrite(const cCallback * a_Client); - - /// Puts a_Data into outgoing data queue for a_Client - void Write(const cCallback * a_Client, const AString & a_Data); - - /// Stops reading from the client - when this call returns, no more calls to the callbacks are made - void StopReading(const cCallback * a_Client); - - /// Queues the client for closing, as soon as its outgoing data is sent - void QueueClose(const cCallback * a_Client); - -private: - - class cSocketThread : - public cIsThread - { - typedef cIsThread super; - - public: - - cSocketThread(cSocketThreads * a_Parent); - ~cSocketThread(); - - // All these methods assume parent's m_CS is locked - bool HasEmptySlot(void) const {return m_NumSlots < MAX_SLOTS; } - bool IsEmpty (void) const {return m_NumSlots == 0; } - - void AddClient (const cSocket & a_Socket, cCallback * a_Client); // Takes ownership of the socket - bool RemoveClient(const cCallback * a_Client); // Returns true if removed, false if not found - bool RemoveSocket(const cSocket * a_Socket); // Returns true if removed, false if not found - bool HasClient (const cCallback * a_Client) const; - bool HasSocket (const cSocket * a_Socket) const; - bool NotifyWrite (const cCallback * a_Client); // Returns true if client handled by this thread - bool Write (const cCallback * a_Client, const AString & a_Data); // Returns true if client handled by this thread - bool StopReading (const cCallback * a_Client); // Returns true if client handled by this thread - bool QueueClose (const cCallback * a_Client); // Returns true if client handled by this thread - - bool Start(void); // Hide the cIsThread's Start method, we need to provide our own startup to create the control socket - - bool IsValid(void) const {return m_ControlSocket2.IsValid(); } // If the Control socket dies, the thread is not valid anymore - - private: - - cSocketThreads * m_Parent; - - // Two ends of the control socket, the first is select()-ed, the second is written to for notifications - cSocket m_ControlSocket1; - cSocket m_ControlSocket2; - - // Socket-client-packetqueues triplets. - // Manipulation with these assumes that the parent's m_CS is locked - struct sSlot - { - cSocket m_Socket; // The socket is primarily owned by this - cCallback * m_Client; - AString m_Outgoing; // If sending writes only partial data, the rest is stored here for another send - bool m_ShouldClose; // If true, the socket is to be closed after sending all outgoing data - bool m_ShouldCallClient; // If true, the client callbacks are called. Set to false in StopReading() - } ; - sSlot m_Slots[MAX_SLOTS]; - int m_NumSlots; // Number of slots actually used - - virtual void Execute(void) override; - - void PrepareSet (fd_set * a_Set, cSocket::xSocket & a_Highest); // Puts all sockets into the set, along with m_ControlSocket1 - void ReadFromSockets(fd_set * a_Read); // Reads from sockets indicated in a_Read - void WriteToSockets (fd_set * a_Write); // Writes to sockets indicated in a_Write - } ; - - typedef std::list<cSocketThread *> cSocketThreadList; - - - cCriticalSection m_CS; - cSocketThreadList m_Threads; -} ; - - - - - -#endif // CSOCKETTHREADS_H_INCLUDED - - - - diff --git a/source/OSSupport/Thread.cpp b/source/OSSupport/Thread.cpp deleted file mode 100644 index 3df75f0e7..000000000 --- a/source/OSSupport/Thread.cpp +++ /dev/null @@ -1,128 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - - - - - -// When in MSVC, the debugger provides "thread naming" by catching special exceptions. Interface here: -#ifdef _MSC_VER -// -// Usage: SetThreadName (-1, "MainThread"); -// -typedef struct tagTHREADNAME_INFO -{ - DWORD dwType; // must be 0x1000 - LPCSTR szName; // pointer to name (in user addr space) - DWORD dwThreadID; // thread ID (-1=caller thread) - DWORD dwFlags; // reserved for future use, must be zero -} THREADNAME_INFO; - -void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName) -{ - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = szThreadName; - info.dwThreadID = dwThreadID; - info.dwFlags = 0; - - __try - { - RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info ); - } - __except(EXCEPTION_CONTINUE_EXECUTION) - { - } -} -#endif // _MSC_VER - - - - - -cThread::cThread( ThreadFunc a_ThreadFunction, void* a_Param, const char* a_ThreadName /* = 0 */ ) - : m_ThreadFunction( a_ThreadFunction ) - , m_Param( a_Param ) - , m_Event( new cEvent() ) - , m_StopEvent( 0 ) -{ - if( a_ThreadName ) - { - m_ThreadName.assign(a_ThreadName); - } -} - - - - - -cThread::~cThread() -{ - delete m_Event; - - if( m_StopEvent ) - { - m_StopEvent->Wait(); - delete m_StopEvent; - } -} - - - - - -void cThread::Start( bool a_bWaitOnDelete /* = true */ ) -{ - if( a_bWaitOnDelete ) - m_StopEvent = new cEvent(); - -#ifndef _WIN32 - pthread_t SndThread; - if( pthread_create( &SndThread, NULL, MyThread, this) ) - LOGERROR("ERROR: Could not create thread!"); -#else - DWORD ThreadID = 0; - HANDLE hThread = CreateThread( 0 // security - ,0 // stack size - , (LPTHREAD_START_ROUTINE) MyThread // function name - ,this // parameters - ,0 // flags - ,&ThreadID ); // thread id - CloseHandle( hThread ); - - #ifdef _MSC_VER - if (!m_ThreadName.empty()) - { - SetThreadName(ThreadID, m_ThreadName.c_str()); - } - #endif // _MSC_VER -#endif - - // Wait until thread has actually been created - m_Event->Wait(); -} - - - - - -#ifdef _WIN32 -unsigned long cThread::MyThread(void* a_Param ) -#else -void *cThread::MyThread( void *a_Param ) -#endif -{ - cThread* self = (cThread*)a_Param; - cEvent* StopEvent = self->m_StopEvent; - - ThreadFunc* ThreadFunction = self->m_ThreadFunction; - void* ThreadParam = self->m_Param; - - // Set event to let other thread know this thread has been created and it's safe to delete the cThread object - self->m_Event->Set(); - - ThreadFunction( ThreadParam ); - - if( StopEvent ) StopEvent->Set(); - return 0; -} diff --git a/source/OSSupport/Thread.h b/source/OSSupport/Thread.h deleted file mode 100644 index 3c9316424..000000000 --- a/source/OSSupport/Thread.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -class cThread -{ -public: - typedef void (ThreadFunc)(void*); - cThread( ThreadFunc a_ThreadFunction, void* a_Param, const char* a_ThreadName = 0 ); - ~cThread(); - - void Start( bool a_bWaitOnDelete = true ); - void WaitForThread(); -private: - ThreadFunc* m_ThreadFunction; - -#ifdef _WIN32 - static unsigned long MyThread(void* a_Param ); -#else - static void *MyThread( void *lpParam ); -#endif - - void* m_Param; - cEvent* m_Event; - cEvent* m_StopEvent; - - AString m_ThreadName; -};
\ No newline at end of file diff --git a/source/OSSupport/Timer.cpp b/source/OSSupport/Timer.cpp deleted file mode 100644 index ed16f9e3a..000000000 --- a/source/OSSupport/Timer.cpp +++ /dev/null @@ -1,37 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "Timer.h" - - - - - - -cTimer::cTimer(void) -{ - #ifdef _WIN32 - QueryPerformanceFrequency(&m_TicksPerSecond); - #endif -} - - - - - -long long cTimer::GetNowTime(void) -{ - #ifdef _WIN32 - LARGE_INTEGER now; - QueryPerformanceCounter(&now); - return ((now.QuadPart * 1000) / m_TicksPerSecond.QuadPart); - #else - struct timeval now; - gettimeofday(&now, NULL); - return (long long)(now.tv_sec * 1000 + now.tv_usec / 1000); - #endif -} - - - - diff --git a/source/OSSupport/Timer.h b/source/OSSupport/Timer.h deleted file mode 100644 index a059daa41..000000000 --- a/source/OSSupport/Timer.h +++ /dev/null @@ -1,32 +0,0 @@ - -// Timer.h - -// Declares the cTimer class representing an OS-independent of retrieving current time with msec accuracy - - - - - -#pragma once - - - - - -class cTimer -{ -public: - cTimer(void); - - // Returns the current time expressed in milliseconds - long long GetNowTime(void); -private: - - #ifdef _WIN32 - LARGE_INTEGER m_TicksPerSecond; - #endif -} ; - - - - |