ilk commit
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
template <typename T>
|
||||
class Atomic
|
||||
{
|
||||
public:
|
||||
Atomic() {}
|
||||
Atomic(T value) : m_atomic(value) {}
|
||||
|
||||
operator T() { return (T) m_atomic; }
|
||||
|
||||
INLINE Atomic<T>& operator++() { increment(); return *this; }
|
||||
INLINE Atomic<T>& operator--() { decrement(); return *this; }
|
||||
|
||||
// NOTE: The following operators should only be used if it can't be helped.
|
||||
#define ATOMIC_COMPARISON(op) \
|
||||
template <typename T2> \
|
||||
INLINE friend bool operator op (Atomic<T>& lhs, const T2 rhs) { return lhs.m_atomic op rhs; }
|
||||
|
||||
// Hide signed/unsigned comparison warning.
|
||||
// It's only valid on VS2010, when the type is always long (so, signed).
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4018)
|
||||
|
||||
ATOMIC_COMPARISON(>)
|
||||
ATOMIC_COMPARISON(>=)
|
||||
ATOMIC_COMPARISON(<)
|
||||
ATOMIC_COMPARISON(<=)
|
||||
ATOMIC_COMPARISON(==)
|
||||
ATOMIC_COMPARISON(!=)
|
||||
|
||||
#pragma warning(pop)
|
||||
#undef ATOMIC_COMPARISON
|
||||
|
||||
template <typename T2> INLINE Atomic<T>& operator=(const T2& rhs) { m_atomic = rhs; return *this; }
|
||||
template <typename T2> INLINE Atomic<T>& operator+=(const T2 rhs) { m_atomic += rhs; return *this; }
|
||||
template <typename T2> INLINE Atomic<T>& operator-=(const T2 rhs) { m_atomic -= rhs; return *this; }
|
||||
|
||||
INLINE T increment() { return ++m_atomic; }
|
||||
INLINE T decrement() { return --m_atomic; }
|
||||
|
||||
INLINE bool compare_exchange(T & expected, T desired) { return m_atomic.compare_exchange_strong(expected, desired); }
|
||||
|
||||
protected:
|
||||
std::atomic<T> m_atomic;
|
||||
|
||||
private:
|
||||
Atomic(const Atomic & other); /* disable copy constructor */
|
||||
};
|
||||
@@ -0,0 +1,175 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
class ByteBuffer
|
||||
{
|
||||
public:
|
||||
const static size_t DEFAULT_SIZE = 32;
|
||||
bool m_doubleByte;
|
||||
|
||||
ByteBuffer(): _rpos(0), _wpos(0), m_doubleByte(true) { _storage.reserve(DEFAULT_SIZE); }
|
||||
ByteBuffer(size_t res): _rpos(0), _wpos(0), m_doubleByte(true) { _storage.reserve(res <= 0 ? DEFAULT_SIZE : res); }
|
||||
ByteBuffer(const ByteBuffer &buf): _rpos(buf._rpos), _wpos(buf._wpos), _storage(buf._storage) { }
|
||||
virtual ~ByteBuffer() {}
|
||||
|
||||
void clear()
|
||||
{
|
||||
_storage.clear();
|
||||
_rpos = _wpos = 0;
|
||||
}
|
||||
|
||||
template <typename T> void append(T value) { append((uint8 *)&value, sizeof(value)); }
|
||||
template <typename T> void put(size_t pos,T value) { put(pos,(uint8 *)&value, sizeof(value)); }
|
||||
|
||||
// stream like operators for storing data
|
||||
ByteBuffer &operator<<(bool value) { append<char>((char)value); return *this; }
|
||||
|
||||
// unsigned
|
||||
ByteBuffer &operator<<(uint8 value) { append<uint8> (value); return *this; }
|
||||
ByteBuffer &operator<<(uint16 value) { append<uint16>(value); return *this; }
|
||||
ByteBuffer &operator<<(uint32 value) { append<uint32>(value); return *this; }
|
||||
ByteBuffer &operator<<(uint64 value) { append<uint64>(value); return *this; }
|
||||
// signed as in 2e complement
|
||||
ByteBuffer &operator<<(int8 value) { append<int8> (value); return *this; }
|
||||
ByteBuffer &operator<<(int16 value) { append<int16>(value); return *this; }
|
||||
ByteBuffer &operator<<(int32 value) { append<int32>(value); return *this; }
|
||||
ByteBuffer &operator<<(int64 value) { append<int64>(value); return *this; }
|
||||
ByteBuffer &operator<<(float value) { append<float>(value); return *this; }
|
||||
|
||||
ByteBuffer &operator<<(ByteBuffer &value)
|
||||
{
|
||||
if (value.wpos())
|
||||
append(value.contents(), value.wpos());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// stream like operators for reading data
|
||||
ByteBuffer &operator>>(bool &value) { value = read<char>() > 0 ? true : false; return *this; }
|
||||
// unsigned
|
||||
ByteBuffer &operator>>(uint8 &value) { value = read<uint8>(); return *this; }
|
||||
ByteBuffer &operator>>(uint16 &value) { value = read<uint16>(); return *this; }
|
||||
ByteBuffer &operator>>(uint32 &value) { value = read<uint32>(); return *this; }
|
||||
ByteBuffer &operator>>(uint64 &value) { value = read<uint64>(); return *this; }
|
||||
// signed as in 2e complement
|
||||
ByteBuffer &operator>>(int8 &value) { value = read<int8>(); return *this; }
|
||||
ByteBuffer &operator>>(int16 &value) { value = read<int16>(); return *this; }
|
||||
ByteBuffer &operator>>(int32 &value) { value = read<int32>(); return *this; }
|
||||
ByteBuffer &operator>>(int64 &value) { value = read<int64>(); return *this; }
|
||||
ByteBuffer &operator>>(float &value) { value = read<float>(); return *this; }
|
||||
|
||||
// Hacky KO string flag - either it's a single byte length, or a double byte.
|
||||
void SByte() { m_doubleByte = false; }
|
||||
void DByte() { m_doubleByte = true; }
|
||||
|
||||
ByteBuffer &operator<<(const std::string &value) { *this << value.c_str(); return *this; }
|
||||
ByteBuffer &operator<<(std::string &value) { *this << value.c_str(); return *this; }
|
||||
ByteBuffer &operator<<(const char *str)
|
||||
{
|
||||
uint16 len = (uint16)strlen(str);
|
||||
if (m_doubleByte)
|
||||
append((uint8*)&len, 2);
|
||||
else
|
||||
append((uint8*)&len, 1);
|
||||
append((uint8 *)str, len);
|
||||
return *this;
|
||||
}
|
||||
ByteBuffer &operator<<(char *str) { *this << (const char*)str; return *this; }
|
||||
|
||||
ByteBuffer &operator>>(std::string& value)
|
||||
{
|
||||
uint16 len;
|
||||
value.clear();
|
||||
if (m_doubleByte)
|
||||
len = read<uint16>();
|
||||
else
|
||||
len = read<uint8>();
|
||||
|
||||
if (_rpos + len <= size())
|
||||
{
|
||||
for (uint16 i = 0; i < len; i++)
|
||||
value.push_back(read<char>());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint8 operator[](size_t pos) { return read<uint8>(pos); }
|
||||
|
||||
INLINE size_t rpos() { return _rpos; };
|
||||
INLINE size_t rpos(size_t rpos) { return _rpos = rpos; };
|
||||
INLINE size_t wpos() { return _wpos; };
|
||||
INLINE size_t wpos(size_t wpos) { return _wpos = wpos; };
|
||||
|
||||
template <typename T> T read()
|
||||
{
|
||||
T r = read<T>(_rpos);
|
||||
_rpos += sizeof(T);
|
||||
return r;
|
||||
};
|
||||
|
||||
template <typename T> T read(size_t pos) const
|
||||
{
|
||||
//ASSERT(pos + sizeof(T) <= size());
|
||||
if (pos + sizeof(T) > size())
|
||||
return (T)0;
|
||||
return *((T*)&_storage[pos]);
|
||||
};
|
||||
|
||||
void read(void *dest, size_t len)
|
||||
{
|
||||
if (_rpos + len <= size())
|
||||
memcpy(dest, &_storage[_rpos], len);
|
||||
else // throw error();
|
||||
memset(dest, 0, len);
|
||||
_rpos += len;
|
||||
};
|
||||
|
||||
const uint8 *contents() const { return &_storage[0]; };
|
||||
INLINE size_t size() const { return _storage.size(); };
|
||||
|
||||
// one should never use resize
|
||||
void resize(size_t newsize)
|
||||
{
|
||||
_storage.resize(newsize);
|
||||
_rpos = 0;
|
||||
_wpos = size();
|
||||
};
|
||||
|
||||
void reserve(size_t ressize) { if (ressize > size()) _storage.reserve(ressize); };
|
||||
|
||||
// append to the end of buffer
|
||||
void append(const std::string& str) { append((uint8 *)str.c_str(),str.size() + 1); }
|
||||
void append(const char *src, size_t cnt) { return append((const uint8 *)src, cnt); }
|
||||
void append(const void *src, size_t cnt)
|
||||
{
|
||||
if (!cnt)
|
||||
return;
|
||||
|
||||
// 10MB is far more than you'll ever need.
|
||||
ASSERT(size() < 10000000);
|
||||
|
||||
if (_storage.size() < _wpos + cnt)
|
||||
_storage.resize(_wpos + cnt);
|
||||
|
||||
memcpy(&_storage[_wpos], src, cnt);
|
||||
_wpos += cnt;
|
||||
}
|
||||
|
||||
void append(const ByteBuffer& buffer) { if (buffer.size() > 0) append(buffer.contents(), buffer.size()); }
|
||||
void append(const ByteBuffer& buffer, size_t len)
|
||||
{
|
||||
ASSERT(buffer._rpos + len <= buffer.size());
|
||||
append(buffer.contents() + buffer._rpos, len);
|
||||
}
|
||||
|
||||
void put(size_t pos, const void *src, size_t cnt)
|
||||
{
|
||||
ASSERT(pos + cnt <= size());
|
||||
memcpy(&_storage[pos], src, cnt);
|
||||
}
|
||||
|
||||
protected:
|
||||
// read and write positions
|
||||
size_t _rpos, _wpos;
|
||||
std::vector<uint8> _storage;
|
||||
};
|
||||
@@ -0,0 +1,258 @@
|
||||
#include "stdafx.h"
|
||||
#include "CircularBuffer.h"
|
||||
|
||||
/** Constructor
|
||||
*/
|
||||
CircularBuffer::CircularBuffer()
|
||||
{
|
||||
m_buffer = m_bufferEnd = m_regionAPointer = m_regionBPointer = nullptr;
|
||||
m_regionASize = m_regionBSize = 0;
|
||||
}
|
||||
|
||||
/** Destructor
|
||||
*/
|
||||
CircularBuffer::~CircularBuffer()
|
||||
{
|
||||
free(m_buffer);
|
||||
}
|
||||
|
||||
/** Read bytes from the buffer
|
||||
* @param destination pointer to destination where bytes will be written
|
||||
* @param bytes number of bytes to read
|
||||
* @return true if there was enough data, false otherwise
|
||||
*/
|
||||
bool CircularBuffer::Read(void * destination, size_t bytes)
|
||||
{
|
||||
// copy as much out of region a
|
||||
size_t cnt = bytes;
|
||||
size_t aRead = 0, bRead = 0;
|
||||
if( (m_regionASize + m_regionBSize) < bytes )
|
||||
return false;
|
||||
|
||||
// If we have both region A and region B, always "finish" off region A first, as
|
||||
// this will contain the "oldest" data
|
||||
if( m_regionASize > 0 )
|
||||
{
|
||||
aRead = (cnt > m_regionASize) ? m_regionASize : cnt;
|
||||
memcpy(destination, m_regionAPointer, aRead);
|
||||
m_regionASize -= aRead;
|
||||
m_regionAPointer += aRead;
|
||||
cnt -= aRead;
|
||||
}
|
||||
|
||||
// Data left over? read the data from buffer B
|
||||
if( cnt > 0 && m_regionBSize > 0 )
|
||||
{
|
||||
bRead = (cnt > m_regionBSize) ? m_regionBSize : cnt;
|
||||
memcpy((char*)destination + aRead, m_regionBPointer, bRead);
|
||||
m_regionBSize -= bRead;
|
||||
m_regionBPointer += bRead;
|
||||
cnt -= bRead;
|
||||
}
|
||||
|
||||
// is buffer A empty? move buffer B to buffer A, to increase future performance
|
||||
if( m_regionASize == 0 )
|
||||
{
|
||||
if( m_regionBSize > 0 )
|
||||
{
|
||||
// push it all to the start of the buffer.
|
||||
if( m_regionBPointer != m_buffer )
|
||||
memmove(m_buffer, m_regionBPointer, m_regionBSize);
|
||||
|
||||
m_regionAPointer = m_buffer;
|
||||
m_regionASize = m_regionBSize;
|
||||
m_regionBPointer = nullptr;
|
||||
m_regionBSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no data in region b
|
||||
m_regionBPointer = nullptr;
|
||||
m_regionBSize = 0;
|
||||
m_regionAPointer = m_buffer;
|
||||
m_regionASize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CircularBuffer::AllocateB()
|
||||
{
|
||||
//printf("[allocating B]\n");
|
||||
m_regionBPointer = m_buffer;
|
||||
}
|
||||
|
||||
/** Write bytes to the buffer
|
||||
* @param data pointer to the data to be written
|
||||
* @param bytes number of bytes to be written
|
||||
* @return true if was successful, otherwise false
|
||||
*/
|
||||
bool CircularBuffer::Write(const void * data, size_t bytes)
|
||||
{
|
||||
// If buffer B exists, write to it.
|
||||
if( m_regionBPointer != nullptr )
|
||||
{
|
||||
if( GetBFreeSpace() < bytes )
|
||||
return false;
|
||||
|
||||
memcpy(&m_regionBPointer[m_regionBSize], data, bytes);
|
||||
m_regionBSize += bytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, write to buffer A, or initialize buffer B depending on which has more space.
|
||||
if( GetAFreeSpace() < GetSpaceBeforeA() )
|
||||
{
|
||||
AllocateB();
|
||||
if( GetBFreeSpace() < bytes )
|
||||
return false;
|
||||
|
||||
memcpy(&m_regionBPointer[m_regionBSize], data, bytes);
|
||||
m_regionBSize += bytes;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( GetAFreeSpace() < bytes )
|
||||
return false;
|
||||
|
||||
memcpy(&m_regionAPointer[m_regionASize], data, bytes);
|
||||
m_regionASize += bytes;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the number of available bytes left.
|
||||
*/
|
||||
size_t CircularBuffer::GetSpace()
|
||||
{
|
||||
if( m_regionBPointer != nullptr )
|
||||
return GetBFreeSpace();
|
||||
else
|
||||
{
|
||||
// would allocating buffer B get us more data?
|
||||
if( GetAFreeSpace() < GetSpaceBeforeA() )
|
||||
{
|
||||
AllocateB();
|
||||
return GetBFreeSpace();
|
||||
}
|
||||
|
||||
// or not?
|
||||
return GetAFreeSpace();
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the number of bytes currently stored in the buffer.
|
||||
*/
|
||||
size_t CircularBuffer::GetSize()
|
||||
{
|
||||
return m_regionASize + m_regionBSize;
|
||||
}
|
||||
|
||||
/** Returns the number of contiguous bytes (that can be pushed out in one operation)
|
||||
*/
|
||||
size_t CircularBuffer::GetContiguousBytes()
|
||||
{
|
||||
if( m_regionASize ) // A before B
|
||||
return m_regionASize;
|
||||
else
|
||||
return m_regionBSize;
|
||||
}
|
||||
|
||||
/** Removes len bytes from the front of the buffer
|
||||
* @param len the number of bytes to "cut"
|
||||
*/
|
||||
void CircularBuffer::Remove(size_t len)
|
||||
{
|
||||
// remove from A first before we remove from b
|
||||
size_t cnt = len;
|
||||
size_t aRem, bRem;
|
||||
|
||||
// If we have both region A and region B, always "finish" off region A first, as
|
||||
// this will contain the "oldest" data
|
||||
if( m_regionASize > 0 )
|
||||
{
|
||||
aRem = (cnt > m_regionASize) ? m_regionASize : cnt;
|
||||
m_regionASize -= aRem;
|
||||
m_regionAPointer += aRem;
|
||||
cnt -= aRem;
|
||||
}
|
||||
|
||||
// Data left over? cut the data from buffer B
|
||||
if( cnt > 0 && m_regionBSize > 0 )
|
||||
{
|
||||
bRem = (cnt > m_regionBSize) ? m_regionBSize : cnt;
|
||||
m_regionBSize -= bRem;
|
||||
m_regionBPointer += bRem;
|
||||
cnt -= bRem;
|
||||
}
|
||||
|
||||
// is buffer A empty? move buffer B to buffer A, to increase future performance
|
||||
if( m_regionASize == 0 )
|
||||
{
|
||||
if( m_regionBSize > 0 )
|
||||
{
|
||||
// push it all to the start of the buffer.
|
||||
if( m_regionBPointer != m_buffer )
|
||||
memmove(m_buffer, m_regionBPointer, m_regionBSize);
|
||||
|
||||
m_regionAPointer = m_buffer;
|
||||
m_regionASize = m_regionBSize;
|
||||
m_regionBPointer = nullptr;
|
||||
m_regionBSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no data in region b
|
||||
m_regionBPointer = nullptr;
|
||||
m_regionBSize = 0;
|
||||
m_regionAPointer = m_buffer;
|
||||
m_regionASize = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a pointer at the "end" of the buffer, where new data can be written
|
||||
*/
|
||||
void * CircularBuffer::GetBuffer()
|
||||
{
|
||||
if( m_regionBPointer != nullptr )
|
||||
return m_regionBPointer + m_regionBSize;
|
||||
else
|
||||
return m_regionAPointer + m_regionASize;
|
||||
}
|
||||
|
||||
/** Allocate the buffer with room for size bytes
|
||||
* @param size the number of bytes to allocate
|
||||
*/
|
||||
void CircularBuffer::Allocate(size_t size)
|
||||
{
|
||||
m_buffer = (uint8*)malloc(size);
|
||||
m_bufferEnd = m_buffer + size;
|
||||
m_regionAPointer = m_buffer; // reset A to the start
|
||||
m_bufferSize = size;
|
||||
}
|
||||
|
||||
/** Increments the "writen" pointer forward len bytes
|
||||
* @param len number of bytes to step
|
||||
*/
|
||||
void CircularBuffer::IncrementWritten(size_t len) // known as "commit"
|
||||
{
|
||||
if( m_regionBPointer != nullptr )
|
||||
m_regionBSize += len;
|
||||
else
|
||||
m_regionASize += len;
|
||||
|
||||
}
|
||||
|
||||
/** Returns a pointer at the "beginning" of the buffer, where data can be pulled from
|
||||
*/
|
||||
void * CircularBuffer::GetBufferStart()
|
||||
{
|
||||
if( m_regionASize > 0 )
|
||||
return m_regionAPointer;
|
||||
else
|
||||
return m_regionBPointer;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
class CircularBuffer
|
||||
{
|
||||
// allocated whole block pointer
|
||||
uint8 * m_buffer;
|
||||
uint8 * m_bufferEnd;
|
||||
|
||||
// region A pointer, and size
|
||||
uint8 * m_regionAPointer;
|
||||
size_t m_regionASize;
|
||||
|
||||
// region size
|
||||
uint8 * m_regionBPointer;
|
||||
size_t m_regionBSize;
|
||||
|
||||
// allocated size
|
||||
size_t m_bufferSize;
|
||||
|
||||
|
||||
// pointer magic!
|
||||
INLINE size_t GetAFreeSpace() { return (m_bufferEnd - m_regionAPointer - m_regionASize); }
|
||||
INLINE size_t GetSpaceBeforeA() { return (m_regionAPointer - m_buffer); }
|
||||
INLINE size_t GetSpaceAfterA() { return (m_bufferEnd - m_regionAPointer - m_regionASize); }
|
||||
INLINE size_t GetBFreeSpace() { if(m_regionBPointer == nullptr) { return 0; } return (m_regionAPointer - m_regionBPointer - m_regionBSize); }
|
||||
|
||||
public:
|
||||
CircularBuffer();
|
||||
~CircularBuffer();
|
||||
|
||||
/** Read bytes from the buffer
|
||||
* @param destination pointer to destination where bytes will be written
|
||||
* @param bytes number of bytes to read
|
||||
* @return true if there was enough data, false otherwise
|
||||
*/
|
||||
bool Read(void * destination, size_t bytes);
|
||||
void AllocateB();
|
||||
|
||||
/** Write bytes to the buffer
|
||||
* @param data pointer to the data to be written
|
||||
* @param bytes number of bytes to be written
|
||||
* @return true if was successful, otherwise false
|
||||
*/
|
||||
bool Write(const void * data, size_t bytes);
|
||||
|
||||
/** Returns the allocated size of the buffer.
|
||||
*/
|
||||
INLINE size_t GetAllocatedSize() const { return m_bufferSize; }
|
||||
|
||||
/** Returns the number of available bytes left.
|
||||
*/
|
||||
size_t GetSpace();
|
||||
|
||||
/** Returns the number of bytes currently stored in the buffer.
|
||||
*/
|
||||
size_t GetSize();
|
||||
|
||||
/** Returns the number of contiguous bytes (that can be pushed out in one operation)
|
||||
*/
|
||||
size_t GetContiguousBytes();
|
||||
|
||||
/** Removes len bytes from the front of the buffer
|
||||
* @param len the number of bytes to "cut"
|
||||
*/
|
||||
void Remove(size_t len);
|
||||
|
||||
/** Returns a pointer at the "end" of the buffer, where new data can be written
|
||||
*/
|
||||
void * GetBuffer();
|
||||
|
||||
/** Allocate the buffer with room for size bytes
|
||||
* @param size the number of bytes to allocate
|
||||
*/
|
||||
void Allocate(size_t size);
|
||||
|
||||
/** Increments the "written" pointer forward len bytes
|
||||
* @param len number of bytes to step
|
||||
*/
|
||||
void IncrementWritten(size_t len); // i.e. "commit"
|
||||
|
||||
/** Returns a pointer at the "beginning" of the buffer, where data can be pulled from
|
||||
*/
|
||||
void * GetBufferStart();
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "KOSocketMgr.h"
|
||||
|
||||
typedef std::map<uint16, KOSocket *> SessionMap;
|
||||
|
||||
template <class T>
|
||||
class ClientSocketMgr : public KOSocketMgr<T>
|
||||
{
|
||||
public:
|
||||
ClientSocketMgr<T>() {}
|
||||
|
||||
virtual Socket *AssignSocket(SOCKET socket) { return nullptr; }
|
||||
|
||||
virtual ~ClientSocketMgr() {}
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "stdafx.h"
|
||||
#include "Condition.h"
|
||||
|
||||
Condition::Condition() : m_nLockCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Condition::BeginSynchronized()
|
||||
{
|
||||
m_lock.lock();
|
||||
++m_nLockCount;
|
||||
}
|
||||
|
||||
void Condition::EndSynchronized()
|
||||
{
|
||||
--m_nLockCount;
|
||||
m_lock.unlock();
|
||||
}
|
||||
|
||||
uint32 Condition::Wait(time_t timeout)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_lock);
|
||||
m_condition.wait_for(lock, std::chrono::milliseconds(timeout));
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 Condition::Wait()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_lock);
|
||||
m_condition.wait(lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Condition::Signal()
|
||||
{
|
||||
m_condition.notify_one();
|
||||
}
|
||||
|
||||
void Condition::Broadcast()
|
||||
{
|
||||
m_condition.notify_all();
|
||||
}
|
||||
|
||||
Condition::~Condition()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
|
||||
class Condition
|
||||
{
|
||||
public:
|
||||
Condition();
|
||||
~Condition();
|
||||
void BeginSynchronized();
|
||||
void EndSynchronized();
|
||||
uint32 Wait(time_t timeout);
|
||||
uint32 Wait();
|
||||
void Signal();
|
||||
void Broadcast();
|
||||
|
||||
private:
|
||||
int m_nLockCount;
|
||||
|
||||
std::condition_variable m_condition;
|
||||
std::mutex m_lock;
|
||||
};
|
||||
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
#include <ctime>
|
||||
|
||||
class DateTime
|
||||
{
|
||||
public:
|
||||
// Uses the current time by default
|
||||
DateTime()
|
||||
{
|
||||
time_t now;
|
||||
time(&now);
|
||||
_tm = localtime(&now);
|
||||
}
|
||||
|
||||
// Uses the timestamp specified
|
||||
DateTime(time_t timestamp)
|
||||
{
|
||||
_tm = localtime(×tamp);
|
||||
}
|
||||
|
||||
// Constructs a date/time using the specified date parts.
|
||||
DateTime(uint16 sYear, uint8 bMonth, uint8 bDay, uint8 bHour = 0, uint8 bMinute = 0, uint8 bSecond = 0)
|
||||
{
|
||||
// Get the current time
|
||||
time_t now;
|
||||
time(&now);
|
||||
_tm = localtime(&now);
|
||||
|
||||
// Now update it with the data specified
|
||||
_tm->tm_year = sYear - 1900;
|
||||
_tm->tm_mon = bMonth - 1;
|
||||
_tm->tm_mday = bDay;
|
||||
_tm->tm_hour = bHour;
|
||||
_tm->tm_min = bMinute;
|
||||
_tm->tm_sec = bSecond;
|
||||
|
||||
// Finally reconstruct it, so the other data is updated.
|
||||
Update();
|
||||
}
|
||||
|
||||
// Uses the specified time struct
|
||||
DateTime(struct tm * _tm)
|
||||
{
|
||||
this->_tm = _tm;
|
||||
}
|
||||
|
||||
// Simple getters to retrieve & convert time data to a more conventional form
|
||||
uint16 GetYear() { return _tm->tm_year + 1900; }
|
||||
uint8 GetMonth() { return _tm->tm_mon + 1; }
|
||||
uint8 GetDay() { return _tm->tm_mday; }
|
||||
uint8 GetDayOfWeek() { return _tm->tm_wday; }
|
||||
uint8 GetHour() { return _tm->tm_hour; }
|
||||
uint8 GetMinute() { return _tm->tm_min; }
|
||||
uint8 GetSecond() { return _tm->tm_sec; }
|
||||
|
||||
// NOTE: If any of these overflow, they'll be handled by mktime() accordingly.
|
||||
// This makes our life *much* easier; date/time logic is not pretty.
|
||||
|
||||
void INLINE AddYears(int iYears)
|
||||
{
|
||||
_tm->tm_year += iYears;
|
||||
Update();
|
||||
}
|
||||
|
||||
void INLINE AddMonths(int iMonths)
|
||||
{
|
||||
_tm->tm_mon += iMonths;
|
||||
Update();
|
||||
}
|
||||
|
||||
void INLINE AddWeeks(int iWeeks)
|
||||
{
|
||||
AddDays(iWeeks * 7);
|
||||
}
|
||||
|
||||
void INLINE AddDays(int iDays)
|
||||
{
|
||||
_tm->tm_mday += iDays;
|
||||
Update();
|
||||
}
|
||||
|
||||
void INLINE AddHours(int iHours)
|
||||
{
|
||||
_tm->tm_hour += iHours;
|
||||
Update();
|
||||
}
|
||||
|
||||
void INLINE AddMinutes(int iMinutes)
|
||||
{
|
||||
_tm->tm_min += iMinutes;
|
||||
Update();
|
||||
}
|
||||
|
||||
void INLINE AddSeconds(int iSeconds)
|
||||
{
|
||||
_tm->tm_sec += iSeconds;
|
||||
Update();
|
||||
}
|
||||
|
||||
private:
|
||||
void INLINE Update() { mktime(_tm); }
|
||||
|
||||
protected:
|
||||
struct tm * _tm;
|
||||
};
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,67 @@
|
||||
f:\005server\shared\debug\shared.pdb
|
||||
f:\005server\shared\debug\shared.ıdb
|
||||
f:\005server\shared\debug\tstrıng.obj
|
||||
f:\005server\shared\debug\socketwın32.obj
|
||||
f:\005server\shared\debug\socketopswın32.obj
|
||||
f:\005server\shared\debug\socketmgr.obj
|
||||
f:\005server\shared\debug\socket.obj
|
||||
f:\005server\shared\debug\jvcryptıon.obj
|
||||
f:\005server\shared\debug\hardwareınformatıon.obj
|
||||
f:\005server\shared\debug\shared.pch
|
||||
f:\005server\shared\debug\stdafx.obj
|
||||
f:\005server\shared\debug\thread.obj
|
||||
f:\005server\shared\debug\sıgnal_handler.obj
|
||||
f:\005server\shared\debug\rwlock.obj
|
||||
f:\005server\shared\debug\referenceobject.obj
|
||||
f:\005server\shared\debug\kosocket.obj
|
||||
f:\005server\shared\debug\globals.obj
|
||||
f:\005server\shared\debug\odbcrecordset.obj
|
||||
f:\005server\shared\debug\odbcparameter.obj
|
||||
f:\005server\shared\debug\odbcconnectıon.obj
|
||||
f:\005server\shared\debug\odbccommand.obj
|
||||
f:\005server\shared\debug\condıtıon.obj
|
||||
f:\005server\shared\debug\cırcularbuffer.obj
|
||||
f:\005server\shared\debug\lzf.obj
|
||||
f:\005server\shared\debug\crc32.obj
|
||||
f:\005server\shared\debug\tımethread.obj
|
||||
f:\005server\shared\debug\smdfıle.obj
|
||||
f:\005server\shared\debug\ını.obj
|
||||
f:\005server\shared\debug\debugutıls.obj
|
||||
f:\bın\debug\shared.lıb
|
||||
f:\005server\shared\debug\vcpkg.applocal.log
|
||||
f:\005server\server source\shared\debug\circularbuffer.obj
|
||||
f:\005server\server source\shared\debug\condition.obj
|
||||
f:\005server\server source\shared\debug\crc32.obj
|
||||
f:\005server\server source\shared\debug\debugutils.obj
|
||||
f:\005server\server source\shared\debug\globals.obj
|
||||
f:\005server\server source\shared\debug\hardwareınformation.obj
|
||||
f:\005server\server source\shared\debug\ıni.obj
|
||||
f:\005server\server source\shared\debug\jvcryption.obj
|
||||
f:\005server\server source\shared\debug\kosocket.obj
|
||||
f:\005server\server source\shared\debug\lzf.obj
|
||||
f:\005server\server source\shared\debug\odbccommand.obj
|
||||
f:\005server\server source\shared\debug\odbcconnection.obj
|
||||
f:\005server\server source\shared\debug\odbcparameter.obj
|
||||
f:\005server\server source\shared\debug\odbcrecordset.obj
|
||||
f:\005server\server source\shared\debug\referenceobject.obj
|
||||
f:\005server\server source\shared\debug\rwlock.obj
|
||||
f:\005server\server source\shared\debug\signal_handler.obj
|
||||
f:\005server\server source\shared\debug\smdfile.obj
|
||||
f:\005server\server source\shared\debug\socket.obj
|
||||
f:\005server\server source\shared\debug\socketmgr.obj
|
||||
f:\005server\server source\shared\debug\socketopswin32.obj
|
||||
f:\005server\server source\shared\debug\socketwin32.obj
|
||||
f:\005server\server source\shared\debug\stdafx.obj
|
||||
f:\005server\server source\shared\debug\thread.obj
|
||||
f:\005server\server source\shared\debug\timethread.obj
|
||||
f:\005server\server source\shared\debug\tstring.obj
|
||||
f:\005server\server source\shared\debug\shared.pch
|
||||
f:\005server\server source\shared\debug\shared.idb
|
||||
f:\005server\server source\shared\debug\shared.pdb
|
||||
f:\005server\server source\shared\debug\shared.tlog\cl.command.1.tlog
|
||||
f:\005server\server source\shared\debug\shared.tlog\cl.read.1.tlog
|
||||
f:\005server\server source\shared\debug\shared.tlog\cl.write.1.tlog
|
||||
f:\005server\server source\shared\debug\shared.tlog\lib-link.read.1.tlog
|
||||
f:\005server\server source\shared\debug\shared.tlog\lib-link.write.1.tlog
|
||||
f:\005server\server source\shared\debug\shared.tlog\lib.command.1.tlog
|
||||
f:\005server\server source\shared\debug\shared.tlog\shared.write.1u.tlog
|
||||
Binary file not shown.
@@ -0,0 +1,27 @@
|
||||
stdafx.cpp
|
||||
CircularBuffer.cpp
|
||||
Condition.cpp
|
||||
HardwareInformation.cpp
|
||||
JvCryption.cpp
|
||||
KOSocket.cpp
|
||||
RWLock.cpp
|
||||
ReferenceObject.cpp
|
||||
Socket.cpp
|
||||
SocketMgr.cpp
|
||||
SocketOpsWin32.cpp
|
||||
SocketWin32.cpp
|
||||
Thread.cpp
|
||||
OdbcCommand.cpp
|
||||
OdbcConnection.cpp
|
||||
OdbcParameter.cpp
|
||||
OdbcRecordset.cpp
|
||||
globals.cpp
|
||||
signal_handler.cpp
|
||||
Generating Code...
|
||||
F:\005SERVER\server source\shared\database\OdbcCommand.cpp(20,6): warning C4267: 'argument': conversion from 'size_t' to 'SQLUSMALLINT', possible loss of data
|
||||
DebugUtils.cpp
|
||||
Ini.cpp
|
||||
SMDFile.cpp
|
||||
TimeThread.cpp
|
||||
Generating Code...
|
||||
shared.vcxproj -> F:\005SERVER\server source\..\bin\Debug\shared.lib
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
#TargetFrameworkVersion=v4.0:PlatformToolSet=v142:EnableManagedIncrementalBuild=false:VCToolArchitecture=Native32Bit:WindowsTargetPlatformVersion=10.0.17763.0
|
||||
Debug|Win32|F:\005SERVER\server source\|
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "stdafx.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
void FormattedDebugString(const char * fmt, ...)
|
||||
{
|
||||
char buf[4096], *p = buf;
|
||||
va_list args;
|
||||
int n;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = _vsnprintf(p, sizeof(buf) - 3, fmt, args); // allow for proper linefeed & null terminator
|
||||
va_end(args);
|
||||
p += (n < 0) ? sizeof buf - 3 : n;
|
||||
while (p > buf && isspace(p[-1]))
|
||||
*--p = '\0';
|
||||
*p++ = '\r';
|
||||
*p++ = '\n';
|
||||
*p = '\0';
|
||||
|
||||
#ifdef WIN32
|
||||
OutputDebugString(buf);
|
||||
#else
|
||||
printf("%s", buf);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void FormattedDebugString(const char * fmt, ...);
|
||||
@@ -0,0 +1,32 @@
|
||||
#include "stdafx.h"
|
||||
#include "HardwareInformation.h"
|
||||
|
||||
HardwareInformation::HardwareInformation()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief License Number Control.
|
||||
*/
|
||||
bool HardwareInformation::IsValidHardwareID(std::vector<int64> HardwareIDArray)
|
||||
{
|
||||
uint16 MACData1, MACData2 = 0;
|
||||
GetMacHash(MACData1, MACData2);
|
||||
int64 nLicenseNumber = GetHardwareID();
|
||||
|
||||
foreach (itr, HardwareIDArray)
|
||||
if (*itr == nLicenseNumber)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get License Number
|
||||
*/
|
||||
int64 HardwareInformation::GetHardwareID()
|
||||
{
|
||||
uint16 MACData1, MACData2 = 0;
|
||||
GetMacHash(MACData1, MACData2);
|
||||
return _atoi64(string_format("%d%d%d%d",MACData1,MACData2,GetCPUHash(),GetVolumeHash()).c_str());
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <Iphlpapi.h>
|
||||
#include <intrin.h>
|
||||
|
||||
#pragma comment(lib, "iphlpapi.lib")
|
||||
|
||||
class HardwareInformation
|
||||
{
|
||||
public:
|
||||
HardwareInformation();
|
||||
int64 GetHardwareID();
|
||||
bool IsValidHardwareID(std::vector<int64> HardwareIDArray);
|
||||
private:
|
||||
uint16 HashMacAddress(PIP_ADAPTER_INFO info)
|
||||
{
|
||||
uint16 nHash = 0;
|
||||
for ( uint32 i = 0; i < info->AddressLength; i++ )
|
||||
nHash += (info->Address[i] << (( i & 1 ) * 8 ));
|
||||
return nHash;
|
||||
}
|
||||
|
||||
void GetMacHash(uint16 & MACOffset1, uint16 & MACOffset2)
|
||||
{
|
||||
IP_ADAPTER_INFO AdapterInfo[32];
|
||||
DWORD dwBufLen = sizeof( AdapterInfo );
|
||||
|
||||
DWORD dwStatus = GetAdaptersInfo( AdapterInfo, &dwBufLen );
|
||||
if ( dwStatus != ERROR_SUCCESS )
|
||||
return;
|
||||
|
||||
PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;
|
||||
MACOffset1 = HashMacAddress( pAdapterInfo );
|
||||
if (pAdapterInfo->Next)
|
||||
MACOffset2 = HashMacAddress( pAdapterInfo->Next );
|
||||
|
||||
if (MACOffset1 > MACOffset2)
|
||||
{
|
||||
uint16 TempOffset = MACOffset2;
|
||||
MACOffset2 = MACOffset1;
|
||||
MACOffset1 = TempOffset;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 GetCPUHash()
|
||||
{
|
||||
int CPUInfo[4] = { 0, 0, 0, 0 };
|
||||
__cpuid(CPUInfo, 0);
|
||||
uint16 nHash = 0;
|
||||
uint16* nPointer = (uint16*)(&CPUInfo[0]);
|
||||
for (uint16 i = 0; i < 8; i++)
|
||||
nHash += nPointer[i];
|
||||
|
||||
return nHash;
|
||||
}
|
||||
|
||||
uint16 GetVolumeHash()
|
||||
{
|
||||
DWORD SerialNum = 0;
|
||||
GetVolumeInformation( "C:\\", NULL, 0, &SerialNum, NULL, NULL, NULL, 0 );
|
||||
uint16 nHash = (uint16)(( SerialNum + ( SerialNum >> 16 )) & 0xFFFF );
|
||||
return nHash;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,162 @@
|
||||
#include "stdafx.h"
|
||||
#include "Ini.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "tstring.h"
|
||||
|
||||
#define INI_BUFFER 512
|
||||
|
||||
CIni::CIni(const char *lpFilename)
|
||||
{
|
||||
m_szFileName = lpFilename;
|
||||
Load(lpFilename);
|
||||
}
|
||||
|
||||
bool CIni::Load(const char * lpFilename /*= nullptr*/)
|
||||
{
|
||||
const char * fn = (lpFilename == nullptr ? m_szFileName.c_str() : lpFilename);
|
||||
std::ifstream file(fn);
|
||||
if (!file)
|
||||
{
|
||||
printf("Warning: %s does not exist, will use configured defaults.\n", fn);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string currentSection;
|
||||
|
||||
// If an invalid section is hit
|
||||
// Ensure that we don't place key/value pairs
|
||||
// from the invalid section into the previously loaded section.
|
||||
bool bSkipNextSection = false;
|
||||
while (!file.eof())
|
||||
{
|
||||
std::string line;
|
||||
getline(file, line);
|
||||
|
||||
rtrim(line);
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
// Check for value strings first
|
||||
// It's faster than checking for a section
|
||||
// at the expense of of not being able to use '=' in section names.
|
||||
// As this is uncommon behaviour, this is a suitable trade-off.
|
||||
size_t keySeparatorPos = line.find(INI_KEY_SEPARATOR);
|
||||
if (keySeparatorPos != std::string::npos)
|
||||
{
|
||||
if (bSkipNextSection)
|
||||
continue;
|
||||
|
||||
std::string key = line.substr(0, keySeparatorPos),
|
||||
value = line.substr(keySeparatorPos + 1);
|
||||
|
||||
// Clean up key/value to allow for 'key = value'
|
||||
rtrim(key); /* remove trailing whitespace from keys */
|
||||
ltrim(value); /* remove preleading whitespace from values */
|
||||
|
||||
ConfigMap::iterator itr = m_configMap.find(currentSection);
|
||||
if (itr == m_configMap.end())
|
||||
{
|
||||
m_configMap.insert(std::make_pair(currentSection, ConfigEntryMap()));
|
||||
itr = m_configMap.find(currentSection);
|
||||
}
|
||||
|
||||
itr->second[key] = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Not a value, so assume it's a section
|
||||
size_t sectionStart = line.find_first_of(INI_SECTION_START),
|
||||
sectionEnd = line.find_last_of(INI_SECTION_END);
|
||||
|
||||
if (sectionStart == std::string::npos
|
||||
|| sectionEnd == std::string::npos
|
||||
|| sectionStart > sectionEnd)
|
||||
{
|
||||
/* invalid section */
|
||||
bSkipNextSection = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
currentSection = line.substr(sectionStart + 1, sectionEnd - 1);
|
||||
bSkipNextSection = false;
|
||||
}
|
||||
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CIni::Save(const char * lpFilename /*= nullptr*/)
|
||||
{
|
||||
const char * fn = (lpFilename == nullptr ? m_szFileName.c_str() : lpFilename);
|
||||
FILE * fp = fopen(fn, "w");
|
||||
foreach (sectionItr, m_configMap)
|
||||
{
|
||||
// Start the section
|
||||
fprintf(fp, "[%s]" INI_NEWLINE, sectionItr->first.c_str());
|
||||
|
||||
// Now list out all the key/value pairs
|
||||
foreach (keyItr, sectionItr->second)
|
||||
fprintf(fp, "%s=%s" INI_NEWLINE, keyItr->first.c_str(), keyItr->second.c_str());
|
||||
|
||||
// Use a trailing newline to finish the section, to make it easier to read
|
||||
fprintf(fp, INI_NEWLINE);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
int CIni::GetInt(const char* lpAppName, const char* lpKeyName, const int nDefault)
|
||||
{
|
||||
ConfigMap::iterator sectionItr = m_configMap.find(lpAppName);
|
||||
if (sectionItr != m_configMap.end())
|
||||
{
|
||||
ConfigEntryMap::iterator keyItr = sectionItr->second.find(lpKeyName);
|
||||
if (keyItr != sectionItr->second.end())
|
||||
return atoi(keyItr->second.c_str());
|
||||
}
|
||||
|
||||
SetInt(lpAppName, lpKeyName, nDefault);
|
||||
return nDefault;
|
||||
}
|
||||
|
||||
bool CIni::GetBool(const char* lpAppName, const char* lpKeyName, const bool bDefault)
|
||||
{
|
||||
return GetInt(lpAppName, lpKeyName, bDefault) == 1;
|
||||
}
|
||||
|
||||
void CIni::GetString(const char* lpAppName, const char* lpKeyName, const char* lpDefault, std::string & lpOutString, bool bAllowEmptyStrings /*= true*/)
|
||||
{
|
||||
ConfigMap::iterator sectionItr = m_configMap.find(lpAppName);
|
||||
if (sectionItr != m_configMap.end())
|
||||
{
|
||||
ConfigEntryMap::iterator keyItr = sectionItr->second.find(lpKeyName);
|
||||
if (keyItr != sectionItr->second.end())
|
||||
{
|
||||
lpOutString = keyItr->second;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SetString(lpAppName, lpKeyName, lpDefault);
|
||||
lpOutString = lpDefault;
|
||||
}
|
||||
|
||||
int CIni::SetInt(const char* lpAppName, const char* lpKeyName, const int nDefault)
|
||||
{
|
||||
char tmpDefault[INI_BUFFER];
|
||||
_snprintf(tmpDefault, INI_BUFFER, "%d", nDefault);
|
||||
return SetString(lpAppName, lpKeyName, tmpDefault);
|
||||
}
|
||||
|
||||
int CIni::SetString(const char* lpAppName, const char* lpKeyName, const char* lpDefault)
|
||||
{
|
||||
ConfigMap::iterator itr = m_configMap.find(lpAppName);
|
||||
if (itr == m_configMap.end())
|
||||
{
|
||||
m_configMap.insert(std::make_pair(lpAppName, ConfigEntryMap()));
|
||||
itr = m_configMap.find(lpAppName);
|
||||
}
|
||||
itr->second[lpKeyName] = lpDefault;
|
||||
Save();
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#define INI_SECTION_START '['
|
||||
#define INI_SECTION_END ']'
|
||||
#define INI_KEY_SEPARATOR '='
|
||||
#define INI_NEWLINE "\n"
|
||||
|
||||
class CIni
|
||||
{
|
||||
private:
|
||||
std::string m_szFileName;
|
||||
// Defines key/value pairs within sections
|
||||
typedef std::map<std::string, std::string> ConfigEntryMap;
|
||||
|
||||
// Defines the sections containing the key/value pairs
|
||||
typedef std::map<std::string, ConfigEntryMap> ConfigMap;
|
||||
|
||||
ConfigMap m_configMap;
|
||||
|
||||
public:
|
||||
CIni(const char *lpFilename);
|
||||
|
||||
bool Load(const char * lpFileName = nullptr);
|
||||
void Save(const char * lpFileName = nullptr);
|
||||
|
||||
int GetInt(const char* lpAppName, const char* lpKeyName, const int nDefault);
|
||||
bool GetBool(const char* lpAppName, const char* lpKeyName, const bool bDefault);
|
||||
void GetString(const char* lpAppName, const char* lpKeyName, const char* lpDefault, std::string & lpOutString, bool bAllowEmptyStrings = true);
|
||||
int SetInt(const char* lpAppName, const char* lpKeyName, const int nDefault);
|
||||
int SetString(const char* lpAppName, const char* lpKeyName, const char* lpDefault);
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "stdafx.h"
|
||||
#include "JvCryption.h"
|
||||
#include "version.h"
|
||||
|
||||
|
||||
#define g_private_key 0x1207500120128966
|
||||
//#define g_private_key 0x1507500150128966
|
||||
|
||||
void CJvCryption::Init() { m_tkey = m_public_key ^ g_private_key; }
|
||||
|
||||
uint64 CJvCryption::GenerateKey()
|
||||
{
|
||||
#ifdef USE_CRYPTION
|
||||
// because of their sucky encryption method, 0 means it effectively won't be encrypted.
|
||||
// We don't want that happening...
|
||||
do
|
||||
{
|
||||
m_public_key = RandUInt64();
|
||||
} while (!m_public_key);
|
||||
#endif
|
||||
return m_public_key;
|
||||
}
|
||||
|
||||
void CJvCryption::JvEncryptionFast(int len, uint8 *datain, uint8 *dataout)
|
||||
{
|
||||
uint8 *pkey, lkey, rsk;
|
||||
int rkey = 2157;
|
||||
|
||||
pkey = (uint8 *)&m_tkey;
|
||||
lkey = (len * 157) & 0xff;
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
rsk = (rkey >> 8) & 0xff;
|
||||
dataout[i] = ((datain[i] ^ rsk) ^ pkey[(i % 8)]) ^ lkey;
|
||||
rkey *= 2171;
|
||||
}
|
||||
}
|
||||
|
||||
int CJvCryption::JvDecryptionWithCRC32(int len, uint8 *datain, uint8 *dataout)
|
||||
{
|
||||
int result;
|
||||
JvDecryptionFast(len, datain, dataout);
|
||||
|
||||
if (crc32(dataout, len - 4, -1) == *(uint32 *)(len - 4 + dataout))
|
||||
result = len - 4;
|
||||
else
|
||||
result = -1;
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#define USE_CRYPTION
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "crc32.h"
|
||||
}
|
||||
|
||||
class CJvCryption
|
||||
{
|
||||
private:
|
||||
uint64 m_public_key, m_tkey;
|
||||
|
||||
public:
|
||||
CJvCryption() : m_public_key(0) {}
|
||||
|
||||
INLINE uint64 GetPublicKey() { return m_public_key; }
|
||||
uint64 GenerateKey();
|
||||
|
||||
void Init();
|
||||
|
||||
void JvEncryptionFast(int len, uint8 *datain, uint8 *dataout);
|
||||
INLINE void JvDecryptionFast(int len, uint8 *datain, uint8 *dataout) { JvEncryptionFast(len, datain, dataout); };
|
||||
|
||||
int JvDecryptionWithCRC32(int len, uint8 *datain, uint8 *dataout);
|
||||
};
|
||||
@@ -0,0 +1,235 @@
|
||||
#include "stdafx.h"
|
||||
#include "KOSocket.h"
|
||||
#include "packets.h"
|
||||
#include "version.h"
|
||||
|
||||
KOSocket::KOSocket(uint16 socketID, SocketMgr * mgr, SOCKET fd, uint32 sendBufferSize, uint32 recvBufferSize)
|
||||
: Socket(fd, sendBufferSize, recvBufferSize),
|
||||
m_socketID(socketID), m_remaining(0), m_usingCrypto(false),
|
||||
m_readTries(0), m_sequence(0), m_lastResponse(0)
|
||||
{
|
||||
SetSocketMgr(mgr);
|
||||
}
|
||||
|
||||
void KOSocket::OnConnect()
|
||||
{
|
||||
if (GetRemoteIP() == "127.0.0.1")
|
||||
TRACE("Connection received from %s:%d\n", GetRemoteIP().c_str(), GetRemotePort());
|
||||
|
||||
m_remaining = 0;
|
||||
m_usingCrypto = false;
|
||||
m_readTries = 0;
|
||||
m_sequence = 0;
|
||||
m_lastResponse = UNIXTIME;
|
||||
}
|
||||
|
||||
void KOSocket::OnRead()
|
||||
{
|
||||
Packet pkt;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (m_remaining == 0)
|
||||
{
|
||||
if (GetReadBuffer().GetSize() < 5)
|
||||
return; //check for opcode as well
|
||||
|
||||
uint16 header = 0;
|
||||
GetReadBuffer().Read(&header, 2);
|
||||
if (header != 0x55AA)
|
||||
{
|
||||
TRACE("%s: Got packet without header 0x55AA, got 0x%X\n", GetRemoteIP().c_str(), header);
|
||||
goto error_handler;
|
||||
}
|
||||
|
||||
GetReadBuffer().Read(&m_remaining, 2);
|
||||
if (m_remaining == 0)
|
||||
{
|
||||
TRACE("%s: Got packet without an opcode, this should never happen.\n", GetRemoteIP().c_str());
|
||||
goto error_handler;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_remaining > GetReadBuffer().GetAllocatedSize())
|
||||
{
|
||||
TRACE("%s: Packet received which was %u bytes in size, maximum of %u.\n", GetRemoteIP().c_str(), m_remaining, GetReadBuffer().GetAllocatedSize());
|
||||
goto error_handler;
|
||||
}
|
||||
|
||||
if (m_remaining > GetReadBuffer().GetSize())
|
||||
{
|
||||
if (m_readTries > 4)
|
||||
{
|
||||
TRACE("%s: packet fragmentation count is over 4, disconnecting as they're probably up to something bad\n", GetRemoteIP().c_str());
|
||||
goto error_handler;
|
||||
}
|
||||
m_readTries++;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 *in_stream = new uint8[m_remaining];
|
||||
|
||||
m_readTries = 0;
|
||||
GetReadBuffer().Read(in_stream, m_remaining);
|
||||
|
||||
uint16 footer = 0;
|
||||
GetReadBuffer().Read(&footer, 2);
|
||||
|
||||
if (footer != 0xAA55 || !DecryptPacket(in_stream, pkt))
|
||||
{
|
||||
TRACE("%s: Footer invalid (%X) or failed to decrypt.\n", GetRemoteIP().c_str(), footer);
|
||||
delete [] in_stream;
|
||||
goto error_handler;
|
||||
}
|
||||
|
||||
delete [] in_stream;
|
||||
|
||||
m_lastResponse = UNIXTIME;
|
||||
|
||||
if (!HandlePacket(pkt))
|
||||
{
|
||||
TRACE("%s: Handler for packet %X returned false\n", GetRemoteIP().c_str(), pkt.GetOpcode());
|
||||
#ifndef _DEBUG
|
||||
goto error_handler;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Update the time of the last (valid) response from the client.
|
||||
|
||||
m_remaining = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error_handler:
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
bool KOSocket::DecryptPacket(uint8 *in_stream, Packet & pkt)
|
||||
{
|
||||
uint8* final_packet = nullptr;
|
||||
|
||||
if (isCryptoEnabled())
|
||||
{
|
||||
// Invalid packet (all encrypted packets need a CRC32 checksum!)
|
||||
if (m_remaining < 4
|
||||
// Invalid checksum
|
||||
|| m_crypto.JvDecryptionWithCRC32(m_remaining, in_stream, in_stream) < 0
|
||||
// Invalid sequence ID
|
||||
|| ++m_sequence != *(uint32 *)(in_stream))
|
||||
return false;
|
||||
|
||||
m_remaining -= 8; // remove the sequence ID & CRC checksum
|
||||
final_packet = &in_stream[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
final_packet = in_stream; // for simplicity :P
|
||||
}
|
||||
|
||||
m_remaining--;
|
||||
pkt = Packet(final_packet[0], (size_t)m_remaining);
|
||||
if (m_remaining > 0)
|
||||
{
|
||||
pkt.resize(m_remaining);
|
||||
memcpy((void*)pkt.contents(), &final_packet[1], m_remaining);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KOSocket::Send(Packet * pkt)
|
||||
{
|
||||
if (!IsConnected() || pkt->size() + 1 > GetWriteBuffer().GetAllocatedSize())
|
||||
return false;
|
||||
|
||||
bool r;
|
||||
|
||||
uint8 opcode = pkt->GetOpcode();
|
||||
uint8 * out_stream = nullptr;
|
||||
uint16 len = (uint16)(pkt->size() + 1);
|
||||
|
||||
if (isCryptoEnabled())
|
||||
{
|
||||
len += 5;
|
||||
|
||||
out_stream = new uint8[len];
|
||||
|
||||
*(uint16 *)&out_stream[0] = 0x1efc;
|
||||
*(uint16 *)&out_stream[2] = (uint16)(m_sequence); // this isn't actually incremented here
|
||||
out_stream[4] = 0;
|
||||
out_stream[5] = pkt->GetOpcode();
|
||||
|
||||
if (pkt->size() > 0)
|
||||
memcpy(&out_stream[6], pkt->contents(), pkt->size());
|
||||
|
||||
m_crypto.JvEncryptionFast(len, out_stream, out_stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
out_stream = new uint8[len];
|
||||
out_stream[0] = pkt->GetOpcode();
|
||||
if (pkt->size() > 0)
|
||||
memcpy(&out_stream[1], pkt->contents(), pkt->size());
|
||||
}
|
||||
|
||||
|
||||
BurstBegin();
|
||||
if (GetWriteBuffer().GetSpace() < size_t(len + 6))
|
||||
{
|
||||
TRACE("Disonnected due to insufficient buffer space [%d]. \n", GetSocketID());
|
||||
BurstEnd();
|
||||
Disconnect();
|
||||
return false;
|
||||
}
|
||||
r = BurstSend((const uint8*)"\xaa\x55", 2);
|
||||
if (r) r = BurstSend((const uint8*)&len, 2);
|
||||
if (r) r = BurstSend((const uint8*)out_stream, len);
|
||||
if (r) r = BurstSend((const uint8*)"\x55\xaa", 2);
|
||||
if (r) BurstPush();
|
||||
BurstEnd();
|
||||
|
||||
delete [] out_stream;
|
||||
return r;
|
||||
}
|
||||
|
||||
bool KOSocket::SendCompressed(Packet * pkt)
|
||||
{
|
||||
if (pkt->size() < 500)
|
||||
return Send(pkt);
|
||||
|
||||
Packet result(WIZ_COMPRESS_PACKET);
|
||||
uint32 inLength = pkt->size() + 1, outLength = inLength + LZF_MARGIN, crc;
|
||||
uint8 *buffer = new uint8[inLength], *outBuffer = new uint8[outLength];
|
||||
|
||||
*buffer = pkt->GetOpcode();
|
||||
if (pkt->size() > 0)
|
||||
memcpy(buffer + 1, pkt->contents(), pkt->size());
|
||||
|
||||
crc = (uint32)crc32(buffer, inLength, 0);
|
||||
outLength = lzf_compress(buffer, inLength, outBuffer, outLength);
|
||||
|
||||
result << outLength << inLength;
|
||||
result << uint32(crc);
|
||||
|
||||
result.append(outBuffer, outLength);
|
||||
|
||||
delete [] buffer;
|
||||
delete [] outBuffer;
|
||||
|
||||
return Send(&result);
|
||||
}
|
||||
|
||||
void KOSocket::OnDisconnect()
|
||||
{
|
||||
if (GetRemoteIP() == "127.0.0.1")
|
||||
printf("Connection closed from %s:%d\n", GetRemoteIP().c_str(), GetRemotePort());
|
||||
}
|
||||
|
||||
void KOSocket::EnableCrypto()
|
||||
{
|
||||
#ifdef USE_CRYPTION
|
||||
m_crypto.Init();
|
||||
m_usingCrypto = true;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include "SocketMgr.h"
|
||||
#include "Packet.h"
|
||||
#include "JvCryption.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "lzf.h"
|
||||
}
|
||||
|
||||
// KO sockets time out after at least 30 seconds of inactivity. 6.1.2016
|
||||
#define KOSOCKET_TIMEOUT (60)
|
||||
|
||||
// Allow up to 30 minutes for the player to create their character / the client to load.
|
||||
#define KOSOCKET_LOADING_TIMEOUT (30 * 60)
|
||||
|
||||
class KOSocket : public Socket
|
||||
{
|
||||
public:
|
||||
KOSocket(uint16 socketID, SocketMgr * mgr, SOCKET fd, uint32 sendBufferSize, uint32 recvBufferSize);
|
||||
|
||||
INLINE bool isCryptoEnabled() { return m_usingCrypto; };
|
||||
INLINE uint16 GetSocketID() { return m_socketID; };
|
||||
INLINE uint16 GetTargetID() { return m_targetID; };
|
||||
INLINE time_t GetLastResponseTime() { return m_lastResponse; }
|
||||
|
||||
virtual void OnConnect();
|
||||
virtual void OnRead();
|
||||
virtual bool DecryptPacket(uint8 *in_stream, Packet & pkt);
|
||||
virtual bool HandlePacket(Packet & pkt) = 0;
|
||||
|
||||
virtual bool Send(Packet * pkt);
|
||||
virtual bool SendCompressed(Packet * pkt);
|
||||
|
||||
virtual void OnDisconnect();
|
||||
|
||||
void EnableCrypto();
|
||||
|
||||
protected:
|
||||
CJvCryption m_crypto;
|
||||
time_t m_lastResponse;
|
||||
uint32 m_sequence;
|
||||
uint16 m_remaining, m_socketID, m_targetID, bytesReceived;
|
||||
uint8 m_readTries;
|
||||
bool m_usingCrypto;
|
||||
};
|
||||
@@ -0,0 +1,160 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "RWLock.h"
|
||||
#include "SocketMgr.h"
|
||||
#include "KOSocket.h"
|
||||
|
||||
typedef std::map<uint16, KOSocket *> SessionMap;
|
||||
|
||||
template <class T>
|
||||
class KOSocketMgr : public SocketMgr
|
||||
{
|
||||
public:
|
||||
KOSocketMgr<T>() : m_server(nullptr) {}
|
||||
|
||||
virtual void InitSessions(uint16 sTotalSessions);
|
||||
virtual bool Listen(uint16 sPort, uint16 sTotalSessions);
|
||||
virtual bool Listen(std::string sIPAddress, uint16 sPort, uint16 sTotalSessions);
|
||||
virtual void OnConnect(Socket *pSock);
|
||||
virtual Socket *AssignSocket(SOCKET socket);
|
||||
virtual void DisconnectCallback(Socket *pSock);
|
||||
|
||||
void RunServer()
|
||||
{
|
||||
SpawnWorkerThreads();
|
||||
GetServer()->run();
|
||||
}
|
||||
|
||||
// Send a packet to all active sessions
|
||||
void SendAll(Packet * pkt)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_lock);
|
||||
SessionMap & sessizmap = m_activeSessions;
|
||||
for (auto itr = sessizmap.begin(); itr != sessizmap.end(); ++itr)
|
||||
itr->second->Send(pkt);
|
||||
}
|
||||
|
||||
void SendAllCompressed(Packet * result)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_lock);
|
||||
SessionMap & sessMap = m_activeSessions;
|
||||
for (auto itr = sessMap.begin(); itr != sessMap.end(); ++itr)
|
||||
itr->second->SendCompressed(result);
|
||||
}
|
||||
|
||||
ListenSocket<T> * GetServer() { return m_server; }
|
||||
INLINE SessionMap & GetIdleSessionMap() { return m_idleSessions; }
|
||||
INLINE SessionMap & GetActiveSessionMap() { return m_activeSessions; }
|
||||
INLINE std::recursive_mutex& GetLock() { return m_lock; }
|
||||
|
||||
T * operator[] (uint16 id)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_lock);
|
||||
|
||||
auto itr = m_activeSessions.find(id);
|
||||
if (itr != m_activeSessions.end())
|
||||
return static_cast<T *>(itr->second);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Shutdown();
|
||||
virtual ~KOSocketMgr();
|
||||
|
||||
protected:
|
||||
SessionMap m_idleSessions, m_activeSessions;
|
||||
std::recursive_mutex m_lock;
|
||||
|
||||
private:
|
||||
ListenSocket<T> * m_server;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void KOSocketMgr<T>::InitSessions(uint16 sTotalSessions)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_lock);
|
||||
for (uint16 i = 0; i < sTotalSessions; i++)
|
||||
m_idleSessions.insert(std::make_pair(i, new T(i, this)));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool KOSocketMgr<T>::Listen(uint16 sPort, uint16 sTotalSessions)
|
||||
{
|
||||
return Listen("0.0.0.0", sPort, sTotalSessions);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool KOSocketMgr<T>::Listen(std::string sIPAddress, uint16 sPort, uint16 sTotalSessions)
|
||||
{
|
||||
if (m_server != nullptr)
|
||||
return false;
|
||||
|
||||
CreateCompletionPort();
|
||||
|
||||
m_server = new ListenSocket<T>(this, sIPAddress.c_str(), sPort);
|
||||
if (!m_server->IsOpen())
|
||||
return false;
|
||||
|
||||
InitSessions(sTotalSessions);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Socket * KOSocketMgr<T>::AssignSocket(SOCKET socket)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_lock);
|
||||
Socket *pSock = nullptr;
|
||||
|
||||
for (auto itr = m_idleSessions.begin(); itr != m_idleSessions.end(); itr++)
|
||||
{
|
||||
m_activeSessions.insert(std::make_pair(itr->first, itr->second));
|
||||
pSock = itr->second;
|
||||
m_idleSessions.erase(itr);
|
||||
pSock->SetFd(socket);
|
||||
break;
|
||||
}
|
||||
return pSock;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void KOSocketMgr<T>::OnConnect(Socket *pSock)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_lock);
|
||||
auto itr = m_idleSessions.find(static_cast<KOSocket *>(pSock)->GetSocketID());
|
||||
if (itr != m_idleSessions.end())
|
||||
{
|
||||
m_activeSessions.insert(std::make_pair(itr->first, itr->second));
|
||||
m_idleSessions.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void KOSocketMgr<T>::DisconnectCallback(Socket *pSock)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_lock);
|
||||
auto itr = m_activeSessions.find(static_cast<T *>(pSock)->GetSocketID());
|
||||
if (itr != m_activeSessions.end())
|
||||
{
|
||||
m_idleSessions.insert(std::make_pair(itr->first, itr->second));
|
||||
m_activeSessions.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void KOSocketMgr<T>::Shutdown()
|
||||
{
|
||||
if (m_bShutdown)
|
||||
return;
|
||||
|
||||
if (m_server != nullptr)
|
||||
delete m_server;
|
||||
|
||||
SocketMgr::Shutdown();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
KOSocketMgr<T>::~KOSocketMgr()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Multiplatform Async Network Library
|
||||
* Copyright (c) 2007 Burlex
|
||||
*
|
||||
* ListenSocket<T>: Creates a socket listener on specified address and port,
|
||||
* requires Update() to be called every loop.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
template <class T>
|
||||
uint32 THREADCALL ListenSocketThread(void * lpParam)
|
||||
{
|
||||
ListenSocket<T> * ls = (ListenSocket<T> *)lpParam;
|
||||
return ls->runnable() ? 0 : 1;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
class ListenSocket
|
||||
{
|
||||
public:
|
||||
ListenSocket(SocketMgr *socketMgr, const char * ListenAddress, uint32 Port) : m_threadRunning(false)
|
||||
{
|
||||
m_socket = WSASocket(AF_INET, SOCK_STREAM, 0, nullptr, 0, WSA_FLAG_OVERLAPPED);
|
||||
|
||||
// Enable blocking on the socket
|
||||
SocketOps::Blocking(m_socket);
|
||||
|
||||
m_address.sin_family = AF_INET;
|
||||
m_address.sin_port = ntohs((u_short)Port);
|
||||
m_address.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
m_opened = false;
|
||||
|
||||
if (strcmp(ListenAddress, "0.0.0.0"))
|
||||
{
|
||||
struct hostent * hostname = gethostbyname(ListenAddress);
|
||||
if (hostname != nullptr)
|
||||
memcpy(&m_address.sin_addr.s_addr, hostname->h_addr_list[0], hostname->h_length);
|
||||
}
|
||||
|
||||
// bind. well, attempt to...
|
||||
int ret = ::bind(m_socket, (const sockaddr*)&m_address, sizeof(m_address));
|
||||
if (ret != 0)
|
||||
{
|
||||
printf("Bind unsuccessful on port %u.\n", Port);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = listen(m_socket, 5);
|
||||
if (ret != 0)
|
||||
{
|
||||
printf("Unable to listen on port %u.\n", Port);
|
||||
return;
|
||||
}
|
||||
|
||||
m_opened = true;
|
||||
m_cp = socketMgr->GetCompletionPort();
|
||||
m_socketMgr = socketMgr;
|
||||
}
|
||||
|
||||
~ListenSocket() { Close(); }
|
||||
|
||||
bool run()
|
||||
{
|
||||
if (m_thread.isStarted())
|
||||
return false;
|
||||
|
||||
m_thread.start(ListenSocketThread<T>, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool runnable()
|
||||
{
|
||||
struct sockaddr_in m_tempAddress;
|
||||
uint32 len = sizeof(sockaddr_in);
|
||||
m_threadRunning = true;
|
||||
|
||||
while (m_opened && m_threadRunning)
|
||||
{
|
||||
//SOCKET aSocket = accept(m_socket, (sockaddr*)&m_tempAddress, (socklen_t*)&len);
|
||||
SOCKET aSocket = WSAAccept(m_socket, (sockaddr*)&m_tempAddress, (socklen_t*)&len, 0, 0);
|
||||
if (aSocket == INVALID_SOCKET)
|
||||
{
|
||||
//sleep(10); // Don't kill the CPU!
|
||||
continue;
|
||||
}
|
||||
|
||||
// Attempt to assign the socket to an available session
|
||||
Socket *socket = m_socketMgr->AssignSocket(aSocket);
|
||||
|
||||
// No available sessions... unfortunately, we're going to have to let you go.
|
||||
if (socket == nullptr)
|
||||
{
|
||||
SocketOps::CloseSocket(aSocket);
|
||||
continue;
|
||||
}
|
||||
socket->SetCompletionPort(m_cp);
|
||||
socket->Accept(&m_tempAddress);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
// prevent a race condition here.
|
||||
bool mo = m_opened;
|
||||
|
||||
m_opened = false;
|
||||
m_threadRunning = false;
|
||||
|
||||
if (mo)
|
||||
SocketOps::CloseSocket(m_socket);
|
||||
|
||||
m_thread.waitForExit();
|
||||
}
|
||||
|
||||
INLINE bool IsOpen() { return m_opened; }
|
||||
INLINE HANDLE GetCompletionPort() { return m_cp; }
|
||||
|
||||
private:
|
||||
bool m_threadRunning;
|
||||
Thread m_thread;
|
||||
|
||||
HANDLE m_cp;
|
||||
SocketMgr *m_socketMgr;
|
||||
SOCKET m_socket;
|
||||
struct sockaddr_in m_address;
|
||||
bool m_opened;
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "CircularBuffer.h"
|
||||
#include "SocketDefines.h"
|
||||
#include "SocketOps.h"
|
||||
#include "Socket.h"
|
||||
#include "SocketMgr.h"
|
||||
#include "ListenSocketWin32.h"
|
||||
|
||||
#include "JvCryption.h"
|
||||
#include "KOSocket.h"
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
#define CRYPT_KEY 129
|
||||
|
||||
class Packet : public ByteBuffer
|
||||
{
|
||||
public:
|
||||
INLINE Packet() : ByteBuffer(), m_opcode(0) { }
|
||||
INLINE Packet(uint8 opcode) : ByteBuffer(4096), m_opcode(opcode) {}
|
||||
INLINE Packet(uint8 opcode, size_t res) : ByteBuffer(res), m_opcode(opcode) {}
|
||||
INLINE Packet(const Packet &packet) : ByteBuffer(packet), m_opcode(packet.m_opcode) {}
|
||||
INLINE Packet(uint8 opcode, uint8 subOpcode) : m_opcode(opcode)
|
||||
{
|
||||
append(&subOpcode, 1);
|
||||
}
|
||||
|
||||
//! Clear packet and set opcode all in one mighty blow
|
||||
INLINE void Initialize(uint8 opcode)
|
||||
{
|
||||
clear();
|
||||
m_opcode = opcode;
|
||||
}
|
||||
|
||||
INLINE uint8 GetOpcode() const { return m_opcode; }
|
||||
INLINE void SetOpcode(uint8 opcode) { m_opcode = opcode; }
|
||||
INLINE uint8 GetByte(uint16 sira) const { return _storage[sira]; }
|
||||
INLINE void SetByte(uint16 sira,uint8 val) { _storage[sira] = val; }
|
||||
protected:
|
||||
uint8 m_opcode;
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "stdafx.h"
|
||||
#include "RWLock.h"
|
||||
|
||||
RWLock::RWLock()
|
||||
{
|
||||
_readers = _writers = 0;
|
||||
}
|
||||
|
||||
void RWLock::AcquireReadLock()
|
||||
{
|
||||
_cond.BeginSynchronized();
|
||||
_readers++;
|
||||
_cond.EndSynchronized();
|
||||
}
|
||||
|
||||
void RWLock::ReleaseReadLock()
|
||||
{
|
||||
_cond.BeginSynchronized();
|
||||
if (!(--_readers))
|
||||
if(_writers)
|
||||
_cond.Signal();
|
||||
_cond.EndSynchronized();
|
||||
}
|
||||
|
||||
void RWLock::AcquireWriteLock()
|
||||
{
|
||||
_cond.BeginSynchronized();
|
||||
_writers++;
|
||||
if (_readers)
|
||||
_cond.Wait();
|
||||
}
|
||||
|
||||
void RWLock::ReleaseWriteLock()
|
||||
{
|
||||
if (--_writers)
|
||||
_cond.Signal();
|
||||
_cond.EndSynchronized();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "Condition.h"
|
||||
|
||||
class RWLock
|
||||
{
|
||||
public:
|
||||
RWLock();
|
||||
void AcquireReadLock();
|
||||
void ReleaseReadLock();
|
||||
void AcquireWriteLock();
|
||||
void ReleaseWriteLock();
|
||||
|
||||
private:
|
||||
Condition _cond;
|
||||
volatile unsigned int _readers;
|
||||
volatile unsigned int _writers;
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "stdafx.h"
|
||||
#include "ReferenceObject.h"
|
||||
|
||||
ReferenceObject::ReferenceObject()
|
||||
: m_refCount(0)
|
||||
{
|
||||
IncRef();
|
||||
}
|
||||
|
||||
void ReferenceObject::IncRef()
|
||||
{
|
||||
++m_refCount;
|
||||
}
|
||||
|
||||
void ReferenceObject::DecRef()
|
||||
{
|
||||
if (m_refCount.decrement() == 0)
|
||||
delete this;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
class ReferenceObject
|
||||
{
|
||||
public:
|
||||
ReferenceObject();
|
||||
|
||||
// Increment the reference count
|
||||
void IncRef();
|
||||
|
||||
// Decrease the reference count and delete the object if it hits 0 (i.e. no more references).
|
||||
void DecRef();
|
||||
|
||||
virtual ~ReferenceObject() {}
|
||||
|
||||
private:
|
||||
Atomic<uint32> m_refCount;
|
||||
};
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,10 @@
|
||||
DebugUtils.cpp
|
||||
Ini.cpp
|
||||
F:\005SERVER\server source\shared\DebugUtils.cpp(1,10): error C1083: Cannot open precompiled header file: 'Release\shared.pch': No such file or directory
|
||||
SMDFile.cpp
|
||||
F:\005SERVER\server source\shared\Ini.cpp(1,10): error C1083: Cannot open precompiled header file: 'Release\shared.pch': No such file or directory
|
||||
stdafx.cpp
|
||||
F:\005SERVER\server source\shared\SMDFile.cpp(1,10): error C1083: Cannot open precompiled header file: 'Release\shared.pch': No such file or directory
|
||||
TimeThread.cpp
|
||||
F:\005SERVER\server source\shared\stdafx.cpp(1,10): error C1083: Cannot open precompiled header file: 'Release\shared.pch': No such file or directory
|
||||
F:\005SERVER\server source\shared\TimeThread.cpp(1,10): error C1083: Cannot open precompiled header file: 'Release\shared.pch': No such file or directory
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
#TargetFrameworkVersion=v4.0:PlatformToolSet=v142:EnableManagedIncrementalBuild=false:VCToolArchitecture=Native32Bit:WindowsTargetPlatformVersion=10.0.17763.0
|
||||
Release|Win32|F:\005SERVER\server source\|
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,223 @@
|
||||
#include "stdafx.h"
|
||||
#include "../N3BASE/N3ShapeMgr.h"
|
||||
#include "STLMapOnlyLoad.h"
|
||||
#include "database/structs.h"
|
||||
#include <set>
|
||||
#include "SMDFile.h"
|
||||
|
||||
SMDFile::SMDMap SMDFile::s_loadedMaps;
|
||||
|
||||
SMDFile::SMDFile() : m_ppnEvent(nullptr), m_fHeight(nullptr),
|
||||
m_nXRegion(0), m_nZRegion(0), m_nMapSize(0), m_fUnitDist(0.0f),
|
||||
m_N3ShapeMgr(new CN3ShapeMgr())
|
||||
{
|
||||
}
|
||||
|
||||
SMDFile *SMDFile::Load(std::string mapName, bool bLoadWarpsAndRegeneEvents /*= false*/)
|
||||
{
|
||||
// case insensitive filenames, allowing for database inconsistency...
|
||||
STRTOLOWER(mapName);
|
||||
|
||||
// Look to see if that SMD file has been loaded already
|
||||
SMDMap::iterator itr = s_loadedMaps.find(mapName);
|
||||
|
||||
// If it's been loaded already, we don't need to do anything.
|
||||
if (itr != s_loadedMaps.end())
|
||||
{
|
||||
// Add another reference.
|
||||
itr->second->IncRef();
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
// Map hasn't already been loaded
|
||||
std::string filename = string_format(MAP_DIR "%s", mapName.c_str());
|
||||
|
||||
// Does this file exist/can it be opened?
|
||||
FILE *fp = fopen(filename.c_str(), "rb");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
printf("ERROR: %s does not exist or no permission to access.\n", filename.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Try to load the file now.
|
||||
SMDFile *smd = new SMDFile();
|
||||
if (!smd->LoadMap(fp, mapName, bLoadWarpsAndRegeneEvents))
|
||||
{
|
||||
// Problem? Make sure we clean up after ourselves.
|
||||
smd->DecRef(); // it's the only reference anyway
|
||||
smd = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Loaded fine, so now add it to the map.
|
||||
s_loadedMaps.insert(std::make_pair(mapName, smd));
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return smd;
|
||||
}
|
||||
|
||||
void SMDFile::OnInvalidMap()
|
||||
{
|
||||
printf("\n ** An error has occurred **\n\n");
|
||||
printf("ERROR: %s is not a valid map file.\n\n", m_MapName.c_str());
|
||||
printf("Previously, we ignored all invalid map behaviour, however this only hides\n");
|
||||
printf("very real problems - especially with things like AI pathfinding.\n\n");
|
||||
printf("This problem is most likely occur with maps tweaked to use a different\n");
|
||||
printf("map size. Unfortunately, doing this means data after that (almost everything)\n");
|
||||
printf("becomes corrupt, which is known to cause extremely 'unusual' buggy behaviour.\n\n");
|
||||
printf("It is recommended you use a map built for this zone, or at the very least,\n");
|
||||
printf("you should use a map originally built for the same zone size.\n\n");
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
bool SMDFile::LoadMap(FILE *fp, std::string & mapName, bool bLoadWarpsAndRegeneEvents)
|
||||
{
|
||||
m_MapName = mapName;
|
||||
|
||||
LoadTerrain(fp);
|
||||
|
||||
m_N3ShapeMgr->Create((m_nMapSize - 1)*m_fUnitDist, (m_nMapSize-1)*m_fUnitDist);
|
||||
if (!m_N3ShapeMgr->LoadCollisionData(fp)
|
||||
|| (m_nMapSize - 1) * m_fUnitDist != m_N3ShapeMgr->Width()
|
||||
|| (m_nMapSize - 1) * m_fUnitDist != m_N3ShapeMgr->Height())
|
||||
return false;
|
||||
|
||||
int mapwidth = (int)m_N3ShapeMgr->Width();
|
||||
|
||||
m_nXRegion = (int)(mapwidth / VIEW_DISTANCE) + 1;
|
||||
m_nZRegion = (int)(mapwidth / VIEW_DISTANCE) + 1;
|
||||
|
||||
LoadObjectEvent(fp);
|
||||
LoadMapTile(fp);
|
||||
|
||||
if (bLoadWarpsAndRegeneEvents)
|
||||
{
|
||||
LoadRegeneEvent(fp);
|
||||
LoadWarpList(fp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SMDFile::LoadTerrain(FILE *fp)
|
||||
{
|
||||
if (fread(&m_nMapSize, sizeof(m_nMapSize), 1, fp) != 1
|
||||
|| fread(&m_fUnitDist, sizeof(m_fUnitDist), 1, fp) != 1)
|
||||
return OnInvalidMap();
|
||||
|
||||
m_fHeight = new float[m_nMapSize * m_nMapSize];
|
||||
if (fread(m_fHeight, sizeof(float) * m_nMapSize * m_nMapSize, 1, fp) != 1)
|
||||
OnInvalidMap();
|
||||
}
|
||||
|
||||
void SMDFile::LoadObjectEvent(FILE *fp)
|
||||
{
|
||||
int iEventObjectCount = 0;
|
||||
if (fread(&iEventObjectCount, sizeof(int), 1, fp) != 1)
|
||||
return OnInvalidMap();
|
||||
|
||||
// Load on K_OBJECTPOS table, this is set fd to last pointer...
|
||||
for (int i = 0; i < iEventObjectCount; i++)
|
||||
{
|
||||
if (fread((new _OBJECT_EVENT), 24, 1, fp) != 1)
|
||||
return OnInvalidMap();
|
||||
}
|
||||
}
|
||||
|
||||
void SMDFile::LoadMapTile(FILE *fp)
|
||||
{
|
||||
m_ppnEvent = new short[m_nMapSize * m_nMapSize];
|
||||
if (fread(m_ppnEvent, sizeof(short) * m_nMapSize * m_nMapSize, 1, fp) != 1)
|
||||
return OnInvalidMap();
|
||||
}
|
||||
|
||||
void SMDFile::LoadRegeneEvent(FILE *fp)
|
||||
{
|
||||
int iEventObjectCount = 0;
|
||||
if (fread(&iEventObjectCount, sizeof(iEventObjectCount), 1, fp) != 1)
|
||||
return OnInvalidMap();
|
||||
|
||||
for (int i = 0; i < iEventObjectCount; i++)
|
||||
{
|
||||
_REGENE_EVENT *pEvent = new _REGENE_EVENT;
|
||||
if (fread(pEvent, sizeof(_REGENE_EVENT) - sizeof(pEvent->sRegenePoint), 1, fp) != 1)
|
||||
return OnInvalidMap();
|
||||
|
||||
pEvent->sRegenePoint = i;
|
||||
|
||||
if (pEvent->sRegenePoint < 0
|
||||
|| !m_ObjectRegeneArray.PutData(pEvent->sRegenePoint, pEvent))
|
||||
delete pEvent;
|
||||
}
|
||||
}
|
||||
|
||||
void SMDFile::LoadWarpList(FILE *fp)
|
||||
{
|
||||
int WarpCount = 0;
|
||||
|
||||
if (fread(&WarpCount, sizeof(WarpCount), 1, fp) != 1)
|
||||
return OnInvalidMap();
|
||||
|
||||
for (int i = 0; i < WarpCount; i++)
|
||||
{
|
||||
_WARP_INFO *pWarp = new _WARP_INFO;
|
||||
if (fread(pWarp, sizeof(_WARP_INFO), 1, fp) != 1)
|
||||
{
|
||||
// NOTE: Some SMDs are so horribly broken warps are incomplete.
|
||||
// This will stop this (reasonably) normal use case from behaving any differently.
|
||||
if (feof(fp))
|
||||
return;
|
||||
|
||||
return OnInvalidMap();
|
||||
}
|
||||
|
||||
if (pWarp->sWarpID == 0
|
||||
|| !m_WarpArray.PutData(pWarp->sWarpID, pWarp))
|
||||
delete pWarp;
|
||||
}
|
||||
}
|
||||
|
||||
void SMDFile::GetWarpList(int warpGroup, std::set<_WARP_INFO *> & warpEntries)
|
||||
{
|
||||
foreach_stlmap_nolock (itr, m_WarpArray)
|
||||
{
|
||||
_WARP_INFO *pWarp = itr->second;
|
||||
if (pWarp == nullptr || (pWarp->sWarpID / 10) != warpGroup)
|
||||
continue;
|
||||
|
||||
warpEntries.insert(pWarp);
|
||||
}
|
||||
}
|
||||
|
||||
bool SMDFile::IsValidPosition(float x, float z, float y)
|
||||
{
|
||||
// TODO: Implement more thorough check
|
||||
return (x < m_N3ShapeMgr->Width() && z < m_N3ShapeMgr->Height());
|
||||
}
|
||||
|
||||
int SMDFile::GetEventID(int x, int z)
|
||||
{
|
||||
if (x < 0 || x >= m_nMapSize || z < 0 || z >= m_nMapSize)
|
||||
return -1;
|
||||
|
||||
return m_ppnEvent[x * m_nMapSize + z];
|
||||
}
|
||||
|
||||
SMDFile::~SMDFile()
|
||||
{
|
||||
if (m_ppnEvent != nullptr)
|
||||
{
|
||||
delete [] m_ppnEvent;
|
||||
m_ppnEvent = nullptr;
|
||||
}
|
||||
|
||||
if (m_fHeight != nullptr)
|
||||
{
|
||||
delete[] m_fHeight;
|
||||
m_fHeight = nullptr;
|
||||
}
|
||||
|
||||
delete m_N3ShapeMgr;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include "ReferenceObject.h"
|
||||
|
||||
class CUser;
|
||||
|
||||
typedef CSTLMapOnlyLoad <_OBJECT_EVENT> ObjectEventArray;
|
||||
typedef CSTLMapOnlyLoad <_REGENE_EVENT> ObjectRegeneArray;
|
||||
typedef CSTLMapOnlyLoad <_WARP_INFO> WarpArray;
|
||||
|
||||
class CN3ShapeMgr;
|
||||
class SMDFile : public ReferenceObject
|
||||
{
|
||||
public:
|
||||
SMDFile();
|
||||
|
||||
static SMDFile *Load(std::string mapName, bool bLoadWarpsAndRegeneEvents = false /* AI server doesn't need them */);
|
||||
|
||||
void OnInvalidMap();
|
||||
bool LoadMap(FILE *fp, std::string & mapName, bool bLoadWarpsAndRegeneEvents /* AI server doesn't need them */);
|
||||
void LoadTerrain(FILE *fp);
|
||||
void LoadObjectEvent(FILE *fp);
|
||||
void LoadMapTile(FILE *fp);
|
||||
void LoadRegeneEvent(FILE *fp);
|
||||
void LoadWarpList(FILE *fp);
|
||||
|
||||
bool IsValidPosition(float x, float z, float y);
|
||||
bool CheckEvent( float x, float z, CUser* pUser = nullptr );
|
||||
|
||||
int GetEventID(int x, int z);
|
||||
|
||||
INLINE int GetMapSize() { return m_nMapSize - 1; }
|
||||
INLINE float GetUnitDistance() { return m_fUnitDist; }
|
||||
INLINE int GetXRegionMax() { return m_nXRegion - 1; }
|
||||
INLINE int GetZRegionMax() { return m_nZRegion - 1; }
|
||||
|
||||
INLINE short * GetEventIDs() { return m_ppnEvent; }
|
||||
|
||||
INLINE ObjectEventArray * GetObjectEventArray() { return &m_ObjectEventArray; }
|
||||
INLINE _OBJECT_EVENT * GetObjectEvent(int objectindex) { return m_ObjectEventArray.GetData(objectindex); }
|
||||
INLINE _REGENE_EVENT * GetRegeneEvent(int objectindex) { return m_ObjectRegeneArray.GetData(objectindex); }
|
||||
INLINE _WARP_INFO * GetWarp(int warpID) { return m_WarpArray.GetData(warpID); }
|
||||
|
||||
void GetWarpList(int warpGroup, std::set<_WARP_INFO *> & warpEntries);
|
||||
|
||||
virtual ~SMDFile();
|
||||
|
||||
private:
|
||||
std::string m_MapName;
|
||||
|
||||
short* m_ppnEvent;
|
||||
WarpArray m_WarpArray;
|
||||
|
||||
ObjectEventArray m_ObjectEventArray;
|
||||
ObjectRegeneArray m_ObjectRegeneArray;
|
||||
|
||||
CN3ShapeMgr *m_N3ShapeMgr;
|
||||
|
||||
float* m_fHeight;
|
||||
|
||||
int m_nXRegion, m_nZRegion;
|
||||
|
||||
int m_nMapSize; // Grid Unit ex) 4m
|
||||
float m_fUnitDist; // i Grid Distance
|
||||
|
||||
typedef std::map<std::string, SMDFile *> SMDMap;
|
||||
static SMDMap s_loadedMaps;
|
||||
|
||||
#if defined(GAMESERVER)
|
||||
friend class C3DMap;
|
||||
#elif defined(AI_SERVER)
|
||||
friend class MAP;
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
template <class T>
|
||||
class CSTLMap
|
||||
{
|
||||
public:
|
||||
typedef typename std::map<uint32, T*>::iterator Iterator;
|
||||
std::map<uint32, T*> m_UserTypeMap;
|
||||
std::recursive_mutex m_lock;
|
||||
|
||||
int GetSize()
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
return m_UserTypeMap.size();
|
||||
}
|
||||
|
||||
bool IsExist(uint32 key)
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
return (m_UserTypeMap.find(key) != m_UserTypeMap.end());
|
||||
}
|
||||
|
||||
bool IsEmpty()
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
return m_UserTypeMap.empty();
|
||||
}
|
||||
|
||||
bool PutData(uint32 key_value, T* pData)
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
return m_UserTypeMap.insert(std::make_pair(key_value, pData)).second;
|
||||
}
|
||||
|
||||
T* GetData(uint32 key_value)
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
auto itr = m_UserTypeMap.find(key_value);
|
||||
return (itr != m_UserTypeMap.end() ? itr->second : nullptr);
|
||||
}
|
||||
|
||||
void DeleteData(uint32 key_value)
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
auto itr = m_UserTypeMap.find(key_value);
|
||||
if (itr!= m_UserTypeMap.end())
|
||||
{
|
||||
delete itr->second;
|
||||
m_UserTypeMap.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteAllData()
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
if (m_UserTypeMap.empty())
|
||||
return;
|
||||
|
||||
foreach (itr, m_UserTypeMap)
|
||||
delete itr->second;
|
||||
|
||||
m_UserTypeMap.clear();
|
||||
}
|
||||
|
||||
~CSTLMap() { DeleteAllData(); }
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
template <class T>
|
||||
class CSTLMapOnlyLoad
|
||||
{
|
||||
public:
|
||||
typedef typename std::map<uint32, T*>::iterator Iterator;
|
||||
std::map<uint32, T*> m_UserTypeMap;
|
||||
std::recursive_mutex m_lock;
|
||||
|
||||
int GetSize()
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
return m_UserTypeMap.size();
|
||||
}
|
||||
|
||||
bool IsExist(uint32 key)
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
return (m_UserTypeMap.find(key) != m_UserTypeMap.end());
|
||||
}
|
||||
|
||||
bool IsEmpty()
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
return m_UserTypeMap.empty();
|
||||
}
|
||||
|
||||
bool PutData(uint32 key_value, T* pData)
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
return m_UserTypeMap.insert(std::make_pair(key_value, pData)).second;
|
||||
}
|
||||
|
||||
T* GetData(uint32 key_value)
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
auto itr = m_UserTypeMap.find(key_value);
|
||||
return (itr != m_UserTypeMap.end() ? itr->second : nullptr);
|
||||
}
|
||||
|
||||
void DeleteData(uint32 key_value)
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
auto itr = m_UserTypeMap.find(key_value);
|
||||
if (itr!= m_UserTypeMap.end())
|
||||
{
|
||||
delete itr->second;
|
||||
m_UserTypeMap.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteAllData()
|
||||
{
|
||||
Guard lock(m_lock);
|
||||
if (m_UserTypeMap.empty())
|
||||
return;
|
||||
|
||||
foreach (itr, m_UserTypeMap)
|
||||
delete itr->second;
|
||||
|
||||
m_UserTypeMap.clear();
|
||||
}
|
||||
|
||||
~CSTLMapOnlyLoad() { DeleteAllData(); }
|
||||
};
|
||||
@@ -0,0 +1,139 @@
|
||||
#include "stdafx.h"
|
||||
#include "SocketMgr.h"
|
||||
#pragma warning(disable:4996)
|
||||
Socket::Socket(SOCKET fd, uint32 sendbuffersize, uint32 recvbuffersize)
|
||||
: m_fd(fd), m_connected(false), m_deleted(false), m_socketMgr(nullptr)
|
||||
{
|
||||
// Allocate buffers
|
||||
readBuffer.Allocate(recvbuffersize);
|
||||
writeBuffer.Allocate(sendbuffersize);
|
||||
|
||||
// IOCP member variables
|
||||
m_completionPort = 0;
|
||||
m_writeLock = 0;
|
||||
|
||||
// Check for needed fd allocation.
|
||||
if (m_fd == 0)
|
||||
m_fd = SocketOps::CreateTCPFileDescriptor();
|
||||
}
|
||||
|
||||
bool Socket::Connect(const char * Address, uint32 Port)
|
||||
{
|
||||
struct hostent * ci = gethostbyname(Address);
|
||||
if (ci == 0)
|
||||
return false;
|
||||
|
||||
m_client.sin_family = ci->h_addrtype;
|
||||
m_client.sin_port = ntohs((u_short)Port);
|
||||
memcpy(&m_client.sin_addr.s_addr, ci->h_addr_list[0], ci->h_length);
|
||||
|
||||
SocketOps::Blocking(m_fd);
|
||||
|
||||
if (m_fd == 0)
|
||||
m_fd = SocketOps::CreateTCPFileDescriptor();
|
||||
|
||||
if (connect(m_fd, (const sockaddr*)&m_client, sizeof(m_client)) == -1)
|
||||
return false;
|
||||
|
||||
// at this point the connection was established
|
||||
m_completionPort = m_socketMgr->GetCompletionPort();
|
||||
|
||||
_OnConnect();
|
||||
return true;
|
||||
}
|
||||
void Socket::Accept(sockaddr_in * address)
|
||||
{
|
||||
memcpy(&m_client, address, sizeof(*address));
|
||||
_OnConnect();
|
||||
}
|
||||
|
||||
void Socket::_OnConnect()
|
||||
{
|
||||
// set common parameters on the file descriptor
|
||||
m_connected = true;
|
||||
|
||||
m_writeLockMutex.lock();
|
||||
m_writeLock = 0;
|
||||
m_writeLockMutex.unlock();
|
||||
|
||||
AssignToCompletionPort();
|
||||
m_socketMgr->OnConnect(this);
|
||||
|
||||
// Call virtual onconnect
|
||||
OnConnect();
|
||||
//printf("_OnConnect %s:%d\n",GetRemoteIP().c_str(),GetRemotePort());
|
||||
|
||||
// Setting the read event up after calling OnConnect() ensures OnConnect() & subsequent connection setup code is run first (which is NOT GUARANTEED otherwise)
|
||||
SetupReadEvent();
|
||||
}
|
||||
|
||||
bool Socket::Send(const uint8 * Bytes, uint32 Size)
|
||||
{
|
||||
bool rv;
|
||||
|
||||
// This is really just a wrapper for all the burst stuff.
|
||||
BurstBegin();
|
||||
rv = BurstSend(Bytes, Size);
|
||||
if (rv)
|
||||
BurstPush();
|
||||
BurstEnd();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool Socket::BurstSend(const uint8 * Bytes, uint32 Size)
|
||||
{
|
||||
return writeBuffer.Write(Bytes, Size);
|
||||
}
|
||||
|
||||
std::string Socket::GetRemoteIP()
|
||||
{
|
||||
char* ip = (char*)inet_ntoa(m_client.sin_addr);
|
||||
if (ip != nullptr)
|
||||
return std::string(ip);
|
||||
|
||||
return std::string("noip");
|
||||
}
|
||||
|
||||
void Socket::Disconnect()
|
||||
{
|
||||
|
||||
if (!IsConnected())
|
||||
return;
|
||||
|
||||
m_connected = false;
|
||||
|
||||
m_readEvent.Unmark();
|
||||
|
||||
// Call virtual ondisconnect
|
||||
OnDisconnect();
|
||||
GetSocketMgr()->OnDisconnect(this);
|
||||
|
||||
SocketOps::CloseSocket(m_fd);
|
||||
m_fd = 0;
|
||||
|
||||
m_writeLockMutex.lock();
|
||||
m_writeLock = 0;
|
||||
m_writeLockMutex.unlock();
|
||||
|
||||
// Reset the read/write buffers
|
||||
GetReadBuffer().Remove(GetReadBuffer().GetSize());
|
||||
GetWriteBuffer().Remove(GetWriteBuffer().GetSize());
|
||||
}
|
||||
|
||||
void Socket::Delete()
|
||||
{
|
||||
if (IsDeleted())
|
||||
return;
|
||||
|
||||
m_deleted = true;
|
||||
|
||||
if (IsConnected())
|
||||
Disconnect();
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
Socket::~Socket()
|
||||
{
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user